Ejemplo n.º 1
0
def kcorr_mangle(days, filts, mags, m_mask, restfilts, z, version='H', 
      colorfilts=None, full_output=0, mepoch=False, **mopts):
   '''Compute (cross-)band K-corrections with "mangling" using built-in library
   of spectral SEDs. The SEDs are first multiplied by a smooth spline such that
   the synthetic colors match the observed colors.

   Args:
      days (float array): epochs (t-Tmax(B)) at which to compute K-corrections
      filts (list of str): list of observed filters
      mags (2d float array): Observed magnitude array indexed by
                             [spectrum index,filter index]
      m_mask (2d bool array): mask array indicating valid magnitudes. Indexed
                              by [spectrum index,filter index]
      restfilts (list of str): Rest-frame filters corresponing to filts.
      z (float):  redshift
      version (str): Specify which spectral sequence to use. See
                     :func:`.get_SED`.
      colorfilts (list of str): (optional) Sub set of filters to use in 
                              mangling colors (filters that have very similar
                              effective wavelengths can make for unstable
                              splines).
      full_output (bool):  If True, output more information than just the
                          K-corrections and mask.
      mepoch (bool): If True, a single mangling function is solved for
                     all epochs. EXPERIMENTAL.
      mopts (dict): All additional arguments to function are sent to 
                    :func:`snpy.mangle_spectrum.mangle_spectrum2`.
   
   Returns:
      tuple:

         * if not full_output: 2-tuple (K,mask):
            * K (flaot array):  K-corrections for filts
            * mask (bool array): mask of valid K-corrections
         * if full_output: 5-tuple (K,mask,anchors,factors,funcs)
            * anchors (float array): wavelengths of anchor points
            * factors (float array): factors corresponding to anchors
            * funcs (float array): mangling function evaluated at anchors
   '''

   if 'method' in mopts:
      method = mopts['method']
   else:
      method = 'tspline'

   if colorfilts is None:  colorfilts = filts
   for filter1 in filts + restfilts + colorfilts:
      if filter1 not in filters.fset:
         raise AttributeError, "filter %s not defined in filters module" % filter1

   kcorrs = []
   mask = []      # Masks the good values (1) and bad (not defined) values (0)
   m_opts = []
   Rts = []
   if debug:  mopts['verbose'] = 1

   if mepoch:
      # Doing multi epoch simultaneously with one mangling function...
      spec_wavs = []
      spec_fs = []
      sids = []
      for j in range(len(days)):
         day = int(days[j])
         s,f = get_SED(day, version)
         if s is None:
            spec_wavs.append(num.arange(980.,24981.0,10.))
            spec_fs.append(num.zeros((2401,), dtype=num.float64))
            sids.append(False)
         else:
            spec_wavs.append(s)
            spec_fs.append(f)
            sids.append(True)
      spec_wavs = num.array(spec_wavs)
      spec_fs = num.array(spec_fs)
      sids = num.array(sids)
      fs = [colorfilts[i] for i in range(len(colorfilts)) \
            if num.sometrue(m_mask[:,i])]
      if len(fs) <=1 :
         waves,man_spec_fs,factors = spec_wavs,spec_fs,spec_wavs*0.0+1.0
      else:
         #cs = mags[:,:-1] - mags[:,1:]
         #gids = m_mask[:,:-1]*m_mask[:,1:]
         #gids = gids*sids[:,num.newaxis]
         #cs[-gids] = 99.9   # flag invalid value
         gids = m_mask*sids[:,num.newaxis]
         ms = where(gids, ms, 99.9)
         man_spec_fs,waves,factors = mangle_spectrum2(spec_wavs*(1+z),
               spec_fs, fs, ms, **mopts)


      for j in range(len(days)):
         kcorrs.append([])
         mask.append([])
         if not sids[j]:
            kcorrs[-1] = num.zeros((len(filts),), dtype=num.float32)
            mask[-1] = num.zeros((len(filts),), dtype=num.int8)
            Rts.append(kcorrs[-1] - 1.0)
            m_opts.append(None)
            continue
         if full_output:
            args = {'sw':waves, 'sf':factors}
            for key in mopts:
               args[key] = mopts[key]
            m_opts.append(args)
 
         for i in range(len(filts)):
             f1 = filters.fset[restfilts[i]]
             f2 = filters.fset[filts[i]]
             k,f = K(spec_wavs[j], man_spec_fs[j], f1, f2, z)
             kcorrs[-1].append(k)
             mask[-1].append(0)
         Rts.append(R_obs_spectrum(filts, spec_wavs[j], man_spec_fs[j], z, 
            0.01, 0.0))
   else:
      for j in range(len(days)):
         kcorrs.append([])
         mask.append([])
         day = int(days[j])
         spec_wav,spec_f = get_SED(day, version)
         if spec_wav is None:
            # print "Warning:  no spectra for day %d, setting Kxy=0" % day
            kcorrs[-1] = num.zeros((len(filts),), dtype=num.float32)
            mask[-1] = num.zeros((len(filts),), dtype=num.int8)
            Rts.append(kcorrs[-1] - 1.0)
            m_opts.append(None)
            continue
 
         # Now determine which colors to use:
         fs = [colorfilts[i] for i in range(len(colorfilts)) if m_mask[j,i]]
         if len(fs) <= 1:
            # only one filter, so no color information, leave the SED alone:
            waves,man_spec_f,factors = spec_wav,spec_f,spec_wav*0.0+1.0
            man_spec_f = [man_spec_f]
         else:
            #cs = num.compress(m_mask[j],mags[j])[0:-1] - \
            #     num.compress(m_mask[j],mags[j])[1:]
            ms = num.compress(m_mask[j], mags[j])
            if debug:
               print "filters and colors for day %f:" % (days[j])
               print fs
               print ms[:-1]-ms[1:]
  
            # Now we mangle the spectrum.  Note, we are redshifting the spectrum
            # here, so do NOT set z in mangle_spectrum2.
            man_spec_f,waves,factors = mangle_spectrum2(spec_wav*(1+z),spec_f,
                  fs, ms, **mopts)
 
            if debug:  print "factors = ",factors
            if debug:
               # check the colors
               for i in range(len(fs)-1):
 
                  print "input color:  %s-%s = %f" % (fs[i],fs[i+1], ms[i]-ms[i+1]),
                  f1 = filters.fset[fs[i]]
                  f2 = filters.fset[fs[i+1]]
                  col = f1.synth_mag(spec_wav*(1+z), man_spec_f[0]) - \
                        f2.synth_mag(spec_wav*(1+z), man_spec_f[0])
                  print "  output color:  %f" % (col)
  
         if full_output:
            args = {'sw':waves, 'sf':factors}
            for key in mopts:
               args[key] = mopts[key]
            m_opts.append(args)
  
         for i in range(len(filts)):
            f1 = filters.fset[restfilts[i]]
            f2 = filters.fset[filts[i]]
            k,f = K(spec_wav,man_spec_f[0], f1, f2, z)
            kcorrs[-1].append(k)
            mask[-1].append(f)
         Rts.append(R_obs_spectrum(filts, spec_wav, man_spec_f[0], z, 0.01, 
            0.0))
   Rts = num.array(Rts)
   gids = num.greater(Rts, 0)
   Rtave = num.array([num.average(num.compress(gids[:,k], Rts[:,k])) \
         for k in range(len(gids[0]))])
   Rts = num.array([num.where(gids[i], Rts[i], Rtave) for i in range(len(gids))])

   kcorrs = num.array(kcorrs)
   mask = num.array(mask)

   if not full_output:
      return(kcorrs,mask)
   else:
      return(kcorrs, mask, Rts, m_opts)
Ejemplo n.º 2
0
def kcorr_mangle2(waves, spectra, filts, mags, m_mask, restfilts, z, 
      colorfilts=None, full_output=0, **mopts): 
   '''Compute (cross-)band K-corrections with "mangling" using provided
   spectral SEDs. The SEDs are first multiplied by a smooth spline such that
   the synthetic colors match the observed colors.

   Args:
      waves (list of float arrays):  Input wavelengths in Angstroms
      spectra (list of float arrays):  Input fluxes in arbitrary units
      filts (list of str): list of observed filters
      mags (2d float array): Observed magnitude array indexed by
                             [spectrum index,filter index]
      m_mask (2d bool array): mask array indicating valid magnitudes. Indexed
                              by [spectrum index,filter index]
      restfilts (list of str): Rest-frame filters corresponing to filts.
      z (float):  redshift
      colorfilts (list of str): (optional) Sub set of filters to use in 
                              mangling colors (filters that have very similar
                              effective wavelengths can make for unstable
                              splines).
      full_output (bool):  If True, output more information than just the
                          K-corrections and mask.
      mopts (dict): All additional arguments to function are sent to 
                    :func:`snpy.mangle_spectrum.mangle_spectrum2`.
   
   Returns:
      tuple:

         * if not full_output: 2-tuple (K,mask):
            * K (flaot array):  K-corrections for filts
            * mask (bool array): mask of valid K-corrections
         * if full_output: 5-tuple (K,mask,anchors,factors,funcs)
            * anchors (float array): wavelengths of anchor points
            * factors (float array): factors corresponding to anchors
            * funcs (float array): mangling function evaluated at anchors
   '''
   if colorfilts is None:  colorfilts = filts
   for filter1 in filts + restfilts + colorfilts:
      if filter1 not in filters.fset:
         raise AttributeError, "filter %s not defined in filters module" % filter1

   if len(num.shape(waves)) < 2:
      scalar = 1
      waves = num.array([waves])
      spectra = num.array([spectra])
      mags = num.array([mags])
      m_mask = num.array([m_mask])
   else:
      scalar = 0


   kcorrs = []
   mask = []      # Masks the good values (1) and bad (not defined) values (0)
   waves_a = []
   manf_a = []
   factors_a = []

   for j in range(len(spectra)):
      kcorrs.append([])
      mask.append([])
      spec_wav,spec_f = waves[j],spectra[j]

      # Now determine which colors to use:
      fs = [colorfilts[i] for i in range(len(colorfilts)) if m_mask[j,i]]
      if len(fs) <= 1:
         # only one filter, so no color information, leave the SED alone:
         man_waves,man_spec_f,factors = spec_wav,spec_f,spec_wav*0.0+1.0
      else:
         #cs = num.compress(m_mask[j],mags[j])[0:-1] - \
         #      num.compress(m_mask[j],mags[j])[1:]
         ms = num.compress(m_mask[j],mags[j])
 
         # Now we mangle the spectrum:
         man_spec_f,man_waves,factors = mangle_spectrum2(spec_wav*(1+z),spec_f,fs, 
               ms, **mopts)
      if full_output:
         waves_a.append(man_waves)
         manf_a.append(man_spec_f)
         factors_a.append(factors)
 
      for i in range(len(filts)):
         f1 = filters.fset[restfilts[i]]
         f2 = filters.fset[filts[i]]

         k,f = K(spec_wav, man_spec_f[0], f1, f2, z)
         if f == 1:
            kcorrs[-1].append(k)
            mask[-1].append(len(fs))
         else:
            kcorrs[-1].append(0)
            mask[-1].append(0)
   kcorrs = num.array(kcorrs)
   mask = num.array(mask)

   if full_output:
      if scalar:
         return(kcorrs[0], mask[0], waves_a[0], factors_a[0], manf_a[0])
      else:
         return(kcorrs, mask, waves_a, factors_a, manf_a)
   else:
      if scalar:
         return(kcorrs[0],mask[0])
      else:
         return(kcorrs,mask)
Ejemplo n.º 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))
Ejemplo n.º 4
0
Archivo: kcorr.py Proyecto: wmwv/snpy
def kcorr_mangle(days,
                 filts,
                 mags,
                 m_mask,
                 restfilts,
                 z,
                 version='H',
                 colorfilts=None,
                 full_output=0,
                 mepoch=False,
                 **mopts):
    '''Compute (cross-)band K-corrections with "mangling" using built-in library
   of spectral SEDs. The SEDs are first multiplied by a smooth spline such that
   the synthetic colors match the observed colors.

   Args:
      days (float array): epochs (t-Tmax(B)) at which to compute K-corrections
      filts (list of str): list of observed filters
      mags (2d float array): Observed magnitude array indexed by
                             [spectrum index,filter index]
      m_mask (2d bool array): mask array indicating valid magnitudes. Indexed
                              by [spectrum index,filter index]
      restfilts (list of str): Rest-frame filters corresponing to filts.
      z (float):  redshift
      version (str): Specify which spectral sequence to use. See
                     :func:`.get_SED`.
      colorfilts (list of str): (optional) Sub set of filters to use in 
                              mangling colors (filters that have very similar
                              effective wavelengths can make for unstable
                              splines).
      full_output (bool):  If True, output more information than just the
                          K-corrections and mask.
      mepoch (bool): If True, a single mangling function is solved for
                     all epochs. EXPERIMENTAL.
      mopts (dict): All additional arguments to function are sent to 
                    :func:`snpy.mangle_spectrum.mangle_spectrum2`.
   
   Returns:
      tuple:

         * if not full_output: 2-tuple (K,mask):
            * K (flaot array):  K-corrections for filts
            * mask (bool array): mask of valid K-corrections
         * if full_output: 5-tuple (K,mask,anchors,factors,funcs)
            * anchors (float array): wavelengths of anchor points
            * factors (float array): factors corresponding to anchors
            * funcs (float array): mangling function evaluated at anchors
   '''

    if 'method' in mopts:
        method = mopts['method']
    else:
        method = 'tspline'

    if colorfilts is None: colorfilts = filts
    for filter1 in filts + restfilts + colorfilts:
        if filter1 not in filters.fset:
            raise AttributeError, "filter %s not defined in filters module" % filter1

    kcorrs = []
    mask = []  # Masks the good values (1) and bad (not defined) values (0)
    m_opts = []
    Rts = []
    if debug: mopts['verbose'] = 1

    if mepoch:
        # Doing multi epoch simultaneously with one mangling function...
        spec_wavs = []
        spec_fs = []
        sids = []
        for j in range(len(days)):
            day = int(days[j])
            s, f = get_SED(day, version)
            if s is None:
                spec_wavs.append(num.arange(980., 24981.0, 10.))
                spec_fs.append(num.zeros((2401, ), dtype=num.float64))
                sids.append(False)
            else:
                spec_wavs.append(s)
                spec_fs.append(f)
                sids.append(True)
        spec_wavs = num.array(spec_wavs)
        spec_fs = num.array(spec_fs)
        sids = num.array(sids)
        fs = [colorfilts[i] for i in range(len(colorfilts)) \
              if num.sometrue(m_mask[:,i])]
        if len(fs) <= 1:
            waves, man_spec_fs, factors = spec_wavs, spec_fs, spec_wavs * 0.0 + 1.0
        else:
            #cs = mags[:,:-1] - mags[:,1:]
            #gids = m_mask[:,:-1]*m_mask[:,1:]
            #gids = gids*sids[:,num.newaxis]
            #cs[-gids] = 99.9   # flag invalid value
            gids = m_mask * sids[:, num.newaxis]
            ms = where(gids, ms, 99.9)
            man_spec_fs, waves, factors = mangle_spectrum2(
                spec_wavs * (1 + z), spec_fs, fs, ms, **mopts)

        for j in range(len(days)):
            kcorrs.append([])
            mask.append([])
            if not sids[j]:
                kcorrs[-1] = num.zeros((len(filts), ), dtype=num.float32)
                mask[-1] = num.zeros((len(filts), ), dtype=num.int8)
                Rts.append(kcorrs[-1] - 1.0)
                m_opts.append(None)
                continue
            if full_output:
                args = {'sw': waves, 'sf': factors}
                for key in mopts:
                    args[key] = mopts[key]
                m_opts.append(args)

            for i in range(len(filts)):
                f1 = filters.fset[restfilts[i]]
                f2 = filters.fset[filts[i]]
                k, f = K(spec_wavs[j], man_spec_fs[j], f1, f2, z)
                kcorrs[-1].append(k)
                mask[-1].append(0)
            Rts.append(
                R_obs_spectrum(filts, spec_wavs[j], man_spec_fs[j], z, 0.01,
                               0.0))
    else:
        for j in range(len(days)):
            kcorrs.append([])
            mask.append([])
            day = int(days[j])
            spec_wav, spec_f = get_SED(day, version)
            if spec_wav is None:
                # print "Warning:  no spectra for day %d, setting Kxy=0" % day
                kcorrs[-1] = num.zeros((len(filts), ), dtype=num.float32)
                mask[-1] = num.zeros((len(filts), ), dtype=num.int8)
                Rts.append(kcorrs[-1] - 1.0)
                m_opts.append(None)
                continue

            # Now determine which colors to use:
            fs = [
                colorfilts[i] for i in range(len(colorfilts)) if m_mask[j, i]
            ]
            if len(fs) <= 1:
                # only one filter, so no color information, leave the SED alone:
                waves, man_spec_f, factors = spec_wav, spec_f, spec_wav * 0.0 + 1.0
                man_spec_f = [man_spec_f]
            else:
                #cs = num.compress(m_mask[j],mags[j])[0:-1] - \
                #     num.compress(m_mask[j],mags[j])[1:]
                ms = num.compress(m_mask[j], mags[j])
                if debug:
                    print "filters and colors for day %f:" % (days[j])
                    print fs
                    print ms[:-1] - ms[1:]

                # Now we mangle the spectrum.  Note, we are redshifting the spectrum
                # here, so do NOT set z in mangle_spectrum2.
                man_spec_f, waves, factors = mangle_spectrum2(
                    spec_wav * (1 + z), spec_f, fs, ms, **mopts)

                if debug: print "factors = ", factors
                if debug:
                    # check the colors
                    for i in range(len(fs) - 1):

                        print "input color:  %s-%s = %f" % (fs[i], fs[i + 1],
                                                            ms[i] - ms[i + 1]),
                        f1 = filters.fset[fs[i]]
                        f2 = filters.fset[fs[i + 1]]
                        col = f1.synth_mag(spec_wav*(1+z), man_spec_f[0]) - \
                              f2.synth_mag(spec_wav*(1+z), man_spec_f[0])
                        print "  output color:  %f" % (col)

            if full_output:
                args = {'sw': waves, 'sf': factors}
                for key in mopts:
                    args[key] = mopts[key]
                m_opts.append(args)

            for i in range(len(filts)):
                f1 = filters.fset[restfilts[i]]
                f2 = filters.fset[filts[i]]
                k, f = K(spec_wav, man_spec_f[0], f1, f2, z)
                kcorrs[-1].append(k)
                mask[-1].append(f)
            Rts.append(
                R_obs_spectrum(filts, spec_wav, man_spec_f[0], z, 0.01, 0.0))
    Rts = num.array(Rts)
    gids = num.greater(Rts, 0)
    Rtave = num.array([num.average(num.compress(gids[:,k], Rts[:,k])) \
          for k in range(len(gids[0]))])
    Rts = num.array(
        [num.where(gids[i], Rts[i], Rtave) for i in range(len(gids))])

    kcorrs = num.array(kcorrs)
    mask = num.array(mask)

    if not full_output:
        return (kcorrs, mask)
    else:
        return (kcorrs, mask, Rts, m_opts)
Ejemplo n.º 5
0
Archivo: kcorr.py Proyecto: wmwv/snpy
def kcorr_mangle2(waves,
                  spectra,
                  filts,
                  mags,
                  m_mask,
                  restfilts,
                  z,
                  colorfilts=None,
                  full_output=0,
                  **mopts):
    '''Compute (cross-)band K-corrections with "mangling" using provided
   spectral SEDs. The SEDs are first multiplied by a smooth spline such that
   the synthetic colors match the observed colors.

   Args:
      waves (list of float arrays):  Input wavelengths in Angstroms
      spectra (list of float arrays):  Input fluxes in arbitrary units
      filts (list of str): list of observed filters
      mags (2d float array): Observed magnitude array indexed by
                             [spectrum index,filter index]
      m_mask (2d bool array): mask array indicating valid magnitudes. Indexed
                              by [spectrum index,filter index]
      restfilts (list of str): Rest-frame filters corresponing to filts.
      z (float):  redshift
      colorfilts (list of str): (optional) Sub set of filters to use in 
                              mangling colors (filters that have very similar
                              effective wavelengths can make for unstable
                              splines).
      full_output (bool):  If True, output more information than just the
                          K-corrections and mask.
      mopts (dict): All additional arguments to function are sent to 
                    :func:`snpy.mangle_spectrum.mangle_spectrum2`.
   
   Returns:
      tuple:

         * if not full_output: 2-tuple (K,mask):
            * K (flaot array):  K-corrections for filts
            * mask (bool array): mask of valid K-corrections
         * if full_output: 5-tuple (K,mask,anchors,factors,funcs)
            * anchors (float array): wavelengths of anchor points
            * factors (float array): factors corresponding to anchors
            * funcs (float array): mangling function evaluated at anchors
   '''
    if colorfilts is None: colorfilts = filts
    for filter1 in filts + restfilts + colorfilts:
        if filter1 not in filters.fset:
            raise AttributeError, "filter %s not defined in filters module" % filter1

    if len(num.shape(waves)) < 2:
        scalar = 1
        waves = num.array([waves])
        spectra = num.array([spectra])
        mags = num.array([mags])
        m_mask = num.array([m_mask])
    else:
        scalar = 0

    kcorrs = []
    mask = []  # Masks the good values (1) and bad (not defined) values (0)
    waves_a = []
    manf_a = []
    factors_a = []

    for j in range(len(spectra)):
        kcorrs.append([])
        mask.append([])
        spec_wav, spec_f = waves[j], spectra[j]

        # Now determine which colors to use:
        fs = [colorfilts[i] for i in range(len(colorfilts)) if m_mask[j, i]]
        if len(fs) <= 1:
            # only one filter, so no color information, leave the SED alone:
            man_waves, man_spec_f, factors = spec_wav, spec_f, spec_wav * 0.0 + 1.0
        else:
            #cs = num.compress(m_mask[j],mags[j])[0:-1] - \
            #      num.compress(m_mask[j],mags[j])[1:]
            ms = num.compress(m_mask[j], mags[j])

            # Now we mangle the spectrum:
            man_spec_f, man_waves, factors = mangle_spectrum2(
                spec_wav * (1 + z), spec_f, fs, ms, **mopts)
        if full_output:
            waves_a.append(man_waves)
            manf_a.append(man_spec_f)
            factors_a.append(factors)

        for i in range(len(filts)):
            f1 = filters.fset[restfilts[i]]
            f2 = filters.fset[filts[i]]

            k, f = K(spec_wav, man_spec_f[0], f1, f2, z)
            if f == 1:
                kcorrs[-1].append(k)
                mask[-1].append(len(fs))
            else:
                kcorrs[-1].append(0)
                mask[-1].append(0)
    kcorrs = num.array(kcorrs)
    mask = num.array(mask)

    if full_output:
        if scalar:
            return (kcorrs[0], mask[0], waves_a[0], factors_a[0], manf_a[0])
        else:
            return (kcorrs, mask, waves_a, factors_a, manf_a)
    else:
        if scalar:
            return (kcorrs[0], mask[0])
        else:
            return (kcorrs, mask)
Ejemplo n.º 6
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))