OpenMD 3.0
Molecular Dynamics in the Open
Loading...
Searching...
No Matches
SectionParserManager.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#include "io/SectionParserManager.hpp"
45
46#include <algorithm>
47#include <cstdio>
48#include <stack>
49
50#include "utils/Trim.hpp"
51#include "utils/simError.h"
52
53namespace OpenMD {
54
55 SectionParserManager::~SectionParserManager() {
56 SectionParserManager::iterator i;
57 for (i = sectionParsers_.begin(); i != sectionParsers_.end(); ++i) {
58 delete (i->sectionParser);
59 }
60 sectionParsers_.clear();
61 }
62
63 void SectionParserManager::parse(std::istream& input, ForceField& ff) {
64 // reset active flags
65 SectionParserManager::iterator i;
66 for (i = sectionParsers_.begin(); i != sectionParsers_.end(); ++i) {
67 i->isActive = false;
68 }
69
70 const int bufferSize = 65535;
71 char buffer[bufferSize];
72 int lineNo = 0;
73 std::stack<std::string> sectionNameStack;
74 // scan through the input stream and find section names
75 while (input.getline(buffer, bufferSize)) {
76 ++lineNo;
77
78 std::string line = Utils::trimLeftCopy(buffer);
79 // a line begins with "//" is a comment line
80 if (line.empty() ||
81 (line.size() >= 2 && line[0] == '/' && line[1] == '/')) {
82 continue;
83 } else {
84 StringTokenizer tokenizer(line);
85 if (tokenizer.countTokens() < 2) {
86 continue;
87 } else {
88 std::string keyword = tokenizer.nextToken();
89
90 if (keyword == "begin") {
91 std::string section = tokenizer.nextToken();
92 sectionNameStack.push(section);
93
94 i = std::find_if(sectionParsers_.begin(), sectionParsers_.end(),
95 SameSectionParserFunctor(section));
96 if (i == sectionParsers_.end()) {
97 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
98 "SectionParserManager Error: Can not find corresponding "
99 "section parser for %s\n",
100 section.c_str());
101 painCave.isFatal = 1;
102 simError();
103 } else {
104 if (i->isActive) {
105 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
106 "SectionParserManager Error: Found multiple %s "
107 "sections\n",
108 section.c_str());
109 painCave.isFatal = 1;
110 simError();
111 } else {
112 i->isActive = true;
113 i->lineNo = lineNo;
114 i->offset = input.tellg();
115 }
116 }
117 } else if (keyword == "end") {
118 std::string section = tokenizer.nextToken();
119 if (sectionNameStack.top() == section) {
120 sectionNameStack.pop();
121 } else {
122 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
123 "SectionParserManager Error: begin %s "
124 "and end %s do not match at line %d\n",
125 sectionNameStack.top().c_str(), section.c_str(), lineNo);
126 painCave.isFatal = 1;
127 simError();
128 }
129 } else {
130 continue;
131 }
132 }
133 }
134 }
135
136 if (!sectionNameStack.empty()) {
137 snprintf(painCave.errMsg, MAX_SIM_ERROR_MSG_LENGTH,
138 "SectionParserManager Error: Stack is not empty\n");
139 painCave.isFatal = 1;
140 simError();
141 }
142
143 // invoke parser
144 for (i = sectionParsers_.begin(); i != sectionParsers_.end(); ++i) {
145 if (i->isActive) {
146 // C++ standard does not guarantee seekg resets EOF, in that
147 // case, seekg will fail. It is always a good idea to call
148 // clear() before seek
149 input.clear();
150 input.seekg(i->offset);
151 (i->sectionParser)->parse(input, ff, i->lineNo);
152 (i->sectionParser)->validateSection(ff);
153 }
154 }
155 }
156
157 void SectionParserManager::push_front(SectionParser* sp) {
158 SectionParserManager::iterator i;
159 i = findSectionParser(sp->getSectionName());
160 if (i != sectionParsers_.end()) {
161 std::cerr << sp->getSectionName() << " section parser already exists"
162 << std::endl;
163 return;
164 }
165
166 SectionParserContext context;
167
168 if (sectionParsers_.empty()) {
169 context.priority = beginPriority_;
170 } else {
171 context.priority = sectionParsers_.front().priority - priorityDifference_;
172 }
173
174 context.sectionParser = sp;
175 context.lineNo = 0;
176 context.offset = 0;
177 context.isActive = false;
178
179 sectionParsers_.push_front(context);
180 }
181
182 void SectionParserManager::push_back(SectionParser* sp) {
183 SectionParserManager::iterator i;
184 i = findSectionParser(sp->getSectionName());
185 if (i != sectionParsers_.end()) {
186 std::cerr << sp->getSectionName() << " section parser already exists"
187 << std::endl;
188 return;
189 }
190
191 SectionParserContext context;
192 if (sectionParsers_.empty()) {
193 context.priority = beginPriority_;
194 } else {
195 context.priority = sectionParsers_.back().priority + priorityDifference_;
196 }
197
198 context.sectionParser = sp;
199 context.lineNo = 0;
200 context.offset = 0;
201 context.isActive = false;
202
203 sectionParsers_.push_back(context);
204 }
205
206 void SectionParserManager::insert(SectionParser* sp, int priority) {
207 SectionParserManager::iterator i;
208 i = findSectionParser(sp->getSectionName());
209 if (i != sectionParsers_.end()) {
210 std::cerr << sp->getSectionName() << " section parser already exists"
211 << std::endl;
212 }
213
214 SectionParserContext context;
215 context.priority = priority;
216 context.sectionParser = sp;
217 context.lineNo = 0;
218 context.offset = 0;
219 context.isActive = false;
220
221 if (sectionParsers_.empty()) {
222 sectionParsers_.push_back(context);
223 } else {
224 for (i = sectionParsers_.begin(); i != sectionParsers_.end(); ++i) {
225 if (i->priority == priority) {
226 std::cerr << "Priority " << priority << " already used" << std::endl;
227 return;
228 } else if (i->priority > priority) {
229 sectionParsers_.insert(i, context);
230 break;
231 }
232 }
233 }
234 }
235
236 SectionParserManager::iterator SectionParserManager::findSectionParser(
237 const std::string& sectionName) {
238 SectionParserManager::iterator i;
239 for (i = sectionParsers_.begin(); i != sectionParsers_.end(); ++i) {
240 if (i->sectionParser->getSectionName() == sectionName) { break; }
241 }
242 return i;
243 }
244} // namespace OpenMD
This basic Periodic Table class was originally taken from the data.cpp file in OpenBabel.