def test_abundance(): # Float value _tmp_ion = ion(test_ion,abundance=0.01,setup=False) assert _tmp_ion.Abundance==0.01 # FIXME: if setting custom abundance, AbundanceName should not be set, but right # now it is by the proton/electron density ratio calculation. # Custom filename _tmp_ion = ion(test_ion,abundance='sun_coronal_2012_schmelz',setup=False) assert _tmp_ion.AbundanceName=='sun_coronal_2012_schmelz' abundance = ch_tools.io.abundanceRead(abundancename='sun_coronal_2012_schmelz') assert _tmp_ion.Abundance==abundance['abundance'][_tmp_ion.Z-1]
def test_abundance(): # Float value _tmp_ion = ion(test_ion, temperature = temperature_1, eDensity = density_1, abundance=0.01, setup=False) assert _tmp_ion.Abundance == 0.01 # FIXME: if setting custom abundance, AbundanceName should not be set, but right # now it is by the proton/electron density ratio calculation. # Custom filename _tmp_ion = ion(test_ion, temperature = temperature_1, eDensity = density_1, abundance='sun_coronal_2012_schmelz', setup=False) assert _tmp_ion.AbundanceName == 'sun_coronal_2012_schmelz' abundance = ch_tools.io.abundanceRead(abundancename='sun_coronal_2012_schmelz') assert _tmp_ion.Abundance == abundance['abundance'][_tmp_ion.Z-1]
def print_elvlc(ion="c_4"): """ Print out values of information in the Elvlc file that might be used """ x = ch.ion(ion, temperature=1e5) imax = len(x.Elvlc["lvl"]) print(imax) i = 0 while i < imax: if x.Elvlc["l"][i] % 2 == 1: p = 1 else: p = 0 islp = x.Elvlc["spin"][i] * 100 + x.Elvlc["l"][i] * 10 + p e = x.Ip - x.Elvlc["erydth"][i] * 13.605693009 pretty = x.Elvlc["pretty"][i] pretty = pretty.replace(" ", "_") print("%2d %10s %d %s %d %5.1f %5.1f %15s %3d %10.5f" % ( x.Elvlc["lvl"][i], x.Elvlc["term"][i], x.Elvlc["spin"][i], x.Elvlc["spd"][i], x.Elvlc["l"][i], x.Elvlc["j"][i], x.Elvlc["mult"][i], pretty, islp, e, )) i += 1
def doIonQ(inQueue, outQueue): """ Multiprocessing helper for `ChiantiPy.core.ion` and `ChiantiPy.core.ion.twoPhoton` Parameters ----------- inQueue : `~multiprocessing.Queue` Jobs queued up by multiprocessing module outQueue : `~multiprocessing.Queue` Finished jobs """ for inpts in iter(inQueue.get, 'STOP'): ionS = inpts[0] temperature = inpts[1] density = inpts[2] wavelength = inpts[3] wvlRange = [wavelength.min(), wavelength.max()] filter = inpts[4] allLines = inpts[5] abund = inpts[6] em = inpts[7] doContinuum = inpts[8] thisIon = ch.ion(ionS, temperature, density, abundance=abund) thisIon.intensity(wvlRange = wvlRange, allLines = allLines, em=em) if 'errorMessage' not in sorted(thisIon.Intensity.keys()): thisIon.spectrum(wavelength, filter=filter) outList = [ionS, thisIon] if not thisIon.Dielectronic and doContinuum: if (thisIon.Z - thisIon.Ion) in [0, 1]: thisIon.twoPhoton(wavelength) outList.append(thisIon.TwoPhoton) outQueue.put(outList) return
def get_phot(ion="c_4"): """ Obtain the photoionization x-sectons from TopBase. This routine uses normal astronomical terminology, that is CIV would be element 6 and ion 4 First check if we already have the data, and if not retrieve it Note that the TopBase file names are based on the element number and the number of electrons that the ion of interest has, but we convert to astronomical notation in this routine """ x = ch.ion(ion, temperature=1e5) nelec = x.Z - x.Ion + 1 fileroot = "p%02d.%02d" % (x.Z, nelec) outroot = "p%02d.%02d" % (x.Z, x.Ion) print("Looking for ", fileroot) if os.path.isfile("%s.txt" % outroot): print("TopBase Phot file for element %d and ion %d exists" % (x.Z, x.Ion)) return os.system("wget cdsweb.u-strasbg.fr/topbase/p/%s.gz" % (fileroot)) os.system("gunzip %s.gz" % (fileroot)) os.system("mv %s %s.txt" % (fileroot, outroot)) print( "TopBase Phot file for element %s and ion %d has now been retrieved" % (x.Z, x.Ion)) return
def rec_rate(network): ion = ch.ion(ion_name, temperature=network.T) # for some reason, the latest chiantipy # failed to update the tempeature for fully ionized ion.Temperature = network.T ion.recombRate() vals = ion.RecombRate['rate'] return vals
def test_temperature_density(): # TODO: test case where neither are set/ one or the other is not set # Two single values _tmp_ion = ion(test_ion, temperature=temperature_1, eDensity=density_1, setup=True) assert _tmp_ion.Temperature == np.array(temperature_1) assert _tmp_ion.EDensity == np.array(density_1) # Multiple temperatures, one density _tmp_ion = ion(test_ion, temperature=temperature_2, eDensity=density_1, setup=True) assert np.all(_tmp_ion.Temperature == temperature_2) assert np.all(_tmp_ion.EDensity == np.array(temperature_2.size * [density_1])) # One temperature, multiple densities _tmp_ion = ion(test_ion, temperature=temperature_1, eDensity=density_2, setup=True) assert np.all(_tmp_ion.Temperature == np.array(density_2.size * [temperature_1])) assert np.all(_tmp_ion.EDensity == density_2) # Two equal-sized temperature and density arrays _tmp_ion = ion(test_ion, temperature=temperature_2, eDensity=density_2, setup=True) assert np.all(_tmp_ion.Temperature == temperature_2) assert np.all(_tmp_ion.EDensity == density_2) # Two unequal sized temperature and density arrays with pytest.raises( ValueError, message= '''Expecting ValueError when temperature and density are not of equal size.'''): _tmp_ion = ion(test_ion, temperature=temperature_2, eDensity=density_3, setup=True)
def ion_rate(network): ion = ch.ion(ion_name, temperature=network.T) try: ion.ionizRate() except AttributeError: print(f"{ion_name} is not defined in ChiantiPy master list") print(f"manually adding temperature to {ion_name}_ion") ion.Temperature = network.T ion.NTempDens = len(network.T) ion.ionizRate() vals = ion.IonizRate['rate'] return vals
def test_temperature_density(): # TODO: test case where neither are set/ one or the other is not set # Two single values _tmp_ion = ion(test_ion,temperature=temperature_1,eDensity=density_1,setup=False) assert _tmp_ion.Temperature==np.array(temperature_1) assert _tmp_ion.EDensity==np.array(density_1) # Multiple temperatures, one density _tmp_ion = ion(test_ion,temperature=temperature_2,eDensity=density_1,setup=False) assert np.all(_tmp_ion.Temperature==temperature_2) assert np.all(_tmp_ion.EDensity==np.array(temperature_2.size*[density_1])) # One temperature, multiple densities _tmp_ion = ion(test_ion,temperature=temperature_1,eDensity=density_2,setup=False) assert np.all(_tmp_ion.Temperature==np.array(density_2.size*[temperature_1])) assert np.all(_tmp_ion.EDensity==density_2) # Two equal-sized temperature and density arrays _tmp_ion = ion(test_ion,temperature=temperature_2,eDensity=density_2,setup=False) assert np.all(_tmp_ion.Temperature==temperature_2) assert np.all(_tmp_ion.EDensity==density_2) # Two unequal sized temperature and density arrays with pytest.raises(ValueError, message='''Expecting ValueError when temperature and density are not of equal size.'''): _tmp_ion = ion(test_ion,temperature=temperature_2,eDensity=density_3,setup=False)
def match_line(ion_name, wvls, s_flux, tmax, density): # t = 10**((tmax - 0.3) + 0.001*np.arange(600)) lowtemp = 4.0 hightemp = 8.0 npoints = 1000 t = 10**(np.linspace(lowtemp, hightemp, npoints)) print("HERE WE GO") ion_n = ch.ion(ion_name, temperature=t, eDensity=density) print("LET'S GO") ion_n.gofnt(wvlRange=[min(wvls) - 1, max(wvls) + 1]) return ion_n.Gofnt
def old_e_measure(ion_name, wvls, s_flux, tmax, star_dist, star_radius, density): rs = 6.96e10 pc = 3.08567758e18 t = 10**((tmax - 0.3) + 0.001*np.arange(600)) ion_n = ch.ion(ion_name, temperature=t, eDensity=density) ion_n.gofnt(wvlRange=[min(wvls)-1,max(wvls)+1]) star_dist = star_dist*pc star_radius = star_radius*rs flux = s_flux*(star_dist/star_radius)**2.0 print('ANYONE THERE?!') quit() ion_n.Gofnt['emeasure'] = (flux/density) / (2*np.pi*ion_n.Gofnt['gofnt']) return ion_n.Gofnt
def old_find_tm(ion_name): h = 6.626068e-34 c = 299792458 k = 1.3806503e-23 ion_state = int(ion_name.rsplit('_')[1]) t = 10**(3.8+ 0.01*np.arange(400)) ion = ch.ion(ion_name, temperature=t) ioneq = ion.IoneqOne W = h*c*ion.Elvlc['ecm'][ion_state - 1]*100 gt = ioneq*(t**-0.5)*np.exp(-W/(k*t)) tm = t[np.argmax(gt)] return np.log10(tm)
def sum_match_lines(ion_name, wvls, t, density, search_width=1.0): ion_n = ch.ion(ion_name, temperature=t, eDensity=density) intensity = t.copy() * 0.0 print(wvls) for wvl in wvls: # ion_n.intensity(wvlRange=[min(wvls)-search_width,max(wvls)+search_width]) ion_n.intensity() if wvl in (ion_n.Intensity['wvl']): intensity_s = ion_n.Intensity['intensity'][:, ( ion_n.Intensity['wvl'] == wvl)] intensity += np.array(intensity_s.T[0]) print('match') else: print('Something is wrong - cannot find matching line! for {} {}'. format(ion_name, wvl)) intensity += 0 return intensity
from ChiantiPy.core import ion,ioneq import ChiantiPy.tools as ch_tools # use an ion with relatively small chianti files test_ion = 'fe_15' # TODO: probably should check a few different ions, i.e. dielectronic, some without certain kinds # files, etc. # set a few temperature and density arrays temperature_1 = 1e+6 temperature_2 = np.logspace(5,8,20) density_1 = 1e+9 density_2 = np.logspace(5,8,20) density_3 = np.logspace(5,8,21) # setup an ion object to reuse in several tests tmp_ion = ion(test_ion,temperature=temperature_2,eDensity=density_2) #Check various ways to specify the temperature and density def test_temperature_density(): # TODO: test case where neither are set/ one or the other is not set # Two single values _tmp_ion = ion(test_ion,temperature=temperature_1,eDensity=density_1,setup=False) assert _tmp_ion.Temperature==np.array(temperature_1) assert _tmp_ion.EDensity==np.array(density_1) # Multiple temperatures, one density _tmp_ion = ion(test_ion,temperature=temperature_2,eDensity=density_1,setup=False) assert np.all(_tmp_ion.Temperature==temperature_2) assert np.all(_tmp_ion.EDensity==np.array(temperature_2.size*[density_1])) # One temperature, multiple densities _tmp_ion = ion(test_ion,temperature=temperature_1,eDensity=density_2,setup=False)
def chianti_excitation_rates_fn(chianti_string, temps, eDens, no_levels): """ now we need to load in the Chianti data for CaII """ chianti_ion = ch.ion(chianti_string, temperature=temps, eDensity=eDens) chianti_ion.upsilonDescale() lower_lvl_index = chianti_ion.Scups["lvl1"] upper_lvl_index = chianti_ion.Scups["lvl2"] exRates = chianti_ion.Upsilon["exRate"] dexRates = chianti_ion.Upsilon["dexRate"] # squeeze the ex and dex lists as they are multi-D but really are 1D exRates = np.squeeze(exRates) dexRates = np.squeeze(dexRates) chianti_ion_collision_df = pd.DataFrame( { "lower_lvl": lower_lvl_index, "upper_lvl": upper_lvl_index, "Chianti_exRate": exRates, "Chianti_dexRate": dexRates, } ) # print(chianti_ion_collision_df) indexes = chianti_ion_collision_df[ chianti_ion_collision_df["upper_lvl"] > no_levels ].index # print(indexes) chianti_ion_collision_df = chianti_ion_collision_df.drop(indexes.values) # print(chianti_ion_collision_df) # building df from Chianti for the wavelength, gf, A-values for transitions wgfa_lower_lvl = chianti_ion.Wgfa["lvl1"] wgfa_upper_lvl = chianti_ion.Wgfa["lvl2"] wgfa_lambda = chianti_ion.Wgfa["wvl"] wgfa_A = chianti_ion.Wgfa["avalue"] chianti_ion_transition_df = pd.DataFrame( { "lower_lvl": wgfa_lower_lvl, "upper_lvl": wgfa_upper_lvl, "Chianti_lambda(AA)": wgfa_lambda, "Chianti_A-value(s-1)": wgfa_A, } ) # print(chianti_ion_transition_df) indexes = chianti_ion_transition_df[ chianti_ion_transition_df["upper_lvl"] > no_levels ].index # print(indexes) chianti_ion_transition_df = chianti_ion_transition_df.drop(indexes.values) # print(chianti_ion_transition_df) chianti_ion_df = pd.merge( chianti_ion_collision_df, chianti_ion_transition_df, on=["lower_lvl", "upper_lvl"], how="left", ) # print(chianti_ion_df) # later on, our code will crash if we don't have an entry in chianti_ion_df # for every downward transition, so here we append any missing ones to the # end of the df, and fill with zeros for ii in range(no_levels): # column no./initial level for jj in range(no_levels): # row no./final level # the indices will be 1 less than Chianti level indices if ii < jj: # checking whether the downward transition exists in # chianti_ion_df if ( any( (chianti_ion_df.lower_lvl == ii + 1) & (chianti_ion_df.upper_lvl == jj + 1) ) is False ): # print("we don't have a line for this transition:", # ii + 1, jj + 1) chianti_ion_df.loc[len(chianti_ion_df)] = 0 chianti_ion_df.lower_lvl.loc[len(chianti_ion_df) - 1] = ( ii + 1 ) chianti_ion_df.upper_lvl.loc[len(chianti_ion_df) - 1] = ( jj + 1 ) # print(chianti_ion_df) return (chianti_ion, chianti_ion_df)
def doit(atom="h_1", nlev=10): """ Do something magnificent Description: Notes: History: """ nlev = int(nlev) xion = ch.ion(atom, temperature=1e5) xlevels = get_levels(atom, nlev) # If we could not find the number of levels # requested, reduce the number so that the # rest of the routines will not generate more comments on this if len(xlevels) < nlev: nlev = len(xlevels) # Find the ionization potential of lower ionization # states as well ex_offset = 0 i = 1 while i < xion.Ion: words = atom.split("_") element_string = "%s_%d" % (words[0], i) xx = ch.ion(element_string, 1e5) ex_offset += xx.Ip i += 1 xlevels.add_row([ "LevMacro", xion.Z, xion.Ion + 1, 1, 0.00000, xion.Ip + ex_offset, 1, 1.00e21, "Next", 0, 0, ]) xlevels.write(atom + "_levels.dat", format="ascii.fixed_width_two_line", overwrite=True) xlines = get_lines(atom, nlev) xlines.write(atom + "_lines.dat", format="ascii.fixed_width_two_line", overwrite=True) get_phot(atom) make_phot(atom) write_phot(atom) xcol = get_collisions(atom, nlev) return
import ChiantiPy.core as ch import numpy as np import ChiantiPy.tools.filters as chfilters import matplotlib.pyplot as plt t = 10.**(3.84 + 0.05 * np.arange(8.)) H1 = ch.ion('h_1', temperature=t, eDensity=1.e+14, em=1.e+27) H1.popPlot(top=10) H1.intensityPlot(wvlRange=[6564, 6565], linLog='log', index=4, top=10) H1.intensityList(wvlRange=[4000, 7000], index=4, top=10) plt.show(H1) H1a = ch.ioneq(1) H1a.load() H1a.plot() #plt.xlim(0,3e4) plt.tight_layout() plt.show(H1a)
def get_levels(ion="h_1", nlevels=10): """ Extract the information needed to write out the the levels file, and return it as an astropy Table. Note: In Keara's notes, she derives the multiplicity from J, but the multiplicity can be accessed directly This returns the information needed to write out a level file. Depending on whether one plans to include more ions, one needs to add a dummy line for the next ion up for the purposes of created a full data set. The excitation energy has to be conistent across ions Python can read the astropy table for levels directly, so normally one would write this to a file """ x = ch.ion(ion, temperature=1e5) First_Ion_Pot = x.Ip # Find the ionization potential of lower ionization # states as well ex_offset = 0 i = 1 while i < x.Ion: words = ion.split("_") element_string = "%s_%d" % (words[0], i) xx = ch.ion(element_string, 1e5) ex_offset += xx.Ip i += 1 n = 0 lvl = [] rad_rate = [] ex_energy = [] g = [] ion_pot = [] islp = [] configuration = [] if len(x.Elvlc["lvl"]) < nlevels: print("There are only %d levels, not %d as requested" % (len(x.Elvlc["lvl"]), nlevels)) nlevels = len(x.Elvlc["lvl"]) while n < nlevels: lv = x.Elvlc["lvl"][n] lvl.append(lv) if lv == 1: rad_rate.append(1e21) else: rad_rate.append(1e-9) # Calculate the parity. Note that one cannot calculate the parity from # L in LS coupling. It is calculated from the the indidual l's of the # electrons in unfilled shells. It is given by the number of electrons # in the p, f, or h orbitals, so for a term of 2s2p3, which means you 1 # electorn in the 2s state and 3 in the 2p state, you count to 3, and # this has odd parity, which is 1 in our notation. This information is # contained in the term term = x.Elvlc["term"][n] xterm = list(term) j = 0 num = 0 while j < len(xterm): if xterm[j] == "p" or xterm[j] == "f" or xterm[j] == "h": try: delta = int(xterm[j + 1]) except: delta = 1 num += delta j += 1 # print('%14s %2d' % (term,num)) parity = num % 2 # if x.Elvlc["l"][n] % 2 == 1: # p = 1 # else: # p = 0 xislp = x.Elvlc["spin"][n] * 100 + x.Elvlc["l"][n] * 10 + parity islp.append(xislp) ex = x.Elvlc["ecm"][n] / 8065.5 ex_energy.append(ex) # g.append(x.Elvlc['j'][n]*2+1) g.append(x.Elvlc["mult"][n]) ion_pot.append(-(First_Ion_Pot - ex)) pretty = x.Elvlc["pretty"][n] pretty = pretty.replace(" ", "_") configuration.append(pretty) n += 1 # Before setting up the table add the offset to ex ex_energy = np.array(ex_energy) + ex_offset xtab = Table( [lvl, ion_pot, ex_energy, g, rad_rate, configuration, islp], names=["lvl", "ion_pot", "ex", "g", "rad_rate", "config", "islp"], ) xtab["Element"] = x.Z xtab["Ion"] = x.Ion xtab["Dtype"] = "LevMacro" xxtab = xtab["Dtype", "Element", "Ion", "lvl", "ion_pot", "ex", "g", "rad_rate", "config", "islp", ] xxtab["ion_pot"].format = ".6f" xxtab["ex"].format = ".6f" # Now try to set up the TopBass Ilv for this file # The approach here is to use the absolute value of the # difference in the energy, but this may not be ideal. qslp = np.unique(xxtab["islp"]) xxtab["ilv"] = -99 # for q in qslp: # i = 0 # n = 0 # e_old = 0 # while i < len(xxtab): # if xxtab["islp"][i] == q: # if n == 0: # e_old = xxtab["ex"][i] # n += 1 # elif abs(xxtab["ex"][i] - e_old) < 0.1: # pass # else: # e_old = xxtab["ex"][i] # n += 1 # xxtab["ilv"][i] = n # i += 1 # This is an alternative, which simply assumes that # All of the sublevels are displayed at once # xxtab["ilv"] = -99 # for q in qslp: # i = 0 # n = 0 # while i < len(xxtab): # if xxtab["islp"][i] == q: # if n==0: # i_old=i # n+=1 # elif i_old+1==i: # i_old=i # else: # i_old=i # n+=1 # xxtab["ilv"][i] = n # i+=1 # Use the term to idenfify all of the sublevels that are associated with # one topbase level. This approach assumes that all fo the sublevels assoicated # with a single level are contiguous in the Elvlc dictionary. for q in qslp: i = 0 n = 0 term_old = "" while i < len(xxtab): if xxtab["islp"][i] == q: if n == 0: term_old = x.Elvlc["term"][i] n += 1 elif x.Elvlc["term"][i] == term_old: pass else: term_old = x.Elvlc["term"][i] n += 1 xxtab["ilv"][i] = n i += 1 return xxtab
import ChiantiPy.core as ch for s in (ion_by_ion.required_species): print(s, type(s)) if start_neutral: for s in ion_by_ion.required_species: if getattr(s, 'free_electrons', -1) == 0: init_values[s.name] = init_array.copy() else: init_values[s.name] = X * init_array # Scale to solar abundances if s.name not in ['de', 'ge']: ion_name = s.name.lower() ion = ch.ion(ion_name, temperature=init_values['T']) init_values[s.name] *= ion.Abundance init_values['de'][:] = 1e-30 init_values = ion_by_ion.convert_to_mass_density(init_values) else: # start CIE for s in sorted(ion_by_ion.required_species): if s.name != 'ge': if s.name == 'de': continue else: ion_name = s.name.lower() ion = ch.ion(ion_name, temperature=init_values['T']) print(ion_name)
__author__ = 'Wayne Green' __version__ = '0.1' ############################################################################## # Main # Regression Tests ############################################################################## # HEREHEREHERE if __name__ == "__main__": opts = optparse.OptionParser(usage="%prog "+__doc__) opts.add_option("-v", "--verbose", action="store_true", dest="verboseflag", default=False, help="<bool> be verbose about work.") (options, args) = opts.parse_args() #if(len(args) == 0 ): args.append(None) t = 10.**(5.8 + 0.05*np.arange(21.)) fe14 = ch.ion('fe_14', temperature=t, eDensity=1.e+9, em=1.e+27) fe14.popPlot()
import ChiantiPy.tools as ch_tools # use an ion with relatively small chianti files #test_ion = 'fe_15' # want an ion with auto-ionization rates test_ion = 'o_6' # TODO: probably should check a few different ions, i.e. dielectronic, some without certain kinds # files, etc. # set a few temperature and density arrays temperature_1 = 1e+6 temperature_2 = np.logspace(5, 8, 20) density_1 = 1e+9 density_2 = np.logspace(5, 8, 20) density_3 = np.logspace(5, 8, 21) # setup an ion object to reuse in several tests tmp_ion = ion(test_ion, temperature=temperature_2, eDensity=density_2) # Check various ways to specify the temperature and density def test_temperature_density(): # TODO: test case where neither are set/ one or the other is not set # Two single values _tmp_ion = ion(test_ion, temperature=temperature_1, eDensity=density_1, setup=True) assert _tmp_ion.Temperature == np.array(temperature_1) assert _tmp_ion.EDensity == np.array(density_1) # Multiple temperatures, one density _tmp_ion = ion(test_ion, temperature=temperature_2,
def get_lines(ion="h_4", nlevels=10): """ Given an astropy table that contains all of the levels, get the associated line information. Notes: This routine calls get_lev to decide which lines to retrieve so that it only produces a table with lines for which levels are known There are some lines in the Chianti database that have 0 wavelength. These are all strictly forbidden lines, but Python still needs a wavelength to calculate the collision x-section in the absence of Burgess-style collision data, so we fill in the wavelength from the upper and lower level energies in this case, and issue a warning. """ lev = get_levels(ion, nlevels) # Next bit is duplicated if I decide to put into a single routine x = ch.ion(ion, temperature=1e5) # End of duplication wavelength = x.Wgfa["wvl"] lower = x.Wgfa["lvl1"] upper = x.Wgfa["lvl2"] gf = x.Wgfa["gf"] a = x.Wgfa["avalue"] xtab = Table([wavelength, lower, upper, gf, a], names=["Wave", "ll", "ul", "gf", "a"]) # xtab.info() select = [] gl = [] gu = [] el = [] eu = [] i = 0 for one in xtab: got_upper = False got_lower = False for one_level in lev: if one_level["lvl"] == one["ll"]: got_lower = True xgl = one_level["g"] xel = one_level["ion_pot"] if one_level["lvl"] == one["ul"]: got_upper = True xgu = one_level["g"] xeu = one_level["ion_pot"] if got_lower and got_upper: select.append(i) gl.append(xgl) gu.append(xgu) el.append(xel) eu.append(xeu) break # print(i,len(xtab)) i += 1 # print(select) xxtab = xtab[select] xxtab["gl"] = gl xxtab["gu"] = gu xxtab["f"] = xxtab["gf"] / xxtab["gl"] xxtab["el"] = x.Ip + el xxtab["eu"] = x.Ip + eu xxtab["el"].format = "10.6f" xxtab["eu"].format = "10.6f" xxtab["f"].format = "9.6f" xxtab["Dtype"] = "LinMacro" xxtab["z"] = lev["Element"][0] xxtab["ion"] = lev["Ion"][0] # Check for lines that have a Wavelength of 0 and if tis happens fix the # wavelegnth using el and eu, but issue a warning when you do this for one in xxtab: if one["Wave"] == 0: one["Wave"] = 12396.1914 / (one["eu"] - one["el"]) print( "Line with ll %d and ul %d is missing wavelength. Correcting to %.3f using el and eu" % (one["ll"], one["ul"], one["Wave"])) xxtab["Wave"].format = "10.3f" xxxtab = xxtab["Dtype", "z", "ion", "Wave", "f", "gl", "gu", "el", "eu", "ll", "ul"] return xxxtab
def __init__(self, ion_name): self.ion = ch.ion(ion_name) self._levels = None self._lines = None self._collisions = None
def make_phot(ion="c_4"): """ Read a retrieved TopBase file and make a Python-Photon file Note that althought the TopBase data on Vizier does not use astronomical notation, we changed the naming convention when we retrieved the files """ x = ch.ion(ion, temperature=1e5) z = x.Z xion = x.Ion fileroot = "p%02d.%02d" % (z, xion) try: x = open("%s.txt" % fileroot) lines = x.readlines() except: print("Error: %s.txt not found %s" % fileroot) return records = [] for line in lines: words = line.split() records.append(words) f = open("%s.dat" % fileroot, "w") # z=int(records[0][0]) # xion=int(records[0][1]) i = 1 num = 0 xsection = 1 while i < len(records): one_record = records[i] # print('test5',one_record) if len(one_record) == 4: # This is a new x-section # if i>1: # print('Number of x-sections %d' % num) h = records[i] # print(h) islp = h[0] + h[1] + h[2] if islp == "000": break ilv = h[3] i += 1 # print(records[i]) h = records[i] npts = int(h[1]) i += 1 h = records[i] ex = eval(h[0]) * 13.605693009 if ex == 0: xh = records[i + 1] ex = eval(xh[0]) * 13.605693009 print( "Warning: ex=0 for %d %d %s %s %d - changing to %10.6f" % (z, xion, islp, ilv, npts, ex)) string = "PhotTopS %d %d %s %s %10.6f %d" % (z, xion, islp, ilv, ex, npts) # string='PhotTop %d %d %d %d %d %d' % (z,xion,islp,ilv,ex,npts) # print(string) f.write("%s\n" % string) num = 0 xsection += 1 else: energy = eval(records[i][0]) * 13.605693009 xsection = eval(records[i][1]) * 1e-18 string = "Phot %10.6f %10.6e" % (energy, xsection) f.write("%s\n" % string) num += 1 i += 1 if i == len(records): print("Number of x-sections %d" % num) f.close() return
# array c_ori = np.ndarray(shape=(nstat, nte), dtype=np.float64) r_ori = np.ndarray(shape=(nstat, nte), dtype=np.float64) for ion in range(nstat): for ite in range(nte): c_ori[ion, ite] = 0 r_ori[ion, ite] = 0 # ionization ion loop for ion in range(1, nstat): ionstr = '{:d}'.format(ion) ionname = elemstr + ionstr #fe14 = ch.ion('fe_14',temperature=temperature,eDensity=1.e+9,em=1.e+27) ionicstruc = ch.ion(ionname, temperature=temperature, eDensity=1.e+9) ionicstruc.ionizRate() ionizrate = ionicstruc.IonizRate['rate'] #print(ionname) #print('ioniz', ionizrate) # save into arraies for ite in range(nte): c_ori[ion - 1, ite] = ionizrate[ite] # test negative value if ((ionizrate[ite] < -0.0) or (ionizrate[ite] >= 1.0)): print('Negative_ioniz', ion, ite, iatom, ionizrate[ite]) systime.sleep(40) # recombination ion loop
def write_phot(ion="c_4"): x = ch.ion(ion, temperature=1e5) xion = x.Ion z = x.Z fileroot = "p%02d.%02d" % (x.Z, x.Ion) # First strip of the headers of the phot_file try: phot = open(fileroot + ".dat") lines = xx = phot.readlines() except: print("Error: Could not open %s.dat" % fileroot) headers = [] i = 0 for one in xx: if one.count("PhotTopS"): word = one.split() word[0] = i word[1] = int(word[1]) word[2] = int(word[2]) word[3] = int(word[3]) word[4] = int(word[4]) word[5] = eval(word[5]) word[6] = int(word[6]) headers.append(word) i += 1 phot.close() # Now we have a set of records we can make into a table if we are clever headers = np.array(headers) xxhead = Table( headers, names=["Row", "Element", "Ion", "islp", "ilv", "e_thresh", "np"], dtype=["i", "i", "i", "i", "i", "f", "i"], ) xxhead.write("head.txt", format="ascii.fixed_width_two_line", overwrite=True) # xxhead.info() # Now find, if we can the parts of the photon file that match what we need lev_file = ion + "_levels.dat" try: lev = ascii.read(lev_file) except: print("Error: Could not open %s.dat" % lev_file) # lev.info() # In princple a join of some of this would allow us to find everything we need try: foo = join(lev, xxhead, keys=["Element", "Ion", "islp", "ilv"], join_type="left") except: print("Error: join failed") xxhead.info() lev.info() xxhead.write("head.txt", format="ascii.fixed_width_two_line", overwrite=True) lev.write("levels.txt", format="ascii.fixed_width_two_line", overwrite=True) foo.sort(["Ion", "lvl"]) foo["delta_e"] = foo["ion_pot"] + foo["e_thresh"] foo["delta_e"].format = "8.2f" foo.write(ion + "_lev2phot.txt", format="ascii.fixed_width_two_line", overwrite=True) # Now in principle we can write out the PhotFile output_file = ion + "_phot.dat" f = open(output_file, "w") for one in foo: if one["e_thresh"] > 0: xstring = "PhotMacS %2d %2d %2d %2d %10.6f %3d" % ( z, xion, one["lvl"], 1, one["e_thresh"], one["np"], ) f.write("%s\n" % xstring) i = int(one["Row"]) nphot = int(one["np"]) j = i + 1 jstop = j + nphot while j < jstop: xstring = "PhotMac 13.598430 6.3039999e-18" xstring = lines[j] xstring = xstring.replace("Phot", "PhotMac") f.write(xstring) j += 1 f.close()
#construct list of all partial ionisation stages for each element (i.e. h_1, he_1, he_2, c_1, ... ion_names = [ elem + '_' + str(ionstage + 1) for anum, elem in enumerate(elems, start=1) for ionstage in range(anum) ] # array of temperatures at which to evaluate the collisional ionisation rates temp = np.logspace(3, 5, 1000) # output temperatures in eV for consistency with other methods in spherical_cloudy kB = 1.3806488E-23 elvolt = 1.60217657E-19 eV_temp = temp * kB / elvolt # construct ChiantiPy objects for each ion under consideration ion_objs = [ch.ion(name, temperature=temp) for name in ion_names] out_data = np.zeros((len(temp), len(ion_names) + 1)) out_data[:, 0] = eV_temp for i, ion in enumerate(ion_objs): print('Getting ' + ion_names[i]) ion.ionizRate() # populate field in ChiantiPy object with the rates out_data[:, i + 1] = ion.IonizRate['rate'] # extract rates data np.savetxt('colioniz_chianti.dat', out_data, header='temp ' + ' '.join(ion_names)) #plt.figure() #plt.plot(np.log10(out_data[:,0]), np.log10(out_data[:,1:]))
def get_collisions(ion="h_1", nlev=20): """ Given a set of levels, get the collision information associatred with these levels. Note that as far as I can determine the scups file does not contain collisionl information for collisional ionization Currently in Python collisions are tightly tied to the lines that are going to be used in a dataset. The information about line information is used as a mechanism to identify the collision x-section. (This probably dates back to simple atoms, where lines are used for radiative transfer and levels are used in calculating densities of upper level states, but we don't really have a concept of an integrated atom) """ # Get the collision data x = ch.ion(ion, temperature=1e5) lower = x.Scups["lvl1"] upper = x.Scups["lvl2"] de = x.Scups["de"] gf = x.Scups["gf"] ntemp = x.Scups["ntemp"] btemp = x.Scups["btemp"] bscups = x.Scups["bscups"] lim = x.Scups["lim"] ttype = x.Scups["ttype"] cups = x.Scups["cups"] xtab = Table( [lower, upper, de, lim, ntemp, btemp, bscups, ttype, cups], names=[ "ll", "ul", "de", "lim", "ntemp", "btemp", "bscups", "ttype", "cups" ], ) npossible = 0 for one in xtab: if one["ul"] <= nlev: npossible += 1 xtab.write("T_cups.txt", format="ascii.fixed_width_two_line", overwrite=True) # Get the lines linetab = get_lines(ion=ion, nlevels=nlev) # linetab.info() linetab.write("T_lines.txt", format="ascii.fixed_width_two_line", overwrite=True) xxtab = join(xtab, linetab) xxtab.write("T_all.txt", format="ascii.fixed_width_two_line", overwrite=True) xxtab["gf"] = xxtab["gl"] * xxtab["f"] print( "There were %d (of %d) collision x-sections with nlev <= %d, and %d that matched %d lines" % (npossible, len(xtab), nlev, len(xxtab), len(linetab))) # xtab=Table([lower,upper,gf,ntemp,btemp,bscups],names=['ll','de','ul','gf','ntemp','btemp','bscups']) # xxtab.info() xout = open(ion + "_upsilon.dat", "w") for one in xxtab: # print(one) xstring = "CSTREN Line %3d %3d %10.3f %9.6f %2d %2d %10.6f %10.6f " % ( one["z"], one["ion"], one["Wave"], one["f"], one["gl"], one["gu"], one["el"], one["eu"], ) xstring = xstring + "%3d %3d %3d %3d %10.3e %10.3e %10.3e %3d %3d %10.3e" % ( one["ll"], one["ul"], one["ll"], one["ul"], one["de"], one["gf"], one["lim"], one["ntemp"], one["ttype"], one["cups"], ) # print(xstring) xout.write("%s\n" % xstring) xstring = "SCT " for one_temp in one["btemp"]: xstring = xstring + (" %10.3e" % one_temp) xout.write("%s\n" % xstring) xstring = "SCUPS " for one_bscup in one["bscups"]: xstring = xstring + (" %10.3e" % one_bscup) xout.write("%s\n" % xstring) xout.close() return xxtab