Exemplo n.º 1
0
 def store_matches(
     self,
     parameter_handler: ChargeIncrementModelHandler,
     topology: Topology,
 ) -> None:
     matches = parameter_handler.find_matches(topology)
     for key, val in matches.items():
         top_key = TopologyKey(atom_indices=key)
         pot_key = PotentialKey(id=val.parameter_type.smirks)
         self.slot_map[top_key] = pot_key
Exemplo n.º 2
0
    def store_matches(self, parameter_handler: AngleHandler,
                      topology: Topology) -> None:
        """
        Populate self.slot_map with key-val pairs of slots
        and unique potential identifiers

        """
        matches = parameter_handler.find_matches(topology)
        for key, val in matches.items():
            topology_key = TopologyKey(atom_indices=key)
            potential_key = PotentialKey(id=val.parameter_type.smirks)
            self.slot_map[topology_key] = potential_key
Exemplo n.º 3
0
    def store_matches(self, parameter_handler: ProperTorsionHandler,
                      topology: Topology) -> None:
        """
        Populate self.slot_map with key-val pairs of slots
        and unique potential identifiers

        """
        matches = parameter_handler.find_matches(topology)
        for key, val in matches.items():
            n_terms = len(val.parameter_type.k)
            for n in range(n_terms):
                smirks = val.parameter_type.smirks
                topology_key = TopologyKey(atom_indices=key, mult=n)
                potential_key = PotentialKey(id=smirks, mult=n)
                self.slot_map[topology_key] = potential_key
Exemplo n.º 4
0
def test_argon_buck():
    mol = Molecule.from_smiles("[#18]")
    top = Topology.from_molecules([mol, mol])

    A = 1.69e-8 * unit.Unit("erg / mol") * Avogadro
    B = 1 / (0.273 * unit.angstrom)
    C = 102e-12 * unit.Unit("erg / mol") * unit.angstrom**6 * Avogadro

    A = A.to(unit.Unit("kilojoule/mol"))
    B = B.to(unit.Unit("1 / nanometer"))
    C = C.to(unit.Unit("kilojoule / mol * nanometer ** 6"))

    r = 0.3 * unit.nanometer

    buck = BuckinghamvdWHandler()
    coul = ElectrostaticsMetaHandler()  # Just to pass compatibility checks

    pot_key = PotentialKey(id="[#18]")
    pot = Potential(parameters={"A": A, "B": B, "C": C})

    for top_atom in top.topology_atoms:
        top_key = TopologyKey(atom_indices=(top_atom.topology_atom_index, ))
        buck.slot_map.update({top_key: pot_key})
        coul.charges.update({top_key: 0 * unit.elementary_charge})

    buck.potentials[pot_key] = pot

    from openff.system.components.system import System

    out = System()
    out.handlers["Buckingham-6"] = buck
    out.handlers["Electrostatics"] = coul
    out.topology = top
    out.box = [10, 10, 10] * unit.nanometer
    out.positions = [[0, 0, 0], [0.3, 0, 0]] * unit.nanometer
    out.to_gro("out.gro", writer="internal")
    out.to_top("out.top", writer="internal")

    gmx_energies = get_gromacs_energies(out, mdp="cutoff_buck")
    omm_energies = get_openmm_energies(out)
    by_hand = A * exp(-B * r) - C * r**-6

    gmx_energies.compare(omm_energies)

    resid = simtk_to_pint(gmx_energies.energies["Nonbonded"]) - by_hand
    assert resid < 1e-5 * unit.kilojoule / unit.mol
Exemplo n.º 5
0
def from_parmed(cls) -> "System":

    from openff.system.components.system import System

    out = System()

    if cls.positions:
        out.positions = np.asarray(cls.positions._value) * unit.angstrom

    if any(cls.box[3:] != 3 * [90.0]):
        from openff.system.exceptions import UnsupportedBoxError

        raise UnsupportedBoxError(f"Found box with angles {cls.box[3:]}. Only"
                                  "rectangular boxes are currently supported.")

    out.box = cls.box[:3] * unit.angstrom

    from openff.toolkit.topology import Molecule, Topology

    top = Topology()

    for res in cls.residues:
        mol = Molecule()
        mol.name = res.name
        for atom in res.atoms:
            mol.add_atom(atomic_number=atom.atomic_number,
                         formal_charge=0,
                         is_aromatic=False)
        for atom in res.atoms:
            for bond in atom.bonds:
                try:
                    mol.add_bond(
                        atom1=bond.atom1.idx,
                        atom2=bond.atom2.idx,
                        bond_order=int(bond.order),
                        is_aromatic=False,
                    )
                # TODO: Use a custom exception after
                # https://github.com/openforcefield/openff-toolkit/issues/771
                except Exception as e:
                    if "Bond already exists" in str(e):
                        pass
                    else:
                        raise e

        top.add_molecule(mol)

    out.topology = top

    from openff.system.components.smirnoff import (
        ElectrostaticsMetaHandler,
        SMIRNOFFAngleHandler,
        SMIRNOFFBondHandler,
        SMIRNOFFImproperTorsionHandler,
        SMIRNOFFProperTorsionHandler,
        SMIRNOFFvdWHandler,
    )

    vdw_handler = SMIRNOFFvdWHandler()
    coul_handler = ElectrostaticsMetaHandler()

    for atom in cls.atoms:
        atom_idx = atom.idx
        sigma = atom.sigma * unit.angstrom
        epsilon = atom.epsilon * kcal_mol
        charge = atom.charge * unit.elementary_charge
        top_key = TopologyKey(atom_indices=(atom_idx, ))
        pot_key = PotentialKey(id=str(atom_idx))
        pot = Potential(parameters={"sigma": sigma, "epsilon": epsilon})

        vdw_handler.slot_map.update({top_key: pot_key})
        vdw_handler.potentials.update({pot_key: pot})

        coul_handler.charges.update({top_key: charge})

    bond_handler = SMIRNOFFBondHandler()

    for bond in cls.bonds:
        atom1 = bond.atom1
        atom2 = bond.atom2
        k = bond.type.k * kcal_mol_a2
        length = bond.type.req * unit.angstrom
        top_key = TopologyKey(atom_indices=(atom1.idx, atom2.idx))
        pot_key = PotentialKey(id=f"{atom1.idx}-{atom2.idx}")
        pot = Potential(parameters={"k": k * 2, "length": length})

        bond_handler.slot_map.update({top_key: pot_key})
        bond_handler.potentials.update({pot_key: pot})

    out.handlers.update({"vdW": vdw_handler})
    out.handlers.update({"Electrostatics":
                         coul_handler})  # type: ignore[dict-item]
    out.handlers.update({"Bonds": bond_handler})

    angle_handler = SMIRNOFFAngleHandler()

    for angle in cls.angles:
        atom1 = angle.atom1
        atom2 = angle.atom2
        atom3 = angle.atom3
        k = angle.type.k * kcal_mol_rad2
        theta = angle.type.theteq * unit.degree
        top_key = TopologyKey(atom_indices=(atom1.idx, atom2.idx, atom3.idx))
        pot_key = PotentialKey(id=f"{atom1.idx}-{atom2.idx}-{atom3.idx}")
        pot = Potential(parameters={"k": k * 2, "angle": theta})

        angle_handler.slot_map.update({top_key: pot_key})
        angle_handler.potentials.update({pot_key: pot})

    proper_torsion_handler = SMIRNOFFProperTorsionHandler()
    improper_torsion_handler = SMIRNOFFImproperTorsionHandler()

    for dihedral in cls.dihedrals:
        atom1 = dihedral.atom1
        atom2 = dihedral.atom2
        atom3 = dihedral.atom3
        atom4 = dihedral.atom4
        k = dihedral.type.phi_k * kcal_mol_rad2
        periodicity = dihedral.type.per * unit.dimensionless
        phase = dihedral.type.phase * unit.degree
        if dihedral.improper:
            # ParmEd stores the central atom _third_ (AMBER style)
            # SMIRNOFF stores the central atom _second_
            # https://parmed.github.io/ParmEd/html/topobj/parmed.topologyobjects.Dihedral.html#parmed-topologyobjects-dihedral
            # https://open-forcefield-toolkit.readthedocs.io/en/latest/smirnoff.html#impropertorsions
            top_key = TopologyKey(
                atom_indices=(atom1.idx, atom2.idx, atom2.idx, atom4.idx),
                mult=1,
            )
            pot_key = PotentialKey(
                id=f"{atom1.idx}-{atom3.idx}-{atom2.idx}-{atom4.idx}",
                mult=1,
            )
            pot = Potential(parameters={
                "k": k,
                "periodicity": periodicity,
                "phase": phase
            })

            while pot_key in improper_torsion_handler.potentials:
                pot_key.mult += 1  # type: ignore[operator]
                top_key.mult += 1  # type: ignore[operator]

            improper_torsion_handler.slot_map.update({top_key: pot_key})
            improper_torsion_handler.potentials.update({pot_key: pot})
        else:
            top_key = TopologyKey(
                atom_indices=(atom1.idx, atom2.idx, atom3.idx, atom4.idx),
                mult=1,
            )
            pot_key = PotentialKey(
                id=f"{atom1.idx}-{atom2.idx}-{atom3.idx}-{atom4.idx}",
                mult=1,
            )
            pot = Potential(parameters={
                "k": k,
                "periodicity": periodicity,
                "phase": phase
            })

            while pot_key in proper_torsion_handler.potentials:
                pot_key.mult += 1  # type: ignore[operator]
                top_key.mult += 1  # type: ignore[operator]

            proper_torsion_handler.slot_map.update({top_key: pot_key})
            proper_torsion_handler.potentials.update({pot_key: pot})

    out.handlers.update({"Electrostatics":
                         coul_handler})  # type: ignore[dict-item]
    out.handlers.update({"Bonds": bond_handler})
    out.handlers.update({"Angles": angle_handler})
    out.handlers.update({"ProperTorsions": proper_torsion_handler})

    return out
Exemplo n.º 6
0
def test_ethanol_opls():
    mol = Molecule.from_smiles("CC")
    mol.generate_conformers(n_conformers=1)
    top = mol.to_topology()
    parsley = ForceField("openff-1.0.0.offxml")
    out = parsley.create_openff_system(top)
    out.box = [4, 4, 4]
    out.positions = mol.conformers[0]
    out.positions = np.round(out.positions, 2)

    rb_torsions = RBTorsionHandler()
    smirks = "[#1:1]-[#6X4:2]-[#6X4:3]-[#1:4]"
    pot_key = PotentialKey(id=smirks)
    for proper in top.propers:
        top_key = TopologyKey(atom_indices=tuple(a.topology_atom_index
                                                 for a in proper))
        rb_torsions.slot_map.update({top_key: pot_key})

    # Values from HC-CT-CT-HC RB torsion
    # https://github.com/mosdef-hub/foyer/blob/7816bf53a127502520a18d76c81510f96adfdbed/foyer/forcefields/xml/oplsaa.xml#L2585
    pot = Potential(
        parameters={
            "c0": 0.6276 * kj_mol,
            "c1": 1.8828 * kj_mol,
            "c2": 0.0 * kj_mol,
            "c3": -2.5104 * kj_mol,
            "c4": 0.0 * kj_mol,
            "c5": 0.0 * kj_mol,
        })

    rb_torsions.potentials.update({pot_key: pot})

    out.handlers.update({"RBTorsions": rb_torsions})
    out.handlers.pop("ProperTorsions")

    gmx = get_openmm_energies(out, round_positions=3).energies["Torsion"]
    omm = get_gromacs_energies(out).energies["Torsion"]

    assert (gmx - omm).value_in_unit(omm_unit.kilojoule_per_mole) < 1e-3

    # Given that these force constants are copied from Foyer's OPLS-AA file,
    # compare to processing through the current MoSDeF pipeline
    try:
        import foyer
        import mbuild
    except ModuleNotFoundError:
        return

    comp = mbuild.load("CC", smiles=True)
    comp.xyz = mol.conformers[0].value_in_unit(omm_unit.nanometer)
    ff = foyer.Forcefield(name="oplsaa")
    from_foyer = ff.apply(comp)
    from_foyer.box = [40, 40, 40, 90, 90, 90]
    from_foyer.save("from_foyer.top")
    from_foyer.save("from_foyer.gro")

    rb_torsion_energy_from_foyer = run_gmx_energy(
        top_file="from_foyer.top",
        gro_file="from_foyer.gro",
        mdp_file=get_mdp_file("default"),
    ).energies["Torsion"]

    assert (omm - rb_torsion_energy_from_foyer).value_in_unit(
        omm_unit.kilojoule_per_mole) < 1e-3