def intensityRatio(self, wvlRange=None, wvlRanges=None, top=10): """ Plot the intensity ratio of 2 lines or sums of lines. Shown as a function of density and/or temperature. For a single wavelength range, set wvlRange = [wMin, wMax] For multiple wavelength ranges, set wvlRanges = [[wMin1,wMax1],[wMin2,wMax2], ...] A plot of relative emissivities is shown and then a dialog appears for the user to choose a set of lines. Parameters ----------- wvlRange : array-like Wavelength range, i.e. min and max wvlRanges: a tuple, list or array that contains at least 2 2 element tuples, lists or arrays so that multiple wavelength ranges can be specified top : `int` specifies to plot only the top strongest lines, default = 10 """ if not hasattr(self, 'Intensity'): try: self.intensity() except: print( ' intensities not calculated and emiss() is unable to calculate them' ) print(' perhaps the temperature and/or eDensity are not set') return fontsize = 14 eDensity = self.EDensity temperature = self.Temperature ntemp = temperature.size if ntemp > 0: if temperature[0] == temperature[-1]: ntemp = 1 ndens = eDensity.size if ndens > 0: if eDensity[0] == eDensity[-1]: ndens = 1 print(' ndens = %5i ntemp = %5i' % (ndens, ntemp)) ionS = self.Intensity['ionS'] # see if we are dealing with more than a single ion ionSet = set(ionS) ionNum = len(ionSet) wvl = self.Intensity["wvl"] # find which lines are in the wavelength range if it is set if wvlRange: igvl = util.between(wvl, wvlRange) if len(igvl) == 0: print('no lines in wavelength range %12.2f - %12.2f' % (wvlRange[0], wvlRange[1])) return elif wvlRanges: igvl = [] for awvlRange in wvlRanges: igvl.extend(util.between(wvl, awvlRange)) if len(igvl) == 0: print('no lines in wavelength ranges specified ') return else: igvl = range(len(wvl)) nlines = len(igvl) igvl = np.take(igvl, wvl[igvl].argsort()) if top > nlines: top = nlines intensity = self.Intensity['intensity'] maxIntens = np.zeros(nlines, np.float64) for iline in range(nlines): maxIntens[iline] = intensity[:, igvl[iline]].max() for iline in range(nlines): if maxIntens[iline] == maxIntens.max(): maxAll = intensity[:, igvl[iline]] igvlsort = np.take(igvl, np.argsort(maxIntens)) topLines = igvlsort[-top:] maxWvl = '%5.3f' % wvl[topLines[-1]] topLines = topLines[wvl[topLines].argsort()] print(' maxWvl = %s' % (maxWvl)) # need to make sure there are no negative values before plotting good = intensity > 0. intensMin = intensity[good].min() bad = intensity <= 0. intensity[bad] = intensMin ylabel = 'Intensity relative to ' + maxWvl if ndens == 1 and ntemp == 1: print(' only a single temperature and eDensity') return elif ndens == 1: xlbl = 'Temperature (K)' xvalues = self.Temperature outTemperature = self.Temperature outDensity = self.EDensity desc_str = ' Density = %10.2e (cm$^{-3}$)' % self.EDensity[0] elif ntemp == 1: xvalues = self.EDensity outTemperature = self.Temperature outDensity = self.EDensity xlbl = 'Electron Density (cm$^{-3}$)' desc_str = ' Temp = %10.2e (K)' % self.Temperature[0] else: outTemperature = self.Temperature outDensity = self.EDensity xlbl = 'Temperature (K)' xvalues = self.Temperature desc_str = ' Variable Density' # put all actual plotting here plt.ion() # maxAll is an array ymax = np.max(intensity[:, topLines[0]] / maxAll) ymin = ymax plt.figure() ax = plt.subplot(111) nxvalues = len(xvalues) # reversing is necessary - otherwise, get a ymin=ymax and a matplotlib error for iline in range(top - 1, -1, -1): tline = topLines[iline] plt.loglog(xvalues, intensity[:, tline] / maxAll) if np.min(intensity[:, tline] / maxAll) < ymin: ymin = np.min(intensity[:, tline] / maxAll) if np.max(intensity[:, tline] / maxAll) > ymax: ymax = np.max(intensity[:, tline] / maxAll) skip = 2 start = divmod(iline, nxvalues)[1] for ixvalue in range(start, nxvalues, nxvalues // skip): if ionNum == 1: text = '%10.4f' % (wvl[tline]) else: text = '%s %10.4f' % (ionS[tline], wvl[tline]) plt.text(xvalues[ixvalue], intensity[ixvalue, tline] / maxAll[ixvalue], text) if ndens == 1: print('%12.2e %12.2e ' % (xvalues.min(), xvalues.max())) plt.xlim(xvalues.min(), xvalues.max()) plt.xlabel(xlbl, fontsize=fontsize) plt.ylabel(ylabel, fontsize=fontsize) elif ntemp == 1: ax2 = plt.twiny() xlblDen = r'Electron Density (cm$^{-3}$)' plt.xlabel(xlblDen, fontsize=fontsize) plt.loglog(eDensity, intensity[:, topLines[top - 1]] / maxAll, visible=False) ax2.xaxis.tick_top() plt.ylim(ymin / 1.2, 1.2 * ymax) else: plt.ylim(ymin / 1.2, 1.2 * ymax) plt.tight_layout() plt.draw() # need time to let matplotlib finish plotting time.sleep(0.5) # get line selection selectTags = [] for itop in topLines: if ionNum == 1: selectTags.append(str(wvl[itop])) else: selectTags.append(ionS[itop] + ' ' + str(wvl[itop])) numden = chGui.gui.choice2Dialog(selectTags) # num_idx and den_idx are tuples num_idx = numden.numIndex if len(num_idx) == 0: print(' no numerator lines were selected') return den_idx = numden.denIndex if len(den_idx) == 0: print(' no denominator lines were selected') return numIntens = np.zeros(len(xvalues), np.float64) for aline in num_idx: numIntens += intensity[:, topLines[aline]] denIntens = np.zeros(len(xvalues), np.float64) for aline in den_idx: denIntens += intensity[:, topLines[aline]] # plot the desired ratio # maxAll is an array plt.figure() ax = plt.subplot(111) plt.loglog(xvalues, numIntens / denIntens) plt.xlim(xvalues.min(), xvalues.max()) plt.xlabel(xlbl, fontsize=fontsize) plt.ylabel('Ratio (' + self.Defaults['flux'] + ')', fontsize=fontsize) if ionNum == 1: desc = ionS[0] else: desc = '' for aline in num_idx: if ionNum == 1: desc += ' ' + str(wvl[topLines[aline]]) else: desc += ' ' + ionS[topLines[aline]] + ' ' + str( wvl[topLines[aline]]) desc += ' / ' for aline in den_idx: if ionNum == 1: desc += ' ' + str(wvl[topLines[aline]]) else: desc += ' ' + ionS[topLines[aline]] + ' ' + str( wvl[topLines[aline]]) if ndens == ntemp and ntemp > 1: plt.text(0.07, 0.5, desc, horizontalalignment='left', verticalalignment='center', fontsize=fontsize, transform=ax.transAxes) # ax2 = plt.twiny() xlblDen = r'Electron Density (cm$^{-3}$)' plt.xlabel(xlblDen, fontsize=fontsize) plt.loglog(eDensity, numIntens / denIntens, visible=False) ax2.xaxis.tick_top() else: plt.title(desc, fontsize=fontsize) plt.tight_layout() cnt = desc.count(' ') intensityRatioFileName = desc.replace(' ', '_', cnt) + '.rat' intensityRatioFileName = intensityRatioFileName.lstrip('_').replace( '_/_', '-') self.IntensityRatio = { 'ratio': numIntens / denIntens, 'desc': desc, 'temperature': outTemperature, 'eDensity': outDensity, 'filename': intensityRatioFileName, 'numIdx': num_idx, 'denIdx': den_idx }
def intensityList(self, index=-1, wvlRange=None, wvlRanges=None, top=10, relative=0, outFile=0, rightDigits=4): """ List the line intensities. Checks to see if there is an existing Intensity attribute. If it exists, then those values are used. Otherwise, the `intensity` method is called. This method prints an ASCII table with the following columns: 1. Ion: the CHIANTI style notation for the ion, e.g. 'c_4' for C IV 2. lvl1: the lower level of the transition in the CHIANTI .elvlc file 3. lvl2: the upper level of the transition in the CHIANTI .elvlc file 4. lower: the notation, usually in LS coupling, of the lower fine structure level 5. upper: the notation, usually in LS coupling, of the upper fine structure level 6. Wvl(A): the wavelength of the transition in units as specified in the chiantirc file. 7. Intensity 8. A value: the Einstein coefficient for spontaneous emission from level 'j' to level 'i' 9. Obs: indicates whether the CHIANTI database considers this an observed line or one obtained from theoretical energy levels Regarding the intensity column, if 'flux' in the chiantirc file is set to 'energy', the intensity is given by, .. math:: I = \Delta E_{ij}n_jA_{ij}\mathrm{Ab}\\frac{1}{N_e} \\frac{N(X^{+m})}{N(X)}\mathrm{EM}, in units of ergs cm\ :sup:`-2` s\ :sup:`-1` sr\ :sup:`-1`. If 'flux' is set to 'photon', .. math:: I = n_jA_{ij}\mathrm{Ab}\\frac{1}{N_e}\\frac{N(X^{+m})}{N(X)} \mathrm{EM}, where, - :math:`\Delta E_{ij}` is the transition energy (ergs) - :math:`n_j` is the fractions of ions in level :math:`j` - :math:`A_{ij}` is the Einstein coefficient for spontaneous emission from level :math:`j` to level :math:`i` (in s\ :sup:`-1`) - :math:`\mathrm{Ab}` is the abundance of the specified element relative to hydrogen - :math:`N_e` is the electron density (in cm\ :sup:`-3`) - :math:`N(X^{+m})/N(X)` is the fractional ionization of ion as a function of temperature - :math:`\mathrm{EM}` is the emission measure integrated along the line-of-sight, :math:`\int\mathrm{d}l\,N_eN_H` (cm\ :sup:`-5`) where :math:`N_H` is the density of hydrogen (neutral + ionized) (cm\ :sup:`-3`) Note that if `relative` is set, the line intensity is relative to the strongest line and so the output will be unitless. Parameters ----------- index : `int`,optional Index the temperature or eDensity array to use. -1 (default) sets the specified value to the middle of the array wvlRange : `tuple` Wavelength range wvlRanges : a tuple, list or array that contains at least 2 2 element tuples, lists or arrays so that multiple wavelength ranges can be specified top : `int` Number of lines to plot, sorted by descending magnitude. relative : `int` specifies whether to normalize to strongest line default (relative = 0) specified that the intensities should be their calculated values outFile : `str` specifies the file that the intensities should be output to default(outFile = 0) intensities are output to the terminal rightDigits: `int` specifies the format for the wavelengths for the number of digits to right of the decimal place """ if not hasattr(self, 'Intensity'): try: self.intensity() #TODO: specify what exception to catch! or omit the try, catch except: print( ' intensities not calculated and emiss() is unable to calculate them' ) print(' perhaps the temperature and/or eDensity are not set') return temperature = self.Temperature eDensity = self.EDensity em = self.Em ndens = eDensity.size ntemp = temperature.size intens = copy.deepcopy(self.Intensity) if 'errorMessage' in intens.keys(): print(' errorMessage: %s' % (intens['errorMessage'])) return intensity = intens['intensity'] ionS = intens['ionS'] wvl = intens['wvl'] lvl1 = intens['lvl1'] lvl2 = intens['lvl2'] pretty1 = intens['pretty1'] pretty2 = intens['pretty2'] obs = intens['obs'] avalue = intens['avalue'] if ndens == 1 and ntemp == 1: if index < 0: index = 0 dstr = ' - Density = %10.2e (cm$^{-3}$)' % (eDensity[index]) tstr = ' - T = %10.2e (K)' % (temperature[index]) intensity = intensity[index] print(' temperature = %10.2e eDensity = %10.2e' % (temperature[index], eDensity[index])) elif ndens == 1 and ntemp > 1: if index < 0: index = ntemp // 2 print('using index = %5i specifying temperature = %10.2e' % (index, temperature[index])) self.Message = 'using index = %5i specifying temperature = %10.2e' % ( index, temperature[index]) intensity = intensity[index] elif ndens > 1 and ntemp == 1: if index < 0: index = ntemp // 2 print('using index =%5i specifying eDensity = %10.2e' % (index, eDensity[index])) self.Message = 'using index =%5i specifying eDensity = %10.2e' % ( index, eDensity[index]) intensity = intensity[index] elif ndens > 1 and ntemp > 1: if index < 0: index = ntemp // 2 print( 'using index = %5i specifying temperature = %10.2e, eDensity = %10.2e em = %10.2e' % (index, temperature[index], eDensity[index], em[index])) self.Message = 'using index = %5i specifying temperature = %10.2e, eDensity = %10.2e = %10.2e' % ( index, temperature[index], eDensity[index], em[index]) intensity = intensity[index] if wvlRange: wvlIndex = util.between(wvl, wvlRange) elif wvlRanges: wvlIndex = [] for awvlRange in wvlRanges: wvlIndex.extend(util.between(wvl, awvlRange)) else: wvlIndex = range(wvl.size) # get lines in the specified wavelength range intensity = intensity[wvlIndex] ionS = ionS[wvlIndex] wvl = wvl[wvlIndex] lvl1 = lvl1[wvlIndex] lvl2 = lvl2[wvlIndex] avalue = avalue[wvlIndex] pretty1 = pretty1[wvlIndex] pretty2 = pretty2[wvlIndex] obs = obs[wvlIndex] self.Error = 0 if wvl.size == 0: print('No lines in this wavelength interval') self.Error = 1 self.Message = 'No lines in this wavelength interval' return elif top == 0: top = wvl.size elif top > wvl.size: top = wvl.size # sort by intensity isrt = np.argsort(intensity) ionS = ionS[isrt[-top:]] wvl = wvl[isrt[-top:]] lvl1 = lvl1[isrt[-top:]] lvl2 = lvl2[isrt[-top:]] obs = obs[isrt[-top:]] intensity = intensity[isrt[-top:]] avalue = avalue[isrt[-top:]] pretty1 = pretty1[isrt[-top:]] pretty2 = pretty2[isrt[-top:]] # must follow setting top if relative: intensity = intensity / intensity[:top].max() idx = np.argsort(wvl) fmt1 = '%5s %5s %5s %25s - %-25s %12s %12s %12s %3s' fmt = '%5s %5i %5i %25s - %-25s %12.' + str(rightDigits) + \ 'f %12.2e %12.2e %1s' print(' ') print(' ------------------------------------------') print(' ') print(fmt1 % ('Ion', 'lvl1', 'lvl2', 'lower', 'upper', 'Wvl(A)', 'Intensity', 'A value', 'Obs')) for kdx in idx: print(fmt % (ionS[kdx], lvl1[kdx], lvl2[kdx], pretty1[kdx], pretty2[kdx], wvl[kdx], intensity[kdx], avalue[kdx], obs[kdx])) print(' ') print(' ------------------------------------------') print(' ') # self.Intensity['wvlTop'] = wvl[idx] self.Intensity['intensityTop'] = intensity[idx] if outFile: fmt1a = '%5s %5s %5s %25s - %-25s %12s %12s %12s %3s \n' fmt = '%5s %5i %5i %25s - %-25s %12.4' + str(rightDigits) + \ 'f %12.2e %12.2e %1s \n' outpt = open(outFile, 'w') outpt.write(fmt1a % ('Ion', 'lvl1', 'lvl2', 'lower', 'upper', 'Wvl(A)', 'Intensity', 'A value', 'Obs')) for kdx in idx: outpt.write(fmt % (ionS[kdx], lvl1[kdx], lvl2[kdx], pretty1[kdx], pretty2[kdx], wvl[kdx], intensity[kdx], avalue[kdx], obs[kdx])) outpt.close()
def intensityPlot(self, index=-1, wvlRange=None, top=10, linLog='lin', relative=False, verbose=False, plotFile=0, em=0): """ Plot the line intensities. Uses `Intensity` if it already exists. If not, call the `intensity` method. Parameters ----------- index: integer specified which value of the temperature array or eDensity array to use. default (index=-1) sets the specified value to the middle of the array wvlRange: 2 element tuple, list or array determines the wavelength range top: integer specifies to plot only the top strongest lines, default = 10 linLog: str default('lin') produces a plot where the intensity scale is linear if set to 'log', produces a plot where the intensity scale is logarithmic normalize: = 1 specifies whether to normalize to strongest line default (relative = 0) specified that the intensities should be their calculated values plotFile: default=0, the plot is not saved to a file othewise, the plot is saved to the 'plotFile' em: emission measure if an Intensity attribute needs be created, then the emission measure is applied """ if hasattr(self, 'Spectroscopic'): title = self.Spectroscopic else: title = '' if not hasattr(self, 'Intensity'): try: self.intensity() except: print( ' emissivities not calculated and emiss() is unable to calculate them' ) print(' perhaps the temperature and/or eDensity are not set') return wvl = self.Intensity['wvl'] temperature = self.Temperature eDensity = self.EDensity ndens = eDensity.size ntemp = temperature.size if ndens == 1 and ntemp == 1: if index < 0: index = 0 intensity = self.Intensity['intensity'][index] dstr = ' - Density = %10.2e (cm$^{-3}$)' % (eDensity[index]) tstr = ' - T = %10.2e (K)' % (temperature[index]) elif ndens == 1 and ntemp > 1: if index < 0: index = ntemp // 2 print('using index = %5i specifying temperature = %10.2e' % (index, temperature[index])) self.Message = 'using index = %5i specifying temperature = %10.2e' % ( index, temperature[index]) intensity = self.Intensity['intensity'][index] dstr = ' - Density = %10.2e (cm$^{-3}$)' % eDensity tstr = ' - T = %10.2e (K)' % temperature[index] elif ndens > 1 and ntemp == 1: if index < 0: index = ntemp // 2 print('using index =%5i specifying eDensity = %10.2e' % (index, eDensity[index])) self.Message = 'using index =%5i specifying eDensity = %10.2e' % ( index, eDensity[index]) intensity = self.Intensity['intensity'][index] dstr = ' - Density = %10.2e (cm$^{-3}$)' % eDensity[index] tstr = ' - T = %10.2e (K)' % temperature elif ndens > 1 and ntemp > 1: if index < 0: index = ntemp // 2 print( 'using index = %5i specifying temperature = %10.2e, eDensity = %10.2e' % (index, temperature[index], eDensity[index])) self.Message = 'using index = %5i specifying temperature = %10.2e, eDensity = %10.2e' % ( index, temperature[index], eDensity[index]) intensity = self.Intensity['intensity'][index] dstr = ' - Density = %10.2e (cm$^{-3}$)' % eDensity[index] tstr = ' - T = %10.2e (K)' % temperature[index] if wvlRange is not None: wvlIndex = util.between(wvl, wvlRange) else: wvlIndex = range(wvl.size) intensity = intensity[wvlIndex] wvl = wvl[wvlIndex] self.Error = 0 if wvl.size == 0: print('No lines in this wavelength interval') self.Error = 1 self.Message = 'No lines in this wavelength interval' return elif top == 0: top = wvl.size elif wvl.size > top: intsrt = np.argsort(intensity) wvl = wvl[intsrt[-top:]] intensity = intensity[intsrt[-top:]] else: top = wvl.size # must follow setting top plt.figure() ylabel = 'intensity' if relative: intensity = intensity / intensity[-1] ylabel += ' (Relative)' xlbl = 'Wavelength (' + self.Defaults['wavelength'] + ')' ymin = 10.**(np.log10(intensity[0].min()).round(0) - 0.5) plt.ion() for idx in range(top): xx = [wvl[idx], wvl[idx]] if linLog == 'lin': yy = [0., intensity[idx]] plt.plot(xx, yy) else: yy = [ymin / 10., intensity[idx]] plt.semilogy(xx, yy) plt.xlabel(xlbl) plt.ylabel(ylabel) plt.title(title + tstr + dstr) plt.tight_layout() if wvlRange: plt.axis([wvlRange[0], wvlRange[1], ymin, intensity.max()]) if plotFile: plt.savefig(plotFile)
def intensityRatio(self, wvlRange=None, wvlRanges=None, top=10): """ Plot the intensity ratio of 2 lines or sums of lines. Shown as a function of density and/or temperature. For a single wavelength range, set wvlRange = [wMin, wMax] For multiple wavelength ranges, set wvlRanges = [[wMin1,wMax1],[wMin2,wMax2], ...] A plot of relative emissivities is shown and then a dialog appears for the user to choose a set of lines. Parameters ----------- wvlRange : array-like Wavelength range, i.e. min and max wvlRanges: a tuple, list or array that contains at least 2 2 element tuples, lists or arrays so that multiple wavelength ranges can be specified top : `int` specifies to plot only the top strongest lines, default = 10 """ if not hasattr(self, 'Intensity'): try: self.intensity() except: print(' intensities not calculated and emiss() is unable to calculate them') print(' perhaps the temperature and/or eDensity are not set') return fontsize=14 eDensity = self.EDensity temperature = self.Temperature ntemp = temperature.size if ntemp > 0: if temperature[0] == temperature[-1]: ntemp = 1 ndens = eDensity.size if ndens > 0: if eDensity[0] == eDensity[-1]: ndens = 1 print(' ndens = %5i ntemp = %5i'%(ndens, ntemp)) ionS = self.Intensity['ionS'] # see if we are dealing with more than a single ion ionSet = set(ionS) ionNum = len(ionSet) wvl = self.Intensity["wvl"] # find which lines are in the wavelength range if it is set if wvlRange: igvl=util.between(wvl,wvlRange) if len(igvl) == 0: print('no lines in wavelength range %12.2f - %12.2f'%(wvlRange[0], wvlRange[1])) return elif wvlRanges: igvl = [] for awvlRange in wvlRanges: igvl.extend(util.between(wvl,awvlRange)) if len(igvl) == 0: print('no lines in wavelength ranges specified ') return else: igvl=range(len(wvl)) nlines=len(igvl) igvl=np.take(igvl,wvl[igvl].argsort()) if top > nlines: top=nlines intensity = self.Intensity['intensity'] maxIntens = np.zeros(nlines,'Float64') for iline in range(nlines): maxIntens[iline] = intensity[:, igvl[iline]].max() for iline in range(nlines): if maxIntens[iline]==maxIntens.max(): maxAll=intensity[:, igvl[iline]] igvlsort=np.take(igvl,np.argsort(maxIntens)) topLines=igvlsort[-top:] maxWvl='%5.3f' % wvl[topLines[-1]] topLines=topLines[wvl[topLines].argsort()] # need to make sure there are no negative values before plotting good = intensity > 0. intensMin = intensity[good].min() bad = intensity <= 0. intensity[bad] = intensMin ylabel='Intensity relative to '+maxWvl if ionNum == 1: title=self.Spectroscopic else: title = '' if ndens==1 and ntemp==1: print(' only a single temperature and eDensity') return elif ndens == 1: xlabel='Temperature (K)' xvalues=self.Temperature outTemperature=self.Temperature outDensity = self.EDensity desc_str=' Density = %10.2e (cm)$^{-3}$' % self.EDensity[0] elif ntemp == 1: xvalues=self.EDensity outTemperature = self.Temperature outDensity=self.EDensity xlabel=r'$\rm{Electron Density (cm)^{-3}}$' desc_str=' Temp = %10.2e (K)' % self.Temperature[0] else: outTemperature=self.Temperature outDensity=self.EDensity xlabel='Temperature (K)' xvalues=self.Temperature desc_str=' Variable Density' # put all actual plotting here plt.ion() # maxAll is an array ymax = np.max(intensity[:, topLines[0]]/maxAll) ymin = ymax plt.figure() ax = plt.subplot(111) nxvalues=len(xvalues) # reversing is necessary - otherwise, get a ymin=ymax and a matplotlib error for iline in range(top-1, -1, -1): tline=topLines[iline] plt.loglog(xvalues,intensity[:, tline]/maxAll) if np.min(intensity[:, tline]/maxAll) < ymin: ymin = np.min(intensity[:, tline]/maxAll) if np.max(intensity[:, tline]/maxAll) > ymax: ymax = np.max(intensity[:, tline]/maxAll) skip=2 start=divmod(iline,nxvalues)[1] for ixvalue in range(start,nxvalues,nxvalues//skip): if ionNum == 1: text = '%10.4f'%(wvl[tline]) else: text = '%s %10.4f'%(ionS[tline], wvl[tline]) plt.text(xvalues[ixvalue], intensity[ixvalue, tline]/maxAll[ixvalue], text) plt.xlim(xvalues.min(),xvalues.max()) plt.xlabel(xlabel,fontsize=fontsize) plt.ylabel(ylabel,fontsize=fontsize) if ndens == ntemp and ntemp > 1: plt.text(0.07, 0.5,title, horizontalalignment='left', verticalalignment='center', fontsize=fontsize, transform = ax.transAxes) ax2 = plt.twiny() xlabelDen=r'Electron Density (cm$^{-3}$)' plt.xlabel(xlabelDen, fontsize=fontsize) plt.loglog(eDensity,intensity[:, topLines[top-1]]/maxAll, visible=False) ax2.xaxis.tick_top() plt.ylim(ymin/1.2, 1.2*ymax) else: plt.ylim(ymin/1.2, 1.2*ymax) plt.title(title+desc_str,fontsize=fontsize) plt.draw() # need time to let matplotlib finish plotting time.sleep(0.5) # get line selection selectTags = [] for itop in topLines: if ionNum == 1: selectTags.append(str(wvl[itop])) else: selectTags.append(ionS[itop]+ ' '+ str(wvl[itop])) numden = chGui.gui.choice2Dialog(selectTags) # num_idx and den_idx are tuples num_idx=numden.numIndex if len(num_idx) == 0: print(' no numerator lines were selected') return den_idx=numden.denIndex if len(den_idx) == 0: print(' no denominator lines were selected') return numIntens=np.zeros(len(xvalues),'Float64') for aline in num_idx: numIntens += intensity[:, topLines[aline]] denIntens = np.zeros(len(xvalues),'Float64') for aline in den_idx: denIntens += intensity[:, topLines[aline]] # plot the desired ratio # maxAll is an array plt.figure() ax = plt.subplot(111) plt.loglog(xvalues,numIntens/denIntens) plt.xlim(xvalues.min(),xvalues.max()) plt.xlabel(xlabel,fontsize=fontsize) plt.ylabel('Ratio ('+self.Defaults['flux']+')',fontsize=fontsize) if ionNum == 1: desc = ionS[0] else: desc = '' for aline in num_idx: if ionNum == 1: desc += ' ' + str(wvl[topLines[aline]]) else: desc += ' ' + ionS[topLines[aline]] + ' ' + str(wvl[topLines[aline]]) desc += ' / ' for aline in den_idx: if ionNum == 1: desc += ' ' + str(wvl[topLines[aline]]) else: desc += ' ' + ionS[topLines[aline]] + ' ' + str(wvl[topLines[aline]]) if ndens == ntemp and ntemp > 1: plt.text(0.07, 0.5,desc, horizontalalignment='left', verticalalignment='center', fontsize=fontsize, transform = ax.transAxes) # ax2 = plt.twiny() xlabelDen=r'Electron Density (cm$^{-3}$)' plt.xlabel(xlabelDen, fontsize=fontsize) plt.loglog(eDensity,numIntens/denIntens, visible=False) ax2.xaxis.tick_top() else: plt.title(desc,fontsize=fontsize) cnt = desc.count(' ') intensityRatioFileName = desc.replace(' ', '_', cnt) + '.rat' intensityRatioFileName = intensityRatioFileName.lstrip('_').replace('_/_','-') self.IntensityRatio={'ratio':numIntens/denIntens,'desc':desc, 'temperature':outTemperature,'eDensity':outDensity,'filename':intensityRatioFileName, 'numIdx':num_idx, 'denIdx':den_idx}
def intensityPlot(self, index=-1, wvlRange=None, top=10, linLog='lin', relative=False, verbose=False, plotFile=0, em=0 ): """ Plot the line intensities. Uses `Intensity` if it already exists. If not, call the `intensity` method. Parameters ----------- index: integer specified which value of the temperature array or eDensity array to use. default (index=-1) sets the specified value to the middle of the array wvlRange: 2 element tuple, list or array determines the wavelength range top: integer specifies to plot only the top strongest lines, default = 10 linLog: str default('lin') produces a plot where the intensity scale is linear if set to 'log', produces a plot where the intensity scale is logarithmic normalize: = 1 specifies whether to normalize to strongest line default (relative = 0) specified that the intensities should be their calculated values plotFile: default=0, the plot is not saved to a file othewise, the plot is saved to the 'plotFile' em: emission measure if an Intensity attribute needs be created, then the emission measure is applied """ if hasattr(self, 'Spectroscopic'): title = self.Spectroscopic else: title = '' if not hasattr(self, 'Intensity'): try: self.intensity(em=em) except: print(' emissivities not calculated and emiss() is unable to calculate them') print(' perhaps the temperature and/or eDensity are not set') return wvl = self.Intensity['wvl'] temperature = self.Temperature eDensity = self.EDensity ndens = eDensity.size ntemp = temperature.size if ndens == 1 and ntemp == 1: dstr = ' - Density = %10.2e (cm$^{-3}$)' %(eDensity) tstr = ' - T = %10.2e (K)' %(temperature) elif ndens == 1 and ntemp > 1: if index < 0: index = ntemp//2 print('using index = %5i specifying temperature = %10.2e'%(index, temperature[index])) self.Message = 'using index = %5i specifying temperature = %10.2e'%(index, temperature[index]) intensity=self.Intensity['intensity'][index] dstr=' - Density = %10.2e (cm$^{-3}$)' % eDensity tstr=' - T = %10.2e (K)' % temperature[index] elif ndens > 1 and ntemp == 1: if index < 0: index = ntemp//2 print('using index =%5i specifying eDensity = %10.2e'%(index, eDensity[index])) self.Message = 'using index =%5i specifying eDensity = %10.2e'%(index, eDensity[index]) intensity = self.Intensity['intensity'][index] dstr=' - Density = %10.2e (cm$^{-3}$)' % eDensity[index] tstr=' - T = %10.2e (K)' % temperature elif ndens > 1 and ntemp > 1: if index < 0: index = ntemp//2 print('using index = %5i specifying temperature = %10.2e, eDensity = %10.2e'%(index, temperature[index], eDensity[index])) self.Message = 'using index = %5i specifying temperature = %10.2e, eDensity = %10.2e'%(index, temperature[index], eDensity[index]) intensity = self.Intensity['intensity'][index] dstr=' - Density = %10.2e (cm$^{-3}$)' % eDensity[index] tstr=' - T = %10.2e (K)' % temperature[index] if type(wvlRange) != type(None): wvlIndex = util.between(wvl, wvlRange) else: wvlIndex = range(wvl.size) intensity = intensity[wvlIndex] wvl = wvl[wvlIndex] self.Error = 0 if wvl.size == 0: print('No lines in this wavelength interval') self.Error = 1 self.Message = 'No lines in this wavelength interval' return elif top == 0: top = wvl.size elif wvl.size > top: intsrt = np.argsort(intensity) wvl = wvl[intsrt[-top:]] intensity = intensity[intsrt[-top:]] else: top = wvl.size # must follow setting top plt.figure() ylabel = 'intensity' if relative: intensity = intensity/intensity[-1] ylabel += ' (Relative)' xlabel = 'Wavelength ('+self.Defaults['wavelength'] +')' ymin = 10.**(np.log10(intensity[0].min()).round(0)-0.5 ) plt.ion() for idx in range(top): xx=[wvl[idx], wvl[idx]] if linLog == 'lin': yy=[0., intensity[idx]] plt.plot(xx, yy) else: yy=[ymin/10., intensity[idx]] plt.semilogy(xx, yy) plt.xlabel(xlabel) plt.ylabel(ylabel) plt.title(title+tstr+dstr) if wvlRange: plt.axis([wvlRange[0], wvlRange[1], ymin, intensity.max()]) if plotFile: plt.savefig(plotFile)
def intensityList(self, index=-1, wvlRange=None, wvlRanges=None, top=10, relative=0, outFile=0, rightDigits=4 ): """ List the line intensities. Checks to see if there is an existing Intensity attribute. If it exists, then those values are used. Otherwise, the `intensity` method is called. This method prints an ASCII table with the following columns: 1. Ion: the CHIANTI style notation for the ion, e.g. 'c_4' for C IV 2. lvl1: the lower level of the transition in the CHIANTI .elvlc file 3. lvl2: the upper level of the transition in the CHIANTI .elvlc file 4. lower: the notation, usually in LS coupling, of the lower fine structure level 5. upper: the notation, usually in LS coupling, of the upper fine structure level 6. Wvl(A): the wavelength of the transition in units as specified in the chiantirc file. 7. Intensity 8. A value: the Einstein coefficient for spontaneous emission from level 'j' to level 'i' 9. Obs: indicates whether the CHIANTI database considers this an observed line or one obtained from theoretical energy levels Regarding the intensity column, if 'flux' in the chiantirc file is set to 'energy', the intensity is given by, .. math:: I = \Delta E_{ij}n_jA_{ij}\mathrm{Ab}\\frac{1}{N_e} \\frac{N(X^{+m})}{N(X)}\mathrm{EM}, in units of ergs cm\ :sup:`-2` s\ :sup:`-1` sr\ :sup:`-1`. If 'flux' is set to 'photon', .. math:: I = n_jA_{ij}\mathrm{Ab}\\frac{1}{N_e}\\frac{N(X^{+m})}{N(X)} \mathrm{EM}, where, - :math:`\Delta E_{ij}` is the transition energy (ergs) - :math:`n_j` is the fractions of ions in level :math:`j` - :math:`A_{ij}` is the Einstein coefficient for spontaneous emission from level :math:`j` to level :math:`i` (in s\ :sup:`-1`) - :math:`\mathrm{Ab}` is the abundance of the specified element relative to hydrogen - :math:`N_e` is the electron density (in cm\ :sup:`-3`) - :math:`N(X^{+m})/N(X)` is the fractional ionization of ion as a function of temperature - :math:`\mathrm{EM}` is the emission measure integrated along the line-of-sight, :math:`\int\mathrm{d}l\,N_eN_H` (cm\ :sup:`-5`) where :math:`N_H` is the density of hydrogen (neutral + ionized) (cm\ :sup:`-3`) Note that if `relative` is set, the line intensity is relative to the strongest line and so the output will be unitless. Parameters ----------- index : `int`,optional Index the temperature or eDensity array to use. -1 (default) sets the specified value to the middle of the array wvlRange : `tuple` Wavelength range wvlRanges : a tuple, list or array that contains at least 2 2 element tuples, lists or arrays so that multiple wavelength ranges can be specified top : `int` Number of lines to plot, sorted by descending magnitude. relative : `int` specifies whether to normalize to strongest line default (relative = 0) specified that the intensities should be their calculated values outFile : `str` specifies the file that the intensities should be output to default(outFile = 0) intensities are output to the terminal rightDigits: `int` specifies the format for the wavelengths for the number of digits to right of the decimal place """ if not hasattr(self, 'Intensity'): try: self.intensity() #TODO: specify what exception to catch! or omit the try, catch except: print(' intensities not calculated and emiss() is unable to calculate them') print(' perhaps the temperature and/or eDensity are not set') return temperature = self.Temperature eDensity = self.EDensity em = self.Em ndens = eDensity.size ntemp = temperature.size intens = copy.deepcopy(self.Intensity) intensity = intens['intensity'] ionS = intens['ionS'] wvl = intens['wvl'] lvl1 = intens['lvl1'] lvl2 = intens['lvl2'] pretty1 = intens['pretty1'] pretty2 = intens['pretty2'] obs = intens['obs'] avalue = intens['avalue'] if ndens == 1 and ntemp == 1: dstr = ' - Density = %10.2e (cm$^{-3}$)' %(eDensity) tstr = ' - T = %10.2e (K)' %(temperature) elif ndens == 1 and ntemp > 1: if index < 0: index = ntemp//2 print('using index = %5i specifying temperature = %10.2e'%(index, temperature[index])) self.Message = 'using index = %5i specifying temperature = %10.2e'%(index, temperature[index]) intensity=intensity[index] elif ndens > 1 and ntemp == 1: if index < 0: index = ntemp//2 print('using index =%5i specifying eDensity = %10.2e'%(index, eDensity[index])) self.Message = 'using index =%5i specifying eDensity = %10.2e'%(index, eDensity[index]) intensity=intensity[index] elif ndens > 1 and ntemp > 1: if index < 0: index = ntemp//2 print('using index = %5i specifying temperature = %10.2e, eDensity = %10.2e em = %10.2e'%(index, temperature[index], eDensity[index], em[index])) self.Message = 'using index = %5i specifying temperature = %10.2e, eDensity = %10.2e = %10.2e'%(index, temperature[index], eDensity[index], em[index]) intensity=intensity[index] if wvlRange: wvlIndex=util.between(wvl,wvlRange) elif wvlRanges: wvlIndex = [] for awvlRange in wvlRanges: wvlIndex.extend(util.between(wvl,awvlRange)) else: wvlIndex = range(wvl.size) # get lines in the specified wavelength range intensity = intensity[wvlIndex] ionS = ionS[wvlIndex] wvl = wvl[wvlIndex] lvl1 = lvl1[wvlIndex] lvl2 = lvl2[wvlIndex] avalue = avalue[wvlIndex] pretty1 = pretty1[wvlIndex] pretty2 = pretty2[wvlIndex] obs = obs[wvlIndex] self.Error = 0 if wvl.size == 0: print('No lines in this wavelength interval') self.Error = 1 self.Message = 'No lines in this wavelength interval' return elif top == 0: top = wvl.size elif top > wvl.size: top = wvl.size # sort by intensity isrt = np.argsort(intensity) ionS = ionS[isrt[-top:]] wvl = wvl[isrt[-top:]] lvl1 = lvl1[isrt[-top:]] lvl2 = lvl2[isrt[-top:]] obs = obs[isrt[-top:]] intensity = intensity[isrt[-top:]] avalue = avalue[isrt[-top:]] pretty1 = pretty1[isrt[-top:]] pretty2 = pretty2[isrt[-top:]] # must follow setting top if relative: intensity = intensity/intensity[:top].max() idx = np.argsort(wvl) fmt1 = '%5s %5s %5s %25s - %-25s %12s %12s %12s %3s' fmt = '%5s %5i %5i %25s - %-25s %12.' + str(rightDigits) + \ 'f %12.2e %12.2e %1s' print(' ') print(' ------------------------------------------') print(' ') print(fmt1%('Ion','lvl1','lvl2','lower','upper','Wvl(A)','Intensity','A value','Obs')) for kdx in idx: print(fmt%(ionS[kdx], lvl1[kdx], lvl2[kdx], pretty1[kdx], pretty2[kdx], wvl[kdx], intensity[kdx], avalue[kdx], obs[kdx])) print(' ') print(' ------------------------------------------') print(' ') # self.Intensity['wvlTop'] = wvl[idx] self.Intensity['intensityTop'] = intensity[idx] if outFile: fmt1a = '%5s %5s %5s %25s - %-25s %12s %12s %12s %3s \n' fmt = '%5s %5i %5i %25s - %-25s %12.4' + str(rightDigits) + \ 'f %12.2e %12.2e %1s \n' outpt = open(outFile, 'w') outpt.write(fmt1a%('Ion','lvl1','lvl2','lower','upper','Wvl(A)','Intensity','A value','Obs')) for kdx in idx: outpt.write(fmt%(ionS[kdx], lvl1[kdx], lvl2[kdx], pretty1[kdx], pretty2[kdx], wvl[kdx], intensity[kdx], avalue[kdx], obs[kdx])) outpt.close()
def intensityList(self, index=-1, wvlRange=None, wvlRanges=None, top=10, relative=0, outFile=0 ): ''' List the line intensities First, checks to see if there is an existing Intensity attribute. If it exists, then 'intensityList' uses those values. If it does not exist, then 'intensityList' invokes the intensity() method to produce the attribute Arguments. ---------- None Keyword Arguments. ------------------ index: integer specified which value of the temperature array or eDensity array to use. default (index=-1) sets the specified value to the middle of the array wvlRange: 2 element tuple, list or array determines the wavelength range wvlRanges: a tuple, list or array that contains at least 2 2 element tuples, lists or arrays so that multiple wavelength ranges can be specified top: integer specifies to plot only the top strongest lines, default = 10 normalize: = 1 specifies whether to normalize to strongest line default (relative = 0) specified that the intensities should be their calculated values outFile: str specifies the file that the intensities should be output to default(outFile = 0) intensities are output to the terminal Output ------ outputs an ascii table with the following columns Ion: the CHIANTI style notation for the ion, such as, c_4 for C IV lvl1: the lower level of the transition in the CHIANTI .elvlc file lvl2: the upper level of the transition in the CHIANTI .elvlc file lower: the notation, usually in LS coupling, of the lower fine structure level upper: the notation, usually in LS coupling, of the upper fine structure level Wvl(A): the wavelength of the transition, usually in Angstroms. However, other units, such as 'nm' or 'kev' can be specified in the chiantirc file. Intensity: if flux set to 'energy' in chiantirc file (default) intensity = (delta E)_ij * n_j * A_ij * Abund * Ioneq(T) * em where (delta E)_ij is the transition energy in ergs n_j: the fractions of ions in level 'j' A_ij: the Einstein coefficient for spontaneous emission from level 'j' to level 'i' Abund: the abundance of the specified element relative to hydrogen 'H' em: the line-of-sight emission measure - the integral of n_e * n_H dl along the line-of-sight n_e: the electron density (cm^-3) n_H: the density of hydrogen (neutral + ionized) (cm^-3) dl: the line of sight (cm) if flux set to 'photon' in chiantirc file intensity = n_j * A_ij * Abund * Ioneq(T) * em default(relative = 0): the line intensity in ergs cm^-3 s^-1 str^-1 if relative > : the line intensity relative to the strongest line in the specified wavelength range(s) A value: the Einstein coefficient for spontaneous emission from level 'j' to level 'i' Obs: indicates whether the CHIANTI database considers this an observed line or one obtained from theoretical energy levels ''' # # if not hasattr(self, 'Intensity'): try: self.intensity() except: print(' intensities not calculated and emiss() is unable to calculate them') print(' perhaps the temperature and/or eDensity are not set') return # # everything in self.Intensity should be a numpy array # # # temperature = self.Temperature eDensity = self.EDensity em = self.Em # ndens = eDensity.size ntemp = temperature.size # # intens = copy.deepcopy(self.Intensity) intensity = intens['intensity'] ionS = intens['ionS'] wvl = intens['wvl'] lvl1 = intens['lvl1'] lvl2 = intens['lvl2'] pretty1 = intens['pretty1'] pretty2 = intens['pretty2'] obs = intens['obs'] avalue = intens['avalue'] # if ndens == 1 and ntemp == 1: dstr = ' - Density = %10.2e (cm$^{-3}$)' %(eDensity) tstr = ' - T = %10.2e (K)' %(temperature) elif ndens == 1 and ntemp > 1: if index < 0: index = ntemp//2 print('using index = %5i specifying temperature = %10.2e'%(index, temperature[index])) self.Message = 'using index = %5i specifying temperature = %10.2e'%(index, temperature[index]) intensity=intensity[index] elif ndens > 1 and ntemp == 1: if index < 0: index = ntemp//2 print('using index =%5i specifying eDensity = %10.2e'%(index, eDensity[index])) self.Message = 'using index =%5i specifying eDensity = %10.2e'%(index, eDensity[index]) intensity=intensity[index] elif ndens > 1 and ntemp > 1: if index < 0: index = ntemp//2 print('using index = %5i specifying temperature = %10.2e, eDensity = %10.2e em = %10.2e'%(index, temperature[index], eDensity[index], em[index])) self.Message = 'using index = %5i specifying temperature = %10.2e, eDensity = %10.2e = %10.2e'%(index, temperature[index], eDensity[index], em[index]) intensity=intensity[index] # # print('shpae of intensity 0 = %5i %5i'%(intensity.shape)) # if wvlRange: wvlIndex=util.between(wvl,wvlRange) elif wvlRanges: wvlIndex = [] for awvlRange in wvlRanges: wvlIndex.extend(util.between(wvl,awvlRange)) else: wvlIndex = range(wvl.size) # # get lines in the specified wavelength range # # print('shpae of intensity 1 = %5i %5i'%(intensity.shape)) # intensity = intensity[wvlIndex] ionS = ionS[wvlIndex] wvl = wvl[wvlIndex] lvl1 = lvl1[wvlIndex] lvl2 = lvl2[wvlIndex] avalue = avalue[wvlIndex] pretty1 = pretty1[wvlIndex] pretty2 = pretty2[wvlIndex] obs = obs[wvlIndex] # self.Error = 0 if wvl.size == 0: print('No lines in this wavelength interval') self.Error = 1 self.Message = 'No lines in this wavelength interval' return # elif top == 0: top = wvl.size elif top > wvl.size: top = wvl.size # # sort by intensity # isrt = np.argsort(intensity) ionS = ionS[isrt[-top:]] wvl = wvl[isrt[-top:]] lvl1 = lvl1[isrt[-top:]] lvl2 = lvl2[isrt[-top:]] obs = obs[isrt[-top:]] intensity = intensity[isrt[-top:]] avalue = avalue[isrt[-top:]] pretty1 = pretty1[isrt[-top:]] pretty2 = pretty2[isrt[-top:]] # # print('shpae of intensity 2= %5i %5i'%(intensity.shape)) # # must follow setting top # if relative: intensity = intensity/intensity[:top].max() # # idx = np.argsort(wvl) fmt1 = '%5s %5s %5s %25s - %-25s %12s %12s %12s %3s' fmt = '%5s %5i %5i %25s - %-25s %12.4f %12.3e %12.2e %1s' print(' ') print(' ------------------------------------------') print(' ') print(fmt1%('Ion','lvl1','lvl2','lower','upper','Wvl(A)','Intensity','A value','Obs')) for kdx in idx: print(fmt%(ionS[kdx], lvl1[kdx], lvl2[kdx], pretty1[kdx], pretty2[kdx], wvl[kdx], intensity[kdx], avalue[kdx], obs[kdx])) print(' ') print(' ------------------------------------------') print(' ') # self.Intensity['wvlTop'] = wvl[idx] self.Intensity['intensityTop'] = intensity[idx] if outFile: fmt1a = '%5s %5s %5s %25s - %-25s %12s %12s %12s %3s \n' fmt = '%5s %5i %5i %25s - %-25s %12.4f %12.3e %12.2e %1s \n' outpt = open(outFile, 'w') outpt.write(fmt1a%('Ion','lvl1','lvl2','lower','upper','Wvl(A)','Intensity','A value','Obs')) for kdx in idx: outpt.write(fmt%(ionS[kdx], lvl1[kdx], lvl2[kdx], pretty1[kdx], pretty2[kdx], wvl[kdx], intensity[kdx], avalue[kdx], obs[kdx])) outpt.close()