Beispiel #1
0
def redden(wave, flux, ebv_gal, ebv_host, z, R_gal=3.1, R_host=3.1,
      redlaw='ccm', strict_ccm=False):
   '''Artificially redden the spectral template to simulate dust reddening, a la
   Cardelli et al.
   
   Args:
      wave (float array): Input wavelength in Angstroms
      flux (float array): arbitrarily scaled SED flux
      ebv_gal (float): color excess to be applied in rest-frame (due to MW)
      ebv_host (floag): color excess to be applied at host redshift
      z (float): redshift of the host extinction
      R_gal (float): Ratio of total to selective absoption in V for restframe
                     component of extinction.
      R_host (float): Ratio of total to selective absorption in V for host
                      frame extinction.
      redlaw (str): Form of the dust extinction curve. Possible values are
                    'ccm', 'f99', or 'fm07'. See :mod:`snpy.utils.deredden`.
   
   Returns:
      float array: reddened flux.
   '''

   #First we redden due to galactic extinction:
   newflux = 1.0*flux
   # ebv_host is in the frame of the SN
   if ebv_host != 0:
      newflux,a,b = deredden.unred(wave, flux, -ebv_host, R_host,redlaw=redlaw,
            strict_ccm=strict_ccm)
   # ebv_gal is in the frame of the observer
   if ebv_gal != 0:
      newflux,a,b = deredden.unred(wave, newflux, -ebv_gal, R_gal, z, 
            redlaw=redlaw, strict_ccm=strict_ccm)

   return(newflux)
Beispiel #2
0
def redden(wave,
           flux,
           ebv_gal,
           ebv_host,
           z,
           R_gal=3.1,
           R_host=3.1,
           redlaw='ccm',
           strict_ccm=False):
    '''Artificially redden the spectral template to simulate dust reddening, a la
   Cardelli et al.
   
   Args:
      wave (float array): Input wavelength in Angstroms
      flux (float array): arbitrarily scaled SED flux
      ebv_gal (float): color excess to be applied in rest-frame (due to MW)
      ebv_host (floag): color excess to be applied at host redshift
      z (float): redshift of the host extinction
      R_gal (float): Ratio of total to selective absoption in V for restframe
                     component of extinction.
      R_host (float): Ratio of total to selective absorption in V for host
                      frame extinction.
      redlaw (str): Form of the dust extinction curve. Possible values are
                    'ccm', 'f99', or 'fm07'. See :mod:`snpy.utils.deredden`.
   
   Returns:
      float array: reddened flux.
   '''

    #First we redden due to galactic extinction:
    newflux = 1.0 * flux
    # ebv_host is in the frame of the SN
    if ebv_host != 0:
        newflux, a, b = deredden.unred(wave,
                                       flux,
                                       -ebv_host,
                                       R_host,
                                       redlaw=redlaw,
                                       strict_ccm=strict_ccm)
    # ebv_gal is in the frame of the observer
    if ebv_gal != 0:
        newflux, a, b = deredden.unred(wave,
                                       newflux,
                                       -ebv_gal,
                                       R_gal,
                                       z,
                                       redlaw=redlaw,
                                       strict_ccm=strict_ccm)

    return (newflux)
Beispiel #3
0
def bolometric_SED(sn, bands=None, lam1=None, lam2=None, refband=None,
              EBVhost=None, Rv=None, redlaw=None, extrap_red='RJ',
              Tmax=None, interpolate=None, extrapolate=False, mopts={}, 
              SED='H3', DM=None, cosmo='LambdaCDM', use_stretch=True, 
              extrap_SED=True, extra_output=False, verbose=False):

   w,f = get_SED(0, version='H3')
   if verbose: log("Starting bolometric calculation for %s\n" % sn.name)

   if EBVhost is None:
      EBVhost = getattr(sn, 'EBVhost', None)
      if EBVhost is None:
         raise AttributeError, "Error:  you must either specify E(B-V) or "\
                               "fit a model that has EBVhost as a parameter"
   if Rv is None:
      Rv = getattr(sn, 'Rv', None)
      if Rv is None:
         raise AttributeError, "Error:  you must either specify Rv or "\
                               "fit a model that has Rv as a parameter"

   if redlaw is None:
      redlaw = getattr(sn, 'redlaw', None)
      if redlaw is None:
         raise AttributeError, "Error:  you must either specify redlaw or "\
                               "fit a model that has redlaw is defined"

   if bands is None:
      bands = getattr(sn.model, '_fbands', None)
      if bands is None:
         bands = sn.data.keys()
   for b in bands:
      if b not in sn.data:
         raise AttributeError, "band %s not defined in data set" % (b)
   # Bands must be increasing in wavelength
   eff_waves = array([fset[b].eff_wave(w,f) for b in bands])
   sids = argsort(eff_waves)
   bands = [bands[i] for i in sids]
   pars0 = {}
   for b in bands:  pars0[b] = 1.0

   # Get itegration limits in SN restframe. So if we get it from the observer
   #  frame filter limits, we need to divide by (1+z)
   if lam1 is None:
      lam1 = array([fset[b].waverange()[0] for b in bands]).min()/(1+sn.z)
   if lam2 is None:
      lam2 = array([fset[b].waverange()[1] for b in bands]).max()/(1+sn.z)

   if refband is not None:
      if refband not in bands:
         raise ValueError, "refband %s is not one of your observed filters" % \
               refband


   # We need a time of maximum to set the scale of the Hsiao templates
   if Tmax is None:
      Tmax = getattr(sn, 'Tmax', None)
      if Tmax is None:
         raise ValueError, "You must supply a time of B maximum or fit a "\
               "model that has Tmax as a parameter"

   # Now check that we can interpolate if needed
   if interpolate is not None:
      if interpolate == 'spline':
         if verbose: log("   Using spline interpolation")
         for b in bands:
            if getattr(sn.data[b], 'interp', None) is None:
               raise ValueError, "You asked for spline interpolation, but "\
                     "filter %s has not interpolator defined" % b
      else:
         if verbose: log("   Using model interpolation")
         for b in bands:
            if b not in sn.model._fbands:
               raise ValueError, "You asked for model interpolation, but "\
                     "filter %f was not fit with the model" % b
   else:
      if verbose: log("   Not using interpolation")

   if type(SED) is type(""):
      # Assume it is a spectrum by name
      if SED in ['H3','H','N','91bg']:
         fSED = lambda x: get_SED(x, version=SED, extrapolate=True)
         if verbose: log("   Using SED template '%s'" % SED)
      elif SED in standards:
         fSED = lambda x: (standards[SED].wave,standards[SED].flux)
         if verbose: log("   Using standards['%s'] to compute effective wavelengths" % (SED))
      else:
         raise KeyError, "SED '%s' not found in standards database" % SED
   elif type(SED) in [types.ListType,types.TupleType]:
      if len(SED) != 2:
         raise ValueError, "SED must be tuple or list of length 2"
      fSED = lambda x: SED
   elif type(SED) is types.FunctionType:
      try:
         w,f = SED(0)
      except:
         raise ValueError, "If SED is a function, it must take single" \
               " argument (epoch) and return (wave,flux) tuple"
      fSED = SED
   else:
      raise ValueError, "Unrecognized type (%s) for SED" % (type(SED))


   s = 1.0
   if use_stretch:
      s = getattr(sn, 'st', None)
      dm15 = getattr(sn, 'dm15', None)
      if s is None:
         if dm15 is None:
            raise ValueError, "If you want to apply a stretch to the SED's, "\
                  "you must fit a model that uses dm15 or st as a parameter"
         if dm15 > 1.7:
            if verbose: log("Warning:  dm15 > 1.7. Hsiao template is not "
                  "compatible with fast decliners. Proceed a your own risk")
            s = kcorr.dm152s(1.7)
         elif dm15 < 0.7:
            if verbose: log("Warning:  dm15 < 0.7. This is a very slow "
                  "decliner. Proceed at your own risk")
            s = kcorr.dm152s(0.7)
         else:
            s = kcorr.dm152s(dm15)
      if verbose: log("   Using a stretch of %f" % s)

   # Now, we build up the times at which we will be integrating and the 
   # assocuated fluxes. We do things in the frame of the SN and de-stretch
   # the times.
   res = sn.get_mag_table(bands)
   ts = (res['MJD'] - Tmax)/(1+sn.z)
   # Restrict to valid interval of Eric's templates if extrap_SED is False
   if not extrap_SED:
      gids = greater_equal(ts/s, -19)*less_equal(ts/s,70)
   else:
      gids = -isnan(ts/s)
   ts = ts[gids]
   mags = []
   masks = []
   for b in bands:
      mags.append(res[b][gids])
      masks.append(less(res[b][gids],90))

   if interpolate == 'spline':
      # we fill in (where we can) missing data using splines
      for i,b in enumerate(bands):
         # interpolation is in the absolute time, so use MJD
         mag,mask = sn.data[b].interp(res['MJD'][gids])
         mags[i] = where(masks[i], mags[i], mag)
         masks[i] = masks[i] + mask

   elif interpolate == 'model':
      # we fill in (where we can) missing data using the model
      for i,b in enumerate(bands):
         mag,emag,mask = sn.model(b, res['MJD'][gids], extrap=extrapolate)
         mags[i] = where(masks[i], mags[i], mag)
         masks[i] = masks[i] + mask

   mags = transpose(array(mags))
   masks = transpose(array(masks))
   if verbose:  log("   Working on data matrix with size (%d,%d)" % mags.shape)
   # see if any days have zero data
   gids = greater(sum(masks, axis=1), 0)
   mags = mags[gids,:]
   masks = masks[gids,:]
   ts = ts[gids]

   # Now mangle the spectra, deredden and integrate-em
   filters_used = []
   boloflux = []
   epochs = []
   mfuncs = []
   fluxes = []
   waves = []
   parss = []

   for i in range(len(ts)):
      t = ts[i]
      wave,flux = fSED(t/s)
      # Check limits of integration (in rest frame of SN)
      if lam1 < wave.min() or (lam2 > wave.max() and not extrap_red):
         raise RuntimeError, "Error: your limits of integration (%.3f,%.3f) "\
                             "are outside the limits of the SED (%.3f,%.3f)" %\
                             (lam1,lam2,wave.min(), wave.max())

      # integration limits
      i1 = searchsorted(wave, lam1)
      i2 = searchsorted(wave, lam2)
      bs = [bands[j] for j in range(masks.shape[1]) if masks[i,j]]
      if len(bs) == 1:
         # No mangling possible
         mflux = flux
         mfuncs.append(flux*0+1)
      else:
         init = [pars0.get(b, 1.0) for b in bs]
         mflux,ave_wave,pars = mangle_spectrum2(wave*(1+sn.z), flux, bs, 
               mags[i,masks[i]], normfilter=refband, init=init, **mopts)
         mfuncs.append(mflux[0]/flux)
         mflux = mflux[0]
         for k,b in enumerate(bs):
            pars0[b] = pars[k]
         parss.append(pars)

      # Now scale the spectrum to one of the observed filters
      if refband is None:
         idx = bands.index(bs[0])
         filt = fset[bs[0]]
         if verbose:  log("   Using %s as reference filter" % bs[0])
      else:
         if refband not in bs:
            if verbose: log("Warning: refband %s has no observation or "
                  "interpolation for epoch %f" % ts[i])
            continue 
         idx = bands.index(refband)
         filt = fset[refband]

      # Scale to match photometry. We need to be careful here. The magnitude
      # measures the response of the filter to the *redshifted* spectrum
      mag = mags[i, idx]
      mflux = mflux*power(10, 
            -0.4*(mag - filt.zp))/filt.response(wave, mflux/(1+sn.z), z=sn.z)
      # Note:  the quantity power()/filt.response() is actually
      # dimensionless. Therefore mflux is in erg/s/cm^2/AA
      # and *not* in photons

      # Next, de-redden MW extinction and host extinction
      mflux,a,b = deredden.unred(wave*(1+sn.z),mflux,sn.EBVgal,R_V=3.1,redlaw=redlaw)
      mflux,a,b = deredden.unred(wave,mflux,EBVhost, R_V=Rv, redlaw=redlaw)

      # Finally!  integrate!
      fbol = trapz(mflux[i1:i2], x=wave[i1:i2])
      if lam2 > wave.max():
         # add Rayleigh-Jeans extrapolation (~ 1/lam^4)
         fbol += mflux[-1]*wave[-1]/3*(1 - power(wave[-1]/lam2,3))

      filters_used.append(bs)
      boloflux.append(fbol)
      epochs.append(ts[i])
      waves.append(wave[i1:i2])
      fluxes.append(mflux[i1:i2])

   boloflux = array(boloflux)
   epochs = array(epochs)

   # lastly, inverse-square law
   if DM is None:
      DM = sn.get_distmod(cosmo=cosmo)
   dlum = power(10, 0.2*(DM+5))*3.086e18
   boloflux = boloflux*4*pi*dlum**2

   return(dict(epochs=array(epochs), 
               boloflux=array(boloflux), 
               filters_used=filters_used,waves=waves,fluxes=fluxes,
               mfuncs=mfuncs, mags=mags, masks=masks, pars=parss))
Beispiel #4
0
def bolometric_SED(sn,
                   bands=None,
                   lam1=None,
                   lam2=None,
                   refband=None,
                   EBVhost=None,
                   Rv=None,
                   redlaw=None,
                   extrap_red='RJ',
                   Tmax=None,
                   interpolate=None,
                   extrapolate=False,
                   mopts={},
                   SED='H3',
                   DM=None,
                   cosmo='LambdaCDM',
                   use_stretch=True,
                   extrap_SED=True,
                   extra_output=False,
                   verbose=False):

    w, f = get_SED(0, version='H3')
    if verbose: log("Starting bolometric calculation for %s\n" % sn.name)

    if EBVhost is None:
        EBVhost = getattr(sn, 'EBVhost', None)
        if EBVhost is None:
            raise AttributeError, "Error:  you must either specify E(B-V) or "\
                                  "fit a model that has EBVhost as a parameter"
    if Rv is None:
        Rv = getattr(sn, 'Rv', None)
        if Rv is None:
            raise AttributeError, "Error:  you must either specify Rv or "\
                                  "fit a model that has Rv as a parameter"

    if redlaw is None:
        redlaw = getattr(sn, 'redlaw', None)
        if redlaw is None:
            raise AttributeError, "Error:  you must either specify redlaw or "\
                                  "fit a model that has redlaw is defined"

    if bands is None:
        bands = getattr(sn.model, '_fbands', None)
        if bands is None:
            bands = sn.data.keys()
    for b in bands:
        if b not in sn.data:
            raise AttributeError, "band %s not defined in data set" % (b)
    # Bands must be increasing in wavelength
    eff_waves = array([fset[b].eff_wave(w, f) for b in bands])
    sids = argsort(eff_waves)
    bands = [bands[i] for i in sids]
    pars0 = {}
    for b in bands:
        pars0[b] = 1.0

    # Get itegration limits in SN restframe. So if we get it from the observer
    #  frame filter limits, we need to divide by (1+z)
    if lam1 is None:
        lam1 = array([fset[b].waverange()[0]
                      for b in bands]).min() / (1 + sn.z)
    if lam2 is None:
        lam2 = array([fset[b].waverange()[1]
                      for b in bands]).max() / (1 + sn.z)

    if refband is not None:
        if refband not in bands:
            raise ValueError, "refband %s is not one of your observed filters" % \
                  refband

    # We need a time of maximum to set the scale of the Hsiao templates
    if Tmax is None:
        Tmax = getattr(sn, 'Tmax', None)
        if Tmax is None:
            raise ValueError, "You must supply a time of B maximum or fit a "\
                  "model that has Tmax as a parameter"

    # Now check that we can interpolate if needed
    if interpolate is not None:
        if interpolate == 'spline':
            if verbose: log("   Using spline interpolation")
            for b in bands:
                if getattr(sn.data[b], 'interp', None) is None:
                    raise ValueError, "You asked for spline interpolation, but "\
                          "filter %s has not interpolator defined" % b
        else:
            if verbose: log("   Using model interpolation")
            for b in bands:
                if b not in sn.model._fbands:
                    raise ValueError, "You asked for model interpolation, but "\
                          "filter %f was not fit with the model" % b
    else:
        if verbose: log("   Not using interpolation")

    if type(SED) is type(""):
        # Assume it is a spectrum by name
        if SED in ['H3', 'H', 'N', '91bg']:
            fSED = lambda x: get_SED(x, version=SED, extrapolate=True)
            if verbose: log("   Using SED template '%s'" % SED)
        elif SED in standards:
            fSED = lambda x: (standards[SED].wave, standards[SED].flux)
            if verbose:
                log("   Using standards['%s'] to compute effective wavelengths"
                    % (SED))
        else:
            raise KeyError, "SED '%s' not found in standards database" % SED
    elif type(SED) in [types.ListType, types.TupleType]:
        if len(SED) != 2:
            raise ValueError, "SED must be tuple or list of length 2"
        fSED = lambda x: SED
    elif type(SED) is types.FunctionType:
        try:
            w, f = SED(0)
        except:
            raise ValueError, "If SED is a function, it must take single" \
                  " argument (epoch) and return (wave,flux) tuple"
        fSED = SED
    else:
        raise ValueError, "Unrecognized type (%s) for SED" % (type(SED))

    s = 1.0
    if use_stretch:
        s = getattr(sn, 'st', None)
        dm15 = getattr(sn, 'dm15', None)
        if s is None:
            if dm15 is None:
                raise ValueError, "If you want to apply a stretch to the SED's, "\
                      "you must fit a model that uses dm15 or st as a parameter"
            if dm15 > 1.7:
                if verbose:
                    log("Warning:  dm15 > 1.7. Hsiao template is not "
                        "compatible with fast decliners. Proceed a your own risk"
                        )
                s = kcorr.dm152s(1.7)
            elif dm15 < 0.7:
                if verbose:
                    log("Warning:  dm15 < 0.7. This is a very slow "
                        "decliner. Proceed at your own risk")
                s = kcorr.dm152s(0.7)
            else:
                s = kcorr.dm152s(dm15)
        if verbose: log("   Using a stretch of %f" % s)

    # Now, we build up the times at which we will be integrating and the
    # assocuated fluxes. We do things in the frame of the SN and de-stretch
    # the times.
    res = sn.get_mag_table(bands)
    ts = (res['MJD'] - Tmax) / (1 + sn.z)
    # Restrict to valid interval of Eric's templates if extrap_SED is False
    if not extrap_SED:
        gids = greater_equal(ts / s, -19) * less_equal(ts / s, 70)
    else:
        gids = -isnan(ts / s)
    ts = ts[gids]
    mags = []
    masks = []
    for b in bands:
        mags.append(res[b][gids])
        masks.append(less(res[b][gids], 90))

    if interpolate == 'spline':
        # we fill in (where we can) missing data using splines
        for i, b in enumerate(bands):
            # interpolation is in the absolute time, so use MJD
            mag, mask = sn.data[b].interp(res['MJD'][gids])
            mags[i] = where(masks[i], mags[i], mag)
            if extrapolate:
                masks[i] = -isnan(mags[i])
            else:
                masks[i] = masks[i] + mask

    elif interpolate == 'model':
        # we fill in (where we can) missing data using the model
        for i, b in enumerate(bands):
            mag, emag, mask = sn.model(b, res['MJD'][gids], extrap=extrapolate)
            mags[i] = where(masks[i], mags[i], mag)
            masks[i] = masks[i] + mask

    mags = transpose(array(mags))
    masks = transpose(array(masks))
    if verbose: log("   Working on data matrix with size (%d,%d)" % mags.shape)
    # see if any days have zero data
    gids = greater(sum(masks, axis=1), 0)
    mags = mags[gids, :]
    masks = masks[gids, :]
    ts = ts[gids]

    # Now mangle the spectra, deredden and integrate-em
    filters_used = []
    boloflux = []
    epochs = []
    mfuncs = []
    fluxes = []
    waves = []
    parss = []

    for i in range(len(ts)):
        t = ts[i]
        wave, flux = fSED(t / s)
        # Check limits of integration (in rest frame of SN)
        if lam1 < wave.min() or (lam2 > wave.max() and not extrap_red):
            raise RuntimeError, "Error: your limits of integration (%.3f,%.3f) "\
                                "are outside the limits of the SED (%.3f,%.3f)" %\
                                (lam1,lam2,wave.min(), wave.max())

        # integration limits
        i1 = searchsorted(wave, lam1)
        i2 = searchsorted(wave, lam2)
        bs = [bands[j] for j in range(masks.shape[1]) if masks[i, j]]
        if len(bs) == 1:
            # No mangling possible
            mflux = flux
            mfuncs.append(flux * 0 + 1)
        else:
            init = [pars0.get(b, 1.0) for b in bs]
            mflux, ave_wave, pars = mangle_spectrum2(wave * (1 + sn.z),
                                                     flux,
                                                     bs,
                                                     mags[i, masks[i]],
                                                     normfilter=refband,
                                                     init=init,
                                                     **mopts)
            mfuncs.append(mflux[0] / flux)
            mflux = mflux[0]
            for k, b in enumerate(bs):
                pars0[b] = pars[k]
            parss.append(pars)

        # Now scale the spectrum to one of the observed filters
        if refband is None:
            idx = bands.index(bs[0])
            filt = fset[bs[0]]
            if verbose: log("   Using %s as reference filter" % bs[0])
        else:
            if refband not in bs:
                if verbose:
                    log("Warning: refband %s has no observation or "
                        "interpolation for epoch %f" % ts[i])
                continue
            idx = bands.index(refband)
            filt = fset[refband]

        # Scale to match photometry. We need to be careful here. The magnitude
        # measures the response of the filter to the *redshifted* spectrum
        mag = mags[i, idx]
        mflux = mflux * power(10, -0.4 * (mag - filt.zp)) / filt.response(
            wave, mflux / (1 + sn.z), z=sn.z)
        # Note:  the quantity power()/filt.response() is actually
        # dimensionless. Therefore mflux is in erg/s/cm^2/AA
        # and *not* in photons

        # Next, de-redden MW extinction and host extinction
        mflux, a, b = deredden.unred(wave * (1 + sn.z),
                                     mflux,
                                     sn.EBVgal,
                                     R_V=3.1,
                                     redlaw=redlaw)
        mflux, a, b = deredden.unred(wave,
                                     mflux,
                                     EBVhost,
                                     R_V=Rv,
                                     redlaw=redlaw)

        # Finally!  integrate!
        fbol = trapz(mflux[i1:i2], x=wave[i1:i2])
        if lam2 > wave.max():
            # add Rayleigh-Jeans extrapolation (~ 1/lam^4)
            fbol += mflux[-1] * wave[-1] / 3 * (1 - power(wave[-1] / lam2, 3))

        filters_used.append(bs)
        boloflux.append(fbol)
        epochs.append(ts[i])
        waves.append(wave[i1:i2])
        fluxes.append(mflux[i1:i2])

    boloflux = array(boloflux)
    epochs = array(epochs)

    # lastly, inverse-square law
    if DM is None:
        DM = sn.get_distmod(cosmo=cosmo)
    dlum = power(10, 0.2 * (DM + 5)) * 3.086e18
    boloflux = boloflux * 4 * pi * dlum**2

    return (dict(epochs=array(epochs),
                 boloflux=array(boloflux),
                 filters_used=filters_used,
                 waves=waves,
                 fluxes=fluxes,
                 mfuncs=mfuncs,
                 mags=mags,
                 masks=masks,
                 pars=parss))