source: src/Parser/XmlParser.cpp@ ff4fff9

CombiningParticlePotentialParsing
Last change on this file since ff4fff9 was 2affd1, checked in by Frederik Heber <heber@…>, 9 years ago

Removed molecules_deprecated from World and unnecessary includes of MoleculeListClass and all insert/erase.

  • this goes along the lines of removing "remove me when we don't need MoleculeCistClass anymore".
  • Property mode set to 100644
File size: 12.5 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2012 University of Bonn. All rights reserved.
5 * Copyright (C) 2013 Frederik Heber. All rights reserved.
6 *
7 *
8 * This file is part of MoleCuilder.
9 *
10 * MoleCuilder is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * MoleCuilder is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24/*
25 * XmlParser.cpp
26 *
27 * Created on: Mar 23, 2012
28 * Author: heber
29 */
30
31// include config.h
32#ifdef HAVE_CONFIG_H
33#include <config.h>
34#endif
35
36#include "CodePatterns/MemDebug.hpp"
37
38#include <limits>
39#include <vector>
40
41#include "CodePatterns/Log.hpp"
42#include "CodePatterns/Verbose.hpp"
43
44#include "XmlParser.hpp"
45
46#include "Atom/atom.hpp"
47#include "Box.hpp"
48#include "Element/element.hpp"
49#include "Element/periodentafel.hpp"
50#include "molecule.hpp"
51#include "World.hpp"
52
53#include "Parser/pugixml/pugixml.hpp"
54
55// static instances
56FormatParser< xml >::additionalAtomInfo FormatParser< xml >::defaultAtomInfo;
57
58// declare specialized static variables
59const std::string FormatParserTrait<xml>::name = "xml";
60const std::string FormatParserTrait<xml>::suffix = "xml";
61const ParserTypes FormatParserTrait<xml>::type = xml;
62
63const char *box_axis[NDIM] = { "box_a", "box_b", "box_c" };
64
65/**
66 * Constructor.
67 */
68FormatParser< xml >::FormatParser() :
69 FormatParser_common(NULL)
70{}
71
72/**
73 * Destructor.
74 */
75FormatParser< xml >::~FormatParser()
76{}
77
78Vector toVector(const std::string &value)
79{
80 std::stringstream inputstream(value);
81 Vector returnVector;
82 for (size_t i=0;i<NDIM;++i)
83 inputstream >> std::setprecision(16) >> returnVector[i];
84 return returnVector;
85}
86
87double toDouble(const std::string &value)
88{
89 std::stringstream inputstream(value);
90 double returnDouble;
91 inputstream >> std::setprecision(16) >> returnDouble;
92 return returnDouble;
93}
94
95std::string fromVector(const Vector&a)
96{
97 std::stringstream returnstring;
98 for (size_t i=0;i<NDIM;++i) {
99 returnstring << std::setprecision(16) << a[i];
100 if (i != NDIM-1)
101 returnstring << std::string(" ");
102 }
103 return returnstring.str();
104}
105
106std::string fromDouble(const double &a)
107{
108 std::stringstream returnstring;
109 returnstring << std::setprecision(16) << a;
110 return returnstring.str();
111}
112
113std::string fromBoolean(const bool c[])
114{
115 std::stringstream returnstring;
116 for (size_t i=0;i<NDIM;++i) {
117 returnstring << (c[i] ? std::string("1") : std::string("0"));
118 if (i != NDIM-1)
119 returnstring << std::string(" ");
120 }
121 return returnstring.str();
122}
123
124/**
125 * Loads an XYZ file into the World.
126 *
127 * \param XYZ file
128 */
129void FormatParser< xml >::load(std::istream* file)
130{
131 // create the molecule
132 molecule * const newmol = World::getInstance().createMolecule();
133 newmol->ActiveFlag = true;
134
135 // load file into xml tree
136 pugi::xml_document doc;
137 doc.load(*file);
138
139 // header
140 pugi::xml_node scafacos_test = doc.root().child("scafacos_test");
141 data.name = toString(scafacos_test.attribute("name").value());
142 data.description = toString(scafacos_test.attribute("description").value());
143 data.reference_method = toString(scafacos_test.attribute("reference_method").value());
144 data.error_potential = scafacos_test.attribute("error_potential").as_double();
145 data.error_field = scafacos_test.attribute("error_field").as_double();
146 LOG(1, "INFO: scafacos_test.name is '" << data.name << "'.");
147 newmol->setName(data.name);
148
149 // configuration information
150 pugi::xml_node configuration = scafacos_test.child("configuration");
151 data.config.offset = toVector(configuration.attribute("offset").value());
152 for (size_t i=0; i<NDIM; ++i)
153 data.config.box.column(i) = toVector(configuration.attribute(box_axis[i]).value());
154 World::getInstance().getDomain().setM(data.config.box);
155 {
156 std::stringstream inputstream(configuration.attribute("periodicity").value());
157 for (size_t i=0; i<NDIM; ++i) {
158 ASSERT( inputstream.good(),
159 "FormatParser< xml >::load() - periodicity attribute has less than 3 entries.");
160 inputstream >> data.config.periodicity[i];
161 }
162 }
163 data.config.epsilon = toString(configuration.attribute("epsilon").value());
164
165 // use a map to at least give each charge a different element
166 typedef std::map<double, atomicNumber_t> charge_map_t;
167 charge_map_t charge_map;
168 size_t last_atomicnumber = 1;
169 // particles
170 for(pugi::xml_node::iterator iter = configuration.begin();
171 iter != configuration.end(); ++iter) {
172 struct scafacos::configuration::particle p;
173 p.position = toVector((*iter).attribute("position").value());
174 p.q = toDouble((*iter).attribute("q").value());
175 p.potential = toDouble((*iter).attribute("potential").value());
176 p.field = toVector((*iter).attribute("field").value());
177 data.config.p.push_back(p);
178 LOG(2, "DEBUG: Parsing particle at " << p.position << ".");
179 atom * const newAtom = World::getInstance().createAtom();
180 charge_map_t::const_iterator chargeiter = charge_map.find(p.q);
181 if (chargeiter == charge_map.end()) {
182 // create new entry and set iter pointing to it
183 std::pair<charge_map_t::const_iterator, bool> inserter =
184 charge_map.insert( std::make_pair( p.q, last_atomicnumber++) );
185 chargeiter = inserter.first;
186 }
187 newAtom->setType(World::getInstance().getPeriode()->FindElement(chargeiter->second));
188 newAtom->setPosition(p.position);
189 newAtom->setCharge(p.q);
190 newmol->AddAtom(newAtom);
191 additionalAtomInfo atomInfo(p.q, p.potential, p.field);
192#ifndef NDEBUG
193 std::pair<AtomInfoMap_t::iterator, bool> inserter =
194#endif
195 additionalAtomData.insert( std::make_pair(newAtom->getId(), atomInfo) );
196 ASSERT( inserter.second,
197 "FormatParser< xml >::load() - atomInfo entry for atom "+toString(newAtom->getId())
198 +" already present.");
199 }
200
201 BOOST_FOREACH(const atom *_atom, const_cast<const World &>(World::getInstance()).getAllAtoms())
202 LOG(3, "INFO: Atom " << _atom->getName() << " " << *dynamic_cast<const AtomInfo *>(_atom) << ".");
203
204 // refresh atom::nr and atom::name
205 newmol->getAtomCount();
206}
207
208/**
209 * Saves the \a atoms into as a XYZ file.
210 *
211 * \param file where to save the state
212 * \param atoms atoms to store
213 */
214void FormatParser< xml >::save(
215 std::ostream* file,
216 const std::vector<const atom *> &atoms) {
217 LOG(2, "DEBUG: Saving changes to xml.");
218
219 // fill the structure with updated information
220 const Box &domain = World::getInstance().getDomain();
221 data.config.box = domain.getM();
222 for (size_t i=0;i<NDIM;++i)
223 data.config.periodicity[i] = domain.getCondition(i) == BoundaryConditions::Wrap;
224 data.config.p.clear();
225 for(std::vector<const atom*>::const_iterator it = atoms.begin(); it != atoms.end(); it++) {
226 struct scafacos::configuration::particle p;
227 const additionalAtomInfo &atomInfo = getAtomData(*(*it));
228 p.position = (*it)->getPosition();
229 p.q = (*it)->getCharge();
230 p.potential = atomInfo.potential;
231 p.field = atomInfo.field;
232 data.config.p.push_back(p);
233 }
234
235 // create the xml tree
236 pugi::xml_document doc;
237 pugi::xml_attribute attr;
238
239 // header
240 pugi::xml_node xml_scafacos_test = doc.root().append_child();
241 xml_scafacos_test.set_name("scafacos_test");
242 xml_scafacos_test.append_attribute("name").set_value(data.name.c_str());
243 xml_scafacos_test.append_attribute("description").set_value(data.description.c_str());
244 xml_scafacos_test.append_attribute("reference_method").set_value(data.reference_method.c_str());
245 xml_scafacos_test.append_attribute("error_potential").set_value(data.error_potential);
246 xml_scafacos_test.append_attribute("error_field").set_value(data.error_field);
247
248 // configuration
249 pugi::xml_node xml_configuration = xml_scafacos_test.append_child();
250 xml_configuration.set_name("configuration");
251 xml_configuration.append_attribute("offset").set_value(fromVector(data.config.offset).c_str());
252 for (size_t i=0; i<NDIM; ++i)
253 xml_configuration.append_attribute(box_axis[i]).set_value(fromVector(data.config.box.column(i)).c_str());
254 xml_configuration.append_attribute("periodicity").set_value(fromBoolean(data.config.periodicity).c_str());
255 xml_configuration.append_attribute("epsilon").set_value(toString(data.config.epsilon).c_str());
256
257 // particles
258 for (std::vector<scafacos::configuration::particle>::const_iterator iter = data.config.p.begin();
259 iter != data.config.p.end();++iter) {
260 pugi::xml_node particle = xml_configuration.append_child();
261 particle.set_name("particle");
262 particle.append_attribute("position").set_value(fromVector((*iter).position).c_str());
263 particle.append_attribute("q").set_value(fromDouble((*iter).q).c_str());
264 particle.append_attribute("potential").set_value(fromDouble((*iter).potential).c_str());
265 particle.append_attribute("field").set_value(fromVector((*iter).field).c_str());
266 }
267
268 // print standard header and save without declaration
269 *file << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
270 *file << "<!DOCTYPE scafacos_test SYSTEM 'scafacos_test.dtd'>\n";
271 doc.save(*file, "\t", pugi::format_no_declaration, pugi::encoding_utf8);
272}
273
274/** Observer callback when new atom is added to World.
275 *
276 * @param id of atom
277 */
278void FormatParser< xml >::AtomInserted(atomId_t id)
279{
280 std::map<const atomId_t, additionalAtomInfo>::iterator iter = additionalAtomData.find(id);
281 ASSERT(iter == additionalAtomData.end(),
282 "FormatParser< xml >::AtomInserted() - additionalAtomData already present for newly added atom "
283 +toString(id)+".");
284 // additionalAtomData.insert( std::make_pair(id, additionalAtomInfo()) );
285}
286
287/** Remove additional AtomData info, when atom has been removed from World.
288 *
289 * @param id of atom
290 */
291void FormatParser< xml >::AtomRemoved(atomId_t id)
292{
293 std::map<const atomId_t, additionalAtomInfo>::iterator iter = additionalAtomData.find(id);
294 // as we do not insert AtomData on AtomInserted, we cannot be assured of its presence
295// ASSERT(iter != additionalAtomData.end(),
296// "FormatParser< tremolo >::AtomRemoved() - additionalAtomData is not present for atom "
297// +toString(id)+" to remove.");
298 if (iter != additionalAtomData.end())
299 additionalAtomData.erase(iter);
300}
301
302const FormatParser< xml >::additionalAtomInfo&
303FormatParser< xml >::getAtomData(const atom &_atom) const
304{
305 {
306 // has its own entry?
307 AtomInfoMap_t::const_iterator iter = additionalAtomData.find(_atom.getId());
308 if (iter != additionalAtomData.end()) {
309 return iter->second;
310 }
311 }
312 {
313 // father has an entry?
314 AtomInfoMap_t::const_iterator iter = additionalAtomData.find(_atom.GetTrueFather()->getId());
315 if (iter != additionalAtomData.end()) {
316 return iter->second;
317 }
318 }
319 return defaultAtomInfo;
320}
321
322
323#define comparator(x,y) if (x != y) { LOG(2, "DEBUG: Mismatch in " << #x << ": " << x << " != " << y); return false; }
324#define num_comparator(x,y) if (fabs(x - y) > MYEPSILON) { LOG(2, "DEBUG: Numeric mismatch in " << #x << ": " << x << " != " << y << " by " << fabs(x - y) << "."); return false; }
325
326bool FormatParser< xml >::scafacos::configuration::particle::operator==(const particle &p) const {
327 comparator(position, p.position)
328 num_comparator(q, p.q)
329 num_comparator(potential, p.potential)
330 comparator(field, p.field)
331 return true;
332}
333
334bool FormatParser< xml >::scafacos::configuration::operator==(const configuration &c) const {
335 comparator(offset, c.offset)
336 comparator(box, c.box)
337 for (size_t i=0;i<NDIM;++i)
338 comparator(periodicity[i], c.periodicity[i])
339 comparator(epsilon, c.epsilon)
340
341 if (p.size() != c.p.size()) {
342 LOG(2, "DEBUG: Mismatch in p's size: " << p.size() << " != " << c.p.size() << ".");
343 return false;
344 }
345 std::vector<scafacos::configuration::particle>::const_iterator iter = p.begin();
346 std::vector<scafacos::configuration::particle>::const_iterator citer = c.p.begin();
347 for (;iter != p.end(); ++iter, ++citer) {
348 if ((*iter) != (*citer))
349 return false;
350 }
351 return true;
352}
353
354
355bool FormatParser< xml >::scafacos::operator==(const scafacos &s) const {
356 comparator(name, s.name)
357 comparator(description, s.description)
358 comparator(reference_method, s.reference_method)
359 num_comparator(error_potential, s.error_potential)
360 num_comparator(error_field, s.error_field)
361
362 if (config != s.config) {
363 return false;
364 }
365 return true;
366}
Note: See TracBrowser for help on using the repository browser.