Project persistence
The asymmetry.core.project module provides versioned JSON project files
(.asymp) that capture the full GUI session — loaded datasets, panel
settings, fit configuration, and Fourier settings — so you can close the
application and resume exactly where you left off.
Raw data arrays are not embedded in the project file; instead, source file paths are stored and the files are reloaded on open. This keeps project files small and avoids duplicating data.
The schema version embedded in every .asymp file is independent of the
package version, so project files survive package upgrades as long as the
schema version is supported.
Public API
- asymmetry.core.project.load_project(path: str | Path) dict[source]
Load, migrate, and validate a project file.
- Parameters:
path (str or Path) – Path to the
.asympproject file.- Returns:
Validated project state dict at the current schema version.
- Return type:
- Raises:
UnsupportedSchemaVersion – If the schema version is not supported.
ValueError – If required keys are missing or the file is not valid JSON.
OSError – If the file cannot be read.
- asymmetry.core.project.save_project(state: dict, path: str | Path) None[source]
Write a project state dict to a JSON file.
- asymmetry.core.project.CURRENT_SCHEMA_VERSION = 17
int([x]) -> integer int(x, base=10) -> integer
Convert a number or string to an integer, or return 0 if no arguments are given. If x is a number, return x.__int__(). For floating-point numbers, this truncates towards zero.
If x is not a number or if base is given, then x must be a string, bytes, or bytearray instance representing an integer literal in the given base. The literal can be preceded by ‘+’ or ‘-’ and be surrounded by whitespace. The base defaults to 10. Valid bases are 0 and 2-36. Base 0 means to interpret the base from the string as an integer literal. >>> int(‘0b100’, base=0) 4
The integer schema version written into every new project file. Currently
7.
Schema internals
These functions are used internally by load_project() and
save_project() but may be useful for testing or migration scripts.
- asymmetry.core.project.schema.validate(data: dict) None[source]
Validate that required top-level keys are present.
- Parameters:
data (dict) – Project dict at the current schema version.
- Raises:
ValueError – If required keys are missing.
- asymmetry.core.project.schema.migrate_to_current(data: dict) dict[source]
Migrate a raw project dict to the current schema version.
Future schemas will chain
_migrate_v1_to_v2, etc.- Parameters:
data (dict) – Raw JSON dict loaded from a project file.
- Returns:
Data at the current schema version.
- Return type:
- Raises:
UnsupportedSchemaVersion – If the schema version is not in the supported window.
Project file format
A project file is a UTF-8 JSON document with the following top-level structure:
{
"schema_version": 7,
"created_with_app_version": "0.1.0",
"datasets": [
{
"source_file": "/absolute/path/to/file.nxs",
"run_number": 1234,
"metadata_overrides": { "field": 50.0 },
"representations": {
"time_fb_asymmetry": {
"recipe": {},
"fit": {
"model": { "component_names": ["Exponential"], "operators": [] },
"parameters": [...],
"result": { "success": true, "reduced_chi_squared": 0.97, ... },
"provenance": "single",
"batch_id": null,
"diverged": false,
"include_in_trend": true
},
"trend_state": {}
},
"freq_fft": {
"recipe": { "fourier_config": { "window": "gaussian", ... } },
"fit": { "model": null, "provenance": "none", ... },
"trend_state": {}
}
}
}
],
"combined_datasets": [
{ "source_run_numbers": [1234, 1235] }
],
"batches": [
{
"batch_id": "batch-1",
"rep_type": "time_fb_asymmetry",
"member_kind": "runs",
"member_run_numbers": [1234, 1235, 1236],
"member_source_run": {},
"order_key": "field",
"canonical_model": { "component_names": ["Exponential"], "operators": [] },
"param_roles": { "A": "local", "Lambda": "global" },
"nuisance_params": [],
"results_by_run": {
"1234": { "success": true, "parameters": { "Lambda": 0.31 }, ... }
},
"diverged_runs": []
}
],
"browser_state": {
"sort_column": 0,
"sort_order": "ascending",
"filters": {},
"selected_run_numbers": [1234],
"selected_group_ids": [],
"data_groups": [],
"extra_columns": []
},
"plot_state": { ... },
"single_fit_state": {
"model_name": "ExponentialRelaxation",
"parameters": [...],
"result_html": "<b>χ² = ...</b>"
},
"global_fit_state": {
"model_name": "ExponentialRelaxation",
"parameters": [...],
"result_html": "<b>χ² = ...</b>"
},
"fit_ui_state": { "active_tab_index": 0 },
"fit_parameters_state": { "rows": [...], "x_axis": "Auto", ... },
"fourier_state": {
"window": "gaussian",
"filter_start_us": 0.0,
"filter_time_constant_us": 1.5,
"padding": 4,
"display": "Power"
}
}
Schema versioning history:
v1–v4 — initial releases
v5 — grouping overrides, wizard cache
v6 — per-dataset
representationsmap (recipe-only FFT, per-runFitSlot, trend state); top-levelbatcheslistv7 —
FitSeriesgainsmember_kind,nuisance_params,member_source_run;trend_statenormalised to structured shape; group series recorded inbatches
Unknown top-level keys are silently preserved during migration, ensuring forward compatibility when a newer version of the application adds new state.
Representation
Each dataset entry’s representations map holds one entry per analysis
view the user has exercised. Keys are RepresentationType values:
"time_fb_asymmetry", "time_groups", "freq_fft", "freq_maxent".
Each representation stores:
recipeGeneration parameters (for FFT spectra: the
GroupSpectrumConfigserialisation; for time-domain views: empty). On project load the transient arrays are recomputed from the recipe rather than stored.fitA single
FitSlot— the most recent fit for this (dataset, representation) pair. Includes the model dict, fitted-parameter list, result summary, provenance marker ("none","single","batch","global"), thebatch_idof the owningFitSerieswhen the fit was part of a series, and divergence flags used by the trending panel.trend_stateOpaque dict persisting the user’s x-axis and y-parameter selections in the Fit Parameters panel for this representation.
FitSeries (batches)
The top-level batches list stores
FitSeries objects that
accumulate results across multiple members.
Key fields:
member_kind"runs"for F-B asymmetry / FFT batch fits;"groups"for multi-run grouped time-domain fits.member_run_numbersOrdered list of member keys. For
"runs"series these are real run numbers; for"groups"series they are synthetic negative keys of the form-(source_run * 1000 + group_index).member_source_runMap from synthetic group key → source run number (
"groups"series only).param_rolesPer-parameter classification:
"global","local", or"fixed".nuisance_paramsList of per-(run, group) nuisance parameter names excluded from trending (
"groups"series only).results_by_runPer-member fit result summaries (parameter values, uncertainties, χ²) used to drive the Fit Parameters trending panel.