Summary
The contribution function computed by fiasco diverges from CHIANTI IDL (and ChiantiPy) at low temperatures — e.g. ~+6% at $T = 10^5$ K for the Fe IX 171.073 Å line in the IDL comparison gallery example. The cause is that fiasco uses the scups file de (the theoretical transition energy from the original scattering calculation) in the detailed-balance Boltzmann factor of the collisional excitation rate, whereas CHIANTI IDL and ChiantiPy both use the observed energy difference from the elvlc file there.
Details
All three codes agree on the Burgess–Tully descaling of the effective collision strength — the scups de is the correct energy for the scaled temperature, and fiasco uses it there (Ion.effective_collision_strength). The difference is only in the exponential converting the de-excitation rate to the excitation rate:
-
fiasco (Ion.electron_collision_excitation_rate, fiasco/ions.py):
kBTE = np.outer(1./self.thermal_energy, self._scups['delta_energy'])
return omega_upper / omega_lower * self.electron_collision_deexcitation_rate * np.exp(-kBTE)
-
CHIANTI IDL (level_population/ch_load_ion_rates.pro):
; ecmc contains the elvlc "best" energies (observed where available)
kte=(hck*abs(ecmc[l1]-(ecmc[l2]-ip_cm))) # (1d0/temp)
...
xx[ind_pos,*]=8.63e-6* exp(-kte[ind_pos,*]) * 1./(mult[l1[ind_pos]] # sqrt(t)) ; excitation
-
ChiantiPy (Ion.upsilonDescale) uses Scups['de'] for the descaling but recomputes the energy for the exponential from elvlc, observed-first:
elvlc = np.where(eryd >= 0., eryd, erydth)
...
de = np.abs(elvlc[l2idx] - elvlc[l1idx])
ekt = (de*const.ryd2erg)/(const.boltzmann*temp)
exRate[iscups] = const.collision*ups[iscups]*np.exp(-ekt)/(fmult1*np.sqrt(temp))
Magnitude for Fe IX 171.073 Å
For the 1 → 13 transition in CHIANTI v11.0.2:
| quantity |
value |
| elvlc observed energy of level 13 |
584,546 cm⁻¹ = 5.3268 Ry |
scups de (matches elvlc theoretical) |
580,435 cm⁻¹ = 5.2893 Ry |
| difference δE/k |
5,915 K |
Since the 1P₁ upper level is populated almost entirely by direct excitation from the ground level at low temperature, the fiasco/IDL contribution function ratio should be ≈ exp(δE/kT). Comparing fiasco (main) against the cached IDL result (goft_26_9_171.073_v11.0.2.asdf) confirms this:
T [K] fiasco/IDL exp(δE/kT)
1.000e+05 1.0616 1.0615
1.585e+05 1.0384 1.0383
2.512e+05 1.0233 1.0240
1.000e+06 1.0032 1.0060
1.000e+07 0.9998 1.0006
This fully accounts for the low-temperature divergence visible in the goft comparison example (the same effect is reproduced when comparing fiasco against ChiantiPy, which rules out database differences).
Possible fix
In electron_collision_excitation_rate, compute ΔE from the level energies (observed with theoretical fallback, i.e. what Levels.energy exposes) rather than from self._scups['delta_energy'], keeping the scups de in effective_collision_strength for the descaling.
One note on proton rates: CHIANTI IDL uses the psplups de in its proton detailed-balance exponential (de=ABS(prot_struc[i].de) in ch_load_ion_rates.pro), so fiasco's current treatment of proton rates already matches IDL; ChiantiPy is the outlier there.
Summary
The contribution function computed by fiasco diverges from CHIANTI IDL (and ChiantiPy) at low temperatures — e.g. ~+6% at$T = 10^5$ K for the Fe IX 171.073 Å line in the IDL comparison gallery example. The cause is that fiasco uses the scups file
de(the theoretical transition energy from the original scattering calculation) in the detailed-balance Boltzmann factor of the collisional excitation rate, whereas CHIANTI IDL and ChiantiPy both use the observed energy difference from the elvlc file there.Details
All three codes agree on the Burgess–Tully descaling of the effective collision strength — the scups
deis the correct energy for the scaled temperature, and fiasco uses it there (Ion.effective_collision_strength). The difference is only in the exponential converting the de-excitation rate to the excitation rate:fiasco (
Ion.electron_collision_excitation_rate,fiasco/ions.py):CHIANTI IDL (
level_population/ch_load_ion_rates.pro):ChiantiPy (
Ion.upsilonDescale) usesScups['de']for the descaling but recomputes the energy for the exponential from elvlc, observed-first:Magnitude for Fe IX 171.073 Å
For the 1 → 13 transition in CHIANTI v11.0.2:
de(matches elvlc theoretical)Since the 1P₁ upper level is populated almost entirely by direct excitation from the ground level at low temperature, the fiasco/IDL contribution function ratio should be ≈ exp(δE/kT). Comparing fiasco (
main) against the cached IDL result (goft_26_9_171.073_v11.0.2.asdf) confirms this:This fully accounts for the low-temperature divergence visible in the goft comparison example (the same effect is reproduced when comparing fiasco against ChiantiPy, which rules out database differences).
Possible fix
In
electron_collision_excitation_rate, compute ΔE from the level energies (observed with theoretical fallback, i.e. whatLevels.energyexposes) rather than fromself._scups['delta_energy'], keeping the scupsdeineffective_collision_strengthfor the descaling.One note on proton rates: CHIANTI IDL uses the psplups
dein its proton detailed-balance exponential (de=ABS(prot_struc[i].de)inch_load_ion_rates.pro), so fiasco's current treatment of proton rates already matches IDL; ChiantiPy is the outlier there.