コード例 #1
0
    def test_from_toolkit_packmol_boxes(self, pdb_path, unique_molecules):
        """
        Test loading some pre-prepared PACKMOL-generated systems.

        These use PDB files already prepared in the toolkit because PDB files are a pain.
        """
        pdb_file_path = get_data_file_path("systems/packmol_boxes/" + pdb_path)
        pdbfile = openmm.app.PDBFile(pdb_file_path)
        Topology.from_openmm(
            pdbfile.topology,
            unique_molecules=unique_molecules,
        )
コード例 #2
0
    def test_chemical_environments_matches_RDK(self):
        """Test Topology.chemical_environment_matches"""
        from simtk.openmm import app

        toolkit_wrapper = RDKitToolkitWrapper()
        pdbfile = app.PDBFile(
            get_data_file_path(
                "systems/packmol_boxes/cyclohexane_ethanol_0.4_0.6.pdb"))
        # toolkit_wrapper = RDKitToolkitWrapper()
        # molecules = [Molecule.from_file(get_data_file_path(name)) for name in ('molecules/ethanol.mol2',
        #                                                                      'molecules/cyclohexane.mol2')]
        molecules = []
        molecules.append(Molecule.from_smiles("CCO"))
        molecules.append(Molecule.from_smiles("C1CCCCC1"))
        topology = Topology.from_openmm(pdbfile.topology,
                                        unique_molecules=molecules)
        # Count CCO matches
        matches = topology.chemical_environment_matches(
            "[C:1]-[C:2]-[O:3]", toolkit_registry=toolkit_wrapper)
        assert len(matches) == 143
        assert matches[0].topology_atom_indices == (1728, 1729, 1730)
        matches = topology.chemical_environment_matches(
            "[H][C:1]([H])([H])-[C:2]([H])([H])-[O:3][H]",
            toolkit_registry=toolkit_wrapper,
        )
        assert (len(matches) == 1716
                )  # 143 * 12 (there are 12 possible hydrogen mappings)
        assert matches[0].topology_atom_indices == (1728, 1729, 1730)
        # Search for a substructure that isn't there
        matches = topology.chemical_environment_matches(
            "[C][C:1]-[C:2]-[O:3]", toolkit_registry=toolkit_wrapper)
        assert len(matches) == 0
コード例 #3
0
    def test_from_openmm_pdbfile(self, argon_ff, argon_top):
        pdb_file_path = get_test_file_path("10-argons.pdb")
        pdbfile = openmm.app.PDBFile(pdb_file_path)

        mol = Molecule.from_smiles("[#18]")
        top = Topology.from_openmm(pdbfile.topology, unique_molecules=[mol])
        box = pdbfile.topology.getPeriodicBoxVectors()
        box = box.value_in_unit(nm) * unit.nanometer

        out = argon_ff.create_openff_system(top)
        out.box = box
        out.positions = pdbfile.getPositions()

        assert np.allclose(
            out.positions.to(unit.nanometer).magnitude,
            pdbfile.getPositions().value_in_unit(nm),
        )

        get_openmm_energies(out, hard_cutoff=True).compare(
            _get_openmm_energies(
                omm_sys=argon_ff.create_openmm_system(top),
                box_vectors=pdbfile.topology.getPeriodicBoxVectors(),
                positions=pdbfile.getPositions(),
                hard_cutoff=True,
            ))
コード例 #4
0
    def test_from_toolkit_packmol_boxes(self, pdb_path, unique_molecules):
        """
        Test loading some pre-prepared PACKMOL-generated systems.

        These use PDB files already prepared in the toolkit because PDB files are a pain.
        """
        ff = ForceField("openff-1.0.0.offxml")

        pdb_file_path = get_data_file_path("systems/packmol_boxes/" + pdb_path)
        pdbfile = openmm.app.PDBFile(pdb_file_path)
        top = Topology.from_openmm(
            pdbfile.topology,
            unique_molecules=unique_molecules,
        )
        box = pdbfile.topology.getPeriodicBoxVectors()
        box = box.value_in_unit(nm) * unit.nanometer

        out = ff.create_openff_system(top)
        out.box = box
        out.positions = pdbfile.getPositions()

        assert np.allclose(
            out.positions.to(unit.nanometer).magnitude,
            pdbfile.getPositions().value_in_unit(nm),
        )

        get_openmm_energies(out, hard_cutoff=True).compare(
            _get_openmm_energies(
                omm_sys=ff.create_openmm_system(top),
                box_vectors=pdbfile.topology.getPeriodicBoxVectors(),
                positions=pdbfile.getPositions(),
                hard_cutoff=True,
            ))
コード例 #5
0
    def test_from_openmm(self):
        """Test creation of an OpenFF Topology object from an OpenMM Topology and component molecules"""
        from simtk.openmm import app

        pdbfile = app.PDBFile(
            get_data_file_path(
                "systems/packmol_boxes/cyclohexane_ethanol_0.4_0.6.pdb"))

        with pytest.raises(MissingUniqueMoleculesError,
                           match="requires a list of Molecule objects"):
            Topology.from_openmm(pdbfile.topology)

        molecules = [create_ethanol(), create_cyclohexane()]

        topology = Topology.from_openmm(pdbfile.topology,
                                        unique_molecules=molecules)
        assert topology.n_reference_molecules == 2
        assert topology.n_topology_molecules == 239
コード例 #6
0
    def test_to_from_openmm(self):
        """Test a round-trip OpenFF -> OpenMM -> OpenFF Topology."""
        from simtk.openmm.app import Aromatic

        # Create OpenFF topology with 1 ethanol and 2 benzenes.
        ethanol = Molecule.from_smiles("CCO")
        benzene = Molecule.from_smiles("c1ccccc1")
        off_topology = Topology.from_molecules(
            molecules=[ethanol, benzene, benzene])

        # Convert to OpenMM Topology.
        omm_topology = off_topology.to_openmm()

        # Check that bond orders are preserved.
        n_double_bonds = sum([b.order == 2 for b in omm_topology.bonds()])
        n_aromatic_bonds = sum(
            [b.type is Aromatic for b in omm_topology.bonds()])
        assert n_double_bonds == 6
        assert n_aromatic_bonds == 12

        # Check that there is one residue for each molecule.
        assert omm_topology.getNumResidues() == 3
        assert omm_topology.getNumChains() == 3

        # Convert back to OpenFF Topology.
        off_topology_copy = Topology.from_openmm(
            omm_topology, unique_molecules=[ethanol, benzene])

        # The round-trip OpenFF Topology is identical to the original.
        # The reference molecules are the same.
        assert (off_topology.n_reference_molecules ==
                off_topology_copy.n_reference_molecules)
        reference_molecules_copy = list(off_topology_copy.reference_molecules)
        for ref_mol_idx, ref_mol in enumerate(
                off_topology.reference_molecules):
            assert ref_mol == reference_molecules_copy[ref_mol_idx]

        # The number of topology molecules is the same.
        assert (off_topology.n_topology_molecules ==
                off_topology_copy.n_topology_molecules)

        # Check atoms.
        assert off_topology.n_topology_atoms == off_topology_copy.n_topology_atoms
        for atom_idx, atom in enumerate(off_topology.topology_atoms):
            atom_copy = off_topology_copy.atom(atom_idx)
            assert atom.atomic_number == atom_copy.atomic_number

        # Check bonds.
        for bond_idx, bond in enumerate(off_topology.topology_bonds):
            bond_copy = off_topology_copy.bond(bond_idx)
            bond_atoms = [a.atomic_number for a in bond.atoms]
            bond_atoms_copy = [a.atomic_number for a in bond_copy.atoms]
            assert bond_atoms == bond_atoms_copy
            assert bond.bond_order == bond_copy.bond_order
            assert bond.bond.is_aromatic == bond_copy.bond.is_aromatic
コード例 #7
0
    def _execute(self, directory, available_resources):

        from openff.toolkit.topology import Molecule, Topology

        pdb_file = app.PDBFile(self.coordinate_file_path)

        force_field_source = ForceFieldSource.from_json(self.force_field_path)

        if not isinstance(force_field_source, SmirnoffForceFieldSource):
            raise ValueError(
                "Only SMIRNOFF force fields are supported by this protocol."
            )

        force_field = force_field_source.to_force_field()

        # Create the molecules to parameterize from the input substance.
        unique_molecules = []

        for component in self.substance.components:

            molecule = Molecule.from_smiles(smiles=component.smiles)

            if molecule is None:
                raise ValueError(f"{component} could not be converted to a Molecule")

            unique_molecules.append(molecule)

        # Create the topology to parameterize from the input coordinates and the
        # expected molecule species.
        topology = Topology.from_openmm(
            pdb_file.topology, unique_molecules=unique_molecules
        )

        system = force_field.create_openmm_system(topology)

        if system is None:

            raise RuntimeError(
                "Failed to create a system from the specified topology and molecules."
            )

        system_xml = openmm.XmlSerializer.serialize(system)
        system_path = os.path.join(directory, "system.xml")

        with open(system_path, "w") as file:
            file.write(system_xml)

        self.parameterized_system = ParameterizedSystem(
            substance=self.substance,
            force_field=force_field_source,
            topology_path=self.coordinate_file_path,
            system_path=system_path,
        )
コード例 #8
0
    def test_from_openmm_missing_reference(self):
        """Test creation of an OpenFF Topology object from an OpenMM Topology when missing a unique molecule"""
        from simtk.openmm import app

        pdbfile = app.PDBFile(
            get_data_file_path(
                "systems/packmol_boxes/cyclohexane_ethanol_0.4_0.6.pdb"))

        molecules = [create_ethanol()]
        with pytest.raises(
                ValueError,
                match="No match found for molecule C6H12") as excinfo:
            topology = Topology.from_openmm(pdbfile.topology,
                                            unique_molecules=molecules)
コード例 #9
0
def test_openmm_nonbonded_methods(inputs):
    """See test_nonbonded_method_resolution in openff/toolkit/tests/test_forcefield.py"""
    vdw_method = inputs["vdw_method"]
    electrostatics_method = inputs["electrostatics_method"]
    periodic = inputs["periodic"]
    result = inputs["result"]

    molecules = [create_ethanol()]
    forcefield = ForceField("test_forcefields/test_forcefield.offxml")

    pdbfile = app.PDBFile(get_data_file_path("systems/test_systems/1_ethanol.pdb"))
    topology = Topology.from_openmm(pdbfile.topology, unique_molecules=molecules)

    if not periodic:
        topology.box_vectors = None

    if type(result) == int:
        nonbonded_method = result
        # The method is validated and may raise an exception if it's not supported.
        forcefield.get_parameter_handler("vdW", {}).method = vdw_method
        forcefield.get_parameter_handler(
            "Electrostatics", {}
        ).method = electrostatics_method
        openff_interchange = Interchange.from_smirnoff(
            force_field=forcefield, topology=topology
        )
        openmm_system = openff_interchange.to_openmm(combine_nonbonded_forces=True)
        for force in openmm_system.getForces():
            if isinstance(force, openmm.NonbondedForce):
                assert force.getNonbondedMethod() == nonbonded_method
                break
        else:
            raise Exception
    elif issubclass(result, (BaseException, Exception)):
        exception = result
        forcefield.get_parameter_handler("vdW", {}).method = vdw_method
        forcefield.get_parameter_handler(
            "Electrostatics", {}
        ).method = electrostatics_method
        openff_interchange = Interchange.from_smirnoff(
            force_field=forcefield, topology=topology
        )
        with pytest.raises(exception):
            openff_interchange.to_openmm(combine_nonbonded_forces=True)
    else:
        raise Exception("uh oh")
コード例 #10
0
    def test_from_openmm_duplicate_unique_mol(self):
        """Check that a DuplicateUniqueMoleculeError is raised if we try to pass in two indistinguishably unique mols"""
        from simtk.openmm import app

        pdbfile = app.PDBFile(
            get_data_file_path(
                "systems/packmol_boxes/cyclohexane_ethanol_0.4_0.6.pdb"))
        molecules = [
            Molecule.from_file(get_data_file_path(name)) for name in (
                "molecules/ethanol.mol2",
                "molecules/ethanol_reordered.mol2",
                "molecules/cyclohexane.mol2",
            )
        ]
        with self.assertRaises(DuplicateUniqueMoleculeError) as context:
            topology = Topology.from_openmm(pdbfile.topology,
                                            unique_molecules=molecules)
コード例 #11
0
def test_liquid_argon():
    argon = Molecule.from_smiles("[#18]")
    pdbfile = app.PDBFile(get_test_file_path("packed-argon.pdb"))

    top = Topology.from_openmm(pdbfile.topology, unique_molecules=[argon])

    argon_ff = ForceField(get_test_file_path("argon.offxml"))

    out = Interchange.from_smirnoff(argon_ff, top)
    out.positions = pdbfile.positions

    omm_energies = get_openmm_energies(out)

    gmx_energies = get_gromacs_energies(
        out,
        mdp="auto",
        writer="internal",
    )

    omm_energies.compare(
        gmx_energies,
        custom_tolerances={
            "vdW": 0.008 * simtk_unit.kilojoule_per_mole,
        },
    )

    argon_ff_no_switch = deepcopy(argon_ff)
    argon_ff_no_switch["vdW"].switch_width *= 0

    out_no_switch = Interchange.from_smirnoff(argon_ff_no_switch, top)
    out_no_switch.positions = pdbfile.positions

    lmp_energies = get_lammps_energies(out_no_switch)

    omm_energies.compare(
        lmp_energies,
        custom_tolerances={
            "vdW": 10.5 * simtk_unit.kilojoule_per_mole,
        },
    )
コード例 #12
0
    def test_from_openmm_missing_conect(self):
        """
        Test creation of an OpenFF Topology object from an OpenMM Topology
        when the origin PDB lacks CONECT records
        """
        from simtk.openmm import app

        pdbfile = app.PDBFile(
            get_data_file_path("systems/test_systems/1_ethanol_no_conect.pdb"))

        molecules = []
        molecules.append(Molecule.from_smiles("CCO"))
        with pytest.raises(
                ValueError,
                match="No match found for molecule C. This would be a "
                "very unusual molecule to try and parameterize, "
                "and it is likely that the data source it was "
                "read from does not contain connectivity "
                "information. If this molecule is coming from "
                "PDB, please ensure that the file contains CONECT "
                "records.",
        ) as excinfo:
            topology = Topology.from_openmm(pdbfile.topology,
                                            unique_molecules=molecules)
コード例 #13
0
def compare_condensed_systems(mol, force_field):
    from openff.evaluator import unit as evaluator_unit
    from openff.evaluator.utils.packmol import pack_box

    mass_density = 500 * evaluator_unit.kilogram / evaluator_unit.meter ** 3

    trj, assigned_residue_names = pack_box(
        molecules=[mol], number_of_copies=[100], mass_density=mass_density
    )

    try:
        openff_top = Topology.from_openmm(trj.top.to_openmm(), unique_molecules=[mol])
    except ValueError:
        print(f"Molecule failed! (conversion from OpenMM)\t{mol.to_inchi()}")
        return

    box_vectors = trj.unitcell_vectors[0] * simtk_unit.nanometer
    openff_top.box_vectors = box_vectors

    try:
        toolkit_sys = force_field.create_openmm_system(
            openff_top,
            charge_from_molecules=[mol],
        )

    except (
        UnassignedBondParameterException,
        UnassignedAngleParameterException,
        UnassignedProperTorsionParameterException,
    ):
        print(f"Molecule failed! (missing valence parameters)\t{mol.to_inchi()}")
        return

    positions = trj.xyz[0] * simtk_unit.nanometer
    toolkit_energy = _get_openmm_energies(
        toolkit_sys,
        box_vectors=box_vectors,
        positions=positions,
    )

    openff_sys = Interchange.from_smirnoff(force_field=force_field, topology=openff_top)
    openff_sys.box = box_vectors
    openff_sys.positions = trj.xyz[0] * unit.nanometer

    new_sys = openff_sys.to_openmm(combine_nonbonded_forces=True)

    system_energy = _get_openmm_energies(
        new_sys,
        box_vectors=box_vectors,
        positions=positions,
    )

    # Where energies to not precisely match, inspect all parameters in each force
    try:
        toolkit_energy.compare(
            system_energy,
            custom_tolerances={
                "Bond": 1e-6 * kj_mol,
                "Angle": 1e-6 * kj_mol,
                "Torsion": 4e-5 * kj_mol,
                "Nonbonded": 1e-5 * kj_mol,
            },
        )
    except EnergyError as e:
        if "Torsion" in str(e):
            _compare_torsion_forces(
                _get_force(toolkit_sys, openmm.PeriodicTorsionForce),
                _get_force(new_sys, openmm.PeriodicTorsionForce),
            )
        if "Nonbonded" in str(e):
            _compare_nonbonded_settings(
                _get_force(toolkit_sys, openmm.NonbondedForce),
                _get_force(new_sys, openmm.NonbondedForce),
            )
            _compare_nonbonded_parameters(
                _get_force(toolkit_sys, openmm.NonbondedForce),
                _get_force(new_sys, openmm.NonbondedForce),
            )
        if "Bond" in str(e):
            raise e
        if "Angle" in str(e):
            raise e
コード例 #14
0
    def _execute(self, directory, available_resources):

        from openff.toolkit.topology import Molecule, Topology

        force_field_source = ForceFieldSource.from_json(self.force_field_path)
        cutoff = pint_quantity_to_openmm(force_field_source.cutoff)

        # Load in the systems topology
        openmm_pdb_file = app.PDBFile(self.coordinate_file_path)

        # Create an OFF topology for better insight into the layout of the system
        # topology.
        unique_molecules = {}

        for component in self.substance:
            unique_molecule = Molecule.from_smiles(component.smiles)
            unique_molecules[unique_molecule.to_smiles()] = unique_molecule

        # Parameterize each component in the system.
        system_templates = {}

        for index, (smiles, unique_molecule) in enumerate(unique_molecules.items()):

            if smiles in ["O", "[H]O[H]", "[H][O][H]"]:

                component_system = self._build_tip3p_system(
                    cutoff,
                    openmm_pdb_file.topology.getUnitCellDimensions(),
                )

            else:

                component_directory = os.path.join(directory, str(index))
                os.makedirs(component_directory, exist_ok=True)

                with temporarily_change_directory(component_directory):

                    component_system = self._parameterize_molecule(
                        unique_molecule, force_field_source, cutoff
                    )

            system_templates[smiles] = component_system

        # Apply the parameters to the topology.
        topology = Topology.from_openmm(
            openmm_pdb_file.topology, unique_molecules.values()
        )

        # Create the full system object from the component templates.
        system = self._create_empty_system(cutoff)

        for topology_molecule in topology.topology_molecules:

            smiles = topology_molecule.reference_molecule.to_smiles()
            system_template = system_templates[smiles]

            index_map = {}

            for index, topology_atom in enumerate(topology_molecule.atoms):
                index_map[topology_atom.atom.molecule_particle_index] = index

            # Append the component template to the full system.
            self._append_system(system, system_template, index_map)

        if openmm_pdb_file.topology.getPeriodicBoxVectors() is not None:

            system.setDefaultPeriodicBoxVectors(
                *openmm_pdb_file.topology.getPeriodicBoxVectors()
            )

        # Serialize the system object.
        system_path = os.path.join(directory, "system.xml")

        with open(system_path, "w") as file:
            file.write(openmm.XmlSerializer.serialize(system))

        self.parameterized_system = ParameterizedSystem(
            substance=self.substance,
            force_field=force_field_source,
            topology_path=self.coordinate_file_path,
            system_path=system_path,
        )
コード例 #15
0
    def prepare(self, pbc=False, mmopts={}, **kwargs):
        """
        Prepare the calculation.  Note that we don't create the
        Simulation object yet, because that may depend on MD
        integrator parameters, thermostat, barostat etc.

        This is mostly copied and modified from openmmio.py's OpenMM.prepare(),
        but we are calling ForceField() from the OpenFF toolkit and ignoring
        AMOEBA stuff.
        """

        if hasattr(self, 'abspdb'):
            self.pdb = PDBFile(self.abspdb)
        else:
            pdb1 = "%s-1.pdb" % os.path.splitext(os.path.basename(
                self.mol.fnm))[0]
            self.mol[0].write(pdb1)
            self.pdb = PDBFile(pdb1)
            os.unlink(pdb1)

        # Create the OpenFF ForceField object.
        if hasattr(self, 'FF'):
            self.offxml = [self.FF.offxml]
            self.forcefield = self.FF.openff_forcefield
        else:
            self.offxml = listfiles(kwargs.get('offxml'), 'offxml', err=True)
            self.forcefield = OpenFF_ForceField(*self.offxml,
                                                load_plugins=True)

        ## Load mol2 files for smirnoff topology
        openff_mols = []
        for fnm in self.mol2:
            try:
                mol = OffMolecule.from_file(fnm)
            except Exception as e:
                logger.error("Error when loading %s" % fnm)
                raise e
            openff_mols.append(mol)
        self.off_topology = OffTopology.from_openmm(
            self.pdb.topology, unique_molecules=openff_mols)

        ## OpenMM options for setting up the System.
        self.mmopts = dict(mmopts)

        ## Specify frozen atoms and restraint force constant
        if 'restrain_k' in kwargs:
            self.restrain_k = kwargs['restrain_k']
        if 'freeze_atoms' in kwargs:
            self.freeze_atoms = kwargs['freeze_atoms'][:]

        ## Set system options from ForceBalance force field options.
        fftmp = False
        if hasattr(self, 'FF'):
            self.mmopts['rigidWater'] = self.FF.rigid_water
            if not all([os.path.exists(f) for f in self.FF.fnms]):
                # If the parameter files don't already exist, create them for the purpose of
                # preparing the engine, but then delete them afterward.
                fftmp = True
                self.FF.make(np.zeros(self.FF.np))

        ## Set system options from periodic boundary conditions.
        self.pbc = pbc
        ## print warning for 'nonbonded_cutoff' keywords
        if 'nonbonded_cutoff' in kwargs:
            logger.warning(
                "nonbonded_cutoff keyword ignored because it's set in the offxml file\n"
            )

        # Apply the FF parameters to the system. Currently this is the only way to
        # determine if the FF will apply virtual sites to the system.
        _, openff_topology = self.forcefield.create_openmm_system(
            self.off_topology, return_topology=True)

        ## Generate OpenMM-compatible positions
        self.xyz_omms = []

        for I in range(len(self.mol)):
            xyz = self.mol.xyzs[I]
            xyz_omm = ([Vec3(i[0], i[1], i[2]) for i in xyz]
                       # Add placeholder positions for an v-sites.
                       + [Vec3(0.0, 0.0, 0.0)] *
                       openff_topology.n_topology_virtual_sites) * angstrom

            if self.pbc:
                # Obtain the periodic box
                if self.mol.boxes[I].alpha != 90.0 or self.mol.boxes[
                        I].beta != 90.0 or self.mol.boxes[I].gamma != 90.0:
                    logger.error('OpenMM cannot handle nonorthogonal boxes.\n')
                    raise RuntimeError
                box_omm = np.diag([
                    self.mol.boxes[I].a, self.mol.boxes[I].b,
                    self.mol.boxes[I].c
                ]) * angstrom
            else:
                box_omm = None
            # Finally append it to list.
            self.xyz_omms.append((xyz_omm, box_omm))

        # used in create_simulation()
        openmm_topology = SMIRNOFF._openff_to_openmm_topology(openff_topology)
        openmm_positions = (
            self.pdb.positions.value_in_unit(angstrom) +
            # Add placeholder positions for an v-sites.
            [Vec3(0.0, 0.0, 0.0)] *
            openff_topology.n_topology_virtual_sites) * angstrom

        self.mod = Modeller(openmm_topology, openmm_positions)

        ## Build a topology and atom lists.
        Top = self.mod.getTopology()
        Atoms = list(Top.atoms())

        # vss = [(i, [system.getVirtualSite(i).getParticle(j) for j in range(system.getVirtualSite(i).getNumParticles())]) \
        #            for i in range(system.getNumParticles()) if system.isVirtualSite(i)]
        self.AtomLists = defaultdict(list)
        self.AtomLists['Mass'] = [
            a.element.mass.value_in_unit(dalton)
            if a.element is not None else 0 for a in Atoms
        ]
        self.AtomLists['ParticleType'] = [
            'A' if m >= 1.0 else 'D' for m in self.AtomLists['Mass']
        ]
        self.AtomLists['ResidueNumber'] = [a.residue.index for a in Atoms]
        self.AtomMask = [a == 'A' for a in self.AtomLists['ParticleType']]
        self.realAtomIdxs = [
            i for i, a in enumerate(self.AtomMask) if a is True
        ]
        if hasattr(self, 'FF') and fftmp:
            for f in self.FF.fnms:
                os.unlink(f)
コード例 #16
0
def reparm(ligands, base):
    print(
        '**Running reparameterization of ligand(s) using open force fields\'s SMIRNOFF with openff 2.0.0**'
    )
    # Load already parm'd system
    in_prmtop = base + '.prmtop'
    in_crd = base + '.inpcrd'

    # Create parmed strucuture
    orig_structure = parmed.amber.AmberParm(in_prmtop, in_crd)

    # Split orig_stucuture into unique structure instances e.g. protein, water, ligand, etc.
    pieces = orig_structure.split()
    for piece in pieces:
        # TODO: Figure out how to know which piece is which
        print(f"There are {len(piece[1])} instance(s) of {piece[0]}")

    # Generate an openff topology for the ligand
    # Openff Molecule does not support mol2 so conversion is needed
    ligs_w_sdf = []
    for ligand in ligands:
        obabel[ligand[0], '-O', util.get_base(ligand[0]) + '.sdf']()
        ligs_w_sdf.append(
            (ligand[0], ligand[1], util.get_base(ligand[0]) + '.sdf'))

    # Keep track of ligands that were successfully reparmed so we know to skip them when putting the pieces back together
    reparmed_pieces = []
    complex_structure = parmed.Structure()
    force_field = ForceField("openff_unconstrained-2.0.0.offxml")

    for lig in ligs_w_sdf:
        # Set up openff topology
        ligand_off_molecule = Molecule(lig[2])
        ligand_pdbfile = PDBFile(lig[0])
        ligand_off_topology = Topology.from_openmm(
            ligand_pdbfile.topology,
            unique_molecules=[ligand_off_molecule],
        )
        # Parameterizing the ligand
        # Find ligand "piece", reparm, add to the new structure
        for piece in pieces:
            new_ligand_structure = None
            # TODO: Figure out how to know which piece is which
            if (ligand_off_molecule.n_atoms == len(piece[0].atoms)):
                if (ligand_off_molecule.n_bonds == len(piece[0].bonds)):
                    if ([
                            atom.atomic_number
                            for atom in ligand_off_molecule.atoms
                    ] == [atom.element for atom in piece[0].atoms]):
                        print('Found ligand piece', piece)
                        try:
                            # Since the method of matching the piece to ligand is imperfect, ligands that are isomers could mess things up.
                            # So try any piece that matches and see if we get an error
                            print('Reparameterizing ligand using SMIRNOFF')
                            ligand_system = force_field.create_openmm_system(
                                ligand_off_topology)
                            new_ligand_structure = parmed.openmm.load_topology(
                                ligand_off_topology.to_openmm(),
                                ligand_system,
                                xyz=piece[0].positions,
                            )
                            # A quick check to make sure things were not messed up during param
                            if check_discrepencies(new_ligand_structure,
                                                   piece):
                                # Add the newly parameterized ligand the complex structure
                                reparmed_pieces.append(piece)
                                new_ligand_structure *= len(piece[1])
                                complex_structure += parmed.amber.AmberParm.from_structure(
                                    new_ligand_structure)
                            break
                        except:
                            pass

    # Stick all the pieces back together
    for piece in pieces:
        if (piece not in reparmed_pieces):
            curr_structure = parmed.Structure()
            curr_structure += piece[0]
            curr_structure *= len(piece[1])
            complex_structure += parmed.amber.AmberParm.from_structure(
                curr_structure)

    # print("Unique atom names:",sorted(list({atom.atom_type.name for atom in complex_structure})),)
    # print("Number of unique atom types:", len({atom.atom_type for atom in complex_structure}))
    # print("Number of unique epsilons:", len({atom.epsilon for atom in complex_structure}))
    # print("Number of unique sigmas:", len({atom.sigma for atom in complex_structure}))

    # # Copy over the original coordinates and box vectors
    complex_structure.coordinates = orig_structure.coordinates
    complex_structure.box_vectors = orig_structure.box_vectors

    # Save the newly parameterized system
    complex_structure.save(base + ".prmtop", overwrite=True)
    complex_structure.save(base + ".inpcrd", overwrite=True)
コード例 #17
0
ファイル: test_energies.py プロジェクト: LaYeqa/openff-system
def test_packmol_boxes(toolkit_file_path):
    # TODO: Isolate a set of systems here instead of using toolkit data
    # TODO: Fix nonbonded energy differences
    from openff.toolkit.utils import get_data_file_path

    pdb_file_path = get_data_file_path(toolkit_file_path)
    pdbfile = openmm.app.PDBFile(pdb_file_path)

    ethanol = Molecule.from_smiles("CCO")
    cyclohexane = Molecule.from_smiles("C1CCCCC1")
    omm_topology = pdbfile.topology
    off_topology = Topology.from_openmm(
        omm_topology, unique_molecules=[ethanol, cyclohexane]
    )

    parsley = ForceField("openff_unconstrained-1.0.0.offxml")

    off_sys = parsley.create_openff_system(off_topology)

    off_sys.box = np.asarray(
        pdbfile.topology.getPeriodicBoxVectors() / omm_unit.nanometer,
    )
    off_sys.positions = np.asarray(
        pdbfile.positions / omm_unit.nanometer,
    )

    sys_from_toolkit = parsley.create_openmm_system(off_topology)

    omm_energies = get_openmm_energies(off_sys, hard_cutoff=True, electrostatics=False)
    reference = _get_openmm_energies(
        sys_from_toolkit,
        off_sys.box,
        off_sys.positions,
        hard_cutoff=True,
        electrostatics=False,
    )

    omm_energies.compare(
        reference,
        custom_tolerances={
            "Nonbonded": 2e-2 * omm_unit.kilojoule_per_mole,
        },
    )

    # custom_tolerances={"HarmonicBondForce": 1.0}

    # Compare GROMACS writer and OpenMM export
    gmx_energies = get_gromacs_energies(off_sys, electrostatics=False)

    omm_energies_rounded = get_openmm_energies(
        off_sys,
        round_positions=8,
        hard_cutoff=True,
        electrostatics=False,
    )

    omm_energies_rounded.compare(
        other=gmx_energies,
        custom_tolerances={
            "Angle": 1e-2 * omm_unit.kilojoule_per_mole,
            "Torsion": 1e-2 * omm_unit.kilojoule_per_mole,
            "Nonbonded": 3200 * omm_unit.kilojoule_per_mole,
        },
    )