static int DetermineFRJ(OBMol &mol) { vector<vector<int> >::iterator i; vector<vector<int> > cfl; //find all continuous graphs in the mol area mol.ContigFragList(cfl); if (cfl.empty()) return(0); if (cfl.size() == 1) return(mol.NumBonds() - mol.NumAtoms() + 1); //count up the atoms and bonds belonging to each graph OBBond *bond; vector<OBBond*>::iterator j; int numatoms,numbonds,frj=0; OBBitVec frag; for (i = cfl.begin();i != cfl.end();++i) { frag.Clear(); frag.FromVecInt(*i); numatoms = (*i).size(); numbonds=0; for (bond = mol.BeginBond(j);bond;bond = mol.NextBond(j)) if (frag.BitIsOn(bond->GetBeginAtomIdx()) && frag.BitIsOn(bond->GetEndAtomIdx())) numbonds++; frj += numbonds - numatoms + 1; } return(frj); }
/** @since version 2.3 Adds an OBPairData object to each atom and bond in a substructure. The substructure's atoms are specified in an input parameter, a vector of atom indx; the bonds are those in the molecule that join these atoms. The attribute and value of the OBPairObject (the same for all the added objects) are specified as parameters. **/ bool AddDataToSubstruct(OBMol* pmol, const std::vector<int>& atomIdxs, const std::string& attribute, const std::string& value) { //Add data to atoms for(unsigned int j=0; j<atomIdxs.size(); ++j) { OBAtom* pAtom = pmol->GetAtom(atomIdxs[j]); if(!pAtom) continue; OBPairData* dp = new OBPairData; dp->SetAttribute(attribute); dp->SetValue(value); pAtom->SetData(dp); } OBBond* pBond; vector<OBBond*>::iterator i; for(pBond = pmol->BeginBond(i); pBond; pBond = pmol->NextBond(i)) { //Add data to bond if it joins two atoms in list if(count(atomIdxs.begin(), atomIdxs.end(), pBond->GetBeginAtomIdx()) && count(atomIdxs.begin(), atomIdxs.end(), pBond->GetEndAtomIdx())) { OBPairData* dp = new OBPairData; dp->SetAttribute(attribute); dp->SetValue(value); pBond->SetData(dp); } } return true; }
bool OBRotorList::FindRotors(OBMol &mol, bool sampleRingBonds) { // Find ring atoms & bonds // This function will set OBBond::IsRotor(). mol.FindRingAtomsAndBonds(); obErrorLog.ThrowError(__FUNCTION__, "Ran OpenBabel::FindRotors", obAuditMsg); // // Score the bonds using the graph theoretical distance (GTD). // The GTD is the distance from atom i to every other atom j. // Atoms on the "inside" of the molecule will have a lower GTD // value than atoms on the "outside" // // The scoring will rank "inside" bonds first. // vector<int> gtd; mol.GetGTDVector(gtd); // compute the scores vector<OBBond*>::iterator i; vector<pair<OBBond*,int> > vtmp; for (OBBond *bond = mol.BeginBond(i);bond;bond = mol.NextBond(i)) { // check if the bond is "rotatable" if (bond->IsRotor(sampleRingBonds)) { // check if the bond is fixed (using deprecated fixed atoms or new fixed bonds) if ((HasFixedAtoms() || HasFixedBonds()) && IsFixedBond(bond)) continue; if (bond->IsInRing()) { //otherwise mark that we have them and add it to the pile _ringRotors = true; } int score = gtd[bond->GetBeginAtomIdx()-1] + gtd[bond->GetEndAtomIdx()-1]; // compute the GTD bond score as sum of atom GTD scores vtmp.push_back(pair<OBBond*,int> (bond,score)); } } // sort the rotatable bonds by GTD score sort(vtmp.begin(),vtmp.end(),CompareRotor); // create rotors for the bonds int count = 0; vector<pair<OBBond*,int> >::iterator j; for (j = vtmp.begin(); j != vtmp.end(); ++j, ++count) { OBRotor *rotor = new OBRotor; rotor->SetBond((*j).first); rotor->SetIdx(count); rotor->SetNumCoords(mol.NumAtoms()*3); _rotor.push_back(rotor); } return true; }
bool WriteAlchemy(ostream &ofs,OBMol &mol) { unsigned int i; char buffer[BUFF_SIZE]; char bond_string[10]; snprintf(buffer, BUFF_SIZE, "%5d ATOMS, %5d BONDS, 0 CHARGES", mol.NumAtoms(), mol.NumBonds()); ofs << buffer << endl; ttab.SetFromType("INT"); ttab.SetToType("ALC"); OBAtom *atom; string str,str1; for(i = 1;i <= mol.NumAtoms(); i++) { atom = mol.GetAtom(i); str = atom->GetType(); ttab.Translate(str1,str); snprintf(buffer, BUFF_SIZE, "%5d %-6s%8.4f %8.4f %8.4f 0.0000", i, (char*)str1.c_str(), atom->GetX(), atom->GetY(), atom->GetZ()); ofs << buffer << endl; } OBBond *bond; vector<OBEdgeBase*>::iterator j; for (bond = mol.BeginBond(j);bond;bond = mol.NextBond(j)) { switch(bond->GetBO()) { case 1 : strcpy(bond_string,"SINGLE"); break; case 2 : strcpy(bond_string,"DOUBLE"); break; case 3 : strcpy(bond_string,"TRIPLE"); break; case 5 : strcpy(bond_string,"AROMATIC"); break; default : strcpy(bond_string,"SINGLE"); } snprintf(buffer, BUFF_SIZE, "%5d %4d %4d %s", bond->GetIdx()+1, bond->GetBeginAtomIdx(), bond->GetEndAtomIdx(), bond_string); ofs << buffer << endl; } return(true); }
static void FindRings(OBMol &mol,vector<int> &path,OBBitVec &avisit, OBBitVec &bvisit, int natom,int depth ) { OBAtom *atom; OBBond *bond; vector<OBBond*>::iterator k; // don't return if all atoms are visited // (For example, some atoms are in multiple rings!) -GRH if (avisit[natom]) { int j = depth-1; bond=mol.GetBond(path[j--]); bond->SetInRing(); while( j >= 0 ) { bond=mol.GetBond(path[j--]); bond->SetInRing(); (bond->GetBeginAtom())->SetInRing(); (bond->GetEndAtom())->SetInRing(); if(bond->GetBeginAtomIdx()==static_cast<unsigned int>(natom) || bond-> GetEndAtomIdx()==static_cast<unsigned int>(natom)) break; } } else { avisit.SetBitOn(natom); atom = mol.GetAtom(natom); for(bond = atom->BeginBond(k);bond;bond=atom->NextBond(k)) if( !bvisit[bond->GetIdx()]) { path[depth] = bond->GetIdx(); bvisit.SetBitOn(bond->GetIdx()); FindRings(mol,path,avisit,bvisit,bond->GetNbrAtomIdx(atom), depth+1); } } }
bool MOL2Format::WriteMolecule(OBBase* pOb, OBConversion* pConv) { OBMol* pmol = dynamic_cast<OBMol*>(pOb); if(pmol==NULL) return false; //Define some references so we can use the old parameter names ostream &ofs = *pConv->GetOutStream(); OBMol &mol = *pmol; bool ligandsOnly = pConv->IsOption("l", OBConversion::OUTOPTIONS)!=NULL; //The old code follows.... string str,str1; char buffer[BUFF_SIZE],label[BUFF_SIZE]; char rnum[BUFF_SIZE],rlabel[BUFF_SIZE]; ofs << "@<TRIPOS>MOLECULE" << endl; str = mol.GetTitle(); if (str.empty()) ofs << "*****" << endl; else ofs << str << endl; snprintf(buffer, BUFF_SIZE," %d %d 0 0 0", mol.NumAtoms(),mol.NumBonds()); ofs << buffer << endl; ofs << "SMALL" << endl; OBPairData *dp = (OBPairData*)mol.GetData("PartialCharges"); if (dp != NULL) { // Tripos spec says: // NO_CHARGES, DEL_RE, GASTEIGER, GAST_HUCK, HUCKEL, PULLMAN, // GAUSS80_CHARGES, AMPAC_CHARGES, MULLIKEN_CHARGES, DICT_ CHARGES, // MMFF94_CHARGES, USER_CHARGES if (dp->GetValue() == "Mulliken") ofs << "MULLIKEN_CHARGES" << endl; else // should pick from the Tripos types ofs << "GASTEIGER" << endl; } else { // No idea what these charges are... all our code sets "PartialCharges" ofs << "GASTEIGER" << endl; } ofs << "Energy = " << mol.GetEnergy() << endl; if (mol.HasData(OBGenericDataType::CommentData)) { OBCommentData *cd = (OBCommentData*)mol.GetData(OBGenericDataType::CommentData); ofs << cd->GetData(); } ofs << endl; ofs << "@<TRIPOS>ATOM" << endl; OBAtom *atom; OBResidue *res; vector<OBAtom*>::iterator i; vector<int> labelcount; labelcount.resize( etab.GetNumberOfElements() ); ttab.SetFromType("INT"); ttab.SetToType("SYB"); for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i)) { // // Use sequentially numbered atom names if no residues // snprintf(label,BUFF_SIZE, "%s%d", etab.GetSymbol(atom->GetAtomicNum()), ++labelcount[atom->GetAtomicNum()]); strcpy(rlabel,"<1>"); strcpy(rnum,"1"); str = atom->GetType(); ttab.Translate(str1,str); // // Use original atom names if there are residues // if (!ligandsOnly && (res = atom->GetResidue()) ) { // use original atom names defined by residue snprintf(label,BUFF_SIZE,"%s",(char*)res->GetAtomID(atom).c_str()); // make sure that residue name includes its number snprintf(rlabel,BUFF_SIZE,"%s%d",res->GetName().c_str(), res->GetNum()); snprintf(rnum,BUFF_SIZE,"%d",res->GetNum()); } snprintf(buffer,BUFF_SIZE,"%7d%1s%-6s%12.4f%10.4f%10.4f%1s%-5s%4s%1s %-8s%10.4f", atom->GetIdx(),"",label, atom->GetX(),atom->GetY(),atom->GetZ(), "",str1.c_str(), rnum,"",rlabel, atom->GetPartialCharge()); ofs << buffer << endl; } ofs << "@<TRIPOS>BOND" << endl; OBBond *bond; vector<OBBond*>::iterator j; OBSmartsPattern pat; string s1, s2; for (bond = mol.BeginBond(j);bond;bond = mol.NextBond(j)) { s1 = bond->GetBeginAtom()->GetType(); s2 = bond->GetEndAtom()->GetType(); if (bond->IsAromatic() || s1 == "O.co2" || s2 == "O.co2") strcpy(label,"ar"); else if (bond->IsAmide()) strcpy(label,"am"); else snprintf(label,BUFF_SIZE,"%d",bond->GetBO()); snprintf(buffer, BUFF_SIZE,"%6d%6d%6d%3s%2s", bond->GetIdx()+1,bond->GetBeginAtomIdx(),bond->GetEndAtomIdx(), "",label); ofs << buffer << endl; } // NO trailing blank line (PR#1868929). // ofs << endl; return(true); }
bool AlchemyFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv) { OBMol* pmol = dynamic_cast<OBMol*>(pOb); if(pmol==NULL) return false; //Define some references so we can use the old parameter names ostream &ofs = *pConv->GetOutStream(); OBMol &mol = *pmol; unsigned int i; char buffer[BUFF_SIZE]; char bond_string[10]; snprintf(buffer, BUFF_SIZE, "%5d ATOMS, %5d BONDS, 0 CHARGES", mol.NumAtoms(), mol.NumBonds()); ofs << buffer << endl; OBAtom *atom; string str,str1; for(i = 1;i <= mol.NumAtoms(); i++) { atom = mol.GetAtom(i); str = atom->GetType(); ttab.SetFromType("INT"); ttab.SetToType("ALC"); ttab.Translate(str1,str); snprintf(buffer, BUFF_SIZE, "%5d %-6s%8.4f %8.4f %8.4f 0.0000", i, (char*)str1.c_str(), atom->GetX(), atom->GetY(), atom->GetZ()); ofs << buffer << endl; } OBBond *bond; vector<OBBond*>::iterator j; for (bond = mol.BeginBond(j);bond;bond = mol.NextBond(j)) { switch(bond->GetBO()) { case 1 : strcpy(bond_string,"SINGLE"); break; case 2 : strcpy(bond_string,"DOUBLE"); break; case 3 : strcpy(bond_string,"TRIPLE"); break; case 5 : strcpy(bond_string,"AROMATIC"); break; default : strcpy(bond_string,"SINGLE"); } snprintf(buffer, BUFF_SIZE, "%5d %4d %4d %s", bond->GetIdx()+1, bond->GetBeginAtomIdx(), bond->GetEndAtomIdx(), bond_string); ofs << buffer << endl; } return(true); }
/** * \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) }