Skip to content

Commit 0232377

Browse files
jwreepwtbarnes
andauthored
Replace ioneq with ionization_fraction and add setter (#337)
* first pass at replacing ioneq * test fixes -- ._ioneq not removed * copy_arrays -> memmap * revert ioneq in examples -- asdf files still have ioneq key * fix property names * add setter for ionization fraction * add setter test; remove ionization_filename * fix tests * fix bug with generate_hash_table * fix test list to found other ioneq file * add one new test * Update fiasco/ions.py Co-authored-by: Will Barnes <will.t.barnes@gmail.com> * Update fiasco/ions.py Co-authored-by: Will Barnes <will.t.barnes@gmail.com> * Update fiasco/ions.py Co-authored-by: Will Barnes <will.t.barnes@gmail.com> * Update fiasco/ions.py Co-authored-by: Will Barnes <will.t.barnes@gmail.com> * Update fiasco/ions.py Co-authored-by: Will Barnes <will.t.barnes@gmail.com> * undo change to add_property and update setter test * undo change to util * fix util test * remove redundant ValueError; fix test accordingly * update example for new aiapy version --------- Co-authored-by: Will Barnes <will.t.barnes@gmail.com>
1 parent f6188e8 commit 0232377

22 files changed

+176
-119
lines changed

docs/quick_start.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ Now that you have your database, you can use your ion object that you created ab
8383
<BLANKLINE>
8484
HDF5 Database: ...chianti_dbase.h5
8585
Using Datasets:
86-
ioneq: chianti
86+
ionization_fraction: chianti
8787
abundance: sun_coronal_1992_feldman_ext
8888
ip: chianti
8989
<BLANKLINE>

examples/idl_comparisons/continuum_comparison.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def plot_idl_comparison(wavelength, temperature, result_fiasco, result_idl):
6464
# continuum emission, i.e. that emission produced by
6565
# thermal bremsstrahlung.
6666
idl_result_freefree = read_idl_test_output('freefree_all_ions', '8.0.7')
67-
ion_kwargs = {'abundance': idl_result_freefree['abundance'], 'ioneq_filename': idl_result_freefree['ioneq']}
67+
ion_kwargs = {'abundance': idl_result_freefree['abundance'], 'ionization_fraction': idl_result_freefree['ioneq']}
6868
all_ions = [fiasco.Ion(ion_name, idl_result_freefree['temperature'], **ion_kwargs) for ion_name in fiasco.list_ions()]
6969
all_ions = fiasco.IonCollection(*all_ions)
7070
free_free = all_ions.free_free(idl_result_freefree['wavelength'])
@@ -82,7 +82,7 @@ def plot_idl_comparison(wavelength, temperature, result_fiasco, result_idl):
8282
# Next, let's compare the outputs for the free-bound
8383
# continuum emission.
8484
idl_result_freebound = read_idl_test_output('freebound_all_ions', '8.0.7')
85-
ion_kwargs = {'abundance': idl_result_freebound['abundance'], 'ioneq_filename': idl_result_freebound['ioneq']}
85+
ion_kwargs = {'abundance': idl_result_freebound['abundance'], 'ionization_fraction': idl_result_freebound['ioneq']}
8686
all_ions = [fiasco.Ion(ion_name, idl_result_freebound['temperature'], **ion_kwargs) for ion_name in fiasco.list_ions()]
8787
all_ions = fiasco.IonCollection(*all_ions)
8888
free_bound = all_ions.free_bound(idl_result_freebound['wavelength'])
@@ -99,7 +99,7 @@ def plot_idl_comparison(wavelength, temperature, result_fiasco, result_idl):
9999
# Finally, let's compare the outputs for the two-photon
100100
# continuum emission.
101101
idl_result_twophoton = read_idl_test_output('twophoton_all_ions', '8.0.7')
102-
ion_kwargs = {'abundance': idl_result_twophoton['abundance'], 'ioneq_filename': idl_result_twophoton['ioneq']}
102+
ion_kwargs = {'abundance': idl_result_twophoton['abundance'], 'ionization_fraction': idl_result_twophoton['ioneq']}
103103
all_ions = [fiasco.Ion(ion_name, idl_result_twophoton['temperature'], **ion_kwargs) for ion_name in fiasco.list_ions()]
104104
all_ions = fiasco.IonCollection(*all_ions)
105105
two_photon = all_ions.two_photon(idl_result_twophoton['wavelength'], idl_result_twophoton['density']).squeeze()

examples/idl_comparisons/goft_comparison.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ def plot_idl_comparison(x, y_idl, y_python, fig, n_rows, i_row, quantity_name, t
8282
ion = fiasco.Ion((idl_result['Z'], idl_result['iz']),
8383
idl_result['temperature'],
8484
abundance_filename=idl_result['abundance'],
85-
ioneq_filename=idl_result['ioneq'])
85+
ionization_fraction=idl_result['ioneq'])
8686
contribution_func = ion.contribution_function(idl_result['density'])
8787
transitions = ion.transitions.wavelength[~ion.transitions.is_twophoton]
8888
idx = np.argmin(np.abs(transitions - idl_result['wavelength']))

examples/idl_comparisons/ioneq_comparison.py

+9-9
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def plot_idl_comparison(x, y_idl, y_python, fig, n_rows, i_row, quantity_name, t
6969
# as differences due to the interpolation schemes may show large deviations between
7070
# the two approaches. However, the ionization fraction in these regions does not
7171
# meaningfully contribute to any other derived quantities.
72-
ioneq_files = [
72+
ionization_files = [
7373
'ioneq_1_1',
7474
'ioneq_6_1',
7575
'ioneq_6_2',
@@ -81,19 +81,19 @@ def plot_idl_comparison(x, y_idl, y_python, fig, n_rows, i_row, quantity_name, t
8181
'ioneq_26_20',
8282
'ioneq_26_27',
8383
]
84-
fig = plt.figure(figsize=(9,3*len(ioneq_files)), layout='constrained')
85-
for i, name in enumerate(ioneq_files):
84+
fig = plt.figure(figsize=(9,3*len(ionization_files)), layout='constrained')
85+
for i, name in enumerate(ionization_files):
8686
idl_result = read_idl_test_output(name, '8.0.7')
8787
ion = fiasco.Ion((idl_result['Z'], idl_result['iz']),
8888
idl_result['temperature'],
89-
ioneq_filename=idl_result['ioneq_filename'])
89+
ionization_filename=idl_result['ioneq_filename'])
9090
element = fiasco.Element(ion.atomic_symbol, ion.temperature)
91-
ioneq = element.equilibrium_ionization
92-
print(f'IDL code to produce ioneq result for {ion.ion_name_roman}:')
91+
ionization_fraction = element.equilibrium_ionization
92+
print(f'IDL code to produce ionization_fraction result for {ion.ion_name_roman}:')
9393
print(Template(idl_result['idl_script']).render(**idl_result))
94-
axes = plot_idl_comparison(ion.temperature, idl_result['ioneq'], ion.ioneq,
95-
fig, len(ioneq_files), 3*i, f'{ion.ion_name_roman}')
96-
axes[0].plot(element.temperature, ioneq[:, ion.charge_state],
94+
axes = plot_idl_comparison(ion.temperature, idl_result['ioneq'], ion.ionization_fraction,
95+
fig, len(ionization_files), 3*i, f'{ion.ion_name_roman}')
96+
axes[0].plot(element.temperature, ionization_fraction[:, ion.charge_state],
9797
label='fiasco (rates)', color='C1', ls='-')
9898
axes[0].legend()
9999
plt.show()

examples/user_guide/aia_response.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import matplotlib.pyplot as plt
1313
import numpy as np
1414

15+
from aiapy.calibrate.util import get_correction_table
1516
from aiapy.response import Channel
1617
from astropy.visualization import quantity_support
1718
from scipy.interpolate import interp1d
@@ -26,7 +27,9 @@
2627
# First, create the `~aiapy.response.Channel` object for the
2728
# 94 angstrom channel and compute the wavelength response.
2829
ch = Channel(94*u.angstrom)
29-
response = ch.wavelength_response() * ch.plate_scale
30+
correction_table = get_correction_table("jsoc")
31+
response = ch.wavelength_response(correction_table=correction_table)
32+
response *= ch.plate_scale
3033

3134
#############################################################
3235
# Plot the wavelength response

examples/user_guide/plot_ioneq.py examples/user_guide/plot_ionization_fraction.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -30,24 +30,24 @@
3030
# We can use this to plot the population fraction of each ion as a
3131
# function of temperature.
3232
for ion in el:
33-
ioneq = el.equilibrium_ionization[:, ion.charge_state]
34-
imax = np.argmax(ioneq)
35-
plt.plot(el.temperature, ioneq)
36-
plt.text(el.temperature[imax], ioneq[imax], ion.ionization_stage_roman,
33+
ionization_fraction = el.equilibrium_ionization[:, ion.charge_state]
34+
imax = np.argmax(ionization_fraction)
35+
plt.plot(el.temperature, ionization_fraction)
36+
plt.text(el.temperature[imax], ionization_fraction[imax], ion.ionization_stage_roman,
3737
horizontalalignment='center')
3838
plt.xscale('log')
3939
plt.title(f'{el.atomic_symbol} Equilibrium Ionization')
4040
plt.show()
4141

4242
################################################
4343
# The CHIANTI database also includes tabulated ionization equilibria for
44-
# all ions in the database. The ``ioneq`` attribute on each
44+
# all ions in the database. The ``ionization_fraction`` attribute on each
4545
# `~fiasco.Ion` object returns the tabulated population
4646
# fractions interpolated onto the ``temperature`` array.
47-
# Note that these population fractions returned by `~fiasco.Ion.ioneq` are
47+
# Note that these population fractions returned by `~fiasco.Ion.ionization_fraction` are
4848
# stored in the CHIANTI database and therefore are set to NaN
4949
# for temperatures outside of the tabulated temperature data given in CHIANTI.
50-
plt.plot(el.temperature, el[11].ioneq)
50+
plt.plot(el.temperature, el[11].ionization_fraction)
5151
plt.xscale('log')
5252
plt.title(f'{el[11].ion_name_roman} Equilibrium Ionization')
5353
plt.show()
@@ -58,7 +58,7 @@
5858
# the tabulated results were calculated or due to artifacts from the
5959
# interpolation.
6060
plt.plot(el.temperature, el.equilibrium_ionization[:, el[11].charge_state], label='calculated')
61-
plt.plot(el.temperature, el[11].ioneq, label='interpolated')
61+
plt.plot(el.temperature, el[11].ionization_fraction, label='interpolated')
6262
plt.xlim(5e5, 5e6)
6363
plt.xscale('log')
6464
plt.legend()

fiasco/base.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,11 @@ def _abund(self):
142142
data_path = '/'.join([self.atomic_symbol.lower(), 'abundance'])
143143
return DataIndexer.create_indexer(self.hdf5_dbase_root, data_path)
144144

145+
@property
146+
def _ion_fraction(self):
147+
data_path = '/'.join([self.atomic_symbol.lower(), self._ion_name, 'ioneq'])
148+
return DataIndexer.create_indexer(self.hdf5_dbase_root, data_path)
149+
145150

146151
def add_property(cls, filetype):
147152
"""
@@ -162,4 +167,3 @@ def property_template(self):
162167
add_property(IonBase, filetype)
163168
add_property(IonBase, '/'.join(['dielectronic', filetype]))
164169
add_property(IonBase, 'ip')
165-
add_property(IonBase, 'ioneq')

fiasco/collections.py

+9-9
Original file line numberDiff line numberDiff line change
@@ -118,12 +118,12 @@ def free_free(self, wavelength: u.angstrom):
118118
ff = ion.free_free(wavelength)
119119
try:
120120
abundance = ion.abundance
121-
ioneq = ion.ioneq
121+
ionization_fraction = ion.ionization_fraction
122122
except MissingDatasetException as e:
123123
self.log.warning(f'{ion.ion_name} not included in free-free emission. {e}')
124124
continue
125125
else:
126-
free_free += ff * abundance * ioneq[:, np.newaxis]
126+
free_free += ff * abundance * ionization_fraction[:, np.newaxis]
127127
return free_free
128128

129129
@u.quantity_input
@@ -164,12 +164,12 @@ def free_bound(self, wavelength: u.angstrom, **kwargs):
164164
# NOTE: the free-bound emissivity gets multiplied by the population
165165
# fraction of the recombining ion, that is, the ion with one higher
166166
# charge state.
167-
ioneq = ion.next_ion().ioneq
167+
ionization_fraction = ion.next_ion().ionization_fraction
168168
except MissingDatasetException as e:
169169
self.log.warning(f'{ion.ion_name} not included in free-bound emission. {e}')
170170
continue
171171
else:
172-
free_bound += fb * abundance * ioneq[:, np.newaxis]
172+
free_bound += fb * abundance * ionization_fraction[:, np.newaxis]
173173
return free_bound
174174

175175
@u.quantity_input
@@ -211,7 +211,7 @@ def two_photon(self, wavelength: u.angstrom, electron_density: u.cm**-3, **kwarg
211211
self.log.warning(f'{ion.ion_name} not included in two-photon emission. {e}')
212212
continue
213213
else:
214-
two_photon += tp * ion.abundance * ion.ioneq[:, np.newaxis, np.newaxis]
214+
two_photon += tp * ion.abundance * ion.ionization_fraction[:, np.newaxis, np.newaxis]
215215
return two_photon
216216

217217
@u.quantity_input
@@ -399,12 +399,12 @@ def free_free_radiative_loss(self, use_itoh=False) -> u.Unit('erg cm3 s-1'):
399399
try:
400400
ff = ion.free_free_radiative_loss(use_itoh=use_itoh)
401401
abundance = ion.abundance
402-
ioneq = ion.ioneq
402+
ionization_fraction = ion.ionization_fraction
403403
except MissingDatasetException as e:
404404
self.log.warning(f'{ion.ion_name} not included in free-free radiative loss. {e}')
405405
continue
406406
else:
407-
free_free += ff * abundance * ioneq
407+
free_free += ff * abundance * ionization_fraction
408408
return free_free
409409

410410
@u.quantity_input
@@ -423,10 +423,10 @@ def free_bound_radiative_loss(self) -> u.Unit('erg cm3 s-1'):
423423
try:
424424
fb = ion.free_bound_radiative_loss()
425425
abundance = ion.abundance
426-
ioneq = ion.ioneq
426+
ionization_fraction = ion.ionization_fraction
427427
except MissingDatasetException as e:
428428
self.log.warning(f'{ion.ion_name} not included in free-bound radiative loss. {e}')
429429
continue
430430
else:
431-
free_bound += fb * abundance * ioneq
431+
free_bound += fb * abundance * ionization_fraction
432432
return free_bound

fiasco/elements.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ def equilibrium_ionization(self):
106106
--------
107107
>>> temperature = 10**np.arange(3.9, 6.5, 0.01) * u.K
108108
>>> carbon = Element('C', temperature)
109-
>>> carbon_ioneq = carbon.equilibrium_ionization
110-
>>> carbon_ioneq[:, 4].max() # max populuation fraction of C V as a function of temperature
109+
>>> carbon_ionization = carbon.equilibrium_ionization
110+
>>> carbon_ionization[:, 4].max() # max population fraction of C V as a function of temperature
111111
<Quantity 0.99776769>
112112
113113
See Also
@@ -120,10 +120,10 @@ def equilibrium_ionization(self):
120120
# Select columns of V with smallest eigenvalues (returned in descending order)
121121
# NOTE: must take the absolute value as the SVD solution is only accurate up
122122
# to the sign. We require that the solutions must be positive.
123-
ioneq = np.fabs(V[:, -1, :])
124-
ioneq /= ioneq.sum(axis=1)[:, np.newaxis]
123+
ionization_fraction = np.fabs(V[:, -1, :])
124+
ionization_fraction /= ionization_fraction.sum(axis=1)[:, np.newaxis]
125125

126-
return u.Quantity(ioneq)
126+
return u.Quantity(ionization_fraction)
127127

128128
def __getitem__(self, value):
129129
if isinstance(value, (str, tuple)): # NOQA: UP038

fiasco/fiasco.py

+11-10
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ def proton_electron_ratio(temperature: u.K, **kwargs):
126126
# Import here to avoid circular imports
127127
from fiasco import log
128128
h_2 = fiasco.Ion('H +1', temperature, **kwargs)
129-
numerator = h_2.abundance * h_2._ioneq[h_2._instance_kwargs['ioneq_filename']]['ionization_fraction']
129+
numerator = h_2.abundance * h_2._ion_fraction[h_2._instance_kwargs['ionization_fraction']]['ionization_fraction']
130130
denominator = u.Quantity(np.zeros(numerator.shape))
131131
for el_name in list_elements(h_2.hdf5_dbase_root):
132132
el = fiasco.Element(el_name, temperature, **h_2._instance_kwargs)
@@ -138,21 +138,22 @@ def proton_electron_ratio(temperature: u.K, **kwargs):
138138
f'Not including {el.atomic_symbol}. Abundance not available from {abund_file}.')
139139
continue
140140
for ion in el:
141-
ioneq_file = ion._instance_kwargs['ioneq_filename']
142-
# NOTE: We use ._ioneq here rather than .ioneq to avoid doing an interpolation to the
143-
# temperature array every single time and instead only interpolate once at the end.
144-
# It is assumed that the ioneq temperature array for each ion is the same.
141+
ionization_file = ion._instance_kwargs['ionization_fraction']
142+
# NOTE: We use ._ion_fraction here rather than .ionization_fraction to avoid
143+
# doing an interpolation to the temperature array every single time and instead only
144+
# interpolate once at the end.
145+
# It is assumed that the ionization_fraction temperature array for each ion is the same.
145146
try:
146-
ioneq = ion._ioneq[ioneq_file]['ionization_fraction']
147-
t_ioneq = ion._ioneq[ioneq_file]['temperature']
147+
ionization_fraction = ion._ion_fraction[ionization_file]['ionization_fraction']
148+
t_ionization_fraction = ion._ion_fraction[ionization_file]['temperature']
148149
except KeyError:
149150
log.warning(
150-
f'Not including {ion.ion_name}. Ionization fraction not available from {ioneq_file}.')
151+
f'Not including {ion.ion_name}. Ionization fraction not available from {ionization_file}.')
151152
continue
152-
denominator += ioneq * abundance * ion.charge_state
153+
denominator += ionization_fraction * abundance * ion.charge_state
153154

154155
ratio = numerator / denominator
155-
f_interp = interp1d(t_ioneq.to(temperature.unit).value,
156+
f_interp = interp1d(t_ionization_fraction.to(temperature.unit).value,
156157
ratio.value,
157158
kind='linear',
158159
bounds_error=False,

0 commit comments

Comments
 (0)