def get_atom_str(atom): """ return atom with leading 0. eg: get_atom_str('Mg5') -> Mg005 """ ato, ion = parseAtom(atom) return('{}{:03d}'.format(remove_iso(ato), int(ion)))
def get_atom_str(atom): """ return atom with leading 0. eg: get_atom_str('Mg5') -> Mg005 """ ato, ion = parseAtom(atom) return ('{}{:03d}'.format(remove_iso(ato), int(ion)))
def p5(): # this will plot all the available data in pyneb for the omegas ions = [ 'C2', 'C3', 'N2', 'N3', 'O2', 'O3', 'O4', 'Ne2', 'Ne3', 'Ne5', 'S2', 'S3', 'S4', 'Cl3', 'Ar2', 'Ar3', 'Ar4', 'Ar5', ] for ion in ions: # split ion into elem and spec, e.g 'O3' into 'O' and 3 elem, spec = parseAtom(ion) # instanciate the corresponding Atom object atom = pn.Atom(elem, spec) # print information including transition probabilities #atom.printIonic(printA = True) dp = pn.DataPlot(elem, spec) dp.plotOmega(save=True)
def plot_2comp(tem1=1e4, tem2=1e4, dens1=3e2, dens2=5e5, mass1=1, mass2=5e-4): # List of diagnostics used to analyze the region diags = pn.Diagnostics() diags.addDiag([ '[NI] 5198/5200', '[NII] 5755/6548', '[OII] 3726/3729', '[OII] 3727+/7325+', '[OIII] 4363/5007', '[ArIII] 5192/7136', '[ArIII] 5192/7300+', '[ArIV] 4740/4711', '[ArIV] 7230+/4720+', '[SII] 6731/6716', '[SII] 4072+/6720+', '[SIII] 6312/9069', '[ClIII] 5538/5518' ]) """ for diag in pn.diags_dict: if diag[0:7] != '[FeIII]': diags.addDiag(diag) print('Adding', diag) diags.addClabel('[SIII] 6312/9069', '[SIII]A') diags.addClabel('[OIII] 4363/5007', '[OIII]A') """ # Define all the ions that are involved in the diagnostics adict = diags.atomDict pn.log_.message('Atoms built') obs = pn.Observation(corrected=True) for atom in adict: # Computes all the intensities of all the lines of all the ions considered for line in pn.LINE_LABEL_LIST[atom]: if line[-1] == 'm': wavelength = float(line[:-1]) * 1e4 else: wavelength = float(line[:-1]) elem, spec = parseAtom(atom) intens1 = adict[atom].getEmissivity( tem1, dens1, wave=wavelength) * dens1 * mass1 intens2 = adict[atom].getEmissivity( tem2, dens2, wave=wavelength) * dens2 * mass2 obs.addLine( pn.EmissionLine( elem, spec, wavelength, obsIntens=[intens1, intens2, intens1 + intens2], obsError=[0.0, 0.0, 0.0])) pn.log_.message('Virtual observations computed') emisgrids = pn.getEmisGridDict(atomDict=adict) pn.log_.message('EmisGrids available') # Produce a diagnostic plot for each of the two regions and another one for the # (misanalyzed) overall region f, axes = plt.subplots(2, 2) diags.plot(emisgrids, obs, i_obs=0, ax=axes[0, 0]) diags.plot(emisgrids, obs, i_obs=1, ax=axes[0, 1]) diags.plot(emisgrids, obs, i_obs=2, ax=axes[1, 0])
def p1(ion): # split ion into elem and spec, e.g 'O3' into 'O' and 3 elem, spec = parseAtom(ion) # instanciate the corresponding Atom object atom = pn.Atom(elem, spec) # print information including transition probabilities #atom.printIonic(printA = True) # prepare a new figure plt.figure() # plot energy levels atom.plotGrotrian()
def plot_2comp(tem1=1e4, tem2=1e4, dens1=3e2, dens2=5e5, mass1=1, mass2=5e-4): # List of diagnostics used to analyze the region diags = pn.Diagnostics() for diag in pn.diags_dict: if diag[0:7] != '[FeIII]': diags.addDiag(diag) diags.addClabel('[SIII] 6312/9069', '[SIII]A') diags.addClabel('[OIII] 4363/5007', '[OIII]A') # Define all the ions that are involved in the diagnostics all_atoms = diags.atomDict pn.log_.message('Atoms built') obs = pn.Observation(corrected=True) for atom in all_atoms: # Computes all the intensities of all the lines of all the ions considered for wavelength in all_atoms[atom].lineList: elem, spec = parseAtom(atom) intens1 = all_atoms[atom].getEmissivity( tem1, dens1, wave=wavelength) * dens1 * mass1 intens2 = all_atoms[atom].getEmissivity( tem2, dens2, wave=wavelength) * dens2 * mass2 obs.addLine( pn.EmissionLine( elem, spec, wavelength, obsIntens=[intens1, intens2, intens1 + intens2], obsError=[0.0, 0.0, 0.0])) pn.log_.message('Virtual observations computed') emisgrids = pn.getEmisGridDict(atomDict=all_atoms) pn.log_.message('EmisGrids available') # Produce a diagnostic plot for each of the two regions and another one for the (misanalyzed) overall region plt.subplot(2, 2, 1) diags.plot(emisgrids, obs, i_obs=0) plt.subplot(2, 2, 2) diags.plot(emisgrids, obs, i_obs=1) plt.subplot(2, 1, 2) pn.log_.level = 3 diags.plot(emisgrids, obs, i_obs=2)
def p2(diag): # get the ion, and diagnostic description from the dictionary: ion, diag_eval, err = pn.diags_dict[diag] # split ion into elem and spec, e.g 'O3' into 'O' and 3 elem, spec = parseAtom(ion) # prepare a new figure plt.figure() # create a grid of emissivities #NB: one can use a pypic file containing all the emissivities, if already made # in that case set restore_file to the name of the pypic file. grid = pn.EmisGrid(elem, spec, restore_file=None, OmegaInterp='Linear') # plot the contours grid.plotContours(to_eval=diag_eval, low_level=None, high_level=None, n_levels=20, linestyles='-', clabels=True, log_levels=True, title='{0} {1}'.format(ion, diag_eval)) # save the plot into pdf files plt.savefig('{0}_{1}.pdf'.format(ion, diag_eval.replace('/', '_')))
def getCrossTemDen(self, diag_tem, diag_den, value_tem=None, value_den=None, obs=None, i_obs=None, guess_tem=10000, tol_tem=1., tol_den=1., max_iter=5, maxError=1e-3, start_tem= -1, end_tem= -1, start_den= -1, end_den= -1): """ Cross-converge the temperature and density derived from two sensitive line ratios, by inputting the quantity derived with one line ratio into the other and then iterating. The temperature- and density-sensitive ratios can be input directly or as an Observation object Parameters: - diag_tem temperature-sensitive diagnostic line ratio - diag_den density-sensitive diagnostic line ratio - value_tem value of the temperature-sensitive diagnostic - value_den value of the density-sensitive diagnostic - obs np.Observation object. Values for observed temperature and density diagnostics are taken from it if value_tem and value_den are None - i_obs index of the observations to be used from obs. If None, all the observations are considered. May be a boolean array - guess_tem temperature assumed in the first iteration, in K - tol_tem tolerance of the temperature result, in % - tol_den tolerance of the density result, in % - max_iter maximum number of iterations to be performed, after which the function will throw a result - maxError maximum error in the calls to getTemDen, in % - start_tem, end_tem lower and upper limit of the explored temperature range - start_den, end_den lower and upper limit of the explored density range Example: tem, den = diags.getCrossTemDen('[OIII] 4363/5007', '[SII] 6731/6716', 0.0050, 1.0, guess_tem=10000, tol_tem = 1., tol_den = 1., max_iter = 5) """ # TODO: # Define a lower/upper density and temperature # to be used in case the diag is pointing to values out of the boundaires if diag_tem not in self.diags: self.addDiag(diag_tem) atom_tem = self.diags[diag_tem][0] elem_tem, spec_tem = parseAtom(atom_tem) if atom_tem not in self.atomDict: self.atomDict[atom_tem] = pn.Atom(elem_tem, spec_tem, self.OmegaInterp, NLevels=self.NLevels) atom_tem = self.atomDict[atom_tem] if diag_den not in self.diags: self.addDiag(diag_den) atom_den = self.diags[diag_den][0] elem_den, spec_den = parseAtom(self.diags[diag_den][0]) if (atom_den) not in self.atomDict: self.atomDict[atom_den] = pn.Atom(elem_den, spec_den, self.OmegaInterp, NLevels=self.NLevels) atom_den = self.atomDict[atom_den] eval_tem = self.diags[diag_tem][1] eval_den = self.diags[diag_den][1] calling = 'Diag.getCrossTemDen %s %s' % (diag_tem, diag_den) if value_tem is None: def L(wave): if i_obs is None: return obs.getLine(elem_tem, spec_tem, wave).corrIntens else: return obs.getLine(elem_tem, spec_tem, wave).corrIntens[i_obs] def I(i, j): wave = atom_tem.wave_Ang[i - 1, j - 1] if i_obs is None: return obs.getLine(elem_tem, spec_tem, wave).corrIntens else: return obs.getLine(elem_tem, spec_tem, wave).corrIntens[i_obs] def B(label, I=I, L=L): full_label = elem_tem + spec_tem + '_' + label if i_obs is None: corrIntens = obs.getLine(label=full_label).corrIntens else: corrIntens = obs.getLine(label=full_label).corrIntens[i_obs] return corrIntens #pn.log_.debug('to eval is {0}'.format(eval_tem), calling=calling + 'TEST') try: value_tem = eval(eval_tem) #pn.log_.debug('to eval = {0}'.format(value_tem), calling=calling + 'TEST') except: pn.log_.warn('No value for {0} {1}: {2} in obs'.format(elem_tem, spec_tem, diag_tem), calling=calling) return None else: if type(value_tem) == type([]): value_tem = np.asarray(value_tem) if value_den is None: def L(wave): if i_obs is None: return obs.getLine(elem_den, spec_den, wave).corrIntens else: return obs.getLine(elem_den, spec_den, wave).corrIntens[i_obs] def I(i, j): wave = atom_den.wave_Ang[i - 1, j - 1] pn.log_.debug('wave is {0}'.format(wave), calling=calling + 'TEST3') if i_obs is None: return obs.getLine(elem_den, spec_den, wave).corrIntens else: return obs.getLine(elem_den, spec_den, wave).corrIntens[i_obs] def B(label, I=I, L=L): full_label = elem_den + spec_den + '_' + label if i_obs is None: corrIntens = obs.getLine(label=full_label).corrIntens else: corrIntens = obs.getLine(label=full_label).corrIntens[i_obs] return corrIntens #pn.log_.debug('to eval is {0}'.format(eval_den), calling=calling + ' TEST') try: value_den = eval(eval_den) #pn.log_.debug('to eval = {0}'.format(value_den), calling=calling + ' TEST1') except: pn.log_.warn('No value for {0} {1}: {2} in obs'.format(elem_den, spec_den, diag_den), calling=calling) return None else: if type(value_den) == type([]): value_den = np.asarray(value_den) den = atom_den.getTemDen(value_den, tem=guess_tem, to_eval=eval_den, maxError=maxError, start_x=start_den, end_x=end_den) tem = atom_tem.getTemDen(value_tem, den=den, to_eval=eval_tem, maxError=maxError, start_x=start_tem, end_x=end_tem) # self.log_.debug('tem: ' + str(tem) + ' den:' + str(den), calling='getCrossTemDen') no_conv = np.ones_like(den).astype(bool) n_tot = np.asarray(value_tem).size for i in np.arange(max_iter): if type(tem) == type(1.): tem_old = tem else: tem_old = tem.copy() if type(den) == type(1.): den_old = den else: den_old = den.copy() if n_tot > 1: den[no_conv] = atom_den.getTemDen(value_den[no_conv], tem=tem_old[no_conv], to_eval=eval_den, start_x=start_den, end_x=end_den) tem[no_conv] = atom_tem.getTemDen(value_tem[no_conv], den=den_old[no_conv], to_eval=eval_tem, start_x=start_tem, end_x=end_tem) else: den = atom_den.getTemDen(value_den, tem=tem_old, to_eval=eval_den, start_x=start_den, end_x=end_den) tem = atom_tem.getTemDen(value_tem, den=den_old, to_eval=eval_tem, start_x=start_tem, end_x=end_tem) no_conv = ((abs(den_old - den) / den * 100) > tol_den) | ((abs(tem_old - tem) / tem * 100) > tol_tem) if type(no_conv) == type(True): n_no_conv = int(no_conv) else: n_no_conv = no_conv.sum() pn.log_.message('{0} (max={1}): not converged {2} of {3}.'.format(i, max_iter, n_no_conv, n_tot), calling=calling) if n_no_conv == 0: return tem, den if n_tot == 1: tem = np.nan den = np.nan else: tem[no_conv] = np.nan den[no_conv] = np.nan return tem, den
def addDiag(self, label=None, diag_tuple=None, atom=None, wave_range=None): """ Add diagnostics to the list of available diagnostics. It can either be one of the built-in diagnostics, a new, user-defined one, or a subset of the built-in diagnostics corresponding to a given atom or wavelength. Parameters: - label a string or a list of strings describing the diagnostic, e.g. '[OIII] 4363/5007'. If it is not a key of diags_dict (a diagnostic define by PyNeb), diag_tuple must also be specified - diag_tuple a 3 elements tuple containing: + the atom, e.g. 'Ar5' + the algebraic description of the diagnostic, in terms of line wavelengths or blends or levels, e.g. '(L(6435)+L(7006))/L(4626)' + the algebraic description of the error, e.g. 'RMS([E(6435)*L(6435)/(L(6435)+L(7006)), E(7006)*L(7006)/(L(6435)+L(7006)), E(4626)])' - atom the selected atom, e.g. 'O3' - wave_range the selected wavelength range Usage: diags.addDiag('[OIII] 4363/5007') diags.addDiag('[OIII] 5007/51m', ('O3', 'L(5007)/L(51800)', 'RMS([E(51800), E(5007)])')) diags.addDiag(atom='O3') diags.addDiag(wave_range=[4000, 6000]) """ if type(label) is list: for lab in label: self.addDiag(lab) elif label in self.diags: self.log_.warn('{0} already in diagnostic'.format(label), calling=self.calling) elif label in diags_dict: self.log_.message('Adding diag {0}'.format(label), calling=self.calling) self.diags[label] = diags_dict[label] atom = diags_dict[label][0] elif type(diag_tuple) is tuple: if len(diag_tuple) == 3: self.diags[label] = diag_tuple atom = diag_tuple[0] else: self.log_.error('{0} is not in the list of diagnostics. The parameter diag_tuple must be a 3-elements tuple describing the diagnostic'.format(label), calling=self.calling + '.addDiag') elif atom is not None: for label in diags_dict: if diags_dict[label][0] == atom: self.addDiag(label) # if atom not in self.atomDict: # self.atomDict[atom] = pn.Atom(parseAtom(atom)[0], parseAtom(atom)[1]) elif wave_range is not None: # To be done: add the possibility to use several independent ranges. The following bit does the trick, but # only if all the wavelengths of a diagnostic are included in the same range # if type(wave_range[0]) is list: # for subrange in wave_range: # self.addDiag(label, diag_tuple, atom, subrange) for label in diags_dict: expr = diags_dict[label][1] waves = [] wave = '' in_wave = False for i in expr: if i.isdigit(): wave = wave + i in_wave = True elif (i == 'm'): if in_wave == True: waves.append(int(wave) * 10000.) in_wave = False wave = '' else: if in_wave == True: waves.append(int(wave)) in_wave = False wave = '' if (min(waves) > min(wave_range)) and (max(waves) < max(wave_range)): self.addDiag(label) else: self.log_.error('Bad syntax. You must either give the label of an existing diagnostic, or the label and the tuple of a new one,' + 'or an ion, or a wave range. label={0}, diag_tuple={1}, atom={2}, wave_range={3}'.format(label, diag_tuple, atom, wave_range), calling=self.calling + '.addDiag') if atom not in self.atomDict and (type(label) is not list): self.atomDict[atom] = pn.Atom(parseAtom(atom)[0], parseAtom(atom)[1], NLevels=self.NLevels)
def __init__(self, elem=None, spec=None, all_data=[], atom=None, n_tem_points=10000, ref_tem=None, OmegaInterp='linear', NLevels=None): """ Parameters: - elem atomic elem - spec ionization stage in spectroscopic notation (I = 1, II = 2, etc.) - atom e.g. 'O3' - all_data dictionary of all_data to be compared (see above for format) - [n_tem_points] number of points in the fit (default=100; increase if fit is not smooth) - [ref_tem] array of temperature values to be signaled in the plots - OmegaInterp interpolating function between Omega values ('Cheb' [default], 'Linear') Example: dataplot = pn.DataPlot('O', 3) # initializes the plot dataplot.plotA() # transition probabilities plot dataplot.plotRelA() # relative transition probabilities plot dataplot.plotOmega() # collision strength plot """ colors = np.array(['r', 'g', 'b', 'm', 'c', 'y']) self.calling = 'DataPlot' if atom is not None: self.atom = str.capitalize(atom) self.elem = parseAtom(self.atom)[0] self.spec = int(parseAtom(self.atom)[1]) else: self.elem = str.capitalize(elem) self.spec = int(spec) self.atom = self.elem + str(self.spec) old_data = pn.atomicData.getDataFile(self.atom) # Check if matplotlib installed if not pn.config.INSTALLED['plt']: pn.log_.warn('Matplotlib not installed!', calling=self.calling) # Separate omega and A data sets atom_data = [] coll_data = [] if all_data == []: all_data = pn.atomicData.getAllAvailableFiles(self.atom, mark_current=False) i_colors = 0 for file_ in all_data: ID = file_.split('_')[-1] type_ = (file_.split('_')[2]).split('.')[0] if type_ in ['atom', 'coll']: data_list = type_ + '_data' vars()[data_list].append({ 'ID': ID, 'file_': file_, 'type': type_, 'color': colors[i_colors % len(colors)] }) i_colors += 1 self.atom_data = atom_data self.coll_data = coll_data # Temperature values to be signaled by vertical lines in omega plots. Can be changed by defining ref_tem if ref_tem is None: self.ref_tem = np.log10([5000., 10000., 20000.]) else: self.ref_tem = ref_tem # If it's not standard effective collision strengths, we don't want it coll_data_temp = [] for item in self.coll_data: coll_data_temp.append(item) for data in coll_data_temp: pn.atomicData.setDataFile(data['file_']) atom = pn.Atom(self.elem, self.spec, OmegaInterp=OmegaInterp, NLevels=NLevels) """ try: if 'O_UNIT' in atom.CollData.comments.keys(): self.coll_data.remove(data) except: pass """ # For each data set, an atom is built. del (atom) for data in self.atom_data + self.coll_data: pn.atomicData.setDataFile(data['file_']) atom = pn.Atom(self.elem, self.spec, OmegaInterp=OmegaInterp, NLevels=NLevels) data['atom'] = atom for data in old_data: if data is not None: pn.atomicData.setDataFile(data) self.atom_rom = (self.elem + '_' + int_to_roman(int(self.spec))).lower() self.n_tem_points = n_tem_points self.atom_n_max = 0 for at in self.atom_data: if at['atom'].atomFileType != 'chianti': if at['atom'].atomNLevels > self.atom_n_max: self.atom_n_max = at['atom'].atomNLevels self.coll_n_max = 0 for at in self.coll_data: if at['atom'].collFileType != 'chianti': if at['atom'].collNLevels > self.coll_n_max: self.coll_n_max = at['atom'].collNLevels
def get_atoms_by_Z(extra_file=None, atoms=None): if atoms is None: atoms = get_atoms_by_name(extra_file=extra_file) return sorted(atoms, key=lambda k: Z[parseAtom(remove_iso(k))[0]])
""" 'phyat_list_DP_01.dat' """ atoms = pn.atomicData.getAllAtoms() atoms.extend(get_extra_atoms(extra_file, uniq=True)) atoms.remove('3He2') return sorted(atoms, key=get_atom_str) def get_atoms_by_Z(extra_file=None, atoms=None): if atoms is None: atoms = get_atoms_by_name(extra_file=extra_file) return sorted(atoms, key=lambda k: Z[parseAtom(remove_iso(k))[0]]) ZmI = lambda atom: Z[parseAtom(remove_iso(atom))[0]] - int( parseAtom(remove_iso(atom))[1]) def get_atoms_by_ZmI(extra_file=None, atoms=None): atoms = get_atoms_by_Z(extra_file=extra_file, atoms=atoms) return sorted(atoms, key=ZmI) def get_atoms_by_conf(extra_file=None, atoms=None): if atoms is None: atoms = get_atoms_by_ZmI(extra_file=extra_file) res = [] gss = {} for atom in atoms: gss[remove_iso(atom)] = gsFromAtom(remove_iso(atom))
def get_atoms_by_Z(extra_file=None, atoms=None): if atoms is None: atoms = get_atoms_by_name(extra_file=extra_file) return sorted(atoms, key=lambda k:Z[parseAtom(remove_iso(k))[0]])
def get_atoms_by_name(extra_file=None): """ 'phyat_list_DP_01.dat' """ atoms = pn.atomicData.getAllAtoms() atoms.extend(get_extra_atoms(extra_file, uniq=True)) atoms.remove('3He2') return sorted(atoms, key=get_atom_str) def get_atoms_by_Z(extra_file=None, atoms=None): if atoms is None: atoms = get_atoms_by_name(extra_file=extra_file) return sorted(atoms, key=lambda k:Z[parseAtom(remove_iso(k))[0]]) ZmI = lambda atom: Z[parseAtom(remove_iso(atom))[0]] - int(parseAtom(remove_iso(atom))[1]) def get_atoms_by_ZmI(extra_file=None, atoms=None): atoms = get_atoms_by_Z(extra_file=extra_file, atoms=atoms) return sorted(atoms, key=ZmI) def get_atoms_by_conf(extra_file=None, atoms=None): if atoms is None: atoms = get_atoms_by_ZmI(extra_file=extra_file) res = [] gss = {} for atom in atoms: gss[remove_iso(atom)] = gsFromAtom(remove_iso(atom)) for gs in ('s1', 's2', 'p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'd1', 'd2', 'd3', 'd4', 'd5', 'd6', 'd7', 'd8', 'd9', 'd10',