Main Module
Project Class
- class trspecfit.trspecfit.Project(path: str | Path | None, name: str = 'test', config_file: str | Path | None = 'project.yaml')[source]
Bases:
objectProject-wide configuration and directory structure management.
Project provides centralized configuration for spectroscopy analysis workflows. It manages project directories, plot settings, file I/O formats, and analysis parameters. Configuration can be customized via YAML files to support different users, instruments, or spectroscopy techniques.
- Parameters:
path (str or Path) – Base directory for project data files and YAML configuration. If None, defaults to ‘test’ directory.
name (str, default='test') – Name for this analysis run. Creates subdirectory in results folder.
config_file (str or Path, optional) – YAML configuration file name (located in path directory). If None, uses default settings only.
- path
Base project directory containing data and configuration
- Type:
Path
- path_results
Results directory (path + ‘_fits’ suffix)
- Type:
Path
- show_output
Verbosity level:
0: Silent / programmatic / API mode – no prints, no plots displayed or saved
1: Interactive / notebook / UI mode – show timing, fit results, save plots and data
- Type:
- spec_fun_str
Name of fitting function in
trspecfit.spectra(e.g.'fit_model_gir','fit_model_mcp','fit_model_compare')- Type:
Notes
Plot Configuration: Plot-related attributes (axis labels, directions, colormaps, DPI, etc.) are used to construct PlotConfig objects. See trspecfit.config.plot.PlotConfig for full documentation of available plot settings.
YAML Configuration: Create a YAML file in the project directory to override defaults. Only specified settings need to be included; others use defaults.
File I/O Settings: Attributes ext, num_fmt, delim, da_fmt, and da_slices_fmt control file export formats and can be customized per project via YAML or direct attribute assignment.
- add_time_dependences(*, target_model: str, target_parameter: str, dynamics_yaml: str | Path, dynamics_model: str | list[str], frequency: float = -1) None[source]
Add time dependence to a parameter on every file in the project.
- Parameters:
target_model (str) – Name of the energy model (must exist on every file).
target_parameter (str) – Parameter to make time-dependent (e.g.
'GLP_01_x0').dynamics_yaml (str or Path) – YAML file defining the dynamics model.
dynamics_model (str or list of str) – Dynamics model name(s) (see
File.add_time_dependence).frequency (float, default=-1) – Sub-cycle frequency (-1 = single cycle).
- define_baselines(*, time_start: float, time_stop: float, time_type: str = 'abs') None[source]
Define baseline on every file in the project.
- describe(detail: int = 0) None[source]
Display project configuration summary.
- Parameters:
detail (int, default=0) –
Verbosity level.
0: project paths and config source.
1: also list attached Files (path, dim, shape, models) and plot 2D data grid.
2: also show plot and file I/O settings.
- export_fits(filepath: str | Path | None = None, *, format: Literal['csv'] = 'csv', file: int | str | File | Sequence[int | str | File] | None = None, model: str | Sequence[str] | None = None, fit_type: Literal['baseline', 'spectrum', 'sbs', '2d'] | Sequence[Literal['baseline', 'spectrum', 'sbs', '2d']] | None = None, overwrite: bool = False, show_output: int = 1) None[source]
Export filtered fit slots from
_fit_historyas a CSV/PNG tree.Same filter + snapshot-collapse pipeline as
save_fits(), but the output is a directory of human-readable artifacts rather than an HDF5 archive. One-way export — there is noloadcounterpart; round-tripping fits to disk is HDF5’s job (usesave_fits/load_fitsfor that).- Parameters:
filepath (path, optional) – Output directory. Default:
./fit_results/<project_name>. Created if missing.format ({“csv”}, default
"csv") – Reserved kwarg; only CSV is implemented in v1.file (slot in the snapshot shares the same) – Restrict to slots whose live
Project.filesentry matches; same semantics assave_fits().model (str | sequence, optional) – String filter on
slot.model_name.fit_type (str | sequence, optional) – String filter on
slot.fit_type.overwrite (bool, default False) – Per-slot directory: a non-empty target dir raises
FileExistsErrorunless True. Pre-checked across all slots before any writes (single conflict aborts the entire export).show_output (int, default 1) –
0to silence the per-call summary line.layout (Output)
-------------
directory (Exports are grouped by output)
name (model)
name
and
underscores; (fit type. The model and fit-type parts are joined with two)
file
model
type (and fit)
an
appended. (additional two-underscore hash suffix is)
params.csv (Each slot contains)
metrics_per_slice.csv (metrics.csv (or)
SbS) (for)
present (conf_ci.csv / mcmc/flatchain.csv when)
plus
artifacts (per-fit-type)
spectrum (- baseline /)
sbs (- 2d /) – 2D_data_fit_res.png.
only (- sbs) – parameter from plt_fit_res_pars.
one (The optional hash directory suffix appears only when more than)
file
model
(i.e. (and fit type)
history (different selections); the hash is the first 8 chars of the)
key.
- fit_2d(*, model_name: str, stages: int = 2, **fit_wrapper_kwargs) None[source]
Fit all files simultaneously with shared/independent parameters.
Builds a combined parameter set from all files, runs the optimizer once, and distributes final results back to each file’s model. Parameter sharing is controlled by the
varyfield in each model’s YAML ("project"/"file"/"static").- Parameters:
model_name (str) – Model name (must exist on every File in the project).
stages ({1, 2}, default=2) – Number of optimization stages (see
fitlib.fit_wrapper).**fit_wrapper_kwargs – Additional keyword arguments passed to
fitlib.fit_wrapper.
- fit_baselines(*, model_name: str, stages: int = 2, **fit_wrapper_kwargs) None[source]
Fit baseline on every file in the project.
Each file must already have the named model loaded and a baseline defined (via
define_baselinesorFile.define_baseline).- Parameters:
model_name (str) – Name of baseline model (must exist on every file).
stages ({1, 2}, default=2) – Number of optimization stages.
**fit_wrapper_kwargs – Additional keyword arguments passed to
fitlib.fit_wrapper.
- load_fits(filepath: str | Path, *, file: str | Sequence[str] | None = None, model: str | Sequence[str] | None = None, fit_type: Literal['baseline', 'spectrum', 'sbs', '2d'] | Sequence[Literal['baseline', 'spectrum', 'sbs', '2d']] | None = None, show_output: int = 1) FitResults[source]
Load a fit archive and return a
FitResultsview.Convenience wrapper around
FitResults.loadfor users who already have aProjectin hand. Does not mutate Project state — the returnedFitResultsis independent of_fit_historyand never merges into it.
- load_models(*, model_yaml: str | Path, model_info: str | list[str]) None[source]
Load the same energy model onto every file in the project.
- property results: FitResults
Snapshot view over the in-session fit history.
Returns a fresh
FitResultswrapping a copy of_fit_history; subsequent fits append to the log and do not affect previously returnedFitResults. Object identity is unstable (p.results is p.resultsis False); the contents at a given access are fixed.
- save_fits(filepath: str | Path | None = None, *, file: int | str | File | Sequence[int | str | File] | None = None, model: str | Sequence[str] | None = None, fit_type: Literal['baseline', 'spectrum', 'sbs', '2d'] | Sequence[Literal['baseline', 'spectrum', 'sbs', '2d']] | None = None, overwrite: bool = False, show_output: int = 1) None[source]
Save filtered fit slots from
_fit_historyto an HDF5 archive.Filters
_fit_historyby(file, model, fit_type), collapses to latest-per-history_key(snapshot semantics), assembles aSavedProject, and writes viautils.fit_io.write_archive.- Parameters:
filepath (path, optional) – Archive path. Default:
./fit_results/<project_name>.fit.h5. Append-mode: existing archives are augmented in place; pass a new path to start fresh.file (int | str | File | sequence, optional) – Restrict to slots whose live
Project.filesentry matches.intindexes intoself.files;strmatchesFile.name;Fileis taken directly. Resolved to file fingerprints, then matched againstslot.file_fingerprint.model (str | sequence, optional) – String filter on
slot.model_name.fit_type (str | sequence, optional) – String filter on
slot.fit_type.overwrite (bool, default False) – Slot-scoped: a slot collision (same canonical identity already in the archive) raises
FileExistsErrorunless True.show_output (int, default 1) –
0to silence the per-call summary line.
Notes
v1 behavior is snapshot-only (one slot per
history_key).keep_history=Truefor full-log save is deferred.
File Class
The File class provides a complete workflow for spectroscopy data analysis. Methods are organized below in the typical order of use:
Data Inspection
- File.__init__(parent_project: Project | None = None, path: str | Path = 'test', name: str | None = None, data: ndarray | None = None, energy: ndarray | None = None, time: ndarray | None = None, aux_axis: ndarray | None = None) None[source]
- File.describe(*, waterfall: float | None = None) None[source]
Display information about this file’s data.
Plots the data with current fit limits indicated by reference lines (or reduced opacity in waterfall mode). For 1D data, shows energy spectrum. For 2D data, shows time- and energy-resolved map or a waterfall plot for small datasets.
- Parameters:
waterfall (float or None, optional) –
Controls 2D data visualization mode.
None(default) — auto-select: waterfall plot iflen(self.time) <= 12, 2D map otherwise. The waterfall offset is set to the maximum peak-to-peak range across spectra.0— force 2D map regardless of dataset size.nonzero float — force waterfall plot with this y-offset between traces.
Notes
In waterfall mode, traces outside the active time fit window (
t_lim_abs) are drawn at reduced opacity (alpha = 0.35).
Model Management
- File.load_model(model_yaml: str | Path, model_info: str | list[str], par_name: str = '', model_type: Literal['energy', 'dynamics', 'profile'] = 'energy') Model[source]
Load a model from YAML file.
Loads a model defined in
model_yamlfile located in Parent.path.- Parameters:
model_yaml (str or Path) – YAML file name (located in project path) defining the model
model_info (str or list of str) –
Model name(s) to load. A bare string is treated as a single-element list.
For energy-dependent models (1D or 2D):
'model_name'or['model_name'](single element). Model will be set as active model.For standard time-dependent models:
'model_name'or['model_name']. Single element applies to entire time axis.For multi-cycle time-dependent models:
['model1', 'model2', ...]. Element 0 applies to entire time axis, elements 1+ apply to respective subcycles only.For profile models:
'model_name'or['model_name'](single element).
par_name (str, default='') – Parameter name for dynamics and profile models. Empty string (default) indicates an energy-dependent model. For
"dynamics"and"profile"model types, must match the name of the energy model parameter that the loaded model will be attached to.model_type ({'energy', 'dynamics', 'profile'}, default='energy') –
Type of model to load:
'energy': energy- (and time-)dependent spectral model'dynamics': time-dependence of a single model parameter'profile': spatial profile of a single model parameter over aux_axis
- Returns:
The loaded model. For
'energy'models the model is also registered inself.modelsand set as the active model.- Return type:
- File.set_active_model(model_info: str | int | list[str]) None[source]
Set model to be used as active model.
All functions requiring a model input will default to the currently active model unless a model is specified as input to the respective function (via
model_info).
- File.describe_model(model_info: str | int | list[str] | None = None, detail: int = 0) None[source]
Display information about a specific model.
Shows model parameters and optionally plots data with initial guess and residual. Useful for inspecting models before fitting.
- File.select_model(model_info: str | int | list[str]) Model | None[source]
Select model by name, index, or multi-cycle name list.
- File.delete_model(model_to_delete: str | int | list[str] | None = None) None[source]
Remove a model from this file’s model list.
- Parameters:
model_to_delete (str, int, list of str, or None, optional) – Model to delete (name, index, multi-cycle name list, or None for the currently active model).
Notes
After deletion, model_active may be invalid. Set a new active model if needed using set_active_model().
Data Corrections
- File.subtract_dark(dark: ndarray) None[source]
Subtract a dark/background spectrum from the data.
The dark spectrum is subtracted from every row (time slice) of the data before dividing by the sensitivity calibration. Replaces any previously set dark spectrum.
- Parameters:
dark (ndarray, shape (n_energy,)) – Dark/background spectrum to subtract. Must have the same length as the energy axis.
Notes
Apply dark subtraction before fitting. The correction is stored and can be replaced by calling this method again, or removed with
reset_dark(). The original data is always preserved indata_raw.
- File.calibrate_data(calibration: ndarray) None[source]
Apply sensitivity calibration by dividing the data.
The (dark-subtracted) data is divided by the calibration spectrum. Replaces any previously set calibration.
- Parameters:
calibration (ndarray, shape (n_energy,)) – Sensitivity/response spectrum to divide by. Must have the same length as the energy axis and must not contain zeros.
Notes
Apply calibration before fitting. The correction is stored and can be replaced by calling this method again, or removed with
reset_calibration(). The original data is always preserved indata_raw.
Fitting Workflow
Note
Recommended composition for profile-aware 2D models is serial:
attach a profile to a base parameter with add_par_profile(), then
attach dynamics to a profile parameter with add_time_dependence().
Adding profile and dynamics directly to the same base parameter is
currently disabled to avoid strongly correlated fits.
- File.define_baseline(time_start: float, time_stop: float, *, time_type: str = 'abs', show_plot: bool = True) None[source]
Define ground state/pre-trigger/baseline reference spectrum.
2D data will be cut and averaged between the specified time points to produce the baseline spectrum.
- Parameters:
time_start (float or int) – Start point in time, inclusive (absolute value or index, see time_type)
time_stop (float or int) – Stop point in time, inclusive (absolute value or index, see time_type)
time_type ({'abs', 'ind'}, default='abs') –
Type of time specification:
’abs’: Absolute time stamps
’ind’: Time array indices
show_plot (bool, default=True) – If True, plot the resulting baseline spectrum
- File.set_fit_limits(energy_limits: Sequence[float] | None, *, time_limits: Sequence[float] | None = None, show_plot: bool = True) None[source]
Set energy (and time) limits for fits.
Pass absolute values (NOT indices).
- Parameters:
energy_limits (list of float or None) – Energy range for fitting
[min, max]in absolute values. If None, uses full energy range[np.min(energy), np.max(energy)].time_limits (list of float, optional) – Time range for fitting
[min, max]in absolute values. If None, no time limits are applied.show_plot (bool, default=True) – If True, plot data with fit limits indicated
- File.fit_baseline(model_name: str, stages: int = 1, **lmfit_wrapper_kwargs) None[source]
Fit the baseline/ground state/pre-trigger reference spectrum.
- Parameters:
model_name (str) – Name of a previously loaded model (use File.load_model first)
stages ({1, 2}, default=1) –
Number of optimization stages:
1: Single optimization with
fit_alg_12: Two-stage fit (
fit_alg_1thenfit_alg_2)
**lmfit_wrapper_kwargs – Additional keyword arguments passed to fitlib.fit_wrapper
- File.fit_slice_by_slice(model_name: str, stages: int = 1, n_workers: int | None = None, *, seed_source: Literal['model', 'baseline', 'explicit'] = 'baseline', seed_values: Any | None = None, seed_adapt: Literal['argmax_shift'] | None = 'argmax_shift', **fit_wrapper_kwargs) None[source]
Fit time- and energy-resolved spectrum Slice-by-Slice (SbS).
Treats every time step as independent from other times. Each slice starts from a shared seed template selected via
seed_source, optionally adapted per slice viaseed_adapt. There is no cross-slice warm start, which keeps the workflow embarrassingly parallel.- Parameters:
model_name (str) – Name of a previously loaded model (use File.load_model first)
stages ({1, 2}, default=1) –
Number of optimization stages:
1: Single optimization with
fit_alg_12: Two-stage fit (
fit_alg_1thenfit_alg_2)
n_workers (int or None, default=None) –
Number of parallel worker processes. Slices are independent so SbS is embarrassingly parallel.
None: auto,os.cpu_count() - 1(leaves one core free)1: serial path (debug escape hatch — no pool overhead)N > 1:ProcessPoolExecutorwith thespawnstart method, the only portable option (Windows lacksfork). Workers reuse one pickled model installed at startup, so per-slice pickle overhead is bounded.
Notes for very small fits: spawn worker startup costs ~200-500ms on Linux/macOS and ~1-2s on Windows per worker, so for fits of fewer than ~20 slices,
n_workers=1is usually faster.seed_source ({'model', 'baseline', 'explicit'}, default='baseline') –
Shared parameter template used to seed every slice before any per-slice adaptation is applied.
'model': use the currentmodel_sbs.lmfit_parsvalues'baseline': use the storedfit_baseline()result values'explicit': useseed_valuesafter normalizing it to the model parameter order
seed_values (optional) – Explicit seed template used when
seed_source='explicit'. Accepts the same broad value shapes asulmfit.par_extract()plus dicts keyed by parameter name.seed_adapt ({None, 'argmax_shift'}, default='argmax_shift') –
Optional per-slice tweak applied after resolving the shared seed template and before fitting a slice.
None: use the same initial guess for every slice'argmax_shift': shift all parameters ending in'_x0'by the difference between the current slice’s argmax energy and the baseline spectrum’s argmax energy
**fit_wrapper_kwargs – Additional keyword arguments passed to fitlib.fit_wrapper
Notes
The actual per-slice fit results live in
self.results_sbs.self.model_sbsis retained as shared model/reconstruction context and is restored to the unadapted seed template after fitting.
- File.add_par_profile(target_model: str, target_parameter: str, profile_yaml: str | Path, profile_model: str | list[str]) None[source]
Add a parameter profile over the auxiliary axis to a model.
Loads a
"profile"-type model from a YAML file and attaches it to the named parameter, so that the parameter varies overaux_axis(uniform averaging over the auxiliary dimension).If any parameters inside the profile model are time-dependent (
t_vary=True), the model’s dim is automatically set to 2.To avoid strongly correlated fits, adding a profile to an energy-model parameter that already has time dependence (
t_vary=True) is currently disallowed.- Parameters:
target_model (str) – Name of the energy model to add the profile to.
target_parameter (str) – Name of the parameter to attach the profile to (e.g.
'GLP_01_A').profile_yaml (str or Path) – YAML file name defining the Profile model.
profile_model (str or list of str) – Model name(s) for the profile (single element).
- File.add_time_dependence(target_model: str, target_parameter: str, dynamics_yaml: str | Path, dynamics_model: str | list[str], *, frequency: float = -1) None[source]
Add time dependence for one parameter of a model.
Loads a “Dynamics”-type model to describe time-dependent behavior. The parameter can live either directly in the energy model or inside a Profile model attached to an energy model parameter.
To avoid strongly correlated fits, adding dynamics directly to an energy-model parameter that already has a profile (
p_vary=True) is currently disallowed. In that case, add dynamics to a profile parameter instead.- Parameters:
target_model (str) – Name of the energy model to add dynamics to.
target_parameter (str) – Name of parameter to make time-dependent. Can be an energy model parameter or a profile model parameter.
dynamics_yaml (str or Path) – YAML file name defining the Dynamics model.
dynamics_model (str or list of str) – Model name(s) for time-dependent behavior.
frequency (float, default=-1) – Repetition frequency for time-dependent behavior. -1 (default) means no repetition (single cycle).
- File.fit_2d(model_name: str, stages: int = 1, **fit_wrapper_kwargs) None[source]
Perform energy- and time-dependent 2D model fit.
- Parameters:
model_name (str) – Name of the model to fit (loaded via File.load_model)
stages ({1, 2}, default=1) –
Number of optimization stages:
1: Single optimization with
fit_alg_12: Two-stage fit (
fit_alg_1thenfit_alg_2)
**fit_wrapper_kwargs – Additional keyword arguments passed to fitlib.fit_wrapper (see fitlib.fit_wrapper for details)
- File.fit_spectrum(model_name: str, *, time_point: float | None = None, time_range: tuple[float, float] | None = None, time_type: Literal['abs', 'ind'] = 'abs', stages: int = 1, show_plot: bool = True, **lmfit_wrapper_kwargs) None[source]
Fit a 1D model to an individual spectrum at a selected time point or range.
Extracts a single spectrum from 2D data at the given time point or by averaging over a time range, then fits it with the specified model.
- Parameters:
model_name (str) – Name of a previously loaded model (use File.load_model first).
time_point (float or int, optional) – Single time value to extract the spectrum at. Mutually exclusive with time_range.
time_range (tuple of (float, float), optional) –
(start, stop)time bounds (inclusive). Slices in this window are averaged to produce the spectrum. Mutually exclusive with time_point.time_type ({'abs', 'ind'}, default='abs') –
How time_point / time_range values are interpreted:
'abs': absolute time-axis values'ind': integer indices into the time array
stages ({1, 2}, default=1) –
Number of optimization stages:
1: single optimization with
fit_alg_12: two-stage fit (
fit_alg_1thenfit_alg_2)
show_plot (bool, default=True) – If True, display the fit result plot.
**lmfit_wrapper_kwargs – Additional keyword arguments passed to
fitlib.fit_wrapper.
- Raises:
ValueError – If the data is not 2D, or neither time_point nor time_range is provided, or time_type is invalid.
Utility Methods
Note
These methods are typically called automatically by the fitting workflow. Most users won’t need to call these directly.
- File.model_list_to_name(model_list: Sequence[str]) str[source]
Create composite model name from list of submodel names.
Joins individual model names with underscores. Used primarily for mcp.Dynamics models with multiple subcycles. For single-element lists, returns that element unchanged.
- File.create_model_path(model_name: str, *, fit_type: Literal['baseline', 'spectrum', 'sbs', '2d'], subfolders: list[str] | None = None) Path[source]
Create directory structure for saving model fit results.
Layout:
{Project.path_results}/{File.name}/{fit_type}/{model_name}/. Creates directories if they don’t exist.- Parameters:
- Returns:
Path to model results directory
- Return type:
Path
- File.get_fit_results(*, fit_type: Literal['baseline', 'spectrum', 'sbs', '2d'] = 'baseline') DataFrame[source]
Return fit results as a DataFrame for programmatic access.
- Parameters:
fit_type ({'baseline', 'spectrum', 'sbs', '2d'}, default='baseline') –
Which fit results to return:
’baseline’: Baseline/ground-state fit (from
fit_baseline)’spectrum’: Single-spectrum fit (from
fit_spectrum)’sbs’: Slice-by-Slice fit (from
fit_slice_by_slice)’2d’: 2D global fit (from
fit_2d)
- Returns:
For ‘baseline’, ‘spectrum’, and ‘2d’: one row per parameter with columns
['name', 'value', 'stderr', 'init_value', 'min', 'max', 'vary', 'expr']. For ‘sbs’: one row per time slice with columns = parameter names.- Return type:
pd.DataFrame
- Raises:
ValueError – If the requested fit has not been performed yet.