def init_guess_breakout_exp(sn, tel, band, a2=1., maxt=5.): """ initial guess for breakout phase for exponential fit Parameters ---------- sn: snlc::getlc::SNLC object, SN light curve object tel: string, telescope under consideration band: string, band under consideration kwargs ------ a2: float, initial guess for a2 parameter maxt: float, maximum time of breakout phase Returns ------- dict with initial guesses """ par = {} # discovery date tdisc = sn.get_dates_mjd(datetype='discover')[0] # first measurement t1 = sn.dat[tel][band].t[0] # par['t0'] = 0.5 * (tdisc + t1) par['t0'] = t1 - 1e-2 # convert mag to flux y = mag2flux(sn.dat[tel][band].m, **ref) # exlcude upper limits and only use first days mask = (sn.dat[tel][band].dm > 0.) & \ (sn.dat[tel][band].t - par['t0'] < maxt) itmax = np.argmax(y[mask]) # get measurement closest to maximum ymax = y[mask][itmax] dt = sn.dat[tel][band].t[mask][itmax] - par['t0'] par['a2'] = a2 # get initial guesses if dt > 10.: logging.warning('Estimated maximum more than 10 days after discovery!') par['a1'] = ymax / (1. - np.exp(-dt / par['a2'])) return par
def init_guess_arnett(sn, tel, band, t0, delay=10., y=2., subtract=lambda t: 0.): """ initial guess for expansion phase model with arnett Parameters ---------- sn: snlc::getlc::SNLC object, SN light curve object tel: string, telescope under consideration band: string, band under consideration t0: float, estimate for explosion time y: float, estimate for tauM (a4), where y = tauM / 2 / tauNi kwargs ------ delay: float, delay time in days when expansion should dominate. Flux estimated from flux corresponding to closest time substract: fuction pointer, additional flux that might contribute at time of delay Returns ------- dict with initial guesses """ par = {} # take discovery date as initial guess for explosion time par['t0'] = t0 # get measurement closest to maximum it = np.argmin(np.abs(sn.dat[tel][band].t - (par['t0'] + delay))) # convert mag to flux f = mag2flux(sn.dat[tel][band].m, **ref) # get initial guesses par['a4'] = 2. * y * tauNi x = delay / par['a4'] par['a3'] = (f[it] - subtract(sn.dat[tel][band].t[it])) / Lambda(x, y) print subtract(sn.dat[tel][band].t[it]), sn.dat[tel][band].t[it] if par['a3'] < 0.: par['a3'] = 1e-5 return par
def init_guess_breakout_exp(tdisc, time, mag, a2 = 1., maxt = 5.): """ initial guess for breakout phase for exponential fit Parameters ---------- tdisc: float discovery date time: `~numpy.ndarray` measured times mag: `~numpy.ndarray` measured magnitudes (no upper limits) kwargs ------ a2: float, initial guess for a2 parameter maxt: float, maximum time of breakout phase Returns ------- dict with initial guesses """ par = {} par['t0'] = tdisc # convert mag to flux y = mag2flux(mag,**ref) # exlcude upper limits and only use first days mask = time - par['t0'] < maxt itmax = np.argmax(y[mask]) # get measurement closest to maximum ymax = y[mask][itmax] dt = time[mask][itmax] - par['t0'] par['a2'] = a2 # get initial guesses if dt > 10.: logging.warning('Estimated maximum more than 10 days after discovery!') par['a1'] = ymax / (1. - np.exp(-dt / par['a2'])) return par
def init_guess_arnett(tdisc, time, mag, delay = 10., y = 2., subtract = lambda t: 0.): """ initial guess for expansion phase model with arnett Parameters ---------- tdisc: float discovery date time: `~numpy.ndarray` measured times mag: `~numpy.ndarray` measured magnitudes (no upper limits) y: float, estimate for tauM (a4), where y = tauM / 2 / tauNi kwargs ------ delay: float, delay time in days when expansion should dominate. Flux estimated from flux corresponding to closest time substract: fuction pointer, additional flux that might contribute at time of delay Returns ------- dict with initial guesses """ par = {} # take discovery date as initial guess for explosion time par['t0'] = tdisc # get measurement closest to maximum m = np.isfinite(mag) it = np.argmin(np.abs(time[m] - (par['t0'] + delay))) # convert mag to flux f = mag2flux(mag[m],**ref) # get initial guesses par['a4'] = 2. * y * tauNi x = delay / par['a4'] par['a3'] = (f[it] - subtract(time[it])) / Lambda(x,y) if par['a3'] < 0.: par['a3'] = 1e-5 return par
def init_guess_expansion(tdisc, time, mag, delay = 10., subtract = lambda t: 0.): """ initial guess for expansion phase Parameters ---------- tdisc: float discovery date time: `~numpy.ndarray` measured times mag: `~numpy.ndarray` measured magnitudes (no upper limits) kwargs ------ delay: float, delay time in days when expansion should dominate. Flux estimated from flux corresponding to closest time substract: function pointer, additional flux that might contribute at time of delay Returns ------- dict with initial guesses """ par = {} # take discovery date as initial guess for explosion time par['t0'] = tdisc # get measurement closest to maximum it = np.argmin(np.abs(time - (par['t0'] + delay))) # convert mag to flux y = mag2flux(mag,**ref) # get initial guesses par['a4'] = 2. par['a3'] = (y[it] - subtract(time[it])) / delay ** par['a4'] if par['a3'] < 0.: par['a3'] = 1e-5 return par
def __init__(self, sn, tel, bands, **kwargs): """ Initialize the class Parameters ---------- sn: snlc::getlc::SNLC object, SN light curve object tel: string, name of instrument for which light curve is fitted bands: list, list with strings with the bands included in the fit kwargs ------ tmin: float, min MJD for fit tmax: float, max MJD for fit model: string identifier for the model. Possibilities are: - "break+exp" breakout and expansion phase, expansion phase modeled as simple quadratic expansion as in Cowen et al. (2010) - "break+arnett" breakout and expansion phase, expansion phase modeled as with function from Arnett (1982) """ self.llhs = {} self.y = {} self.dy = {} self.t = {} self.mask = {} self.maxL = {} self.bands = bands self.t_first_data_point = 1e10 # get the data and build Gaussian likelihood curves from them for i, b in enumerate(bands): if not i: self.llhs[b] = [] self.t[b] = [] self.y[b] = [] self.dy[b] = [] self.mask[b] = [] # mask min, max times and ULs self.mask[b] = (sn.dat[tel][b].dm > 0) & (sn.dat[tel][b].t > kwargs['tmin']) & \ (sn.dat[tel][b].t < kwargs['tmax']) if not np.sum(self.mask[b]): logging.warning( 'no data points remaining for {0:s} band {1:s}'.format( tel, b)) # convert magnitude to flux # and symmetrize errors self.y[b] = mag2flux(sn.dat[tel][b].m, **ref) self.dy[b] = np.abs( np.array([ self.y[b] - mag2flux(sn.dat[tel][b].m + sn.dat[tel][b].dm, **ref), mag2flux(sn.dat[tel][b].m - sn.dat[tel][b].dm, **ref) - self.y[b] ]).mean(axis=0)) self.t[b] = sn.dat[tel][b].t # find first data point if np.min(self.t[b][self.mask[b]]) < self.t_first_data_point: self.t_first_data_point = np.min(self.t[b][self.mask[b]]) # get a likelihood curve for each data point self.maxL[b] = 0. for j, f in enumerate(self.y[b][self.mask[b]]): self.llhs[b].append( stats.norm(loc=f, scale=(self.dy[b][self.mask[b]])[j])) self.maxL[b] -= self.llhs[b][-1].pdf( (self.y[b][self.mask[b]])[j]) if kwargs['model'] == 'break+exp': self.flux_model = lambda t, **par: breakoutphase( t, **par) + expansionphase(t, **par) self.parnames = ['t0', 'a1', 'a2', 'a3'] elif kwargs['model'] == 'break+arnett': self.flux_model = lambda t, **par: breakoutphase( t, **par) + expansionphase_arnett(t, **par) self.parnames = ['t0', 'a1', 'a2', 'a3', 'a4'] elif kwargs['model'] == 'breakexp+arnett': self.flux_model = lambda t, **par: breakoutexp( t, **par) + expansionphase_arnett(t, **par) self.parnames = ['t0', 'a1', 'a2', 'a3', 'a4'] else: raise ValueError('Model {0[model]:s} unknown!'.format(kwargs)) self.corr = [] self.chi2 = kwargs['chi2'] return
def init_guess_breakout(sn, tel, band, a2=5., da=1., maxt=5.): """ initial guess for breakout phase Parameters ---------- sn: snlc::getlc::SNLC object, SN light curve object tel: string, telescope under consideration band: string, band under consideration kwargs ------ a2: float, initial guess for a2 parameter da: float, increment and decrement for a2 to find root maxt: float, maximum time of breakout phase Returns ------- dict with initial guesses """ par = {} # discovery date tdisc = sn.get_dates_mjd(datetype='discover')[0] # first measurement t1 = sn.dat[tel][band].t[0] # par['t0'] = 0.5 * (tdisc + t1) par['t0'] = t1 - 1e-2 # convert mag to flux y = mag2flux(sn.dat[tel][band].m, **ref) # exlcude upper limits and only use first days mask = (sn.dat[tel][band].dm > 0.) & \ (sn.dat[tel][band].t - par['t0'] < maxt) itmax = np.argmax(y[mask]) # get measurement closest to maximum ymax = y[mask][itmax] dt = sn.dat[tel][band].t[mask][itmax] - par['t0'] # determine a2 such that maximum flux coincides with max of function # the derivative = 0: df_dt = lambda a2, dt: (1. - a2 / 3.2 * np.sqrt(dt)) * np.exp(a2 * np.sqrt( dt)) - 1. logging.info('root finding interval: [{0},{1}] gives [{2},{3}]'.format( a2 - 1, a2 + 1, df_dt(a2 - da, dt), df_dt(a2 + da, dt))) try: par['a2'] = op.brentq(df_dt, a2 - da, a2 + da, args=(dt)) logging.info('Root found at {0[a2]:.2f}.'.format(par)) except ValueError: logging.warning( 'Could not run brentq, setting a2 to {0:.2f}'.format(a2)) par['a2'] = a2 # get initial guesses if dt > 10.: logging.warning('Estimated maximum more than 10 days after discovery!') par['a1'] = ymax * np.power(dt, -1.6) * (np.exp(par['a2'] * np.sqrt(dt)) - 1.) return par
def __init__(self,time,mag,dmag,tdisc,**kwargs): """ Initialize the class Parameters ---------- time: `~numpy.ndarray` measured times mag: `~numpy.ndarray` measured magnitudes (no upper limits) dmag: `~numpy.ndarray` uncertainties measured magnitudes (no upper limits) tdisc: float discovery date kwargs ------ tmin: float, min time for fit tmax: float, max time for fit model: string identifier for the model. Possibilities are: - "break+expand" breakout and expansion phase, expansion phase modeled as simple quadratic expansion as in Cowen et al. (2010), modified so that it can be non-quadratic - "break+arnett" breakout and expansion phase, expansion phase modeled as with function from Arnett (1982) - "breakexp+expand" exponential breakout and expansion phase, breakout modeled with simple exponential function of Ofek et al. (2014) - "breakexp+arnett" breakout and expansion phase, breakout modeled with simple exponential function of Ofek et al. (2014) and expansion phase modeled as with function from Arnett (1982) """ kwargs.setdefault('name','sn') self.name = kwargs['name'] m = (time >= kwargs['tmin']) & (time <= kwargs['tmax']) self._t = time[m] self._y = mag2flux(mag, **ref)[m] self._dy = np.abs(np.array([self._y - mag2flux(mag + dmag,**ref)[m], mag2flux(mag-dmag,**ref)[m] - self._y]).mean(axis = 0)) self.t_first_data_point = tdisc self.__set_llhs() self.modelname = kwargs['model'] self.parnames = ['t0','a1','a2'] # Set the breakout model if kwargs['model'].find('break') == 0 and kwargs['model'].find('breakexp') < 0: self.breakout = lambda t,**par : breakoutphase(t,**par) elif kwargs['model'].find('breakexp') == 0: self.breakout = lambda t,**par : breakoutexp(t,**par) else: raise ValueError('Model {0[model]:s} unknown!'.format(kwargs)) # Set the expansion model if kwargs['model'].find('expand') > 0: self.expansion = lambda t,**par : expansionphase(t,**par) self.parnames += ['a3','a4'] elif kwargs['model'].find('arnett') > 0: self.expansion = lambda t,**par : expansionphase_arnett(t,**par) self.parnames += ['a3','a4'] else: self.expansion = lambda t,**par : np.squeeze(np.zeros(t.size)) self.flux_model = lambda t,**par : self.breakout(t,**par) + self.expansion(t,**par) self.corr = [] self.chi2 = kwargs['chi2'] return
def init_guess_breakout(tdisc, time, mag, a2 = 5., da = 1., maxt = 5.): """ initial guess for breakout phase Parameters ---------- tdisc: float discovery date time: `~numpy.ndarray` measured times mag: `~numpy.ndarray` measured magnitudes (no upper limits) kwargs ------ a2: float, initial guess for a2 parameter da: float, increment and decrement for a2 to find root maxt: float, maximum time of breakout phase Returns ------- dict with initial guesses """ par = {} par['t0'] = tdisc # convert mag to flux y = mag2flux(mag,**ref) # only use first days mask = time - par['t0'] < maxt itmax = np.argmax(y[mask]) # get measurement closest to maximum ymax = y[mask][itmax] dt = time[mask][itmax] - par['t0'] # determine a2 such that maximum flux coincides with max of function # the derivative = 0: df_dt = lambda a2,dt: (1. - a2 / 3.2 * np.sqrt(dt) ) * np.exp(a2 * np.sqrt(dt)) - 1. logging.info('root finding interval: [{0},{1}] gives [{2},{3}]'.format(a2 - 1, a2 + 1, df_dt(a2 - da,dt), df_dt(a2 + da,dt))) try: res = op.brentq(df_dt, a2 - da , a2 + da, args = (dt)) if res > 1e-4: par['a2'] = res logging.info('Root found at {0[a2]:.2f}.'.format(par)) else: par['a2'] = a2 except ValueError: logging.warning('Could not run brentq, setting a2 to {0:.2f}'.format(a2)) par['a2'] = a2 # get initial guesses if dt > 10.: logging.warning('Estimated maximum more than 10 days after discovery!') par['a1'] = ymax * np.power(dt,-1.6) * (np.exp(par['a2'] * np.sqrt(dt)) - 1.) return par