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