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; }
void GenerateRingReference() { std::ifstream ifs; if (!SafeOpen(ifs,"attype.00.smi")) return; std::ofstream ofs; if (!SafeOpen(ofs,"ringresults.txt")) return; int count; OBAtom *atom; OBBond *bond; char buffer[BUFF_SIZE]; vector<OBRing*> vr; vector<OBEdgeBase*>::iterator i; vector<OBNodeBase*>::iterator j; vector<OBRing*>::iterator k; OBMol mol(SMI,SMI); OBFileFormat ff; for (;ifs;) { mol.Clear(); ff.ReadMolecule(ifs, mol); if (mol.Empty()) continue; //write out ring bonds for (bond = mol.BeginBond(i);bond;bond = mol.NextBond(i)) if (bond->IsInRing()) { sprintf(buffer,"%3d",bond->GetIdx()); ofs << buffer; } ofs << endl; vr = mol.GetSSSR(); //write the total number of rings ofs << vr.size() << endl; //write the number of rings that each atom is a member of for (atom = mol.BeginAtom(j);atom;atom = mol.NextAtom(j)) { count = 0; for (k = vr.begin();k != vr.end();k++) if ((*k)->_pathset[atom->GetIdx()]) count++; sprintf(buffer,"%3d",count); ofs << buffer; } ofs << endl; } ThrowError("Ring perception test results written successfully"); }
bool MacroModFormat::ReadMolecule(OBBase* pOb, OBConversion* pConv) { OBMol* pmol = pOb->CastAndClear<OBMol>(); if(pmol==NULL) return false; //Define some references so we can use the old parameter names istream &ifs = *pConv->GetInStream(); OBMol &mol = *pmol; const char* defaultTitle = pConv->GetTitle(); // Get Title char buffer[BUFF_SIZE]; int natoms; vector<vector<pair<int,int> > > connections; if (ifs.getline(buffer,BUFF_SIZE)) { vector<string> vs; tokenize(vs,buffer," \n"); if ( !vs.empty() && vs.size() > 0) sscanf(buffer,"%i%*s",&natoms); if (natoms == 0) return false; if ( !vs.empty() && vs.size() > 1) mol.SetTitle(vs[1]); else { string s = defaultTitle; mol.SetTitle(defaultTitle); } } else return(false); mol.BeginModify(); mol.ReserveAtoms(natoms); connections.resize(natoms+1); /***********************************************************************/ // Get Type Bonds, BondOrder, X, Y, Z double x,y,z; vector3 v; char temp_type[10]; int i,j; double charge; OBAtom atom; ttab.SetFromType("MMD"); for (i = 1; i <= natoms; i++) { if (!ifs.getline(buffer,BUFF_SIZE)) break; int end[6], order[6]; sscanf(buffer,"%9s%d%d%d%d%d%d%d%d%d%d%d%d%lf%lf%lf", temp_type,&end[0],&order[0],&end[1],&order[1],&end[2],&order[2], &end[3], &order[3], &end[4], &order[4], &end[5], &order[5], &x, &y, &z); pair<int,int> tmp; for ( j = 0 ; j <=5 ; j++ ) { if ( end[j] > 0 && end[j] > i) { tmp.first = end[j]; tmp.second = order[j]; connections[i].push_back(tmp); } } v.SetX(x); v.SetY(y); v.SetZ(z); atom.SetVector(v); string str = temp_type,str1; ttab.SetToType("ATN"); ttab.Translate(str1,str); atom.SetAtomicNum(atoi(str1.c_str())); ttab.SetToType("INT"); ttab.Translate(str1,str); atom.SetType(str1); // stuff for optional fields buffer[109]='\0'; sscanf(&buffer[101],"%lf", &charge); atom.SetPartialCharge(charge); mol.AddAtom(atom); } for (i = 1; i <= natoms; i++) for (j = 0; j < (signed)connections[i].size(); j++) mol.AddBond(i, connections[i][j].first, connections[i][j].second); mol.EndModify(); OBBond *bond; vector<OBBond*>::iterator bi; for (bond = mol.BeginBond(bi);bond;bond = mol.NextBond(bi)) if (bond->GetBO() == 5 && !bond->IsInRing()) bond->SetBO(1); if ( natoms != (signed)mol.NumAtoms() ) return(false); // clean out remaining blank lines while(ifs.peek() != EOF && ifs.good() && (ifs.peek() == '\n' || ifs.peek() == '\r')) ifs.getline(buffer,BUFF_SIZE); return(true); }
void ring_test() { ostringstream os; #ifdef TESTDATADIR string testdatadir = TESTDATADIR; string results_file = testdatadir + "ringresults.txt"; string smilestypes_file = testdatadir + "attype.00.smi"; #else string results_file = "files/ringresults.txt"; string smilestypes_file = "files/attype.00.smi"; #endif cout << "# Testing ring perception..." << endl; std::ifstream mifs; os << "Bail out! Cannot read test data " << smilestypes_file.c_str(); BOOST_REQUIRE_MESSAGE( SafeOpen(mifs, smilestypes_file.c_str()), os.str().c_str() ); std::ifstream rifs; os.str(""); os << "Bail out! Cannot read test data " << results_file.c_str(); BOOST_REQUIRE_MESSAGE( SafeOpen(rifs, results_file.c_str()), os.str().c_str() ); unsigned int size; OBBond *bond; OBAtom *atom; int count; char buffer[BUFF_SIZE]; vector<string> vs; vector<OBRing*> vr; vector<bool> vb; vector<int> vi; OBMol mol; vector<string>::iterator i; vector<OBBond*>::iterator j; vector<OBAtom*>::iterator k; vector<OBRing*>::iterator m; OBConversion conv(&mifs, &cout); unsigned int currentTest = 0; BOOST_REQUIRE_MESSAGE( conv.SetInAndOutFormats("SMI","SMI"), "Bail out! SMILES format is not loaded" ); for (;mifs;) { mol.Clear(); conv.Read(&mol); if (mol.Empty()) continue; BOOST_REQUIRE_MESSAGE( rifs.getline(buffer,BUFF_SIZE), "Bail out! error reading reference data" ); vb.clear(); vb.resize(mol.NumBonds(),false); //check ring bonds tokenize(vs,buffer); for (i = vs.begin();i != vs.end();i++) vb[atoi(i->c_str())] = true; for (bond = mol.BeginBond(j);bond;bond = mol.NextBond(j)) { os.str(""); os << "ring bond data different than reference # Molecule: " << mol.GetTitle(); BOOST_CHECK_MESSAGE( vb[bond->GetIdx()] == bond->IsInRing(), os.str().c_str() ); } vr = mol.GetSSSR(); BOOST_REQUIRE_MESSAGE( rifs.getline(buffer,BUFF_SIZE), "Bail out! error reading reference data" ); sscanf(buffer,"%d",&size); os.str(""); os << "SSSR size different than reference # Molecule: " << mol.GetTitle(); BOOST_CHECK_MESSAGE( vr.size() == size, os.str().c_str() ); //check SSSR size BOOST_REQUIRE_MESSAGE( rifs.getline(buffer,BUFF_SIZE), "Bail out! error reading reference data" ); tokenize(vs,buffer); i = vs.begin(); for (atom = mol.BeginAtom(k);atom;atom = mol.NextAtom(k)) { os.str(""); os << "error in SSSR count # Molecule: " << mol.GetTitle(); BOOST_CHECK_MESSAGE( i != vs.end(), os.str().c_str() ); //check SSSR size count = 0; for (m = vr.begin();m != vr.end();m++) if ((*m)->_pathset[atom->GetIdx()]) count++; os.str(""); os << "ring membership test failed # Molecule: " << mol.GetTitle(); BOOST_CHECK_MESSAGE( atoi(i->c_str()) == count, os.str().c_str() ); i++; } } }
int main(int argc,char *argv[]) { // turn off slow sync with C-style output (we don't use it anyway). std::ios::sync_with_stdio(false); OBConversion conv; OBFormat *inFormat, *canFormat; OBMol mol; ifstream ifs; vector<OBMol> fragments; unsigned int fragmentCount = 0; // track how many in library -- give a running count map<string, int> index; // index of cansmi string currentCAN; unsigned int size; OBAtom *atom; OBBond *bond; bool nonRingAtoms, nonRingBonds; char buffer[BUFF_SIZE]; canFormat = conv.FindFormat("can"); conv.SetOutFormat(canFormat); if (argc < 2) { cout << "Usage: obfragment <file>" << endl; return(-1); } for (int i = 1; i < argc; i++) { cerr << " Reading file " << argv[i] << endl; inFormat = conv.FormatFromExt(argv[i]); if(inFormat==NULL || !conv.SetInFormat(inFormat)) { cerr << " Cannot read file format for " << argv[i] << endl; continue; // try next file } ifs.open(argv[i]); if (!ifs) { cerr << "Cannot read input file: " << argv[i] << endl; continue; } while(ifs.peek() != EOF && ifs.good()) { conv.Read(&mol, &ifs); if (!mol.Has3D()) continue; // invalid coordinates! mol.DeleteHydrogens(); // remove these before we do anything else do { nonRingAtoms = false; size = mol.NumAtoms(); for (unsigned int i = 1; i <= size; ++i) { atom = mol.GetAtom(i); if (!atom->IsInRing()) { mol.DeleteAtom(atom); nonRingAtoms = true; break; // don't know how many atoms there are } // Previously, we changed atoms to carbon here. // Now we perform this alchemy in terms of string-rewriting // once the canonical SMILES is generated } } while (nonRingAtoms); if (mol.NumAtoms() < 3) continue; if (mol.NumBonds() == 0) continue; do { nonRingBonds = false; size = mol.NumBonds(); for (unsigned int i = 0; i < size; ++i) { bond = mol.GetBond(i); if (!bond->IsInRing()) { mol.DeleteBond(bond); nonRingBonds = true; break; // don't know how many bonds there are } } } while (nonRingBonds); fragments = mol.Separate(); for (unsigned int i = 0; i < fragments.size(); ++i) { if (fragments[i].NumAtoms() < 3) // too small to care continue; currentCAN = conv.WriteString(&fragments[i], true); currentCAN = RewriteSMILES(currentCAN); // change elements to "a/A" for compression if (index.find(currentCAN) != index.end()) { // already got this index[currentCAN] += 1; // add to the count for bookkeeping continue; } index[currentCAN] = 1; // don't ever write this ring fragment again // OK, now retrieve the canonical ordering for the fragment vector<string> canonical_order; if (fragments[i].HasData("Canonical Atom Order")) { OBPairData *data = (OBPairData*)fragments[i].GetData("Canonical Atom Order"); tokenize(canonical_order, data->GetValue().c_str()); } // Write out an XYZ-style file with the CANSMI as the title cout << fragments[i].NumAtoms() << '\n'; cout << currentCAN << '\n'; // endl causes a flush vector<string>::iterator can_iter; unsigned int order; OBAtom *atom; fragments[i].Center(); fragments[i].ToInertialFrame(); for (unsigned int index = 0; index < canonical_order.size(); ++index) { order = atoi(canonical_order[index].c_str()); atom = fragments[i].GetAtom(order); snprintf(buffer, BUFF_SIZE, "C%8.3f%8.3f%8.3f\n", atom->x(), atom->y(), atom->z()); cout << buffer; } } fragments.clear(); if (index.size() > fragmentCount) { fragmentCount = index.size(); cerr << " Fragments: " << fragmentCount << endl; } } // while reading molecules (in this file) ifs.close(); ifs.clear(); } // while reading files // loop through the map and output frequencies map<string, int>::const_iterator indexItr; for (indexItr = index.begin(); indexItr != index.end(); ++indexItr) { cerr << (*indexItr).second << " INDEX " << (*indexItr).first << "\n"; } return(0); }
bool OBDepict::DrawMolecule(OBMol *mol) { if (!d->painter) return false; d->mol = mol; double width=0.0, height=0.0; OBAtom *atom; OBBondIterator j; OBAtomIterator i; if(mol->NumAtoms()>0) { // scale bond lengths double bondLengthSum = 0.0; for (OBBond *bond = mol->BeginBond(j); bond; bond = mol->NextBond(j)) bondLengthSum += bond->GetLength(); const double averageBondLength = bondLengthSum / mol->NumBonds(); const double f = mol->NumBonds() ? d->bondLength / averageBondLength : 1.0; for (atom = mol->BeginAtom(i); atom; atom = mol->NextAtom(i)) atom->SetVector(atom->GetX() * f, atom->GetY() * f, 0.0); // find min/max values double min_x, max_x; double min_y, max_y; atom = mol->BeginAtom(i); min_x = max_x = atom->GetX(); min_y = max_y = atom->GetY(); for (atom = mol->NextAtom(i); atom; atom = mol->NextAtom(i)) { min_x = std::min(min_x, atom->GetX()); max_x = std::max(max_x, atom->GetX()); min_y = std::min(min_y, atom->GetY()); max_y = std::max(max_y, atom->GetY()); } const double margin = 40.0; // translate all atoms so the bottom-left atom is at margin,margin for (atom = mol->BeginAtom(i); atom; atom = mol->NextAtom(i)) atom->SetVector(atom->GetX() - min_x + margin, atom->GetY() - min_y + margin, 0.0); width = max_x - min_x + 2*margin; height = max_y - min_y + 2*margin; //d->painter->SetPenWidth(d->penWidth); //d->painter->SetPenColor(d->pen)); //d->painter->SetFillColor(OBColor("black")); } d->painter->NewCanvas(width, height); // draw bonds if(d->options & genWedgeHash) d->SetWedgeAndHash(mol); for (OBBond *bond = mol->BeginBond(j); bond; bond = mol->NextBond(j)) { OBAtom *begin = bond->GetBeginAtom(); OBAtom *end = bond->GetEndAtom(); if((d->options & internalColor) && bond->HasData("color")) d->painter->SetPenColor(OBColor(bond->GetData("color")->GetValue())); else d->painter->SetPenColor(d->bondColor); if (bond->IsWedge()) { d->DrawWedge(begin, end); } else if (bond->IsHash()) { d->DrawHash(begin, end); } else if (!bond->IsInRing()) { d->DrawSimpleBond(begin, end, bond->GetBO()); } } // draw ring bonds std::vector<OBRing*> rings(mol->GetSSSR()); OBBitVec drawnBonds; for (std::vector<OBRing*>::iterator k = rings.begin(); k != rings.end(); ++k) { OBRing *ring = *k; std::vector<int> indexes = ring->_path; vector3 center(VZero); for (std::vector<int>::iterator l = indexes.begin(); l != indexes.end(); ++l) { center += mol->GetAtom(*l)->GetVector(); } center /= indexes.size(); for (unsigned int l = 0; l < indexes.size(); ++l) { OBAtom *begin = mol->GetAtom(indexes[l]); OBAtom *end; if (l+1 < indexes.size()) end = mol->GetAtom(indexes[l+1]); else end = mol->GetAtom(indexes[0]); OBBond *ringBond = mol->GetBond(begin, end); if (drawnBonds.BitIsSet(ringBond->GetId())) continue; if((d->options & internalColor) && ringBond->HasData("color")) d->painter->SetPenColor(OBColor(ringBond->GetData("color")->GetValue())); else d->painter->SetPenColor(d->bondColor); d->DrawRingBond(begin, end, center, ringBond->GetBO()); drawnBonds.SetBitOn(ringBond->GetId()); } } // draw atom labels for (atom = mol->BeginAtom(i); atom; atom = mol->NextAtom(i)) { double x = atom->GetX(); double y = atom->GetY(); int alignment = GetLabelAlignment(atom); bool rightAligned = false; switch (alignment) { case TopRight: case CenterRight: case BottomRight: rightAligned = true; default: break; } if((d->options & internalColor) && atom->HasData("color")) d->painter->SetPenColor(OBColor(atom->GetData("color")->GetValue())); else if(d->options & bwAtoms) d->painter->SetPenColor(d->bondColor); else d->painter->SetPenColor(OBColor(etab.GetRGB(atom->GetAtomicNum()))); //charge and radical int charge = atom->GetFormalCharge(); int spin = atom->GetSpinMultiplicity(); if(charge || spin) { OBFontMetrics metrics = d->painter->GetFontMetrics("N"); double yoffset = d->HasLabel(atom) ? 0.4 * metrics.height : 0.0; switch (GetLabelAlignment(atom)) { case TopCenter: case TopRight: case TopLeft: case CenterLeft: case CenterRight: yoffset = - 1.2 * metrics.height; } stringstream ss; if(charge) { if(abs(charge)!=1) ss << abs(charge); ss << (charge>0 ? "+" : "-") ; } if(spin) { ss << (spin==2 ? "." : ".."); yoffset += 0.5 * metrics.height; } if(spin || charge<0) d->painter->SetFontSize(2 * metrics.fontSize); d->painter->DrawText(x-0.4*metrics.width, y-yoffset, ss.str()); d->painter->SetFontSize(metrics.fontSize);//restore } if (atom->IsCarbon()) { if(!(d->options & drawAllC)) { if (atom->GetValence() > 1) continue; if ((atom->GetValence() == 1) && !(d->options & drawTermC))//!d->drawTerminalC) continue; } } stringstream ss; AliasData* ad = NULL; if(d->aliasMode && atom->HasData(AliasDataType)) ad = static_cast<AliasData*>(atom->GetData(AliasDataType)); //For unexpanded aliases use appropriate form of alias instead of element symbol, Hs, etc if(ad && !ad->IsExpanded()) { ss <<ad->GetAlias(rightAligned); OBColor aliasColor = !ad->GetColor().empty() ? ad->GetColor() : d->bondColor; d->painter->SetPenColor(aliasColor); } else { const char* atomSymbol; if(atom->IsHydrogen() && atom->GetIsotope()>1) atomSymbol = atom->GetIsotope()==2 ? "D" : "T"; else atomSymbol = etab.GetSymbol(atom->GetAtomicNum()); unsigned int hCount = atom->ImplicitHydrogenCount(); // rightAligned: // false CH3 // true H3C if (hCount && rightAligned) ss << "H"; if ((hCount > 1) && rightAligned) ss << hCount; ss << atomSymbol; if (hCount && !rightAligned) ss << "H"; if ((hCount > 1) && !rightAligned) ss << hCount; } d->DrawAtomLabel(ss.str(), alignment, vector3(x, y, 0.0)); } return true; }
int main(int argc,char *argv[]) { if (argc != 1) { if (strncmp(argv[1], "-g", 2)) { cout << "Usage: ringtest" << endl; cout << " Tests Open Babel ring perception testing." << endl; return 0; } else { GenerateRingReference(); return 0; } } cout << endl << "Testing RINGS..." << endl; #ifdef TESTDATADIR string testdatadir = TESTDATADIR; string results_file = testdatadir + "ringresults.txt"; string smilestypes_file = testdatadir + "attype.00.smi"; #else string results_file = "ringresults.txt"; string smilestypes_file = "attype.00.smi"; #endif std::ifstream mifs; if (!SafeOpen(mifs, (char*)smilestypes_file.c_str())) { return -1; // test failed } std::ifstream rifs; if (!SafeOpen(rifs, (char*)results_file.c_str())) { return -1; // test failed } unsigned int size; OBBond *bond; OBAtom *atom; int count; char buffer[BUFF_SIZE]; vector<string> vs; vector<OBRing*> vr; vector<bool> vb; vector<int> vi; OBMol mol(SMI,SMI); vector<string>::iterator i; vector<OBEdgeBase*>::iterator j; vector<OBNodeBase*>::iterator k; vector<OBRing*>::iterator m; OBFileFormat ff; for (;mifs;) { mol.Clear(); ff.ReadMolecule(mifs, mol); if (mol.Empty()) continue; if (!rifs.getline(buffer,BUFF_SIZE)) { ThrowError("error reading reference data"); return -1; // test failed } vb.clear(); vb.resize(mol.NumBonds(),false); //check ring bonds tokenize(vs,buffer); for (i = vs.begin();i != vs.end();i++) vb[atoi((char*)i->c_str())] = true; for (bond = mol.BeginBond(j);bond;bond = mol.NextBond(j)) if (vb[bond->GetIdx()] != bond->IsInRing()) { ThrowError("ring bond data different than reference"); ThrowError((char*)mol.GetTitle()); return -1; // test failed } vr = mol.GetSSSR(); if (!rifs.getline(buffer,BUFF_SIZE)) { ThrowError("error reading reference data"); return -1; // test failed } sscanf(buffer,"%d",&size); if (vr.size() != size) //check SSSR size { ThrowError("SSSR size different than reference"); ThrowError((char*)mol.GetTitle()); return -1; // test failed } if (!rifs.getline(buffer,BUFF_SIZE)) { ThrowError("error reading reference data"); return -1; // test failed } tokenize(vs,buffer); i = vs.begin(); for (atom = mol.BeginAtom(k);atom;atom = mol.NextAtom(k)) { if (i == vs.end()) { ThrowError("Error in SSSR count"); ThrowError((char*)mol.GetTitle()); return -1; // test failed } count = 0; for (m = vr.begin();m != vr.end();m++) if ((*m)->_pathset[atom->GetIdx()]) count++; if (atoi((char*)i->c_str()) != count) { ThrowError("Ring membership test failed"); ThrowError((char*)mol.GetTitle()); return -1; // test failed } i++; } } // Passed tests return 0; }