Esempio n. 1
0
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
Esempio n. 2
0
 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)
Esempio n. 3
0
    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()
Esempio n. 4
0
    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()
Esempio n. 5
0
    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()
Esempio n. 6
0
    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
Esempio n. 7
0
    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")
Esempio n. 8
0
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))
Esempio n. 9
0
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()
Esempio n. 10
0
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()