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