1.1.3. Your First 2D Fixed-Source Calculation

This notebook extends the one-dimensional slab calculation to a square Cartesian domain.

1.1.3.1. Learning objectives

You will create a two-dimensional mesh, name its orthogonal boundaries, choose a quadrature appropriate to 2D Cartesian transport, solve a one-group fixed-source problem, and verify the scalar flux.

Prerequisite: Your First 1D Fixed-Source Calculation.

1.1.3.2. Import the OpenSn objects

[ ]:
if "opensn_console" not in globals():
    from mpi4py import MPI
    from pyopensn.aquad import GLCProductQuadrature2DXY
    from pyopensn.context import Finalize, UseColor
    from pyopensn.fieldfunc import FieldFunctionInterpolationVolume
    from pyopensn.logvol import RPPLogicalVolume
    from pyopensn.mesh import OrthogonalMeshGenerator
    from pyopensn.solver import DiscreteOrdinatesProblem, SteadyStateSourceSolver
    from pyopensn.source import VolumetricSource
    from pyopensn.xs import MultiGroupXS

    rank = MPI.COMM_WORLD.rank
    UseColor(False)

1.1.3.3. Create the square mesh

Supplying two node sets creates a Cartesian mesh in the \(x\)-\(y\) plane. SetOrthogonalBoundaries assigns the names xmin, xmax, ymin, and ymax; the problem uses vacuum conditions on all four by default.

[ ]:
num_cells = 16
length = 4.0
nodes = [length * i / num_cells for i in range(num_cells + 1)]
mesh = OrthogonalMeshGenerator(node_sets=[nodes, nodes]).Execute()
mesh.SetOrthogonalBoundaries()
mesh.SetUniformBlockID(0)

1.1.3.4. Define the physical and angular model

As in the 1D example, the material is purely absorbing and a uniform isotropic source fills the domain. The two-dimensional product quadrature combines polar and azimuthal directions so particles can travel throughout the \(x\)-\(y\) plane.

[ ]:
cross_sections = MultiGroupXS()
cross_sections.CreateSimpleOneGroup(sigma_t=1.0, c=0.0)
source = VolumetricSource(block_ids=[0], group_strength=[1.0])
quadrature = GLCProductQuadrature2DXY(
    n_polar=2, n_azimuthal=8, scattering_order=0
)

1.1.3.5. Assemble and solve the problem

The same problem-and-solver pattern applies in any dimension. Only the mesh and angular quadrature have changed from the slab example.

[ ]:
problem = DiscreteOrdinatesProblem(
    mesh=mesh,
    num_groups=1,
    groupsets=[
        {
            "groups_from_to": (0, 0),
            "angular_quadrature": quadrature,
            "inner_linear_method": "petsc_gmres",
            "l_abs_tol": 1.0e-10,
            "l_max_its": 100,
            "gmres_restart_interval": 30,
        }
    ],
    xs_map=[{"block_ids": [0], "xs": cross_sections}],
    volumetric_sources=[source],
)

solver = SteadyStateSourceSolver(problem=problem)
solver.Initialize()
solver.Execute()

1.1.3.6. Verify and interpret the scalar flux

The scalar flux is symmetric about both centerlines because the square, material, source, and boundary conditions are symmetric. Its maximum is near the center and below the infinite-medium value of 1 because particles can leak through four vacuum boundaries.

[ ]:
whole_domain = RPPLogicalVolume(infx=True, infy=True, infz=True)
interpolator = FieldFunctionInterpolationVolume()
interpolator.SetOperationType("max")
interpolator.SetLogicalVolume(whole_domain)
interpolator.AddFieldFunction(problem.GetScalarFluxFieldFunction()[0])
interpolator.Execute()
max_flux = interpolator.GetValue()

if rank == 0:
    print(f"FOUNDATION_2D_MAX_FLUX={max_flux:.8e}")

1.1.3.7. Exercises and next steps

Try using a rectangular domain, increasing n_azimuthal, or making one boundary reflecting. Before rerunning, predict whether the maximum scalar flux should rise or fall.

Next: Running in Serial and Parallel. The modeling tutorials cover mesh, logical-volume, material, source, boundary, and groupset choices in more detail.

[ ]:
if "opensn_console" not in globals():
    from IPython import get_ipython

    if get_ipython() is not None:
        Finalize()
        MPI.Finalize()