コード例 #1
0
def womreddening(hop):
    """redden or deredden with various reddening laws"""
    import matplotlib.pyplot as plt
    import extinction
    from tmath.wombat.inputter_single import inputter_single
    from tmath.wombat.inputter import inputter
    from tmath.wombat.yesno import yesno
    r_v=3.1
    print('Redden or deredden a spectrum')
    plt.cla()
    plt.plot(hop[0].wave,hop[0].flux,drawstyle='steps-mid',color='k')
    plt.xlabel('Wavelength')
    plt.ylabel('Flux')
    plt.title(hop[0].obname)
    flux=hop[0].flux.copy()
    action=inputter_single('(r)edden or (d)eredden the spectrum? (r/d) ', 'rd')
    print(' ')
    type=inputter_single('Do you want to enter the (c)olor excess, or (v)isual extinction? ','cv')
    print(' ')
    if (type == 'v'):
        av=inputter('Enter A_V in magnitudes: ','float',False)
    else:
        ebv=inputter('Enter E(B-V) in magnitudes: ','float',False)
        av=r_v*ebv
    print(' ')
    print('Do you want to use: ')
    print('(c)ardelli, Clayton, Mathis 1989')
    print("(o)'donnell 1994")
    print('(f)itzpatrick 1999\n')
    
    method=inputter_single('(c/o/f) ','cof')
    if (action == 'r'):
        if (method == 'c'):
            newflux=extinction.apply(extinction.ccm89(hop[0].wave,av,r_v),flux)
        elif (method == 'o'):
            newflux=extinction.apply(extinction.odonnell94(hop[0].wave,av,r_v),flux)
        else:
            newflux=extinction.apply(extinction.fitzpatrick99(hop[0].wave,av,r_v),flux)
    else:
        if (method == 'c'):
            ext=extinction.ccm89(hop[0].wave,av,r_v)
        elif (method == 'o'):
            ext=extinction.odonnell94(hop[0].wave,av,r_v)
        else:
            ext=extinction.fitzpatrick99(hop[0].wave,av,r_v)
        newflux=flux*10**(0.4*ext)
    plt.plot(hop[0].wave,newflux,drawstyle='steps-mid',color='r')
    print('\nOriginal spectrum in black, red/dered in red\n')
    print('Is this OK?\n')
    answer=yesno('y')
    if (answer == 'y'):
        hop[0].flux=newflux.copy()
        print('\nActive spectrum now changed')
    else:
        print('\nSorry to disappoint you, active spectrum unchanged')
    return hop
コード例 #2
0
ファイル: losextinction.py プロジェクト: SSantosLab/notMOSFiT
 def preprocess(self, **kwargs):
     """Preprocess module."""
     if self._preprocessed:
         return
     self._ebv = kwargs[self.key('ebv')]
     self._av_mw = self.MW_RV * self._ebv
     self._nh_mw = self._av_mw * 1.8e21
     # Pre-calculate LOS dust from MW for all bands
     self._mw_extinct = np.zeros_like(self._sample_wavelengths)
     self._ext_indices = []
     self._x_indices = []
     add_refs = set()
     for si, sw in enumerate(self._sample_wavelengths):
         self._ext_indices.append(
             self._sample_wavelengths[si] >= self.LYMAN)
         self._x_indices.append(
             (self._sample_wavelengths[si] >= self._min_wavelength)
             & (self._sample_wavelengths[si] < self.LYMAN))
         if len(self._ext_indices[si]) > 0:
             self._mw_extinct[si][self._ext_indices[si]] = odonnell94(
                 self._sample_wavelengths[si][self._ext_indices[si]],
                 self._av_mw, self.MW_RV)
             add_refs.add('1')
         if len(self._x_indices[si]) > 0:
             self._mw_extinct[si][self._x_indices[si]] = self.mm83(
                 self._nh_mw,
                 self._sample_wavelengths[si][self._x_indices[si]])
             add_refs.add('2')
     for ref in list(add_refs):
         self._REFERENCES.extend(self._ref_table[ref])
     self._preprocessed = True
コード例 #3
0
    def apply_dust(self):

        import extinction

        for ii in range(self.n_zz):
            if self.dust['flag'] == 'calzetti':
                self.lum_em[:, ii] = extinction.apply(
                    extinction.calzetti00(self.wav_em, self.dust['Av'], 4.05),
                    self.lum_em[:, ii])
            elif self.dust['flag'] == 'cardelli':
                self.lum_em[:, ii] = extinction.apply(
                    extinction.ccm89(self.wav_em, self.dust['Av'], 4.05),
                    self.lum_em[:, ii])
            elif self.dust['flag'] == 'odonnell':
                self.lum_em[:, ii] = extinction.apply(
                    extinction.odonnell94(self.wav_em, self.dust['Av'], 4.05),
                    self.lum_em[:, ii])
            elif self.dust['flag'] == 'fitzpatrick':
                self.lum_em[:, ii] = extinction.apply(
                    extinction.fitzpatrick99(self.wav_em, self.dust['Av'],
                                             3.1), self.lum_em[:, ii])
            elif self.dust['flag'] == 'fitzpatrick07':
                self.lum_em[:, ii] = extinction.apply(
                    extinction.fm07(self.wav_em, self.dust['Av']),
                    self.lum_em[:, ii])
コード例 #4
0
def extinction_correction(wave, flux, ebv, r_v=3.1):

    if ebv is None:
        return flux

    ext = extinction.odonnell94(wave, r_v * ebv, r_v)
    return extinction.apply(-1. * ext, flux)  # de-redden
コード例 #5
0
    def process(self, **kwargs):
        """Process module."""
        kwargs = self.prepare_input(self.key('luminosities'), **kwargs)
        self.preprocess(**kwargs)
        zp1 = 1.0 + kwargs[self.key('redshift')]
        self._seds = kwargs[self.key('seds')]
        self._nh_host = kwargs[self.key('nhhost')]
        self._rv_host = kwargs[self.key('rvhost')]
        self._bands = kwargs['all_bands']
        self._band_indices = kwargs['all_band_indices']
        self._frequencies = kwargs['all_frequencies']
        self._band_rest_wavelengths = self._sample_wavelengths / zp1

        av_host = self._nh_host / 1.8e21

        extinct_cache = OrderedDict()
        for si, cur_band in enumerate(self._bands):
            bi = self._band_indices[si]
            # Extinct out host gal (using rest wavelengths)
            if bi >= 0:
                if bi not in extinct_cache:
                    extinct_cache[bi] = np.zeros_like(
                        self._band_rest_wavelengths[bi])
                    ind = self._ext_indices[bi]
                    if len(ind) > 0:
                        extinct_cache[bi][ind] = odonnell94(
                            self._band_rest_wavelengths[bi][ind], av_host,
                            self._rv_host)
                    ind = self._x_indices[bi]
                    if len(ind) > 0:
                        extinct_cache[bi][ind] = self.mm83(
                            self._nh_host,
                            self._band_rest_wavelengths[bi][ind])
                # Add host and MW contributions
                eapp(self._mw_extinct[bi] + extinct_cache[bi],
                     self._seds[si],
                     inplace=True)
            else:
                # wavelengths = np.array(
                #   [c.c.cgs.value / self._frequencies[si]])
                # Need extinction function for radio
                pass

        # Units of `seds` is ergs / s / Angstrom.
        return {
            'sample_wavelengths': self._sample_wavelengths,
            self.key('seds'): self._seds,
            self.key('avhost'): av_host
        }
コード例 #6
0
ファイル: test.py プロジェクト: earnric/modules
def test_odonnell94():
    # NOTE: The tabulated values go to 0.001, but the test is only for matching
    # at the 0.005 level, because there is currently a discrepancy up to 0.0047
    # of unknown origin.
    #
    # Tests od94() at Rv = 3.1 against the widely used values tabulated in
    # Schlegel, Finkbeiner and Davis (1998)
    # http://adsabs.harvard.edu/abs/1998ApJ...500..525S
    #
    # This is tested by evaluating the extinction curve at a (given)
    # effective wavelength, since these effective wavelengths:
    # "... represent(s) that wavelength on the extinction curve 
    # with the same extinction as the full passband."
    #
    # The test does not include UKIRT L' (which, at 3.8 microns) is 
    # beyond the range of wavelengths allowed by the function
    # or the APM b_J filter which is defined in a non-standard way. 
    #
    # The SFD98 tabulated values go to 1e-3, so we should be able to match at
    # that level.

    wave = np.array([3372., 4404., 5428., 6509., 8090.,
                     3683., 4393., 5519., 6602., 8046.,
                     12660., 16732., 22152.,
                     5244., 6707., 7985., 9055.,
                     6993.,
                     3502., 4676., 4127.,
                     4861., 5479.,
                     3546., 4925., 6335., 7799., 9294.,
                     3047., 4711., 5498.,
                     6042., 7068., 8066.,
                     4814., 6571., 8183.])

    ref_values = np.array([1.664, 1.321, 1.015, 0.819, 0.594,
                           1.521, 1.324, 0.992, 0.807, 0.601,
                           0.276, 0.176, 0.112,
                           1.065, 0.793, 0.610, 0.472,
                           0.755,
                           1.602, 1.240, 1.394,
                           1.182, 1.004,
                           1.579, 1.161, 0.843, 0.639, 0.453,
                           1.791, 1.229, 0.996,
                           0.885, 0.746, 0.597,
                           1.197, 0.811, 0.580])

    assert_allclose(extinction.odonnell94(wave, 1.0, 3.1), ref_values,
                    rtol=0.0051, atol=0.)
コード例 #7
0
ファイル: test.py プロジェクト: hsalas/extinction
def test_odonnell94():
    # NOTE: The tabulated values go to 0.001, but the test is only for matching
    # at the 0.005 level, because there is currently a discrepancy up to 0.0047
    # of unknown origin.
    #
    # Tests od94() at Rv = 3.1 against the widely used values tabulated in
    # Schlegel, Finkbeiner and Davis (1998)
    # http://adsabs.harvard.edu/abs/1998ApJ...500..525S
    #
    # This is tested by evaluating the extinction curve at a (given)
    # effective wavelength, since these effective wavelengths:
    # "... represent(s) that wavelength on the extinction curve
    # with the same extinction as the full passband."
    #
    # The test does not include UKIRT L' (which, at 3.8 microns) is
    # beyond the range of wavelengths allowed by the function
    # or the APM b_J filter which is defined in a non-standard way.
    #
    # The SFD98 tabulated values go to 1e-3, so we should be able to match at
    # that level.

    wave = np.array([
        3372., 4404., 5428., 6509., 8090., 3683., 4393., 5519., 6602., 8046.,
        12660., 16732., 22152., 5244., 6707., 7985., 9055., 6993., 3502.,
        4676., 4127., 4861., 5479., 3546., 4925., 6335., 7799., 9294., 3047.,
        4711., 5498., 6042., 7068., 8066., 4814., 6571., 8183.
    ])

    ref_values = np.array([
        1.664, 1.321, 1.015, 0.819, 0.594, 1.521, 1.324, 0.992, 0.807, 0.601,
        0.276, 0.176, 0.112, 1.065, 0.793, 0.610, 0.472, 0.755, 1.602, 1.240,
        1.394, 1.182, 1.004, 1.579, 1.161, 0.843, 0.639, 0.453, 1.791, 1.229,
        0.996, 0.885, 0.746, 0.597, 1.197, 0.811, 0.580
    ])

    assert_allclose(extinction.odonnell94(wave, 1.0, 3.1),
                    ref_values,
                    rtol=0.0051,
                    atol=0.)
コード例 #8
0
ファイル: ml.py プロジェクト: jpierel14/sntd
 def propagate(self, phase, wave, flux):
     """Propagate the flux."""
     ebv, r_v = self._parameters
     return extinction.apply(extinction.odonnell94(wave, ebv * r_v, r_v),
                             flux)
コード例 #9
0
def deredden(wave,
             flux,
             ra,
             dec,
             scaling=0.86,
             reddening_law='fitzpatrick99',
             dustmaps_dir=None,
             r_v=3.1,
             ebv=None):
    """Dereddens the given spectrum, given a right ascension and declination or :math:`E(B-V)`.

    Parameters
    ----------
    wave : array
        Wavelength values.
    flux : array
        Flux density values.
    ra : float
        Right ascension in degrees.
    dec : float
        Declination in degrees.
    scaling: float, default ``0.86``
        Calibration of the Milky Way dust maps. Either ``0.86``
        for the Schlafly & Finkbeiner (2011) recalibration or ``1.0`` for the original
        dust map of Schlegel, Fikbeiner & Davis (1998).
    reddening_law: str, default ``fitzpatrick99``
        Reddening law. The options are: ``ccm89`` (Cardelli, Clayton & Mathis 1989), ``odonnell94`` (O’Donnell 1994),
        ``fitzpatrick99`` (Fitzpatrick 1999), ``calzetti00`` (Calzetti 2000) and ``fm07`` (Fitzpatrick & Massa 2007 with
        :math:`R_V` = 3.1.)
    dustmaps_dir : str, default ``None``
        Directory where the dust maps of Schlegel, Fikbeiner & Davis (1998) are found.
    r_v : float, default ``3.1``
        Total-to-selective extinction ratio (:math:`R_V`)
    ebv : float, default ``None``
        Colour excess (:math:`E(B-V)`). If given, this is used instead of the dust map value.

    Returns
    -------
    deredden_flux : array
        Deredden flux values.

    """
    pisco_path = piscola.__path__[0]
    if dustmaps_dir is None:
        dustmaps_dir = os.path.join(pisco_path, 'sfddata-master')

    if ebv is None:
        m = sfdmap.SFDMap(mapdir=dustmaps_dir, scaling=scaling)
        ebv = m.ebv(ra, dec)  # RA and DEC in degrees

    a_v = r_v * ebv

    rl_list = ['ccm89', 'odonnell94', 'fitzpatrick99', 'calzetti00', 'fm07']
    assert reddening_law in rl_list, f'Choose one of the available reddening laws: {rl_list}'

    if reddening_law == 'ccm89':
        ext = extinction.ccm89(wave, a_v, r_v)
    elif reddening_law == 'odonnell94':
        ext = extinction.odonnell94(wave, a_v, r_v)
    elif reddening_law == 'fitzpatrick99':
        ext = extinction.fitzpatrick99(wave, a_v, r_v)
    elif reddening_law == 'calzetti00':
        ext = extinction.calzetti00(wave, a_v, r_v)
    elif reddening_law == 'fm07':
        ext = extinction.fm07(wave, a_v)

    deredden_flux = extinction.remove(ext, flux)

    return deredden_flux
コード例 #10
0
#!/usr/bin/env python
"""Plot extinction functions for comparison"""

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rcParams
from mpl_toolkits.axes_grid1 import make_axes_locatable

import extinction

rcParams['font.family'] = 'serif'

wave = np.logspace(np.log10(910.), np.log10(30000.), 2000)

a_lambda = {'ccm89': extinction.ccm89(wave, 1.0, 3.1),
            'odonnell94': extinction.odonnell94(wave, 1.0, 3.1),
            'fitzpatrick99': extinction.fitzpatrick99(wave, 1.0),
            'fm07': extinction.fm07(wave, 1.0)}

names = list(a_lambda.keys())  # consistent ordering between panels

fig = plt.figure(figsize=(8.5, 6.))

ax = plt.axes()
for name in names:
    plt.plot(wave, a_lambda[name], label=name)
plt.axvline(x=2700., ls=':', c='k')
plt.axvline(x=3030.3030, ls=':', c='k')
plt.axvline(x=9090.9091, ls=':', c='k')
plt.axvspan(wave[0], 1150., fc='0.8', ec='none', zorder=-1000)
plt.axvspan(1150., 1250., fc='0.9', ec='none', zorder=-1000)    
コード例 #11
0
ファイル: reddening.py プロジェクト: galaxyumi/DECam_PGCM
def getReddeningLaw(law='fitzpatrick99',Rv=3.1,inv=False):

    import numpy as np
    from scipy import interpolate
    import extinction

    # Wavelength ranges (lambda_min - lambda_max) of the various reddening laws 
    #  (in Angstroms)...
    lambda_min = {'ccm89':          1250., 
                  'odonnell94':     1250., 
                  'calzetti00':     1200., 
                  'fitzpatrick99':   910., 
                  'fm07':            910.}
    lambda_max = {'ccm89':         33000.,
                  'odonnell94':    33000.,
                  'calzetti00':    22000.,
                  'fitzpatrick99': 60000.,
                  'fm07':          60000.}
    # We can extract the list of supported reddening laws by
    #  grabbing those that are keys within the lambda_min dictionary...
    supported_laws = lambda_min.keys()

    # If reddening law not in the the list of supported reddening laws,
    #  return an Exception...
    if law not in supported_laws: 
        print """Un-supported reddening law:  %s""" % (law)
        print 'Supported reddening laws are: ', supported_laws 
        print 'Returning exception'
        return Exception

    # Calculate and return the reddening law in either
    #  inverse wavelength form (inv=True) or in wavelength
    #  form (inv=False)...
    if inv==True:

        # Use inverse microns to call to "extinction" module
        #  and return reddening law in inverse Angstroms...

        # Calculate inverse wavelengths...
        x_lambda_min = 1.0e4/lambda_max[law]
        x_lambda_max = 1.0e4/lambda_min[law]
        x_micron = np.linspace(x_lambda_min, x_lambda_max, 2000) # microns^-1
        x_angstrom = x_micron * 1.0e-4 # Convert from microns^-1 to Anstroms^-1

        # Call appropriate reddening law function...
        if law == 'ccm89':
            r_array = Rv*extinction.ccm89(x_micron, 1.0, Rv, unit='invum')
        elif law == 'odonnell94':
            r_array = Rv*extinction.odonnell94(x_micron, 1.0, Rv, unit='invum')
        elif law == 'calzetti00':
            r_array = Rv*extinction.calzetti00(x_micron, 1.0, Rv, unit='invum')
        elif law == 'fitzpatrick99':
            r_array = Rv*extinction.fitzpatrick99(x_micron, 1.0, Rv, unit='invum')
        elif law == 'fm07':
            r_array = Rv*extinction.fm07(x_micron, 1.0, unit='invum')

        # Create interpolation function for reddening law...
        r = interpolate.interp1d(x_angstrom, r_array, 
                                 bounds_error=False, fill_value=0., kind=3)

    else:

        # Use Angstroms to call to "extinction" module
        #  and return reddening law in Angstroms...

        # Create wavelength array...
        angstrom = np.logspace(np.log10(lambda_min[law]), np.log10(lambda_max[law]), 2000)

        # Call appropriate reddening law function...
        if law == 'ccm89':
            r_array = Rv*extinction.ccm89(angstrom, 1.0, Rv, unit='aa')
        elif law == 'odonnell94':
            r_array = Rv*extinction.odonnell94(angstrom, 1.0, Rv, unit='aa')
        elif law == 'calzetti00':
            r_array = Rv*extinction.calzetti00(angstrom, 1.0, Rv, unit='aa')
        elif law == 'fitzpatrick99':
            r_array = Rv*extinction.fitzpatrick99(angstrom, 1.0, Rv, unit='aa')
        elif law == 'fm07':
            r_array = Rv*extinction.fm07(angstrom, 1.0, unit='aa')

        # Create interpolation function for reddening law...
        r = interpolate.interp1d(angstrom, r_array, 
                                 bounds_error=False, fill_value=0., kind='linear')

    # Return interpolation fucntion...
    return r
コード例 #12
0
ファイル: ext_laws.py プロジェクト: michaelJwilson/LBGCMB
def extinct(ls,
            EBV=0.1,
            HyperZ=True,
            type='calzetti',
            atmos=False,
            tatmos='eso',
            unit='aa'):
    """
  http://extinction.readthedocs.io/en/latest/                                                                                                             
  https://github.com/kbarbary/extinction/blob/19be03f7e04ce22802c52137205aa67ae7a0a8de/extinction.pyx

  ls: wavelength in angstroms; alternative unit of 'invum' (inverse microns).                                                                           
  A_V: extinction in magnitudes at characteristic V band.                                                                                               
  Ratio of total to selective extinction, Rv = A_V / E(B - V).                                                                                         
  
  -- https://arxiv.org/pdf/1209.2152.pdf                                                                                                             
  -- https://arxiv.org/pdf/astro-ph/9911459.pdf                                                                                                      
  
  Both studies used template spectra including dust attenuation following the Calzetti law.                                                              
  Finkelstein et al. inferred an attenuation at 1500A, A1500, of 1.3 magnitudes at z=4                                                                
  and A1500 < 0.25 at z=7. In contrast, for galaxies with z = 6.5, McLure et al. found A1500=0.4,                                                     
  a value above the upper limit found by Finkelstein et al. In many observational studies the dust                                                     
  attenuation is inferred from the UV continuum slope estimated from a single colour. Bouwens et al. (2011)                                          
  measured an average UV continuum slope of -3 for galaxies at z = 7. However, this value was measured to be -2.2                                      
  when more data were collected by the HST WFC3 (Bouwens et al. 2012). This illustrates how the scarcity of high                                       
  redshift data can bias the estimation of dust attenuation.                                                                                         
      
  UV continuum slope is a poor indicator of dust attenuation, as our results are extremely sensitive to the choice                                      
  of extinction curve used as the input to the attenuation of starlight calculations. For our standard choice, a Milky Way (MW)                          
  extinction curve, galaxies get bluer when they are attenuated, which, as we explain in Section 6 is due to the presence of a                          
  bump in the extinction curve.                                                                                                             
  Usually the term dust 'extinction' refers to the attenuation of the light from a point source placed behind a screen of dust.                          
  Thus, the 'extinction' is independent of the geometry of the system.                                                                                    

  With a_\lambda = L_\lambda (attenuated) /L_\lambda (unattenuated), t_eff (\lambda) = -ln(a_\lambda).                                                   
  Magnitudes: \tau_\eff = A_\lambda / (2.5 \log_10 e).                                                                                                  
  
  MW extinction: Cardelli, Clayton & Mathis (1989) with A_V = 1.0 (Amplitude) and R_V = 3.1 (Shape).                                                     
  """

    ## Av = Rv * E(B-V); Rv = 4.05
    if HyperZ == False:
        if type == 'odonnell':
            ## MW extinction O'Donnell (1994)
            Rv = 3.1
            ext = extinction.odonnell94(ls, Rv * EBV, Rv)

        elif type == 'fitzpatrick':
            ## LMC extinction; Fitzpatrick (1999)
            Rv = 3.10
            ext = extinction.fitzpatrick99(ls, Rv * EBV, Rv)

        else:
            Rv = 4.05
            ext = extinction.calzetti00(
                ls, Rv * EBV,
                Rv)  ## Extinction in magnitudes at each input wavelength.

    else:
        """
    http://webast.ast.obs-mip.fr/hyperz/hyperz_manual1/node10.html                                                                                      
    The extinction curve are expressed in  k(lambda[A]) vs lambda[A].                                                                                   
    Apply a E(B-V) correction by:                                                                                                                            
    flux_attenuated = flux_intrinsic * 10^[-0.4*k(l)*Av/Rv] 
    """

        files = {
            'fitzpatrick': 'LMC_Fitzpatrick.dat',
            'allen': 'MW_Allen.dat',
            'seaton': 'MW_seaton.dat',
            'prevot': 'SMC_prevot.dat',
            'calzetti': 'SB_calzetti.dat'
        }
        Rvs = {
            'fitzpatrick': 3.10,
            'allen': 3.10,
            'seaton': 3.10,
            'prevot': 2.72,
            'calzetti': 4.05
        }

        files[
            'calzetti_mod'] = 'SB_calzetti_mod.dat'  ## modified Calzetti law including contribution from 2175A bump (Massaroti et al., 2001)
        Rvs['calzetti_mod'] = 4.05

        data = np.loadtxt('ext-laws/' + files[type])
        extinterp = interp1d(data[:, 0],
                             EBV * data[:, 1],
                             kind='cubic',
                             bounds_error=False,
                             fill_value=0.0)
        ext = extinterp(ls)

    if atmos == True:
        files = {
            'eso': 'extinc_eso.dat',
            'ctio': 'extinc_ctio.dat'
        }  ## Atmospheric extinction curves
        Rv = 3.1

        data = np.loadtxt('ext-laws/' + files[tatmos])
        extinterp = interp1d(data[:, 0],
                             EBV * data[:, 1],
                             kind='cubic',
                             bounds_error=False,
                             fill_value=0.0)

        ext += extinterp(ls)

    return 10.**(
        -0.4 * ext
    )  ## Deredden with -Av; Positive extinction values decrease flux.
コード例 #13
0
    wave_aa = wave[fltr] * 1e4
    av = calzetti00(wave_aa, Av, Rv)
    f0 = np.ones_like(wave)
    f0[fltr] = 10**(-0.4 * av)
    return f0


if __name__ == "__main__":
    import extinction
    import matplotlib.pyplot as plt

    Rv = 3.1
    wave = np.logspace(np.log10(910.), np.log10(30000.), 2000)
    a_lambda = {
        'ccm89': extinction.ccm89(wave, 1.0, Rv),
        'odonnell94': extinction.odonnell94(wave, 1.0, Rv),
        'fitzpatrick99': extinction.fitzpatrick99(wave, 1.0),
        "c00": extinction.calzetti00(wave, 1.0, Rv),
        'fm07': extinction.fm07(wave, 1.0)
    }
    for mn in a_lambda.keys():
        ext = a_lambda[mn]
        plt.plot(wave, ext, label=mn)
    c00_2 = -2.5 * np.log10(Calzetti00(2., wave / 1e4, Rv))
    c00_3 = extinction.calzetti00(wave, 2.0, Rv)
    plt.plot(wave, c00_2, color="turquoise")
    plt.plot(wave, c00_3, color="tomato", linestyle=":")
    plt.xscale("log")
    plt.legend(loc="upper right")
    plt.show()