The Atom class is equipped with method which give access to the populations, emissivities, and other atomic quantities:
In [1]:
import pyneb as pn
O3 = pn.Atom('O', 3)
N2 = pn.Atom('N', 2)
S2 = pn.Atom('S', 2)
In [2]:
O3.getEnergy(4, unit='eV')
Out[2]:
In [3]:
O3.getStatWeight(level=4)
Out[3]:
In [4]:
O3.getPopulations(tem=1.0e4, den=1e2)
Out[4]:
In [5]:
O3.getPopulations(tem=1.5e4, den=1e2)
Out[5]:
In [6]:
O3.getPopulations(tem=1e4, den=1e2).sum()
Out[6]:
In [7]:
print('Critical densities')
print('N2' + ' '.join('{:8.2e}'.format(cd) for cd in N2.getCritDensity(tem=12000)))
print('O3' + ' '.join('{:8.2e}'.format(cd) for cd in O3.getCritDensity(tem=12000)))
In [8]:
O3.getEmissivity(tem=1e4, den=1e2, wave=5007) # in erg.s-1.cm3
Out[8]:
Wavelengths should be entered with enough precision to avoid confusion with nearby lines. Use printTransition to check if the transition selected by the code actually correponds to the one you intended:
In [9]:
O3.printTransition(5007)
getTransition is an abridged version which only returns the tuple of levels rather than an extended output, and is therefore apt to be used in scripts.
In [10]:
O3.getTransition(5007)
Out[10]:
Or you can explicitly use the levels corresponding to the transition:
In [11]:
O3.getEmissivity(tem=1e4, den=1e2, lev_i=4, lev_j=3)
Out[11]:
In the case of getEmissivity, tem and den can be arrays. In such a case, if they have different dimensions N and M, the function will return an array of NxM emissivities corresponding to all tem-den combinations; if both arrays have the same dimension, you can obtain the emissivities of either the NxN array of tem-den combinations as in the previous case, or of the 1D, N-length array obtained pairing tem and den element by element. This is controlled by the “product” parameter, the default being True (results is NxN matrix):
In [12]:
O3.getEmissivity([10000, 12000], [100, 500], 4, 2, product=True)
Out[12]:
In [13]:
O3.getEmissivity([10000, 12000], [100, 500], 4, 2, product=False)
Out[13]:
The Atom object also contains a method to compute the electron temperature or density given a line ratio:
In [14]:
O3.getTemDen(int_ratio=150., den=100., wave1=5007, wave2=4363)
Out[14]:
The keyword tem (or den) specifies the supplied value of the temperature (or density). Which quantity is computed (temperature or density) is determined by which quantity is provided to the method: if “den” is given, then “tem” is computed, and vice versa.
If the intensity ratio is a simple ratio of two transitions, you can:
In [15]:
O3.getTemDen(0.02, den=1.e4, wave1=4363, wave2=5007)
Out[15]:
In [16]:
O3.getTemDen(0.02, den=1.e4, lev_i1=5, lev_j1=4, lev_i2=4, lev_j2=3)
Out[16]:
In the general case of an intensity ratio formed by any number of transitions, an algebraic expression must be supplied as the argument of the keyword to_eval:
In [17]:
O3.getTemDen(0.02, den=1.e4, to_eval="I(5, 4) / (I(4, 3) + I(4, 2))" )
Out[17]:
In [18]:
N2.getTemDen(150., den=100., to_eval = "(L(6584) + L(6548)) / L(5755)")
Out[18]:
The to_eval argument accepts either I(i, j) or L(wavelength) to identify the transitions involved in the diagnostic. Both can be mixed in the same string. If you do not know what transition corresponds to a given wavelength, use printTransition to find it.
The parameters tem and den, as well as the line ratio, may be arrays (1D or 2D, as in the case of observations obtained from IFUs), in which case the result will have the same shape. Some restrictions can be set to the domain explored by the method when looking for the solution; see the method's documentation for further details.
In [19]:
O3.getTemDen([0.015, 0.019], den=[1.e4, 1.1e4], to_eval="I(5, 4) / (I(4, 3) + I(4, 2))")
Out[19]:
In [20]:
O3.getTemDen([0.015, 0.019], den=1.e4, to_eval="I(5, 4) / (I(4, 3) + I(4, 2))")
Out[20]:
Notice that if you want to simultaneously determine both temperature and density combining two diagnostics (from two different atoms), you need to use the getCrossTemDen method of the Diagnostic class
Example of use in the case of density determination:
In [21]:
S2.getTemDen(1.1, tem = 1e4, wave1=6730, wave2 = 6716)
Out[21]:
The ionic abundance is obtained from the intensity of a line normalized to Hbeta=100.
In [22]:
O3.getIonAbundance(int_ratio=127, tem=1.5e4, den=100., wave=5007)
Out[22]:
In [23]:
S2.getIonAbundance(int_ratio=72, tem=1.5e4, den=100., to_eval='L(6716)+L(6731)')
Out[23]:
The ionic abundance from recombination lines is treated below
You can define all the atoms at once and put them in a dictionary by creating each atom at a time through the commands:
In [24]:
O3 = pn.Atom('O', '3')
O2 = pn.Atom('O', '2')
N2 = pn.Atom('N', '2')
or rather use one of the following shortcuts:
In [25]:
atoms = pn.getAtomDict() # a method always requires parenthesis, even without argument
In [26]:
atoms # All the available atoms
Out[26]:
It is also possible to select only a subset of the elements or ions available by specifying the arguments elem_list or atom_list:
In [27]:
print(len(atoms))
In [28]:
atoms = pn.getAtomDict(elem_list=['C', 'N', 'O']) # all the ions with spectra from 1 to 6 are created
In [29]:
atoms # All the CNO available atoms
Out[29]:
In [30]:
atoms = pn.getAtomDict(atom_list=['O2', 'O3', 'Ar3', 'N2'])
In [31]:
atoms
Out[31]:
In all these cases, a dictionary is created whose keys are the conventional atom names $<$element$><$spectrum$>$, and the corresponding entries the atoms themselves; e. g.:
In [32]:
atoms['N2']
Out[32]:
In [33]:
atoms['N2'].getEmissivity(tem=1e4, den=1e2, wave=6584) # example of use
Out[33]:
This can be useful if you need to loop on a list of atoms, to plot atomic data for example. To see what atoms have been created (which is limited by the data included in the selected atomic data set), enter:
In [34]:
atoms.keys()
Out[34]:
If you want to be able to access them directly rather than through a dictionary, input from the command line:
In [35]:
for key in atoms.keys():
vars()[key]=atoms[key]
and then you will be able to do the following:
In [36]:
Ar3.NLevels
Out[36]: