torchref.scaling.solvent

A class for modelling solvent contribution to structure factors.

Module Attributes

SS_HALF_BOUNDS

Bounds on the solvent falloff, applied as clamps inside SolventModel.damping().

Classes

SolventModel([model, radius, k_solvent, ...])

Bulk-solvent contribution to structure factors, Phenix-style.

torchref.scaling.solvent.SS_HALF_BOUNDS = (0.0025, 0.04)

Bounds on the solvent falloff, applied as clamps inside SolventModel.damping(). ss_half is the half-point in (sin(theta)/lambda)**2, quoted here as the resolution d_half = 1 / (2 sqrt(ss_half)); the range spans well beyond the observed spread while excluding the degenerate slow-power-law fits the unbounded form can reach. n = 1 is exactly a Debye-Waller factor with B = ln2 / ss_half, so the shipped exponential is nested at the lower bound rather than merely approximated.

class torchref.scaling.solvent.SolventModel(model=None, radius=1.1, k_solvent=1.1, d_half=3.59, n_exp=5.0, erosion_radius=0.9, optimize_phase=True, initial_phase_offset=0.0, verbose=1, float_type=None, device=None)[source]

Bulk-solvent contribution to structure factors, Phenix-style.

Constructed either with a model (SolventModel(model, k_solvent=0.35) – the value Scaler injects; the bare-constructor default is 1.1) or empty, as a shell for load_state_dict.

The solvent falls off as k_sol * exp(-ln2 * (ss / ss_half)**n) in ss = (sin(theta)/lambda)**2. ss_half is where the term is halved and n how sharply it switches off; n = 1 is exactly exp(-B ss) with B = ln2 / ss_half, so a Debye-Waller solvent is a special case rather than a different model. Both are clamped to SS_HALF_BOUNDS / N_EXP_BOUNDS.

model

The atomic model the solvent mask is built from.

Type:

ModelFT or None

device

Device for tensor operations.

Type:

torch.device

verbose

Verbosity level.

Type:

int

float_type

Float dtype; defaults to the configured get_float_dtype(), not a hard-wired torch.float32.

Type:

torch.dtype

solvent_radius, erosion_radius

Probe radius for dilation and radius for the erosion step (Å).

Type:

float

optimize_phase

Whether the phase offset is refined.

Type:

bool

log_k_solvent, log_ss_half, log_n_exp

Log solvent scattering scale, and the logs of the falloff half-point and exponent. Refined in log space so each stays positive.

Type:

torch.nn.Parameter

phase_offset

Phase offset in radians: a trainable parameter when optimize_phase=True, otherwise a buffer fixed at 0.0.

Type:

torch.nn.Parameter or buffer

__init__(model=None, radius=1.1, k_solvent=1.1, d_half=3.59, n_exp=5.0, erosion_radius=0.9, optimize_phase=True, initial_phase_offset=0.0, verbose=1, float_type=None, device=None)[source]

Initialize SolventModel.

If model is provided, fully initializes the solvent model. If not provided (empty init), creates a shell ready for load_state_dict().

Parameters:
  • model (ModelFT, optional) – The atomic model used for structure factor calculations (optional for empty init).

  • radius (float, default 1.1) – Probe radius in Angstroms for dilation (water radius).

  • k_solvent (float, default 1.1) – Solvent scattering scale factor.

  • d_half (float, default 3.59) – Resolution (A) at which the solvent term is halved; stored as ss_half = 1 / (4 d_half**2).

  • n_exp (float, default 5.0) – Falloff exponent. 1.0 reduces the form to exp(-B ss).

  • erosion_radius (float, default 0.9) – Radius in Angstroms for erosion step.

  • optimize_phase (bool, default True) – Whether to optimize phase offset parameter.

  • initial_phase_offset (float, default 0.0) – Initial phase offset in radians.

  • verbose (int, default 1) – Verbosity level.

  • float_type (torch.dtype, optional) – Float dtype. None (default) resolves at runtime to get_float_dtype(), not a hard-wired torch.float32.

  • device (torch.device, default: configured device.current) – Device for tensor operations.

ss_half()[source]

Half-point of the solvent falloff in (sin(theta)/lambda)**2, clamped.

n_exp()[source]

Falloff exponent, clamped. 1 is a Debye-Waller factor.

k_solvent()[source]

Solvent scattering scale.

damping(s_half_sq)[source]

exp(-ln2 * (ss / ss_half)**n) at ss = (sin(theta)/lambda)**2.

Parameters:

s_half_sq (torch.Tensor) – (sin(theta)/lambda)**2 per reflection.

Returns:

Falloff factor in [0, 1], same shape as the input.

Return type:

torch.Tensor

b_solvent_equivalent(s_half_sq)[source]

The single B whose exp(-B ss) best matches this falloff.

A reporting quantity: PDB REMARK 3 and mmCIF have a field for a solvent B-factor and the fitted form has none, so it is back-fitted by least squares on log(damping) over the reflections actually present, weighted by the damping itself so the fit follows the range where the solvent contributes.

get_solvent_mask()[source]

Generate solvent mask following Phenix’s three-step process.

Step 1 (dilation): classify voxels around each atom as protein

(inside VdW), boundary (between VdW and VdW+solvent_radius), or bulk solvent (further out). Built in chunks over atoms so peak memory is O(atom_chunk_size × N_box_voxels) rather than O(N_atoms × N_box_voxels) — critical because for typical macromolecule + grid combinations the dense form is multi-GB.

Step 2 (symmetry expansion): transform the sparse ASU protein /

boundary voxel indices through each symop and scatter into the P1 grid masks.

Step 3 (erosion): a boundary voxel becomes solvent if any voxel

within erosion_radius of it is bulk solvent, computed with a precomputed spherical structuring element under circular padding.

Returns:

Solvent mask (boolean) where True = solvent.

Return type:

torch.Tensor

update_solvent()[source]

Rebuild the solvent mask from current coordinates and drop the mask-derived cache.

Prefer update_solvent(), which also clears the scaler’s own _f_sol_raw; that one is what F_calc reads. Calling this directly refreshes the mask but leaves the scaler on the old F_sol.

get_rec_solvent(hkl)[source]

Compute solvent structure factors.

Uses the standard crystallographic approach: compute SFs from the solvent mask. The mask represents regions where bulk solvent scattering occurs.

Parameters:

hkl (torch.Tensor) – Miller indices.

Returns:

Complex solvent structure factors.

Return type:

torch.Tensor

forward(hkl, update_fsol=False, F_protein=None)[source]

Compute solvent contribution to structure factors at given HKL.

Differentiable w.r.t. log_k_solvent, log_ss_half, log_n_exp and phase_offset. Takes f_sol (the FFT of the binary mask) from a per-hkl cache, applies damping() at ss = (sin(θ)/λ)**2, blends mask phases toward the protein phases when optimize_phase and F_protein are both given (phase_offset 0 = mask phases, ±π = protein phases), and scales by k_solvent.

Parameters:
  • hkl (torch.Tensor) – Miller indices, shape (N, 3).

  • update_fsol (bool, default False) – Force recomputation of the cached solvent structure factors for this hkl and refresh the cache entry, instead of reusing a cached entry keyed on the hkl fingerprint.

  • F_protein (torch.Tensor, optional) – Protein structure factors, used for phase blending.

Returns:

Complex solvent structure factors, shape (N,).

Return type:

torch.Tensor

parameters()[source]

Refinable solvent parameters as a list (phase offset only if refined).