Package chianti :: Package core :: Module Mspectrum
[hide private]
[frames] | no frames]

Source Code for Module chianti.core.Mspectrum

  1  from datetime import datetime 
  2  import copy 
  3  # 
  4  import numpy as np 
  5   
  6  import chianti.data as chdata 
  7  import chianti.constants as const 
  8  import chianti.filters as chfilters 
  9  import chianti.util as util 
 10  import chianti.io as chio 
 11  import chianti.Gui as chgui 
 12  from ._IonTrails import _ionTrails 
 13  from ._SpecTrails import _specTrails 
 14  # 
 15  #chInteractive = chdata.chInteractive 
 16  #if chInteractive: 
 17  #    import pylab as pl 
 18  #else: 
 19  #    import matplotlib 
 20  #    matplotlib.use('Agg') 
 21  #    import matplotlib.pyplot as pl 
 22   
 23  try: 
 24      import multiprocessing as mp 
 25  #    from chianti import mputil 
 26      import chianti.mputil as mputil 
 27  except: 
 28      print(' your version of Python does not support multiprocessing \n you will not be able to use mspectrum') 
 29  # 
 30  defaults = chdata.Defaults 
 31  # 
 32  # the following is necessary to make chiantipy non interactive for the web 
 33  #try: 
 34  #    chInteractive = int(os.environ['CHIANTIPY_INTERACTIVE']) 
 35  #except: 
 36  #    chInteractive = 1 
 37  # 
38 -class mspectrum(_ionTrails, _specTrails):
39 ''' this is the multiprocessing version of spectrum 40 set proc to the desired number of processors, default=3 41 42 Calculate the emission spectrum as a function of temperature and density. 43 44 temperature and density can be arrays but, unless the size of either is one (1), 45 the two must have the same size 46 47 the returned spectrum will be convolved with a filter of the specified width on the 48 specified wavelength array 49 50 the default filter is gaussianR with a resolving power of 100. Other filters, 51 such as gaussian, box and lorentz, are available in chianti.filters. When using the box filter, 52 the width should equal the wavelength interval to keep the units of the continuum and line 53 spectrum the same. 54 55 A selection of elements can be make with elementList a list containing the names of elements 56 that are desired to be included, e.g., ['fe','ni'] 57 58 A selection of ions can be make with ionList containing the names of 59 the desired lines in Chianti notation, i.e. C VI = c_6 60 61 Both elementList and ionList can not be specified at the same time 62 63 a minimum abundance can be specified so that the calculation can be speeded up by excluding 64 elements with a low abundance. With solar photospheric abundances - 65 66 setting minAbund = 1.e-4 will include H, He, C, O, Ne 67 setting minAbund = 2.e-5 adds N, Mg, Si, S, Fe 68 setting minAbund = 1.e-6 adds Na, Al, Ar, Ca, Ni 69 70 Setting em will multiply the spectrum at each temperature by the value of em. 71 72 em [for emission measure], can be a float or an array of the same length as the 73 temperature/density. 74 allLines = 1 will include lines with either theoretical or observed wavelengths. allLines=0 will 75 include only those lines with observed wavelengths 76 77 proc = the number of processors to use 78 timeout - a small but non-zero value seems to be necessary 79 '''
80 - def __init__(self, temperature, eDensity, wavelength, filter=(chfilters.gaussianR, 1000.), label=0, elementList = 0, ionList = 0, minAbund=0, keepIons=0, abundanceName=0, doContinuum=1, allLines = 1, em =0, proc=3, verbose = 0, timeout=0.1):
81 # 82 t1 = datetime.now() 83 # creates Intensity dict from first ion calculated 84 setupIntensity = 0 85 # 86 #masterlist = chdata.MasterList 87 # use the ionList but make sure the ions are in the database 88 #if elementList: 89 #for i, one in enumerate(elementList): 90 #elementList[i] = one.lower() 91 #alist = [] 92 #for one in masterlist: 93 #stuff = util.convertName(one) 94 #if stuff['Element'] in elementList: 95 #alist.append(one) 96 #masterlist = alist 97 #elif ionList: 98 #alist=[] 99 #for one in ionList: 100 #if masterlist.count(one): 101 #alist.append(one) 102 #else: 103 #if verbose: 104 #pstring = ' %s not in CHIANTI database'%(one) 105 #print(pstring) 106 #masterlist = alist 107 self.Defaults = defaults 108 # 109 masterlist = chdata.MasterList 110 self.Defaults = defaults 111 self.Temperature = np.asarray(temperature, 'float64') 112 nTemp = self.Temperature.size 113 self.EDensity = np.asarray(eDensity, 'float64') 114 nDen = self.EDensity.size 115 nTempDen = max([nTemp, nDen]) 116 self.NTempDen = nTempDen 117 # 118 if type(em) == int and em == 0: 119 em = np.ones(self.NTempDen, 'float64') 120 elif type(em) == float and em > 0.: 121 em = np.ones(self.NTempDen, 'float64')*em 122 elif type(em) == list or type(em) == tuple: 123 em = np.asarray(em, 'float64') 124 self.Em = em 125 # 126 # 127 if self.Em.any() > 0.: 128 ylabel = r'erg cm$^{-2}$ s$^{-1}$ sr$^{-1} \AA^{-1}$ $' 129 else: 130 ylabel = r'erg cm$^{-2}$ s$^{-1}$ sr$^{-1} \AA^{-1}$ ($\int\,$ N$_e\,$N$_H\,$d${\it l}$)$^{-1}$' 131 # 132 xlabel = 'Wavelength ('+self.Defaults['wavelength'] +')' 133 # 134 # 135 self.AllLines = allLines 136 # 137 if not abundanceName: 138 self.AbundanceName = self.Defaults['abundfile'] 139 else: 140 if abundanceName in chdata.Abundance: 141 self.AbundanceName = abundanceName 142 else: 143 abundChoices = list(chdata.Abundance.keys()) 144 # for one in wvl[topLines]: 145 # wvlChoices.append('%12.3f'%(one)) 146 abundChoice = chgui.gui.selectorDialog(abundChoices,label='Select Abundance name') 147 abundChoice_idx = abundChoice.selectedIndex 148 self.AbundanceName = abundChoices[abundChoice_idx[0]] 149 abundanceName = self.AbundanceName 150 print(' Abundance chosen: %s '%(self.AbundanceName)) 151 # 152 abundAll = chdata.Abundance[self.AbundanceName]['abundance'] 153 self.AbundAll = abundAll 154 # 155 # nonzed = abundAll > 0. 156 # minAbundAll = abundAll[nonzed].min() 157 # # if minAbund is even set 158 # if minAbund: 159 # if minAbund < minAbundAll: 160 # minAbund = minAbundAll 161 #ionInfo = chio.masterListInfo() 162 wavelength = np.asarray(wavelength) 163 nWvl = wavelength.size 164 self.Wavelength = wavelength 165 # wvlRange = [wavelength.min(), wavelength.max()] 166 # 167 proc = min([proc, mp.cpu_count()]) 168 # 169 freeFree = np.zeros((nTempDen, nWvl), 'float64').squeeze() 170 freeBound = np.zeros((nTempDen, nWvl), 'float64').squeeze() 171 twoPhoton = np.zeros((nTempDen, nWvl), 'float64').squeeze() 172 lineSpectrum = np.zeros((nTempDen, nWvl), 'float64').squeeze() 173 # 174 # free-free multiprocessing setup 175 ffWorkerQ = mp.Queue() 176 ffDoneQ = mp.Queue() 177 # 178 # free-bound multiprocessing setup 179 # 180 fbWorkerQ = mp.Queue() 181 fbDoneQ = mp.Queue() 182 # 183 # ion multiprocessing setup 184 ionWorkerQ = mp.Queue() 185 ionDoneQ = mp.Queue() 186 # 187 self.IonsCalculated = [] 188 if keepIons: 189 self.IonInstances = {} 190 self.Finished = [] 191 # 192 193 # self.Todo = [] 194 self.ionGate(elementList = elementList, ionList = ionList, minAbund=minAbund, doContinuum=doContinuum, verbose = verbose) 195 # 196 for akey in sorted(self.Todo.keys()): 197 zStuff = util.convertName(akey) 198 Z = zStuff['Z'] 199 abundance = chdata.Abundance[self.AbundanceName]['abundance'][Z - 1] 200 if verbose: 201 print(' %5i %5s abundance = %10.2e '%(Z, const.El[Z-1], abundance)) 202 if verbose: 203 print(' doing ion %s for the following processes %s'%(akey, self.Todo[akey])) 204 if 'ff' in self.Todo[akey]: 205 # if verbose: 206 # print(' doing ff') 207 ffWorkerQ.put((akey, temperature, wavelength, abundance, em)) 208 # allInpt.append([akey, 'ff', temperature, wavelength, abundance]) 209 if 'fb' in self.Todo[akey]: 210 # if verbose: 211 # print(' doing fb') 212 fbWorkerQ.put((akey, temperature, wavelength, abundance, em)) 213 # allInpt.append([akey, 'fb', temperature, wavelength, abundance]) 214 if 'line' in self.Todo[akey]: 215 # if verbose: 216 # print(' doing line') 217 ionWorkerQ.put((akey, temperature, eDensity, wavelength, filter, allLines, abundance, em, doContinuum)) 218 # allInpt.append([akey, 'line', temperature, eDensity, wavelength, filter, allLines, abundance, em, doContinuum]) 219 220 221 # 222 ffWorkerQSize = ffWorkerQ.qsize() 223 fbWorkerQSize = fbWorkerQ.qsize() 224 ionWorkerQSize = ionWorkerQ.qsize() 225 if doContinuum: 226 ffProcesses = [] 227 for i in range(proc): 228 p = mp.Process(target=mputil.doFfQ, args=(ffWorkerQ, ffDoneQ)) 229 p.start() 230 ffProcesses.append(p) 231 # timeout is not necessary 232 for p in ffProcesses: 233 if p.is_alive(): 234 p.join(timeout=timeout) 235 # for i in range(proc): 236 # ffProcesses.append('STOP') 237 # 238 for iff in range(ffWorkerQSize): 239 thisFreeFree = ffDoneQ.get() 240 # freeFree += thisFreeFree['rate'] 241 # if nTempDen ==1: 242 # freeFree += thisFreeFree['rate']*em[0] 243 # else: 244 # for iTempDen in range(nTempDen): 245 # freeFree[iTempDen] += thisFreeFree['rate'][iTempDen]*em[iTempDen] 246 freeFree += thisFreeFree['rate'] 247 for p in ffProcesses: 248 if not isinstance(p, str): 249 p.terminate() 250 # 251 fbProcesses = [] 252 for i in range(proc): 253 p = mp.Process(target=mputil.doFbQ, args=(fbWorkerQ, fbDoneQ)) 254 p.start() 255 fbProcesses.append(p) 256 # timeout is not necessary 257 for p in fbProcesses: 258 if p.is_alive(): 259 p.join(timeout=timeout) 260 # for i in range(proc): 261 # fbProcesses.append('STOP') 262 # 263 for ifb in range(fbWorkerQSize): 264 thisFreeBound = fbDoneQ.get() 265 if 'rate' in sorted(thisFreeBound.keys()): 266 # freeBound += thisFreeBound['rate'] 267 # if nTempDen ==1: 268 # freeBound += thisFreeBound['rate']*em[0] 269 # else: 270 # for iTempDen in range(nTempDen): 271 # freeBound[iTempDen] += thisFreeBound['rate'][iTempDen]*em[iTempDen] 272 freeBound += thisFreeBound['rate'] 273 for p in fbProcesses: 274 if not isinstance(p, str): 275 p.terminate() 276 # 277 ionProcesses = [] 278 if ionWorkerQSize < proc: 279 proc = ionWorkerQSize 280 for i in range(proc): 281 p = mp.Process(target=mputil.doIonQ, args=(ionWorkerQ, ionDoneQ)) 282 p.start() 283 ionProcesses.append(p) 284 # ionWorkerQ.put('STOP') 285 # timeout is not necessary 286 for p in ionProcesses: 287 # print' process is alive: ', p.is_alive() 288 if p.is_alive(): 289 # p.join() 290 p.join(timeout=timeout) 291 # for i in range(proc): 292 # ionProcesses.append('STOP') 293 # 294 for ijk in range(ionWorkerQSize): 295 out = ionDoneQ.get() 296 ions = out[0] 297 if verbose: 298 print(' collecting calculation for %s'%(ions)) 299 thisIon = out[1] 300 # thisSpectrum = thisIon.Spectrum 301 thisIntensity = thisIon.Intensity 302 if not 'errorMessage' in sorted(thisIntensity.keys()): 303 self.Finished.append(ions) 304 if keepIons: 305 self.IonInstances[ions] = copy.deepcopy(thisIon) 306 if setupIntensity: 307 for akey in sorted(self.Intensity.keys()): 308 self.Intensity[akey] = np.hstack((copy.copy(self.Intensity[akey]), thisIntensity[akey])) 309 else: 310 setupIntensity = 1 311 self.Intensity = thisIntensity 312 # 313 if not 'errorMessage' in sorted(thisIon.Spectrum.keys()): 314 lineSpectrum += thisIon.Spectrum['intensity'] 315 # if nTempDen == 1: 316 # lineSpectrum += thisSpectrum['intensity'] 317 # else: 318 # for iTempDen in range(nTempDen): 319 # lineSpectrum[iTempDen] += thisSpectrum['intensity'][iTempDen] 320 # check for two-photon emission 321 if len(out) == 3: 322 tp = out[2] 323 twoPhoton += tp['rate'] 324 # if nTempDen == 1: 325 # twoPhoton += tp['rate']*em[0] 326 # else: 327 # for iTempDen in range(nTempDen): 328 # twoPhoton[iTempDen] += tp['rate'][iTempDen]*em[iTempDen] 329 else: 330 if 'errorMessage' in sorted(thisIntensity.keys()): 331 print(thisIntensity['errorMessage']) 332 # 333 for p in ionProcesses: 334 if not isinstance(p, str): 335 p.terminate() 336 # 337 # 338 # 339 self.FreeFree = {'wavelength':wavelength, 'intensity':freeFree.squeeze()} 340 self.FreeBound = {'wavelength':wavelength, 'intensity':freeBound.squeeze()} 341 self.LineSpectrum = {'wavelength':wavelength, 'intensity':lineSpectrum.squeeze()} 342 self.TwoPhoton = {'wavelength':wavelength, 'intensity':twoPhoton.squeeze()} 343 # 344 total = freeFree + freeBound + lineSpectrum + twoPhoton 345 # 346 t2 = datetime.now() 347 dt=t2-t1 348 print(' elapsed seconds = %12.3f'%(dt.seconds)) 349 # 350 if nTempDen == 1: 351 integrated = total 352 else: 353 integrated = total.sum(axis=0) 354 # 355 if type(label) == type(''): 356 if hasattr(self, 'Spectrum'): 357 self.Spectrum[label] = {'wavelength':wavelength, 'intensity':total.squeeze(), 'filter':filter[0].__name__, 'width':filter[1], 'integrated':integrated, 'ions':self.IonsCalculated, 'em':em, 358 'ions':self.IonsCalculated, 'Abundance':self.AbundanceName, 'xlabel':xlabel, 'ylabel':ylabel} 359 else: 360 self.Spectrum = {label:{'wavelength':wavelength, 'intensity':total.squeeze(), 'filter':filter[0].__name__, 'width':filter[1], 'integrated':integrated, 'ions':self.IonsCalculated, 'em':em, 361 'ions':self.IonsCalculated, 'Abundance':self.AbundanceName, 'xlabel':xlabel, 'ylabel':ylabel}} 362 else: 363 self.Spectrum ={'wavelength':wavelength, 'intensity':total.squeeze(), 'filter':filter[0].__name__, 'width':filter[1], 'integrated':integrated, 'ions':self.IonsCalculated, 364 'em':em, 'Abundance':self.AbundanceName, 'xlabel':xlabel, 'ylabel':ylabel}
365 # 366 # ------------------------------------------------------------------------- 367 # 368