def test_is_periodic(self): """Test the getter and setter for is_periodic""" vacuum_top = Topology() assert vacuum_top.is_periodic is False with pytest.raises(InvalidPeriodicityError): vacuum_top.is_periodic = True solvent_box = Topology() solvent_box.box_vectors = np.eye(3) * 4 * unit.nanometer assert solvent_box.is_periodic is True with pytest.raises(InvalidPeriodicityError): solvent_box.is_periodic = False solvent_box.box_vectors = None assert solvent_box.is_periodic is False
def test_box_vectors(self): """Test the getter and setter for box_vectors""" topology = Topology() good_box_vectors = unit.Quantity(np.eye(3) * 20 * unit.angstrom) one_dim_vectors = unit.Quantity(np.ones(3) * 20 * unit.angstrom) bad_shape_vectors = unit.Quantity(np.ones(2) * 20 * unit.angstrom) bad_units_vectors = unit.Quantity(np.ones(3) * 20 * unit.year) unitless_vectors = np.array([10, 20, 30]) assert topology.box_vectors is None for bad_vectors in [ bad_shape_vectors, bad_units_vectors, unitless_vectors, ]: with self.assertRaises(InvalidBoxVectorsError): topology.box_vectors = bad_vectors assert topology.box_vectors is None for good_vectors in [good_box_vectors, one_dim_vectors]: topology.box_vectors = good_vectors assert (topology.box_vectors == good_vectors * np.eye(3)).all()
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, )