Source code for jax_sn.operators.scatter_operator.scatter_operator_base
import jax
from jax_sn.operators.base_linear_operator import (
BaseOperatorData, SymmetricDataStrategyLinearOperator, SymmetricStrategy,
)
from jax_sn.domain.cross_sections import CrossSectionsIndexed
import equinox as eqx
[docs]
class ScatterData(BaseOperatorData):
energy_group_out : int
energy_group_in : int
cross_sections_indexed : CrossSectionsIndexed
[docs]
class ScatterStrategy(SymmetricStrategy):
'''How to apply the (symmetric-shaped) scatter contraction. Reads ``data``.'''
[docs]
class ScatterOperator(SymmetricDataStrategyLinearOperator):
r'''
Maps the flux moments to scattering for a specific energy group in and a specific energy group out, using indexed cross sections.
Mathematical description
---------------------------
We have:
.. math::
\mathbf{S}_{\tilde{g} g} = \overline{\mathbf{S}}_{\tilde{g} g} \otimes \mathbf{I}_{\mathcal{B}} : \mathcal{M} \otimes \mathcal{E}\otimes \mathcal{B} \to \mathcal{M} \otimes \mathcal{E}\otimes \mathcal{B}
with :math:`\tilde{g}` the outgoing energy group, :math:`g` the incoming energy group, :math:`\mathcal{F} = \mathcal{E}\otimes \mathcal{B}` the space of elements and basis functions, and :math:`\mathbf{S}_{\tilde{g} g}` the single-element scattering operator defined as:
.. math::
\overline{\mathbf{S}}_{\tilde{g} g} [\psi]
=\sigma_{\ell \tilde{g} g e} \psi_{g\ell e}
for an arbitrary :math:`\psi\in \mathcal{M} \otimes \mathcal{E}` (we use :math:`\ell` to denote :math:`(l,m)` moment index for brevity; for :math:`\sigma_{\ell}` this just equals :math:`\sigma_{l}` for all :math:`m`).
Transposition
---------------------------
Since this is a element wise multiplication, the transpose is itself.
Technical details
---------------------------
We use a :class:`jax.ShapeDtypeStruct` to represent the shape of the moments, elements and basis functions over which this operator is defined. This is used to define a consistent in and output structure.
Since we want to have the flexibility to have a different number of moments than is present in the cross sections, we explicitly provide it here.
'''
data : ScatterData
r'''ScatterData containing the indexed cross sections for the scatter operator. [differentiable except for groups]'''
strategy : ScatterStrategy
r'''How to apply the scatter contraction.'''
moments_elements_basis_shape : jax.ShapeDtypeStruct
r'''The shape of the moments, elements and basis functions over which this operator is batched. Identified with :math:`\mathcal{M}\otimes \mathcal{E}\otimes \mathcal{B}` in the documentation above.'''
def __check_init__(self):
assert self.moments_elements_basis_shape.ndim == 3, f"elements_basis_shape must be 2D [moments_n_elements, n_basis], but has shape {self.moments_elements_basis_shape.shape}."
assert self.moments_elements_basis_shape.shape[1] == self.data.cross_sections_indexed.indices.shape[0], f"Number of elements in elements_basis_shape {self.moments_elements_basis_shape.shape[0]} must match number of elements in cross_sections_indexed {self.data.cross_sections_indexed.indices.shape[0]}."
def _structure(self):
return self.moments_elements_basis_shape
[docs]
def to_energy_group(self, energy_group_out : int, energy_group_in : int) -> "ScatterOperator":
return eqx.tree_at(lambda op: (op.data.energy_group_out, op.data.energy_group_in), self,
(energy_group_out, energy_group_in))