예제 #1
0
    def add_interactions(self, state: interfaces.IState, system: mm.System,
                         topology: app.Topology) -> mm.System:
        if self.active:
            if self.use_pbc:
                cartesian_force = mm.CustomExternalForce(
                    "0.5 * cart_force_const * r_eff^2;"
                    "r_eff = max(0.0, r - cart_delta);"
                    "r = periodicdistance(x, y, z, cart_x, cart_y, cart_z)")
            else:
                cartesian_force = mm.CustomExternalForce(
                    "0.5 * cart_force_const * r_eff^2;"
                    "r_eff = max(0.0, r - cart_delta);"
                    "r = sqrt(dx*dx + dy*dy + dz*dz);"
                    "dx = x - cart_x;"
                    "dy = y - cart_y;"
                    "dz = z - cart_z;")
            cartesian_force.addPerParticleParameter("cart_x")
            cartesian_force.addPerParticleParameter("cart_y")
            cartesian_force.addPerParticleParameter("cart_z")
            cartesian_force.addPerParticleParameter("cart_delta")
            cartesian_force.addPerParticleParameter("cart_force_const")

            # add the atoms
            for r in self.restraints:
                weight = r.force_const
                cartesian_force.addParticle(r.atom_index,
                                            [r.x, r.y, r.z, r.delta, weight])
            system.addForce(cartesian_force)
            self.force = cartesian_force
        return system
예제 #2
0
def add_harmonic_restraints(system: mm.System, args: ListOfArgs):
    """Restraints format is different here than in SM webservice.
    Example record: :10 :151\n
    or
    :10 :151 0.1 30000\n
    :i :j distance energy
    """
    print("      Adding harmonic restraints")
    if args.HR_USE_FLAT_BOTTOM_FORCE:
        contact_force = mm.CustomBondForce('step(r-r0) * (k/2) * (r-r0)^2')
        contact_force.addPerBondParameter('r0')
        contact_force.addPerBondParameter('k')
    else:
        contact_force = mm.HarmonicBondForce()
    system.addForce(contact_force)

    with open(args.HR_RESTRAINTS_PATH) as input_file:
        counter = 0
        for line in input_file:
            columns = line.split()
            atom_index_i = int(columns[0][1:]) - 1
            atom_index_j = int(columns[1][1:]) - 1
            try:
                r0 = float(columns[2])
                k = float(columns[3]) * args.HR_K_SCALE
            except IndexError:
                r0 = args.HR_R0_PARAM
                k = args.HR_K_PARAM
            if args.HR_USE_FLAT_BOTTOM_FORCE:
                contact_force.addBond(atom_index_i, atom_index_j, [r0, k])
            else:
                contact_force.addBond(atom_index_i, atom_index_j, r0, k)
            counter += 1
    print(f"         {counter} restraints added.")
예제 #3
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)
예제 #4
0
파일: ommtop.py 프로젝트: jbarnoud/omm-top
    def setup_system_non_bonded(self, system: mm.System, cutoff: Quantity):
        if self.non_bonded_function_type != NB_FUNCTION_LENNARD_JONES:
            # TODO: Implement Buckingham potential
            raise NotImplementedError(
                f'Non bonded function {self.non_bonded_function_type} '
                'is not implemented.')

        if self.combination_rule in '1':
            potential = potentials.create_c6c12(cutoff=cutoff)
        elif self.combination_rule in '2':
            potential = potentials.create_epsilon_sigma(cutoff=cutoff)
        else:
            # TODO: implement combination rule 3
            raise NotImplementedError(
                f'Combination rule {self.combination_rule} is not implemented.'
            )

        for molecule_name, number_of_molecule_copies in self.molecules:
            molecule = self.molecule_types[molecule_name]
            for _ in range(number_of_molecule_copies):
                for atom in molecule.atoms.values():
                    ptype = self.atom_types[atom.type_]
                    potential.addParticle([ptype.v, ptype.w])

        system.addForce(potential)
        return potential
예제 #5
0
    def add_interactions(self, state: interfaces.IState,
                         openmm_system: mm.System,
                         topology: app.Topology) -> mm.System:
        if not self._active:
            return openmm_system

        cmap_force = mm.CMAPTorsionForce()
        cmap_force.addMap(self._gly_map.shape[0], self._gly_map.flatten())
        cmap_force.addMap(self._pro_map.shape[0], self._pro_map.flatten())
        cmap_force.addMap(self._ala_map.shape[0], self._ala_map.flatten())
        cmap_force.addMap(self._gen_map.shape[0], self._gen_map.flatten())

        # loop over all of the contiguous chains of amino acids
        for chain in self._iterate_cmap_chains():
            # loop over the interior residues
            n_res = len(chain)
            for i in range(1, n_res - 1):
                map_index = residue_to_map[chain[i].res_name]
                c_prev = chain[i - 1].index_C
                n = chain[i].index_N
                ca = chain[i].index_CA
                c = chain[i].index_C
                n_next = chain[i + 1].index_N
                cmap_force.addTorsion(map_index, c_prev, n, ca, c, n, ca, c,
                                      n_next)
        openmm_system.addForce(cmap_force)
        return openmm_system
예제 #6
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
예제 #7
0
def add_reaction_coordinate(
    system: openmm.System,
    host_index: List[int],
    guest_index: List[int],
    k_z: simtk_unit.Quantity,
    z_0: simtk_unit.Quantity,
    force_group: Optional[int] = 11,
):
    """
    Applies the umbrella reaction coordinate to the guest molecule
    """

    # Simple umbrella potential string expression
    reaction = openmm.CustomCentroidBondForce(
        2, "0.5 * k_z * (r_z - z_0)^2;" "r_z = z2 - z1;"
    )
    reaction.setUsesPeriodicBoundaryConditions(False)
    reaction.setForceGroup(force_group)

    # Umbrella parameters
    reaction.addPerBondParameter("k_z", k_z)
    reaction.addPerBondParameter("z_0", z_0)

    # Add host and guest indices
    g1 = reaction.addGroup(host_index)
    g2 = reaction.addGroup(guest_index)

    # Add bond
    reaction.addBond([g1, g2], [k_z, z_0])

    # Add force to system
    system.addForce(reaction)
예제 #8
0
    def add_interactions(
        self, state: interfaces.IState, system: mm.System, topology: app.Topology
    ) -> mm.System:
        if self.active:
            # create the confinement force
            if self.use_pbc:
                confinement_force = mm.CustomExternalForce(
                    "step(r - radius) * force_const * (radius - r)^2;"
                    "r = periodicdistance(x, y, z, 0, 0 ,0)"
                )
            else:
                confinement_force = mm.CustomExternalForce(
                    "step(r - radius) * force_const * (radius - r)^2;"
                    "r=sqrt(x*x + y*y + z*z)"
                )
            confinement_force.addPerParticleParameter("radius")
            confinement_force.addPerParticleParameter("force_const")

            # add the atoms
            for r in self.restraints:
                weight = r.force_const
                confinement_force.addParticle(r.atom_index, [r.radius, weight])
            system.addForce(confinement_force)
            self.force = confinement_force

        return system
예제 #9
0
def add_constraints(system: mm.System, args: ListOfArgs):
    print("      Adding constraints...")
    print(f"         r = {args.POL_CONSTRAINT_DISTANCE}")
    counter = 0
    for i in range(system.getNumParticles() - 1):
        system.addConstraint(i, i + 1, args.POL_CONSTRAINT_DISTANCE)
        counter += 1
    print(f"         {counter} constraints added.")
예제 #10
0
파일: meld.py 프로젝트: arupmondal835/meld
    def add_interactions(self, state: interfaces.IState, system: mm.System,
                         topology: app.Topology) -> mm.System:
        if self.active:
            meld_force = MeldForce()

            # Add all of the always-on restraints
            if self.always_on:
                group_list = []
                for rest in self.always_on:
                    rest_index = _add_meld_restraint(self.tracker, rest,
                                                     meld_force, 0, 0)
                    # Each restraint goes in its own group.
                    group_index = meld_force.addGroup([rest_index], 1)
                    group_list.append(group_index)

                    # Add the group to the tracker, but as None, so
                    # we won't update it.
                    self.tracker.groups.append(None)

                # All of the always-on restraints go in a single collection
                meld_force.addCollection(group_list, len(group_list))

                # Add this collection to the tracker, but as
                # None, so we won't update it
                self.tracker.collections.append(None)

            # Add the selectively active restraints
            for coll in self.selective_on:
                group_indices = []
                for group in coll.groups:
                    restraint_indices = []
                    for rest in group.restraints:
                        rest_index = _add_meld_restraint(
                            self.tracker, rest, meld_force, 0, 0)
                        restraint_indices.append(rest_index)

                    # Create the group in the meldplugin
                    group_num_active = self._handle_num_active(
                        group.num_active, state)
                    group_index = meld_force.addGroup(restraint_indices,
                                                      group_num_active)
                    group_indices.append(group_index)

                    # Add the group to the tracker so we can update it
                    self.tracker.groups.append(group)

                # Create the collection in the meldplugin
                coll_num_active = self._handle_num_active(
                    group.num_active, state)
                meld_force.addCollection(group_indices, coll_num_active)

                # Add the collection to the tracker so we can update it
                self.tracker.collections.append(coll)

            system.addForce(meld_force)
            self.force = meld_force
        return system
예제 #11
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
예제 #12
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]
예제 #13
0
def add_harmonic_angle(system: mm.System, args: ListOfArgs):
    print("      Adding harmonic angles...")
    print(f"         r0 = {args.POL_HARMONIC_ANGLE_R0}")
    print(f"         k = {args.POL_HARMONIC_ANGLE_K} kJ/mol/radian^2")
    bond_force = mm.HarmonicAngleForce()
    system.addForce(bond_force)
    counter = 0
    for i in range(system.getNumParticles() - 2):
        bond_force.addAngle(i, i + 1, i + 2, args.POL_HARMONIC_ANGLE_R0, args.POL_HARMONIC_ANGLE_K)
        counter += 1
    print(f"         {counter} harmonic bonds added.")
예제 #14
0
def add_harmonic_bond(system: mm.System, args: ListOfArgs):
    print("      Adding harmonic bonds...")
    print(f"         r0 = {args.POL_HARMONIC_BOND_R0}")
    print(f"         k = {args.POL_HARMONIC_BOND_K} kJ/mol/nm^2")
    bond_force = mm.HarmonicBondForce()
    system.addForce(bond_force)
    counter = 0
    for i in range(system.getNumParticles() - 1):
        bond_force.addBond(i, i + 1, args.POL_HARMONIC_BOND_R0, args.POL_HARMONIC_BOND_K)
        counter += 1
    print(f"         {counter} harmonic bonds added.")
예제 #15
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]
예제 #16
0
def add_excluded_volume(system: mm.System, args: ListOfArgs):
    print("      Adding excluded volume...")
    print(f"         epsilon = {args.EV_EPSILON}")
    print(f"         sigma = {args.EV_SIGMA}")
    ev_force = mm.CustomNonbondedForce('epsilon*((sigma1+sigma2)/r)^12')
    ev_force.addGlobalParameter('epsilon', defaultValue=args.EV_EPSILON)
    ev_force.addPerParticleParameter('sigma')
    system.addForce(ev_force)
    counter = 0
    for i in range(system.getNumParticles()):
        ev_force.addParticle([args.EV_SIGMA])
        counter += 1
    print(f"         {counter} ev interactions added.")
예제 #17
0
def add_external_field(system: mm.System, args: ListOfArgs):
    """Add external forcefield for image-driven modelling purposes."""
    print('      Adding external forcefield.')
    size = os.stat(args.EF_PATH).st_size
    print(f"   Reading {args.EF_PATH} file ({sizeof_fmt(size)})...")
    img = np.load(args.EF_PATH)
    print(f"   Array of shape {img.shape} loaded.")
    print(f"   Number of values: {img.size}")
    print(f"   Min: {np.min(img)}")
    print(f"   Max: {np.max(img)}")
    if args.EF_NORMALIZE:
        print('   [INFO] Field will be normalized to [0, -1]')
        img = standardize_image(img)
    print(f'   [INFO] IMG min = {np.min(img)}, max = {np.max(img)}')
    print(f'   [INFO] Adding funnel like border to image')
    mask_p = (img < -0.1)
    mask_n = np.logical_not(mask_p)
    img = add_funnel(img, mask_n)
    print("  Creating a force based on density...")
    voxel_size = np.array((args.EF_VOXEL_SIZE_X, args.EF_VOXEL_SIZE_Y, args.EF_VOXEL_SIZE_Z))
    real_size = img.shape * voxel_size
    density_fun_args = dict(
        xsize=img.shape[2],
        ysize=img.shape[1],
        zsize=img.shape[0],
        values=img.flatten().astype(np.float64),
        xmin=0 * simtk.unit.angstrom - 0.5 * voxel_size[0],
        ymin=0 * simtk.unit.angstrom - 0.5 * voxel_size[1],
        zmin=0 * simtk.unit.angstrom - 0.5 * voxel_size[2],
        xmax=(img.shape[0] - 1) * voxel_size[0] + 0.5 * voxel_size[0],
        ymax=(img.shape[1] - 1) * voxel_size[1] + 0.5 * voxel_size[1],
        zmax=(img.shape[2] - 1) * voxel_size[2] + 0.5 * voxel_size[2])

    print(f'   [INFO] Voxel size: ({args.EF_VOXEL_SIZE_X}, {args.EF_VOXEL_SIZE_Y}, {args.EF_VOXEL_SIZE_Z})')
    print(f'   [INFO] Real size (Shape * voxel size): ({real_size[0]}, {real_size[1]}, {real_size[2]})')
    print(
        f"   [INFO] begin coords: ({density_fun_args['xmin']}, {density_fun_args['ymin']}, {density_fun_args['zmin']})")
    print(
        f"   [INFO] end coords:   ({density_fun_args['xmax']}, {density_fun_args['ymax']}, {density_fun_args['zmax']})")
    center_x = (density_fun_args['xmax'] - density_fun_args['xmin']) / 2 + density_fun_args['xmin']
    center_y = (density_fun_args['ymax'] - density_fun_args['ymin']) / 2 + density_fun_args['ymin']
    center_z = (density_fun_args['zmax'] - density_fun_args['zmin']) / 2 + density_fun_args['zmin']
    print(f"   [INFO] Image central point: ({center_x}, {center_y}, {center_z}) ")
    field_function = mm.Continuous3DFunction(**density_fun_args)
    field_force = mm.CustomCompoundBondForce(1, 'ksi*fi(x1,y1,z1)')
    field_force.addTabulatedFunction('fi', field_function)
    field_force.addGlobalParameter('ksi', args.EF_SCALING_FACTOR)
    print("  Adding force to the system...")
    for i in range(system.getNumParticles()):
        field_force.addBond([i], [])
    system.addForce(field_force)
예제 #18
0
def add_spherical_container(system: mm.System, args: ListOfArgs):
    print("      Adding spherical container...")
    container_force = mm.CustomExternalForce(
        '{}*max(0, r-{})^2; r=sqrt((x-{})^2+(y-{})^2+(z-{})^2)'.format(args.SC_SCALE,
                                                                       args.SC_RADIUS,
                                                                       args.SC_CENTER_X,
                                                                       args.SC_CENTER_Y,
                                                                       args.SC_CENTER_Z,
                                                                       ))
    system.addForce(container_force)
    for i in range(system.getNumParticles()):
        container_force.addParticle(i, [])
    print(f"         Spherical container added.")
    print(f"            radius: {args.SC_RADIUS} nm")
    print(f"            scale:  {args.SC_SCALE} ")
    print(f"            center: ({args.SC_CENTER_X}, {args.SC_CENTER_Y}, {args.SC_CENTER_Z})")
예제 #19
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]
예제 #20
0
def add_funnel_potential(
    system: openmm.System,
    host_index: List[int],
    guest_index: List[int],
    k_xy: Optional[simtk_unit.Quantity] = 10.0
    * simtk_unit.kilocalorie_per_mole
    / simtk_unit.angstrom ** 2,
    z_cc: Optional[simtk_unit.Quantity] = 11.0 * simtk_unit.angstrom,
    alpha: Optional[simtk_unit.Quantity] = 35.0 * simtk_unit.degrees,
    R_cylinder: Optional[simtk_unit.Quantity] = 1.0 * simtk_unit.angstrom,
    force_group: Optional[int] = 10,
):
    """
    Applies a funnel potential to a guest molecule
    """

    # Funnel potential string expression
    funnel = openmm.CustomCentroidBondForce(
        2,
        "U_funnel + U_cylinder;"
        "U_funnel = step(z_cc - abs(r_z))*step(r_xy - R_funnel)*Wall;"
        "U_cylinder = step(abs(r_z) - z_cc)*step(r_xy - R_cylinder)*Wall;"
        "Wall = 0.5 * k_xy * r_xy^2;"
        "R_funnel = (z_cc-abs(r_z))*tan(alpha) + R_cylinder;"
        "r_xy = sqrt((x2 - x1)^2 + (y2 - y1)^2);"
        "r_z = z2 - z1;",
    )
    funnel.setUsesPeriodicBoundaryConditions(False)
    funnel.setForceGroup(force_group)

    # Funnel parameters
    funnel.addGlobalParameter("k_xy", k_xy)
    funnel.addGlobalParameter("z_cc", z_cc)
    funnel.addGlobalParameter("alpha", alpha)
    funnel.addGlobalParameter("R_cylinder", R_cylinder)

    # Add host and guest indices
    g1 = funnel.addGroup(host_index)
    g2 = funnel.addGroup(guest_index)

    # Add bond
    funnel.addBond([g1, g2], [])

    # Add force to system
    system.addForce(funnel)
예제 #21
0
def _add_restraints(system: openmm.System, reference_pdb: openmm_app.PDBFile,
                    stiffness: unit.Unit, rset: str,
                    exclude_residues: Sequence[int]):
    """Adds a harmonic potential that restrains the system to a structure."""
    assert rset in ["non_hydrogen", "c_alpha"]

    force = openmm.CustomExternalForce(
        "0.5 * k * ((x-x0)^2 + (y-y0)^2 + (z-z0)^2)")
    force.addGlobalParameter("k", stiffness)
    for p in ["x0", "y0", "z0"]:
        force.addPerParticleParameter(p)

    for i, atom in enumerate(reference_pdb.topology.atoms()):
        if atom.residue.index in exclude_residues:
            continue
        if will_restrain(atom, rset):
            force.addParticle(i, reference_pdb.positions[i])
    logger.info("Restraining %d / %d particles.", force.getNumParticles(),
                system.getNumParticles())
    system.addForce(force)
예제 #22
0
    def add_interactions(self, state: interfaces.IState, system: mm.System,
                         topology: app.Topology) -> mm.System:
        if self.active:
            rest = self.restraints[0]

            # create the expression for the energy
            components = []
            if "x" in rest.dims:
                components.append("(x1-abscom_x)*(x1-abscom_x)")
            if "y" in rest.dims:
                components.append("(y1-abscom_y)*(y1-abscom_y)")
            if "z" in rest.dims:
                components.append("(z1-abscom_z)*(z1-abscom_z)")
            dist_expr = "dist2={};".format(" + ".join(components))
            energy_expr = "0.5 * com_k * dist2;"
            expr = "\n".join([energy_expr, dist_expr])

            # create the force
            force = mm.CustomCentroidBondForce(1, expr)
            force.addPerBondParameter("com_k")
            force.addPerBondParameter("abscom_x")
            force.addPerBondParameter("abscom_y")
            force.addPerBondParameter("abscom_z")

            # create the restraint with parameters
            if rest.weights:
                g1 = force.addGroup(rest.indices, rest.weights)
            else:
                g1 = force.addGroup(rest.indices)
            force_const = rest.force_const
            pos_x = rest.position[0]
            pos_y = rest.position[1]
            pos_z = rest.position[2]
            force.addBond([g1], [force_const, pos_x, pos_y, pos_z])

            system.addForce(force)
            self.force = force
        return system
예제 #23
0
    def add_interactions(self, state: interfaces.IState, system: mm.System,
                         topology: app.Topology) -> mm.System:
        if self.active:
            rest = self.restraints[0]

            # create the expression for the energy
            components = []
            if "x" in rest.dims:
                components.append("(x1-x2)*(x1-x2)")
            if "y" in rest.dims:
                components.append("(y1-y2)*(y1-y2)")
            if "z" in rest.dims:
                components.append("(z1-z2)*(z1-z2)")
            dist_expr = "dist = sqrt({});".format(" + ".join(components))
            energy_expr = "0.5 * com_k * (dist - com_ref_dist)*(dist-com_ref_dist);"
            expr = "\n".join([energy_expr, dist_expr])

            # create the force
            force = mm.CustomCentroidBondForce(2, expr)
            force.addPerBondParameter("com_k")
            force.addPerBondParameter("com_ref_dist")

            # create the restraint with parameters
            if rest.weights1:
                g1 = force.addGroup(rest.indices1, rest.weights1)
            else:
                g1 = force.addGroup(rest.indices1)
            if rest.weights2:
                g2 = force.addGroup(rest.indices2, rest.weights2)
            else:
                g2 = force.addGroup(rest.indices2)
            force_const = rest.force_const
            pos = rest.positioner(0)
            force.addBond([g1, g2], [force_const, pos])

            system.addForce(force)
            self.force = force
        return system
예제 #24
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
            )
예제 #25
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
예제 #26
0
    def addHydrogens(self, forcefield=None, pH=None, variants=None, platform=None):
        """Add missing hydrogens to the model.

        This function automatically changes compatible residues into their constant-pH variant if no variant is specified.:

        Aspartic acid:
            AS4: Form with a 2 hydrogens on each one of the delta oxygens (syn,anti)
                It has 5 titration states.

            Alternative:
            AS2: Has 2 hydrogens (syn, anti) on one of the delta oxygens
                It has 3 titration states.

        Cysteine:
            CYS: Neutral form with a hydrogen on the sulfur
            CYX: No hydrogen on the sulfur (either negatively charged, or part of a disulfide bond)

        Glutamic acid:
            GL4: Form with a 2 hydrogens on each one of the epsilon oxygens (syn,anti)
                It has 5 titration states.

        Histidine:
            HIP: Positively charged form with hydrogens on both ND1 and NE2
                It has 3 titration states.

        The variant to use for each residue is determined by the following rules:

        1. Any Cysteine that participates in a disulfide bond uses the CYX variant regardless of pH.
        2. Other residues are all set to maximally protonated state, which can be updated using a proton drive

        You can override these rules by explicitly specifying a variant for any residue.  To do that, provide a list for the
        'variants' parameter, and set the corresponding element to the name of the variant to use.

        A special case is when the model already contains a hydrogen that should not be present in the desired variant.
        If you explicitly specify a variant using the 'variants' parameter, the residue will be modified to match the
        desired variant, removing hydrogens if necessary.  On the other hand, for residues whose variant is selected
        automatically, this function will only add hydrogens.  It will never remove ones that are already present in the
        model.

        Definitions for standard amino acids and nucleotides are built in.  You can call loadHydrogenDefinitions() to load
        additional definitions for other residue types.

        Parameters
        ----------
        forcefield : ForceField=None
            the ForceField to use for determining the positions of hydrogens.
            If this is None, positions will be picked which are generally
            reasonable but not optimized for any particular ForceField.
        pH : None,
            Kept for compatibility reasons. Has no effect.
        variants : list=None
            an optional list of variants to use.  If this is specified, its
            length must equal the number of residues in the model.  variants[i]
            is the name of the variant to use for residue i (indexed starting at
            0). If an element is None, the standard rules will be followed to
            select a variant for that residue.
        platform : Platform=None
            the Platform to use when computing the hydrogen atom positions.  If
            this is None, the default Platform will be used.

        Returns
        -------
        list
             a list of what variant was actually selected for each residue,
             in the same format as the variants parameter

        Notes
        -----

        This function does not use a pH specification. The argument is kept for compatibility reasons.

        """
        # Check the list of variants.

        if pH is not None:
            print("Ignored pH argument provided for constant-pH residues.")

        residues = list(self.topology.residues())
        if variants is not None:
            if len(variants) != len(residues):
                raise ValueError(
                    "The length of the variants list must equal the number of residues"
                )
        else:
            variants = [None] * len(residues)
        actualVariants = [None] * len(residues)

        # Load the residue specifications.

        if not Modeller._hasLoadedStandardHydrogens:
            Modeller.loadHydrogenDefinitions(
                os.path.join(
                    os.path.dirname(__file__), "data", "hydrogens-amber10-constph.xml"
                )
            )

        # Make a list of atoms bonded to each atom.

        bonded = {}
        for atom in self.topology.atoms():
            bonded[atom] = []
        for atom1, atom2 in self.topology.bonds():
            bonded[atom1].append(atom2)
            bonded[atom2].append(atom1)

        # Define a function that decides whether a set of atoms form a hydrogen bond, using fairly tolerant criteria.

        def isHbond(d, h, a):
            if norm(d - a) > 0.35 * nanometer:
                return False
            deltaDH = h - d
            deltaHA = a - h
            deltaDH /= norm(deltaDH)
            deltaHA /= norm(deltaHA)
            return acos(dot(deltaDH, deltaHA)) < 50 * degree

        # Loop over residues.

        newTopology = Topology()
        newTopology.setPeriodicBoxVectors(self.topology.getPeriodicBoxVectors())
        newAtoms = {}
        newPositions = [] * nanometer
        newIndices = []
        acceptors = [
            atom
            for atom in self.topology.atoms()
            if atom.element in (elem.oxygen, elem.nitrogen)
        ]
        for chain in self.topology.chains():
            newChain = newTopology.addChain(chain.id)
            for residue in chain.residues():
                newResidue = newTopology.addResidue(residue.name, newChain, residue.id)
                isNTerminal = residue == chain._residues[0]
                isCTerminal = residue == chain._residues[-1]
                if residue.name in Modeller._residueHydrogens:
                    # Add hydrogens.  First select which variant to use.

                    spec = Modeller._residueHydrogens[residue.name]
                    variant = variants[residue.index]
                    if variant is None:
                        if residue.name == "CYS":
                            # If this is part of a disulfide, use CYX.

                            sulfur = [
                                atom
                                for atom in residue.atoms()
                                if atom.element == elem.sulfur
                            ]
                            if len(sulfur) == 1 and any(
                                (atom.residue != residue for atom in bonded[sulfur[0]])
                            ):
                                variant = "CYX"
                        if residue.name == "HIS":
                            variant = "HIP"
                        if residue.name == "GLU":
                            variant = "GL4"
                        if residue.name == "ASP":
                            variant = "AS4"
                    if variant is not None and variant not in spec.variants:
                        raise ValueError(
                            "Illegal variant for %s residue: %s"
                            % (residue.name, variant)
                        )
                    actualVariants[residue.index] = variant
                    removeExtraHydrogens = variants[residue.index] is not None

                    # Make a list of hydrogens that should be present in the residue.

                    parents = [
                        atom
                        for atom in residue.atoms()
                        if atom.element != elem.hydrogen
                    ]
                    parentNames = [atom.name for atom in parents]
                    hydrogens = [
                        h
                        for h in spec.hydrogens
                        if (variant is None)
                        or (h.variants is None)
                        or (h.variants is not None and variant in h.variants)
                    ]
                    hydrogens = [
                        h
                        for h in hydrogens
                        if h.terminal is None
                        or (isNTerminal and h.terminal == "N")
                        or (isCTerminal and h.terminal == "C")
                    ]
                    hydrogens = [h for h in hydrogens if h.parent in parentNames]

                    # Loop over atoms in the residue, adding them to the new topology along with required hydrogens.

                    for parent in residue.atoms():
                        # Check whether this is a hydrogen that should be removed.

                        if (
                            removeExtraHydrogens
                            and parent.element == elem.hydrogen
                            and not any(parent.name == h.name for h in hydrogens)
                        ):
                            continue

                        # Add the atom.

                        newAtom = newTopology.addAtom(
                            parent.name, parent.element, newResidue
                        )
                        newAtoms[parent] = newAtom
                        newPositions.append(deepcopy(self.positions[parent.index]))
                        if parent in parents:
                            # Match expected hydrogens with existing ones and find which ones need to be added.

                            existing = [
                                atom
                                for atom in bonded[parent]
                                if atom.element == elem.hydrogen
                            ]
                            expected = [h for h in hydrogens if h.parent == parent.name]
                            if len(existing) < len(expected):
                                # Try to match up existing hydrogens to expected ones.

                                matches = []
                                for e in existing:
                                    match = [h for h in expected if h.name == e.name]
                                    if len(match) > 0:
                                        matches.append(match[0])
                                        expected.remove(match[0])
                                    else:
                                        matches.append(None)

                                # If any hydrogens couldn't be matched by name, just match them arbitrarily.

                                for i in range(len(matches)):
                                    if matches[i] is None:
                                        matches[i] = expected[-1]
                                        expected.remove(expected[-1])

                                # Add the missing hydrogens.

                                for h in expected:
                                    newH = newTopology.addAtom(
                                        h.name, elem.hydrogen, newResidue
                                    )
                                    newIndices.append(newH.index)
                                    delta = Vec3(0, 0, 0) * nanometer
                                    if len(bonded[parent]) > 0:
                                        for other in bonded[parent]:
                                            delta += (
                                                self.positions[parent.index]
                                                - self.positions[other.index]
                                            )
                                    else:
                                        delta = (
                                            Vec3(
                                                random.random(),
                                                random.random(),
                                                random.random(),
                                            )
                                            * nanometer
                                        )
                                    delta *= 0.1 * nanometer / norm(delta)
                                    delta += (
                                        0.05
                                        * Vec3(
                                            random.random(),
                                            random.random(),
                                            random.random(),
                                        )
                                        * nanometer
                                    )
                                    delta *= 0.1 * nanometer / norm(delta)
                                    newPositions.append(
                                        self.positions[parent.index] + delta
                                    )
                                    newTopology.addBond(newAtom, newH)
                else:
                    # Just copy over the residue.

                    for atom in residue.atoms():
                        newAtom = newTopology.addAtom(
                            atom.name, atom.element, newResidue
                        )
                        newAtoms[atom] = newAtom
                        newPositions.append(deepcopy(self.positions[atom.index]))
        for bond in self.topology.bonds():
            if bond[0] in newAtoms and bond[1] in newAtoms:
                newTopology.addBond(newAtoms[bond[0]], newAtoms[bond[1]])

        # The hydrogens were added at random positions.  Now perform an energy minimization to fix them up.

        if forcefield is not None:
            # Use the ForceField the user specified.

            system = forcefield.createSystem(newTopology, rigidWater=False)
            atoms = list(newTopology.atoms())
            for i in range(system.getNumParticles()):
                if atoms[i].element != elem.hydrogen:
                    # This is a heavy atom, so make it immobile.
                    system.setParticleMass(i, 0)
        else:
            # Create a System that restrains the distance of each hydrogen from its parent atom
            # and causes hydrogens to spread out evenly.

            system = System()
            nonbonded = CustomNonbondedForce("100/((r/0.1)^4+1)")
            bonds = HarmonicBondForce()
            angles = HarmonicAngleForce()
            system.addForce(nonbonded)
            system.addForce(bonds)
            system.addForce(angles)
            bondedTo = []
            for atom in newTopology.atoms():
                nonbonded.addParticle([])
                if atom.element != elem.hydrogen:
                    system.addParticle(0.0)
                else:
                    system.addParticle(1.0)
                bondedTo.append([])
            for atom1, atom2 in newTopology.bonds():
                if atom1.element == elem.hydrogen or atom2.element == elem.hydrogen:
                    bonds.addBond(atom1.index, atom2.index, 0.1, 100_000.0)
                bondedTo[atom1.index].append(atom2)
                bondedTo[atom2.index].append(atom1)
            for residue in newTopology.residues():
                if residue.name == "HOH":
                    # Add an angle term to make the water geometry correct.

                    atoms = list(residue.atoms())
                    oindex = [
                        i for i in range(len(atoms)) if atoms[i].element == elem.oxygen
                    ]
                    if len(atoms) == 3 and len(oindex) == 1:
                        hindex = list(set([0, 1, 2]) - set(oindex))
                        angles.addAngle(
                            atoms[hindex[0]].index,
                            atoms[oindex[0]].index,
                            atoms[hindex[1]].index,
                            1.824,
                            836.8,
                        )
                else:
                    # Add angle terms for any hydroxyls.

                    for atom in residue.atoms():
                        index = atom.index
                        if (
                            atom.element == elem.oxygen
                            and len(bondedTo[index]) == 2
                            and elem.hydrogen in (a.element for a in bondedTo[index])
                        ):
                            angles.addAngle(
                                bondedTo[index][0].index,
                                index,
                                bondedTo[index][1].index,
                                1.894,
                                460.24,
                            )

        if platform is None:
            context = Context(system, VerletIntegrator(0.0))
        else:
            context = Context(system, VerletIntegrator(0.0), platform)
        context.setPositions(newPositions)
        LocalEnergyMinimizer.minimize(context, 1.0, 50)
        self.topology = newTopology
        self.positions = context.getState(getPositions=True).getPositions()
        del context
        return actualVariants
예제 #27
0
from simtk.openmm import System
from ANN import *

system = System()
a = ANN_Force()
a.set_list_of_index_of_atoms_forming_dihedrals_from_index_of_backbone_atoms(
    [1, 2, 3, 4, 5, 6])
system.addForce(a)
print "Python wrapper test passed!"
예제 #28
0
    def addHydrogens(self,
                     forcefield=None,
                     pH=None,
                     variants=None,
                     platform=None):
        """Add missing hydrogens to the model.

        This function automatically changes compatible residues into their constant-pH variant if no variant is specified.:

        Aspartic acid:
            AS4: Form with a 2 hydrogens on each one of the delta oxygens (syn,anti)
                It has 5 titration states.

            Alternative:
            AS2: Has 2 hydrogens (syn, anti) on one of the delta oxygens
                It has 3 titration states.

        Cysteine:
            CYS: Neutral form with a hydrogen on the sulfur
            CYX: No hydrogen on the sulfur (either negatively charged, or part of a disulfide bond)

        Glutamic acid:
            GL4: Form with a 2 hydrogens on each one of the epsilon oxygens (syn,anti)
                It has 5 titration states.

        Histidine:
            HIP: Positively charged form with hydrogens on both ND1 and NE2
                It has 3 titration states.

        The variant to use for each residue is determined by the following rules:

        1. Any Cysteine that participates in a disulfide bond uses the CYX variant regardless of pH.
        2. Other residues are all set to maximally protonated state, which can be updated using a proton drive

        You can override these rules by explicitly specifying a variant for any residue.  To do that, provide a list for the
        'variants' parameter, and set the corresponding element to the name of the variant to use.

        A special case is when the model already contains a hydrogen that should not be present in the desired variant.
        If you explicitly specify a variant using the 'variants' parameter, the residue will be modified to match the
        desired variant, removing hydrogens if necessary.  On the other hand, for residues whose variant is selected
        automatically, this function will only add hydrogens.  It will never remove ones that are already present in the
        model.

        Definitions for standard amino acids and nucleotides are built in.  You can call loadHydrogenDefinitions() to load
        additional definitions for other residue types.

        Parameters
        ----------
        forcefield : ForceField=None
            the ForceField to use for determining the positions of hydrogens.
            If this is None, positions will be picked which are generally
            reasonable but not optimized for any particular ForceField.
        pH : None,
            Kept for compatibility reasons. Has no effect.
        variants : list=None
            an optional list of variants to use.  If this is specified, its
            length must equal the number of residues in the model.  variants[i]
            is the name of the variant to use for residue i (indexed starting at
            0). If an element is None, the standard rules will be followed to
            select a variant for that residue.
        platform : Platform=None
            the Platform to use when computing the hydrogen atom positions.  If
            this is None, the default Platform will be used.

        Returns
        -------
        list
             a list of what variant was actually selected for each residue,
             in the same format as the variants parameter

        Notes
        -----

        This function does not use a pH specification. The argument is kept for compatibility reasons.

        """
        # Check the list of variants.

        if pH is not None:
            print("Ignored pH argument provided for constant-pH residues.")

        residues = list(self.topology.residues())
        if variants is not None:
            if len(variants) != len(residues):
                raise ValueError(
                    "The length of the variants list must equal the number of residues"
                )
        else:
            variants = [None] * len(residues)
        actualVariants = [None] * len(residues)

        # Load the residue specifications.

        if not Modeller._hasLoadedStandardHydrogens:
            Modeller.loadHydrogenDefinitions(
                os.path.join(os.path.dirname(__file__), "data",
                             "hydrogens-amber10-constph.xml"))

        # Make a list of atoms bonded to each atom.

        bonded = {}
        for atom in self.topology.atoms():
            bonded[atom] = []
        for atom1, atom2 in self.topology.bonds():
            bonded[atom1].append(atom2)
            bonded[atom2].append(atom1)

        # Define a function that decides whether a set of atoms form a hydrogen bond, using fairly tolerant criteria.

        def isHbond(d, h, a):
            if norm(d - a) > 0.35 * nanometer:
                return False
            deltaDH = h - d
            deltaHA = a - h
            deltaDH /= norm(deltaDH)
            deltaHA /= norm(deltaHA)
            return acos(dot(deltaDH, deltaHA)) < 50 * degree

        # Loop over residues.

        newTopology = Topology()
        newTopology.setPeriodicBoxVectors(
            self.topology.getPeriodicBoxVectors())
        newAtoms = {}
        newPositions = [] * nanometer
        newIndices = []
        acceptors = [
            atom for atom in self.topology.atoms()
            if atom.element in (elem.oxygen, elem.nitrogen)
        ]
        for chain in self.topology.chains():
            newChain = newTopology.addChain(chain.id)
            for residue in chain.residues():
                newResidue = newTopology.addResidue(residue.name, newChain,
                                                    residue.id)
                isNTerminal = residue == chain._residues[0]
                isCTerminal = residue == chain._residues[-1]
                if residue.name in Modeller._residueHydrogens:
                    # Add hydrogens.  First select which variant to use.

                    spec = Modeller._residueHydrogens[residue.name]
                    variant = variants[residue.index]
                    if variant is None:
                        if residue.name == "CYS":
                            # If this is part of a disulfide, use CYX.

                            sulfur = [
                                atom for atom in residue.atoms()
                                if atom.element == elem.sulfur
                            ]
                            if len(sulfur) == 1 and any(
                                (atom.residue != residue
                                 for atom in bonded[sulfur[0]])):
                                variant = "CYX"
                        if residue.name == "HIS":
                            variant = "HIP"
                        if residue.name == "GLU":
                            variant = "GL4"
                        if residue.name == "ASP":
                            variant = "AS4"
                    if variant is not None and variant not in spec.variants:
                        raise ValueError("Illegal variant for %s residue: %s" %
                                         (residue.name, variant))
                    actualVariants[residue.index] = variant
                    removeExtraHydrogens = variants[residue.index] is not None

                    # Make a list of hydrogens that should be present in the residue.

                    parents = [
                        atom for atom in residue.atoms()
                        if atom.element != elem.hydrogen
                    ]
                    parentNames = [atom.name for atom in parents]
                    hydrogens = [
                        h for h in spec.hydrogens
                        if (variant is None) or (h.variants is None) or (
                            h.variants is not None and variant in h.variants)
                    ]
                    hydrogens = [
                        h for h in hydrogens if h.terminal is None or (
                            isNTerminal and h.terminal == "N") or (
                                isCTerminal and h.terminal == "C")
                    ]
                    hydrogens = [
                        h for h in hydrogens if h.parent in parentNames
                    ]

                    # Loop over atoms in the residue, adding them to the new topology along with required hydrogens.

                    for parent in residue.atoms():
                        # Check whether this is a hydrogen that should be removed.

                        if (removeExtraHydrogens
                                and parent.element == elem.hydrogen
                                and not any(parent.name == h.name
                                            for h in hydrogens)):
                            continue

                        # Add the atom.

                        newAtom = newTopology.addAtom(parent.name,
                                                      parent.element,
                                                      newResidue)
                        newAtoms[parent] = newAtom
                        newPositions.append(
                            deepcopy(self.positions[parent.index]))
                        if parent in parents:
                            # Match expected hydrogens with existing ones and find which ones need to be added.

                            existing = [
                                atom for atom in bonded[parent]
                                if atom.element == elem.hydrogen
                            ]
                            expected = [
                                h for h in hydrogens if h.parent == parent.name
                            ]
                            if len(existing) < len(expected):
                                # Try to match up existing hydrogens to expected ones.

                                matches = []
                                for e in existing:
                                    match = [
                                        h for h in expected if h.name == e.name
                                    ]
                                    if len(match) > 0:
                                        matches.append(match[0])
                                        expected.remove(match[0])
                                    else:
                                        matches.append(None)

                                # If any hydrogens couldn't be matched by name, just match them arbitrarily.

                                for i in range(len(matches)):
                                    if matches[i] is None:
                                        matches[i] = expected[-1]
                                        expected.remove(expected[-1])

                                # Add the missing hydrogens.

                                for h in expected:
                                    newH = newTopology.addAtom(
                                        h.name, elem.hydrogen, newResidue)
                                    newIndices.append(newH.index)
                                    delta = Vec3(0, 0, 0) * nanometer
                                    if len(bonded[parent]) > 0:
                                        for other in bonded[parent]:
                                            delta += (
                                                self.positions[parent.index] -
                                                self.positions[other.index])
                                    else:
                                        delta = (Vec3(
                                            random.random(),
                                            random.random(),
                                            random.random(),
                                        ) * nanometer)
                                    delta *= 0.1 * nanometer / norm(delta)
                                    delta += (0.05 * Vec3(
                                        random.random(),
                                        random.random(),
                                        random.random(),
                                    ) * nanometer)
                                    delta *= 0.1 * nanometer / norm(delta)
                                    newPositions.append(
                                        self.positions[parent.index] + delta)
                                    newTopology.addBond(newAtom, newH)
                else:
                    # Just copy over the residue.

                    for atom in residue.atoms():
                        newAtom = newTopology.addAtom(atom.name, atom.element,
                                                      newResidue)
                        newAtoms[atom] = newAtom
                        newPositions.append(
                            deepcopy(self.positions[atom.index]))
        for bond in self.topology.bonds():
            if bond[0] in newAtoms and bond[1] in newAtoms:
                newTopology.addBond(newAtoms[bond[0]], newAtoms[bond[1]])

        # The hydrogens were added at random positions.  Now perform an energy minimization to fix them up.

        if forcefield is not None:
            # Use the ForceField the user specified.

            system = forcefield.createSystem(newTopology, rigidWater=False)
            atoms = list(newTopology.atoms())
            for i in range(system.getNumParticles()):
                if atoms[i].element != elem.hydrogen:
                    # This is a heavy atom, so make it immobile.
                    system.setParticleMass(i, 0)
        else:
            # Create a System that restrains the distance of each hydrogen from its parent atom
            # and causes hydrogens to spread out evenly.

            system = System()
            nonbonded = CustomNonbondedForce("100/((r/0.1)^4+1)")
            bonds = HarmonicBondForce()
            angles = HarmonicAngleForce()
            system.addForce(nonbonded)
            system.addForce(bonds)
            system.addForce(angles)
            bondedTo = []
            for atom in newTopology.atoms():
                nonbonded.addParticle([])
                if atom.element != elem.hydrogen:
                    system.addParticle(0.0)
                else:
                    system.addParticle(1.0)
                bondedTo.append([])
            for atom1, atom2 in newTopology.bonds():
                if atom1.element == elem.hydrogen or atom2.element == elem.hydrogen:
                    bonds.addBond(atom1.index, atom2.index, 0.1, 100_000.0)
                bondedTo[atom1.index].append(atom2)
                bondedTo[atom2.index].append(atom1)
            for residue in newTopology.residues():
                if residue.name == "HOH":
                    # Add an angle term to make the water geometry correct.

                    atoms = list(residue.atoms())
                    oindex = [
                        i for i in range(len(atoms))
                        if atoms[i].element == elem.oxygen
                    ]
                    if len(atoms) == 3 and len(oindex) == 1:
                        hindex = list(set([0, 1, 2]) - set(oindex))
                        angles.addAngle(
                            atoms[hindex[0]].index,
                            atoms[oindex[0]].index,
                            atoms[hindex[1]].index,
                            1.824,
                            836.8,
                        )
                else:
                    # Add angle terms for any hydroxyls.

                    for atom in residue.atoms():
                        index = atom.index
                        if (atom.element == elem.oxygen
                                and len(bondedTo[index]) == 2 and elem.hydrogen
                                in (a.element for a in bondedTo[index])):
                            angles.addAngle(
                                bondedTo[index][0].index,
                                index,
                                bondedTo[index][1].index,
                                1.894,
                                460.24,
                            )

        if platform is None:
            context = Context(system, VerletIntegrator(0.0))
        else:
            context = Context(system, VerletIntegrator(0.0), platform)
        context.setPositions(newPositions)
        LocalEnergyMinimizer.minimize(context, 1.0, 50)
        self.topology = newTopology
        self.positions = context.getState(getPositions=True).getPositions()
        del context
        return actualVariants
예제 #29
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
예제 #30
0
def __simulate(
    positions: unit.Quantity,
    box_vectors: Optional[unit.Quantity],
    omm_topology: app.Topology,
    omm_system: openmm.System,
    n_steps: int,
    temperature: unit.Quantity,
    pressure: Optional[unit.Quantity],
    platform: Literal["Reference", "OpenCL", "CUDA", "CPU"] = "Reference",
):
    """

    Parameters
    ----------
    positions
        The starting coordinates of the molecules in the system.
    box_vectors
        The box vectors to use. These will overwrite the topology box vectors.
    omm_topology
        The topology detailing the system to simulate.
    omm_system
        The object which defines the systems hamiltonian.
    n_steps
        The number of steps to simulate for.
    temperature
        The temperature to simulate at.
    pressure
        The pressure to simulate at.
    platform
        The platform to simulate using.
    """
    """A helper function for simulating a system with OpenMM."""

    with open("input.pdb", "w") as file:
        app.PDBFile.writeFile(omm_topology, positions, file)

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

    if pressure is not None:
        omm_system.addForce(
            openmm.MonteCarloBarostat(pressure, temperature, 25))

    integrator = openmm.LangevinIntegrator(
        temperature,  # simulation temperature,
        1.0 / unit.picosecond,  # friction
        2.0 * unit.femtoseconds,  # simulation timestep
    )

    platform = openmm.Platform.getPlatformByName(platform)

    simulation = app.Simulation(omm_topology, omm_system, integrator, platform)

    if box_vectors is not None:
        simulation.context.setPeriodicBoxVectors(box_vectors[0, :],
                                                 box_vectors[1, :],
                                                 box_vectors[2, :])

    simulation.context.setPositions(positions)
    simulation.context.computeVirtualSites()

    simulation.minimizeEnergy()

    # Randomize the velocities from a Boltzmann distribution at a given temperature.
    simulation.context.setVelocitiesToTemperature(temperature * unit.kelvin)

    # Configure the information in the output files.
    pdb_reporter = openmm.app.DCDReporter("trajectory.dcd",
                                          int(0.05 * n_steps))

    state_data_reporter = openmm.app.StateDataReporter(
        "data.csv",
        int(0.05 * n_steps),
        step=True,
        potentialEnergy=True,
        temperature=True,
        density=True,
    )
    simulation.reporters.append(pdb_reporter)
    simulation.reporters.append(state_data_reporter)

    logger.debug("Starting simulation")
    start = time.process_time()

    # Run the simulation
    simulation.step(n_steps)

    end = time.process_time()
    logger.debug("Elapsed time %.2f seconds" % (end - start))
    logger.debug("Done!")
예제 #31
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
예제 #32
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