torchref.refinement.targets.difference module
- class torchref.refinement.targets.difference.DifferenceXrayTarget(dataset_collection=None, data_light=None, data_dark=None, model_light=None, model_dark=None, scaler_light=None, scaler_dark=None, use_work_set=True, verbose=0)[source]
Bases:
TargetTarget for time-resolved crystallography comparing light/dark states.
Computes difference structure factors and compares against observed differences:
ΔF_calc = |F_light_calc| - |F_dark_calc|
ΔF_obs = F_light_obs - F_dark_obs
Uses Gaussian NLL with proper error propagation:
σ_diff = sqrt(σ_light² + σ_dark²)
NLL = 0.5 * (ΔF_obs - ΔF_calc)² / σ_diff² + log(σ_diff) + 0.5*log(2π)
Supports two initialization modes:
DatasetCollection mode (recommended): Pass a DatasetCollection with pre-aligned datasets. This is more efficient and ensures consistency with other targets using the same data.
Separate datasets mode: Pass individual ReflectionData objects. HKL matching is performed automatically.
- Parameters:
dataset_collection (DatasetCollection, optional) – Collection containing ‘dark’ and ‘light’ datasets (pre-aligned HKL). If provided, data_light and data_dark are ignored.
data_light (ReflectionData, optional) – Reflection data for the light (excited) state.
data_dark (ReflectionData, optional) – Reflection data for the dark (ground) state.
model_light (ModelFT or MixedModel) – Model for the light state structure factor calculation.
model_dark (ModelFT) – Model for the dark state structure factor calculation.
scaler_light (ScalerBase, optional) – Scaler for the light state F_calc. Can be shared with other targets.
scaler_dark (ScalerBase, optional) – Scaler for the dark state F_calc. Can be shared with other targets.
use_work_set (bool, optional) – If True, compute loss on work set. Default is True.
verbose (int, optional) – Verbosity level. Default is 0.
Examples
Using DatasetCollection (recommended for sharing scalers):
# Create collection with aligned HKL collection = DatasetCollection() collection.add_dataset('dark', data_dark, set_as_reference=True) collection.add_dataset('light', data_light) # Create shared scalers scaler_dark = IsotropicScaler(data=collection['dark'], model=model_dark) scaler_light = IsotropicScaler(data=collection['light'], model=model_mixed) # Create targets that share scalers xray_dark = GaussianXrayTarget( data=collection['dark'], model=model_dark, scaler=scaler_dark ) xray_light = GaussianXrayTarget( data=collection['light'], model=model_mixed, scaler=scaler_light ) diff_target = DifferenceXrayTarget( dataset_collection=collection, model_light=model_mixed, model_dark=model_dark, scaler_light=scaler_light, scaler_dark=scaler_dark, ) # Combined loss loss = xray_dark() + xray_light() + diff_target()
Using separate datasets:
diff_target = DifferenceXrayTarget( data_light=data_light, data_dark=data_dark, model_light=model_light, model_dark=model_dark, ) loss = diff_target()
With mixed model for partial occupancy:
mixed_light = MixedModel([model_dark, model_light], [0.7, 0.3]) diff_target = DifferenceXrayTarget( dataset_collection=collection, model_light=mixed_light, model_dark=model_dark, scaler_light=scaler_light, scaler_dark=scaler_dark, )
- __init__(dataset_collection=None, data_light=None, data_dark=None, model_light=None, model_dark=None, scaler_light=None, scaler_dark=None, use_work_set=True, verbose=0)[source]
Initialize DifferenceXrayTarget.
- property dataset_collection
DatasetCollection if using collection mode.
- property data_light: ReflectionData
Light state reflection data.
- property data_dark: ReflectionData
Dark state reflection data.
- property hkl: Tensor
Common HKL indices for both datasets.
Returns the aligned HKL from DatasetCollection if available, otherwise the matched HKL computed from separate datasets.
- get_delta_F_calc(fcalc_light=None, fcalc_dark=None, recalc=False)[source]
Compute calculated difference structure factors.
ΔF_calc = |F_light_calc| - |F_dark_calc|
- Parameters:
fcalc_light (torch.Tensor, optional) – Pre-computed light state structure factors.
fcalc_dark (torch.Tensor, optional) – Pre-computed dark state structure factors.
recalc (bool, optional) – Force recalculation if True. Default is False.
- Returns:
ΔF_calc for all reflections (full size, use mask from get_delta_F_obs).
- Return type:
- forward(fcalc_light=None, fcalc_dark=None, recalc=False)[source]
Compute Gaussian NLL loss for difference structure factors.
NLL = 0.5 * (ΔF_obs - ΔF_calc)² / σ_diff² + log(σ_diff) + 0.5*log(2π)
- Parameters:
fcalc_light (torch.Tensor, optional) – Pre-computed light state structure factors.
fcalc_dark (torch.Tensor, optional) – Pre-computed dark state structure factors.
recalc (bool, optional) – Force recalculation if True. Default is False.
- Returns:
Mean NLL loss value.
- Return type:
- stats(fcalc_light=None, fcalc_dark=None)[source]
Get statistics for difference refinement.
- Parameters:
fcalc_light (torch.Tensor, optional) – Pre-computed light state structure factors.
fcalc_dark (torch.Tensor, optional) – Pre-computed dark state structure factors.
- Returns:
Statistics dict with correlation, R_diff, etc.
- Return type:
- class torchref.refinement.targets.difference.PhaseInformedDifferenceTarget(dataset_collection, model_light=None, model_dark=None, scaler_light=None, scaler_dark=None, phase_source='difference', use_work_set=True, verbose=0)[source]
Bases:
TargetPhase-informed difference target for time-resolved crystallography.
Uses model phases to create complex observed differences, then compares with calculated complex differences:
ΔF_calc = F_mixed_calc - F_dark_calc (complex) ΔF_obs_complex = ΔF_obs * exp(i * φ) (using model phases) Loss = |ΔF_obs_complex - ΔF_calc|² / σ_diff²
The phase source can be configured: - “dark”: Use dark model phases (stable reference) - “difference”: Use phase of calculated difference ΔF_calc (self-consistent) - “mixed”: Use mixed/light model phases
Using current model phases is standard practice in difference Fourier methods. The iterative nature of refinement self-corrects any phase bias, and the localized nature of difference peaks allows detection of weak signals.
- Parameters:
dataset_collection (DatasetCollection) – Collection containing ‘dark’ and ‘light’ datasets.
model_light (ModelFT or MixedModel) – Model for the light/excited state.
model_dark (ModelFT) – Model for the dark/ground state.
scaler_light (Scaler, optional) – Scaler for light state F_calc.
scaler_dark (Scaler, optional) – Scaler for dark state F_calc.
phase_source (str, optional) – Source for phases: “dark”, “difference”, or “mixed”. Default is “difference”.
use_work_set (bool, optional) – If True, compute loss on work set only. Default is True.
verbose (int, optional) – Verbosity level. Default is 0.
Examples
Using difference phases (recommended):
target = PhaseInformedDifferenceTarget( dataset_collection=collection, model_light=mixed_model, model_dark=model_dark, phase_source="difference", )
Using dark phases:
target = PhaseInformedDifferenceTarget( dataset_collection=collection, model_light=mixed_model, model_dark=model_dark, phase_source="dark", )
- __init__(dataset_collection, model_light=None, model_dark=None, scaler_light=None, scaler_dark=None, phase_source='difference', use_work_set=True, verbose=0)[source]
Initialize target.
- Parameters:
verbose (int, optional) – Verbosity level. Default is 0.
- forward(fcalc_light=None, fcalc_dark=None, recalc=True)[source]
Compute phase-informed difference loss.
- Parameters:
fcalc_light (torch.Tensor, optional) – Pre-computed light state structure factors.
fcalc_dark (torch.Tensor, optional) – Pre-computed dark state structure factors.
recalc (bool, optional) – Force recalculation if True. Default is True.
- Returns:
Mean weighted squared error.
- Return type:
- class torchref.refinement.targets.difference.TaylorCorrectedDifferenceTarget(dataset_collection, model_light=None, model_dark=None, scaler_light=None, scaler_dark=None, use_work_set=True, verbose=0)[source]
Bases:
TargetTaylor-corrected difference target for time-resolved crystallography.
Uses an exact Taylor expansion to properly account for the phase shift between dark and light states when constructing observed complex differences:
ΔF_obs = exp(i*φ_dark) * [F_obs_dark * (exp(i*dφ) - 1) + dF_obs * exp(i*dφ)]
- Where:
dφ = φ_light_calc - φ_dark_calc (phase rotation from model)
dF_obs = F_obs_light - F_obs_dark (observed amplitude difference)
- This formulation:
Uses the exact complex exponential (no small-angle approximation)
Properly accounts for both the amplitude difference and phase rotation
Eliminates the false minimum that causes refinement to stop at ~70%
- The loss is computed as:
Loss = |ΔF_obs_corrected - ΔF_calc|² / σ_diff²
- Parameters:
dataset_collection (DatasetCollection) – Collection containing ‘dark’ and ‘light’ datasets.
model_light (ModelFT or MixedModel) – Model for the light/excited state.
model_dark (ModelFT) – Model for the dark/ground state.
scaler_light (Scaler, optional) – Scaler for light state F_calc.
scaler_dark (Scaler, optional) – Scaler for dark state F_calc.
use_work_set (bool, optional) – If True, compute loss on work set only. Default is True.
verbose (int, optional) – Verbosity level. Default is 0.
Examples
Basic usage:
target = TaylorCorrectedDifferenceTarget( dataset_collection=collection, model_light=mixed_model, model_dark=model_dark, )
With scalers:
target = TaylorCorrectedDifferenceTarget( dataset_collection=collection, model_light=mixed_model, model_dark=model_dark, scaler_light=scaler_light, scaler_dark=scaler_dark, )
- __init__(dataset_collection, model_light=None, model_dark=None, scaler_light=None, scaler_dark=None, use_work_set=True, verbose=0)[source]
Initialize target.
- Parameters:
verbose (int, optional) – Verbosity level. Default is 0.
- forward(fcalc_light=None, fcalc_dark=None, recalc=True)[source]
Compute Taylor-corrected difference loss.
- The observed complex difference is constructed using the exact Taylor expansion:
ΔF_obs = exp(i*φ_dark) * [F_obs_dark * (exp(i*dφ) - 1) + dF_obs * exp(i*dφ)]
- Parameters:
fcalc_light (torch.Tensor, optional) – Pre-computed light state structure factors.
fcalc_dark (torch.Tensor, optional) – Pre-computed dark state structure factors.
recalc (bool, optional) – Force recalculation if True. Default is True.
- Returns:
Mean weighted squared error.
- Return type:
- compute_free_metrics(fcalc_light=None, fcalc_dark=None)[source]
Compute loss and correlation on the FREE (test) set.
This is the key metric for detecting overfitting in the α-δF degeneracy. The correct solution should have better free set metrics.
- Returns:
Dictionary with ‘free_loss’ and ‘free_correlation’.
- Return type:
- class torchref.refinement.targets.difference.RiceDifferenceTarget(dataset_collection, model_light=None, model_dark=None, scaler_light=None, scaler_dark=None, use_work_set=True, verbose=0)[source]
Bases:
TargetRice-distribution difference target for time-resolved crystallography.
Works in complex space by grafting detached model phases onto observed amplitudes, then taking the complex difference. The magnitude of this complex difference is always non-negative, enabling a proper Rice distribution likelihood.
The procedure:
Reconstruct complex observed structure factors using detached model phases:
F_obs_light_complex = F_obs_light * exp(i * φ_calc_light) F_obs_dark_complex = F_obs_dark * exp(i * φ_calc_dark)
Form complex differences:
ΔF_obs_complex = F_obs_light_complex - F_obs_dark_complex ΔF_calc = F_calc_light - F_calc_dark
Compute strictly positive amplitudes:
A_obs = |ΔF_obs_complex| (always ≥ 0) ν = |ΔF_calc| (always ≥ 0)
Apply Rice distribution NLL:
NLL = -log(A) + log(σ²) + (A² + ν²)/(2σ²) - log(I₀(A·ν/σ²))
The Rice distribution naturally models the magnitude of a complex signal plus Gaussian noise, making it statistically appropriate for comparing amplitudes that are always positive by construction.
- Parameters:
dataset_collection (DatasetCollection) – Collection containing ‘dark’ and ‘light’ datasets.
model_light (ModelFT or MixedModel) – Model for the light/excited state.
model_dark (ModelFT) – Model for the dark/ground state.
scaler_light (Scaler, optional) – Scaler for light state F_calc.
scaler_dark (Scaler, optional) – Scaler for dark state F_calc.
use_work_set (bool, optional) – If True, compute loss on work set only. Default is True.
verbose (int, optional) – Verbosity level. Default is 0.
Examples
Basic usage:
target = RiceDifferenceTarget( dataset_collection=collection, model_light=mixed_model, model_dark=model_dark, )
With scalers:
target = RiceDifferenceTarget( dataset_collection=collection, model_light=mixed_model, model_dark=model_dark, scaler_light=scaler_light, scaler_dark=scaler_dark, )
- __init__(dataset_collection, model_light=None, model_dark=None, scaler_light=None, scaler_dark=None, use_work_set=True, verbose=0)[source]
Initialize target.
- Parameters:
verbose (int, optional) – Verbosity level. Default is 0.
- forward(fcalc_light=None, fcalc_dark=None, recalc=True)[source]
Compute Rice distribution NLL loss for difference structure factors.
- Parameters:
fcalc_light (torch.Tensor, optional) – Pre-computed light state structure factors.
fcalc_dark (torch.Tensor, optional) – Pre-computed dark state structure factors.
recalc (bool, optional) – Force recalculation if True. Default is True.
- Returns:
Mean Rice NLL loss value.
- Return type: