diff --git a/Code/GraphMol/Atom.cpp b/Code/GraphMol/Atom.cpp index 860a1d264..49205af8c 100644 --- a/Code/GraphMol/Atom.cpp +++ b/Code/GraphMol/Atom.cpp @@ -742,6 +742,11 @@ bool Atom::needsUpdatePropertyCache() const { (this->df_noImplicit || this->d_implicitValence >= 0)); } +void Atom::clearPropertyCache() { + d_explicitValence = -1; + d_implicitValence = -1; +} + // returns the number of swaps required to convert the ordering // of the probe list to match the order of our incoming bonds: // diff --git a/Code/GraphMol/Atom.h b/Code/GraphMol/Atom.h index 2ef85b796..e853b9ed6 100644 --- a/Code/GraphMol/Atom.h +++ b/Code/GraphMol/Atom.h @@ -345,6 +345,7 @@ class RDKIT_GRAPHMOL_EXPORT Atom : public RDProps { void updatePropertyCache(bool strict = true); bool needsUpdatePropertyCache() const; + void clearPropertyCache(); //! calculates and returns our explicit valence /*! diff --git a/Code/GraphMol/ROMol.cpp b/Code/GraphMol/ROMol.cpp index 82dc24a38..30752e7b8 100644 --- a/Code/GraphMol/ROMol.cpp +++ b/Code/GraphMol/ROMol.cpp @@ -604,6 +604,12 @@ bool ROMol::needsUpdatePropertyCache() const { return false; } +void ROMol::clearPropertyCache() { + for (auto atom : atoms()) { + atom->clearPropertyCache(); + } +} + const Conformer &ROMol::getConformer(int id) const { // make sure we have more than one conformation if (d_confs.size() == 0) { diff --git a/Code/GraphMol/ROMol.h b/Code/GraphMol/ROMol.h index 519c6b613..738e6dfc0 100644 --- a/Code/GraphMol/ROMol.h +++ b/Code/GraphMol/ROMol.h @@ -765,6 +765,7 @@ class RDKIT_GRAPHMOL_EXPORT ROMol : public RDProps { void updatePropertyCache(bool strict = true); bool needsUpdatePropertyCache() const; + void clearPropertyCache(); //! @} diff --git a/Code/GraphMol/Wrap/Atom.cpp b/Code/GraphMol/Wrap/Atom.cpp index 540a83e3e..32ffcb73e 100644 --- a/Code/GraphMol/Wrap/Atom.cpp +++ b/Code/GraphMol/Wrap/Atom.cpp @@ -458,6 +458,10 @@ struct atom_wrapper { "Returns true or false depending on whether implicit and explicit " "valence of the molecule have already been calculated.\n\n") + .def("ClearPropertyCache", &Atom::clearPropertyCache, + (python::arg("self")), + "Clears implicit and explicit valence information.\n\n") + .def("GetMonomerInfo", AtomGetMonomerInfo, python::return_internal_reference< 1, python::with_custodian_and_ward_postcall<0, 1>>(), diff --git a/Code/GraphMol/Wrap/Mol.cpp b/Code/GraphMol/Wrap/Mol.cpp index 58e99922c..e34109caa 100644 --- a/Code/GraphMol/Wrap/Mol.cpp +++ b/Code/GraphMol/Wrap/Mol.cpp @@ -767,6 +767,11 @@ struct mol_wrapper { "explicit " "valence of the molecule have already been calculated.\n\n") + .def( + "ClearPropertyCache", &ROMol::clearPropertyCache, + (python::arg("self")), + "Clears implicit and explicit valence information from all atoms.\n\n") + .def("GetStereoGroups", &ROMol::getStereoGroups, "Returns a list of StereoGroups defining the relative " "stereochemistry " diff --git a/Code/GraphMol/Wrap/rough_test.py b/Code/GraphMol/Wrap/rough_test.py index 6c8499937..046e947ce 100644 --- a/Code/GraphMol/Wrap/rough_test.py +++ b/Code/GraphMol/Wrap/rough_test.py @@ -1797,20 +1797,22 @@ M END child_bonds = bonds[1:] self.assertEqual(len(list(bond.GetStereoAtoms())), 2) bond.SetStereo(Chem.BondStereo.STEREOTRANS) - for isomer in self.recursive_enumerate_stereo_bonds(mol, done_bonds + [Chem.BondStereo.STEREOTRANS], + for isomer in self.recursive_enumerate_stereo_bonds(mol, + done_bonds + [Chem.BondStereo.STEREOTRANS], child_bonds): yield isomer self.assertEqual(len(list(bond.GetStereoAtoms())), 2) bond.SetStereo(Chem.BondStereo.STEREOCIS) - for isomer in self.recursive_enumerate_stereo_bonds(mol, done_bonds + [Chem.BondStereo.STEREOCIS], + for isomer in self.recursive_enumerate_stereo_bonds(mol, + done_bonds + [Chem.BondStereo.STEREOCIS], child_bonds): yield isomer def testBondSetStereoDifficultCase(self): origVal = Chem.GetUseLegacyStereoPerception() Chem.SetUseLegacyStereoPerception(False) - + unspec_smiles = "CCC=CC(CO)=C(C)CC" mol = Chem.MolFromSmiles(unspec_smiles) Chem.FindPotentialStereoBonds(mol) @@ -1839,7 +1841,6 @@ M END self.assertEqual(len(isomers), 4) Chem.SetUseLegacyStereoPerception(origVal) - def getNumUnspecifiedBondStereo(self, smi): mol = Chem.MolFromSmiles(smi) Chem.FindPotentialStereoBonds(mol) @@ -1847,7 +1848,7 @@ M END count = 0 for bond in mol.GetBonds(): if bond.GetStereo() != Chem.BondStereo.STEREONONE: - print(bond.GetIdx(),bond.GetStereo()) + print(bond.GetIdx(), bond.GetStereo()) if bond.GetStereo() == Chem.BondStereo.STEREOANY: count += 1 @@ -5370,15 +5371,15 @@ width='200px' height='200px' > self.assertEqual(atom0.GetChiralTag(), Chem.rdchem.ChiralType.CHI_TETRAHEDRAL_CCW) def testAssignStereochemistryFrom3D(self): - + def _stereoTester(mol, expectedTag, expectedStereo): Chem.AssignStereochemistryFrom3D(mol) - self.assertEqual(mol.GetNumAtoms(), 9) + self.assertEqual(mol.GetNumAtoms(), 9) self.assertEqual(mol.GetAtomWithIdx(1).GetChiralTag(), expectedTag) self.assertEqual(mol.GetBondWithIdx(3).GetStereo(), expectedStereo) origVal = Chem.GetUseLegacyStereoPerception() - for useLegacy in (True,False): + for useLegacy in (True, False): Chem.SetUseLegacyStereoPerception(useLegacy) fileN = os.path.join(RDConfig.RDBaseDir, 'Code', 'GraphMol', 'test_data', 'stereochem.sdf') @@ -8117,8 +8118,9 @@ M END 'ferrocene.mol') femol = Chem.MolFromMolFile(fefile) newfemol = Chem.rdmolops.HapticBondsToDative(femol) - self.assertEqual(Chem.MolToSmiles(newfemol), - '[cH]12->[Fe+2]3456789(<-[cH]1[cH]->3[cH-]->4[cH]->52)<-[cH]1[cH]->6[cH]->7[cH-]->8[cH]->91') + self.assertEqual( + Chem.MolToSmiles(newfemol), + '[cH]12->[Fe+2]3456789(<-[cH]1[cH]->3[cH-]->4[cH]->52)<-[cH]1[cH]->6[cH]->7[cH-]->8[cH]->91') def test_DativeBondsToHaptic(self): fefile = os.path.join(RDConfig.RDBaseDir, 'Code', 'GraphMol', 'MolStandardize', 'test_data', @@ -8382,7 +8384,17 @@ M END m.GetAtomWithIdx(1).SetChiralTag(Chem.CHI_UNSPECIFIED) Chem.CleanupStereoGroups(m) self.assertEqual(len(m.GetStereoGroups()), 0) - + + def testClearPropertyCache(self): + m = Chem.MolFromSmiles("CC") + self.assertFalse(m.NeedsUpdatePropertyCache()) + for atom in m.GetAtoms(): + self.assertFalse(atom.NeedsUpdatePropertyCache()) + m.ClearPropertyCache() + self.assertTrue(m.NeedsUpdatePropertyCache()) + for atom in m.GetAtoms(): + self.assertTrue(atom.NeedsUpdatePropertyCache()) + if __name__ == '__main__': if "RDTESTCASE" in os.environ: diff --git a/Code/GraphMol/catch_graphmol.cpp b/Code/GraphMol/catch_graphmol.cpp index 187c50a76..2456b3eb9 100644 --- a/Code/GraphMol/catch_graphmol.cpp +++ b/Code/GraphMol/catch_graphmol.cpp @@ -4823,3 +4823,17 @@ TEST_CASE("stereogroups operator<<") { CHECK(oss.str() == "AND rId: 0 wId: 0 bonds: { 7 }"); } } + +TEST_CASE("clearPropertyCache") { + auto m = "CC"_smiles; + REQUIRE(m); + CHECK(!m->needsUpdatePropertyCache()); + for (const auto atom : m->atoms()) { + CHECK(!atom->needsUpdatePropertyCache()); + } + m->clearPropertyCache(); + CHECK(m->needsUpdatePropertyCache()); + for (const auto atom : m->atoms()) { + CHECK(atom->needsUpdatePropertyCache()); + } +}