bool CHEM3D1Format::ReadChem3d(istream &ifs,OBMol &mol,bool mmads,const char *type_key) { char buffer[BUFF_SIZE]; int natoms,i; char tmp[16],tmp1[16]; char atomic_type[16]; double exponent = 0.0; double divisor = 1.0; double Alpha,Beta,Gamma,A,B,C; bool has_fractional = false, has_divisor = false; matrix3x3 m; vector<string> vs; ifs.getline(buffer,BUFF_SIZE); tokenize(vs,buffer); if (mmads) { if (vs.empty()) return(false); natoms = atoi((char*)vs[0].c_str()); if (vs.size() == 2) mol.SetTitle(vs[1]); } else { switch(vs.size()) { case 7 : sscanf(buffer,"%d%lf%lf%lf%lf%lf%lf", &natoms,&Alpha,&Beta,&Gamma,&A,&B,&C); m.FillOrth(Alpha,Beta,Gamma,A,B,C); has_fractional = true; break; case 8 : sscanf(buffer,"%d%lf%lf%lf%lf%lf%lf%lf", &natoms,&Alpha,&Beta,&Gamma,&A,&B,&C,&exponent); m.FillOrth(Alpha,Beta,Gamma,A,B,C); has_fractional = true; has_divisor = true; break; default : sscanf(buffer,"%d",&natoms); break; } } if (!natoms) return(false); divisor = pow(10.0,exponent); mol.ReserveAtoms(natoms); ttab.SetToType("INT"); ttab.SetFromType(type_key); OBAtom *atom; double x,y,z; vector3 v; unsigned int k; for (i = 1; i <= natoms; i++) { ifs.getline(buffer,BUFF_SIZE); sscanf(buffer,"%15s%*d%lf%lf%lf%15s", atomic_type, &x, &y, &z, tmp); v.Set(x,y,z); if (has_fractional) v *= m; if (has_divisor) v/= divisor; tokenize(vs,buffer); if (vs.empty()) return(false); atom = mol.NewAtom(); ttab.Translate(tmp1,tmp); atom->SetType(tmp1); atom->SetVector(v); atom->SetAtomicNum(etab.GetAtomicNum(atomic_type)); for (k = 6;k < vs.size(); k++) mol.AddBond(atom->GetIdx(),atoi((char*)vs[k].c_str()),1); } // clean out remaining blank lines while(ifs.peek() != EOF && ifs.good() && (ifs.peek() == '\n' || ifs.peek() == '\r')) ifs.getline(buffer,BUFF_SIZE); mol.PerceiveBondOrders(); 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) { 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
//! Calculate the signed volume for an atom. If the atom has a valence of 3 //! the coordinates of an attached hydrogen are calculated //! Puts attached Hydrogen last at the moment, like mol V3000 format. //! If ReZero=false (the default is true) always make pseudo z coords and leave them in mol double CalcSignedVolume(OBMol &mol,OBAtom *atm, bool ReZeroZ) { vector3 tmp_crd; vector<unsigned int> nbr_atms; vector<vector3> nbr_crds; bool use_central_atom = false,is2D=false; // double hbrad = etab.CorrectedBondRad(1,0); if (!ReZeroZ || !mol.Has3D()) //give pseudo Z coords if mol is 2D { vector3 v,vz(0.0,0.0,1.0); is2D = true; OBAtom *nbr; OBBond *bond; vector<OBBond*>::iterator i; for (bond = atm->BeginBond(i);bond;bond = atm->NextBond(i)) { nbr = bond->GetEndAtom(); if (nbr != atm) { v = nbr->GetVector(); if (bond->IsWedge()) v += vz; else if (bond->IsHash()) v -= vz; nbr->SetVector(v); } else { nbr = bond->GetBeginAtom(); v = nbr->GetVector(); if (bond->IsWedge()) v -= vz; else if (bond->IsHash()) v += vz; nbr->SetVector(v); } } } if (atm->GetHvyValence() < 3) { stringstream errorMsg; errorMsg << "Cannot calculate a signed volume for an atom with a heavy atom valence of " << atm->GetHvyValence() << endl; obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obInfo); return(0.0); } // Create a vector with the coordinates of the neighbor atoms // Also make a vector with Atom IDs OBAtom *nbr; vector<OBBond*>::iterator bint; for (nbr = atm->BeginNbrAtom(bint);nbr;nbr = atm->NextNbrAtom(bint)) { nbr_atms.push_back(nbr->GetIdx()); } // sort the neighbor atoms to insure a consistent ordering sort(nbr_atms.begin(),nbr_atms.end()); for (unsigned int i = 0; i < nbr_atms.size(); ++i) { OBAtom *tmp_atm = mol.GetAtom(nbr_atms[i]); nbr_crds.push_back(tmp_atm->GetVector()); } /* // If we have three heavy atoms we need to calculate the position of the fourth if (atm->GetHvyValence() == 3) { double bondlen = hbrad+etab.CorrectedBondRad(atm->GetAtomicNum(),atm->GetHyb()); atm->GetNewBondVector(tmp_crd,bondlen); nbr_crds.push_back(tmp_crd); } */ for(unsigned int j=0;j < nbr_crds.size();++j) // Checks for a neighbour having 0 co-ords (added hydrogen etc) { // are the coordinates zero to 6 or more significant figures if (nbr_crds[j].IsApprox(VZero, 1.0e-6) && use_central_atom==false) use_central_atom=true; else if (nbr_crds[j].IsApprox(VZero, 1.0e-6)) { obErrorLog.ThrowError(__FUNCTION__, "More than 2 neighbours have 0 co-ords when attempting 3D chiral calculation", obInfo); } } // If we have three heavy atoms we can use the chiral center atom itself for the fourth // will always give same sign (for tetrahedron), magnitude will be smaller. if(nbr_atms.size()==3 || use_central_atom==true) { nbr_crds.push_back(atm->GetVector()); nbr_atms.push_back(mol.NumAtoms()+1); // meed to add largest number on end to work } OBChiralData* cd=(OBChiralData*)atm->GetData(OBGenericDataType::ChiralData); //Set the output atom4refs to the ones used if(cd==NULL) { cd = new OBChiralData; cd->SetOrigin(perceived); atm->SetData(cd); } cd->SetAtom4Refs(nbr_atms,calcvolume); //re-zero psuedo-coords if (is2D && ReZeroZ) { vector3 v; OBAtom *atom; vector<OBAtom*>::iterator k; for (atom = mol.BeginAtom(k);atom;atom = mol.NextAtom(k)) { v = atom->GetVector(); v.SetZ(0.0); atom->SetVector(v); } } return(signed_volume(nbr_crds[0],nbr_crds[1],nbr_crds[2],nbr_crds[3])); }
void SuperCellExtension::fillCell() { /* Change coords back to inverse space, apply the space group transforms * then change coords back to real space */ if (!m_molecule) return; OBUnitCell *uc = m_molecule->OBUnitCell(); if (!uc) { qDebug() << "No unit cell found - fillCell() returning..."; return; } const SpaceGroup *sg = uc->GetSpaceGroup(); // the actual space group and transformations for this unit cell if (sg) { qDebug() << "Space group:" << sg->GetId();// << sg->GetHMName(); // We operate on a copy of the Avogadro molecule // For each atom, we loop through: // * convert the coords back to inverse space // * apply the transformations // * create new (duplicate) atoms OBMol mol = m_molecule->OBMol(); vector3 uniqueV, newV; list<vector3> transformedVectors; // list of symmetry-defined copies of the atom list<vector3>::iterator transformIterator, duplicateIterator; vector3 updatedCoordinate; bool foundDuplicate; OBAtom *addAtom; QList<OBAtom*> atoms; // keep the current list of unique atoms -- don't double-create list<vector3> coordinates; // all coordinates to prevent duplicates FOR_ATOMS_OF_MOL(atom, mol) atoms.push_back(&(*atom)); foreach(OBAtom *atom, atoms) { uniqueV = atom->GetVector(); // Assert: won't crash because we already ensure uc != NULL uniqueV = uc->CartesianToFractional(uniqueV); uniqueV = transformedFractionalCoordinate(uniqueV); coordinates.push_back(uniqueV); transformedVectors = sg->Transform(uniqueV); for (transformIterator = transformedVectors.begin(); transformIterator != transformedVectors.end(); ++transformIterator) { // coordinates are in reciprocal space -- check if it's in the unit cell // if not, transform it in place updatedCoordinate = transformedFractionalCoordinate(*transformIterator); foundDuplicate = false; // Check if the transformed coordinate is a duplicate of an atom for (duplicateIterator = coordinates.begin(); duplicateIterator != coordinates.end(); ++duplicateIterator) { if (duplicateIterator->distSq(updatedCoordinate) < 1.0e-4) { foundDuplicate = true; break; } } if (foundDuplicate) continue; coordinates.push_back(updatedCoordinate); // make sure to check the new atom for dupes addAtom = mol.NewAtom(); addAtom->Duplicate(atom); addAtom->SetVector(uc->FractionalToCartesian(updatedCoordinate)); } // end loop of transformed atoms // Put the original atom into the proper space in the unit cell too atom->SetVector(uc->FractionalToCartesian(uniqueV)); } // end loop of atoms m_molecule->setOBMol(&mol); qDebug() << "Spacegroups done..."; // Need a fresh pointer to the new unit cell - setOBMol is invalidating // the old one. This should be cleaned up to use a more permanent data // structure. uc = m_molecule->OBUnitCell(); uc->SetSpaceGroup(1); }
//! Transform the supplied vector<OBInternalCoord*> into cartesian and update //! the OBMol accordingly. The size of supplied internal coordinate vector //! has to be the same as the number of atoms in molecule (+ NULL in the //! beginning). //! Implements <a href="http://qsar.sourceforge.net/dicts/blue-obelisk/index.xhtml#zmatrixCoordinatesIntoCartesianCoordinates">blue-obelisk:zmatrixCoordinatesIntoCartesianCoordinates</a> void InternalToCartesian(std::vector<OBInternalCoord*> &vic,OBMol &mol) { vector3 n,nn,v1,v2,v3,avec,bvec,cvec; double dst = 0.0, ang = 0.0, tor = 0.0; OBAtom *atom; vector<OBAtom*>::iterator i; unsigned int index; if (vic.empty()) return; if (vic[0] != NULL) { std::vector<OBInternalCoord*>::iterator it = vic.begin(); vic.insert(it, static_cast<OBInternalCoord*>(NULL)); } if (vic.size() != mol.NumAtoms() + 1) { string error = "Number of internal coordinates is not the same as"; error += " the number of atoms in molecule"; obErrorLog.ThrowError(__FUNCTION__, error, obError); return; } obErrorLog.ThrowError(__FUNCTION__, "Ran OpenBabel::InternalToCartesian", obAuditMsg); for (atom = mol.BeginAtom(i);atom;atom = mol.NextAtom(i)) { index = atom->GetIdx(); // make sure we always have valid pointers if (index >= vic.size() || !vic[index]) return; if (vic[index]->_a) // make sure we have a valid ptr { avec = vic[index]->_a->GetVector(); dst = vic[index]->_dst; } else { // atom 1 atom->SetVector(0.0, 0.0, 0.0); continue; } if (vic[index]->_b) { bvec = vic[index]->_b->GetVector(); ang = vic[index]->_ang * DEG_TO_RAD; } else { // atom 2 atom->SetVector(dst, 0.0, 0.0); continue; } if (vic[index]->_c) { cvec = vic[index]->_c->GetVector(); tor = vic[index]->_tor * DEG_TO_RAD; } else { // atom 3 cvec = VY; tor = 90. * DEG_TO_RAD; } v1 = avec - bvec; v2 = avec - cvec; n = cross(v1,v2); nn = cross(v1,n); n.normalize(); nn.normalize(); n *= -sin(tor); nn *= cos(tor); v3 = n + nn; v3.normalize(); v3 *= dst * sin(ang); v1.normalize(); v1 *= dst * cos(ang); v2 = avec + v3 - v1; atom->SetVector(v2); } // Delete dummy atoms vector<OBAtom*> for_deletion; FOR_ATOMS_OF_MOL(a, mol) if (a->GetAtomicNum() == 0) for_deletion.push_back(&(*a)); for(vector<OBAtom*>::iterator a_it=for_deletion.begin(); a_it!=for_deletion.end(); ++a_it) mol.DeleteAtom(*a_it); }
bool BGFFormat::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; mol.SetTitle( pConv->GetTitle()); //default title is the filename mol.BeginModify(); char buffer[BUFF_SIZE]; char tmp[16],tmptyp[16]; while (ifs.getline(buffer,BUFF_SIZE)) if (EQn(buffer,"FORMAT",6)) break; ttab.SetFromType("DRE"); ttab.SetToType("INT"); OBAtom *atom; double x,y,z,chrg; for (;;) { if (!ifs.getline(buffer,BUFF_SIZE)) break; if (EQn(buffer,"FORMAT",6)) break; sscanf(buffer,"%*s %*s %*s %*s %*s %*s %lf %lf %lf %15s %*s %*s %lf", &x,&y,&z, tmptyp, &chrg); atom = mol.NewAtom(); ttab.Translate(tmp,tmptyp); atom->SetType(tmp); CleanAtomType(tmptyp); atom->SetAtomicNum(etab.GetAtomicNum(tmptyp)); atom->SetVector(x,y,z); } unsigned int i; vector<int> vtmp; vector<vector<int> > vcon; vector<vector<int> > vord; for (i = 0; i < mol.NumAtoms();i++) { vcon.push_back(vtmp); vord.push_back(vtmp); } unsigned int bgn; vector<string> vs; for (;;) { if (!ifs.getline(buffer,BUFF_SIZE) || EQn(buffer,"END",3)) break; tokenize(vs,buffer); if (vs.empty() || vs.size() < 3 || vs.size() > 10) continue; if (EQn(buffer,"CONECT",6)) { bgn = atoi((char*)vs[1].c_str()) - 1; if (bgn < 1 || bgn > mol.NumAtoms()) continue; for (i = 2;i < vs.size();i++) { vcon[bgn].push_back(atoi((char*)vs[i].c_str())); vord[bgn].push_back(1); } } else if (EQn(buffer,"ORDER",5)) { bgn = atoi((char*)vs[1].c_str()) - 1; if (bgn < 1 || bgn > mol.NumAtoms()) continue; if (vs.size() > vord[bgn].size()+2) continue; for (i = 2;i < vs.size();i++) vord[bgn][i-2] = atoi((char*)vs[i].c_str()); } } unsigned int j; for (i = 1;i <= mol.NumAtoms();i++) if (!vcon[i - 1].empty()) for (j = 0;j < vcon[i - 1].size();j++) { mol.AddBond(i,vcon[i - 1][j],vord[i - 1][j]); } //load up the next line after the END marker ifs.getline(buffer,BUFF_SIZE); mol.EndModify(); return(true); }
bool CCCFormat::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; mol.SetTitle( pConv->GetTitle()); //default title is the filename char buffer[BUFF_SIZE]; ifs.getline(buffer,BUFF_SIZE); if (strlen(buffer) > 5) mol.SetTitle(&buffer[5]); mol.SetEnergy(0.0); int natoms; ifs.getline(buffer,BUFF_SIZE); sscanf(buffer,"%*s%d",&natoms); mol.ReserveAtoms(natoms); mol.BeginModify(); int end,order; double x,y,z; OBAtom atom; vector3 v; vector<string> vs; char element[3]; element[2] = '\0'; for (int i = 1;i <= natoms;i++) { if (!ifs.getline(buffer,BUFF_SIZE)) return(false); atom.Clear(); element[0] = buffer[0]; element[1] = (buffer[1] != ' ') ? buffer[1]:'\0'; atom.SetAtomicNum(etab.GetAtomicNum(element)); sscanf(&buffer[15],"%lf%lf%lf",&x,&y,&z); v.Set(x,y,z); atom.SetVector(v); if (!mol.AddAtom(atom)) return(false); tokenize(vs,&buffer[60]); vector<string>::iterator j; for (j = vs.begin();j != vs.end();j++) if (!j->empty()) { //get the bond order switch((char)(*j)[j->size()-1]) { case 'S': order = 1; break; case 'D': order = 2; break; case 'T': order = 3; break; default: order = 1; } (*j)[j->size()-1] = ' '; end = atoi(j->c_str()); if (i>end) mol.AddBond(i,end,order); } } mol.EndModify(); return(true); }
bool PWscfFormat::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(); char buffer[BUFF_SIZE], tag[BUFF_SIZE]; double x,y,z; double alat = 1.0; vector<string> vs; matrix3x3 ortho; int atomicNum; OBUnitCell *cell = new OBUnitCell(); bool hasEnthalpy=false; double enthalpy, pv; pmol->BeginModify(); while (ifs.getline(buffer,BUFF_SIZE)) { // Older version of pwscf may use this for alat if (strstr(buffer, "lattice parameter (a_0)")) { tokenize(vs, buffer); alat = atof(vs.at(4).c_str()); } // Newer versions will use this for alat instead if (strstr(buffer, "lattice parameter (alat)")) { tokenize(vs, buffer); alat = atof(vs.at(4).c_str()); } // Unit cell info // Newer versions will also say "CELL_PARAMETERS" to complain that no // units were specified if (strstr(buffer, "CELL_PARAMETERS") && !strstr(buffer, "no units specified in CELL_PARAMETERS card")) { // Discover units double conv = 1.0; tokenize(vs, buffer); if (strstr(vs[1].c_str(), "alat")) { conv = alat * BOHR_TO_ANGSTROM; } else if (strstr(vs[1].c_str(), "bohr")) { conv = BOHR_TO_ANGSTROM; } // Add others if needed double v11, v12, v13, v21, v22, v23, v31, v32, v33; ifs.getline(buffer,BUFF_SIZE); // v1 tokenize(vs, buffer); v11 = atof(vs.at(0).c_str()) * conv; v12 = atof(vs.at(1).c_str()) * conv; v13 = atof(vs.at(2).c_str()) * conv; ifs.getline(buffer,BUFF_SIZE); // v2 tokenize(vs, buffer); v21 = atof(vs.at(0).c_str()) * conv; v22 = atof(vs.at(1).c_str()) * conv; v23 = atof(vs.at(2).c_str()) * conv; ifs.getline(buffer,BUFF_SIZE); // v3 tokenize(vs, buffer); v31 = atof(vs.at(0).c_str()) * conv; v32 = atof(vs.at(1).c_str()) * conv; v33 = atof(vs.at(2).c_str()) * conv; // Build unit cell cell->SetData(vector3(v11,v12,v13), vector3(v21,v22,v23), vector3(v31,v32,v33)); } // Unit cell info (for non-variable cell calcs) if (strstr(buffer, "crystal axes: (cart. coord. in units of a_0)") || strstr(buffer, "crystal axes: (cart. coord. in units of alat)")) { double conv = alat * BOHR_TO_ANGSTROM; double v11, v12, v13, v21, v22, v23, v31, v32, v33; ifs.getline(buffer,BUFF_SIZE); // v1 tokenize(vs, buffer); v11 = atof(vs.at(3).c_str()) * conv; v12 = atof(vs.at(4).c_str()) * conv; v13 = atof(vs.at(5).c_str()) * conv; ifs.getline(buffer,BUFF_SIZE); // v2 tokenize(vs, buffer); v21 = atof(vs.at(3).c_str()) * conv; v22 = atof(vs.at(4).c_str()) * conv; v23 = atof(vs.at(5).c_str()) * conv; ifs.getline(buffer,BUFF_SIZE); // v3 tokenize(vs, buffer); v31 = atof(vs.at(3).c_str()) * conv; v32 = atof(vs.at(4).c_str()) * conv; v33 = atof(vs.at(5).c_str()) * conv; // Build unit cell cell->SetData(vector3(v11,v12,v13), vector3(v21,v22,v23), vector3(v31,v32,v33)); } // Atoms info if (strstr(buffer, "ATOMIC_POSITIONS")) { // Clear old atoms from pmol vector<OBAtom*> toDelete; FOR_ATOMS_OF_MOL(a, *pmol) toDelete.push_back(&*a); for (size_t i = 0; i < toDelete.size(); i++) pmol->DeleteAtom(toDelete.at(i)); // Discover units matrix3x3 conv (1); tokenize(vs, buffer); if (strstr(vs[1].c_str(), "alat")) { conv *= (alat * BOHR_TO_ANGSTROM); } else if (strstr(vs[1].c_str(), "crystal")) { // Set to the zero matrix and test below. conv = matrix3x3 (0.0); } // Add others if needed // Load new atoms from molecule ifs.getline(buffer,BUFF_SIZE); // First entry tokenize(vs, buffer); int size = vs.size(); while (size == 4) { atomicNum = OBElements::GetAtomicNum(vs[0].c_str()); x = atof((char*)vs[1].c_str()); y = atof((char*)vs[2].c_str()); z = atof((char*)vs[3].c_str()); // Add atom OBAtom *atom = pmol->NewAtom(); atom->SetAtomicNum(atomicNum); vector3 coords (x,y,z); if (conv.determinant() == 0.0) { // Fractional coords atom->SetVector(cell->FractionalToCartesian(coords)); } else { atom->SetVector(conv * coords); } // Reset vars ifs.getline(buffer,BUFF_SIZE); // First entry tokenize(vs, buffer); size = vs.size(); } } // Free energy if (strstr(buffer, "Final energy =")) { tokenize(vs, buffer); pmol->SetEnergy(atof(vs[3].c_str()) * RYDBERG_TO_KCAL_PER_MOL); } // H - PV = U energy if (strstr(buffer, "! total energy =")) { tokenize(vs, buffer); pmol->SetEnergy(atof(vs[4].c_str()) * RYDBERG_TO_KCAL_PER_MOL); } // Enthalphy if (strstr(buffer, "Final enthalpy =")) { tokenize(vs, buffer); hasEnthalpy = true; enthalpy = atof(vs.at(3).c_str()) * RYDBERG_TO_KCAL_PER_MOL; pv = enthalpy - pmol->GetEnergy(); } } // set final unit cell pmol->SetData(cell); // Set enthalpy if (hasEnthalpy) { OBPairData *enthalpyPD = new OBPairData(); OBPairData *enthalpyPD_pv = new OBPairData(); OBPairData *enthalpyPD_eV = new OBPairData(); OBPairData *enthalpyPD_pv_eV = new OBPairData(); enthalpyPD->SetAttribute("Enthalpy (kcal/mol)"); enthalpyPD_pv->SetAttribute("Enthalpy PV term (kcal/mol)"); enthalpyPD_eV->SetAttribute("Enthalpy (eV)"); enthalpyPD_pv_eV->SetAttribute("Enthalpy PV term (eV)"); double en_kcal_per_mole = enthalpy; double pv_kcal_per_mole = pv; double en_eV = enthalpy / EV_TO_KCAL_PER_MOL; double pv_eV = pv / EV_TO_KCAL_PER_MOL; snprintf(tag, BUFF_SIZE, "%f", en_kcal_per_mole); enthalpyPD->SetValue(tag); snprintf(tag, BUFF_SIZE, "%f", pv_kcal_per_mole); enthalpyPD_pv->SetValue(tag); snprintf(tag, BUFF_SIZE, "%f", en_eV); enthalpyPD_eV->SetValue(tag); snprintf(tag, BUFF_SIZE, "%f", pv_eV); enthalpyPD_pv_eV->SetValue(tag); pmol->SetData(enthalpyPD); pmol->SetData(enthalpyPD_pv); pmol->SetData(enthalpyPD_eV); pmol->SetData(enthalpyPD_pv_eV); } pmol->EndModify(); return true; }
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; } // OK, just read MOLECULE line int lcount; int natoms,nbonds; bool hasPartialCharges = true; 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 == 3) // charge descriptions { // Annotate origin of partial charges OBPairData *dp = new OBPairData; dp->SetAttribute("PartialCharges"); dp->SetValue(buffer); dp->SetOrigin(fileformatInput); mol.SetData(dp); if (strncasecmp(buffer, "NO_CHARGES", 10) == 0) hasPartialCharges = false; } 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; 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); } // 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(); /* Disabled due to PR#3048758 -- seekg is very slow with gzipped mol2 // 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 MSIFormat::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]; stringstream errorMsg; if (!ifs) return false; // we're attempting to read past the end of the file if (!ifs.getline(buffer,BUFF_SIZE)) { obErrorLog.ThrowError(__FUNCTION__, "Problems reading an MSI file: Cannot read the first line.", obWarning); return(false); } if (!EQn(buffer, "# MSI CERIUS2 DataModel File", 28)) { obErrorLog.ThrowError(__FUNCTION__, "Problems reading an MSI file: The first line must contain the MSI header.", obWarning); return(false); } // "records" start with // (1 Model // .... // and end with // .... // ) unsigned int openParens = 0; // the count of "open parentheses" tags unsigned int startBondAtom, endBondAtom, bondOrder; bool atomRecord = false; bool bondRecord = false; OBAtom *atom; // OBBond *bond; vector<string> vs; const SpaceGroup *sg; bool setSpaceGroup = false; double x,y,z; vector3 translationVectors[3]; int numTranslationVectors = 0; mol.BeginModify(); while (ifs.getline(buffer,BUFF_SIZE)) { // model record if (strstr(buffer, "Model") != NULL) { openParens++; continue; } // atom record if (!bondRecord && strstr(buffer, "Atom") != NULL) { atomRecord = true; openParens++; continue; } if (strstr(buffer, "Bond") != NULL) { bondRecord = true; startBondAtom = endBondAtom = 0; bondOrder = 1; openParens++; continue; } /* (A I PeriodicType 100) (A D A3 (6.2380000000000004 0 0)) (A D B3 (0 6.9909999999999997 0)) (A D C3 (0 0 6.9960000000000004)) (A C SpaceGroup "63 5") */ if (strstr(buffer, "PeriodicType") != NULL) { ifs.getline(buffer,BUFF_SIZE); // next line should be translation vector tokenize(vs,buffer); while (vs.size() == 6) { x = atof((char*)vs[3].erase(0,1).c_str()); y = atof((char*)vs[4].c_str()); z = atof((char*)vs[5].c_str()); translationVectors[numTranslationVectors++].Set(x, y, z); if (!ifs.getline(buffer,BUFF_SIZE)) break; tokenize(vs,buffer); } } if (strstr(buffer, "SpaceGroup") != NULL) { tokenize(vs, buffer); if (vs.size() != 5) continue; // invalid space group setSpaceGroup = true; sg = SpaceGroup::GetSpaceGroup(vs[4]); // remove the initial " character } // atom information if (atomRecord) { if (strstr(buffer, "ACL") != NULL) { tokenize(vs, buffer); // size should be 5 -- need a test here if (vs.size() != 5) return false; // timvdm 18/06/2008 vs[3].erase(0,1); // "6 => remove the first " character unsigned int atomicNum = atoi(vs[3].c_str()); if (atomicNum == 0) atomicNum = 1; // hydrogen ? // valid element, so create the atom atom = mol.NewAtom(); atom->SetAtomicNum(atomicNum); continue; } else if (strstr(buffer, "XYZ") != NULL) { tokenize(vs, buffer); // size should be 6 -- need a test here if (vs.size() != 6) return false; // timvdm 18/06/2008 vs[3].erase(0,1); // remove ( character vs[5].erase(vs[5].length()-2, 2); // remove trailing )) characters atom->SetVector(atof(vs[3].c_str()), atof(vs[4].c_str()), atof(vs[5].c_str())); continue; } } // end of atom records // bond information if (bondRecord) { if (strstr(buffer, "Atom1") != NULL) { tokenize(vs, buffer); if (vs.size() < 4) return false; // timvdm 18/06/2008 vs[3].erase(vs[3].length()-1,1); startBondAtom = atoi(vs[3].c_str()); continue; } else if (strstr(buffer, "Atom2") != NULL) { tokenize(vs, buffer); if (vs.size() < 4) return false; // timvdm 18/06/2008 vs[3].erase(vs[3].length()-1,1); endBondAtom = atoi(vs[3].c_str()); continue; } else if (strstr(buffer, "Type") != NULL) { tokenize(vs, buffer); if (vs.size() < 4) return false; // timvdm 18/06/2008 vs[3].erase(vs[3].length()-1,1); bondOrder = atoi(vs[3].c_str()); if (bondOrder == 4) // triple bond? bondOrder = 3; else if (bondOrder == 8) // aromatic? bondOrder = 5; else if (bondOrder != 2) // 1 OK, 2 OK, others unknown bondOrder = 1; continue; } } // ending a "tag" -- a lone ")" on a line if (strstr(buffer,")") != NULL && strstr(buffer, "(") == NULL) { openParens--; if (atomRecord) { atomRecord = false; } if (bondRecord) { // Bond records appear to be questionable mol.AddBond(startBondAtom - 1, endBondAtom - 1, bondOrder); bondRecord = false; } if (openParens == 0) { ifs.getline(buffer, BUFF_SIZE); break; // closed this molecule } } } mol.EndModify(); // clean out any remaining blank lines while(ifs.peek() != EOF && ifs.good() && (ifs.peek() == '\n' || ifs.peek() == '\r')) ifs.getline(buffer,BUFF_SIZE); /* if (!pConv->IsOption("b",OBConversion::INOPTIONS)) mol.ConnectTheDots(); if (!pConv->IsOption("s",OBConversion::INOPTIONS) && !pConv->IsOption("b",OBConversion::INOPTIONS)) mol.PerceiveBondOrders(); */ if (numTranslationVectors > 0) { OBUnitCell* uc = new OBUnitCell; uc->SetData(translationVectors[0], translationVectors[1], translationVectors[2]); uc->SetOrigin(fileformatInput); if (setSpaceGroup) { uc->SetSpaceGroup(sg); } mol.SetData(uc); } return(true); }
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(); mol.SetPartialChargesPerceived(); // Annotate origin of partial charges OBPairData *dp = new OBPairData; dp->SetAttribute("PartialCharges"); dp->SetValue("MACROMODEL"); dp->SetOrigin(fileformatInput); mol.SetData(dp); OBBond *bond; vector<OBBond*>::iterator bi; for (bond = mol.BeginBond(bi);bond;bond = mol.NextBond(bi)) if (bond->GetBondOrder() == 5 && !bond->IsInRing()) bond->SetBondOrder(1); if ( natoms != (signed)mol.NumAtoms() ) return(false); // clean out remaining blank lines std::streampos ipos; do { ipos = ifs.tellg(); ifs.getline(buffer,BUFF_SIZE); } while(strlen(buffer) == 0 && !ifs.eof() ); ifs.seekg(ipos); return(true); }
bool TurbomoleFormat::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; double UnitConv=AAU; if(pConv->IsOption("a", OBConversion::INOPTIONS)) UnitConv=1; char buffer[BUFF_SIZE]; do { ifs.getline(buffer,BUFF_SIZE); if (ifs.peek() == EOF || !ifs.good()) return false; } while(strncmp(buffer,"$coord",6)); mol.BeginModify(); OBAtom atom; while(!(!ifs)) { ifs.getline(buffer,BUFF_SIZE); if(*buffer=='$') break; if(*buffer=='#') continue; float x,y,z; char atomtype[8]; if(sscanf(buffer,"%f %f %f %7s",&x,&y,&z,atomtype)!=4) return false; atom.SetVector(x*UnitConv, y*UnitConv, z*UnitConv); atom.SetAtomicNum(OBElements::GetAtomicNum(atomtype)); atom.SetType(atomtype); if(!mol.AddAtom(atom)) return false; atom.Clear(); } while(!(!ifs) && strncmp(buffer,"$end",4)) ifs.getline(buffer,BUFF_SIZE); if (!pConv->IsOption("b",OBConversion::INOPTIONS)) mol.ConnectTheDots(); if (!pConv->IsOption("s",OBConversion::INOPTIONS) && !pConv->IsOption("b",OBConversion::INOPTIONS)) mol.PerceiveBondOrders(); // clean out remaining blank lines std::streampos ipos; do { ipos = ifs.tellg(); ifs.getline(buffer,BUFF_SIZE); } while(strlen(buffer) == 0 && !ifs.eof() ); ifs.seekg(ipos); mol.EndModify(); return true; }
bool OBDepict::DrawMolecule(OBMol *mol) { if (!d->painter) return false; d->mol = mol; OBAtom *atom; OBBondIterator j; OBAtomIterator i; // 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); double width = max_x - min_x + 2*margin; double 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 for (OBBond *bond = mol->BeginBond(j); bond; bond = mol->NextBond(j)) { OBAtom *begin = bond->GetBeginAtom(); OBAtom *end = bond->GetEndAtom(); 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; 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; } d->painter->SetPenColor(OBColor(etab.GetRGB(atom->GetAtomicNum()))); //charge and radical NEEDS REVISION 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 (atom->GetValence() > 1) continue; if ((atom->GetValence() == 1) && !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 { unsigned int hCount = atom->ImplicitHydrogenCount(); // rightAligned: // false CH3 // true H3C if (hCount && rightAligned) ss << "H"; if ((hCount > 1) && rightAligned) ss << hCount; ss << etab.GetSymbol(atom->GetAtomicNum()); if (hCount && !rightAligned) ss << "H"; if ((hCount > 1) && !rightAligned) ss << hCount; } d->DrawAtomLabel(ss.str(), alignment, vector3(x, y, 0.0)); } return true; }
int mol(int argc, char* argv[]) { int defaultchoice = 1; int choice = defaultchoice; if (argc > 1) { if(sscanf(argv[1], "%d", &choice) != 1) { printf("Couldn't parse that input as a number\n"); return -1; } } // Define location of file formats for testing #ifdef FORMATDIR char env[BUFF_SIZE]; snprintf(env, BUFF_SIZE, "BABEL_LIBDIR=%s", FORMATDIR); putenv(env); #endif cout << "# Unit tests for OBMol \n"; cout << "ok 1\n"; // for loading tests OBMol emptyMol, testMol1; cout << "ok 2\n"; // ctor works testMol1.ReserveAtoms(-1); testMol1.ReserveAtoms(0); testMol1.ReserveAtoms(2); cout << "ok 3\n"; // atom component tests if (testMol1.NumAtoms() == 0) { cout << "ok 4\n"; } else { cout << "not ok 4\n"; } testMol1.NewAtom(); if (testMol1.NumAtoms() == 1) { cout << "ok 5\n"; } else { cout << "not ok 5\n"; } testMol1.NewAtom(); testMol1.AddBond(1, 2, 1); if (testMol1.NumBonds() == 1) { cout << "ok 6\n"; } else { cout << "not ok 6\n"; } testMol1.Clear(); if (testMol1.NumAtoms() == 0) { cout << "ok 7\n"; } else { cout << "not ok 7\n"; } ifstream ifs1(kd3file.c_str()); if (!ifs1) { cout << "Bail out! Cannot read input file!" << endl; return(-1); } OBConversion conv(&ifs1, &cout); OBFormat* pFormat; pFormat = conv.FindFormat("XYZ"); if ( pFormat == NULL ) { cout << "Bail out! Cannot read file format!" << endl; return(-1); } if (! conv.SetInAndOutFormats(pFormat, pFormat)) { cout << "Bail out! File format isn't loaded" << endl; return (-1); } OBMol testMol2D, testMol3D; if (conv.Read(&testMol3D)) cout << "ok 8\n"; else cout << "not ok 8\n"; testMol3D.Center(); // test bond insertion (PR#1665649) OBMol doubleBondMol; OBAtom *a1, *a2; OBBond *b; doubleBondMol.BeginModify(); a1 = doubleBondMol.NewAtom(); a1->SetVector(0.0, 0.0, 0.0); a1->SetAtomicNum(6); a2 = doubleBondMol.NewAtom(); a2->SetVector(1.6, 0.0, 0.0); a2->SetAtomicNum(6); b = doubleBondMol.NewBond(); b->SetBegin(a1); b->SetEnd(a2); a1->AddBond(b); a2->AddBond(b); doubleBondMol.EndModify(); cout << "ok 9" << endl; // test AddHydrogens OBMol testMolH; testMolH.BeginModify(); OBAtom *testAtom = testMolH.NewAtom(); testAtom->SetVector(0.5f, 0.5f, 0.5f); testAtom->SetAtomicNum(6); testAtom->SetImplicitHCount(4); testMolH.EndModify(); testMolH.AddHydrogens(); if (testMolH.NumAtoms() == 5) { cout << "ok 10" << endl; } else { cout << "not ok 10" << endl; } // test AddHydrogens (pr #1665519) OBMol testMolH2; OBAtom *testAtom2 = testMolH2.NewAtom(); testAtom2->SetVector(0.5f, 0.5f, 0.5f); testAtom2->SetAtomicNum(6); testAtom2->SetImplicitHCount(4); testMolH2.AddHydrogens(); if (testMolH2.NumAtoms() == 5) { cout << "ok 11" << endl; } else { cout << "not ok 11 # hydrogen additions" << endl; } // Attempt to write an empty InChI (PR#2864334) pFormat = conv.FindFormat("InChI"); if ( pFormat != NULL && conv.SetOutFormat(pFormat)) { if (conv.Write(&emptyMol)) cout << "ok 12" << endl; else cout << "not ok 12 # failed empty InChI" << endl; } OBMol testMolFormula; string formula("C6"); testMolFormula.SetFormula(formula); if ( testMolFormula.GetFormula() == formula ) { cout << "ok 13" << endl; } else { cout << "not ok 13 # SetFormula "<< endl; } // Reset the formula to test for a double delete error testMolFormula.SetFormula(formula); // Test molecular formulas with large atomic numbers OBMol testLgAtNo; testLgAtNo.BeginModify(); OBAtom *lgAtom = testLgAtNo.NewAtom(); lgAtom->SetAtomicNum(118); // Undefined atomic numbers should be ignored with an obWarning instead of segfault lgAtom = testLgAtNo.NewAtom(); lgAtom->SetAtomicNum(200); lgAtom = testLgAtNo.NewAtom(); lgAtom->SetAtomicNum(1); lgAtom->SetIsotope(2); testLgAtNo.EndModify(); if ( testLgAtNo.GetFormula() == "DOg" ) { cout << "ok 14" << endl; } else { cout << "not ok 14" << endl; } double dihedral = CalcTorsionAngle(vector3(-1., -1., 0.), vector3(-1., 0., 0.), vector3( 1., 0., 0.), vector3( 1., 1., 0.)); double dihedral_error = fabs(dihedral) - 180.0; if (fabs(dihedral_error) < 0.001) { std::cout << "ok 15 " << dihedral_error << std::endl; } else { std::cout << "not ok 15 # CalcTorsionAngle " << dihedral << "!= 180.0" << std::endl; } cout << "1..15\n"; // total number of tests for Perl's "prove" tool return(0); }
bool TinkerFormat::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 natoms; char buffer[BUFF_SIZE]; vector<string> vs; ifs.getline(buffer, BUFF_SIZE); tokenize(vs,buffer); if (vs.size() < 2) return false; natoms = atoi(vs[0].c_str()); // title is 2nd token (usually add tokens for the atom types) mol.SetTitle(vs[1]); mol.ReserveAtoms(natoms); mol.BeginModify(); string str; double x,y,z; OBAtom *atom; int atomicNum; for (int i = 1; i <= natoms; ++i) { if (!ifs.getline(buffer,BUFF_SIZE)) return(false); tokenize(vs,buffer); // e.g. "2 C 2.476285 0.121331 -0.001070 2 1 3 14" if (vs.size() < 5) return(false); atom = mol.NewAtom(); x = atof((char*)vs[2].c_str()); y = atof((char*)vs[3].c_str()); z = atof((char*)vs[4].c_str()); atom->SetVector(x,y,z); //set coordinates //set atomic number atom->SetAtomicNum(etab.GetAtomicNum(vs[1].c_str())); // add bonding if (vs.size() > 6) for (int j = 6; j < vs.size(); ++j) mol.AddBond(mol.NumAtoms(), atoi((char *)vs[j].c_str()), 1); // we don't know the bond order } if (!pConv->IsOption("s",OBConversion::INOPTIONS)) mol.PerceiveBondOrders(); // clean out 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); }