EndToEndPlan
Compute end-to-end distance for polymer chains.
Constructor
from warp_md import EndToEndPlan
plan = EndToEndPlan(selection)
Polymer backbone atoms (automatically detects chains)
run() Method
Returns: 2D array of shape (n_frames, n_chains) with end-to-end distances in Å
Example
import warp_md as wmd
import numpy as np
import matplotlib.pyplot as plt
system = wmd.System("polymer.pdb")
traj = wmd.open_trajectory("md.xtc", system)
# Select polymer backbone
backbone = system.select("name CA or name C or name N")
plan = wmd.EndToEndPlan(backbone)
ree = plan.run(traj, system)
# If multiple chains
n_chains = ree.shape[1]
for i in range(n_chains):
plt.plot(ree[:, i], label=f"Chain {i+1}", alpha=0.7)
plt.xlabel("Frame")
plt.ylabel("End-to-End Distance (Å)")
plt.legend()
plt.title("Polymer Extension")
plt.show()
print(f"Average R_ee: {ree.mean(axis=0)}")
print(f"Std R_ee: {ree.std(axis=0)}")
Chains are automatically detected based on chain IDs in the topology. For synthetic polymers without chain IDs, ensure proper segmentation.
ChainRgPlan
Compute radius of gyration for each polymer chain separately.
Constructor
plan = ChainRgPlan(selection, mass_weighted=True)
Use mass-weighted Rg calculation
run() Method
Returns: 2D array of shape (n_frames, n_chains) with Rg values in Å
Example
# Compare Rg and end-to-end distance
backbone = system.select("polymer")
ree_plan = wmd.EndToEndPlan(backbone)
rg_plan = wmd.ChainRgPlan(backbone, mass_weighted=True)
ree = ree_plan.run(traj, system)
rg = rg_plan.run(traj, system)
# Plot relationship
import matplotlib.pyplot as plt
plt.scatter(ree.flatten(), rg.flatten(), alpha=0.3)
plt.xlabel("End-to-End Distance (Å)")
plt.ylabel("Radius of Gyration (Å)")
plt.title("Polymer Conformation")
# Theoretical line for ideal chain: Rg = Ree/sqrt(6)
ree_range = np.linspace(ree.min(), ree.max(), 100)
plt.plot(ree_range, ree_range / np.sqrt(6), 'r--', label='Ideal chain')
plt.legend()
plt.show()
print(f"Rg/Ree ratio: {(rg.mean() / ree.mean()):.3f}")
print(f"Expected for ideal chain: {1/np.sqrt(6):.3f}")
PersistenceLengthPlan
Calculate persistence length from bond angle correlation.
Constructor
plan = PersistenceLengthPlan(
selection,
bond_length=3.8
)
Polymer backbone atoms in sequence
Average bond length in Å (for C-C: ~1.5 Å, for C-alpha: ~3.8 Å)
run() Method
Returns: Dictionary containing:
persistence_length: Persistence length in Å
bond_correlations: Bond angle correlation decay
fit_data: Exponential fit parameters
Example
# Calculate persistence length
backbone = system.select("name CA")
plan = wmd.PersistenceLengthPlan(
backbone,
bond_length=3.8 # C-alpha spacing
)
result = plan.run(traj, system)
lp = result["persistence_length"]
corr = result["bond_correlations"]
print(f"Persistence length: {lp:.2f} Å")
# Plot correlation decay
import matplotlib.pyplot as plt
import numpy as np
separation = np.arange(len(corr)) * 3.8
plt.semilogy(separation, corr, 'o-')
plt.xlabel("Contour separation (Å)")
plt.ylabel("Bond correlation")
plt.axhline(np.exp(-1), color='r', linestyle='--', label='1/e')
plt.axvline(lp, color='r', linestyle='--', label=f'Lp = {lp:.1f} Å')
plt.legend()
plt.title("Persistence Length Analysis")
plt.show()
Persistence length (Lp) is the length scale over which the polymer chain “remembers” its direction:
- Rigid polymers: Lp > 100 Å
- Semi-flexible: 10 Å < Lp < 100 Å
- Flexible: Lp < 10 Å
Advanced: Kuhn Length
# Calculate Kuhn length from persistence length and contour length
result = plan.run(traj, system)
lp = result["persistence_length"]
# Kuhn length b = 2 * Lp
kuhn_length = 2 * lp
# Contour length (total chain length)
backbone_indices = list(backbone.indices)
n_bonds = len(backbone_indices) - 1
contour_length = n_bonds * 3.8 # bond_length
# Number of Kuhn segments
n_kuhn = contour_length / kuhn_length
print(f"Kuhn length: {kuhn_length:.2f} Å")
print(f"Contour length: {contour_length:.2f} Å")
print(f"Number of Kuhn segments: {n_kuhn:.1f}")
# Expected Rg for Gaussian chain
rg_expected = kuhn_length * np.sqrt(n_kuhn / 6)
print(f"Expected Rg (Gaussian chain): {rg_expected:.2f} Å")
Polymer Classification
import warp_md as wmd
import numpy as np
def classify_polymer(system, traj, selection):
"""Classify polymer behavior from scaling analysis."""
# Calculate Rg and end-to-end distance
rg_plan = wmd.ChainRgPlan(selection)
ree_plan = wmd.EndToEndPlan(selection)
rg = rg_plan.run(traj, system).mean()
ree = ree_plan.run(traj, system).mean()
# Calculate persistence length
lp_plan = wmd.PersistenceLengthPlan(selection, bond_length=3.8)
result = lp_plan.run(traj, system)
lp = result["persistence_length"]
# Estimate contour length
n_atoms = len(selection.indices)
contour_length = (n_atoms - 1) * 3.8
# Flexibility ratio
flexibility = contour_length / lp
# Shape factor
shape = rg / ree
print("=== Polymer Classification ===")
print(f"Contour length: {contour_length:.1f} Å")
print(f"Persistence length: {lp:.1f} Å")
print(f"Flexibility ratio (L/Lp): {flexibility:.2f}")
print(f"Shape factor (Rg/Ree): {shape:.3f}")
print()
if flexibility < 1:
regime = "Rod-like (rigid)"
elif flexibility < 10:
regime = "Semi-flexible"
else:
regime = "Flexible coil"
print(f"Regime: {regime}")
if 0.38 < shape < 0.42:
conformation = "Gaussian coil"
elif shape < 0.38:
conformation = "Collapsed/Compact"
else:
conformation = "Extended"
print(f"Conformation: {conformation}")
return {
"lp": lp,
"contour_length": contour_length,
"flexibility": flexibility,
"shape_factor": shape,
"regime": regime,
"conformation": conformation
}
# Usage
backbone = system.select("name CA")
result = classify_polymer(system, traj, backbone)