OpenBabel::OBMol Schuffenhauer::RemoveRing(OpenBabel::OBMol& oldMol, std::vector<OpenBabel::OBRing*>& rings, unsigned int ringIdx) { OpenBabel::OBMol newMol(oldMol); // Make list of the ring bonds std::set<OpenBabel::OBBond*> ringBonds; OpenBabel::OBBond* bond; std::vector<OpenBabel::OBBond*>::iterator bvi; for (bond = newMol.BeginBond(bvi); bond; bond = newMol.NextBond(bvi)) { if (rings[ringIdx]->IsMember(bond)) { ringBonds.insert(bond); } } // Make list of delocalizable bonds (aromatic, single and flanked by two double bonds) std::set<OpenBabel::OBBond*> delocalizableBonds; std::set<OpenBabel::OBBond*>::iterator bli; OpenBabel::OBBondIterator bi; OpenBabel::OBAtom* atom; OpenBabel::OBBond* nbrBond; unsigned int n; for (bli = ringBonds.begin(); bli != ringBonds.end(); ++bli) { bond = *bli; if ((bond->GetBondOrder() == 1) && bond->IsAromatic()) { n = 0; atom = bond->GetBeginAtom(); for (nbrBond = atom->BeginBond(bi); nbrBond; nbrBond = atom->NextBond(bi)) { if ((nbrBond != bond) && ringBonds.count(nbrBond) && (nbrBond->GetBondOrder() == 2)) { ++n; } } atom = bond->GetEndAtom(); for (nbrBond = atom->BeginBond(bi); nbrBond; nbrBond = atom->NextBond(bi)) { if ((nbrBond != bond) && ringBonds.count(nbrBond) && (nbrBond->GetBondOrder() == 2)) { ++n; } } } if (n == 2) { delocalizableBonds.insert(bond); } } // Make list of bonds which form the fusion with other rings std::set<OpenBabel::OBBond*> fusionBonds; for (bli = ringBonds.begin(); bli != ringBonds.end(); ++bli) { bond = *bli; for (unsigned int i(0); i < rings.size(); ++i) { if (i != ringIdx) { if (rings[i]->IsMember(bond)) { fusionBonds.insert(bond); } } } } // Make list of bonds which are the fusion between aromatic and non-aromatic std::set<OpenBabel::OBBond*> aromaticNonaromaticFusionBonds; if (rings[ringIdx]->IsAromatic()) { for (bli = fusionBonds.begin(); bli != fusionBonds.end(); ++bli) { bond = *bli; for (unsigned int i(0); i < rings.size(); ++i) { if (i != ringIdx) { if (rings[i]->IsMember(bond) && !rings[i]->IsAromatic()) { aromaticNonaromaticFusionBonds.insert(bond); } } } } } // Make list of bonds which are the fusion between aromatic and aromatic std::set<OpenBabel::OBBond*> aromaticAromaticFusionBonds; if (rings[ringIdx]->IsAromatic()) { for (bli = fusionBonds.begin(); bli != fusionBonds.end(); ++bli) { bond = *bli; for (unsigned int i(0); i < rings.size(); ++i) { if (i != ringIdx) { if (rings[i]->IsMember(bond) && rings[i]->IsAromatic()) { aromaticAromaticFusionBonds.insert(bond); } } } } } // Remove ring std::set<OpenBabel::OBBond*> bondsToBeDeleted; std::set<OpenBabel::OBAtom*> atomsToBeDeleted; OpenBabel::OBAtom* nbrAtom[2]; for (bli = ringBonds.begin(); bli != ringBonds.end(); ++bli) { bond = *bli; if (fusionBonds.count(bond)) { continue; } else { bondsToBeDeleted.insert(bond); nbrAtom[0] = bond->GetBeginAtom(); nbrAtom[1] = bond->GetEndAtom(); if (nbrAtom[0] && nbrAtom[1]) { if (nbrAtom[0]->MemberOfRingCount() == 1) { atomsToBeDeleted.insert(nbrAtom[0]); } if (nbrAtom[1]->MemberOfRingCount() == 1) { atomsToBeDeleted.insert(nbrAtom[1]); } } } } newMol.BeginModify(); for (bli = bondsToBeDeleted.begin(); bli != bondsToBeDeleted.end(); ++bli) { newMol.DeleteBond(*bli); } newMol.EndModify(); newMol.BeginModify(); std::set<OpenBabel::OBAtom*>::iterator ali; for (ali = atomsToBeDeleted.begin(); ali != atomsToBeDeleted.end(); ++ali) { newMol.DeleteAtom(*ali); } newMol.EndModify(); // Correct the bond orders of the ex-fusion bond(s) newMol.BeginModify(); for (bond = newMol.BeginBond(bvi); bond; bond = newMol.NextBond(bvi)) { if (aromaticNonaromaticFusionBonds.count(bond)) { bond->SetBondOrder(2); } else if (aromaticAromaticFusionBonds.count(bond) && delocalizableBonds.count(bond)) { bond->SetBondOrder(2); } } newMol.EndModify(); // Remove single atoms that originate from exocyclic bonds at ring (void) RemoveSidechains(&newMol); // Check if there are atoms with valences that are not allowed std::vector<OpenBabel::OBAtom*>::iterator avi; for (atom = newMol.BeginAtom(avi); atom; atom = newMol.NextAtom(avi)) { if (atom->IsCarbon() && (atom->BOSum() > 4)) { newMol.Clear(); break; } else if (atom->IsNitrogen() && (atom->BOSum() > 3)) { newMol.Clear(); break; } else if (atom->IsOxygen() && (atom->BOSum() > 2)) { newMol.Clear(); break; } } // Check if there are no discontinuous fragments if (newMol.Separate().size() > 1) { newMol.Clear(); } return newMol; }
OpenBabel::OBMol Schuffenhauer::Rule_7(OpenBabel::OBMol& oldMol) { std::vector<OpenBabel::OBRing*> allrings(oldMol.GetSSSR()); if (allrings.size() <= _ringsToBeRetained) { return oldMol; } // Are all atoms and bonds aromatic? std::vector<OpenBabel::OBAtom*>::iterator avi; OpenBabel::OBAtom* atom; for (atom = oldMol.BeginAtom(avi); atom; atom = oldMol.NextAtom(avi)) { if (!atom->IsAromatic()) { return oldMol; } } std::vector<OpenBabel::OBBond*>::iterator bvi; OpenBabel::OBBond* bond; for (bond = oldMol.BeginBond(bvi); bond; bond = oldMol.NextBond(bvi)) { if (!bond->IsAromatic()) { return oldMol; } } std::vector<OpenBabel::OBMol> mols; for (unsigned int i(0); i < allrings.size(); ++i) { mols.push_back(oldMol); } std::vector<OpenBabel::OBMol> validMols; for (unsigned int i(0); i < mols.size(); ++i) { mols[i] = RemoveRing(mols[i], allrings, i); if (!mols[i].Empty()) { // Has aromaticity been broken? bool broken(false); for (atom = mols[i].BeginAtom(avi); atom; atom = mols[i].NextAtom(avi)) { if (atom->IsInRing() && !atom->IsAromatic()) { broken = true; break; } } if (!broken) { validMols.push_back(mols[i]); } } } if (validMols.size() == 1) { return validMols[0]; } return oldMol; }