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")
Ejemplo n.º 2
0
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,
        )