Esempio n. 1
0
    def _find_nb_force(self, system: mm.System) -> None:
        forces = [system.getForce(i) for i in range(system.getNumForces())]
        nb_forces = [f for f in forces if isinstance(f, mm.NonbondedForce)]

        if not nb_forces:
            raise RuntimeError("REST2 could not find NonbondedForce")
        if len(nb_forces) > 1:
            raise RuntimeError("REST2 found more than one NonbondedForce")

        self.nb_force = nb_forces[0]
Esempio n. 2
0
    def _find_dihedral_force(self, system: mm.System) -> None:
        forces = [system.getForce(i) for i in range(system.getNumForces())]
        dihed_forces = [
            f for f in forces if isinstance(f, mm.PeriodicTorsionForce)
        ]

        if not dihed_forces:
            raise RuntimeError("REST2 could not find PeriodicTorsionForce")
        if len(dihed_forces) > 1:
            raise RuntimeError(
                "REST2 found more than one PeriodicTorsionForce")

        self.dihedral_force = dihed_forces[0]
Esempio n. 3
0
def _get_openmm_energies(
    omm_sys: openmm.System,
    box_vectors,
    positions,
    round_positions=None,
    hard_cutoff=False,
    electrostatics: bool = True,
) -> EnergyReport:
    """Given a prepared `openmm.System`, run a single-point energy calculation."""
    """\
    if hard_cutoff:
        omm_sys = _set_nonbonded_method(
            omm_sys, "cutoff", electrostatics=electrostatics
        )
    else:
        omm_sys = _set_nonbonded_method(omm_sys, "PME")
    """

    for idx, force in enumerate(omm_sys.getForces()):
        force.setForceGroup(idx)

    integrator = openmm.VerletIntegrator(1.0 * unit.femtoseconds)
    context = openmm.Context(omm_sys, integrator)

    if box_vectors is not None:
        if not isinstance(box_vectors, (unit.Quantity, list)):
            box_vectors = box_vectors.magnitude * unit.nanometer
        context.setPeriodicBoxVectors(*box_vectors)

    if isinstance(positions, unit.Quantity):
        # Convert list of Vec3 into a NumPy array
        positions = np.asarray(positions.value_in_unit(
            unit.nanometer)) * unit.nanometer
    else:
        positions = positions.magnitude * unit.nanometer

    if round_positions is not None:
        rounded = np.round(positions, round_positions)
        context.setPositions(rounded)
    else:
        context.setPositions(positions)

    raw_energies = dict()
    omm_energies = dict()

    for idx in range(omm_sys.getNumForces()):
        state = context.getState(getEnergy=True, groups={idx})
        raw_energies[idx] = state.getPotentialEnergy()
        del state

    # This assumes that only custom forces will have duplicate instances
    for key in raw_energies:
        force = omm_sys.getForce(key)
        if type(force) == openmm.HarmonicBondForce:
            omm_energies["HarmonicBondForce"] = raw_energies[key]
        elif type(force) == openmm.HarmonicAngleForce:
            omm_energies["HarmonicAngleForce"] = raw_energies[key]
        elif type(force) == openmm.PeriodicTorsionForce:
            omm_energies["PeriodicTorsionForce"] = raw_energies[key]
        elif type(force) in [
                openmm.NonbondedForce,
                openmm.CustomNonbondedForce,
                openmm.CustomBondForce,
        ]:
            if "Nonbonded" in omm_energies:
                omm_energies["Nonbonded"] += raw_energies[key]
            else:
                omm_energies["Nonbonded"] = raw_energies[key]

    # Fill in missing keys if interchange does not have all typical forces
    for required_key in [
            "HarmonicBondForce",
            "HarmonicAngleForce",
            "PeriodicTorsionForce",
            "NonbondedForce",
    ]:
        if not any(required_key in val for val in omm_energies):
            pass  # omm_energies[required_key] = 0.0 * kj_mol

    del context
    del integrator

    report = EnergyReport()

    report.update_energies({
        "Bond":
        omm_energies.get("HarmonicBondForce", 0.0 * kj_mol),
        "Angle":
        omm_energies.get("HarmonicAngleForce", 0.0 * kj_mol),
        "Torsion":
        _canonicalize_torsion_energies(omm_energies),
        "Nonbonded":
        omm_energies.get("Nonbonded",
                         _canonicalize_nonbonded_energies(omm_energies)),
    })

    report.energies.pop("vdW")
    report.energies.pop("Electrostatics")

    return report
Esempio n. 4
0
    def from_system(cls, system: openmm.System, indices: Dict[str, int]):
        """Instantiate a COOHDummyMover for a single C-COOH moiety in your system.

        Parameters
        ----------
        system - The OpenMM system containting the COOH moiety
        indices - a dictionary labeling the indices of the C-COOH atoms with keys:
            HO - index in the system of the hydroxyl hydrogen.
            OH - index in the system of the hydroxyl oxygen
            OC - index in the system of the carbonyl oxygen
            CO - index in the system of the carbonyl carbon
            R -  index in the system of the atom "R"  this COOH group is connected to.
        """
        obj = cls()
        # Hydroxyl hydrogen
        obj.HO = indices["HO"]
        # Hydroxyl oxygen
        obj.OH = indices["OH"]
        # Carbonyl oxygen
        obj.OC = indices["OC"]
        # The carbons are used as reference points for reflection
        obj.CO = indices["CO"]
        obj.R = indices["R"]

        # All atoms that this class may decide to move
        obj.movable = [indices["OC"], indices["OH"], indices["HO"]]
        # The parameters for angles
        obj.angles = []
        # The parameters for dihedrals
        obj.dihedrals = []

        # Instantiate the class variable
        # This is to keep track of angle and torsion force indices for all future instances
        if (
            COOHDummyMover.angleforceindex is None
            or COOHDummyMover.dihedralforceindex is None
        ):
            for force_index in range(system.getNumForces()):
                force = system.getForce(force_index)
                if force.__class__.__name__ == "HarmonicAngleForce":
                    COOHDummyMover.angleforceindex = force_index
                elif force.__class__.__name__ == "PeriodicTorsionForce":
                    COOHDummyMover.dihedralforceindex = force_index
            if COOHDummyMover.angleforceindex is None:
                raise RuntimeError(
                    "{} requires the system to have a HarmonicAngleForce!".format(
                        COOHDummyMover.__name__
                    )
                )
            if COOHDummyMover.dihedralforceindex is None:
                raise RuntimeError(
                    "{} requires the system to have a PeriodicTorsionForce!".format(
                        COOHDummyMover.__name__
                    )
                )

        angleforce = system.getForce(COOHDummyMover.angleforceindex)
        torsionforce = system.getForce(COOHDummyMover.dihedralforceindex)

        # Loop through and collect all angle energy terms that include moving atoms
        for angle_index in range(angleforce.getNumAngles()):
            *particles, theta0, k = angleforce.getAngleParameters(angle_index)
            if any(particle in obj.movable for particle in particles):
                # Energy function for this angle.
                params = [k._value, theta0._value, *particles]
                log.debug("Found this COOH angle: %s", params)
                obj.angles.append(params)

        # Loop through and collect all torsion energy terms that include moving atoms
        for torsion_index in range(torsionforce.getNumTorsions()):
            *particles, n, theta0, k = torsionforce.getTorsionParameters(torsion_index)
            if any(particle in obj.movable for particle in particles):
                # Energy function for this dihedral.
                params = [k._value, n, theta0._value, *particles]
                log.debug("Found this COOH dihedral: %s", params)
                obj.dihedrals.append(params)
        return obj