void CheckValidDipeptide(OBConversion &conv, const string &test, unsigned int testCount) { OBMol mol; OBResidue *res; ostringstream os; mol.Clear(); conv.ReadString(&mol, test); chainsparser.PerceiveChains(mol); if (mol.NumResidues() != 2) { os << "not ok " << testCount << " # expected 2 residues, but found " << mol.NumResidues() << '\n'; os << "# "; FOR_RESIDUES_OF_MOL(res, mol) os << res->GetName() << " "; os << endl; BOOST_CHECK_MESSAGE( 0, os.str().c_str() ); } else { res = mol.GetResidue(0); BOOST_CHECK_MESSAGE( res, "Get first AA from dipeptide" ); res = mol.GetResidue(1); BOOST_CHECK_MESSAGE( res, "Get second AA from dipeptide" ); } }
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); }
void CheckInvalidResidue(OBConversion &conv, const string &test, unsigned int testCount) { OBMol mol; mol.Clear(); conv.ReadString(&mol, test); chainsparser.PerceiveChains(mol); if (mol.NumResidues() != 0) { OBResidue *res = mol.GetResidue(0); if (res->GetName() == "LIG") { // ligand, not residue cout << "ok " << testCount << " # found ligand, not residue " << test << '\n'; } else { cout << "not ok " << testCount << " # expected 0 residues, found " << mol.NumResidues() << '\n'; cout << "# " << res->GetName() << endl; } } else cout << "ok " << testCount << " # correctly rejected " << test << '\n'; }
void CheckInvalidResidue(OBConversion &conv, const string &test, unsigned int testCount) { OBMol mol; ostringstream os; mol.Clear(); conv.ReadString(&mol, test); chainsparser.PerceiveChains(mol); if (mol.NumResidues() != 0) { OBResidue *res = mol.GetResidue(0); if (res->GetName() == "LIG") { // ligand, not residue BOOST_CHECK( 1 ); } else { os << "not ok " << testCount << " # expected 0 residues, found " << mol.NumResidues() << '\n'; os << "# " << res->GetName() << endl; BOOST_CHECK_MESSAGE( 0, os.str().c_str() ); } } else BOOST_CHECK( 1 ); }
void CheckValidDipeptide(OBConversion &conv, const string &test, unsigned int testCount) { OBMol mol; mol.Clear(); conv.ReadString(&mol, test); chainsparser.PerceiveChains(mol); if (mol.NumResidues() != 2) { cout << "not ok " << testCount << " # expected 2 residues, but found " << mol.NumResidues() << '\n'; cout << "# "; FOR_RESIDUES_OF_MOL(res, mol) cout << res->GetName() << " "; cout << endl; } else { OBResidue *res; res = mol.GetResidue(0); cout << "ok " << testCount << " # " << res->GetName(); res = mol.GetResidue(1); cout << " " << res->GetName() << '\n'; } }
bool MOL2Format::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; //Old code follows... bool foundAtomLine = false; char buffer[BUFF_SIZE]; char *comment = NULL; string str,str1; vector<string> vstr; int len; mol.BeginModify(); for (;;) { if (!ifs.getline(buffer,BUFF_SIZE)) return(false); if (EQn(buffer,"@<TRIPOS>MOLECULE",17)) break; } int lcount; int natoms,nbonds; for (lcount=0;;lcount++) { if (!ifs.getline(buffer,BUFF_SIZE)) return(false); if (EQn(buffer,"@<TRIPOS>ATOM",13)) { foundAtomLine = true; break; } if (lcount == 0) { tokenize(vstr,buffer); if (!vstr.empty()) mol.SetTitle(buffer); } else if (lcount == 1) sscanf(buffer,"%d%d",&natoms,&nbonds); else if (lcount == 4) //energy { tokenize(vstr,buffer); if (!vstr.empty() && vstr.size() == 3) if (vstr[0] == "Energy") mol.SetEnergy(atof(vstr[2].c_str())); } else if (lcount == 5) //comment { if ( buffer[0] ) { len = (int) strlen(buffer)+1; // TODO allow better multi-line comments // which don't allow ill-formed data to consume memory // Thanks to Andrew Dalke for the pointer if (comment != NULL) delete [] comment; comment = new char [len]; memcpy(comment,buffer,len); } } } if (!foundAtomLine) { mol.EndModify(); mol.Clear(); obErrorLog.ThrowError(__FUNCTION__, "Unable to read Mol2 format file. No atoms found.", obWarning); return(false); } mol.ReserveAtoms(natoms); int i; vector3 v; OBAtom atom; bool hasPartialCharges=false; double x,y,z,pcharge; char temp_type[BUFF_SIZE], resname[BUFF_SIZE], atmid[BUFF_SIZE]; int elemno, resnum = -1; ttab.SetFromType("SYB"); for (i = 0;i < natoms;i++) { if (!ifs.getline(buffer,BUFF_SIZE)) return(false); sscanf(buffer," %*s %1024s %lf %lf %lf %1024s %d %1024s %lf", atmid, &x,&y,&z, temp_type, &resnum, resname, &pcharge); atom.SetVector(x, y, z); // Handle "CL" and "BR" and other mis-typed atoms str = temp_type; if (strncmp(temp_type, "CL", 2) == 0) { str = "Cl"; } else if (strncmp(temp_type,"BR",2) == 0) { str = "Br"; } else if (strncmp(temp_type,"S.o2", 4) == 02) { str = "S.O2"; } else if (strncmp(temp_type,"S.o", 3) == 0) { str = "S.O"; } else if (strncmp(temp_type,"SI", 2) == 0) { str = "Si"; // The following cases are entries which are not in openbabel/data/types.txt // and should probably be added there } else if (strncmp(temp_type,"S.1", 3) == 0) { str = "S.2"; // no idea what the best type might be here } else if (strncmp(temp_type,"P.", 2) == 0) { str = "P.3"; } else if (strncasecmp(temp_type,"Ti.", 3) == 0) { // e.g. Ti.th str = "Ti"; } else if (strncasecmp(temp_type,"Ru.", 3) == 0) { // e.g. Ru.oh str = "Ru"; } ttab.SetToType("ATN"); ttab.Translate(str1,str); elemno = atoi(str1.c_str()); ttab.SetToType("IDX"); // We might have missed some SI or FE type things above, so here's // another check if( !elemno && isupper(temp_type[1]) ) { temp_type[1] = (char)tolower(temp_type[1]); str = temp_type; ttab.Translate(str1,str); elemno = atoi(str1.c_str()); } // One last check if there isn't a period in the type, // it's a malformed atom type, but it may be the element symbol // GaussView does this (PR#1739905) if ( !elemno ) { obErrorLog.ThrowError(__FUNCTION__, "This Mol2 file is non-standard. Cannot interpret atom types correctly, instead attempting to interpret as elements instead.", obWarning); string::size_type dotPos = str.find('.'); if (dotPos == string::npos) { elemno = etab.GetAtomicNum(str.c_str()); } } atom.SetAtomicNum(elemno); ttab.SetToType("INT"); ttab.Translate(str1,str); atom.SetType(str1); atom.SetPartialCharge(pcharge); if (!mol.AddAtom(atom)) return(false); if (!IsNearZero(pcharge)) hasPartialCharges = true; // Add residue information if it exists if (resnum != -1 && resnum != 0 && strlen(resname) != 0 && strncmp(resname,"<1>", 3) != 0) { OBResidue *res = (mol.NumResidues() > 0) ? mol.GetResidue(mol.NumResidues()-1) : NULL; if (res == NULL || res->GetName() != resname || static_cast<int>(res->GetNum()) != resnum) { vector<OBResidue*>::iterator ri; for (res = mol.BeginResidue(ri) ; res ; res = mol.NextResidue(ri)) if (res->GetName() == resname && static_cast<int>(res->GetNum()) == resnum) break; if (res == NULL) { res = mol.NewResidue(); res->SetName(resname); res->SetNum(resnum); } } OBAtom *atomPtr = mol.GetAtom(mol.NumAtoms()); res->AddAtom(atomPtr); res->SetAtomID(atomPtr, atmid); } // end adding residue info } for (;;) { if (!ifs.getline(buffer,BUFF_SIZE)) return(false); str = buffer; if (!strncmp(buffer,"@<TRIPOS>BOND",13)) break; } int start,end,order; for (i = 0; i < nbonds; i++) { if (!ifs.getline(buffer,BUFF_SIZE)) return(false); sscanf(buffer,"%*d %d %d %1024s",&start,&end,temp_type); str = temp_type; order = 1; if (str == "ar" || str == "AR" || str == "Ar") order = 5; else if (str == "AM" || str == "am" || str == "Am") order = 1; else order = atoi(str.c_str()); mol.AddBond(start,end,order); } // update neighbour bonds information for each atom. vector<OBAtom*>::iterator apos; vector<OBBond*>::iterator bpos; OBAtom* patom; OBBond* pbond; for (patom = mol.BeginAtom(apos); patom; patom = mol.NextAtom(apos)) { patom->ClearBond(); for (pbond = mol.BeginBond(bpos); pbond; pbond = mol.NextBond(bpos)) { if (patom == pbond->GetBeginAtom() || patom == pbond->GetEndAtom()) { patom->AddBond(pbond); } } } // Suggestion by Liu Zhiguo 2008-01-26 // Mol2 files define atom types -- there is no need to re-perceive mol.SetAtomTypesPerceived(); mol.EndModify(); //must add generic data after end modify - otherwise it will be blown away if (comment) { OBCommentData *cd = new OBCommentData; cd->SetData(comment); cd->SetOrigin(fileformatInput); mol.SetData(cd); delete [] comment; comment = NULL; } if (hasPartialCharges) mol.SetPartialChargesPerceived(); // continue untill EOF or untill next molecule record streampos pos; for(;;) { pos = ifs.tellg(); if (!ifs.getline(buffer,BUFF_SIZE)) break; if (EQn(buffer,"@<TRIPOS>MOLECULE",17)) break; } ifs.seekg(pos); // go back to the end of the molecule 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); }
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); }
static bool parseAtomRecord(char *buffer, OBMol &mol,int /*chainNum*/) /* ATOMFORMAT "(i5,1x,a4,a1,a3,1x,a1,i4,a1,3x,3f8.3,2f6.2,a2,a2)" */ { string sbuf = &buffer[6]; if (sbuf.size() < 48) return(false); bool hetatm = (EQn(buffer,"HETATM",6)) ? true : false; bool elementFound = false; // true if correct element found in col 77-78 /* serial number */ string serno = sbuf.substr(0,5); /* atom name */ string atmid = sbuf.substr(6,4); /* chain */ char chain = sbuf.substr(15,1)[0]; /* element */ string element = " "; if (sbuf.size() > 71) { element = sbuf.substr(70,2); if (isalpha(element[1])) { if (element[0] == ' ') { element.erase(0, 1); elementFound = true; } else if (isalpha(element[0])) { elementFound = true; } } } if (!elementFound) { stringstream errorMsg; errorMsg << "WARNING: Problems reading a PDB file\n" << " Problems reading a HETATM or ATOM record.\n" << " According to the PDB specification,\n" << " columns 77-78 should contain the element symbol of an atom.\n" << " but OpenBabel found '" << element << "' (atom " << mol.NumAtoms()+1 << ")"; obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obWarning); } // charge - optional string scharge; if (sbuf.size() > 73) { scharge = sbuf.substr(72,2); } //trim spaces on the right and left sides while (!atmid.empty() && atmid[0] == ' ') atmid = atmid.erase(0, 1); while (!atmid.empty() && atmid[atmid.size()-1] == ' ') atmid = atmid.substr(0,atmid.size()-1); /* residue name */ string resname = sbuf.substr(11,3); if (resname == " ") resname = "UNK"; else { while (!resname.empty() && resname[0] == ' ') resname = resname.substr(1,resname.size()-1); while (!resname.empty() && resname[resname.size()-1] == ' ') resname = resname.substr(0,resname.size()-1); } string type; if (!elementFound) { // OK, we have to fall back to determining the element from the atom type // This is unreliable, but there's no other choice if (EQn(buffer,"ATOM",4)) { type = atmid.substr(0,2); if (isdigit(type[0])) { // sometimes non-standard files have, e.g 11HH if (!isdigit(type[1])) type = atmid.substr(1,1); else type = atmid.substr(2,1); } else if ((sbuf[6] == ' ' && strncasecmp(type.c_str(), "Zn", 2) != 0 && strncasecmp(type.c_str(), "Fe", 2) != 0) || isdigit(type[1])) //type[1] is digit in Platon type = atmid.substr(0,1); // one-character element if (resname.substr(0,2) == "AS" || resname[0] == 'N') { if (atmid == "AD1") type = "O"; if (atmid == "AD2") type = "N"; } if (resname.substr(0,3) == "HIS" || resname[0] == 'H') { if (atmid == "AD1" || atmid == "AE2") type = "N"; if (atmid == "AE1" || atmid == "AD2") type = "C"; } if (resname.substr(0,2) == "GL" || resname[0] == 'Q') { if (atmid == "AE1") type = "O"; if (atmid == "AE2") type = "N"; } // fix: #2002557 if (atmid[0] == 'H' && (atmid[1] == 'D' || atmid[1] == 'E' || atmid[1] == 'G' || atmid[1] == 'H')) // HD, HE, HG, HH, .. type = "H"; } else { //must be hetatm record if (isalpha(element[1]) && (isalpha(element[0]) || (element[0] == ' '))) { if (isalpha(element[0])) type = element.substr(0,2); else type = element.substr(1,1); if (type.size() == 2) type[1] = tolower(type[1]); } else { // no element column to use if (isalpha(atmid[0])) { if (atmid.size() > 2 && (atmid[2] == '\0' || atmid[2] == ' ')) type = atmid.substr(0,2); else if (atmid[0] == 'A') // alpha prefix type = atmid.substr(1, atmid.size() - 1); else type = atmid.substr(0,1); } else if (atmid[0] == ' ') type = atmid.substr(1,1); // one char element else type = atmid.substr(1,2); // Some cleanup steps if (atmid == resname) { type = atmid; if (type.size() == 2) type[1] = tolower(type[1]); } else if (resname == "ADR" || resname == "COA" || resname == "FAD" || resname == "GPG" || resname == "NAD" || resname == "NAL" || resname == "NDP" || resname == "ABA") { if (type.size() > 1) type = type.substr(0,1); //type.erase(1,type.size()-1); } else // other residues if (isdigit(type[0])){ type = type.substr(1,1); } else if (type.size() > 1 && isdigit(type[1])) type = type.substr(0,1); else if (type.size() > 1 && isalpha(type[1])) { if (type[0] == 'O' && type[1] == 'H') type = type.substr(0,1); // no "Oh" element (e.g. 1MBN) else if(isupper(type[1])) { type[1] = tolower(type[1]); } } } } // HETATM records } // no element column to use OBAtom atom; /* X, Y, Z */ string xstr = sbuf.substr(24,8); string ystr = sbuf.substr(32,8); string zstr = sbuf.substr(40,8); vector3 v(atof(xstr.c_str()),atof(ystr.c_str()),atof(zstr.c_str())); atom.SetVector(v); atom.ForceImplH(); // useful for debugging unknown atom types (e.g., PR#1577238) // cout << mol.NumAtoms() + 1 << " : '" << element << "'" << " " << etab.GetAtomicNum(element.c_str()) << endl; if (elementFound) atom.SetAtomicNum(etab.GetAtomicNum(element.c_str())); else // use our old-style guess from athe atom type atom.SetAtomicNum(etab.GetAtomicNum(type.c_str())); if ( (! scharge.empty()) && " " != scharge ) { if ( isdigit(scharge[0]) && ('+' == scharge[1] || '-' == scharge[1]) ) { const char reorderCharge[3] = { scharge[1], scharge[0], '\0' }; const int charge = atoi(reorderCharge); atom.SetFormalCharge(charge); } else { stringstream errorMsg; errorMsg << "WARNING: Problems reading a PDB file\n" << " Problems reading a HETATM or ATOM record.\n" << " According to the PDB specification,\n" << " columns 79-80 should contain charge of the atom\n" << " but OpenBabel found '" << scharge << "' (atom " << mol.NumAtoms()+1 << ")."; obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obWarning); } } else { atom.SetFormalCharge(0); } /* residue sequence number */ string resnum = sbuf.substr(16,4); OBResidue *res = (mol.NumResidues() > 0) ? mol.GetResidue(mol.NumResidues()-1) : NULL; if (res == NULL || res->GetName() != resname || res->GetNumString() != resnum || res->GetChain() != chain) { vector<OBResidue*>::iterator ri; for (res = mol.BeginResidue(ri) ; res ; res = mol.NextResidue(ri)) if (res->GetName() == resname && res->GetNumString() == resnum && static_cast<int>(res->GetChain()) == chain) break; if (res == NULL) { res = mol.NewResidue(); res->SetChain(chain); res->SetName(resname); res->SetNum(resnum); } } if (!mol.AddAtom(atom)) return(false); else { OBAtom *atom = mol.GetAtom(mol.NumAtoms()); res->AddAtom(atom); res->SetSerialNum(atom, atoi(serno.c_str())); res->SetAtomID(atom, sbuf.substr(6,4)); res->SetHetAtom(atom, hetatm); return(true); } } // end reading atom records
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 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); }