Homodyne Package Overview

Learning Objectives

By the end of this section you will understand:

  • What homodyne does and what it does not do

  • Key design decisions (JAX-first, CPU-only, two optimization methods)

  • The supported analysis modes and their differences

  • How homodyne fits into the broader XPCS analysis ecosystem

What Homodyne Does

Homodyne is a Python package for fitting two-time correlation functions measured in homodyne XPCS experiments. Given experimental \(C_2(t_1, t_2)\) data as input, it returns estimates of the physical parameters governing particle dynamics—diffusion coefficients, shear rates, and related quantities.

The package solves the inverse problem: given measured correlations, find the parameter values that best explain the data.

Supported analyses:

  • Static mode: diffusion coefficient \(D_0\), anomalous exponent \(\alpha\), diffusion offset \(D_\text{offset}\) — 3 free parameters

  • Laminar flow mode: all static parameters plus shear rate \(\dot\gamma_0\), shear exponent \(\beta\), shear offset \(\dot\gamma_\text{offset}\), angular offset \(\phi_0\) — 7 free parameters

  • Per-angle scaling: optional per-angle contrast and offset corrections (adds 0, 2, or 2×n_phi parameters depending on mode)

Two optimization methods are provided:

  • NLSQ (primary): trust-region nonlinear least squares — fast, reliable

  • CMC (secondary): Consensus Monte Carlo with NumPyro/NUTS — full Bayesian posterior with uncertainty quantification

What Homodyne Does Not Do

Understanding the package boundaries helps avoid misuse:

Not in scope

What to use instead

Raw detector data reduction (pixel masking, flat-field)

Beamline-specific software (pynx, pyFAI, xi-cam)

Computing \(C_2\) from raw intensity frames

XPCS reduction pipelines (e.g., pyxpcs, multitau). The \(C_2\) array must already be computed before calling homodyne.

GPU acceleration

By design: CPU-only for reproducibility on HPC batch nodes

Heterodyne (XSVS, XCCA) analysis

Different model equations not yet implemented

Multi-angle or multi-q simultaneous fitting

Each q-value is fitted independently

Key Design Decisions

JAX-first computation

All numerical computations use JAX, which provides:

  • JIT compilation of compute-intensive loops to native CPU code

  • Automatic differentiation for Jacobian computation

  • Functional programming style that avoids global state

  • Reproducible results through explicit random seeds

CPU-only architecture

Homodyne targets CPU execution rather than GPU. This is a deliberate choice:

  • XPCS datasets fit comfortably in CPU RAM (typically 1–100 GB)

  • CPU clusters (HPC batch nodes) are universally available

  • CPU execution avoids CUDA versioning and driver dependency issues

  • NumPyro’s multiprocessing backend distributes chains across CPU cores efficiently

Two-method strategy

Method

Best For

Limitations

Speed

NLSQ

Initial exploration, production runs, large datasets

Point estimates only; uncertainty via covariance approximation

Fast (seconds to minutes)

CMC

Publication results, multi-modal posteriors, uncertainty propagation

Slower; requires NLSQ warm-start for best results

Minutes to hours

The recommended workflow is: NLSQ first for rapid exploration, CMC for publication-quality uncertainty quantification.

No silent data loss

Homodyne enforces strict validation at all I/O boundaries:

  • Shape, dtype, NaN, and monotonicity checks on input data

  • Explicit errors on invalid configurations

  • No silent downsampling or truncation of data

  • All parameter bounds are enforced

Package Architecture

The package is organized into focused modules:

homodyne/
├── core/               # Physics engine (JAX)
│   ├── jax_backend.py      # JIT-compiled C2 computations (NLSQ path)
│   ├── physics_cmc.py      # Element-wise model (CMC path)
│   ├── physics.py          # Constants, bounds, validation
│   ├── models.py           # DiffusionModel, ShearModel, CombinedModel
│   ├── theory.py           # g1, g2 analytical expressions
│   └── homodyne_model.py   # Unified model interface
├── optimization/
│   ├── nlsq/               # Primary: trust-region L-M optimizer
│   │   ├── core.py             # fit_nlsq_jax() entry point
│   │   ├── adapter.py          # NLSQAdapter (CurveFit class)
│   │   ├── wrapper.py          # NLSQWrapper (full features)
│   │   └── cmaes_wrapper.py    # CMA-ES global optimization
│   └── cmc/                # Secondary: Consensus Monte Carlo
│       ├── core.py             # fit_mcmc_jax() entry point
│       ├── model.py            # NumPyro probabilistic models
│       ├── sampler.py          # SamplingPlan, NUTS execution
│       └── backends/           # multiprocessing, pjit backends
├── data/               # HDF5 loading (XPCSDataLoader)
├── config/             # YAML config (ConfigManager)
├── cli/                # Command-line interface
└── device/             # CPU/NUMA configuration

Data Flow

A complete analysis pipeline:

YAML config
    |
    v
ConfigManager()                # Parse and validate configuration
    |
    v
XPCSDataLoader.load_experimental_data()  # Load HDF5 data, validate arrays
    |
    v
fit_nlsq_jax(data, config)     # Trust-region NLSQ optimization
    |                          # Returns OptimizationResult
    v
fit_mcmc_jax(data, config,     # Optional: Bayesian CMC
    nlsq_result=result)        # Returns CMCResult with posteriors
    |
    v
Result saved as JSON + NPZ     # Persistent output

Comparison with Other XPCS Analysis Tools

Package

Scope

Backend

Mode

Uncertainty

homodyne

C2 model fitting

JAX/CPU

Static + shear

NLSQ + Bayesian

pyxpcs

Data reduction + g2

NumPy

g2 only

None

lmfit

General curve fitting

SciPy

User-defined

NLSQ only

emcee

General Bayesian

NumPy

User-defined

MCMC

Homodyne is specialized for the XPCS two-time correlation fitting problem. It is not a general fitting framework.

Installation

# Install with uv (recommended)
uv sync

# Or with pip
pip install homodyne

# Verify installation
homodyne --help
homodyne-config --help

After installation, set up shell completion and aliases:

homodyne-post-install
# Then reload your shell: source ~/.zshrc  or  exec $SHELL

Version Information

import homodyne
print(homodyne.__version__)

# Check optimization backend availability
from homodyne.optimization import OPTIMIZATION_STATUS
print(OPTIMIZATION_STATUS)

See Also