def openff_openmm_pmd_gmx( topology: Topology, forcefield: ForceField, box: ArrayQuantity, prefix: str, ) -> None: """Pipeline to write GROMACS files from and OpenMM system through ParmEd""" topology.box_vectors = box.to(unit.nanometer).magnitude * omm_unit.nanometer omm_sys = forcefield.create_openmm_system(topology) struct = pmd.openmm.load_topology( system=omm_sys, topology=topology.to_openmm(), xyz=topology.topology_molecules[0].reference_molecule.conformers[0], ) # Assign dummy residue names, GROMACS will not accept empty strings # TODO: Patch upstream? for res in struct.residues: res.name = "FOO" struct.save(prefix + ".gro") struct.save(prefix + ".top")
def simulate( force_field: ForceField, topology: Topology, positions: unit.Quantity, box_vectors: Optional[unit.Quantity], n_steps: int, temperature: unit.Quantity, pressure: Optional[unit.Quantity], platform: Literal["Reference", "OpenCL", "CUDA", "CPU"] = "Reference", output_directory: Optional[str] = None, ): """A helper function for simulating a system parameterised with a specific OpenFF force field using OpenMM. Parameters ---------- force_field The force field to apply. topology The topology detailing the system to simulate. positions The starting coordinates of the molecules in the system. box_vectors The box vectors to use. These will overwrite the topology box vectors. n_steps The number of steps to simulate for. temperature The temperature to simulate at. pressure The pressure to simulate at. platform The platform to simulate using. output_directory The optional directory to store the simulation outputs in. """ assert pressure is None or ( pressure is not None and box_vectors is not None ), "box vectors must be provided when the pressure is specified." topology.box_vectors = box_vectors # Create an OpenMM system by applying the parameters to the topology. omm_system, topology = force_field.create_openmm_system( topology, return_topology=True) if output_directory is not None: os.makedirs(output_directory, exist_ok=True) # Add the virtual sites to the OpenMM topology and positions. omm_topology = topology.to_openmm() omm_chain = [*omm_topology.chains()][0] omm_residue = omm_topology.addResidue("", chain=omm_chain) for particle in topology.topology_particles: if isinstance(particle, TopologyAtom): continue omm_topology.addAtom(particle.virtual_site.name, app.Element.getByMass(0), omm_residue) positions = numpy.vstack( [positions, numpy.zeros((topology.n_topology_virtual_sites, 3))]) with temporary_cd(output_directory): __simulate( positions=positions * unit.angstrom, box_vectors=box_vectors, omm_topology=omm_topology, omm_system=omm_system, n_steps=n_steps, temperature=temperature, pressure=pressure, platform=platform, )