Fit Multiple Files with Shared Parameters#
This notebook fits multiple datasets simultaneously, sharing some parameters across all files while fitting others independently per file.
Example System:
6 datasets with identical spectral model (GLP + linear background)
Different shift amplitudes across files (varying pump fluence)
Shared time dependence: the peak position shifts at t = 0 and relaxes back exponentially (blurred by the IRF)
Key Concept:
Parameters are classified by vary level in the YAML model:
"project": shared across all files (fitted once)"file": independent per file (fitted separately for each)"static": fixed (not fitted); energy-model parameters are set from each file’s baseline fit
Workflow:
Load all datasets into a single Project
Fit baseline for each file
Load 2D models with project/file/static vary levels and
runproject.fit_2d()for one joint fit over all filesCompare fit results to known truth used to create synthetic data
from pathlib import Path
import numpy as np
import pandas as pd
from ruamel.yaml import YAML
import trspecfit
1. Load Data#
Create a Project and load all 6 datasets. Each file shares the same energy and
time axes but has a different shift amplitude (expFun A).
project = trspecfit.Project(path=Path.cwd())
data_folder = "data"
energy = np.loadtxt(project.path / data_folder / "energy.csv")
time = np.loadtxt(project.path / data_folder / "time.csv")
shift_amplitudes = [5, 2, 1, 0.5, 0.2, 0.1]
files = []
for i, amp in enumerate(shift_amplitudes, start=1):
file_data = np.loadtxt(project.path / data_folder / f'data_{i}.csv', delimiter=",")
f = trspecfit.File(
parent_project=project,
path=f'data_{i}',
data=file_data,
energy=energy,
time=time,
)
files.append(f)
print(f"{f.name}: expFun A = {amp}, shape {file_data.shape}")
# detail=1 also lists the attached files and plots each 2D data grid
project.describe(detail=1)
data_1: expFun A = 5, shape (98, 200)
data_2: expFun A = 2, shape (98, 200)
data_3: expFun A = 1, shape (98, 200)
data_4: expFun A = 0.5, shape (98, 200)
data_5: expFun A = 0.2, shape (98, 200)
data_6: expFun A = 0.1, shape (98, 200)
Project
path: <repo>/examples/fitting_workflows/21_multi_file_shared_fit
name: my_project
config: <repo>/examples/fitting_workflows/21_multi_file_shared_fit/project.yaml
Files (6):
data_1: 2D (98, 200), energy [0.00, 19.90], time [-20.00, 99.00], z [0, 19.62]
data_2: 2D (98, 200), energy [0.00, 19.90], time [-20.00, 99.00], z [0, 18.18]
data_3: 2D (98, 200), energy [0.00, 19.90], time [-20.00, 99.00], z [0, 18.18]
data_4: 2D (98, 200), energy [0.00, 19.90], time [-20.00, 99.00], z [0, 18.36]
data_5: 2D (98, 200), energy [0.00, 19.90], time [-20.00, 99.00], z [0, 18]
data_6: 2D (98, 200), energy [0.00, 19.90], time [-20.00, 99.00], z [0, 19.44]
2. Fit Baseline Spectra#
2.1. Define Fitting Region and Baseline#
Set energy and time limits, then define the baseline (ground state) spectrum for all files at once.
# Set fitting limits (same for all files)
project.set_fit_limits(
energy_limits=[5, 18],
time_limits=[-20, 99],
)
# time_type='ind': indices, not times. Slices 0-22 are t = -20 ... -9, which ends
# three IRF widths (SD = 3) before t = 0 so the onset cannot bleed into the baseline
project.define_baselines(time_start=0, time_stop=22, time_type="ind")
Fit limits set for 6 files: energy [5, 18], time [-20, 99]
Baseline defined for 6 files: time (index) [0, 22]
2.2. Fit the Baseline Model on Every File#
Load a baseline model and fit it on every file. The spectral shape is identical across files (only the shift amplitude differs), so the fitted line-shape parameters should come out alike, and the table below checks them against the truth the data was generated with. Most do; the Lorentzian fraction GLP_01_m is the exception. It only shows in the peak’s tails and a single spectrum barely constrains it, so it scatters widely around its truth.
# Load baseline model onto all files
project.load_models(model_yaml="models_energy.yaml", model_info="base")
# Fit baselines: one independent fit per file
project.fit_baselines(
model_name="base",
stages=2, # simplex pass, then leastsq refinement
try_ci=0, # skip confidence intervals: see 12_uncertainty_mcmc
)
Model 'base' loaded for 6 files
Baseline fit complete for 6 files: 01.109(ss.ms)
# per-file baseline line shape next to the truth the data was generated with
truth_yaml = YAML(typ="safe").load(project.path / data_folder / "models_energy_truth.yaml")["single_peak"]
truth_base = {
"LinBack_m": truth_yaml["LinBack"]["m"][0],
"LinBack_b": truth_yaml["LinBack"]["b"][0],
"GLP_01_A": truth_yaml["GLP"]["A"][0],
"GLP_01_x0": truth_yaml["GLP"]["x0"][0],
"GLP_01_F": truth_yaml["GLP"]["F"][0],
"GLP_01_m": truth_yaml["GLP"]["m"][0],
}
rows = []
for f in files:
vals = f.get_parameters(fit_type="baseline").set_index("name")["value"]
rows.append({"file": f.name, **{k: vals[k] for k in truth_base}})
rows.append({"file": "truth", **truth_base})
pd.DataFrame(rows).set_index("file").round(3)
| LinBack_m | LinBack_b | GLP_01_A | GLP_01_x0 | GLP_01_F | GLP_01_m | |
|---|---|---|---|---|---|---|
| file | ||||||
| data_1 | 0.400 | 0.009 | 9.794 | 10.005 | 1.000 | 0.056 |
| data_2 | 0.401 | -0.019 | 10.007 | 9.991 | 0.995 | 0.286 |
| data_3 | 0.403 | -0.039 | 9.606 | 10.004 | 1.046 | 0.207 |
| data_4 | 0.404 | -0.078 | 9.800 | 9.998 | 1.016 | 0.317 |
| data_5 | 0.400 | -0.010 | 9.768 | 10.007 | 1.016 | 0.305 |
| data_6 | 0.399 | 0.039 | 10.353 | 10.000 | 0.967 | 0.434 |
| truth | 0.400 | 0.000 | 10.000 | 10.000 | 1.000 | 0.300 |
Amplitude, position, width and background slope agree across files and with the truth to within a few percent, and the offset LinBack_b stays within a hundredth of the peak height of its truth, zero. GLP_01_m scatters from 0.06 to 0.43 around its truth of 0.3, with data_1 fit as an almost pure Gaussian. That is the one line-shape parameter a single spectrum cannot pin, and the 2D fit below inherits each file’s value as a static parameter: “static” means “as fit in the baseline”, not “known”.
3. Joint 2D Fit Across Files#
Load the 2D model, add the time dependence, and fit all files jointly: one residual over every file, minimized once.
The vary levels control parameter sharing:
Energy model (models_energy.yaml):
every line-shape parameter is
"static", pinned to its baseline value
Time model (models_time.yaml):
"project":tau,gaussCONV SD— shared dynamics across all files"file":expFun A— independent shift amplitude per file"static":expFun t0— fixed at 0
Why share tau and SD? The IRF width is an instrument property and the decay time a sample property, common to every fluence, while the shift amplitude is what the fluence changes. Sharing them lets the strong files pin what the weak files cannot: fit on its own, a file with a 0.1 shift barely constrains tau or SD (see 20_multi_file_independent_fit).
# Load 2D model onto all files
project.load_models(model_yaml="models_energy.yaml", model_info="2D")
# Add time dependence to peak position
project.add_time_dependences(
target_model="2D",
target_parameter="GLP_01_x0",
dynamics_yaml="models_time.yaml",
dynamics_model="MonoExpPosIRF",
)
# Fit all files jointly; the returned JointFitResult carries the combined table
joint = project.fit_2d(
model_name="2D",
stages=2, # simplex pass, then leastsq refinement
try_ci=0, # skip confidence intervals: see 12_uncertainty_mcmc
)
Model '2D' loaded for 6 files
Time dependence 'GLP_01_x0' added for 6 files
Project fit: 6 files, 2 project-vary, 6 file-vary, 54 static params (interpreter backend)
Time initialize: 1.1920928955078125e-05 s
Results global minumum fit (method=Nelder):
[[Variables]]
file00_LinBack_m: 0.3998635 (fixed)
file00_LinBack_b: 0.008688754 (fixed)
file00_LinBack_xStart: 0 (fixed)
file00_LinBack_xStop: 20 (fixed)
file00_GLP_01_A: 9.794339 (fixed)
file00_GLP_01_x0: 10.00546 (fixed)
GLP_01_x0_gaussCONV_SD: 5.00000174 +/- 0.05454086 (1.09%) (init = 5)
file00_GLP_01_x0_expFun_01_A: 5.30659754 +/- 0.01166111 (0.22%) (init = 5)
GLP_01_x0_expFun_01_tau: 46.7309669 +/- 0.14297245 (0.31%) (init = 10)
file00_GLP_01_x0_expFun_01_t0: 0 (fixed)
file00_GLP_01_F: 0.9999502 (fixed)
file00_GLP_01_m: 0.0563767 (fixed)
file01_LinBack_m: 0.4005746 (fixed)
file01_LinBack_b: -0.01868768 (fixed)
file01_LinBack_xStart: 0 (fixed)
file01_LinBack_xStop: 20 (fixed)
file01_GLP_01_A: 10.00687 (fixed)
file01_GLP_01_x0: 9.990536 (fixed)
file01_GLP_01_x0_expFun_01_A: 2.15309596 +/- 0.00718476 (0.33%) (init = 5)
file01_GLP_01_x0_expFun_01_t0: 0 (fixed)
file01_GLP_01_F: 0.9946391 (fixed)
file01_GLP_01_m: 0.2860204 (fixed)
file02_LinBack_m: 0.4033922 (fixed)
file02_LinBack_b: -0.03938399 (fixed)
file02_LinBack_xStart: 0 (fixed)
file02_LinBack_xStop: 20 (fixed)
file02_GLP_01_A: 9.606165 (fixed)
file02_GLP_01_x0: 10.004 (fixed)
file02_GLP_01_x0_expFun_01_A: 1.04905610 +/- 0.00657774 (0.63%) (init = 5)
file02_GLP_01_x0_expFun_01_t0: 0 (fixed)
file02_GLP_01_F: 1.045554 (fixed)
file02_GLP_01_m: 0.2074394 (fixed)
file03_LinBack_m: 0.4044803 (fixed)
file03_LinBack_b: -0.07764829 (fixed)
file03_LinBack_xStart: 0 (fixed)
file03_LinBack_xStop: 20 (fixed)
file03_GLP_01_A: 9.799693 (fixed)
file03_GLP_01_x0: 9.998345 (fixed)
file03_GLP_01_x0_expFun_01_A: 0.53656212 +/- 0.00624687 (1.16%) (init = 5)
file03_GLP_01_x0_expFun_01_t0: 0 (fixed)
file03_GLP_01_F: 1.016047 (fixed)
file03_GLP_01_m: 0.3172321 (fixed)
file04_LinBack_m: 0.3996662 (fixed)
file04_LinBack_b: -0.01004322 (fixed)
file04_LinBack_xStart: 0 (fixed)
file04_LinBack_xStop: 20 (fixed)
file04_GLP_01_A: 9.767538 (fixed)
file04_GLP_01_x0: 10.00745 (fixed)
file04_GLP_01_x0_expFun_01_A: 0.19673032 +/- 0.00623976 (3.17%) (init = 5)
file04_GLP_01_x0_expFun_01_t0: 0 (fixed)
file04_GLP_01_F: 1.016252 (fixed)
file04_GLP_01_m: 0.3045525 (fixed)
file05_LinBack_m: 0.3992315 (fixed)
file05_LinBack_b: 0.03945658 (fixed)
file05_LinBack_xStart: 0 (fixed)
file05_LinBack_xStop: 20 (fixed)
file05_GLP_01_A: 10.35277 (fixed)
file05_GLP_01_x0: 10.00032 (fixed)
file05_GLP_01_x0_expFun_01_A: 0.10997345 +/- 0.00604275 (5.49%) (init = 5)
file05_GLP_01_x0_expFun_01_t0: 0 (fixed)
file05_GLP_01_F: 0.9665539 (fixed)
file05_GLP_01_m: 0.4341475 (fixed)
[[Correlations]] (unreported correlations are < 0.100)
C(file00_GLP_01_x0_expFun_01_A, GLP_01_x0_expFun_01_tau) = -0.7631
C(GLP_01_x0_gaussCONV_SD, file00_GLP_01_x0_expFun_01_A) = +0.5039
C(GLP_01_x0_expFun_01_tau, file01_GLP_01_x0_expFun_01_A) = -0.4472
C(file00_GLP_01_x0_expFun_01_A, file01_GLP_01_x0_expFun_01_A) = +0.3856
C(GLP_01_x0_gaussCONV_SD, GLP_01_x0_expFun_01_tau) = -0.3761
C(GLP_01_x0_gaussCONV_SD, file01_GLP_01_x0_expFun_01_A) = +0.3437
C(GLP_01_x0_expFun_01_tau, file02_GLP_01_x0_expFun_01_A) = -0.2356
C(file00_GLP_01_x0_expFun_01_A, file02_GLP_01_x0_expFun_01_A) = +0.1986
C(GLP_01_x0_gaussCONV_SD, file02_GLP_01_x0_expFun_01_A) = +0.1633
C(GLP_01_x0_expFun_01_tau, file03_GLP_01_x0_expFun_01_A) = -0.1269
C(file01_GLP_01_x0_expFun_01_A, file02_GLP_01_x0_expFun_01_A) = +0.1206
C(file00_GLP_01_x0_expFun_01_A, file03_GLP_01_x0_expFun_01_A) = +0.1082
Time fit (global minimum): 57.66439080238342 s
Results local optimization fit (method=leastsq):
[[Variables]]
file00_LinBack_m: 0.3998635 (fixed)
file00_LinBack_b: 0.008688754 (fixed)
file00_LinBack_xStart: 0 (fixed)
file00_LinBack_xStop: 20 (fixed)
file00_GLP_01_A: 9.794339 (fixed)
file00_GLP_01_x0: 10.00546 (fixed)
GLP_01_x0_gaussCONV_SD: 2.98834297 +/- 0.01455372 (0.49%) (init = 5)
file00_GLP_01_x0_expFun_01_A: 4.97589760 +/- 0.00774839 (0.16%) (init = 5)
GLP_01_x0_expFun_01_tau: 50.0788670 +/- 0.12928627 (0.26%) (init = 10)
file00_GLP_01_x0_expFun_01_t0: 0 (fixed)
file00_GLP_01_F: 0.9999502 (fixed)
file00_GLP_01_m: 0.0563767 (fixed)
file01_LinBack_m: 0.4005746 (fixed)
file01_LinBack_b: -0.01868768 (fixed)
file01_LinBack_xStart: 0 (fixed)
file01_LinBack_xStop: 20 (fixed)
file01_GLP_01_A: 10.00687 (fixed)
file01_GLP_01_x0: 9.990536 (fixed)
file01_GLP_01_x0_expFun_01_A: 2.01684523 +/- 0.00574378 (0.28%) (init = 5)
file01_GLP_01_x0_expFun_01_t0: 0 (fixed)
file01_GLP_01_F: 0.9946391 (fixed)
file01_GLP_01_m: 0.2860204 (fixed)
file02_LinBack_m: 0.4033922 (fixed)
file02_LinBack_b: -0.03938399 (fixed)
file02_LinBack_xStart: 0 (fixed)
file02_LinBack_xStop: 20 (fixed)
file02_GLP_01_A: 9.606165 (fixed)
file02_GLP_01_x0: 10.004 (fixed)
file02_GLP_01_x0_expFun_01_A: 0.98749596 +/- 0.00572794 (0.58%) (init = 5)
file02_GLP_01_x0_expFun_01_t0: 0 (fixed)
file02_GLP_01_F: 1.045554 (fixed)
file02_GLP_01_m: 0.2074394 (fixed)
file03_LinBack_m: 0.4044803 (fixed)
file03_LinBack_b: -0.07764829 (fixed)
file03_LinBack_xStart: 0 (fixed)
file03_LinBack_xStop: 20 (fixed)
file03_GLP_01_A: 9.799693 (fixed)
file03_GLP_01_x0: 9.998345 (fixed)
file03_GLP_01_x0_expFun_01_A: 0.50410441 +/- 0.00549338 (1.09%) (init = 5)
file03_GLP_01_x0_expFun_01_t0: 0 (fixed)
file03_GLP_01_F: 1.016047 (fixed)
file03_GLP_01_m: 0.3172321 (fixed)
file04_LinBack_m: 0.3996662 (fixed)
file04_LinBack_b: -0.01004322 (fixed)
file04_LinBack_xStart: 0 (fixed)
file04_LinBack_xStop: 20 (fixed)
file04_GLP_01_A: 9.767538 (fixed)
file04_GLP_01_x0: 10.00745 (fixed)
file04_GLP_01_x0_expFun_01_A: 0.18568026 +/- 0.00548172 (2.95%) (init = 5)
file04_GLP_01_x0_expFun_01_t0: 0 (fixed)
file04_GLP_01_F: 1.016252 (fixed)
file04_GLP_01_m: 0.3045525 (fixed)
file05_LinBack_m: 0.3992315 (fixed)
file05_LinBack_b: 0.03945658 (fixed)
file05_LinBack_xStart: 0 (fixed)
file05_LinBack_xStop: 20 (fixed)
file05_GLP_01_A: 10.35277 (fixed)
file05_GLP_01_x0: 10.00032 (fixed)
file05_GLP_01_x0_expFun_01_A: 0.10332184 +/- 0.00510252 (4.94%) (init = 5)
file05_GLP_01_x0_expFun_01_t0: 0 (fixed)
file05_GLP_01_F: 0.9665539 (fixed)
file05_GLP_01_m: 0.4341475 (fixed)
[[Correlations]] (unreported correlations are < 0.100)
C(file00_GLP_01_x0_expFun_01_A, GLP_01_x0_expFun_01_tau) = -0.6763
C(GLP_01_x0_gaussCONV_SD, file00_GLP_01_x0_expFun_01_A) = +0.4214
C(GLP_01_x0_expFun_01_tau, file01_GLP_01_x0_expFun_01_A) = -0.3698
C(GLP_01_x0_gaussCONV_SD, GLP_01_x0_expFun_01_tau) = -0.2824
C(file00_GLP_01_x0_expFun_01_A, file01_GLP_01_x0_expFun_01_A) = +0.2816
C(GLP_01_x0_gaussCONV_SD, file01_GLP_01_x0_expFun_01_A) = +0.2304
C(GLP_01_x0_expFun_01_tau, file02_GLP_01_x0_expFun_01_A) = -0.1815
C(file00_GLP_01_x0_expFun_01_A, file02_GLP_01_x0_expFun_01_A) = +0.1383
C(GLP_01_x0_gaussCONV_SD, file02_GLP_01_x0_expFun_01_A) = +0.1131
Time fit (local optimization): 1.2711539268493652 s
Time elapsed for project-level 2D fit: 59.068(ss.ms)
The correlation block the fit printed is the method’s fingerprint. Per-file parameters carry the optimizer’s file00_…, file01_… prefix, numbered from zero in load order, so file00_ is data_1. The A of the stronger files is anti-correlated with the shared tau (a slower decay and a smaller shift describe the same early trace), and SD and tau trade off weakly.
4. Shared vs. Per-File Parameters#
Confirm the vary levels in the output. file.get_parameters(fit_type="2d") returns one row per parameter; below we collect the three fitted dynamics parameters (t0 is pinned) for every file into one table. Next to them sits the truth: shared SD = 3, tau = 50 (data/models_time_truth.yaml) and per-file A = [5, 2, 1, 0.5, 0.2, 0.1] (amplitudes in data/generate_data.ipynb).
SDandtauare identical down every row: fit once, shared.Avaries row to row and tracks the shift each file was generated with.
# vary level per parameter: "project" = shared (fit once), "file" = independent
rows = []
for f, A_truth in zip(files, shift_amplitudes):
vals = f.get_parameters(fit_type="2d").set_index("name")["value"]
rows.append(
{
"file": f.name,
"SD (project)": vals["GLP_01_x0_gaussCONV_SD"],
"tau (project)": vals["GLP_01_x0_expFun_01_tau"],
"A (file)": vals["GLP_01_x0_expFun_01_A"],
"A truth": A_truth,
}
)
pd.DataFrame(rows).set_index("file").round(3)
| SD (project) | tau (project) | A (file) | A truth | |
|---|---|---|---|---|
| file | ||||
| data_1 | 2.988 | 50.079 | 4.976 | 5.0 |
| data_2 | 2.988 | 50.079 | 2.017 | 2.0 |
| data_3 | 2.988 | 50.079 | 0.987 | 1.0 |
| data_4 | 2.988 | 50.079 | 0.504 | 0.5 |
| data_5 | 2.988 | 50.079 | 0.186 | 0.2 |
| data_6 | 2.988 | 50.079 | 0.103 | 0.1 |
Error bars live on the joint result, not on the per-file tables: after a joint fit, file.get_parameters reports no stderr. The per-file tables are projections of the joint values only; the covariance stays with the joint record, because the shared parameters it couples are constrained by every file’s data at once. The JointFitResult that project.fit_2d returned (also reachable later as project.results.get_joint(model="2D")) carries the combined table with uncertainties, under the optimizer-scoped file00_… names:
# the fitted parameters of the joint fit with their uncertainties
joint.params.loc[joint.params["vary"], ["name", "value", "stderr"]].round(4)
| name | value | stderr | |
|---|---|---|---|
| 6 | GLP_01_x0_gaussCONV_SD | 2.9883 | 0.0146 |
| 7 | file00_GLP_01_x0_expFun_01_A | 4.9759 | 0.0077 |
| 8 | GLP_01_x0_expFun_01_tau | 50.0789 | 0.1293 |
| 18 | file01_GLP_01_x0_expFun_01_A | 2.0168 | 0.0057 |
| 28 | file02_GLP_01_x0_expFun_01_A | 0.9875 | 0.0057 |
| 38 | file03_GLP_01_x0_expFun_01_A | 0.5041 | 0.0055 |
| 48 | file04_GLP_01_x0_expFun_01_A | 0.1857 | 0.0055 |
| 58 | file05_GLP_01_x0_expFun_01_A | 0.1033 | 0.0051 |
Every fitted parameter lands within a few stderr of its truth. The shared SD and tau come out to a fraction of a percent, and the smallest shift, 0.1, is recovered at about five percent relative uncertainty. Compare 20_multi_file_independent_fit: fit on its own, the tau of data_6 carried an uncertainty fifty times larger than that of data_1; here one shared tau is pinned by all six files at once.
Tips#
varylevels live in the YAML, not the code.project/file/staticon each parameter decide what is shared, fit per-file, or frozen from the baseline — reshape the sharing scheme by editingmodels_time.yaml, no code change.project.fit_2d()is a true joint fit. Every file enters one residual;projectparameters resolve to a single shared value,fileparameters to one per file. Contrast20_multi_file_independent_fit, which fits each file separately.Static energy parameters come from the baseline. Every line-shape parameter is
static, so the ground-state shape is frozen per file and only the time dynamics are fit in 2D.
Next Steps#
20_multi_file_independent_fit— the independent-fit counterpart, no shared parameters.The
stderrcolumn above is the tier-1 error bar.12_uncertainty_mcmcexplains the profiled and MCMC tiers on a single file;project.fit_2dtakes the samemc_settingsfor the joint posterior (project.results.get_joint(model="2D").mcmc,plot_joint_mcmc).11_save_load_export—project.save_fits()archives the joint result as one bundle with its per-file slots.
Model files#
The YAML files next to this notebook, as shipped with the example.
models_energy.yaml#
# use these models to describe the energy-dependent data
# (available functions info: /src/trspecfit/functions/energy.py)
# ground state (most parameters should be able to vary)
base:
LinBack:
m: [1E-2, True, -1, 1]
b: [0, True, -5, 5]
xStart: [0, False]
xStop: [20, False]
GLP:
A: [12, True, 5, 15]
x0: [8, True, 5, 15]
F: [1.5, True, 0.75, 2.5]
m: [0.3, True, 0, 1]
# 2D model: every line-shape parameter is "static" (not fitted, set from the
# baseline fit); the "project" / "file" levels live in models_time.yaml
2D:
LinBack:
m: [1E-2, static]
b: [0, static]
xStart: [0, static]
xStop: [20, static]
GLP:
A: [12, static]
x0: [8, static]
F: [1.5, static]
m: [0.3, static]
models_time.yaml#
# use these models to add time-dependence to a parameter in a 2D model
# (available functions info: /src/trspecfit/functions/time.py)
# vary field uses "project" / "file" / "static" strings
# - "project": shared across all files in project.fit_2d (fitted once)
# - "file": independent per file (fitted separately)
# - "static": fixed (not fitted); energy-model parameters are set from the baseline fit
MonoExpPosIRF:
gaussCONV:
SD: [5, project, 1.0E-6, 10]
expFun:
A: [5, file, 0, 15]
tau: [10, project, 1, 100]
t0: [0, static]
project.yaml#
# Project configuration for project-level fitting example
# Display settings
show_output: 1
# Axis labels
e_label: 'Energy (arb. units)'
t_label: 'Time (arb. units)'
z_label: 'Intensity (arb. units)'
# Plot settings
x_dir: 'def'
x_type: 'lin'
y_dir: 'def'
y_type: 'lin'
z_colormap: 'viridis'
z_type: 'lin'
dpi_plt: 100
dpi_save: 300
res_mult: 5
The data were generated by data/generate_data.ipynb; its page shows the truth model files.