Source code for desisim.transients

"""Module for defining interface to transient models.
"""

from abc import ABC, abstractmethod
from astropy import units as u
import numpy as np

from desiutil.log import get_logger, DEBUG

# Hide sncosmo import from the module.
try:
    import sncosmo
    log = get_logger(DEBUG)
    log.info('Enabling sncosmo models.')
    use_sncosmo = True
except ImportError as e:
    log = get_logger(DEBUG)
    log.warning('{}; disabling sncosmo models.'.format(e))
    use_sncosmo = False


[docs]class Transient(ABC): """Abstract base class to enforce interface for transient flux models.""" def __init__(self, modelname, modeltype): self.model = modelname self.type = modeltype self.hostratio = 1. self.phase = 0.*u.day @abstractmethod def minwave(self): pass @abstractmethod def maxwave(self): pass @abstractmethod def mintime(self): pass @abstractmethod def maxtime(self): pass @abstractmethod def set_model_pars(modelpars): pass @abstractmethod def flux(self, t, wl): pass
if use_sncosmo: class Supernova(Transient): def __init__(self, modelname, modeltype, modelpars): """Initialize a built-in supernova model from the sncosmo package. Parameters ---------- modelname : str Name of the model. modeltype : str Type or class of the model [Ia, IIP, ...]. modelpars : dict Parameters used to initialize the model. """ super().__init__(modelname, modeltype) # In sncosmo, some models have t0=tmax, and others have t0=0. # These lines ensure that for our purposes t0=tmax=0 for all models. self.t0 = modelpars['t0'] * u.day modelpars['t0'] = 0. self.snmodel = sncosmo.Model(self.model) self.set_model_pars(modelpars) def minwave(self): """Return minimum wavelength stored in model.""" return self.snmodel.minwave() * u.Angstrom def maxwave(self): """Return maximum wavelength stored in model.""" return self.snmodel.maxwave() * u.Angstrom def mintime(self): """Return minimum time used in model (peak light at t=0).""" return self.snmodel.mintime() * u.day - self.t0 def maxtime(self): """Return maximum time used in model (peak light at t=0).""" return self.snmodel.maxtime() * u.day - self.t0 def set_model_pars(self, modelpars): """Set sncosmo model parameters. Parameters ---------- modelpars : dict Parameters used to initialize the internal model. """ self.snmodel.set(**modelpars) def flux(self, t, wl): """Return flux vs wavelength at a given time t. Parameters ---------- t : float or astropy.units.quantity.Quantity Time of observation, with t=0 representing max light. wl : list or ndarray Wavelength array to compute the flux. Returns ------- flux : list or ndarray Normalized flux array as a function of wavelength. """ # Time should be expressed w.r.t. maximum, in days. if type(t) is u.quantity.Quantity: self.phase = t else: self.phase = t * u.day time_ = (self.phase + self.t0).to('day').value # Convert wavelength to angstroms. wave_ = wl.to('Angstrom').value if type(wl) is u.quantity.Quantity else wl flux = self.snmodel.flux(time_, wl) return flux / np.sum(flux)
[docs]class TabularModel(Transient): def __init__(self, modelname, modeltype, filename, filefmt): """Initialize a model from tabular data in an external file. Parameters ---------- modelname : str Name of the model. modeltype : str Type or class of the model [TDE, AGN, ...]. filename : str File with columns of wavelength and flux. filefmt : str File format (ascii, csv, fits, hdf5, ...). """ super().__init__(modelname, modeltype) from astropy.table import Table data = Table.read(filename, format=filefmt, names=['wavelength','flux']) self.wave_ = data['wavelength'].data self.flux_ = data['flux'].data from scipy.interpolate import PchipInterpolator self.fvsw_ = PchipInterpolator(self.wave_, self.flux_)
[docs] def minwave(self): """Return minimum wavelength stored in model.""" return self.wave_[0] * u.Angstrom
[docs] def maxwave(self): """Return maximum wavelength stored in model.""" return self.wave_[-1] * u.Angstrom
[docs] def mintime(self): """Return minimum time used in model (peak light at t=0).""" return 0 * u.day
[docs] def maxtime(self): """Return maximum time used in model (peak light at t=0).""" return 1 * u.day
[docs] def set_model_pars(self, modelpars): """Set model parameters. Parameters ---------- modelpars : dict Parameters used to initialize the internal model. """ pass
[docs] def flux(self, t, wl): """Return flux vs wavelength at a given time t. Parameters ---------- t : float or astropy.units.quantity.Quantity Time of observation, with t=0 representing max light. wl : list or ndarray Wavelength array to compute the flux. Returns ------- flux : list or ndarray Normalized flux array as a function of wavelength. """ # Convert wavelength to angstroms. wave_ = wl.to('Angstrom').value if type(wl) is u.quantity.Quantity else wl flux = self.fvsw_(wave_) return flux / np.sum(flux)
[docs]class ModelBuilder: """A class which can build a transient model. It allows the TransientModels object registry to register the model without instantiating it until it's needed. This is handy because some models take time and memory to instantiate. """ def __init__(self, modelclass): """Initialize the ModelBuilder with a type of model. Parameters ---------- modelclass : Transient A subclass of Transient, e.g., Supernova or TabularModel. """ self._instance = None self._modclass = modelclass def __call__(self, modelpars): """Instantiate a model using a list of modelpars. Parameters ---------- modelpars : dict Parameters needed to create a TabularModel (modelname, modeltype, filename, filefmt). Returns ------- instance : subclass of Transient (Supernova, TabularModel, etc.). """ if self._instance is None: self._instance = self._modclass(**modelpars) return self._instance
class TransientModels: def __init__(self): """Create a registry of transient model builder classes, model types, and model parameters. """ self._builders = {} self._modelpars = {} self._types = {} def register_builder(self, modelpars, builder): """Register a model builder. Parameters ---------- modelpars : dict Dictionary of model parameters (type, name, params). builder : A Transient builder class which instantiates a Transient. """ modtype, modname = modelpars['modeltype'], modelpars['modelname'] if modtype in self._types: self._types[modtype].append(modname) else: self._types[modtype] = [modname] self._builders[modname] = builder self._modelpars[modname] = modelpars def get_model(self, modelname): """Given a model name, returns a Transient using its builder. Parameters ---------- modelname : str Name of registered Transient model. Returns ------- instance : Transient Instance of a registered transient. """ builder = self._builders.get(modelname) modelpars = self._modelpars.get(modelname) if not builder: raise ValueError(modelname) return builder(modelpars) def get_type_dict(self): """Return a dictionary of registered model types. Returns ------- types : dict Dictionary of types and models. """ return self._types def get_type(self, modeltype): """Given a Transient type, randomly return a registered model of that type. Parameters ---------- modeltype : str Transient type (Ia, Ib, IIP, ...). Returns ------- instance : Transient A registered Transient of the requested type. """ mtype = self._types.get(modeltype) if not mtype: raise ValueError(modeltype) mname = np.random.choice(mtype) return self.get_model(mname) def __str__(self): """A list of registered transient types and model names. Returns ------- repr : str Representation of registered model types and names. """ s = [] for t, models in self._types.items(): s.append('- {}'.format(t)) for m in models: s.append(' + {}'.format(m)) return '\n'.join(s) transients = TransientModels() # Set up sncosmo models. if use_sncosmo: # Register SN Ia models transients.register_builder({ 'modelname': 'hsiao', 'modeltype': 'Ia', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'nugent-sn1a', 'modeltype': 'Ia', 'modelpars': {'z':0., 't0':20., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'nugent-sn91t', 'modeltype': 'Ia', 'modelpars': {'z':0., 't0':20., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'nugent-sn91bg', 'modeltype': 'Ia', 'modelpars': {'z':0., 't0':15., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'salt2-extended', 'modeltype': 'Ia', 'modelpars': {'z':0., 't0':0., 'x0':1., 'x1':0., 'c':0.} }, ModelBuilder(Supernova)) # Register SN Ib models transients.register_builder({ 'modelname': 's11-2005hl', 'modeltype': 'Ib', 'modelpars': {'z':0., 't0':-5., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 's11-2005hm', 'modeltype': 'Ib', 'modelpars': {'z':0., 't0':5., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 's11-2006jo', 'modeltype': 'Ib', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2004gv', 'modeltype': 'Ib', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2006ep', 'modeltype': 'Ib', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2007y', 'modeltype': 'Ib', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2004ib', 'modeltype': 'Ib', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2005hm', 'modeltype': 'Ib', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2007nc', 'modeltype': 'Ib', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) # Register SN Ib/c models transients.register_builder({ 'modelname': 'nugent-sn1bc', 'modeltype': 'Ib/c', 'modelpars': {'z':0., 't0':20., 'amplitude':1.} }, ModelBuilder(Supernova)) # Register SN Ic models transients.register_builder({ 'modelname': 's11-2006fo', 'modeltype': 'Ic', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2004fe', 'modeltype': 'Ic', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2004gq', 'modeltype': 'Ic', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-sdss004012', 'modeltype': 'Ic', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2006fo', 'modeltype': 'Ic', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-sdss014475', 'modeltype': 'Ic', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2006lc', 'modeltype': 'Ic', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-04d1la', 'modeltype': 'Ic', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-04d4jv', 'modeltype': 'Ic', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) # Register SN IIn models transients.register_builder({ 'modelname': 'nugent-sn2n', 'modeltype': 'IIn', 'modelpars': {'z':0., 't0':20., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2006ez', 'modeltype': 'IIn', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2006ix', 'modeltype': 'IIn', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) # Register SN IIP models transients.register_builder({ 'modelname': 'nugent-sn2p', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':20., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 's11-2005lc', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 's11-2005gi', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 's11-2006jl', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2004hx', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2005gi', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2006gq', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2006kn', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2006jl', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2006iw', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2006kv', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2006ns', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2007iz', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2007nr', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2007kw', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2007ky', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2007lj', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2007lb', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2007ll', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2007nw', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2007ld', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2007md', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2007lz', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2007lx', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2007og', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2007nv', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) transients.register_builder({ 'modelname': 'snana-2007pg', 'modeltype': 'IIP', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) # Register SN IIL transients.register_builder({ 'modelname': 'nugent-sn2l', 'modeltype': 'IIL', 'modelpars': {'z':0., 't0':12., 'amplitude':1.} }, ModelBuilder(Supernova)) # Register SN IIL/P transients.register_builder({ 'modelname': 's11-2004hx', 'modeltype': 'IIL/P', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova)) # Register SN II-pec transients.register_builder({ 'modelname': 'snana-2007ms', 'modeltype': 'II-pec', 'modelpars': {'z':0., 't0':0., 'amplitude':1.} }, ModelBuilder(Supernova))