1
/**********************************************************************
2
opendxformat.cpp - Read in OpenDX cube format files from APBS
4
Copyright (c) 2007-2008 by Geoffrey R. Hutchison
5
Some Portions Copyright (C) 2008 by Marcus D. Hanwell
7
This file is part of the Open Babel project.
8
For more information, see <http://openbabel.sourceforge.net/>
10
This program is free software; you can redistribute it and/or modify
11
it under the terms of the GNU General Public License as published by
12
the Free Software Foundation: either version 2 of the License, or (at
13
your option) any later version.
15
This program is distributed in the hope that it will be useful,
16
but WITHOUT ANY WARRANTY; without even the implied warranty of
17
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
GNU General Public License for more details.
19
***********************************************************************/
23
#include <openbabel/babelconfig.h>
24
#include <openbabel/obmolecformat.h>
25
#include <openbabel/griddata.h>
32
// Ultimately, this should just read in an OBFloatGrid, rather than a "molecule"
33
// since there's no actual molecular data. For now, we'll read in an OBMol with no atoms
34
// and attach an OBGridData
35
class OBOpenDXCubeFormat : public OpenBabel::OBMoleculeFormat
38
// Constructor: register "dx" extension code
41
OpenBabel::OBConversion::RegisterFormat( "dx", this );
44
// Return description.
45
virtual const char* Description() //required
48
"OpenDX cube format for APBS\n"
52
// Return a specification url, not really a specification since
53
// I couldn't find it but close enough.
54
virtual const char* SpecificationURL()
56
return "http://apbs.sourceforge.net/doc/user-guide/index.html#id504516";
59
// Return MIME type, NULL in this case.
60
virtual const char* GetMIMEType() { return 0; };
62
// Skip to object: used for multi-object file formats.
63
virtual int SkipObjects( int n, OpenBabel::OBConversion* pConv ) { return 0; }
65
virtual unsigned int Flags()
67
return READONEONLY | WRITEONEONLY | ZEROATOMSOK;
70
/// The "API" interface functions
71
virtual bool ReadMolecule( OpenBabel::OBBase* pOb, OpenBabel::OBConversion* pConv );
72
virtual bool WriteMolecule( OpenBabel::OBBase* pOb, OpenBabel::OBConversion* pConv );
76
//------------------------------------------------------------------------------
78
// Global variable used to register Gaussian cube format.
79
OBOpenDXCubeFormat theGaussianCubeFormat;
81
//------------------------------------------------------------------------------
82
bool OBOpenDXCubeFormat::ReadMolecule( OBBase* pOb, OBConversion* pConv )
84
OBMol* pmol = pOb->CastAndClear<OBMol>();
88
istream& ifs = *pConv->GetInStream();
90
const char* title = pConv->GetTitle();
91
char buffer[BUFF_SIZE];
93
stringstream errorMsg;
96
return false; // We are attempting to read past the end of the file
98
pmol->SetTitle(title);
100
while (ifs.good() && ifs.getline(buffer,BUFF_SIZE)) {
101
if (buffer[0] == '#')
102
continue; // comment line
103
if (EQn(buffer, "object", 6))
107
return false; // ran out of lines
110
tokenize(vs, buffer);
112
// Number of grid points (voxels)
113
vector<int> voxels(3);
114
if (!EQn(buffer, "object", 6) || vs.size() != 8)
117
voxels[0] = atoi(vs[5].c_str());
118
voxels[1] = atoi(vs[6].c_str());
119
voxels[2] = atoi(vs[7].c_str());
123
if (!ifs.getline(buffer, BUFF_SIZE) || !EQn(buffer, "origin", 6))
126
tokenize(vs, buffer);
129
x = atof(vs[1].c_str());
130
y = atof(vs[2].c_str());
131
z = atof(vs[3].c_str());
133
vector3 origin(x, y, z);
135
// now three lines with the x, y, and z axes
136
vector<vector3> axes;
137
for (unsigned int i = 0; i < 3; ++i) {
138
if (!ifs.getline(buffer, BUFF_SIZE) || !EQn(buffer, "delta", 5))
141
tokenize(vs, buffer);
144
x = atof(vs[1].c_str());
145
y = atof(vs[2].c_str());
146
z = atof(vs[3].c_str());
147
axes.push_back(vector3(x, y, z));
151
// Two remaining header lines before the data:
153
object 2 class gridconnections counts nx ny nz
154
object 3 class array type double rank 0 times n data follows
156
if (!ifs.getline(buffer, BUFF_SIZE) || !EQn(buffer, "object", 6))
158
if (!ifs.getline(buffer, BUFF_SIZE) || !EQn(buffer, "object", 6))
162
pmol->SetDimension(3);
164
OBGridData *gd = new OBGridData;
165
gd->SetAttribute("OpenDX");
167
// get all values as one vector<double>
169
vector<double> values;
170
int n = voxels[0]*voxels[1]*voxels[2];
173
while (ifs.getline(buffer, BUFF_SIZE))
176
if (EQn(buffer, "attribute", 9))
177
break; // we're finished with reading data -- although we should probably have a voxel check in here too
179
tokenize(vs, buffer);
182
errorMsg << "Problem reading the OpenDX grid file: cannot"
183
<< " read line " << line
184
<< ", there does not appear to be any data in it.\n"
186
obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obError);
190
for (unsigned int l = 0; l < vs.size(); ++l)
192
values.push_back(strtod(static_cast<const char*>(vs[l].c_str()), &endptr));
196
gd->SetNumberOfPoints(voxels[0], voxels[1], voxels[2]);
197
gd->SetLimits(origin, axes[0], axes[1], axes[2]);
198
gd->SetUnit(OBGridData::ANGSTROM);
199
gd->SetOrigin(fileformatInput); // i.e., is this data from a file or determined by Open Babel
200
gd->SetValues(values); // set the values
201
pmol->SetData(gd); // store the grids in the OBMol
204
// Trailing control lines
206
attribute "dep" string "positions"
207
object "regular positions regular connections" class field
208
component "positions" value 1
209
component "connections" value 2
210
component "data" value 3
212
if (!ifs.getline(buffer, BUFF_SIZE) || !EQn(buffer, "object", 6))
214
if (!ifs.getline(buffer, BUFF_SIZE) || !EQn(buffer, "component", 9))
216
if (!ifs.getline(buffer, BUFF_SIZE) || !EQn(buffer, "component", 9))
218
if (!ifs.getline(buffer, BUFF_SIZE) || !EQn(buffer, "component", 9))
221
// clean out any remaining blank lines
222
while(ifs.peek() != EOF && ifs.good() &&
223
(ifs.peek() == '\n' || ifs.peek() == '\r'))
224
ifs.getline(buffer,BUFF_SIZE);
229
//------------------------------------------------------------------------------
230
bool OBOpenDXCubeFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv)
232
OBMol* pmol = dynamic_cast<OBMol*>(pOb);
236
ostream &ofs = *pConv->GetOutStream();
239
char buffer[BUFF_SIZE];
241
stringstream errorMsg;
243
OBGridData *gd = (OBGridData*)mol.GetData(OBGenericDataType::GridData);
245
errorMsg << "The molecule has no grid.";
246
obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obWarning);
250
// APBS-style OpenDX Multigrid
251
// First some comments
252
ofs << "# Data from Open Babel " << BABEL_VERSION << "\n";
253
str = mol.GetTitle();
255
ofs << "# Molecule Title: *****" << "\n";
257
ofs << "# Molecule Title: " << str << "\n";
260
double origin[3], xAxis[3], yAxis[3], zAxis[3];
261
gd->GetAxes(xAxis, yAxis, zAxis);
262
gd->GetNumberOfPoints(nx, ny, nz);
263
gd->GetOriginVector(origin);
265
// data line 1: # of points in x, y, z (nx, ny, nz)
266
snprintf(buffer, BUFF_SIZE, "object 1 class gridposition counts %5d %5d %5d", nx, ny, nz);
267
ofs << buffer << "\n";
269
// data line 2: origin (x, y, z)
270
snprintf(buffer, BUFF_SIZE,"origin %12.6f %12.6f %12.6f",
271
origin[0], origin[1], origin[2]);
272
ofs << buffer << "\n";
274
// data line 3: x-displacement
275
snprintf(buffer, BUFF_SIZE,"delta %12.6f %12.6f %12.6f",
276
xAxis[0], xAxis[1], xAxis[2]);
277
ofs << buffer << "\n";
279
// data line 4: y-displacement
280
snprintf(buffer, BUFF_SIZE,"delta %12.6f %12.6f %12.6f",
281
yAxis[0], yAxis[1], yAxis[2]);
282
ofs << buffer << "\n";
284
// data line 5: z-displacement
285
snprintf(buffer, BUFF_SIZE,"delta %12.6f %12.6f %12.6f",
286
zAxis[0], zAxis[1], zAxis[2]);
287
ofs << buffer << "\n";
289
// data line 6: # of points in x, y, z (nx, ny, nz)
290
snprintf(buffer, BUFF_SIZE, "object 2 class gridconnections counts %5d %5d %5d", nx, ny, nz);
291
ofs << buffer << "\n";
293
// data line 7: total # of points
294
snprintf(buffer, BUFF_SIZE, "object 3 class array type double rank 0 times %5d data follows", nx*ny*nz);
295
ofs << buffer << "\n";
299
unsigned int count = 1;
300
for (int i = 0; i < nx; ++i)
302
for (int j = 0; j < ny; ++j)
304
for (int k = 0; k < nz; ++k)
306
value = gd->GetValue(i, j, k);
307
snprintf(buffer, BUFF_SIZE," %12.5E", value);
309
ofs << buffer << "\n";
319
ofs << "attribute \"dep\" string \"positions\"\n";
320
ofs << "object \"regular positions regular connections\" class field\n";
321
ofs << "component \"positions\" value 1\n";
322
ofs << "component \"connections\" value 2\n";
323
ofs << "component \"data\" value 3\n";