Repository navigation
Releases: imewei/xpcsjax
Release list
v0.1.8
codebase-review hardening: data-integrity fixes, covariance-contract unification, dead-code cleanup
- Mode-agnostic fit-quality metric
nrmsesurfaced innlsq_diagnostics["fit_quality"]/nlsq_result.json. - Homodyne and heterodyne uncertainties now follow one covariance contract on every solve path — placeholder/singular covariance reports NaN with
covariance_is_placeholderinstead of a fabricated zero, identity, or floored value. - Data-integrity fixes: APS-U bin-skip index mislabeling, NPZ cache keyed to its source HDF5 file, homodyne angle-stratified fits no longer fit the
c2diagonal. - ~4K lines of dead code removed (
performance_engine.py,memory_managerdead methods, unreachableImportErrorfallback shims) with no numerical or CLI-facing behavior change.
Full details in CHANGELOG.md.
v0.1.7
xpcsjax v0.1.7
NLSQ floor raised to nlsq>=0.7.6 across every pin site (pyproject.toml,
.pre-commit-config.yaml, the runtime dependency check, both conda
recipes, and the docs that quote it). conda-recipe/nlsq updated to the
0.7.6 sdist; upstream changed neither the dependency set nor the
entry points, so the recipe's run deps are unchanged.
make verify now reports zero warnings (was 10): three non-actionable
upstream nlsq warnings are filtered at the narrowest honest scope.
Verified: make verify (2670 passed), strict sphinx-build -W, and
make verify-nlsq all clean at 0.1.7.
v0.1.6
[0.1.6] - 2026-08-30
Fixed
- Negative-dominant
D_offsetnow detected in physics validators. The
D_offset/D0overfitting checks only comparedratio > 0.5, missing the
symmetric case where a large-magnitude negative offset dominatesD0
(e.g.D_offset_ref/D0_ref = -0.503in a real C045two_componentfit,
implying a negative diffusion coefficient at early times). Both checks now
compareabs(ratio) > 0.5(#75). - Resolved mypy hard-gate failures on main (CI run 33300386957): explicit
type annotations for union-typed locals infallback_chain.py,
recovery.py, andvalidation.py, plus a newAngleGroupTypedDictin
chunking.pyreplacing an overly-loosedict[str, Any](#73). - Duplicate
HeterodyneModelclass name. Two unrelated classes shared
the name —core/heterodyne_model.py'sPhysicsModelBaseadapter and
core/heterodyne_model_stateful.py's public stateful model — so
from xpcsjax.core.heterodyne_model import HeterodyneModeland
from xpcsjax.core import HeterodyneModelsilently returned different
classes. Renamed the adapter toHeterodynePhysicsAdapteracross every
real call site; the publicxpcsjax.core.HeterodyneModelexport is
unaffected (#71). - Stratified-LS (>=1M point) diagonal-exclusion mask compared indices
into two independently-builtnp.unique()arrays instead of the actual
t1/t2values, wrongly zeroing real off-diagonal points and keeping
true diagonal ones (#71). - Hybrid-streaming
per_angle_mode="constant"fallback index
misalignment. In the quantile-estimation-failure fallback, L3's
regularization group indices and L4's gradient-collapse-monitor watched
indices were resolved via the literalper_angle_mode_actualstring
instead of the real 2-param[contrast_mean, offset_mean, *physical]
layout the fallback actually uses, watching the scaling head as if it
were physics (#71). coerce_finite_floatno longer silently coerces a stray YAML boolean
(e.g. a typo'dmax: true) to1.0/0.0at the shared bounds/values
validation boundary (#71).- Degenerate 1-frame Siegert-ceiling check no longer reads the excluded
tau=0diagonal spike. Thematrix.shape[1] <= 1fallback branch in
data/filtering_utils.pyanddata/validation.pyreaddiagonal[0]
into the check instead of skipping it, reintroducing the anti-pattern the
surrounding code otherwise avoids (#71). - 19 correctness gaps closed in the NLSQ fitting workflow and 6 more across
config/core/viz, found via independent step-by-step audits that traced the
NLSQ workflow anddocs/diagrams/architecture.mdagainst the real code.
Removed
- ~7800 lines of confirmed-dead code removed repo-wide (ponytail-audit).
Documentation
- Config examples across the documentation now match the shipped YAML
templates exactly — bounds format, key nesting, and the heterodyne
physics/scaling parameter layout — instead of several invented shapes
that a reader could not actually load (#70). - Theory prose terminology and notation cleaned up: dropped the "diffusion
integral" label forD(t1,t2)(referred to by symbol only, alongside
J(t)), and aligned Sphinx theory notation with the README (#69, #70).
Dependencies
nlsqbumped 0.7.1 → 0.7.4 andevosaxbumped 0.2.0 → 0.3.1 in
uv.lockand the conda recipe (conda-recipe/xpcsjax/meta.yaml); host
setuptoolsfloor raised to>=77to match evosax 0.3.1's build
requirement (#74).
v0.1.5
[0.1.5] - 2026-08-25
Added
fixed_parameters/active_parameterssupport across every NLSQ execution
tier (#55, #57, #59). A user can now freeze named physical parameters or
restrict the optimized set forNLSQWrapper.fit(),NLSQAdapter.fit(), the
CMA-ES escape, and the sequential, out-of-core, stratified-LS, and
hybrid-streaming tiers alike —resolve_optimized_physical_parameterscomputes
a single mask-based strip/restore descriptor threaded through all of them, so
the free-parameter subset stays consistent regardless of which tier a fit
dispatches to. Unknown names in either config key raiseValueErrorinstead of
silently narrowing or ignoring the request.tied_parametersis now homodyne-invalid, not silently ignored. Homodyne's
ParameterSpace/ParameterManagerhave no tie/DOF-reduction mechanism (it is
atwo_component-only feature); configuringtied_parameterson
static_anisotropic/static_isotropic/laminar_flownow raisesValueError
at construction instead of silently producing two fully independent free
parameters.- Heterodyne hybrid-streaming L2 now reports a real Hessian-based covariance
(2*sigma^2*H^-1, pseudo-inverse fallback on a singular Hessian) in place of
the previous identity placeholder, mirroring thelaminar_flowfix. Falls back
to identity withcovariance_is_placeholder=Trueonly when the Hessian itself
is non-finite.
Fixed
tied_parametersalias/canonical name collisions are now rejected, not
silently last-writer-wins, across six config-load sites: the heterodyne
_apply_tied_parameters,_apply_initial_parameters,_apply_fixed_parameters,
_apply_parameter_space_bounds, and the homodyneParameterManager's bounds
loader (#67). A config that names both a parameter's public alias (e.g.
v_beta) and its internal canonical name (beta) as separate entries — for
exampletied_parameters: {beta: v_beta, v_beta: D0_ref}— previously
collapsed to whichever entry a dict comprehension processed last, dropping one
tie/bound/fixed-value with no diagnostic; all now raiseValueErroron
collision.active_parameterstypos now raise, matchingfixed_parameters.
resolve_optimized_physical_parametersvalidatedfixed_parametersnames
strictly but had no equivalent check foractive_parameters, so a typo'd name
silently narrowed the optimized set instead of erroring.- Heterodyne stratified-LS no longer attempts a doomed OOM allocation before
falling back to the Layer-2 escape. Atper_angle_mode=individualwith
enough angles, the unconditional baselinetrfsolve's dense Jacobian sizing
didn't account for the per-angle scaling tail, so a fit that was always going
to need the hierarchical escape first tried (and failed) a multi-tens-of-GB
allocation, wasting time and logging a misleading error. A pre-flight memory
estimate now skips straight to the escape when the baseline solve would exceed
budget and the escape can pick up fromp0_fullanyway. - Cached
t1/t2arrays are now always recomputed from the currentdt
convention instead of trusted verbatim from a.npzcache. The dt
fingerprint check only fired when the cache carried dt metadata, so a
cache built by an older xpcsjax version or an external converter (no dt key)
passed silently and could desync frame-0 alignment against a cache-free run. - Scalar
per_angle_scalingcontrast/offset values are no longer dropped.
get_initial_parameters()only injected list-typed contrast/offset values,
so atwo_componentconfig writing a bare scalar (documented as equivalent to
a length-1 list) hit aKeyErrorin simulated-data plot rendering; scalars are
now normalized to length-1 lists at both injection sites. - CI stability: retry workflow hardened against starvation and
false-positive cancellations, the runner-cancellation label mismatch (GitHub
reports a runner-killed step asfailure, notcancelled) is now handled,
and the Ubuntu test matrix is sharded to cut per-shard wall time (#65, #66). NLSQAdapter's real-solve path (fit_nlsq_jax(use_adapter=True)) is
repaired._flatten_xpcs_datadidn't handle the standard raw-loader data
shape (shared 1D marginalt1/t2time vectors plus aphiarray of
unique angles), and a separate mismatch betweennlsq's own internal input
validators over 2-Dxdataorientation made every real solve through this
path fail and silently fall back toNLSQWrapper. Both are fixed; the
adapter path now completes a genuine solve.
v0.1.4
Fixed
nlsq_result.npznow carriesc2_exp/c2_fitted/residuals/t1/t2/phi_angles/wavevector_q.
save_results_npzpreviously wrote only scalars, parameters, and
covariance — the raw(n_phi, n_t1, n_t2)correlation surfaces (and the
scattering wavevector needed to interpret them) a user needs for
downstream re-analysis were only ever written to
plots/simulated_data/c2_fitted_data.npz, and only when plotting was
enabled.service/persist.py::merge_fitted_c2()now folds those
already-computed arrays into the primary NPZ (best-effort, mtime-guarded
against stale leftovers from a previous run in the same output directory)
after plotting runs, for both the CLI and the GUI worker.- Whole-codebase module-review sweep: 18 findings fixed across 12 modules
(2 confirmed HIGH blockers + 16 advisory). Highlights:ParameterSpace.from_config
crashed on a blankparameter_space:YAML section; publicxpcsjax.HeterodyneModel
resolved to the no-argPhysicsModelBaseadapter instead of the documented
stateful model used by every production heterodyne path and the test suite.
Advisory fixes span CLI persistence logging, config parameter-name aliasing,
path-traversal-check de-duplication, an OOM-risk unbounded residuals scatter
plot, and more.
v0.1.3
Fixed
- Deep-RCA whole-codebase debug audit: 21 confirmed bugs across 24 files (#49, #50). Highlights:
wrapper.py/strategies/stratified_ls.py: a DOF-correction truthiness bug understated reduced-chi2/quality_flagwhen theanti_degeneracyconfig section is absent but averaged/individual scaling is still active.heterodyne_core.py: the CMA-ES warm-start auto-skip compared raw (non noise-normalized) SSR/dof against a threshold meant for noise-normalized reduced chi2, silently defeating the global escape on genuinely poor basins; added a missing weights/data shape guard in_fit_cmaes.jax_backend.py:validate_backend()'s self-test usedjax.gradon a matrix-output function, sogradient_supportwas alwaysFalseeven on a working JAX install; fixed to usejacobian, resolving the downstream always-ImportErrorfallout inmodel_mixins.py.anti_degeneracy_controller.py: Layer 2 (HierarchicalOptimizer) was constructed mode-blind, reporting active even inaveraged/constantmode where its hard-coded individual-mode layout is unusable; construction is now gated on the resolved per-angle mode.hierarchical.py: outer-loop convergence was gated on absolute parameter change instead of the already-computed relative change, making convergence unreachable for parameters spanning 6+ orders of magnitude.adaptive_regularization.py: the CV-safe-divide fix sanitized the numerator as well as the denominator, silently changing the near-zero-mean fallback value and killing the L3 regularization penalty exactly where it is needed; corrected to sanitize only the denominator (applied to all three CV sites).strategies/sequential.py:combine_angle_resultsused a scalar per-angle weight forcombined_paramswhilecombined_covused an unmasked per-parameter inverse-variance weight, an internally inconsistent pairing; both now share the same masked/floored weight matrix.data/performance_engine.py:MultiLevelCachedisk writes were not serialized per key (unsynchronized"wb"opens race); fixed via atomic temp-file +os.replace.data/memory_manager.py:cleanup_virtual_memory()deleted files by a shared filename-prefix scan instead of tracking self-created files, risking deletion of another live instance's mmap-backed file.config.py:NLSQConfig.from_dict()crashed (instead of degrading to default) on an explicit YAMLnullfor non-Optional numeric fields.- GUI:
project_panel.py/result_presenter.pyrendered a NaN parameter with the same "—" sentinel as "run has no such parameter," silently defeating the comparison-view diff marker; both now render"NaN"distinctly. - Smaller fixes: an unguarded
end_frameKeyErrorinHeterodyneModel.from_config, an unboundedlscpusubprocess call (hang risk) indevice/cpu.py, an uncommented emptyexcept FileNotFoundErrorflagged by CodeQL, and unloggedfast_chi2_modesubsampling inout_of_core.py. - Verification: ruff clean, mypy clean (0 issues, 198 files), full suite green (2628 passed, +6 new regression tests, 0 failures).
Full Changelog: v0.1.2...v0.1.3
v0.1.2
What's Changed
- docs: modernization assessment for xpcsjax by @imewei in #6
- build: repo-level write-time Python quality gate (Plankton-equivalent) by @imewei in #7
- docs: add module map to root CLAUDE.md by @imewei in #9
- fix: bundle Pillow in the PyInstaller spec, close drift-guard gap by @imewei in #10
- docs: scaffold Matt Pocock engineering-skills config by @imewei in #8
- fix(gui): address design-critique findings on the workbench by @imewei in #11
- docs(graphify): update knowledge graph (66 files changed) by @imewei in #12
- fix(gui): resolve 6 click-path-audit state-conflict bugs + doc sync by @imewei in #13
- fix: whole-codebase debug audit — 30 confirmed bugs across 11 modules by @imewei in #14
- fix: 6 remaining debug-audit findings (NaN-q, diagonal-correction skip, fallback escalation, sigma-weighting, cmaes_seed, negative-correlation repair) by @imewei in #15
- release: bump version to 0.1.2 by @imewei in #16
- docs: add missing API pages for device/io/utils modules by @imewei in #18
- fix: codex+agy multi-tool audit — 145 confirmed bugs across all 12 modules by @imewei in #19
- test: close 4 of 5 remaining test-coverage gaps from debug-audit review by @imewei in #17
- test: close heterodyne streaming auto_tune_lambda test-coverage gap by @imewei in #21
- fix: drop extra solver-space arg from adjust_covariance_for_transforms call by @imewei in #22
- fix: silence redundant JAX_PLATFORMS warning in device.cpu by @imewei in #23
- fix: seed heterodyne multistart candidates into the frozen initial-values snapshot by @imewei in #24
- fix: don't report converged/good for a CMA-ES escape kept via refinement-only success by @imewei in #25
- chore(deps): drop scikit-learn, cloudpickle, interpax — never imported by @imewei in #26
- feat(nlsq): tied_parameters equality-constraint support for heterodyne two_component by @imewei in #27
- refactor(heterodyne): consolidate _decompose_chi2_per_angle import (TODO(C3)) by @imewei in #28
- fix: resolve CodeQL alerts #352-357 by @imewei in #29
- docs: document heterodyne tied_parameters config feature by @imewei in #30
- fix(heterodyne): correct chi2/scaling/config bugs in two_component fit path by @imewei in #31
- refactor: remove 17 dead-code symbols (graphify-guided sweep) by @imewei in #32
- fix(data): break AdvancedMemoryManager<->MemoryPressureMonitor ref cycle by @imewei in #33
- fix(core): correctness sweep across xpcsjax/core/ (6 bugs) by @imewei in #34
- fix(data): deep-RCA multi-agent audit — 12 confirmed production bugs by @imewei in #35
- fix(silent-failures): close 4 High + 9 mechanical findings from full-codebase review-pr sweep by @imewei in #36
- fix(optimization): deep-RCA multi-agent audit — 29 confirmed bugs in xpcsjax/optimization/ by @imewei in #37
- fix(optimization): close PR #37 review findings (4-agent review-pr sweep) by @imewei in #38
- fix(review): close 15 confirmed bugs from whole-codebase code-reviewer sweep by @imewei in #39
- fix(data): use with-statement for XPCSDataLoader (CodeQL #360) by @imewei in #40
- docs: add missing make test-viz to commands reference by @imewei in #41
- fix(test): skip killpg-race test on non-POSIX platforms by @imewei in #42
- fix: deep RCA sweep across optimization, io, core, data, device by @imewei in #43
- build: add conda-forge-style recipes for imewei anaconda.org channel by @imewei in #44
- docs: add conda/mamba channel install instructions by @imewei in #45
- chore: bump config-schema version to 0.1.2 by @imewei in #46
- Fix GUI fit-time warnings: param labeling, XLA flag timing by @imewei in #47
Full Changelog: v0.1.1...v0.1.2
v0.1.1
Maintenance release. No user-facing behavioural or API changes — fitting results, the public API, and config formats are identical to v0.1.0.
Changed
- System memory detection in the optimization memory-strategy layer unified and simplified into a single detection path (behaviour-preserving).
- Removed obsolete adapter metadata methods that were no longer referenced by any live path.
Internal / CI
- GitHub→GitLab mirror workflow (
wchen/xpcsjax) via.github/workflows/mirror.yml. - Repinned
pypa/gh-action-pypi-publishto a validv1.14.0commit SHA in the release workflow. - Rebuilt the graphify knowledge graph and refreshed README badges.
Publishing this release uploads the sdist + wheel to PyPI via Trusted Publishing (OIDC).
Full changelog: https://github.com/imewei/xpcsjax/blob/v0.1.1/CHANGELOG.md
v0.1.0
xpcsjax v0.1.0 — unified homodyne + heterodyne NLSQ fitting (JAX-native, NLSQ-only, float64, CPU).
Added
- Initial consolidated release. xpcsjax v0.1 ports the homodyne and
heterodyne NLSQ pipelines into a single JAX-native package. - Unified public API — seven lazy-loaded symbols:
xpcsjax.data.xpcs_loader.load_xpcs_data,
xpcsjax.optimization.nlsq.fit_nlsq,
xpcsjax.config.ConfigManager,
xpcsjax.core.HomodyneModel,
xpcsjax.core.HeterodyneModel,
xpcsjax.optimization.nlsq.results.OptimizationResult,
xpcsjax.viz.nlsq_plots.generate_nlsq_plots. - JAX-first with float64.
JAX_ENABLE_X64=1is set at package
import time; parameters span 6+ orders of magnitude and float32 is
unsafe. - Homodyne parity oracle. Characterisation tests pin xpcsjax's
homodyne output to upstreamhomodyneresults atrtol=1e-10. - Heterodyne multi-angle. Joint fitting across φ angles with
χ²-exact residuals using the per-angle scaling layoutsconstant/
individual/auto(autoresolves toaveragedatn_phi ≥ 3,
elseindividual); returns a singleOptimizationResult. - NLSQ engine split. xpcsjax owns strategy routing, the 5-layer
anti-degeneracy controller, CMA-ES escape, LHS multistart,
angle-stratified chunking, and shear weighting. NLSQ owns the
CurveFitJIT cache and the trust-region solve. - Anti-degeneracy controller with five composable layers: per-angle
reparameterisation, hierarchical optimisation, adaptive
cross-validation regularisation, gradient-collapse monitoring, and
shear-sensitivity weighting. - Memory-aware strategy selection via
xpcsjax.optimization.nlsq.select_nlsq_strategy— picks between
in-memory, hybrid-streaming, and out-of-core paths based on dataset
size and available RAM. (Angle-stratified least squares is a separate
≥1M-point dispatch path.) - Visualization module (
xpcsjax.viz) — three public plot
functions (plot_nlsq_fit3-panel comparison,plot_residual_map
4-panel diagnostic,plot_simulated_datasingle-panel theoretical
heatmap), orchestrated bygenerate_nlsq_plots. Artifacts are
serialised as LZMA-compressed NPZ + JSON under
output_dir/simulated_data/. Optional Datashader fast path (5–10×
per-call speedup; install viapip install 'xpcsjax[viz-fast]')
with transparent matplotlib fallback. Parallel multi-process
rendering viamultiprocessing.Pool(spawn).
xpcsjax.viz.diagnostics.compute_diagonal_overlay_statsextracts
the t₁ = t₂ diagonal from experimental and fitted c² surfaces. - Desktop analysis workbench (GUI) (
xpcsjax/gui/). A PySide6 graphical
front-end registered as thexpcsjax-gui/xj-guiconsole script
(xpcsjax.gui.app:main; recognises--help/--version, forwards the rest
to Qt). Config tab (form + raw-YAML + live JAX-free validation), Data tab
(h5py-only HDF5 browser + two-time C₂ preview), Fit tab, Inspector dock
(params / uncertainties / diagnostics), live-diagnostics view (SSR curve,
L1–L5 layer chips, banner log), interactive PyQtGraph plots, and a
datasets→runs project sidebar with side-by-side comparison. Sessions persist
to.xpcsprojJSON (atomic writes, per-run output dirs).
Architectural invariant: the GUI process never imports JAX — every fit
runs in a separatespawnworker (xpcsjax/gui/ipc/) that lazily imports
JAX + the service layer and streams structuredFitEvents back to the UI.
Optional install:pip install -e ".[gui]". PyInstaller freeze support via
.[packaging]+packaging/xpcsjax-gui.spec(one-dir bundle,
multiprocessing.freeze_support()first). Documentation:
docs/source/user_guide/gui.rst. - Headless core-service layer (
xpcsjax/service/). The argparse-free,
Qt-free orchestration seam shared by the CLI and the GUI worker:
service.config(JAX-freeload_config/validate_config/available_modes
/template_dict),service.events(JAX-free streamedFitEventschema),
and the worker-sideservice.data/service.fit/service.plots, plus
service.persist(result serialisation, relocated fromcli.result_saving).
Documentation:docs/source/api/service.rst. - Command-line interface (
xpcsjax/cli/). Console scripts registered in
pyproject.toml, each with anxjshort alias:xpcsjax/xj— single flat flag-driven command for NLSQ fits;
--plot-experimental-data/--plot-simulated-dataswitch to a
standalone-plot path that skips optimisation.xpcsjax-config/xj-config— generate,--show-template,
--validate, or--interactively build a YAML config from the four
mode templates.xpcsjax-config-xla/xj-config-xla— inspect/print the CPU
XLA_FLAGS.xpcsjax-validate/xj-validate— validate the installation.xpcsjax-post-install/xpcsjax-cleanup(+xj-aliases) — install
and remove shell completion + XLA activation scripts.xjexp/xjsim— plotting shortcuts (experimental QC / simulated C₂),
mirroring upstream heterodyne'shexp/hsim.
- Runtime utilities (
xpcsjax/runtime/). System validator
(xpcsjax.runtime.utils.system_validator) checking environment, dependency
versions, JAX/float64 config, and template / public-API integrity
(NLSQ-only — no Bayesian/MCMC probes), plus the bash/zsh/fish completion and
XLA activation shell assets underxpcsjax.runtime.shell. - Documentation:
docs/source/user_guide/cli.rst,docs/source/api/cli.rst,
anddocs/source/api/runtime.rst. - Heterodyne joint global escapes (parity gap C closed). The joint
CMA-ES (enable_cmaes=True) and joint multistart (multistart=True)
escapes inheterodyne_core.pyare now real global escapes over the full
[physics | scaling]vector — seed-pinned, keep-better vs. the plain NLSQ
joint fit, and best-effort fall back on failure (reusing the shared
fit_with_cmaes/run_multistart_nlsq). Escape results are tagged
nlsq_diagnostics["global_escape"]and carry NaN covariance /
uncertainties withn_iterations=0by construction. See
docs/source/theory/heterodyne_anti_degeneracy.rst. - Dedicated heterodyne logging module
(optimization/nlsq/heterodyne_logging.py). Thetwo_componentcore and
stratified-LS paths now route progress/banner logging through it for
structured-logging parity with thelaminar_flowpipeline (resolves the
multi-minute stratified-LS silence).
Changed
-
Heterodyne streaming anti-degeneracy (parity gap D closed). The
two_componentSTREAMING tier no longer freezes the quantile-estimated
per-angle scaling. It now optimizes the scaling tail (contrast + offset)
and runs L1–L4, reaching mechanism parity withlaminar_flowstreaming.
The scaling treatment is selected byanti_degeneracy_config.per_angle_mode,
with"auto"as the default — including whenanti_degeneracy_configis
absent/None(no "freeze when unconfigured" special case)."auto"
resolves toauto_averagedatn_phi ≥ constant_scaling_threshold
(default 3), elseindividual;per_angle_mode="constant"is the explicit
frozen-scaling opt-out. See
docs/source/theory/heterodyne_memory_strategy.rst. -
Symmetric anti-degeneracy diagnostics. Both
laminar_flowand
two_componentnow emit the same top-levelnlsq_diagnosticsactivation
keys (hierarchical_active,regularization_active,shear_weighting,
plusgradient_monitorwhen L4 ran) via the shared
assemble_anti_degeneracy_diagnosticsacross every dataset-size path.
shear_weightingis reported inactive for heterodyne by design (L5 is
laminar_flow-only). -
Deprecation —
analysis_modetaxonomy. The bare value
analysis_mode: staticis deprecated. It was ambiguous between
static_isotropic(angle-collapsed) andstatic_anisotropic
(angle-resolved) and silently collapsed downstream. The canonical set
is now exactly four modes:static_isotropicstatic_anisotropiclaminar_flowtwo_component(withheterodyneaccepted as a case-insensitive
synonym, normalised totwo_componentat config load time)
ConfigManager._normalize_analysis_modestill accepts the legacy bare
value but rewrites it tostatic_anisotropic(the drop-in replacement
that preserves angle resolution) and emits a deprecation warning at
config-load time. Migrate old configs to one of the canonical modes to
silence the warning.See
docs/source/user_guide/analysis_modes.rstfor the full mode
reference.
Removed
- Per-angle-mode unification (Phase 7) — the
fourierper-angle scaling
mode is gone. Bothlaminar_flowandtwo_componentnow expose a single
canonical vocabulary of three per-angle scaling layouts —constant,
averaged, andindividual(resolved from theautodefault) — across all
eight execution paths. The Fourier-reparameterized scaling tail and its
independentsibling were deleted along with the
optimization/nlsq/fourier_reparam.pymodule, theFourierReparameterizer
class, thefourier_order/fourier_auto_thresholdconfig keys (all four
mode templates plus the homodyne and heterodyne config dataclasses), and the
fourier_basis_dimdiagnostics key. Breaking: configs that set
per_angle_mode: fourier(orindependent) are rejected at resolve time —
useindividualfor free per-angle scaling oraveragedfor the
angularly-averaged two-DOF tail. Verified no-worse-SSR on the laminar
CMA-ES / stratified / streaming paths; the homodynertol=1e-10parity
baselines were regenerated against explicitindividual. - Dead-code cleanup — removed code that was unreachable, superseded, or
never wired into the ...