Beispiel #1
0
 def optg_c(self, steps=60, ff="mmff94", optimizer='cg'):
     """
     Opt geometry by ff with constrained torsions
     ==============================================
     defaut ff: mmff94, mmff94s seems to be
                problematic, sometimes it
                leads to weird geometries
     steps: ff steps for constraint opt
     """
     m = self.m  #copy.copy( self.m )
     # Define constraints
     c = ob.OBFFConstraints()
     #c.AddDistanceConstraint(1, 8, 10)        # Angstroms
     #c.AddAngleConstraint(1, 2, 3, 120.0)     # Degrees
     # constrain torsion only
     torsions = self.get_all_torsions()
     for torsion in torsions:
         i, j, k, l = torsion
         ang = torsions[torsion]
         c.AddTorsionConstraint(i, j, k, l, ang)  # Degrees
     # Setup the force field with the constraints
     obff = ob.OBForceField.FindForceField(ff)
     obff.Setup(m, c)
     obff.SetConstraints(c)
     obff.ConjugateGradients(steps)
     obff.GetCoordinates(m)
     self.m = m
     self.M = pb.Molecule(m)
     self.coords = get_coords(m)
Beispiel #2
0
def opt_mmff_FG(mol, numAtoms, outfile):
    # initialize force field and constraint classes
    MMFF = ob.OBForceField.FindType("MMFF94")
    constraints = ob.OBFFConstraints()
    conv = ob.OBConversion()

    # setup force field
    MMFF.Setup(mol)

    # add constraints
    [constraints.AddAtomConstraint(i) for i in range(1, numAtoms)]
    MMFF.SetConstraints(constraints)

    # run optization
    MMFF.ConjugateGradients(1000)

    # update coordinates
    MMFF.UpdateCoordinates(mol)

    # write to xyz file
    print outfile
    conv.WriteFile(mol, "test/" + outfile)

    # clear mol class
    mol.Clear()
Beispiel #3
0
    def optimize(self, constraint=False, steps=100):
        """ Perform conjugate gradient optimization with the MMFF94 force field.

            Keyword arguments:
            constraint -- Apply harmonic constraint to dihedral angles. (default False)
            steps -- Max number of CG steps. (default 100)

        """

        mol = self._molecule.OBMol

        restraints = self._get_dihedral_constraints()

        cnstr = openbabel.OBFFConstraints()

        if constraint:
            for r in restraints:
                a = mol.GetTorsion(r[0], r[1], r[2], r[3])
                cnstr.AddTorsionConstraint(r[0], r[1], r[2], r[3], a)

        FF = openbabel.OBForceField.FindForceField("MMFF94")
        FF.Setup(mol, cnstr)
        FF.SetConstraints(cnstr)
        FF.ConjugateGradients(steps)
        FF.GetCoordinates(mol)

        return
Beispiel #4
0
def chain_ffopt(ff, mol, frozenats):
    ### FORCE FIELD OPTIMIZATION ##
    # INPUT
    #   - ff: force field to use, available MMFF94, UFF< Ghemical, GAFF
    #   - mol: mol3D to be ff optimized
    #   - connected: indices of connection atoms to metal
    #   - constopt: flag for constrained optimization
    # OUTPUT
    #   - mol: force field optimized mol3D
    metals = range(21, 31) + range(39, 49) + range(72, 81)
    ### check requested force field
    ffav = 'mmff94, uff, ghemical, gaff, mmff94s'  # force fields
    if ff.lower() not in ffav:
        print 'Requested force field not available. Defaulting to MMFF94'
        ff = 'mmff94'
    ### convert mol3D to OBMol via xyz file, because AFTER/END option have coordinates
    backup_mol = mol3D()
    backup_mol.copymol3D(mol)
    #   print('bck ' + str(backup_mol.getAtom(0).coords()))
    #   print('mol_ibf ' + str(mol.getAtom(0).coords()))
    mol.convert2OBMol()
    ### initialize constraints
    constr = openbabel.OBFFConstraints()
    ### openbabel indexing starts at 1 ### !!!
    # convert metals to carbons for FF
    indmtls = []
    mtlsnums = []
    for iiat, atom in enumerate(openbabel.OBMolAtomIter(OBMol)):
        if atom.atomicnum in metals:
            indmtls.append(iiat)
            mtlsnums.append(atom.GetAtomicNum())
            atom.OBAtom.SetAtomicNum(19)
    for cat in frozenats:
        constr.AddAtomConstraint(cat + 1)  # indexing babel
    ### set up forcefield
    forcefield = openbabel.OBForceField.FindForceField(ff)
    OBMol = mol.OBMol
    forcefield.Setup(obmol, constr)
    ## force field optimize structure
    forcefield.ConjugateGradients(2500)
    forcefield.GetCoordinates(OBMol)
    mol.OBMol = OBMol

    # reset atomic number to metal
    for i, iiat in enumerate(indmtls):
        mol.OBMol.GetAtomById(iiat).SetAtomicNum(mtlsnums[i])
    mol.convert2mol3D()

    en = forcefield.Energy()
    #   print(str(mol.OBmol.atoms[1].OBAtom.GetVector().GetZ()))
    #    print(str(forcefield.Validate()))
    # print('mol_af ' + str(mol.getAtom(0).coords()))

    #  print('ff delta = ' + str(backup_mol.rmsd(mol)))
    del forcefield, constr, OBMol
    return mol, en
Beispiel #5
0
def minimize(selection='tmp',
             forcefield='MMFF94',
             method='steepest descent',
             nsteps=2000,
             conv=1E-6,
             cutoff=False,
             cut_vdw=6.0,
             cut_elec=8.0,
             rigid_geometry=True):
    """
    Use openbabel to minimize the energy of a molecule.
    """
    pdb_string = cmd.get_pdbstr(selection)
    name = cmd.get_legal_name(selection)
    obconversion = ob.OBConversion()
    obconversion.SetInAndOutFormats('pdb', 'pdb')
    mol = ob.OBMol()
    obconversion.ReadString(mol, pdb_string)
    if rigid_geometry:
        constraints = ob.OBFFConstraints()
        for angle in ob.OBMolAngleIter(mol):
            b, a, c = [mol.GetAtom(x + 1) for x in angle]
            value = mol.GetAngle(a, b, c)
            b, a, c = [x + 1 for x in angle]
            constraints.AddAngleConstraint(a, b, c, value)
        for i in ob.OBMolBondIter(mol):
            a, b = (i.GetBeginAtomIdx(), i.GetEndAtomIdx())
            value = i.GetLength()
            constraints.AddDistanceConstraint(a, b, value)
        ff = ob.OBForceField.FindForceField(forcefield)
        ff.Setup(mol, constraints)
        ff.SetConstraints(constraints)
    else:
        ff = ob.OBForceField.FindForceField(forcefield)
        ff.Setup(mol)
    if cutoff:
        ff.EnableCutOff(True)
        ff.SetVDWCutOff(cut_vdw)
        ff.SetElectrostaticCutOff(cut_elec)
    if method == 'conjugate gradients':
        ff.ConjugateGradients(nsteps, conv)
    else:
        ff.SteepestDescent(nsteps, conv)
    ff.GetCoordinates(mol)
    nrg = ff.Energy()
    pdb_string = obconversion.WriteString(mol)
    cmd.delete(name)
    if name == 'all':
        name = 'all_'
    cmd.delete(selection)
    cmd.read_pdbstr(pdb_string, selection)
    return nrg
Beispiel #6
0
def constrained_ff_optimization(xyz_filename, constraints):
    """
    Do a constrained optimization with UFF to make
    sure that the ab initio MD won't explode
    Code modified from gist.github.com/andersx/7784817
    """

    # Standard openbabel molecule load
    conv = ob.OBConversion()
    conv.SetInAndOutFormats('xyz','xyz')
    mol = ob.OBMol()
    conv.ReadFile(mol,xyz_filename)

    # Define constraints
    ffconstraints = ob.OBFFConstraints()
    for idx1, idx2, distance in constraints:
        ffconstraints.AddDistanceConstraint(int(idx1)+1, int(idx2)+1, float(distance))

    ## If only two constraints, then add additional angle constraint
    #if len(constraints) == 2:
    #    idx1 = constraints[0][0]
    #    idx2 = constraints[0][1]
    #    idx3 = constraints[1][0]
    #    idx4 = constraints[1][1]

    #    #if idx1 == idx3:
    #    #    ffconstraints.AddAngleConstraint(int(idx2), int(idx1), int(idx4), 180.0)
    #    #    #ffconstraints.AddAngleConstraint(int(idx2), int(idx1), int(idx4)+1, 180.0)
    #    #elif idx1 == idx4:
    #    #    ffconstraints.AddAngleConstraint(int(idx2), int(idx1), int(idx3), 180.0)
    #    #elif idx2 == idx3:
    #    #    ffconstraints.AddAngleConstraint(int(idx1), int(idx2), int(idx4), 180.0)
    #    #elif idx2 == idx4:
    #    #    ffconstraints.AddAngleConstraint(int(idx1), int(idx2), int(idx3), 180.0)




    # Setup the force field with the constraints
    forcefield = ob.OBForceField.FindForceField("UFF")
    forcefield.Setup(mol, ffconstraints)
    forcefield.SetConstraints(ffconstraints)

    # Do a 1000 steps conjugate gradient minimization
    # and save the coordinates to mol.
    forcefield.ConjugateGradients(500)

    forcefield.GetCoordinates(mol)

    return conv, mol
Beispiel #7
0
def set_dihedral(angles):
    """ Set the dihedral angles of the carbon chain
    """

    global mol
    global forcefield

    constraints = ob.OBFFConstraints()
    # constraints.AddDistanceConstraint(1, 10, 3.4)       # Angstroms
    # constraints.AddAngleConstraint(1, 2, 3, 120.0)      # Degrees
    # constraints.AddTorsionConstraint(1, 2, 3, 4, 180.0) # Degrees


    # Find all carbons
    smarts = pb.Smarts("C")
    smarts = smarts.findall(mol)

    for i in xrange(len(angles)):

        angle = angles[i]

        # Get the next 4 carbons
        Cs = smarts[i:i+4]

        ai, = Cs[0]
        bi, = Cs[1]
        ci, = Cs[2]
        di, = Cs[3]

        a = mol.OBMol.GetAtom(ai)
        b = mol.OBMol.GetAtom(bi)
        c = mol.OBMol.GetAtom(ci)
        d = mol.OBMol.GetAtom(di)

        mol.OBMol.SetTorsion(a, b, c, d, angle/(180.0)*np.pi) # Radians
        anglep = mol.OBMol.GetTorsion(a, b, c, d)

        # Define constraint
        constraints.AddTorsionConstraint(ai, bi, ci, di, anglep) # Degrees

    # Setup the force field with the constraints
    forcefield = ob.OBForceField.FindForceField("GAFF")
    forcefield.Setup(mol.OBMol)
    forcefield.SetConstraints(constraints)
    forcefield.EnableCutOff(True) # VDW cutoff
    forcefield.SetElectrostaticCutOff(0) # Remove electrostatics

    # Use forcefield to reoptimize bondlengths+angles
    find_local_min()
Beispiel #8
0
def cell_ffopt(ff, mol, frozenats):
    ### FORCE FIELD OPTIMIZATION ##
    # INPUT
    #   - ff: force field to use, available MMFF94, UFF< Ghemical, GAFF
    #   - mol: mol3D to be ff optimized
    # OUTPUT
    #   - mol: force field optimized mol3D
    metals = list(range(21, 31))+list(range(39, 49))+list(range(72, 81))
    # check requested force field
    ffav = 'mmff94, uff, ghemical, gaff, mmff94s'  # force fields
    if ff.lower() not in ffav:
        print('Requested force field not available. Defaulting to UFF')
        ff = 'UFF'
    # convert mol3D to OBMol via xyz file, because AFTER/END option have coordinates
    backup_mol = mol3D()
    backup_mol.copymol3D(mol)
 #   print('bck ' + str(backup_mol.getAtom(0).coords()))
 #   print('mol_ibf ' + str(mol.getAtom(0).coords()))
    mol.convert2OBMol()
    # initialize constraints
    constr = openbabel.OBFFConstraints()
    # openbabel indexing starts at 1 ### !!!
    # convert metals to carbons for FF
    indmtls = []
    mtlsnums = []
    for iiat, atom in enumerate(openbabel.OBMolAtomIter(mol.OBMol)):
        if atom.GetAtomicNum() in metals:
            indmtls.append(iiat)
            mtlsnums.append(atom.GetAtomicNum())
            atom.SetAtomicNum(6)
    for cat in frozenats:
        constr.AddAtomConstraint(cat+1)  # indexing babel
    # set up forcefield
    forcefield = openbabel.OBForceField.FindForceField(ff)
    forcefield.Setup(mol.OBMol, constr)
    # force field optimize structure
    forcefield.ConjugateGradients(2500)
    forcefield.GetCoordinates(mol.OBMol)
    # reset atomic number to metal
    for i, iiat in enumerate(indmtls):
        mol.OBMol.GetAtomById(iiat).SetAtomicNum(mtlsnums[i])
    mol.convert2mol3D()
    en = forcefield.Energy()

    del forcefield, constr
    return mol, en
Beispiel #9
0
    def gen_types_from_bonds(self):
        """
        Pass the bonding information into openbabel to get the atomic types.
        """
        # import these locally so we can run fapswitch without them
        import openbabel as ob
        import pybel

        # Construct the molecule from atoms and bonds

        obmol = ob.OBMol()
        obmol.BeginModify()

        for atom in self.atoms:
            new_atom = obmol.NewAtom()
            new_atom.SetAtomicNum(atom.atomic_number)

        for bond, bond_info in self.bonds.items():
            # Remember openbabel indexes from 1
            obmol.AddBond(bond[0] + 1, bond[1] + 1,
                          OB_BOND_ORDERS[bond_info[1]])

        obmol.EndModify()

        pybel_mol = pybel.Molecule(obmol)

        # need to tell the typing system to ignore all atoms in the setup
        # or it will silently crash with memory issues
        constraint = ob.OBFFConstraints()
        for at_idx in range(pybel_mol.OBMol.NumAtoms()):
            constraint.AddIgnore(at_idx)
        uff = ob.OBForceField_FindForceField('uff')
        uff.Setup(pybel_mol.OBMol, constraint)
        uff.GetAtomTypes(pybel_mol.OBMol)
        # Dative nitrogen bonds break aromaticity determination from resonant
        # structures, so make anything with an aromatic bond be aromatic
        for at_idx, atom, ob_atom in zip(count(), self.atoms, pybel_mol):
            uff_type = ob_atom.OBAtom.GetData("FFAtomType").GetValue()
            if atom.type in ['C', 'N', 'O', 'S']:
                for bond, bond_info in self.bonds.items():
                    if at_idx in bond and bond_info[1] == 1.5:
                        uff_type = uff_type[0] + '_R'
                        break

            atom.uff_type = uff_type
Beispiel #10
0
def SaveConf(X, mol, ffclean=True, catoms=[]):
    conf3D = mol3D()
    conf3D.copymol3D(mol)
    # set coordinates using OBMol to keep bonding info
    OBMol = conf3D.OBMol
    for i, atom in enumerate(openbabel.OBMolAtomIter(OBMol)):
        atom.SetVector(X[i, 0], X[i, 1], X[i, 2])

    #First stage of cleaning takes place with the metal still present
    if ffclean:
        ff = openbabel.OBForceField.FindForceField('UFF')
        s = ff.Setup(OBMol)
        if not s:
            print('FF setup failed')

        for i in range(200):
            ff.SteepestDescent(10)
            ff.ConjugateGradients(10)
        ff.GetCoordinates(OBMol)

    last_atom_index = OBMol.NumAtoms(
    )  #Delete the dummy metal atom that we added earlier
    metal_atom = OBMol.GetAtom(last_atom_index)
    OBMol.DeleteAtom(metal_atom)

    #Second stage of cleaning removes the metal, but uses constraints on the bonding atoms to ensure a binding conformer is maintained
    #This stage is critical for getting planar aromatic ligands like porphyrin and correct. Not really sure why though...
    if ffclean:
        ff = openbabel.OBForceField.FindForceField('UFF')
        constr = openbabel.OBFFConstraints()
        for atom in catoms:
            constr.AddAtomConstraint(atom + 1)
        s = ff.Setup(OBMol, constr)
        if not s:
            print('FF setup failed')

        for i in range(200):
            ff.SteepestDescent(10)
            ff.ConjugateGradients(10)
        ff.GetCoordinates(OBMol)

    conf3D.OBMol = OBMol
    conf3D.convert2mol3D()
    return conf3D
Beispiel #11
0
    def optg_c2(self, smartss, iass, ff='MMFF94', step=500):
        """
        optg with constraints specified by `smartss

        vars
        ================
        smartss -- ['[#1]', 'C(=O)[OH]']
        iass    -- [[0,], [1,2,3] ]
        """
        # Define constraints
        c = ob.OBFFConstraints()

        iast = list(range(self.na))
        iasf = []
        for i, smarts_i in enumerate(smartss):
            #if 'H' in smarts_i: assert self.addh
            q = pb.Smarts(smarts_i)
            assert q.obsmarts.Match(self.m), '#ERROR: no match?'
            for match in q.obsmarts.GetMapList():
                idxs = [self.m.GetAtom(ia).GetIdx() for ia in match]
                for j in iass[i]:
                    iasf.append(idxs[j])

        for ia in list(set(iast) ^ set(iasf)):
            c.AddAtomConstraint(idxs[j])

        # Setup the force field with the constraints
        f = ob.OBForceField.FindForceField(ff)
        assert f.Setup(
            self.m, c
        ), '#ERROR: ForceFiled setup failure [contains non-mmff94 elements]?'
        f.SetConstraints(c)
        #if optimizer in ['cg','CG','ConjugateGradients']:
        f.ConjugateGradients(step)
        #elif optimizer in ['sd','SD','SteepestDescent']:
        #    f.SteepestDescent(step)
        f.GetCoordinates(self.m)
        self.M = pb.Molecule(m)
        self.coords = get_coords(m)
Beispiel #12
0
def SaveConf(X, mol, ffclean=True, catoms=[]):
    conf3D = mol3D()
    conf3D.copymol3D(mol)
    # set coordinates using OBMol to keep bonding info
    OBMol = conf3D.OBMol
    for i, atom in enumerate(openbabel.OBMolAtomIter(OBMol)):
        atom.SetVector(X[i, 0], X[i, 1], X[i, 2])
    if ffclean:
        ff = openbabel.OBForceField.FindForceField('mmff94')
        constr = openbabel.OBFFConstraints()
        # constrain connecting atoms
        for catom in catoms:
            constr.AddAtomConstraint(catom + 1)
        s = ff.Setup(OBMol, constr)
        if not s:
            print('FF setup failed')
        for i in range(200):
            ff.SteepestDescent(10)
            ff.ConjugateGradients(10)
        ff.GetCoordinates(OBMol)
        conf3D.OBMol = OBMol
    conf3D.convert2mol3D()
    return conf3D
Beispiel #13
0
def cons_opt(infile,outfile,idx):
    """
    Only Mol2/UFF can Optimize
    Optimize with Pd1-P-P1 constraints
    :param infile:
    :param outfile:
    :param idx:
    :return:
    """
    p1,p2,pd = idx

    conv = ob.OBConversion()
    conv.SetInAndOutFormats("mol2", "mol2")
    mol = ob.OBMol()
    conv.ReadFile(mol, infile)

    cons = ob.OBFFConstraints()
    pp = 3.2
    ppd = 2.4
    cons.AddDistanceConstraint(p1, p2, pp)
    cons.AddDistanceConstraint(p1, pd, ppd)
    cons.AddDistanceConstraint(p2, pd, ppd)

        

    # Set up FF
    ff = ob.OBForceField.FindForceField("UFF")
    ff.Setup(mol, cons)
    ff.SetConstraints(cons)
    ff.EnableCutOff(True)

    # Optimize
    ff.ConjugateGradients(10000)
    ff.GetCoordinates(mol)


    def ring_bond(ring):
        """

        :param ring: OBRing class
        :return: list of lists [atom1,atom2]
        """
        bonds = []
        mol = ring.GetParent()
        for bond in ob.OBMolBondIter(mol):
            at1 = bond.GetBeginAtom().GetIndex() + 1
            at2 = bond.GetEndAtom().GetIndex() + 1
            if ring.IsMember(bond):
                if not bond.IsAromatic():
                    bonds.append(sorted([at1,at2]))
        return bonds
    def common_atom(bond,bonds):
        """
        :param bond: list [atom1,atom2]
        :param bonds: list of list [atom1,atom2]
        :return: True if there is common atom in bonds
        """
        result = False
        if len(bonds) == 0:
            return result
        for bond2 in bonds:
            for at1 in bond:
                for at2 in bond2:
                    if at1 == at2:
                        result = True
                        return result
        return result

    # extract ring info
    # iterate over all bond
    # CHIRAL ATOMS
    chiral = []
    for atom in ob.OBMolAtomIter(mol):
        if atom.IsChiral():
            chiral.append(atom.GetIndex() + 1)
    rot_bond = []
    rca4 = []

    rca23 = []
    for bond in ob.OBMolBondIter(mol):
        at1 = bond.GetBeginAtom().GetIndex() + 1
        at2 = bond.GetEndAtom().GetIndex() + 1
#        print(at1, at2)
        if bond.IsRotor() and not bond.IsAromatic():
            rot = sorted([at1,at2])
#            print(outfile,"ROT ",rot)
            rot_bond.append(rot)
        if bond.IsClosure():
            rca0 = sorted([at1,at2])
            rca = sorted([at1,at2])

            # The Assumption is IsClosure picking up only one bond in the ring
            # and bond.IsRotor() does not provide any ring bonds.
            # to prevent rca23 sharing common atoms
            if len(rca23) != 0:
                if common_atom(rca,rca23):
                    ringbonds = ring_bond(bond.FindSmallestRing())
                    for rbond in ringbonds:
                        if common_atom(rbond,rca23):
                            continue
                        else:
                            rca0 = rbond.copy()
                            rca = rbond.copy()
                            break
            else:
                ringbonds = ring_bond(bond.FindSmallestRing())
                for rbond in ringbonds:
                    if not (rbond[0] in rca or rbond[1] in rca):
                        rca0 = rbond.copy()
                        rca = rbond.copy()
                        break
            rca23.append(rca0)

            #print(outfile,"RING OPENING BOND", rca0)
            ring = bond.FindSmallestRing()
            ring_rots = []
            if not ring.IsAromatic():
                for bond1 in ob.OBMolBondIter(mol):
                    if ring.IsMember(bond1):
                        b1 = bond1.GetBeginAtom().GetIndex() + 1
                        b2 = bond1.GetEndAtom().GetIndex() + 1
                        rot = sorted([b1,b2])
                        if rot != rca0:
                            ring_rots.append(rot)
                #print("RING ROT:",ring_rots)
                for rrot in ring_rots:
                    if rca0[0] in rrot:
                        atom = rrot.copy()
                        atom.remove(rca0[0])
                        #print(atom)
                        rca.insert(0,atom[0])
                        #print("INSERT ",rca)
                    elif rca0[1] in rrot:
                        atom = rrot.copy()
                        atom.remove(rca0[1])
                        #print(rca)
                        rca.append(atom[0])
                        #print("APPEND ",rca)
                    elif rca0 != rot:
                        rot_bond.append(rrot)
                    
                rca4.append(rca)
    # print(outfile,"CHIRAL",chiral)
    # print(outfile,"RCA4",rca4)
    # print(outfile,"RCA23",rca23)
    check = []
    for rr in rca4:
        check.append(rr[1])
        check.append(rr[2])
        bond = sorted([rr[1],rr[2]])
        if bond in rot_bond:
            rot_bond.remove(bond)
    if len(check) != len(set(check)):
        print("\t\tBAD",outfile)
        print("\t\t",rca4)
 #   else:
#        print("\t\tBAD",outfile)

    # print(outfile,"ROT", rot_bond)

    conv.WriteFile(mol, outfile)
    return chiral, rca4, rot_bond
Beispiel #14
0
def add_pd(infile,outfile):
    conv = ob.OBConversion()
    conv.SetInAndOutFormats("mol2","mol2")
    mol = ob.OBMol()
    conv.ReadFile(mol, infile)

    nAtoms = mol.NumAtoms()

    p = []
    for i in range(nAtoms):
        n = i + 1
        at = mol.GetAtom(n)
        an = (at.GetAtomicNum())
        if an == 15:
            p.append(n)
        elif an == 8:
            # Oxygen
            neis = []
            for nei in ob.OBAtomAtomIter(at):
                neis.append(nei)
            # Oxygen has one neighbor
            lnei = len(neis)
            if lnei == 1:
                nei = neis[0]
                # neighbor is P (i.e. P=O)
                if nei.GetAtomicNum() == 15:
                    return None

    if len(p) != 2:
        return None
    # optimize for P-P distance first
    p1, p2 = p
    cons = ob.OBFFConstraints()
    pp = 3.2
    cons.AddDistanceConstraint(p1, p2, pp)

    # Set up FF
    ff = ob.OBForceField.FindForceField("UFF")
    ff.Setup(mol, cons)
    ff.SetConstraints(cons)
    ff.EnableCutOff(True)
    # Optimize
    ff.ConjugateGradients(10000)
    ff.GetCoordinates(mol)
    cont = True
    while cont:
        pho1 = mol.GetAtom(p1)
        pho2 = mol.GetAtom(p2)
        pp1 = pho1.GetDistance(pho2)
        err0 = abs(pp1-pp)
        if err0 < 0.015:
            cont = False

        else:
            print("\tNOT converged YET:",outfile, " diff:", err0)
            ff.ConjugateGradients(10000)
            ff.GetCoordinates(mol)


    p = []
    pxyz = []
    nxyz = []
    # find out where two P are located
    for i in range(nAtoms):
        n = i + 1
        at = mol.GetAtom(n)
        an = (at.GetAtomicNum())
        if an == 15:
            p.append(n)
            pxyz.append([at.x(),at.y(),at.z()])
        else:
            nxyz.append([at.x(),at.y(),at.z()])
    nxyz = np.array(nxyz)






    # Add Pd and connect it to two Ps
    a = mol.NewAtom()
    a.SetAtomicNum(46)
    pxyz = np.array(pxyz)
    x,y,z = (pxyz[0] + pxyz[1])/2
    pdxyz = np.array([x,y,z])
    vec0 = None
    r0 = 100.0
    for vec in nxyz:
        vec = vec - pdxyz
        r = np.linalg.norm(vec)
        if r < r0:
            r0 = r
            vec0 = vec
    x,y,z = pdxyz-10.0*vec0
    a.SetVector(x,y,z)
    # AddBond(BeginIdx,EndIdx,bond order)
    pd = mol.NumAtoms()
    p1,p2 = p
    mol.AddBond(pd,p1,1)
    mol.AddBond(pd,p2,1)
    mol.NumAtoms()
    
    conv.WriteFile(mol, outfile)
    return [p1,p2,pd]
def generate_limited_rotamer_set(
        input_path,
        output_path,
        atoms_to_unfreeze,
        output_format='mol2',
        include_input_conformation_in_output=True,
        # Note: the Confab settings below (rmsd_cutoff, conf_cutoff, energy_cutoff, verbose)
        # are currently set to the default values from Confab.
        # You you might need to change these for your project.
        rmsd_cutoff=0.5,
        conf_cutoff=10000,
        energy_cutoff=25.0,
        confab_verbose=True):
    assert (output_path.endswith(output_format))

    assert (os.path.isfile(input_path))
    mol = read_molecules(input_path, single=True)
    # force field for open babel applied - mmff94
    pff = ob.OBForceField_FindType("mmff94")
    assert (pff.Setup(mol))  # Make sure setup works OK

    count_aromatic_bonds(mol)

    print("Molecule " + mol.GetTitle())
    print("Number of rotatable bonds = " + str(mol.NumRotors()))

    if len(atoms_to_unfreeze) > 0:
        print('%d atoms will be allowed to move; freezing others' %
              len(atoms_to_unfreeze))
        constraints = ob.OBFFConstraints()
        for atom in ob.OBMolAtomIter(mol):
            atom_id = atom.GetIndex() + 1
            if atom_id not in atoms_to_unfreeze:
                constraints.AddAtomConstraint(atom_id)
        pff.SetConstraints(constraints)

    # Run Confab conformer generation
    pff.DiverseConfGen(rmsd_cutoff, conf_cutoff, energy_cutoff, confab_verbose)

    pff.GetConformers(mol)
    if include_input_conformation_in_output:
        confs_to_write = mol.NumConformers()
    else:
        confs_to_write = mol.NumConformers() - 1

    print("Generated %d conformers total (%d will be written)" %
          (mol.NumConformers(), confs_to_write))

    obconversion = ob.OBConversion()
    obconversion.SetOutFormat(output_format)

    output_strings = []

    for conf_num in range(confs_to_write):
        mol.SetConformer(conf_num)
        output_strings.append(obconversion.WriteString(mol))

    print('Writing %d conformations to %s' %
          (len(output_strings), output_path))
    with open(output_path, 'w') as f:
        for output_string in output_strings:
            f.write(output_string)
Beispiel #16
0
    def gen_babel_uff_properties(self):
        """
        Process a supercell with babel to calculate UFF atom types and
        bond orders.
        """
        # import these locally so we can run fapswitch without them
        import openbabel as ob
        import pybel
        # Pass as free form fractional
        # GG's periodic should take care of bonds
        warning("Assuming periodic openbabel; not generating supercell")
        cell = self.cell
        as_fffract = [
            'generated fractionals\n',
            '%f %f %f %f %f %f\n' % cell.params
        ]
        for atom in self.atoms:
            atom_line = ("%s " % atom.type +
                         "%f %f %f\n" % tuple(atom.cellfpos))
            as_fffract.append(atom_line)
        pybel_string = ''.join(as_fffract)
        pybel_mol = pybel.readstring('fract', pybel_string)
        # need to tell the typing system to ignore all atoms in the setup
        # or it will silently crash with memory issues
        constraint = ob.OBFFConstraints()
        for at_idx in range(pybel_mol.OBMol.NumAtoms()):
            constraint.AddIgnore(at_idx)
        uff = ob.OBForceField_FindForceField('uff')
        uff.Setup(pybel_mol.OBMol, constraint)
        uff.GetAtomTypes(pybel_mol.OBMol)
        for atom, ob_atom in zip(self.atoms, pybel_mol):
            atom.uff_type = ob_atom.OBAtom.GetData("FFAtomType").GetValue()

        bonds = {}
        max_idx = self.natoms
        # look at all the bonds separately from the atoms
        for bond in ob.OBMolBondIter(pybel_mol.OBMol):
            # These rules are translated from ob/forcefielduff.cpp...
            start_idx = bond.GetBeginAtomIdx()
            end_idx = bond.GetEndAtomIdx()
            if start_idx > max_idx and end_idx > max_idx:
                continue
            if end_idx > max_idx:
                end_idx %= max_idx
            if start_idx > max_idx:
                start_idx %= max_idx

            start_atom = bond.GetBeginAtom()
            end_atom = bond.GetEndAtom()

            bond_order = bond.GetBondOrder()
            if bond.IsAromatic():
                bond_order = 1.5
            # e.g., in Cp rings, may not be "aromatic" by OB
            # but check for explicit hydrogen counts
            #(e.g., biphenyl inter-ring is not aromatic)
            #FIXME(tdaff): aromatic C from GetType is "Car" is this correct?
            if start_atom.GetType()[-1] == 'R' and end_atom.GetType(
            )[-1] == 'R' and start_atom.ExplicitHydrogenCount(
            ) == 1 and end_atom.ExplicitHydrogenCount() == 1:
                bond_order = 1.5
            if bond.IsAmide():
                bond_order = 1.41
            # save the indicies as zero based
            bond_length = bond.GetLength()
            bond_id = tuple(sorted((start_idx - 1, end_idx - 1)))
            bonds[bond_id] = (bond_length, bond_order)

        self.bonds = bonds
Beispiel #17
0
def SaveConf(X, mol, ffclean=True, catoms=[]):
    """Further cleans up with OB FF and saves to a new mol3D object.
    Note that distance geometry tends to produce puckered aromatic rings because of the 
    lack of explicit impropers, see Riniker et al. JCIM (2015) 55, 2562-74 for details.
    Hence, a FF optimization (with connection atoms constrained) is recommended to clean up the structure.
        
    Parameters
    ----------
        x : np.array
            Array of coordinates.
        mol : mol3D
            mol3D class instance of original molecule.
        ffclean : bool, optional
            Flag for openbabel forcefield cleanup. Default is True.
        catoms : list, optional
            List of connection atoms used to generate FF constraints if specified. Default is empty.
        
    Returns
    -------
        conf3D : mol3D
            mol3D class instance of conformer.

    """
    conf3D = mol3D()
    conf3D.copymol3D(mol)
    # set coordinates using OBMol to keep bonding info
    OBMol = conf3D.OBMol
    for i, atom in enumerate(openbabel.OBMolAtomIter(OBMol)):
        atom.SetVector(X[i, 0], X[i, 1], X[i, 2])

    #First stage of cleaning takes place with the metal still present
    if ffclean:
        ff = openbabel.OBForceField.FindForceField('UFF')
        s = ff.Setup(OBMol)
        if not s:
            print('FF setup failed')

        for i in range(200):
            ff.SteepestDescent(10)
            ff.ConjugateGradients(10)
        ff.GetCoordinates(OBMol)

    last_atom_index = OBMol.NumAtoms(
    )  #Delete the dummy metal atom that we added earlier
    metal_atom = OBMol.GetAtom(last_atom_index)
    OBMol.DeleteAtom(metal_atom)

    #Second stage of cleaning removes the metal, but uses constraints on the bonding atoms to ensure a binding conformer is maintained
    #This stage is critical for getting planar aromatic ligands like porphyrin and correct. Not really sure why though...
    if ffclean:
        ff = openbabel.OBForceField.FindForceField('UFF')
        constr = openbabel.OBFFConstraints()
        for atom in catoms:
            constr.AddAtomConstraint(atom + 1)
        s = ff.Setup(OBMol, constr)
        if not s:
            print('FF setup failed')

        for i in range(200):
            ff.SteepestDescent(10)
            ff.ConjugateGradients(10)
        ff.GetCoordinates(OBMol)

    conf3D.OBMol = OBMol
    conf3D.convert2mol3D()
    return conf3D
Beispiel #18
0
    def confab_conformers(self,
                          forcefield="mmff94",
                          freeze_atoms=None,
                          rmsd_cutoff=0.5,
                          energy_cutoff=50.0,
                          conf_cutoff=100000,
                          verbose=False):
        """
        Conformer generation based on Confab to generate all diverse low-energy
        conformers for molecules. This is different from rotor_conformer or
        gen3d_conformer as it aims to not simply to find a low energy
        conformation but to generate several different conformations.

        Args:
            forcefield (str): Default is mmff94. Options are 'gaff', 'ghemical',
                'mmff94', 'mmff94s', and 'uff'.
            freeze_atoms ([int]): index of atoms to be freezed when performing
                conformer search, default is None.
            rmsd_cutoff (float): rmsd_cufoff, default is 0.5 Angstrom.
            energy_cutoff (float): energy_cutoff, default is 50.0 kcal/mol.
            conf_cutoff (float): max number of conformers to test,
                default is 1 million.
            verbose (bool): whether to display information on torsions found,
                default is False.

        Returns:
             (list): list of pymatgen Molecule objects for generated conformers.
        """
        if self._obmol.GetDimension() != 3:
            self.make3d()
        else:
            self.add_hydrogen()

        ff = ob.OBForceField_FindType(forcefield)
        if ff == 0:
            print("Could not find forcefield {} in openbabel, the forcefield "
                  "will be reset as default 'mmff94'".format(forcefield))
            ff = ob.OBForceField_FindType("mmff94")

        if freeze_atoms:
            print('{} atoms will be freezed'.format(len(freeze_atoms)))
            constraints = ob.OBFFConstraints()

            for atom in ob.OBMolAtomIter(self._obmol):
                atom_id = atom.GetIndex() + 1
                if id in freeze_atoms:
                    constraints.AddAtomConstraint(atom_id)
            ff.SetConstraints(constraints)

        # Confab conformer generation
        ff.DiverseConfGen(rmsd_cutoff, conf_cutoff, energy_cutoff, verbose)
        ff.GetConformers(self._obmol)

        # Number of conformers generated by Confab conformer generation
        conformer_num = self._obmol.NumConformers()

        conformers = []
        for i in range(conformer_num):
            self._obmol.SetConformer(i)
            conformer = copy.deepcopy(
                BabelMolAdaptor(self._obmol).pymatgen_mol)
            conformers.append(conformer)
        self._obmol.SetConformer(0)
        return conformers
Beispiel #19
0
def minimize_ob(selection='enabled',
                state=-1,
                ff='UFF',
                nsteps=500,
                conv=0.0001,
                cutoff=0,
                cut_vdw=6.0,
                cut_elec=8.0,
                name='',
                quiet=1,
                _self=cmd):
    '''
DESCRIPTION

    Emergy minimization with openbabel

    Supports fixed atoms (flag fix)

ARGUMENTS

    selection = str: atom selection

    state = int: object state {default: -1}

    ff = GAFF|MMFF94s|MMFF94|UFF|Ghemical: force field {default: UFF}

    nsteps = int: number of steps {default: 500}
    '''
    import openbabel as ob

    state = int(state)

    sele = _self.get_unused_name('_sele')
    _self.select(sele, selection, 0)

    try:
        ioformat = 'mol'
        molstr = _self.get_str(ioformat, sele, state)

        obconversion = ob.OBConversion()
        obconversion.SetInAndOutFormats(ioformat, ioformat)

        mol = ob.OBMol()
        obconversion.ReadString(mol, molstr)

        # add hydrogens
        orig_ids = [a.GetId() for a in ob.OBMolAtomIter(mol)]
        mol.AddHydrogens()
        added_ids = set(a.GetId()
                        for a in ob.OBMolAtomIter(mol)).difference(orig_ids)

        consttrains = ob.OBFFConstraints()
        consttrains.Setup(mol)

        # atoms with "flag fix"
        fixed_indices = get_fixed_indices(sele, state, _self)
        for idx in fixed_indices:
            consttrains.AddAtomConstraint(idx + 1)

        # setup forcefield (one of: GAFF, MMFF94s, MMFF94, UFF, Ghemical)
        ff = ob.OBForceField.FindForceField(ff)
        ff.Setup(mol, consttrains)

        if int(cutoff):
            ff.EnableCutOff(True)
            ff.SetVDWCutOff(float(cut_vdw))
            ff.SetElectrostaticCutOff(float(cut_elec))

        # run minimization
        ff.SteepestDescent(int(nsteps) // 2, float(conv))
        ff.ConjugateGradients(int(nsteps) // 2, float(conv))
        ff.GetCoordinates(mol)

        # remove previously added hydrogens
        for hydro_id in added_ids:
            mol.DeleteAtom(mol.GetAtomById(hydro_id))

        molstr = obconversion.WriteString(mol)
        load_or_update(molstr, name, sele, state, _self)

        if not int(quiet):
            print(' Energy: %8.2f %s' % (ff.Energy(), ff.GetUnit()))
    finally:
        _self.delete(sele)