/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 */ |