#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/internalcoord.h>
#include <openbabel/generic.h>
#include <cstdlib>
const char *_strcasestr(const char *s, const char *pattern);
#ifndef strcasestr
#define strcasestr _strcasestr
#endif
using namespace std;
namespace OpenBabel
{
class GaussianZMatrixInputFormat : public OBMoleculeFormat
{
public:
GaussianZMatrixInputFormat()
{
OBConversion::RegisterFormat("gzmat",this, "chemical/x-gaussian-input");
}
virtual const char* Description() {
return
"Gaussian Z-Matrix Input\n"
"Read Options e.g. -as\n"
" s Output single bonds only\n"
" b Disable bonding entirely\n\n"
"Write Options e.g. -xk\n"
" k \"keywords\" Use the specified keywords for input\n"
" f <file> Read the file specified for input keywords\n\n";
};
virtual const char* SpecificationURL()
{ return "https://www.gaussian.com/zmat/"; };
virtual const char* GetMIMEType()
{ return "chemical/x-gaussian-input"; };
virtual bool ReadMolecule(OBBase* pOb, OBConversion* pConv);
virtual bool WriteMolecule(OBBase* pOb, OBConversion* pConv);
};
GaussianZMatrixInputFormat theGaussianZMatrixInputFormat;
bool GaussianZMatrixInputFormat::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];
const char *keywords = pConv->IsOption("k",OBConversion::OUTOPTIONS);
const char *keywordsEnable = pConv->IsOption("k",OBConversion::GENOPTIONS);
const char *keywordFile = pConv->IsOption("f",OBConversion::OUTOPTIONS);
string defaultKeywords = "!Put Keywords Here, check Charge and Multiplicity.\n#";
if(keywords) {
defaultKeywords = keywords;
}
if (keywordsEnable) {
string model;
string basis;
string method;
OBPairData *pd = (OBPairData *) pmol->GetData("model");
if(pd)
model = pd->GetValue();
pd = (OBPairData *) pmol->GetData("basis");
if(pd)
basis = pd->GetValue();
pd = (OBPairData *) pmol->GetData("method");
if(pd)
method = pd->GetValue();
if(method == "optimize") {
method = "opt";
}
if(model != "" && basis != "" && method != "") {
ofs << model << "/" << basis << "," << method << "\n";
}
else {
ofs << "#Unable to translate keywords!\n";
ofs << defaultKeywords << "\n";
}
}
else if (keywordFile) {
ifstream kfstream(keywordFile);
string keyBuffer;
if (kfstream) {
while (getline(kfstream, keyBuffer))
ofs << keyBuffer << "\n";
}
}
else {
ofs << defaultKeywords << "\n";
}
ofs << "\n"; ofs << " " << mol.GetTitle() << "\n\n";
snprintf(buffer, BUFF_SIZE, "%d %d",
mol.GetTotalCharge(),
mol.GetTotalSpinMultiplicity());
ofs << buffer << "\n";
OBAtom *a,*b,*c;
vector<OBInternalCoord*> vic;
vic.push_back(nullptr);
FOR_ATOMS_OF_MOL(atom, mol)
vic.push_back(new OBInternalCoord);
CartesianToInternal(vic,mol);
double r,w,t;
string type;
FOR_ATOMS_OF_MOL(atom, mol)
{
a = vic[atom->GetIdx()]->_a;
b = vic[atom->GetIdx()]->_b;
c = vic[atom->GetIdx()]->_c;
type = OBElements::GetSymbol(atom->GetAtomicNum());
if (atom->GetIsotope() != 0) {
snprintf(buffer, BUFF_SIZE, "(Iso=%d)", atom->GetIsotope());
type += buffer;
}
switch(atom->GetIdx())
{
case 1:
snprintf(buffer, BUFF_SIZE, "%-s\n",type.c_str());
ofs << buffer;
continue;
break;
case 2:
snprintf(buffer, BUFF_SIZE, "%-s %d r%d\n",
type.c_str(), a->GetIdx(), atom->GetIdx());
ofs << buffer;
continue;
break;
case 3:
snprintf(buffer, BUFF_SIZE, "%-s %d r%d %d a%d\n",
type.c_str(), a->GetIdx(), atom->GetIdx(), b->GetIdx(), atom->GetIdx());
ofs << buffer;
continue;
break;
default:
snprintf(buffer, BUFF_SIZE, "%-s %d r%d %d a%d %d d%d\n",
type.c_str(), a->GetIdx(), atom->GetIdx(),
b->GetIdx(), atom->GetIdx(), c->GetIdx(), atom->GetIdx());
ofs << buffer;
}
}
ofs << "Variables:\n";
FOR_ATOMS_OF_MOL(atom, mol)
{
r = vic[atom->GetIdx()]->_dst;
w = vic[atom->GetIdx()]->_ang;
if (w < 0.0)
w += 360.0;
t = vic[atom->GetIdx()]->_tor;
if (t < 0.0)
t += 360.0;
switch(atom->GetIdx())
{
case 1:
continue;
break;
case 2:
snprintf(buffer, BUFF_SIZE, "r2= %6.4f\n", r);
ofs << buffer;
continue;
break;
case 3:
snprintf(buffer, BUFF_SIZE, "r3= %6.4f\na3= %6.2f\n", r, w);
ofs << buffer;
continue;
break;
default:
snprintf(buffer, BUFF_SIZE, "r%d= %6.4f\na%d= %6.2f\nd%d= %6.2f\n",
atom->GetIdx(), r, atom->GetIdx(), w, atom->GetIdx(), t);
ofs << buffer;
}
}
ofs << "\n";
return(true);
}
bool GaussianZMatrixInputFormat::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];
OBAtom *atom;
vector<OBInternalCoord*> vic;
vic.push_back(nullptr);
vector<string> vs;
int charge = 0;
unsigned int spin = 1;
unsigned int blankLines = 0;
bool readVariables = false; bool foundVariables = false; map<string, double> variables; vector<string> atomLines;
mol.BeginModify();
while (ifs.getline(buffer,BUFF_SIZE))
if (strncmp(buffer,"#", 1) == 0) break;
while (ifs.getline(buffer,BUFF_SIZE)) { if (strlen(buffer) == 0)
blankLines++;
if (blankLines == 2)
break;
}
ifs.getline(buffer,BUFF_SIZE); tokenize(vs, buffer, " \t\n");
if (vs.size() == 2)
{
charge = atoi(vs[0].c_str());
spin = atoi(vs[1].c_str());
}
while (ifs.getline(buffer,BUFF_SIZE)) {
if (strlen(buffer) == 0) {
if (foundVariables)
break; else {
readVariables = true;
continue;
}
}
if (strcasestr(buffer, "VARIABLE") != nullptr) {
readVariables = true;
continue;
}
if (readVariables) {
tokenize(vs, buffer, "= \t\n");
if (vs.size() >= 2) {
variables[vs[0]] = atof(vs[1].c_str());
foundVariables = true;
}
}
else {
atomLines.push_back(buffer);
vic.push_back(new OBInternalCoord);
}
}
char *endptr;
double temp;
if (atomLines.size() > 0) {
unsigned int i, j;
for (i = 0; i < atomLines.size(); ++i) {
j = i+1;
tokenize(vs, atomLines[i]);
atom = mol.NewAtom();
atom->SetAtomicNum(OBElements::GetAtomicNum(vs[0].c_str()));
if (j == 1) {
continue; }
if (j >= 2) {
if (vs.size() < 3) {return false;}
vic[j]->_a = mol.GetAtom(atoi(vs[1].c_str()));
temp = strtod((char*)vs[2].c_str(), &endptr);
if (endptr != (char*)vs[2].c_str())
vic[j]->_dst = temp;
else
vic[j]->_dst = variables[vs[2].c_str()];
}
if (j >= 3) {
if (vs.size() < 5) {return false;}
vic[j]->_b = mol.GetAtom(atoi(vs[3].c_str()));
temp = strtod((char*)vs[4].c_str(), &endptr);
if (endptr != (char*)vs[4].c_str())
vic[j]->_ang = temp;
else
vic[j]->_ang = variables[vs[4].c_str()];
}
if (j >= 4) {
if (vs.size() < 7) {return false;}
vic[j]->_c = mol.GetAtom(atoi(vs[5].c_str()));
temp = strtod((char*)vs[6].c_str(), &endptr);
if (endptr != (char*)vs[6].c_str()) {
vic[j]->_tor = temp;
} else {
const char* tor_str = vs[6].c_str();
if (tor_str[0] == '-')
vic[j]->_tor = -1 * variables[tor_str+1];
else
vic[j]->_tor = variables[tor_str];
}
}
}
}
if (mol.NumAtoms() == 0) { mol.EndModify();
return false;
}
InternalToCartesian(vic,mol);
if (!pConv->IsOption("b",OBConversion::INOPTIONS))
mol.ConnectTheDots();
if (!pConv->IsOption("s",OBConversion::INOPTIONS) && !pConv->IsOption("b",OBConversion::INOPTIONS))
mol.PerceiveBondOrders();
mol.EndModify();
mol.SetTotalCharge(charge);
mol.SetTotalSpinMultiplicity(spin);
mol.SetTitle(title);
return(true);
}
}
const char *
_strcasestr(const char *s, const char *pattern)
{
int length = strlen(pattern);
while (*s)
{
if (strncasecmp(s, pattern, length) == 0)
return s;
s++;
}
return nullptr;
}