1 from datetime import datetime
2 import numpy as np
3 import pylab as pl
4 np.seterr(over='ignore')
5
6 import chianti
7 import chianti.data as chdata
8 import chianti.constants as const
9 import chianti.util as util
10 import chianti.Gui as chgui
11 from ._SpecTrails import _specTrails
12
13 defaults = chdata.Defaults
14
15
16
17
18
19
20
21
23 '''
24 Calculate the emission spectrum as a function of temperature and density.
25
26 includes elemental abundances or ionization equilibria
27
28 temperature and density can be arrays but, unless the size of either is one (1),
29 the two must have the same size
30
31 the returned spectrum will be convolved with a filter of the specified width on the
32 specified wavelength array
33
34 the default filter is gaussianR with a resolving power of 1000. Other filters,
35 such as gaussian, box and lorentz, are available in chianti.filters. When using the box filter,
36 the width should equal the wavelength interval to keep the units of the continuum and line
37 spectrum the same.
38
39 A selection of ions can be make with ionList containing the names of
40 the desired lines in Chianti notation, i.e. C VI = c_6
41
42 a minimum abundance can be specified so that the calculation can be speeded up by excluding
43 elements with a low abundance. With solar photospheric abundances -
44
45 setting minAbund = 1.e-4 will include H, He, C, O, Ne
46 setting minAbund = 2.e-5 adds N, Mg, Si, S, Fe
47 setting minAbund = 1.e-6 adds Na, Al, Ar, Ca, Ni
48
49 Setting em will multiply the spectrum at each temperature by the value of em.
50
51 em [for emission measure], can be a float or an array of the same length as the
52 temperature/density.
53 '''
54 - def __init__(self, temperature, eDensity, elementList=0, ionList = 0, minAbund=0, doContinuum=1, abundanceName=0, verbose=0, allLines=1, keepIons=0):
55 t1 = datetime.now()
56 masterlist = chdata.MasterList
57
58 if ionList:
59 alist=[]
60 for one in ionList:
61 if masterlist.count(one):
62 alist.append(one)
63 else:
64 if verbose:
65 pstring = ' %s not in CHIANTI database'%(one)
66 print(pstring)
67 masterlist = alist
68 self.Defaults=defaults
69 self.Temperature = np.asarray(temperature, 'float64')
70 nTemp = self.Temperature.size
71 self.EDensity = np.asarray(eDensity, 'float64')
72 nDen = self.EDensity.size
73 nTempDen = max([nTemp, nDen])
74
75 if not abundanceName:
76 self.AbundanceName = self.Defaults['abundfile']
77 else:
78 if abundanceName in sorted(chdata.Abundance.keys()):
79 self.AbundanceName = abundanceName
80 else:
81 abundChoices = sorted(chdata.Abundance.keys())
82
83
84 abundChoice = chgui.gui.selectorDialog(abundChoices,label='Select Abundance name')
85 abundChoice_idx = abundChoice.selectedIndex
86 self.AbundanceName = abundChoices[abundChoice_idx[0]]
87 abund = self.AbundanceName
88 print(' Abundance chosen: %s '%(self.AbundanceName))
89
90 abundAll = chdata.Abundance[self.AbundanceName]['abundance']
91
92 self.AbundAll = abundAll
93
94 nonzed = abundAll > 0.
95 minAbundAll = abundAll[nonzed].min()
96
97 if minAbund:
98 if minAbund < minAbundAll:
99 minAbund = minAbundAll
100
101
102 freeFreeLoss = np.zeros((nTempDen), 'float64').squeeze()
103 freeBoundLoss = np.zeros((nTempDen), 'float64').squeeze()
104 twoPhotonLoss = np.zeros((nTempDen), 'float64').squeeze()
105 boundBoundLoss = np.zeros((nTempDen), 'float64').squeeze()
106 twoPhotonLoss = np.zeros((nTempDen), 'float64').squeeze()
107
108 self.IonsCalculated = []
109 if keepIons:
110 self.IonInstances = {}
111 self.Finished = []
112
113 self.WvlRange = [0., 1.e+30]
114
115 self.ionGate(elementList = elementList, ionList = ionList, minAbund=minAbund, doContinuum=doContinuum, doWvlTest=0, verbose=verbose)
116
117
118 for akey in sorted(self.Todo.keys()):
119 zStuff = util.convertName(akey)
120 Z = zStuff['Z']
121 ionstage = zStuff['Ion']
122 dielectronic = zStuff['Dielectronic']
123 abundance = chdata.Abundance[self.AbundanceName]['abundance'][Z - 1]
124 if verbose:
125 print(' %5i %5s abundance = %10.2e '%(Z, const.El[Z-1], abundance))
126 if verbose:
127 print(' doing ion %s for the following processes %s'%(akey, self.Todo[akey]))
128 if ionstage != 1:
129 if verbose:
130 print(' calculating ff continuum for : %s'%(akey))
131 if 'ff' in self.Todo[akey]:
132
133 cont = chianti.core.continuum(akey, temperature, abundanceName=self.AbundanceName)
134 cont.freeFreeLoss()
135 freeFreeLoss += cont.FreeFreeLoss['rate']
136
137
138
139
140
141
142 if 'fb' in self.Todo[akey]:
143 if verbose:
144 print(' calculating fb continuum for : %s'%(akey))
145
146
147 if hasattr(cont, 'FreeFreeLoss'):
148 cont.freeBoundLoss()
149 else:
150 cont = chianti.core.continuum(akey, temperature, abundanceName=self.AbundanceName)
151 cont.freeBoundLoss()
152 if 'errorMessage' not in list(cont.FreeBoundLoss.keys()):
153
154 freeBoundLoss += cont.FreeBoundLoss['rate']
155
156
157
158
159
160
161
162
163
164
165
166
167 if 'line' in self.Todo[akey]:
168 if verbose:
169 print(' calculating spectrum for : %s'%(akey))
170 thisIon = chianti.core.ion(akey, temperature, eDensity, abundanceName=self.AbundanceName)
171 thisIon.intensity(allLines=allLines)
172 self.IonsCalculated.append(akey)
173 if 'errorMessage' not in list(thisIon.Intensity.keys()):
174 self.Finished.append(akey)
175 thisIon.boundBoundLoss()
176
177
178
179
180
181
182
183 boundBoundLoss += thisIon.BoundBoundLoss['rate']
184
185
186
187
188
189 else:
190 if verbose:
191 print(thisIon.Intensity['errorMessage'])
192
193 if (Z - ionstage) in [0, 1] and not dielectronic:
194 thisIon.twoPhotonLoss()
195 twoPhotonLoss += thisIon.TwoPhotonLoss['rate']
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271 self.FreeFreeLoss = freeFreeLoss
272 self.FreeBoundLoss = freeBoundLoss
273 self.BoundBoundLoss = boundBoundLoss
274 self.TwoPhotonLoss = twoPhotonLoss
275
276 total = freeFreeLoss + freeBoundLoss + boundBoundLoss + twoPhotonLoss
277 t2 = datetime.now()
278 dt=t2-t1
279 print(' elapsed seconds = %10.2e'%(dt.seconds))
280 self.RadLoss = {'rate':total, 'temperature':self.Temperature, 'density':self.EDensity, 'minAbund':minAbund, 'abundance':self.AbundanceName}
281
282
283
285 '''
286 to plot the radiative losses vs temperature
287 '''
288 fontsize = 16
289 temp = self.RadLoss['temperature']
290 rate = self.RadLoss['rate']
291 pl.loglog(temp, rate)
292 pl.xlabel('Temperature (K)',fontsize=fontsize)
293 pl.ylabel(r'erg s$^{-1}$ ($\int\,$ N$_e\,$N$_H\,$d${\it l}$)$^{-1}$',fontsize=fontsize)
294
295
296
297
298