Ejemplo n.º 1
0
def set_nonbonded_method(
    omm_sys: openmm.System,
    key: str,
    electrostatics: bool = True,
) -> openmm.System:

    if key == "cutoff":
        for force in omm_sys.getForces():
            if type(force) == openmm.NonbondedForce:
                force.setNonbondedMethod(openmm.NonbondedForce.CutoffPeriodic)
                force.setCutoffDistance(0.9 * unit.nanometer)
                force.setReactionFieldDielectric(1.0)
                force.setUseDispersionCorrection(False)
                force.setUseSwitchingFunction(False)
                if not electrostatics:
                    for i in range(force.getNumParticles()):
                        params = force.getParticleParameters(i)
                        force.setParticleParameters(
                            i,
                            0,
                            params[1],
                            params[2],
                        )

    elif key == "PME":
        for force in omm_sys.getForces():
            if type(force) == openmm.NonbondedForce:
                force.setNonbondedMethod(openmm.NonbondedForce.PME)
                force.setEwaldErrorTolerance(1e-6)

    return omm_sys
Ejemplo n.º 2
0
def _get_charges_from_openmm_system(omm_sys: openmm.System):
    for force in omm_sys.getForces():
        if type(force) == openmm.NonbondedForce:
            break
    for idx in range(omm_sys.getNumParticles()):
        param = force.getParticleParameters(idx)
        yield param[0].value_in_unit(simtk_unit.elementary_charge)
Ejemplo n.º 3
0
def _get_force(openmm_sys: openmm.System, force_type):
    forces = [f for f in openmm_sys.getForces() if type(f) == force_type]

    if len(forces) > 1:
        raise NotImplementedError(
            "Not yet able to process duplicate forces types")
    return forces[0]
Ejemplo n.º 4
0
def _get_lj_params_from_openmm_system(omm_sys: openmm.System):
    for force in omm_sys.getForces():
        if type(force) == openmm.NonbondedForce:
            break
    n_particles = omm_sys.getNumParticles()
    sigmas = np.asarray([*_get_sigma_from_nonbonded_force(n_particles, force)])
    epsilons = np.asarray([*_get_epsilon_from_nonbonded_force(n_particles, force)])

    return sigmas, epsilons
Ejemplo n.º 5
0
def zero_dihedral_contribution(openmm_system: openmm.System, dihedral_indices: Tuple[int, int]):
    """
    Author Simon Boothroyd
    Link gist.github.com/SimonBoothroyd/667b50314c628aabe5064f0defb6ad8e
    Zeroes out the contributions of a particular dihedral to the total potential
    energy for a given OpenMM system object.

    Parameters
    ----------
    openmm_system:
        The OpenMM system object which will be modified so the specified dihedral will
        not contribute to the total potential energy of the system.
    dihedral_indices:
        The indices of the two central atoms in the dihedral whose contributions should
        be zeroed.
    """
    torsion_forces = [
        force
        for force in openmm_system.getForces()
        if isinstance(force, openmm.PeriodicTorsionForce)
    ]
    for torsion_force in torsion_forces:
        for torsion_index in range(torsion_force.getNumTorsions()):
            (
                index_i,
                index_j,
                index_k,
                index_l,
                periodicity,
                phase,
                k,
            ) = torsion_force.getTorsionParameters(torsion_index)
            if (
                    index_j not in [dihedral_indices[0], dihedral_indices[1]]
                    or index_k not in [dihedral_indices[0], dihedral_indices[1]]
            ):
                continue
            torsion_force.setTorsionParameters(
                torsion_index,
                index_i,
                index_j,
                index_k,
                index_l,
                periodicity,
                phase,
                0.0
            )
Ejemplo n.º 6
0
def _get_openmm_energies(
    omm_sys: openmm.System,
    box_vectors,
    positions,
    round_positions=None,
    hard_cutoff=False,
    electrostatics: bool = True,
) -> EnergyReport:

    if hard_cutoff:
        omm_sys = set_nonbonded_method(omm_sys,
                                       "cutoff",
                                       electrostatics=electrostatics)
    else:
        omm_sys = set_nonbonded_method(omm_sys, "PME")

    force_names = {force.__class__.__name__ for force in omm_sys.getForces()}
    group_to_force = {
        i: force_name
        for i, force_name in enumerate(force_names)
    }
    force_to_group = {
        force_name: i
        for i, force_name in group_to_force.items()
    }

    for force in omm_sys.getForces():
        force_name = force.__class__.__name__
        force.setForceGroup(force_to_group[force_name])

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

    if not isinstance(box_vectors, unit.Quantity):
        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)

    force_groups = {
        force.getForceGroup()
        for force in context.getSystem().getForces()
    }

    omm_energies = dict()

    for force_group in force_groups:
        state = context.getState(getEnergy=True, groups={force_group})
        omm_energies[group_to_force[force_group]] = state.getPotentialEnergy()
        del state

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

    del context
    del integrator

    report = EnergyReport()

    report.energies.update({
        "Bond": omm_energies["HarmonicBondForce"],
        "Angle": omm_energies["HarmonicAngleForce"],
        "Torsion": omm_energies["PeriodicTorsionForce"],
        "Nonbonded": omm_energies["NonbondedForce"],
    })

    if "CustomNonbondedForce" in omm_energies:
        report.energies["Nonbonded"] += omm_energies["CustomNonbondedForce"]

    if "RBTorsionForce" in omm_energies:
        report.energies["Torsion"] += omm_energies["RBTorsionForce"]

    return report
Ejemplo n.º 7
0
    def add_interactions(self, state: interfaces.IState, system: mm.System,
                         topology: app.Topology) -> mm.System:
        # The approach we use is based on
        # Habeck, Nilges, Rieping, J. Biomol. NMR., 2007, 135-144.
        #
        # Rather than solving for the exact alignment tensor
        # every step, we sample from a distribution of alignment
        # tensors.
        #
        # We encode the five components of the alignment tensor in
        # the positions of two dummy atoms relative to the center
        # of mass. The value of kappa should be scaled so that the
        # components of the alignment tensor are approximately unity.
        #
        # There is a restraint on the z-component of the seocnd dummy
        # particle to ensure that it does not diffuse off to ininity,
        # which could cause precision issues.
        if self.active:
            rdc_force = mm.CustomCentroidBondForce(
                5,
                "Erest + z_scaler*Ez;"
                "Erest = (1 - step(dev - quadcut)) * quad + step(dev - quadcut) * linear;"
                "linear = 0.5 * k_rdc * quadcut^2 + k_rdc * quadcut * (dev - quadcut);"
                "quad = 0.5 * k_rdc * dev^2;"
                "dev = max(0, abs(d_obs - dcalc) - flat);"
                "dcalc=2/3 * kappa_rdc/r^5 * (s1*(rx^2-ry^2) + s2*(3*rz^2-r^2) + s3*2*rx*ry + s4*2*rx*rz + s5*2*ry*rz);"
                "r=distance(g4, g5);"
                "rx=x4-x5;"
                "ry=y4-y5;"
                "rz=z4-z5;"
                "s1=x2-x1;"
                "s2=y2-y1;"
                "s3=z2-z1;"
                "s4=x3-x1;"
                "s5=y3-y1;"
                "Ez=(z3-z1)^2;",
            )
            rdc_force.addPerBondParameter("d_obs")
            rdc_force.addPerBondParameter("kappa_rdc")
            rdc_force.addPerBondParameter("k_rdc")
            rdc_force.addPerBondParameter("flat")
            rdc_force.addPerBondParameter("quadcut")
            rdc_force.addPerBondParameter("z_scaler")

            for experiment in self.expt_dict:
                # find the set of all atoms involved in this experiment
                com_ind = set()
                for r in self.expt_dict[experiment]:
                    com_ind.add(r.atom_index_1)
                    com_ind.add(r.atom_index_2)

                # add groups for the COM and dummy particles
                s1 = self.expt_dict[experiment][0].s1_index
                s2 = self.expt_dict[experiment][0].s2_index
                g1 = rdc_force.addGroup(list(com_ind))
                g2 = rdc_force.addGroup([s1])
                g3 = rdc_force.addGroup([s2])

                # add non-bonded exclusions between dummy particles and all other atoms
                nb_forces = [
                    f for f in system.getForces()
                    if isinstance(f, mm.NonbondedForce)
                    or isinstance(f, mm.CustomNonbondedForce)
                ]
                for nb_force in nb_forces:
                    n_parts = nb_force.getNumParticles()
                    for i in range(n_parts):
                        if isinstance(nb_force, mm.NonbondedForce):
                            if i != s1:
                                nb_force.addException(i,
                                                      s1,
                                                      0.0,
                                                      0.0,
                                                      0.0,
                                                      replace=True)
                            if i != s2:
                                nb_force.addException(i,
                                                      s2,
                                                      0.0,
                                                      0.0,
                                                      0.0,
                                                      replace=True)
                        else:
                            if i != s1:
                                nb_force.addExclusion(i, s1)
                            if i != s2:
                                nb_force.addExclusion(i, s2)

                for r in self.expt_dict[experiment]:
                    # add groups for the atoms involved in the RDC
                    g4 = rdc_force.addGroup([r.atom_index_1])
                    g5 = rdc_force.addGroup([r.atom_index_2])
                    rdc_force.addBond(
                        [g1, g2, g3, g4, g5],
                        [
                            r.d_obs,
                            r.kappa,
                            0.0,
                            r.tolerance,
                            r.quadratic_cut,
                            0,
                        ],  # z_scaler initial value shouldn't matter
                    )

            system.addForce(rdc_force)
            self.force = rdc_force
        return system
Ejemplo n.º 8
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