#include <openbabel/babelconfig.h>
#include <openbabel/obmolecformat.h>
#include <openbabel/mol.h>
#include <openbabel/atom.h>
#include <openbabel/bond.h>
#include <openbabel/obiter.h>
#include <openbabel/elements.h>
#include <openbabel/generic.h>
#include <cmath>
#include <algorithm>
#define HARTREE_TO_KCAL 627.509469
#define AU_TO_ANGSTROM 0.529177249
#define EV_TO_NM(x) 1239.84193/x
using namespace std;
namespace OpenBabel
{
class NWChemOutputFormat : public OBMoleculeFormat
{
public:
NWChemOutputFormat()
{
OBConversion::RegisterFormat("nwo",this);
}
virtual const char* Description() {
return
"NWChem output format\n"
"Read Options e.g. -as\n"
" s Output single bonds only\n"
" f Overwrite molecule if more than one\n"
" calculation with different molecules\n"
" is present in the output file\n"
" (last calculation will be prefered)\n"
" b Disable bonding entirely\n\n";
};
virtual const char* SpecificationURL()
{return "http://www.emsl.pnl.gov/docs/nwchem/";};
virtual unsigned int Flags()
{
return READONEONLY | NOTWRITABLE;
};
virtual bool ReadMolecule(OBBase* pOb, OBConversion* pConv);
private:
void ReadCoordinates(istream* ifs, OBMol* molecule);
void ReadPartialCharges(istream* ifs, OBMol* molecule);
void ReadOrbitals(istream* ifs, OBMol* molecule);
void ReadMultipoleMoment(istream* ifs, OBMol* molecule);
void ReadFrequencyCalculation(istream* ifs, OBMol* molecule);
void ReadGeometryOptimizationCalculation(istream* ifs, OBMol* molecule);
void ReadSinglePointCalculation(istream* ifs, OBMol* molecule);
void ReadZTSCalculation(istream* ifs, OBMol* molecule);
void ReadTDDFTCalculation(istream* ifs, OBMol* molecule);
void ReadMEPCalculation(istream* ifs, OBMol* molecule);
void ReadNEBCalculation(istream* ifs, OBMol* molecule);
};
static const char* COORDINATES_PATTERN = "Output coordinates";
static const char* GEOMETRY_OPTIMIZATION_PATTERN = "NWChem Geometry Optimization";
static const char* PROPERTY_CALCULATION_PATTERN = "NWChem Property Module";
static const char* ZTS_CALCULATION_PATTERN = " String method.";
static const char* NEB_CALCULATION_PATTERN = "NWChem Minimum Energy Pathway Program (NEB)";
static const char* PYTHON_CALCULATION_PATTERN = "NWChem Python program";
static const char* ESP_CALCULATION_PATTERN = "NWChem Electrostatic Potential Fit Module";
static const char* SCF_CALCULATION_PATTERN = "SCF Module";
static const char* DFT_CALCULATION_PATTERN = "DFT Module";
static const char* TDDFT_CALCULATION_PATTERN = "TDDFT Module";
static const char* MEP_CALCULATION_PATTERN = "Gonzalez & Schlegel IRC Optimization";
static const char* SCF_ENERGY_PATTERN = "SCF energy =";
static const char* DFT_ENERGY_PATTERN = "DFT energy =";
static const char* FREQUENCY_PATTERN = "NWChem Nuclear Hessian and Frequency Analysis";
static const char* OPTIMIZATION_STEP_PATTERN = "Step Energy";
static const char* VIBRATIONS_TABLE_PATTERN = "P.Frequency";
static const char* INTENSITIES_TABLE_PATTERN = "Projected Infra Red Intensities";
static const char* DIGITS = "1234567890";
static const char* END_OF_CALCULATION_PATTERN = "times cpu";
static const char* ORBITAL_START_PATTERN = "Vector";
static const char* ORBITAL_SECTION_PATTERN_1 = "Analysis";
static const char* ORBITAL_SECTION_PATTERN_2 = "rbital";
static const char* BETA_ORBITAL_PATTERN = "Beta";
static const char* MULLIKEN_CHARGES_PATTERN = "Mulliken analysis of the total density";
static const char* GEOMETRY_PATTERN = "Geometry \"geometry\"";
static const char* ZTS_CONVERGED_PATTERN = " The string calculation ";
static const char* NBEADS_PATTERN = " Number of replicas";
static const char* ROOT_PATTERN = "Root";
static const char* OSCILATOR_STRENGTH_PATTERN = "Oscillator Strength";
static const char* SPIN_FORBIDDEN_PATTERN = "Spin forbidden";
static const char* MULTIPOLE_MOMENT_PATTERN = "Multipole analysis of the density";
static const char* MEP_STEP_END_PATTERN = "& Point";
static const char* NEB_BEAD_START_PATTERN = "neb: running bead";
static const char* NEB_BEAD_ENERGY_PATTERN = "neb: final energy";
static const char* NEB_NBEADS_PATTERN = "number of images in path";
static const char* GRADIENT_PATTERN = "ENERGY GRADIENTS";
static const char* OPTIMIZATION_END_PATTERN = " Optimization converged";
NWChemOutputFormat theNWChemOutputFormat;
class NWChemInputFormat : public OBMoleculeFormat
{
public:
NWChemInputFormat()
{
OBConversion::RegisterFormat("nw",this);
}
virtual const char* Description() {
return
"NWChem input format\n"
"No comments yet\n";
};
virtual const char* SpecificationURL()
{return "http://www.emsl.pnl.gov/docs/nwchem/";};
virtual unsigned int Flags()
{
return NOTREADABLE | WRITEONEONLY;
};
virtual bool WriteMolecule(OBBase* pOb, OBConversion* pConv);
};
NWChemInputFormat theNWChemInputFormat;
static void GotoCalculationEnd(istream* ifs)
{
char buffer[BUFF_SIZE];
while (strstr(buffer, END_OF_CALCULATION_PATTERN) == nullptr)
if (!ifs->getline(buffer,BUFF_SIZE))
break;
}
void NWChemOutputFormat::ReadCoordinates(istream* ifs, OBMol* molecule)
{
if (molecule == nullptr || ifs == nullptr)
return;
vector<string> vs;
char buffer[BUFF_SIZE];
double x, y, z;
unsigned int natoms = molecule->NumAtoms();
bool from_scratch = false;
double* coordinates;
if (natoms == 0)
from_scratch = true;
else
coordinates = new double[3*natoms];
ifs->getline(buffer,BUFF_SIZE); ifs->getline(buffer,BUFF_SIZE); ifs->getline(buffer,BUFF_SIZE); ifs->getline(buffer,BUFF_SIZE);
tokenize(vs,buffer);
unsigned int i=0;
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());
if (from_scratch)
{
OBAtom* atom = molecule->NewAtom();
atom->SetAtomicNum(atoi(vs[2].c_str()));
atom->SetVector(x,y,z);
}
else
{
if ((i>=natoms) || (molecule->GetAtom(i+1)->GetAtomicNum() != atoi(vs[2].c_str())))
{
delete[] coordinates;
return;
}
coordinates[i*3] = x;
coordinates[i*3+1] = y;
coordinates[i*3+2] = z;
i++;
}
if (!ifs->getline(buffer,BUFF_SIZE))
break;
tokenize(vs,buffer);
}
if (from_scratch)
{
return;
}
if (i != natoms) {
delete[] coordinates;
return;
}
molecule->AddConformer(coordinates);
}
void NWChemOutputFormat::ReadMultipoleMoment(istream* ifs, OBMol* molecule)
{
if (ifs == nullptr || molecule == nullptr)
return;
char buffer[BUFF_SIZE];
vector<string> vs;
matrix3x3 quadrupole;
double dipole[3];
int charge;
bool blank_line = false;
ifs->getline(buffer, BUFF_SIZE); ifs->getline(buffer, BUFF_SIZE); ifs->getline(buffer, BUFF_SIZE); ifs->getline(buffer, BUFF_SIZE);
while (ifs->getline(buffer, BUFF_SIZE))
{
tokenize(vs, buffer);
if (vs.size() < 7)
{
if (blank_line)
{
molecule->SetTotalCharge(charge);
OBVectorData* dipole_moment = new OBVectorData;
dipole_moment->SetData(vector3(dipole));
dipole_moment->SetAttribute("Dipole Moment");
molecule->SetData(dipole_moment);
OBMatrixData* quadrupole_moment = new OBMatrixData;
quadrupole_moment->SetData(quadrupole);
quadrupole_moment->SetAttribute("Quadrupole Moment");
molecule->SetData(quadrupole_moment);
return;
}
blank_line = true;
continue;
}
blank_line = false;
if (vs[0][0] == '0')
charge = atoi(vs[4].c_str());
else if (vs[0][0] == '1')
for (unsigned int i = 0; i < 3; i++)
if (vs[i+1][0] == '1')
dipole[i] = atof(vs[4].c_str());
else if (vs[0][0] == '2')
{
double value = atof(vs[4].c_str());
unsigned int i[2], j = 0;
for (unsigned int k = 0 ; k<3; k++)
{
if (vs[k+1][0] == '2')
i[0] = i[1] = k; else if (vs[k+1][0] == '1')
i[j++] = k;
}
quadrupole.Set(i[0], i[1], value);
quadrupole.Set(i[1], i[0], value);
}
else
return;
}
}
void NWChemOutputFormat::ReadTDDFTCalculation(istream* ifs, OBMol* molecule)
{
if (ifs == nullptr || molecule == nullptr)
return;
char buffer[BUFF_SIZE];
vector<string> vs;
vector<double> wavelengths;
vector<double> oscilator_strengths;
while (ifs->getline(buffer, BUFF_SIZE))
{
if (strstr(buffer, ROOT_PATTERN) != nullptr)
{
tokenize(vs, buffer);
if (vs.size() < 8)
break;
wavelengths.push_back(EV_TO_NM(atof(vs[6].c_str())));
}
else if (strstr(buffer, OSCILATOR_STRENGTH_PATTERN) != nullptr)
{
if (strstr(buffer, SPIN_FORBIDDEN_PATTERN) != nullptr)
oscilator_strengths.push_back(0);
else
{
tokenize(vs, buffer);
if (vs.size() < 4)
break;
oscilator_strengths.push_back(atof(vs[3].c_str()));
}
}
else if (strstr(buffer, END_OF_CALCULATION_PATTERN) != nullptr)
break;
}
if (wavelengths.size() != oscilator_strengths.size())
return;
OBElectronicTransitionData* et_data = new OBElectronicTransitionData;
et_data->SetData(wavelengths, oscilator_strengths);
molecule->SetData(et_data);
}
void NWChemOutputFormat::ReadPartialCharges(istream* ifs, OBMol* molecule)
{
if (molecule == nullptr || ifs == nullptr)
return;
vector<string> vs;
char buffer[BUFF_SIZE];
bool from_scratch = false;
vector<int> charges;
vector<double> partial_charges;
unsigned int natoms = molecule->NumAtoms();
if (natoms == 0)
from_scratch = true;
ifs->getline(buffer,BUFF_SIZE); ifs->getline(buffer,BUFF_SIZE); ifs->getline(buffer,BUFF_SIZE); ifs->getline(buffer,BUFF_SIZE); ifs->getline(buffer,BUFF_SIZE);
tokenize(vs, buffer);
unsigned int i = 1;
while (vs.size() >= 4)
{
int charge = atoi(vs[2].c_str());
if (!from_scratch)
{
if (i > natoms)
return;
if (molecule->GetAtom(i++)->GetAtomicNum() != charge)
return;
}
else
charges.push_back(charge);
partial_charges.push_back(atof(vs[3].c_str()) - charge);
ifs->getline(buffer,BUFF_SIZE);
tokenize(vs, buffer);
}
if (from_scratch)
molecule->ReserveAtoms(partial_charges.size());
else if (partial_charges.size() != natoms)
return;
for(unsigned int j=0;j<partial_charges.size();j++)
{
OBAtom* atom;
if (from_scratch)
{
atom = molecule->NewAtom();
atom->SetAtomicNum(charges[j]);
}
else
{
atom = molecule->GetAtom(j+1);
}
atom->SetPartialCharge(partial_charges[j]);
}
}
void NWChemOutputFormat::ReadOrbitals(istream* ifs, OBMol* molecule)
{
if (ifs == nullptr || molecule == nullptr)
return;
vector<string> vs;
char buffer[BUFF_SIZE];
vector<OBOrbital> orbitals;
OBOrbitalData* orbital_data = new OBOrbitalData;
ifs->getline(buffer, BUFF_SIZE); ifs->getline(buffer, BUFF_SIZE);
while (ifs->getline(buffer,BUFF_SIZE))
{
if (strstr(buffer, ORBITAL_START_PATTERN))
{
tokenize(vs, buffer);
if (vs.size() < 5)
break;
double energy = atof(vs[4].c_str()) * HARTREE_TO_KCAL;
double occupation = atof(vs[2].c_str()+4); string symbol;
if (vs.size() > 5)
symbol = vs[5].substr(9, string::npos);
else
symbol = " "; OBOrbital orbital;
orbital.SetData(energy, occupation, symbol);
orbitals.push_back(orbital);
ifs->getline(buffer, BUFF_SIZE); ifs->getline(buffer, BUFF_SIZE); ifs->getline(buffer,BUFF_SIZE); while (ifs->getline(buffer,BUFF_SIZE))
if (strlen(buffer) < 2) break;
} else if (strstr(buffer, ORBITAL_SECTION_PATTERN_2) != nullptr && strstr(buffer, ORBITAL_SECTION_PATTERN_1) != nullptr)
{
orbital_data->SetAlphaOrbitals(orbitals);
orbital_data->SetOpenShell(true);
orbitals.clear();
ifs->getline(buffer, BUFF_SIZE); ifs->getline(buffer, BUFF_SIZE); } else
{
if (orbital_data->IsOpenShell())
orbital_data->SetBetaOrbitals(orbitals);
else
orbital_data->SetAlphaOrbitals(orbitals);
molecule->SetData(orbital_data);
return;
}
}
delete orbital_data;
}
void NWChemOutputFormat::ReadMEPCalculation(istream* ifs, OBMol* molecule)
{
if (molecule == nullptr || ifs == nullptr)
return;
if (molecule->NumConformers() > 0)
return;
vector<string> vs;
char buffer[BUFF_SIZE];
vector<double> energies;
while (ifs->getline(buffer, BUFF_SIZE))
{
if (strstr(buffer, OPTIMIZATION_END_PATTERN) != nullptr)
{
while(ifs->getline(buffer, BUFF_SIZE))
{
if (strstr(buffer, COORDINATES_PATTERN))
ReadCoordinates(ifs, molecule);
else if (strstr(buffer, OPTIMIZATION_STEP_PATTERN))
{
ifs->getline(buffer, BUFF_SIZE); ifs->getline(buffer, BUFF_SIZE);
tokenize(vs, buffer);
molecule->SetConformer(molecule->NumConformers() - 1);
if (vs.size() > 2) energies.push_back(atof(vs[2].c_str()) * HARTREE_TO_KCAL);
}
else if (strstr(buffer, MULTIPOLE_MOMENT_PATTERN) != nullptr)
ReadMultipoleMoment(ifs, molecule);
else if (strstr(buffer, MEP_STEP_END_PATTERN) != nullptr)
break;
}
}
else if (strstr(buffer, END_OF_CALCULATION_PATTERN) != nullptr)
break;
}
if (energies.size() != molecule->NumConformers())
{
cerr << "Number of read energies (" << energies.size();
cerr << ") does not match number of read conformers (";
cerr << molecule->NumConformers() << ")!" << endl;
return;
}
molecule->SetEnergies(energies);
}
void NWChemOutputFormat::ReadGeometryOptimizationCalculation(istream* ifs, OBMol* molecule)
{
if (molecule == nullptr || ifs == nullptr)
return;
vector<string> vs;
char buffer[BUFF_SIZE];
vector<double> energies;
while (ifs->getline(buffer, BUFF_SIZE))
{
if (strstr(buffer, COORDINATES_PATTERN) != nullptr)
{
ReadCoordinates(ifs, molecule);
molecule->SetConformer(molecule->NumConformers() - 1);
}
else if (strstr(buffer, ORBITAL_SECTION_PATTERN_2) != nullptr && strstr(buffer, ORBITAL_SECTION_PATTERN_1) != nullptr)
ReadOrbitals(ifs, molecule);
else if (strstr(buffer, OPTIMIZATION_STEP_PATTERN) != nullptr)
{
ifs->getline(buffer, BUFF_SIZE); ifs->getline(buffer, BUFF_SIZE);
tokenize(vs, buffer);
molecule->SetConformer(molecule->NumConformers() - 1);
if (vs.size() > 2) energies.push_back(atof(vs[2].c_str()) * HARTREE_TO_KCAL);
}
else if (strstr(buffer, MULTIPOLE_MOMENT_PATTERN) != nullptr)
ReadMultipoleMoment(ifs, molecule);
else if (strstr(buffer, MULLIKEN_CHARGES_PATTERN) != nullptr)
ReadPartialCharges(ifs, molecule);
else if (strstr(buffer, END_OF_CALCULATION_PATTERN) != nullptr)
break;
}
vector<double> old_energies = molecule->GetEnergies();
old_energies.reserve(old_energies.size() + energies.size());
old_energies.insert(old_energies.end(), energies.begin(), energies.end());
molecule->SetEnergies(old_energies);
}
void NWChemOutputFormat::ReadFrequencyCalculation(istream* ifs, OBMol* molecule)
{
if (ifs == nullptr || molecule == nullptr)
return;
if (molecule->NumAtoms() == 0)
return;
OBVibrationData* vibration_data = nullptr;
vector<double> Frequencies, Intensities;
vector<vector<vector3> > Lx;
vector<string> vs;
char buffer[BUFF_SIZE];
while (ifs->getline(buffer, BUFF_SIZE))
{
if (strstr(buffer, VIBRATIONS_TABLE_PATTERN) != nullptr)
{
vector<double> freq;
vector<vector<vector3> > vib;
tokenize(vs,buffer);
for(unsigned int i=1; i<vs.size(); ++i)
{
vib.push_back(vector<vector3>());
freq.push_back(atof(vs[i].c_str()));
}
ifs->getline(buffer,BUFF_SIZE); ifs->getline(buffer,BUFF_SIZE);
tokenize(vs,buffer);
while(vs.size() > 2)
{
vector<double> x, y, z;
for (unsigned int i = 1; i < vs.size(); i++)
x.push_back(atof(vs[i].c_str()));
ifs->getline(buffer, BUFF_SIZE);
tokenize(vs,buffer);
for (unsigned int i = 1; i < vs.size(); i++)
y.push_back(atof(vs[i].c_str()));
ifs->getline(buffer, BUFF_SIZE);
tokenize(vs,buffer);
for (unsigned int i = 1; i < vs.size(); i++)
z.push_back(atof(vs[i].c_str()));
ifs->getline(buffer, BUFF_SIZE);
tokenize(vs,buffer);
if (x.size() == y.size() && y.size() == z.size()) {
for (unsigned int i = 0; i < freq.size(); i++)
{
vib[i].push_back(vector3(x[i], y[i], z[i]));
}
}
} for (unsigned int i = 0; i < freq.size(); i++)
{
if (abs(freq[i]) > 10.0) {
Frequencies.push_back(freq[i]);
Lx.push_back(vib[i]);
}
} } else if (strstr(buffer, INTENSITIES_TABLE_PATTERN) != nullptr)
{
ifs->getline(buffer, BUFF_SIZE); ifs->getline(buffer, BUFF_SIZE); ifs->getline(buffer, BUFF_SIZE);
tokenize(vs,buffer);
while (vs.size() == 7)
{
if (abs(atof(vs[1].c_str())) > 10.0)
Intensities.push_back(atof(vs[5].c_str()));
ifs->getline(buffer, BUFF_SIZE);
tokenize(vs,buffer);
}
} else if (strstr(buffer, MULLIKEN_CHARGES_PATTERN) != nullptr)
ReadPartialCharges(ifs, molecule);
else if (strstr(buffer, MULTIPOLE_MOMENT_PATTERN) != nullptr)
ReadMultipoleMoment(ifs, molecule);
else if (strstr(buffer, ORBITAL_SECTION_PATTERN_2) != nullptr && strstr(buffer, ORBITAL_SECTION_PATTERN_1) != nullptr)
ReadOrbitals(ifs, molecule);
else if (strstr(buffer, END_OF_CALCULATION_PATTERN) != nullptr) break;
}
if (Frequencies.size() == 0)
return;
vibration_data = new OBVibrationData;
vibration_data->SetData(Lx, Frequencies, Intensities);
molecule->SetData(vibration_data);
}
void NWChemOutputFormat::ReadSinglePointCalculation(istream* ifs, OBMol* molecule)
{
if (molecule == nullptr || ifs == nullptr)
return;
double energy;
vector<string> vs;
char buffer[BUFF_SIZE];
while (ifs->getline(buffer, BUFF_SIZE))
{
if (strstr(buffer, DFT_ENERGY_PATTERN) != nullptr || strstr(buffer, SCF_ENERGY_PATTERN) != nullptr)
{
tokenize(vs, buffer);
energy = atof(vs[4].c_str()) * HARTREE_TO_KCAL;
}
else if (strstr(buffer, ORBITAL_SECTION_PATTERN_2) != nullptr && strstr(buffer, ORBITAL_SECTION_PATTERN_1) != nullptr)
ReadOrbitals(ifs, molecule);
else if (strstr(buffer, MULTIPOLE_MOMENT_PATTERN) != nullptr)
ReadMultipoleMoment(ifs, molecule);
else if (strstr(buffer, MULLIKEN_CHARGES_PATTERN) != nullptr)
ReadPartialCharges(ifs, molecule);
else if (strstr(buffer, TDDFT_CALCULATION_PATTERN) != nullptr)
ReadTDDFTCalculation(ifs, molecule);
else if (strstr(buffer, END_OF_CALCULATION_PATTERN) != nullptr)
break;
}
if (energy == 0)
return;
molecule->SetEnergy(energy);
}
void NWChemOutputFormat::ReadNEBCalculation(istream* ifs, OBMol* molecule)
{
if (ifs == nullptr || molecule == nullptr)
return;
unsigned int natoms = molecule->NumAtoms();
if (natoms == 0)
return;
char buffer[BUFF_SIZE];
vector<string> vs;
vector<double*> beads;
vector<double> energies;
unsigned int nbeads = 0;
unsigned int current_bead = UINT_MAX;
while(ifs->getline(buffer, BUFF_SIZE))
{
if (strstr(buffer, NEB_BEAD_START_PATTERN) != nullptr)
{
tokenize(vs, buffer);
if (vs.size() < 4)
break;
current_bead = atoi(vs[3].c_str()) - 1;
}
else if (strstr(buffer, NEB_BEAD_ENERGY_PATTERN) != nullptr)
{
tokenize(vs, buffer);
if (vs.size() < 4)
break;
if (current_bead >= nbeads)
{
cerr << "Current bead out of range: " << current_bead << " of " << nbeads << endl;
break;
}
energies[current_bead] = atof(vs[3].c_str());
}
else if (strstr(buffer, GRADIENT_PATTERN) != nullptr)
{
ifs->getline(buffer, BUFF_SIZE); ifs->getline(buffer, BUFF_SIZE); ifs->getline(buffer, BUFF_SIZE); for (unsigned int i = 0; i<natoms; i++)
{
ifs->getline(buffer, BUFF_SIZE);
tokenize(vs, buffer);
if (vs.size() < 8)
break;
unsigned int end_of_symbol = vs[1].find_last_not_of(DIGITS) + 1;
if (OBElements::GetAtomicNum(vs[1].substr(0, end_of_symbol).c_str()) != molecule->GetAtom(i+1)->GetAtomicNum())
break;
if (current_bead >= nbeads)
{
cerr << "Current bead out of range: " << current_bead << " of " << nbeads << endl;
break;
}
beads[current_bead][i*3] = atof(vs[2].c_str())*AU_TO_ANGSTROM;
beads[current_bead][1+i*3] = atof(vs[3].c_str())*AU_TO_ANGSTROM;
beads[current_bead][2+i*3] = atof(vs[4].c_str())*AU_TO_ANGSTROM;
}
}
else if (strstr(buffer, NEB_NBEADS_PATTERN) != nullptr)
{
tokenize(vs, buffer);
if (vs.size() < 8)
break;
nbeads = atoi(vs[7].c_str());
beads.reserve(nbeads);
energies.reserve(nbeads);
for (unsigned int i = 0;i<nbeads;i++)
{
beads.push_back(new double[natoms*3]);
energies.push_back(0.0);
}
}
else if (strstr(buffer, END_OF_CALCULATION_PATTERN) != nullptr)
{
molecule->SetConformers(beads);
molecule->SetEnergies(energies);
return;
}
}
cerr << "Failed to read NEB calculation!" << endl;
for(unsigned int i = 0; i < beads.size();i++)
delete beads[i];
}
void NWChemOutputFormat::ReadZTSCalculation(istream* ifs, OBMol* molecule)
{
if (ifs == nullptr || molecule == nullptr)
return;
unsigned int natoms = molecule->NumAtoms();
if (natoms == 0)
return;
char buffer[BUFF_SIZE];
vector<string> vs;
vector<double*> beads;
vector<double> energies;
unsigned int nbeads;
while(ifs->getline(buffer, BUFF_SIZE))
{
if (strstr(buffer, NBEADS_PATTERN) != nullptr)
{
tokenize(vs, buffer);
if (vs.size() < 6)
break; nbeads = atoi(vs[5].c_str());
beads.reserve(nbeads);
} else if (strstr(buffer, ZTS_CONVERGED_PATTERN) != nullptr)
{
ifs->getline(buffer, BUFF_SIZE); ifs->getline(buffer, BUFF_SIZE);
tokenize(vs, buffer);
unsigned int vsize = vs.size();
while (vsize > 7)
{
unsigned int bead_number = atoi(vs[vsize-5].c_str());
double bead_energy = atof(vs[vsize-1].c_str()) * HARTREE_TO_KCAL;
ifs->getline(buffer, BUFF_SIZE); if (atoi(buffer) != natoms)
break; ifs->getline(buffer, BUFF_SIZE); double* bead = new double[natoms*3];
for(unsigned int i = 0; i<natoms; i++)
{
ifs->getline(buffer, BUFF_SIZE);
tokenize(vs, buffer);
if ((vs.size() < 4) || (molecule->GetAtom(i+1)->GetAtomicNum() != OBElements::GetAtomicNum(vs[0].c_str())))
break;
unsigned int atom_idx = i*3;
bead[atom_idx] = atof(vs[1].c_str()); bead[atom_idx+1] = atof(vs[2].c_str()); bead[atom_idx+2] = atof(vs[3].c_str()); }
beads.push_back(bead);
energies.push_back(bead_energy);
ifs->getline(buffer, BUFF_SIZE);
tokenize(vs, buffer);
if (vs.size() <= 1) {
if (bead_number != nbeads)
break;
molecule->SetEnergies(energies);
molecule->SetConformers(beads);
unsigned int ts_position = distance(energies.begin(), max_element(energies.begin(), energies.end()));
molecule->SetConformer(ts_position);
return;
}
}
break; } else if (strstr(buffer, END_OF_CALCULATION_PATTERN) != nullptr)
{
molecule->SetEnergies(energies);
molecule->SetConformers(beads);
unsigned int ts_position = distance(energies.begin(), max_element(energies.begin(), energies.end()));
molecule->SetConformer(ts_position);
return;
}
}
for(unsigned int i = 0; i < beads.size();i++)
delete beads[i];
}
bool NWChemOutputFormat::ReadMolecule(OBBase* pOb, OBConversion* pConv)
{
OBMol* pmol = pOb->CastAndClear<OBMol>();
if (pmol == nullptr)
return false;
istream &ifs = *pConv->GetInStream();
OBMol &mol = *pmol;
const char* title = pConv->GetTitle();
char buffer[BUFF_SIZE];
mol.BeginModify();
while (ifs.getline(buffer,BUFF_SIZE))
{
if (strstr(buffer, GEOMETRY_PATTERN) != nullptr)
{
if (mol.NumAtoms() == 0 || pConv->IsOption("f", OBConversion::INOPTIONS) != nullptr)
{
mol.Clear();
mol.BeginModify();
ifs.getline(buffer,BUFF_SIZE); ifs.getline(buffer,BUFF_SIZE); ifs.getline(buffer,BUFF_SIZE); ReadCoordinates(&ifs, &mol);
}
else
{
int i;
for(i=0; buffer[i] != '\0';i++);
ifs.seekg(-i, ios_base::cur);
break;
}
}
else if (strstr(buffer, GEOMETRY_OPTIMIZATION_PATTERN) != nullptr)
ReadGeometryOptimizationCalculation(&ifs, &mol);
else if (strstr(buffer, FREQUENCY_PATTERN) != nullptr)
ReadFrequencyCalculation(&ifs, &mol);
else if(strstr(buffer, SCF_CALCULATION_PATTERN) != strstr(buffer, DFT_CALCULATION_PATTERN))
ReadSinglePointCalculation(&ifs, &mol);
else if (strstr(buffer, ZTS_CALCULATION_PATTERN) != nullptr)
ReadZTSCalculation(&ifs, &mol);
else if (strstr(buffer, MEP_CALCULATION_PATTERN) != nullptr)
ReadMEPCalculation(&ifs, &mol);
else if (strstr(buffer, NEB_CALCULATION_PATTERN) != nullptr)
ReadNEBCalculation(&ifs, &mol);
else if (strstr(buffer, PROPERTY_CALCULATION_PATTERN) != nullptr)
GotoCalculationEnd(&ifs);
else if (strstr(buffer, ESP_CALCULATION_PATTERN) != nullptr)
GotoCalculationEnd(&ifs);
else if (strstr(buffer, PYTHON_CALCULATION_PATTERN) != nullptr)
GotoCalculationEnd(&ifs);
}
if (mol.NumAtoms() == 0) { mol.EndModify();
return false;
}
if (!pConv->IsOption("b",OBConversion::INOPTIONS))
mol.ConnectTheDots();
if (!pConv->IsOption("s",OBConversion::INOPTIONS) && !pConv->IsOption("b",OBConversion::INOPTIONS))
mol.PerceiveBondOrders();
mol.EndModify();
unsigned int nconformers = mol.NumConformers();
if (nconformers > 1)
mol.DeleteConformer(nconformers - 1);
mol.SetTitle(title);
return(true);
}
bool NWChemInputFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv)
{
OBMol* pmol = dynamic_cast<OBMol*>(pOb);
if (pmol == nullptr)
return false;
ostream &ofs = *pConv->GetOutStream();
OBMol &mol = *pmol;
char buffer[BUFF_SIZE];
ofs << "start molecule" << "\n\n";
ofs << "title " << endl << " " << mol.GetTitle() << "\n\n";
ofs << "geometry units angstroms print xyz autosym\n";
FOR_ATOMS_OF_MOL(atom, mol)
{
snprintf(buffer, BUFF_SIZE, "%3s%15.5f%15.5f%15.5f\n",
OBElements::GetSymbol(atom->GetAtomicNum()),
atom->GetX(),
atom->GetY(),
atom->GetZ());
ofs << buffer;
}
ofs << "end\n";
return(true);
}
}