3.2. Product Quadrature

This set uses a Gauss-Legendre quadrature along the polar angle, and a Gauss-Chebyshev quadrature along the azimuthal angle.

To run the code, simply type: jupyter nbconvert --to python --execute <basename>.ipynb.

To convert it to a python file (named <basename>.py), simply type: jupyter nbconvert --to python <basename>.ipynb

[ ]:
import os
import sys
import numpy as np

sys.path.append("../../..")

from pyopensn.aquad import GLCProductQuadrature2DXY
from pyopensn.context import UseColor, Finalize

UseColor(False)

3.2.1. Quadrature parameters

Here, we use a Product Quadrature for two-dimensional geometries.

We pick a quadrature set with 4 polar angles (whose cosines are between -1 and 1), and 12 azimuthal angles (between 0 and \(2\pi\)). Hence, in 2D, we will have a total of \(2 \times 12 = 24\) directions.

[ ]:
# Create a 2D angular quadrature with 4 polar and 12 azimuthal angles.
pquad = GLCProductQuadrature2DXY(4, 12)

3.2.2. Retrieve directions

[ ]:
vec3_omegas = pquad.omegas

n_directions = len(vec3_omegas)
print('number of directions =',n_directions)
omegas = np.zeros((n_directions,3))

for d in range(n_directions):
    omegas[d,:] = [vec3_omegas[d].x, vec3_omegas[d].y, vec3_omegas[d].z]

dim = 2

3.2.3. Create a function to plot the quadrature

[ ]:
import matplotlib.pyplot as plt
from matplotlib.patches import FancyArrowPatch
from mpl_toolkits.mplot3d import proj3d
import itertools

colors = itertools.cycle(["r", "g", "b", "k", "m", "c", "y", "crimson"])

# Create figure with options
fig = plt.figure(dpi=150)
ax = fig.add_subplot(111, projection='3d')

# Transparent sphere data
u = np.linspace(0, 2 * np.pi, 100)
v = np.linspace(0, np.pi, 100)
x = np.outer(np.cos(u), np.sin(v))
y = np.outer(np.sin(u), np.sin(v))
z = np.outer(np.ones(np.size(u)), np.cos(v))
# Plot the surface
ax.plot_surface(x, y, z, color='b', alpha=0.1)

# Create a custom 3D arrow class
class Arrow3D(FancyArrowPatch):
    def __init__(self, xs, ys, zs, *args, **kwargs):
        # Initialize with dummy 2D points
        super().__init__((0, 0), (0, 0), *args, **kwargs)
        self._verts3d = xs, ys, zs

    def do_3d_projection(self, renderer=None):
        # Project 3D coordinates to 2D using the axes projection matrix
        xs3d, ys3d, zs3d = self._verts3d
        xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, self.axes.get_proj())
        self.set_positions((xs[0], ys[0]), (xs[1], ys[1]))
        # Return a numerical depth value (for example, the mean of the projected z-values)
        return np.mean(zs)

    def draw(self, renderer):
        # Perform projection using the axes' projection matrix
        xs3d, ys3d, zs3d = self._verts3d
        xs, ys, zs = proj3d.proj_transform(xs3d, ys3d, zs3d, self.axes.get_proj())
        self.set_positions((xs[0], ys[0]), (xs[1], ys[1]))
        return super().draw(renderer)


start = -1.0

# Create axes arrows
a = Arrow3D(
    [start, 1.1],
    [0, 0],
    [0, 0],
    mutation_scale=10,
    lw=0.5,
    arrowstyle="-|>",
    color="darkorange",
)
ax.add_artist(a)

a = Arrow3D(
    [0, 0],
    [start, 1.1],
    [0, 0],
    mutation_scale=10,
    lw=0.5,
    arrowstyle="-|>",
    color="darkorange",
)
ax.add_artist(a)

a = Arrow3D(
    [0, 0],
    [0, 0],
    [start, 1.1],
    mutation_scale=10,
    lw=0.5,
    arrowstyle="-|>",
    color="darkorange",
)
ax.add_artist(a)

# The following code plots quadrature directions.
# Variables 'dim', 'n_directions', and 'omegas' must be defined appropriately elsewhere.
d_skip = 0
n_octants = int(2 ** dim)
n_dir_per_oct = int(n_directions / n_octants)
print("n octants=", n_octants, "ndir per octant=", n_dir_per_oct)
for oc in range(n_octants):
    clr = next(colors)
    d_skip = oc * n_dir_per_oct
    for d in range(n_dir_per_oct):
        om = omegas[d + d_skip, :]
        ax.plot3D([0, om[0]], [0, om[1]], [0, om[2]], c=clr, linewidth=0.75)

mu = omegas[:, -1]
polar_level = np.unique(mu)
for r in polar_level:
    x = np.sqrt(1 - r ** 2) * np.cos(u)
    y = np.sqrt(1 - r ** 2) * np.sin(u)
    z = r * np.ones_like(u)
    ax.plot3D(x, y, z, 'grey', linestyle="dashed", linewidth=0.5)

ax.view_init(30, 70)

# uncomment this line for interactive plot
# plt.show()

product_quadrature

3.2.4. Finalize (for Jupyter Notebook only)

In Python script mode, PyOpenSn automatically handles environment termination. However, this automatic finalization does not occur when running in a Jupyter notebook, so explicit finalization of the environment at the end of the notebook is required. Do not call the finalization in Python script mode, or in console mode.

Note that PyOpenSn’s finalization must be called before MPI’s finalization.

[ ]:
from IPython import get_ipython

def finalize_env():
    Finalize()
    MPI.Finalize()

ipython_instance = get_ipython()
if ipython_instance is not None:
    ipython_instance.events.register("post_execute", finalize_env)