Source code for jax_sn.operators.scatter_operator.scatter_operator_strategies
import jax
import jax.numpy as jnp
import equinox as eqx
from jax_sn.domain.cross_sections import CrossSectionsIndexed
from .scatter_operator_base import ScatterData, ScatterStrategy
from jax_sn.quadrature_set.quadrature_set_base import _lm_real_expansion
[docs]
class IndexedScatter(ScatterStrategy):
[docs]
def forward(self, data: ScatterData, x):
return total_scatter_kernel_xs_indexed(
data.energy_group_out, data.energy_group_in, data.cross_sections_indexed, x
)
def _scatter_kernel_xs_indexed_kernel(elem_idx : int, g_out : int, g_in : int, cross_sections_indexed : CrossSectionsIndexed, moments_array : jnp.ndarray) -> jnp.ndarray:
r'''
From an element index, outgoing/incoming group, indexed cross sections and the moments buffer for
the incoming group, the scattering source :math:`s^{g_{out}}_{lm} = \sigma_{l, g_{out}\from g_{in}}^{(e)} \psi_{lm}^{(e, g_{in})}`.
Pads/truncates the cross-section :math:`l`-expansion to the number of moments in ``moments_array``.
'''
assert moments_array.ndim == 3, f"moments_array must be 3D [n_moments, n_elements, n_basis], but has shape {moments_array.shape}."
xs_idx = cross_sections_indexed.indices[elem_idx]
sigma_l_gg = cross_sections_indexed.cross_section_data.scattering[xs_idx, :, g_out, g_in] # [lmax + 1]
# l-expansion (not lm), expand locally to n_moments
extended_sigma_lm_gg = sigma_l_gg[_lm_real_expansion(sigma_l_gg.shape[0] - 1)[0]] # [n_moments]
n_moments = moments_array.shape[0]
extended_sigma_lm_gg = extended_sigma_lm_gg[:n_moments] # truncate if needed
extended_sigma_lm_gg = jnp.pad(extended_sigma_lm_gg, (0, n_moments - extended_sigma_lm_gg.shape[0])) # pad if needed
return extended_sigma_lm_gg[:, None] * moments_array[:, elem_idx, :] # [n_moments, n_basis]
[docs]
@eqx.filter_jit
def total_scatter_kernel_xs_indexed(g_out : int, g_in : int, cross_sections_indexed : CrossSectionsIndexed, moments_array : jnp.ndarray) -> jnp.ndarray:
return jax.vmap(_scatter_kernel_xs_indexed_kernel, in_axes=(0, None, None, None, None), out_axes=1)(jnp.arange(cross_sections_indexed.indices.shape[0]), g_out, g_in, cross_sections_indexed, moments_array)