Fit saving - #30
Merged
Merged
Conversation
Dropped Project.path_run (trspecfit.py:171-173) and removed it from the class docstring.
Dropped File.path_da (trspecfit.py:1125) and removed it from the class docstring.
Rewrote create_model_path (trspecfit.py:1652) — now takes a keyword-only fit_type and produces {path_results}/{File.name}/{fit_type}/{model_name}/. Dropped the mod lookup, the yaml_f_name segment, and the model_unknown fallback (no longer reachable).
Updated 7 call sites with the appropriate fit_type=...: "baseline" (×2), "spectrum", "sbs", "2d" (×3).
utils/fit_io.py (new): SavedFitSlot dataclass (frozen, single source of truth for observed/fit/metrics/observed_sha256/selection_json/history_key); identity helpers (compute_file_fingerprint, compute_history_key, compute_observed_sha256, build_selection_json); per-fit-type extractors (_slot_from_baseline, _slot_from_spectrum, _slot_from_sbs, _slot_from_2d) — all take copied snapshot args, never live Model references. fit_results.py (new): FitResults class with __iter__, __len__, files(), models(), find(), get(). Immutable after construction; tuple-backed slot list. trspecfit.py: Project._fit_history: list[SavedFitSlot] initialized empty in __init__. Project.results property returns a fresh FitResults snapshot per access. File.fingerprint() (cached multi-sha) at trspecfit.py:1683. Four _append_<fit_type>_slot helpers (each guarded against mocked/placeholder result[1]) wired into fit_baseline, fit_spectrum, fit_slice_by_slice (before the seed-template restoration), and fit_2d.
fit_2d exports the full 2D fit result (similar to SbS) both get added time.csv and energy.csv to be self-contained base and spectrum fits export fit results (sum plus individual components as one column each in a 2D spreadsheet) [includes energy as first column to be self-contained] all files saved use project num_fmt and delim arguments in saved csv files renaming: "num_fmt" was previously named just "fmt"
- docs/design/fit_archive_schema.md: v1 wire format. Positional zero-padded group keys, identity in attrs, unified DataFrame encoding (homogeneous 2D float64 + columns attr; heterogeneous structured c000000-fields + columns/dtypes attrs), separate write-side strict identity (fingerprint+name+original_path) vs read-side fingerprint matching, history_key persisted as non-authoritative, source-dtype preservation for raw arrays + observed/fit, project-scoped joint slot deferred to v2. - utils/fit_io.py: writer (write_archive) + dataclasses (SavedFile, SavedProject) + identity helpers (compute_archive_slot_key, _find_file_by_fingerprint, _find_slot_by_archive_key) + DataFrame encoder (_encode_dataframe). Append-mode default with slot-scoped overwrite, pre-checked across all files before any mutation. Foreign HDF5 / schema-mismatch rejected; empty stub initialized. Pyright clean. - PLAN.md: tick completed in-memory + writer items, clarify project-level 2D wording (per-file 2d slots are in v1; only the joint construct is deferred).
Project.save_fits / Project.load_fits / File.save_fit. Default path ./fit_results/<project_name>.fit.h5. Slot identity now includes file_name. compute_history_key folds file_name into the hash, save_fits groups by (fingerprint, name) instead of fingerprint alone, and the live-file lookup (_find_file_for_slot, renamed) requires both name and fingerprint to match. Fixes a class of silent bugs where two byte-identical Project.files with different names would (a) collapse to one slot in the snapshot, (b) be saved under whichever name appeared first, and (c) leak across each other's file= filters. Project enforces unique File.name in-session, so name is enough to break the fingerprint tie; the archive's full identity tuple stays (fingerprint, name, original_path).
Filters _fit_history with the same pipeline as save_fits (extracted into Project._build_saved_project_from_history), then writes a slot-driven CSV/PNG tree via fit_io.write_csv_export. Output layout is <root>/<file_name>/<model_name>__<fit_type>[__<hash>]/, with per-slot params/metrics/conf_ci/mcmc plus fit_1d.csv (1D) or fit_2d.csv + observed_2d.csv + axis sidecars + 2D residual map (sbs/2d) plus fit_pars.csv + per-parameter PNGs (sbs). Disambiguation: slot dirs gain a history_key[:8] suffix when one (file, model, fit_type) triple has multiple selections; per-file dirs get a positional ordinal (__000, __001, ...) when two SavedFile records share a name, so even byte-identical records resolve to distinct directories. Per-file PlotConfig is preserved by passing a dict[file_name, PlotConfig] keyed by the live File.plot_config. Overwrite is per-slot directory, pre-checked across all slots.
- FitResults.compare_models: filter on (file, models, fit_type), defend against silent grid drift via observed_sha256 grouped by (fingerprint, file_name, fit_type), aggregate SbS per-slice metrics (median/mean/sum/long). - FitResults.plot_residuals: 1D side-by-side panels, 2D residual heatmaps with one global diverging scale shared across subplots. - File.export_fit + File.compare_models: 1-line delegates to Project / FitResults; existing save_fit kept. - File.save_sbs_fit / save_2d_fit: deprecated wrappers (DeprecationWarning, stacklevel=2) over renamed _save_*_fit_legacy impls. Internal auto-export call sites updated. Behavior preserved byte-for-byte. - TODO.md: name the v1.0.0 removal targets under "Remove legacy/backwards-compat".
- tests/test_fit_archive_roundtrip.py: 10 save→load field-equality tests across F1/F3/F6/F8 × applicable fit types. - tests/test_fit_history.py: history accumulation + snapshot-collapse and selection-identity (base_t_ind / e_lim / t_lim) tests. - tests/test_export_fits_parity.py: parity vs legacy _save_sbs_fit_legacy / _save_2d_fit_legacy outputs. - docs/design/repo_architecture.md: fit_results.py + utils/fit_io.py module entries, new save/export/load architecture section. - Remove dead File.load_fit TODO stub.
Add `Project.auto_export` (default True, settable via project.yaml or post-init mutation) to suppress the automatic CSV+PNG writes triggered on every fit_baseline / fit_spectrum / fit_slice_by_slice / fit_2d / Project.fit_2d. Driven by parameter-sweep, ML training-data, and the long-term real-time-fitting workflows where the ~6 CSVs and several PNGs per fit dominate per-fit cost on small data.
anything above 2s marked as slow
…ma() Slots now carry their own σ snapshot (noise_type, sigma_source, sigma_type, sigma_data, sigma_eff) and a 7-key metrics dict (chi2_raw, chi2_red_raw, chi2, chi2_red, r2, aic, bic). Calibrated chi2/chi2_red are populated only when σ was set on the File at fit time; raw fields are always populated. This bumps the HDF5 schema_version to "2" — archives written by the older schema can no longer be read (clean break before the branch ships). Sigma now enters via File.set_sigma() (forward-looking; existing slots keep their snapshot, immutable-slot invariant from PLAN.md preserved). Project YAML grew flat noise_type / sigma_source / sigma_type / sigma_data defaults with validation, and File inherits them at construction. compare_models() lost its sigma= kwarg: the default column set is dynamic (4 cols without σ, 6 with), explicit calibrated-metric requests raise a helpful KeyError when no matched slot has σ, and SbS sum-mode aggregates both chi2_red flavors as Σ numerator / Σ DoF so the "≈ 1" reading stays canonical. Other: notebook 10_model_comparison/ uses file.set_sigma() once and exercises every column meaning; targeted tests at tests/test_file.py:: TestSetSigma, tests/test_fit_history.py::TestFitResultsCompareModelsSigma Columns, and slot-side noise round-trip in test_fit_archive_roundtrip.py; PLAN.md updated to lock the schema decisions, refresh the slot-extractor signatures, and check off the notebook task; .gitignore catches *.fit.h5 artifacts.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.