#include <openbabel/babelconfig.h>
#include <openbabel/obmolecformat.h>
#include <openbabel/mol.h>
#include <openbabel/atom.h>
#include <openbabel/elements.h>
#include <openbabel/generic.h>
#include <openbabel/obiter.h>
#include <iomanip>
#include <map>
namespace OpenBabel
{
class DlpolyInputReader
{
public:
bool ParseHeader( std::istream &ifs, OBMol &mol );
bool ParseUnitCell( std::istream &ifs, OBMol &mol );
bool ReadAtom( std::istream &ifs, OBMol &mol );
template <class T>
bool from_string(T& t, const std::string& s,
std::ios_base& (*f)(std::ios_base&))
{
std::istringstream iss(s);
return !(iss >> f >> t).fail();
}
int LabelToAtomicNumber(std::string label);
std::stringstream errorMsg;
char buffer[BUFF_SIZE];
std::string line; std::vector<std::string> tokens;
int levcfg,imcon;
std::string title;
std::vector< vector3 > forces;
typedef std::map<std::string, int> labelToZType;
labelToZType labelToZ;
};
int DlpolyInputReader::LabelToAtomicNumber(std::string label)
{
labelToZType::const_iterator it;
it = labelToZ.find( label );
if ( it != labelToZ.end() ) return it-> second;
int Z=OBElements::GetAtomicNum(label.substr(0,2).c_str());
if (Z==0) Z=OBElements::GetAtomicNum(label.substr(0,1).c_str());
if (Z==0){
errorMsg << "LabelToAtomicNumber got bad Label: " << label << std::endl;
obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obWarning);
}
labelToZ.insert( std::pair<std::string,int>(label,Z) );
return Z;
}
bool DlpolyInputReader::ParseHeader( std::istream &ifs, OBMol &mol )
{
if ( ! ifs.getline(buffer,BUFF_SIZE) )
{
obErrorLog.ThrowError(__FUNCTION__, "Problem reading title line", obWarning);
return false;
}
title=buffer;
Trim(title); mol.BeginModify();
mol.SetTitle(title);
mol.EndModify();
if ( ! ifs.getline(buffer,BUFF_SIZE) )
{
line=buffer;
line="Problem reading levcfg line: " + line;
obErrorLog.ThrowError(__FUNCTION__, line, obWarning);
return false;
}
tokenize(tokens, buffer, " \t\n");
if ( tokens.size() < 2 || ! ( from_string<int>(levcfg, tokens.at(0), std::dec)
&& from_string<int>(imcon, tokens.at(1), std::dec) ) )
{
line=buffer;
line="Problem reading keytrj line: " + line;
obErrorLog.ThrowError(__FUNCTION__, line, obWarning);
return false;
}
return true;
}
bool DlpolyInputReader::ParseUnitCell( std::istream &ifs, OBMol &mol )
{
bool ok;
double x,y,z;
ifs.getline(buffer,BUFF_SIZE);
tokenize(tokens, buffer, " \t\n");
ok = from_string<double>(x, tokens.at(0), std::dec);
ok = from_string<double>(y, tokens.at(1), std::dec);
ok = from_string<double>(z, tokens.at(2), std::dec);
vector3 vx = vector3( x, y, z );
ifs.getline(buffer,BUFF_SIZE);
tokenize(tokens, buffer, " \t\n");
ok = from_string<double>(x, tokens.at(0), std::dec);
ok = from_string<double>(y, tokens.at(1), std::dec);
ok = from_string<double>(z, tokens.at(2), std::dec);
vector3 vy = vector3( x, y, z );
ifs.getline(buffer,BUFF_SIZE);
tokenize(tokens, buffer, " \t\n");
ok = from_string<double>(x, tokens.at(0), std::dec);
ok = from_string<double>(y, tokens.at(1), std::dec);
ok = from_string<double>(z, tokens.at(2), std::dec);
vector3 vz = vector3( x, y, z );
OBUnitCell * unitcell = new OBUnitCell();
unitcell->SetData( vx, vy, vz );
unitcell->SetSpaceGroup(1);
mol.BeginModify();
mol.SetData( unitcell );
mol.EndModify();
return true;
}
bool DlpolyInputReader::ReadAtom( std::istream &ifs, OBMol &mol )
{
std::string AtomLabel;
int AtomIndex,AtomicNumber=-1;
double x,y,z;
OBAtom *atom;
bool ok;
if ( ! ifs.getline(buffer,BUFF_SIZE) ) return false;
tokenize(tokens, buffer, " \t\n");
AtomLabel = tokens.at(0);
if ( tokens.size() >= 2 ) ok = from_string<int>(AtomIndex, tokens.at(1), std::dec);
if ( tokens.size() == 3 )
{
ok = from_string<int>(AtomicNumber, tokens.at(2), std::dec);
if ( ! ok ) AtomicNumber=-1;
}
if ( !ifs.getline(buffer,BUFF_SIZE) ) return false;
tokenize(tokens, buffer, " \t\n");
ok = from_string<double>(x, tokens.at(0), std::dec);
ok = from_string<double>(y, tokens.at(1), std::dec);
ok = from_string<double>(z, tokens.at(2), std::dec);
if ( AtomicNumber == -1 ) {
AtomicNumber = LabelToAtomicNumber( AtomLabel );
}
atom = mol.NewAtom();
atom->SetAtomicNum(AtomicNumber);
atom->SetVector(x, y, z);
AtomicNumber=-1;
if (levcfg > 0 )
{
if ( !ifs.getline(buffer,BUFF_SIZE) ) return false;
}
if ( levcfg > 1 )
{
if ( !ifs.getline(buffer,BUFF_SIZE) ) return false;
tokenize(tokens, buffer, " \t\n");
ok = from_string<double>(x, tokens.at(0), std::dec);
ok = from_string<double>(y, tokens.at(1), std::dec);
ok = from_string<double>(z, tokens.at(2), std::dec);
forces.push_back( vector3( x,y,z ) );
}
return true;
}
class DlpolyConfigFormat : public OBMoleculeFormat, public DlpolyInputReader
{
public:
DlpolyConfigFormat()
{
OBConversion::RegisterFormat("CONFIG",this);
}
virtual const char* Description() {
return "DL-POLY CONFIG\n";
};
virtual const char* SpecificationURL()
{
return "http://www.cse.scitech.ac.uk/ccg/software/DL_POLY";
};
virtual unsigned int Flags()
{
return WRITEONEONLY;
};
virtual bool ReadMolecule(OBBase* pOb, OBConversion* pConv);
virtual bool WriteMolecule(OBBase* pOb, OBConversion* pConv);
};
DlpolyConfigFormat theDlpolyConfigFormat;
bool DlpolyConfigFormat::ReadMolecule(OBBase* pOb, OBConversion* pConv)
{
bool ok;
levcfg=0;
imcon=0;
forces.clear();
OBMol* pmol = pOb->CastAndClear<OBMol>();
if (pmol == nullptr)
return false;
std::istream &ifs = *pConv->GetInStream();
OBMol &mol = *pmol;
if ( ! ParseHeader( ifs, mol ) ) return false;
if ( imcon > 0 ) ParseUnitCell( ifs, mol );
mol.BeginModify();
ok = true;
while ( ok )
{
ok = ReadAtom( ifs, mol );
}
if ( levcfg > 1 && forces.size() )
{
OBConformerData * conformer = new OBConformerData();
std::vector< std::vector< vector3 > > conflist;
conflist.push_back( forces );
conformer->SetForces( conflist );
mol.SetData( conformer );
}
mol.EndModify();
if ( mol.NumAtoms() == 0 )
return(false);
else
return(true);
}
bool DlpolyConfigFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv)
{
OBMol* pmol = dynamic_cast<OBMol*>(pOb);
if (pmol == nullptr)
return false;
std::ostream &ofs = *pConv->GetOutStream();
OBMol &mol = *pmol;
levcfg=0;
imcon=0;
int idx=0; std::string title = mol.GetTitle();
ofs << title.substr(0,80) << std::endl;
ofs << std::setw(10) << levcfg << std::setw(10) << imcon << std::endl;
FOR_ATOMS_OF_MOL(atom, mol)
{
ofs << std::setw(8) << OBElements::GetSymbol(atom->GetAtomicNum()) << std::setw(10) << ++idx << std::setw(10) << atom->GetAtomicNum() << std::endl;
snprintf(buffer, BUFF_SIZE, "%20.15f %20.15f %20.15f\n",
atom->GetX(),
atom->GetY(),
atom->GetZ()
);
ofs << buffer;
}
return(true);
}
class DlpolyHISTORYFormat : public OBMoleculeFormat, public DlpolyInputReader
{
public:
DlpolyHISTORYFormat()
{
OBConversion::RegisterFormat("HISTORY",this);
}
virtual const char* Description() {
return "DL-POLY HISTORY\n";
};
virtual const char* SpecificationURL()
{
return "http://www.cse.scitech.ac.uk/ccg/software/DL_POLY";
};
virtual unsigned int Flags()
{
return NOTWRITABLE;
};
virtual bool ReadMolecule(OBBase* pOb, OBConversion* pConv);
};
DlpolyHISTORYFormat theDlpolyHISTORYFormat;
bool DlpolyHISTORYFormat::ReadMolecule(OBBase* pOb, OBConversion* pConv)
{
std::string tstitle;
bool ok;
int nstep,natms=0;
levcfg=0;
imcon=0;
forces.clear();
OBMol* pmol = pOb->CastAndClear<OBMol>();
if (pmol == nullptr)
return false;
std::istream &ifs = *pConv->GetInStream();
OBMol &mol = *pmol;
if ( ! ifs.tellg() )
{
if ( ! ParseHeader( ifs, mol ) ) return false;
}
if ( ! ifs.getline(buffer,BUFF_SIZE) ) return false;
tokenize(tokens, buffer, " \t\n");
if ( tokens.size() < 6 )
{
line=buffer;
line="Problem reading trajectory line: " + line;
obErrorLog.ThrowError(__FUNCTION__, line, obWarning);
return false;
}
ok = from_string<int>(nstep, tokens.at(1), std::dec);
ok = from_string<int>(natms, tokens.at(2), std::dec);
if ( ! ok )
{
line=buffer;
line="Problem reading natoms on trajectory line: " + line;
obErrorLog.ThrowError(__FUNCTION__, line, obWarning);
return false;
}
ok = from_string<int>(levcfg, tokens.at(3), std::dec);
ok = from_string<int>(imcon, tokens.at(4), std::dec);
tstitle=title + ": timestep=" + tokens.at(1);
mol.SetTitle( tstitle );
if ( imcon > 0 ) ParseUnitCell( ifs, mol );
int atomsRead=0;
mol.BeginModify();
while ( true )
{
if ( ! ReadAtom( ifs, mol ) ) break;
atomsRead++;
if ( atomsRead >= natms) break;
}
if ( levcfg > 1 && forces.size() )
{
OBConformerData * conformer = new OBConformerData();
std::vector< std::vector< vector3 > > conflist;
conflist.push_back( forces );
conformer->SetForces( conflist );
mol.SetData( conformer );
}
mol.EndModify();
if ( mol.NumAtoms() == 0 )
return(false);
else
return(true);
}
}