Skip to content

Commit 66759af

Browse files
committed
Backport PR #262: Use total recombination data if available to calculate recombination rate
1 parent 6f14205 commit 66759af

File tree

2 files changed

+55
-9
lines changed

2 files changed

+55
-9
lines changed

fiasco/ions.py

+36
Original file line numberDiff line numberDiff line change
@@ -1159,6 +1159,17 @@ def dielectronic_recombination_rate(self) -> u.cm**3 / u.s:
11591159
else:
11601160
raise ValueError(f"Unrecognized fit type {self._drparams['fit_type']}")
11611161

1162+
@cached_property
1163+
@needs_dataset('trparams')
1164+
@u.quantity_input
1165+
def _total_recombination_rate(self) -> u.cm**3 / u.s:
1166+
temperature_data = self._trparams['temperature'].to_value('K')
1167+
rate_data = self._trparams['recombination_rate'].to_value('cm3 s-1')
1168+
f_interp = interp1d(temperature_data, rate_data, fill_value='extrapolate', kind='cubic')
1169+
f_interp = PchipInterpolator(np.log10(temperature_data), np.log10(rate_data), extrapolate=True)
1170+
rate_interp = 10**f_interp(np.log10(self.temperature.to_value('K')))
1171+
return u.Quantity(rate_interp, 'cm3 s-1')
1172+
11621173
@cached_property
11631174
@u.quantity_input
11641175
def recombination_rate(self) -> u.cm**3 / u.s:
@@ -1172,18 +1183,43 @@ def recombination_rate(self) -> u.cm**3 / u.s:
11721183
11731184
\alpha_{R} = \alpha_{RR} + \alpha_{DR}
11741185
1186+
.. warning::
1187+
1188+
For most ions, this total recombination rate is computed by summing the
1189+
outputs of the `radiative_recombination_rate` and `dielectronic_recombination_rate` methods.
1190+
However, for some ions, total recombination rate data is available in the
1191+
so-called ``.trparams`` files. For these ions, the output of this method
1192+
will *not* be equal to the sum of the `dielectronic_recombination_rate` and
1193+
`radiative_recombination_rate` method. As such, when computing the total
1194+
recombination rate, this method should always be used.
1195+
11751196
See Also
11761197
--------
11771198
radiative_recombination_rate
11781199
dielectronic_recombination_rate
11791200
"""
1201+
# NOTE: If the trparams data is available, then it is prioritized over the sum
1202+
# of the dielectronic and radiative recombination rates. This is also how the
1203+
# total recombination rates are computed in IDL. The reasoning here is that the
1204+
# total recombination rate data, if available, is more reliable than the sum of
1205+
# the radiative and dielectronic recombination rates. According to P. Young, there
1206+
# is some slight controversy over this within some communities, but CHIANTI has chosen
1207+
# to prioritize this data if it exists.
1208+
try:
1209+
tr_rate = self._total_recombination_rate
1210+
except MissingDatasetException:
1211+
self.log.debug(f'No total recombination data available for {self.ion_name}.')
1212+
else:
1213+
return tr_rate
11801214
try:
11811215
rr_rate = self.radiative_recombination_rate
11821216
except MissingDatasetException:
1217+
self.log.debug(f'No radiative recombination data available for {self.ion_name}.')
11831218
rr_rate = u.Quantity(np.zeros(self.temperature.shape), 'cm3 s-1')
11841219
try:
11851220
dr_rate = self.dielectronic_recombination_rate
11861221
except MissingDatasetException:
1222+
self.log.debug(f'No dielectronic recombination data available for {self.ion_name}.')
11871223
dr_rate = u.Quantity(np.zeros(self.temperature.shape), 'cm3 s-1')
11881224
return rr_rate + dr_rate
11891225

fiasco/tests/test_ion.py

+19-9
Original file line numberDiff line numberDiff line change
@@ -287,18 +287,28 @@ def test_intensity(ion, em):
287287
assert intens.shape == ion.temperature.shape + (1, ) + wave_shape
288288

289289

290-
def test_excitation_autoionization_rate(ion):
291-
rate = ion.excitation_autoionization_rate
290+
@pytest.mark.parametrize(('rate_name','answer'), [
291+
# NOTE: The expected values have not been tested for correctness and
292+
# are only meant to indicate whether a value has changed or not.
293+
('direct_ionization_rate', 9.448935172152884e-13*u.cm**3 / u.s),
294+
('excitation_autoionization_rate', 1.14821255e-12 * u.cm**3 / u.s),
295+
('dielectronic_recombination_rate', 1.60593802e-11 * u.cm**3 / u.s),
296+
('radiative_recombination_rate', 1.6221634159408823e-12*u.cm**3 / u.s),
297+
])
298+
def test_rates(ion, rate_name, answer):
299+
rate = getattr(ion, rate_name)
292300
assert rate.shape == ion.temperature.shape
293-
# This value has not been tested for correctness
294-
assert u.allclose(rate[0], 1.14821255e-12 * u.cm**3 / u.s)
301+
assert u.allclose(rate[0], answer)
295302

296303

297-
def test_dielectronic_recombination_rate(ion):
298-
rate = ion.dielectronic_recombination_rate
299-
assert rate.shape == ion.temperature.shape
300-
# This value has not been tested for correctness
301-
assert u.allclose(rate[0], 1.60593802e-11 * u.cm**3 / u.s)
304+
def test_total_recombination_rate_priority(ion):
305+
# This tests that in cases where the total recombination data in the trparams
306+
# files is available that it is prioritized over the sum of the DR and RR rates.
307+
# This is the case for this ion because Fe V has total recombination rate data
308+
# available.
309+
recomb_rate = ion.recombination_rate
310+
tot_recomb_rate = ion._total_recombination_rate
311+
assert np.all(recomb_rate == tot_recomb_rate)
302312

303313

304314
def test_free_free(ion):

0 commit comments

Comments
 (0)