Coverage Report

Created: 2025-07-13 06:44

/src/openbabel/src/formats/fchkformat.cpp
Line
Count
Source (jump to first uncovered line)
1
/**********************************************************************
2
Copyright (C) 2007 by Maxim Fedorovsky, University of Fribourg (Switzerland).
3
4
This program is free software; you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation version 2 of the License.
7
8
This program is distributed in the hope that it will be useful,
9
but WITHOUT ANY WARRANTY; without even the implied warranty of
10
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
GNU General Public License for more details.
12
***********************************************************************/
13
14
#include <numeric>
15
#include <typeinfo>
16
#include <functional>
17
#include <cstdlib>
18
#include <algorithm>
19
20
// No diagnoalization yet. Perhaps for 2.2 -GRH
21
// #include <eigen/matrix.h>
22
23
#include <openbabel/mol.h>
24
#include <openbabel/obconversion.h>
25
#include <openbabel/obmolecformat.h>
26
#include <openbabel/mol.h>
27
#include <openbabel/atom.h>
28
#include <openbabel/bond.h>
29
#include <openbabel/obiter.h>
30
#include <openbabel/elements.h>
31
#include <openbabel/generic.h>
32
33
#include <openbabel/math/matrix3x3.h>
34
35
0
#define BOHR2ANGSTROM 0.5291772083
36
#define HARTREE2INVCM 219474.631371
37
#define AMU2AU 1822.88848
38
#define REDDIPSTR2INT 974.864
39
40
using namespace std;
41
42
namespace OpenBabel
43
{
44
  //! \brief Class for parsing Gaussian formatted checkpoint files
45
  class FCHKFormat : public OBMoleculeFormat
46
  {
47
  public :
48
    /* Register this format type ID */
49
    FCHKFormat()
50
6
    {
51
6
      OBConversion::RegisterFormat("fchk", this,
52
6
                                   "chemical/x-gaussian-checkpoint");
53
6
      OBConversion::RegisterFormat("fch", this,
54
6
                                   "chemical/x-gaussian-checkpoint");
55
6
      OBConversion::RegisterFormat("fck", this,
56
6
                                   "chemical/x-gaussian-checkpoint");
57
6
    }
58
59
    const char * Description() override
60
0
    {
61
0
      return "Gaussian formatted checkpoint file format\n"
62
0
             "A formatted text file containing the results of a Gaussian calculation\n"
63
0
             "Currently supports reading molecular geometries from fchk files. More to come.\n\n"
64
65
0
             "Read options e.g. -as\n"
66
0
             " s  Single bonds only\n"
67
0
             " b  No bond perception\n\n";
68
      // Vibrational analysis not yet supported in OB-2.1.
69
      //                    v  Do not perform the vibrational analysis\n\n";
70
0
    }
71
72
    const char * GetMIMEType() override
73
0
    {
74
0
      return "chemical/x-gaussian-checkpoint";
75
0
    }
76
77
    unsigned int Flags() override
78
21
    {
79
21
      return NOTWRITABLE;
80
21
    }
81
82
    bool ReadMolecule(OBBase *, OBConversion *) override;
83
84
  private :
85
    bool static read_int(const char * const, int * const);
86
    template<class T>  static bool read_numbers(const char * const,
87
                                                vector<T> &,
88
                                                const unsigned int width = 0);
89
    template <class T> static bool read_section(const char * const,
90
                                                vector<T> &,
91
                                                const unsigned int,
92
                                                bool * const,
93
                                                const char * const,
94
                                                const unsigned int,
95
                                                const unsigned int width = 0);
96
    bool static validate_section(const char * const,
97
                                 const int,
98
                                 const char * const,
99
                                 const unsigned int);
100
    bool static validate_number(const int,
101
                                const char * const,
102
                                const unsigned int);
103
    void static construct_mol(OBMol * const,
104
                              OBConversion * const,
105
                              const unsigned int,
106
                              const vector<int> &,
107
                              const vector<double> &,
108
                              const int,
109
                              const vector<int> &,
110
                              const vector<int> &);
111
    //       void static vibana(OBMol * const,
112
    //                          const vector<double> &,
113
    //                          const vector<double> &);
114
    //       bool static generate_tr_rot(OBMol * const,
115
    //                                   double * const,
116
    //                                   unsigned int * const);
117
    //       void static rotmatrix_axis(const double * const, const double,
118
    //                                  matrix3x3 &);
119
    //       double static cosine(const double * const, const double * const);
120
    //       void static normalize_set(double * const,
121
    //                                 const unsigned int, const unsigned int);
122
    //       void static orthogonalize_set(double * const,
123
    //                                     const unsigned int, const unsigned int,
124
    //                                     const bool);
125
    //       void static rests(const unsigned int, unsigned int * const,
126
    //                         unsigned int * const, const unsigned int);
127
128
    //       void static retrieve_hessian_indices(const unsigned int,
129
    //                                            unsigned int * const,
130
    //                                            unsigned int * const,
131
    //                                            unsigned int * const,
132
    //                                            unsigned int * const);
133
  };
134
135
  /* Make an instance of the format class */
136
  FCHKFormat theFCHKFormat;
137
138
139
  /*!
140
  **\brief Extract the data.
141
  **
142
  **The data are :
143
  **  comment
144
  **  charge
145
  **  multiplicity
146
  **  geometry
147
  **  connection table
148
  */
149
  bool FCHKFormat::ReadMolecule(OBBase * pOb, OBConversion * pConv)
150
0
  {
151
0
    OBMol * const pmol = dynamic_cast<OBMol*>(pOb);
152
153
0
    if (!pmol)
154
0
      return false;
155
156
    /* input stream */
157
0
    istream * const pifs = pConv->GetInStream();
158
159
    /* for logging errors */
160
0
    stringstream  error_msg;
161
162
    /* help variables */
163
0
    char buff[BUFF_SIZE];
164
0
    unsigned int lineno = 0;
165
0
    int  intvar;
166
0
    bool finished;
167
0
    bool atomnos_found = false;
168
0
    bool coords_found = false;
169
0
    bool nbond_found = false;
170
0
    bool ibond_found = false;
171
0
    bool hessian_found = false;
172
0
    bool dipder_found = false;
173
0
    bool alphaorb_found = false;
174
0
    bool betaorb_found = false;
175
176
    /* variables for storing the read data */
177
0
    int  Natoms = -1, MxBond = -1;
178
0
    int  numAOrb = -1, numBOrb = -1;
179
0
    int  numAElec = -1, numBElec = -1;
180
0
    vector<int>    atomnos, NBond, IBond;
181
0
    vector<double> coords, hessian, dipder, alphaorb, betaorb;
182
183
    /*** start reading ***/
184
0
    pmol->BeginModify();
185
186
    /* first line : comment */
187
0
    if (!pifs->getline(buff, BUFF_SIZE))
188
0
      {
189
0
        obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
190
0
                              "Failed to read the comment.",
191
0
                              obError);
192
0
        return false;
193
0
      }
194
195
0
    ++lineno;
196
0
    pmol->SetTitle(buff);
197
198
    /* extract all the information here */
199
0
    while (pifs->getline(buff, BUFF_SIZE))
200
0
      {
201
0
        ++lineno;
202
203
        /* Number of atoms */
204
0
        if (buff == strstr(buff, "Number of atoms"))
205
0
          {
206
0
            if (!FCHKFormat::read_int(buff, &Natoms))
207
0
              {
208
0
                error_msg << "Could not read the number of atoms from line #"
209
0
                          << lineno << ".";
210
211
0
                obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
212
0
                                      error_msg.str(),
213
0
                                      obError);
214
0
                return false;
215
0
              }
216
0
            if (0 >= Natoms)
217
0
              {
218
0
                error_msg << "Invalid number of atoms : " << Natoms << ".";
219
0
                obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
220
0
                                      error_msg.str(),
221
0
                                      obError);
222
0
                return false;
223
0
              }
224
0
            continue;
225
0
          }
226
227
        /* Dipole Moment */
228
0
        if (buff == strstr(buff, "Dipole Moment"))
229
0
          {
230
0
            if (!pifs->getline(buff, BUFF_SIZE)) {
231
0
              error_msg << "Could not read the dipole moment after line #"
232
0
                        << lineno << ".";
233
0
              obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
234
0
                                    error_msg.str(),
235
0
                                    obError);
236
0
              return false;
237
0
            }
238
0
            ++lineno;
239
0
            vector<double> moments;
240
0
            if (!FCHKFormat::read_numbers(buff, moments) || moments.size() != 3) {
241
0
              error_msg << "Could not read the dipole moment from line #"
242
0
                        << lineno << ".";
243
0
              obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
244
0
                                    error_msg.str(),
245
0
                                    obError);
246
0
              return false;
247
0
            }
248
249
0
            OBVectorData *dipoleMoment = new OBVectorData;
250
0
            dipoleMoment->SetAttribute("Dipole Moment");
251
0
            dipoleMoment->SetData(moments[0], moments[1], moments[2]);
252
0
            dipoleMoment->SetOrigin(fileformatInput);
253
0
            pmol->SetData(dipoleMoment);
254
0
            continue;
255
0
          }
256
257
        /* Charge */
258
0
        if (buff == strstr(buff, "Charge"))
259
0
          {
260
0
            if (!FCHKFormat::read_int(buff, &intvar))
261
0
              {
262
0
                error_msg << "Could not read the charge from line #"
263
0
                          << lineno << ".";
264
0
                obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
265
0
                                      error_msg.str(),
266
0
                                      obError);
267
0
                return false;
268
0
              }
269
270
0
            pmol->SetTotalCharge(intvar);
271
0
            continue;
272
0
          }
273
274
        /* Multiplicity */
275
0
        if (buff == strstr(buff, "Multiplicity"))
276
0
          {
277
0
            if (!FCHKFormat::read_int(buff, &intvar))
278
0
              {
279
0
                error_msg << "Could not read the multiplicity from line #"
280
0
                          << lineno << ".";
281
0
                obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
282
0
                                      error_msg.str(),
283
0
                                      obError);
284
0
                return false;
285
0
              }
286
287
0
            pmol->SetTotalSpinMultiplicity(intvar);
288
0
            continue;
289
0
          }
290
291
        /* start of the "Atomic numbers" section */
292
0
        if (buff == strstr(buff, "Atomic numbers"))
293
0
          {
294
0
            if (!FCHKFormat::validate_number(Natoms, "number of atoms", lineno))
295
0
              return false;
296
297
0
            if (!FCHKFormat::validate_section(buff,
298
0
                                              Natoms,
299
0
                                              "number of atomic numbers",
300
0
                                              lineno))
301
0
              return false;
302
303
0
            atomnos_found = true;
304
0
            continue;
305
0
          }
306
307
        /* start of the "Current cartesian coordinates" section */
308
0
        if (buff == strstr(buff, "Current cartesian coordinates"))
309
0
          {
310
0
            if (!FCHKFormat::validate_number(Natoms, "number of atoms", lineno))
311
0
              return false;
312
313
0
            if (!FCHKFormat::validate_section(buff,
314
0
                                              3 * Natoms,
315
0
                                              "number of coordinates",
316
0
                                              lineno))
317
0
              return false;
318
319
0
            coords_found = true;
320
0
            continue;
321
0
          }
322
323
        /* MxBond - largest number of bonds to an atom */
324
0
        if (buff == strstr(buff, "MxBond"))
325
0
          {
326
0
            if (!FCHKFormat::read_int(buff, &MxBond))
327
0
              {
328
0
                error_msg << "Could not read the number of bonds to each atom"
329
0
                          << " (MxBond) from line #" << lineno << ".";
330
331
0
                obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
332
0
                                      error_msg.str(),
333
0
                                      obError);
334
0
                return false;
335
0
              }
336
0
            if (0 >= MxBond)
337
0
              {
338
0
                error_msg << "Invalid number of bonds to each atom : "
339
0
                          << MxBond << ".";
340
0
                obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
341
0
                                      error_msg.str(),
342
0
                                      obError);
343
0
                return false;
344
0
              }
345
0
            continue;
346
0
          }
347
348
        /* start of the "NBond" section */
349
0
        if (buff == strstr(buff, "NBond"))
350
0
          {
351
0
            if (!FCHKFormat::validate_number(Natoms, "number of atoms", lineno))
352
0
              return false;
353
354
0
            if (!FCHKFormat::validate_number(MxBond,
355
0
                                             "number of bonds to each atom",
356
0
                                             lineno))
357
0
              return false;
358
359
0
            if (!FCHKFormat::validate_section(buff,
360
0
                                              Natoms,
361
0
                                              "number of bonds to each atom",
362
0
                                              lineno))
363
0
              return false;
364
365
0
            nbond_found = true;
366
0
            continue;
367
0
          }
368
369
        /* start of the "IBond" section */
370
0
        if (buff == strstr(buff, "IBond"))
371
0
          {
372
0
            if (!FCHKFormat::validate_number(Natoms, "number of atoms", lineno))
373
0
              return false;
374
375
0
            if (!FCHKFormat::validate_number(MxBond,
376
0
                                             "number of bonds to each atom",
377
0
                                             lineno))
378
0
              return false;
379
380
0
            if (!FCHKFormat::validate_section(buff,
381
0
                                              MxBond * Natoms,
382
0
                                              "number of bonds",
383
0
                                              lineno))
384
0
              return false;
385
386
0
            ibond_found = true;
387
0
            continue;
388
0
          }
389
390
        /* start of the "Cartesian Force Constants" section */
391
0
        if (buff == strstr(buff, "Cartesian Force Constants"))
392
0
          {
393
0
            if (!FCHKFormat::validate_number(Natoms, "number of atoms", lineno))
394
0
              return false;
395
396
0
            if (!FCHKFormat::validate_section(buff,
397
0
                                              (3 * Natoms) * (3 * Natoms + 1) / 2,
398
0
                                              "number of force constants",
399
0
                                              lineno))
400
0
              return false;
401
402
0
            hessian_found = true;
403
0
            continue;
404
0
          }
405
406
        /* start of the "Dipole Derivatives" section */
407
0
        if (buff == strstr(buff, "Dipole Derivatives"))
408
0
          {
409
0
            if (!FCHKFormat::validate_number(Natoms, "number of atoms", lineno))
410
0
              return false;
411
412
0
            if (!FCHKFormat::validate_section(buff,
413
0
                                              9 * Natoms,
414
0
                                              "number of dipole derivatives",
415
0
                                              lineno))
416
0
              return false;
417
418
0
            dipder_found = true;
419
0
            continue;
420
0
          }
421
422
0
        if (buff == strstr(buff, "Number of alpha electrons"))
423
0
          {
424
0
            if (!FCHKFormat::read_int(buff, &numAElec))
425
0
              {
426
0
                error_msg << "Could not read the number of alpha electrons"
427
0
                          << " from line #" << lineno << ".";
428
429
0
                obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
430
0
                                      error_msg.str(),
431
0
                                      obError);
432
0
                return false;
433
0
              }
434
0
            if (0 >= numAElec)
435
0
              {
436
0
                error_msg << "Invalid number of alpha electrons: "
437
0
                          << MxBond << ".";
438
0
                obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
439
0
                                      error_msg.str(),
440
0
                                      obError);
441
0
                return false;
442
0
              }
443
0
            continue;
444
0
          }
445
446
0
        if (buff == strstr(buff, "Number of beta electrons"))
447
0
          {
448
0
            if (!FCHKFormat::read_int(buff, &numBElec))
449
0
              {
450
0
                error_msg << "Could not read the number of beta electrons"
451
0
                          << " from line #" << lineno << ".";
452
453
0
                obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
454
0
                                      error_msg.str(),
455
0
                                      obError);
456
0
                return false;
457
0
              }
458
0
            if (0 >= numBElec)
459
0
              {
460
0
                error_msg << "Invalid number of beta electrons: "
461
0
                          << MxBond << ".";
462
0
                obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
463
0
                                      error_msg.str(),
464
0
                                      obError);
465
0
                return false;
466
0
              }
467
0
            continue;
468
0
          }
469
470
        /* start of the alpha orbitals section */
471
0
        if (buff == strstr(buff, "Alpha Orbital Energies"))
472
0
          {
473
0
            if (!FCHKFormat::read_int(buff, &numAOrb))
474
0
              {
475
0
                error_msg << "Could not read the number of alpha orbitals"
476
0
                          << " from line #" << lineno << ".";
477
478
0
                obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
479
0
                                      error_msg.str(),
480
0
                                      obError);
481
0
                return false;
482
0
              }
483
0
            if (0 >= numAOrb)
484
0
              {
485
0
                error_msg << "Invalid number of alpha orbitals: "
486
0
                          << MxBond << ".";
487
0
                obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
488
0
                                      error_msg.str(),
489
0
                                      obError);
490
0
                return false;
491
0
              }
492
493
0
            alphaorb_found = true;
494
0
            continue;
495
0
          }
496
497
        /* start of the beta orbitals section */
498
0
        if (buff == strstr(buff, "Beta Orbital Energies"))
499
0
          {
500
0
            if (!FCHKFormat::read_int(buff, &numBOrb))
501
0
              {
502
0
                error_msg << "Could not read the number of beta orbitals"
503
0
                          << " from line #" << lineno << ".";
504
505
0
                obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
506
0
                                      error_msg.str(),
507
0
                                      obError);
508
0
                return false;
509
0
              }
510
0
            if (0 >= numBOrb)
511
0
              {
512
0
                error_msg << "Invalid number of beta orbitals: "
513
0
                          << MxBond << ".";
514
0
                obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
515
0
                                      error_msg.str(),
516
0
                                      obError);
517
0
                return false;
518
0
              }
519
520
0
            betaorb_found = true;
521
0
            continue;
522
0
          }
523
524
        /* reading the atomic numbers */
525
0
        if (atomnos_found && Natoms > (int)atomnos.size())
526
0
          {
527
0
            if (!FCHKFormat::read_section(buff, atomnos, Natoms, &finished,
528
0
                                          "atomic numbers", lineno))
529
0
              return false;
530
531
0
            atomnos_found = !finished;
532
0
            continue;
533
0
          }
534
535
        /* reading the coordinates */
536
0
        if (coords_found && 3 * Natoms > (int)coords.size())
537
0
          {
538
0
            if (!FCHKFormat::read_section(buff, coords, 3 * Natoms, &finished,
539
0
                                          "coordinates", lineno, 16))
540
0
              return false;
541
542
0
            coords_found = !finished;
543
0
            continue;
544
0
          }
545
546
        /* reading the numbers of bonds to each atom */
547
0
        if (nbond_found && Natoms > (int)NBond.size())
548
0
          {
549
0
            if (!FCHKFormat::read_section(buff, NBond, Natoms, &finished,
550
0
                                          "number of bonds to each atom", lineno))
551
0
              return false;
552
553
0
            nbond_found = !finished;
554
0
            continue;
555
0
          }
556
557
        /* reading the list of atoms bound to each atom */
558
0
        if (ibond_found && MxBond * Natoms > (int)IBond.size())
559
0
          {
560
0
            if (!FCHKFormat::read_section(buff, IBond, MxBond * Natoms, &finished,
561
0
                                          "atom bonds", lineno))
562
0
              return false;
563
564
0
            ibond_found = !finished;
565
0
            continue;
566
0
          }
567
568
        /* reading the hessian */
569
0
        if (hessian_found &&
570
0
            (3 * Natoms) * (3 * Natoms + 1) / 2 > (int)hessian.size())
571
0
          {
572
0
            if (!FCHKFormat::read_section(buff, hessian,
573
0
                                          (3 * Natoms) * (3 * Natoms + 1) / 2,
574
0
                                          &finished,
575
0
                                          "hessian", lineno))
576
0
              return false;
577
578
0
            hessian_found = !finished;
579
0
            continue;
580
0
          }
581
582
        /* reading the dipole derivatives */
583
0
        if (dipder_found && 9 * Natoms > (int)dipder.size())
584
0
          {
585
0
            if (!FCHKFormat::read_section(buff, dipder,
586
0
                                          9 * Natoms,
587
0
                                          &finished,
588
0
                                          "dipole derivatives", lineno))
589
0
              return false;
590
591
0
            dipder_found = !finished;
592
0
            continue;
593
0
          }
594
595
        /* reading the alpha orbital energies */
596
0
        if (alphaorb_found && (numAOrb > alphaorb.size()))
597
0
          {
598
0
            if (!FCHKFormat::read_section(buff, alphaorb,
599
0
                                          numAOrb,
600
0
                                          &finished,
601
0
                                          "alpha orbital energies", lineno))
602
0
              return false;
603
604
0
            alphaorb_found = !finished; // if we've read once, don't re-read
605
0
            continue;
606
0
          }
607
608
        /* reading the beta orbital energies */
609
0
        if (betaorb_found &&  (numBOrb > betaorb.size()))
610
0
          {
611
0
            if (!FCHKFormat::read_section(buff, betaorb,
612
0
                                          numBOrb,
613
0
                                          &finished,
614
0
                                          "beta orbital energies", lineno))
615
0
              return false;
616
617
0
            betaorb_found = !finished;
618
0
            continue;
619
0
          }
620
621
0
      } /* while */
622
623
    /*** validating ***/
624
0
    if (0 >= Natoms)
625
0
      {
626
0
        error_msg << "Number of atoms could not be read.";
627
0
        obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
628
0
                              error_msg.str(),
629
0
                              obError);
630
0
        return false;
631
0
      }
632
633
0
    if (atomnos.empty())
634
0
      {
635
0
        error_msg << "\"Atomic numbers\" section was not found.";
636
0
        obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
637
0
                              error_msg.str(),
638
0
                              obError);
639
0
        return false;
640
0
      }
641
642
0
    if (coords.empty())
643
0
      {
644
0
        error_msg << "\"Current cartesian coordinates\" section was not found.";
645
0
        obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
646
0
                              error_msg.str(),
647
0
                              obError);
648
0
        return false;
649
0
      }
650
651
    /* connectivity : if MxBond is set, all the sections must be supplied */
652
0
    if (-1 != MxBond)
653
0
      {
654
0
        if (NBond.empty() || IBond.empty())
655
0
          {
656
0
            error_msg << "If MxBond is set, then the \"NBond\" and \"IBond\""
657
0
                      << " sections *must* be supplied.";
658
0
            obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
659
0
                                  error_msg.str(),
660
0
                                  obError);
661
0
            return false;
662
0
          }
663
664
        /* not nbonds > MxBond or <= 0
665
           no atom numbers < 0 or > Natoms */
666
0
        if (NBond.end() != find_if(NBond.begin(),
667
0
                                   NBond.end(),
668
0
                                   [](int i) { return i <= 0; }) ||
669
0
            NBond.end() != find_if(NBond.begin(),
670
0
                                   NBond.end(),
671
0
                                   [=](int i) { return i > MxBond; }) ||
672
0
            IBond.end() != find_if(IBond.begin(),
673
0
                                   IBond.end(),
674
0
                                   [](int i) { return i < 0; }) ||
675
0
            IBond.end() != find_if(IBond.begin(),
676
0
                                   IBond.end(),
677
0
                                   [=](int i) { return i > Natoms; }))
678
0
          {
679
0
            error_msg << "Invalid connectivity : check the \"NBond\" and/or"
680
0
                      << " \"IBond\" section(s).";
681
0
            obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
682
0
                                  error_msg.str(),
683
0
                                  obWarning);
684
0
            MxBond = -1;
685
0
          }
686
0
      }
687
688
    /*** finalizing ***/
689
0
    FCHKFormat::construct_mol(pmol, pConv, Natoms, atomnos, coords,
690
0
                              MxBond, NBond, IBond);
691
692
    //    if (!hessian.empty() && !pConv->IsOption("v", OBConversion::INOPTIONS))
693
    //    {
694
    //      FCHKFormat::vibana(pmol, hessian, dipder);
695
    //    }
696
697
    /*** finished ***/
698
0
    pmol->EndModify();
699
700
0
    if (numAOrb > 0 && alphaorb.size() == numAOrb) {
701
0
      OBOrbitalData *od = new OBOrbitalData; // create new store
702
0
      vector<string> symmetries;
703
704
0
      if (numBOrb > 0 && betaorb.size() == numBOrb) {  // open shell calculation
705
0
        od->LoadAlphaOrbitals(alphaorb, symmetries, numAElec);
706
0
        od->LoadBetaOrbitals(betaorb, symmetries, numBElec);
707
0
      } else {
708
0
        od->LoadClosedShellOrbitals(alphaorb, symmetries, numAElec);
709
0
      }
710
0
      od->SetOrigin(fileformatInput);
711
0
      pmol->SetData(od);
712
0
    }
713
714
0
    return true;
715
0
  }
716
717
  /*!
718
  **\brief Convert the last token in a string to integer
719
  **
720
  **Return false if the conversion failed.
721
  **The read integer is stored in the num argument.
722
  */
723
  bool FCHKFormat::read_int(const char * const line, int * const num)
724
0
  {
725
0
    vector<string>  vs;
726
0
    char * endptr;
727
728
0
    tokenize(vs, line);
729
0
    *num = strtol(vs.back().c_str(), &endptr, 10);
730
731
0
    return endptr != vs.back().c_str();
732
0
  }
733
734
  /*!
735
  **\brief Read integers or doubles into a vector from a string
736
  **\param line string
737
  **\param v    vector to read in
738
  */
739
  template<class T>
740
  bool FCHKFormat::read_numbers(const char * const line, vector<T> & v, const unsigned int width)
741
0
  {
742
0
    if (width == 0) {
743
0
      vector<string>  vs;
744
0
      tokenize(vs, line);
745
746
0
      if (0 < vs.size())
747
0
        {
748
0
          char * endptr;
749
0
          T num;
750
751
0
          for (vector<string>::const_iterator it=vs.begin(); vs.end() != it; ++it)
752
0
            {
753
0
              if (typeid(double) == typeid(T))
754
0
                num = static_cast<T>(strtod((*it).c_str(), &endptr));
755
0
              else
756
0
                num = static_cast<T>(strtol((*it).c_str(), &endptr, 10));
757
758
              /* quit if the value cannot be read */
759
0
              if (endptr == (*it).c_str())
760
0
                return false;
761
762
0
              v.push_back(num);
763
0
            }
764
0
        }
765
0
    } else {
766
      // fixed width records (e.g., coordinates = 16 characters)
767
0
      string lineCopy(line), substring;
768
0
      T num;
769
0
      char * endptr;
770
0
      int maxColumns = 80 / width;
771
772
0
      for (int column = 0; column < maxColumns; ++column) {
773
0
        substring = lineCopy.substr(column * width, width);
774
775
0
        if (typeid(double) == typeid(T))
776
0
          num = static_cast<T>(strtod(substring.c_str(), &endptr));
777
0
        else
778
0
          num = static_cast<T>(strtol(substring.c_str(), &endptr, 10));
779
780
        /* quit if the value cannot be read */
781
0
        if (endptr == substring.c_str())
782
0
          break;
783
784
0
        v.push_back(num);
785
0
      }
786
0
    }
787
788
0
    return true;
789
0
  }
Unexecuted instantiation: bool OpenBabel::FCHKFormat::read_numbers<double>(char const*, std::__1::vector<double, std::__1::allocator<double> >&, unsigned int)
Unexecuted instantiation: bool OpenBabel::FCHKFormat::read_numbers<int>(char const*, std::__1::vector<int, std::__1::allocator<int> >&, unsigned int)
790
791
  /*!
792
  **\brief Validate a section
793
  **
794
  **Try to convert the last token of a string to integer and compare it to a
795
  **given number. If they are not equal report an error and return false.
796
  **Otherwise return true.
797
  */
798
  bool FCHKFormat::validate_section(const char * const line,
799
                                    const int nreq,
800
                                    const char * const desc,
801
                                    const unsigned int lineno)
802
0
  {
803
0
    int intvar;
804
0
    stringstream error_msg;
805
806
0
    if (!FCHKFormat::read_int(line, &intvar))
807
0
      {
808
0
        error_msg << "Could not read the " << desc
809
0
                  << " from line #" << lineno << ".";
810
0
        obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
811
0
                              error_msg.str(),
812
0
                              obError);
813
0
        return false;
814
0
      }
815
0
    if (intvar != nreq)
816
0
      {
817
0
        error_msg << desc << " must be exactly " << nreq
818
0
                  << ", found " << intvar << ".";
819
0
        obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
820
0
                              error_msg.str(),
821
0
                              obError);
822
0
        return false;
823
0
      }
824
825
0
    return true;
826
0
  }
827
828
  /*!
829
  **\brief Validate a number
830
  **
831
  **Compare it with a given value and report an error unless they are equal.
832
  */
833
  bool FCHKFormat::validate_number(const int num,
834
                                   const char * const desc,
835
                                   const unsigned int lineno)
836
0
  {
837
0
    stringstream error_msg;
838
839
0
    if (-1 == num)
840
0
      {
841
0
        error_msg << desc   << " must be already read before line #"
842
0
                  << lineno << ".";
843
0
        obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
844
0
                              error_msg.str(),
845
0
                              obError);
846
0
        return false;
847
0
      }
848
0
    return true;
849
0
  }
850
851
  /*!
852
  **\brief Read numbers in a section
853
  **\param line     line
854
  **\param v        vector to read in
855
  **\param nreq     maximum number of elements in v
856
  **\param finished whether the reading is finished
857
  **\param desc     name of the section
858
  **\param lineno   line number
859
  */
860
  template <class T>
861
  bool FCHKFormat::read_section(const char * const line,
862
                                vector<T> & v,
863
                                const unsigned int nreq,
864
                                bool * const finished,
865
                                const char * const desc,
866
                                const unsigned int lineno,
867
                                const unsigned int width)
868
0
  {
869
0
    stringstream error_msg;
870
871
0
    *finished = false;
872
873
0
    if(!FCHKFormat::read_numbers(line, v, width))
874
0
      {
875
0
        error_msg << "Expecting " << desc << " in line #" << lineno << ".";
876
0
        obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
877
0
                              error_msg.str(),
878
0
                              obError);
879
0
        return false;
880
0
      }
881
0
    if (nreq <= v.size())
882
0
      {
883
0
        *finished = true;
884
0
        if (nreq < v.size())
885
0
          {
886
0
            error_msg << "Ignoring the superfluous " << desc
887
0
                      << "in line #" << lineno << ".";
888
0
            obErrorLog.ThrowError("FCHKFormat::ReadMolecule()",
889
0
                                  error_msg.str(),
890
0
                                  obWarning);
891
0
          }
892
0
      }
893
894
0
    return true;
895
0
  }
Unexecuted instantiation: bool OpenBabel::FCHKFormat::read_section<int>(char const*, std::__1::vector<int, std::__1::allocator<int> >&, unsigned int, bool*, char const*, unsigned int, unsigned int)
Unexecuted instantiation: bool OpenBabel::FCHKFormat::read_section<double>(char const*, std::__1::vector<double, std::__1::allocator<double> >&, unsigned int, bool*, char const*, unsigned int, unsigned int)
896
897
  /*!
898
  **\brief Construct the molecule
899
  **\param pmol    molecule
900
  **\param Natoms  number of atoms
901
  **\param atomnos atomic numbers
902
  **\param coords  coordinates
903
  **\param MxBond  largest number of bonds to an atom (usually 4)
904
  **\param NBond   number of bonds to each atom
905
  **\param IBond   list of atoms bounded to each atom
906
  */
907
  void FCHKFormat::construct_mol(OBMol * const pmol,
908
                                 OBConversion * const pConv,
909
                                 const unsigned int Natoms,
910
                                 const vector<int> & atomnos,
911
                                 const vector<double> & coords,
912
                                 const int MxBond,
913
                                 const vector<int> & NBond,
914
                                 const vector<int> & IBond)
915
0
  {
916
0
    pmol->ReserveAtoms(Natoms);
917
918
0
    OBAtom * atom;
919
0
    for (unsigned int a = 0; Natoms > a; ++a)
920
0
      {
921
0
        atom = pmol->NewAtom();
922
923
0
        atom->SetAtomicNum(atomnos[a]);
924
0
        atom->SetVector(coords[0 + 3 * a] * BOHR2ANGSTROM,
925
0
                        coords[1 + 3 * a] * BOHR2ANGSTROM,
926
0
                        coords[2 + 3 * a] * BOHR2ANGSTROM);
927
0
      }
928
929
    /* unless suppressed */
930
0
    if (!pConv->IsOption("b", OBConversion::INOPTIONS))
931
0
      {
932
        /* if the connectivity is provided */
933
0
        if (-1 != MxBond)
934
0
          {
935
            /* atoms */
936
0
            for (unsigned int a = 0; Natoms > a; ++a)
937
0
              {
938
                /* bonds for an atom */
939
0
                for (unsigned int i = 0; (unsigned int)NBond[a] > i; ++i)
940
0
                  {
941
0
                    pmol->AddBond(1 + a, IBond[MxBond*a + i], 1);
942
0
                  }
943
0
              }
944
0
          }
945
0
        else
946
0
          {
947
0
            pmol->ConnectTheDots();
948
0
          }
949
0
      }
950
951
0
    if (!pConv->IsOption("s", OBConversion::INOPTIONS) &&
952
0
        !pConv->IsOption("b", OBConversion::INOPTIONS))
953
0
      pmol->PerceiveBondOrders();
954
0
  }
955
956
} /* namespace OpenBabel */