class TestLevel(): g = 2 E = 3 level = atomic_transition.Level(g=g,E=E,number=1) def test_LTE_level_pop(self): T = 50 Z = 3 lte_level_pop = self.level.LTE_level_pop(Z=Z,T=T) assert lte_level_pop == self.g*np.exp(-self.E/(constants.k*T))/Z shape = (5,5) T_array = np.ones(shape)*T Z_array = np.ones(shape)*Z lte_level_pop_array = self.level.LTE_level_pop(Z=Z_array,T=T_array) assert lte_level_pop_array.shape == shape assert np.all(lte_level_pop==lte_level_pop_array)
class TestTransition(): up = atomic_transition.Level(g=1,E=1,number=1) low = atomic_transition.Level(g=1,E=0,number=0) line_profile_cls = atomic_transition.SquareLineProfile A21 = 1 radiative_transition = atomic_transition.RadiativeTransition( up=up,low=low,A21=A21) width_v = 1*constants.kilo K21_data=np.array((2,1,4,6,3)) Tkin_data=np.array((1,2,3,4,5)) coll_transition = atomic_transition.CollisionalTransition( up=up,low=low,K21_data=K21_data,Tkin_data=Tkin_data) test_emission_line = atomic_transition.EmissionLine( up=up,low=low,A21=A21, line_profile_cls=line_profile_cls, width_v=width_v) def test_transition(self): with pytest.raises(AssertionError): atomic_transition.Transition(up=self.low,low=self.up) def test_emission_line_constructor(self): assert self.test_emission_line.nu0 == self.test_emission_line.line_profile.nu0 def test_constructor_from_radiative_transition(self): emission_line = atomic_transition.EmissionLine.from_radiative_transition( radiative_transition=self.radiative_transition, line_profile_cls=self.line_profile_cls, width_v=self.width_v) assert emission_line.nu0 == self.radiative_transition.nu0 assert emission_line.B12 == self.radiative_transition.B12 def test_coll_coeffs(self): Tkin_interp = np.array((self.Tkin_data[0],self.Tkin_data[-1])) coeff = self.coll_transition.coeffs(Tkin_interp)['K21'] expected_coeff = np.array((self.K21_data[0],self.K21_data[-1])) assert np.allclose(coeff,expected_coeff,atol=0) intermediate_temp = np.mean(self.Tkin_data[:2]) intermediate_coeff = self.coll_transition.coeffs(intermediate_temp)['K21'] boundaries = np.sort(self.K21_data[:2]) assert boundaries[0] <= intermediate_coeff <= boundaries[1] @pytest.mark.filterwarnings('ignore:invalid value','ignore:divide by zero') def test_Tex(self): assert self.radiative_transition.Tex(x1=0,x2=0) == 0 assert self.radiative_transition.Tex(x1=1,x2=0) == 0 assert self.radiative_transition.Tex(x1=0.5,x2=0) == 0 def tau_nu(self): nu = np.ones((2,4,7))*50 N1 = 1 N2 = 3 tau_nu = self.test_emission_line.tau_nu(N1=N1,N2=N2,nu=nu) assert tau_nu.shape == nu.shape tau_nu_array = self.test_emission_line.tau_nu_array(N1=N1,N2=N2) tau_nu_array_explicit = self.test_emission_line.tau_nu( N1=N1,N2=N2, nu=self.test_emission_line.line_profile.nu_array) assert np.all(tau_nu_array==tau_nu_array_explicit)
def read(datafilepath): ''' Read a LAMDA data file. Reads a LAMDA data file and returns the data in the form of a dictionary. The LAMDA database can be found at http://home.strw.leidenuniv.nl/~moldata/molformat.html Parameters ---------- datafilepath : str path to the file Returns ------- dict Dictionary containing the data read from the file. The dictionary has the following keys: - 'levels': list of levels (instances of the Level class) - 'radiative transitions': list of radiative transitions (instances of RadiativeTransition class) - 'collisional transitions': dict, containing lists of instances of the CollisionalTransition class for each collision partner appearing in the file The elements of these lists are in the order they appear in the file ''' #identifiers used in the LAMDA database files: LAMDA_coll_ID = {'1':'H2','2':'para-H2','3':'ortho-H2','4':'e', '5':'H','6':'He','7':'H+'} datafile = open(datafilepath,'r') levels = [] rad_transitions = [] coll_transitions = {} for i,line in enumerate(datafile): if i<5: continue if is_comment(line): continue if line=='' or line=='\n': continue if i == 5: n_levels = int(line) continue if 6 < i <= 6+n_levels: leveldata = [float(string) for string in line.split()[:3]] #transforming energy from cm-1 to J; level numbers starting from 0: lev = atomic_transition.Level( g=leveldata[2], E=constants.c*constants.h*leveldata[1]/constants.centi, number=int(leveldata[0])-1) levels.append(lev) continue if i == 8+n_levels: n_rad_transitions = int(line) continue if 9+n_levels < i <= 9+n_levels+n_rad_transitions: radtransdata = [float(string) for string in line.split()] up = next(level for level in levels if level.number==radtransdata[1]-1) low = next(level for level in levels if level.number==radtransdata[2]-1) rad_trans = atomic_transition.RadiativeTransition( up=up,low=low,A21=radtransdata[3]) rad_transitions.append(rad_trans) continue if i == 11+n_levels+n_rad_transitions: coll_partner_offset = 0 continue if i == 13+n_levels+n_rad_transitions + coll_partner_offset: coll_ID = LAMDA_coll_ID[line[0]] coll_transitions[coll_ID] = [] continue if i == 15+n_levels+n_rad_transitions + coll_partner_offset: n_coll_transitions = int(line) continue if i == 17+n_levels+n_rad_transitions + coll_partner_offset: continue #this lines contains the number of temperature elements if i == 19+n_levels+n_rad_transitions + coll_partner_offset: coll_temperatures = np.array([float(string) for string in line.split()]) continue if 20+n_levels+n_rad_transitions+coll_partner_offset < i <=\ 20+n_levels+n_rad_transitions+coll_partner_offset+n_coll_transitions: coll_trans_data = [float(string) for string in line.split()] up = next(level for level in levels if level.number==coll_trans_data[1]-1) low = next(level for level in levels if level.number==coll_trans_data[2]-1) K21_data = np.array(coll_trans_data[3:])*constants.centi**3 coll_trans = atomic_transition.CollisionalTransition( up=up,low=low,K21_data=K21_data, Tkin_data=coll_temperatures) coll_transitions[coll_ID].append(coll_trans) if i == 20+n_levels+n_rad_transitions+coll_partner_offset+n_coll_transitions: coll_partner_offset += 9+n_coll_transitions continue datafile.close() return {'levels':levels,'radiative transitions':rad_transitions, 'collisional transitions':coll_transitions}
def read(datafilepath, read_frequencies, read_quantum_numbers=False): ''' Read a LAMDA data file. Reads a LAMDA data file and returns the data in the form of a dictionary. The LAMDA database can be found at http://home.strw.leidenuniv.nl/~moldata/molformat.html Parameters ---------- datafilepath : str path to the file read_frequencies : bool Read the radiative transition frequencies from the file rather than computing them from the level energies. This can be useful since frequencies are sometimes given with more significant digits. However, the LAMDA standard does not require a file to list the frequencies. read_quantum_numbers : bool Read the quantum numbers from the file. The LAMDA standard does not require a file to list quantum numbers though. Returns ------- dict Dictionary containing the data read from the file. The dictionary has the following keys: - 'levels': list of levels (instances of the Level class) - 'radiative transitions': list of radiative transitions (instances of RadiativeTransition class) - 'collisional transitions': dict, containing lists of instances of the CollisionalTransition class for each collision partner appearing in the file - 'quantum numbers': list containing quantum number string for all levels. Empty if read_quantum_numbers=False The elements of these lists are in the order they appear in the file ''' #identifiers used in the LAMDA database files: LAMDA_coll_ID = { '1': 'H2', '2': 'para-H2', '3': 'ortho-H2', '4': 'e', '5': 'H', '6': 'He', '7': 'H+' } datafile = open(datafilepath, 'r') levels = [] rad_transitions = [] coll_transitions = {} quantum_numbers = [] comment_offset = 0 for i, line in enumerate(datafile): if is_comment(line) or line == '' or line == '\n': comment_offset += 1 continue if i == 0 + comment_offset: continue if i == 1 + comment_offset: continue if i == 2 + comment_offset: n_levels = int(line) continue if 3 + comment_offset <= i < 3 + comment_offset + n_levels: line_entries = line.split() leveldata = [float(string) for string in line_entries[:3]] assert int(leveldata[0]) == i-2-comment_offset,\ 'level numeration not consistent' #transforming energy from cm-1 to J; level numbers starting from 0: lev = atomic_transition.Level(g=leveldata[2], E=constants.c * constants.h * leveldata[1] / constants.centi, number=int(leveldata[0]) - 1) levels.append(lev) if read_quantum_numbers: quantum_numbers.append(line_entries[3]) continue if i == 3 + comment_offset + n_levels: n_rad_transitions = int(line) continue if 4 + comment_offset + n_levels <= i < 4 + comment_offset + n_levels + n_rad_transitions: radtransdata = [float(string) for string in line.split()] up = next(level for level in levels if level.number == radtransdata[1] - 1) low = next(level for level in levels if level.number == radtransdata[2] - 1) rad_trans_kwargs = {'up': up, 'low': low, 'A21': radtransdata[3]} if read_frequencies: rad_trans_kwargs['nu0'] = radtransdata[4] * constants.giga rad_trans = atomic_transition.RadiativeTransition( **rad_trans_kwargs) rad_transitions.append(rad_trans) continue if i == 4 + comment_offset + n_levels + n_rad_transitions: coll_partner_offset = 0 continue if i == 5 + comment_offset + n_levels + n_rad_transitions + coll_partner_offset: coll_ID = LAMDA_coll_ID[line[0]] coll_transitions[coll_ID] = [] continue if i == 6 + comment_offset + n_levels + n_rad_transitions + coll_partner_offset: n_coll_transitions = int(line) continue if i == 7 + comment_offset + n_levels + n_rad_transitions + coll_partner_offset: continue #this lines contains the number of temperature elements if i == 8 + comment_offset + n_levels + n_rad_transitions + coll_partner_offset: coll_temperatures = np.array( [float(string) for string in line.split()]) continue last_coll_trans_i = 9+comment_offset+n_levels+n_rad_transitions\ +coll_partner_offset+n_coll_transitions-1 if 9+comment_offset+n_levels+n_rad_transitions+coll_partner_offset <= i <=\ last_coll_trans_i: coll_trans_data = [float(string) for string in line.split()] up = next(level for level in levels if level.number == coll_trans_data[1] - 1) low = next(level for level in levels if level.number == coll_trans_data[2] - 1) K21_data = np.array(coll_trans_data[3:]) * constants.centi**3 coll_trans = atomic_transition.CollisionalTransition( up=up, low=low, K21_data=K21_data, Tkin_data=coll_temperatures) coll_transitions[coll_ID].append(coll_trans) if i == last_coll_trans_i: coll_partner_offset += 4 + n_coll_transitions continue datafile.close() return { 'levels': levels, 'radiative transitions': rad_transitions, 'collisional transitions': coll_transitions, 'quantum numbers': quantum_numbers }