def trans_emis_label(label): trans_dic = {} trans_dic['BLND 5199.00A'] = 'N 1 5199.00A' trans_dic['BLND 4363.00A'] = 'O 3 4363.00A' trans_dic['BLND 7323.00A'] = 'O 2 7323.00A' trans_dic['BLND 5755.00A'] = 'N 2 5755.00A' trans_dic['BLND 7332.00A'] = 'O 2 7332.00A' trans_dic['BLND 1909.00A'] = 'C 3 1909.00A' trans_dic['BLND 2326.00A'] = 'C 2 2326.00A' trans_dic['BLND 3726.00A'] = 'O 2 3726.00A' trans_dic['BLND 3729.00A'] = 'O 2 3729.00A' trans_dic['Ca B 5875.64A'] = 'He 1 5875.64A' if label in trans_dic: new_label = trans_dic[label] else: new_label = label elem, ion, wlstr = new_label.split() if ion == 'B': ion = '1' elem = 'H' wlr = wlstr[-1] wl = float(wlstr[:-1]) if elem in ('H', 'He'): if wlr == 'A': out_label = '~{}{} {:.0f}\AA'.format(elem, int_to_roman(int(ion)), wl) elif wlr == 'm': out_label = '~{}{} {:.2f}$\mu$m'.format(elem, int_to_roman(int(ion)), wl) else: if wlr == 'A': out_label = '~[{}{}] {:.0f}\AA'.format(elem, int_to_roman(int(ion)), wl) elif wlr == 'm': out_label = '~[{}{}] {:.2f}$\mu$m'.format(elem, int_to_roman(int(ion)), wl) return out_label
def plot(self, emis_grids, obs, quad=True, i_obs=None, alpha=0.3, ax=None, error_band=True): """ PLotting tool to generate Te-Ne diagrams. Usage: diags.plot(emisgrids, obs, i_obs=3) Parameters: - emis_grids A dictionary of EmisGrid objects refereed by their atom strings (e.g. 'O3') This can for example be the output of pn.getEmisGridDict() - obs A pn.Observation object that is supposed to contain the line intensities used for the plot (corrected intensities). - quad If True (default) the sum of the error is quadratic,otherwise is linear. - i_obs reference for the observation to be plotted, in case there is more than one in the obs object - alpha Transparency for the error bands in the plot - error_band Boolean: plot [default] an error band """ if not pn.config.INSTALLED['plt']: pn.log_.error('Matplotlib not available, no plot', calling=self.calling + '.plot') return None else: import matplotlib.pyplot as plt if type(emis_grids) != type({}): self.log_.error('the first parameter must be a dictionary', calling=self.calling + '.plot') return None for em in emis_grids: if not isinstance(emis_grids[em], pn.EmisGrid): self.log_.error('the first parameter must be a dictionary of EmisGrid', calling=self.calling + '.plot') return None if not isinstance(obs, pn.Observation): self.log_.error('the second parameter must be an Observation', calling=self.calling + '.plot') return None if (i_obs is None) and (obs.n_obs != 1): self.log_.error('i_obs must be specified when obs is multiple. try i_obs=0', calling=self.calling) return None if ax is None: f, ax = plt.subplots() else: f = plt.gcf() X = np.log10(emis_grids[list(emis_grids.keys())[0]].den2D) Y = emis_grids[list(emis_grids.keys())[0]].tem2D for label in self.diags: diag = self.diags[label] atom = diag[0] def I(i, j): return emis_grids[atom].getGrid(lev_i=i, lev_j=j) def L(wave): return emis_grids[atom].getGrid(wave=wave) def S(label): return emis_grids[atom].getGrid(label=label) def B(label, I=I, L=L): full_label = atom + '_' + label if full_label in BLEND_LIST: to_eval = BLEND_LIST[full_label] else: self.log_.warn('{0} not in BLEND_LIST'.format(full_label), calling=self.calling) return None return eval(to_eval) diag_map = eval(diag[1]) try: diag_map = eval(diag[1]) except: diag_map = None self.log_.warn('diag {0} {1} not used'.format(diag[0], diag[1]), calling=self.calling) if diag_map is not None: sym, spec, rec = parseAtom2(atom) def I(i, j): wave = emis_grids[atom].atom.wave_Ang[i - 1, j - 1] corrIntens = obs.getLine(sym, spec, wave).corrIntens if i_obs is None: return corrIntens else: return corrIntens[i_obs] def L(wave): corrIntens = obs.getLine(sym, spec, wave).corrIntens if i_obs is None: return corrIntens else: return corrIntens[i_obs] def S(label): full_label = atom + '_' + label + 'A' corrIntens = obs.getLine(label=full_label).corrIntens if i_obs is None: return corrIntens else: return corrIntens[i_obs] def B(label): full_label = atom + '_' + label corrIntens = obs.getLine(label=full_label).corrIntens if i_obs is None: return corrIntens else: return corrIntens[i_obs] try: ee = eval(diag[1]) if type(ee) == np.float64: diag_value = ee else: diag_value = ee[0] except: #print(ee, type(ee)) diag_value = None self.log_.warn('A line in diagnostic {0} of {1}{2} is missing'.format(diag[1], sym, spec), calling=self.calling) if diag_value is not None and not np.isnan(diag_value) and not np.isinf(diag_value): def E(wave): err = obs.getLine(sym, spec, wave).corrError if i_obs is None: return err else: return err[i_obs] def BE(label): full_label = atom + '_' + label err = obs.getLine(label=full_label).corrError if i_obs is None: return err else: return err[i_obs] def SE(label): full_label = atom + '_' + label + 'A' err = obs.getLine(label=full_label).corrError if i_obs is None: return err else: return err[i_obs] if quad is True: RMS = lambda err: np.sqrt((np.asarray(err) ** 2.).sum()) else: RMS = lambda err: (np.asarray(err)).sum() tol_value = eval(diag[2]) col_dic = {'C':'cyan', 'N':'blue', 'O':'green', 'Ne':'magenta', 'Ar':'red', 'Cl':'magenta', 'S':'black', 'Fe':'blue'} col = col_dic[sym] style_dic = {'1':'-', '2':'--', '3':':', '4':'-.', '5':'-', '6':'--'} style = style_dic[spec] if tol_value > 0. and error_band: levels = [(1 - tol_value) * diag_value, (1 + tol_value) * diag_value] if levels[0] < levels[1]: #pn.log_.debug('{} levels {}'.format(label, levels), calling=self.calling) CS = ax.contourf(X, Y, diag_map, levels=levels, alpha=alpha, colors=col) CS = ax.contour(X, Y, diag_map, levels=[diag_value], colors=col, linestyles=style) ax.set_xlabel(r'log(n$_{\rm e}$) [cm$^{-3}$]') ax.set_ylabel(r'T$_{\rm e}$ [K]') if len(diag) >= 4: fmt = diag[3] else: fmt = '[{0}{1}]'.format(sym, int_to_roman(int(spec))) ax.clabel(CS, inline=True, fmt=fmt, fontsize=15, colors=col) if type(diag_value) is np.ndarray: diag_value = diag_value[0] self.log_.message('plotting {0}: {1} = {2:.2} with error of {3:.2} %'.format(fmt, label, diag_value, tol_value * 100), calling=self.calling)
def plotOmega(self, save=False, figsize=(18, 12), fignum=1, scan_orders=None, NLevels=None, fig=None): """ Plot the tabulated collision strengths of each data set and the fit that is performed by PyNeb Parameters: - save Boolean. Determine if the plot is automatically saved in a file (default: False) - figsize List. figure size in inches (default: [18, 12]) - fignum Figure Number DEPRECATED!!! - scan_orders = None or (min_order, max_order) or (min_order, -1) to go until the max. DEPRECATED!!! - fig: DEPRECATED!!! """ if NLevels is None: coll_n_max = self.coll_n_max else: coll_n_max = NLevels # Plotting range somewhat larger than actual data range (less tight) if not pn.config.INSTALLED['plt']: pn.log_.error('Matplotlib not installed!', calling=self.calling) if fig is None: #fig = plt.figure(fignum, figsize=figsize) fig, axes = plt.subplots(coll_n_max - 1, coll_n_max - 1, figsize=figsize) plt.autoscale(tight=False) # I need two first = True first_done = False legend_text = [] legend_lines = [] axes_plotaxis = np.zeros_like(axes, dtype=bool) # style_dic = ['-', '--', '-.', ':'] * 10 for data in self.coll_data: # tem_points = tabulated temperature points (different for each data set) tem_points = self.tem_in_K(data['atom'].tem_units, data['atom'].getTemArray()) tem_min = min(tem_points) tem_max = max(tem_points) # tem_funct = array of temperature values for which the fit is evaluated tem_funct = np.linspace(tem_min, tem_max, self.n_tem_points) x_dots = np.log10(tem_points) x_lines = np.log10(tem_funct) if 'COEFF' in data['atom'].CollData.comments.keys(): coeff = float(data['atom'].CollData.comments['COEFF']) else: coeff = 1.0 # Loops over all levels for i in range(1, coll_n_max + 1): for j in range(i + 1, coll_n_max + 1): # N levels require an N-1 x N-1 array of plots # The subplots are arranged in rows and columns according to the upper and lower levels ax = axes[j - 2, i - 1] axes_plotaxis[j - 2, i - 1] = True if (i <= data['atom'].collNLevels) and ( j <= data['atom'].collNLevels): y_dots = data['atom'].getOmega(tem_points, j, i) try: if 'O_UNIT' not in data['atom'].CollData.comments: y_dots = coeff * data['atom'].getOmegaArray( j, i) if y_dots.sum() > 0.0: ax.plot(x_dots, y_dots, color=data['color'], marker='*', linestyle='None', label='_nolegend_', markersize=10) y_dots = data['atom'].getOmega(tem_points, j, i) if y_dots.sum() > 0.0: ax.plot(x_dots, y_dots, color=data['color'], marker='o', linestyle='None', label='_nolegend_') y_lines = data['atom'].getOmega(tem_funct, j, i) if y_lines.sum() > 0.: ax.plot(x_lines, y_lines, color=data['color'], label='_nolegend_') except: pn.log_.warn('Problem with plotting a data set', calling=self.calling) # Draws vertical lines at selected temperature values (only once for each subplot, hence "first") if (first and (data['atom'].collNLevels == coll_n_max)): for tem in self.ref_tem: ax.axvline(tem, c='blue', alpha=0.4, ls=':') lbl = "$\Omega$" + "(" + str(j) + "," + str(i) + ")" ax.text(0.95, 0.95, lbl, transform=ax.transAxes, ha="right", va="top") first_done = True # Maximum number of ticks to avoid overcrowding ax.xaxis.set_major_locator(MaxNLocator(4)) ax.yaxis.set_major_locator(MaxNLocator(3)) # The line type and identifier of each data set are stored for the legend legend_lines.append( mpl.lines.Line2D(tem_funct, tem_funct, color=data['color'], linestyle='-')) legend_text.append(data['ID']) if first_done: first = False # The label of the reference temperature values are only plotted above the last plot for tem in self.ref_tem: ax.text(tem, ax.get_ylim()[1], ' %0.0f K' % (10**tem), ha="left", va="bottom", rotation=65, fontsize=12, color='#FF0000', alpha=0.35) # Axis labels, title and legend fig.text(.5, .05, "Log($T_e/K$)", fontsize=16, ha='center', va='top') fig.text(.05, .5, "$\Omega$", va='center', fontsize=20, rotation=90) fig.text(.5, .95, "[%s %s] collision strengths" % (self.elem, int_to_roman(int(self.spec))), color="#191970", fontsize=16, ha='center') # plt.legend(legend_lines, legend_text, loc='upper right', borderpad=1, # labelspacing=1, bbox_to_anchor=(1, 1 * coll_n_max)) axes[0, coll_n_max - 2].legend(legend_lines, legend_text, loc='upper right', borderpad=1, labelspacing=1) for ax, ax_plt in zip(axes.ravel(), axes_plotaxis.ravel()): if not ax_plt: ax.set_axis_off() #plt.tight_layout() if save: fig.savefig(self.atom_rom + "_CS.pdf") fig.show()
def plotRelA(self, ref_data=None, save=False, figsize=None, fignum=None, NLevels=None, fig=None): """ Plot the relative difference of the A of each data set with respect to the reference one Parameters: - ref_data reference data set for comparing transition probabilities (default=first data ID) - save if True, save the plot in a file (default: False) - figsize figure size (default: [18, 12]) - fignum figure number """ if NLevels is None: atom_n_max = self.atom_n_max else: atom_n_max = NLevels if not pn.config.INSTALLED['plt']: pn.log_.error('Matplotlib not installed!', calling=self.calling) # Commented out because it produced an extra, empty frame - VL 30 Jul 2015 #if fig is None: # fig = plt.figure(fignum, figsize=figsize) #plt.clf() ticks = range(atom_n_max + 1)[1:] # The As of the reference data set are stored if ref_data is None: ref_data = self.atom_data[0]['ID'] for data in self.atom_data: if (data['ID'] is ref_data): ref_A = data['atom'].getA() # Only non-zero values are taken into account to prevent dividing by zero nonzero_ref_A_indexes = np.nonzero(ref_A) for data in self.atom_data: if (data['ID'] is not ref_data): A = data['atom'].getA() try: # The data to be compared might have fewer levels than the reference one. Only the ones in common are considered. tmp_indexes = np.asarray(nonzero_ref_A_indexes) up_indexes = tmp_indexes[0][ tmp_indexes[0] < data['atom'].atomNLevels] lo_indexes = tmp_indexes[1][ tmp_indexes[0] < data['atom'].atomNLevels] # Indexes for which the reference data set is not zero ref_indexes = (up_indexes, lo_indexes) # Ratio of A/A_ref for non-zero A_ref values A_ratio = A[ref_indexes] / ref_A[ref_indexes] nonzero_A_ratio_indexes = np.nonzero(A_ratio) rel_A = np.log10(A_ratio[nonzero_A_ratio_indexes]) # Plotting starts #fig = plt.figure() if fig is None: fig = plt.figure(fignum, figsize=figsize) plt.clf() ax = plt.subplot(111) fig.subplots_adjust(top=0.9) # Physical levels = array levels + 1 x = np.asarray(lo_indexes) + 1 y = np.asarray(up_indexes) + 1 # Size is proportional to difference between As # Numerical value of size adjusted empirically, no particular meaning size = np.multiply(10000., np.abs(rel_A)) # A different color is assigned to data points depending on whether they are smaller or larger # than the reference data. # The ratio is not compared to exactly one to include only truly different values index_grt = np.where(rel_A > 0.0000) color_grt = np.array(['#FF8C00']).repeat(x[index_grt].size) index_sml = np.where(rel_A <= 0.0) color_sml = np.array(['#FF1480']).repeat(x[index_sml].size) # The range is adjusted to include only values for which there is a difference xmin = np.max([np.min(x[index_sml]), np.min(x[index_grt])]) xmax = np.min([np.max(x[index_sml]), np.max(x[index_sml])]) ax.set_xticks(ticks) ax.set_xlim((xmin - 0.25, xmax + 0.25)[:]) # The x-axis is plotted on the top to mimic the data array in the fits file for tick in ax.xaxis.get_major_ticks(): tick.label1On = False tick.label2On = True ymin = np.min([np.min(y[index_sml]), np.min(y[index_grt])]) ymax = np.max([np.max(y[index_sml]), np.max(y[index_sml])]) ax.set_yticks(ticks) # The y axis increases downward to mimic the data array in the fits file ax.set_ylim((ymin - 0.25, ymax + 0.25)[::-1]) # Fake points, just to generate the labels (I don't know how to generate a reasonable label # for data points with markers of different size) plt.scatter(x[index_grt][0], y[index_grt][0], marker='o', s=.0002, c=color_grt[0], label='Positive (max = %.2f)' % (np.max(rel_A))) plt.scatter(x[index_grt][0], y[index_grt][0], marker='o', s=.0002, c=color_sml[0], label='Negative (min = %.2f)' % (np.min(rel_A))) # True data; size reflects divergence from reference data, color whether positive or negative plt.scatter(x[index_grt], y[index_grt], marker='o', s=size[index_grt], c=np.asarray(color_grt), alpha=1.0) plt.scatter(x[index_sml], y[index_sml], marker='o', s=size[index_sml], c=np.asarray(color_sml), alpha=1.0) # X-axis label ax.text(.5, 1.05, '$i$ (lower level)', transform=ax.transAxes, ha='center', va='bottom') #plt.xlabel('$i$ (lower level)') # Y-axis label plt.ylabel('$j$ (upper level)') # Legend plt.legend(loc='upper right', markerscale=1000., scatterpoints=1, borderpad=1, labelspacing=1, prop=dict(size=12), title=u'Log (%s / %s)' % (data['ID'], ref_data)) # Plot title ax.text( .5, -.10, "Relative difference between $A$s data for [%s %s]" % (self.elem, int_to_roman(int(self.spec))), transform=ax.transAxes, ha='center', va='bottom', color='#191970', size=12) except: pn.log_.warn('Problem in plotting relA', calling='DatasetPlot') if save: plt.savefig(self.atom_rom + '_' + data['ID'] + "-" + ref_data + "_relA.pdf") plt.show()
def plotAllA(self, save=False, figsize=(18, 12), fignum=None, NLevels=None): """ Plot the log of the A values of each data set Parameters: - save if True, saves the plot in a file - figsize figure size (default: [18, 12]) - fignum figure Number """ if NLevels is None: atom_n_max = self.atom_n_max else: atom_n_max = NLevels if not pn.config.INSTALLED['plt']: pn.log_.error('Matplotlib not installed!', calling=self.calling) fig = plt.figure(fignum, figsize=figsize) plt.clf() max_y_ticks = 6 ticks = np.arange(len(self.atom_data) + 1)[1:] A = np.zeros([len(self.atom_data), atom_n_max, atom_n_max]) color = [] for i, data in enumerate(self.atom_data): A_tmp = data['atom'].getA() if A_tmp.shape[0] > atom_n_max: A[i, :] = A_tmp[0:atom_n_max, 0:atom_n_max] else: A[i, 0:A_tmp.shape[0], 0:A_tmp.shape[1]] = A_tmp color.append(data['color']) A[np.where((A <= 0))] = np.NaN lgA = np.log10(A) x = ticks color = np.array(color) for j in range(2, atom_n_max + 1): for i in range(1, j): y = lgA[:, j - 1, i - 1] ax = plt.subplot(atom_n_max - 1, atom_n_max - 1, (atom_n_max - 1) * (j - 2) + i) ax.set_xticks(x) plt.xlim((min(x) - 0.5, max(x) + 0.5)) ax.yaxis.set_major_locator(MaxNLocator(max_y_ticks - 1)) try: plt.scatter(x, y, c=color, label='_nolegend_', s=40, edgecolor='None') lbl = '({0} -> {1})'.format(j, i) ax.text(0.95, 0.95, lbl, fontsize=10, color="#660066", transform=ax.transAxes, ha="right", va="top") except: pn.log_.warn( 'Problem with plotting a subplot {} {}'.format(i, j), calling=self.calling) if (j == atom_n_max) & (i == 1): plt.xlabel('Reference #', fontsize=8) plt.ylabel('Log(A$_{ji}$)', fontsize=8) plt.subplots_adjust(left=0.15, right=0.95, top=0.95, bottom=0.12) plt.gca().get_yaxis().get_major_formatter().set_useOffset(False) ax.set_xticks(x) #fig.text(.5, .05, "i (lower level)", fontsize=12, ha='center', color="#660066", va='top') #fig.text(.05, .5, "j (upper level)", ha='left', va='center', fontsize=12, color="#660066", rotation=90) title = "Available transition probabilities for {0} {1}".format( self.elem, int_to_roman(int(self.spec))) fig.text(.5, .95, title, color="#191970", fontsize=14, ha='center') for i, data in enumerate(self.atom_data): x_txt = .95 y_txt = .85 - .04 * i fig.text(x_txt, y_txt, "Ref. %d: %s" % (i + 1, data['ID']), color=color[i], ha='right') plt.tight_layout(pad=0.1) if save: plt.savefig(self.atom_rom + "_all_As.pdf") plt.show()
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 plotA(self, save=False, figsize=(18, 12), fignum=None, NLevels=None): """ Plot the log of the A values of each data set Parameters: - save if True, saves the plot in a file - figsize figure size (default: [18, 12]) - fignum figure Number """ if NLevels is None: atom_n_max = self.atom_n_max else: atom_n_max = NLevels if not pn.config.INSTALLED['plt']: pn.log_.error('Matplotlib not installed!', calling=self.calling) plt.figure(fignum, figsize=figsize) plt.clf() ax = plt.subplot(111) x = np.arange(atom_n_max * (atom_n_max - 1) / 2.) ticks = x # Inventory of markers. Chosen to be distinguished even when overlapped mark = ['<', (5, 1), '>', 'o', '|'] i_marker = 0 # Background colors to distinguish lower levels bg_color = 'grbymc' tick_label = [] for i in range(atom_n_max - 1): # x0, x1 are start and end points of each level x0 = i * (atom_n_max - 1) - i * (i - 1) / 2 - 0.5 width = atom_n_max - i - 1 x1 = x0 + width plt.axvspan(x0, x1, facecolor=bg_color[i % 6], alpha=0.05) # The x axis must stretch the maximum range (although some data set might have a lower n_level) for j in range(i + 1, atom_n_max): tick_label.append('(' + str(j + 1) + ', ' + str(i + 1) + ')') for data in self.atom_data: n_levels = data['atom'].atomNLevels Ay = [] A = data['atom'].getA() color = data['color'] try: for i in range(n_levels - 1): for j in range(i + 1, n_levels): if A[j, i] > 0: Ay.append(np.log10(A[j, i])) else: Ay.append(np.NaN) plt.scatter(x, Ay, marker=mark[i_marker], s=300., c=color, alpha=0.35, linewidths=1, label='%s' % (data['ID'])) ax.set_xticks(ticks) except: pn.log_.warn('Problem in plotting A', calling=self.calling + '.plotA') i_marker += 1 ax.set_xticklabels(tick_label) # Plot features plt.xlabel('Transition') plt.ylabel('Log A(j, i)') plt.title('Transition probabilities for [%s %s]' % (self.elem, int_to_roman(int(self.spec)))) plt.legend(loc='lower right', markerscale=1., scatterpoints=1, borderpad=1, labelspacing=1) plt.show() if save: plt.figure(figsize=[18, 12]) plt.savefig(self.atom_rom + '_' + data['ID'] + "-" + self.ref_data + "_A.pdf")
def make_ionrec_file(phy_cond_file='phy_cond.dat', abund_file='asplund_2009.dat', ion_frac_file='50_-2_R_ionfrac.dat', Teff=None, MB=None, logU=None, ion_only=None, out_file='ions_rec.dat', ion=None, iwr_phyat=1, vzero=13., liste_phyat_rec_name='liste_phyat_rec.dat', outputcond_name='outputcond.dat', IP_cut=300.): if ion_only is not None: if ',' in ion_only: ion_only = [ii.strip() for ii in ion_only.split(',')] else: ion_only = [ion_only] ion_only.append('H_I') if Teff is not None and logU is not None and MB is not None: ion_frac_file = '{}_{}_{}_ionfrac.dat'.format(Teff, logU, MB) ion_frac_file_full = get_full_name(ion_frac_file, extra='ionfracs') abund_file_full = get_full_name(abund_file) phy_cond_file_full = get_full_name(phy_cond_file) elems = ('H', 'D', 'He', '3He', 'Li', 'C', 'N', 'O', 'Ne', 'Mg', 'Si', 'S') Z['3He'] = 2 IP['3He'] = IP['He'] IP['D'] = IP['H'] phycond = np.genfromtxt(phy_cond_file_full, dtype='U3, float,U4, float, float', names='name, value, RC, temp, dens') dic_temp_ion = {} dic_dens_ion = {} tab_ips = [] tab_temps = [] tab_denss = [] for record in phycond: if 'R' in record['RC']: if record['name'] == 'IP': tab_ips.append(record['value']) tab_temps.append(record['temp']) tab_denss.append(record['dens']) else: dic_temp_ion['{}{}'.format(record['name'], int( record['value']))] = record['temp'] dic_dens_ion['{}{}'.format(record['name'], int( record['value']))] = record['dens'] tab_temp_dens = np.array(list(zip(tab_ips, tab_temps, tab_denss)), dtype=[('IP', float), ('temp', float), ('dens', float)]) tab_temp_dens.sort() ab_data = np.genfromtxt(abund_file_full, dtype='U2, float', names='elem, abund', usecols=(0, 1)) ab_dic = {} for record in ab_data: ab_dic[record['elem']] = record['abund'] ab_dic['3He'] = 1e-3 try: ion_frac_data = np.genfromtxt(ion_frac_file_full, dtype='U4, float', names='ion, ion_frac') except: raise NameError('File not found {}'.format(ion_frac_file_full)) ion_frac_dic = {} for record in ion_frac_data: ion_frac_dic[record['ion']] = record['ion_frac'] ion_frac_dic['H0'] = 0.0 ion_frac_dic['H1'] = 1.0 ion_frac_dic['D0'] = ion_frac_dic['H0'] ion_frac_dic['D1'] = ion_frac_dic['H1'] ion_frac_dic['3He0'] = ion_frac_dic['He0'] ion_frac_dic['3He1'] = ion_frac_dic['He1'] ion_frac_dic['3He2'] = ion_frac_dic['He2'] with open(out_file, 'w') as f: f.write( """ {} iwr_phyat I4 ; =0 --> .res, =1 --> .res and WILL CHANGE liste_phyat {:6.2f} vzero km/s E6. {:30s}A30 {:30s}A30 0=no,1=yes y/n Te Ne Ionab """.format(iwr_phyat, vzero, liste_phyat_rec_name, outputcond_name)) for elem in elems: for z in np.arange(Z[elem]): ion_str = '{}{}'.format(elem, z + 1) ion_roman = '{}{}'.format(elem, int_to_roman(int(z + 1))) ion_roman_ = '{}_{}'.format(elem, int_to_roman(int(z + 1))) if ion_only is None or ion_roman_ in ion_only: print('Doing ion {}'.format(ion_roman_)) thisIP = IP[elem][z] if thisIP < IP_cut: ion_abund = 10**(ab_dic[elem] - 12) * ion_frac_dic[ion_str] if ion is None: yn_code = 1 else: if ion_str == ion: yn_code = 1 else: yn_code = 0 if ion_str in dic_temp_ion: temp = dic_temp_ion[ion_str] dens = dic_dens_ion[ion_str] else: for temp_dens in tab_temp_dens: if temp_dens['IP'] > thisIP: temp = temp_dens['temp'] dens = temp_dens['dens'] break f.write('{:7s} {:1} {:8.2e} {:8.2e} {:8.2e}\n'.format( ion_roman, yn_code, temp, dens, ion_abund))
def print_phyat_list(atom, tem, den, cut=1e-3, cut_inter=1e-5, ij_ref=None, filename=None, up_lev_rule=None, NLevels=None, E_cut=20, log_file=None, help_file=None, verbose=False, Aij_zero=None): """ atom: a string e.g. 'O3' or a pn.Atom object tem in K den in cm-3 cut: relative intensity (to the master one) for a line to be printed cut_inter [deprecated]: largest dynamic between ref lines. ij_ref: None: is computed. Otherwise must be of the form e.g. (4, 2) or ((4, 2), (5, 3)) filename: where to output the result. May be None, a string or a file object up_lev_rule: 'each': each upper level are used to define a different master line 'all': all the transitions are grouped into a single master line list, e.g. [2, 3, [4, 5]]: levels 2, 3 and 4-5 together are used to define a master line. None: default hard coded value is used, see up_levs below NLevels : max number of levels for the atom E_cut: max energy in eV for the energy level to give a line log_file: for the log help_file: for the comments on the Te, Ne for each ion. """ up_levs = { 's1': [[2, 3], 4, 5, 6], 's2': 'each', 'p1': [2, [3, 4, 5], [6, 7]], 'p2': 'each', 'p3': [2, 3, [4, 5]], 'p4': 'each', 'p5': 'each', 'd2': 'split 3', 'd3': 'split 4', 'd4': 'split 5', 'd6': 'split 5', 'd7': 'split 3', 'd8': 'split 3', 'd9': 'split 3' } # The others are 'all' by default (i.e. only one master line, with all the lines depending on it ij_refs = { 's1': ((3, 1), ), 'p1': ((3, 1), (7, 1)), 'p3': ((4, 2), ), 'd6': ((4, 2), ), 'd5': ( (2, 1), (5, 1), ), 'd4': ( (3, 2), (7, 5), ), 'd3': ((6, 1), ), 'd2': ( (2, 1), (12, 1), ) } str_print = '{}{:02d}{:02d}{:01d}{:01d}0{:03d}{:03d} {:<8s} {:11.3f} 0.000{:10.3e} 1.000 {:02d}{:02d}{:01d}{:01d}0{:03d}{:03d} -1 1.00 {}' if filename is None: f = None else: str_print += '\n' if type(filename) is str: f = open(filename, 'w') elif hasattr(filename, 'write'): f = filename if filename is None: def myprint(s): print(s) else: def myprint(s): f.write(s) if log_file is None: def logprint(s): print(s) elif type(log_file) is str: lf = open(log_file, 'w') def logprint(s): lf.write(s) elif hasattr(log_file, 'write'): lf = log_file def logprint(s): lf.write(s) if help_file is None: def hprint(s): print(s) elif type(help_file) is str: hf = open(log_file, 'w') def hprint(s): hf.write(s) elif hasattr(help_file, 'write'): hf = help_file def hprint(s): hf.write(s) if type(atom) is str: atom = pn.Atom(atom=atom, NLevels=NLevels) try: atom_str = '{}-{}'.format(atom.atomFile, atom.collFile) except: atom_str = '' if atom.NLevels == 0: logprint('Atom {} without data.'.format(atom_str)) return None energies = atom.getEnergy(unit='eV') N_energies = (energies < E_cut).sum() if NLevels is not None: this_NLevels = np.min((NLevels, atom.NLevels, N_energies)) else: this_NLevels = np.min((atom.NLevels, N_energies)) if this_NLevels <= 1: if N_energies <= 1: logprint('Atom {} without level below {} eV'.format( atom_str, E_cut)) else: logprint('Atom {} without energy levels'.format(atom_str)) return None #print('Doing {} with NLevels={}'.format(atom.atom, this_NLevels)) atom = pn.Atom(atom=atom.atom, NLevels=this_NLevels) if Aij_zero is not None: for ij in Aij_zero: atom._A[ij[0] - 1, ij[1] - 1] = 0.0 try: NIST_gsconf = atom.NIST[0][0].split('.')[-1] if NIST_gsconf[-1] in ('0123456789'): NIST_gsconf = NIST_gsconf[-2:] else: NIST_gsconf = NIST_gsconf[-1] + '1' except: NIST_gsconf = 'unknown' logprint('{} levels. '.format(this_NLevels)) emis = atom.getEmissivity(tem, den) emis_max_tot = np.max(emis) wls = atom.wave_Ang[0:this_NLevels, 0:this_NLevels] wls_mask = wls < 911.0 emis[wls_mask] = 0.0 gs = gsFromAtom(atom.atom) if up_lev_rule is None: if gs in up_levs: up_lev_rule = up_levs[gs] else: up_lev_rule = 'all' if up_lev_rule == 'each': up_lev_list = range(2, this_NLevels + 1) elif up_lev_rule == 'all': up_lev_list = [range(2, this_NLevels + 1)] elif 'split' in up_lev_rule: N_split = int(up_lev_rule.split()[-1]) up_lev_list = [ range(2, N_split + 1), range(N_split + 1, this_NLevels + 1) ] else: up_lev_list = up_lev_rule if ij_ref is not None: if type(ij_ref[0]) is not tuple: ij_ref = (ij_ref, ) else: if gs in ij_refs: ij_ref = ij_refs[gs] #print('up_lev_rule: {}, up_lev_list: {}'.format(up_lev_rule, up_lev_list)) NLevels_max = 0 print_any = False to_print = [] ion_name = '{:>2s}_{:<5s}'.format(atom.elem, int_to_roman(atom.spec)).strip() N_lines = 0 for i_up_lev, up_lev in enumerate(up_lev_list): if type(up_lev) is int: up_lev = [up_lev] emis_ref = 0 i_emis_ref_loc = None j_emis_ref_loc = None for i in up_lev: if i < this_NLevels + 1: for j in 1 + np.arange(i): if ij_ref is not None and (i, j) in ij_ref: i_emis_ref_loc = i j_emis_ref_loc = j emis_ref = emis[i - 1, j - 1] if i_emis_ref_loc is None: for i in up_lev: if i < this_NLevels + 1: for j in 1 + np.arange(i): if emis[i - 1, j - 1] > emis_ref: i_emis_ref_loc = i j_emis_ref_loc = j emis_ref = emis[i - 1, j - 1] """ if emis_ref < cut_inter * np.max(emis): if verbose: print('reset emis ref loc {} < {} * {} (emis_ref < cut_inter * np.max(emis))'.format(emis_ref, cut_inter, np.max(emis))) i_emis_ref_loc = None """ if i_emis_ref_loc is not None: com_ref = '{} {} {:.1f}'.format( i_emis_ref_loc, j_emis_ref_loc, wls[i_emis_ref_loc - 1, j_emis_ref_loc - 1]) if ("split" in up_lev_rule) or ("all" in up_lev_rule): i_emis_ref_loc = i_up_lev + 1 if i_emis_ref_loc > 9: logprint('Ref line level is {}. '.format(i_emis_ref_loc)) ref_str = str_print.format('9', Z[atom.elem], atom.spec, 3, i_emis_ref_loc / 10, i_emis_ref_loc % 10, 0, ion_name, 1.0, emis_ref, 0, 0, 0, 0, 0, 999, com_ref) else: ref_str = str_print.format('9', Z[atom.elem], atom.spec, 3, i_emis_ref_loc, 0, 0, ion_name, 1.0, emis_ref, 0, 0, 0, 0, 0, 999, com_ref) print_ref = True for i in up_lev: print_it = False if i > this_NLevels: break for j in 1 + np.arange(i): if emis[i - 1, j - 1] > cut * emis_ref and wls[i - 1, j - 1] > 912: print_it = True print_any = True if i > NLevels_max: NLevels_max = i if print_it: for j in 1 + np.arange(i): if emis[i - 1, j - 1] > cut * emis_ref and wls[i - 1, j - 1] > 912: com = '{} {}'.format(i, j) ion_name = '{:>2s}_{:<5s}'.format( atom.elem, int_to_roman(atom.spec)).strip() if print_ref: to_print.append(ref_str) print_ref = False i_to_print = np.min((i, 9)) i_to_print = i_emis_ref_loc if i_emis_ref_loc > 9: to_print.append( str_print.format( ' ', Z[atom.elem], atom.spec, 3, i_to_print, i, j, ion_name, wls[i - 1, j - 1], emis[i - 1, j - 1] / emis_ref, Z[atom.elem], atom.spec, 3, i_emis_ref_loc / 10, i_emis_ref_loc % 10, 0, com)) else: to_print.append( str_print.format( ' ', Z[atom.elem], atom.spec, 3, i_to_print, i, j, ion_name, wls[i - 1, j - 1], emis[i - 1, j - 1] / emis_ref, Z[atom.elem], atom.spec, 3, i_emis_ref_loc, 0, 0, com)) N_lines += 1 if print_any: hprint('# {} - Temp. = {} K, Dens. = {} cm-3 \n'.format( atom.atom, tem, den)) for str_ in to_print: myprint(str_) logprint('{} lines printed. {}'.format(N_lines, atom_str)) else: logprint('No print. ') if len(up_lev_list) == 0: logprint('No up lev. ') if i_emis_ref_loc is None: logprint('No ref loc. ') if type(help_file) is str: hf.close() if type(log_file) is str: lf.close()
def print_phyat_list(atom, tem, den, cut=1e-3, cut_inter=1e-5, ij_ref = None, filename=None, up_lev_rule=None, NLevels=None, E_cut=20, log_file=None, help_file= None, verbose=False, Aij_zero = None): """ atom: a string e.g. 'O3' or a pn.Atom object tem in K den in cm-3 cut: relative intensity (to the master one) for a line to be printed cut_inter [deprecated]: largest dynamic between ref lines. ij_ref: None: is computed. Otherwise must be of the form e.g. (4, 2) or ((4, 2), (5, 3)) filename: where to output the result. May be None, a string or a file object up_lev_rule: 'each': each upper level are used to define a different master line 'all': all the transitions are grouped into a single master line list, e.g. [2, 3, [4, 5]]: levels 2, 3 and 4-5 together are used to define a master line. None: default hard coded value is used, see up_levs below NLevels : max number of levels for the atom E_cut: max energy in eV for the energy level to give a line log_file: for the log help_file: for the comments on the Te, Ne for each ion. """ up_levs = {'s1': [[2, 3], 4, 5, 6], 's2': 'each', 'p1': [2, [3, 4, 5], [6, 7]], 'p2': 'each', 'p3': [2, 3, [4, 5]], 'p4': 'each', 'p5': 'each'} # The others are 'all' by default (i.e. only one master line, with all the lines depending on it ij_refs = {'s1': ((3, 1),), 'p1': ((3, 1), (7, 1)), 'p3': ((5, 1),)} str_print = '{}{:02d}{:02d}{:01d}{:01d}0{:03d}{:03d} {:<8s} {:11.3f} 0.000{:10.3e} 1.000 {:02d}{:02d}{:01d}00{:03d}{:03d} 1 1.00 {}' if filename is None: f = None else: str_print += '\n' if type(filename) is str: f = open(filename, 'w') elif type(filename) is file: f = filename if filename is None: def myprint(s): print(s) else: def myprint(s): f.write(s) if log_file is None: def logprint(s): print(s) elif type(log_file) is str: lf = open(log_file, 'w') def logprint(s): lf.write(s) elif type(log_file) is file: lf = log_file def logprint(s): lf.write(s) if help_file is None: def hprint(s): print(s) elif type(help_file) is str: hf = open(log_file, 'w') def hprint(s): hf.write(s) elif type(help_file) is file: hf = help_file def hprint(s): hf.write(s) if type(atom) is str: atom = pn.Atom(atom=atom, NLevels=NLevels) if atom.NLevels == 0: logprint('Atom without data. '.format(atom.atom)) return None energies = atom.getEnergy(unit='eV') N_energies = (energies < E_cut).sum() if NLevels is not None: this_NLevels = np.min((NLevels,atom.NLevels, N_energies)) else: this_NLevels = np.min((atom.NLevels, N_energies)) if this_NLevels <=1: if N_energies <= 1: logprint('Atom without level below {} eV'.format(E_cut)) else: logprint('Atom without energy levels') return None #print('Doing {} with NLevels={}'.format(atom.atom, this_NLevels)) atom = pn.Atom(atom=atom.atom, NLevels=this_NLevels) if Aij_zero is not None: for ij in Aij_zero: atom._A[ij[0]-1, ij[1]-1] = 0.0 try: NIST_gsconf = atom.NIST[0][0].split('.')[-1] if NIST_gsconf[-1] in ('0123456789'): NIST_gsconf = NIST_gsconf[-2:] else: NIST_gsconf = NIST_gsconf[-1] + '1' except: NIST_gsconf = 'unknown' logprint('{} levels. '.format(this_NLevels)) emis = atom.getEmissivity(tem, den) emis_max_tot = np.max(emis) wls = atom.wave_Ang[0:this_NLevels, 0:this_NLevels] wls_mask = wls < 911.0 emis[wls_mask] = 0.0 gs = gsFromAtom(atom.atom) if up_lev_rule is None: if gs in up_levs: up_lev_rule = up_levs[gs] else: up_lev_rule = 'all' if up_lev_rule == 'each': up_lev_list = range(2, this_NLevels+1) elif up_lev_rule == 'all': up_lev_list = [range(2, this_NLevels+1)] elif 'split' in up_lev_rule: N_split = int(up_lev_rule.split()[-1]) up_lev_list = [range(2, N_split+1), range(N_split+1, this_NLevels+1)] else: up_lev_list = up_lev_rule if ij_ref is not None: if type(ij_ref[0]) is not tuple: ij_ref = (ij_ref,) else: if gs in ij_refs: ij_ref = ij_refs[gs] #print('up_lev_rule: {}, up_lev_list: {}'.format(up_lev_rule, up_lev_list)) NLevels_max = 0 print_any = False to_print = [] ion_name = '{:>2s}_{:<5s}'.format(atom.elem, int_to_roman(atom.spec)).strip() N_lines = 0 for i_up_lev, up_lev in enumerate(up_lev_list): if type(up_lev) is int: up_lev = [up_lev] emis_ref = 0 i_emis_ref_loc = None j_emis_ref_loc = None for i in up_lev: if i < this_NLevels+1: for j in 1+np.arange(i): if ij_ref is not None and (i, j) in ij_ref: i_emis_ref_loc = i j_emis_ref_loc = j emis_ref = emis[i-1,j-1] if i_emis_ref_loc is None: for i in up_lev: if i < this_NLevels+1: for j in 1+np.arange(i): if emis[i-1,j-1] > emis_ref: i_emis_ref_loc = i j_emis_ref_loc = j emis_ref = emis[i-1,j-1] """ if emis_ref < cut_inter * np.max(emis): if verbose: print('reset emis ref loc {} < {} * {} (emis_ref < cut_inter * np.max(emis))'.format(emis_ref, cut_inter, np.max(emis))) i_emis_ref_loc = None """ if i_emis_ref_loc is not None: com_ref = '{} {} {:.1f}'.format(i_emis_ref_loc, j_emis_ref_loc, wls[i_emis_ref_loc-1,j_emis_ref_loc-1]) if ("split" in up_lev_rule) or ("all" in up_lev_rule): i_emis_ref_loc = i_up_lev + 1 if i_emis_ref_loc > 9: logprint('Ref line level is {}. '.format(i_emis_ref_loc)) ref_str=str_print.format('9', Z[atom.elem], atom.spec,i_emis_ref_loc/10 , i_emis_ref_loc%10, 0, 0, ion_name, 1.0, 1.0, 0, 0, 0, 0, 999, com_ref) else: ref_str=str_print.format('9', Z[atom.elem], atom.spec,i_emis_ref_loc , 0, 0, 0, ion_name, 1.0, 1.0, 0, 0, 0, 0, 999, com_ref) print_ref = True for i in up_lev: print_it = False if i > this_NLevels: break for j in 1+np.arange(i): if emis[i-1,j-1] > cut * emis_ref and wls[i-1,j-1] > 912: print_it = True print_any = True if i > NLevels_max: NLevels_max = i if print_it: for j in 1+np.arange(i): if emis[i-1,j-1] > cut * emis_ref and wls[i-1,j-1] > 912: com = '{} {}'.format(i, j) ion_name = '{:>2s}_{:<5s}'.format(atom.elem, int_to_roman(atom.spec)).strip() if print_ref: to_print.append(ref_str) print_ref = False i_to_print = np.min((i, 9)) i_to_print = i_emis_ref_loc if i_emis_ref_loc > 9: to_print.append(str_print.format(' ', Z[atom.elem], atom.spec, i_to_print, 0, i, j, ion_name, wls[i-1,j-1], emis[i-1,j-1]/emis_ref, Z[atom.elem], atom.spec, i_emis_ref_loc/10, i_emis_ref_loc%10, 0, com)) else: to_print.append(str_print.format(' ', Z[atom.elem], atom.spec, i_to_print, 0, i, j, ion_name, wls[i-1,j-1], emis[i-1,j-1]/emis_ref, Z[atom.elem], atom.spec, i_emis_ref_loc, 0, 0, com)) N_lines += 1 if print_any: hprint('# {} - Temp. = {} K, Dens. = {} cm-3 \n'.format(atom.atom, tem, den)) for str_ in to_print: myprint(str_) logprint('{} lines printed. '.format(N_lines)) else: logprint('No print. ') if len(up_lev_list) == 0: logprint('No up lev. ') if i_emis_ref_loc is None: logprint('No ref loc. ') if type(help_file) is str: hf.close() if type(log_file) is str: lf.close()