OpenMD 3.2
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
DumpReader.cpp
1/*
2 * Copyright (c) 2004-present, The University of Notre Dame. All rights
3 * reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 *
31 * SUPPORT OPEN SCIENCE! If you use OpenMD or its source code in your
32 * research, please cite the following paper when you publish your work:
33 *
34 * [1] Drisko et al., J. Open Source Softw. 9, 7004 (2024).
35 *
36 * Good starting points for code and simulation methodology are:
37 *
38 * [2] Meineke, et al., J. Comp. Chem. 26, 252-271 (2005).
39 * [3] Fennell & Gezelter, J. Chem. Phys. 124, 234104 (2006).
40 * [4] Sun, Lin & Gezelter, J. Chem. Phys. 128, 234107 (2008).
41 * [5] Vardeman, Stocker & Gezelter, J. Chem. Theory Comput. 7, 834 (2011).
42 * [6] Kuang & Gezelter, Mol. Phys., 110, 691-701 (2012).
43 * [7] Lamichhane, Gezelter & Newman, J. Chem. Phys. 141, 134109 (2014).
44 * [8] Bhattarai, Newman & Gezelter, Phys. Rev. B 99, 094106 (2019).
45 * [9] Drisko & Gezelter, J. Chem. Theory Comput. 20, 4986-4997 (2024).
46 */
47
48#define _LARGEFILE_SOURCE64
49#define _FILE_OFFSET_BITS 64
50
51#include "io/DumpReader.hpp"
52
53#include <cmath>
54#include <cstdio>
55#include <cstdlib>
56#include <cstring>
57#include <iostream>
58
59#include <sys/stat.h>
60#include <sys/types.h>
61
62#ifdef IS_MPI
63#include <mpi.h>
64#endif
65
66#include "brains/Thermo.hpp"
69#include "utils/simError.h"
70
71namespace OpenMD {
72
73 DumpReader::DumpReader(SimInfo* info, const std::string& filename) :
74 info_(info), filename_(filename), isScanned_(false), nframes_(0),
75 needCOMprops_(false) {
76#ifdef IS_MPI
77 if (worldRank == 0) {
78#endif
79
80 inFile_ =
81 std::ifstream(filename_.c_str(), ifstream::in | ifstream::binary);
82
83 if (inFile_.fail()) {
84 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
85 "DumpReader: Cannot open file: %s\n", filename_.c_str());
86 painCave.isFatal = 1;
87 simError();
88 }
89#ifdef IS_MPI
90 }
91 strcpy(checkPointMsg, "Dump file opened for reading successfully.");
92 errorCheckPoint();
93#endif
94 }
95
96 DumpReader::~DumpReader() {
97#ifdef IS_MPI
98 strcpy(checkPointMsg, "Dump file closed successfully.");
99 errorCheckPoint();
100#endif
101 }
102
104 if (!isScanned_) scanFile();
105
106 return nframes_;
107 }
108
109 void DumpReader::scanFile(void) {
110 std::streampos prevPos;
111 std::streampos currPos;
112
113#ifdef IS_MPI
114 if (worldRank == 0) {
115#endif
116
117 currPos = inFile_.tellg();
118 prevPos = currPos;
119 bool foundOpenSnapshotTag = false;
120 bool foundClosedSnapshotTag = false;
121
122 int lineNo = 0;
123 while (inFile_.getline(buffer, bufferSize)) {
124 ++lineNo;
125
126 std::string line = buffer;
127 currPos = inFile_.tellg();
128 if (line.find("<Snapshot>") != std::string::npos) {
129 if (foundOpenSnapshotTag) {
130 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
131 "DumpReader:<Snapshot> is multiply nested at line %d "
132 "in %s \n",
133 lineNo, filename_.c_str());
134 painCave.isFatal = 1;
135 simError();
136 }
137 foundOpenSnapshotTag = true;
138 foundClosedSnapshotTag = false;
139 framePos_.push_back(prevPos);
140
141 } else if (line.find("</Snapshot>") != std::string::npos) {
142 if (!foundOpenSnapshotTag) {
143 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
144 "DumpReader:</Snapshot> appears before <Snapshot> at "
145 "line %d in %s \n",
146 lineNo, filename_.c_str());
147 painCave.isFatal = 1;
148 simError();
149 }
150
151 if (foundClosedSnapshotTag) {
152 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
153 "DumpReader:</Snapshot> appears multiply nested at "
154 "line %d in %s \n",
155 lineNo, filename_.c_str());
156 painCave.isFatal = 1;
157 simError();
158 }
159 foundClosedSnapshotTag = true;
160 foundOpenSnapshotTag = false;
161 }
162 prevPos = currPos;
163 }
164
165 // only found <Snapshot> for the last frame means the file is
166 // corrupted, we should discard it and give a warning message
167 if (foundOpenSnapshotTag) {
168 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
169 "DumpReader: last frame in %s is invalid\n",
170 filename_.c_str());
171 painCave.isFatal = 0;
172 simError();
173 framePos_.pop_back();
174 }
175
176 nframes_ = framePos_.size();
177
178 if (nframes_ == 0) {
179 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
180 "DumpReader: %s does not contain a valid frame\n",
181 filename_.c_str());
182 painCave.isFatal = 1;
183 simError();
184 }
185
186#ifdef IS_MPI
187 }
188 MPI_Bcast(&nframes_, 1, MPI_INT, 0, MPI_COMM_WORLD);
189#endif // is_mpi
190
191 isScanned_ = true;
192 }
193
194 void DumpReader::readFrame(int whichFrame) {
195 if (!isScanned_) scanFile();
196
197 int asl = info_->getSnapshotManager()->getAtomStorageLayout();
198 int rbsl = info_->getSnapshotManager()->getRigidBodyStorageLayout();
199
200 needPos_ =
201 (asl & DataStorage::dslPosition || rbsl & DataStorage::dslPosition) ?
202 true :
203 false;
204 needVel_ =
205 (asl & DataStorage::dslVelocity || rbsl & DataStorage::dslVelocity) ?
206 true :
207 false;
208 needQuaternion_ =
209 (asl & DataStorage::dslAmat || asl & DataStorage::dslDipole ||
210 asl & DataStorage::dslQuadrupole || rbsl & DataStorage::dslAmat ||
211 rbsl & DataStorage::dslDipole || rbsl & DataStorage::dslQuadrupole) ?
212 true :
213 false;
214 needAngMom_ = (asl & DataStorage::dslAngularMomentum ||
215 rbsl & DataStorage::dslAngularMomentum) ?
216 true :
217 false;
218
219 // some dump files contain the efield, but we should only parse
220 // and set the field if we have actually allocated memory for it
221 readField_ = (asl & DataStorage::dslElectricField) ? true : false;
222
223 readSet(whichFrame);
224
225 if (needCOMprops_) {
226 Thermo thermo(info_);
227 Vector3d com;
228
229 if (needPos_ && needVel_) {
230 Vector3d comvel;
231 Vector3d comw;
232 thermo.getComAll(com, comvel);
233 comw = thermo.getAngularMomentum();
234 } else {
235 com = thermo.getCom();
236 }
237 }
238 }
239
240 void DumpReader::readSet(int whichFrame) {
241 std::string line;
242
243#ifndef IS_MPI
244 inFile_.clear();
245 inFile_.seekg(framePos_[whichFrame]);
246
247 std::istream& inputStream = inFile_;
248#else
249
250 int primaryNode = 0;
251 std::stringstream sstream;
252 if (worldRank == primaryNode) {
253 std::string sendBuffer;
254
255 inFile_.clear();
256 inFile_.seekg(framePos_[whichFrame]);
257
258 while (inFile_.getline(buffer, bufferSize)) {
259 line = buffer;
260 sendBuffer += line;
261 sendBuffer += '\n';
262 if (line.find("</Snapshot>") != std::string::npos) { break; }
263 }
264
265 int sendBufferSize = sendBuffer.size();
266 MPI_Bcast(&sendBufferSize, 1, MPI_INT, primaryNode, MPI_COMM_WORLD);
267 MPI_Bcast((void*)sendBuffer.c_str(), sendBufferSize, MPI_CHAR,
268 primaryNode, MPI_COMM_WORLD);
269
270 sstream.str(sendBuffer);
271 } else {
272 int sendBufferSize;
273 MPI_Bcast(&sendBufferSize, 1, MPI_INT, primaryNode, MPI_COMM_WORLD);
274 char* recvBuffer = new char[sendBufferSize + 1];
275 assert(recvBuffer);
276 recvBuffer[sendBufferSize] = '\0';
277 MPI_Bcast(recvBuffer, sendBufferSize, MPI_CHAR, primaryNode,
278 MPI_COMM_WORLD);
279 sstream.str(recvBuffer);
280 delete[] recvBuffer;
281 }
282
283 std::istream& inputStream = sstream;
284#endif
285
286 inputStream.getline(buffer, bufferSize);
287
288 line = buffer;
289 if (line.find("<Snapshot>") == std::string::npos) {
290 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
291 "DumpReader Error: can not find <Snapshot>\n");
292 painCave.isFatal = 1;
293 simError();
294 }
295
296 // read frameData
297 readFrameProperties(inputStream);
298
299 // read StuntDoubles
300 int nSD = readStuntDoubles(inputStream);
301
302 inputStream.getline(buffer, bufferSize);
303 line = buffer;
304
305 if (line.find("<SiteData>") != std::string::npos) {
306 // read SiteData
307 readSiteData(inputStream);
308 } else {
309 if (line.find("</Snapshot>") == std::string::npos) {
310 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
311 "DumpReader Error: can not find </Snapshot>\n");
312 painCave.isFatal = 1;
313 simError();
314 }
315 }
316
317 if (nSD != info_->getNGlobalIntegrableObjects()) {
318 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
319 "DumpReader Error: Number of parsed StuntDouble lines (%d)\n"
320 "\tis not the same as the expected number of Objects (%d)\n",
321 nSD, info_->getNGlobalIntegrableObjects());
322 painCave.isFatal = 1;
323 simError();
324 }
325 }
326
327 void DumpReader::parseDumpLine(const std::string& line) {
328 StringTokenizer tokenizer(line);
329 int nTokens;
330
331 nTokens = tokenizer.countTokens();
332
333 if (nTokens < 2) {
334 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
335 "DumpReader Error: Not enough Tokens.\n%s\n", line.c_str());
336 painCave.isFatal = 1;
337 simError();
338 }
339
340 int index = tokenizer.nextTokenAsInt();
341
342 StuntDouble* sd = info_->getIOIndexToIntegrableObject(index);
343
344 if (sd == NULL) { return; }
345 std::string type = tokenizer.nextToken();
346 int size = type.size();
347
348 size_t found;
349
350 if (needPos_) {
351 found = type.find("p");
352 if (found == std::string::npos) {
353 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
354 "DumpReader Error: StuntDouble %d has no Position\n"
355 "\tField (\"p\") specified.\n%s\n",
356 index, line.c_str());
357 painCave.isFatal = 1;
358 simError();
359 }
360 }
361
362 if (sd->isDirectional()) {
363 if (needQuaternion_) {
364 found = type.find("q");
365 if (found == std::string::npos) {
366 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
367 "DumpReader Error: Directional StuntDouble %d has no\n"
368 "\tQuaternion Field (\"q\") specified.\n%s\n",
369 index, line.c_str());
370 painCave.isFatal = 1;
371 simError();
372 }
373 }
374 }
375
376 for (int i = 0; i < size; ++i) {
377 switch (type[i]) {
378 case 'p': {
379 Vector3d pos;
380 pos[0] = tokenizer.nextTokenAsDouble();
381 pos[1] = tokenizer.nextTokenAsDouble();
382 pos[2] = tokenizer.nextTokenAsDouble();
383 if (needPos_) { sd->setPos(pos); }
384 break;
385 }
386 case 'v': {
387 Vector3d vel;
388 vel[0] = tokenizer.nextTokenAsDouble();
389 vel[1] = tokenizer.nextTokenAsDouble();
390 vel[2] = tokenizer.nextTokenAsDouble();
391 if (needVel_) { sd->setVel(vel); }
392 break;
393 }
394
395 case 'q': {
396 Quat4d q;
397 if (sd->isDirectional()) {
398 q[0] = tokenizer.nextTokenAsDouble();
399 q[1] = tokenizer.nextTokenAsDouble();
400 q[2] = tokenizer.nextTokenAsDouble();
401 q[3] = tokenizer.nextTokenAsDouble();
402
403 RealType qlen = q.length();
404 if (qlen < OpenMD::epsilon) { // check quaternion is not
405 // equal to 0
406
407 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
408 "DumpReader Error: initial quaternion error "
409 "(q0^2 + q1^2 + q2^2 + q3^2) ~ 0\n");
410 painCave.isFatal = 1;
411 simError();
412 }
413
414 q.normalize();
415 if (needQuaternion_) { sd->setQ(q); }
416 }
417 break;
418 }
419 case 'j': {
420 Vector3d ji;
421 if (sd->isDirectional()) {
422 ji[0] = tokenizer.nextTokenAsDouble();
423 ji[1] = tokenizer.nextTokenAsDouble();
424 ji[2] = tokenizer.nextTokenAsDouble();
425 if (needAngMom_) { sd->setJ(ji); }
426 }
427 break;
428 }
429 case 'f': {
430 Vector3d force;
431 force[0] = tokenizer.nextTokenAsDouble();
432 force[1] = tokenizer.nextTokenAsDouble();
433 force[2] = tokenizer.nextTokenAsDouble();
434 sd->setFrc(force);
435 break;
436 }
437 case 't': {
438 Vector3d torque;
439 torque[0] = tokenizer.nextTokenAsDouble();
440 torque[1] = tokenizer.nextTokenAsDouble();
441 torque[2] = tokenizer.nextTokenAsDouble();
442 sd->setTrq(torque);
443 break;
444 }
445 case 'u': {
446 RealType particlePot;
447 particlePot = tokenizer.nextTokenAsDouble();
448 sd->setParticlePot(particlePot);
449 break;
450 }
451 case 'c': {
452 RealType flucQPos;
453 flucQPos = tokenizer.nextTokenAsDouble();
454 if (sd->isAtom())
455 if (dynamic_cast<Atom*>(sd)->isFluctuatingCharge())
456 sd->setFlucQPos(flucQPos);
457 break;
458 }
459 case 'w': {
460 RealType flucQVel;
461 flucQVel = tokenizer.nextTokenAsDouble();
462 if (sd->isAtom())
463 if (dynamic_cast<Atom*>(sd)->isFluctuatingCharge())
464 sd->setFlucQVel(flucQVel);
465 break;
466 }
467 case 'g': {
468 RealType flucQFrc;
469 flucQFrc = tokenizer.nextTokenAsDouble();
470 if (sd->isAtom())
471 if (dynamic_cast<Atom*>(sd)->isFluctuatingCharge())
472 sd->setFlucQFrc(flucQFrc);
473 break;
474 }
475 case 'e': {
476 Vector3d eField;
477 eField[0] = tokenizer.nextTokenAsDouble();
478 eField[1] = tokenizer.nextTokenAsDouble();
479 eField[2] = tokenizer.nextTokenAsDouble();
480 // only set the field if we have allocated memory for it
481 if (readField_) sd->setElectricField(eField);
482 break;
483 }
484 case 's': {
485 RealType sPot;
486 sPot = tokenizer.nextTokenAsDouble();
487 sd->setSitePotential(sPot);
488 break;
489 }
490 case 'd': {
491 RealType density;
492 density = tokenizer.nextTokenAsDouble();
493 sd->setDensity(density);
494 break;
495 }
496
497 default: {
498 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
499 "DumpReader Error: %s is an unrecognized type\n",
500 type.c_str());
501 painCave.isFatal = 1;
502 simError();
503 break;
504 }
505 }
506 }
507 if (sd->isRigidBody()) {
508 RigidBody* rb = static_cast<RigidBody*>(sd);
509 if (needPos_) {
510 // This should let us use various atom-based selections even
511 // if we have only rigid bodies:
512 rb->updateAtoms();
513 }
514 if (needVel_) { rb->updateAtomVel(); }
515 }
516 }
517
518 void DumpReader::parseSiteLine(const std::string& line) {
519 StringTokenizer tokenizer(line);
520 int nTokens;
521
522 nTokens = tokenizer.countTokens();
523
524 if (nTokens < 1) {
525 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
526 "DumpReader Error: Not enough Tokens.\n%s\n", line.c_str());
527 painCave.isFatal = 1;
528 simError();
529 }
530
531 /**
532 * The first token is the global integrable object index.
533 */
534
535 int index = tokenizer.nextTokenAsInt();
536 StuntDouble* sd = info_->getIOIndexToIntegrableObject(index);
537 if (sd == NULL) { return; }
538
539 // StuntDoubles have a line even if there is nothing stored in the
540 // site data:
541 if (nTokens == 1) { return; }
542
543 /**
544 * Test to see if the next token is an integer or not. If not,
545 * we've got data on the integrable object itself. If there is an
546 * integer, we're parsing data for a site on a rigid body.
547 */
548 std::string indexTest = tokenizer.peekNextToken();
549 std::istringstream i(indexTest);
550 int siteIndex;
551 if (i >> siteIndex) {
552 // chew up this token and parse as an int:
553 siteIndex = tokenizer.nextTokenAsInt();
554 if (sd->isRigidBody()) {
555 RigidBody* rb = static_cast<RigidBody*>(sd);
556
557 // Sometimes site lines are inherited from other models, so
558 // just ignore a site line that exceeds the number of atoms in
559 // our RB:
560 if (siteIndex >= static_cast<int>(rb->getNumAtoms())) { return; }
561
562 sd = rb->getAtoms()[siteIndex];
563 }
564 }
565
566 /**
567 * The next token contains information on what follows.
568 */
569 std::string type = tokenizer.nextToken();
570 int size = type.size();
571
572 for (int i = 0; i < size; ++i) {
573 switch (type[i]) {
574 case 'u': {
575 RealType particlePot;
576 particlePot = tokenizer.nextTokenAsDouble();
577 sd->setParticlePot(particlePot);
578 break;
579 }
580 case 'c': {
581 RealType flucQPos;
582 flucQPos = tokenizer.nextTokenAsDouble();
583 if (sd->isAtom())
584 if (dynamic_cast<Atom*>(sd)->isFluctuatingCharge())
585 sd->setFlucQPos(flucQPos);
586 break;
587 }
588 case 'w': {
589 RealType flucQVel;
590 flucQVel = tokenizer.nextTokenAsDouble();
591 if (sd->isAtom())
592 if (dynamic_cast<Atom*>(sd)->isFluctuatingCharge())
593 sd->setFlucQVel(flucQVel);
594 break;
595 }
596 case 'g': {
597 RealType flucQFrc;
598 flucQFrc = tokenizer.nextTokenAsDouble();
599 if (sd->isAtom())
600 if (dynamic_cast<Atom*>(sd)->isFluctuatingCharge())
601 sd->setFlucQFrc(flucQFrc);
602 break;
603 }
604 case 'e': {
605 Vector3d eField;
606 eField[0] = tokenizer.nextTokenAsDouble();
607 eField[1] = tokenizer.nextTokenAsDouble();
608 eField[2] = tokenizer.nextTokenAsDouble();
609 if (readField_) sd->setElectricField(eField);
610 break;
611 }
612 case 's': {
613 RealType sPot;
614 sPot = tokenizer.nextTokenAsDouble();
615 sd->setSitePotential(sPot);
616 break;
617 }
618 case 'd': {
619 RealType dens;
620 dens = tokenizer.nextTokenAsDouble();
621 sd->setDensity(dens);
622 break;
623 }
624 default: {
625 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
626 "DumpReader Error: %s is an unrecognized type\n",
627 type.c_str());
628 painCave.isFatal = 1;
629 simError();
630 break;
631 }
632 }
633 }
634 }
635
636 int DumpReader::readStuntDoubles(std::istream& inputStream) {
637 inputStream.getline(buffer, bufferSize);
638 std::string line(buffer);
639
640 if (line.find("<StuntDoubles>") == std::string::npos) {
641 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
642 "DumpReader Error: Missing <StuntDoubles>\n");
643 painCave.isFatal = 1;
644 simError();
645 }
646
647 int nSD = 0;
648
649 while (inputStream.getline(buffer, bufferSize)) {
650 line = buffer;
651
652 if (line.find("</StuntDoubles>") != std::string::npos) { break; }
653
654 parseDumpLine(line);
655 nSD++;
656 }
657
658 return nSD;
659 }
660
661 void DumpReader::readSiteData(std::istream& inputStream) {
662 std::string line(buffer);
663
664 // We already found the starting <SiteData> tag or we wouldn't be
665 // here, so just start parsing until we get to the ending
666 // </SiteData> tag:
667
668 while (inputStream.getline(buffer, bufferSize)) {
669 line = buffer;
670
671 if (line.find("</SiteData>") != std::string::npos) { break; }
672
673 parseSiteLine(line);
674 }
675 }
676
677 void DumpReader::readFrameProperties(std::istream& inputStream) {
678 Snapshot* s = info_->getSnapshotManager()->getCurrentSnapshot();
679 // We're about to overwrite all frame properties, so clear out any
680 // derived properties from previous use:
681 s->clearDerivedProperties();
682
683 inputStream.getline(buffer, bufferSize);
684 std::string line(buffer);
685
686 if (line.find("<FrameData>") == std::string::npos) {
687 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
688 "DumpReader Error: Missing <FrameData>\n");
689 painCave.isFatal = 1;
690 simError();
691 }
692
693 while (inputStream.getline(buffer, bufferSize)) {
694 line = buffer;
695
696 if (line.find("</FrameData>") != std::string::npos) { break; }
697
698 StringTokenizer tokenizer(line, " ;\t\n\r{}:,");
699 if (!tokenizer.hasMoreTokens()) {
700 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
701 "DumpReader Error: Not enough Tokens.\n%s\n", line.c_str());
702 painCave.isFatal = 1;
703 simError();
704 }
705
706 std::string propertyName = tokenizer.nextToken();
707 if (propertyName == "Time") {
708 RealType currTime = tokenizer.nextTokenAsDouble();
709 s->setTime(currTime);
710 } else if (propertyName == "Hmat") {
711 Mat3x3d hmat;
712 hmat(0, 0) = tokenizer.nextTokenAsDouble();
713 hmat(0, 1) = tokenizer.nextTokenAsDouble();
714 hmat(0, 2) = tokenizer.nextTokenAsDouble();
715 hmat(1, 0) = tokenizer.nextTokenAsDouble();
716 hmat(1, 1) = tokenizer.nextTokenAsDouble();
717 hmat(1, 2) = tokenizer.nextTokenAsDouble();
718 hmat(2, 0) = tokenizer.nextTokenAsDouble();
719 hmat(2, 1) = tokenizer.nextTokenAsDouble();
720 hmat(2, 2) = tokenizer.nextTokenAsDouble();
721 s->setHmat(hmat);
722 } else if (propertyName == "Thermostat") {
723 pair<RealType, RealType> thermostat;
724 thermostat.first = tokenizer.nextTokenAsDouble();
725 thermostat.second = tokenizer.nextTokenAsDouble();
726 s->setThermostat(thermostat);
727 } else if (propertyName == "Barostat") {
728 Mat3x3d eta;
729 eta(0, 0) = tokenizer.nextTokenAsDouble();
730 eta(0, 1) = tokenizer.nextTokenAsDouble();
731 eta(0, 2) = tokenizer.nextTokenAsDouble();
732 eta(1, 0) = tokenizer.nextTokenAsDouble();
733 eta(1, 1) = tokenizer.nextTokenAsDouble();
734 eta(1, 2) = tokenizer.nextTokenAsDouble();
735 eta(2, 0) = tokenizer.nextTokenAsDouble();
736 eta(2, 1) = tokenizer.nextTokenAsDouble();
737 eta(2, 2) = tokenizer.nextTokenAsDouble();
738 s->setBarostat(eta);
739 } else if (propertyName == "SPFData") {
740 std::shared_ptr<SPFData> spfData = s->getSPFData();
741
742 spfData->pos[0] = tokenizer.nextTokenAsDouble();
743 spfData->pos[1] = tokenizer.nextTokenAsDouble();
744 spfData->pos[2] = tokenizer.nextTokenAsDouble();
745 spfData->lambda = tokenizer.nextTokenAsDouble();
746 spfData->globalID = tokenizer.nextTokenAsInt();
747 } else {
748 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
749 "DumpReader Error: %s is an invalid property in <FrameData>\n",
750 propertyName.c_str());
751 painCave.isFatal = 0;
752 simError();
753 }
754 }
755 }
756} // namespace OpenMD
void parseSiteLine(const std::string &)
int getNFrames()
Returns the number of frames in the dump file.
size_t getNumAtoms()
Returns the number of atoms in this rigid body.
std::vector< Atom * > getAtoms()
Returns the atoms of this rigid body.
One of the heavy-weight classes of OpenMD, SimInfo maintains objects and variables relating to the cu...
Definition SimInfo.hpp:96
The string tokenizer class allows an application to break a string into tokens The set of delimiters ...
std::string peekNextToken()
Returns the next token without advancing the position of the StringTokenizer.
std::string nextToken()
Returns the next token from this string tokenizer.
int countTokens()
Calculates the number of times that this tokenizer's nextToken method can be called before it generat...
int nextTokenAsInt()
Returns the next token from this string tokenizer as an integer.
RealType nextTokenAsDouble()
Returns the next token from this string tokenizer as a RealType.
"Don't move, or you're dead! Stand up! Captain, we've got them!"
void setFlucQVel(RealType cvel)
Sets the current charge velocity of this stuntDouble.
void setFlucQPos(RealType charge)
Sets the current fluctuating charge of this stuntDouble.
void setParticlePot(const RealType &particlePot)
Sets the current particlePot of this stuntDouble.
void setSitePotential(RealType spot)
Sets the current site potential of this stuntDouble.
void setElectricField(const Vector3d &eField)
Sets the current electric field of this stuntDouble.
bool isRigidBody()
Tests if this stuntDouble is a rigid body.
bool isAtom()
Tests if this stuntDouble is an atom.
void setFlucQFrc(RealType cfrc)
Sets the current charge force of this stuntDouble.
void setDensity(RealType dens)
Sets the current density of this stuntDouble.
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.