// Reading Gaussian output has been tested for G98 and G03 to some degree // If you have problems (or examples of older output), please contact // the [email protected] mailing list and/or post a bug bool GaussianOutputFormat::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,str1,str2,thermo_method; double x,y,z; OBAtom *atom; vector<string> vs,vs2; int total_charge = 0; unsigned int spin_multiplicity = 1; bool hasPartialCharges = false; string chargeModel; // descriptor for charges (e.g. "Mulliken") // Variable for G2/G3/G4 etc. calculations double ezpe,Hcorr,Gcorr,E0,CV; bool ezpe_set=false,Hcorr_set=false,Gcorr_set=false,E0_set=false,CV_set=false; double temperature = 0; /* Kelvin */ std::vector<double> Scomponents; // Electrostatic potential OBFreeGrid *esp = NULL; // coordinates of all steps // Set conformers to all coordinates we adopted std::vector<double*> vconf; // index of all frames/conformers std::vector<double> coordinates; // coordinates in each frame int natoms = 0; // number of atoms -- ensure we don't go to a new job with a different molecule // OBConformerData stores information about multiple steps // we can change attribute later if needed (e.g., IRC) OBConformerData *confData = new OBConformerData(); confData->SetOrigin(fileformatInput); std::vector<unsigned short> confDimensions = confData->GetDimension(); // to be fair, set these all to 3D std::vector<double> confEnergies = confData->GetEnergies(); std::vector< std::vector< vector3 > > confForces = confData->GetForces(); //Vibrational data std::vector< std::vector< vector3 > > Lx; std::vector<double> Frequencies, Intensities; //Rotational data std::vector<double> RotConsts(3); int RotSymNum=1; OBRotationData::RType RotorType = OBRotationData::UNKNOWN; // Translation vectors (if present) vector3 translationVectors[3]; int numTranslationVectors = 0; //Electronic Excitation data std::vector<double> Forces, Wavelengths, EDipole, RotatoryStrengthsVelocity, RotatoryStrengthsLength; // Orbital data std::vector<double> orbitals; std::vector<std::string> symmetries; int aHOMO, bHOMO, betaStart; aHOMO = bHOMO = betaStart = -1; int i=0; bool no_symmetry=false; char coords_type[25]; //Prescan file to find second instance of "orientation:" //This will be the kind of coords used in the chk/fchk file //Unless the "nosym" keyword has been requested while (ifs.getline(buffer,BUFF_SIZE)) { if (strstr(buffer,"Symmetry turned off by external request.") != NULL) { // The "nosym" keyword has been requested no_symmetry = true; } if (strstr(buffer,"orientation:") !=NULL) { i++; tokenize (vs, buffer); // gotta check what types of orientation are present strncpy (coords_type, vs[0].c_str(), 24); strcat (coords_type, " orientation:"); } if ((no_symmetry && i==1) || i==2) break; } // Reset end-of-file pointers etc. ifs.clear(); ifs.seekg(0); //rewind mol.BeginModify(); while (ifs.getline(buffer,BUFF_SIZE)) { if(strstr(buffer, "Entering Gaussian") != NULL) { //Put some metadata into OBCommentData string comment("Gaussian "); if(NULL != strchr(buffer,'=')) { comment += strchr(buffer,'=')+2; comment += ""; for(unsigned i=0; i<115 && ifs; ++i) { ifs.getline(buffer,BUFF_SIZE); if(strstr(buffer,"Revision") != NULL) { if (buffer[strlen(buffer)-1] == ',') { buffer[strlen(buffer)-1] = '\0'; } add_unique_pairdata_to_mol(&mol,"program",buffer,0); } else if(buffer[1]=='#') { //the line describing the method comment += buffer; OBCommentData *cd = new OBCommentData; cd->SetData(comment); cd->SetOrigin(fileformatInput); mol.SetData(cd); tokenize(vs,buffer); if (vs.size() > 1) { char *str = strdup(vs[1].c_str()); char *ptr = strchr(str,'/'); if (NULL != ptr) { *ptr = ' '; add_unique_pairdata_to_mol(&mol,"basis",ptr,0); *ptr = '\0'; add_unique_pairdata_to_mol(&mol,"method",str,0); } } break; } } } } else if (strstr(buffer,"Multiplicity") != NULL) { tokenize(vs, buffer, " \t\n"); if (vs.size() == 6) { total_charge = atoi(vs[2].c_str()); spin_multiplicity = atoi(vs[5].c_str()); } ifs.getline(buffer,BUFF_SIZE); } else if (strstr(buffer, coords_type) != NULL) { numTranslationVectors = 0; // ignore old translationVectors ifs.getline(buffer,BUFF_SIZE); // --------------- ifs.getline(buffer,BUFF_SIZE); // column headings ifs.getline(buffer,BUFF_SIZE); // column headings ifs.getline(buffer,BUFF_SIZE); // --------------- ifs.getline(buffer,BUFF_SIZE); tokenize(vs,buffer); while (vs.size()>4) { int corr = vs.size()==5 ? -1 : 0; //g94; later versions have an extra column x = atof((char*)vs[3+corr].c_str()); y = atof((char*)vs[4+corr].c_str()); z = atof((char*)vs[5+corr].c_str()); int atomicNum = atoi((char*)vs[1].c_str()); if (atomicNum > 0) // translation vectors are "-2" { if (natoms == 0) { // first time reading the molecule, create each atom atom = mol.NewAtom(); atom->SetAtomicNum(atoi((char*)vs[1].c_str())); } coordinates.push_back(x); coordinates.push_back(y); coordinates.push_back(z); } else { translationVectors[numTranslationVectors++].Set(x, y, z); } if (!ifs.getline(buffer,BUFF_SIZE)) { break; } tokenize(vs,buffer); } // done with reading atoms natoms = mol.NumAtoms(); if(natoms==0) return false; // malloc / memcpy double *tmpCoords = new double [(natoms)*3]; memcpy(tmpCoords, &coordinates[0], sizeof(double)*natoms*3); vconf.push_back(tmpCoords); coordinates.clear(); confDimensions.push_back(3); // always 3D -- OBConformerData allows mixing 2D and 3D structures } else if(strstr(buffer,"Dipole moment") != NULL) { ifs.getline(buffer,BUFF_SIZE); // actual components X ### Y #### Z ### tokenize(vs,buffer); if (vs.size() >= 6) { OBVectorData *dipoleMoment = new OBVectorData; dipoleMoment->SetAttribute("Dipole Moment"); double x, y, z; x = atof(vs[1].c_str()); y = atof(vs[3].c_str()); z = atof(vs[5].c_str()); dipoleMoment->SetData(x, y, z); dipoleMoment->SetOrigin(fileformatInput); mol.SetData(dipoleMoment); } if (!ifs.getline(buffer,BUFF_SIZE)) break; } else if(strstr(buffer,"Traceless Quadrupole moment") != NULL) { ifs.getline(buffer,BUFF_SIZE); // actual components XX ### YY #### ZZ ### tokenize(vs,buffer); ifs.getline(buffer,BUFF_SIZE); // actual components XY ### XZ #### YZ ### tokenize(vs2,buffer); if ((vs.size() >= 6) && (vs2.size() >= 6)) { double Q[3][3]; OpenBabel::OBMatrixData *quadrupoleMoment = new OpenBabel::OBMatrixData; Q[0][0] = atof(vs[1].c_str()); Q[1][1] = atof(vs[3].c_str()); Q[2][2] = atof(vs[5].c_str()); Q[1][0] = Q[0][1] = atof(vs2[1].c_str()); Q[2][0] = Q[0][2] = atof(vs2[3].c_str()); Q[2][1] = Q[1][2] = atof(vs2[5].c_str()); matrix3x3 quad(Q); quadrupoleMoment->SetAttribute("Traceless Quadrupole Moment"); quadrupoleMoment->SetData(quad); quadrupoleMoment->SetOrigin(fileformatInput); mol.SetData(quadrupoleMoment); } if (!ifs.getline(buffer,BUFF_SIZE)) break; } else if(strstr(buffer,"Exact polarizability") != NULL) { // actual components XX, YX, YY, XZ, YZ, ZZ tokenize(vs,buffer); if (vs.size() >= 8) { double Q[3][3]; OpenBabel::OBMatrixData *pol_tensor = new OpenBabel::OBMatrixData; Q[0][0] = atof(vs[2].c_str()); Q[1][1] = atof(vs[4].c_str()); Q[2][2] = atof(vs[7].c_str()); Q[1][0] = Q[0][1] = atof(vs[3].c_str()); Q[2][0] = Q[0][2] = atof(vs[5].c_str()); Q[2][1] = Q[1][2] = atof(vs[6].c_str()); matrix3x3 pol(Q); pol_tensor->SetAttribute("Exact polarizability"); pol_tensor->SetData(pol); pol_tensor->SetOrigin(fileformatInput); mol.SetData(pol_tensor); } if (!ifs.getline(buffer,BUFF_SIZE)) break; } else if(strstr(buffer,"Total atomic charges") != NULL || strstr(buffer,"Mulliken atomic charges") != NULL) { hasPartialCharges = true; chargeModel = "Mulliken"; ifs.getline(buffer,BUFF_SIZE); // column headings ifs.getline(buffer,BUFF_SIZE); tokenize(vs,buffer); while (vs.size() >= 3 && strstr(buffer,"Sum of ") == NULL) { atom = mol.GetAtom(atoi(vs[0].c_str())); if (!atom) break; atom->SetPartialCharge(atof(vs[2].c_str())); if (!ifs.getline(buffer,BUFF_SIZE)) break; tokenize(vs,buffer); } } else if (strstr(buffer, "Atomic Center") != NULL) { // Data points for ESP calculation tokenize(vs,buffer); if (NULL == esp) esp = new OpenBabel::OBFreeGrid(); if (vs.size() == 8) { esp->AddPoint(atof(vs[5].c_str()),atof(vs[6].c_str()), atof(vs[7].c_str()),0); } else if (vs.size() > 5) { double x,y,z; if (3 == sscanf(buffer+32,"%10lf%10lf%10lf",&x,&y,&z)) { esp->AddPoint(x,y,z,0); } } } else if (strstr(buffer, "ESP Fit Center") != NULL) { // Data points for ESP calculation tokenize(vs,buffer); if (NULL == esp) esp = new OpenBabel::OBFreeGrid(); if (vs.size() == 9) { esp->AddPoint(atof(vs[6].c_str()),atof(vs[7].c_str()), atof(vs[8].c_str()),0); } else if (vs.size() > 6) { double x,y,z; if (3 == sscanf(buffer+32,"%10lf%10lf%10lf",&x,&y,&z)) { esp->AddPoint(x,y,z,0); } } } else if (strstr(buffer, "Electrostatic Properties (Atomic Units)") != NULL) { int i,np; OpenBabel::OBFreeGridPoint *fgp; OpenBabel::OBFreeGridPointIterator fgpi; for(i=0; (i<5); i++) { ifs.getline(buffer,BUFF_SIZE); // skip line } // Assume file is correct and that potentials are present // where they should. np = esp->NumPoints(); fgpi = esp->BeginPoints(); i = 0; for(fgp = esp->BeginPoint(fgpi); (NULL != fgp); fgp = esp->NextPoint(fgpi)) { ifs.getline(buffer,BUFF_SIZE); tokenize(vs,buffer); if (vs.size() >= 2) { fgp->SetV(atof(vs[2].c_str())); i++; } } if (i == np) { esp->SetAttribute("Electrostatic Potential"); mol.SetData(esp); } else { cout << "Read " << esp->NumPoints() << " ESP points i = " << i << "\n"; } } else if (strstr(buffer, "Charges from ESP fit") != NULL) { hasPartialCharges = true; chargeModel = "ESP"; ifs.getline(buffer,BUFF_SIZE); // Charge / dipole line ifs.getline(buffer,BUFF_SIZE); // column header ifs.getline(buffer,BUFF_SIZE); // real charges tokenize(vs,buffer); while (vs.size() >= 3 && strstr(buffer,"-----") == NULL) { atom = mol.GetAtom(atoi(vs[0].c_str())); if (!atom) break; atom->SetPartialCharge(atof(vs[2].c_str())); if (!ifs.getline(buffer,BUFF_SIZE)) break; tokenize(vs,buffer); } } else if(strstr(buffer,"Natural Population") != NULL) { hasPartialCharges = true; chargeModel = "NBO"; ifs.getline(buffer,BUFF_SIZE); // column headings ifs.getline(buffer,BUFF_SIZE); // again ifs.getline(buffer,BUFF_SIZE); // again (-----) ifs.getline(buffer,BUFF_SIZE); // real data tokenize(vs,buffer); while (vs.size() >= 3 && strstr(buffer,"=====") == NULL) { atom = mol.GetAtom(atoi(vs[1].c_str())); if (!atom) break; atom->SetPartialCharge(atof(vs[2].c_str())); if (!ifs.getline(buffer,BUFF_SIZE)) break; tokenize(vs,buffer); } } else if(strstr(buffer, " Frequencies -- ")) //vibrational frequencies { //The info should appear only once as several blocks starting with this line tokenize(vs, buffer); for(unsigned int i=2; i<vs.size(); ++i) Frequencies.push_back(atof(vs[i].c_str())); ifs.getline(buffer,BUFF_SIZE); //Red. masses ifs.getline(buffer,BUFF_SIZE); //Frc consts ifs.getline(buffer,BUFF_SIZE); //IR Inten tokenize(vs, buffer); for(unsigned int i=3; i<vs.size(); ++i) Intensities.push_back(atof(vs[i].c_str())); ifs.getline(buffer, BUFF_SIZE); // column labels or Raman intensity if(strstr(buffer, "Raman Activ")) { ifs.getline(buffer, BUFF_SIZE); // Depolar (P) ifs.getline(buffer, BUFF_SIZE); // Depolar (U) ifs.getline(buffer, BUFF_SIZE); // column labels } ifs.getline(buffer, BUFF_SIZE); // actual displacement data tokenize(vs, buffer); vector<vector3> vib1, vib2, vib3; double x, y, z; while(vs.size() >= 5) { for (unsigned int i = 2; i < vs.size()-2; i += 3) { x = atof(vs[i].c_str()); y = atof(vs[i+1].c_str()); z = atof(vs[i+2].c_str()); if (i == 2) vib1.push_back(vector3(x, y, z)); else if (i == 5) vib2.push_back(vector3(x, y, z)); else if (i == 8) vib3.push_back(vector3(x, y, z)); } if (!ifs.getline(buffer, BUFF_SIZE)) break; tokenize(vs,buffer); } Lx.push_back(vib1); if (vib2.size()) Lx.push_back(vib2); if (vib3.size()) Lx.push_back(vib3); } else if(strstr(buffer, " This molecule is "))//rotational data { if(strstr(buffer, "asymmetric")) RotorType = OBRotationData::ASYMMETRIC; else if(strstr(buffer, "symmetric")) RotorType = OBRotationData::SYMMETRIC; else if(strstr(buffer, "linear")) RotorType = OBRotationData::LINEAR; else RotorType = OBRotationData::UNKNOWN; ifs.getline(buffer,BUFF_SIZE); //symmetry number tokenize(vs, buffer); RotSymNum = atoi(vs[3].c_str()); } else if(strstr(buffer, "Rotational constant")) { tokenize(vs, buffer); RotConsts.clear(); for (unsigned int i=3; i<vs.size(); ++i) RotConsts.push_back(atof(vs[i].c_str())); } else if(strstr(buffer, "alpha electrons")) // # of electrons / orbital { tokenize(vs, buffer); if (vs.size() == 6) { // # alpha electrons # beta electrons aHOMO = atoi(vs[0].c_str()); bHOMO = atoi(vs[3].c_str()); } } else if(strstr(buffer, "rbital symmetries")) // orbital symmetries { symmetries.clear(); std::string label; // used as a temporary to remove "(" and ")" from labels int iii,offset = 0; bool bDoneSymm; // Extract both Alpha and Beta symmetries ifs.getline(buffer, BUFF_SIZE); // skip the current line for(iii=0; (iii<2); iii++) { if (strstr(buffer, "electronic state")) break; // We've gone too far! while (!ifs.eof() && ((NULL != strstr(buffer,"Alpha")) || (NULL != strstr(buffer,"Beta")))) { // skip the Alpha: and Beta: title lines ifs.getline(buffer, BUFF_SIZE); } do { bDoneSymm = (NULL == strstr(buffer, "(")); if (!bDoneSymm) { tokenize(vs, buffer); if ((NULL != strstr(buffer, "Occupied")) || (NULL != strstr(buffer, "Virtual"))) { offset = 1; // skip first token } else { offset = 0; } for (unsigned int i = offset; i < vs.size(); ++i) { label = vs[i].substr(1, vs[i].length() - 2); symmetries.push_back(label); } ifs.getline(buffer, BUFF_SIZE); // get a new line if we've been reading symmetries } // don't read a new line if we're done with symmetries } while (!ifs.eof() && !bDoneSymm); } // end alpha/beta section } else if (strstr(buffer, "Alpha") && strstr(buffer, ". eigenvalues --")) { orbitals.clear(); betaStart = 0; while (strstr(buffer, ". eigenvalues --")) { tokenize(vs, buffer); if (vs.size() < 4) break; if (vs[0].find("Beta") !=string::npos && betaStart == 0) // mark where we switch from alpha to beta betaStart = orbitals.size(); for (unsigned int i = 4; i < vs.size(); ++i) { orbitals.push_back(atof(vs[i].c_str())); } ifs.getline(buffer, BUFF_SIZE); } } else if(strstr(buffer, " Excited State")) // Force and wavelength data { // The above line appears for each state, so just append the info to the vectors tokenize(vs, buffer); if (vs.size() >= 9) { double wavelength = atof(vs[6].c_str()); double force = atof(vs[8].substr(2).c_str()); // remove the "f=" part Forces.push_back(force); Wavelengths.push_back(wavelength); } } else if(strstr(buffer, " Ground to excited state Transition electric dipole moments (Au):")) // Electronic dipole moments { ifs.getline(buffer, BUFF_SIZE); // Headings ifs.getline(buffer, BUFF_SIZE); // First entry tokenize(vs, buffer); while (vs.size() == 5) { double s = atof(vs[4].c_str()); EDipole.push_back(s); ifs.getline(buffer, BUFF_SIZE); tokenize(vs, buffer); } } else if(strstr(buffer, " state X Y Z R(velocity)")) { // Rotatory Strengths ifs.getline(buffer, BUFF_SIZE); // First entry tokenize(vs, buffer); while (vs.size() == 5) { double s = atof(vs[4].c_str()); RotatoryStrengthsVelocity.push_back(s); ifs.getline(buffer, BUFF_SIZE); tokenize(vs, buffer); } } else if(strstr(buffer, " state X Y Z R(length)")) { // Rotatory Strengths ifs.getline(buffer, BUFF_SIZE); // First entry tokenize(vs, buffer); while (vs.size() == 5) { double s = atof(vs[4].c_str()); RotatoryStrengthsLength.push_back(s); ifs.getline(buffer, BUFF_SIZE); tokenize(vs, buffer); } } else if (strstr(buffer, "Forces (Hartrees/Bohr)")) { ifs.getline(buffer, BUFF_SIZE); // column headers ifs.getline(buffer, BUFF_SIZE); // ------ ifs.getline(buffer, BUFF_SIZE); // real data } else if (strstr(buffer, "Isotropic = ")) // NMR shifts { tokenize(vs, buffer); if (vs.size() >= 4) { atom = mol.GetAtom(atoi(vs[0].c_str())); OBPairData *nmrShift = new OBPairData(); nmrShift->SetAttribute("NMR Isotropic Shift"); string shift = vs[4].c_str(); nmrShift->SetValue(shift); atom->SetData(nmrShift); } } else if(strstr(buffer,"SCF Done:") != NULL) { tokenize(vs,buffer); mol.SetEnergy(atof(vs[4].c_str()) * HARTEE_TO_KCALPERMOL); confEnergies.push_back(mol.GetEnergy()); } /* Temporarily commented out until the handling of energy in OBMol is sorted out // MP2 energies also use a different syntax // PM3 energies use a different syntax else if(strstr(buffer,"E (Thermal)") != NULL) { ifs.getline(buffer,BUFF_SIZE); //Headers ifs.getline(buffer,BUFF_SIZE); //Total energy; what we want tokenize(vs,buffer); mol.SetEnergy(atof(vs[1].c_str())); confEnergies.push_back(mol.GetEnergy()); } */ else if(strstr(buffer,"Standard basis:") != NULL) { add_unique_pairdata_to_mol(&mol,"basis",buffer,2); } else if(strstr(buffer,"Zero-point correction=") != NULL) { tokenize(vs,buffer); ezpe = atof(vs[2].c_str()); ezpe_set = true; } else if(strstr(buffer,"Thermal correction to Enthalpy=") != NULL) { tokenize(vs,buffer); Hcorr = atof(vs[4].c_str()); Hcorr_set = true; } else if(strstr(buffer,"Thermal correction to Gibbs Free Energy=") != NULL) { tokenize(vs,buffer); Gcorr = atof(vs[6].c_str()); Gcorr_set = true; } else if (strstr(buffer,"CV") != NULL) { ifs.getline(buffer,BUFF_SIZE); //Headers ifs.getline(buffer,BUFF_SIZE); //Total heat capacity tokenize(vs,buffer); if (vs.size() == 4) { if (vs[0].compare("Total") == 0) { CV = atof(vs[2].c_str()); CV_set = true; } } ifs.getline(buffer,BUFF_SIZE); //Electronic ifs.getline(buffer,BUFF_SIZE); //Translational tokenize(vs,buffer); if ((vs.size() == 4) && (vs[0].compare("Translational") == 0) ) { Scomponents.push_back(atof(vs[3].c_str())); } ifs.getline(buffer,BUFF_SIZE); //Rotational tokenize(vs,buffer); if ((vs.size() == 4) && (vs[0].compare("Rotational") == 0)) { Scomponents.push_back(atof(vs[3].c_str())); } ifs.getline(buffer,BUFF_SIZE); //Vibrational tokenize(vs,buffer); if ((vs.size() == 4) && (vs[0].compare("Vibrational") == 0)) { Scomponents.push_back(atof(vs[3].c_str())); } } else if ((strstr(buffer,"Temperature=") != NULL) && (strstr(buffer,"Pressure=") != NULL)) { tokenize(vs,buffer); temperature = atof(vs[1].c_str()); } else if (strstr(buffer, "(0 K)") != NULL) { /* This must be the last else */ int i,nsearch; const char *search[] = { "CBS-QB3 (0 K)", "G2(0 K)", "G3(0 K)", "G4(0 K)", "W1BD (0 K)", "W1U (0 K)" }; const char *mymeth[] = { "CBS-QB3", "G2", "G3", "G4", "W1BD", "W1U" }; const int myindex[] = { 3, 2, 2, 2, 3, 3 }; nsearch = sizeof(search)/sizeof(search[0]); for(i=0; (i<nsearch); i++) { if(strstr(buffer,search[i]) != NULL) { tokenize(vs,buffer); E0 = atof(vs[myindex[i]].c_str()); E0_set = 1; thermo_method = mymeth[i]; break; } } } } // end while if (mol.NumAtoms() == 0) { // e.g., if we're at the end of a file PR#1737209 mol.EndModify(); return false; } mol.EndModify(); // Set conformers to all coordinates we adopted // but remove last geometry -- it's a duplicate if (vconf.size() > 1) vconf.pop_back(); mol.SetConformers(vconf); mol.SetConformer(mol.NumConformers() - 1); // Copy the conformer data too confData->SetDimension(confDimensions); confData->SetEnergies(confEnergies); confData->SetForces(confForces); mol.SetData(confData); // Check whether we have data to extract heat of formation. if (ezpe_set && Hcorr_set && Gcorr_set && E0_set && CV_set && (thermo_method.size() > 0)) { extract_thermo(&mol,thermo_method,temperature,ezpe, Hcorr,Gcorr,E0,CV,RotSymNum,Scomponents); } // Attach orbital data, if there is any if (orbitals.size() > 0) { OBOrbitalData *od = new OBOrbitalData; if (aHOMO == bHOMO) { od->LoadClosedShellOrbitals(orbitals, symmetries, aHOMO); } else { // we have to separate the alpha and beta vectors std::vector<double> betaOrbitals; std::vector<std::string> betaSymmetries; unsigned int initialSize = orbitals.size(); unsigned int symmSize = symmetries.size(); if (initialSize != symmSize || betaStart == -1) { cerr << "Inconsistency: orbitals have " << initialSize << " elements while symmetries have " << symmSize << endl; } else { for (unsigned int i = betaStart; i < initialSize; ++i) { betaOrbitals.push_back(orbitals[i]); if (symmetries.size() > 0) betaSymmetries.push_back(symmetries[i]); } // ok, now erase the end elements of orbitals and symmetries for (unsigned int i = betaStart; i < initialSize; ++i) { orbitals.pop_back(); if (symmetries.size() > 0) symmetries.pop_back(); } // and load the alphas and betas od->LoadAlphaOrbitals(orbitals, symmetries, aHOMO); od->LoadBetaOrbitals(betaOrbitals, betaSymmetries, bHOMO); } } od->SetOrigin(fileformatInput); mol.SetData(od); } //Attach vibrational data, if there is any, to molecule if(Frequencies.size()>0) { OBVibrationData* vd = new OBVibrationData; vd->SetData(Lx, Frequencies, Intensities); vd->SetOrigin(fileformatInput); mol.SetData(vd); } //Attach rotational data, if there is any, to molecule if(RotConsts[0]!=0.0) { OBRotationData* rd = new OBRotationData; rd->SetData(RotorType, RotConsts, RotSymNum); rd->SetOrigin(fileformatInput); mol.SetData(rd); } // Attach unit cell translation vectors if found if (numTranslationVectors > 0) { OBUnitCell* uc = new OBUnitCell; uc->SetData(translationVectors[0], translationVectors[1], translationVectors[2]); uc->SetOrigin(fileformatInput); mol.SetData(uc); } //Attach electronic transition data, if there is any, to molecule if(Forces.size() > 0 && Forces.size() == Wavelengths.size()) { OBElectronicTransitionData* etd = new OBElectronicTransitionData; etd->SetData(Wavelengths, Forces); if (EDipole.size() == Forces.size()) etd->SetEDipole(EDipole); if (RotatoryStrengthsLength.size() == Forces.size()) etd->SetRotatoryStrengthsLength(RotatoryStrengthsLength); if (RotatoryStrengthsVelocity.size() == Forces.size()) etd->SetRotatoryStrengthsVelocity(RotatoryStrengthsVelocity); etd->SetOrigin(fileformatInput); mol.SetData(etd); } if (!pConv->IsOption("b",OBConversion::INOPTIONS)) mol.ConnectTheDots(); if (!pConv->IsOption("s",OBConversion::INOPTIONS) && !pConv->IsOption("b",OBConversion::INOPTIONS)) mol.PerceiveBondOrders(); if (hasPartialCharges) { mol.SetPartialChargesPerceived(); // Annotate that partial charges come from Mulliken OBPairData *dp = new OBPairData; dp->SetAttribute("PartialCharges"); dp->SetValue(chargeModel); // Mulliken, ESP, etc. dp->SetOrigin(fileformatInput); mol.SetData(dp); } mol.SetTotalCharge(total_charge); mol.SetTotalSpinMultiplicity(spin_multiplicity); mol.SetTitle(title); return(true); }
// Reading Gaussian output has been tested for G98 and G03 to some degree // If you have problems (or examples of older output), please contact // the [email protected] mailing list and/or post a bug bool GaussianOutputFormat::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,str1; double x,y,z; OBAtom *atom; vector<string> vs; int charge = 0; unsigned int spin = 1; bool hasPartialCharges = false; string chargeModel; // descriptor for charges (e.g. "Mulliken") // coordinates of all steps // Set conformers to all coordinates we adopted std::vector<double*> vconf; // index of all frames/conformers std::vector<double> coordinates; // coordinates in each frame int natoms = 0; // number of atoms -- ensure we don't go to a new job with a different molecule // OBConformerData stores information about multiple steps // we can change attribute later if needed (e.g., IRC) OBConformerData *confData = new OBConformerData(); confData->SetOrigin(fileformatInput); std::vector<unsigned short> confDimensions = confData->GetDimension(); // to be fair, set these all to 3D std::vector<double> confEnergies = confData->GetEnergies(); std::vector< std::vector< vector3 > > confForces = confData->GetForces(); //Vibrational data std::vector< std::vector< vector3 > > Lx; std::vector<double> Frequencies, Intensities; //Rotational data std::vector<double> RotConsts(3); int RotSymNum=1; OBRotationData::RType RotorType; // Translation vectors (if present) vector3 translationVectors[3]; int numTranslationVectors = 0; //Electronic Excitation data std::vector<double> Forces, Wavelengths, EDipole, RotatoryStrengthsVelocity, RotatoryStrengthsLength; // Orbital data std::vector<double> orbitals; std::vector<std::string> symmetries; int aHOMO, bHOMO, betaStart; //Put some metadata into OBCommentData string comment("Gaussian "); ifs.getline(buffer,BUFF_SIZE); if(*buffer) { comment += strchr(buffer,'=')+2; comment += ""; for(unsigned i=0; i<115, ifs; ++i) { ifs.getline(buffer,BUFF_SIZE); if(buffer[1]=='#') { //the line describing the method comment += buffer; OBCommentData *cd = new OBCommentData; cd->SetData(comment); cd->SetOrigin(fileformatInput); mol.SetData(cd); break; } } } int i=0; bool no_symmetry=false; char coords_type[25]; //Prescan file to find second instance of "orientation:" //This will be the kind of coords used in the chk/fchk file //Unless the "nosym" keyword has been requested while (ifs.getline(buffer,BUFF_SIZE)) { if (strstr(buffer,"Symmetry turned off by external request.") != NULL) { // The "nosym" keyword has been requested no_symmetry = true; } if (strstr(buffer,"orientation:") !=NULL) { i++; tokenize (vs, buffer); strcpy (coords_type, vs[0].c_str()); strcat (coords_type, " orientation:"); } if ((no_symmetry && i==1) || i==2) break; // Check for the last line of normal output and exit loop, otherwise, // the rewind below will no longer work. if (strstr(buffer,"Normal termination of Gaussian") != NULL) break; } ifs.seekg(0); //rewind mol.BeginModify(); while (ifs.getline(buffer,BUFF_SIZE)) { if (strstr(buffer,"Multiplicity") != NULL) { tokenize(vs, buffer, " \t\n"); if (vs.size() == 6) { charge = atoi(vs[2].c_str()); spin = atoi(vs[5].c_str()); } ifs.getline(buffer,BUFF_SIZE); } else if (strstr(buffer, coords_type) != NULL) { numTranslationVectors = 0; // ignore old translationVectors ifs.getline(buffer,BUFF_SIZE); // --------------- ifs.getline(buffer,BUFF_SIZE); // column headings ifs.getline(buffer,BUFF_SIZE); // column headings ifs.getline(buffer,BUFF_SIZE); // --------------- ifs.getline(buffer,BUFF_SIZE); tokenize(vs,buffer); while (vs.size() == 6) { x = atof((char*)vs[3].c_str()); y = atof((char*)vs[4].c_str()); z = atof((char*)vs[5].c_str()); int atomicNum = atoi((char*)vs[1].c_str()); if (atomicNum > 0) // translation vectors are "-2" { if (natoms == 0) { // first time reading the molecule, create each atom atom = mol.NewAtom(); atom->SetAtomicNum(atoi((char*)vs[1].c_str())); } coordinates.push_back(x); coordinates.push_back(y); coordinates.push_back(z); } else { translationVectors[numTranslationVectors++].Set(x, y, z); } if (!ifs.getline(buffer,BUFF_SIZE)) { break; } tokenize(vs,buffer); } // done with reading atoms natoms = mol.NumAtoms(); // malloc / memcpy double *tmpCoords = new double [(natoms)*3]; memcpy(tmpCoords, &coordinates[0], sizeof(double)*natoms*3); vconf.push_back(tmpCoords); coordinates.clear(); confDimensions.push_back(3); // always 3D -- OBConformerData allows mixing 2D and 3D structures } else if(strstr(buffer,"Dipole moment") != NULL) { ifs.getline(buffer,BUFF_SIZE); // actual components X ### Y #### Z ### tokenize(vs,buffer); if (vs.size() >= 6) { OBVectorData *dipoleMoment = new OBVectorData; dipoleMoment->SetAttribute("Dipole Moment"); double x, y, z; x = atof(vs[1].c_str()); y = atof(vs[3].c_str()); z = atof(vs[5].c_str()); dipoleMoment->SetData(x, y, z); dipoleMoment->SetOrigin(fileformatInput); mol.SetData(dipoleMoment); } if (!ifs.getline(buffer,BUFF_SIZE)) break; } else if(strstr(buffer,"Total atomic charges") != NULL || strstr(buffer,"Mulliken atomic charges") != NULL) { hasPartialCharges = true; chargeModel = "Mulliken"; ifs.getline(buffer,BUFF_SIZE); // column headings ifs.getline(buffer,BUFF_SIZE); tokenize(vs,buffer); while (vs.size() >= 3 && strstr(buffer,"Sum of ") == NULL) { atom = mol.GetAtom(atoi(vs[0].c_str())); if (!atom) break; atom->SetPartialCharge(atof(vs[2].c_str())); if (!ifs.getline(buffer,BUFF_SIZE)) break; tokenize(vs,buffer); } } else if (strstr(buffer, "Charges from ESP fit") != NULL) { hasPartialCharges = true; chargeModel = "ESP"; ifs.getline(buffer,BUFF_SIZE); // Charge / dipole line ifs.getline(buffer,BUFF_SIZE); // column header ifs.getline(buffer,BUFF_SIZE); // real charges tokenize(vs,buffer); while (vs.size() >= 3 && strstr(buffer,"-----") == NULL) { atom = mol.GetAtom(atoi(vs[0].c_str())); if (!atom) break; atom->SetPartialCharge(atof(vs[2].c_str())); if (!ifs.getline(buffer,BUFF_SIZE)) break; tokenize(vs,buffer); } } else if(strstr(buffer,"Natural Population") != NULL) { hasPartialCharges = true; chargeModel = "NBO"; ifs.getline(buffer,BUFF_SIZE); // column headings ifs.getline(buffer,BUFF_SIZE); // again ifs.getline(buffer,BUFF_SIZE); // again (-----) ifs.getline(buffer,BUFF_SIZE); // real data tokenize(vs,buffer); while (vs.size() >= 3 && strstr(buffer,"=====") == NULL) { atom = mol.GetAtom(atoi(vs[1].c_str())); if (!atom) break; atom->SetPartialCharge(atof(vs[2].c_str())); if (!ifs.getline(buffer,BUFF_SIZE)) break; tokenize(vs,buffer); } } else if(strstr(buffer, " Frequencies -- ")) //vibrational frequencies { //The info should appear only once as several blocks starting with this line tokenize(vs, buffer); for(unsigned int i=2; i<vs.size(); ++i) Frequencies.push_back(atof(vs[i].c_str())); ifs.getline(buffer,BUFF_SIZE); //Red. masses ifs.getline(buffer,BUFF_SIZE); //Frc consts ifs.getline(buffer,BUFF_SIZE); //IR Inten tokenize(vs, buffer); for(unsigned int i=3; i<vs.size(); ++i) Intensities.push_back(atof(vs[i].c_str())); ifs.getline(buffer, BUFF_SIZE); // column labels or Raman intensity if(strstr(buffer, "Raman Activ")) { ifs.getline(buffer, BUFF_SIZE); // Depolar (P) ifs.getline(buffer, BUFF_SIZE); // Depolar (U) ifs.getline(buffer, BUFF_SIZE); // column labels } ifs.getline(buffer, BUFF_SIZE); // actual displacement data tokenize(vs, buffer); vector<vector3> vib1, vib2, vib3; double x, y, z; while(vs.size() > 5) { for (unsigned int i = 2; i < vs.size()-2; i += 3) { x = atof(vs[i].c_str()); y = atof(vs[i+1].c_str()); z = atof(vs[i+2].c_str()); if (i == 2) vib1.push_back(vector3(x, y, z)); else if (i == 5) vib2.push_back(vector3(x, y, z)); else if (i == 8) vib3.push_back(vector3(x, y, z)); } if (!ifs.getline(buffer, BUFF_SIZE)) break; tokenize(vs,buffer); } Lx.push_back(vib1); if (vib2.size()) Lx.push_back(vib2); if (vib3.size()) Lx.push_back(vib3); } else if(strstr(buffer, " This molecule is "))//rotational data { if(strstr(buffer, "asymmetric")) RotorType = OBRotationData::ASYMMETRIC; else if(strstr(buffer, "symmetric")) RotorType = OBRotationData::SYMMETRIC; else if(strstr(buffer, "linear")) RotorType = OBRotationData::LINEAR; else RotorType = OBRotationData::UNKNOWN; ifs.getline(buffer,BUFF_SIZE); //symmetry number tokenize(vs, buffer); RotSymNum = atoi(vs[3].c_str()); } else if(strstr(buffer, "Rotational constant")) { tokenize(vs, buffer); RotConsts.clear(); for (unsigned int i=3; i<vs.size(); ++i) RotConsts.push_back(atof(vs[i].c_str())); } else if(strstr(buffer, "alpha electrons")) // # of electrons / orbital { tokenize(vs, buffer); if (vs.size() == 6) { // # alpha electrons # beta electrons aHOMO = atoi(vs[0].c_str()); bHOMO = atoi(vs[3].c_str()); } } else if(strstr(buffer, "rbital symmetries")) // orbital symmetries { symmetries.clear(); std::string label; // used as a temporary to remove "(" and ")" from labels int offset = 0; while(true) { ifs.getline(buffer, BUFF_SIZE); tokenize(vs, buffer); // parse first line "Occupied" ... for (unsigned int i = 1; i < vs.size(); ++i) { label = vs[i].substr(1, vs[i].length() - 2); symmetries.push_back(label); } ifs.getline(buffer, BUFF_SIZE); // Parse remaining lines while (strstr(buffer, "(")) { tokenize(vs, buffer); if (strstr(buffer, "Virtual")) { offset = 1; // skip first token } else { offset = 0; } for (unsigned int i = offset; i < vs.size(); ++i) { label = vs[i].substr(1, vs[i].length() - 2); symmetries.push_back(label); } ifs.getline(buffer, BUFF_SIZE); // get next line } // end parsing symmetry labels if (!strstr(buffer, "Beta")) // no beta orbitals break; } // end alpha/beta section } else if (strstr(buffer, "Alpha") && strstr(buffer, ". eigenvalues --")) { orbitals.clear(); betaStart = 0; while (strstr(buffer, ". eigenvalues --")) { tokenize(vs, buffer); if (vs.size() < 4) break; if (vs[0].find("Beta") !=string::npos && betaStart == 0) // mark where we switch from alpha to beta betaStart = orbitals.size(); for (unsigned int i = 4; i < vs.size(); ++i) { orbitals.push_back(atof(vs[i].c_str())); } ifs.getline(buffer, BUFF_SIZE); } } else if(strstr(buffer, " Excited State")) // Force and wavelength data { // The above line appears for each state, so just append the info to the vectors tokenize(vs, buffer); if (vs.size() == 9) { double wavelength = atof(vs[6].c_str()); double force = atof(vs[8].substr(2).c_str()); Forces.push_back(force); Wavelengths.push_back(wavelength); } } else if(strstr(buffer, " Ground to excited state Transition electric dipole moments (Au):")) // Electronic dipole moments { ifs.getline(buffer, BUFF_SIZE); // Headings ifs.getline(buffer, BUFF_SIZE); // First entry tokenize(vs, buffer); while (vs.size() == 5) { double s = atof(vs[4].c_str()); EDipole.push_back(s); ifs.getline(buffer, BUFF_SIZE); tokenize(vs, buffer); } } else if(strstr(buffer, " state X Y Z R(velocity)")) { // Rotatory Strengths ifs.getline(buffer, BUFF_SIZE); // First entry tokenize(vs, buffer); while (vs.size() == 5) { double s = atof(vs[4].c_str()); RotatoryStrengthsVelocity.push_back(s); ifs.getline(buffer, BUFF_SIZE); tokenize(vs, buffer); } } else if(strstr(buffer, " state X Y Z R(length)")) { // Rotatory Strengths ifs.getline(buffer, BUFF_SIZE); // First entry tokenize(vs, buffer); while (vs.size() == 5) { double s = atof(vs[4].c_str()); RotatoryStrengthsLength.push_back(s); ifs.getline(buffer, BUFF_SIZE); tokenize(vs, buffer); } } else if (strstr(buffer, "Forces (Hartrees/Bohr)")) { ifs.getline(buffer, BUFF_SIZE); // column headers ifs.getline(buffer, BUFF_SIZE); // ------ ifs.getline(buffer, BUFF_SIZE); // real data } else if (strstr(buffer, "Isotropic = ")) // NMR shifts { tokenize(vs, buffer); if (vs.size() >= 4) { atom = mol.GetAtom(atoi(vs[0].c_str())); OBPairData *nmrShift = new OBPairData(); nmrShift->SetAttribute("NMR Isotropic Shift"); string shift = vs[4].c_str(); nmrShift->SetValue(shift); atom->SetData(nmrShift); } } else if(strstr(buffer,"SCF Done:") != NULL) { #define HARTREE_TO_KCAL 627.509469 tokenize(vs,buffer); mol.SetEnergy(atof(vs[4].c_str()) * HARTREE_TO_KCAL); confEnergies.push_back(mol.GetEnergy()); } /* Temporarily commented out until the handling of energy in OBMol is sorted out // MP2 energies also use a different syntax // PM3 energies use a different syntax else if(strstr(buffer,"E (Thermal)") != NULL) { ifs.getline(buffer,BUFF_SIZE); //Headers ifs.getline(buffer,BUFF_SIZE); //Total energy; what we want tokenize(vs,buffer); mol.SetEnergy(atof(vs[1].c_str())); confEnergies.push_back(mol.GetEnergy()); } */ } // end while if (mol.NumAtoms() == 0) { // e.g., if we're at the end of a file PR#1737209 mol.EndModify(); return false; } mol.EndModify(); // Set conformers to all coordinates we adopted // but remove last geometry -- it's a duplicate if (vconf.size() > 1) vconf.pop_back(); mol.SetConformers(vconf); mol.SetConformer(mol.NumConformers() - 1); // Copy the conformer data too confData->SetDimension(confDimensions); confData->SetEnergies(confEnergies); confData->SetForces(confForces); mol.SetData(confData); // Attach orbital data, if there is any if (orbitals.size() > 0) { OBOrbitalData *od = new OBOrbitalData; if (aHOMO == bHOMO) { od->LoadClosedShellOrbitals(orbitals, symmetries, aHOMO); } else { // we have to separate the alpha and beta vectors std::vector<double> betaOrbitals; std::vector<std::string> betaSymmetries; unsigned int initialSize = orbitals.size(); for (unsigned int i = betaStart; i < initialSize; ++i) { betaOrbitals.push_back(orbitals[i]); if (symmetries.size() > 0) betaSymmetries.push_back(symmetries[i]); } // ok, now erase the end elements of orbitals and symmetries for (unsigned int i = betaStart; i < initialSize; ++i) { orbitals.pop_back(); if (symmetries.size() > 0) symmetries.pop_back(); } // and load the alphas and betas od->LoadAlphaOrbitals(orbitals, symmetries, aHOMO); od->LoadBetaOrbitals(betaOrbitals, betaSymmetries, bHOMO); } od->SetOrigin(fileformatInput); mol.SetData(od); } //Attach vibrational data, if there is any, to molecule if(Frequencies.size()>0) { OBVibrationData* vd = new OBVibrationData; vd->SetData(Lx, Frequencies, Intensities); vd->SetOrigin(fileformatInput); mol.SetData(vd); } //Attach rotational data, if there is any, to molecule if(RotConsts[0]!=0.0) { OBRotationData* rd = new OBRotationData; rd->SetData(RotorType, RotConsts, RotSymNum); rd->SetOrigin(fileformatInput); mol.SetData(rd); } // Attach unit cell translation vectors if found if (numTranslationVectors > 0) { OBUnitCell* uc = new OBUnitCell; uc->SetData(translationVectors[0], translationVectors[1], translationVectors[2]); uc->SetOrigin(fileformatInput); mol.SetData(uc); } //Attach electronic transition data, if there is any, to molecule if(Forces.size() > 0 && Forces.size() == Wavelengths.size()) { OBElectronicTransitionData* etd = new OBElectronicTransitionData; etd->SetData(Wavelengths, Forces); if (EDipole.size() == Forces.size()) etd->SetEDipole(EDipole); if (RotatoryStrengthsLength.size() == Forces.size()) etd->SetRotatoryStrengthsLength(RotatoryStrengthsLength); if (RotatoryStrengthsVelocity.size() == Forces.size()) etd->SetRotatoryStrengthsVelocity(RotatoryStrengthsVelocity); etd->SetOrigin(fileformatInput); mol.SetData(etd); } if (!pConv->IsOption("b",OBConversion::INOPTIONS)) mol.ConnectTheDots(); if (!pConv->IsOption("s",OBConversion::INOPTIONS) && !pConv->IsOption("b",OBConversion::INOPTIONS)) mol.PerceiveBondOrders(); if (hasPartialCharges) { mol.SetPartialChargesPerceived(); // Annotate that partial charges come from Mulliken OBPairData *dp = new OBPairData; dp->SetAttribute("PartialCharges"); dp->SetValue(chargeModel); // Mulliken, ESP, etc. dp->SetOrigin(fileformatInput); mol.SetData(dp); } mol.SetTotalCharge(charge); mol.SetTotalSpinMultiplicity(spin); mol.SetTitle(title); return(true); }