Exemplo n.º 1
0
 def testMMFFTorsionConstraints(self):
     m = Chem.MolFromMolBlock(self.molB, True, False)
     conf = m.GetConformer()
     rdMolTransforms.SetDihedralDeg(conf, 1, 3, 6, 8, 15.0)
     mp = ChemicalForceFields.MMFFGetMoleculeProperties(m)
     ff = ChemicalForceFields.MMFFGetMoleculeForceField(m, mp)
     self.assertTrue(ff)
     ff.MMFFAddTorsionConstraint(1, 3, 6, 8, False, 10.0, 20.0, 100.0)
     r = ff.Minimize()
     self.assertTrue(r == 0)
     dihedral = rdMolTransforms.GetDihedralDeg(conf, 1, 3, 6, 8)
     self.assertEquals(int(dihedral), 20)
     rdMolTransforms.SetDihedralDeg(conf, 1, 3, 6, 8, -30.0)
     ff = ChemicalForceFields.MMFFGetMoleculeForceField(m, mp)
     self.assertTrue(ff)
     ff.MMFFAddTorsionConstraint(1, 3, 6, 8, True, -10.0, 8.0, 100.0)
     r = ff.Minimize()
     self.assertTrue(r == 0)
     conf = m.GetConformer()
     dihedral = rdMolTransforms.GetDihedralDeg(conf, 1, 3, 6, 8)
     self.assertTrue(int(dihedral) == -40)
     rdMolTransforms.SetDihedralDeg(conf, 1, 3, 6, 8, -10.0)
     ff = ChemicalForceFields.MMFFGetMoleculeForceField(m, mp)
     self.assertTrue(ff)
     ff.MMFFAddTorsionConstraint(1, 3, 6, 8, False, -10.0, 8.0, 100.0)
     r = ff.Minimize(1000)
     self.assertTrue(r == 0)
     conf = m.GetConformer()
     dihedral = rdMolTransforms.GetDihedralDeg(conf, 1, 3, 6, 8)
     self.assertTrue(int(dihedral) == -10)
Exemplo n.º 2
0
 def testUFFTorsionConstraints(self):
     m = Chem.MolFromMolBlock(self.molB, True, False)
     conf = m.GetConformer()
     rdMolTransforms.SetDihedralDeg(conf, 1, 3, 6, 8, 15.0)
     ff = ChemicalForceFields.UFFGetMoleculeForceField(m)
     self.assertTrue(ff)
     ff.UFFAddTorsionConstraint(1, 3, 6, 8, False, 10.0, 20.0, 100.0)
     r = ff.Minimize()
     self.assertTrue(r == 0)
     dihedral = rdMolTransforms.GetDihedralDeg(conf, 1, 3, 6, 8)
     self.assertAlmostEqual(dihedral, 20, delta=0.1)
     rdMolTransforms.SetDihedralDeg(conf, 1, 3, 6, 8, -30.0)
     ff = ChemicalForceFields.UFFGetMoleculeForceField(m)
     self.assertTrue(ff)
     ff.UFFAddTorsionConstraint(1, 3, 6, 8, True, -10.0, 8.0, 100.0)
     r = ff.Minimize()
     self.assertTrue(r == 0)
     conf = m.GetConformer()
     dihedral = rdMolTransforms.GetDihedralDeg(conf, 1, 3, 6, 8)
     self.assertAlmostEqual(dihedral, -40, delta=0.1)
     rdMolTransforms.SetDihedralDeg(conf, 1, 3, 6, 8, -10.0)
     ff = ChemicalForceFields.UFFGetMoleculeForceField(m)
     self.assertTrue(ff)
     ff.UFFAddTorsionConstraint(1, 3, 6, 8, False, -10.0, 8.0, 1.0e6)
     r = ff.Minimize(500)
     self.assertTrue(r == 0)
     conf = m.GetConformer()
     dihedral = rdMolTransforms.GetDihedralDeg(conf, 1, 3, 6, 8)
     self.assertAlmostEqual(dihedral, -10, delta=0.1)
Exemplo n.º 3
0
    def testGetSetDihedralThroughTripleBond(self):
        file = os.path.join(RDConfig.RDBaseDir, 'Code', 'GraphMol',
                            'MolTransforms', 'test_data', 'github1262_2.mol')

        m = Chem.MolFromMolFile(file, True, False)
        conf = m.GetConformer()
        rdmt.SetDihedralDeg(conf, 6, 1, 2, 9, 0.0)
        dihedral = rdmt.GetDihedralDeg(conf, 6, 1, 2, 9)
        self.assertAlmostEqual(dihedral, 0.0, 1)
        dist = rdmt.GetBondLength(conf, 6, 9)
        rdmt.SetDihedralDeg(conf, 6, 1, 2, 9, 120.0)
        dihedral = rdmt.GetDihedralDeg(conf, 6, 1, 2, 9)
        self.assertAlmostEqual(dihedral, 120.0, 1)
        dist2 = rdmt.GetBondLength(conf, 6, 7)
        self.assertAlmostEqual(dist, dist2, 1)
        rdmt.SetDihedralDeg(conf, 6, 1, 2, 9, 180.0)
        dihedral = rdmt.GetDihedralDeg(conf, 6, 1, 2, 9)
        self.assertAlmostEqual(dihedral, 180.0, 1)
        dist3 = rdmt.GetBondLength(conf, 6, 9)
        self.assertNotAlmostEqual(dist, dist3, 1)
        exceptionRaised = False
        try:
            rdmt.SetDihedralDeg(conf, 6, 0, 3, 9, 0.0)
        except ValueError:
            exceptionRaised = True
        self.assertTrue(exceptionRaised)
Exemplo n.º 4
0
 def testUFFTorsionConstraints(self) :
   m = Chem.MolFromMolBlock(self.molB, True, False)
   conf = m.GetConformer()
   rdMolTransforms.SetDihedralDeg(conf, 1, 3, 6, 8, 50.0);
   ff = ChemicalForceFields.UFFGetMoleculeForceField(m)
   self.assertTrue(ff)
   ff.UFFAddTorsionConstraint(1, 3, 6, 8, False, 10.0, 20.0, 1.0e5)
   r = ff.Minimize()
   self.assertTrue(r == 0)
   dihedral = rdMolTransforms.GetDihedralDeg(conf, 1, 3, 6, 8)
   self.assertTrue(int(dihedral) == 20)
   rdMolTransforms.SetDihedralDeg(conf, 1, 3, 6, 8, -30.0);
   ff = ChemicalForceFields.UFFGetMoleculeForceField(m)
   self.assertTrue(ff)
   ff.UFFAddTorsionConstraint(1, 3, 6, 8, True, -10.0, -8.0, 1.0e5)
   r = ff.Minimize()
   self.assertTrue(r == 0)
   conf = m.GetConformer()
   dihedral = rdMolTransforms.GetDihedralDeg(conf, 1, 3, 6, 8)
   self.assertTrue(int(dihedral) == -40)
   rdMolTransforms.SetDihedralDeg(conf, 1, 3, 6, 8, 30.0);
   ff = ChemicalForceFields.UFFGetMoleculeForceField(m)
   self.assertTrue(ff)
   ff.UFFAddTorsionConstraint(1, 3, 6, 8, False, -10.0, -8.0, 1.0e5)
   r = ff.Minimize(1000)
   self.assertTrue(r == 0)
   conf = m.GetConformer()
   dihedral = rdMolTransforms.GetDihedralDeg(conf, 1, 3, 6, 8)
   self.assertTrue(int(dihedral) == -10)
Exemplo n.º 5
0
def tinker_minimize_angles(poltype,molecprefix,a,b,c,d,optmol,consttorlist,phaseanglelist,prevstrctfname,torsionrestraint,torang,bondtopology):
    tinkerstructnamelist=[]
    # load prevstruct

    # create xyz and key and write restraint then minimize, getting .xyz_2
    for phaseangle in phaseanglelist: # we need to send back minimized structure in XYZ (not tinker) format to load for next tinker minimization,but append the xyz_2 tinker XYZ file so that com file can be generated from that 
        prevstruct = opt.load_structfile(poltype,prevstrctfname)
        prevstruct = opt.PruneBonds(poltype,prevstruct,bondtopology) # sometimes extra bonds are made when atoms get too close during minimization
        prevstruct=opt.rebuild_bonds(poltype,prevstruct,optmol)
        obConversion = openbabel.OBConversion()
        obConversion.SetInFormat('mol')
        obConversion.SetOutFormat('mol2')
        obConversion.WriteFile(prevstruct, 'temp.mol2')
        try:
            rdmol=MolFromMol2File('temp.mol2',False,False)   
        except:
            rdmol=MolFromMol2File('temp.mol2',True,False)
        conf = rdmol.GetConformer()
        dihedral = optmol.GetTorsion(a,b,c,d)
        newdihedral=round((dihedral+phaseangle)%360)
        rdmt.SetDihedralDeg(conf, a-1, b-1, c-1, d-1, newdihedral)
        try:
            print(Chem.MolToMolBlock(rdmol,kekulize=True),file=open('tempout.mol','w+'))
        except:
            print(Chem.MolToMolBlock(rdmol,kekulize=False),file=open('tempout.mol','w+'))

        obConversion.ReadFile(prevstruct, 'tempout.mol')
        prevstrctfname,torxyzfname,newtorxyzfname,keyfname=tinker_minimize(poltype,molecprefix,a,b,c,d,optmol,consttorlist,phaseangle,torsionrestraint,prevstruct,torang,'_preQMOPTprefit',poltype.key4fname,'../')
        tinkerstructnamelist.append(newtorxyzfname)
    return tinkerstructnamelist
    def generate_dihedral_conformers(self, resolution):
        """
        Given a resolution, it generates all the possible conformers
        that come out when rotating the dihedral's rotatable bond.

        Parameters
        ----------
        resolution : float
            The resolution, in degrees, that is applied when rotating
            the dihedral rotatable bond. Default is 30 degrees

        Returns
        -------
        rdkit_mol : an rdkit.Chem.rdchem.Mol object
            The RDKit's Molecule object with the conformers that were
            generated
        """
        from copy import deepcopy
        from rdkit.Chem import rdMolTransforms

        rdkit_mol = deepcopy(self.molecule.rdkit_molecule)

        conformer = rdkit_mol.GetConformer()

        for angle in range(0, 360, resolution):
            rdMolTransforms.SetDihedralDeg(conformer, *self.atom_indexes,
                                           angle)
            rdkit_mol.AddConformer(conformer, assignId=True)

        # Remove initial conformer (which is repeated)
        rdkit_mol.RemoveConformer(conformer.GetId())

        return rdkit_mol
Exemplo n.º 7
0
    def test12CrippenO3A(self):
        " test CrippenO3A with constraints "

        #we superimpose two identical coplanar 4-phenylpyridines:
        #1) the usual way
        #2) forcing the pyridine nitrogen to match with the para
        #   carbon of the phenyl ring
        m = Chem.MolFromSmiles('n1ccc(cc1)-c1ccccc1')
        m1 = Chem.AddHs(m)
        rdDistGeom.EmbedMolecule(m1)
        mp = ChemicalForceFields.MMFFGetMoleculeProperties(m1)
        ff = ChemicalForceFields.MMFFGetMoleculeForceField(m1, mp)
        ff.Minimize()
        sub1 = m1.GetSubstructMatch(Chem.MolFromSmarts('nccc-cccc'))
        nIdx = sub1[0]
        cIdx = sub1[-1]
        dihe = sub1[2:6]
        rdMolTransforms.SetDihedralDeg(m1.GetConformer(), dihe[0], dihe[1],
                                       dihe[2], dihe[3], 0)
        m2 = copy.copy(m1)
        rdMolAlign.RandomTransform(m2)
        m3 = copy.copy(m2)
        pyO3A = rdMolAlign.GetCrippenO3A(m2, m1)
        pyO3A.Align()
        d = m2.GetConformer().GetAtomPosition(cIdx). \
          Distance(m1.GetConformer().GetAtomPosition(cIdx))
        self.assertAlmostEqual(d, 0, 0)
        pyO3A = rdMolAlign.GetCrippenO3A(m3, m1, constraintMap=[[cIdx, nIdx]])
        pyO3A.Align()
        d = m3.GetConformer().GetAtomPosition(cIdx). \
          Distance(m1.GetConformer().GetAtomPosition(cIdx))
        self.assertAlmostEqual(d, 7, 0)
Exemplo n.º 8
0
    def _get_child_states(self):
        child_states = []
        if len(self.state[1]) < len(self._rotatable_bonds):
            mol = self.state[0]
            conf = mol.GetConformer()
            mol.AddConformer(conf, assignId=True)
            bond_to_rotate = self._rotatable_bonds[len(self.state[1])]
            theta = rdMolTransforms.GetDihedralDeg(conf, bond_to_rotate[0],
                                                   bond_to_rotate[1],
                                                   bond_to_rotate[2],
                                                   bond_to_rotate[3])
            for allowed_angle_value in self._allowed_angle_values:
                new_theta = theta + allowed_angle_value
                rdMolTransforms.SetDihedralDeg(conf, bond_to_rotate[0],
                                               bond_to_rotate[1],
                                               bond_to_rotate[2],
                                               bond_to_rotate[3], new_theta)
                mol.AddConformer(conf, assignId=True)
            mol.RemoveConformer(conf.GetId())

            for i, conf in enumerate(mol.GetConformers()):
                theta = rdMolTransforms.GetDihedralDeg(conf, bond_to_rotate[0],
                                                       bond_to_rotate[1],
                                                       bond_to_rotate[2],
                                                       bond_to_rotate[3])
                child_mol = Chem.Mol(mol, False, conf.GetId())
                child_states.append((child_mol, self.state[1] + [theta]))

        return child_states
Exemplo n.º 9
0
    def set_dihedrals(self, list_of_changes):
        """ 
        Change the dihedrals of the RDkit molecule. The molecule is not optimised
        """
        current_angles = self.get_dihedrals()
        conf = self.molecule.GetConformer()
        for change, current in zip(list_of_changes, current_angles):
            rdMolTransforms.SetDihedralDeg(conf, current[0], current[1],
                                           current[2], current[3], change)

        self.dihedrals = list_of_changes
Exemplo n.º 10
0
    def testGetSetDihedral(self):
        file = os.path.join(RDConfig.RDBaseDir, 'Code', 'GraphMol',
                            'MolTransforms', 'test_data',
                            '3-cyclohexylpyridine.mol')

        m = Chem.MolFromMolFile(file, True, False)
        conf = m.GetConformer()
        dihedral = rdmt.GetDihedralDeg(conf, 0, 19, 21, 24)
        self.failUnlessAlmostEqual(dihedral, 176.05, 2)
        rdmt.SetDihedralDeg(conf, 8, 0, 19, 21, 65.0)
        dihedral = rdmt.GetDihedralDeg(conf, 8, 0, 19, 21)
        self.failUnlessAlmostEqual(dihedral, 65.0, 1)
        rdmt.SetDihedralDeg(conf, 8, 0, 19, 21, -130.0)
        dihedral = rdmt.GetDihedralDeg(conf, 8, 0, 19, 21)
        self.failUnlessAlmostEqual(dihedral, -130.0, 1)
        rdmt.SetDihedralRad(conf, 21, 19, 0, 8, -2. / 3. * math.pi)
        dihedral = rdmt.GetDihedralRad(conf, 8, 0, 19, 21)
        self.failUnlessAlmostEqual(dihedral, -2. / 3. * math.pi, 1)
        dihedral = rdmt.GetDihedralDeg(conf, 8, 0, 19, 21)
        self.failUnlessAlmostEqual(dihedral, -120.0, 1)
Exemplo n.º 11
0
    def set_torsion_angles(self, conf, angles, reflect=False):
        """
        reset the torsion angles and update molecular xyz
        """
        from rdkit.Chem import rdMolTransforms as rdmt

        for id, torsion in enumerate(self.torsionlist):
            (i, j, k, l) = torsion
            rdmt.SetDihedralDeg(conf, i, j, k, l, angles[id])
        
        xyz = self.align(conf, reflect)
        return xyz
Exemplo n.º 12
0
    def SetTorsionDeg(self,
                      torsion: list,
                      degree: Union[float, int]):
        """
        Set the dihedral angle of the torsion in degrees. The torsion can only be defined
        by a chain of bonded atoms.

        Args:
            torsion (list): A list of four atom indexes.
            degree (float, int): The dihedral angle of the torsion.
        """
        rdMT.SetDihedralDeg(self._conf, *torsion, degree)
Exemplo n.º 13
0
 def _select_next_move_randomly(self, state):
     mol = Chem.Mol(state[0])  # create a copy of the Mol
     conf = mol.GetConformer()
     bond_to_rotate = self._rotatable_bonds[len(state[1])]
     theta = rdMolTransforms.GetDihedralDeg(conf, bond_to_rotate[0],
                                            bond_to_rotate[1],
                                            bond_to_rotate[2],
                                            bond_to_rotate[3])
     theta += np.random.choice(self._allowed_angle_values)
     rdMolTransforms.SetDihedralDeg(conf, bond_to_rotate[0],
                                    bond_to_rotate[1], bond_to_rotate[2],
                                    bond_to_rotate[3], theta)
     conformer_id = mol.AddConformer(conf, assignId=True)
     return Chem.Mol(mol, False, conformer_id), state[1] + [theta]
Exemplo n.º 14
0
 def testUFFTorsionConstraints(self):
     m = Chem.MolFromMolBlock(self.molB, True, False)
     ff = ChemicalForceFields.UFFGetMoleculeForceField(m)
     self.failUnless(ff)
     conf = m.GetConformer()
     rdMolTransforms.SetDihedralDeg(conf, 1, 3, 6, 8, 60.0)
     ff.UFFAddTorsionConstraint(1, 3, 6, 8, False, 30.0, 30.0, 1.0e5)
     r = ff.Minimize()
     self.failUnless(r == 0)
     dihedral = rdMolTransforms.GetDihedralDeg(conf, 1, 3, 6, 8)
     self.failUnless(int(dihedral) == 30)
     ff = ChemicalForceFields.UFFGetMoleculeForceField(m)
     self.failUnless(ff)
     ff.UFFAddTorsionConstraint(1, 3, 6, 8, True, -10.0, 10.0, 1.0e5)
     r = ff.Minimize()
     self.failUnless(r == 0)
     conf = m.GetConformer()
     dihedral = rdMolTransforms.GetDihedralDeg(conf, 1, 3, 6, 8)
     self.failUnless(int(dihedral) == 40)
Exemplo n.º 15
0
def systematic_conformers(mol,
                          init_rdkit_mol,
                          theta=120.,
                          charged_fragments=True,
                          ff_variant='UFF',
                          max_iters=200,
                          threads=1,
                          check_stero=False):
    """Systematic rotation of dihedral angles theta degrees"""

    # find dihedrals of parent molecule and create all combinations
    # where the angles are rotated theta degrees.
    dihedral_idx = RotatableBonds(mol)

    conf = mol.GetConformer()

    dihedrals = list()
    for k, i, j, l in dihedral_idx:
        mol_dihedral = rdMolTransforms.GetDihedralDeg(conf, k, i, j, l)

        new_dihedrals = [
            mol_dihedral + x * theta for x in range(int(360. / theta))
        ]
        dihedrals.append(new_dihedrals)

    dihedralCombs = list(itertools.product(*dihedrals))

    # Create the conformations according to angle combinations
    # in dihedralCombs.
    for idx, dihedrals in enumerate(dihedralCombs):

        for (k, i, j, l), angle in zip(dihedral_idx, dihedrals):
            rdMolTransforms.SetDihedralDeg(conf, k, i, j, l, angle)

        mol.AddConformer(conf, assignId=True)

    # Clean conformers. Test if structure is corrupted or the stereo
    # chemistry changed.
    ff_clean(mol, init_rdkit_mol, ff_variant, max_iters, threads,
             charged_fragments, check_stero)

    return mol
Exemplo n.º 16
0
def dihedral_set(sdf_string, position, value):
    """ Set the dihedral angle.

    Args:
        sdf_string (string):
        position (list): 4 atoms defining the dihedral
        value : value to set
    Returns:
        modified sdf_string
    Raises:
        ValueError: If the lenght of the list is not equal 4.
    """
    if len(position) != 4:
        raise ValueError("The position needs to be defined by 4 integers")
    mol = Chem.MolFromMolBlock(sdf_string, removeHs=False)
    rdMolTransforms.SetDihedralDeg(mol.GetConformer(),
                                   ig(0)(position),
                                   ig(1)(position),
                                   ig(2)(position),
                                   ig(3)(position), value)

    return Chem.MolToMolBlock(mol)
def get_conformations(mol, max_number_of_conformations):
    raw_rot_bonds = mol.GetSubstructMatches(
        Chem.MolFromSmarts("[!#1]~[!$(*#*)&!D1]-!@[!$(*#*)&!D1]~[!#1]"))
    raw_rot_bonds += mol.GetSubstructMatches(
        Chem.MolFromSmarts("[*]~[*]-[O,S]-[#1]"))
    raw_rot_bonds += mol.GetSubstructMatches(
        Chem.MolFromSmarts("[*]~[*]-[NX3;H2]-[#1]"))

    bonds = []
    rot_bonds = []
    for k, i, j, l in raw_rot_bonds:
        if (i, j) not in bonds:
            bonds.append((i, j))
            rot_bonds.append((k, i, j, l))

    conf = mol.GetConformer()

    angles = []
    for k, i, j, l in rot_bonds:
        theta = rdMolTransforms.GetDihedralDeg(conf, k, i, j, l)
        angles.append([theta, theta + 120., theta - 120.])

    angle_combinations = list(itertools.product(*angles))

    number_of_conformations = len(angle_combinations)

    if number_of_conformations > max_number_of_conformations:
        angle_combinations = get_subset(number_of_conformations,
                                        max_number_of_conformations,
                                        angle_combinations)

    for angle_combination in angle_combinations:
        for (k, i, j, l), angle in zip(rot_bonds, angle_combination):
            rdMolTransforms.SetDihedralDeg(conf, k, i, j, l, angle)
        mol.AddConformer(conf, assignId=True)

    #print mol.GetNumConformers()

    return mol
Exemplo n.º 18
0
def set_rdkit_dihedrals(conf, rd_mol, index_map, rd_scan, deg_increment=None, deg_abs=None):
    """
    A helper function for setting dihedral angles
    `conf` is the RDKit conformer with the current xyz information
    `rd_mol` is the RDKit molecule
    `indx_map` is an atom index mapping dictionary, keys are xyz_index, values are rd_index
    `rd_scan` is the torsion scan atom indices corresponding to the RDKit conformer indices
    Either `deg_increment` or `deg_abs` must be specified for the dihedral increment
    Returns xyz in an array format ordered according to the map,
    the elements in the xyz should be identified by the calling function from the context
    """
    if deg_increment is None and deg_abs is None:
        raise SpeciesError('Cannot set dihedral without either a degree increment or an absolute degree')
    if deg_increment is not None:
        deg0 = rdMT.GetDihedralDeg(conf, rd_scan[0], rd_scan[1], rd_scan[2], rd_scan[3])  # get original dihedral
        deg = deg0 + deg_increment
    else:
        deg = deg_abs
    rdMT.SetDihedralDeg(conf, rd_scan[0], rd_scan[1], rd_scan[2], rd_scan[3], deg)
    new_xyz = list()
    for i in range(rd_mol.GetNumAtoms()):
        new_xyz.append([conf.GetAtomPosition(index_map[i]).x, conf.GetAtomPosition(index_map[i]).y,
                        conf.GetAtomPosition(index_map[i]).z])
    return new_xyz
Exemplo n.º 19
0
    def get_energies(self, resolution=30, get_thetas=False):
        """
        It returns the energies of this energetic profile calculator.

        Parameters
        ----------
        resolution : float
            The resolution, in degrees, that is applied when rotating
            the dihedral rotatable bond. Default is 30 degrees
        get_thetas : bool
            Whether to return thetas (dihedral angles) or not. Default
            is False

        Returns
        -------
        dihedral_energies : a simtk.unit.Quantity object
            The array of energies represented with a simtk's Quantity
            object
        thetas : list[float]
            The array of thetas, only if requested in the corresponding
            function parameter
        """

        import numpy as np
        from copy import deepcopy
        from simtk import unit
        from rdkit.Chem import rdMolTransforms

        xs = unit.Quantity(np.arange(0, 360, resolution), unit=unit.degrees)
        ys = unit.Quantity(np.zeros(len(xs)),
                           unit=(unit.kilocalorie / unit.mole))

        rdkit_mol = deepcopy(self.dihedral_benchmark.molecule.rdkit_molecule)
        conformer = rdkit_mol.GetConformer()

        propers = self.dihedral_benchmark.molecule.propers

        a1, a2 = self.dihedral_benchmark.rotatable_bond

        for proper in propers:
            rot_bond = set((proper.atom2_idx, proper.atom3_idx))

            if a1 in rot_bond and a2 in rot_bond:
                if proper.constant == 0:
                    continue

                constant = proper.constant
                prefactor = proper.prefactor
                periodicity = proper.periodicity
                phase = proper.phase

                for j, x in enumerate(xs):
                    rdMolTransforms.SetDihedralDeg(
                        conformer, *self.dihedral_benchmark.atom_indexes,
                        float(x.value_in_unit(unit.degree)))
                    theta = unit.Quantity(value=rdMolTransforms.GetDihedralDeg(
                        conformer, *indexes),
                                          unit=unit.degree)

                    ys[j] += constant * (
                        1 + prefactor *
                        np.cos(periodicity * theta.value_in_unit(unit.radian) -
                               phase.value_in_unit(unit.radian)))

        if get_thetas:
            return ys, xs

        return ys
Exemplo n.º 20
0
def changeAndOpt(rdkit, theta):

    Chem.SanitizeMol(rdkit)
    initconf = rdkit.GetConformer()

    # set outer most dihedral to 180 degrees.
    smarts_patt = "C-S-C-[C,Si,Ge;H0]"
    outer_dihedral_idx = find_dihedral_idx(rdkit, smarts_patt)

    for k, i, j, l in outer_dihedral_idx:
        rdMolTransforms.SetDihedralDeg(initconf, k, i, j, l, 180.0)

    # change second outmost dihedral with +-120 degrees.
    patt = "S-C-[C,Si,Ge;H0]-[C,Si,Ge]"
    dihedral_idx = find_dihedral_idx(rdkit, patt)

    new_angles = list()
    for k, i, j, l in dihedral_idx:
        init_dihedral_angle = rdMolTransforms.GetDihedralDeg(
            initconf, k, i, j, l)
        new_angles.append([
            init_dihedral_angle + x * theta for x in range(int(360. / theta))
        ])

    angle_combinations = list(
        itertools.product(*new_angles))  # all combinations.

    for dihedrals in angle_combinations:

        for (k, i, j, l), angle in zip(dihedral_idx, dihedrals):
            rdMolTransforms.SetDihedralDeg(initconf, k, i, j, l, angle)

        rdkit.AddConformer(initconf, assignId=True)

    rdMolAlign.AlignMolConformers(rdkit)

    mol_list = list()
    for idx, conf in enumerate(rdkit.GetConformers()):

        if idx == 0:
            continue

        sdf_txt = Chem.SDWriter.GetText(rdkit, conf.GetId())
        m = Chem.MolFromMolBlock(sdf_txt, removeHs=False)

        conf_name = m.GetProp("_Name") + "-" + str(idx - 1)
        m.SetProp("_Name", conf_name)

        mol_list.append(m)

    # Optimize structures with new dihedrals.
    confqmmol = QMMol(mol_list,
                      fmt="mol_list",
                      charge=0,
                      multi=1,
                      charged_fragments=True)
    confqmmol.optimize(program="xtb", method="opt", cpus=24, babelAC=True)

    # Write xyz files of conformers
    for newConf in confqmmol.GetConformers():

        obConversion = openbabel.OBConversion()
        obConversion.SetInAndOutFormats("sdf", "xyz")

        newConfm = openbabel.OBMol()
        obConversion.ReadString(newConfm, Chem.MolToMolBlock(newConf))

        new_xyz = obConversion.WriteString(newConfm)

        with open(newConf.GetProp("_Name") + ".xyz", 'w') as f:
            f.write(new_xyz)
Exemplo n.º 21
0
def main():

    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument('-s', '--smiles', action='store', help='', metavar="str")
    parser.add_argument('-f', '--filename', action='store', help='', metavar="filename", default="hash.sdf")
    parser.add_argument('-a', '--align', action='store_true', help='align molecules')
    parser.add_argument('--scan', action='store_true', help='scan angles')
    parser.add_argument('--scan_theta', action='store', type=float, help='', metavar="angle", default=170.0)
    parser.add_argument('--add_hydrogens', action='store_true', help='Add hydrogens', default=True)

    args = parser.parse_args()

    if not args.smiles:
        print("No smiles set")
        quit()

    m = Chem.MolFromSmiles(args.smiles)

    smart = "~".join(["[*]"]*4)
    idx_list = m.GetSubstructMatches(Chem.MolFromSmarts(smart))

    m = Chem.AddHs(m)

    # if args.add_hydrogens:
    #     m = Chem.AddHs(m)
    #     AllChem.EmbedMolecule(m, AllChem.ETKDG())

    AllChem.EmbedMultipleConfs(m, numConfs=1, useExpTorsionAnglePrefs=True, useBasicKnowledge=True)
    # AllChem.EmbedMultipleConfs(m, numConfs=1, useBasicKnowledge=True)

    atoms = m.GetAtoms()

    # for i, a in enumerate(atoms):
    #     print(i, a.GetAtomicNum())


    cm = m.GetConformer()

    if args.scan:
        for x in range(0, 1080, 10):
            rdMolTransforms.SetDihedralDeg(cm, 0, 1, 2, 3, x)
            m.AddConformer(cm, assignId=True)

    # if args.scan:
    #     set_conformers_random(m, 1)
    #     set_dehedral_angles(m, theta=args.scan_theta)

    else:
        n_conformers = 70
        # n_conformers = rdMolDescriptors.CalcNumRotatableBonds(m)
        m = get_conformers(args.smiles, n_conformers)

    # Alignment
    if args.align:
        if True:
            Chem.rdMolAlign.AlignMolConformers(m)

        # if True:
        #     for i, m in enumerate(m.GetConformations()):
        #         if i == 0: continue
        #
        #         # m.AddConformer(parent, assignId=True)


    writer = Chem.SDWriter(args.filename)
    for i in range(m.GetNumConformers()):
        writer.write(m, i)

    return
Exemplo n.º 22
0
def set_dehedral_angles(m, theta=120.0, rotate_general=True, rotate_ol=True, rotate_ine=True):
    """
    Systematic rotation of dihedral angles theta degrees

    Taken from Mads

    """

    rotate_idx_list = list()

    if rotate_general:
        smart = "[!#1]~[!$(*#*)&!D1]-!@[!$(*#*)&!D1]~[!#1]"
        rotate_idx_list += m.GetSubstructMatches(Chem.MolFromSmarts(smart))

    if rotate_ol:
        smart = "[*]~[*]-[O,S]-[#1]"
        rotate_idx_list += m.GetSubstructMatches(Chem.MolFromSmarts(smart))

    if rotate_ine:
        smart = "[*]~[*]-[NX3;H2]-[#1]"
        rotate_idx_list += m.GetSubstructMatches(Chem.MolFromSmarts(smart))


    # Find unique bonds and dihedral angles indexes

    idx_bonds = list()
    idx_dihedral = list()

    atoms = m.GetAtoms()

    for k, i, j, l in rotate_idx_list:

        if (i,j) in idx_bonds: continue
        idx_bonds.append((i,j))
        idx_dihedral.append((k,i,j,l))

        print("found", k,i,j,l)
        print(atoms[k].GetAtomicNum())
        print(atoms[i].GetAtomicNum())
        print(atoms[j].GetAtomicNum())
        print(atoms[l].GetAtomicNum())




    # find dihedrals of parent molecule and create all combinations
    # where the angles are rotated theta degrees.
    parent = m.GetConformer()

    # List of alle moveable angles
    dihedrals = list()

    for k, i, j, l in idx_dihedral:
        parent_dihedral = rdMolTransforms.GetDihedralDeg(parent, k, i, j, l)

        new_dihedrals = [ x*theta for x in range(int(360./theta))]

        print(new_dihedrals)

        dihedrals.append(new_dihedrals)



    # make all possible combinations of dihedral angles
    dihedral_combinations = list(itertools.product(*dihedrals))

    # Create the conformations according to angle combinations
    for dihedrals in dihedral_combinations:

        for (k,i,j,l), angle in zip(idx_dihedral, dihedrals):

            print(k,i,j,l, angle)

            rdMolTransforms.SetDihedralDeg(parent, k, i, j, l, angle)

        # translate mol to centroid
        rdMolTransforms.CanonicalizeConformer(parent)
        m.AddConformer(parent, assignId=True)

    return m
Exemplo n.º 23
0
def summ_search(mol,
                name,
                args,
                log,
                dup_data,
                dup_data_idx,
                coord_Map=None,
                alg_Map=None,
                mol_template=None):
    '''embeds core conformers, then optimizes and filters based on RMSD. Finally the rotatable torsions are systematically rotated'''

    sdwriter = Chem.SDWriter(name + '_' + 'rdkit' + args.output)

    Chem.SanitizeMol(mol)
    mol = Chem.AddHs(mol)
    mol.SetProp("_Name", name)

    # detects and applies auto-detection of initial number of conformers
    if args.sample == 'auto':
        initial_confs = int(auto_sampling(args.auto_sample, mol, log))

    else:
        initial_confs = int(args.sample)

    #
    dup_data.at[dup_data_idx, 'Molecule'] = name
    dup_data.at[dup_data_idx, 'RDKIT-Initial-samples'] = initial_confs

    if args.nodihedrals == False:
        rotmatches = getDihedralMatches(mol, args.heavyonly, log)
    else:
        rotmatches = []

    if len(rotmatches) > args.max_torsions:
        log.write("x  Too many torsions (%d). Skipping %s" %
                  (len(rotmatches), (name + args.output)))
        status = -1
    else:
        if coord_Map == None and alg_Map == None and mol_template == None:
            if args.etkdg:
                ps = Chem.ETKDG()
                ps.randomSeed = args.seed
                ps.ignoreSmoothingFailures = True
                ps.numThreads = 0
                cids = rdDistGeom.EmbedMultipleConfs(mol,
                                                     initial_confs,
                                                     params=ps)
            else:
                cids = rdDistGeom.EmbedMultipleConfs(
                    mol,
                    initial_confs,
                    ignoreSmoothingFailures=True,
                    randomSeed=args.seed,
                    numThreads=0)
            if len(cids) == 0 or len(cids) == 1 and initial_confs != 1:
                log.write(
                    "o  conformers initially sampled with random coordinates")
                cids = rdDistGeom.EmbedMultipleConfs(
                    mol,
                    initial_confs,
                    randomSeed=args.seed,
                    useRandomCoords=True,
                    boxSizeMult=10.0,
                    ignoreSmoothingFailures=True,
                    numZeroFail=1000,
                    numThreads=0)
            if args.verbose:
                log.write("o  " + str(len(cids)) +
                          " conformers initially sampled")
        # case of embed for templates
        else:
            if args.etkdg:
                ps = Chem.ETKDG()
                ps.randomSeed = args.seed
                ps.coordMap = coord_Map
                ps.ignoreSmoothingFailures = True
                ps.numThreads = 0
                cids = rdDistGeom.EmbedMultipleConfs(mol,
                                                     initial_confs,
                                                     params=ps)
            else:
                cids = rdDistGeom.EmbedMultipleConfs(
                    mol,
                    initial_confs,
                    randomSeed=args.seed,
                    ignoreSmoothingFailures=True,
                    coordMap=coord_Map,
                    numThreads=0)
            if len(cids) == 0 or len(cids) == 1 and initial_confs != 1:
                log.write(
                    "o  conformers initially sampled with random coordinates")
                cids = rdDistGeom.EmbedMultipleConfs(
                    mol,
                    initial_confs,
                    randomSeed=args.seed,
                    useRandomCoords=True,
                    boxSizeMult=10.0,
                    numZeroFail=1000,
                    ignoreSmoothingFailures=True,
                    coordMap=coord_Map,
                    numThreads=0)
            if args.verbose:
                log.write("o  " + str(len(cids)) +
                          " conformers initially sampled")

        #energy minimize all to get more realistic results
        #identify the atoms and decide Force Field

        for atom in mol.GetAtoms():
            if atom.GetAtomicNum() > 36:  #upto Kr for MMFF, if not use UFF
                args.ff = "UFF"
                #log.write("UFF is used because there are atoms that MMFF doesn't recognise")
        if args.verbose:
            log.write("o  Optimizing " + str(len(cids)) +
                      " initial conformers with" + args.ff)
        if args.verbose:
            if args.nodihedrals == False:
                log.write("o  Found " + str(len(rotmatches)) +
                          " rotatable torsions")
                # for [a,b,c,d] in rotmatches:
                # 	log.write('  '+mol.GetAtomWithIdx(a).GetSymbol()+str(a+1)+ mol.GetAtomWithIdx(b).GetSymbol()+str(b+1)+ mol.GetAtomWithIdx(c).GetSymbol()+str(c+1)+mol.GetAtomWithIdx(d).GetSymbol()+str(d+1))
            else:
                log.write("o  Systematic torsion rotation is set to OFF")

        cenergy, outmols = [], []
        bar = IncrementalBar('o  Minimizing', max=len(cids))
        for i, conf in enumerate(cids):
            if coord_Map == None and alg_Map == None and mol_template == None:
                if args.ff == "MMFF":
                    GetFF = Chem.MMFFGetMoleculeForceField(
                        mol, Chem.MMFFGetMoleculeProperties(mol), confId=conf)
                elif args.ff == "UFF":
                    GetFF = Chem.UFFGetMoleculeForceField(mol, confId=conf)
                else:
                    log.write('   Force field {} not supported!'.format(
                        args.ff))
                    sys.exit()

                GetFF.Initialize()
                converged = GetFF.Minimize(maxIts=args.opt_steps_RDKit)
                energy = GetFF.CalcEnergy()
                cenergy.append(GetFF.CalcEnergy())

                #if args.verbose:
                #    log.write("-   conformer", (i+1), "optimized: ", args.ff, "energy", GetFF.CalcEnergy())
            #id template realign before doing calculations
            else:
                num_atom_match = mol.GetSubstructMatch(mol_template)
                # Force field parameters
                if args.ff == "MMFF":
                    GetFF = lambda mol, confId=conf: Chem.MMFFGetMoleculeForceField(
                        mol, Chem.MMFFGetMoleculeProperties(mol), confId=conf)
                elif args.ff == "UFF":
                    GetFF = lambda mol, confId=conf: Chem.UFFGetMoleculeForceField(
                        mol, confId=conf)
                else:
                    log.write('   Force field {} not supported!'.format(
                        options.ff))
                    sys.exit()
                getForceField = GetFF

                # clean up the conformation
                ff_temp = getForceField(mol, confId=conf)
                for k, idxI in enumerate(num_atom_match):
                    for l in range(k + 1, len(num_atom_match)):
                        idxJ = num_atom_match[l]
                        d = coord_Map[idxI].Distance(coord_Map[idxJ])
                        ff_temp.AddDistanceConstraint(idxI, idxJ, d, d, 10000)
                ff_temp.Initialize()
                #reassignned n from 4 to 10 for better embed and minimzation
                n = 10
                more = ff_temp.Minimize()
                while more and n:
                    more = ff_temp.Minimize()
                    n -= 1
                energy = ff_temp.CalcEnergy()
                # rotate the embedded conformation onto the core_mol:
                rms = rdMolAlign.AlignMol(mol,
                                          mol_template,
                                          prbCid=conf,
                                          atomMap=alg_Map,
                                          reflect=True,
                                          maxIters=100)
                # elif len(num_atom_match) == 5:
                #     ff_temp = GetFF(mol, confId=conf)
                #     conf_temp = mol_template.GetConformer()
                #     for k in range(mol_template.GetNumAtoms()):
                #         p = conf_temp.GetAtomPosition(k)
                #         q = mol.GetConformer(conf).GetAtomPosition(k)
                #         pIdx = ff_temp.AddExtraPoint(p.x, p.y, p.z, fixed=True) - 1
                #         ff_temp.AddDistanceConstraint(pIdx, num_atom_match[k], 0, 0, 10000)
                #     ff_temp.Initialize()
                #     n = 10
                #     more = ff_temp.Minimize(energyTol=1e-6, forceTol=1e-5)
                #     while more and n:
                #         more = ff_temp.Minimize(energyTol=1e-6, forceTol=1e-5)
                #         n -= 1
                #     # realign
                #     energy = ff_temp.CalcEnergy()
                #     rms = rdMolAlign.AlignMol(mol, mol_template,prbCid=conf, atomMap=alg_Map,reflect=True,maxIters=50)
                cenergy.append(energy)

            # outmols is gonna be a list containing "initial_confs" mol objects with "initial_confs"
            # conformers. We do this to SetProp (Name and Energy) to the different conformers
            # and log.write in the SDF file. At the end, since all the mol objects has the same
            # conformers, but the energies are different, we can log.write conformers to SDF files
            # with the energies of the parent mol objects. We measured the computing time and
            # it's the same as using only 1 parent mol object with 10 conformers, but we couldn'temp
            # SetProp correctly
            pmol = PropertyMol.PropertyMol(mol)
            outmols.append(pmol)
            bar.next()
        bar.finish()

        for i, cid in enumerate(cids):
            outmols[cid].SetProp('_Name', name + ' conformer ' + str(i + 1))
            outmols[cid].SetProp('Energy', cenergy[cid])

        cids = list(range(len(outmols)))
        sortedcids = sorted(cids, key=lambda cid: cenergy[cid])

        log.write("\n\no  Filters after intial embedding of " +
                  str(initial_confs) + " conformers")
        selectedcids, selectedcids_initial, eng_dup, eng_rms_dup = [], [], -1, -1
        bar = IncrementalBar('o  Filtering based on energy (pre-filter)',
                             max=len(sortedcids))
        for i, conf in enumerate(sortedcids):
            # This keeps track of whether or not your conformer is unique
            excluded_conf = False
            # include the first conformer in the list to start the filtering process
            if i == 0:
                selectedcids_initial.append(conf)
            # check rmsd
            for seenconf in selectedcids_initial:
                E_diff = abs(cenergy[conf] - cenergy[seenconf])  # in kcal/mol
                if E_diff < args.initial_energy_threshold:
                    eng_dup += 1
                    excluded_conf = True
                    break
            if excluded_conf == False:
                if conf not in selectedcids_initial:
                    selectedcids_initial.append(conf)
            bar.next()
        bar.finish()

        if args.verbose == True:
            log.write("o  " + str(eng_dup) +
                      " Duplicates removed  pre-energy filter (E < " +
                      str(args.initial_energy_threshold) + " kcal/mol )")

        #reduce to unique set
        if args.verbose:
            log.write("o  Removing duplicate conformers ( RMSD < " +
                      str(args.rms_threshold) + " and E difference < " +
                      str(args.energy_threshold) + " kcal/mol)")

        bar = IncrementalBar('o  Filtering based on energy and rms',
                             max=len(selectedcids_initial))
        #check rmsd
        for i, conf in enumerate(selectedcids_initial):

            #set torsions to same value
            for m in rotmatches:
                rdMolTransforms.SetDihedralDeg(
                    outmols[conf].GetConformer(conf), *m, 180.0)

            # This keeps track of whether or not your conformer is unique
            excluded_conf = False
            # include the first conformer in the list to start the filtering process
            if i == 0:
                selectedcids.append(conf)
            # check rmsd
            for seenconf in selectedcids:
                E_diff = abs(cenergy[conf] - cenergy[seenconf])  # in kcal/mol
                if E_diff < args.energy_threshold:
                    rms = get_conf_RMS(outmols[conf], outmols[conf], seenconf,
                                       conf, args.heavyonly,
                                       args.max_matches_RMSD, log)
                    if rms < args.rms_threshold:
                        excluded_conf = True
                        eng_rms_dup += 1
                        break
            if excluded_conf == False:
                if conf not in selectedcids:
                    selectedcids.append(conf)
            bar.next()
        bar.finish()

        # unique_mols, unique_energies = [],[]
        # for id in selectedcids:
        #     unique_mols.append(outmols[id])
        #     unique_energies.append(cenergy[id])

        # log.write(unique_mols[0:2].GetConformers()[0].GetPositions())

        if args.verbose == True:
            log.write("o  " + str(eng_rms_dup) +
                      " Duplicates removed (RMSD < " +
                      str(args.rms_threshold) + " / E < " +
                      str(args.energy_threshold) + " kcal/mol) after rotation")
        if args.verbose:
            log.write("o  " + str(len(selectedcids)) +
                      " unique (ignoring torsions) starting conformers remain")

        dup_data.at[dup_data_idx, 'RDKit-energy-duplicates'] = eng_dup
        dup_data.at[dup_data_idx,
                    'RDKit-RMS-and-energy-duplicates'] = eng_rms_dup
        dup_data.at[dup_data_idx,
                    'RDKIT-Unique-conformers'] = len(selectedcids)

        # now exhaustively drive torsions of selected conformers
        n_confs = int(len(selectedcids) * (360 / args.degree)**len(rotmatches))
        if args.verbose and len(rotmatches) != 0:
            log.write("\n\no  Systematic generation of " + str(n_confs) +
                      " confomers")
            bar = IncrementalBar(
                'o  Generating conformations based on dihedral rotation',
                max=len(selectedcids))
        else:
            bar = IncrementalBar('o  Generating conformations',
                                 max=len(selectedcids))

        total = 0
        for conf in selectedcids:
            #log.write(outmols[conf])
            total += genConformer_r(outmols[conf], conf, 0, rotmatches,
                                    args.degree, sdwriter, args,
                                    outmols[conf].GetProp('_Name'), log)
            bar.next()
        bar.finish()
        if args.verbose and len(rotmatches) != 0:
            log.write("o  %d total conformations generated" % total)
        status = 1
    sdwriter.close()

    #getting the energy from and mols after rotations
    if len(rotmatches) != 0:
        rdmols = Chem.SDMolSupplier(name + '_' + 'rdkit' + args.output,
                                    removeHs=False)
        if rdmols is None:
            log.write("Could not open " + name + args.output)
            sys.exit(-1)

        bar = IncrementalBar(
            'o  Filtering based on energy and rms after rotation of dihedrals',
            max=len(rdmols))
        sdwriter = Chem.SDWriter(name + '_' + 'rdkit' + '_' + 'rotated' +
                                 args.output)

        rd_count = 0
        rd_selectedcids, rd_dup_energy, rd_dup_rms_eng = [], -1, 0
        for i in range(len(rdmols)):
            # This keeps track of whether or not your conformer is unique
            excluded_conf = False
            # include the first conformer in the list to start the filtering process
            if rd_count == 0:
                rd_selectedcids.append(i)
                if args.metal_complex == True:
                    for atom in rdmols[i].GetAtoms():
                        if atom.GetSymbol() == 'I' and (
                                len(atom.GetBonds()) == 6
                                or len(atom.GetBonds()) == 5
                                or len(atom.GetBonds()) == 4
                                or len(atom.GetBonds()) == 3
                                or len(atom.GetBonds()) == 2):
                            for el in elementspt:
                                if el.symbol == args.metal:
                                    atomic_number = el.number
                            atom.SetAtomicNum(atomic_number)
                sdwriter.write(rdmols[i])
            # Only the first ID gets included
            rd_count = 1
            # check rmsd
            for j in rd_selectedcids:
                if abs(
                        float(rdmols[i].GetProp('Energy')) -
                        float(rdmols[j].GetProp('Energy'))
                ) < args.initial_energy_threshold:  # comparison in kcal/mol
                    excluded_conf = True
                    rd_dup_energy += 1
                    break
                if abs(
                        float(rdmols[i].GetProp('Energy')) -
                        float(rdmols[j].GetProp('Energy'))
                ) < args.energy_threshold:  # in kcal/mol
                    rms = get_conf_RMS(rdmols[i], rdmols[j], -1, -1,
                                       args.heavyonly, args.max_matches_RMSD,
                                       log)
                    if rms < args.rms_threshold:
                        excluded_conf = True
                        rd_dup_rms_eng += 1
                        break
            if excluded_conf == False:
                if args.metal_complex == True:
                    for atom in rdmols[i].GetAtoms():
                        if atom.GetSymbol() == 'I' and (
                                len(atom.GetBonds()) == 6
                                or len(atom.GetBonds()) == 5
                                or len(atom.GetBonds()) == 4
                                or len(atom.GetBonds()) == 3
                                or len(atom.GetBonds()) == 2):
                            for el in elementspt:
                                if el.symbol == args.metal:
                                    atomic_number = el.number
                            atom.SetAtomicNum(atomic_number)
                sdwriter.write(rdmols[i])
                if i not in rd_selectedcids:
                    rd_selectedcids.append(i)
            bar.next()
        bar.finish()
        sdwriter.close()

        if args.verbose == True:
            log.write("o  " + str(rd_dup_energy) +
                      " Duplicates removed initial energy ( E < " +
                      str(args.initial_energy_threshold) + " kcal/mol )")
        if args.verbose == True:
            log.write("o  " + str(rd_dup_rms_eng) +
                      " Duplicates removed (RMSD < " +
                      str(args.rms_threshold) + " / E < " +
                      str(args.energy_threshold) + " kcal/mol) after rotation")
        if args.verbose == True:
            log.write("o  " + str(len(rd_selectedcids)) +
                      " unique (after torsions) conformers remain")

        #filtering process after rotations
        dup_data.at[dup_data_idx, 'RDKIT-Rotated-conformers'] = total
        dup_data.at[dup_data_idx,
                    'RDKIT-Rotated-Unique-conformers'] = len(rd_selectedcids)

    return status