homodyne.core.homodyne_model¶
The homodyne_model module provides HomodyneModel — the unified model
facade used by both NLSQ and CMC optimization backends. It wraps configuration
parsing, physics factor pre-computation, and time grid construction into a
single stateful object that feeds into compute_g2_scaled_with_factors().
Note
HomodyneModel is the recommended entry point for computing correlation
matrices from a YAML configuration. It validates the config once during
__init__, pre-computes physics factors (q²dt/2, qLdt/2π), and
builds time grids — so repeated calls to compute_c2() skip all setup
overhead.
HomodyneModel¶
- class homodyne.core.homodyne_model.HomodyneModel[source]
Bases:
objectHybrid architecture wrapper for homodyne XPCS analysis.
This class combines the robustness of stateful object-oriented design with the performance of functional JAX programming. It:
Stores configuration (dt, q, L) as instance state
Pre-computes physics factors once at initialization
Provides high-level methods that use stored state
Calls JIT-compiled functional cores for performance
Benefits¶
Robustness: Configuration validated once at initialization
Performance: Physics factors pre-computed, JIT-compiled cores
Usability: Simple API, no dt parameter passing needed
Safety: No dt estimation errors possible
Efficiency: Factors computed once, reused for all calculations
- physics_factors
Pre-computed physics factors (q²dt/2, qLdt/2π)
- Type:
PhysicsFactors
- time_array
Time array for correlation calculations [s]
- Type:
jnp.ndarray
- t1_grid, t2_grid
2D time grids for correlation matrices
- Type:
jnp.ndarray
- model
Underlying physics model (for backward compatibility)
- Type:
homodyne.core.models.CombinedModel
- dt
Time step [s]
- Type:
- wavevector_q
Scattering wave vector magnitude [Å⁻¹]
- Type:
- stator_rotor_gap
Sample-detector distance [Å]
- Type:
- analysis_mode
Analysis mode (“static”, “laminar_flow”)
- Type:
Examples
Basic usage:
>>> model = HomodyneModel(config) >>> c2 = model.compute_c2(params, phi_angles)
With plotting:
>>> model.plot_simulated_data(params, phi_angles, output_dir="./results")
Access configuration:
>>> print(model.config_summary) >>> print(f"dt = {model.dt} s") >>> print(f"Pre-computed factors: {model.physics_factors}")
- __init__(config)[source]
Initialize HomodyneModel from configuration dictionary.
- Parameters:
config (
dict) –Homodyne configuration dictionary with structure:
{ 'analyzer_parameters': { 'temporal': {'dt': float, 'start_frame': int, 'end_frame': int}, 'scattering': {'wavevector_q': float}, 'geometry': {'stator_rotor_gap': float} }, 'analysis_settings': {...} # Optional }
- Raises:
KeyError – If required configuration keys are missing
ValueError – If configuration values are invalid
- compute_c2(params, phi_angles, contrast=0.5, offset=1.0)[source]
Compute C2 correlation function using stored configuration.
This high-level method: - Uses pre-computed time grids (self.t1_grid, self.t2_grid) - Uses pre-computed physics factors (self.physics_factors) - Calls JIT-compiled functional core for performance - Returns C2 for all phi angles
NO dt parameter needed - uses stored configuration!
- Parameters:
params (
ndarray) – Physical parameters: - For laminar_flow (7 params): [D0, alpha, D_offset, gamma_dot_t0, beta, gamma_dot_t_offset, phi0] - For static (3 params): [D0, alpha, D_offset]phi_angles (
ndarray) – Scattering angles [degrees], shape (n_phi,)contrast (
float) – Contrast parameter (β in literature)offset (
float) – Baseline offset
- Returns:
C2 correlation matrices, shape (n_phi, n_time, n_time)
- Return type:
Examples
>>> model = HomodyneModel(config) >>> params = np.array([100.0, 0.0, 10.0, 1e-4, 0.0, 0.0, 0.0]) >>> phi_angles = np.array([0, 30, 45, 60, 90]) >>> c2 = model.compute_c2(params, phi_angles) >>> print(c2.shape) # (5, 100, 100) for 5 angles, 100 time points
- compute_c2_single_angle(params, phi, contrast=0.5, offset=1.0)[source]
Compute C2 correlation function for a single angle.
Convenience method for single-angle calculations.
- plot_simulated_data(params, phi_angles, output_dir='./simulated_data', contrast=0.5, offset=1.0, generate_plots=True)[source]
Generate and optionally plot simulated C2 data.
This convenience method: 1. Computes C2 using stored configuration 2. Optionally generates heatmap plots for each angle 3. Saves data to NumPy file 4. Returns both data and output path
- Parameters:
- Returns:
(c2_data, output_path) - c2_data: Computed correlation matrices - output_path: Path to saved data file
- Return type:
Examples
>>> model = HomodyneModel(config) >>> c2_data, output_path = model.plot_simulated_data( ... params, phi_angles, output_dir="./results" ... ) >>> print(f"Data saved to: {output_path}")
- property config_summary: dict
Get configuration summary for logging/debugging.
- Returns:
Configuration summary with all key parameters
- Return type:
Architecture¶
HomodyneModel sits between configuration and optimization:
YAML → ConfigManager → HomodyneModel → NLSQ / CMC
│
├── physics_factors (pre-computed q²dt/2, qLdt/2π)
├── t1_grid, t2_grid (2-D time meshgrids)
└── compute_c2() → compute_g2_scaled_with_factors()
The model delegates actual physics to the JIT-compiled functions in
homodyne.core.theory and jax_backend, ensuring that the hot path
(Jacobian evaluation in NLSQ, leapfrog steps in NUTS) never re-parses
configuration or recomputes static factors.
Key Attributes¶
Attribute |
Type |
Description |
|---|---|---|
|
|
Pre-computed factors |
|
|
1-D time grid |
|
|
2-D correlation time grids (shape |
|
|
Time step [s] from config |
|
|
Scattering wave-vector magnitude [Å⁻¹] |
|
|
Sample-detector gap [Å] |
|
|
|
Usage Examples¶
Computing correlation matrices¶
from homodyne.core.homodyne_model import HomodyneModel
import numpy as np
config = {
"analysis_mode": "laminar_flow",
"analyzer_parameters": {
"temporal": {"dt": 0.001, "start_frame": 0, "end_frame": 99},
"scattering": {"wavevector_q": 0.01},
"geometry": {"stator_rotor_gap": 2_000_000.0},
},
}
model = HomodyneModel(config)
# 7-parameter laminar_flow vector
params = np.array([19231.0, 1.5, 0.1, 0.003, 0.8, 0.0, 0.0])
phi_angles = np.array([0.0, np.pi / 4, np.pi / 2])
c2 = model.compute_c2(params, phi_angles, contrast=0.5, offset=1.0)
print(f"C2 shape: {c2.shape}") # (3, 100, 100)
Generating simulated data¶
c2_data, output_path = model.plot_simulated_data(
params, phi_angles, output_dir="./simulated"
)
# Saves compressed .npz and per-angle heatmap PNGs