Skip to main content

A light-curve fitting framework for astronomical transients

Project description

TransFit

Language: English | 简体中文

TransFit logo

Python License Inference Models Data

TransFit is a Python package for forward modeling and fitting astronomical transient light curves. It provides a compact interface for bolometric and multi-band data, with built-in nickel, magnetar, magnetar-plus-nickel, and CSM interaction models.

Features

  • Physical light-curve models with bolometric luminosity, effective temperature, and photospheric radius outputs.
  • Multi-band photometry in flux or magnitude space, including filter, extinction, and SED handling.
  • Bayesian fitting through a consistent result object, with emcee installed by default and optional zeus and dynesty backends.

Installation

python -m pip install transfit

For local development:

git clone <your-repo-url>
cd TransFit
python -m pip install -e ".[plot,examples]"

Install optional sampler backends with:

python -m pip install "transfit[all-samplers]"

Quick Start

Forward bolometric light curve
import matplotlib.pyplot as plt
import transfit as tf

params = {
    "M_ej": 3.0,
    "v_ej": 1.0,
    "E_Th_in": 1.5,
    "M_ni": 0.08,
    "R_0": 120.0,
    "f_ni": 0.2,
    "kappa": 0.12,
    "kappa_gamma": 0.03,
    "T_floor": 4500.0,
}

lc = tf.lightcurve_bol(
    model="nickel",
    params=params,
    z=0.001728,
    t_max_days=120.0,
)

plt.plot(lc.t_days, lc.Lbol)
plt.yscale("log")
plt.xlabel("Observer-frame time (days)")
plt.ylabel("Bolometric luminosity (erg s$^{-1}$)")
plt.show()

Bolometric forward model example

Forward multi-band light curve
import matplotlib.pyplot as plt
import transfit as tf

params = {
    "M_ej": 3.0,
    "v_ej": 1.0,
    "E_Th_in": 1.5,
    "M_ni": 0.08,
    "R_0": 120.0,
    "f_ni": 0.2,
    "kappa": 0.12,
    "kappa_gamma": 0.03,
    "T_floor": 4500.0,
}

filters = {
    "B": "johnson_cousins.B",
    "V": "johnson_cousins.V",
    "R": "johnson_cousins.R",
    "I": "johnson_cousins.I",
}

lc = tf.lightcurve_multiband(
    model="nickel",
    params=params,
    z=0.001728,
    filters=filters,
    bands=["B", "V", "R", "I"],
    y_kind="mag",
    mag_system="vega",
    t_max_days=120.0,
)

for band in lc.bands:
    plt.plot(lc.t_days, lc.y[band], label=band)
plt.gca().invert_yaxis()
plt.xlabel("Observer-frame time (days)")
plt.ylabel("Vega magnitude")
plt.legend()
plt.show()

filters maps the band labels in your data to filter definitions. Built-in filters use string IDs. Custom mono filters should use an effective wavelength:

filters = {
    "g": {"lambda_eff_A": 4770.0},
    "r": {"lambda_eff_nm": 623.1},
}

For custom Vega magnitudes, also provide a Vega zero point:

filters = {
    "B": {"lambda_eff_A": 4400.0, "vega_zero_point_jy": 4260.0},
}

Multi-band forward model example

Fit a bolometric light curve
import numpy as np
import transfit as tf

arr = np.loadtxt("examples/data/sn1993j_lbol.txt")
data = tf.BolometricData(
    t_days=arr[:, 0] - arr[:, 0].min(),
    y=arr[:, 1],
    yerr=arr[:, 2],
)

res = tf.fit_bol(
    data=data,
    model="nickel",
    z=0.001728,
    priors={
        "M_ej": (0.5, 8.0),
        "v_ej": (0.2, 3.0),
        "E_Th_in": (0.05, 8.0),
        "M_ni": ("log10", -3.0, -0.2),
        "R_0": (10.0, 400.0),
        "t_shift": (0.0, 20.0),
    },
    fixed={
        "f_ni": 0.2,
        "kappa": 0.12,
        "kappa_gamma": 0.03,
    },
    sampler_kwargs={"nwalkers": 32, "nsteps": 5000, "burnin": 1000, "thin": 10},
)

print(res.best_params_raw)
tf.save(res, "mcmc_out/sn1993j_bol_nickel.npz")
Fit a multi-band light curve
import numpy as np
import transfit as tf

raw = np.genfromtxt(
    "examples/data/sn2007gr.csv",
    delimiter=",",
    names=True,
    dtype=float,
    encoding="utf-8",
)

bands, t_days, y, yerr = [], [], [], []
t0 = np.nanmin(raw["Phase"])
columns = {
    "B": ("Bmag", "e_Bmag"),
    "V": ("Vmag", "e_Vmag"),
    "R": ("Rmag", "e_Rmag"),
    "I": ("Imag", "e_Imag"),
}

for band, (mag_col, err_col) in columns.items():
    good = (
        np.isfinite(raw["Phase"])
        & np.isfinite(raw[mag_col])
        & np.isfinite(raw[err_col])
        & (raw[err_col] > 0)
    )
    t_days.extend((raw["Phase"][good] - t0).tolist())
    y.extend(raw[mag_col][good].tolist())
    yerr.extend(raw[err_col][good].tolist())
    bands.extend([band] * int(np.sum(good)))

data = tf.MultiBandData(
    t_days=np.asarray(t_days, float),
    band=np.asarray(bands, dtype=object),
    y=np.asarray(y, float),
    yerr=np.asarray(yerr, float),
)

filters = {
    "B": "johnson_cousins.B",
    "V": "johnson_cousins.V",
    "R": "johnson_cousins.R",
    "I": "johnson_cousins.I",
}

res = tf.fit_multiband(
    data=data,
    model="nickel",
    z=0.001728,
    filters=filters,
    y_kind="mag",
    mag_system="vega",
    priors={
        "M_ej": (0.5, 8.0),
        "v_ej": (0.2, 3.0),
        "E_Th_in": (0.05, 8.0),
        "M_ni": ("log10", -3.0, -0.2),
        "R_0": (10.0, 400.0),
        "t_shift": (0.0, 20.0),
    },
    fixed={
        "f_ni": 0.2,
        "kappa": 0.12,
        "kappa_gamma": 0.03,
        "T_floor": 4500.0,
    },
    sampler_kwargs={"nwalkers": 32, "nsteps": 5000, "burnin": 1000, "thin": 10},
)

print(res.best_params_raw)
tf.save(res, "mcmc_out/sn2007gr_multiband_nickel.npz")

Public API

Data containers
tf.BolometricData(t_days, y, yerr, mask=None)
tf.MultiBandData(t_days, band, y, yerr, mask=None)
Model inspection
tf.model_param_names("nickel")
tf.param_template("csm")

Canonical model names are nickel, magnetar, magnetar_ni, and csm.

Forward and prediction
tf.lightcurve_bol(model=..., params=..., z=..., t_max_days=...)
tf.lightcurve_multiband(
    model=...,
    params=...,
    z=...,
    filters=...,
    bands=...,
    y_kind="mag",
)

tf.predict_bol(model=..., params=..., z=..., t_days=...)
tf.predict_multiband(
    model=...,
    params=...,
    z=...,
    filters=...,
    t_days=...,
    band=...,
)
Fitting
tf.fit_bol(
    data=...,
    model=...,
    z=...,
    priors=...,
    fixed=...,
    sampler="emcee",
    sampler_kwargs=None,
    model_kwargs=None,
)

tf.fit_multiband(
    data=...,
    model=...,
    z=...,
    filters=...,
    y_kind="mag",
    priors=...,
    fixed=...,
    sed=None,
    sampler="emcee",
    sampler_kwargs=None,
    model_kwargs=None,
)
Results, plotting, and I/O
res.best_params
res.best_params_raw
res.median_params
res.best_fit
res.best_index
res.best_log_prob
res.best_sample
res.samples
res.log_prob
res.meta

tf.plot.fit_bol(res, data=data)
tf.plot.fit_multiband(res, data=data)
tf.plot.corner(res)

path = tf.save(res, path="mcmc_out/result.npz")
loaded = tf.load(path)

Full details are available in API and parameter reference.

Documentation

Contact

For questions about this project, please contact:

Citation

If TransFit is helpful for your work, please consider giving the repository a star. This helps other researchers discover the project.

GitHub stars

If you use TransFit in research, please cite the TransFit paper:

@ARTICLE{2025ApJ...992...20L,
       author = {{Liu}, Liang-Duan and {Zhang}, Yu-Hao and {Yu}, Yun-Wei and {Du}, Ze-Xin and {Li}, Jing-Yao and {Wu}, Guang-Lei and {Dai}, Zi-Gao},
        title = "{TransFit: An Efficient Framework for Transient Light-curve Fitting with Time-dependent Radiative Diffusion}",
      journal = {\apj},
     keywords = {Supernovae, Radiative transfer, Core-collapse supernovae, Time domain astronomy, 1668, 1335, 304, 2109, High Energy Astrophysical Phenomena, Instrumentation and Methods for Astrophysics},
         year = 2025,
        month = oct,
       volume = {992},
       number = {1},
          eid = {20},
        pages = {20},
          doi = {10.3847/1538-4357/adfed6},
archivePrefix = {arXiv},
       eprint = {2505.13825},
 primaryClass = {astro-ph.HE},
       adsurl = {https://ui.adsabs.harvard.edu/abs/2025ApJ...992...20L},
      adsnote = {Provided by the SAO/NASA Astrophysics Data System}
}

For the csm model, also cite:

@ARTICLE{2026ApJ...999..186Z,
       author = {{Zhang}, Yu-Hao and {Liu}, Liang-Duan and {Du}, Ze-Xin and {Wu}, Guang-Lei and {Li}, Jing-Yao and {Yu}, Yun-Wei},
        title = "{TransFit-CSM: A Fast, Physically Consistent Framework for Interaction-powered Transients}",
      journal = {\apj},
     keywords = {Core-collapse supernovae, Supernovae, Circumstellar matter, Stellar mass loss, 304, 1668, 241, 1613, High Energy Astrophysical Phenomena},
         year = 2026,
        month = mar,
       volume = {999},
       number = {2},
          eid = {186},
        pages = {186},
          doi = {10.3847/1538-4357/ae434a},
archivePrefix = {arXiv},
       eprint = {2511.13265},
 primaryClass = {astro-ph.HE},
       adsurl = {https://ui.adsabs.harvard.edu/abs/2026ApJ...999..186Z},
      adsnote = {Provided by the SAO/NASA Astrophysics Data System}
}

Papers Using TransFit

  • Yuan et al., Thermal X-rays breaking out from pre-explosion ejecta of a dying massive star, arXiv e-print (2026), arXiv:2606.10014.
  • Liu et al., SN 2024igg: A Super-Chandrasekhar/03fg-like SN exhibiting C II-dominated spectra after explosion, submitted to A&A (2026), arXiv:2602.03427.

AI Assistance

Parts of the code and documentation in this project were generated with assistance from OpenAI Codex.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

transfit-0.1.0.tar.gz (84.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

transfit-0.1.0-py3-none-any.whl (102.2 kB view details)

Uploaded Python 3

File details

Details for the file transfit-0.1.0.tar.gz.

File metadata

  • Download URL: transfit-0.1.0.tar.gz
  • Upload date:
  • Size: 84.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for transfit-0.1.0.tar.gz
Algorithm Hash digest
SHA256 5cf86fb322ff22033645b5ba7efa42e5adbd25edcf18185aee44dbf641d1db3b
MD5 201c27092da1ed86088ce1702757f4ba
BLAKE2b-256 1d52b8f2266b1eec4fa6bdc8cc34fcc53dd68bdff41598fad4216daa215d1b45

See more details on using hashes here.

Provenance

The following attestation bundles were made for transfit-0.1.0.tar.gz:

Publisher: publish.yml on YuHaoZhang01/TransFit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file transfit-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: transfit-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 102.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for transfit-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 405e12e9966950e6a49643295c89e4749b5e1ceeddcf2923feb88b90983c499e
MD5 2166e3c274e8f29990cfc4c6145e684b
BLAKE2b-256 a9dd4974a0dbba284a478acab63fdb0d743208603ba268492bb59e49231814b8

See more details on using hashes here.

Provenance

The following attestation bundles were made for transfit-0.1.0-py3-none-any.whl:

Publisher: publish.yml on YuHaoZhang01/TransFit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page