Coverage Report

Created: 2023-06-07 06:20

/src/openbabel/src/formats/gausscubeformat.cpp
Line
Count
Source (jump to first uncovered line)
1
/**********************************************************************
2
gausscubeformat.cpp - Read in Gaussian cube format files.
3
4
// Molekel - Molecular Visualization Program
5
// Copyright (C) 2006, 2007 Swiss National Supercomputing Centre (CSCS)
6
7
 Some Portions Copyright (c) 2007 by Geoffrey R. Hutchison
8
 Some Portions Copyright (C) 2008 by Marcus D. Hanwell
9
 Some Portions Copyright (C) 2008 by Tim Vandermeersch
10
11
This file is part of the Open Babel project.
12
For more information, see <http://openbabel.org/>
13
14
This program is free software; you can redistribute it and/or modify
15
it under the terms of the GNU General Public License as published by
16
the Free Software Foundation: either version 2 of the License, or (at
17
your option) any later version.
18
19
This program is distributed in the hope that it will be useful,
20
but WITHOUT ANY WARRANTY; without even the implied warranty of
21
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
GNU General Public License for more details.
23
***********************************************************************/
24
25
#include <sstream>
26
#include <cstdlib>
27
28
#include <openbabel/babelconfig.h>
29
#include <openbabel/obmolecformat.h>
30
#include <openbabel/mol.h>
31
#include <openbabel/atom.h>
32
#include <openbabel/bond.h>
33
#include <openbabel/obiter.h>
34
#include <openbabel/elements.h>
35
36
#include <openbabel/griddata.h>
37
38
using namespace std;
39
40
/// @warning seems that every position in cube files has always to be
41
/// multiplied by this constant even if according to:
42
/// reference: https://www.gaussian.com/cubegen/
43
/// <Num points along first axis> > 0 means that the values
44
/// are already in Angstroms.
45
static const double BOHR_TO_ANGSTROM = 0.529177249;
46
static const double ANGSTROM_TO_BOHR = 1.0 / 0.529177249;
47
48
namespace OpenBabel
49
{
50
51
  class OBGaussianCubeFormat : public OpenBabel::OBMoleculeFormat
52
  {
53
  public:
54
    // Constructor: register 'cube' and "CUBE" format.
55
    OBGaussianCubeFormat()
56
4
    {
57
4
        OpenBabel::OBConversion::RegisterFormat( "cube", this );
58
4
        OpenBabel::OBConversion::RegisterFormat( "cub", this );
59
4
    }
60
61
    // Return description.
62
    const char* Description() override  // required
63
0
    {
64
0
        return
65
0
        "Gaussian cube format\n"
66
0
        "A grid format for volume data used by Gaussian\n"
67
0
        "Open Babel supports reading and writing Gaussian cubes, including multiple\n"
68
0
        "grids in one file.\n\n"
69
70
0
        "Read Options e.g. -as\n"
71
0
        "  b no bonds\n"
72
0
        "  s no multiple bonds\n\n";
73
0
    }
74
75
    // Return a specification url, not really a specification since
76
    // I couldn't find it but close enough.
77
    const char* SpecificationURL() override
78
0
    {
79
0
        return "https://www.gaussian.com/cubegen/";
80
0
    }
81
82
    // Return MIME type, NULL in this case.
83
0
    const char* GetMIMEType() override { return nullptr; }
84
85
    // Skip to object: used for multi-object file formats.
86
0
    int SkipObjects(int n, OpenBabel::OBConversion* pConv) override { return 0; }
87
88
    unsigned int Flags() override
89
8
    {
90
8
        return 0;
91
8
    }
92
93
    /// The "API" interface functions
94
    bool ReadMolecule(OpenBabel::OBBase* pOb, OpenBabel::OBConversion* pConv) override;
95
    /// Write: always returns false right now - read only
96
    bool WriteMolecule(OpenBabel::OBBase* pOb, OpenBabel::OBConversion* pConv) override;
97
98
};
99
100
//------------------------------------------------------------------------------
101
102
    // Global variable used to register Gaussian cube format.
103
    OBGaussianCubeFormat theGaussianCubeFormat;
104
105
//------------------------------------------------------------------------------
106
bool OBGaussianCubeFormat::ReadMolecule( OBBase* pOb, OBConversion* pConv )
107
0
{
108
0
    OBMol* pmol = pOb->CastAndClear<OBMol>();
109
0
    if (pmol == nullptr)
110
0
      return false;
111
112
0
    istream& ifs = *pConv->GetInStream();
113
114
0
    const char* title = pConv->GetTitle();
115
0
    char buffer[BUFF_SIZE];
116
117
0
    stringstream errorMsg;
118
119
0
    int nAtoms = 0;
120
0
    int negAtoms = false;
121
122
0
    int line = 0; // Line counter - help in debugging...
123
124
0
    if (!ifs)
125
0
      return false; // We are attempting to read past the end of the file
126
127
    // The first two lines are comments - and so not needed.
128
0
    ++line;
129
0
    if (!ifs.getline(buffer, BUFF_SIZE))
130
0
    {
131
0
      obErrorLog.ThrowError(__FUNCTION__,
132
0
                            "Problem reading the Gaussian cube file: cannot read the first line (title/comments).", obWarning);
133
0
      return false;
134
0
    }
135
0
    string cubeTitle = buffer; // save for later use
136
137
0
    ++line;
138
0
    if (!ifs.getline(buffer,BUFF_SIZE))
139
0
    {
140
0
      obErrorLog.ThrowError(__FUNCTION__,
141
0
                            "Problem reading the Gaussian cube file: cannot read the second line (title/comments).", obWarning);
142
0
      return false;
143
0
    }
144
145
    // This line contains the number of atoms included in the file followed by
146
    // the position of the origin of the cube.
147
0
    ++line;
148
0
    if (!ifs.getline(buffer, BUFF_SIZE))
149
0
    {
150
0
      obErrorLog.ThrowError(__FUNCTION__,
151
0
                            "Problem reading the Gaussian cube file: cannot read the third line. This should contain the number of atoms and the position of the origin of the cube.", obWarning);
152
0
      return false;
153
0
    }
154
0
    vector<string> vs;
155
0
    tokenize(vs, buffer);
156
0
    if (vs.size() < 4)
157
0
    {
158
0
      obErrorLog.ThrowError(__FUNCTION__,
159
0
                            "Problem reading the Gassian cube file: The third line must contain the number of atoms and the origin of the cube.", obWarning);
160
0
      return false;
161
0
    }
162
0
    char *endptr;
163
0
    nAtoms = strtol(static_cast<const char*>(vs.at(0).c_str()), &endptr, 10);
164
0
    if (endptr == static_cast<const char*>(vs.at(0).c_str()))
165
0
    {
166
0
      errorMsg << "Problems reading the Gaussian cube file: "
167
0
               << "Could not read line #3.\n"
168
0
               << "According to the specification this line should contain "
169
0
               << "four entries separated by white space.\n"
170
0
               << "OpenBabel could not interpret item #0 as an integer.";
171
0
      obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obWarning);
172
0
      return false;
173
0
    }
174
0
    if (nAtoms < 0)
175
0
    {
176
      // If the number of atoms is negative it means there is data between
177
      // the atom positions and grid data.
178
0
      negAtoms = true;
179
0
      nAtoms *= -1;
180
0
    }
181
//    cerr << "Number of atoms: " << nAtoms << " Orig: " << vs.at(0) << endl;
182
0
    double x = strtod(static_cast<const char*>(vs.at(1).c_str()), &endptr);
183
0
    if (endptr == static_cast<const char*>(vs.at(1).c_str()))
184
0
    {
185
0
      errorMsg << "Problems reading the Gaussian cube file: "
186
0
               << "Could not read line #3.\n"
187
0
               << "According to the specification this line should contain "
188
0
               << "four entries separated by white space.\n"
189
0
               << "OpenBabel could not interpret item #1 as a double.";
190
0
      obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obWarning);
191
0
      return false;
192
0
    }
193
0
    double y = strtod(static_cast<const char*>(vs.at(2).c_str()), &endptr);
194
0
    if (endptr == static_cast<const char*>(vs.at(2).c_str()))
195
0
    {
196
0
      errorMsg << "Problems reading the Gaussian cube file: "
197
0
               << "Could not read line #3.\n"
198
0
               << "According to the specification this line should contain "
199
0
               << "four entries separated by white space.\n"
200
0
               << "OpenBabel could not interpret item #2 as a double.";
201
0
      obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obWarning);
202
0
      return false;
203
0
    }
204
0
    double z = strtod(static_cast<const char*>(vs.at(3).c_str()), &endptr);
205
0
    if (endptr == static_cast<const char*>(vs.at(3).c_str()))
206
0
    {
207
0
      errorMsg << "Problems reading the Gaussian cube file: "
208
0
               << "Could not read line #3.\n"
209
0
               << "According to the specification this line should contain "
210
0
               << "four entries separated by white space.\n"
211
0
               << "OpenBabel could not interpret item #3 as a double.";
212
0
      obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obWarning);
213
0
      return false;
214
0
    }
215
0
    vector3 origin(x, y, z);
216
0
    origin *= BOHR_TO_ANGSTROM;
217
218
    // The next three lines contain the number of voxels in x, y and z along
219
    // with the three cube cell axes.
220
0
    vector<int> voxels(3);
221
0
    vector<vector3> axes(3);
222
0
    bool angstroms = true;
223
0
    for (int i = 0; i < 3; i++)
224
0
    {
225
0
      ++line;
226
0
      if (!ifs.getline(buffer, BUFF_SIZE))
227
0
      {
228
0
        errorMsg << "Problem reading the Gaussian cube file: cannot read the "
229
0
                 << line << "line.\nAccording to the specification this line "
230
0
                 << "should contain header information on the size of the cube.\n";
231
0
        obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obWarning);
232
0
        return false;
233
0
      }
234
0
      vs.clear();
235
0
      tokenize(vs, buffer);
236
0
      if (vs.size() < 4)
237
0
      {
238
0
        errorMsg << "Problem reading the Gaussian cube file: cannot read the "
239
0
                 << i+4 << "line.\nAccording to the specification this line "
240
0
                 << "should contain four elements (cube header).\n";
241
0
        obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obWarning);
242
0
        return false;
243
0
      }
244
0
      voxels[i] = strtol(static_cast<const char*>(vs.at(0).c_str()), &endptr, 10);
245
0
      if (endptr == static_cast<const char*>(vs.at(0).c_str()))
246
0
      {
247
0
        errorMsg << "Problems reading the Gaussian cube file: "
248
0
                 << "Could not read line " << i+4 << ".\n"
249
0
                 << "According to the specification this line should contain "
250
0
                 << "four entries separated by white space.\n"
251
0
                 << "OpenBabel could not interpret item #0 as an integer.";
252
0
        obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obWarning);
253
0
        return false;
254
0
      }
255
0
      if (voxels[i] < 0)
256
0
      {
257
        // If the number of voxels is negative then the cube is in Bohr
258
0
        angstroms = false;
259
0
        voxels[i] *= -1;
260
0
      }
261
0
      x = strtod(static_cast<const char*>(vs.at(1).c_str()), &endptr);
262
0
      if (endptr == static_cast<const char*>(vs.at(1).c_str()))
263
0
      {
264
0
        errorMsg << "Problems reading the Gaussian cube file: "
265
0
                 << "Could not read line " << i+4 << ".\n"
266
0
                 << "According to the specification this line should contain "
267
0
                 << "four entries separated by white space.\n"
268
0
                 << "OpenBabel could not interpret item #1 as a double.";
269
0
        obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obWarning);
270
0
        return false;
271
0
      }
272
0
      y = strtod(static_cast<const char*>(vs.at(2).c_str()), &endptr);
273
0
      if (endptr == static_cast<const char*>(vs.at(2).c_str()))
274
0
      {
275
0
        errorMsg << "Problems reading the Gaussian cube file: "
276
0
                 << "Could not read line " << i+4 << ".\n"
277
0
                 << "According to the specification this line should contain "
278
0
                 << "four entries separated by white space.\n"
279
0
                 << "OpenBabel could not interpret item #2 as a double.";
280
0
        obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obWarning);
281
0
        return false;
282
0
      }
283
0
      z = strtod(static_cast<const char*>(vs.at(3).c_str()), &endptr);
284
0
      if (endptr == static_cast<const char*>(vs.at(3).c_str()))
285
0
      {
286
0
        errorMsg << "Problems reading the Gaussian cube file: "
287
0
                 << "Could not read line " << i+4 << ".\n"
288
0
                 << "According to the specification this line should contain "
289
0
                 << "four entries separated by white space.\n"
290
0
                 << "OpenBabel could not interpret item #3 as a double.";
291
0
        obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obWarning);
292
0
        return false;
293
0
      }
294
0
      axes[i] = vector3(x, y, z);
295
0
      axes[i] *= BOHR_TO_ANGSTROM;
296
0
    }
297
298
0
    pmol->BeginModify();
299
0
    pmol->SetDimension(3);
300
0
    pmol->ReserveAtoms(nAtoms);
301
302
    // Now to read in the atoms contained in the Gaussian cube
303
0
    for (int i = 0; i < nAtoms; i++)
304
0
    {
305
0
      ++line;
306
0
      if (!ifs.getline(buffer, BUFF_SIZE))
307
0
      {
308
0
        errorMsg << "Problem reading the Gaussian cube file: cannot read the "
309
0
                 << line << "line.\nAccording to the specification this line "
310
0
                 << "should contain atomic number and coordinates.\n";
311
0
        obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obWarning);
312
0
        return false;
313
0
      }
314
0
      vs.clear();
315
0
      tokenize(vs, buffer);
316
0
      if (vs.size() < 5)
317
0
      {
318
0
        errorMsg << "Problem reading the Gaussian cube file: cannot read the "
319
0
                 << line << "line.\nAccording to the specification this line "
320
0
                 << "should contain five elements (atom information).\n";
321
0
        obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obWarning);
322
0
        return false;
323
0
      }
324
325
      // Only contains atoms - no bonds
326
0
      OBAtom *atom = pmol->NewAtom();
327
328
0
      int atomicNum = strtol(static_cast<const char*>(vs.at(0).c_str()), &endptr, 10);
329
0
      if (endptr == static_cast<const char*>(vs.at(0).c_str()))
330
0
      {
331
0
        errorMsg << "Problems reading the Gaussian cube file: "
332
0
                 << "Could not read line " << line << ".\n"
333
0
                 << "According to the specification this line should contain "
334
0
                 << "five entries separated by white space.\n"
335
0
                 << "OpenBabel could not interpret item #0 as an integer.";
336
0
        obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obWarning);
337
0
        return false;
338
0
      }
339
340
0
      atom->SetAtomicNum(atomicNum);
341
342
      // Read the atom coordinates
343
0
      x = strtod(static_cast<const char*>(vs.at(2).c_str()), &endptr);
344
0
      if (endptr == static_cast<const char*>(vs.at(2).c_str()))
345
0
      {
346
0
        errorMsg << "Problems reading the Gaussian cube file: "
347
0
                 << "Could not read line " << line << ".\n"
348
0
                 << "According to the specification this line should contain "
349
0
                 << "five entries separated by white space.\n"
350
0
                 << "OpenBabel could not interpret item #2 as a double.";
351
0
        obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obWarning);
352
0
        return false;
353
0
      }
354
0
      y = strtod(static_cast<const char*>(vs.at(3).c_str()), &endptr);
355
0
      if (endptr == static_cast<const char*>(vs.at(3).c_str()))
356
0
      {
357
0
        errorMsg << "Problems reading the Gaussian cube file: "
358
0
                 << "Could not read line " << line << ".\n"
359
0
                 << "According to the specification this line should contain "
360
0
                 << "five entries separated by white space.\n"
361
0
                 << "OpenBabel could not interpret item #3 as a double.";
362
0
        obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obWarning);
363
0
        return false;
364
0
      }
365
0
      z = strtod(static_cast<const char*>(vs.at(4).c_str()), &endptr);
366
0
      if (endptr == static_cast<const char*>(vs.at(4).c_str()))
367
0
      {
368
0
        errorMsg << "Problems reading the Gaussian cube file: "
369
0
                 << "Could not read line " << line << ".\n"
370
0
                 << "According to the specification this line should contain "
371
0
                 << "five entries separated by white space.\n"
372
0
                 << "OpenBabel could not interpret item #4 as a double.";
373
0
        obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obWarning);
374
0
        return false;
375
0
      }
376
      // Convert units...
377
0
      x *= BOHR_TO_ANGSTROM;
378
0
      y *= BOHR_TO_ANGSTROM;
379
0
      z *= BOHR_TO_ANGSTROM;
380
0
      atom->SetVector(x, y, z);
381
0
    }
382
383
0
    int nCubes = 1;
384
0
    vector<OBGridData*> vgd;
385
    // If the number of atoms was negative then there is some data between the
386
    // atom data and the cube data, i.e. we have multiple cubes...
387
0
    if (negAtoms)
388
0
    {
389
0
      ++line;
390
0
      if (!ifs.getline(buffer, BUFF_SIZE))
391
0
      {
392
0
        obErrorLog.ThrowError(__FUNCTION__,
393
0
                              "Problem reading the Gaussian cube file: cannot read the line between the atom data and cube data.", obError);
394
0
        return false;
395
0
      }
396
397
0
      tokenize(vs, buffer);
398
0
      if (vs.size() < 1) return false; // timvdm 18/06/2008
399
0
      nCubes = strtol(static_cast<const char*>(vs.at(0).c_str()), &endptr, 10);
400
0
      if (endptr == static_cast<const char*>(vs.at(0).c_str()))
401
0
      {
402
0
        errorMsg << "Problems reading the Gaussian cube file: "
403
0
                 << "Could not read line " << line << ".\n"
404
0
                 << "According to the specification this line should contain "
405
0
                 << "the number of cubes and a number for each cube (orbital number).\n"
406
0
                 << "OpenBabel could not interpret item #0 as an integer.";
407
0
        obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obWarning);
408
0
        return false;
409
0
      }
410
411
0
      vgd.reserve(nCubes);
412
0
      for (unsigned int i = 1; i < vs.size(); ++i)
413
0
      {
414
0
        int cubeNumber = strtol(static_cast<const char*>(vs.at(i).c_str()), &endptr, 10);
415
0
        if (endptr == static_cast<const char*>(vs.at(i).c_str()))
416
0
        {
417
0
          errorMsg << "Problems reading the Gaussian cube file: "
418
0
                   << "Could not read line " << line << ".\n"
419
0
                   << "According to the specification this line should contain "
420
0
                   << "the number of cubes and a number for each cube (orbital number).\n"
421
0
                   << "OpenBabel could not interpret item #" << vgd.size()
422
0
                   << " as an integer.";
423
0
          obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obWarning);
424
0
          return false;
425
0
        }
426
0
        vgd.push_back(new OBGridData);
427
0
        stringstream cubeTitle;
428
0
        cubeTitle << "MO " << cubeNumber;
429
0
        vgd.at(vgd.size()-1)->SetAttribute(cubeTitle.str().c_str());
430
0
      }
431
      // Now if we have lots of cubes we need to read in more line(s)
432
0
      while (vgd.size() < nCubes)
433
0
      {
434
0
        ++line;
435
0
        if (!ifs.getline(buffer, BUFF_SIZE))
436
0
        {
437
0
          errorMsg << "Problem reading the Gaussian cube file: cannot"
438
0
                   << " read line " << line
439
0
                   << " of the file. More data was expected.\n"
440
0
                   << "Grid MO titles read in = " << vgd.size()
441
0
                   << " and expected number of values = "
442
0
                   << nCubes << endl;
443
0
          obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obError);
444
0
          return false;
445
0
        }
446
0
        tokenize(vs, buffer);
447
0
        for (unsigned int i = 0; i < vs.size(); ++i)
448
0
        {
449
0
          int cubeNumber = strtol(static_cast<const char*>(vs.at(i).c_str()), &endptr, 10);
450
0
          if (endptr == static_cast<const char*>(vs.at(i).c_str()))
451
0
          {
452
0
            errorMsg << "Problems reading the Gaussian cube file: "
453
0
                     << "Could not read line " << line << ".\n"
454
0
                     << "According to the specification this line should contain "
455
0
                     << "the number of cubes and a number for each cube (orbital number).\n"
456
0
                     << "OpenBabel could not interpret item #" << vgd.size()
457
0
                     << " as an integer.";
458
0
            obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obWarning);
459
0
            return false;
460
0
          }
461
0
          vgd.push_back(new OBGridData);
462
0
          stringstream cubeTitle;
463
0
          cubeTitle << "MO " << cubeNumber;
464
0
          vgd.at(vgd.size()-1)->SetAttribute(cubeTitle.str().c_str());
465
0
        }
466
0
      }
467
0
    }
468
0
    else
469
0
    {
470
      // only one cube
471
0
      vgd.push_back(new OBGridData);
472
0
      vgd.at(0)->SetAttribute(cubeTitle.c_str());
473
0
    }
474
475
    // get all values as one vector<double>
476
0
    vector<double> values;
477
0
    int n = voxels[0]*voxels[1]*voxels[2];
478
0
    values.reserve(n*nCubes);
479
0
    while (values.size() < n*nCubes)
480
0
    {
481
      // Read in values until we have a complete row of data
482
0
      ++line;
483
0
      if (!ifs.getline(buffer, BUFF_SIZE))
484
0
      {
485
0
        errorMsg << "Problem reading the Gaussian cube file: cannot"
486
0
                 << " read line " << line
487
0
                 << " of the file. More data was expected.\n"
488
0
                 << "Values read in = " << values.size()
489
0
                 << " and expected number of values = "
490
0
                 << n*nCubes << endl;
491
0
        obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obError);
492
0
        return false;
493
0
      }
494
0
      tokenize(vs, buffer);
495
0
      if (vs.size() == 0)
496
0
      {
497
0
        errorMsg << "Problem reading the Gaussian cube file: cannot"
498
0
                 << " read line " << line
499
0
                 << ", there does not appear to be any data in it.\n"
500
0
                 << buffer << "\n";
501
0
        obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obError);
502
0
        return false;
503
0
      }
504
505
0
      for (unsigned int l = 0; l < vs.size(); ++l)
506
0
      {
507
0
        values.push_back(strtod(static_cast<const char*>(vs.at(l).c_str()), &endptr));
508
0
      }
509
0
    }
510
511
    // translate the vector<double> to vector<vector<double> >
512
0
    vector<vector<double> > vvd;
513
0
    vvd.resize(nCubes);
514
0
    for (unsigned int i = 0; i < values.size(); )
515
0
    {
516
0
      for (int j = 0; j < nCubes; ++j, ++i) // foreach cube
517
0
      {
518
0
        vvd[j].push_back(values[i]);
519
0
      }
520
0
    }
521
522
0
    for (int i = 0; i < nCubes; ++i) // foreach cube
523
0
    {
524
0
      vgd[i]->SetNumberOfPoints(voxels[0], voxels[1], voxels[2]);
525
0
      vgd[i]->SetLimits(origin, axes[0], axes[1], axes[2]);
526
0
      vgd[i]->SetUnit(angstroms ? OBGridData::ANGSTROM : OBGridData::BOHR);
527
0
      vgd[i]->SetOrigin(fileformatInput); // i.e., is this data from a file or determined by Open Babel
528
0
      vgd[i]->SetValues(vvd[i]); // set the values
529
0
      pmol->SetData(vgd[i]); // store the grids in the OBMol
530
0
    }
531
532
0
    pmol->EndModify();
533
534
    // clean out any remaining blank lines
535
0
    std::streampos ipos;
536
0
    do
537
0
    {
538
0
      ipos = ifs.tellg();
539
0
      ifs.getline(buffer,BUFF_SIZE);
540
0
    }
541
0
    while(strlen(buffer) == 0 && !ifs.eof() );
542
0
    ifs.seekg(ipos);
543
544
    // Connect the dots and guess bond orders
545
0
    if (!pConv->IsOption("b", OBConversion::INOPTIONS))
546
0
      pmol->ConnectTheDots();
547
0
    if (!pConv->IsOption("s", OBConversion::INOPTIONS) && !pConv->IsOption("b", OBConversion::INOPTIONS))
548
0
      pmol->PerceiveBondOrders();
549
550
0
    pmol->SetDimension(3); // always a 3D structure
551
552
0
    return true;
553
0
  }
554
555
//------------------------------------------------------------------------------
556
  bool OBGaussianCubeFormat::WriteMolecule(OBBase* pOb, OBConversion* pConv)
557
0
  {
558
0
    OBMol* pmol = dynamic_cast<OBMol*>(pOb);
559
0
    if (pmol == nullptr)
560
0
      return false;
561
562
0
    ostream &ofs = *pConv->GetOutStream();
563
0
    OBMol &mol = *pmol;
564
565
0
    char buffer[BUFF_SIZE];
566
0
    string str;
567
0
    stringstream errorMsg;
568
569
    // first two lines are comments
570
0
    str = mol.GetTitle();
571
0
    if (str.empty())
572
0
      ofs << "*****" << endl;
573
0
    else
574
0
      ofs << str << endl;
575
576
0
    ofs << endl; // line 2
577
578
0
    OBGridData *gd = (OBGridData*)mol.GetData(OBGenericDataType::GridData);
579
0
    if (gd == nullptr) {
580
0
      errorMsg << "The molecule has no grid.";
581
0
      obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obWarning);
582
0
      return false;
583
0
    }
584
585
0
    int nx, ny, nz;
586
0
    double origin[3], xAxis[3], yAxis[3], zAxis[3];
587
0
    gd->GetAxes(xAxis, yAxis, zAxis);
588
0
    gd->GetNumberOfPoints(nx, ny, nz);
589
0
    gd->GetOriginVector(origin);
590
591
    // line 3: number of atoms, origin x y z
592
0
    snprintf(buffer, BUFF_SIZE,"%5d%12.6f%12.6f%12.6f", - static_cast<signed int> (mol.NumAtoms()),
593
0
        origin[0]*ANGSTROM_TO_BOHR, origin[1]*ANGSTROM_TO_BOHR, origin[2]*ANGSTROM_TO_BOHR);
594
0
    ofs << buffer << endl;
595
596
    // line 4: number of points x direction, axis x direction x y z
597
0
    snprintf(buffer, BUFF_SIZE,"%5d%12.6f%12.6f%12.6f", nx,
598
0
        xAxis[0]*ANGSTROM_TO_BOHR, xAxis[1]*ANGSTROM_TO_BOHR, xAxis[2]*ANGSTROM_TO_BOHR);
599
0
    ofs << buffer << endl;
600
601
    // line 5: number of points y direction, axis y direction x y z
602
0
    snprintf(buffer, BUFF_SIZE,"%5d%12.6f%12.6f%12.6f", ny,
603
0
        yAxis[0]*ANGSTROM_TO_BOHR, yAxis[1]*ANGSTROM_TO_BOHR, yAxis[2]*ANGSTROM_TO_BOHR);
604
0
    ofs << buffer << endl;
605
606
    // line 6: number of points z direction, axis z direction x y z
607
0
    snprintf(buffer, BUFF_SIZE,"%5d%12.6f%12.6f%12.6f", nz,
608
0
        zAxis[0]*ANGSTROM_TO_BOHR, zAxis[1]*ANGSTROM_TO_BOHR, zAxis[2]*ANGSTROM_TO_BOHR);
609
0
    ofs << buffer << endl;
610
611
    // Atom lines: atomic number, ?, X, Y, Z
612
0
    FOR_ATOMS_OF_MOL (atom, mol) {
613
0
      double *coordPtr = atom->GetCoordinate();
614
0
      snprintf(buffer, BUFF_SIZE,"%5d%12.6f%12.6f%12.6f%12.6f", atom->GetAtomicNum(),
615
0
          static_cast<double>(atom->GetAtomicNum()),
616
0
          coordPtr[0]*ANGSTROM_TO_BOHR, coordPtr[1]*ANGSTROM_TO_BOHR, coordPtr[2]*ANGSTROM_TO_BOHR);
617
0
      ofs << buffer << endl;
618
0
    }
619
620
0
    vector<OBGenericData*> grids = pmol->GetAllData(OBGenericDataType::GridData);
621
0
    snprintf(buffer, BUFF_SIZE," %5lu", (unsigned long)grids.size());
622
0
    ofs << buffer << flush;
623
0
    for (unsigned int l = 1; l <= grids.size(); ++l)
624
0
    {
625
0
      snprintf(buffer, BUFF_SIZE," %3d", l);
626
0
      ofs << buffer << flush;
627
0
    }
628
0
    ofs << endl;
629
630
0
    for (unsigned int l = 0; l < grids.size(); ++l)
631
0
    {
632
0
      gd = static_cast<OBGridData*>(grids[l]);
633
0
      int mx, my, mz;
634
0
      gd->GetNumberOfPoints(mx, my, mz);
635
636
0
      if ((nx != mx) || (ny != my) || (nz != mz))
637
0
      {
638
0
          errorMsg << "Problem writing the Gaussian cube file: cube " << l
639
0
                   << " does not have the same dimentions as cube 0.\n"
640
0
                   << "This cube will be skipped.\n";
641
0
          obErrorLog.ThrowError(__FUNCTION__, errorMsg.str(), obError);
642
0
      }
643
0
    }
644
645
    // The cube(s)
646
0
    double value;
647
0
    unsigned int count = 1;
648
0
    for (int i = 0; i < nx; ++i)
649
0
    {
650
0
      for (int j = 0; j < ny; ++j)
651
0
      {
652
0
        for (int k = 0; k < nz; ++k)
653
0
        {
654
          // The cube files are stored in staggered z
655
0
          for (unsigned int l = 0; l < grids.size(); ++l)
656
0
          {
657
0
            value = static_cast<OBGridData*>(grids[l])->GetValue(i, j, k);
658
0
            snprintf(buffer, BUFF_SIZE," %12.5E", value);
659
0
            if (count % 6 == 0)
660
0
              ofs << buffer << endl;
661
0
            else
662
0
              ofs << buffer;
663
0
            count++;
664
0
          }
665
0
        } // z-axis
666
0
      } // y-axis
667
0
    } // x-axis
668
669
0
    return true;
670
0
  }
671
}