jax_sn.operators.multi_group_operator.multi_group_operator_base module¶
- class MultiGroupStrategyBase[source]¶
Bases:
TransposableStrategy,RequiresNonDifferentiableDataApply a multigroup operator, base class for both full operator and chain.
States its requirement on the whole non-differentiable tier (see
RequiresNonDifferentiableData), not on the sweep data alone: it is handed anOperatorData, so what it needs of that tier is its own business and may grow past the sweep ordering.- abstractmethod forward(operator_data: OperatorData, x)[source]¶
- abstractmethod transpose(operator_data: OperatorData, x)[source]¶
- class MultiGroupStrategy[source]¶
Bases:
MultiGroupStrategyBaseMultigroup strategy for $mathbf{A}= mathbf{I} - mathbf{M}mathbf{T}^{-1}mathbf{H}mathbf{D}mathbf{S}$, with $mathbf{S}$ the full scattering operator.
- class MultiGroupChainStrategy[source]¶
Bases:
MultiGroupStrategyBaseMultigroup strategy for chain $mathbf{M}mathbf{T}^{-1}mathbf{H}mathbf{D}$
- class MultiGroupOperatorBase(data: OperatorData, strategy: MultiGroupStrategyBase, transpose_bool: bool = False)[source]¶
Bases:
TransposeBoolDataStrategyLinearOperatorBase operator acting on the full energy-group axis: shared operand structure and data accessors.
- data: OperatorData¶
- strategy: MultiGroupStrategyBase¶
- transpose_bool: bool = False¶
- property n_energy_groups: int¶
Number of energy groups, derived from
operator_data’s cross sections.
- property solution_domain¶
Reconstruct the
SolutionDomainthis operator was built from (e.g. for interpolation).
- class MultiGroupOperator(data: OperatorData, strategy: MultiGroupStrategy, transpose_bool: bool = False)[source]¶
Bases:
MultiGroupOperatorBaseMulti energy group linear operator implementation base class.
Mathematical Description¶
This operator maps as:
\[\mathbf{A} : \mathcal{G} \otimes \mathcal{M} \otimes \mathcal{F} \rightarrow \mathcal{G}\otimes \mathcal{M} \otimes \mathcal{F}\]The structure of the operator is
\[\begin{split}\mathbf{A} = \begin{bmatrix} \mathbf{A}_0 & B_{01} & B_{02} & \dots & B_{0G} \\ B_{10} & \mathbf{A}_1 & B_{12} & \dots & B_{1G} \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ B_{G0} & B_{G1} & B_{G2} & \dots & \mathbf{A}_G \end{bmatrix}\end{split}\]where \(\mathbf{A}_g\) is the single group operator for energy group g, and \(B_{ij}\) is the scattering operator from group j to group i.
These operators are defined as:
\[\mathbf{A}_g = \mathbf{I} - \mathbf{M}\mathbf{T}_g^{-1}\mathbf{H} \mathbf{D} \mathbf{S}_{gg}\]\[\mathbf{B}_{ij} = - \mathbf{M}\mathbf{T}_i^{-1}\mathbf{H} \mathbf{D}\mathbf{S}_{ij}\]where \(\mathbf{M}\) is the batched moment operator (see
MomentOperator), \(\mathbf{T}_g\) is the transport operator for group g (seeTransportOperatorMultiAngle), \(\mathbf{H}\) is the mass operator (seeMassOperator), \(\mathbf{D}\) is the moment-to-discrete operator (seeDiscreteOperator), and \(\mathbf{S}_{ij}\) is the scattering operator from group j to group i (seeScatterOperator). These operators are all defined for a single energy group, as in their original definitions.These are combined to form the multi-group operator as shown above. However, the naive implementation would require \(G^2\) transport sweeps to apply the operator (one for each block in the matrix). This is clearly very inefficient. We can exploit the forward and transpose structure instead to limit this to only \(G\) sweeps per application of the operator.
Forward Structure¶
Note that for a specific row (energy group), the operator acts as a single group operator plus a scattering source from all other energy groups. Writing out explicitly the action on a vector \(\psi\) for energy group g, we have:
\[\mathbf{A}[\psi]_g = \left[\mathbf{I} - \mathbf{M}\mathbf{T}_g^{-1}\mathbf{H}\mathbf{D}\mathbf{S}_{gg} \right] \psi_{g} - \sum_{g' \neq g} \mathbf{M}\mathbf{T}_g^{-1}\mathbf{H}\mathbf{D}\mathbf{S}_{gg'} \psi_{g'}\]which is equivalent to:
\[\mathbf{A}[\psi]_g = \left[\mathbf{I} - \mathbf{M} \mathbf{T}_g^{-1} \mathbf{H}\mathbf{D}\left(\mathbf{S}_{gg}[\psi_g] - \sum_{g'\neq g} \mathbf{S}_{gg'}[\psi_{g'}]\right)\right] \equiv \left[\mathbf{I} - \mathbf{M} \mathbf{T}_g^{-1} \mathbf{H} \mathbf{D}\mathbf{U}_{g}[\psi]\right]\]This latter operator:
\[\mathbf{U}_g[\psi] = \sum_{\tilde{g}} \mathbf{S}_{g\tilde{g}}[\psi_{\tilde{g}}]\]is implemented efficiently in the
GatherScatterOperatorclass.This procedure minimizes the number of sweeps to just one per group in the forward direction.
Transposed Structure¶
The transposition structure is not as straightforward as the forward structure. We have
\[\begin{split}\mathbf{A}^T = \begin{bmatrix} \mathbf{A}_0^T & B_{10}^T & B_{20}^T & \dots & B_{G0}^T \\ B_{01}^T & \mathbf{A}_1^T & B_{21}^T & \dots & B_{G1}^T \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ B_{0G}^T & B_{1G}^T & B_{2G}^T & \dots & \mathbf{A}_G^T \end{bmatrix}\end{split}\]For a single row, we have
\[\mathbf{A}^T[\psi]_g = \left[\mathbf{I} - \mathbf{S}_{gg}^T \mathbf{D}^T \mathbf{H}^T (\mathbf{T}_g^{-1})^T \mathbf{M}^T \right] \psi_{g} - \sum_{g' \neq g} \mathbf{S}_{g'g}^T \mathbf{D}^T\mathbf{H}^T (\mathbf{T}_{g'}^{-1})^T \mathbf{M}^T \psi_{g'}\]Now, we note that we cannot take together the \(\mathbf{T}_{g'}^{-1}\) terms since this is a different energy group for each term in the sum.
So, instead we precompute, for all energy groups \(g\):
\[\zeta_g = \mathbf{D}^T \mathbf{H}^T (\mathbf{T}_{g}^{-1})^T \mathbf{M}^T \psi_g\]and then combine these with the transposed indexed scattering operators to form the final result (note that the scatter operator transposition is itself, since it is element-wise multiplication):
\[\mathbf{A}^T[\psi]_g = \psi_g - \sum_{g'} \mathbf{S}_{g'g}^T[\zeta_{g'}] \equiv \psi_g - \sum_{g'}\mathbf{S}_{g'g}[\zeta_{g'}] \equiv \psi_g - \mathbf{V}_g[g]\]with
\[\mathbf{V}_g[\zeta] = \sum_{\tilde{g}} \mathbf{S}_{\tilde{g} g}[\zeta_{\tilde{g}}]\]again implemented efficiently in the
GatherScatterOperatorclass.This again minimizes the number of sweeps to just one per group in the transposed direction, although some extra storage is required for the intermediate \(\zeta_g\) vector
Solution¶
Since this is a iteratively defined linear operator, the standard way to solve systems involving this operator is to use an iterative solver (e.g., GMRES, CG, etc.) with the mv() method defined here. This can be accomplished using e.g. lineax solvers. This allows for the propagation of the derivatives through the solver as well. However, in some cases, e.g. downscattering only problems (such as often found in fusion applications), the multi-group operator is lower triangular. In these cases, it is much more efficient to solve the system directly using a block forward substitution approach, solving each energy group sequentially using the single-group operator for that group and the already computed higher energy group solutions to form the scattering source. This is implemented in the function
solve_lower_triangular().- strategy: MultiGroupStrategy¶
- class MultiGroupChainOperator(data: OperatorData, strategy: MultiGroupChainStrategy, transpose_bool: bool = False)[source]¶
Bases:
MultiGroupOperatorBaseThe chain \(\mathbf{C} = \mathbf{M}\mathbf{T}^{-1}\mathbf{H}\mathbf{D}\) applied independently to every group (no gather-scatter, so groups don’t couple). Same operand structure as
MultiGroupOperator; used to precondition a per-group right-hand side.Wrapping the strategy as an operator is what buys
transpose()and lineax composition for free. It is a view: it sharesdatawith the multigroup operator it accompanies, so build it at the call site – a stored copy would not follow aneqx.tree_aton the original’s data.- strategy: MultiGroupChainStrategy¶