solrat.atom_model.multi_term_atom_model.statistical_equilibrium_equations module

class solrat.atom_model.multi_term_atom_model.statistical_equilibrium_equations.MultiTermAtomSEE(level_registry: LevelRegistry, transition_registry: TransitionRegistry, disable_r_s: bool = False)[source]

Bases: BaseSEE

Statistical Equilibrium Equations within Multi-Term atom model

Parameters:
  • level_registry – LevelRegistry instance for the multi-term atom under study.

  • transition_registry – TransitionRegistry instance for the multi-term atom under study.

  • disable_r_s – Whether to disable stimulated emission \(R_S\) (7.46c).

Reference: (LL04 7.38)

Note on precomputing: All frames are built lazily on first use and cached as instance attributes. Atom-specific frames (no radiation tensor) are built once and reused across calls. Frames that depend on the radiation tensor are partially precomputed; the radiation-tensor factor is applied per fill_all_equations() call. Precomputed frames can be extracted after the first fill_all_equations() call and injected into a new instance via PrecomputedData to skip the build step.

classmethod from_model_config(config: MultiTermAtomConfig) Self[source]

Constructor from the model config.

fill_all_equations(atmosphere_parameters: AtmosphereParameters, radiation_tensor_in_magnetic_frame: RadiationTensor)[source]

Loop through all equations to construct the complete system of equations for rho.

Parameters:
  • atmosphere_parameters – AtmosphereParameters instance carrying the magnetic field and other variables.

  • radiation_tensor_in_magnetic_frame – RadiationTensor instance

Reference: (LL04 7.38)

Note: Calling this function multiple times with different atmosphere_parameters of \(J\) tensors is safe, it will build the system of equations from scratch each time.

add_coherence_decay(atmosphere_parameters: AtmosphereParameters)[source]

Add the coherence decay \(N = n_0 + n_1 \nu_L\)

Reference: (LL04 7.38, 7.41)

add_absorption(radiation_tensor: RadiationTensor)[source]

Add absorption \(T_a = t_{a1} \cdot J^{K_r}_{Q_r}\).

Reference: (LL04 7.38, 7.45a)

add_emission_e()[source]

Add spontaneous emission \(T_e\).

Reference: (LL04 7.38, 7.45b)

add_emission_s(radiation_tensor: RadiationTensor)[source]

Add stimulated emission \(T_s = t_{s1} \cdot J^{K_r}_{Q_r}\).

Reference: (LL04 7.38, 7.45c)

add_relaxation_e()[source]

Add spontaneous emission relaxation \(R_E = -r_{e0}\).

Reference: (LL04 7.38, 7.46b)

add_relaxation_a(radiation_tensor: RadiationTensor)[source]

Add absorption relaxation \(R_A = -r_{a1} \cdot J^{K_r}_{Q_r}\).

Reference: (LL04 7.38, 7.46a)

add_relaxation_s(radiation_tensor: RadiationTensor)[source]

Add stimulated emission relaxation \(R_S = -r_{s1} \cdot J^{K_r}_{Q_r}\).

Reference: (LL04 7.38, 7.46c)

get_solution() Rho[source]

Get the solution of the Statistical Equilibrium Equations.

Returns:

Rho instance

The solution is constructed by manual linalg solving, which proved to be a bit more reliable than available homogeneous solvers. The idea is simple:

The matrix equation is \(A x = 0\).

Let \(x[0] = 1\) (it is always \(\rho_0^0\) of some kind, so it is least likely to be exactly zero). Then we have a non-homogeneous system of equations:

\[ \begin{align}\begin{aligned}A[1:] x &= 0\\A[1:, 1:] x[1:] &= -A[1:, 0]\end{aligned}\end{align} \]

This system generally behaves well enough for linalg.solve to succeed, but pinv is more robust.

add_coefficient_for_rho(frame: Frame, term_id: str, K: str, Q: str, J: str, : str, multiply_by: complex | float | None = None)[source]
add_equation_index(df: DataFrame, term_id: str, K: str, Q: str, J: str, : str, index: str)[source]

A helper function to keep track of which matrix row/column each term in SEE corresponds to. Set either index0 or index1 using the provided \(K, Q,\) ….