Fit Multiple Files Independently#
Fit six datasets with the same model, each on its own — no parameters tied across files. This is the bridge between single-file fitting (01_basic_fitting) and shared multi-file fitting (21_multi_file_shared_fit): the setup is shared, the fits are not.
Running this through a Project instead of a hand-rolled for f in files: loop buys four things: setup applied once, one coherent export tree, one-call cross-file comparison, and one portable HDF5 archive. Each shows up in the workflow below.
Workflow:
Load six files into one Project
Shared setup across all files (fit limits, baseline window, model)
Per-file baseline fits
Per-file 2D fits
Cross-file comparison
Export and archive the whole batch
The data is the shift-and-decay dataset from 21_multi_file_shared_fit (6 files, expFun A from 5 down to 0.1), loaded here by relative path to avoid duplication.
from pathlib import Path
import numpy as np
import pandas as pd
import trspecfit
1. Load Six Files Into One Project#
project = trspecfit.Project(path=Path.cwd(), name="per_file_batch")
# Data lives next door so we don't duplicate the 6 CSVs in this example dir.
data_root = project.path.parent / "21_multi_file_shared_fit" / "data"
energy = np.loadtxt(data_root / "energy.csv")
time = np.loadtxt(data_root / "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(data_root / 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/20_multi_file_independent_fit
name: per_file_batch
config: <repo>/examples/fitting_workflows/20_multi_file_independent_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]
3. Per-File Baseline Fits#
project.fit_baselines is a thin loop over file.fit_baseline, so each baseline is fit independently. The line shape these fits recover is checked against the committed truth in 21_multi_file_shared_fit §2, on the same data and model; here the baselines only supply the static parameters of the 2D fits.
project.fit_baselines(
model_name="base",
stages=2, # simplex pass, then leastsq refinement
try_ci=0, # skip confidence intervals: see 12_uncertainty_mcmc
)
Baseline fit complete for 6 files: 01.082(ss.ms)
4. Per-File 2D Fits#
For the 2D step we deliberately use a per-file loop (for f in files: f.fit_2d(...)) instead of project.fit_2d(...). The latter is the shared-parameter path (notebook 21_multi_file_shared_fit); here we want every file’s tau, SD, A fit independently.
The 2D YAML uses vary: project/file/static strings (carried over from notebook 21). For per-file fits those are reduced to a simple True/False vary level (project and file both → True; static → False), so the same YAML works in either workflow.
project.load_models(model_yaml="models_energy.yaml", model_info="2D")
project.add_time_dependences(
target_model="2D",
target_parameter="GLP_01_x0",
dynamics_yaml="models_time.yaml",
dynamics_model="MonoExpPosIRF",
)
for f in files:
f.fit_2d(
model_name="2D",
stages=2, # simplex pass, then leastsq refinement (fit_2d alone defaults to 1)
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
Time initialize: 9.775161743164062e-06 s
Results global minumum fit (method=Nelder):
[[Variables]]
LinBack_m: 0.3998635 (fixed)
LinBack_b: 0.008688754 (fixed)
LinBack_xStart: 0 (fixed)
LinBack_xStop: 20 (fixed)
GLP_01_A: 9.794339 (fixed)
GLP_01_x0: 10.00546 (fixed)
GLP_01_x0_gaussCONV_SD: 4.99999962 +/- 0.11146601 (2.23%) (init = 5)
GLP_01_x0_expFun_01_A: 5.32090014 +/- 0.01836074 (0.35%) (init = 5)
GLP_01_x0_expFun_01_tau: 46.4693353 +/- 0.21631774 (0.47%) (init = 10)
GLP_01_x0_expFun_01_t0: 0 (fixed)
GLP_01_F: 0.9999502 (fixed)
GLP_01_m: 0.0563767 (fixed)
[[Correlations]] (unreported correlations are < 0.100)
C(GLP_01_x0_expFun_01_A, GLP_01_x0_expFun_01_tau) = -0.8299
C(GLP_01_x0_gaussCONV_SD, GLP_01_x0_expFun_01_A) = +0.6920
C(GLP_01_x0_gaussCONV_SD, GLP_01_x0_expFun_01_tau) = -0.5370
Time fit (global minimum): 0.09099793434143066 s
Results local optimization fit (method=leastsq):
[[Variables]]
LinBack_m: 0.3998635 (fixed)
LinBack_b: 0.008688754 (fixed)
LinBack_xStart: 0 (fixed)
LinBack_xStop: 20 (fixed)
GLP_01_A: 9.794339 (fixed)
GLP_01_x0: 10.00546 (fixed)
GLP_01_x0_gaussCONV_SD: 2.97928732 +/- 0.01603162 (0.54%) (init = 5)
GLP_01_x0_expFun_01_A: 4.98148301 +/- 0.00818268 (0.16%) (init = 5)
GLP_01_x0_expFun_01_tau: 49.8914561 +/- 0.14208435 (0.28%) (init = 10)
GLP_01_x0_expFun_01_t0: 0 (fixed)
GLP_01_F: 0.9999502 (fixed)
GLP_01_m: 0.0563767 (fixed)
[[Correlations]] (unreported correlations are < 0.100)
C(GLP_01_x0_expFun_01_A, GLP_01_x0_expFun_01_tau) = -0.7075
C(GLP_01_x0_gaussCONV_SD, GLP_01_x0_expFun_01_A) = +0.4416
C(GLP_01_x0_gaussCONV_SD, GLP_01_x0_expFun_01_tau) = -0.2825
Time fit (local optimization): 0.09671545028686523 s
Time elapsed for 2D model fit: 00.704(ss.ms)
Time initialize: 1.0013580322265625e-05 s
Results global minumum fit (method=Nelder):
[[Variables]]
LinBack_m: 0.4005746 (fixed)
LinBack_b: -0.01868768 (fixed)
LinBack_xStart: 0 (fixed)
LinBack_xStop: 20 (fixed)
GLP_01_A: 10.00687 (fixed)
GLP_01_x0: 9.990536 (fixed)
GLP_01_x0_gaussCONV_SD: 5.00000000 +/- 0.07686508 (1.54%) (init = 5)
GLP_01_x0_expFun_01_A: 2.12544946 +/- 0.00920127 (0.43%) (init = 5)
GLP_01_x0_expFun_01_tau: 48.2403953 +/- 0.34943703 (0.72%) (init = 10)
GLP_01_x0_expFun_01_t0: 0 (fixed)
GLP_01_F: 0.9946391 (fixed)
GLP_01_m: 0.2860204 (fixed)
[[Correlations]] (unreported correlations are < 0.100)
C(GLP_01_x0_expFun_01_A, GLP_01_x0_expFun_01_tau) = -0.7261
C(GLP_01_x0_gaussCONV_SD, GLP_01_x0_expFun_01_A) = +0.3473
C(GLP_01_x0_gaussCONV_SD, GLP_01_x0_expFun_01_tau) = -0.2071
Time fit (global minimum): 0.08553671836853027 s
Results local optimization fit (method=leastsq):
[[Variables]]
LinBack_m: 0.4005746 (fixed)
LinBack_b: -0.01868768 (fixed)
LinBack_xStart: 0 (fixed)
LinBack_xStop: 20 (fixed)
GLP_01_A: 10.00687 (fixed)
GLP_01_x0: 9.990536 (fixed)
GLP_01_x0_gaussCONV_SD: 3.06468268 +/- 0.03903390 (1.27%) (init = 5)
GLP_01_x0_expFun_01_A: 2.00205347 +/- 0.00784105 (0.39%) (init = 5)
GLP_01_x0_expFun_01_tau: 51.4207095 +/- 0.35184641 (0.68%) (init = 10)
GLP_01_x0_expFun_01_t0: 0 (fixed)
GLP_01_F: 0.9946391 (fixed)
GLP_01_m: 0.2860204 (fixed)
[[Correlations]] (unreported correlations are < 0.100)
C(GLP_01_x0_expFun_01_A, GLP_01_x0_expFun_01_tau) = -0.7109
C(GLP_01_x0_gaussCONV_SD, GLP_01_x0_expFun_01_A) = +0.4375
C(GLP_01_x0_gaussCONV_SD, GLP_01_x0_expFun_01_tau) = -0.2817
Time fit (local optimization): 0.0159757137298584 s
Time elapsed for 2D model fit: 00.633(ss.ms)
Time initialize: 1.049041748046875e-05 s
Results global minumum fit (method=Nelder):
[[Variables]]
LinBack_m: 0.4033922 (fixed)
LinBack_b: -0.03938399 (fixed)
LinBack_xStart: 0 (fixed)
LinBack_xStop: 20 (fixed)
GLP_01_A: 9.606165 (fixed)
GLP_01_x0: 10.004 (fixed)
GLP_01_x0_gaussCONV_SD: 5.00000105 +/- 0.14943894 (2.99%) (init = 5)
GLP_01_x0_expFun_01_A: 1.05440107 +/- 0.00905246 (0.86%) (init = 5)
GLP_01_x0_expFun_01_tau: 46.1630242 +/- 0.66072692 (1.43%) (init = 10)
GLP_01_x0_expFun_01_t0: 0 (fixed)
GLP_01_F: 1.045554 (fixed)
GLP_01_m: 0.2074394 (fixed)
[[Correlations]] (unreported correlations are < 0.100)
C(GLP_01_x0_expFun_01_A, GLP_01_x0_expFun_01_tau) = -0.7211
C(GLP_01_x0_gaussCONV_SD, GLP_01_x0_expFun_01_A) = +0.2961
C(GLP_01_x0_gaussCONV_SD, GLP_01_x0_expFun_01_tau) = -0.1705
Time fit (global minimum): 0.1253974437713623 s
Results local optimization fit (method=leastsq):
[[Variables]]
LinBack_m: 0.4033922 (fixed)
LinBack_b: -0.03938399 (fixed)
LinBack_xStart: 0 (fixed)
LinBack_xStop: 20 (fixed)
GLP_01_A: 9.606165 (fixed)
GLP_01_x0: 10.004 (fixed)
GLP_01_x0_gaussCONV_SD: 2.94574071 +/- 0.08350436 (2.83%) (init = 5)
GLP_01_x0_expFun_01_A: 0.99374515 +/- 0.00858173 (0.86%) (init = 5)
GLP_01_x0_expFun_01_tau: 49.1056479 +/- 0.73228352 (1.49%) (init = 10)
GLP_01_x0_expFun_01_t0: 0 (fixed)
GLP_01_F: 1.045554 (fixed)
GLP_01_m: 0.2074394 (fixed)
[[Correlations]] (unreported correlations are < 0.100)
C(GLP_01_x0_expFun_01_A, GLP_01_x0_expFun_01_tau) = -0.7058
C(GLP_01_x0_gaussCONV_SD, GLP_01_x0_expFun_01_A) = +0.4434
C(GLP_01_x0_gaussCONV_SD, GLP_01_x0_expFun_01_tau) = -0.2826
Time fit (local optimization): 0.017481088638305664 s
Time elapsed for 2D model fit: 00.659(ss.ms)
Time initialize: 9.775161743164062e-06 s
Results global minumum fit (method=Nelder):
[[Variables]]
LinBack_m: 0.4044803 (fixed)
LinBack_b: -0.07764829 (fixed)
LinBack_xStart: 0 (fixed)
LinBack_xStop: 20 (fixed)
GLP_01_A: 9.799693 (fixed)
GLP_01_x0: 9.998345 (fixed)
GLP_01_x0_gaussCONV_SD: 5.00000178 +/- 0.28359166 (5.67%) (init = 5)
GLP_01_x0_expFun_01_A: 0.53956616 +/- 0.00879328 (1.63%) (init = 5)
GLP_01_x0_expFun_01_tau: 46.0937881 +/- 1.27218156 (2.76%) (init = 10)
GLP_01_x0_expFun_01_t0: 0 (fixed)
GLP_01_F: 1.016047 (fixed)
GLP_01_m: 0.3172321 (fixed)
[[Correlations]] (unreported correlations are < 0.100)
C(GLP_01_x0_expFun_01_A, GLP_01_x0_expFun_01_tau) = -0.7256
C(GLP_01_x0_gaussCONV_SD, GLP_01_x0_expFun_01_A) = +0.3261
C(GLP_01_x0_gaussCONV_SD, GLP_01_x0_expFun_01_tau) = -0.1854
Time fit (global minimum): 0.10620641708374023 s
Results local optimization fit (method=leastsq):
[[Variables]]
LinBack_m: 0.4044803 (fixed)
LinBack_b: -0.07764829 (fixed)
LinBack_xStart: 0 (fixed)
LinBack_xStop: 20 (fixed)
GLP_01_A: 9.799693 (fixed)
GLP_01_x0: 9.998345 (fixed)
GLP_01_x0_gaussCONV_SD: 2.91627723 +/- 0.15805937 (5.42%) (init = 5)
GLP_01_x0_expFun_01_A: 0.50583205 +/- 0.00829488 (1.64%) (init = 5)
GLP_01_x0_expFun_01_tau: 49.3615863 +/- 1.40093993 (2.84%) (init = 10)
GLP_01_x0_expFun_01_t0: 0 (fixed)
GLP_01_F: 1.016047 (fixed)
GLP_01_m: 0.3172321 (fixed)
[[Correlations]] (unreported correlations are < 0.100)
C(GLP_01_x0_expFun_01_A, GLP_01_x0_expFun_01_tau) = -0.7058
C(GLP_01_x0_gaussCONV_SD, GLP_01_x0_expFun_01_A) = +0.4433
C(GLP_01_x0_gaussCONV_SD, GLP_01_x0_expFun_01_tau) = -0.2829
Time fit (local optimization): 0.015168428421020508 s
Time elapsed for 2D model fit: 00.636(ss.ms)
Time initialize: 9.298324584960938e-06 s
Results global minumum fit (method=Nelder):
[[Variables]]
LinBack_m: 0.3996662 (fixed)
LinBack_b: -0.01004322 (fixed)
LinBack_xStart: 0 (fixed)
LinBack_xStop: 20 (fixed)
GLP_01_A: 9.767538 (fixed)
GLP_01_x0: 10.00745 (fixed)
GLP_01_x0_gaussCONV_SD: 5.00000172 +/- 1.27538734 (25.51%) (init = 5)
GLP_01_x0_expFun_01_A: 0.19024726 +/- 0.00877150 (4.61%) (init = 5)
GLP_01_x0_expFun_01_tau: 50.9106366 +/- 3.93475661 (7.73%) (init = 10)
GLP_01_x0_expFun_01_t0: 0 (fixed)
GLP_01_F: 1.016252 (fixed)
GLP_01_m: 0.3045525 (fixed)
[[Correlations]] (unreported correlations are < 0.100)
C(GLP_01_x0_expFun_01_A, GLP_01_x0_expFun_01_tau) = -0.7289
C(GLP_01_x0_gaussCONV_SD, GLP_01_x0_expFun_01_A) = +0.4256
C(GLP_01_x0_gaussCONV_SD, GLP_01_x0_expFun_01_tau) = -0.2591
Time fit (global minimum): 0.13216257095336914 s
Results local optimization fit (method=leastsq):
[[Variables]]
LinBack_m: 0.3996662 (fixed)
LinBack_b: -0.01004322 (fixed)
LinBack_xStart: 0 (fixed)
LinBack_xStop: 20 (fixed)
GLP_01_A: 9.767538 (fixed)
GLP_01_x0: 10.00745 (fixed)
GLP_01_x0_gaussCONV_SD: 2.31655896 +/- 0.39941292 (17.24%) (init = 5)
GLP_01_x0_expFun_01_A: 0.17611723 +/- 0.00779477 (4.43%) (init = 5)
GLP_01_x0_expFun_01_tau: 55.4595513 +/- 4.48864431 (8.09%) (init = 10)
GLP_01_x0_expFun_01_t0: 0 (fixed)
GLP_01_F: 1.016252 (fixed)
GLP_01_m: 0.3045525 (fixed)
[[Correlations]] (unreported correlations are < 0.100)
C(GLP_01_x0_expFun_01_A, GLP_01_x0_expFun_01_tau) = -0.7048
C(GLP_01_x0_gaussCONV_SD, GLP_01_x0_expFun_01_A) = +0.4292
C(GLP_01_x0_gaussCONV_SD, GLP_01_x0_expFun_01_tau) = -0.2795
Time fit (local optimization): 0.012473821640014648 s
Time elapsed for 2D model fit: 00.679(ss.ms)
Time initialize: 1.0013580322265625e-05 s
Results global minumum fit (method=Nelder):
[[Variables]]
LinBack_m: 0.3992315 (fixed)
LinBack_b: 0.03945658 (fixed)
LinBack_xStart: 0 (fixed)
LinBack_xStop: 20 (fixed)
GLP_01_A: 10.35277 (fixed)
GLP_01_x0: 10.00032 (fixed)
GLP_01_x0_gaussCONV_SD: 5.00000183 +/- 1.09900196 (21.98%) (init = 5)
GLP_01_x0_expFun_01_A: 0.10475245 +/- 0.00794854 (7.59%) (init = 5)
GLP_01_x0_expFun_01_tau: 52.9523256 +/- 7.24400126 (13.68%) (init = 10)
GLP_01_x0_expFun_01_t0: 0 (fixed)
GLP_01_F: 0.9665539 (fixed)
GLP_01_m: 0.4341475 (fixed)
[[Correlations]] (unreported correlations are < 0.100)
C(GLP_01_x0_expFun_01_A, GLP_01_x0_expFun_01_tau) = -0.7272
C(GLP_01_x0_gaussCONV_SD, GLP_01_x0_expFun_01_A) = +0.2206
C(GLP_01_x0_gaussCONV_SD, GLP_01_x0_expFun_01_tau) = -0.1371
Time fit (global minimum): 0.12525129318237305 s
Results local optimization fit (method=leastsq):
[[Variables]]
LinBack_m: 0.3992315 (fixed)
LinBack_b: 0.03945658 (fixed)
LinBack_xStart: 0 (fixed)
LinBack_xStop: 20 (fixed)
GLP_01_A: 10.35277 (fixed)
GLP_01_x0: 10.00032 (fixed)
GLP_01_x0_gaussCONV_SD: 3.22276772 +/- 0.79321489 (24.61%) (init = 5)
GLP_01_x0_expFun_01_A: 0.09982888 +/- 0.00758895 (7.60%) (init = 5)
GLP_01_x0_expFun_01_tau: 56.0816173 +/- 7.66080961 (13.66%) (init = 10)
GLP_01_x0_expFun_01_t0: 0 (fixed)
GLP_01_F: 0.9665539 (fixed)
GLP_01_m: 0.4341475 (fixed)
[[Correlations]] (unreported correlations are < 0.100)
C(GLP_01_x0_expFun_01_A, GLP_01_x0_expFun_01_tau) = -0.7196
C(GLP_01_x0_gaussCONV_SD, GLP_01_x0_expFun_01_A) = +0.4271
C(GLP_01_x0_gaussCONV_SD, GLP_01_x0_expFun_01_tau) = -0.2801
Time fit (local optimization): 0.02029871940612793 s
Time elapsed for 2D model fit: 00.662(ss.ms)
| name | value | standard error | relative error | initial value | min | max | vary |
|---|---|---|---|---|---|---|---|
| LinBack_m | 0.39986352 | 0.00000000 | (0.00%) | 0.399863515782638 | -inf | inf | False |
| LinBack_b | 0.00868875 | 0.00000000 | (0.00%) | 0.008688753805944138 | -inf | inf | False |
| LinBack_xStart | 0.00000000 | 0.00000000 | 0.0 | -inf | inf | False | |
| LinBack_xStop | 20.0000000 | 0.00000000 | (0.00%) | 20.0 | -inf | inf | False |
| GLP_01_A | 9.79433902 | 0.00000000 | (0.00%) | 9.794339016195368 | -inf | inf | False |
| GLP_01_x0 | 10.0054613 | 0.00000000 | (0.00%) | 10.00546128963923 | -inf | inf | False |
| GLP_01_x0_gaussCONV_SD | 2.97928732 | 0.01603162 | (0.54%) | 5.0 | 1.0000e-06 | 10.0000000 | True |
| GLP_01_x0_expFun_01_A | 4.98148301 | 0.00818268 | (0.16%) | 5.0 | 0.00000000 | 15.0000000 | True |
| GLP_01_x0_expFun_01_tau | 49.8914561 | 0.14208435 | (0.28%) | 10.0 | 1.00000000 | 100.000000 | True |
| GLP_01_x0_expFun_01_t0 | 0.00000000 | 0.00000000 | 0.0 | -inf | inf | False | |
| GLP_01_F | 0.99995019 | 0.00000000 | (0.00%) | 0.9999501878659243 | -inf | inf | False |
| GLP_01_m | 0.05637670 | 0.00000000 | (0.00%) | 0.0563766987436915 | -inf | inf | False |
| name | value | standard error | relative error | initial value | min | max | vary |
|---|---|---|---|---|---|---|---|
| LinBack_m | 0.40057460 | 0.00000000 | (0.00%) | 0.4005745992918963 | -inf | inf | False |
| LinBack_b | -0.01868768 | 0.00000000 | (0.00%) | -0.018687680147102093 | -inf | inf | False |
| LinBack_xStart | 0.00000000 | 0.00000000 | 0.0 | -inf | inf | False | |
| LinBack_xStop | 20.0000000 | 0.00000000 | (0.00%) | 20.0 | -inf | inf | False |
| GLP_01_A | 10.0068702 | 0.00000000 | (0.00%) | 10.006870163689907 | -inf | inf | False |
| GLP_01_x0 | 9.99053648 | 0.00000000 | (0.00%) | 9.990536476687957 | -inf | inf | False |
| GLP_01_x0_gaussCONV_SD | 3.06468268 | 0.03903390 | (1.27%) | 5.0 | 1.0000e-06 | 10.0000000 | True |
| GLP_01_x0_expFun_01_A | 2.00205347 | 0.00784105 | (0.39%) | 5.0 | 0.00000000 | 15.0000000 | True |
| GLP_01_x0_expFun_01_tau | 51.4207095 | 0.35184641 | (0.68%) | 10.0 | 1.00000000 | 100.000000 | True |
| GLP_01_x0_expFun_01_t0 | 0.00000000 | 0.00000000 | 0.0 | -inf | inf | False | |
| GLP_01_F | 0.99463905 | 0.00000000 | (0.00%) | 0.9946390503307071 | -inf | inf | False |
| GLP_01_m | 0.28602044 | 0.00000000 | (0.00%) | 0.28602043569995544 | -inf | inf | False |
| name | value | standard error | relative error | initial value | min | max | vary |
|---|---|---|---|---|---|---|---|
| LinBack_m | 0.40339223 | 0.00000000 | (0.00%) | 0.403392232372648 | -inf | inf | False |
| LinBack_b | -0.03938399 | 0.00000000 | (0.00%) | -0.03938399230427336 | -inf | inf | False |
| LinBack_xStart | 0.00000000 | 0.00000000 | 0.0 | -inf | inf | False | |
| LinBack_xStop | 20.0000000 | 0.00000000 | (0.00%) | 20.0 | -inf | inf | False |
| GLP_01_A | 9.60616477 | 0.00000000 | (0.00%) | 9.606164768643747 | -inf | inf | False |
| GLP_01_x0 | 10.0039977 | 0.00000000 | (0.00%) | 10.003997650906015 | -inf | inf | False |
| GLP_01_x0_gaussCONV_SD | 2.94574071 | 0.08350436 | (2.83%) | 5.0 | 1.0000e-06 | 10.0000000 | True |
| GLP_01_x0_expFun_01_A | 0.99374515 | 0.00858173 | (0.86%) | 5.0 | 0.00000000 | 15.0000000 | True |
| GLP_01_x0_expFun_01_tau | 49.1056479 | 0.73228352 | (1.49%) | 10.0 | 1.00000000 | 100.000000 | True |
| GLP_01_x0_expFun_01_t0 | 0.00000000 | 0.00000000 | 0.0 | -inf | inf | False | |
| GLP_01_F | 1.04555398 | 0.00000000 | (0.00%) | 1.0455539804959926 | -inf | inf | False |
| GLP_01_m | 0.20743936 | 0.00000000 | (0.00%) | 0.20743935974626337 | -inf | inf | False |
| name | value | standard error | relative error | initial value | min | max | vary |
|---|---|---|---|---|---|---|---|
| LinBack_m | 0.40448032 | 0.00000000 | (0.00%) | 0.404480315748283 | -inf | inf | False |
| LinBack_b | -0.07764829 | 0.00000000 | (0.00%) | -0.07764829257825401 | -inf | inf | False |
| LinBack_xStart | 0.00000000 | 0.00000000 | 0.0 | -inf | inf | False | |
| LinBack_xStop | 20.0000000 | 0.00000000 | (0.00%) | 20.0 | -inf | inf | False |
| GLP_01_A | 9.79969326 | 0.00000000 | (0.00%) | 9.799693258009018 | -inf | inf | False |
| GLP_01_x0 | 9.99834489 | 0.00000000 | (0.00%) | 9.998344891029214 | -inf | inf | False |
| GLP_01_x0_gaussCONV_SD | 2.91627723 | 0.15805937 | (5.42%) | 5.0 | 1.0000e-06 | 10.0000000 | True |
| GLP_01_x0_expFun_01_A | 0.50583205 | 0.00829488 | (1.64%) | 5.0 | 0.00000000 | 15.0000000 | True |
| GLP_01_x0_expFun_01_tau | 49.3615863 | 1.40093993 | (2.84%) | 10.0 | 1.00000000 | 100.000000 | True |
| GLP_01_x0_expFun_01_t0 | 0.00000000 | 0.00000000 | 0.0 | -inf | inf | False | |
| GLP_01_F | 1.01604723 | 0.00000000 | (0.00%) | 1.016047230730233 | -inf | inf | False |
| GLP_01_m | 0.31723205 | 0.00000000 | (0.00%) | 0.3172320526601427 | -inf | inf | False |
| name | value | standard error | relative error | initial value | min | max | vary |
|---|---|---|---|---|---|---|---|
| LinBack_m | 0.39966621 | 0.00000000 | (0.00%) | 0.39966620986027035 | -inf | inf | False |
| LinBack_b | -0.01004322 | 0.00000000 | (0.00%) | -0.01004321597306479 | -inf | inf | False |
| LinBack_xStart | 0.00000000 | 0.00000000 | 0.0 | -inf | inf | False | |
| LinBack_xStop | 20.0000000 | 0.00000000 | (0.00%) | 20.0 | -inf | inf | False |
| GLP_01_A | 9.76753792 | 0.00000000 | (0.00%) | 9.767537917718917 | -inf | inf | False |
| GLP_01_x0 | 10.0074456 | 0.00000000 | (0.00%) | 10.007445645217235 | -inf | inf | False |
| GLP_01_x0_gaussCONV_SD | 2.31655896 | 0.39941292 | (17.24%) | 5.0 | 1.0000e-06 | 10.0000000 | True |
| GLP_01_x0_expFun_01_A | 0.17611723 | 0.00779477 | (4.43%) | 5.0 | 0.00000000 | 15.0000000 | True |
| GLP_01_x0_expFun_01_tau | 55.4595513 | 4.48864431 | (8.09%) | 10.0 | 1.00000000 | 100.000000 | True |
| GLP_01_x0_expFun_01_t0 | 0.00000000 | 0.00000000 | 0.0 | -inf | inf | False | |
| GLP_01_F | 1.01625177 | 0.00000000 | (0.00%) | 1.0162517706897238 | -inf | inf | False |
| GLP_01_m | 0.30455245 | 0.00000000 | (0.00%) | 0.30455245168491063 | -inf | inf | False |
| name | value | standard error | relative error | initial value | min | max | vary |
|---|---|---|---|---|---|---|---|
| LinBack_m | 0.39923153 | 0.00000000 | (0.00%) | 0.3992315322222493 | -inf | inf | False |
| LinBack_b | 0.03945658 | 0.00000000 | (0.00%) | 0.03945657615582476 | -inf | inf | False |
| LinBack_xStart | 0.00000000 | 0.00000000 | 0.0 | -inf | inf | False | |
| LinBack_xStop | 20.0000000 | 0.00000000 | (0.00%) | 20.0 | -inf | inf | False |
| GLP_01_A | 10.3527655 | 0.00000000 | (0.00%) | 10.352765477714904 | -inf | inf | False |
| GLP_01_x0 | 10.0003212 | 0.00000000 | (0.00%) | 10.000321237048198 | -inf | inf | False |
| GLP_01_x0_gaussCONV_SD | 3.22276772 | 0.79321489 | (24.61%) | 5.0 | 1.0000e-06 | 10.0000000 | True |
| GLP_01_x0_expFun_01_A | 0.09982888 | 0.00758895 | (7.60%) | 5.0 | 0.00000000 | 15.0000000 | True |
| GLP_01_x0_expFun_01_tau | 56.0816173 | 7.66080961 | (13.66%) | 10.0 | 1.00000000 | 100.000000 | True |
| GLP_01_x0_expFun_01_t0 | 0.00000000 | 0.00000000 | 0.0 | -inf | inf | False | |
| GLP_01_F | 0.96655393 | 0.00000000 | (0.00%) | 0.966553925940148 | -inf | inf | False |
| GLP_01_m | 0.43414750 | 0.00000000 | (0.00%) | 0.434147504940918 | -inf | inf | False |
5. Cross-File Comparison#
Omit file= to survey the whole batch: project.results.compare_models(fit_type="2d") reads the in-session fit history (no disk I/O) and returns one row per (file, model, fit_type) slot. The file= filter takes a single file name or File to zoom into one row; loop over the files to inspect a subset.
With one model and one fit type per file, the comparison becomes a per-file fit-quality survey: which files fit best and which carry the largest residuals. Parameter values are not in this table; project.results.get_parameters(file=..., fit_type=...) returns them per file, as the next cell does. For a true model-vs-model comparison see 10_model_comparison.
project.results.compare_models(fit_type="2d")
| file | model | fit_type | handle | selection_json | chi2_red_raw | r2 | aic | bic | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | data_1 | 2D | 2d | effe5e26 | {"e_lim": [50, 181], "t_lim": [0, 98]} | 0.965527 | 0.880389 | -447.379098 | -424.998603 |
| 1 | data_2 | 2D | 2d | 9ae3b441 | {"e_lim": [50, 181], "t_lim": [0, 98]} | 0.935770 | 0.875460 | -849.262073 | -826.881578 |
| 2 | data_3 | 2D | 2d | 5634cb62 | {"e_lim": [50, 181], "t_lim": [0, 98]} | 0.971906 | 0.868855 | -362.836234 | -340.455739 |
| 3 | data_4 | 2D | 2d | cff2916c | {"e_lim": [50, 181], "t_lim": [0, 98]} | 0.966268 | 0.867271 | -437.524765 | -415.144271 |
| 4 | data_5 | 2D | 2d | 810127e4 | {"e_lim": [50, 181], "t_lim": [0, 98]} | 0.970370 | 0.864553 | -383.136250 | -360.755756 |
| 5 | data_6 | 2D | 2d | b73565cf | {"e_lim": [50, 181], "t_lim": [0, 98]} | 0.979175 | 0.865728 | -267.178903 | -244.798409 |
The survey shows six fits of the same quality — chi2_red_raw and r2 agree across files to within a few percent — but no parameters. Each file was generated with a known shift amplitude (the shift_amplitudes printed in section 1) and the shared truth tau = 50, SD = 3, so a short loop over get_parameters pairs what every independent fit recovered with what went in:
# what each independent 2D fit recovered, next to the truth it was generated with
rows = []
for f, amp in zip(files, shift_amplitudes):
fit_df = project.results.get_parameters(file=f.name, fit_type="2d")
fit_df = fit_df.set_index("name")
rows.append({
"file": f.name,
"A truth": amp,
"A fit": fit_df.loc["GLP_01_x0_expFun_01_A", "value"],
"A stderr": fit_df.loc["GLP_01_x0_expFun_01_A", "stderr"],
"tau fit (truth 50)": fit_df.loc["GLP_01_x0_expFun_01_tau", "value"],
"tau stderr": fit_df.loc["GLP_01_x0_expFun_01_tau", "stderr"],
"SD fit (truth 3)": fit_df.loc["GLP_01_x0_gaussCONV_SD", "value"],
"SD stderr": fit_df.loc["GLP_01_x0_gaussCONV_SD", "stderr"],
})
pd.DataFrame(rows).round(3)
| file | A truth | A fit | A stderr | tau fit (truth 50) | tau stderr | SD fit (truth 3) | SD stderr | |
|---|---|---|---|---|---|---|---|---|
| 0 | data_1 | 5.0 | 4.981 | 0.008 | 49.891 | 0.142 | 2.979 | 0.016 |
| 1 | data_2 | 2.0 | 2.002 | 0.008 | 51.421 | 0.352 | 3.065 | 0.039 |
| 2 | data_3 | 1.0 | 0.994 | 0.009 | 49.106 | 0.732 | 2.946 | 0.084 |
| 3 | data_4 | 0.5 | 0.506 | 0.008 | 49.362 | 1.401 | 2.916 | 0.158 |
| 4 | data_5 | 0.2 | 0.176 | 0.008 | 55.460 | 4.489 | 2.317 | 0.399 |
| 5 | data_6 | 0.1 | 0.100 | 0.008 | 56.082 | 7.661 | 3.223 | 0.793 |
The four strong files recover A to about a percent, and tau and SD to a few percent. The two weakest miss tau by more than 10 % and SD by up to a quarter, and their stderr say so: on tau it grows fiftyfold from the strongest file to the weakest. A shift of 0.1 barely constrains a time constant or an IRF width on its own; when those two are the same physical quantity in every file, sharing them is the fix, and that is what 21_multi_file_shared_fit does.
6. Export and Archive the Whole Batch#
Two methods, two audiences:
project.export_fit(ref)→ one CSV + PNG directory per fit. One reference, one directory at<path>/files/<file_name>/<model>/<handle>/with afit_info.csv; looping over one reference per file builds one coherent tree that is easy to diff or zip. One-way; noloadcounterpart.project.save_fits()→ single HDF5 archive. Lossless, σ-snapshot included, round-trips back into trspecfit viaFitResults.load.
save_fits takes file= / model= / fit_type= filters and select= to ship a subset instead of the whole batch; export_fit takes exactly one reference — below, each file’s 2D fit; the baselines stay in the archive. See 11_save_load_export for the save filters, select=, and the round trip.
for f in files:
# find() lists a file's fits oldest first, so [-1] is its 2D fit
slot_2d = project.results.find(file=f.name)[-1]
project.export_fit(slot_2d.handle, filepath="batch_export", overwrite=True)
project.save_fits("batch.fit.h5", overwrite=True)
loaded = trspecfit.FitResults.load("batch.fit.h5")
print(loaded)
print("\nfiles: ", loaded.files())
print("models: ", loaded.models())
Exported slot effe5e26 to batch_export/files/data_1/2D/effe5e26
Exported slot 9ae3b441 to batch_export/files/data_2/2D/9ae3b441
Exported slot 5634cb62 to batch_export/files/data_3/2D/5634cb62
Exported slot cff2916c to batch_export/files/data_4/2D/cff2916c
Exported slot 810127e4 to batch_export/files/data_5/2D/810127e4
Exported slot b73565cf to batch_export/files/data_6/2D/b73565cf
Saved 12 slot(s) across 6 file(s) to batch.fit.h5
FitResults(12 slots, 6 files)
files: ['data_1', 'data_2', 'data_3', 'data_4', 'data_5', 'data_6']
models: ['base', '2D']
Tips#
Choose the right
Projectmethod.project.fit_baselines()andproject.load_models()are setup helpers — loops that share boilerplate.project.fit_2d()is a true shared-parameter fit (see21_multi_file_shared_fit). Use a barefor f in files: f.fit_2d(...)loop for independent 2D fits, as shown here.Survey vs zoom.
compare_models()with nofile=returns one row per slot across the whole project — the cross-file survey.compare_models(file=name)filters to one file (single-target only; loop to inspect a subset).
Next Steps#
Share parameters across files (instrument response, decay constants):
21_multi_file_shared_fit. The YAMLs here already carry theproject/file/staticflags that driveproject.fit_2d().Save filters,
select=, and the archive round trip:11_save_load_exportModel-vs-model comparison on one file:
10_model_comparison
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
# In a per-file fit (this notebook) project and file both mean vary=True.
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