Rate Analysis & Target-model Engine for Transient Absorption in Python
Kinetic analysis of ultrafast time-resolved spectroscopy data: multi-exponential fitting, global analysis and target analysis with rate-matrix (K-matrix) models, lifetime density analysis (LDA) with regularisation and automatic parameter selection, and the DAS / EAS / SAS spectra that come out of them.
PyRATE-TA is the analysis half of a two-project pair.
PyMORGAN owns loading,
processing and plotting: the file-format readers (PDAT, P2DAT, MESS
directories, …), the Dataset1D / Dataset2D objects, the presentation
Settings and every Matplotlib plotter.
The dependency is one-way: PyRATE-TA imports PyMORGAN, never the reverse.
PyRATE-TA does not reimplement readers, dataset objects or standard figures. The
seam is deliberately narrow — PyMORGAN's plot_species_spectra takes plain
arrays (Sfit, Taus, TauErr, isFixTau, modelType) rather than a PyRATE-TA
object, so the arrow never has to reverse; the adapter (as_species_args) lives
on this side.
- Shared data layer — datasets are loaded through PyMORGAN's pluggable
loader registry, so every format it supports (
PDAT,MESS_TRIR,Helios_TA,UniGE_fsTA, …) is available here without a second reader. New formats are contributed upstream, not forked. - Analysis-only settings — solver tolerances, iteration limits, default
component count and IRF handling, round-tripped to a commented
settings.toml. The dataclass field is the single source of truth: serialisation, type coercion and the GUI widgets are all derived from it. Presentation settings are deliberately not duplicated — style, colourmap and label conventions stay inpymorgan.Settings. - Global analysis by variable projection — for fixed lifetimes the linear
amplitudes are the least-squares solution
S = pinv(C) @ D, so only the non-linear parameters reach the optimiser. Far better conditioned than fitting amplitudes and lifetimes jointly. - Kinetic models — parallel (independent decays → DAS), sequential
(
A → B → C→ EAS) and general compartmental K-matrix models with branching (→ SAS).C(t)by eigendecomposition whereKis diagonalisable, by matrix-exponential propagation otherwise, with the near-degenerate eigenvalue case guarded. - Analytic IRF convolution — Gaussian-convolved exponentials (exponentially
modified Gaussian) rather than numerical convolution, with clipping (
t_min) as the alternative for the coherent artefact. - Coherent artefact suppression — append the IRF and its first two
derivatives to the design matrix (
coherent_artifact=True) so cross-phase modulation and Raman signals are absorbed by their own amplitudes instead of distorting the shortest lifetime. - Lifetime density analysis (LDA) — a dense regularised grid of fixed lifetimes with Tikhonov / first- or second-difference penalties. Automatic alpha selection by L-curve corner detection, GCV or the Morozov discrepancy principle. Optional non-negative constraint (NNLS), SVD pre-filtering, Monte Carlo bootstrap errors, and automatic peak centroid detection. Exports the 2D map to PDAT format.
- Ground-state bleach / absolute spectra — convert difference species spectra to absolute absorption spectra by adding back a scaled ground-state spectrum. The maximum physically allowable scale factor is computed automatically.
- Constrained amplitudes — a per-component sign mask (
sign_mask) imposes non-negative (+1) or non-positive (−1) constraints on any species spectrum without touching the lifetimes. - Reproducible results — every result carries the model identity, initial guesses, bounds, fixed/free masks, the delay and probe ranges actually used, and the solver's convergence report. A lifetime without its uncertainty and its fixed/free flag is not a result.
- Fit session files —
pr.save_fit/pr.load_fitround-trip the full result (arrays + JSON metadata) to a.prfitfile. A target fit reopens with its scheme in editable text so it can be modified without re-entering it. - Honest convergence — a fit that did not converge raises or is flagged; it is never returned as though it had. Parameters resting on a bound and near-degenerate lifetimes are reported explicitly.
- Preview mode —
pr.preview_globalevaluates a model at given lifetimes without optimising, showing what those lifetimes imply and what the residual would be, clearly marked as a guess rather than a result. - Analysis-only plots — residual matrices, concentration profiles
C(t), K-matrix diagrams, fit-monitor bars (live parameter tracking during a fit), kinetic traces with residuals panels, and spectra with residuals. Everything PyMORGAN can already draw is delegated upstream. - Headless-first fitting — every fit is reachable and testable from a plain
script with no
QApplication; the GUI is a caller, never a prerequisite. - Bundled PyQt6 GUI (
pyrate-ta-gui) — data loading, model building, global / target / LDA fitting, fit control and results inspection, reusing PyMORGAN's theme so the two applications look identical side by side. - Fast start-up — the public API is lazy (PEP 562), so
import pyrate_tadoes not pay for scipy or, through PyMORGAN, matplotlib and the loader registries. - Logging, not prints — library messages go through the
pyratelogger (pyrate.configure_logging()); a console handler is attached only when the host has not configured logging, so it does not fight PyMORGAN's. - uv-managed, ruff-linted, pytest-tested.
Install the latest release directly from PyPI:
pip install pyrate-ta
# or with uv:
uv pip install pyrate-ta
# Register bundled fonts in matplotlib:
pymorgan-install-fontsYou can also run the GUI directly without installing using uvx:
uvx --from pyrate-ta pyrate-ta-guiClone the repository and install in editable mode with uv:
git clone https://github.com/RJFernandezTeran/PyRATE-TA.git
cd PyRATE-TA
uv venv # create .venv (Python >= 3.12)
# Install the package (choose one):
uv pip install -e . # core workflow (includes PyQt6 GUI)
# or:
uv pip install -e ".[dev]" # + ruff and pytest
uv run pymorgan-install-fonts # register PyMORGAN's fonts in this environmentPyMORGAN is resolved from the sibling checkout (../PyMORGAN) through
[tool.uv.sources], so upstream edits are picked up without a reinstall. The
two folders must stay siblings; replace that entry with a plain version pin
once PyMORGAN is published to an index.
Console scripts installed with the package:
| Command | Purpose |
|---|---|
pyrate-ta-gui |
Launch the fitting interface |
pyrate-ta-edit-gui |
Open main_window.ui in Qt Designer |
pyrate-ta-settings |
Standalone analysis-settings editor |
import pyrate_ta as pr
import pymorgan as pm
pm.load_settings("settings.toml") # aesthetics: profile, labels, cmap, ...
pm.apply_style()
# --- Load and process: PyMORGAN ---
data = pm.load_1D("scan.pdat", data_type="PDAT")
data.background_correct(tmin=-20, tmax=-5)
# --- Global fit: PyRATE-TA ---
fit = pr.fit_global(data, n_components=3, model_type="Sequential")
print(fit.taus, fit.tau_err) # lifetimes and 1-sigma uncertainties
# --- Preview (no optimisation) ---
prev = pr.preview_global(data, taus=[1.0, 10.0, 100.0])
# --- Target analysis ---
fit_t = pr.fit_target(data, scheme="A_eq_B_to_C", taus=[2.0, 5.0, 20.0, 200.0])
# --- Lifetime density analysis ---
from pyrate_ta.fit.lda import solve_lda
lda = solve_lda(data, n_taus=100, alpha="auto", non_negative=True)
# --- Plot the species spectra: PyMORGAN ---
data.plot_species_spectra(*fit.as_species_args())
# --- Save the result ---
pr.save_fit("scan_fit", fit) # -> scan_fit.prfit
pm.show_plots()Analysis defaults come from pyrate.Settings (solver tolerances, component
count, IRF handling); everything about how the figures look comes from
pymorgan.Settings.
src/pyrate_ta/
models/ kinetic models: parallel · sequential · target (K-matrix) · irf · schemes · scheme_text
fit/ solvers & engines: driver · engines · varpro · cost · lda (lifetime density)
groundstate (absolute spectra) · constrained · prepare
results/ KineticFit · GlobalFit · TargetFit · LDAResult · serialisation
plot/ analysis-only views: concentrations · scheme · matrix · monitor
traces (kinetics + residuals) · lda · style
io/ fit-session import/export (.prfit — raw formats belong upstream to PyMORGAN)
gui/ PyQt6 application (pyrate-ta-gui)
main_window.py / .ui window assembly, wiring, menus (layout lives in the .ui)
settings_app.py standalone analysis-settings editor (pyrate-ta-settings)
settings_panel.py embedded settings editor widget
scheme_dialog.py / .ui target analysis model scheme builder dialog
tabs/ per-tab mixins: data · model · fitting · lda
crosshair.py · designer.py · monitor.py · mw_common.py
icons/ application icons (pirate_ship.png)
settings.py Settings (TOML auto-merge, solver, model and LDA defaults, GUI field specs)
settings.default.toml canonical default settings template shipped with the package
cite.py academic citation registry and logger (pyrate-ta-cite)
helpers.py shared numerical and plotting helpers
log.py logger factory and console configuration
examples/ runnable example scripts (quick_fit.py, lda_fit.py)
tests/ pytest suite (headless matplotlib, offscreen Qt)
scripts/ bump_version.py · run_checks.py · run_changed_tests.py
docs/ LaTeX manual (main + boundary + models + fitting + gui + settings + extending + installation)
uv pip install -e ".[dev]"
uv run pytest # full test suite
uv run python scripts/run_checks.py # boundary, API and Qt-layout checksSynthetic-recovery tests are the backbone of the suite: build data from known parameters, fit it, assert the parameters come back within tolerance. A fitting project without those is untested regardless of line coverage. The failure modes are tested too — non-convergence must be flagged rather than silently returned, and near-degenerate lifetimes must not produce exploding amplitudes unwarned.
Ruff handles linting and formatting
(configured in pyproject.toml):
uvx ruff@latest check src tests scripts
uvx ruff@latest format src testsThe version string in src/pyrate_ta/__about__.py follows 0.x.yymmdd.devN
(PEP 440) and is maintained by python scripts/bump_version.py (--minor for a
design bump, --check to verify it was bumped today).
If you publish results obtained with PyRATE-TA, please cite:
- The PyRATE-TA / PyMORGAN software paper — manuscript in preparation.
- R. J. Fernández-Terán, E. Sucre-Rosales, L. Echevarria, F. E. Hernández, A Sweet Introduction to the Mathematical Analysis of Time-Resolved Spectra and Complex Kinetic Mechanisms: The Chameleon Reaction Revisited, J. Chem. Educ. 2022, 99, 2327–2337. 10.1021/acs.jchemed.2c00104
- I. H. M. van Stokkum, D. S. Larsen, R. van Grondelle, Global and target analysis of time-resolved spectra, Biochim. Biophys. Acta Bioenerg. 2004, 1657, 82–104. 10.1016/j.bbabio.2004.04.011 — global/target analysis and variable projection.
- M. N. Berberan-Santos, J. M. G. Martinho, The integration of kinetic rate equations by matrix methods, J. Chem. Educ. 1990, 67, 375. 10.1021/ed067p375 — the eigenvector solution used by the propagator.
- P. C. Hansen, Analysis of discrete ill-posed problems by means of the L-curve, SIAM Review 1992, 34, 561–580. — L-curve corner detection for LDA alpha selection.
The list is printed by pyrate-ta-cite and logged when the GUI starts. Routines
that implement a published method also log their own reference when they run,
so the log of a fit records which formalism produced it.
- Development assisted by Google Antigravity, with all code, algorithms, and implementations manually verified and tested.
- PyRATE-TA builds upon and modernizes the original MATLAB implementation from the now-deprecated DataAnalysis repository, written by Dr. Ricardo J. Fernández-Terán during his PhD and validated iteratively throughout the years.
Released under the GNU Affero General Public License v3.0 (AGPLv3). © 2026 Dr. Ricardo J. Fernández-Terán