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)
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)
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))
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)
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)
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))