def _addVirtualSitesToSystem(self, sys):
        """Create any virtual sites in the systempy
        """
        if not any(t.startswith('virtual_') for t in self._tables.keys()):
            return

        if 'virtual_lc2_term' in self._tables:
            q = """SELECT p0, p1, p2, c1
            FROM virtual_lc2_term INNER JOIN virtual_lc2_param
            ON virtual_lc2_term.param=virtual_lc2_param.id"""
            for p0, p1, p2, c1 in self._conn.execute(q):
                vsite = mm.TwoParticleAverageSite(p1, p2, (1-c1), c1)
                sys.setVirtualSite(p0, vsite)

        if 'virtual_lc3_term' in self._tables:
            q = """SELECT p0, p1, p2, p3, c1, c2
            FROM virtual_lc3_term INNER JOIN virtual_lc3_param
            ON virtual_lc3_term.param=virtual_lc3_param.id"""
            for p0, p1, p2, p3, c1, c2 in self._conn.execute(q):
                vsite = mm.ThreeParticleAverageSite(p1, p2, p3, (1-c1-c2), c1, c2)
                sys.setVirtualSite(p0, vsite)

        if 'virtual_out3_term' in self._tables:
            q = """SELECT p0, p1, p2, p3, c1, c2, c3
            FROM virtual_out3_term INNER JOIN virtual_out3_param
            ON virtual_out3_term.param=virtual_out3_param.id"""
            for p0, p1, p2, p3, c1, c2, c3 in self._conn.execute(q):
                vsite = mm.OutOfPlaneSite(p1, p2, p3, c1, c2, c3)
                sys.setVirtualSite(p0, vsite)

        if 'virtual_fdat3_term' in self._tables:
            raise NotImplementedError('OpenMM does not currently support '
                                      'fdat3-style virtual sites')
Esempio n. 2
0
    def testWrappingAlreadyCreated(self):
        base_inst = openmm.System()
        base_inst.addParticle(1.)
        base_inst.addParticle(2.)
        base_inst.addParticle(3.)
        vs = openmm.TwoParticleAverageSite(0, 1, 0.5, 0.5)
        base_inst.setVirtualSite(2, vs)
        inst = kapow.System.Wrap(base_inst)

        self.assertEqual(len(inst.particles), 3)
        self.assertEqual(
            [p.mass.value_in_unit(dalton) for p in inst.particles],
            [1., 2, 3.])
        self.assertTrue(inst.wrapped_object.isVirtualSite(2))
        self.assertEqual(inst.virtualSites.keys(), [2])
Esempio n. 3
0
    def createSystem(self, topology, nonbondedMethod=NoCutoff,
                     nonbondedCutoff=1.0*u.nanometer, constraints=None,
                     rigidWater=True, removeCMMotion=True, hydrogenMass=None,
                     **args):
        """Construct an OpenMM System representing a Topology with this force field.

        Parameters
        ----------
        topology : Topology
            The Topology for which to create a System
        nonbondedMethod : object=NoCutoff
            The method to use for nonbonded interactions.  Allowed values are
            NoCutoff, CutoffNonPeriodic, CutoffPeriodic, Ewald, or PME.
        nonbondedCutoff : distance=1*nanometer
            The cutoff distance to use for nonbonded interactions
        constraints : object=None
            Specifies which bonds and angles should be implemented with constraints.
            Allowed values are None, HBonds, AllBonds, or HAngles.
        rigidWater : boolean=True
            If true, water molecules will be fully rigid regardless of the value
            passed for the constraints argument
        removeCMMotion : boolean=True
            If true, a CMMotionRemover will be added to the System
        hydrogenMass : mass=None
            The mass to use for hydrogen atoms bound to heavy atoms.  Any mass
            added to a hydrogen is subtracted from the heavy atom to keep
            their total mass the same.
        args
             Arbitrary additional keyword arguments may also be specified.
             This allows extra parameters to be specified that are specific to
             particular force fields.

        Returns
        -------
        system
            the newly created System
        """

        # Atomtype the system.
        G = nx.Graph()
        G.add_nodes_from(topology.atoms())
        G.add_edges_from(topology.bonds())
        cycles = nx.cycle_basis(G)

        for atom in topology.atoms():
            atom.cycles = set()

        for cycle in cycles:
            for atom in cycle:
                atom.cycles.add(tuple(cycle))

        find_atomtypes(atoms=list(topology.atoms()), forcefield=self)

        data = app.ForceField._SystemData()
        data.atoms = list(topology.atoms())
        for atom in data.atoms:
            data.excludeAtomWith.append([])

        # Make a list of all bonds
        for bond in topology.bonds():
            data.bonds.append(app.ForceField._BondData(bond[0].index, bond[1].index))

        # Record which atoms are bonded to each other atom
        bondedToAtom = []
        for i in range(len(data.atoms)):
            bondedToAtom.append(set())
            data.atomBonds.append([])
        for i in range(len(data.bonds)):
            bond = data.bonds[i]
            bondedToAtom[bond.atom1].add(bond.atom2)
            bondedToAtom[bond.atom2].add(bond.atom1)
            data.atomBonds[bond.atom1].append(i)
            data.atomBonds[bond.atom2].append(i)

        # TODO: Better way to lookup nonbonded parameters...?
        nonbonded_params = None
        for generator in self.getGenerators():
            if isinstance(generator, NonbondedGenerator):
                nonbonded_params = generator.params.paramsForType
                break

        for chain in topology.chains():
            for res in chain.residues():
                for atom in res.atoms():
                    data.atomType[atom] = atom.id
                    if nonbonded_params:
                        params = nonbonded_params[atom.id]
                        data.atomParameters[atom] = params

        # Create the System and add atoms
        sys = mm.System()
        for atom in topology.atoms():
            # Look up the atom type name, returning a helpful error message if it cannot be found.
            if atom not in data.atomType:
                raise Exception("Could not identify atom type for atom '%s'." % str(atom))
            typename = data.atomType[atom]

            # Look up the type name in the list of registered atom types, returning a helpful error message if it cannot be found.
            if typename not in self._atomTypes:
                msg  = "Could not find typename '%s' for atom '%s' in list of known atom types.\n" % (typename, str(atom))
                msg += "Known atom types are: %s" % str(self._atomTypes.keys())
                raise Exception(msg)

            # Add the particle to the OpenMM system.
            mass = self._atomTypes[typename].mass
            sys.addParticle(mass)

        # Adjust hydrogen masses if requested.
        if hydrogenMass is not None:
            if not u.is_quantity(hydrogenMass):
                hydrogenMass *= u.dalton
            for atom1, atom2 in topology.bonds():
                if atom1.element == elem.hydrogen:
                    (atom1, atom2) = (atom2, atom1)
                if atom2.element == elem.hydrogen and atom1.element not in (elem.hydrogen, None):
                    transferMass = hydrogenMass-sys.getParticleMass(atom2.index)
                    sys.setParticleMass(atom2.index, hydrogenMass)
                    sys.setParticleMass(atom1.index, sys.getParticleMass(atom1.index)-transferMass)

        # Set periodic boundary conditions.
        boxVectors = topology.getPeriodicBoxVectors()
        if boxVectors is not None:
            sys.setDefaultPeriodicBoxVectors(boxVectors[0], boxVectors[1], boxVectors[2])
        elif nonbondedMethod not in [NoCutoff, CutoffNonPeriodic]:
            raise ValueError('Requested periodic boundary conditions for a Topology that does not specify periodic box dimensions')

        # Make a list of all unique angles
        uniqueAngles = set()
        for bond in data.bonds:
            for atom in bondedToAtom[bond.atom1]:
                if atom != bond.atom2:
                    if atom < bond.atom2:
                        uniqueAngles.add((atom, bond.atom1, bond.atom2))
                    else:
                        uniqueAngles.add((bond.atom2, bond.atom1, atom))
            for atom in bondedToAtom[bond.atom2]:
                if atom != bond.atom1:
                    if atom > bond.atom1:
                        uniqueAngles.add((bond.atom1, bond.atom2, atom))
                    else:
                        uniqueAngles.add((atom, bond.atom2, bond.atom1))
        data.angles = sorted(list(uniqueAngles))

        # Make a list of all unique proper torsions
        uniquePropers = set()
        for angle in data.angles:
            for atom in bondedToAtom[angle[0]]:
                if atom not in angle:
                    if atom < angle[2]:
                        uniquePropers.add((atom, angle[0], angle[1], angle[2]))
                    else:
                        uniquePropers.add((angle[2], angle[1], angle[0], atom))
            for atom in bondedToAtom[angle[2]]:
                if atom not in angle:
                    if atom > angle[0]:
                        uniquePropers.add((angle[0], angle[1], angle[2], atom))
                    else:
                        uniquePropers.add((atom, angle[2], angle[1], angle[0]))
        data.propers = sorted(list(uniquePropers))

        # Make a list of all unique improper torsions
        for atom in range(len(bondedToAtom)):
            bondedTo = bondedToAtom[atom]
            if len(bondedTo) > 2:
                for subset in itertools.combinations(bondedTo, 3):
                    data.impropers.append((atom, subset[0], subset[1], subset[2]))

        # Identify bonds that should be implemented with constraints
        if constraints == AllBonds or constraints == HAngles:
            for bond in data.bonds:
                bond.isConstrained = True
        elif constraints == HBonds:
            for bond in data.bonds:
                atom1 = data.atoms[bond.atom1]
                atom2 = data.atoms[bond.atom2]
                bond.isConstrained = atom1.name.startswith('H') or atom2.name.startswith('H')
        if rigidWater:
            for bond in data.bonds:
                atom1 = data.atoms[bond.atom1]
                atom2 = data.atoms[bond.atom2]
                if atom1.residue.name == 'HOH' and atom2.residue.name == 'HOH':
                    bond.isConstrained = True

        # Identify angles that should be implemented with constraints
        if constraints == HAngles:
            for angle in data.angles:
                atom1 = data.atoms[angle[0]]
                atom2 = data.atoms[angle[1]]
                atom3 = data.atoms[angle[2]]
                numH = 0
                if atom1.name.startswith('H'):
                    numH += 1
                if atom3.name.startswith('H'):
                    numH += 1
                data.isAngleConstrained.append(numH == 2 or (numH == 1 and atom2.name.startswith('O')))
        else:
            data.isAngleConstrained = len(data.angles)*[False]
        if rigidWater:
            for i in range(len(data.angles)):
                angle = data.angles[i]
                atom1 = data.atoms[angle[0]]
                atom2 = data.atoms[angle[1]]
                atom3 = data.atoms[angle[2]]
                if atom1.residue.name == 'HOH' and atom2.residue.name == 'HOH' and atom3.residue.name == 'HOH':
                    data.isAngleConstrained[i] = True

        # Add virtual sites
        for atom in data.virtualSites:
            (site, atoms, excludeWith) = data.virtualSites[atom]
            index = atom.index
            data.excludeAtomWith[excludeWith].append(index)
            if site.type == 'average2':
                sys.setVirtualSite(index, mm.TwoParticleAverageSite(atoms[0], atoms[1], site.weights[0], site.weights[1]))
            elif site.type == 'average3':
                sys.setVirtualSite(index, mm.ThreeParticleAverageSite(atoms[0], atoms[1], atoms[2], site.weights[0], site.weights[1], site.weights[2]))
            elif site.type == 'outOfPlane':
                sys.setVirtualSite(index, mm.OutOfPlaneSite(atoms[0], atoms[1], atoms[2], site.weights[0], site.weights[1], site.weights[2]))
            elif site.type == 'localCoords':
                sys.setVirtualSite(index, mm.LocalCoordinatesSite(atoms[0], atoms[1], atoms[2],
                                                                  mm.Vec3(site.originWeights[0], site.originWeights[1], site.originWeights[2]),
                                                                  mm.Vec3(site.xWeights[0], site.xWeights[1], site.xWeights[2]),
                                                                  mm.Vec3(site.yWeights[0], site.yWeights[1], site.yWeights[2]),
                                                                  mm.Vec3(site.localPos[0], site.localPos[1], site.localPos[2])))

        # Add forces to the System
        for force in self._forces:
            force.createForce(sys, data, nonbondedMethod, nonbondedCutoff, args)
        if removeCMMotion:
            sys.addForce(mm.CMMotionRemover())

        # Let force generators do postprocessing
        for force in self._forces:
            if 'postprocessSystem' in dir(force):
                force.postprocessSystem(sys, data, args)

        # Execute scripts found in the XML files.
        for script in self._scripts:
            exec(script, locals())
        return sys
Esempio n. 4
0
    def _addVirtualSitesToSystem(self, sys):
        """Create any virtual sites in the system
        """
        go = []

        for (fcounter, conn, tables, offset) in self._localVars():
            if not any(t.startswith('virtual_') for t in list(tables.keys())):
                go.append(False)
            else:
                go.append(True)

        if not any(go):
            return

        for (fcounter, conn, tables, offset) in self._localVars():
            if not go[fcounter]:
                continue
            if 'virtual_lc2_term' in tables:
                q = """SELECT p0, p1, p2, c1
                FROM virtual_lc2_term INNER JOIN virtual_lc2_param
                ON virtual_lc2_term.param=virtual_lc2_param.id"""
                for p0, p1, p2, c1 in conn.execute(q):
                    p0 += offset
                    p1 += offset
                    p2 += offset
                    vsite = mm.TwoParticleAverageSite(p1, p2, (1 - c1), c1)
                    sys.setVirtualSite(p0, vsite)

        for (fcounter, conn, tables, offset) in self._localVars():
            if not go[fcounter]:
                continue
            if 'virtual_lc3_term' in tables:
                q = """SELECT p0, p1, p2, p3, c1, c2
                FROM virtual_lc3_term INNER JOIN virtual_lc3_param
                ON virtual_lc3_term.param=virtual_lc3_param.id"""
                for p0, p1, p2, p3, c1, c2 in conn.execute(q):
                    p0 += offset
                    p1 += offset
                    p2 += offset
                    p3 += offset
                    vsite = mm.ThreeParticleAverageSite(
                        p1, p2, p3, (1 - c1 - c2), c1, c2)
                    sys.setVirtualSite(p0, vsite)

        for (fcounter, conn, tables, offset) in self._localVars():
            if not go[fcounter]:
                continue
            if 'virtual_out3_term' in tables:
                q = """SELECT p0, p1, p2, p3, c1, c2, c3
                FROM virtual_out3_term INNER JOIN virtual_out3_param
                ON virtual_out3_term.param=virtual_out3_param.id"""
                for p0, p1, p2, p3, c1, c2, c3 in conn.execute(q):
                    p0 += offset
                    p1 += offset
                    p2 += offset
                    p3 += offset
                    vsite = mm.OutOfPlaneSite(p1, p2, p3, c1, c2, c3)
                    sys.setVirtualSite(p0, vsite)

        for (fcounter, conn, tables, offset) in self._localVars():
            if not go[fcounter]:
                continue
            if 'virtual_fdat3_term' in tables:
                raise NotImplementedError('OpenMM does not currently support '
                                          'fdat3-style virtual sites')
    def add_fluorine(self, system, nonbonded_force, snapshot, ligand_name):
        pos = list(snapshot.xyz[0] * 10)
        top = self.input_pdb.topology

        bond_list = []
        hydrogen_order = []
        carbons = list(
            snapshot.topology.select(
                'element C and resname {}'.format(ligand_name)))
        hydrogens = list(
            snapshot.topology.select(
                'element H and resname {}'.format(ligand_name)))
        for index in range(system.getNumConstraints()):
            i, j, r = system.getConstraintParameters(index)
            if i in carbons and j in hydrogens:
                bond_list.append([j, i])
                hydrogen_order.append(j - self.offset)
            if j in carbons and i in hydrogens:
                bond_list.append([i, j])
                hydrogen_order.append(i - self.offset)

        hydrogen_order = sorted(hydrogen_order)
        bond_list = sorted(bond_list)

        element = app.element.fluorine
        chain = top.addChain()
        res = top.addResidue('FLU', chain)
        f_weight = 0.24  #1.340Ang/1.083Ang -1 = 0.24
        #f_charge = -0.2463
        #f_sig = 0.3034222854639816
        #f_eps = 0.3481087995050717

        ligand_ghost_atoms = []
        ligand_ghost_exceptions = []

        h_exceptions = []
        f_exceptions = []
        all_new_atoms = []
        for new_atom in bond_list:
            exceptions = []
            system.addParticle(0.00)
            x, y, z = tuple(snapshot.xyz[0, new_atom[0], :] * 10)
            pos.extend([[x, y, z]])
            atom_added = nonbonded_force.addParticle(0.0, 1.0, 0.0)
            all_new_atoms.append(atom_added)
            ligand_ghost_atoms.append(atom_added)
            vs = mm.TwoParticleAverageSite(new_atom[0], new_atom[1],
                                           1 + f_weight, -f_weight)
            system.setVirtualSite(atom_added, vs)
            #If ligand is over 1000 atoms there will be repeated names
            top.addAtom('F{}'.format(abs(new_atom[0]) % 1000), element, res)
            #here the fluorine will inherited the exception of its parent hydrogen
            for exception_index in range(nonbonded_force.getNumExceptions()):
                [iatom, jatom, chargeprod, sigma, epsilon
                 ] = nonbonded_force.getExceptionParameters(exception_index)
                if jatom == new_atom[0]:
                    #Hinders multi permu (will not add new flu, flu interactions as they not in ligand_info)
                    if iatom in self.ligand_info[0]:
                        h_exceptions.append([iatom, jatom])
                        exceptions.append([iatom, atom_added, 0.1, 0.1, 0.1])
                if iatom == new_atom[0]:
                    # Hinders multi permu (will not add new flu, flu interactions)
                    if jatom in self.ligand_info[0]:
                        h_exceptions.append([jatom, iatom])
                        exceptions.append([jatom, atom_added, 0.1, 0.1, 0.1])
            for i, exception in enumerate(exceptions):
                idx = nonbonded_force.addException(*exception)
                f_exceptions.append(
                    [idx, exception[0], exception[1], 0.0, 0.1, 0.0])
                ligand_ghost_exceptions.append(idx)
            nonbonded_force.addException(atom_added, new_atom[0], 0.0, 0.1,
                                         0.0, False)

        #add exclusions between all atoms in hybrid topo.
        for atomi in all_new_atoms:
            for atomj in all_new_atoms:
                if atomj != atomi:
                    try:
                        nonbonded_force.addException(atomi, atomj, 0.0, 0.1,
                                                     0.0, False)
                    except:
                        pass

        virt_excep_shift = [[x[0], y[2] - x[1]]
                            for x, y in zip(h_exceptions, f_exceptions)]
        h_virt_excep = [frozenset((x[0], x[1])) for x in h_exceptions]

        return pos, top, hydrogen_order, h_virt_excep, virt_excep_shift, f_exceptions, [
            ligand_ghost_atoms, ligand_ghost_exceptions
        ]
    def add_sulphur(self, system, nonbonded_force, bonded_force, snapshot,
                    ligand_name):
        pos = list(snapshot.xyz[0] * 10)
        top = self.input_pdb.topology

        bond_list = []
        oxygen_order = []
        carbons = list(
            snapshot.topology.select(
                'element C and resname {}'.format(ligand_name)))
        oxygens = list(
            snapshot.topology.select(
                'element O and resname {}'.format(ligand_name)))
        for index in range(bonded_force.getNumBonds()):
            i, j, r, k = bonded_force.getBondParameters(index)
            if i in carbons and j in oxygens:
                bond_list.append([j, i])
                oxygen_order.append(j - self.offset)
            if j in carbons and i in oxygens:
                bond_list.append([i, j])
                oxygen_order.append(i - self.offset)

        oxygen_order = sorted(oxygen_order)
        bond_list = sorted(bond_list)

        element = app.element.sulphur
        chain = top.addChain()
        res = top.addResidue('SUL', chain)
        s_weight = 0.3  #1.6Ang/1.2Ang - 1

        ligand_ghost_bonds = []
        ligand_ghost_atoms = []
        ligand_ghost_exceptions = []

        o_exceptions = []
        s_exceptions = []
        for new_atom in bond_list:
            exceptions = []
            system.addParticle(0.00)
            x, y, z = tuple(snapshot.xyz[0, new_atom[0], :] * 10)
            pos.extend([[x, y, z]])
            atom_added = nonbonded_force.addParticle(0.0, 1.0, 0.0)
            bonded_force.addBond(atom_added, new_atom[1], 0.15 * nm,
                                 0.0 * kj_mol / (nm**2))
            ligand_ghost_atoms.append(atom_added)
            vs = mm.TwoParticleAverageSite(new_atom[0], new_atom[1],
                                           1 + s_weight, -s_weight)
            system.setVirtualSite(atom_added, vs)
            #If ligand is over 1000 atoms there will be repeated names
            atom1 = top.addAtom('S{}'.format(abs(new_atom[0]) % 1000), element,
                                res)
            for x in top.atoms():
                if x.index == new_atom[1]:
                    atom2 = x
            top.addBond(atom1, atom2)
            #here the sulphur will inherited the exception of its parent oxygen
            for exception_index in range(nonbonded_force.getNumExceptions()):
                [iatom, jatom, chargeprod, sigma, epsilon
                 ] = nonbonded_force.getExceptionParameters(exception_index)
                if jatom == new_atom[0]:
                    if iatom in self.ligand_info[0]:
                        o_exceptions.append([iatom, jatom])
                        exceptions.append([iatom, atom_added, 0.1, 0.1, 0.1])
                if iatom == new_atom[0]:
                    if jatom in self.ligand_info[0]:
                        o_exceptions.append([jatom, iatom])
                        exceptions.append([jatom, atom_added, 0.1, 0.1, 0.1])
            for i, exception in enumerate(exceptions):
                idx = nonbonded_force.addException(*exception)
                s_exceptions.append(
                    [idx, exception[0], exception[1], 0.0, 0.1, 0.0])
                ligand_ghost_exceptions.append(idx)

            nonbonded_force.addException(atom_added, new_atom[0], 0.0, 0.1,
                                         0.0, False)

        virt_excep_shift = [[x[0], y[2] - x[1]]
                            for x, y in zip(o_exceptions, s_exceptions)]
        o_virt_excep = [frozenset((x[0], x[1])) for x in o_exceptions]

        return pos, top, oxygen_order, o_virt_excep, virt_excep_shift, s_exceptions, [
            ligand_ghost_atoms, ligand_ghost_exceptions, ligand_ghost_bonds
        ]