void testIssue3399798(std::string rdbase){ BOOST_LOG(rdInfoLog) << "---------------------------------------" << std::endl; BOOST_LOG(rdInfoLog) << "-- testing issue 3399798 --" << std::endl; BOOST_LOG(rdInfoLog) << "---------------------------------------" << std::endl; { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/Issue3399798.mol2"; RWMol *m = Mol2FileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(0)->getChiralTag()==Atom::CHI_UNSPECIFIED); TEST_ASSERT(m->getAtomWithIdx(3)->getChiralTag()==Atom::CHI_UNSPECIFIED); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/Issue3399798.2.mol2"; RWMol *m = Mol2FileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(0)->getChiralTag()==Atom::CHI_UNSPECIFIED); TEST_ASSERT(m->getAtomWithIdx(3)->getChiralTag()!=Atom::CHI_UNSPECIFIED); delete m; } BOOST_LOG(rdInfoLog) << "------------------------------------" << std::endl; BOOST_LOG(rdInfoLog) << "-- DONE --" << std::endl; BOOST_LOG(rdInfoLog) << "------------------------------------" << std::endl; }
void testGithub186(){ BOOST_LOG(rdInfoLog) << "testing github issue 186: chiral S not written to ctab" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { std::string fName = rdbase + "github186.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms()==11); TEST_ASSERT(m->getNumBonds()==10); TEST_ASSERT(m->getAtomWithIdx(6)->getChiralTag()!=Atom::CHI_UNSPECIFIED && m->getAtomWithIdx(6)->getChiralTag()!=Atom::CHI_OTHER ); std::string mb=MolToMolBlock(*m); delete m; m = MolBlockToMol(mb); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms()==11); TEST_ASSERT(m->getNumBonds()==10); TEST_ASSERT(m->getAtomWithIdx(6)->getChiralTag()!=Atom::CHI_UNSPECIFIED && m->getAtomWithIdx(6)->getChiralTag()!=Atom::CHI_OTHER ); delete m; } }
void testGithub438(std::string rdbase) { BOOST_LOG(rdInfoLog) << "-----------------------------------" << std::endl; BOOST_LOG(rdInfoLog) << "-- testing GitHub issue #438: problems with metals in mol2 files --" << std::endl; BOOST_LOG(rdInfoLog) << "-----------------------------------" << std::endl; { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/github438_1.mol2"; RWMol *mol = Mol2FileToMol(fName); TEST_ASSERT(mol); TEST_ASSERT(mol->getAtomWithIdx(0)->getFormalCharge() == 1); delete mol; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/github438_2.mol2"; RWMol *mol = Mol2FileToMol(fName); TEST_ASSERT(mol); TEST_ASSERT(mol->getAtomWithIdx(0)->getFormalCharge() == 2); delete mol; } BOOST_LOG(rdInfoLog) << "------------------------------------" << std::endl; BOOST_LOG(rdInfoLog) << "-- DONE --" << std::endl; BOOST_LOG(rdInfoLog) << "------------------------------------" << std::endl; }
void testGithub187(){ BOOST_LOG(rdInfoLog) << "testing github issue 187: A not written to mol block" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { std::string fName = rdbase + "github187.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms()==1); TEST_ASSERT(m->getNumBonds()==0); TEST_ASSERT(m->getAtomWithIdx(0)->hasQuery()); std::string mb=MolToMolBlock(*m); TEST_ASSERT(mb.find(" A 0")!=std::string::npos); // try the v3000 version: mb=MolToMolBlock(*m,true,-1,true,true); TEST_ASSERT(mb.find("V30 1 A 0")!=std::string::npos); delete m; } { std::string fName = rdbase + "github187.v3k.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms()==1); TEST_ASSERT(m->getNumBonds()==0); TEST_ASSERT(m->getAtomWithIdx(0)->hasQuery()); std::string mb=MolToMolBlock(*m); TEST_ASSERT(mb.find(" A 0")!=std::string::npos); // try the v3000 version: mb=MolToMolBlock(*m,true,-1,true,true); TEST_ASSERT(mb.find("V30 1 A 0")!=std::string::npos); delete m; } { std::string fName = rdbase + "github187.2.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms()==1); TEST_ASSERT(m->getNumBonds()==0); TEST_ASSERT(m->getAtomWithIdx(0)->hasQuery()); std::string mb=MolToMolBlock(*m); TEST_ASSERT(mb.find(" Q 0")!=std::string::npos); // try the v3000 version: mb=MolToMolBlock(*m,true,-1,true,true); TEST_ASSERT(mb.find("V30 1 \"NOT [C,H]\" 0")!=std::string::npos); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; }
void test4Coulomb () { std::string path = getenv("RDBASE"); path += "/Code/GraphMol/MIF/test_data/"; RWMol mol = *MolFileToMol(path + "HCl.mol", true, false); computeGasteigerCharges(mol); std::vector<double> charges; std::vector<Point3D> pos; Conformer conf = mol.getConformer(0); for (int i = 0; i < mol.getNumAtoms(); ++i) { charges.push_back(mol.getAtomWithIdx (i)->getProp<double> ("_GasteigerCharge")); pos.push_back(conf.getAtomPos(i)); } UniformRealValueGrid3D grd = *constructGrid(mol); UniformRealValueGrid3D grd2 = *constructGrid(mol); Coulomb coul(mol); calculateDescriptors<Coulomb>(grd, coul); calculateDescriptors<Coulomb>(grd2, Coulomb (charges, pos)); CHECK_INVARIANT(grd.compareGrids(grd2), "Coulomb: Different constructors do not yield the same descriptor."); CHECK_INVARIANT(feq (coul(0.0,0.0,0.0, 1000), 0.0), "Coulomb: Potential between atoms wrong.(should be 0)"); CHECK_INVARIANT(coul(2.0,0.0,0.0, 1000) < 0, "Coulomb: Potential between positive charges not positive."); CHECK_INVARIANT(coul(-2.0,0.0,0.0, 1000) > 0, "Coulomb: Potential between positive and negative charges not negative."); CHECK_INVARIANT(feq(coul(0.0,0.0,0.0, 0.1), 0.0), "Coulomb: Small threshold dist does not give 0."); calculateDescriptors<Coulomb>(grd, Coulomb(mol, 0, 1.0, true)); for (unsigned int i = 0; i < grd.getSize(); i++) { CHECK_INVARIANT(grd.getVal (i) <= 0.0, "Coulomb: Absolute value field not negative"); } Coulomb coul1(mol, 0, -1.0, false, "_GasteigerCharge", 0.0, 0.01); CHECK_INVARIANT(coul1(-2.0, 0.0, 0.0, 1000) < 0, "Coulomb: Potential between negative charges not positive."); CHECK_INVARIANT(coul1(2.0, 0.0, 0.0, 1000) > 0, "Coulomb: Potential between positive and negative charges not negative."); Coulomb coul2 = Coulomb(mol, 0, -.5, false, "_GasteigerCharge", 0.0, 0.01); CHECK_INVARIANT(coul1(-2.0, 0.0, 0.0, 1000) < coul2 (-2.0, 0.0, 0.0, 1000), "Coulomb: Higher probecharge does not result in stronger forces."); Coulomb coul3(mol, 0, 1.0, false, "_GasteigerCharge", 0.01, 1.0); CHECK_INVARIANT(coul3(0.0, 0.0, 0.0, 1000) > coul3(0.1, 0.0, 0.0, 1000), "Coulomb: Softcore interaction wrong."); CHECK_INVARIANT(coul3(0.66, 0.0, 0.0, 1000) > coul3(0.68, 0.0, 0.0, 1000), "Coulomb: Softcore interaction wrong."); CHECK_INVARIANT(coul3(0.70, 0.0, 0.0, 1000) > coul3(0.68, 0.0, 0.0, 1000), "Coulomb: Softcore interaction wrong."); CHECK_INVARIANT(feq(coul3(0.0,0.0,0.0, 0.1), 0.0), "Coulomb: Small threshold dist does not give 0."); }
void test504() { BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdInfoLog) << "Testing FMCS test504" << std::endl; std::cout << "\ntest504()\n"; std::vector<ROMOL_SPTR> mols; const char* smi[] = { // TEST 504 "C(CCNC(C1CC1[c:1]1[c:2]c(Cl)c(Cl)c[c:3]1)=O)CCN1CCC(NC(Nc2ccc(Cl)cc2)=O)" "C1 CHEMBL545864", // - QUERY "FC(F)(F)c1cc(NC(N2CCCN(CCCCCNC(C3CC3c3ccc(Cl)c(Cl)c3)=O)CC2)=O)ccc1Cl " "CHEMBL528228", "FC(F)(F)c1cc(NC(NC2CCN(CCCCCNC(C3CC3c3ccc(Cl)c(Cl)c3)=O)C2)=O)ccc1Cl " "CHEMBL525875", "Fc1ccc(NC(N2CCCN(CCCCCNC(C3CC3c3ccc(Cl)c(Cl)c3)=O)CC2)=O)cc1C(F)(F)F " "CHEMBL527277", "FC(F)(F)c1cc(NC(NC2CCN(CCCCCNC(C3CC3c3ccc(Cl)c(Cl)c3)=O)CC2)=O)ccc1Cl " "CHEMBL537333", "Fc1ccc(NC(NC2CCN(CCCCCNC(C3CC3c3ccc(Cl)c(Cl)c3)=O)C2)=O)cc1C(F)(F)F " "CHEMBL588077", "FC(F)(F)c1ccc(NC(NC2CCN(CCCCCNC(C3CC3c3cc(Cl)c(Cl)cc3)=O)C2)=O)cc1 " "CHEMBL525307", "Fc1ccc(NC(NC2CCN(CCCCCNC(C3CC3c3ccc(Cl)c(Cl)c3)=O)CC2)=O)cc1C(F)(F)F " "CHEMBL581847", "FC(F)(F)c1ccc(NC(NC2CCN(CCCCCNC(C3CC3c3cc(Cl)c(Cl)cc3)=O)CC2)=O)cc1 " "CHEMBL579547", "N#Cc1cccc(NC(NC2CCN(CCCCCNC(C3CC3c3ccc(Cl)c(Cl)c3)=O)CC2)=O)c1 " "CHEMBL529994", }; RWMol* qm = SmilesToMol(getSmilesOnly(smi[0])); unsigned nq = qm->getNumAtoms(); for (size_t ai = 0; ai < nq; ai++) { Atom* atom = qm->getAtomWithIdx(ai); atom->setProp("molAtomMapNumber", (int)ai); } std::cout << "Query +MAP " << MolToSmiles(*qm) << "\n"; mols.push_back(ROMOL_SPTR(qm)); // with RING INFO for (size_t i = 1; i < sizeof(smi) / sizeof(smi[0]); i++) mols.push_back( ROMOL_SPTR(SmilesToMol(getSmilesOnly(smi[i])))); // with RING INFO t0 = nanoClock(); MCSResult res = findMCS(mols); std::cout << "MCS: " << res.SmartsString << " " << res.NumAtoms << " atoms, " << res.NumBonds << " bonds\n"; printTime(); TEST_ASSERT(res.NumAtoms == 34 && res.NumBonds == 36); BOOST_LOG(rdInfoLog) << "\tdone" << std::endl; }
void test3CubeFiles () { std::string path = getenv ("RDBASE"); path += "/Code/GraphMol/MIF/test_data/"; RWMol mol = *MolFileToMol(path + "HCl.mol", true, false); RealValueVect *data = new RealValueVect (0.0, 125); UniformRealValueGrid3D grd (5.0, 5.0, 5.0, 1.0, new Point3D (0.0, 0.0, 0.0), data); for (unsigned int i = 0; i < grd.getSize (); i++) { grd.setVal (i, double (i / 10.0)); } writeToCubeFile (grd, mol, path + "test3.cube"); UniformRealValueGrid3D grd2; RWMol mol2 = *readFromCubeFile (grd2, path + "test3.cube"); CHECK_INVARIANT(grd.getSize() == grd2.getSize(), "I/O: grid sizes are not the same."); for (unsigned int i = 0; i < grd2.getSize (); i++) { CHECK_INVARIANT(feq(grd2.getVal(i), double(i / 10.0)), "I/O: values in grid are not correct."); } CHECK_INVARIANT(grd.getNumX() == grd2.getNumX(), "I/O: grids are not the same."); CHECK_INVARIANT(grd.getNumY() == grd2.getNumY(), "I/O: grids are not the same."); CHECK_INVARIANT(grd.getNumZ() == grd2.getNumZ(), "I/O: grids are not the same."); CHECK_INVARIANT(feq(grd.getOffset().x, grd2.getOffset().x), "I/O: grids are not the same."); CHECK_INVARIANT(feq(grd.getSpacing(), grd2.getSpacing()), "I/O: grids are not the same."); CHECK_INVARIANT(grd.compareVectors(grd2), "I/O: grids are not the same."); CHECK_INVARIANT(grd.compareParams(grd2), "I/O: grids are not the same."); CHECK_INVARIANT(grd.compareGrids(grd2), "I/O: grids are not the same."); CHECK_INVARIANT(mol.getNumAtoms() == mol2.getNumAtoms(), "I/O: number of atoms are not the same."); for (unsigned int i = 0; i < mol.getNumAtoms (); i++) { CHECK_INVARIANT(mol.getAtomWithIdx (i)->getAtomicNum () == mol2.getAtomWithIdx (i)->getAtomicNum (), "I/O: atoms are not the same"); CHECK_INVARIANT(feq (mol.getConformer ().getAtomPos (i).x, mol2.getConformer ().getAtomPos (i).x), "I/O: atom positions are not the same"); CHECK_INVARIANT(feq (mol.getConformer ().getAtomPos (i).y, mol2.getConformer ().getAtomPos (i).y), "I/O: atom positions are not the same"); CHECK_INVARIANT(feq (mol.getConformer ().getAtomPos (i).z, mol2.getConformer ().getAtomPos (i).z), "I/O: atom positions are not the same"); } }
void testQualifiedQueries() { BOOST_LOG(rdErrorLog) << "---------------------- Test queries using qualifiers instead of ==" << std::endl; RWMol *m = SmilesToMol("CNO"); { QueryAtom qA; qA.setQuery(makeAtomNumQuery<ATOM_GREATER_QUERY>(7, "test")); TEST_ASSERT(qA.Match(m->getAtomWithIdx(0))); TEST_ASSERT(!qA.Match(m->getAtomWithIdx(1))); TEST_ASSERT(!qA.Match(m->getAtomWithIdx(2))); } { QueryAtom qA; qA.setQuery(makeAtomNumQuery<ATOM_GREATEREQUAL_QUERY>(7, "test")); TEST_ASSERT(qA.Match(m->getAtomWithIdx(0))); TEST_ASSERT(qA.Match(m->getAtomWithIdx(1))); TEST_ASSERT(!qA.Match(m->getAtomWithIdx(2))); } { QueryAtom qA; qA.setQuery(makeAtomNumQuery<ATOM_LESS_QUERY>(7, "test")); TEST_ASSERT(!qA.Match(m->getAtomWithIdx(0))); TEST_ASSERT(!qA.Match(m->getAtomWithIdx(1))); TEST_ASSERT(qA.Match(m->getAtomWithIdx(2))); } { QueryAtom qA; qA.setQuery(makeAtomNumQuery<ATOM_LESSEQUAL_QUERY>(7, "test")); TEST_ASSERT(!qA.Match(m->getAtomWithIdx(0))); TEST_ASSERT(qA.Match(m->getAtomWithIdx(1))); TEST_ASSERT(qA.Match(m->getAtomWithIdx(2))); } delete m; BOOST_LOG(rdErrorLog) << "Done!" << std::endl; }
void test18() { BOOST_LOG(rdInfoLog) << "-------------------------------------" << std::endl; BOOST_LOG(rdInfoLog) << "Testing FMCS test18" << std::endl; std::cout << "\ntest18()\n"; std::vector<ROMOL_SPTR> mols; const char* smi[] = { // TEST 18 "Cc1nc(CN(C(C)c2ncccc2)CCCCN)ccc1 CHEMBL1682991", //-- QUERY "Cc1ccc(CN(C(C)c2ccccn2)CCCCN)nc1 CHEMBL1682990", "Cc1cccnc1CN(C(C)c1ccccn1)CCCCN CHEMBL1682998", "CC(N(CCCCN)Cc1c(N)cccn1)c1ccccn1 CHEMBL1682987", "Cc1cc(C)c(CN(C(C)c2ccccn2)CCCCN)nc1 CHEMBL1682992", "Cc1cc(C(C)N(CCCCN)Cc2c(C)cccn2)ncc1 CHEMBL1682993", "Cc1nc(C(C)N(CCCCN)Cc2nc3c([nH]2)cccc3)ccc1 CHEMBL1682878", "CC(c1ncccc1)N(CCCCN)Cc1nc2c([nH]1)cccc2 CHEMBL1682867", "CC(N(CCCCN)Cc1c(C(C)(C)C)cccn1)c1ccccn1 CHEMBL1682989", "CC(N(CCCCN)Cc1c(C(F)(F)F)cccn1)c1ccccn1 CHEMBL1682988", //# 18 . 20 20 0.04 sec. Python MCS: CC(c1ccccn1)N(CCCCN)Ccnccc }; RWMol* qm = SmilesToMol(getSmilesOnly(smi[0])); unsigned nq = qm->getNumAtoms(); for (size_t ai = 0; ai < nq; ai++) { Atom* atom = qm->getAtomWithIdx(ai); atom->setProp("molAtomMapNumber", (int)ai); } std::cout << "Query +MAP " << MolToSmiles(*qm) << "\n"; mols.push_back(ROMOL_SPTR(qm)); // with RING INFO for (size_t i = 1; i < sizeof(smi) / sizeof(smi[0]); i++) mols.push_back( ROMOL_SPTR(SmilesToMol(getSmilesOnly(smi[i])))); // with RING INFO t0 = nanoClock(); MCSResult res = findMCS(mols); std::cout << "MCS: " << res.SmartsString << " " << res.NumAtoms << " atoms, " << res.NumBonds << " bonds\n"; printTime(); TEST_ASSERT(res.NumAtoms == 21 && res.NumBonds == 21); BOOST_LOG(rdInfoLog) << "\tdone" << std::endl; }
void testGeneral(std::string rdbase){ BOOST_LOG(rdInfoLog) << "---------------------------------------" << std::endl; BOOST_LOG(rdInfoLog) << "-- testing general mol2 file parsing --" << std::endl; BOOST_LOG(rdInfoLog) << "---------------------------------------" << std::endl; { bool ok=false; std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/nonExistFile.mol2"; try{ RWMol *m = Mol2FileToMol(fName); delete m; } catch(const BadFileException &e){ ok=true; } TEST_ASSERT(ok); } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/pyrazole_pyridine.mol2"; RWMol *m = Mol2FileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms()==5); // this was sf.net issue 2727976: TEST_ASSERT(m->getNumConformers()==1); TEST_ASSERT(m->getConformer().is3D()); TEST_ASSERT(feq(m->getConformer().getAtomPos(0).x,1.5019)); TEST_ASSERT(feq(m->getConformer().getAtomPos(0).y,1.0435)); TEST_ASSERT(feq(m->getConformer().getAtomPos(0).z,0.0000)); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/benzene.mol2"; RWMol *m = Mol2FileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms()==6); delete m; } { bool ok=false; std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/mol_noatoms.mol2"; try { RWMol *m = Mol2FileToMol(fName); delete m; } catch(const FileParseException &e){ ok=true; } TEST_ASSERT(ok); } { bool ok=false; std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/mol_nomol.mol2"; try { RWMol *m = Mol2FileToMol(fName); delete m; } catch(const FileParseException &e){ ok=true; } TEST_ASSERT(ok); } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/lonePairMol.mol2"; RWMol *m = Mol2FileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms()==5 && m->getNumBonds()==4); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/symmetricGuanidine.mol2"; RWMol *m = Mol2FileToMol(fName,false); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(1)->getFormalCharge()==1); TEST_ASSERT(m->getAtomWithIdx(8)->getFormalCharge()==1); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/highlySymmetricGuanidine.mol2"; RWMol *m = Mol2FileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(4)->getFormalCharge()==1); TEST_ASSERT(m->getAtomWithIdx(12)->getFormalCharge()==1); TEST_ASSERT(m->getAtomWithIdx(20)->getFormalCharge()==1); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/Noxide.mol2"; RWMol *m = Mol2FileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(8)->getFormalCharge()==1); TEST_ASSERT(m->getAtomWithIdx(9)->getFormalCharge()==-1); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/Noxide.mol2"; RWMol *m = Mol2FileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(8)->getFormalCharge()==1); TEST_ASSERT(m->getAtomWithIdx(9)->getFormalCharge()==-1); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/fusedRing.mol2"; RWMol *m = Mol2FileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(0)->getFormalCharge()==0); TEST_ASSERT(m->getAtomWithIdx(5)->getFormalCharge()==0); TEST_ASSERT(m->getAtomWithIdx(8)->getFormalCharge()==0); TEST_ASSERT(m->getAtomWithIdx(13)->getFormalCharge()==0); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/pyridiniumPhenyl.mol2"; RWMol *m = Mol2FileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(5)->getFormalCharge()==1); TEST_ASSERT(m->getAtomWithIdx(6)->getFormalCharge()==0); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/sulfonAmide.mol2"; RWMol *m = Mol2FileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(1)->getFormalCharge()==0); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/chargedAmidineRWH.mol2"; RWMol *m = Mol2FileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(6)->getFormalCharge()==1); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/chargedAmidineEC.mol2"; RWMol *m = Mol2FileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(3)->getFormalCharge()==1); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/chargedAmidine.mol2"; RWMol *m = Mol2FileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(9)->getFormalCharge()==1); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/dbtranslateCharged.mol2"; RWMol *m = Mol2FileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(8)->getFormalCharge()==1); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/dbtranslateUncharged.mol2"; RWMol *m = Mol2FileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(8)->getFormalCharge()==0); delete m; } { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/dbtranslateUnchargedRing.mol2"; RWMol *m = Mol2FileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getAtomWithIdx(2)->getFormalCharge()==0); delete m; } #if 0 { std::string fName = rdbase + "/Code/GraphMol/FileParsers/test_data/Sulfonate.mol2"; RWMol *m = Mol2FileToMol(fName); TEST_ASSERT(m); BOOST_LOG(rdInfoLog) <<MolToSmiles(*m)<<std::endl; delete m; } #endif BOOST_LOG(rdInfoLog) << "------------------------------------" << std::endl; BOOST_LOG(rdInfoLog) << "-- DONE general mol2 file parsing --" << std::endl; BOOST_LOG(rdInfoLog) << "------------------------------------" << std::endl; }
int setAromaticity(RWMol &mol) { // FIX: we will assume for now that if the input molecule came // with aromaticity information it is correct and we will not // touch it. Loop through the atoms and check if any atom has // arom stuff set. We may want check this more carefully later // and start from scratch if necessary ROMol::AtomIterator ai; for (ai = mol.beginAtoms(); ai != mol.endAtoms(); ai++) { if ((*ai)->getIsAromatic()) { // found aromatic info return -1; } } // first find the all the simple rings in the molecule VECT_INT_VECT srings; if (mol.getRingInfo()->isInitialized()) { srings = mol.getRingInfo()->atomRings(); } else { MolOps::symmetrizeSSSR(mol, srings); } int narom = 0; // loop over all the atoms in the rings that can be candidates // for aromaticity // Atoms are candidates if // - it is part of ring // - has one or more electron to donate or has empty p-orbitals int natoms = mol.getNumAtoms(); boost::dynamic_bitset<> acands(natoms); boost::dynamic_bitset<> aseen(natoms); VECT_EDON_TYPE edon(natoms); VECT_INT_VECT cRings; // holder for rings that are candidates for aromaticity for (VECT_INT_VECT_I vivi = srings.begin(); vivi != srings.end(); ++vivi) { bool allAromatic = true; for (INT_VECT_I ivi = (*vivi).begin(); ivi != (*vivi).end(); ++ivi) { if (aseen[*ivi]) { if (!acands[*ivi]) allAromatic = false; continue; } aseen[*ivi] = 1; Atom *at = mol.getAtomWithIdx(*ivi); // now that the atom is part of ring check if it can donate // electron or has empty orbitals. Record the donor type // information in 'edon' - we will need it when we get to // the Huckel rule later edon[*ivi] = getAtomDonorTypeArom(at); acands[*ivi] = isAtomCandForArom(at, edon[*ivi]); if (!acands[*ivi]) allAromatic = false; } if (allAromatic) { cRings.push_back((*vivi)); } } // first convert all rings to bonds ids VECT_INT_VECT brings; RingUtils::convertToBonds(cRings, brings, mol); // make the neighbor map for the rings // i.e. a ring is a neighbor a another candidate ring if // shares at least one bond // useful to figure out fused systems INT_INT_VECT_MAP neighMap; RingUtils::makeRingNeighborMap(brings, neighMap, maxFusedAromaticRingSize); // now loop over all the candidate rings and check the // huckel rule - of course paying attention to fused systems. INT_VECT doneRs; int curr = 0; int cnrs = rdcast<int>(cRings.size()); boost::dynamic_bitset<> fusDone(cnrs); INT_VECT fused; while (curr < cnrs) { fused.resize(0); RingUtils::pickFusedRings(curr, neighMap, fused, fusDone); applyHuckelToFused(mol, cRings, brings, fused, edon, neighMap, narom, 6); int rix; for (rix = 0; rix < cnrs; rix++) { if (!fusDone[rix]) { curr = rix; break; } } if (rix == cnrs) { break; } } mol.setProp(common_properties::numArom, narom, true); return narom; }
void deletebonds(const ROMol &mol, String ftype, int hac){ RWMol *newMol = static_cast<RWMol*>(new ROMol(mol,false)); int total_acyclic = 0; int total_cyclic = 0; //find the relevant bonds to break // Single acyclic Cuts if(ftype == acyc_smarts){ acyclic_matching_atoms = mol.getSubstructMatches(acyc); total_acyclic = acyclic_matching_atoms.size(); MatchVectType acyclic_matching_atoms; std::vector<int> bonds_selected; Match_Vect bonds_selected; SubstructMatch(mol, acyc, acyclic_matching_atoms); // if we didn't find any matches, there's nothing to be done here // simply return a list with a copy of the starting molecule if (acyclic_matching_atoms.size() == 0) { newMol.push_back(ROMOL_SPTR(new ROMol(mol,false))); newMol[0]->clearComputedProps(false); return newMol; for(MatchVectType::const_iterator mvit=acyclic_matching_atoms.begin(); mvit!=acyclic_matching_atoms.end(); mvit++){ bonds_selected.push_back(mvit->first); bonds_selected.push_back(mvit->second); bonds_selected[0] = mvit->first; bonds_selected[1] = mvit->second; Atom *at1 = newMol->getAtomWithIdx(bonds_selected[0]); Atom *at2 = newMol->getAtomWithIdx(bonds_selected[1]); Atom *atom0 = newMol->getAtomWithIdx(0); Atom *atom1 = newMol->getAtomWithIdx(0); newMol->removeBond(bonds_selected[0], bonds_selected[1]);// Break the bond with idx=at1, at2. // Introduce two dummy atoms in the molecule newMol->addAtom(atom0); newMol->addAtom(atom1); // Bond the dummy atoms to the new terminal atoms Bond *oBond=newMol->getBondBetweenAtoms(bonds_selected[0],atom0->getIdx()); CHECK_INVARIANT(oBond,"required bond not found"); newMol->addBond(at1, *atom0,Bond::SINGLE); Bond *oBond=newMol->getBondBetweenAtoms(bonds_selected[1],atom1->getIdx()); CHECK_INVARIANT(oBond,"required bond not found"); newMol->addBond(at2, *atom1,Bond::SINGLE); break; } //Now get the modified fragment in smiles(i.e. smi2); String smi2 = MolToSmiles(*newMol); //printf (smi2); } } //cyclic Cuts if(ftype == cyc_smarts){ cyclic_matching_atoms = mol.getSubstructMatches(cyc); int total_cyclic = cyclic_matching_atoms.size(); MatchVectType cyclic_matching_atoms; std::vector<int> bonds_selected; Match_Vect bonds_selected; SubstructMatch(mol, cyc, cyclic_matching_atoms); // if we didn't find any matches, there's nothing to be done here // simply return a list with a copy of the starting molecule if (cyclic_matching_atoms.size() == 0) { newMol.push_back(ROMOL_SPTR(new ROMol(mol,false))); newMol[0]->clearComputedProps(false); return newMol; for(MatchVectType::const_iterator mvit=cyclic_matching_atoms.begin(); mvit!=cyclic_matching_atoms.end(); mvit++){ bonds_selected.push_back(mvit->first); bonds_selected.push_back(mvit->second); bonds_selected[0] = mvit->first; bonds_selected[1] = mvit->second; Atom *at1 = newMol->getAtomWithIdx(bonds_selected[0]); Atom *at2 = newMol->getAtomWithIdx(bonds_selected[1]); Atom *atom0 = newMol->getAtomWithIdx(0); Atom *atom1 = newMol->getAtomWithIdx(0); newMol->removeBond(bonds_selected[0], bonds_selected[1]);// Break the bond with idx=at1, at2. // Introduce two dummy atoms in the molecule newMol->addAtom(atom0); newMol->addAtom(atom1); // Bond the dummy atoms to the new terminal atoms Bond *oBond=newMol->getBondBetweenAtoms(bonds_selected[0],atom0->getIdx()); CHECK_INVARIANT(oBond,"required bond not found"); newMol->addBond(at1, *atom0,Bond::SINGLE); Bond *oBond=newMol->getBondBetweenAtoms(bonds_selected[1],atom1->getIdx()); CHECK_INVARIANT(oBond,"required bond not found"); newMol->addBond(at2, *atom1,Bond::SINGLE); continue; } //Now get the modified fragment in smiles(i.e. smi2); String smi2 = MolToSmiles(*newMol); //printf (smi2); //now do an acyclic cut with the successful cyclic cut on the mol for(MatchVectType::const_iterator mvit=acyclic_matching_atoms.begin(); mvit!=acyclic_matching_atoms.end(); mvit++){ bonds_selected.push_back(mvit->first); bonds_selected.push_back(mvit->second); bonds_selected[0] = mvit->first; bonds_selected[1] = mvit->second; Atom *at1 = newMol->getAtomWithIdx(bonds_selected[0]); Atom *at2 = newMol->getAtomWithIdx(bonds_selected[1]); Atom *atom0 = newMol->getAtomWithIdx(0); Atom *atom1 = newMol->getAtomWithIdx(0); newMol->removeBond(bonds_selected[0], bonds_selected[1]);// Break the bond with idx=at1, at2. // Introduce two dummy atoms in the molecule newMol->addAtom(atom0); newMol->addAtom(atom1); // Bond the dummy atoms to the new terminal atoms Bond *oBond=newMol->getBondBetweenAtoms(bonds_selected[0],atom0->getIdx()); CHECK_INVARIANT(oBond,"required bond not found"); newMol->addBond(at1, *nbrIdx,oBond->getBondType()); Bond *oBond=newMol->getBondBetweenAtoms(bonds_selected[1],atom1->getIdx()); CHECK_INVARIANT(oBond,"required bond not found"); newMol->addBond(at2, *atom1,Bond::SINGLE); continue; } //Now get the modified fragment in smiles(i.e. smi2); String smi2 = MolToSmiles(*newMol); //printf (smi2); } } //determine whether ring cut is valid String cSma1 = ("[#0][r].[r][#0]"); static ROMol *Sma1 = SmartsToMol("[#0][r].[r][#0]"); String cSma2 = ("[#0][r][#0]"); static ROMol *Sma2 = SmartsToMol("[#0][r][#0]"); void is_ring_cut_valid(ROMol *fMol, ROMol *Sma1, ROMol *Sma2){ //to check is a fragment is a valid ring cut, it needs to match the //smarts: [$([#0][r].[r][#0]),$([#0][r][#0])] boolean valid = false; ROMol *m = new RWMol(); //if m is not None: if (m != NULL){ //use global smarts if(m->hasSubstructMatch(Sma1) || m->hasSubstructMatch(Sma2)){ int atom_count = m->getNumAtoms(); valid = true; } } }
void testV3000WriterDetails(){ BOOST_LOG(rdInfoLog) << "testing details of v3000 writing" << std::endl; std::string rdbase = getenv("RDBASE"); rdbase += "/Code/GraphMol/FileParsers/test_data/"; { std::string fName = rdbase + "chebi_57262.v3k.mol"; RWMol *m = MolFileToMol(fName); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms()==22); TEST_ASSERT(m->getNumBonds()==21); TEST_ASSERT(m->getAtomWithIdx(18)->getAtomicNum()==0); TEST_ASSERT(!m->getAtomWithIdx(18)->hasQuery()); TEST_ASSERT(m->getAtomWithIdx(18)->getIsotope()==1); TEST_ASSERT(m->getAtomWithIdx(21)->getAtomicNum()==0); TEST_ASSERT(!m->getAtomWithIdx(21)->hasQuery()); TEST_ASSERT(m->getAtomWithIdx(21)->getIsotope()==2); std::string mb=MolToMolBlock(*m,true,-1,true,true); TEST_ASSERT(mb.find("MASS=1")!=std::string::npos); TEST_ASSERT(mb.find("MASS=2")!=std::string::npos); delete m; m = MolBlockToMol(mb); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms()==22); TEST_ASSERT(m->getNumBonds()==21); TEST_ASSERT(m->getAtomWithIdx(18)->getAtomicNum()==0); TEST_ASSERT(!m->getAtomWithIdx(18)->hasQuery()); TEST_ASSERT(m->getAtomWithIdx(18)->getIsotope()==1); TEST_ASSERT(m->getAtomWithIdx(21)->getAtomicNum()==0); TEST_ASSERT(!m->getAtomWithIdx(21)->hasQuery()); TEST_ASSERT(m->getAtomWithIdx(21)->getIsotope()==2); // repeat that one more time to make sure we're really solid: mb=MolToMolBlock(*m,true,-1,true,true); TEST_ASSERT(mb.find("MASS=1")!=std::string::npos); TEST_ASSERT(mb.find("MASS=2")!=std::string::npos); delete m; m = MolBlockToMol(mb); TEST_ASSERT(m); TEST_ASSERT(m->getNumAtoms()==22); TEST_ASSERT(m->getNumBonds()==21); TEST_ASSERT(m->getAtomWithIdx(18)->getAtomicNum()==0); TEST_ASSERT(!m->getAtomWithIdx(18)->hasQuery()); TEST_ASSERT(m->getAtomWithIdx(18)->getIsotope()==1); TEST_ASSERT(m->getAtomWithIdx(21)->getAtomicNum()==0); TEST_ASSERT(!m->getAtomWithIdx(21)->hasQuery()); TEST_ASSERT(m->getAtomWithIdx(21)->getIsotope()==2); delete m; } BOOST_LOG(rdInfoLog) << "done" << std::endl; }
void testIssue3525000() { { std::string rdbase = getenv("RDBASE"); std::string fname = rdbase + "/Code/GraphMol/FileParsers/test_data/Issue3525000.sdf"; RWMol *mol = MolFileToMol(fname); TEST_ASSERT(mol); std::string cip; TEST_ASSERT(mol->getAtomWithIdx(0)->hasProp("_CIPCode")); mol->getAtomWithIdx(0)->getProp("_CIPCode",cip); TEST_ASSERT(cip=="R"); TEST_ASSERT(mol->getAtomWithIdx(3)->hasProp("_CIPCode")); mol->getAtomWithIdx(3)->getProp("_CIPCode",cip); TEST_ASSERT(cip=="R"); TEST_ASSERT(mol->getAtomWithIdx(6)->hasProp("_CIPCode")); mol->getAtomWithIdx(6)->getProp("_CIPCode",cip); TEST_ASSERT(cip=="R"); TEST_ASSERT(mol->getAtomWithIdx(8)->hasProp("_CIPCode")); mol->getAtomWithIdx(8)->getProp("_CIPCode",cip); TEST_ASSERT(cip=="R"); TEST_ASSERT(mol->getAtomWithIdx(9)->hasProp("_CIPCode")); mol->getAtomWithIdx(9)->getProp("_CIPCode",cip); TEST_ASSERT(cip=="R"); TEST_ASSERT(mol->getAtomWithIdx(10)->hasProp("_CIPCode")); mol->getAtomWithIdx(10)->getProp("_CIPCode",cip); TEST_ASSERT(cip=="S"); TEST_ASSERT(mol->getAtomWithIdx(14)->hasProp("_CIPCode")); mol->getAtomWithIdx(14)->getProp("_CIPCode",cip); TEST_ASSERT(cip=="R"); TEST_ASSERT(mol->getAtomWithIdx(15)->hasProp("_CIPCode")); mol->getAtomWithIdx(15)->getProp("_CIPCode",cip); TEST_ASSERT(cip=="R"); std::string mb=MolToMolBlock(*mol); delete mol; mol = MolBlockToMol(mb); TEST_ASSERT(mol); TEST_ASSERT(mol->getAtomWithIdx(0)->hasProp("_CIPCode")); mol->getAtomWithIdx(0)->getProp("_CIPCode",cip); TEST_ASSERT(cip=="R"); TEST_ASSERT(mol->getAtomWithIdx(3)->hasProp("_CIPCode")); mol->getAtomWithIdx(3)->getProp("_CIPCode",cip); TEST_ASSERT(cip=="R"); TEST_ASSERT(mol->getAtomWithIdx(6)->hasProp("_CIPCode")); mol->getAtomWithIdx(6)->getProp("_CIPCode",cip); TEST_ASSERT(cip=="R"); TEST_ASSERT(mol->getAtomWithIdx(8)->hasProp("_CIPCode")); mol->getAtomWithIdx(8)->getProp("_CIPCode",cip); TEST_ASSERT(cip=="R"); TEST_ASSERT(mol->getAtomWithIdx(9)->hasProp("_CIPCode")); mol->getAtomWithIdx(9)->getProp("_CIPCode",cip); TEST_ASSERT(cip=="R"); TEST_ASSERT(mol->getAtomWithIdx(10)->hasProp("_CIPCode")); mol->getAtomWithIdx(10)->getProp("_CIPCode",cip); TEST_ASSERT(cip=="S"); TEST_ASSERT(mol->getAtomWithIdx(14)->hasProp("_CIPCode")); mol->getAtomWithIdx(14)->getProp("_CIPCode",cip); TEST_ASSERT(cip=="R"); TEST_ASSERT(mol->getAtomWithIdx(15)->hasProp("_CIPCode")); mol->getAtomWithIdx(15)->getProp("_CIPCode",cip); TEST_ASSERT(cip=="R"); } { std::string rdbase = getenv("RDBASE"); std::string fname = rdbase + "/Code/GraphMol/FileParsers/test_data/Issue3525000b.sdf"; RWMol *mol = MolFileToMol(fname); TEST_ASSERT(mol); MolOps::assignChiralTypesFrom3D(*mol); MolOps::assignStereochemistry(*mol); std::string cip; TEST_ASSERT(mol->getAtomWithIdx(0)->hasProp("_CIPCode")); mol->getAtomWithIdx(0)->getProp("_CIPCode",cip); TEST_ASSERT(cip=="S"); TEST_ASSERT(mol->getAtomWithIdx(1)->hasProp("_CIPCode")); mol->getAtomWithIdx(1)->getProp("_CIPCode",cip); TEST_ASSERT(cip=="S"); TEST_ASSERT(mol->getAtomWithIdx(2)->hasProp("_CIPCode")); mol->getAtomWithIdx(2)->getProp("_CIPCode",cip); TEST_ASSERT(cip=="R"); TEST_ASSERT(mol->getAtomWithIdx(3)->hasProp("_CIPCode")); mol->getAtomWithIdx(3)->getProp("_CIPCode",cip); TEST_ASSERT(cip=="R"); TEST_ASSERT(mol->getAtomWithIdx(4)->hasProp("_CIPCode")); mol->getAtomWithIdx(4)->getProp("_CIPCode",cip); TEST_ASSERT(cip=="S"); std::string mb=MolToMolBlock(*mol); delete mol; mol = MolBlockToMol(mb); TEST_ASSERT(mol); TEST_ASSERT(mol->getAtomWithIdx(0)->hasProp("_CIPCode")); mol->getAtomWithIdx(0)->getProp("_CIPCode",cip); TEST_ASSERT(cip=="S"); TEST_ASSERT(mol->getAtomWithIdx(1)->hasProp("_CIPCode")); mol->getAtomWithIdx(1)->getProp("_CIPCode",cip); TEST_ASSERT(cip=="S"); TEST_ASSERT(mol->getAtomWithIdx(2)->hasProp("_CIPCode")); mol->getAtomWithIdx(2)->getProp("_CIPCode",cip); TEST_ASSERT(cip=="R"); TEST_ASSERT(mol->getAtomWithIdx(3)->hasProp("_CIPCode")); mol->getAtomWithIdx(3)->getProp("_CIPCode",cip); TEST_ASSERT(cip=="R"); TEST_ASSERT(mol->getAtomWithIdx(4)->hasProp("_CIPCode")); mol->getAtomWithIdx(4)->getProp("_CIPCode",cip); TEST_ASSERT(cip=="S"); } }
bool kekulizeWorker(RWMol &mol, const INT_VECT &allAtms, boost::dynamic_bitset<> dBndCands, boost::dynamic_bitset<> dBndAdds, INT_VECT done, unsigned int maxBackTracks) { INT_DEQUE astack; INT_INT_DEQ_MAP options; int lastOpt = -1; boost::dynamic_bitset<> localBondsAdded(mol.getNumBonds()); // ok the algorithm goes something like this // - start with an atom that has been marked aromatic before // - check if it can have a double bond // - add its neighbors to the stack // - check if one of its neighbors can also have a double bond // - if yes add a double bond. // - if multiple neighbors can have double bonds - add them to a // options stack we may have to retrace out path if we chose the // wrong neighbor to add the double bond // - if double bond added update the candidates for double bond // - move to the next atom on the stack and repeat the process // - if an atom that can have multiple a double bond has no // neighbors that can take double bond - we made a mistake // earlier by picking a wrong candidate for double bond // - in this case back track to where we made the mistake int curr; INT_DEQUE btmoves; unsigned int numBT = 0; // number of back tracks so far while ((done.size() < allAtms.size()) || (astack.size() > 0)) { // pick a curr atom to work with if (astack.size() > 0) { curr = astack.front(); astack.pop_front(); } else { for (int allAtm : allAtms) { if (std::find(done.begin(), done.end(), allAtm) == done.end()) { curr = allAtm; break; } } } done.push_back(curr); // loop over the neighbors if we can add double bonds or // simply push them onto the stack INT_DEQUE opts; bool cCand = false; if (dBndCands[curr]) { cCand = true; } int ncnd; // if we are here because of backtracking if (options.find(curr) != options.end()) { opts = options[curr]; CHECK_INVARIANT(opts.size() > 0, ""); } else { RWMol::ADJ_ITER nbrIdx, endNbrs; boost::tie(nbrIdx, endNbrs) = mol.getAtomNeighbors(mol.getAtomWithIdx(curr)); while (nbrIdx != endNbrs) { // ignore if the neighbor has already been dealt with before if (std::find(done.begin(), done.end(), static_cast<int>(*nbrIdx)) != done.end()) { ++nbrIdx; continue; } // ignore if the neighbor is not part of the fused system if (std::find(allAtms.begin(), allAtms.end(), static_cast<int>(*nbrIdx)) == allAtms.end()) { ++nbrIdx; continue; } // if the neighbor is not on the stack add it if (std::find(astack.begin(), astack.end(), static_cast<int>(*nbrIdx)) == astack.end()) { astack.push_back(rdcast<int>(*nbrIdx)); } // check if the neighbor is also a candidate for a double bond // the refinement that we'll make to the candidate check we've already // done is to make sure that the bond is either flagged as aromatic // or involves a dummy atom. This was Issue 3525076. // This fix is not really 100% of the way there: a situation like // that for Issue 3525076 but involving a dummy atom in the cage // could lead to the same failure. The full fix would require // a fairly detailed analysis of all bonds in the molecule to determine // which of them is eligible to be converted. if (cCand && dBndCands[*nbrIdx] && (mol.getBondBetweenAtoms(curr, *nbrIdx)->getIsAromatic() || mol.getAtomWithIdx(curr)->getAtomicNum() == 0 || mol.getAtomWithIdx(*nbrIdx)->getAtomicNum() == 0)) { opts.push_back(rdcast<int>(*nbrIdx)); } // end of curr atoms can have a double bond ++nbrIdx; } // end of looping over neighbors } // now add a double bond from current to one of the neighbors if we can if (cCand) { if (opts.size() > 0) { ncnd = opts.front(); opts.pop_front(); Bond *bnd = mol.getBondBetweenAtoms(curr, ncnd); bnd->setBondType(Bond::DOUBLE); // remove current and the neighbor from the dBndCands list dBndCands[curr] = 0; dBndCands[ncnd] = 0; // add them to the list of bonds to which have been made double dBndAdds[bnd->getIdx()] = 1; localBondsAdded[bnd->getIdx()] = 1; // if this is an atom we previously visted and picked we // simply tried a different option now, overwrite the options // stored for this atoms if (options.find(curr) != options.end()) { if (opts.size() == 0) { options.erase(curr); btmoves.pop_back(); if (btmoves.size() > 0) { lastOpt = btmoves.back(); } else { lastOpt = -1; } } else { options[curr] = opts; } } else { // this is new atoms we are trying and have other // neighbors as options to add double bond store this to // the options stack, we may have made a mistake in // which one we chose and have to return here if (opts.size() > 0) { lastOpt = curr; btmoves.push_back(lastOpt); options[curr] = opts; } } } // end of adding a double bond else { // we have an atom that should be getting a double bond // but none of the neighbors can take one. Most likely // because of a wrong choice earlier so back track if ((lastOpt >= 0) && (numBT < maxBackTracks)) { // std::cerr << "PRE BACKTRACK" << std::endl; // mol.debugMol(std::cerr); backTrack(mol, options, lastOpt, done, astack, dBndCands, dBndAdds); // std::cerr << "POST BACKTRACK" << std::endl; // mol.debugMol(std::cerr); numBT++; } else { // undo any remaining changes we made while here // this was github #962 for (unsigned int bidx = 0; bidx < mol.getNumBonds(); ++bidx) { if (localBondsAdded[bidx]) { mol.getBondWithIdx(bidx)->setBondType(Bond::SINGLE); } } return false; } } // end of else try to backtrack } // end of curr atom atom being a cand for double bond } // end of while we are not done with all atoms return true; }