DistanceRestraintForce implements the CHARMM RESDistance/RESD restraint model. It is not limited to a harmonic restraint between one pair of atoms.
One DistanceRestraintForce object may contain multiple restraint terms. Each term may contain one or more weighted atom pairs. Terms accumulate additively in energy, potential-energy gradient, and internal virial.
A single-pair term can represent an ordinary distance restraint. A multi-pair term can represent a reaction coordinate such as a difference of distances.
For one term, let r_j be the raw primary-coordinate distance of pair j, and let c_j be that pair's coefficient. The term deviation and active energy are:
When a one-sided condition makes the term inactive, its energy, gradient, and virial contribution are zero.
For an object containing multiple terms:
A conventional harmonic distance restraint is the special case:
which gives:
The factor KVAL / EVAL is part of the RESD definition; do not replace it with an unnormalized power expression.
Each coefficient multiplies one powered pair distance before the pair contributions are summed.
Nonzero positive, negative, and fractional coefficients are supported. Negative coefficients permit reaction coordinates such as:
Repeating the same pair within a term is supported, and its coefficients accumulate algebraically.
Every coefficient must be nonzero. The current apoCHARMM API also requires coefficients to be finite.
KVAL is the term force constant. It appears in both the energy and its derivative through the normalized factor KVAL / EVAL.
Positive and negative nonzero values are supported. Zero is rejected. The current apoCHARMM API also requires KVAL to be finite.
RVAL is the reference value subtracted from the coefficient-weighted reaction coordinate.
The characterized behavior includes negative, zero, positive, fractional, and near-boundary floating-point values. The current apoCHARMM API requires RVAL to be finite.
No omitted-value default for RVAL has been established.
IVAL is the integer exponent applied independently to every pair distance in one term:
The supported typed values are:
In the characterized CHARMM syntax, omitting IVAL stores IVAL=1. The apoCHARMM C++, C, and Python term-creation APIs require an explicit distance exponent and do not expose an omitted IVAL argument.
The complete CHARMM integer range is unresolved. Values outside the listed characterized set are rejected by the current typed API rather than inferred.
EVAL is the integer exponent applied to D. It also supplies the denominator in KVAL / EVAL.
The supported typed values are:
Zero and negative values are rejected. No omitted-value default for EVAL has been established, so every apoCHARMM term-creation API requires it explicitly.
For negative D, ordinary signed integer powers are used. Odd and even EVAL values therefore retain their ordinary signed-power behavior.
SCALE is one global multiplicative factor applied to every stored term's energy, gradient, and internal virial.
Positive, zero, and negative finite values are supported. Its confirmed initial value is:
Appending another term preserves the current scale. reset() restores the scale to one.
A scale of zero produces zero contribution and may return before pair geometry is evaluated.
The typed API stores setScale() as object state. It does not reproduce the separate CHARMM text-parser command form in which a standalone scale command issued before a subsequent definition was discarded by that definition.
DistanceRestraintCondition.NONE applies no one-sided activation gate. The term is always active.
DistanceRestraintCondition.POSITIVE is active exactly when:
It is inactive when D < 0.
DistanceRestraintCondition.NEGATIVE is active exactly when:
It is inactive when D > 0.
reset() removes every stored term and restores SCALE to one. A new term may be added after reset; terms that existed before reset remain absent.
reset() changes restraint configuration. It does not clear force, energy, or virial output left by an earlier calculation.
A newly constructed apoCHARMM object has:
SCALE=1"resd" in the Python APIThe confirmed CHARMM omission default for IVAL is one in the tested definition syntax.
The following omission defaults remain unresolved and must not be inferred:
EVALKVALRVALThe C++ addRestraint() condition argument defaults to DistanceRestraintCondition::NONE. The C ABI and Python API require an explicit condition value.
DistanceRestraintForce remains atom-count based:
It does not retain or derive its atom count from a CharmmPSF.
All public C++, C, and Python term-creation interfaces require topology-aware AtomReference endpoints. There is no public distance-restraint interface that accepts raw integer endpoint pairs.
The native C++ method accepts:
The C ABI accepts parallel arrays of borrowed apo_atom_reference handles. The Python method accepts sequences containing two live AtomReference wrappers per pair and passes their borrowed handles through that typed C ABI. Python does not pre-extract raw endpoint indices for restraint registration.
For every endpoint, the native force extracts getAtomIndex() and stores only that zero-based integer in its existing flattened index storage. It retains no AtomReference, public C handle, Python wrapper, or source CharmmPSF after addRestraint() returns.
Topology provenance is deliberately ignored. The force does not call hasSameTopology() and does not require the endpoints of a pair to originate from the same native PSF object.
Consequently:
[0, numAtoms) range.Pair definitions and coefficients remain separate parallel collections and must have matching lengths. Pair order and coefficient correspondence are preserved. Each term must contain at least one pair. Repeated pairs remain supported.
Both extracted indices in one pair must be distinct. Rejecting identical indices is an intentional apoCHARMM safety policy. The characterized CHARMM identical-index case produced finite energy but nonfinite gradients and virials rather than a usable restraint.
RESD uses the raw primary-coordinate displacement and distance. It does not replace a pair displacement with a minimum-image displacement.
This behavior is established for:
In those cases, image activation does not alter the pair distance used by RESD. The internal virial uses the same raw displacement, and no image-shift correction is added to make it minimum-image invariant. The characterized external RESD virial is zero.
Compatibility is not claimed for an uncharacterized periodic configuration. The following are unsupported for CHARMM-compatible RESD behavior:
The current object stores force-manager box dimensions for lifecycle compatibility, but those dimensions do not cause minimum-image replacement of the characterized raw pair displacement.
The current apoCHARMM implementation rejects every evaluated pair whose exact distance is zero. Detection occurs before negative-power evaluation or gradient formation.
This is a deliberate safety narrowing of the characterized CHARMM behavior. The supplied CHARMM testing showed:
| IVAL | Characterized exact-zero result |
|---|---|
-2 | Infinite deviation and energy; NaN Cartesian values and virial |
-1 | Infinite deviation and energy; NaN Cartesian values and virial |
0 | Finite energy; NaN Cartesian values and virial |
1 | Finite energy; NaN Cartesian values and virial |
2 | Finite energy; exact zero Cartesian values and virial |
6 | Finite energy; exact zero Cartesian values and virial |
7 | Finite energy; exact zero Cartesian values and virial |
apoCHARMM does not reproduce these exponent-dependent exact-zero branches. It rejects all evaluated exact-zero pairs instead.
When SCALE=0, evaluation may return zero before reading pair geometry, so an otherwise singular pair need not be evaluated.
Exact-zero behavior for uncharacterized IVAL values remains unresolved.
There is no nonzero selector tolerance in the characterized behavior.
POSITIVE includes equality at D=0. NEGATIVE also includes equality at D=0.
With EVAL=1, the energy at D=0 is zero, but a coordinate-dependent active term can have a nonzero gradient and internal virial at that boundary. The first derivative is therefore discontinuous when crossing between the inactive and active sides.
The characterized adjacent binary64 deviations were distinguished by their exact signs:
Do not add an epsilon or tolerance to either selector.
The native C++ clear() operation clears accumulated force, energy, and virial output. It does not remove restraint terms and does not restore the scale.
reset() removes all restraint terms and restores the scale to one. It does not substitute for output clearing.
The C ABI and Python wrapper expose reset() for configuration replacement. Normal C and Python calculations rely on ForceManager and CharmmContext to drive output clearing and force evaluation.
The public typed API deliberately restricts exponents to the characterized sets:
This restriction must not be described as the complete accepted CHARMM range.
The CHARMM text parser converted the tested token 1.5 to stored integer 1. The typed apoCHARMM API does not silently reproduce that parser conversion; exponents are integer API values, and unsupported values are rejected.
At finite nonzero distance, IVAL=0 gives a coordinate-independent r^0 contribution and zero pair gradient.
IVAL=6 and IVAL=7 remained finite at distance two in the characterized cases. That observation does not establish general overflow or underflow limits.
The following remain unresolved:
IVAL values outside the characterized setEVAL values above fourKVAL, RVAL, and SCALEIVAL valuesThe current apoCHARMM API requires finite coefficients, KVAL, RVAL, and SCALE. These finite-value checks are API safety policies, not claims about unrestricted CHARMM behavior.
Construct the force with the same atom count as its ForceManager:
Create exact-one atom references through AtomSelector.selectAtom():
Pass the references, not their integer indices, to addRestraint():
The Python wrapper places the two endpoint-handle sequences and coefficients in temporary arrays. The C ABI borrows the handles and copies temporary native AtomReference values; the native force then extracts and stores only their zero-based indices. After successful return, no Python wrapper, public C handle, native AtomReference, or source topology is retained. Closing or destroying the references does not invalidate the stored restraint.
Set the global scale with setScale() and subscribe through the manager:
Omitting the tag uses the default tag:
The manager retains the restraint after successful subscription. Unsubscribe before closing the restraint:
Closing a still-subscribed Python wrapper destroys its identifying C handle but does not by itself remove the manager's native subscription.
The wrapper and native object provide no internal host-thread synchronization. Serialize configuration, subscription changes, calculation, reset, unsubscription, and closure.
A complete runnable example is provided in:
The native C++ interface is declared in:
The C ABI is declared in:
The AtomReference-only term-creation entry point is:
The Python wrapper and condition enumeration are implemented in: