1
2
3 """
4 A tool set for providing molecular data. Subclasses
5 provide code-specific read and partse methods.
6
7 Author: R. Lombaert
8
9 """
10
11 import numpy as np
12 from cc.tools.io import DataIO
13 from cc.tools.readers.SpectroscopyReader import SpectroscopyReader
14
15 from astropy import units as u
16
17
19
20 '''
21 The MolReader class.
22
23 Inherits from the Reader class.
24
25 Provides methods to manage molecular spectroscopic data (excitation
26 levels, Einstein A coefficients, transitions, etc). The only exception to
27 this is the collisional rate data.
28
29 Subclasses provide the read and parse methods that are code-specific:
30 - MlineReader for GASTRoNOoM output
31 - RadiatReader for GASTRoNOoM input
32 - LamdaReader for ALI/MCP input and Lamda data files in general (see
33 http://home.strw.leidenuniv.nl/~moldata/).
34
35 The level populations are read with PopReader for MCP/ALI, and MlineReader
36 for GASTRoNOoM. The collision rates are read with CollisReader for
37 GASTRoNOoM, and LamdaReader for MCP/ALI.
38
39 '''
40
42
43 '''
44 Initialize an MolReader object. The filename and additional args/kwargs
45 are passed to the Reader parent class, where the dict is made and the
46 filename is stored.
47
48 Additional args/kwargs are used for the dict creation.
49
50 Note that this is the only class directly inheriting from Reader that
51 does not have its own read method (unlike PopReader and CollisReader).
52 This is because it is always combined with a different type of class
53 in multiple inheritance, depending on the input type of the spectroscopy
54 (GASTRoNOoM versus Lamda)
55
56 @param fn: The filename of molecular spectroscopic data.
57 @type fn: str
58
59 '''
60
61 super(MolReader,self).__init__(fn,*args,**kwargs)
62
63
64
66
67 '''
68 Return the frequencies for the <nline> included transitions.
69
70 In case a single frequency is requested via index, the frequency is
71 extracted from the array.
72
73 @keyword index: The index. In case of default, all are returned. Can be
74 any array-like object that includes indices
75
76 (default: None)
77 @type index: int/array
78 @keyword unit: The unit of the returned values. Can be any valid units
79 str from the astropy units module (freq or wavelength),
80 or the unit itself.
81 In case of wavelength, the values are *not* reversed.
82
83 (default: u.GHz)
84 @type unit: string/unit
85
86 @return: The frequencies/y ordered by transition index.
87 @rtype: float/array
88
89 '''
90
91
92 freqs = self.get('trans','frequency',index)
93
94
95 if isinstance(unit,str): unit = getattr(u,unit)
96 return (freqs*u.GHz).to(unit,equivalencies=u.spectral()).value
97
98
99
101
102 '''
103 Return the Einstein A coefficients for the <nline> included transitions.
104
105 In case a single Einstein coefficient is requested via index, the value
106 is extracted from the array.
107
108 @keyword index: The index. In case of default, all are returned. Can be
109 any array-like object that includes indices
110
111 (default: None)
112 @type index: int/array
113
114 @return: The Einstein A coefficient(s) (s^-1) ordered by transition
115 index.
116 @rtype: float/array
117
118 '''
119
120 return self.get('trans','einsteinA',index)
121
122
123
124 - def getTI(self,itype='trans',lup=None,llow=None):
125
126 '''
127 Return the indices of the transitions read from the molecular
128 spectroscopy data.
129
130 A specific index (or array of indices) can be requested by specifying
131 the lower and upper level index.
132
133 LamdaReader first inherits from MolReader, so the default will be itype
134 'trans' for LamdaReader.
135
136 @keyword itype: The type of index. Default is for MolReader. Needs to be
137 here in case LamdaReader calls this method, where the
138 type has to be specified. It will call both this method
139 and the version in CollisReader and pass on the call.
140
141 (default: 'trans')
142 @type itype: str
143 @keyword lup: The index of the upper energy level in the transition. If
144 both this and llow are None, all transition indices are
145 returned.
146
147 (default: None)
148 @type lup: int
149 @keyword llow: The index of the lower energy level in the transition. If
150 both this and lup are None, all transition indices are
151 returned.
152
153 (default: None)
154 @type llow: int
155
156 @return: The transition indices
157 @rtype: array
158
159 '''
160
161 return super(MolReader,self).getTI(itype=itype,lup=lup,llow=llow)
162
163
164
165 - def getTUpper(self,index=None,itype='trans'):
166
167 '''
168 Return the indices of the upper states of the <nline> included
169 transitions.
170
171 These are NOT the quantum numbers! Especially for CO-type molecules,
172 the J-level is equal to level_index-1.
173
174 In case a single upper level is requested via index, the level index is
175 extracted from the array.
176
177 @keyword index: The index. In case of default, all are returned. Can be
178 any array-like object that includes indices
179
180 (default: None)
181 @type index: int/array
182 @keyword itype: The type of index. Default is for MolReader.
183 CollisReader needs this to be 'coll_trans'.
184
185 (default: 'trans')
186 @type itype: str
187
188 @return: The upper level indices/x ordered by transition index.
189 @rtype: int/array
190
191 '''
192
193 return super(MolReader,self).getTUpper(itype=itype,index=index)
194
195
196
197 - def getTLower(self,index=None,itype='trans'):
198
199 '''
200 Return the indices of the lower states of the <nline> included
201 transitions.
202
203 These are NOT the quantum numbers! Especially for CO-type molecules,
204 the J-level is equal to level_index-1.
205
206 In case a single lower level is requested via index, the level index is
207 extracted from the array.
208
209 @keyword index: The index. In case of default, all are returned. Can be
210 any array-like object that includes indices
211
212 (default: None)
213 @type index: int/array
214 @keyword itype: The type of index. Default is for MolReader.
215 CollisReader needs this to be 'coll_trans'.
216
217 (default: 'trans')
218 @type itype: str
219
220 @return: The lower level indices/x ordered by transition index.
221 @rtype: int/array
222
223 '''
224
225 return super(MolReader,self).getTLower(itype=itype,index=index)
226
227
228
230
231 '''
232 Return the indices of the excitation levels read from the molecular
233 spectroscopy data.
234
235 @return: The level indices
236 @rtype: array
237
238 '''
239
240 return self['level']['index']
241
242
243
245
246 '''
247 Return the weights of the <ny_up+ny_low> excitation levels.
248
249 In case a single weight is requested via index, the weight value is
250 extracted from the array.
251
252 @keyword index: The index. In case of default, all are returned. Can be
253 any array-like object that includes indices
254
255 (default: None)
256 @type index: int/array
257
258 @return: The weights ordered by level index.
259 @rtype: float/array
260
261 '''
262
263 return self.get('level','weight',index)
264
265
266
268
269 '''
270 Return the energies of the <ny_up+ny_low> excitation levels.
271
272 In case a single energy level is requested via index the energy value is
273 extracted from the array.
274
275 @keyword index: The index. In case of default, all are returned. Can be
276 any array-like object that includes indices
277
278 (default: None)
279 @type index: int/array
280 @keyword unit: The unit of the returned values. Can be any valid units
281 str from the astropy units module (energy), or the unit
282 itself. 'cm-1' and 'cm^-1' are accepted as well.
283
284 (default: 1./u.cm)
285 @type unit: string/unit
286
287 @return: The energies ordered by level index.
288 @rtype: float/array
289
290 '''
291
292
293 energies = self.get('level','energy',index)
294
295
296 if isinstance(unit,str) and unit.lower() in ['cm-1','cm^-1']:
297 unit = 1./u.cm
298 elif isinstance(unit,str):
299 unit = getattr(u,unit)
300
301
302 if (isinstance(unit,u.Quantity) and unit.unit.is_equivalent(u.K)) \
303 or (isinstance(unit,u.UnitBase) and unit.is_equivalent(u.K)):
304 energies = (energies/u.cm).to(u.erg,equivalencies=u.spectral())
305 return energies.to(unit,equivalencies=u.temperature_energy()).value
306 else:
307 return (energies/u.cm).to(unit,equivalencies=u.spectral()).value
308