============
Models
============
In :code:`redback` we have already implemented a lot of different models, which can be combined or modified to create another model easily.
These models range from phenomenological, to analytical, semi-analytical to numerical surrogates built with machine learning techniques.
Implementing a new model is probably the easiest way to contribute to redback!
Specifically, some models already included are as follows. This list is not exhaustive and we are always adding more models,
We also encourage users to contribute new models as well!
For a full up to date list of models implemented in :code:`redback`, look at the `API `_
Note some models use the plugin system and require users to install additional packages to use those models.
Please see the API docs for more details on which models require additional packages and how to install those packages.
- Afterglow models: Can output in flux density/magnitude
- Several varieties of afterglow models implemented directly in redback following Lamb et al. 2018 and other work. Includes wind-like mediums and complex jet structures. SSA etc.
- Several jet structures but with refreshed shocks and the suite of options available for the set of models above.
- All structured jet models implemented in `afterglowpy `_. Must install afterglowpy to use these models.
- **VegasAfterglow high-performance models** - Millisecond-scale C++ afterglow models providing ~1000x speedup. 6 unified jet structures (vegas_tophat, vegas_gaussian, vegas_powerlaw, vegas_powerlaw_wing, vegas_two_component, vegas_step_powerlaw) supporting ISM, Wind, and Hybrid media through unified lognism/loga interface. Includes full suite of physics: forward/reverse shocks, synchrotron self-Compton, Klein-Nishina corrections, jet spreading, magnetar injection, non-axisymmetric jets. Install with :code:`pip install VegasAfterglow`. See `VegasAfterglow `_ and Wang, Chen & Zhang (2026).
- Some varieties of Kilonova afterglow models e.g., Sarin et al. 2022, Nakar and Piran 2011
- Jetsimpy (requires jetsimpy to be installed)
- Several more...
- Kilonova models: Can output in flux density/magnitude/flux/spectra
- One/two/three component kilonova models
- two_layer_stratified_kilonova
- power_law_stratified_kilonova
- `kilonova heating rate `_
- One component BNS ejecta relation
- Two component BNS ejecta relation
- One component NSBH ejecta relation
- Two component NSBH ejecta relation
- Polytrope EOS ejecta relation
- Aspherical kilonova
- `Three component model `_ ejecta relation
- `Three component model `_ temperature floor
- `Three component model `_ temperature floor and diffusion
- `Metzger 2017 `_
- Kilonovanet-based surrogates (requires kilonovanet to be installed)
- Surrogates of different numerical simulations
- Several more...
- Supernova models: Can output in flux density/magnitude/bolometric luminosity/spectra
- Arnett
- CSM
- CSM + Ni
- Basic magnetar powered
- General magnetar powered
- magnetar + nickel
- SLSN
- exponential powerlaw
- Shock cooling + Arnett
- Every model provided by `SNcosmo `_
- Several more...
- Shock models: Can output in flux density/magnitude/bolometric luminosity/spectra
- Shock cooling
- Thermal synchrotron
- Shocked cocoon
- Several more ...
- Magnetar driven ejecta models:
- Metzger magnetar driven kilonova
- Mergernova
- Trapped magnetar
- General magnetar driven kilonova
- General mergernova
- Magnetic field mergernova
- Magnetic field metzger driven kilonova
- Several more ...
- Millisecond magnetar models
- vacuum dipole magnetar
- basic magnetar
- gw + em magnetar
- magnetar with variable braking index
- evolving magnetar
- magnetar with radiative losses
- collapsing magnetar
- piecewise magnetar
- Several more ...
- Tidal disruption models
- Simple analytic fallback
- Cooling envelope (Metzger 2022)
- Gaussian rise + cooling envelope (Sarin and Metzger 2024)
- Broken power law + cooling envelope (Sarin and Metzger 2024)
- Fitted
- TDEMass
- Mosfit TDE
- Phenomenological and fireball models
- 1-6 component piecewise power law
- exponential_powerlaw
- Gaussian rise
- Evolving blackbody
- Blackbody + powerlaw
- Several more ...
- Spectral energy distributions (SEDs)
- Blackbody
- Powerlaw
- Synchrotron
- Afterglow SED
- Spectral features
- Several more ...
- Combined models
- Interface to combine any optical transient and afterglow model
- Tophat + Stratified kilonova
- Tophat + Two component kilonova
- Tophat + Arnett
We note that these models can output in `flux_density`, `magnitude`, or `spectrum` set by the keyword argument
`output_format` or in integrated flux or luminosity using the appropriate luminosity/flux function.
Please refer to the API docs for additional details.
Alongside these models we also include some general models which can many of the above models as a `base_model`
- Homologous expansion
- Thin shell
- Extinction models
- Phase models
- Phase + extinction models
- Integrated flux afterglow models
- Gaussian process base model:
Model optimizations
-------------------------
Some models in :code:`redback` have been optimized for speed using `numba `_
or available with a fortran, or another optimized backend. Please see the API docs for more details on which models have been optimized and how to use these optimized versions.
Numba is an optional dependency of :code:`redback`, while other models may require users to install additional packages or precompile code.
Using :code:`redback` models as functions
-------------------------
All models in :code:`redback` are implemented as functions with minimal dependencies.
This means that users can simply use these functions by themselves as you would any other python function.
All users need to do is pass into the function a time array and any other parameter required by the function.
In this way, users can use :code:`redback` to just explore the impact of different parameters on the light curve and better understand the physics.
For example:
.. code:: python
from redback.constants import day_to_s
from redback.model_library import all_models_dict
import numpy as np
model = 'arnett_bolometric'
function = all_models_dict[model]
time = np.logspace(2, 8, 100)/day_to_s
bolometric_luminosity = function(time, f_nickel=0.6,
mej=30, vej=1000, kappa=2, kappa_gamma=1e2)
Here we use `all_models_dict` to provide a simple way to access the relevant function. A user could of course just import the function themselves.
Users can also use the prior objects to get a simulation of the light curves predicted by the function for randomly drawn samples from the prior.
.. code:: python
from redback.constants import day_to_s
from redback.model_library import all_models_dict
from redback.priors import get_priors
import numpy as np
import pandas as pd
model = 'arnett_bolometric'
priors = get_priors(model=model, data_mode='luminosity')
samples = pd.DataFrame(priors.sample(100))
function = all_models_dict[model]
time = np.logspace(2, 8, 100)/day_to_s
bolometric_luminosity = function(time, **samples.iloc[0])
Remember that the priors are simply a dictionary so users could also just pass a dictionary/dataframe they created themselves as well.
Users could also sample a lot of different draws from the prior at once (in the above we randomly drew 100 samples) and then loop through them to simulate a population.
Remember that we can also place arbitrary constraints on the priors to make a really specific population/simulation.
For example, we could make a constraint that all priors in the population were brighter than 24th mag at peak or something else.
Almost any time of constraint is possible, as long as it can be written mathematically. Please look at prior documentation for more details on constraints.
We could also use the :code:`redback` `simulation` module to simulate realistic lightcurves of these drawn parameters in a real survey.
Helping capture selection effects in even more detail.
Modifying :code:`redback` models
-------------------------
A lot of the physics in different :code:`redback` models is set by default.
However, several pieces of physics in various models can be changed by either passing your own function/class (see `dependency injections `_),
by switching the default argument with something else already implemented in redback, or changing a keyword argument.
The specific physics that can be changed:
- Jet spreading on/off
- Whether to infer lorentz factor in afterglow models
- Whether to turn on/off pair cascades
- Whether to turn on/off neutron precursor emission
- Different ejecta relations: See relations already implemented `here `_.
- Different equations of states: See eos already implemented `here `_.
- Different interaction process: See processes already implemented `here `_.
- Different photosphere: See photospheres already implemented `here `_.
- Different SED: See SED's already implemented `here `_.
- Gamma-ray leakage
- Engines with different energy injection rates
- Several more things. Please look at the model documentation for more details.
We encourage users to add more of these physics switches, which is another easy way to contribute to :code:`redback`.
Extinction
-------------------------
Redback models by default assume that the light curve is not affected by extinction, either MW or host galaxy.
To include extinction in the model, users must use the extinction models provided in :code:`redback` while using the original model as a :code:`base_model`.
For example, to include extinction in the :code:`arnett` model, users can do the following:
.. code:: python
from redback.model_library import all_models_dict
base_model = 'arnett'
time = np.linspace(10, 500, 100) # Time in days
# define parameters for the arnett model
parameters = {
'f_nickel': 0.6, # Nickel mass fraction
'mej': 5, # Ejecta mass in solar masses
'vej': 1000, # Ejecta velocity in km/s
'kappa': 0.3, # Opacity in cm^2/g
'kappa_gamma': 1e2, # Gamma-ray opacity in cm^2/g
'temperature_floor': 5000, # Temperature floor in K
'redshift': 0.8, # Redshift of the source
}
# generate lsstu magnitudes
bands = 'lsstu' # Bands to output the light curve in
output_format = 'magnitude' # Output format of the light curve
model = 'extinction_with_supernova_base_model'
function = all_models_dict[model]
# define host extinction parameters
av_host = 0.6 # Host galaxy extinction in magnitudes
rv_host = 3.1 # Host galaxy extinction law parameter
# Define the extinction law to use
# options are 'fitzpatrick99', 'fm07', 'calzetti00', 'odonnell94', 'ccm89'
host_law = 'fitzpatrick99' # Host galaxy extinction law
# Define the Milky Way extinction parameters
av_mw = 0.6 # Milky Way extinction in magnitudes
rv_mw = 3.1 # Milky Way extinction law parameter
# Define the Milky Way extinction law
mw_law = 'fitzpatrick99' # Milky Way extinction law
# Generate the light curve with extinction
magnitude = function(time, av_host=av_host, rv_host=rv_host,
av_mw=av_mw, rv_mw=rv_mw, host_law=host_law,
mw_law=mw_law, output_format=output_format,
bands=bands, base_model=base_model, **parameters)
In v1.12.1, we changed the way extinction is handled in :code:`redback` models.
The older interface was similar except users only had the option to pass a single extinction av and rv corresponding to the host extinction, with the extinction law fixed to Fitzpatrick 1999.
Extra kwargs and output formats in :code:`redback` models
-------------------------
All :code:`redback` models have a set of extra keyword arguments that can be passed to the function.
For a specific model, users can see the extra keyword arguments by looking at the docstring of the function. These extra variables are passed in as a dictionary via
.. code:: python
extra_kwargs = {'key1': value1, 'key2': value2}
function(time, **extra_kwargs)
And can allow for more flexibility in the models while keeping the interface of the function simple for the end user.
For several models we also allow users to output the light curve in different formats.
For example, users can output the light curve in `flux_density`, `magnitude`, or `flux` by passing in those via the keyword argument `output_format`.
Or `spectra` itself which will output a multidimensional array of the spectra at each time.
Or `sncosmo_source` which will output the sncosmo source object for the model and users can then use this to make their own plots or look at model with an SNCosmo interface.
Some models also have an additional flag for `luminosity` or a namedtuple which contains a lot of useful diagnostic properties.
We note that for afterglow models we generally assume the magnitude conversion is a simple conversion from flux density to magnitude, ignoring the affect of the full spectrum.
This can be done in the proper way for the `afterglow_sed` model variants.
While for other transient models, the magnitude/flux values are calculated using the full bandpass/spectrum.
The flux_density output for all models is the flux density at the effective frequency of the filter.
Redback assumes flux_density is always in mJy, luminosity is always in erg/s with some models returning the output in 1e50 erg/s (for numerical stability), and magnitude is always in AB mag.
Flux is always in erg/s/cm^2.
Combining arbitrary models in :code:`redback` via combined_models.afterglow_and_optical
-------------------------
Not all possible combination of models are available in combined_models. However, users can combine any afterglow and optical transient model by using the `afterglow_and_optical` combined model.
to do this, users simply need to pass in the name of the afterglow model and the name of the optical transient model as keyword arguments `base_afterglow_model` and `base_optical_model` respectively.
e.g., note; combined models generally output in flux density, please check this for yourself if you are working with magnitudes you should wrap the model again.
.. code:: python
from redback.model_library import all_models_dict
import redback
import numpy as np
afterglow_model = 'vegas_tophat'
optical_model = 'arnett'
time = np.linspace(10, 500, 100) # Time in days
priors = redback.priors.get_priors('vegas_tophat')
priors.update(redback.priors.get_priors('arnett'))
model = 'afterglow_and_optical'
function = all_models_dict[model]
frequency = 2e14 # Frequency in Hz (e.g., optical band)
afterglow_kwargs = {}
optical_kwargs = {}
flux_density = function(time, av=1., frequency=frequency, base_afterglow_model=afterglow_model,
base_optical_model=optical_model, afterglow_kwargs=afterglow_kwargs,
optical_kwargs=optical_kwargs, **priors.sample())
# Any keyword arguments passed to the model that are not used by the afterglow or optical model will be ignored,
# so users should not stress about the kwargs too much.
# If there are optional physics in the afterglow or optical model that users want to use,
# They can just pass those in as well and they will be used by the relevant model.
# To do this you can do something like:
# Note that above we had done the same but with an empty dictionary
afterglow_kwargs = {'kn': True}
optical_kwargs = {'making_this_up': True}
kwargs = {'afterglow_kwargs':afterglow_kwargs, 'optical_kwargs':optical_kwargs}
flux_density = function(time, av=1., frequency=frequency, base_afterglow_model=afterglow_model,
base_optical_model=optical_model, **priors.sample(), **kwargs)
# When sampling/inference you can pass these kwargs via the model kwargs the same way you specify frequency and output_format etc.
# Note **kwargs, always expands in the function so you should make sure things are not duplicated between the kwargs/priors and the
# things you manually specified.
A note about general assumptions in :code:`redback` models.
-------------------------
In :code:`redback`, we generally solve for the physics of the model in the rest frame of the transient, then transformed onto the users desired time/frequency/bandpass.
Each model functions somewhat differently. Generally, for thermal transients, this ultimately involves calculating a spectrum via;
F_nu_obs(nu_obs, t_obs) = (1+z) * L_nu_rest(nu_rest, t_rest) / (4 pi D_L^2). Where nu_rest is the rest frame frequency, t_rest is the rest frame time, D_L is the luminosity distance and z is the redshift.
We typically use the redshift and some cosmology (default to Planck18) to estimate the luminosity distance as opposed to having two independent parameters.
This behaviour could be bypassed by using a custom cosmology dependency injection. See `here `_ for more details.
Plugin models
-------------------------
:code:`redback` supports a plugin system that allows external packages to register custom models and priors without modifying the redback source.
Once a plugin is installed, its models appear in :code:`all_models_dict` and its priors are returned by :code:`get_priors` alongside all built-in models and priors.
**How it works**
Plugin packages register themselves via Python `entry points `_ in their :code:`setup.py` or :code:`pyproject.toml`:
.. code:: python
entry_points={
'redback.model.modules': [
'my_models = my_plugin.models',
],
'redback.model.priors': [
'my_priors = my_plugin.priors:get_prior',
],
}
- :code:`redback.model.modules` — a Python module; redback imports all functions from it and adds them to :code:`all_models_dict`.
- :code:`redback.model.priors` — a callable :code:`get_prior(model_name) -> PriorDict or None`; redback calls it as a fallback when no built-in prior file is found.
After :code:`pip install my_plugin`, the models and priors are available immediately on the next :code:`import redback` — no changes to redback are needed.
**Writing a plugin model**
Model functions follow the same convention as built-in redback models: :code:`time` is the first argument and the function accepts :code:`**kwargs`.
.. code:: python
import numpy as np
def my_custom_model(time, amplitude, timescale, **kwargs):
return amplitude * np.exp(-time / timescale)
**Writing a plugin prior loader**
The prior loader is a callable that takes a model name string and returns a :code:`bilby.core.prior.PriorDict` if it knows that model, or :code:`None` otherwise.
A typical implementation loads a :code:`.prior` file from the plugin's package data:
.. code:: python
import os
from bilby.core.prior import PriorDict
PRIOR_DIR = os.path.join(os.path.dirname(__file__), 'priors')
def get_prior(model_name):
path = os.path.join(PRIOR_DIR, f'{model_name}.prior')
if not os.path.exists(path):
return None
p = PriorDict()
p.from_file(path)
return p
**Collision behaviour**
If a plugin model has the same name as a built-in redback model, the built-in wins and a warning is logged. Rename the plugin model to avoid the conflict.
**X-ray / high-energy spectral models**
X-ray spectral models use the same :code:`redback.model.modules` entry point — no separate group is needed.
The only requirement is that the first argument is :code:`energies_keV` (or :code:`energy_keV`) instead of :code:`time`.
Redback validates this at fit time when using a :code:`CountsSpectrumTransient`.
.. code:: python
import numpy as np
def my_powerlaw_xray(energies_keV, norm, photon_index, **kwargs):
return norm * energies_keV ** (-photon_index)
A complete working example is provided in :code:`examples/example_plugin/`.