def test_unequal_temperatures_raise_assertion_error(hdf5_dbase_root): first_ion = fiasco.Ion('Fe 12', [1e6, 1e7] * u.K, hdf5_dbase_root=hdf5_dbase_root) second_ion = fiasco.Ion('Fe 9', [1e4, 1e5] * u.K, hdf5_dbase_root=hdf5_dbase_root) with pytest.raises(AssertionError): fiasco.IonCollection(first_ion, second_ion)
def test_spectrum(hdf5_dbase_root): i1 = fiasco.Ion('H 1', 1 * u.MK, hdf5_dbase_root=hdf5_dbase_root) i2 = fiasco.Ion('Fe 5', 1 * u.MK, hdf5_dbase_root=hdf5_dbase_root) c = i1 + i2 density = 1e9 * u.cm**-3 em = 1e29 * u.cm**-5 w, spec = c.spectrum(density, em) assert spec.shape == (1, 1, ) + w.shape # Add an ion with no spectral information i3 = fiasco.Ion('H 2', 1 * u.MK, hdf5_dbase_root=hdf5_dbase_root) c += i3 with pytest.warns(UserWarning, match=f'No transition data available for {i3.ion_name}'): w2, spec2 = c.spectrum(density, em) assert spec2.shape == (1, 1, ) + w2.shape assert np.all(spec == spec2)
def test_repr_no_levels(hdf5_dbase_root): """ Ensures the repr can be printed without errors even when no energy level or transition information is available. """ assert fiasco.Ion('Fe 1', temperature, hdf5_dbase_root=hdf5_dbase_root).__repr__
def test_indexing_no_levels(hdf5_dbase_root): ion = fiasco.Ion('Fe 1', temperature, hdf5_dbase_root=hdf5_dbase_root) print(ion) assert [l for l in ion] == [] with pytest.raises(IndexError, match='No energy levels available for Fe 1'): ion[0]
def test_missing_abundance(hdf5_dbase_root): ion = fiasco.Ion('Li 1', temperature, abundance_filename='sun_coronal_1992_feldman', hdf5_dbase_root=hdf5_dbase_root) with pytest.raises(KeyError): _ = ion.abundance
def __init__(self, element_name, temperature: u.K, hdf5_path=None, **kwargs): self.temperature = temperature if type(element_name) is str: element_name = element_name.capitalize() self.atomic_symbol = plasmapy.atomic.atomic_symbol(element_name) self.atomic_number = plasmapy.atomic.atomic_number(element_name) self.element_name = plasmapy.atomic.element_name(element_name) if hdf5_path is None: self.hdf5_dbase_root = fiasco.defaults['hdf5_dbase_root'] else: self.hdf5_dbase_root = hdf5_path ion_kwargs = kwargs.get('ion_kwargs', {}) ion_kwargs['hdf5_path'] = self.hdf5_dbase_root chianti_ions = fiasco.DataIndexer(self.hdf5_dbase_root, self.atomic_symbol.lower()).fields ion_list = [] for i in range(self.atomic_number + 1): ion = f'{self.atomic_symbol.lower()}_{i+1}' if ion in chianti_ions: ion_list.append( fiasco.Ion(f'{self.atomic_symbol} {i+1}', temperature, **ion_kwargs)) super().__init__(*ion_list)
def test_scalar_density(hdf5_dbase_root): ion = fiasco.Ion('H 1', temperature, hdf5_dbase_root=hdf5_dbase_root) pop = ion.level_populations(1e8 * u.cm**-3) assert pop.shape == ion.temperature.shape + ( 1, ) + ion._elvlc['level'].shape # This value has not been checked for correctness np.testing.assert_allclose(pop[0, 0, 0], 0.9965048292729177)
def test_scalar_temperature(hdf5_dbase_root): ion = fiasco.Ion('H 1', 1 * u.MK, hdf5_dbase_root=hdf5_dbase_root) ioneq = ion.ioneq assert ioneq.shape == (1, ) t_data = ion._ioneq[ion._dset_names['ioneq_filename']]['temperature'] ioneq_data = ion._ioneq[ ion._dset_names['ioneq_filename']]['ionization_fraction'] i_t = np.where(t_data == ion.temperature) np.testing.assert_allclose(ioneq, ioneq_data[i_t])
def __init__(self, element_name, temperature: u.K, **kwargs): if type(element_name) is str: element_name = element_name.capitalize() Z = plasmapy.particles.atomic_number(element_name) ion_list = [] for i in range(Z + 1): ion = fiasco.Ion(f'{Z} {i+1}', temperature, **kwargs) ion_list.append(ion) super().__init__(*ion_list)
def test_spectrum_no_valid_ions(hdf5_dbase_root): # Consider the case of an collection with ions with no spectral information c2 = fiasco.IonCollection( fiasco.Ion('H 2', 1 * u.MK, hdf5_dbase_root=hdf5_dbase_root)) with pytest.warns(UserWarning, match='No transition data available for H 2'): with pytest.raises( ValueError, match= 'No collision or transition data available for any ion in collection.' ): c2.spectrum(1e9 * u.cm**-3, 1e29 * u.cm**-5)
def proton_electron_ratio(temperature: u.K, **kwargs): """ Calculate ratio between proton and electron densities as a function of temperature according to Eq. 7 of [1]_. Parameters ---------- temperature : `~astropy.units.Quantity` See Also -------- fiasco.Ion : Accepts same keyword arguments for setting database and dataset names References ---------- .. [1] Young, P. et al., 2003, ApJS, `144 135 <http://adsabs.harvard.edu/abs/2003ApJS..144..135Y>`_ """ h_2 = fiasco.Ion('H +1', temperature, **kwargs) numerator = h_2.abundance * h_2._ioneq[ h_2._dset_names['ioneq_filename']]['ionization_fraction'] denominator = u.Quantity(np.zeros(numerator.shape)) for el_name in list_elements(h_2.hdf5_dbase_root): el = fiasco.Element(el_name, temperature, **kwargs) abundance = el.abundance if abundance is None: warnings.warn( f'Not including {el.atomic_symbol}. Abundance not available.') continue for ion in el: ioneq = ion._ioneq[ ion._dset_names['ioneq_filename']]['ionization_fraction'] if ioneq is None: warnings.warn( f'Not including {ion.ion_name}. Ionization fraction not available.' ) continue denominator += ioneq * abundance * ion.charge_state ratio = numerator / denominator interp = interp1d( ion._ioneq[ion._dset_names['ioneq_filename']]['temperature'].value, ratio.value, kind='linear', bounds_error=False, fill_value=(ratio[0], ratio[-1])) return u.Quantity(interp(temperature))
def from_asdf(cls, filename): """ Restore `EmissionModel` instance from an ASDF file """ with asdf.open(filename, mode='r', copy_arrays=True) as af: temperature = af.tree['temperature'] density = af.tree['density'] ions = af.tree['ions'] dset_names = af.tree['dset_names'] emissivity_table_filename = af.tree['emissivity_table_filename'] ions = [ fiasco.Ion(ion, temperature, **ds) for ion, ds in zip(ions, dset_names) ] em_model = cls(density, *ions) em_model.emissivity_table_filename = emissivity_table_filename return em_model
def test_repr_scalar_temp(ion, hdf5_dbase_root): assert 'Fe 5' in fiasco.Ion('Fe 5', 1e6 * u.K, hdf5_dbase_root=hdf5_dbase_root).__repr__()
def fe10(hdf5_dbase_root): return fiasco.Ion('Fe 10', temperature, hdf5_dbase_root=hdf5_dbase_root)
def test_create_ion_with_wrong_units_raises_unit_conversion_error( hdf5_dbase_root): with pytest.raises(u.UnitsError): fiasco.Ion('Fe 5', temperature.value * u.s, hdf5_dbase_root=hdf5_dbase_root)
############################################################# # Plot the wavelength response plt.plot(ch.wavelength, response) plt.xlim(ch.channel + [-4, 4] * u.angstrom) plt.axvline(x=ch.channel, ls='--', color='k') plt.title(f'{ch.channel.to_string(format="latex")} Wavelength Response') plt.show() ############################################################ # Next, we construct for the `~fiasco.Ion` object for Fe 18. Note # that we choose to use the coronal abundances of # `Feldman et al. (1992) <https://ui.adsabs.harvard.edu/abs/2012SoPh..275...41B/>`_. temperature = 10.**(np.arange(4.5, 8, 0.05)) * u.K fe18 = fiasco.Ion('Fe 18', temperature, abundance_filename='sun_coronal_1992_feldman') ############################################################ # Compute contribution function, # # .. math:: G(n,T,\lambda) = 0.83\mathrm{Ab}\frac{hc}{\lambda}N_{\lambda}A_{\lambda}f\frac{1}{n} # # for each transition of Fe 18 at a single density. # `~fiasco.Ion.contribution_function` also accepts an array of # densities, but this requires significantly more computation. g = fe18.contribution_function(1e9 * u.cm**(-3), include_protons=False) ############################################################ # Get the corresponding transition wavelengths transitions = fe18.transitions.wavelength[~fe18.transitions.is_twophoton]
def test_contains(collection, hdf5_dbase_root): assert 'H 1' in collection assert 'hydrogen 1' in collection assert 'hydrogen +0' in collection ion = fiasco.Ion('H 1', temperature, hdf5_dbase_root=hdf5_dbase_root) assert ion in collection
def another_ion(hdf5_dbase_root): return fiasco.Ion('Ca 2', temperature, hdf5_dbase_root=hdf5_dbase_root)
def test_no_elvlc_raises_index_error(hdf5_dbase_root): with pytest.raises(IndexError): fiasco.Ion('H 2', temperature, hdf5_dbase_root=hdf5_dbase_root)[0]
def test_missing_ip(): ion = fiasco.Ion('Fe 27', temperature) assert ion.ip is None
def test_missing_abundance(): ion = fiasco.Ion('Li 1', temperature, abundance_filename='sun_coronal_1992_feldman') assert ion.abundance is None
def test_no_elvlc_raises_index_error(): with pytest.raises(IndexError): fiasco.Ion('Cr 1', temperature)[0]
def another_ion(): return fiasco.Ion('Fe 6', temperature)
def ion(): return fiasco.Ion('Fe 5', temperature)
def ion(hdf5_dbase_root): return fiasco.Ion('Fe 2', temperature, hdf5_dbase_root=hdf5_dbase_root)
def test_missing_abundance(hdf5_dbase_root): ion = fiasco.Ion('Li 1', temperature, abundance_filename='sun_coronal_1992_feldman', hdf5_dbase_root=hdf5_dbase_root) assert ion.abundance is None
def collection(hdf5_dbase_root): return fiasco.IonCollection( fiasco.Ion('H 1', temperature, hdf5_dbase_root=hdf5_dbase_root), fiasco.Ion('He 2', temperature, hdf5_dbase_root=hdf5_dbase_root))
def test_missing_ip(hdf5_dbase_root): ion = fiasco.Ion('Fe 27', temperature, hdf5_dbase_root=hdf5_dbase_root) assert ion.ip is None
def test_create_ion_without_units_raises_units_error(): with pytest.raises(TypeError): fiasco.Ion('Fe 5', temperature.value)
def test_create_ion_without_units_raises_units_error(hdf5_dbase_root): with pytest.raises(TypeError): fiasco.Ion('Fe 5', temperature.value, hdf5_dbase_root=hdf5_dbase_root)