Skip to content

Core API

The package-level reference below contains Morana’s public problem-definition, numerical-control, execution-report, result, plotting, and export objects. Finite-volume solve functions are documented separately in the finite-volume reference. Start with the modeling and solver workflow for the intended workflow.

morana

Public API for Morana hex-z diffusion calculations.

Problem definitions live in ProblemConfiguration objects and execute through method-scoped functions such as solve_fixed_source.

BoundaryCondition dataclass

BoundaryCondition(
    kind: str,
    flux: ndarray | None = None,
    alpha: float | None = None,
    beta: float | None = None,
    current: ndarray | None = None,
)

Represent immutable diffusion boundary physics for selected faces.

Prefer the named constructors over direct construction; they make the physical convention explicit. Attach the resulting condition to exposed faces with globally() or an on_*() method. Boundary vectors are copied into read-only arrays and are ordered fast to thermal.

Parameters:

Name Type Description Default
kind str

Nonempty direct-construction boundary kind. Supported values are "reflective", "vacuum", "dirichlet", "robin", "partial_current", and "incoming_current". The selected kind determines which remaining fields are accepted.

required
flux ndarray | None

Nonempty, finite, nonnegative one-dimensional prescribed face-flux spectrum in n / cm^2 / s. Accepted only for "dirichlet"; None denotes zero flux. Its length must equal the problem energy group count when the boundary is resolved.

None
alpha float | None

Finite, nonnegative, dimensionless outward net-current-over-face-flux coefficient for "robin" only.

None
beta float | None

Finite, dimensionless returned-to-outgoing partial-current ratio in [0, 1] for "partial_current" only.

None
current ndarray | None

Nonempty, finite, nonnegative one-dimensional imposed incoming partial-current spectrum in n / cm^2 / s. It is accepted by "partial_current" and "incoming_current" only, and its length must equal the problem energy group count when resolved. None is allowed only for "partial_current" and denotes no imposed incidence.

None

Raises:

Type Description
TypeError

If kind is not a string.

ValueError

If kind is empty or unsupported, or its remaining fields do not satisfy the selected boundary convention.

Notes

Reflective, vacuum, zero-Dirichlet, and Robin conditions are homogeneous. A Dirichlet condition is homogeneous when its resolved flux vector is zero. A partial-current-return condition is homogeneous when its optional current is absent or resolves to zero; an incoming-current condition is homogeneous only when its current resolves to zero. Only homogeneous conditions are accepted by morana.solvers.finite_volume.solve_keff(). See the modeling workflow and exposed-boundary theory for selector precedence and finite-volume equations.

dirichlet classmethod

dirichlet(
    flux: ndarray | list[float],
) -> "BoundaryCondition"

Return a prescribed group-resolved face-flux boundary condition.

Parameters:

Name Type Description Default
flux ndarray | list[float]

Nonempty, finite, nonnegative one-dimensional face-flux spectrum in n / cm^2 / s, ordered fast to thermal. Its length must equal the problem energy group count when the boundary is resolved. The values are copied into a read-only array.

required
Notes

A nonzero spectrum contributes an inhomogeneous boundary source and is therefore unavailable to morana.solvers.finite_volume.solve_keff(). Use zero_dirichlet() for a homogeneous zero-flux boundary.

globally

globally() -> 'BoundaryAssignment'

Apply this condition to every exposed face as a fallback.

incoming_current classmethod

incoming_current(
    current: ndarray | list[float],
) -> "BoundaryCondition"

Return a pure group-resolved incoming partial-current boundary.

Parameters:

Name Type Description Default
current ndarray | list[float]

Nonempty, finite, nonnegative imposed incoming partial-current spectrum in n / cm^2 / s, ordered fast to thermal. Its length must equal the problem energy group count when the boundary is resolved. The values are copied into a read-only array.

required
Notes

This is a Marshak-vacuum response with independent incidence: J_out = phi_b / 2 - 2 * current. A nonzero spectrum creates an inhomogeneous boundary source and is unavailable to morana.solvers.finite_volume.solve_keff().

on_bottom

on_bottom() -> 'BoundaryAssignment'

Apply this condition to physical exterior bottom faces.

on_excluded

on_excluded(
    *,
    key: str | None = None,
    kind: str | None = None,
    direction: str | None = None
) -> "BoundaryAssignment"

Apply this condition to faces adjoining excluded material-mesh regions.

Parameters:

Name Type Description Default
key str | None

Excluded neighbor key to match. The key must be a string. Mutually exclusive with kind.

None
kind str | None

Excluded-region kind to match, such as "reflector" or "channel". Mutually exclusive with key.

None
direction str | None

Optional radial ("x+", "u-", and so on) or axial ("bottom" or "top") face direction to match.

None
Notes

Every supplied selector argument must match; an omitted argument matches any value. Therefore, on_excluded() selects every excluded-region interface. This selector does not apply to physical exterior faces. Compatible excluded-interface assignments resolve by key and direction, key, kind and direction, kind, direction, then the unqualified excluded-interface rule; the global rule is the final fallback.

on_outer

on_outer() -> 'BoundaryAssignment'

Apply this condition to every exterior domain face.

on_radial

on_radial() -> 'BoundaryAssignment'

Apply this condition to lateral exterior faces.

on_top

on_top() -> 'BoundaryAssignment'

Apply this condition to physical exterior top faces.

partial_current_return classmethod

partial_current_return(
    beta: float,
    current: ndarray | list[float] | None = None,
) -> "BoundaryCondition"

Return a partial-current-return boundary with optional incidence.

Parameters:

Name Type Description Default
beta float

Finite returned-to-outgoing partial-current ratio in [0, 1]. 0 is Marshak vacuum and 1 is reflective when current is omitted or zero.

required
current ndarray | list[float] | None

Optional nonempty, finite, nonnegative group-resolved imposed incoming partial current in n / cm^2 / s, ordered fast to thermal. Its length must equal the problem energy group count when resolved. The values are copied into a read-only array.

None
Notes

Morana applies j_minus = beta * j_plus + current independently in each group. A nonzero current creates an inhomogeneous boundary source and is unavailable to morana.solvers.finite_volume.solve_keff().

reflective classmethod

reflective() -> 'BoundaryCondition'

Return a homogeneous reflective boundary with J_out = 0.

This condition contributes neither leakage nor a boundary source and is equivalent to partial_current_return(beta=1.0) without imposed incidence.

robin classmethod

robin(alpha: float) -> 'BoundaryCondition'

Return a homogeneous scalar Robin-current boundary.

Parameters:

Name Type Description Default
alpha float

Finite, nonnegative, dimensionless coefficient in J_out = alpha * phi_b. 0 is reflective and 0.5 is the Marshak-vacuum value. Values above 0.5 are mathematical sinks, not passive physical albedos.

required

vacuum classmethod

vacuum() -> 'BoundaryCondition'

Return a homogeneous Marshak-vacuum boundary.

Morana uses J_out = phi_b / 2 at the physical face. It is equivalent to robin(alpha=0.5) and to partial_current_return(beta=0.0) without imposed incidence.

zero_dirichlet classmethod

zero_dirichlet() -> 'BoundaryCondition'

Return a homogeneous Dirichlet boundary with phi_b = 0.

This is not the Marshak-vacuum approximation: it prescribes zero physical face flux and is the limiting case of a Robin coefficient tending to infinity.

BoundaryConditionSet dataclass

BoundaryConditionSet(*assignments: BoundaryAssignment)

Store selector-bound boundary conditions and resolve exposed faces.

Parameters:

Name Type Description Default
*assignments BoundaryAssignment

Fluent boundary assignments returned by methods such as BoundaryCondition.globally and BoundaryCondition.on_top. Every value must be a BoundaryAssignment. Two assignments with the same complete selector identity are rejected; overlapping assignments with distinct selectors are allowed. The set may remain incomplete while a configuration is being assembled.

()

Attributes:

Name Type Description
assignments tuple[BoundaryAssignment, ...]

Tuple of immutable assignments in construction order.

Notes

BoundaryConditionSet is immutable. Use with_assignment() to construct a separate checked set with one additional assignment.

Resolution is independent of construction order. An excluded interface uses key-and-direction, key, kind-and-direction, kind, direction-only, any-excluded, then global precedence. A physical exterior face uses its matching radial, bottom, or top selector, then outer, then global precedence. Call check_coverage with the current material mesh to require a condition for every exposed radial and axial face. Problem assembly and solver execution perform the same coverage requirement.

Build a possibly incomplete boundary set from fluent assignments.

Raises:

Type Description
TypeError

If an input is not a BoundaryAssignment.

ValueError

If an input duplicates a selector already present in this set.

check_coverage

check_coverage(material_mesh: 'MaterialMesh') -> None

Require every exposed radial and axial face to resolve.

Parameters:

Name Type Description Default
material_mesh 'MaterialMesh'

Material layout whose active cells and exposed faces are checked.

required

Raises:

Type Description
TypeError

If material_mesh is not a MaterialMesh.

ValueError

If one or more exposed faces lack a resolved condition. The error lists every uncovered face with its layer, active-cell ID, direction, topology kind, and excluded-neighbor identity when applicable.

Notes

This method does not mutate the set or the material mesh. Use ProblemConfiguration.check_boundary_coverage() when validating the boundary set attached to a complete problem definition.

resolve

resolve(face: 'DomainFace') -> BoundaryCondition

Resolve a condition for one exposed radial or axial face.

Parameters:

Name Type Description Default
face 'DomainFace'

Exposed DomainFace from the material mesh. Internal faces do not have boundary conditions and are rejected.

required

Returns:

Type Description
BoundaryCondition

Condition selected by the locked topology precedence.

Raises:

Type Description
TypeError

If face is not a DomainFace.

ValueError

If face is internal or no assignment covers it.

Notes

Resolution uses selector specificity, not assignment construction order. See the class documentation for both physical-exterior and excluded-interface precedence chains.

with_assignment

with_assignment(
    assignment: BoundaryAssignment,
) -> "BoundaryConditionSet"

Return a new set with one additional fluent assignment.

Parameters:

Name Type Description Default
assignment BoundaryAssignment

Fluent BoundaryAssignment to append after existing assignments. It is checked against every existing selector using the same validation as the constructor.

required

Returns:

Type Description
BoundaryConditionSet

New set; this set and its assignment tuple are unchanged.

Raises:

Type Description
TypeError

If assignment is not a BoundaryAssignment.

ValueError

If assignment duplicates an existing selector.

BoundarySelector dataclass

BoundarySelector(
    scope: str,
    direction: str | None = None,
    excluded_key: str | None = None,
    excluded_kind: str | None = None,
)

Immutably select exposed boundary faces by topology, not physics.

Prefer the fluent BoundaryCondition selection methods in ordinary problem definitions. Direct construction is available when constructing a BoundaryAssignment explicitly. A selector matches topology only; its associated condition supplies the boundary physics.

Parameters:

Name Type Description Default
scope str

Closed selector vocabulary: "global" is the fallback for every exposed face; "outer" selects all physical exterior faces; "radial" selects physical lateral exterior faces; "to_excluded" selects faces adjoining excluded material-mesh positions; and "bottom" and "top" select the corresponding physical axial exterior faces.

required
direction str | None

Optional direction filter for "to_excluded" only. Accepted values are "x+", "x-", "u+", "u-", "v+", "v-", "bottom", and "top".

None
excluded_key str | None

Optional human-readable material-mesh excluded key for "to_excluded" only. It must contain a non-whitespace character and only printable characters.

None
excluded_kind str | None

Optional human-readable excluded-region kind for "to_excluded" only. It must contain a non-whitespace character and only printable characters. Mutually exclusive with excluded_key.

None

Raises:

Type Description
TypeError

If scope is not a string, or a supplied direction, excluded_key, or excluded_kind is not a string.

ValueError

If the scope or direction is unknown; direction is used with another scope; an excluded filter is used with another scope; both excluded filters are supplied; or a supplied identifier is empty, whitespace-only, or non-printable.

Notes

to_excluded filters are combined, and omitted filters match any value. Selector precedence is resolved by BoundaryConditionSet; the selector does not carry a numeric priority.

specificity_key property

specificity_key: tuple[
    str, str | None, str | None, str | None
]

Return the complete selector identity for duplicate detection.

This tuple is not a precedence rank. BoundaryConditionSet rejects assignments with equal identities and resolves distinct overlapping selectors by its documented topology precedence.

bottom classmethod

bottom() -> 'BoundarySelector'

Select physical exterior faces at the bottom of the stack.

Excluded interfaces to a lower in-stack position are selected only by to_excluded(direction="bottom").

everywhere classmethod

everywhere() -> 'BoundarySelector'

Select every exposed face as the global fallback.

This includes both physical exterior and excluded-interface faces. More specific compatible selectors take precedence.

outer classmethod

outer() -> 'BoundarySelector'

Select every physical exterior face, radial and axial.

Excluded-interface faces are not physical exterior faces and are not selected. Radial, bottom, and top selectors refine this scope.

radial classmethod

radial() -> 'BoundarySelector'

Select physical lateral exterior faces only.

This scope excludes bottom, top, and excluded-interface faces. Morana does not provide direction-specific physical-exterior radial selectors.

to_excluded classmethod

to_excluded(
    key: str | None = None,
    kind: str | None = None,
    direction: str | None = None,
) -> "BoundarySelector"

Select faces adjoining excluded material-mesh positions.

Parameters:

Name Type Description Default
key str | None

Optional excluded neighbor key. The key must be a string. Mutually exclusive with kind.

None
kind str | None

Optional excluded-region kind. Mutually exclusive with key.

None
direction str | None

Optional radial or axial face direction: "x+", "x-", "u+", "u-", "v+", "v-", "bottom", or "top".

None
Notes

Every supplied filter must match, while an omitted filter matches any value. Thus to_excluded() selects every excluded interface. This factory does not select physical exterior faces.

top classmethod

top() -> 'BoundarySelector'

Select physical exterior faces at the top of the stack.

Excluded interfaces to an upper in-stack position are selected only by to_excluded(direction="top").

CellInspection dataclass

CellInspection(*args: object, **kwargs: object)

Store one read-only active-cell inspection value.

Instances are returned by Result.cell_at. Direct construction is not supported.

Attributes:

Name Type Description
material_key str

Material-layout key assigned to the selected cell.

cross_sections CrossSections

Immutable macroscopic cross sections assigned to material_key.

flux ndarray

Read-only one-dimensional cell-average scalar-flux array in n / cm^2 / s, ordered fast to thermal.

Reject direct construction; inspect a completed result instead.

CellSource dataclass

CellSource(layers: tuple[ndarray, ...])

Store explicit group/cell source values by axial layer.

Parameters:

Name Type Description Default
layers tuple[ndarray, ...]

Bottom-to-top tuple of group-major arrays shaped (groups, active_cells_in_layer) in n / cm^3 / s and slice-local active-ID order. The tuple must be nonempty, every array must be two-dimensional with one common nonzero group count, and arrays may be ragged in their active-cell dimension. Inputs are copied into read-only floating-point arrays.

required

Raises:

Type Description
TypeError

If a layer is not iterable or contains values other than real non-Boolean numbers.

ValueError

If no layer is supplied, a layer is not two-dimensional, no group is supplied, or layer group counts differ.

Notes

A cell source does not own a material mesh. Assembly requires exactly one supplied source layer per material-mesh layer and checks each column count against that selected layer’s active-cell count. It checks finiteness and nonnegativity then, not at construction. CellSource is immutable; construct a replacement source to change its layers.

values

values(
    axial_index: int,
    material_by_active_id: Mapping[int, str],
) -> np.ndarray

Return explicit read-only source values for one selected layer.

The selected array must have exactly one column for every compact active ID. Requesting an index outside this source’s layer tuple raises ValueError.

CrossSections dataclass

CrossSections(
    D: ndarray | list[float],
    sigma_a: ndarray | list[float],
    sigma_s: ndarray | list[list[float]],
    fission: FissionData | None,
    *,
    multiplicity_matrix: (
        ndarray | list[list[float]] | None
    ) = None
)

Store group-major macroscopic cross sections.

Parameters:

Name Type Description Default
D ndarray | list[float]

Nonempty one-dimensional diffusion-coefficient array in cm. Its length defines the number of energy groups.

required
sigma_a ndarray | list[float]

One-dimensional absorption macroscopic cross-section array in 1 / cm with the same length as D.

required
sigma_s ndarray | list[list[float]]

Complete P0 scattering-transfer matrix in 1 / cm with shape (groups, groups) and convention sigma_s[g_from, g_to].

required
multiplicity_matrix ndarray | list[list[float]] | None

Optional scattering-neutron emission multiplicity with shape (groups, groups) and the same incoming-to-outgoing convention as sigma_s. Values must be finite and nonnegative. None retains the compact unit-multiplicity representation: every scattering event emits one neutron.

None
fission FissionData | None

Optional checked fission-physics bundle. None is the sole representation for a nonfissile material. A supplied bundle must have the same group count as the other cross sections.

required

Attributes:

Name Type Description
groups int

Number of energy groups derived from the length of D.

Raises:

Type Description
TypeError

If a numerical field contains a non-real or Boolean value.

ValueError

If shapes are inconsistent, no groups are supplied, a numeric value is nonfinite or negative, or the supplied fission bundle has an inconsistent group count. FissionData and its selected neutron-production representation validate their own fission-specific inputs.

Notes

Public group ordering is fast-to-thermal. Inputs are converted to NumPy arrays immediately and copied so the container owns its numerical data. Stored numerical arrays are read-only. CrossSections is immutable after construction. Construct a replacement value when changing group data.

from_openmc_mgxs_hdf5 classmethod

from_openmc_mgxs_hdf5(
    path: str | Path,
    dataset: str,
    temperature: float,
    *,
    diffusion: str
) -> CrossSections

Import selected macroscopic data from an OpenMC runtime-MGXS file.

Parameters:

Name Type Description Default
path str | Path

OpenMC runtime-library HDF5 file emitted by openmc.MGXSLibrary.export_to_hdf5(...). Morana accepts filetype="mgxs" format version 1.0, reads it directly, and does not import OpenMC.

required
dataset str

Exact name of one direct-child macroscopic record in the runtime library. Nuclide-like records carrying atomic_weight_ratio are rejected.

required
temperature float

Exact stored physical temperature in K, apart from a small floating-point representation tolerance.

required
diffusion str

Required diffusion convention. "total" uses the runtime record’s total vector directly in D = 1 / (3 total); OpenMC may have populated that field from either TotalXS or TransportXS. "p1-outscatter" requires an uncorrected TotalXS in total and derives D_g = 1 / (3 (Sigma_t,g - sum_h Sigma_s1,g->h)).

required

Returns:

Type Description
CrossSections

Immutable selected material data. The imported value retains no source-file, energy-grid, or selection provenance.

Raises:

Type Description
TypeError

If path, dataset, temperature, or diffusion has an unsupported type.

ValueError

If the file is unreadable or is not a supported runtime-MGXS library; the material or temperature selection is invalid; the diffusion convention is unsupported; or required record data are missing, inconsistent, or outside their accepted ranges.

Notes

The conversion supports nonfissionable records and fissionable records with either separable vector nu-fission plus chi or general transfer matrix nu-fission production data. It requires finite nonnegative P0 scalar-flux isotropic scattering, and finite signed higher Legendre moments, in the runtime writer’s [G][G'][Order] layout and expands its compact bands to Morana’s complete incoming-to-outgoing sigma_s[g_from, g_to] matrix. A separate valid multiplicity_matrix is retained; its absence uses the compact unit-multiplicity representation. A present valid kappa-fission vector is retained as FissionData.kappa_sigma_f in eV / cm.

The importer warns when discarding higher scattering moments, known optional data outside Morana’s steady diffusion scope, or unrecognized selected-temperature fields. See the OpenMC MGXS import guide for the data, unit, warning, and rejection contracts.

The runtime format does not identify whether total came from OpenMC TotalXS or TransportXS. Selecting "p1-outscatter" for a TransportXS value would apply a second transport correction; the caller must avoid this invalid combination because Morana cannot detect it from the file.

DirectLinearSolveSettings dataclass

DirectLinearSolveSettings(
    relative_residual_tolerance: float = 1e-10,
)

Configure the sparse-direct reference linear-solve path.

Parameters:

Name Type Description Default
relative_residual_tolerance float

Finite positive real bound applied to Morana’s independently calculated true relative residual after SciPy returns a candidate solution. Boolean values are not accepted.

1e-10

Raises:

Type Description
TypeError

If relative_residual_tolerance is not a real number or is Boolean.

ValueError

If relative_residual_tolerance is not finite and positive after conversion to float.

strategy property

strategy: str

Return the stable linear-solve strategy identifier "direct".

DomainFace dataclass

DomainFace(*args: object, **kwargs: object)

Store a discretization-neutral active-cell face description.

Instances are returned by MaterialMesh.face. Direct construction is not supported.

Attributes:

Name Type Description
axial_index, active_id, openmc_index

Axial, slice-local, and geometric identity of the owning active cell.

direction, kind

Canonical face direction and its internal, outer, or excluded-interface topology classification.

neighbor_axial_index, neighbor_active_id, neighbor_openmc_index

In-stack axial, slice-local, and geometric identity of an internal or excluded-interface neighbor.

neighbor_key, neighbor_key_kind

Excluded-region identity available only for an excluded interface.

Notes

A domain face describes topology only. Boundary physics, face geometry, and finite-volume conductance are resolved separately by their owning layers. MaterialMesh.face() constructs topology-consistent values. For an "internal" face, every neighbor-identity field is present and both excluded-region fields are None. For a "to_excluded" face, the neighbor axial and OpenMC indices and both excluded-region fields are present, while neighbor_active_id is None. For an "outer" face, every neighbor field is None.

DomainFace is an immutable value record. It carries a snapshot of one topology query and has no live reference to a MaterialMesh.

Reject direct construction; obtain faces from MaterialMesh.

ExcludedRegion dataclass

ExcludedRegion(kind: str, color: str | None = None)

Describe a non-solved material-mesh region.

Parameters:

Name Type Description Default
kind str

Human-readable public region-kind identifier used by boundary selectors and provenance. It must contain a non-whitespace character and only printable characters. Its spelling is preserved, it is not restricted to a closed vocabulary, and kind-based selection uses exact equality.

required
color str | None

Optional nonempty plotting-color string. Its syntax is not validated at construction. A custom region without a color resolves to "#d9d9d9" for material-layout plots.

None

Raises:

Type Description
ValueError

If kind is empty, whitespace-only, or contains a non-printable character.

TypeError

If kind is not a string, or color is neither a string nor None.

Notes

ExcludedRegion is an immutable region description, not an excluded-position identity. Register it as a value in MaterialMesh.stack’s excluded_regions mapping; that mapping’s string key is the excluded-region identity. Select one such identity with on_excluded(key=...) or every identity sharing this kind with on_excluded(kind=...).

Excluded regions live in MaterialMesh layouts but are not active materials. They receive no unknown, source, cross sections, or neutron balance contribution. The built-in key "0" is always the reserved "inactive" region with plotting color "white"; it cannot be redefined.

FissionData dataclass

FissionData(
    neutron_production: SeparableFission | FissionTransfer,
    *,
    kappa_sigma_f: ndarray | list[float] | None = None
)

Bundle fission physics for one multigroup material.

Parameters:

Name Type Description Default
neutron_production SeparableFission | FissionTransfer

Exactly one checked neutron-production representation: SeparableFission or FissionTransfer.

required
kappa_sigma_f ndarray | list[float] | None

Optional incident-group recoverable fission-energy production cross section in eV / cm. When supplied, it must be finite, nonnegative, and match the neutron-production group count.

None

Attributes:

Name Type Description
groups int

Number of energy groups.

fission_transfer ndarray

Canonical read-only event-oriented transfer array with indexing [g_from, g_to].

fission_production ndarray

Canonical read-only total neutron production by incident group.

Notes

FissionData retains the caller-selected neutron-production value. Use SeparableFission when a common outgoing spectrum is appropriate; use FissionTransfer for general incident-to-outgoing group production. The derived fission_transfer and fission_production properties give both forms one common operator-facing representation.

fission_production property

fission_production: ndarray

Return the selected canonical incident-group production array.

fission_transfer property

fission_transfer: ndarray

Return the selected canonical event-oriented transfer array.

FissionSourceNormalization dataclass

FissionSourceNormalization(rate: float)

Scale a converged eigenfunction to a target fission-source rate.

Parameters:

Name Type Description Default
rate float

Finite positive total fission-neutron source rate in n / s. The target scales the returned flux and balance terms but does not alter the returned k_eff. Boolean values are not accepted.

required

Raises:

Type Description
TypeError

If rate is not a real number or is Boolean.

ValueError

If rate is not finite and positive after conversion to float.

Notes

Use PowerNormalization when recoverable fission-energy production cross sections are available and a thermal-power target is required.

FissionTransfer dataclass

FissionTransfer(
    fission_transfer: ndarray | list[list[float]],
)

Store general fission-neutron transfer data.

Parameters:

Name Type Description Default
fission_transfer ndarray | list[list[float]]

Square fission-neutron transfer array in 1 / cm with event-oriented indexing fission_transfer[g_from, g_to]. It must be finite, nonnegative, and have nonzero total neutron production.

required

Attributes:

Name Type Description
groups int

Number of energy groups.

fission_production ndarray

Read-only derived total neutron production by incident group.

FixedSourceBalance dataclass

FixedSourceBalance(*args: object, **kwargs: object)

Store one immutable fixed-source neutron-balance record.

Instances are retained by solver-produced results or restored from checked result archives. Direct construction is not supported.

Attributes:

Name Type Description
by_group Mapping[str, ndarray]

Finite group-resolved vectors in n / s for every fixed-source balance term: source, boundary_source, scattering_coupling, fission_production, fission_emission, removal, absorption, radial_leakage, axial_leakage, net_scattering, and residual.

by_layer_group Mapping[str, tuple[ndarray, ...]]

Bottom-to-top finite group-resolved vectors in n / s for the same terms. Each layer tuple contracts to its corresponding by_group vector.

Reject direct construction; balances belong to completed results.

loss_fractions property

loss_fractions: Mapping[str, float] | None

Return loss fractions, or None when total loss is zero.

scalar property

scalar: Mapping[str, float]

Return immutable scalar totals contracted from group vectors.

source_normalized property

source_normalized: Mapping[str, float] | None

Return source-normalized terms, or None when source is zero.

items

items()

Return immutable scalar balance term pairs.

keys

keys()

Return immutable scalar balance term names.

FixedSourceSettings dataclass

FixedSourceSettings(
    linear_solve: LinearSolveSettings = DirectLinearSolveSettings(),
    flux_nonnegativity_tolerance: float = 1e-12,
)

Configure one fixed-source solve.

Parameters:

Name Type Description Default
linear_solve LinearSolveSettings

Immutable per-call direct or GMRES policy. Direct solving is the default reference path.

DirectLinearSolveSettings()
flux_nonnegativity_tolerance float

Finite nonnegative real relative tolerance for accepting and cleaning negative roundoff in the solved scalar-flux vector. The threshold is this value times the candidate vector’s largest absolute component. Zero rejects every negative candidate; Boolean values are not accepted.

1e-12

Raises:

Type Description
TypeError

If linear_solve is not a supported linear-solve policy, or if flux_nonnegativity_tolerance is not a real number or is Boolean.

ValueError

If flux_nonnegativity_tolerance is not finite and nonnegative after conversion to float.

GmresLinearSolveSettings dataclass

GmresLinearSolveSettings(
    relative_residual_tolerance: float = 1e-10,
    max_krylov_iterations: int = 1000,
    restart: int = 50,
    preconditioner: LinearPreconditioner = NoPreconditioner(),
)

Configure restarted GMRES and its one typed preconditioner.

Parameters:

Name Type Description Default
relative_residual_tolerance float

Finite positive real bound supplied to GMRES and applied again to Morana’s independently calculated true relative residual. Boolean values are not accepted.

1e-10
max_krylov_iterations int

Positive non-Boolean integer maximum number of Krylov iterations across all restarts.

1000
restart int

Positive non-Boolean integer number of Krylov vectors retained in one GMRES cycle. It may not exceed max_krylov_iterations.

50
preconditioner LinearPreconditioner

One immutable no, Jacobi, or threshold-ILU preconditioner policy.

NoPreconditioner()

Raises:

Type Description
TypeError

If a numerical control has an unsupported type or is Boolean, or if preconditioner is not a supported preconditioner policy.

ValueError

If a numerical control is out of range, cannot be represented as a finite float, or restart exceeds max_krylov_iterations.

strategy property

strategy: str

Return the stable linear-solve strategy identifier "gmres".

HexPlanarMesh dataclass

HexPlanarMesh(num_rings: int, pitch: float)

Represent a regular 2D hexagonal mesh.

Parameters:

Name Type Description Default
num_rings int

Positive integer OpenMC-style ring count. 1 is center-only, 2 has 7 cells, and 3 has 19 cells. A mesh with n rings has 1 + 3 * n * (n - 1) full-lattice cells.

required
pitch float

Finite positive flat-to-flat hexagon pitch in cm.

required

Attributes:

Name Type Description
n_cells int

Number of positions in the complete regular lattice.

coords tuple[tuple[int, int], ...]

Integer (x, u) lattice coordinates in planar-ID order.

openmc_indices tuple[OpenMCIndex, ...]

OpenMCIndex values in the same planar-ID order.

direction_labels tuple[str, ...]

Radial neighbor directions in the fixed order ("x+", "x-", "u+", "u-", "v+", "v-").

area, face_length, center_distance, center_to_face

Per-cell planar area in cm^2 and geometric lengths in cm derived from pitch.

index_of Mapping[tuple[int, int], int]

Newly constructed mapping from a lattice coordinate to its planar ID.

Raises:

Type Description
TypeError

If num_rings is not an integer or is a boolean, or if pitch is not a real non-Boolean number.

ValueError

If num_rings is less than one, or pitch is not finite and positive.

Notes

The mesh is a full regular lattice. OpenMC-style ring indices and integer lattice coordinates are constructed internally from num_rings using the locked OpenMC orientation="x" ring-order convention. The coordinate basis is aligned with Morana’s x and u face directions: x+ points right and u+ points upper-right.

Planar IDs enumerate rings outermost to innermost; positions within a ring start at x+ and proceed clockwise. planar_id_at() is the safe reverse lookup and returns None for an index outside this mesh. neighbors() returns full-lattice planar IDs in direction_labels order and uses None for a physical lattice perimeter. The mesh has no material, active-domain, or axial information; MaterialMesh supplies those layers of the problem definition.

area property

area: float

Return the area of a regular 2D hex cell in cm^2.

center_distance property

center_distance: float

Return the center-to-center distance across a face in cm.

center_to_face property

center_to_face: float

Return the perpendicular center-to-face distance in cm.

coords property

coords: tuple[tuple[int, int], ...]

Return lattice (x, u) coordinates in outer-to-inner ID order.

direction_labels property

direction_labels: tuple[str, ...]

Return the mesh-owned face-direction labels in neighbor order.

face_length property

face_length: float

Return the length of one hex face in cm.

index_of property

index_of: Mapping[tuple[int, int], int]

Return the immutable mapping from lattice coordinate to planar ID.

n_cells property

n_cells: int

Return the number of positions in the complete regular lattice.

openmc_indices property

openmc_indices: tuple[OpenMCIndex, ...]

Return orientation-x OpenMC ring indices in planar-ID order.

cartesian_center

cartesian_center(planar_id: int) -> tuple[float, float]

Return a center using the (x, u) Cartesian transform.

Raises:

Type Description
TypeError

If planar_id is not an integer or is a boolean.

IndexError

If planar_id is outside the complete lattice.

cell_vertices

cell_vertices(
    planar_id: int,
) -> tuple[tuple[float, float], ...]

Return Cartesian vertices for one hexagonal cell.

Vertices are ordered counter-clockwise.

Raises:

Type Description
TypeError

If planar_id is not an integer or is a boolean.

IndexError

If planar_id is outside the complete lattice.

export_vtu

export_vtu(path: str | Path) -> None

Export the full lattice as a VTK XML unstructured grid.

Each cell is one planar VTK polygon. Cell data comprises planar_id, lattice_x, lattice_u, openmc_ring, and openmc_position in planar-ID order. The mesh pitch is encoded in geometry. Parent directories are created when needed; an existing file at path is replaced.

Raises:

Type Description
ValueError

If path does not have a .vtu suffix.

IsADirectoryError

If path identifies an existing directory.

OSError

If the parent directory cannot be created or the VTU file cannot be written.

lattice_coord

lattice_coord(planar_id: int) -> tuple[int, int]

Return the (x, u) lattice coordinate for a planar ID.

Raises:

Type Description
TypeError

If planar_id is not an integer or is a boolean.

IndexError

If planar_id is outside the complete lattice.

neighbors

neighbors(planar_id: int) -> tuple[int | None, ...]

Return neighbors in direction_labels order, using None outside.

Raises:

Type Description
TypeError

If planar_id is not an integer or is a boolean.

IndexError

If planar_id is outside the complete lattice.

openmc_index

openmc_index(planar_id: int) -> OpenMCIndex

Return the orientation-x OpenMC ring index for a planar ID.

Raises:

Type Description
TypeError

If planar_id is not an integer or is a boolean.

IndexError

If planar_id is outside the complete lattice.

planar_id_at

planar_id_at(openmc_index: OpenMCIndex) -> int | None

Return the planar ID at an OpenMC index, or None if absent.

Raises:

Type Description
TypeError

If openmc_index is not an OpenMCIndex.

plot_matplotlib

plot_matplotlib(ax: Axes | None = None) -> Axes

Plot the full lattice with planar, lattice, and OpenMC labels.

Parameters:

Name Type Description Default
ax Axes | None

Optional axes to populate. A new figure and axes are created when omitted.

None

Returns:

Type Description
Axes

The populated axes. Each cell label lists planar ID, (x, u), and ring/position on separate lines.

Raises:

Type Description
TypeError

If ax is neither an Axes nor None.

to_plotly

to_plotly() -> Figure

Return a Plotly full-lattice figure with per-cell inspection labels.

The visible cell label lists planar ID, (x, u), and ring/position. Hover text also gives the Cartesian center in cm.

IluPreconditioner dataclass

IluPreconditioner(
    drop_tolerance: float = 0.0001,
    fill_factor: float = 10.0,
)

Select threshold incomplete-LU preconditioning for GMRES.

Parameters:

Name Type Description Default
drop_tolerance float

Finite nonnegative real threshold used to drop incomplete-factor entries. Boolean values are not accepted.

0.0001
fill_factor float

Finite positive real upper bound on incomplete-factor fill relative to the original sparse matrix. Boolean values are not accepted.

10.0

Raises:

Type Description
TypeError

If either control is not a real number or is Boolean.

ValueError

If either control is not finite after conversion to float, or if drop_tolerance is negative or fill_factor is nonpositive.

kind property

kind: str

Return the stable preconditioner identifier "ilu".

JacobiPreconditioner dataclass

JacobiPreconditioner()

Select diagonal (Jacobi) preconditioning for GMRES.

kind property

kind: str

Return the stable preconditioner identifier "jacobi".

KeffBalance dataclass

KeffBalance(*args: object, **kwargs: object)

Store one immutable criticality neutron-balance record.

Instances are retained by solver-produced criticality results or restored from checked result archives. Direct construction is not supported.

Attributes:

Name Type Description
by_group Mapping[str, ndarray]

Finite group-resolved vectors in n / s for every criticality balance term: fission_production, keff_source, scattering_coupling, removal, absorption, radial_leakage, axial_leakage, net_scattering, and residual.

by_layer_group Mapping[str, tuple[ndarray, ...]]

Bottom-to-top finite group-resolved vectors in n / s for the same terms. Each layer tuple contracts to its corresponding by_group vector.

Reject direct construction; balances belong to completed results.

loss_fractions property

loss_fractions: Mapping[str, float]

Return immutable fractions of the positive total loss.

scalar property

scalar: Mapping[str, float]

Return immutable scalar totals contracted from group vectors.

source_normalized property

source_normalized: Mapping[str, float]

Return immutable terms normalized by the positive fission source.

items

items()

Return immutable scalar balance term pairs.

keys

keys()

Return immutable scalar balance term names.

KeffOuterIterationReport dataclass

KeffOuterIterationReport(*args: object, **kwargs: object)

Describe one completed finite-volume criticality outer iteration.

Instances are retained by solver-produced criticality results or restored from checked result archives. Direct construction is not supported.

Attributes:

Name Type Description
iteration int

Positive one-based power-iteration index.

linear_solve LinearSolveReport

Completed loss-system solve nested in this outer iteration.

keff float

Finite positive multiplication-factor estimate.

keff_change float

Finite nonnegative relative multiplication-factor change.

flux_change float

Finite nonnegative volume-weighted normalized-flux change.

keff_relative_residual float

Finite nonnegative relative eigenvalue-equation residual.

Reject direct construction; reports belong to completed results.

KeffSettings dataclass

KeffSettings(
    inner_linear_solve: LinearSolveSettings = DirectLinearSolveSettings(),
    max_outer_iterations: int = 100,
    keff_change_tolerance: float = 1e-10,
    flux_change_tolerance: float = 1e-10,
    keff_relative_residual_tolerance: float = 1e-10,
    flux_nonnegativity_tolerance: float = 1e-12,
    eigenvalue_iteration: EigenvalueIterationSettings = PowerIterationSettings(),
)

Configure one source-normalized fission eigenvalue solve.

Parameters:

Name Type Description Default
inner_linear_solve LinearSolveSettings

Immutable direct or GMRES policy applied separately to each outer iteration. Direct solving is the default reference path.

DirectLinearSolveSettings()
max_outer_iterations int

Positive non-Boolean integer maximum power-iteration count.

100
keff_change_tolerance float

Finite positive real relative multiplication-factor change tolerance. Boolean values are not accepted.

1e-10
flux_change_tolerance float

Finite positive real volume-weighted normalized-flux change tolerance. Boolean values are not accepted.

1e-10
keff_relative_residual_tolerance float

Finite positive real relative eigenvalue-equation residual tolerance. Boolean values are not accepted.

1e-10
flux_nonnegativity_tolerance float

Finite nonnegative real relative tolerance for accepting and cleaning negative roundoff in a power-iteration flux vector. The threshold is this value times the candidate vector’s largest absolute component. Zero rejects every negative candidate; Boolean values are not accepted.

1e-12
eigenvalue_iteration EigenvalueIterationSettings

Immutable ordinary-power or fixed-Wielandt-shift policy. Ordinary power iteration is the default reference path.

PowerIterationSettings()

Raises:

Type Description
TypeError

If a policy input is unsupported, or if a numerical control has an unsupported type or is Boolean.

ValueError

If a numerical control is out of range or cannot be represented as a finite float.

KeffSolveReport dataclass

KeffSolveReport(*args: object, **kwargs: object)

Retain completed records for every criticality outer iteration.

Instances are retained by solver-produced criticality results or restored from checked result archives. Direct construction is not supported.

Attributes:

Name Type Description
outer_iterations tuple[KeffOuterIterationReport, ...]

Nonempty consecutive one-based outer-iteration records.

eigenvalue_iteration EigenvalueIterationSettings

Immutable ordinary-power or fixed-Wielandt-shift policy used for the recorded criticality solve.

iterations int

Number of completed criticality outer iterations.

final_outer_iteration KeffOuterIterationReport

Final completed outer-iteration record.

Reject direct construction; reports belong to completed results.

final_outer_iteration property

final_outer_iteration: KeffOuterIterationReport

Return the final completed criticality outer-iteration record.

iterations property

iterations: int

Return the number of completed criticality outer iterations.

LinearSolveReport dataclass

LinearSolveReport(*args: object, **kwargs: object)

Describe one completed finite-volume linear solve.

Instances are retained by solver-produced results or restored from checked result archives. Direct construction is not supported.

Attributes:

Name Type Description
linear_solve LinearSolveSettings

Immutable strategy and, for GMRES, preconditioner policy used by the completed solve.

iterations int

Nonnegative number of direct or Krylov iterations reported for this solve.

true_relative_residual float

Finite nonnegative true residual calculated by Morana from the final flux, operator, and right-hand side.

Reject direct construction; reports belong to completed results.

preconditioner property

preconditioner: LinearPreconditioner | None

Return the typed GMRES preconditioner, or None for direct solves.

strategy property

strategy: str

Return the stable strategy identifier used by this solve.

Material dataclass

Material(
    name: str,
    xs: CrossSections | None = None,
    color: str | None = None,
)

Represent a user-visible material identity.

Parameters:

Name Type Description Default
name str

Public material name used by material meshes and source definitions. The built-in excluded-region key "0" is reserved and cannot be a material name. A ProblemConfiguration also rejects a material name that collides with any custom excluded-region key in its material mesh; its materials mapping key must exactly equal this value.

required
xs CrossSections | None

Optional cross sections associated with this material. Cross sections may be omitted for layout-only or plotting use, but every active material requires them when a solver constructs its operators.

None
color str | None

Optional nonempty plotting-color string. Its syntax is passed through without validation. Material-layout plots use it when this material is supplied in their materials mapping; otherwise they use their active-material palette.

None

Raises:

Type Description
ValueError

If name is empty, whitespace-only, contains a non-printable character, or is the built-in excluded-region key "0".

TypeError

If name is not a string, xs is neither CrossSections nor None, or color is neither a string nor None.

Notes

Material is immutable. Construct and validate a replacement material before placing it in a ProblemConfiguration.

MaterialMesh

MaterialMesh(*args: object, **kwargs: object)

Store material keys for every lattice position.

Attributes:

Name Type Description
mesh HexPlanarMesh

Authoritative planar mesh shared by all layers.

layers tuple[Mapping[OpenMCIndex, str], ...]

Read-only completed material-key mappings in bottom-to-top order.

axial_layer_heights tuple[float, ...]

Immutable positive heights in bottom-to-top order.

excluded_regions Mapping[str, ExcludedRegion]

Read-only excluded-region catalog.

Notes

HexPlanarMesh owns only the full regular geometry. MaterialMesh overlays material keys on that geometry and defines the active solution domain. Unassigned positions default to the built-in inactive excluded key "0". Direct construction is rejected; use MaterialMesh.stack.

The public API is persistent: public properties expose read-only mappings and immutable height tuples, and supported assignment changes construct an independent material mesh rather than modifying this one. Treat the underscore-prefixed owned state as internal implementation detail.

Reject direct construction; completed meshes are stacked slices.

axial_layer_heights property

axial_layer_heights: tuple[float, ...]

Return the immutable positive layer heights in axial order.

excluded_regions property

excluded_regions: Mapping[str, ExcludedRegion]

Return the read-only excluded-region catalog.

face_direction_labels property

face_direction_labels: tuple[str, ...]

Return radial and axial face labels in canonical domain order.

layers property

layers: tuple[Mapping[OpenMCIndex, str], ...]

Return read-only complete material-key mappings in axial order.

mesh property

mesh: HexPlanarMesh

Return the authoritative planar mesh for the complete stack.

n_axial_layers property

n_axial_layers: int

Return the number of axial material layers.

z_max property

z_max: float

Return the physical upper coordinate of the complete slice stack.

z_min property

z_min: float

Return the physical lower coordinate of the complete slice stack.

active_id_at

active_id_at(
    axial_index: int, openmc_index: OpenMCIndex
) -> int | None

Return a slice-local active ID at a lattice position, or None.

axial_index selects the layer before openmc_index identifies its planar position.

None means that the position is excluded in the selected layer or is not a position of the complete planar mesh. Use key_at when those cases need to be distinguished.

Raises:

Type Description
TypeError

If axial_index is not an integer or openmc_index is not an OpenMCIndex.

IndexError

If axial_index is outside the material-slice stack.

active_indices

active_indices(axial_index: int) -> tuple[OpenMCIndex, ...]

Return active OpenMC positions in compact solver order.

The order is the selected subset of mesh.openmc_indices. It is the canonical order for slice-local active IDs and the active-cell axis of solver arrays for this layer.

axial_face_area

axial_face_area(axial_index: int) -> float

Return one axial top/bottom face area for an axial material layer.

cell_volume

cell_volume(axial_index: int) -> float

Return one hex-z cell volume for an axial material layer.

export_vtm

export_vtm(path: str | Path) -> None

Export active and excluded material cells as VTK multiblock data.

The .vtm file references one .vtu leaf dataset per domain group. ParaView can toggle those leaf datasets through the MultiBlock Inspector. The adjacent material_keys.json maps each exported material_key_id to its material key.

Raises:

Type Description
ValueError

If path does not have a .vtm suffix.

IsADirectoryError

If path identifies an existing directory.

OSError

If an output directory cannot be created or an output file cannot be written.

face

face(
    axial_index: int, active_id: int, direction: str
) -> DomainFace

Return the topology description for one active-cell face.

axial_index and active_id identify the cell in that order. The result is independent of discretization details. Solvers decide how to turn the face classification into matrix coefficients or response relations.

Raises:

Type Description
TypeError

If direction is not a string.

ValueError

If direction is empty or is not one of the radial or axial face-direction labels.

key_at

key_at(axial_index: int, openmc_index: OpenMCIndex) -> str

Return the completed material key at one axial-layer position.

Unassigned positions have the built-in inactive key "0". A position outside the full planar mesh raises KeyError.

Raises:

Type Description
TypeError

If axial_index is not an integer or openmc_index is not an OpenMCIndex.

IndexError

If axial_index is outside the material-slice stack.

layer_height

layer_height(axial_index: int) -> float

Return the height of one axial material layer in cm.

material_by_active_id

material_by_active_id(
    axial_index: int,
) -> Mapping[int, str]

Return a read-only material mapping keyed by slice-local active ID.

The mapping insertion order matches active_indices(axial_index) and therefore the selected layer’s compact solver order. The returned mapping is a stable view of state derived when the material mesh is constructed; copy it with dict(...) if mutation is required.

material_colors

material_colors(
    materials: Mapping[str, Material] | None = None,
) -> dict[str, str]

Return resolved plotting colors for every key in the layout.

Excluded-region colors take precedence and use the region’s configured color or its default. For active keys, a supplied Material.color takes precedence over the repeating default palette. Active palette entries are assigned in first-use order while scanning layers bottom to top and positions in planar order.

Raises:

Type Description
TypeError

If materials is not a mapping of string keys to Material values.

ValueError

If a material-mapping key is empty or differs from its Material.name.

n_active_cells

n_active_cells(axial_index: int) -> int

Return the number of active solver cells in one axial layer.

openmc_index_for_active_id

openmc_index_for_active_id(
    axial_index: int, active_id: int
) -> OpenMCIndex

Return the lattice position for a slice-local active ID.

axial_index selects the layer before active_id identifies a cell in its compact order. The ID must be a nonnegative integer in the selected layer. Another input type raises TypeError; a negative or out-of-range integer raises ValueError.

plot_matplotlib

plot_matplotlib(
    axial_index: int,
    materials: Mapping[str, Material] | None = None,
    ax: Axes | None = None,
) -> Axes

Plot one axial material slice with resolved material-key colors.

materials optionally supplies Material definitions by active key; its explicit colors are resolved by material_colors. When ax is omitted, the method creates and returns a new Matplotlib axes.

Raises:

Type Description
TypeError

If materials is not a mapping of string keys to Material values, or ax is neither an Axes nor None.

ValueError

If a material-mapping key is empty or differs from its Material.name.

radial_face_area

radial_face_area(axial_index: int) -> float

Return one radial face area for an axial material layer.

stack classmethod

stack(
    slices: tuple[MaterialSlice, ...],
    *,
    excluded_regions: (
        Mapping[str, ExcludedRegion] | None
    ) = None
) -> "MaterialMesh"

Complete a bottom-to-top stack of reusable material slices.

Parameters:

Name Type Description Default
slices tuple[MaterialSlice, ...]

Nonempty tuple of MaterialSlice values in bottom-to-top order. Every slice must reference the identical HexPlanarMesh instance. Each sparse mapping is completed independently: positions absent from a slice receive the built-in inactive key "0".

required
excluded_regions Mapping[str, ExcludedRegion] | None

Optional mapping from keys to ExcludedRegion descriptions for additional inactive regions. Keys must be nonempty strings. The built-in key "0" always denotes the "inactive" kind and may not be redefined. A key present in this catalog is excluded from the active solver domain in every layer where it occurs.

None

Returns:

Type Description
MaterialMesh

An independent completed layout with read-only layer mappings and excluded-region catalog.

Raises:

Type Description
TypeError

If slices contains a value other than MaterialSlice, excluded_regions is not a mapping, or an excluded-region key is not a string.

ValueError

If slices is not a nonempty tuple, slices use different mesh instances, or the excluded-region mapping is invalid.

to_plotly

to_plotly(
    axial_index: int,
    materials: Mapping[str, Material] | None = None,
) -> Figure

Return a Plotly figure for one axial material slice.

materials optionally supplies Material definitions by active key. Color resolution follows material_colors.

Raises:

Type Description
TypeError

If materials is not a mapping of string keys to Material values.

ValueError

If a material-mapping key is empty or differs from its Material.name.

z_bounds

z_bounds(axial_index: int) -> tuple[float, float]

Return cumulative lower and upper coordinates for one layer.

MaterialSlice dataclass

MaterialSlice(
    mesh: HexPlanarMesh,
    material_keys: Mapping[OpenMCIndex, str],
    height: float,
)

Immutable height-bearing planar material-layout input.

Parameters:

Name Type Description Default
mesh HexPlanarMesh

Authoritative HexPlanarMesh for this slice.

required
material_keys Mapping[OpenMCIndex, str]

Sparse mapping from OpenMC positions to active or excluded keys. Keys must be OpenMCIndex values belonging to mesh; values must be human-readable identifiers: they must contain a non-whitespace character and only printable characters. The mapping is copied to a read-only mapping. Unspecified positions become the built-in inactive key when stacked.

required
height float

Finite positive axial height in cm.

required

Raises:

Type Description
TypeError

If mesh is not a HexPlanarMesh, material_keys is not a mapping, a mapping key is not an OpenMCIndex, or a material key is not a string, or height is not a real non-Boolean number.

ValueError

If height is not finite and positive, a material key is empty, whitespace-only, or non-printable, or a mapping key is outside mesh.

Notes

A slice is reusable construction data. It deliberately does not own the excluded-region catalog or compact active-cell IDs; MaterialMesh.stack applies those domain-level decisions to a bottom-to-top slice stack. Thus, a key is not classified as active or excluded until stacking, when the material mesh receives its excluded-region catalog.

extrude

extrude(
    *,
    count: int | None = None,
    heights: tuple[float, ...] | None = None
) -> tuple["MaterialSlice", ...]

Return a composable uniform or explicitly height-bearing fragment.

Parameters:

Name Type Description Default
count int | None

Positive integer number of copies retaining this slice’s height. Provide this argument or heights, but not both.

None
heights tuple[float, ...] | None

Nonempty tuple of finite positive heights in cm. Provide this argument or count, but not both.

None

Returns:

Type Description
tuple[MaterialSlice, ...]

A bottom-to-top fragment suitable for concatenation and passing to MaterialMesh.stack. Uniform extrusion repeats this immutable slice value; explicit heights create one independent slice per requested height with the same mesh and material keys.

Raises:

Type Description
TypeError

If count is not an integer or is a boolean.

ValueError

If neither or both forms are supplied, count is nonpositive, heights is not a nonempty tuple, or an explicit height is invalid.

from_openmc_rings classmethod

from_openmc_rings(
    mesh: HexPlanarMesh,
    rings: list[list[str]],
    *,
    height: float
) -> "MaterialSlice"

Build one reusable complete slice from OpenMC-style ring data.

Parameters:

Name Type Description Default
mesh HexPlanarMesh

Authoritative HexPlanarMesh for the returned slice.

required
rings list[list[str]]

List of lists of human-readable material keys for every mesh ring, ordered outermost to innermost. Ring i must contain max(6 * (mesh.num_rings - 1 - i), 1) values. Positions within each ring follow the mesh’s OpenMC orientation="x" order. Unlike direct construction, this form assigns every planar position explicitly.

required
height float

Finite positive slice height in cm.

required

Returns:

Type Description
MaterialSlice

An immutable slice with a complete material-key mapping.

Raises:

Type Description
TypeError

If mesh is not a HexPlanarMesh, rings is not a list of lists, or a ring value is not a string.

ValueError

If the number of rings or a ring length does not match mesh, a ring value is empty, whitespace-only, or non-printable, or the resulting slice has an invalid height.

Notes

Ring values are human-readable identifiers. Their active or excluded classification remains a MaterialMesh.stack decision.

MaterialSource dataclass

MaterialSource(
    values_by_material: Mapping[str, ndarray | list[float]],
)

Assign volumetric source vectors by material name.

Parameters:

Name Type Description Default
values_by_material Mapping[str, ndarray | list[float]]

Nonempty mapping from nonempty material names to common-length nonempty group-major vectors in n / cm^3 / s. Values are copied into read-only floating-point arrays.

required

Raises:

Type Description
TypeError

If values_by_material is not a mapping or a material name is not a string, or a source vector contains values other than real non-Boolean numbers.

ValueError

If a material name is empty, the mapping is empty, a vector is empty or not one-dimensional, or vectors do not have one common group count.

Notes

Every material in a selected active layer must have an entry; evaluation otherwise raises ValueError naming the missing material. The mapping may contain unused entries. Finiteness, nonnegativity, and compatibility with the problem group count are checked during source assembly rather than construction. The stored vectors and mapping are immutable; construct a replacement source to change material-wise values.

values

values(
    axial_index: int,
    material_by_active_id: Mapping[int, str],
) -> np.ndarray

Return material-wise source values in compact active-ID order.

The returned array is read-only with one column for each selected active ID. An empty layer produces a read-only (groups, 0) array.

NoPreconditioner dataclass

NoPreconditioner()

Select unpreconditioned GMRES execution.

kind property

kind: str

Return the stable preconditioner identifier "none".

OpenMCIndex dataclass

OpenMCIndex(ring: int, position: int)

Identify one serialized position in an OpenMC-style hexagonal ring.

Parameters:

Name Type Description Default
ring int

Zero-based serialized ring index. For a HexPlanarMesh, zero is the outermost ring and increasing values move inward.

required
position int

Zero-based position within ring. Positions start at the positive x direction and proceed clockwise in Morana’s supported OpenMC orientation="x" convention.

required

Raises:

Type Description
TypeError

If ring or position is not an integer or is a boolean.

ValueError

If ring or position is negative.

Notes

This is an immutable, hashable value object. Its dataclass ordering is lexicographic by (ring, position), which matches a mesh’s outer-to- inner serialized ring order but is not the same as spatial ordering around the lattice.

OpenMCIndex validates that both fields are nonnegative integers, but membership remains mesh-relative. For a mesh with n rings, a valid ring is 0 <= ring < n and its valid positions are 0 <= position < max(6 * (n - 1 - ring), 1). HexPlanarMesh creates its complete valid sequence as openmc_indices; HexPlanarMesh.planar_id_at() returns None for an index outside that sequence, and MaterialSlice rejects such indices as sparse keys.

The type records a ring-position identity only. It does not require OpenMC at runtime and does not identify a compact material-mesh active_id; use the latter only with an explicit axial layer.

PowerIterationSettings dataclass

PowerIterationSettings()

Select ordinary fission-source-normalized power iteration.

kind property

kind: str

Return the stable eigenvalue-iteration identifier "power".

PowerNormalization dataclass

PowerNormalization(power: float)

Scale a converged eigenfunction to a target recoverable thermal power.

Parameters:

Name Type Description Default
power float

Finite positive target recoverable thermal power in W (J / s). Every fissionable material in the active domain must provide CrossSections.fission.kappa_sigma_f for this normalization to be usable. Boolean values are not accepted.

required

Raises:

Type Description
TypeError

If power is not a real number or is Boolean.

ValueError

If power is not finite and positive after conversion to float.

Notes

The target scales the returned flux and neutron-balance terms but does not alter the returned k_eff. kappa_sigma_f directly represents recoverable fission-energy production, avoiding an implied or fixed value for neutrons emitted per fission.

ProblemConfiguration dataclass

ProblemConfiguration(
    mesh: HexPlanarMesh,
    materials: Mapping[str, Material],
    material_mesh: MaterialMesh,
    *,
    boundary: BoundaryConditionSet | None = None,
    source: (
        UniformSource | MaterialSource | CellSource | None
    ) = None,
    name: str | None = None
)

In-memory representation of a neutronics problem definition.

Parameters:

Name Type Description Default
mesh HexPlanarMesh

Hexagonal mesh topology and geometry.

required
materials Mapping[str, Material]

Mapping from public material name to material object. Every mapping key must match its Material.name.

required
material_mesh MaterialMesh

Material-key layout over the full lattice. This defines the active solution domain and must use mesh. Every active key must identify an entry in materials; material names cannot collide with excluded-region keys.

required
boundary BoundaryConditionSet | None

Boundary-condition assignments for exposed mesh faces. The default is empty; a solve requires complete boundary coverage.

None
source UniformSource | MaterialSource | CellSource | None

Optional volumetric fixed-source object. A fixed-source solve may use this source, an inhomogeneous boundary contribution, or both; eigenvalue solves reject an external source.

None
name str | None

Optional nonempty configuration name for provenance and serialization.

None

Raises:

Type Description
TypeError

If an input does not have its documented type.

ValueError

If checked values are incompatible, a name is invalid, or a material layout refers to an unknown material.

Notes

Public state is read-only. Use set_materials(), replace_material(), set_material_mesh(), set_boundary(), add_boundary(), assign_material(), set_source(), and set_name() to change an existing configuration.

Check and own one mutable problem definition.

boundary property

boundary: BoundaryConditionSet

Return the immutable boundary-assignment set.

material_mesh property

material_mesh: MaterialMesh

Return the immutable material layout for this configuration.

materials property

materials: Mapping[str, Material]

Return the read-only name-to-immutable-material mapping.

mesh property

mesh: HexPlanarMesh

Return the immutable planar geometry for this configuration.

name property

name: str | None

Return the optional configuration provenance name.

source property

source: UniformSource | MaterialSource | CellSource | None

Return the optional fixed-source definition.

unused_material_names property

unused_material_names: frozenset[str]

Return configured material names absent from every active mesh cell.

The returned set is derived from all axial layers of material_mesh. Excluded positions do not use material definitions.

add_boundary

add_boundary(assignment: BoundaryAssignment) -> None

Add one boundary assignment.

Parameters:

Name Type Description Default
assignment BoundaryAssignment

Assignment appended through BoundaryConditionSet.with_assignment. Its selector is checked for duplicate identity and its condition is retained by the resulting immutable boundary set.

required

Raises:

Type Description
TypeError

If assignment is not a BoundaryAssignment.

ValueError

If its selector duplicates an existing assignment.

assign_material

assign_material(
    axial_index: int,
    openmc_index: OpenMCIndex,
    material: str,
) -> None

Assign a known material to one axial-layer lattice position.

Parameters:

Name Type Description Default
axial_index int

Bottom-to-top axial-layer index.

required
openmc_index OpenMCIndex

Public OpenMC-style position in the shared planar mesh.

required
material str

Public name of a material in materials.

required

Raises:

Type Description
TypeError

If axial_index is not an integer, openmc_index is not an OpenMCIndex, or material is not a string.

ValueError

If material is invalid or unknown, or either location index is invalid.

Notes

The replacement updates only the specified layer. The previous immutable material mesh remains unchanged.

check_boundary_coverage

check_boundary_coverage() -> None

Require conditions for every exposed face of the configured layout.

Raises:

Type Description
ValueError

If one or more physical-exterior or excluded-region faces are uncovered.

check_no_unused_materials

check_no_unused_materials() -> None

Require every configured material to occur in an active mesh cell.

Raises:

Type Description
ValueError

If one or more configured material names are absent from every active cell in every axial layer.

replace_material

replace_material(material: Material) -> None

Replace one existing material definition.

Parameters:

Name Type Description Default
material Material

Replacement immutable material. Its name must already identify a material in this configuration.

required

Raises:

Type Description
TypeError

If material is not a Material.

ValueError

If its name is not present.

set_boundary

set_boundary(boundary: BoundaryConditionSet) -> None

Replace all boundary assignments.

Parameters:

Name Type Description Default
boundary BoundaryConditionSet

Complete replacement boundary-condition set.

required

Raises:

Type Description
TypeError

If boundary is not a BoundaryConditionSet.

set_material_mesh

set_material_mesh(material_mesh: MaterialMesh) -> None

Replace the full material layout.

Parameters:

Name Type Description Default
material_mesh MaterialMesh

Completed immutable material layout over this configuration’s planar mesh. Every active material key must identify a configured material.

required

Raises:

Type Description
TypeError

If material_mesh is not a MaterialMesh.

ValueError

If it uses different geometry or assigns an unknown material.

set_materials

set_materials(materials: Mapping[str, Material]) -> None

Replace all material definitions.

Parameters:

Name Type Description Default
materials Mapping[str, Material]

Complete name-to-material replacement mapping. Every key must match its immutable Material.name, every active layout key must remain present, and no name may collide with an excluded key.

required

Raises:

Type Description
TypeError

If materials is not a mapping, a key is not a string, or a value is not a Material.

ValueError

If a name is invalid, a key does not match Material.name, a name collides with an excluded key, or an active layout key is absent from the replacement mapping.

set_name

set_name(name: str | None) -> None

Replace the provenance name.

Raises:

Type Description
TypeError

If name is neither a string nor None.

ValueError

If name is empty.

set_source

set_source(
    source: (
        UniformSource | MaterialSource | CellSource | None
    ),
) -> None

Set or clear the fixed-source definition.

Parameters:

Name Type Description Default
source UniformSource | MaterialSource | CellSource | None

Volumetric fixed-source definition, or None to clear it. Fixed-source solves may instead be driven by inhomogeneous boundary data; eigenvalue solves reject an external source.

required

Raises:

Type Description
TypeError

If source is not a built-in source or None.

snapshot

snapshot() -> 'ProblemConfigurationSnapshot'

Return an immutable, non-aliasing problem-definition snapshot.

Returns:

Type Description
ProblemConfigurationSnapshot

Non-aliasing snapshot of geometry, material layout, material and excluded-region definitions, boundary assignments, source, and name. Its public values are freshly reconstructed, not live references to this mutable configuration. It can be passed to a supported solve function or retained as result provenance.

ProblemConfigurationSnapshot dataclass

ProblemConfigurationSnapshot()

Immutable, non-aliasing problem definition and result provenance.

The snapshot privately owns geometry, material-layout, definition, boundary, source, and provenance records. Its public properties restore fresh immutable Morana values on each access, never a live object or NumPy array from the configuration it captures. Pass it to a supported solve function as immutable input, retain it as result provenance, or call to_configuration() to create an independent mutable problem owner.

UniformSource, MaterialSource, and CellSource are the complete supported fixed-source set. Each is snapshotable and reconstructible.

boundary property

boundary: BoundaryConditionSet

Return a fresh immutable boundary-assignment set.

material_mesh property

material_mesh: MaterialMesh

Return a fresh immutable material-layout value.

materials property

materials: Mapping[str, Material]

Return a fresh read-only mapping of immutable material values.

mesh property

mesh: HexPlanarMesh

Return a fresh immutable planar geometry value.

name property

name: str | None

Return the captured optional configuration name.

source property

source: UniformSource | MaterialSource | CellSource | None

Return a fresh built-in source definition, when present.

excluded_region_map

excluded_region_map() -> dict[str, ExcludedRegion]

Return fresh excluded-region descriptions keyed by layout key.

to_configuration

to_configuration() -> ProblemConfiguration

Reconstruct an independent mutable configuration owner.

Result dataclass

Result(*args: object, **kwargs: object)

Store solution arrays and immutable run provenance.

Instances are returned by the supported solve functions or restored with load_from_disk. Direct construction is not supported.

Attributes:

Name Type Description
flux tuple[ndarray, ...]

Bottom-to-top read-only cell-average scalar-flux arrays in n / cm^2 / s. Each layer has shape (groups, active_cells_in_layer).

balance FixedSourceBalance | KeffBalance

Immutable mode-specific balance record containing group, layer-group, scalar, and derived-ratio diagnostics.

configuration_snapshot ProblemConfigurationSnapshot

Immutable complete, non-aliasing configuration snapshot associated with the completed solve. Its public configuration values are freshly reconstructed on access. Call to_configuration() to create an independent mutable problem definition. A snapshot is required for plotting and VTM export.

solve_settings FixedSourceSettings | KeffSettings

Immutable numerical settings captured for the completed solve.

normalization FissionSourceNormalization | PowerNormalization | None

Immutable fission-source-rate or recoverable-power normalization for a criticality result, otherwise None.

execution_report LinearSolveReport | KeffSolveReport

Immutable typed solver diagnostics and convergence information.

keff float | None

Final multiplication-factor estimate for a criticality report, otherwise None.

groups int

Shared number of energy groups, ordered fast to thermal.

n_axial_layers int

Number of bottom-to-top stored flux layers.

Notes

Result is immutable. Flux arrays and balance diagnostics are owned immutable values, preserving a complete internally consistent record for plotting, export, and provenance.

The active-cell axis is compact and layer-local. Use flux_layer() to select one layer, and use the configuration snapshot or inspection methods to map values back to full planar positions; excluded positions have no stored flux value.

Reject direct construction; use a solve function or archive loader.

groups property

groups: int

Return the shared fast-to-thermal energy-group count.

keff property

keff: float | None

Return the final multiplication-factor estimate, when applicable.

n_axial_layers property

n_axial_layers: int

Return the number of stored axial flux layers.

solve_mode property

solve_mode: str

Return the solve-mode identifier derived from typed provenance.

cell_at

cell_at(
    axial_index: int, openmc_index: OpenMCIndex
) -> CellInspection

Return the material data and all-group flux at one active cell.

Parameters:

Name Type Description Default
axial_index int

Nonnegative bottom-to-top axial-layer index.

required
openmc_index OpenMCIndex

Planar OpenMC-style position in the complete material mesh.

required

Returns:

Type Description
CellInspection

The selected material key, its macroscopic cross sections, and a read-only one-dimensional flux array in fast-to-thermal order.

Raises:

Type Description
TypeError

If axial_index is not an integer or openmc_index is not an OpenMCIndex.

IndexError

If axial_index is outside the material-slice stack.

KeyError

If openmc_index is outside the complete planar mesh.

ValueError

If the selected position is excluded, or its material has no cross sections.

export_vtm

export_vtm(path: str | Path) -> None

Export reconstructed material layout and flux data as VTM blocks.

The VTM references active and excluded VTU leaves. It includes one full-lattice flux_gN cell array per group in fast-to-thermal order; excluded-cell flux entries are NaN. Parent directories are created when needed.

The VTM leaf directory contains material_keys.json, which maps each exported material_key_id to its material key.

Raises:

Type Description
ValueError

If path does not have a .vtm suffix.

IsADirectoryError

If path identifies an existing directory.

OSError

If an output directory cannot be created or an output file cannot be written.

flux_layer

flux_layer(axial_index: int) -> np.ndarray

Return the owned read-only group-major flux for one axial layer.

Parameters:

Name Type Description Default
axial_index int

Nonnegative bottom-to-top axial-layer index.

required

Returns:

Type Description
ndarray

Array shaped (groups, active_cells_in_layer).

Raises:

Type Description
TypeError

If axial_index is not an integer or is a boolean.

ValueError

If axial_index is negative or outside the stored layers.

load_from_disk classmethod

load_from_disk(path: str | Path) -> 'Result'

Load a checked result from a versioned non-pickle archive.

The loader accepts only supported archive schema versions, validates the ZIP member inventory and payload SHA-256 hashes, loads all NumPy payloads with allow_pickle=False, and reconstructs a checked completed result from its internal archive representation.

Parameters:

Name Type Description Default
path str | Path

Source .morana-result archive path. The suffix is conventional and is neither required nor added.

required

Returns:

Type Description
Result

New immutable result with independently owned arrays and provenance.

Raises:

Type Description
ValueError

If the archive is malformed, unsupported, inconsistent, or fails checked completed-result reconstruction.

OSError

If the archive cannot be read.

plot_matplotlib

plot_matplotlib(
    group: int, axial_index: int, ax: Axes | None = None
) -> Axes

Plot one energy group on one axial slice using Matplotlib.

Parameters:

Name Type Description Default
group int

Zero-based fast-to-thermal group index.

required
axial_index int

Nonnegative bottom-to-top layer index.

required
ax Axes | None

Optional axes to populate. A new figure and axes are created when omitted.

None

Returns:

Type Description
Axes

Populated axes with a scalar-flux colorbar. Excluded positions are rendered in the fixed excluded-flux color.

Raises:

Type Description
TypeError

If group is not an integer or is a boolean, or if ax is neither an Axes nor None.

ValueError

If the selected group or layer is invalid or the layer has no active flux values.

plot_plotly

plot_plotly(group: int, axial_index: int) -> Figure

Return a Plotly plot of one energy group on one axial slice.

Polygon hover text includes full-lattice material-position details and the selected scalar flux. Excluded positions use the fixed excluded-flux color and report nan flux.

Raises:

Type Description
TypeError

If group is not an integer or is a boolean.

ValueError

If the selected group or layer is invalid or the layer has no active flux values.

save_to_disk

save_to_disk(path: str | Path) -> None

Save this result as a versioned non-pickle .morana-result archive.

The archive is a standard DEFLATE-compressed ZIP file containing an explicit JSON manifest and named .npy payloads. It records the result, detailed balances, solve settings, normalization, and complete configuration provenance. Array payloads are written without pickle and are checksummed. Parent directories are created and the completed archive replaces path atomically.

Parameters:

Name Type Description Default
path str | Path

Destination archive path. The suffix is conventionally .morana-result but is not required.

required

Raises:

Type Description
ValueError

If the result cannot be represented by the archive schema.

OSError

If the destination cannot be created or replaced.

SeparableFission dataclass

SeparableFission(
    nu_sigma_f: ndarray | list[float],
    chi: ndarray | list[float],
    *,
    chi_normalization_tolerance: float = 1e-08
)

Store compact separable fission-neutron production data.

Parameters:

Name Type Description Default
nu_sigma_f ndarray | list[float]

One-dimensional incident-group fission-neutron production cross section in 1 / cm. It must be finite, nonnegative, and contain at least one positive value.

required
chi ndarray | list[float]

One-dimensional outgoing-group fission spectrum. It must have the same group count as nu_sigma_f, be finite and nonnegative, have a positive sum, and be within chi_normalization_tolerance of one. Accepted spectra are normalized before storage.

required
chi_normalization_tolerance float

Finite positive accepted deviation of the input fission-spectrum sum from one. Defaults to 1.0e-8.

1e-08

Attributes:

Name Type Description
groups int

Number of energy groups.

fission_transfer ndarray

Read-only derived fission-neutron transfer array with event-oriented indexing [g_from, g_to].

fission_production ndarray

Read-only derived total neutron production by incident group.

Notes

SeparableFission owns immutable numerical inputs. Its derived transfer is nu_sigma_f[g_from] * chi[g_to].

UniformSource dataclass

UniformSource(strength: ndarray | list[float])

Apply one volumetric source vector to every active cell.

Parameters:

Name Type Description Default
strength ndarray | list[float]

Nonempty one-dimensional group-major source vector in n / cm^3 / s. It is copied into a read-only floating-point array.

required

Raises:

Type Description
TypeError

If strength contains values other than real non-Boolean numbers.

ValueError

If strength is not a nonempty one-dimensional vector.

Notes

The vector is broadcast to every active cell in the selected layer, including a valid zero-column result for an empty layer. Finiteness, nonnegativity, and compatibility with the problem group count are checked during source assembly rather than construction. UniformSource is immutable; construct a replacement source to change its strength.

values

values(
    axial_index: int,
    material_by_active_id: Mapping[int, str],
) -> np.ndarray

Broadcast source strength over the selected layer’s active cells.

The returned read-only array has shape (len(strength), len(material_by_active_id)). axial_index is checked only as a nonnegative explicit index because this source does not own an axial stack.

WielandtShiftSettings dataclass

WielandtShiftSettings(shift_inverse_keff: float)

Select fixed Wielandt-shifted fission-source power iteration.

Parameters:

Name Type Description Default
shift_inverse_keff float

Finite nonnegative real fixed shift applied to the inverse multiplication factor in the shifted operator A - shift_inverse_keff * F. Boolean values are not accepted. The solver does not adapt this value or fall back to ordinary power iteration when the shifted operator is unusable.

required

Raises:

Type Description
TypeError

If shift_inverse_keff is not a real number or is Boolean.

ValueError

If shift_inverse_keff is not finite and nonnegative after conversion to float.

kind property

kind: str

Return the stable eigenvalue-iteration identifier "wielandt".