示例#1
0
def _assignNamesFromForceFieldTemplates(topology, system, openmm_forcefields_to_use):
    '''
    Assign Amber atom and residue names from specified forcefield templates.
    Requires OpenMM version >= 5.2.

    ARGUMENTS

    topology
    system
    openmm_forcefields_to_use (list of strings) - list of XML files of forcefields containing templates

    RETURNS

    atoms - list of atom information
    sorted_atom_indices (list of int) - atom indices in order that they appear in forcefield templates, in case re-sorting is required

    '''

    # Assign AMBER atom and residue names.
    from simtk.openmm.app import ForceField
    import simtk.openmm.app.forcefield
    forcefield = ForceField(*openmm_forcefields_to_use)

    data = ForceField._SystemData()
    atomIndices = {}
    for index, atom in enumerate(topology.atoms()):
        data.atoms.append(atom)
        atomIndices[atom] = index

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

    # 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)

    # Find the template matching each residue and assign atom types.
    sorted_atom_indices = list()
    for chain in topology.chains():
        for res in chain.residues():
            template = None
            matches = None
            # NOTE: Before OpenMM 5.2, was necessary to convert output of _createResidueSignature using the method simtk.openmm.app.forcefield._signatureToString - this is now done within _createResidueSignature
            sig = simtk.openmm.app.forcefield._createResidueSignature([atom.element for atom in res.atoms()])
            if sig != '':
                if sig in forcefield._templateSignatures:
                    for t in forcefield._templateSignatures[sig]:
                        # NOTE: No longer necessary to pass atomIndices in OpenMM > 5.2
                        matches = simtk.openmm.app.forcefield._matchResidue(res, t, bondedToAtom)
                        if matches is not None:
                            template = t
                            break
            if matches is None:
                # Check templates involving virtual sites
                for t in forcefield._templateSignatures[None]:
                    matches = simtk.openmm.app.forcefield._matchResidue(res, t, bondedToAtom)
                    if matches is not None:
                        template = t
                        break
            if matches is None:
                raise ValueError('No template found for residue %d (%s).  This might mean your input topology is missing some atoms or bonds, or possibly that you are using the wrong force field.' % (res.index+1, res.name))

            # Sort matches by order in template.
            atom_indices = [ atom.index for atom in res.atoms() ]
            for local_index in range(len(template.atoms)):
                if local_index in matches:
                    sorted_atom_indices.append(min(atom_indices) + matches.index(local_index))

            for (atom, match) in zip(res.atoms(), matches):
                data.atomType[atom] = template.atoms[match].type
                # Rename atom (JDC).
                atom.name = template.atoms[match].name
                atom.resname = template.name

                for site in template.virtualSites:
                    if match == site.index:
                        data.virtualSites[atom] = site

    return (data.atoms, sorted_atom_indices)