#include <sstream>
#include <openbabel/babelconfig.h>
#include <openbabel/obmolecformat.h>
#include <openbabel/mol.h>
#include <openbabel/atom.h>
#include <openbabel/elements.h>
#include <openbabel/griddata.h>
#include <cstdlib>
using namespace std;
namespace OpenBabel
{
class OBOpenDXCubeFormat : public OpenBabel::OBMoleculeFormat
{
public:
OBOpenDXCubeFormat()
{
OpenBabel::OBConversion::RegisterFormat( "dx", this );
}
virtual const char* Description() {
return
"OpenDX cube format for APBS\n"
"A volume data format for IBM's Open Source visualization software\n"
"The OpenDX support is currently designed to read the OpenDX cube\n"
"files from APBS. \n\n";
}
virtual const char* SpecificationURL()
{
return "http://apbs.sourceforge.net/doc/user-guide/index.html#id504516";
}
virtual const char* GetMIMEType() { return nullptr; }
virtual int SkipObjects( int n, OpenBabel::OBConversion* pConv ) { return 0; }
virtual unsigned int Flags()
{
return READONEONLY | WRITEONEONLY | ZEROATOMSOK;
};
virtual bool ReadMolecule( OpenBabel::OBBase* pOb, OpenBabel::OBConversion* pConv );
virtual bool WriteMolecule( OpenBabel::OBBase* pOb, OpenBabel::OBConversion* pConv );
};
OBOpenDXCubeFormat theOpenDXCubeFormat;
bool OBOpenDXCubeFormat::ReadMolecule( OBBase* pOb, OBConversion* pConv )
{
OBMol* pmol = pOb->CastAndClear<OBMol>();
if (pmol == nullptr)
return false;
istream& ifs = *pConv->GetInStream();
const char* title = pConv->GetTitle();
char buffer[BUFF_SIZE];
stringstream errorMsg;
if (!ifs)
return false;
pmol->SetTitle(title);
while (ifs.good() && ifs.getline(buffer,BUFF_SIZE)) {
if (buffer[0] == '#')
continue; if (EQn(buffer, "object", 6))
break;
}
if (!ifs)
return false;
vector<string> vs;
tokenize(vs, buffer);
vector<int> voxels(3);
if (!EQn(buffer, "object", 6) || vs.size() != 8)
return false;
else {
voxels[0] = atoi(vs[5].c_str());
voxels[1] = atoi(vs[6].c_str());
voxels[2] = atoi(vs[7].c_str());
}
double x, y, z;
if (!ifs.getline(buffer, BUFF_SIZE) || !EQn(buffer, "origin", 6))
return false;
else {
tokenize(vs, buffer);
if (vs.size() != 4)
return false;
x = atof(vs[1].c_str());
y = atof(vs[2].c_str());
z = atof(vs[3].c_str());
}
vector3 origin(x, y, z);
vector<vector3> axes;
for (unsigned int i = 0; i < 3; ++i) {
if (!ifs.getline(buffer, BUFF_SIZE) || !EQn(buffer, "delta", 5))
return false;
else {
tokenize(vs, buffer);
if (vs.size() != 4)
return false;
x = atof(vs[1].c_str());
y = atof(vs[2].c_str());
z = atof(vs[3].c_str());
axes.push_back(vector3(x, y, z));
}
}
if (!ifs.getline(buffer, BUFF_SIZE) || !EQn(buffer, "object", 6))
return false;
if (!ifs.getline(buffer, BUFF_SIZE) || !EQn(buffer, "object", 6))
return false;
pmol->BeginModify();
pmol->SetDimension(3);
OBGridData *gd = new OBGridData;
gd->SetAttribute("OpenDX");
char *endptr;
vector<double> values;
int n = voxels[0]*voxels[1]*voxels[2];
int line = 0;
values.reserve(n);
while (ifs.getline(buffer, BUFF_SIZE))
{
++line;
if (EQn(buffer, "attribute", 9))
break;
tokenize(vs, buffer);
if (vs.size() == 0)
{
errorMsg << "Problem reading the OpenDX grid file: cannot"
<< " read line " << line
<< ", there does not appear to be any data in it.\n"
<< buffer << "\n";
obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obError);
return false;
}
for (unsigned int l = 0; l < vs.size(); ++l)
{
values.push_back(strtod(static_cast<const char*>(vs[l].c_str()), &endptr));
}
}
gd->SetNumberOfPoints(voxels[0], voxels[1], voxels[2]);
gd->SetLimits(origin, axes[0], axes[1], axes[2]);
gd->SetUnit(OBGridData::ANGSTROM);
gd->SetOrigin(fileformatInput); gd->SetValues(values); pmol->SetData(gd); pmol->EndModify();
if (!ifs.getline(buffer, BUFF_SIZE) || !EQn(buffer, "object", 6))
return false;
if (!ifs.getline(buffer, BUFF_SIZE) || !EQn(buffer, "component", 9))
return false;
if (!ifs.getline(buffer, BUFF_SIZE) || !EQn(buffer, "component", 9))
return false;
if (!ifs.getline(buffer, BUFF_SIZE) || !EQn(buffer, "component", 9))
return false;
std::streampos ipos;
do
{
ipos = ifs.tellg();
ifs.getline(buffer,BUFF_SIZE);
}
while(strlen(buffer) == 0 && !ifs.eof() );
ifs.seekg(ipos);
return true;
}
bool OBOpenDXCubeFormat::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];
string str;
stringstream errorMsg;
OBGridData *gd = (OBGridData*)mol.GetData(OBGenericDataType::GridData);
if (gd == nullptr) {
errorMsg << "The molecule has no grid.";
obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obWarning);
return false;
}
ofs << "# Data from Open Babel " << BABEL_VERSION << "\n";
str = mol.GetTitle();
if (str.empty())
ofs << "# Molecule Title: *****" << "\n";
else
ofs << "# Molecule Title: " << str << "\n";
int nx, ny, nz;
double origin[3], xAxis[3], yAxis[3], zAxis[3];
gd->GetAxes(xAxis, yAxis, zAxis);
gd->GetNumberOfPoints(nx, ny, nz);
gd->GetOriginVector(origin);
snprintf(buffer, BUFF_SIZE, "object 1 class gridpositions counts %5d %5d %5d", nx, ny, nz);
ofs << buffer << "\n";
snprintf(buffer, BUFF_SIZE,"origin %12.6f %12.6f %12.6f",
origin[0], origin[1], origin[2]);
ofs << buffer << "\n";
snprintf(buffer, BUFF_SIZE,"delta %12.6f %12.6f %12.6f",
xAxis[0], xAxis[1], xAxis[2]);
ofs << buffer << "\n";
snprintf(buffer, BUFF_SIZE,"delta %12.6f %12.6f %12.6f",
yAxis[0], yAxis[1], yAxis[2]);
ofs << buffer << "\n";
snprintf(buffer, BUFF_SIZE,"delta %12.6f %12.6f %12.6f",
zAxis[0], zAxis[1], zAxis[2]);
ofs << buffer << "\n";
snprintf(buffer, BUFF_SIZE, "object 2 class gridconnections counts %5d %5d %5d", nx, ny, nz);
ofs << buffer << "\n";
snprintf(buffer, BUFF_SIZE, "object 3 class array type double rank 0 items %5d data follows", nx*ny*nz);
ofs << buffer << "\n";
double value;
unsigned int count = 1;
for (int i = 0; i < nx; ++i)
{
for (int j = 0; j < ny; ++j)
{
for (int k = 0; k < nz; ++k)
{
value = gd->GetValue(i, j, k);
snprintf(buffer, BUFF_SIZE," %12.5E", value);
if (count % 3 == 0)
ofs << buffer << "\n";
else
ofs << buffer;
count++;
} } }
if (count % 3 != 0)
ofs << "\n";
ofs << "attribute \"dep\" string \"positions\"\n";
ofs << "object \"regular positions regular connections\" class field\n";
ofs << "component \"positions\" value 1\n";
ofs << "component \"connections\" value 2\n";
ofs << "component \"data\" value 3\n";
return true;
}
}