Skip to content

Commit 9346188

Browse files
Add parallelism to sequential fitting (#141)
* Replace uid_map with direct parameter references in aliases * Auto-enable constraints on create, add enable/disable API * Implement Project.load() from CIF directory * Encode free flags via CIF uncertainty brackets * Update notebooks * Update serialization process to apply constraints before saving project * Move CIF loop truncation from persistence to display methods * Add CIF round-trip integration tests for experiments and structures * Add new integration test * Move analysis.cif into analysis/ directory * Add destination parameter to extract_data_paths_from_zip * Add missing Returns sections to docstrings * Add sequential fitting infrastructure with CSV output * Unify plot_param_series to read from CSV with snapshot fallback * Add multiprocessing support to fit_sequential * Write results.csv from existing single-fit mode * Add apply_params_from_csv for dataset replay * Prevent spawn re-import of __main__ in parallel fit_sequential * Support negative indexing and force recalc in apply_params_from_csv * Add extract_project_from_zip helper function * Refactor extract_project_from_zip call to use zip_path variable * Refactor notebook cell IDs and update project loading process * Remove CSV writing from fit() to fix sequential crash recovery * Fix extract_project_from_zip to find project.cif from zip contents
1 parent 2ab2f04 commit 9346188

57 files changed

Lines changed: 3852 additions & 851 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

β€Ž.github/copilot-instructions.mdβ€Ž

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@
4242
and UPPER_SNAKE_CASE for constants.
4343
- Use `from __future__ import annotations` in every module.
4444
- Type-annotate all public function signatures.
45-
- Docstrings on all public classes and methods (numpy style).
45+
- Docstrings on all public classes and methods (numpy style). These must
46+
include sections Parameters, Returns and Raises, where applicable.
4647
- Prefer flat over nested, explicit over clever.
4748
- Write straightforward code; do not add defensive checks for unlikely
4849
edge cases.
@@ -147,6 +148,8 @@
147148
`docs/architecture/architecture.md`.
148149
- After changes, run linting and formatting fixes with `pixi run fix`.
149150
Do not check what was auto-fixed, just accept the fixes and move on.
151+
Then, run linting and formatting checks with `pixi run check` and
152+
address any remaining issues until the code is clean.
150153
- After changes, run unit tests with `pixi run unit-tests`.
151154
- After changes, run integration tests with
152155
`pixi run integration-tests`.

β€Ždocs/architecture/architecture.mdβ€Ž

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ GuardedBase
188188
└── GenericDescriptorBase # name, value (validated via AttributeSpec), description
189189
β”œβ”€β”€ GenericStringDescriptor # _value_type = DataTypes.STRING
190190
└── GenericNumericDescriptor # _value_type = DataTypes.NUMERIC, + units
191-
└── GenericParameter # + free, uncertainty, fit_min, fit_max, constrained, uid
191+
└── GenericParameter # + free, uncertainty, fit_min, fit_max, constrained
192192
```
193193

194194
CIF-bound concrete classes add a `CifHandler` for serialisation:
@@ -714,12 +714,13 @@ Projects are saved as a directory of CIF files:
714714
```shell
715715
project_dir/
716716
β”œβ”€β”€ project.cif # ProjectInfo
717-
β”œβ”€β”€ analysis.cif # Analysis settings
718717
β”œβ”€β”€ summary.cif # Summary report
719718
β”œβ”€β”€ structures/
720719
β”‚ └── lbco.cif # One file per structure
721-
└── experiments/
722-
└── hrpt.cif # One file per experiment
720+
β”œβ”€β”€ experiments/
721+
β”‚ └── hrpt.cif # One file per experiment
722+
└── analysis/
723+
└── analysis.cif # Analysis settings
723724
```
724725

725726
### 7.3 Verbosity
@@ -919,6 +920,10 @@ project.experiments['xray_pdf'].peak_profile_type = 'gaussian-damped-sinc'
919920
- `DatablockItem` = one CIF `data_` block, `DatablockCollection` = set
920921
of blocks.
921922
- `CategoryItem` = one CIF category, `CategoryCollection` = CIF loop.
923+
- **Free-flag encoding**: A parameter's free/fixed status is encoded in
924+
CIF via uncertainty brackets. `3.89` = fixed, `3.89(2)` = free with
925+
esd, `3.89()` = free without esd. There is no separate list of free
926+
parameters; the brackets are the single source of truth.
922927

923928
### 9.2 Immutability of Experiment Type
924929

β€Ždocs/architecture/issues_closed.mdβ€Ž

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,56 @@ Issues that have been fully resolved. Kept for historical reference.
44

55
---
66

7+
## Implement `Project.load()`
8+
9+
**Resolution:** implemented `Project.load(dir_path)` as a classmethod
10+
that reads `project.cif`, `structures/*.cif`, `experiments/*.cif`, and
11+
`analysis/analysis.cif` (with fallback to `analysis.cif` at root for
12+
backward compatibility). Reconstructs the full project state including
13+
alias parameter references via `_resolve_alias_references()`.
14+
Integration tests verify save β†’ load β†’ parameter comparison and save β†’
15+
load β†’ fit β†’ χ² comparison. Also used by `fit_sequential` workers to
16+
reconstruct projects from CIF strings.
17+
18+
---
19+
20+
## Eliminate Dummy `Experiments` Wrapper in Single-Fit Mode
21+
22+
**Resolution:** refactored `Fitter.fit()` and `_residual_function()` to
23+
accept `experiments: list[ExperimentBase]` instead of requiring an
24+
`Experiments` collection. `Analysis.fit()` passes
25+
`experiments_list = [experiment]` in single-fit mode and
26+
`list(experiments.values())` in joint-fit mode. Removed the
27+
`object.__setattr__` hack that forced `_parent` on the dummy wrapper.
28+
29+
---
30+
31+
## Replace UID Map with Direct References and Auto-Apply Constraints
32+
33+
**Resolution:** eliminated `UidMapHandler` and random UID generation
34+
from parameters entirely. Aliases now store a direct object reference to
35+
the parameter (`Alias._param_ref`) instead of a random UID string.
36+
`ConstraintsHandler.apply()` uses the direct reference β€” no map lookup.
37+
For CIF serialisation, `Alias._param_unique_name` stores the parameter's
38+
deterministic `unique_name`. `_minimizer_uid` now returns
39+
`unique_name.replace('.', '__')` instead of a random string.
40+
41+
Also added `enable()`/`disable()` on `Constraints` with auto-enable on
42+
`create()`, replacing the manual `apply_constraints()` call.
43+
`Analysis._update_categories()` now always syncs handler state from the
44+
current aliases and constraints when `constraints.enabled` is `True`,
45+
eliminating stale-state bugs (former issue #4). `_set_value_constrained`
46+
bypasses validation like `_set_value_from_minimizer` since constraints
47+
run inside the minimiser loop. `Analysis.fit()` calls
48+
`_update_categories()` before collecting free parameters so that
49+
constrained parameters are correctly excluded.
50+
51+
API change: `aliases.create(label=..., param_uid=...uid)` β†’
52+
`aliases.create(label=..., param=...)`. `apply_constraints()` removed;
53+
`constraints.create()` auto-enables.
54+
55+
---
56+
757
## Dirty-Flag Guard Was Disabled
858

959
**Resolution:** added `_set_value_from_minimizer()` on

β€Ždocs/architecture/issues_open.mdβ€Ž

Lines changed: 15 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -10,25 +10,6 @@ needed.
1010

1111
---
1212

13-
## 1. πŸ”΄ Implement `Project.load()`
14-
15-
**Type:** Completeness
16-
17-
`save()` serialises all components to CIF files but `load()` is a stub
18-
that raises `NotImplementedError`. Users cannot round-trip a project.
19-
20-
**Why first:** this is the highest-severity gap. Without it the save
21-
functionality is only half useful β€” CIF files are written but cannot be
22-
read back. Tutorials that demonstrate save/load are blocked.
23-
24-
**Fix:** implement `load()` that reads CIF files from the project
25-
directory and reconstructs structures, experiments, and analysis
26-
settings.
27-
28-
**Depends on:** nothing (standalone).
29-
30-
---
31-
3213
## 2. 🟑 Restore Minimiser Variant Support
3314

3415
**Type:** Feature loss + Design limitation
@@ -83,31 +64,6 @@ exactly match `project.experiments.names`.
8364

8465
---
8566

86-
## 4. πŸ”΄ Refresh Constraint State Before Automatic Updates and Fitting
87-
88-
**Type:** Correctness
89-
90-
`ConstraintsHandler` is only synchronised from `analysis.aliases` and
91-
`analysis.constraints` when the user explicitly calls
92-
`project.analysis.apply_constraints()`. The normal fit / serialisation
93-
path calls `constraints_handler.apply()` directly, so newly added or
94-
edited aliases and constraints can be ignored until that manual sync
95-
step happens.
96-
97-
**Why high:** this produces silently incorrect results. A user can
98-
define constraints, run a fit, and believe they were applied when the
99-
active singleton still contains stale state from a previous run or no
100-
state at all.
101-
102-
**Fix:** before any automatic constraint application, always refresh the
103-
singleton from the current `Aliases` and `Constraints` collections. The
104-
sync should happen inside `Analysis._update_categories()` or inside the
105-
constraints category itself, not only in a user-facing helper method.
106-
107-
**Depends on:** nothing.
108-
109-
---
110-
11167
## 5. 🟑 Make `Analysis` a `DatablockItem`
11268

11369
**Type:** Consistency
@@ -150,24 +106,6 @@ effectively fixed after experiment creation.
150106

151107
---
152108

153-
## 7. 🟑 Eliminate Dummy `Experiments` Wrapper in Single-Fit Mode
154-
155-
**Type:** Fragility
156-
157-
Single-fit mode creates a throw-away `Experiments` collection per
158-
experiment, manually forces `_parent` via `object.__setattr__`, and
159-
passes it to `Fitter`. This bypasses `GuardedBase` parent tracking and
160-
is fragile.
161-
162-
**Fix:** make `Fitter.fit()` accept a list of experiment objects (or a
163-
single experiment) instead of requiring an `Experiments` collection. Or
164-
add a `fit_single(experiment)` method.
165-
166-
**Depends on:** nothing, but simpler after issue 5 (Analysis refactor)
167-
clarifies the fitting orchestration.
168-
169-
---
170-
171109
## 8. 🟑 Add Explicit `create()` Signatures on Collections
172110

173111
**Type:** API safety
@@ -339,21 +277,18 @@ re-derivable default.
339277

340278
## Summary
341279

342-
| # | Issue | Severity | Type |
343-
| --- | ------------------------------------------ | -------- | ----------------------- |
344-
| 1 | Implement `Project.load()` | πŸ”΄ High | Completeness |
345-
| 2 | Restore minimiser variants | 🟑 Med | Feature loss |
346-
| 3 | Rebuild joint-fit weights | 🟑 Med | Fragility |
347-
| 4 | Refresh constraint state before auto-apply | πŸ”΄ High | Correctness |
348-
| 5 | `Analysis` as `DatablockItem` | 🟑 Med | Consistency |
349-
| 6 | Restrict `data_type` switching | πŸ”΄ High | Correctness/Data safety |
350-
| 7 | Eliminate dummy `Experiments` | 🟑 Med | Fragility |
351-
| 8 | Explicit `create()` signatures | 🟑 Med | API safety |
352-
| 9 | Future enum extensions | 🟒 Low | Design |
353-
| 10 | Unify update orchestration | 🟒 Low | Maintainability |
354-
| 11 | Document `_update` contract | 🟒 Low | Maintainability |
355-
| 12 | CIF round-trip integration test | 🟒 Low | Quality |
356-
| 13 | Suppress redundant dirty-flag sets | 🟒 Low | Performance |
357-
| 14 | Finer-grained change tracking | 🟒 Low | Performance |
358-
| 15 | Validate joint-fit weights | 🟑 Med | Correctness |
359-
| 16 | Persist per-experiment `calculator_type` | 🟑 Med | Completeness |
280+
| # | Issue | Severity | Type |
281+
| --- | ---------------------------------------- | -------- | ----------------------- |
282+
| 2 | Restore minimiser variants | 🟑 Med | Feature loss |
283+
| 3 | Rebuild joint-fit weights | 🟑 Med | Fragility |
284+
| 5 | `Analysis` as `DatablockItem` | 🟑 Med | Consistency |
285+
| 6 | Restrict `data_type` switching | πŸ”΄ High | Correctness/Data safety |
286+
| 8 | Explicit `create()` signatures | 🟑 Med | API safety |
287+
| 9 | Future enum extensions | 🟒 Low | Design |
288+
| 10 | Unify update orchestration | 🟒 Low | Maintainability |
289+
| 11 | Document `_update` contract | 🟒 Low | Maintainability |
290+
| 12 | CIF round-trip integration test | 🟒 Low | Quality |
291+
| 13 | Suppress redundant dirty-flag sets | 🟒 Low | Performance |
292+
| 14 | Finer-grained change tracking | 🟒 Low | Performance |
293+
| 15 | Validate joint-fit weights | 🟑 Med | Correctness |
294+
| 16 | Persist per-experiment `calculator_type` | 🟑 Med | Completeness |

0 commit comments

Comments
Β (0)