static int DetermineFRJ(OBMol &mol) { if (!mol.HasClosureBondsPerceived()) return (int)FindRingAtomsAndBonds2(mol); int frj = 0; OBBond *bond; vector<OBBond*>::iterator j; for (bond = mol.BeginBond(j);bond;bond = mol.NextBond(j)) if (bond->IsClosure()) // bond->HasFlag(OB_CLOSURE_BOND)? frj++; return frj; }
void OBMol::FindLSSR() { if (HasLSSRPerceived()) return; SetLSSRPerceived(); obErrorLog.ThrowError(__FUNCTION__, "Ran OpenBabel::FindLSSR", obAuditMsg); // Delete any old data before we start finding new rings // The following procedure is slow // So if client code is multi-threaded, we don't want to make them wait if (HasData("LSSR")) { DeleteData("LSSR"); } OBRing *ring; vector<OBRing*>::iterator j; //get frerejaque taking int account multiple possible spanning graphs int frj = DetermineFRJ(*this); if (frj) { vector<OBRing*> vr; FindRingAtomsAndBonds(); OBBond *bond; vector<OBBond*> cbonds; vector<OBBond*>::iterator k; //restrict search for rings around closure bonds for (bond = BeginBond(k);bond;bond = NextBond(k)) if (bond->IsClosure()) cbonds.push_back(bond); if (!cbonds.empty()) { OBRingSearch rs; //search for all rings about closures vector<OBBond*>::iterator i; for (i = cbonds.begin();i != cbonds.end();++i) rs.AddRingFromClosure(*this,(OBBond*)*i); rs.SortRings(); rs.RemoveRedundant(-1); // -1 means LSSR //store the LSSR set for (j = rs.BeginRings();j != rs.EndRings();++j) { ring = new OBRing ((*j)->_path,NumAtoms()+1); ring->SetParent(this); vr.push_back(ring); } //rs.WriteRings(); } OBRingData *rd = new OBRingData(); rd->SetOrigin(perceived); // to separate from user or file input rd->SetAttribute("LSSR"); rd->SetData(vr); SetData(rd); } }
/** * \brief Select the root atoms for traversing atoms in rings. * * Picking only the begin atom of a closure bond can cause * difficulties when the selected atom is an inner atom * with three neighbour ring atoms. Why ? Because this atom * can get trapped by the other atoms when determining aromaticity, * because a simple visited flag is used in the * OBAromaticTyper::TraverseCycle() method. * * Ported from JOELib, copyright Joerg Wegner, 2003 under the GPL version 2 * Improved by Fabian (fab5) in 2009 -- PR#2889708 * * @param mol the molecule * @param avoidInnerRingAtoms inner closure ring atoms with more than 2 neighbours will be avoided * */ void OBAromaticTyper::SelectRootAtoms(OBMol &mol, bool avoidInnerRingAtoms) { OBBond *bond; OBAtom *atom, *nbr, *nbr2; OBRing *ring; // vector<OBAtom*>::iterator i; vector<OBBond*>::iterator j, l, nbr2Iter; vector<OBRing*> sssRings = mol.GetSSSR(); vector<OBRing*>::iterator k; int rootAtom; int ringNbrs; int heavyNbrs; int newRoot = -1; vector<int> tmpRootAtoms; vector<int> tmp; vector<OBBond*> cbonds; vector< vector<OBRing*> > ringAtoms; // store ring pointers on an atom basis //generate list of closure bonds for (bond = mol.BeginBond(j);bond;bond = mol.NextBond(j)) { if( bond->IsClosure() ) { cbonds.push_back(bond); if(avoidInnerRingAtoms) { tmpRootAtoms.push_back(bond->GetBeginAtomIdx()); } } } if(avoidInnerRingAtoms) { //for every atom fill vector with ring pointer it's associated with ringAtoms.resize(mol.NumAtoms()+1); for (k = sssRings.begin();k != sssRings.end();++k) { tmp = (*k)->_path; for (unsigned int j (0),j_end(tmp.size()); j < j_end; ++j) { ringAtoms[tmp[j]].push_back(*k); } } } //loop over closure bonds for(OBBondIterator bd(cbonds.begin()),bd_end(cbonds.end());bd!=bd_end;++bd) { bond = *bd; // BASIC APPROACH // pick beginning atom at closure bond // this is really ready, isn't it ! ;-) rootAtom = bond->GetBeginAtomIdx(); _root[rootAtom] = true; // EXTENDED APPROACH if (avoidInnerRingAtoms) { // count the number of neighbor ring atoms atom = mol.GetAtom(rootAtom); ringNbrs = heavyNbrs = 0; for (nbr = atom->BeginNbrAtom(l);nbr;nbr = atom->NextNbrAtom(l)) { // we can get this from atom->GetHvyValence() // but we need to find neighbors in rings too // so let's save some time if (!nbr->IsHydrogen()) { heavyNbrs++; if (nbr->IsInRing()) ringNbrs++; } // if this atom has more than 2 neighbor ring atoms // we could get trapped later when traversing cycles // which can cause aromaticity false detection newRoot = -1; if (ringNbrs > 2) { // try to find another root atom // only loop over rings which contain rootAtom for(k = ringAtoms[rootAtom].begin() ; k != ringAtoms[rootAtom].end(); ++k) { ring = (*k); tmp = ring->_path; bool checkThisRing = false; int rootAtomNumber=0; int idx=0; // avoiding two root atoms in one ring ! for (unsigned int j = 0; j < tmpRootAtoms.size(); ++j) { idx= tmpRootAtoms[j]; if(ring->IsInRing(idx)) { rootAtomNumber++; if(rootAtomNumber>=2) break; } } if(rootAtomNumber<2) { for (unsigned int j = 0; j < tmp.size(); ++j) { // find critical ring if (tmp[j] == rootAtom) { checkThisRing = true; } else { // second root atom in this ring ? if (_root[tmp[j]] == true) { // when there is a second root // atom this ring can not be // used for getting an other // root atom checkThisRing = false; break; } } } } // check ring for getting another // root atom to avoid aromaticity typer problems if (checkThisRing) { // check if we can find another root atom for (unsigned int m = 0; m < tmp.size(); ++m) { ringNbrs = heavyNbrs = 0; for (nbr2 = (mol.GetAtom(tmp[m]))->BeginNbrAtom(nbr2Iter); nbr2;nbr2 = (mol.GetAtom(tmp[m]))->NextNbrAtom(nbr2Iter)) { if (!nbr2->IsHydrogen()) { heavyNbrs++; if (nbr2->IsInRing()) ringNbrs++; } } // if the number of neighboured heavy atoms is also // the number of neighboured ring atoms, the aromaticity // typer could be stuck in a local traversing trap if (ringNbrs <= 2 && ring->IsInRing((mol.GetAtom(tmp[m])->GetIdx()))) { newRoot = tmp[m]; } } } } if ((newRoot != -1) && (rootAtom != newRoot)) { // unset root atom _root[rootAtom] = false; // pick new root atom _root[newRoot] = true; } } // if (ringNbrs > 2) } // end for } // if (avoid) } // end for(closure bonds) }