def report(self, simulation, state): """ Generate a report. Parameters: - simulation (Simulation) The Simulation to generate a report for - state (State) The current state of the simulation """ from parmed.amber.asciicrd import VELSCALE global VELUNIT, FRCUNIT if self.crds: crds = state.getPositions().value_in_unit(u.angstrom) elif self.vels: # crds/vels/frcs are exclusive, elif works vels = state.getVelocities().value_in_unit(VELUNIT) elif self.frcs: frcs = state.getForces().value_in_unit(FRCUNIT) if self._out is None: # This must be the first frame, so set up the trajectory now if self.crds: self.atom = len(crds) elif self.vels: self.atom = len(vels) elif self.frcs: self.atom = len(frcs) self.uses_pbc = simulation.topology.getUnitCellDimensions() is not None self._out = AmberMdcrd(self.fname, self.atom, self.uses_pbc, title="ParmEd-created trajectory using OpenMM", mode='w') # Add the coordinates, velocities, and/or forces as needed if self.crds: flatcrd = [0 for i in range(self.atom*3)] for i in range(self.atom): i3 = i*3 flatcrd[i3], flatcrd[i3+1], flatcrd[i3+2] = crds[i] self._out.add_coordinates(flatcrd) if self.vels: # Divide by the scaling factor (works if vels is a list of Vec3's) # This is necessary since AmberMdcrd does not scale before writing # (since it expects coordinates) vels = [v / VELSCALE for v in vels] flatvel = [0 for i in range(self.atom*3)] for i in range(self.atom): i3 = i*3 flatvel[i3], flatvel[i3+1], flatvel[i3+2] = vels[i] self._out.add_coordinates(flatvel) if self.frcs: flatfrc = [0 for i in range(self.atom*3)] for i in range(self.atom): i3 = i*3 flatfrc[i3], flatfrc[i3+1], flatfrc[i3+2] = frcs[i] self._out.add_coordinates(flatfrc) # Now it's time to add the box lengths if self.uses_pbc: boxvecs = state.getPeriodicBoxVectors() lengths, angles = box_vectors_to_lengths_and_angles(*boxvecs) self._out.add_box(lengths.value_in_unit(u.angstroms))
class MdcrdReporter(object): """ MdcrdReporter prints a trajectory in ASCII Amber format. This reporter will be significantly slower than binary file reporters (like DCDReporter or NetCDFReporter). Parameters ---------- file : str Name of the file to write the trajectory to reportInterval : int Number of steps between writing trajectory frames crds : bool=True Write coordinates to this trajectory file? vels : bool=False Write velocities to this trajectory file? frcs : bool=False Write forces to this trajectory file? Notes ----- You can only write one of coordinates, forces, or velocities to a mdcrd file. """ @needs_openmm def __init__(self, file, reportInterval, crds=True, vels=False, frcs=False): # ASCII mdcrds can have either coordinates, forces, or velocities ntrue = 0 if crds: ntrue += 1 if vels: ntrue += 1 if frcs: ntrue += 1 if ntrue != 1: raise ValueError('MdcrdReporter must print exactly one of either ' 'coordinates, velocities, or forces.') # Control flags self.crds, self.vels, self.frcs = crds, vels, frcs self._reportInterval = reportInterval self._out = None # not written yet self.fname = file def describeNextReport(self, simulation): """ Get information about the next report this object will generate. Parameters ---------- simulation : :class:`app.Simulation` The Simulation to generate a report for Returns ------- nsteps, pos, vel, frc, ene : int, bool, bool, bool, bool nsteps is the number of steps until the next report pos, vel, frc, and ene are flags indicating whether positions, velocities, forces, and/or energies are needed from the Context """ stepsleft = simulation.currentStep % self._reportInterval steps = self._reportInterval - stepsleft return (steps, self.crds, self.vels, self.frcs, False) def report(self, simulation, state): """ Generate a report. Parameters: - simulation (Simulation) The Simulation to generate a report for - state (State) The current state of the simulation """ from parmed.amber.asciicrd import VELSCALE global VELUNIT, FRCUNIT if self.crds: crds = state.getPositions().value_in_unit(u.angstrom) elif self.vels: # crds/vels/frcs are exclusive, elif works vels = state.getVelocities().value_in_unit(VELUNIT) elif self.frcs: frcs = state.getForces().value_in_unit(FRCUNIT) if self._out is None: # This must be the first frame, so set up the trajectory now if self.crds: self.atom = len(crds) elif self.vels: self.atom = len(vels) elif self.frcs: self.atom = len(frcs) self.uses_pbc = simulation.topology.getUnitCellDimensions() is not None self._out = AmberMdcrd(self.fname, self.atom, self.uses_pbc, title="ParmEd-created trajectory using OpenMM", mode='w') # Add the coordinates, velocities, and/or forces as needed if self.crds: flatcrd = [0 for i in range(self.atom*3)] for i in range(self.atom): i3 = i*3 flatcrd[i3], flatcrd[i3+1], flatcrd[i3+2] = crds[i] self._out.add_coordinates(flatcrd) if self.vels: # Divide by the scaling factor (works if vels is a list of Vec3's) # This is necessary since AmberMdcrd does not scale before writing # (since it expects coordinates) vels = [v / VELSCALE for v in vels] flatvel = [0 for i in range(self.atom*3)] for i in range(self.atom): i3 = i*3 flatvel[i3], flatvel[i3+1], flatvel[i3+2] = vels[i] self._out.add_coordinates(flatvel) if self.frcs: flatfrc = [0 for i in range(self.atom*3)] for i in range(self.atom): i3 = i*3 flatfrc[i3], flatfrc[i3+1], flatfrc[i3+2] = frcs[i] self._out.add_coordinates(flatfrc) # Now it's time to add the box lengths if self.uses_pbc: boxvecs = state.getPeriodicBoxVectors() lengths, angles = box_vectors_to_lengths_and_angles(*boxvecs) self._out.add_box(lengths.value_in_unit(u.angstroms)) def __del__(self): try: if self._out is not None: self._out.close() except AttributeError: pass def finalize(self): """ Closes any open file """ try: if self._out is not None: self._out.close() except AttributeError: # pragma: no cover pass # pragma: no cover