コード例 #1
0
ファイル: smirnoff.py プロジェクト: LaYeqa/openff-system
    def store_potentials(self, parameter_handler: vdWHandler) -> None:
        """
        Populate self.potentials with key-val pairs of unique potential
        identifiers and their associated Potential objects

        """
        self.method = parameter_handler.method
        self.cutoff = parameter_handler.cutoff / omm_unit.angstrom

        for potential_key in self.slot_map.values():
            smirks = potential_key.id
            parameter_type = parameter_handler.get_parameter(
                {"smirks": smirks})[0]
            try:
                potential = Potential(parameters={
                    "sigma": parameter_type.sigma,
                    "epsilon": parameter_type.epsilon,
                }, )
            except AttributeError:
                # Handle rmin_half pending https://github.com/openforcefield/openff-toolkit/pull/750
                potential = Potential(parameters={
                    "sigma": parameter_type.sigma,
                    "epsilon": parameter_type.epsilon,
                }, )
            self.potentials[potential_key] = potential
コード例 #2
0
    def store_potentials(self,
                         parameter_handler: ImproperTorsionHandler) -> None:
        """
        Populate self.potentials with key-val pairs of unique potential
        identifiers and their associated Potential objects

        """
        for key in self.slot_map.values():
            # ParameterHandler.get_parameter returns a list, although this
            # should only ever be length 1
            smirks = key.split("_")[0]
            parameter_type = parameter_handler.get_parameter(
                {"smirks": smirks})[0]
            n_terms = len(parameter_type.k)
            for n in range(n_terms):
                identifier = key
                parameters = {
                    "k": parameter_type.k[n],
                    "periodicity":
                    parameter_type.periodicity[n] * unit.dimensionless,
                    "phase": parameter_type.phase[n],
                    "idivf": 3.0 * unit.dimensionless,
                }
                potential = Potential(parameters=parameters)
                self.potentials[identifier] = potential
コード例 #3
0
ファイル: smirnoff.py プロジェクト: LaYeqa/openff-system
 def store_potentials(self,
                      parameter_handler: LibraryChargeHandler) -> None:
     if self.potentials:
         self.potentials = dict()
     for potential_key in self.slot_map.values():
         smirks = potential_key.id
         parameter_type = parameter_handler.get_parameter(
             {"smirks": smirks})[0]
         charges_unitless = [val._value for val in parameter_type.charge]
         potential = Potential(parameters={
             "charges":
             charges_unitless * unit.elementary_charge
         }, )
         self.potentials[potential_key] = potential
コード例 #4
0
    def store_potentials(self, parameter_handler: BondHandler) -> None:
        """
        Populate self.potentials with key-val pairs of unique potential
        identifiers and their associated Potential objects

        """
        if self.potentials:
            self.potentials = dict()
        for smirks in self.slot_map.values():
            parameter_type = parameter_handler.get_parameter(
                {"smirks": smirks})[0]
            potential = Potential(parameters={
                "k": parameter_type.k,
                "length": parameter_type.length,
            }, )
            self.potentials[smirks] = potential
コード例 #5
0
    def store_potentials(self, parameter_handler: AngleHandler) -> None:
        """
        Populate self.potentials with key-val pairs of unique potential
        identifiers and their associated Potential objects

        """
        for smirks in self.slot_map.values():
            # ParameterHandler.get_parameter returns a list, although this
            # should only ever be length 1
            parameter_type = parameter_handler.get_parameter(
                {"smirks": smirks})[0]
            potential = Potential(parameters={
                "k": parameter_type.k,
                "angle": parameter_type.angle,
            }, )
            self.potentials[smirks] = potential
コード例 #6
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
コード例 #7
0
ファイル: smirnoff.py プロジェクト: LaYeqa/openff-system
    def store_potentials(self,
                         parameter_handler: ImproperTorsionHandler) -> None:
        """
        Populate self.potentials with key-val pairs of unique potential
        identifiers and their associated Potential objects

        """
        for potential_key in self.slot_map.values():
            smirks = potential_key.id
            n = potential_key.mult
            parameter_type = parameter_handler.get_parameter(
                {"smirks": smirks})[0]
            parameters = {
                "k": parameter_type.k[n],
                "periodicity":
                parameter_type.periodicity[n] * unit.dimensionless,
                "phase": parameter_type.phase[n],
                "idivf": 3.0 * unit.dimensionless,
            }
            potential = Potential(parameters=parameters)
            self.potentials[potential_key] = potential
コード例 #8
0
ファイル: smirnoff.py プロジェクト: LaYeqa/openff-system
    def store_constraints(
        self,
        parameter_handler: ConstraintHandler,
        bond_handler: SMIRNOFFBondHandler = None,
    ) -> None:
        """
        Populate self.constraints with key-val pairs of unique potential
        identifiers and their associated Potential objects

        TODO: Raname to store_potentials potentials for consistency?

        """
        if self.constraints:
            self.constraints = dict()
        for top_key, pot_key in self.slot_map.items():
            smirks = pot_key.id
            parameter_type = parameter_handler.get_parameter(
                {"smirks": smirks})[0]
            if parameter_type.distance:
                distance = parameter_type.distance
            else:
                if not bond_handler:
                    from openff.system.exceptions import MissingParametersError

                    raise MissingParametersError(
                        f"Constraint with SMIRKS pattern {smirks} found with no distance "
                        "specified, and no corresponding bond parameters were found. The distance "
                        "of this constraint is not specified.")
                # Look up by atom indices because constraint and bond SMIRKS may not match
                bond_key = bond_handler.slot_map[top_key]
                bond_parameter = bond_handler.potentials[bond_key].parameters
                distance = bond_parameter["length"]
            potential = Potential(parameters={
                "distance": distance,
            })
            self.constraints[pot_key] = potential  # type: ignore[assignment]
コード例 #9
0
ファイル: parmed.py プロジェクト: LaYeqa/openff-system
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
コード例 #10
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