Skip to content

EmisGrid

EmisGrid

Bases: object

Instantiates an atom and compute the emissivities of all the atom lines for the (tem, den) values of a regularly spaced grid. Each line is represented in a 2D array, and there are as many arrays as transitions in the atom. The results can be saved for a later use in a cPickle file.

Source code in pyneb/core/emisGrid.py
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
class EmisGrid(object):
    """
    Instantiates an atom and compute the emissivities of all the atom lines for the (tem, den) 
    values of a regularly spaced grid.
    Each line is represented in a 2D array, and there are as many arrays as transitions in the atom.
    The results can be saved for a later use in a cPickle file.

    """

    def __init__(self, elem=None, spec=None, n_tem=100, n_den=100, tem_min=5000., tem_max=20000.,
                 den_min=10., den_max=1.e8, restore_file=None, atomObj=None, NLevels=None, **kwargs):

        """
        Container for the emission line intensity grids depending on Te and Ne.

        Usage:


        Parameters:
           elem:               element (e.g. 'O')
           spec:               spectrum (e.g. 3)
           n_tem:              number of points of the electron temperature sample
           n_den:              number of points of the electron density sample
           tem_min: minimum limit for the electron temperature
           tem_max: maximum limit for the electron temperature
           den_min: minimum limit for the electron density
           den_max: maximum limit for the electron density
           restore_file:       if set, the emissivities are loaded from this file, 
                                 otherwise (None) it is computed
                                 If the tem or den table from the restored file does not match the given parameters,
                                 a new grid is computed and self.compute_new_grid is set to True. The same applies
                                 if the atomic data are not the same.
           atomObj:            an atom object. In this case, no need for elem and spec.

        **Usage:**

            O3map = pn.EmisGrid('O', 3, n_tem=30, n_den=30)

            O3map = pn.EmisGrid(restore_file='plot/O3_10k.pypic') # Recovers the map from a previous computation

        """
        self.log_ = log_
        self.calling = 'EmisGrid'

        if restore_file is not None:
            old = restore(restore_file)
            self.elem = old['elem']
            self.spec = old['spec']
            if atomObj is None:
                self.atom = Atom(elem=self.elem, spec=self.spec, NLevels=NLevels, **kwargs)
            else:
                self.atom = atomObj
            if self.atom.type == 'coll':
                if self.atom.atomFitsFile != old['atomFitsFile']:
                    self.log_.error('You are using {0}, but restoring a file made with {1}'.format(self.atom.atomFitsFile, old['atomFitsFile']),
                                    calling=self.calling)
                if self.atom.collFitsFile != old['collFitsFile']:
                    self.log_.error('You are using {0}, but restoring a file made with {1}'.format(self.atom.collFitsFile, old['collFitsFile']),
                                    calling=self.calling)
            elif self.atom.type == 'rec':
                if self.atom.recFitsFile != old['recFitsFile']:
                    self.log_.error('You are using {0}, but restoring a file made with {1}'.format(self.atom.recFitsFile, old['recFitsFile']),
                                    calling=self.calling)
            self.compute_new_grid = False
            if n_tem != len(old['tem']):
                self.log_.warn('len(tem) does not match saved data. New grid is computed')
                self.compute_new_grid = True
            else:
                if not np.isclose(tem_min, min(old['tem'])):
                    self.log_.warn('Min(tem) does not match saved data. New grid is computed')
                    self.compute_new_grid = True
                if not np.isclose(tem_max, max(old['tem'])):
                    self.log_.warn('Max(tem) does not match saved data. New grid is computed')
                    self.compute_new_grid = True
            if n_den != len(old['den']):
                self.log_.warn('len(den) does not match saved data. New grid is computed')
                self.compute_new_grid = True
            else:
                if not np.isclose(den_min, min(old['den'])):
                    self.log_.warn('Min(den) does not match saved data. New grid is computed')
                    self.compute_new_grid = True
                if not np.isclose(den_max, max(old['den'])):
                    self.log_.warn('Max(den) does not match saved data. New grid is computed')
                    self.compute_new_grid = True
            if not self.compute_new_grid:
                self.tem = old['tem']
                self.den = old['den']
                self.n_tem = self.tem.size
                self.n_den = self.den.size
                self.tem_min = min(self.tem)
                self.tem_max = max(self.tem)
                self.den_min = min(self.den)
                self.den_max = max(self.den)
                self.emis_grid = old['emis_grid']
        else:
            self.compute_new_grid = True

        if self.compute_new_grid:
            if atomObj is None:
                self.elem = elem
                self.spec = spec
                self.atom = Atom(elem, spec, NLevels=NLevels, **kwargs)
            else:
                self.atom = atomObj
                self.elem = self.atom.elem
                self.spec = self.atom.spec
            self.n_tem = n_tem
            self.n_den = n_den
            self.tem_min = tem_min
            self.tem_max = tem_max
            self.den_min = den_min
            self.den_max = den_max
            self.tem = 10 ** np.linspace(np.log10(tem_min), np.log10(tem_max), n_tem)
            self.den = 10 ** np.linspace(np.log10(den_min), np.log10(den_max), n_den)
            try:
                self.atomFitsFile = self.atom.atomFitsFile
                self.collFitsFile = self.atom.collFitsFile
            except:
                self.atomFitsFile = None
                self.collFitsFile = None
            try:
                self.recFitsFile = self.atom.recFitsFile
            except:
                self.recFitsFile = None
            self.emis_grid = self.atom.getEmissivity(self.tem, self.den) #(erg.s-1.cm3)
            if restore_file is not None:
                self.save(restore_file)
                self.log_.message('%s saved to %s' % ((self.atom), restore_file), calling=self.calling)
            #self.emis_grid = np.empty((self.atom.NLevels, self.atom.NLevels, n_tem, n_den))

        self.den2D, self.tem2D = np.meshgrid(self.den, self.tem)

#    def computeEmis(self):
#        """
#        This is where the emissivities are computed, by calling a function from Atom.
#        """
#        self.emis_grid = self.atom.getEmissivity(self.tem, self.den)

    def save(self, file_):
        """
        Save results for a later use.

        Usage:
            O3map.save('plot/O3_30by30.pypic')

        Parameter:
            file_  the name of the file in which the emissivity grids are stored

        """
        save(file_, emis_grid=self.emis_grid, tem=self.tem, den=self.den, elem=self.elem,
             spec=self.spec, 
             atomFitsFile=self.atomFitsFile, collFitsFile=self.collFitsFile, recFitsFile=self.recFitsFile)


    def getGrid(self, lev_i=None, lev_j=None, wave= -1, to_eval=None, label=None):
        """
        2D array of a line emissivity (erg.s-1.cm3) for the (Te, Ne) values of a regularly spaced grid.
        The line is specified either as the wavelength or the levels. An expression can also be used, 
        for example to_eval = 'L(5007)/L(4959)'

        Parameters:
            lev_i: level i for the emission line
            lev_j: level j for the emission line
            wave:           wavelength
            to_eval:        algebraic expression of the line combination to evaluate

        """
        if wave != -1:
            lev_i, lev_j = self.atom.getTransition(wave)
        if label is not None:
            to_eval = 'S("{}")'.format(label)

        if to_eval is None:
            to_eval = 'I(' + str(lev_i) + ',' + str(lev_j) + ')'

        def I(lev_i, lev_j):
            return self.emis_grid[lev_i - 1, lev_j - 1, :, :]
        def L(wave):
            return self.getGrid(wave=wave)
        def S(label):
            return self.emis_grid[label]
        return eval(to_eval)


    def plotImage(self, to_eval=None, lev_i1=None, lev_j1=None, lev_i2=None, lev_j2=None,
                  wave1= -1, wave2= -1, cblabel='', **kwargs):
        """
        Draw a contour plot of a line ratio. The contour is obtained by a horizontal cut in a temden-emissivity array.
        More elaborated plots can be obtained with the Diagnostic object.

        Usage:
            O3map.plotImage('L(4363)/L(5007)')
            O3map.plotImage(wave1=4363, wave2=5007)

        Parameters:
            to_eval:                         algebraic expression of the line combination to draw. May combine L(lambda) and I(i,j).
            lev_i1: levels of the a lines in case of simple line ratio plot.
            lev_i2: levels of the a lines in case of simple line ratio plot.
            lev_j1: levels of the a lines in case of simple line ratio plot.
            lev_j2: levels of the a lines in case of simple line ratio plot.
            wave1: wavelengths of the two lines in case of simple line ratio plot.
            wave2: wavelengths of the two lines in case of simple line ratio plot.
            cblabel:                         a title for the colorbar
            **kwargs:                        any other parameter will be sent to contourf and pcolor

        """
        if not config.INSTALLED['plt']:
            log_.error('Matplotlib not available', calling=self.calling)
            return None
        L = lambda lam: self.getGrid(wave=lam)
        I = lambda i, j: self.getGrid(i, j)
        S = lambda label: self.getGrid(label)
        if to_eval is None:
            if wave1 != -1:
                lev_i1, lev_j1 = self.atom.getTransition(wave1)
            if wave2 != -1:
                lev_i2, lev_j2 = self.atom.getTransition(wave2)
            to_eval = 'I(' + str(lev_i1) + ',' + str(lev_j1) + ') / I(' + str(lev_i2) + ',' + str(lev_j2) + ')'
        X = np.log10(self.den2D)
        Y = self.tem2D / 1e4
        Z = self.getGrid(to_eval=to_eval)
        plt.contourf(X, Y, Z, **kwargs)
        emap = plt.pcolor(X, Y, Z, **kwargs)
        cbar = plt.colorbar(emap)
        cbar.set_label(cblabel)
        # plt.clabel(contour, inline=1)
        plt.xlabel(r'log Electron density (cm$^{-3}$)')
        plt.ylabel(r'Electron temperature ($10^4$K)')
        plt.show()


    def plotContours(self, to_eval, low_level=None, high_level=None, n_levels=20, levels=None,
                      linestyles='-', clabels=True, log_levels=True, title=None, ax=None, **kwargs):
        """
        Plot a contour map of the diagnostic defined by to_eval.

        Usage:
            O3map.plotContours('L(4363)/L(5007)')

        Parameters:
            to_eval:                   algebraic definition of the line ratio to contour-plot
            low_levels: limit levels for the contour. If not set, the limit of the ratio values are used.
            high_levels: limit levels for the contour. If not set, the limit of the ratio values are used.
            n_levels:                  number of levels (20 is the default)
            linestyles:                used for the contour lines (default: solid line)
            clabels:                   Boolean. Controls if line labels are printed (default: True)
            log_levels:                Boolean. If True (default), the log of the line ratio is used.
            title:                     plot title
            **kwargs:                  sent to plt.contour            
        """ 
        if not config.INSTALLED['plt']:
            log_.error('Matplotlib not available', calling=self.calling)
            return None
        X = np.log10(self.den2D)
        Y = self.tem2D
        L = lambda lam: self.getGrid(wave=lam)
        I = lambda i, j: self.getGrid(i, j)
        S = lambda label: self.getGrid(label=label)
        try:
            diag_map = eval(to_eval)
        except:
            self.log_.warn('diag %s not found' % to_eval, calling=self.calling)
            return None
        if low_level is None:
            low_level = np.min(np.log10(diag_map))
        if high_level is None:
            high_level = np.max(np.log10(diag_map))
        if log_levels:
            Z = np.log10(diag_map)
            if levels is None:
                levels = np.linspace(low_level, high_level, n_levels)
            if title is None:
                title = '[%s%s]: log(%s)' % (self.elem, int_to_roman(int(self.spec)), to_eval)
        else:
            Z = diag_map
            if levels is None:
                levels = 10. ** (np.linspace(low_level, high_level, n_levels))
            if title is None:
                title = '[%s%s]: %s' % (self.elem, int_to_roman(int(self.spec)), to_eval)

        if ax is None:
            f, ax = plt.subplots()
        else:
            f = plt.gcf()
        CS = ax.contour(X, Y, Z, levels=levels, linestyles=linestyles, **kwargs)
        if clabels:
            ax.clabel(CS, CS.levels[::3], inline=True, fontsize=12, colors='black')
        ax.set_xlabel(r'log(n$_{\rm e}$) [cm$^{-3}$]')
        ax.set_ylabel(r'T$_{\rm e}$ [K]')
        ax.set_title(title)


    def plotLineRatio(self, to_eval, par=None, par_low=None, par_high=None, n_par=10,
                      linestyles='-', title=None, legend=True, loc=2, **kwargs):
        """
        Plot the diagnostic defined by to_eval as a function of either Ne or Te, with the other
        variable as a parameter.

        Parameters:
            to_eval:      algebraic definition of the line ratio to contour-plot
            par:          quantity to be used as a parameter (either 'den' or 'tem')
            par_low:      lowest limit of the parameter range
            par_high:     highest limit of the parameter range
            n_par:        number of parameter's values (default: 10)
            linestyles:   used for the contour lines (default: solid)
            title:        plot title
            legend:       Boolean. If True, write legend title (default: True) 
            **kwargs:     sent to plt.contour

        **Usage:**

            o3grid.plotLineRatio('L(4363)/L(5007)', par='den')

            s2grid.plotLineRatio('I(2,1)/I(3,1)', par='tem', par_low=5000, par_high=20000, n_par=4)

        """ 
        if not config.INSTALLED['plt']:
            log_.error('Matplotlib not available', calling=self.calling)
            return None

        L = lambda wav: self.getGrid(wave=wav)
        I = lambda i, j: self.getGrid(i, j)

        if par == 'tem':
            X = np.log10(self.den2D)
            Z = self.tem2D
            leg_format = "{0:.0f} K"
            leg_title = r'Temperature'
            xlabel = r'Log(N$_{\rm e}$) [cm$^{-3}$]'
        elif par == 'den':
            X = self.tem2D
            Z = np.log10(self.den2D)
            leg_format = "{0:.2f}"
            leg_title = r'Log(N$_{\rm e}$)'
            xlabel = r'T$_{\rm e}$ [K]'
        else:
            self.log_.error('The parameter must be either den or tem (%s given)' % par, calling=self.calling)

        try:
            Y = eval(to_eval)
        except:
            self.log_.warn('Diagnostic %s not found' % to_eval, calling=self.calling)            
            return None

        if par_low is None:
            par_low = np.min(Z)
        if par_high is None:
            par_high = np.max(Z)
        levels = np.linspace(par_low, par_high, n_par)

        CS = plt.contour(X, Y, Z, levels=levels, linestyles=linestyles, **kwargs)

        if legend:
            for i_level in range(len(levels)):
                CS.collections[i_level].set_label(leg_format.format(levels[i_level]))
                plt.legend(title=leg_title, loc=loc)

        if title is None:
            title = '[%s%s]' % (self.elem, int_to_roman(int(self.spec)))

        plt.xlabel(xlabel)
        plt.ylabel(to_eval)
        plt.title(title)

        plt.show()

__init__(elem=None, spec=None, n_tem=100, n_den=100, tem_min=5000.0, tem_max=20000.0, den_min=10.0, den_max=100000000.0, restore_file=None, atomObj=None, NLevels=None, **kwargs)

Container for the emission line intensity grids depending on Te and Ne.

Usage:

Parameters:

Name Type Description Default
elem

element (e.g. 'O')

None
spec

spectrum (e.g. 3)

None
n_tem

number of points of the electron temperature sample

100
n_den

number of points of the electron density sample

100
tem_min

minimum limit for the electron temperature

5000.0
tem_max

maximum limit for the electron temperature

20000.0
den_min

minimum limit for the electron density

10.0
den_max

maximum limit for the electron density

100000000.0
restore_file

if set, the emissivities are loaded from this file, otherwise (None) it is computed If the tem or den table from the restored file does not match the given parameters, a new grid is computed and self.compute_new_grid is set to True. The same applies if the atomic data are not the same.

None
atomObj

an atom object. In this case, no need for elem and spec.

None

Usage:

O3map = pn.EmisGrid('O', 3, n_tem=30, n_den=30)

O3map = pn.EmisGrid(restore_file='plot/O3_10k.pypic') # Recovers the map from a previous computation
Source code in pyneb/core/emisGrid.py
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
def __init__(self, elem=None, spec=None, n_tem=100, n_den=100, tem_min=5000., tem_max=20000.,
             den_min=10., den_max=1.e8, restore_file=None, atomObj=None, NLevels=None, **kwargs):

    """
    Container for the emission line intensity grids depending on Te and Ne.

    Usage:


    Parameters:
       elem:               element (e.g. 'O')
       spec:               spectrum (e.g. 3)
       n_tem:              number of points of the electron temperature sample
       n_den:              number of points of the electron density sample
       tem_min: minimum limit for the electron temperature
       tem_max: maximum limit for the electron temperature
       den_min: minimum limit for the electron density
       den_max: maximum limit for the electron density
       restore_file:       if set, the emissivities are loaded from this file, 
                             otherwise (None) it is computed
                             If the tem or den table from the restored file does not match the given parameters,
                             a new grid is computed and self.compute_new_grid is set to True. The same applies
                             if the atomic data are not the same.
       atomObj:            an atom object. In this case, no need for elem and spec.

    **Usage:**

        O3map = pn.EmisGrid('O', 3, n_tem=30, n_den=30)

        O3map = pn.EmisGrid(restore_file='plot/O3_10k.pypic') # Recovers the map from a previous computation

    """
    self.log_ = log_
    self.calling = 'EmisGrid'

    if restore_file is not None:
        old = restore(restore_file)
        self.elem = old['elem']
        self.spec = old['spec']
        if atomObj is None:
            self.atom = Atom(elem=self.elem, spec=self.spec, NLevels=NLevels, **kwargs)
        else:
            self.atom = atomObj
        if self.atom.type == 'coll':
            if self.atom.atomFitsFile != old['atomFitsFile']:
                self.log_.error('You are using {0}, but restoring a file made with {1}'.format(self.atom.atomFitsFile, old['atomFitsFile']),
                                calling=self.calling)
            if self.atom.collFitsFile != old['collFitsFile']:
                self.log_.error('You are using {0}, but restoring a file made with {1}'.format(self.atom.collFitsFile, old['collFitsFile']),
                                calling=self.calling)
        elif self.atom.type == 'rec':
            if self.atom.recFitsFile != old['recFitsFile']:
                self.log_.error('You are using {0}, but restoring a file made with {1}'.format(self.atom.recFitsFile, old['recFitsFile']),
                                calling=self.calling)
        self.compute_new_grid = False
        if n_tem != len(old['tem']):
            self.log_.warn('len(tem) does not match saved data. New grid is computed')
            self.compute_new_grid = True
        else:
            if not np.isclose(tem_min, min(old['tem'])):
                self.log_.warn('Min(tem) does not match saved data. New grid is computed')
                self.compute_new_grid = True
            if not np.isclose(tem_max, max(old['tem'])):
                self.log_.warn('Max(tem) does not match saved data. New grid is computed')
                self.compute_new_grid = True
        if n_den != len(old['den']):
            self.log_.warn('len(den) does not match saved data. New grid is computed')
            self.compute_new_grid = True
        else:
            if not np.isclose(den_min, min(old['den'])):
                self.log_.warn('Min(den) does not match saved data. New grid is computed')
                self.compute_new_grid = True
            if not np.isclose(den_max, max(old['den'])):
                self.log_.warn('Max(den) does not match saved data. New grid is computed')
                self.compute_new_grid = True
        if not self.compute_new_grid:
            self.tem = old['tem']
            self.den = old['den']
            self.n_tem = self.tem.size
            self.n_den = self.den.size
            self.tem_min = min(self.tem)
            self.tem_max = max(self.tem)
            self.den_min = min(self.den)
            self.den_max = max(self.den)
            self.emis_grid = old['emis_grid']
    else:
        self.compute_new_grid = True

    if self.compute_new_grid:
        if atomObj is None:
            self.elem = elem
            self.spec = spec
            self.atom = Atom(elem, spec, NLevels=NLevels, **kwargs)
        else:
            self.atom = atomObj
            self.elem = self.atom.elem
            self.spec = self.atom.spec
        self.n_tem = n_tem
        self.n_den = n_den
        self.tem_min = tem_min
        self.tem_max = tem_max
        self.den_min = den_min
        self.den_max = den_max
        self.tem = 10 ** np.linspace(np.log10(tem_min), np.log10(tem_max), n_tem)
        self.den = 10 ** np.linspace(np.log10(den_min), np.log10(den_max), n_den)
        try:
            self.atomFitsFile = self.atom.atomFitsFile
            self.collFitsFile = self.atom.collFitsFile
        except:
            self.atomFitsFile = None
            self.collFitsFile = None
        try:
            self.recFitsFile = self.atom.recFitsFile
        except:
            self.recFitsFile = None
        self.emis_grid = self.atom.getEmissivity(self.tem, self.den) #(erg.s-1.cm3)
        if restore_file is not None:
            self.save(restore_file)
            self.log_.message('%s saved to %s' % ((self.atom), restore_file), calling=self.calling)
        #self.emis_grid = np.empty((self.atom.NLevels, self.atom.NLevels, n_tem, n_den))

    self.den2D, self.tem2D = np.meshgrid(self.den, self.tem)

getGrid(lev_i=None, lev_j=None, wave=-1, to_eval=None, label=None)

2D array of a line emissivity (erg.s-1.cm3) for the (Te, Ne) values of a regularly spaced grid. The line is specified either as the wavelength or the levels. An expression can also be used, for example to_eval = 'L(5007)/L(4959)'

Parameters:

Name Type Description Default
lev_i

level i for the emission line

None
lev_j

level j for the emission line

None
wave

wavelength

-1
to_eval

algebraic expression of the line combination to evaluate

None
Source code in pyneb/core/emisGrid.py
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
def getGrid(self, lev_i=None, lev_j=None, wave= -1, to_eval=None, label=None):
    """
    2D array of a line emissivity (erg.s-1.cm3) for the (Te, Ne) values of a regularly spaced grid.
    The line is specified either as the wavelength or the levels. An expression can also be used, 
    for example to_eval = 'L(5007)/L(4959)'

    Parameters:
        lev_i: level i for the emission line
        lev_j: level j for the emission line
        wave:           wavelength
        to_eval:        algebraic expression of the line combination to evaluate

    """
    if wave != -1:
        lev_i, lev_j = self.atom.getTransition(wave)
    if label is not None:
        to_eval = 'S("{}")'.format(label)

    if to_eval is None:
        to_eval = 'I(' + str(lev_i) + ',' + str(lev_j) + ')'

    def I(lev_i, lev_j):
        return self.emis_grid[lev_i - 1, lev_j - 1, :, :]
    def L(wave):
        return self.getGrid(wave=wave)
    def S(label):
        return self.emis_grid[label]
    return eval(to_eval)

plotContours(to_eval, low_level=None, high_level=None, n_levels=20, levels=None, linestyles='-', clabels=True, log_levels=True, title=None, ax=None, **kwargs)

Plot a contour map of the diagnostic defined by to_eval.

Usage

O3map.plotContours('L(4363)/L(5007)')

Parameters:

Name Type Description Default
to_eval

algebraic definition of the line ratio to contour-plot

required
low_levels

limit levels for the contour. If not set, the limit of the ratio values are used.

required
high_levels

limit levels for the contour. If not set, the limit of the ratio values are used.

required
n_levels

number of levels (20 is the default)

20
linestyles

used for the contour lines (default: solid line)

'-'
clabels

Boolean. Controls if line labels are printed (default: True)

True
log_levels

Boolean. If True (default), the log of the line ratio is used.

True
title

plot title

None
**kwargs

sent to plt.contour

{}
Source code in pyneb/core/emisGrid.py
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
def plotContours(self, to_eval, low_level=None, high_level=None, n_levels=20, levels=None,
                  linestyles='-', clabels=True, log_levels=True, title=None, ax=None, **kwargs):
    """
    Plot a contour map of the diagnostic defined by to_eval.

    Usage:
        O3map.plotContours('L(4363)/L(5007)')

    Parameters:
        to_eval:                   algebraic definition of the line ratio to contour-plot
        low_levels: limit levels for the contour. If not set, the limit of the ratio values are used.
        high_levels: limit levels for the contour. If not set, the limit of the ratio values are used.
        n_levels:                  number of levels (20 is the default)
        linestyles:                used for the contour lines (default: solid line)
        clabels:                   Boolean. Controls if line labels are printed (default: True)
        log_levels:                Boolean. If True (default), the log of the line ratio is used.
        title:                     plot title
        **kwargs:                  sent to plt.contour            
    """ 
    if not config.INSTALLED['plt']:
        log_.error('Matplotlib not available', calling=self.calling)
        return None
    X = np.log10(self.den2D)
    Y = self.tem2D
    L = lambda lam: self.getGrid(wave=lam)
    I = lambda i, j: self.getGrid(i, j)
    S = lambda label: self.getGrid(label=label)
    try:
        diag_map = eval(to_eval)
    except:
        self.log_.warn('diag %s not found' % to_eval, calling=self.calling)
        return None
    if low_level is None:
        low_level = np.min(np.log10(diag_map))
    if high_level is None:
        high_level = np.max(np.log10(diag_map))
    if log_levels:
        Z = np.log10(diag_map)
        if levels is None:
            levels = np.linspace(low_level, high_level, n_levels)
        if title is None:
            title = '[%s%s]: log(%s)' % (self.elem, int_to_roman(int(self.spec)), to_eval)
    else:
        Z = diag_map
        if levels is None:
            levels = 10. ** (np.linspace(low_level, high_level, n_levels))
        if title is None:
            title = '[%s%s]: %s' % (self.elem, int_to_roman(int(self.spec)), to_eval)

    if ax is None:
        f, ax = plt.subplots()
    else:
        f = plt.gcf()
    CS = ax.contour(X, Y, Z, levels=levels, linestyles=linestyles, **kwargs)
    if clabels:
        ax.clabel(CS, CS.levels[::3], inline=True, fontsize=12, colors='black')
    ax.set_xlabel(r'log(n$_{\rm e}$) [cm$^{-3}$]')
    ax.set_ylabel(r'T$_{\rm e}$ [K]')
    ax.set_title(title)

plotImage(to_eval=None, lev_i1=None, lev_j1=None, lev_i2=None, lev_j2=None, wave1=-1, wave2=-1, cblabel='', **kwargs)

Draw a contour plot of a line ratio. The contour is obtained by a horizontal cut in a temden-emissivity array. More elaborated plots can be obtained with the Diagnostic object.

Usage

O3map.plotImage('L(4363)/L(5007)') O3map.plotImage(wave1=4363, wave2=5007)

Parameters:

Name Type Description Default
to_eval

algebraic expression of the line combination to draw. May combine L(lambda) and I(i,j).

None
lev_i1

levels of the a lines in case of simple line ratio plot.

None
lev_i2

levels of the a lines in case of simple line ratio plot.

None
lev_j1

levels of the a lines in case of simple line ratio plot.

None
lev_j2

levels of the a lines in case of simple line ratio plot.

None
wave1

wavelengths of the two lines in case of simple line ratio plot.

-1
wave2

wavelengths of the two lines in case of simple line ratio plot.

-1
cblabel

a title for the colorbar

''
**kwargs

any other parameter will be sent to contourf and pcolor

{}
Source code in pyneb/core/emisGrid.py
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
def plotImage(self, to_eval=None, lev_i1=None, lev_j1=None, lev_i2=None, lev_j2=None,
              wave1= -1, wave2= -1, cblabel='', **kwargs):
    """
    Draw a contour plot of a line ratio. The contour is obtained by a horizontal cut in a temden-emissivity array.
    More elaborated plots can be obtained with the Diagnostic object.

    Usage:
        O3map.plotImage('L(4363)/L(5007)')
        O3map.plotImage(wave1=4363, wave2=5007)

    Parameters:
        to_eval:                         algebraic expression of the line combination to draw. May combine L(lambda) and I(i,j).
        lev_i1: levels of the a lines in case of simple line ratio plot.
        lev_i2: levels of the a lines in case of simple line ratio plot.
        lev_j1: levels of the a lines in case of simple line ratio plot.
        lev_j2: levels of the a lines in case of simple line ratio plot.
        wave1: wavelengths of the two lines in case of simple line ratio plot.
        wave2: wavelengths of the two lines in case of simple line ratio plot.
        cblabel:                         a title for the colorbar
        **kwargs:                        any other parameter will be sent to contourf and pcolor

    """
    if not config.INSTALLED['plt']:
        log_.error('Matplotlib not available', calling=self.calling)
        return None
    L = lambda lam: self.getGrid(wave=lam)
    I = lambda i, j: self.getGrid(i, j)
    S = lambda label: self.getGrid(label)
    if to_eval is None:
        if wave1 != -1:
            lev_i1, lev_j1 = self.atom.getTransition(wave1)
        if wave2 != -1:
            lev_i2, lev_j2 = self.atom.getTransition(wave2)
        to_eval = 'I(' + str(lev_i1) + ',' + str(lev_j1) + ') / I(' + str(lev_i2) + ',' + str(lev_j2) + ')'
    X = np.log10(self.den2D)
    Y = self.tem2D / 1e4
    Z = self.getGrid(to_eval=to_eval)
    plt.contourf(X, Y, Z, **kwargs)
    emap = plt.pcolor(X, Y, Z, **kwargs)
    cbar = plt.colorbar(emap)
    cbar.set_label(cblabel)
    # plt.clabel(contour, inline=1)
    plt.xlabel(r'log Electron density (cm$^{-3}$)')
    plt.ylabel(r'Electron temperature ($10^4$K)')
    plt.show()

plotLineRatio(to_eval, par=None, par_low=None, par_high=None, n_par=10, linestyles='-', title=None, legend=True, loc=2, **kwargs)

Plot the diagnostic defined by to_eval as a function of either Ne or Te, with the other variable as a parameter.

Parameters:

Name Type Description Default
to_eval

algebraic definition of the line ratio to contour-plot

required
par

quantity to be used as a parameter (either 'den' or 'tem')

None
par_low

lowest limit of the parameter range

None
par_high

highest limit of the parameter range

None
n_par

number of parameter's values (default: 10)

10
linestyles

used for the contour lines (default: solid)

'-'
title

plot title

None
legend

Boolean. If True, write legend title (default: True)

True
**kwargs

sent to plt.contour

{}

Usage:

o3grid.plotLineRatio('L(4363)/L(5007)', par='den')

s2grid.plotLineRatio('I(2,1)/I(3,1)', par='tem', par_low=5000, par_high=20000, n_par=4)
Source code in pyneb/core/emisGrid.py
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
def plotLineRatio(self, to_eval, par=None, par_low=None, par_high=None, n_par=10,
                  linestyles='-', title=None, legend=True, loc=2, **kwargs):
    """
    Plot the diagnostic defined by to_eval as a function of either Ne or Te, with the other
    variable as a parameter.

    Parameters:
        to_eval:      algebraic definition of the line ratio to contour-plot
        par:          quantity to be used as a parameter (either 'den' or 'tem')
        par_low:      lowest limit of the parameter range
        par_high:     highest limit of the parameter range
        n_par:        number of parameter's values (default: 10)
        linestyles:   used for the contour lines (default: solid)
        title:        plot title
        legend:       Boolean. If True, write legend title (default: True) 
        **kwargs:     sent to plt.contour

    **Usage:**

        o3grid.plotLineRatio('L(4363)/L(5007)', par='den')

        s2grid.plotLineRatio('I(2,1)/I(3,1)', par='tem', par_low=5000, par_high=20000, n_par=4)

    """ 
    if not config.INSTALLED['plt']:
        log_.error('Matplotlib not available', calling=self.calling)
        return None

    L = lambda wav: self.getGrid(wave=wav)
    I = lambda i, j: self.getGrid(i, j)

    if par == 'tem':
        X = np.log10(self.den2D)
        Z = self.tem2D
        leg_format = "{0:.0f} K"
        leg_title = r'Temperature'
        xlabel = r'Log(N$_{\rm e}$) [cm$^{-3}$]'
    elif par == 'den':
        X = self.tem2D
        Z = np.log10(self.den2D)
        leg_format = "{0:.2f}"
        leg_title = r'Log(N$_{\rm e}$)'
        xlabel = r'T$_{\rm e}$ [K]'
    else:
        self.log_.error('The parameter must be either den or tem (%s given)' % par, calling=self.calling)

    try:
        Y = eval(to_eval)
    except:
        self.log_.warn('Diagnostic %s not found' % to_eval, calling=self.calling)            
        return None

    if par_low is None:
        par_low = np.min(Z)
    if par_high is None:
        par_high = np.max(Z)
    levels = np.linspace(par_low, par_high, n_par)

    CS = plt.contour(X, Y, Z, levels=levels, linestyles=linestyles, **kwargs)

    if legend:
        for i_level in range(len(levels)):
            CS.collections[i_level].set_label(leg_format.format(levels[i_level]))
            plt.legend(title=leg_title, loc=loc)

    if title is None:
        title = '[%s%s]' % (self.elem, int_to_roman(int(self.spec)))

    plt.xlabel(xlabel)
    plt.ylabel(to_eval)
    plt.title(title)

    plt.show()

save(file_)

Save results for a later use.

Usage

O3map.save('plot/O3_30by30.pypic')

Parameter

file_ the name of the file in which the emissivity grids are stored

Source code in pyneb/core/emisGrid.py
149
150
151
152
153
154
155
156
157
158
159
160
161
162
def save(self, file_):
    """
    Save results for a later use.

    Usage:
        O3map.save('plot/O3_30by30.pypic')

    Parameter:
        file_  the name of the file in which the emissivity grids are stored

    """
    save(file_, emis_grid=self.emis_grid, tem=self.tem, den=self.den, elem=self.elem,
         spec=self.spec, 
         atomFitsFile=self.atomFitsFile, collFitsFile=self.collFitsFile, recFitsFile=self.recFitsFile)

getEmisGridDict(elem_list=None, spec_list=None, atom_list=None, restore=True, pypic_path=None, n_tem=100, n_den=100, tem_min=5000.0, tem_max=20000.0, den_min=10.0, den_max=100000000.0, save=True, atomDict=None, createPypicsDir=True, computeIfAbsent=True)

Return a dictionary of EmisGrid objects referred to by their atom string (e.g. 'O3').

Parameters:

Name Type Description Default
elem_list

list of elements

None
spec_list

list of spectrum values (integers)

None
atom_list

list of atoms (e.g. ['N2', 'O3'])

None
restore

Boolean. If True (default), the program will search for a previously computed grid. If not found, it will compute the EmisGrid (unless computeIfAbsent is set to False)

True
pypic_path

directory where to look for the pypic emissivity files. It defaults to pn.config.pypic_path, which is defined when the PyNeb session begins and corresponds to $HOME/.pypics if the ENVIRONMENT variable HOME is accessible or to /tmp/pypics otherwise

None
n_tem

number of points in the Te samples resp.

100
n_den

number of points in the Ne samples resp.

100
tem_min

minimum Te value

5000.0
tem_max

maximum Te value

20000.0
den_min

minimum Ne value

10.0
den_max

maximum Ne value

100000000.0
save bool

If True (default), the emissivity grid will be saved. It has no effect if the EmisGrid has just been restored.

True
atomDict

dictionary of Atom objects

None
computeIfAbsent bool

If the file to restore is absent and this parameter is True, the EmisGrid is computed

True

Usage:

emisgrids = pn.getEmisGridDict(['C', 'N', 'O'], [2, 3], save=True)

emisgrids = pn.getEmisGridDict(atom_list=['N2', 'O2', 'O3'], pypic_path='/tmp/pypics/',
                den_max = 1e6)

emisgrids = pn.getEmisGridDict(atomDict=diags.atomDict)
Source code in pyneb/core/emisGrid.py
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
def getEmisGridDict(elem_list=None, spec_list=None, atom_list=None, restore=True, pypic_path=None,
            n_tem=100, n_den=100, tem_min=5000., tem_max=20000., den_min=10., den_max=1e8, save=True,
            atomDict=None, createPypicsDir=True, computeIfAbsent=True):
    """
    Return a dictionary of EmisGrid objects referred to by their atom string (e.g. 'O3').


    Parameters:
        elem_list:         list of elements
        spec_list:         list of spectrum values (integers)
        atom_list:         list of atoms (e.g. ['N2', 'O3'])
        restore:           Boolean. If True (default), the program will search for a previously computed grid.
                            If not found, it will compute the EmisGrid (unless computeIfAbsent is set to False)
        pypic_path:        directory where to look for the pypic emissivity files. It defaults to pn.config.pypic_path, 
                            which is defined when the PyNeb session begins and corresponds to $HOME/.pypics if
                            the ENVIRONMENT variable HOME is accessible or to /tmp/pypics otherwise
        n_tem:      number of points in the Te  samples resp. 
        n_den:      number of points in the Ne samples resp. 
        tem_min: minimum Te value
        tem_max: maximum Te value
        den_min: minimum Ne value
        den_max: maximum Ne value
        save (bool): If True (default), the emissivity grid will be saved. It has no effect if the 
                            EmisGrid has just been restored.
        atomDict:          dictionary of Atom objects
        computeIfAbsent (bool):   If the file to restore is absent and this parameter is True, the EmisGrid is computed

    **Usage:**

        emisgrids = pn.getEmisGridDict(['C', 'N', 'O'], [2, 3], save=True)

        emisgrids = pn.getEmisGridDict(atom_list=['N2', 'O2', 'O3'], pypic_path='/tmp/pypics/',
                        den_max = 1e6)

        emisgrids = pn.getEmisGridDict(atomDict=diags.atomDict)


    """
    if pypic_path is None:
        pypic_path = config.pypic_path
    else:
        config.pypic_path = pypic_path
    calling = 'getEmisGridDict'
    if pypic_path is None:
        return None
    emis_grids = {}
    atoms = []
    if atomDict is not None:
        atoms = atomDict.keys()
    else:
        if atom_list is not None:
            atoms = atom_list
        else:
# VL Removed 13 March 2015 because it made the code ignore the elem keyword             
#            atoms = atomicData.getAllAtoms()
            if (elem_list is None) and (spec_list is None):
                atoms = atomicData.getAllAtoms()
            else:
                for elem in elem_list:
                    for spec in spec_list:
                        atoms.append(elem + str(spec)) 
    for atom in atoms:
        elem, spec, rec = parseAtom2(atom)
        if atomDict is not None:
            atomObj = atomDict[atom]
        else:
            atomObj = None
        file_ = '{0}/emis_{1}{2}{3}.pypic'.format(pypic_path, elem, spec, rec)
        if restore:
            if os.path.exists(file_):
                try:
                    emis_grids[elem + spec + rec] = EmisGrid(restore_file=file_, n_tem=n_tem, n_den=n_den, 
                                                       tem_min=tem_min, tem_max=tem_max,
                                                       den_min=den_min, den_max=den_max, atomObj=atomObj)
                    log_.message('Read %s' % file_, calling=calling)
                    compute_this = False
                except:
                    if computeIfAbsent:
                        log_.warn('Wrong emission map: {0}, creating it'.format(file_), calling=calling)
                        compute_this = True
                    else:
                        log_.error('Wrong emission map: {0}'.format(file_), calling=calling)
                        compute_this = False
            else:
                log_.warn('Emission map not found: {0}'.format(file_), calling=calling)
                if computeIfAbsent:
                    compute_this = True
        else:
            compute_this = True
        if compute_this:
            try:
                emis_grids[atom] = EmisGrid(elem, spec, n_tem=n_tem, n_den=n_den, tem_min=tem_min, tem_max=tem_max,
                                              den_min=den_min, den_max=den_max, atomObj=atomObj)
                if save:
                    emis_grids[atom].save(file_)
                    log_.message('%s saved to %s' % ((atom), file_), calling=calling)
            except:
                log_.warn('No %s EmisGrid' % (atom), calling=calling)
    return emis_grids