OBMolPairIter::OBMolPairIter(OBMol &mol) { _parent = &mol; bool foundPair = false; OBAtom *a = _parent->BeginAtom(_i); if (!a) return; OBAtom *b = _parent->BeginAtom(_j); while (!foundPair) { b = _parent->NextAtom(_j); if (!b) { a = _parent->NextAtom(_i); if (!a) return; b = _parent->BeginAtom(_j); } if (a->GetIdx() >= b->GetIdx()) continue; if (a->IsConnected(b)) continue; if (a->IsOneThree(b)) continue; foundPair = true; } _pair.clear(); _pair.push_back(a->GetIdx()); _pair.push_back(b->GetIdx()); }
OBMolAtomDFSIter& OBMolAtomDFSIter::operator++() { if (!_stack.empty()) { _ptr = _stack.top(); _stack.pop(); } else // are there any disconnected subgraphs? { int next = _notVisited.FirstBit(); if (next != _notVisited.EndBit()) { _ptr = _parent->GetAtom(next + 1); _notVisited.SetBitOff(next); } else _ptr = NULL; } if (_ptr) { vector<OBBond*>::iterator i; OBAtom *a; for (a = _ptr->BeginNbrAtom(i); a; a = _ptr->NextNbrAtom(i)) if (_notVisited[a->GetIdx() - 1]) { _stack.push(a); _notVisited.SetBitOff(a->GetIdx() - 1); } } return *this; }
// Seems to make a vector chirality become filled with array of +/- 1 for chiral atoms. void GetChirality(OBMol &mol, std::vector<int> &chirality) { chirality.resize(mol.NumAtoms()+1); fill(chirality.begin(),chirality.end(),0); OBAtom *atom; vector<OBAtom*>::iterator i; for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i)) if (atom->IsChiral()) { if (!atom->HasChiralVolume()) { double sv = CalcSignedVolume(mol,atom); if (sv < 0.0) { chirality[atom->GetIdx()-1] = -1; atom->SetNegativeStereo(); } else if (sv > 0.0) { chirality[atom->GetIdx()-1] = 1; atom->SetPositiveStereo(); } } else // already calculated signed volume (e.g., imported from somewhere) { if (atom ->IsPositiveStereo()) chirality[atom->GetIdx()-1] = 1; else chirality[atom->GetIdx()-1] = -1; } } }
bool WriteGromos96(ostream &ofs,OBMol &mol,double fac) { char type_name[10]; char res_name[10],padded_name[10]; char buffer[BUFF_SIZE]; int res_num; sprintf(buffer,"#GENERATED BY OPEN BABEL %s",BABEL_VERSION); ofs << buffer << endl; /* GROMOS wants a TITLE block, so let's write one*/ sprintf(buffer,"TITLE\n%s\nEND",mol.GetTitle()); ofs << buffer << endl; ofs << "POSITION" << endl; OBAtom *atom; OBResidue *res; vector<OBNodeBase*>::iterator i; for(atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i)) { if (res = atom->GetResidue()) { strcpy(res_name,(char*)res->GetName().c_str()); strcpy(type_name,(char*)res->GetAtomID(atom).c_str()); res_num = res->GetNum(); } else { strcpy(type_name,etab.GetSymbol(atom->GetAtomicNum())); strcpy(res_name,"UNK"); sprintf(padded_name,"%2s",type_name); strcpy(type_name,padded_name); res_num = 1; } sprintf(buffer,"%5d %5s %5s %6d %15.5f %15.5f %15.5f", res_num,res_name,type_name,atom->GetIdx(), atom->x()*fac,atom->y()*fac,atom->z()*fac); ofs << buffer << endl; if (!(atom->GetIdx()%10)) { sprintf(buffer,"# %d",atom->GetIdx()); ofs << buffer << endl; } } ofs << "END" << endl; return(true); }
bool OBDepict::AddAtomLabels(AtomLabelType type) { d->painter->SetPenColor(OBColor("red")); d->painter->SetFillColor(OBColor("red")); d->painter->SetFontSize((int)(GetFontSize() * 0.8));// smaller text OBAtomIterator i; for (OBAtom *atom = d->mol->BeginAtom(i); atom; atom = d->mol->NextAtom(i)) { vector3 pos(atom->GetVector()); std::stringstream ss; switch (type) { case AtomId: ss << atom->GetId(); d->painter->DrawText(pos.x(), pos.y(), ss.str()); break; case AtomSymmetryClass: ss << GetAtomSymClass(atom); d->painter->DrawText(pos.x(), pos.y(), ss.str()); break; case AtomIndex: ss << atom->GetIdx(); d->painter->DrawText(pos.x(), pos.y(), ss.str()); break; default: break; } } return true; }
void fingerprint2::getFragments(vector<int> levels, vector<int> curfrag, int level, OBAtom* patom, OBBond* pbond) { //Recursive routine to analyse schemical structure and populate fragset and ringset //Hydrogens,charges(except dative bonds), spinMultiplicity ignored const int Max_Fragment_Size = 7; int bo=0; if(pbond) { bo = pbond->IsAromatic() ? 5 : pbond->GetBO(); // OBAtom* pprevat = pbond->GetNbrAtom(patom); // if(patom->GetFormalCharge() && (patom->GetFormalCharge() == -pprevat->GetFormalCharge())) // ++bo; //coordinate (dative) bond eg C[N+]([O-])=O is seen as CN(=O)=O } curfrag.push_back(bo); curfrag.push_back(patom->GetAtomicNum()); levels[patom->GetIdx()-1] = level; vector<OBEdgeBase*>::iterator itr; OBBond *pnewbond; // PrintFpt(curfrag,(int)patom); for (pnewbond = patom->BeginBond(itr);pnewbond;pnewbond = patom->NextBond(itr)) { if(pnewbond==pbond) continue; //don't retrace steps OBAtom* pnxtat = pnewbond->GetNbrAtom(patom); if(pnxtat->GetAtomicNum() == OBElements::Hydrogen) continue; int atlevel = levels[pnxtat->GetIdx()-1]; if(atlevel) //ring { if(atlevel==1) { //If complete ring (last bond is back to starting atom) add bond at front //and save in ringset curfrag[0] = pnewbond->IsAromatic() ? 5 : pnewbond->GetBO(); ringset.insert(curfrag); curfrag[0] = 0; } } else //no ring { if(level<Max_Fragment_Size) { // TRACE("level=%d size=%d %p frag[0]=%p\n",level, curfrag.size(),&curfrag, &(curfrag[0])); //Do the next atom; levels, curfrag are passed by value and hence copied getFragments(levels, curfrag, level+1, pnxtat, pnewbond); } } } //do not save C,N,O single atom fragments if(curfrag[0]==0 && (level>1 || patom->GetAtomicNum()>8 || patom->GetAtomicNum()<6)) { fragset.insert(curfrag); //curfrag ignored if an identical fragment already present // PrintFpt(curfrag,level); } }
bool BallStickFormat::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* title = pConv->GetTitle(); int i,natoms; char buffer[BUFF_SIZE]; if (!ifs.getline(buffer,BUFF_SIZE)) return(false); if (!ifs.getline(buffer,BUFF_SIZE)) return(false); sscanf(buffer,"%d",&natoms); mol.ReserveAtoms(natoms); mol.BeginModify(); double x,y,z; OBAtom *atom; vector<string> vs; vector<string>::iterator j; for (i = 1; i <= natoms;i ++) { if (!ifs.getline(buffer,BUFF_SIZE)) return(false); tokenize(vs,buffer); if (vs.size() < 4) return(false); if (vs[0].size() > 1) vs[0][1] = tolower(vs[0][1]); atom = mol.NewAtom(); x = atof((char*)vs[1].c_str()); y = atof((char*)vs[2].c_str()); z = atof((char*)vs[3].c_str()); atom->SetVector(x,y,z); //set coordinates atom->SetAtomicNum(etab.GetAtomicNum(vs[0].c_str())); for (j = vs.begin()+4;j != vs.end();j++) mol.AddBond(atom->GetIdx(),atoi((char*)j->c_str()),1); } // clean out any remaining blank lines while(ifs.peek() != EOF && ifs.good() && (ifs.peek() == '\n' || ifs.peek() == '\r')) ifs.getline(buffer,BUFF_SIZE); mol.EndModify(); mol.SetTitle(title); return(true); }
void OBAromaticTyper::PropagatePotentialAromatic(OBAtom *atom) { int count = 0; OBAtom *nbr; vector<OBBond*>::iterator i; for (nbr = atom->BeginNbrAtom(i);nbr;nbr = atom->NextNbrAtom(i)) if ((*i)->IsInRing() && _vpa[nbr->GetIdx()]) count++; if (count < 2) { _vpa[atom->GetIdx()] = false; if (count == 1) for (nbr = atom->BeginNbrAtom(i);nbr;nbr = atom->NextNbrAtom(i)) if ((*i)->IsInRing() && _vpa[nbr->GetIdx()]) PropagatePotentialAromatic(nbr); } }
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"); }
OBMolAtomBFSIter::OBMolAtomBFSIter(OBMol &mol, int StartIndex): _parent(&mol), _ptr(_parent->GetAtom(StartIndex)) { _notVisited.Resize(_parent->NumAtoms()); _notVisited.Negate(); // all on _notVisited.SetBitOff(_ptr->GetIdx() - 1); // Set up storage for the depths _depth.resize(_parent->NumAtoms() + 1, 0); _depth[_ptr->GetIdx()] = 1; vector<OBBond*>::iterator i; OBAtom *a; for (a = _ptr->BeginNbrAtom(i); a; a = _ptr->NextNbrAtom(i)) { _queue.push(a); _depth[a->GetIdx()] = 2; _notVisited.SetBitOff(a->GetIdx() - 1); } }
bool ChemDrawXMLFormat::EndElement(const string& name) { //unsigned int i; if(name=="n") { _pmol->AddAtom(_tempAtom); atoms[_tempAtom.GetIdx()] = _pmol->NumAtoms(); _tempAtom.Clear(); } else if(name=="b") { _pmol->AddBond(Begin, End, Order, Flag); Order = -1; } else if(name=="fragment") //this is the end of the molecule we are extracting { EnsureEndElement(); _pmol->EndModify(); // This alone will already store the "Formula" property in the molecule property block // The "Formula" is required for older ChemDraw generations allowing to match molecules to reaction properties string MolFormula=_pmol->GetFormula(); // additional adding of "Formula" property is not required, as described above //OBPairData *dp = new OBPairData; //dp->SetAttribute("MolecularFormula"); //dp->SetValue(MolFormula); //dp->SetOrigin(fileformatInput); //_pmol->SetData(dp); // alternative is using the molecular title, but a test is needed for preventing overwriting given titles, aka molecule ID //_pmol->SetTitle(MolFormula); atoms.clear(); return false;//means stop parsing } /* // Forget that, the fragment, aka molecule, is in another XML hierachy tree than the data. // Parsing has already stopped before ever getting to this point else if(name=="tags") { } else if(name=="tableCell") { //OBPairData *dp = new OBPairData; //dp->SetAttribute(attr); //dp->SetValue(buff); //dp->SetOrigin(fileformatInput); //mol.SetData(dp); }*/ return true; }
void BuildOBRTreeVector(OBAtom *atom,OBRTree *prv,vector<OBRTree*> &vt,OBBitVec &bv) { vt[atom->GetIdx()] = new OBRTree (atom,prv); int i; OBAtom *nbr; OBMol *mol = (OBMol*)atom->GetParent(); OBBitVec curr,used,next; vector<OBBond*>::iterator j; curr |= atom->GetIdx(); used = bv|curr; #define OB_RTREE_CUTOFF 20 int level=0; for (;;) { next.Clear(); for (i = curr.NextBit(0);i != bv.EndBit();i = curr.NextBit(i)) { atom = mol->GetAtom(i); for (nbr = atom->BeginNbrAtom(j);nbr;nbr = atom->NextNbrAtom(j)) if (!used[nbr->GetIdx()]) { next |= nbr->GetIdx(); used |= nbr->GetIdx(); vt[nbr->GetIdx()] = new OBRTree (nbr,vt[atom->GetIdx()]); } } if (next.Empty()) break; curr = next; level++; if (level > OB_RTREE_CUTOFF) break; } #undef OB_RTREE_CUTOFF }
void ChemDrawXMLFormat::EnsureEndElement(void) { if (_tempAtom.GetAtomicNum() != 0) { _pmol->AddAtom(_tempAtom); atoms[_tempAtom.GetIdx()] = _pmol->NumAtoms(); _tempAtom.Clear(); } else if (Order >= 0) { _pmol->AddBond(Begin, End, Order, Flag); Order = -1; } }
OBMolAtomBFSIter& OBMolAtomBFSIter::operator++() { if (!_queue.empty()) { _ptr = _queue.front(); _queue.pop(); } else // are there any disconnected subgraphs? { int next = _notVisited.FirstBit(); if (next != _notVisited.EndBit()) { _ptr = _parent->GetAtom(next + 1); // Atom index issue if (_ptr != NULL) _depth[_ptr->GetIdx()] = 1; // new island _notVisited.SetBitOff(next); } else _ptr = NULL; } if (_ptr) { vector<OBBond*>::iterator i; OBAtom *a; for (a = _ptr->BeginNbrAtom(i); a; a = _ptr->NextNbrAtom(i)) if (_notVisited[a->GetIdx() - 1]) { _queue.push(a); _depth[a->GetIdx()] = _depth[_ptr->GetIdx()] + 1; _notVisited.SetBitOff(a->GetIdx() - 1); } } return *this; }
OBMolAtomDFSIter::OBMolAtomDFSIter(OBMol &mol, int StartIndex): _parent(&mol), _ptr(_parent->GetAtom(StartIndex)) { _notVisited.Resize(_parent->NumAtoms()); _notVisited.Negate(); // all on _notVisited.SetBitOff(_ptr->GetIdx() - 1); vector<OBBond*>::iterator i; OBAtom *a; for (a = _ptr->BeginNbrAtom(i); a; a = _ptr->NextNbrAtom(i)) { _stack.push(a); _notVisited.SetBitOff(a->GetIdx() - 1); } }
OBMolAtomDFSIter::OBMolAtomDFSIter(OBMol *mol, int StartIndex): _parent(mol), _ptr(_parent->GetAtom(StartIndex)) { _notVisited.Resize(_parent->NumAtoms()); _notVisited.SetRangeOn(0, _parent->NumAtoms() - 1); if (!_ptr) return; _notVisited.SetBitOff(_ptr->GetIdx() - 1); vector<OBBond*>::iterator i; OBAtom *a; for (a = _ptr->BeginNbrAtom(i); a; a = _ptr->NextNbrAtom(i)) { _stack.push(a); _notVisited.SetBitOff(a->GetIdx() - 1); } }
/** \brief Traverse a potentially aromatic cycle starting at @p root. \return True if the cycle is likely aromatic \param root The initial, "root" atom in traversing this ring \param atom The current atom to visit and check \param prev The bond traversed in moving to this @p atom \param er The min and max number of pi electrons for this ring \param depth The maximum number of atoms to visit in a ring (e.g., 6) This method traverses a potentially aromatic ring, adding up the possible pi electrons for each atom. At the end (e.g., when @p atom == @p root) the Huekel 4n+2 rule is checked to see if there is a possible electronic configuration which corresponds to aromaticity. **/ bool OBAromaticTyper::TraverseCycle(OBAtom *root, OBAtom *atom, OBBond *prev, std::pair<int,int> &er,int depth) { if (atom == root) { int i; for (i = er.first;i <= er.second;++i) if (i%4 == 2 && i > 2) return(true); return(false); } if (!depth || !_vpa[atom->GetIdx()] || _visit[atom->GetIdx()]) return(false); bool result = false; depth--; er.first += _velec[atom->GetIdx()].first; er.second += _velec[atom->GetIdx()].second; _visit[atom->GetIdx()] = true; OBAtom *nbr; vector<OBBond*>::iterator i; for (nbr = atom->BeginNbrAtom(i);nbr;nbr = atom->NextNbrAtom(i)) if (*i != prev && (*i)->IsInRing() && _vpa[nbr->GetIdx()]) { if (TraverseCycle(root,nbr,(OBBond*)(*i),er,depth)) { result = true; ((OBBond*) *i)->SetAromatic(); } } _visit[atom->GetIdx()] = false; if (result) atom->SetAromatic(); er.first -= _velec[atom->GetIdx()].first; er.second -= _velec[atom->GetIdx()].second; return(result); }
void WriteChiral(ostream &ofs,OBMol &mol) { OBAtom *atom; vector<OBNodeBase*>::iterator i; char buffer[BUFF_SIZE]; for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i)) { if (atom->IsChiral()) { sprintf(buffer,"%4s %5d is chiral: %s", etab.GetSymbol(atom->GetAtomicNum()), atom->GetIdx(), (atom->IsClockwise() ? "clockwise" : "counterclockwise")); ofs << buffer << endl; } } }
//copy data needed to write out pmol from obmol void PMolCreator::copyFrom(OBMol& mol, bool deleteH) { static OBIsotopeTable isotable; name = mol.GetTitle(); //first construct atoms int typeindex[256]; //position in atoms vector of an atom type, indexed by atomic number int tmpatomindex[mol.NumAtoms()]; //position within the atom type vector memset(typeindex, -1, sizeof(typeindex)); memset(tmpatomindex, -1, sizeof(tmpatomindex)); for (OBAtomIterator aitr = mol.BeginAtoms(); aitr != mol.EndAtoms(); ++aitr) { OBAtom *atom = *aitr; unsigned int idx = atom->GetIdx(); unsigned anum = atom->GetAtomicNum(); assert(anum < 256); if(deleteH && anum == 1) continue; int pos = typeindex[anum]; if (pos < 0) // no vector for this type yet { pos = typeindex[anum] = atoms.size(); atoms.push_back(AtomGroup(anum)); } tmpatomindex[idx] = atoms[pos].coords.size(); atoms[pos].coords.push_back(FloatCoord(atom->x(), atom->y(), atom->z())); } //create mapping to actual atom index numAtoms = 0; BOOST_FOREACH(AtomGroup& ag, atoms) { ag.startIndex = numAtoms; numAtoms += ag.coords.size(); }
/* A recursive O(N) traversal of the molecule */ static int FindRings(OBAtom *atom, int *avisit, unsigned char *bvisit, unsigned int &frj, int depth) { OBBond *bond; int result = -1; vector<OBBond*>::iterator k; for(bond = atom->BeginBond(k);bond;bond=atom->NextBond(k)) { unsigned int bidx = bond->GetIdx(); if (bvisit[bidx] == 0) { bvisit[bidx] = 1; OBAtom *nbor = bond->GetNbrAtom(atom); unsigned int nidx = nbor->GetIdx(); int nvisit = avisit[nidx]; if (nvisit == 0) { avisit[nidx] = depth+1; nvisit = FindRings(nbor,avisit,bvisit,frj,depth+1); if (nvisit > 0) { if (nvisit <= depth) { bond->SetInRing(); if (result < 0 || nvisit < result) result = nvisit; } } } else { if (result < 0 || nvisit < result) result = nvisit; bond->SetClosure(); bond->SetInRing(); frj++; } } } if (result > 0 && result <= depth) atom->SetInRing(); return result; }
void OBAromaticTyper::AssignAromaticFlags(OBMol &mol) { if (!_init) Init(); if (mol.HasAromaticPerceived()) return; mol.SetAromaticPerceived(); obErrorLog.ThrowError(__FUNCTION__, "Ran OpenBabel::AssignAromaticFlags", obAuditMsg); _vpa.clear(); _vpa.resize(mol.NumAtoms()+1); _velec.clear(); _velec.resize(mol.NumAtoms()+1); _root.clear(); _root.resize(mol.NumAtoms()+1); OBBond *bond; OBAtom *atom; vector<OBAtom*>::iterator i; vector<OBBond*>::iterator j; //unset all aromatic flags for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i)) atom->UnsetAromatic(); for (bond = mol.BeginBond(j);bond;bond = mol.NextBond(j)) bond->UnsetAromatic(); int idx; vector<vector<int> >::iterator m; vector<OBSmartsPattern*>::iterator k; //mark atoms as potentially aromatic for (idx=0,k = _vsp.begin();k != _vsp.end();++k,++idx) if ((*k)->Match(mol)) { _mlist = (*k)->GetMapList(); for (m = _mlist.begin();m != _mlist.end();++m) { _vpa[(*m)[0]] = true; _velec[(*m)[0]] = _verange[idx]; } } //sanity check - exclude all 4 substituted atoms and sp centers for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i)) { if (atom->GetImplicitValence() > 3) { _vpa[atom->GetIdx()] = false; continue; } switch(atom->GetAtomicNum()) { //phosphorus and sulfur may be initially typed as sp3 case 6: case 7: case 8: if (atom->GetHyb() != 2) _vpa[atom->GetIdx()] = false; break; } } //propagate potentially aromatic atoms for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i)) if (_vpa[atom->GetIdx()]) PropagatePotentialAromatic(atom); //select root atoms SelectRootAtoms(mol); ExcludeSmallRing(mol); //remove 3 membered rings from consideration //loop over root atoms and look for aromatic rings _visit.clear(); _visit.resize(mol.NumAtoms()+1); for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i)) if (_root[atom->GetIdx()]) CheckAromaticity(atom,14); //for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i)) // if (atom->IsAromatic()) // cerr << "aro = " <<atom->GetIdx() << endl; //for (bond = mol.BeginBond(j);bond;bond = mol.NextBond(j)) //if (bond->IsAromatic()) //cerr << bond->GetIdx() << ' ' << bond->IsAromatic() << endl; }
bool PDBFormat::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 type_name[10], padded_name[10]; char the_res[10]; char the_chain = ' '; const char *element_name; int res_num; bool het=true; int model_num = 0; if (!pConv->IsLast() || pConv->GetOutputIndex() > 1) { // More than one molecule record model_num = pConv->GetOutputIndex(); // MODEL 1-based index snprintf(buffer, BUFF_SIZE, "MODEL %8d", model_num); ofs << buffer << endl; } if (strlen(mol.GetTitle()) > 0) snprintf(buffer, BUFF_SIZE, "COMPND %s ",mol.GetTitle()); else snprintf(buffer, BUFF_SIZE, "COMPND UNNAMED"); ofs << buffer << endl; snprintf(buffer, BUFF_SIZE, "AUTHOR GENERATED BY OPEN BABEL %s",BABEL_VERSION); ofs << buffer << endl; // Write CRYST1 record, containing unit cell parameters, space group // and Z value (supposed to be 1) if (pmol->HasData(OBGenericDataType::UnitCell)) { OBUnitCell *pUC = (OBUnitCell*)pmol->GetData(OBGenericDataType::UnitCell); snprintf(buffer, BUFF_SIZE, "CRYST1%9.3f%9.3f%9.3f%7.2f%7.2f%7.2f %-11s 1", pUC->GetA(), pUC->GetB(), pUC->GetC(), pUC->GetAlpha(), pUC->GetBeta(), pUC->GetGamma(), pUC->GetSpaceGroup() ? pUC->GetSpaceGroup()->GetHMName().c_str() : "P1"); ofs << buffer << endl; } // before we write any records, we should check to see if any coord < -1000 // which will cause errors in the formatting double minX, minY, minZ; minX = minY = minZ = -999.0f; FOR_ATOMS_OF_MOL(a, mol) { if (a->GetX() < minX) minX = a->GetX(); if (a->GetY() < minY) minY = a->GetY(); if (a->GetZ() < minZ) minZ = a->GetZ(); } vector3 transV = VZero; if (minX < -999.0) transV.SetX(-1.0*minX - 900.0); if (minY < -999.0) transV.SetY(-1.0*minY - 900.0); if (minZ < -999.0) transV.SetZ(-1.0*minZ - 900.0); // if minX, minY, or minZ was never changed, shift will be 0.0f // otherwise, move enough so that smallest coord is > -999.0f mol.Translate(transV); OBAtom *atom; OBResidue *res; for (i = 1; i <= mol.NumAtoms(); i++) { atom = mol.GetAtom(i); strncpy(type_name, etab.GetSymbol(atom->GetAtomicNum()), sizeof(type_name)); type_name[sizeof(type_name) - 1] = '\0'; //two char. elements are on position 13 and 14 one char. start at 14 if (strlen(type_name) > 1) type_name[1] = toupper(type_name[1]); else { char tmp[10]; strncpy(tmp, type_name, 10); snprintf(type_name, sizeof(type_name), " %-3s", tmp); } if ( (res = atom->GetResidue()) != 0 ) { het = res->IsHetAtom(atom); snprintf(the_res,4,"%s",(char*)res->GetName().c_str()); snprintf(type_name,5,"%s",(char*)res->GetAtomID(atom).c_str()); the_chain = res->GetChain(); //two char. elements are on position 13 and 14 one char. start at 14 if (strlen(etab.GetSymbol(atom->GetAtomicNum())) == 1) { if (strlen(type_name) < 4) { char tmp[16]; strncpy(tmp, type_name, 16); snprintf(padded_name, sizeof(padded_name), " %-3s", tmp); strncpy(type_name,padded_name,4); type_name[4] = '\0'; } else { /* type_name[4] = type_name[3]; type_name[3] = type_name[2]; type_name[2] = type_name[1]; type_name[1] = type_name[0]; type_name[0] = type_name[4]; */ type_name[4] = '\0'; } } res_num = res->GetNum(); } else { strcpy(the_res,"UNK"); snprintf(padded_name,sizeof(padded_name), "%s",type_name); strncpy(type_name,padded_name,4); type_name[4] = '\0'; res_num = 1; } element_name = etab.GetSymbol(atom->GetAtomicNum()); int charge = atom->GetFormalCharge(); char scharge[3] = { ' ', ' ', '\0' }; if(0 != charge) { snprintf(scharge, 3, "%+d", charge); char tmp = scharge[1]; scharge[1] = scharge[0]; scharge[0] = tmp; } snprintf(buffer, BUFF_SIZE, "%s%5d %-4s %-3s %c%4d %8.3f%8.3f%8.3f 1.00 0.00 %2s%2s\n", het?"HETATM":"ATOM ", i, type_name, the_res, the_chain, res_num, atom->GetX(), atom->GetY(), atom->GetZ(), element_name, scharge); ofs << buffer; } OBAtom *nbr; vector<OBBond*>::iterator k; for (i = 1; i <= mol.NumAtoms(); i ++) { atom = mol.GetAtom(i); if (atom->GetValence() == 0) continue; // no need to write a CONECT record -- no bonds snprintf(buffer, BUFF_SIZE, "CONECT%5d", i); ofs << buffer; // Write out up to 4 real bonds per line PR#1711154 unsigned int currentValence = 0; for (nbr = atom->BeginNbrAtom(k);nbr;nbr = atom->NextNbrAtom(k)) { unsigned int order = mol.GetBond(atom, nbr)->GetBondOrder(); unsigned int it_order = 0; for( it_order = 0; it_order < order; it_order++ ) { if (0 != currentValence && 0 == currentValence % 4) { // Add the trailing space to finish this record ofs << " \n"; // write the start of a new CONECT record snprintf(buffer, BUFF_SIZE, "CONECT%5d", i); ofs << buffer; } currentValence++; snprintf(buffer, BUFF_SIZE, "%5d", nbr->GetIdx()); ofs << buffer; } } // Add trailing spaces unsigned int remainingValence = currentValence % 4; if( 0 < remainingValence ) { for (int count = 0; count < (4 - remainingValence); count++) { snprintf(buffer, BUFF_SIZE, " "); ofs << buffer; } } ofs << " \n"; } snprintf(buffer, BUFF_SIZE, "MASTER 0 0 0 0 0 0 0 0 "); ofs << buffer; snprintf(buffer, BUFF_SIZE, "%4d 0 %4d 0\n",mol.NumAtoms(),mol.NumAtoms()); ofs << buffer; ofs << "END\n"; if (model_num) { ofs << "ENDMDL" << endl; } return(true); }
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); }
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++; } } }
bool ABINITFormat::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* title = pConv->GetTitle(); char buffer[BUFF_SIZE]; string str; vector<string> vs; OBAtom *atom; int natom=-1; vector<int> atomicNumbers, atomTypes; double x, y, z; vector<vector3> atomPositions; vector<double> energies; // Translation vectors (if present) // aka rprim vector3 translationVectors[3]; double acell[3]; // scale of lattice vectors int numTranslationVectors = 0; int symmetryCode = 0; mol.BeginModify(); while (ifs.getline(buffer,BUFF_SIZE)) { // tokens are listed in alphabetical order for code clarity if (strstr(buffer, "acell")) { tokenize(vs, buffer); if (vs.size() < 4) continue; // invalid line // acell= 7.6967369631E+00 7.6967369631E+00 7.6967369631E+00 for (int i = 0; i < 3; ++i) { acell[i] = atof(vs[i+1].c_str()); } } // Sometimes Cartesian has lower-case letter else if ((strstr(buffer, "artesian coordinates")) && (strstr(buffer, "(xcart)")) && (natom > -1) //be sure natom has already been read ) { double unit = BOHR_TO_ANGSTROM; if (strstr(buffer, "ngstrom")) unit = 1.0; // no conversion needed for (int i=0;i<natom;i++) { ifs.getline(buffer,BUFF_SIZE); tokenize(vs, buffer); if (vs.size() != 3) { obErrorLog.ThrowError (__FUNCTION__, "error while parsing coordinates of atoms", obWarning); return(false); } x = atof(vs[0].c_str()) * unit; y = atof(vs[1].c_str()) * unit; z = atof(vs[2].c_str()) * unit; atomPositions.push_back(vector3(x, y, z)); // get next line } } else if (strstr(buffer, "natom")) { tokenize(vs, buffer); if (vs.size() != 2) continue; natom = atoi(vs[1].c_str()); } else if (strstr(buffer, "rprim")) { numTranslationVectors = 0; int column; for (int i = 0; i < 3; ++i) { tokenize(vs, buffer); if (vs.size() < 3) break; // first line, rprim takes up a token if (i == 0) column = 1; else column = 0; x = atof((char*)vs[column].c_str()) * BOHR_TO_ANGSTROM; y = atof((char*)vs[column+1].c_str()) * BOHR_TO_ANGSTROM; z = atof((char*)vs[column+2].c_str()) * BOHR_TO_ANGSTROM; translationVectors[numTranslationVectors++].Set(x, y,z); ifs.getline(buffer,BUFF_SIZE); } } else if (strstr(buffer, "Symmetries")) { tokenize(vs, buffer, "()"); // Should be something like (#160) symmetryCode = atoi(vs[1].substr(1).c_str()); } else if (strstr(buffer, "typat")) { tokenize(vs, buffer); atomTypes.clear(); for (unsigned int i = 1; i < vs.size(); ++i) { atomTypes.push_back(atoi(vs[i].c_str())); } } else if (strstr(buffer, "znucl")) { tokenize(vs, buffer); // make sure znucl is first token if (vs[0] != "znucl") continue; // push back the remaining tokens into atomicNumbers atomicNumbers.clear(); atomicNumbers.push_back(0); // abinit starts typat with 1 for (unsigned int i = 1; i < vs.size(); ++i) atomicNumbers.push_back(int(atof(vs[i].c_str()))); } // xangst // forces } for (int i = 0; i < natom; ++i) { atom = mol.NewAtom(); //set atomic number int idx = atom->GetIdx(); int type = atomTypes[idx - 1]; atom->SetAtomicNum(atomicNumbers[type]); // we set the coordinates by conformers in another loop } mol.EndModify(); int numConformers = atomPositions.size() / natom; for (int i = 0; i < numConformers; ++i) { double *coordinates = new double[natom * 3]; for (int j = 0; j < natom; ++j) { vector3 currentPosition = atomPositions[i*natom + j]; coordinates[j*3] = currentPosition.x(); coordinates[j*3 + 1] = currentPosition.y(); coordinates[j*3 + 2] = currentPosition.z(); } mol.AddConformer(coordinates); } // Delete first conformer, created by EndModify, bunch of 0s mol.DeleteConformer(0); // Set geometry to last one mol.SetConformer(mol.NumConformers() - 1); if (!pConv->IsOption("b",OBConversion::INOPTIONS)) mol.ConnectTheDots(); if (!pConv->IsOption("s",OBConversion::INOPTIONS) && !pConv->IsOption("b",OBConversion::INOPTIONS)) mol.PerceiveBondOrders(); // Attach unit cell translation vectors if found if (numTranslationVectors > 0) { OBUnitCell* uc = new OBUnitCell; uc->SetData(acell[0] * translationVectors[0], acell[1] * translationVectors[1], acell[2] * translationVectors[2]); uc->SetOrigin(fileformatInput); if (symmetryCode) uc->SetSpaceGroup(symmetryCode); mol.SetData(uc); } mol.SetTitle(title); return(true); }
bool GROMOS96Format::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; double fac = pConv->IsOption("n") ? 0.1 : 1.0; //new framework char type_name[16]; char res_name[16]; char buffer[BUFF_SIZE]; string res_num; snprintf(buffer, BUFF_SIZE, "#GENERATED BY OPEN BABEL %s\n",BABEL_VERSION); ofs << buffer; /* GROMOS wants a TITLE block, so let's write one*/ ofs << "TITLE\n" << mol.GetTitle() << "\nEND\n"; ofs << "POSITION\n"; OBAtom *atom; OBResidue *res; vector<OBAtom*>::iterator i; for(atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i)) { if ( (res = atom->GetResidue()) ) { // 16 = sizeof(res_name) and sizeof(type_name) strncpy(res_name,(char*)res->GetName().c_str(), 16); res_name[15] = '\0'; strncpy(type_name,(char*)res->GetAtomID(atom).c_str(), 16); type_name[15] = '\0'; res_num = res->GetNumString(); } else { strncpy(type_name,OBElements::GetSymbol(atom->GetAtomicNum()), 16); strcpy(res_name,"UNK"); res_num = "1"; } snprintf(buffer, BUFF_SIZE, "%5s %5s %5s %6d %15.5f %15.5f %15.5f\n", res_num.c_str(),res_name,type_name,atom->GetIdx(), atom->x()*fac,atom->y()*fac,atom->z()*fac); ofs << buffer; if (!(atom->GetIdx()%10)) { snprintf(buffer, BUFF_SIZE, "# %d\n",atom->GetIdx()); ofs << buffer; } } ofs << "END\n"; return(true); }
bool PDBFormat::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 type_name[10], padded_name[10]; char the_res[10]; char the_chain = ' '; const char *element_name; int res_num; bool het=true; int model_num = 0; if (!pConv->IsLast() || pConv->GetOutputIndex() > 1) { // More than one molecule record model_num = pConv->GetOutputIndex(); // MODEL 1-based index snprintf(buffer, BUFF_SIZE, "MODEL %8d", model_num); ofs << buffer << endl; } // write back all fields (REMARKS, HELIX, SHEET, SITE, ...) bool compndWritten = false; bool authorWritten = false; std::vector<OBGenericData*> pairData = mol.GetAllData(OBGenericDataType::PairData); for (std::vector<OBGenericData*>::iterator data = pairData.begin(); data != pairData.end(); ++data) { OBPairData *pd = static_cast<OBPairData*>(*data); string attr = pd->GetAttribute(); // filter to make sure we are writing pdb fields only if (attr != "HEADER" && attr != "OBSLTE" && attr != "TITLE" && attr != "SPLIT" && attr != "CAVEAT" && attr != "COMPND" && attr != "SOURCE" && attr != "KEYWDS" && attr != "EXPDTA" && attr != "NUMMDL" && attr != "MDLTYP" && attr != "AUTHOR" && attr != "REVDAT" && attr != "SPRSDE" && attr != "JRNL" && attr != "REMARK" && attr != "DBREF" && attr != "DBREF1" && attr != "DBREF2" && attr != "SEQADV" && attr != "SEQRES" && attr != "MODRES" && attr != "HET" && attr != "HETNAM" && attr != "HETSYN" && attr != "FORMUL" && attr != "HELIX" && attr != "SHEET" && attr != "SSBOND" && attr != "LINK" && attr != "CISPEP" && attr != "SITE" && attr != "ORIGX1" && attr != "ORIGX2" && attr != "ORIGX3" && attr != "SCALE1" && attr != "SCALE2" && attr != "SCALE3" && attr != "MATRIX1" && attr != "MATRIX2" && attr != "MATRIX3" && attr != "MODEL") continue; if (attr == "COMPND") compndWritten = true; if (attr == "AUTHOR") authorWritten = true; // compute spacing needed. HELIX, SITE, HET, ... are trimmed when reading int nSpacing = 6 - attr.size(); for (int i = 0; i < nSpacing; ++i) attr += " "; std::string lines = pd->GetValue(); string::size_type last = 0; string::size_type pos = lines.find('\n'); while (last != string::npos) { string line = lines.substr(last, pos - last); if (pos == string::npos) last = string::npos; else last = pos + 1; pos = lines.find('\n', last); ofs << attr << line << endl; } } if (!compndWritten) { if (strlen(mol.GetTitle()) > 0) snprintf(buffer, BUFF_SIZE, "COMPND %s ",mol.GetTitle()); else snprintf(buffer, BUFF_SIZE, "COMPND UNNAMED"); ofs << buffer << endl; } if (!authorWritten) { snprintf(buffer, BUFF_SIZE, "AUTHOR GENERATED BY OPEN BABEL %s",BABEL_VERSION); ofs << buffer << endl; } // Write CRYST1 record, containing unit cell parameters, space group // and Z value (supposed to be 1) if (pmol->HasData(OBGenericDataType::UnitCell)) { OBUnitCell *pUC = (OBUnitCell*)pmol->GetData(OBGenericDataType::UnitCell); if(pUC->GetSpaceGroup()){ string tmpHM=pUC->GetSpaceGroup()->GetHMName(); // Do we have an extended HM symbol, with origin choice as ":1" or ":2" ? If so, remove it. size_t n=tmpHM.find(":"); if(n!=string::npos) tmpHM=tmpHM.substr(0,n); snprintf(buffer, BUFF_SIZE, "CRYST1%9.3f%9.3f%9.3f%7.2f%7.2f%7.2f %-11s 1", pUC->GetA(), pUC->GetB(), pUC->GetC(), pUC->GetAlpha(), pUC->GetBeta(), pUC->GetGamma(), tmpHM.c_str()); } else snprintf(buffer, BUFF_SIZE, "CRYST1%9.3f%9.3f%9.3f%7.2f%7.2f%7.2f %-11s 1", pUC->GetA(), pUC->GetB(), pUC->GetC(), pUC->GetAlpha(), pUC->GetBeta(), pUC->GetGamma(), "P1"); ofs << buffer << endl; } // before we write any records, we should check to see if any coord < -1000 // which will cause errors in the formatting double minX, minY, minZ; minX = minY = minZ = -999.0f; FOR_ATOMS_OF_MOL(a, mol) { if (a->GetX() < minX) minX = a->GetX(); if (a->GetY() < minY) minY = a->GetY(); if (a->GetZ() < minZ) minZ = a->GetZ(); } vector3 transV = VZero; if (minX < -999.0) transV.SetX(-1.0*minX - 900.0); if (minY < -999.0) transV.SetY(-1.0*minY - 900.0); if (minZ < -999.0) transV.SetZ(-1.0*minZ - 900.0); // if minX, minY, or minZ was never changed, shift will be 0.0f // otherwise, move enough so that smallest coord is > -999.0f mol.Translate(transV); OBAtom *atom; OBResidue *res; for (i = 1; i <= mol.NumAtoms(); i++) { atom = mol.GetAtom(i); strncpy(type_name, etab.GetSymbol(atom->GetAtomicNum()), sizeof(type_name)); type_name[sizeof(type_name) - 1] = '\0'; //two char. elements are on position 13 and 14 one char. start at 14 if (strlen(type_name) > 1) type_name[1] = toupper(type_name[1]); else { char tmp[10]; strncpy(tmp, type_name, 9); // make sure to null-terminate tmp snprintf(type_name, sizeof(type_name), " %-3s", tmp); } if ( (res = atom->GetResidue()) != 0 ) { het = res->IsHetAtom(atom); snprintf(the_res,4,"%s",(char*)res->GetName().c_str()); the_res[4] = '\0'; snprintf(type_name,5,"%s",(char*)res->GetAtomID(atom).c_str()); the_chain = res->GetChain(); //two char. elements are on position 13 and 14 one char. start at 14 if (strlen(etab.GetSymbol(atom->GetAtomicNum())) == 1) { if (strlen(type_name) < 4) { char tmp[10]; strncpy(tmp, type_name, 9); // make sure to null-terminate tmp snprintf(padded_name, sizeof(padded_name), " %-3s", tmp); strncpy(type_name,padded_name,4); type_name[4] = '\0'; } else { /* type_name[4] = type_name[3]; type_name[3] = type_name[2]; type_name[2] = type_name[1]; type_name[1] = type_name[0]; type_name[0] = type_name[4]; */ type_name[4] = '\0'; } } res_num = res->GetNum(); } else { strcpy(the_res,"UNK"); the_res[3] = '\0'; snprintf(padded_name,sizeof(padded_name), "%s",type_name); strncpy(type_name,padded_name,4); type_name[4] = '\0'; res_num = 1; } element_name = etab.GetSymbol(atom->GetAtomicNum()); int charge = atom->GetFormalCharge(); char scharge[3] = { ' ', ' ', '\0' }; if(0 != charge) { snprintf(scharge, 3, "%+d", charge); char tmp = scharge[1]; scharge[1] = scharge[0]; scharge[0] = tmp; } snprintf(buffer, BUFF_SIZE, "%s%5d %-4s %-3s %c%4d %8.3f%8.3f%8.3f 1.00 0.00 %2s%2s\n", het?"HETATM":"ATOM ", i, type_name, the_res, the_chain, res_num, atom->GetX(), atom->GetY(), atom->GetZ(), element_name, scharge); ofs << buffer; } OBAtom *nbr; vector<OBBond*>::iterator k; for (i = 1; i <= mol.NumAtoms(); i ++) { atom = mol.GetAtom(i); if (atom->GetValence() == 0) continue; // no need to write a CONECT record -- no bonds snprintf(buffer, BUFF_SIZE, "CONECT%5d", i); ofs << buffer; // Write out up to 4 real bonds per line PR#1711154 int currentValence = 0; for (nbr = atom->BeginNbrAtom(k);nbr;nbr = atom->NextNbrAtom(k)) { snprintf(buffer, BUFF_SIZE, "%5d", nbr->GetIdx()); ofs << buffer; if (++currentValence % 4 == 0) { // Add the trailing space to finish this record ofs << " \n"; // write the start of a new CONECT record snprintf(buffer, BUFF_SIZE, "CONECT%5d", i); ofs << buffer; } } // Add trailing spaces int remainingValence = atom->GetValence() % 4; for (int count = 0; count < (4 - remainingValence); count++) { snprintf(buffer, BUFF_SIZE, " "); ofs << buffer; } ofs << " \n"; } snprintf(buffer, BUFF_SIZE, "MASTER 0 0 0 0 0 0 0 0 "); ofs << buffer; snprintf(buffer, BUFF_SIZE, "%4d 0 %4d 0\n",mol.NumAtoms(),mol.NumAtoms()); ofs << buffer; ofs << "END\n"; if (model_num) { ofs << "ENDMDL" << endl; } return(true); }
bool parseConectRecord(char *buffer,OBMol &mol) { stringstream errorMsg; string clearError; // Setup strings and string buffers vector<string> vs; buffer[70] = '\0'; if (strlen(buffer) < 70) { errorMsg << "WARNING: Problems reading a PDB file\n" << " Problems reading a CONECT record.\n" << " According to the PDB specification,\n" << " the record should have 70 columns, but OpenBabel found " << strlen(buffer) << " columns." << endl; obErrorLog.ThrowError(__FUNCTION__, errorMsg.str() , obInfo); errorMsg.str(clearError); } // Serial number of the first atom, read from column 7-11 of the // connect record, to which the other atoms connect to. long int startAtomSerialNumber; // A pointer to the first atom. OBAtom *firstAtom = NULL; // Serial numbers of the atoms which bind to firstAtom, read from // columns 12-16, 17-21, 22-27 and 27-31 of the connect record. Note // that we reserve space for 5 integers, but read only four of // them. This is to simplify the determination of the bond order; // see below. long int boundedAtomsSerialNumbers[5] = {0,0,0,0,0}; // Bools which tell us which of the serial numbers in // boundedAtomsSerialNumbers are read from the file, and which are // invalid bool boundedAtomsSerialNumbersValid[5] = {false, false, false, false, false}; // Pragmatic approach -- too many non-standard PDB files out there // (including some old ones from us) // So if we have a small number of atoms, then try to break by spaces // Otherwise (i.e., NumAtoms() > 9,999 we need to go by position) // We'll switch back and forth a few times to save duplicating common code if (mol.NumAtoms() <= 9999) { // make sure we don't look at salt bridges or whatever, so cut the buffer short buffer[32] = '\0'; tokenize(vs,buffer); if( vs.empty() || vs.size() < 2) return false; vs.erase(vs.begin()); // remove "CONECT" startAtomSerialNumber = atoi(vs[0].c_str()); } else { if (readIntegerFromRecord(buffer, 7, &startAtomSerialNumber) == false) { errorMsg << "WARNING: Problems reading a PDB file\n" << " Problems reading a CONECT record.\n" << " According to the PDB specification,\n" << " columns 7-11 should contain the serial number of an atom.\n" << " THIS CONECT RECORD WILL BE IGNORED." << endl; obErrorLog.ThrowError(__FUNCTION__, errorMsg.str() , obWarning); return(false); } } vector<OBAtom*>::iterator i; for (OBAtom *a1 = mol.BeginAtom(i);a1;a1 = mol.NextAtom(i)) { // atoms may not have residue information, but if they do, // check serial numbers if (a1->GetResidue() != NULL && static_cast<long int>(a1->GetResidue()-> GetSerialNum(a1)) == startAtomSerialNumber) { firstAtom = a1; break; } } if (firstAtom == NULL) { errorMsg << "WARNING: Problems reading a PDB file:\n" << " Problems reading a CONECT record.\n" << " According to the PDB specification,\n" << " columns 7-11 should contain the serial number of an atom.\n" << " No atom was found with this serial number.\n" << " THIS CONECT RECORD WILL BE IGNORED." << endl; obErrorLog.ThrowError(__FUNCTION__, errorMsg.str() , obWarning); return(false); } if (mol.NumAtoms() < 9999) { if (vs.size() > 1) boundedAtomsSerialNumbers[0] = atoi(vs[1].c_str()); if (vs.size() > 2) boundedAtomsSerialNumbers[1] = atoi(vs[2].c_str()); if (vs.size() > 3) boundedAtomsSerialNumbers[2] = atoi(vs[3].c_str()); if (vs.size() > 4) boundedAtomsSerialNumbers[3] = atoi(vs[4].c_str()); unsigned int limit = 4; if (vs.size() <= 4) limit = vs.size() - 1; for (unsigned int s = 0; s < limit; ++s) boundedAtomsSerialNumbersValid[s] = true; } else { // Now read the serial numbers. If the first serial number is not // present, this connect record probably contains only hydrogen // bonds and salt bridges, which we ignore. In that case, we just // exit gracefully. boundedAtomsSerialNumbersValid[0] = readIntegerFromRecord(buffer, 12, boundedAtomsSerialNumbers+0); if (boundedAtomsSerialNumbersValid[0] == false) return(true); boundedAtomsSerialNumbersValid[1] = readIntegerFromRecord(buffer, 17, boundedAtomsSerialNumbers+1); boundedAtomsSerialNumbersValid[2] = readIntegerFromRecord(buffer, 22, boundedAtomsSerialNumbers+2); boundedAtomsSerialNumbersValid[3] = readIntegerFromRecord(buffer, 27, boundedAtomsSerialNumbers+3); } // Now iterate over the VALID boundedAtomsSerialNumbers and connect // the atoms. for(unsigned int k=0; boundedAtomsSerialNumbersValid[k]; k++) { // Find atom that is connected to, write an error message OBAtom *connectedAtom = 0L; for (OBAtom *a1 = mol.BeginAtom(i);a1;a1 = mol.NextAtom(i)) { // again, atoms may not have residues, but if they do, check serials if (a1->GetResidue() != NULL && static_cast<long int>(a1->GetResidue()-> GetSerialNum(a1)) == boundedAtomsSerialNumbers[k]) { connectedAtom = a1; break; } } if (connectedAtom == 0L) { errorMsg << "WARNING: Problems reading a PDB file:\n" << " Problems reading a CONECT record.\n" << " According to the PDB specification,\n" << " Atoms with serial #" << startAtomSerialNumber << " and #" << boundedAtomsSerialNumbers[k] << " should be connected\n" << " However, an atom with serial #" << boundedAtomsSerialNumbers[k] << " was not found.\n" << " THIS CONECT RECORD WILL BE IGNORED." << endl; obErrorLog.ThrowError(__FUNCTION__, errorMsg.str() , obWarning); return(false); } // Figure the bond order unsigned char order = 0; while(boundedAtomsSerialNumbersValid[k+order+1] && (boundedAtomsSerialNumbers[k+order] == boundedAtomsSerialNumbers[k+order+1])) order++; k += order; // Generate the bond if (firstAtom->GetIdx() < connectedAtom->GetIdx()) { // record the bond 'in one direction' only OBBond *bond = mol.GetBond(firstAtom, connectedAtom); if (!bond) mol.AddBond(firstAtom->GetIdx(), connectedAtom->GetIdx(), order+1); else // An additional CONECT record with the same firstAtom that references // a bond created in the previous CONECT record. // For example, the 1136->1138 double bond in the following: // CONECT 1136 1128 1137 1137 1138 // CONECT 1136 1138 1139 bond->SetBondOrder(bond->GetBondOrder() + order+1); } } return(true); }
bool ChemDrawXMLFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv) { static const xmlChar C_MOLECULE[] = "fragment"; static const xmlChar C_CDXML[] = "CDXML"; static const xmlChar C_BONDLENGTH[] = "BondLength"; static const xmlChar C_PAGE[] = "page"; static const xmlChar C_ATOM[] = "n"; static const xmlChar C_BOND[] = "b"; static const xmlChar C_ID[] = "id"; static const xmlChar C_CHARGE[] = "Charge"; static const xmlChar C_COORDS[] = "p"; static const xmlChar C_ELEMENT[] = "Element"; static const xmlChar C_ORDER[] = "Order"; static const xmlChar C_BEGIN[] = "B"; static const xmlChar C_END[] = "E"; static const xmlChar C_DISPLAY[] = "Display"; _pxmlConv = XMLConversion::GetDerived(pConv,false); if(!_pxmlConv) return false; OBMol* pmol = dynamic_cast<OBMol*>(pOb); if(pmol==NULL) return false; OBMol &mol = *pmol; OBBond *pbond; vector<OBBond*>::iterator j; if(_pxmlConv->GetOutputIndex() == 1) { xmlTextWriterStartDocument(writer(), NULL, NULL, NULL); xmlTextWriterWriteDTD(writer(), BAD_CAST "CDXML", NULL, BAD_CAST "http://www.camsoft.com/xml/cdxml.dtd", NULL); xmlTextWriterStartElement(writer(), C_CDXML); xmlTextWriterWriteFormatAttribute(writer(), C_BONDLENGTH , "30"); xmlTextWriterStartElement(writer(), C_PAGE); // put everything on one page // now guess the average bond size for the first molecule and scale to 30. _scale = 0.; if (mol.NumBonds()) { for (pbond = mol.BeginBond(j); pbond; pbond = mol.NextBond(j)) _scale += pbond->GetLength(); _scale /= mol.NumBonds(); } else _scale = 1.; // FIXME: what happens if the molecule has no bond? _scale = 30. / _scale; _offset = 0; } xmlTextWriterStartElement(writer(), C_MOLECULE); OBAtom *patom; vector<OBAtom*>::iterator i; int n; for (patom = mol.BeginAtom(i); patom; patom = mol.NextAtom(i)) { xmlTextWriterStartElement(writer(), C_ATOM); xmlTextWriterWriteFormatAttribute(writer(), C_ID , "%d", patom->GetIdx() + _offset); xmlTextWriterWriteFormatAttribute(writer(), C_COORDS , "%f %f", patom->GetX() * _scale, patom->GetY() * _scale); n = patom->GetAtomicNum(); if (n != 6) { xmlTextWriterWriteFormatAttribute(writer(), C_ELEMENT , "%d", n); } n = patom->GetFormalCharge(); if (n != 0) { xmlTextWriterWriteFormatAttribute(writer(), C_CHARGE , "%d", n); } xmlTextWriterEndElement(writer()); } for (pbond = mol.BeginBond(j); pbond; pbond = mol.NextBond(j)) { xmlTextWriterStartElement(writer(), C_BOND); patom = pbond->GetBeginAtom(); xmlTextWriterWriteFormatAttribute(writer(), C_BEGIN , "%d", patom->GetIdx() + _offset); patom = pbond->GetEndAtom(); xmlTextWriterWriteFormatAttribute(writer(), C_END , "%d", patom->GetIdx() + _offset); n = pbond->GetBO(); if (n != 1) { xmlTextWriterWriteFormatAttribute(writer(), C_ORDER , "%d", n); } if (pbond->IsHash()) xmlTextWriterWriteFormatAttribute(writer(), C_DISPLAY , "WedgeBegin"); else if (pbond->IsWedge()) xmlTextWriterWriteFormatAttribute(writer(), C_DISPLAY , "WedgedHashEnd"); xmlTextWriterEndElement(writer()); } _offset += mol.NumAtoms (); xmlTextWriterEndElement(writer());//molecule //TODO: Writing property block if(_pxmlConv->IsLast()) { xmlTextWriterEndDocument(writer()); // page xmlTextWriterEndDocument(writer()); //document OutputToStream(); } return true; }
bool BGFFormat::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; vector<OBAtom*>::iterator i; int max_val; OBAtom *atom; char buffer[BUFF_SIZE]; char elmnt_typ[8], dreid_typ[8], atm_sym[16], max_val_str[8]; mol.Kekulize(); ofs << "BIOGRF 200\n"; snprintf(buffer, BUFF_SIZE, "DESCRP %s\n",mol.GetTitle()); ofs << buffer; snprintf(buffer, BUFF_SIZE, "REMARK BGF file created by Open Babel %s\n",BABEL_VERSION); ofs << "FORCEFIELD DREIDING \n"; // write unit cell if available if (mol.HasData(OBGenericDataType::UnitCell)) { OBUnitCell *uc = (OBUnitCell*)mol.GetData(OBGenericDataType::UnitCell); // e.g. CRYSTX 49.30287 49.23010 25.45631 90.00008 89.99995 57.10041 snprintf(buffer, BUFF_SIZE, "CRYSTX%12.5f%12.5f%12.5f%12.5f%12.5f%12.5f", uc->GetA(), uc->GetB(), uc->GetC(), uc->GetAlpha() , uc->GetBeta(), uc->GetGamma()); ofs << buffer << "\n"; } ofs << "FORMAT ATOM (a6,1x,i5,1x,a5,1x,a3,1x,a1,1x,a5,3f10.5,1x,a5,i3,i2,1x,f8.5)\n"; ttab.SetFromType("INT"); for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i)) { strncpy(elmnt_typ,etab.GetSymbol(atom->GetAtomicNum()), 7); // make sure to null-terminate elmnt_typ[sizeof(elmnt_typ) - 1] = '0'; ToUpper(elmnt_typ); ttab.SetToType("DRE"); ttab.Translate(dreid_typ,atom->GetType()); ttab.SetToType("HAD"); ttab.Translate(max_val_str,atom->GetType()); max_val = atoi(max_val_str); if (max_val == 0) max_val = 1; snprintf(atm_sym,16,"%s%d",elmnt_typ,atom->GetIdx()); snprintf(buffer,BUFF_SIZE,"%6s %5d %-5s %3s %1s %5s%10.5f%10.5f%10.5f %-5s%3d%2d %8.5f\n", "HETATM", atom->GetIdx(), atm_sym, "RES", "A", "444", atom->GetX(), atom->GetY(), atom->GetZ(), dreid_typ, max_val, 0, atom->GetPartialCharge()); ofs << buffer; } ofs<< "FORMAT CONECT (a6,12i6)\n\n"; OBAtom *nbr; vector<OBBond*>::iterator j; for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i)) if (atom->GetValence()) { snprintf(buffer,BUFF_SIZE,"CONECT%6d",atom->GetIdx()); ofs << buffer; for (nbr = atom->BeginNbrAtom(j);nbr;nbr = atom->NextNbrAtom(j)) { snprintf(buffer,BUFF_SIZE,"%6d",nbr->GetIdx()); ofs << buffer; } ofs << endl; snprintf(buffer,BUFF_SIZE,"ORDER %6d",atom->GetIdx()); ofs << buffer; for (nbr = atom->BeginNbrAtom(j);nbr;nbr = atom->NextNbrAtom(j)) { snprintf(buffer,BUFF_SIZE,"%6d",(*j)->GetBO()); ofs << buffer; } ofs << endl; } ofs << "END" << endl; return(true); }