Freely jointed chain

Usage examples and full code reference for FreelyJointedChain. For the underlying theory, see Freely jointed chain.

Quick start

from afrc.polymer_models.fjc import FreelyJointedChain

# default segment length b = 3.8 A (one Cα-Cα virtual bond per residue)
model = FreelyJointedChain('MASNDYTQQATQSYGAYPTQPGQGYSQQSSQPYG')

model.get_mean_end_to_end_distance()
model.get_root_mean_squared_end_to_end_distance()
model.get_mean_radius_of_gyration()

# full end-to-end distribution (distances, probabilities)
r, p = model.get_end_to_end_distribution()

# draw a size-matched sample
samples = model.sample_end_to_end_distribution(n=1000)

Change the segment length to make the chain stiffer or more flexible:

stiff = FreelyJointedChain('MASNDYTQQATQSYG', b=4.5)
stiff.get_root_mean_squared_end_to_end_distance()

See also the demo/demo_FreelyJointedChain.ipynb notebook for a worked, plotted example.

Generating 3D ensembles

Generate explicit conformations (one bead per residue), write them to disk, and check how well they reproduce the model:

model = FreelyJointedChain('MASNDYTQQATQSYGAYPTQPGQGYSQQSSQPYG')

xyz = model.sample_conformations(n=5000, seed=1)                 # [n x N x 3] array, Angstroms
model.save_ensemble('ens', n=5000, seed=1)                       # ens.pdb + ens.xtc (needs mdtraj)
print(model.check_ensemble(xyz).format())                  # the model-check report

Or from the command line: afrc-ensemble -s <sequence> -m fjc (see Command-line tools).

Code reference

class afrc.polymer_models.fjc.FreelyJointedChain(seq: str, p_of_r_resolution: float = 0.05, b: float = 3.8)

Freely jointed chain of N rigid segments of length b.

Unlike the (Gaussian) AFRC, the end-to-end distribution here is the non-Gaussian Kuhn-Grün distribution [1], which respects the finite extensibility of the chain - the end-to-end distance can never exceed the contour length \(L = Nb\). At small extensions it reduces to the Gaussian result, so for typical IDR lengths the bulk of the distribution is close to the AFRC and the differences appear in the tail.

This is a composition-independent reference model: the sequence is only used to set the number of segments.

References

[1] Kuhn, W., & Grün, F. (1942). Beziehungen zwischen elastischen Konstanten und Dehnungsdoppelbrechung hochelastischer Stoffe. Kolloid-Zeitschrift, 101(3), 248-271.

[2] Cohen, A. (1991). A Padé approximant to the inverse Langevin function. Rheologica Acta, 30(3), 270-273.

__init__(seq: str, p_of_r_resolution: float = 0.05, b: float = 3.8) → None

Create a FreelyJointedChain object.

Parameters:
  • seq (str) – Amino acid sequence. Only its length (the number of segments) is used, and it is not validated.

  • p_of_r_resolution (float) – Grid spacing (in Angstroms) used for the distribution. Default is 0.05 A.

  • b (float) – Segment (Kuhn) length, in Angstroms. The default of 3.8 A is the Cα-Cα distance, i.e. one segment per residue. Must be > 0.

Raises:

FJCException – If b is not positive.

check_ensemble(conformations: NDArray[float64]) → EnsembleReport

Check how well an ensemble reproduces the freely jointed chain.

The exact checks are the mean-squared distance of every residue pair (\(k b^2\), in bands of separation), the root-mean-square radius of gyration and first-to-last distance that follow from them, and the chain’s geometry: every bond exactly b long and no pair further apart than its contour length. The model’s analytical (Kuhn-Grün) end-to-end distribution and its radius of gyration are reported as context.

Parameters:

conformations (np.ndarray) – Array of shape [n_conformations x N x 3] (in Angstroms).

Returns:

The checks; report.passed says whether the ensemble is model-like and report.format() gives a printable report.

Return type:

EnsembleReport

Raises:

AFRCException – If the conformations do not match this chain.

get_end_to_end_distribution()

Return the end-to-end distance distribution.

The distribution is computed on first use and then cached.

Returns:

(distances, probabilities), where distances are in Angstroms and the probabilities are a normalized probability mass function (they sum to 1). The grid never extends past the contour length.

Return type:

tuple of np.ndarray

get_mean_end_to_end_distance()

Return the mean end-to-end distance, \(\langle R_e \rangle\).

This is the expectation over the end-to-end distribution, \(\sum r P(r)\).

Returns:

The mean end-to-end distance (in Angstroms).

Return type:

float

get_mean_radius_of_gyration()

Return the root-mean-square radius of gyration, \(\sqrt{\langle R_g^2 \rangle}\).

This uses the ideal-chain relation \(\langle R_g^2 \rangle = \langle R_e^2 \rangle / 6\). Note that despite the method name this is the root-mean-square radius of gyration, not \(\langle R_g \rangle\). The name is kept for consistency with the other models.

Returns:

The root-mean-square radius of gyration (in Angstroms).

Return type:

float

get_mean_squared_distance_map() → NDArray[float64]

Return the exact mean-squared distance between every pair of residues.

Beads k residues apart are joined by k freely jointed bonds, so \(\langle r^2 \rangle = k b^2\) exactly.

Returns:

Symmetric [N x N] matrix of mean-squared distances (in Angstroms squared), with zeros on the diagonal.

Return type:

np.ndarray

get_root_mean_squared_end_to_end_distance()

Return the root-mean-square end-to-end distance, \(\sqrt{\langle R_e^2 \rangle}\).

This is the square root of \(\sum r^2 P(r)\) over the end-to-end distribution. For long chains it approaches the ideal-chain value \(b\sqrt{N}\) from below.

Returns:

The root-mean-square end-to-end distance (in Angstroms).

Return type:

float

sample_conformations(n: int = 1000, seed: int | Generator | None = None) → NDArray[float64]

Generate 3D conformations (one bead per residue) of the freely jointed chain.

Consecutive beads are joined by bonds of exactly b pointing in independent, uniformly random directions - the freely jointed chain itself, not an approximation to it. (Note that the model’s analytical end-to-end distribution, the Kuhn-Grün form, is itself an approximation that becomes exact for long chains.)

Parameters:
  • n (int) – Number of conformations. Default is 1000.

  • seed (int, np.random.Generator or None) – Seed (or generator) for reproducible ensembles. If None (default) a fresh, unpredictable seed is used.

Returns:

Array of shape [n x N x 3] with the bead coordinates, in Angstroms, each conformation centred on the origin.

Return type:

np.ndarray

Raises:

AFRCException – If n is not a positive integer.

sample_end_to_end_distribution(n=1000)

Draw random end-to-end distances from the distribution.

Useful for building a size-matched sample to compare against simulation data.

Parameters:

n (int) – Number of values to draw. Default is 1000.

Returns:

n independent end-to-end distances (in Angstroms). For a zero-length chain every value is 0.

Return type:

np.ndarray

save_ensemble(filename: str, n: int = 1000, seed: int | Generator | None = None, pdb_only: bool = False) → NDArray[float64]

Generate a freely jointed chain ensemble and write it to disk.

Writes <filename>.pdb (topology and first conformation) and <filename>.xtc (every conformation; needs mdtraj), or with pdb_only=True a single multi-model <filename>.pdb. See sample_conformations() for how the conformations are generated.

Parameters:
  • filename (str) – Output path without an extension (a trailing .pdb or .xtc is dropped).

  • n (int) – Number of conformations. Default is 1000.

  • seed (int, np.random.Generator or None) – Seed (or generator) for reproducible ensembles.

  • pdb_only (bool) – Write a single multi-model PDB instead of a PDB/XTC pair. Default is False.

Returns:

The conformations that were written, shape [n x N x 3] (Angstroms).

Return type:

np.ndarray

Raises:

AFRCException – If n is invalid, the sequence has non-standard amino acids, mdtraj is missing (for a PDB/XTC pair), or the PDB format limits are exceeded.