Repository navigation
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 NLSQ pipeline. No behavioural change; verified by the
full suite (1253 passed, 8 skipped).xpcsjax/core/theory.py— the unusedTheoryEnginemodule, ported
verbatim from homodyne but never imported by any live path.- Deprecated streaming shims in
optimization/nlsq/strategies/hybrid_streaming.py
(fit_with_streaming_optimizer_deprecated,
fit_with_streaming_optimizer_stratified_deprecated) together with their
only (also dead) callerNLSQWrapper._fit_with_streaming_optimizer. StratifiedResidualFunction._compute_chunk_residuals_raw— raised
RuntimeErroron call; the live path is_call_jax_vectorized.- The duplicate
compute_g2_scaled_with_factorsin
core/physics_nlsq.py(the live copy lives incore/jax_backend.py). - Unused symbols
NLSQCheckpointError,FallbackInfo,
cli/xla_config.auto_configure,
heterodyne_parameter_names.get_param_index, and the module-level
heterodyne_parameter_space.clamp_to_open_interval. - The dangling
xpcsjax.core.theorySphinx autodoc stub in
docs/source/api/modules.rst.
Fixed
- Removed dangling Sphinx autodoc reference to
xpcsjax.config.parameter_space.PriorDistribution(the class was
deleted during the Phase-7 CMC cleanup but the autodoc directive
survived, producing a build warning). - Per-angle heterodyne CMA-ES escape now honours its config.
_fit_cmaes
previously droppedseed(non-reproducible),cmaes_warmstart_auto_skip/
*_skip_threshold(paid for a full global search even when the NLSQ
warm-start was already good), andcmaes_sigma0(always used step0.5).
Each angle is now seed-pinned (_PER_ANGLE_CMAES_SEED + angle_idx), skips
below threshold, and threadssigma0through — and tags
metadata["global_escape"]for diagnostics-contract symmetry with the
joint escapes. - Heterodyne joint global escapes honour the resolved per-angle scaling
mode instead of forcing Fourier —effective_modeis resolved before the
global-escape gate, so enabling CMA-ES / multistart never changes the
scaling layout (auto → averagedatn_phi ≥ 3, elseindividual). - Flow-parameter units corrected in
ParameterRegistry:gamma_dotand
v_offsetwere labellednm/frame; the physically correct unit isÅ/s
(metadata-only — bounds, defaults, and log-space flags unchanged). - Noise-normalized stratified-LS reduced χ².
build_hybrid_streaming_resultnow computesSSR / (σ²_noise · dof)(the
driver threads an estimated far-lag photon-noise variance via
info["sigma2_noise"]) instead of rawSSR/dof, which collapsed to
~0.0024 on normalized C₂ data and mislabelled fits as "good". - Heterodyne visualization reads physics-first parameters. Heterodyne
result.parametersis laid out[physics | contrast | offset](vs.
homodyne's scaling-first layout); the viz unpackers and uncertainty
slicing now use the heterodyne layout, fixing a C044 fitted-C₂ heatmap that
rendered ~1e6. - Robustness guards against non-finite values and a JIT-cache thread race
on the heterodyne paths.
Documentation
- Added
make docstarget that runs Sphinx with-W(warnings treated
as errors), so dangling autodoc references and broken cross-refs fail
the build instead of accumulating silently. Wired intomake ci-full. - Reconciled the
api/modules.rst"All modules" page with the live package:
removed the deletedxpcsjax.core.heterodyne_physics, registered the
modules added since (CLI, runtime, viz, and the new heterodyne NLSQ
modules), and fixed stale:mod:/:func:/:class:cross-references in the
user-guide and theory pages so the strict-Wbuild is warning-clean.
Out of scope (v0.x series)
- Bayesian sampling — NumPyro, BlackJAX, NUTS, HMC, CMC (Consensus
Monte Carlo), ArviZ, parallel tempering. Use the upstreamhomodyne
/heterodynepackages for Bayesian XPCS analysis. - GPU support. v0.1 sets
NLSQ_SKIP_GPU_CHECK=1and runs CPU-only;
GPU paths are planned for v0.2+.
Full changelog: CHANGELOG.md