I have three trajectory replicas (xtc) of a membrane protein in a simulated physiological environment (water, ions, membrane...) in a MDAnalysis' (2.2.0) Universe. I want to save other three additional xtcs that contain only the trajectory of the protein (of the atoms of the protein), one per each of the original xtc trajectories. When I try to iterate through each of the three MDAnalysis' Readers contained in the Universe, the first saved trajectory seems to be correct, but the other two have the same coordinates in all the frames. The starting, complete trajectories are correct. If my starting point is necessarily a Universe with the three Readers, how do I do this correctly and efficiently?
Code:
import MDAnalysis as mda
u = mda.Universe("11159_dyn_117.pdb", "11156_trj_117.xtc", "11157_trj_117.xtc", "11158_trj_117.xtc")
protein = u.select_atoms("protein")
protein.write("protein.pdb")
for num, reader in enumerate(u.trajectory.readers, 1):
with mda.Writer(f"{num}.xtc", protein.n_atoms) as w:
for ts in reader.trajectory:
w.write(protein.atoms)
# Then check the generated individual trajectories by loading them in
# Universes and checking the positions array. I checked them in PyMOL.
Files downloadable at: https://submission.gpcrmd.org/dynadb/dynamics/id/117/ (model file and trajectory files)
You can write a trajectory directly from an AtomGroup with the
AtomGroup.write(name, frames=trajectory_iterator)method. Access the start/stop frames in the chained trajectory with the privateChainReader._start_framesattribute (not documented).This will produce trajectories
protein_0.xtcandprotein_1.xtc. If you want to load them, don't forget to create a file that contains a minimal topology for the selectionso that you can load the new trajectories with
Notes
ChainReader._start_framesinstead of the raw lengths of trajectories because they are updated appropriately if the ChainReader detects overlapping frames when usingcontinuous=True.frames=u.trajectory[start:stop]one can also useframes=slice(start, stop).protein.atoms.write()one normally writesprotein.write(), which is equivalent and shorter, but I wanted to make clear that it's always correct to go to the atoms, in particular if one wanted to write a whole universe, in which case one would useu.atoms.write().AtomGroup.write()one could also use explicit trajectory writing where you open a trajectory for writing with which provides more control over every step but is more verbose.