source: src/Parser/TremoloParser.cpp@ f2d5ce

Candidate_v1.7.1 stable
Last change on this file since f2d5ce was 44d5d9, checked in by Frederik Heber <frederik.heber@…>, 4 weeks ago

FIX: TremoloParser triggered changes too often.

  • when parsing a file with many timestamps, then the element would be set for every time step and not just for the first. We do not support change of elements in the midst of a trajectory.
  • Property mode set to 100644
File size: 40.0 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010-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 * TremoloParser.cpp
26 *
27 * Created on: Mar 2, 2010
28 * Author: metzler
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 "CodePatterns/Assert.hpp"
39#include "CodePatterns/Log.hpp"
40#include "CodePatterns/toString.hpp"
41#include "CodePatterns/Verbose.hpp"
42
43#include "TremoloParser.hpp"
44
45#include "Atom/atom.hpp"
46#include "Bond/bond.hpp"
47#include "Box.hpp"
48#include "Descriptors/AtomIdDescriptor.hpp"
49#include "Element/element.hpp"
50#include "Element/periodentafel.hpp"
51#include "Parser/Exceptions.hpp"
52#include "Potentials/Particles/ParticleRegistry.hpp"
53#include "LinearAlgebra/RealSpaceMatrix.hpp"
54#include "Potentials/Particles/ParticleRegistry.hpp"
55#include "molecule.hpp"
56#include "World.hpp"
57#include "WorldTime.hpp"
58
59
60#include <algorithm>
61#include <boost/bind.hpp>
62#include <boost/function.hpp>
63#include <boost/lambda/lambda.hpp>
64#include <boost/lexical_cast.hpp>
65#include <boost/tokenizer.hpp>
66#include <iostream>
67#include <iomanip>
68#include <map>
69#include <sstream>
70#include <string>
71#include <vector>
72
73#include <boost/assign/list_of.hpp> // for 'map_list_of()'
74#include <boost/assert.hpp>
75
76// declare specialized static variables
77const std::string FormatParserTrait<tremolo>::name = "tremolo";
78const std::string FormatParserTrait<tremolo>::suffix = "data";
79const ParserTypes FormatParserTrait<tremolo>::type = tremolo;
80
81// static instances
82std::map<std::string, TremoloKey::atomDataKey> FormatParser<tremolo>::knownKeys =
83 boost::assign::map_list_of("x",TremoloKey::x)
84 ("u",TremoloKey::u)
85 ("F",TremoloKey::F)
86 ("stress",TremoloKey::stress)
87 ("Id",TremoloKey::Id)
88 ("neighbors",TremoloKey::neighbors)
89 ("imprData",TremoloKey::imprData)
90 ("GroupMeasureTypeNo",TremoloKey::GroupMeasureTypeNo)
91 ("type",TremoloKey::type)
92 ("extType",TremoloKey::extType)
93 ("name",TremoloKey::name)
94 ("resName",TremoloKey::resName)
95 ("chainID",TremoloKey::chainID)
96 ("resSeq",TremoloKey::resSeq)
97 ("occupancy",TremoloKey::occupancy)
98 ("tempFactor",TremoloKey::tempFactor)
99 ("segID",TremoloKey::segID)
100 ("Charge",TremoloKey::Charge)
101 ("charge",TremoloKey::charge)
102 ("GrpTypeNo",TremoloKey::GrpTypeNo)
103 ("torsion",TremoloKey::torsion)
104 (" ",TremoloKey::noKey); // with this we can detect invalid keys
105
106/**
107 * Constructor.
108 */
109FormatParser< tremolo >::FormatParser() :
110 FormatParser_common(NULL),
111 idglobalizer(boost::bind(&FormatParser< tremolo >::getGlobalId, this, _1)),
112 idlocalizer(boost::bind(&FormatParser< tremolo >::getLocalId, this, _1))
113{
114 // invert knownKeys for debug output
115 for (std::map<std::string, TremoloKey::atomDataKey>::iterator iter = knownKeys.begin(); iter != knownKeys.end(); ++iter)
116 knownKeyNames.insert( make_pair( iter->second, iter->first) );
117
118 additionalAtomData.clear();
119}
120
121
122/**
123 * Destructor.
124 */
125FormatParser< tremolo >::~FormatParser()
126{
127 usedFields_save.clear();
128 additionalAtomData.clear();
129}
130
131/**
132 * Loads atoms from a tremolo-formatted file.
133 *
134 * \param tremolo file
135 */
136void FormatParser< tremolo >::load(istream* file) {
137 std::string line;
138 std::string::size_type location;
139
140 // reset the id maps
141 resetIdAssociations();
142
143 molecule *newmol = World::getInstance().createMolecule();
144 newmol->ActiveFlag = true;
145 usedFields_t usedFields_temp;
146 size_t timestep = 0;
147 atom *addedatom = NULL;
148 std::list<atom *> addedatoms;
149 std::list<atom *>::iterator atomiter = addedatoms.begin();
150 while (file->good()) {
151 std::getline(*file, line, '\n');
152 // we only parse in the first ATOMDATA line
153 location = line.find("ATOMDATA", 0);
154 if (location != string::npos) {
155 parseAtomDataKeysLine(line, location + 8, usedFields_temp);
156 if (usedFields_load.empty()) {
157 // first ATOMDATA: use this line
158 usedFields_load.insert(usedFields_load.end(), usedFields_temp.begin(), usedFields_temp.end());
159 LOG(3, "DEBUG: Local usedFields is: " << usedFields_load);
160 } else {
161 // following ATOMDATA: check against present
162 LOG(3, "DEBUG: Parsed check usedFields is: " << usedFields_temp);
163 if (usedFields_load != usedFields_temp) {
164 ELOG(1, "File contains multiple time steps with differing ATOMDATA line, parsing only first time step.");
165 break;
166 } else {
167 // update time step
168 ++timestep;
169 atomiter = addedatoms.begin();
170 }
171 }
172 usedFields_temp.clear();
173 } else {
174 if (line.length() > 0 && line.at(0) != '#') {
175 if (timestep != 0) {
176 ASSERT( atomiter != addedatoms.end(),
177 "FormatParser< tremolo >::load() - timesteps contains more atoms than first one.");
178 addedatom = *atomiter++;
179 }
180 readAtomDataLine(line, newmol, timestep, addedatom);
181 if (timestep == 0)
182 addedatoms.push_back(addedatom);
183 }
184 }
185 }
186 ASSERT( addedatoms.size() == newmol->size(),
187 "FormatParser< tremolo >::load() - number of atoms in mol and addedatoms differ.");
188
189 // refresh atom::nr and atom::name
190 std::vector<atomId_t> atoms(newmol->getAtomCount());
191 std::transform(newmol->begin(), newmol->end(), atoms.begin(),
192 boost::bind(&atom::getId, _1));
193 processNeighborInformation(atoms);
194 adaptImprData(atoms);
195 adaptTorsion(atoms);
196
197 // append usedFields to global usedFields, is made unique on save, clear after use
198 usedFields_save.insert(usedFields_save.end(), usedFields_load.begin(), usedFields_load.end());
199 usedFields_load.clear();
200}
201
202/**
203 * Saves the \a atoms into as a tremolo file.
204 *
205 * \param file where to save the state
206 * \param atoms atoms to store
207 */
208void FormatParser< tremolo >::save(
209 std::ostream* file,
210 const std::vector<const atom *> &AtomList) {
211 LOG(2, "DEBUG: Saving changes to tremolo.");
212
213 // install default usedFields if empty so far
214 if (usedFields_save.empty()) {
215 // default behavior: use all possible keys on output
216 for (std::map<std::string, TremoloKey::atomDataKey>::iterator iter = knownKeys.begin();
217 iter != knownKeys.end(); ++iter)
218 if (iter->second != TremoloKey::noKey) // don't add noKey
219 usedFields_save.push_back(iter->first);
220 }
221 // make present usedFields_save unique
222 makeUsedFieldsUnique(usedFields_save);
223 LOG(1, "INFO: Global (with unique entries) usedFields_save is: " << usedFields_save);
224
225 // distribute ids continuously
226 distributeContinuousIds(AtomList);
227
228 std::pair<size_t, size_t> minmax_trajectories =
229 getMinMaxTrajectories(AtomList);
230 LOG(2, "INFO: There are " << minmax_trajectories.second << " steps to save.");
231
232 for (size_t step = 0; (step < minmax_trajectories.second) || (step == 0); ++step) {
233 // store atomdata
234 save_AtomDataLine(file);
235
236 // store box only on first step
237 if (step == 0)
238 save_BoxLine(file);
239
240 // store particles
241 for (std::vector<const atom*>::const_iterator atomIt = AtomList.begin();
242 atomIt != AtomList.end(); ++atomIt)
243 saveLine(file, *atomIt, step);
244 }
245}
246
247struct usedFieldsWeakComparator
248{
249 /** Special comparator regards "neighbors=4" and "neighbors=2" as equal
250 *
251 * \note This one is used for making usedFields unique, i.e. throwing out the "smaller"
252 * neighbors.
253 */
254 bool operator()(const std::string &a, const std::string &b) const
255 {
256 // only compare up to first equality sign
257 return (a.substr(0, a.find_first_of('=')) == b.substr(0, b.find_first_of('=')));
258 }
259};
260
261struct usedFieldsSpecialOrderer
262{
263 /** Special string comparator that regards "neighbors=4" < "neighbors=2" as true and
264 * the other way round as false.
265 *
266 * Here, we implement the operator "\a < \b" in a special way to allow the
267 * above.
268 *
269 * \note This one is used for sorting usedFields in preparation for making it unique.
270 */
271 bool operator()(const std::string &a, const std::string &b) const
272 {
273 // only compare up to first equality sign
274 size_t a_equality = a.find_first_of('=');
275 size_t b_equality = b.find_first_of('=');
276 // if key before equality is not equal, return whether it is smaller or not
277 if (a.substr(0, a_equality) != b.substr(0, b_equality)) {
278 return a.substr(0, a_equality) < b.substr(0, b_equality);
279 } else { // now we know that the key before equality is the same in either string
280 // if one of them has no equality, the one with equality must go before
281 if ((a_equality != std::string::npos) && (b_equality == std::string::npos))
282 return true;
283 if ((a_equality == std::string::npos) && (b_equality != std::string::npos))
284 return false;
285 // if both don't have equality (and the token before is equal), it is not "<" but "=="
286 if ((a_equality == std::string::npos) && (b_equality == std::string::npos))
287 return false;
288 // if now both have equality sign, the larger value after it, must come first
289 return a.substr(a_equality, std::string::npos) > b.substr(b_equality, std::string::npos);
290 }
291 }
292};
293
294/** Helper function to make \given fields unique while preserving the order of first appearance.
295 *
296 * As std::unique only removes element if equal to predecessor, a vector is only
297 * made unique if sorted beforehand. But sorting would destroy order of first
298 * appearance, hence we do the sorting on a temporary field and add the unique
299 * elements in the order as in \a fields.
300 *
301 * @param fields usedFields to make unique while preserving order of appearance
302 */
303void FormatParser< tremolo >::makeUsedFieldsUnique(usedFields_t &fields) const
304{
305 // std::unique only removes if predecessor is equal, not over whole range, hence do it manually
306 usedFields_t temp_fields(fields);
307 usedFieldsSpecialOrderer SpecialOrderer;
308 usedFieldsWeakComparator WeakComparator;
309 std::sort(temp_fields.begin(), temp_fields.end(), SpecialOrderer);
310 usedFields_t::iterator it =
311 std::unique(temp_fields.begin(), temp_fields.end(), WeakComparator);
312 temp_fields.erase(it, temp_fields.end());
313 usedFields_t usedfields(fields);
314 fields.clear();
315 fields.reserve(temp_fields.size());
316 // now go through each usedFields entry, check if in temp_fields and remove there on first occurence
317 for (usedFields_t::const_iterator iter = usedfields.begin();
318 iter != usedfields.end(); ++iter) {
319 usedFields_t::iterator uniqueiter =
320 std::find(temp_fields.begin(), temp_fields.end(), *iter);
321 if (uniqueiter != temp_fields.end()) {
322 fields.push_back(*iter);
323 // add only once to ATOMDATA
324 temp_fields.erase(uniqueiter);
325 }
326 }
327 ASSERT( temp_fields.empty(),
328 "FormatParser< tremolo >::save() - still unique entries left in temp_fields after unique?");
329}
330
331
332/** Resets and distributes the indices continuously.
333 *
334 * \param atoms atoms to store
335 */
336void FormatParser< tremolo >::distributeContinuousIds(
337 const std::vector<const atom *> &AtomList)
338{
339 resetIdAssociations();
340 atomId_t lastid = 0;
341 for (std::vector<const atom*>::const_iterator atomIt = AtomList.begin();
342 atomIt != AtomList.end(); ++atomIt)
343 associateLocaltoGlobalId(++lastid, (*atomIt)->getId());
344}
345
346/** Store Atomdata line to \a file.
347 *
348 * @param file output stream
349 */
350void FormatParser< tremolo >::save_AtomDataLine(std::ostream* file) const
351{
352 *file << "# ATOMDATA";
353 for (usedFields_t::const_iterator it=usedFields_save.begin();
354 it != usedFields_save.end(); ++it)
355 *file << "\t" << *it;
356 *file << std::endl;
357}
358
359/** Store Box info to \a file
360 *
361 * @param file output stream
362 */
363void FormatParser< tremolo >::save_BoxLine(std::ostream* file) const
364{
365 *file << "# Box";
366 const RealSpaceMatrix &M = World::getInstance().getDomain().getM();
367 for (size_t i=0; i<NDIM;++i)
368 for (size_t j=0; j<NDIM;++j)
369 *file << "\t" << M.at(i,j);
370 *file << std::endl;
371}
372
373/** Add default info, when new atom is added to World.
374 *
375 * @param id of atom
376 */
377void FormatParser< tremolo >::AtomInserted(atomId_t id)
378{
379 std::map<const atomId_t, TremoloAtomInfoContainer>::iterator iter = additionalAtomData.find(id);
380 ASSERT(iter == additionalAtomData.end(),
381 "FormatParser< tremolo >::AtomInserted() - additionalAtomData already present for newly added atom "
382 +toString(id)+".");
383 // don't add entry, as this gives a default resSeq of 0 not the molecule id
384 // additionalAtomData.insert( std::make_pair(id, TremoloAtomInfoContainer()) );
385}
386
387/** Remove additional AtomData info, when atom has been removed from World.
388 *
389 * @param id of atom
390 */
391void FormatParser< tremolo >::AtomRemoved(atomId_t id)
392{
393 std::map<const atomId_t, TremoloAtomInfoContainer>::iterator iter = additionalAtomData.find(id);
394 // as we do not insert AtomData on AtomInserted, we cannot be assured of its presence
395// ASSERT(iter != additionalAtomData.end(),
396// "FormatParser< tremolo >::AtomRemoved() - additionalAtomData is not present for atom "
397// +toString(id)+" to remove.");
398 if (iter != additionalAtomData.end())
399 additionalAtomData.erase(iter);
400}
401
402template <class T>
403T NoOp(const atom * const)
404{
405 return T();
406}
407
408template <class T>
409void writeEntryFromAdditionalAtomData_ifpresent(
410 std::map<const atomId_t, TremoloAtomInfoContainer> &_additionalAtomData,
411 std::map<TremoloKey::atomDataKey, std::string> &_knownKeyNames,
412 std::ostream* _file,
413 const atom * const _currentAtom,
414 const TremoloKey::atomDataKey _currentField,
415 const typename boost::function<T (const atom * const)> _getter)
416{
417 if (_additionalAtomData.count(_currentAtom->getId())) {
418 LOG(3, "Writing for type " << _knownKeyNames[_currentField] << ": "
419 << _additionalAtomData[_currentAtom->getId()].get(_currentField));
420 *_file << _additionalAtomData[_currentAtom->getId()].get(_currentField);
421 } else if (_additionalAtomData.count(_currentAtom->GetTrueFather()->getId())) {
422 LOG(3, "Writing for type " << _knownKeyNames[_currentField] << " stuff from father: "
423 << _additionalAtomData[_currentAtom->GetTrueFather()->getId()].get(_currentField));
424 *_file << _additionalAtomData[_currentAtom->GetTrueFather()->getId()].get(_currentField);
425 } else {
426 LOG(3, "Writing for type " << _knownKeyNames[_currentField] << " its default value: "
427 << _getter(_currentAtom));
428 *_file << _getter(_currentAtom);
429 }
430 *_file << "\t";
431}
432
433template <class T>
434void writeAdditionalAtomDataEntry(
435 std::map<const atomId_t, TremoloAtomInfoContainer> &_additionalAtomData,
436 std::map<TremoloKey::atomDataKey, std::string> &_knownKeyNames,
437 TremoloAtomInfoContainer &_defaultAdditionalData,
438 std::ostream* _file,
439 const atom * const _currentAtom,
440 const TremoloKey::atomDataKey _currentField)
441{
442 if (_additionalAtomData.count(_currentAtom->getId())) {
443 LOG(3, "Writing for type " << _knownKeyNames[_currentField] << ": "
444 << _additionalAtomData[_currentAtom->getId()].get(_currentField));
445 *_file << _additionalAtomData[_currentAtom->getId()].get(_currentField);
446 } else if (_additionalAtomData.count(_currentAtom->GetTrueFather()->getId())) {
447 LOG(3, "Writing for type " << _knownKeyNames[_currentField] << " stuff from father: "
448 << _additionalAtomData[_currentAtom->GetTrueFather()->getId()].get(_currentField));
449 *_file << _additionalAtomData[_currentAtom->GetTrueFather()->getId()].get(_currentField);
450 } else {
451 LOG(3, "Writing for type " << _knownKeyNames[_currentField] << " its default value: "
452 << _defaultAdditionalData.get(_currentField));
453 *_file << _defaultAdditionalData.get(_currentField);
454 }
455 *_file << "\t";
456}
457
458template <class T>
459void writeEntryFromAdditionalAtomData_ifnotempty(
460 std::map<const atomId_t, TremoloAtomInfoContainer> &_additionalAtomData,
461 std::map<TremoloKey::atomDataKey, std::string> &_knownKeyNames,
462 TremoloAtomInfoContainer &_defaultAdditionalData,
463 std::ostream* _file,
464 const atom * const _currentAtom,
465 const TremoloKey::atomDataKey _currentField,
466 const typename boost::function<T (const atom * const)> _getter)
467{
468 if (_additionalAtomData.count(_currentAtom->getId())) {
469 if (_additionalAtomData[_currentAtom->getId()].get(_currentField) != "-") {
470 LOG(3, "Writing for type " << _knownKeyNames[_currentField] << ": "
471 << _additionalAtomData[_currentAtom->getId()].get(_currentField));
472 *_file << _additionalAtomData[_currentAtom->getId()].get(_currentField);
473 } else {
474 LOG(3, "Writing for type " << _knownKeyNames[_currentField] << " default value: "
475 << _getter(_currentAtom));
476 *_file << _getter(_currentAtom);
477 }
478 } else if (_additionalAtomData.count(_currentAtom->GetTrueFather()->getId())) {
479 if (_additionalAtomData[_currentAtom->GetTrueFather()->getId()].get(_currentField) != "-") {
480 LOG(3, "Writing for type " << _knownKeyNames[_currentField] << " stuff from father: "
481 << _additionalAtomData[_currentAtom->GetTrueFather()->getId()].get(_currentField));
482 *_file << _additionalAtomData[_currentAtom->GetTrueFather()->getId()].get(_currentField);
483 } else {
484 LOG(3, "Writing for type " << _knownKeyNames[_currentField] << " default value from father: "
485 << _getter(_currentAtom->GetTrueFather()));
486 *_file << _getter(_currentAtom->GetTrueFather());
487 }
488 } else {
489 LOG(3, "Writing for type " << _knownKeyNames[_currentField] << " its default value: "
490 << _getter(_currentAtom));
491 *_file << _getter(_currentAtom);
492 }
493 *_file << "\t";
494}
495
496/**
497 * Writes one line of tremolo-formatted data to the provided stream.
498 *
499 * \param stream where to write the line to
500 * \param reference to the atom of which information should be written
501 */
502void FormatParser< tremolo >::saveLine(
503 std::ostream* file,
504 const atom * const currentAtom,
505 const size_t _timestep)
506{
507 TremoloKey::atomDataKey currentField;
508
509 LOG(4, "INFO: Saving atom " << *currentAtom << ", its father id is "
510 << currentAtom->GetTrueFather()->getId() << " at time step " << _timestep);
511
512 // note down default precision
513 std::streamsize defaultprecision=file->precision();
514 std::streamsize highprecision=10;
515
516 for (usedFields_t::iterator it = usedFields_save.begin(); it != usedFields_save.end(); it++) {
517 currentField = knownKeys[it->substr(0, it->find("="))];
518 switch (currentField) {
519 case TremoloKey::x :
520 // for the moment, assume there are always three dimensions
521 LOG(3, "Writing for type " << knownKeyNames[currentField] << ": " << currentAtom->getPositionAtStep(_timestep));
522 file->precision(highprecision);
523 *file << currentAtom->atStep(0, _timestep) << "\t";
524 *file << currentAtom->atStep(1, _timestep) << "\t";
525 *file << currentAtom->atStep(2, _timestep) << "\t";
526 file->precision(defaultprecision);
527 break;
528 case TremoloKey::u :
529 // for the moment, assume there are always three dimensions
530 LOG(3, "Writing for type " << knownKeyNames[currentField] << ": " << currentAtom->getAtomicVelocityAtStep(_timestep));
531 file->precision(highprecision);
532 *file << currentAtom->getAtomicVelocityAtStep(_timestep)[0] << "\t";
533 *file << currentAtom->getAtomicVelocityAtStep(_timestep)[1] << "\t";
534 *file << currentAtom->getAtomicVelocityAtStep(_timestep)[2] << "\t";
535 file->precision(defaultprecision);
536 break;
537 case TremoloKey::F :
538 // for the moment, assume there are always three dimensions
539 LOG(3, "Writing for type " << knownKeyNames[currentField] << ": " << currentAtom->getAtomicForceAtStep(_timestep));
540 file->precision(highprecision);
541 *file << currentAtom->getAtomicForceAtStep(_timestep)[0] << "\t";
542 *file << currentAtom->getAtomicForceAtStep(_timestep)[1] << "\t";
543 *file << currentAtom->getAtomicForceAtStep(_timestep)[2] << "\t";
544 file->precision(defaultprecision);
545 break;
546 case TremoloKey::type :
547 writeEntryFromAdditionalAtomData_ifnotempty<std::string>(
548 additionalAtomData,
549 knownKeyNames,
550 defaultAdditionalData,
551 file,
552 currentAtom,
553 currentField,
554 boost::bind(&element::getSymbol, boost::bind(&AtomInfo::getType, _1)));
555 break;
556 case TremoloKey::Id :
557 LOG(3, "Writing for type " << knownKeyNames[currentField] << ": " << currentAtom->getId()+1);
558 *file << getLocalId(currentAtom->getId()) << "\t";
559 break;
560 case TremoloKey::neighbors :
561 LOG(3, "Writing type " << knownKeyNames[currentField]);
562 writeNeighbors(file, atoi(it->substr(it->find("=") + 1, 1).c_str()), currentAtom);
563 break;
564 case TremoloKey::imprData :
565 case TremoloKey::torsion :
566 LOG(3, "Writing type " << knownKeyNames[currentField]);
567 *file << adaptIdDependentDataString(
568 additionalAtomData[currentAtom->getId()].get(currentField),
569 idlocalizer)
570 << "\t";
571 break;
572 case TremoloKey::resSeq :
573 if (additionalAtomData.count(currentAtom->getId())) {
574 LOG(3, "Writing for type " << knownKeyNames[currentField] << ": " << additionalAtomData[currentAtom->getId()].get(currentField));
575 *file << additionalAtomData[currentAtom->getId()].get(currentField);
576 } else if (currentAtom->getMolecule() != NULL) {
577 LOG(3, "Writing for type " << knownKeyNames[currentField] << " its own id: " << currentAtom->getMolecule()->getId()+1);
578 *file << setw(4) << currentAtom->getMolecule()->getId();
579 } else {
580 LOG(3, "Writing for type " << knownKeyNames[currentField] << " default value: " << defaultAdditionalData.get(currentField));
581 *file << defaultAdditionalData.get(currentField);
582 }
583 *file << "\t";
584 break;
585 case TremoloKey::charge :
586 if (currentAtom->getCharge() == 0.) {
587 writeEntryFromAdditionalAtomData_ifpresent<double>(
588 additionalAtomData,
589 knownKeyNames,
590 file,
591 currentAtom,
592 currentField,
593 boost::bind(&AtomInfo::getCharge, _1));
594 } else {
595 LOG(3, "Writing for type " << knownKeyNames[currentField] << " AtomInfo::charge : " << currentAtom->getCharge());
596 *file << currentAtom->getCharge() << "\t";
597 }
598 break;
599 default :
600 writeAdditionalAtomDataEntry<std::string>(
601 additionalAtomData,
602 knownKeyNames,
603 defaultAdditionalData,
604 file,
605 currentAtom,
606 currentField);
607 break;
608 }
609 }
610
611 *file << std::endl;
612}
613
614/**
615 * Writes the neighbor information of one atom to the provided stream.
616 *
617 * Note that ListOfBonds of WorldTime::CurrentTime is used.
618 *
619 * \param stream where to write neighbor information to
620 * \param number of neighbors
621 * \param reference to the atom of which to take the neighbor information
622 */
623void FormatParser< tremolo >::writeNeighbors(
624 std::ostream* file,
625 const int numberOfNeighbors,
626 const atom * const currentAtom) {
627 const BondList& ListOfBonds = currentAtom->getListOfBonds();
628 // sort bonded indices
629 typedef std::set<atomId_t> sortedIndices;
630 sortedIndices sortedBonds;
631 for (BondList::const_iterator iter = ListOfBonds.begin();
632 iter != ListOfBonds.end(); ++iter)
633 sortedBonds.insert(getLocalId((*iter)->GetOtherAtom(currentAtom)->getId()));
634 // print indices
635 sortedIndices::const_iterator currentBond = sortedBonds.begin();
636 for (int i = 0; i < numberOfNeighbors; i++) {
637 *file << (currentBond != sortedBonds.end() ? (*currentBond) : 0) << "\t";
638 if (currentBond != sortedBonds.end())
639 ++currentBond;
640 }
641}
642
643/**
644 * Stores keys from the ATOMDATA line in \a fields.
645 *
646 * \param line to parse the keys from
647 * \param offset with which offset the keys begin within the line
648 * \param fields which usedFields to use
649 */
650void FormatParser< tremolo >::parseAtomDataKeysLine(
651 const std::string &line,
652 const int offset,
653 usedFields_t &fields) {
654 std::string keyword;
655 std::stringstream lineStream;
656
657 lineStream << line.substr(offset);
658 lineStream >> ws;
659 while (lineStream.good()) {
660 lineStream >> keyword;
661 if (knownKeys[keyword.substr(0, keyword.find("="))] == TremoloKey::noKey) {
662 // TODO: throw exception about unknown key
663 cout << "Unknown key: " << keyword.substr(0, keyword.find("=")) << " is not part of the tremolo format specification." << endl;
664 throw IllegalParserKeyException();
665 break;
666 }
667 fields.push_back(keyword);
668 lineStream >> ws;
669 }
670 LOG(2, "INFO: " << fields);
671}
672
673/**
674 * Tests whether the keys from the ATOMDATA line can be read correctly.
675 *
676 * \param line to parse the keys from
677 */
678bool FormatParser< tremolo >::testParseAtomDataKeysLine(
679 const std::string &line) {
680 std::string keyword;
681 std::stringstream lineStream;
682
683 // check string after ATOMDATA
684 const std::string AtomData("ATOMDATA");
685 const size_t AtomDataOffset = line.find(AtomData, 0);
686 if (AtomDataOffset == std::string::npos)
687 lineStream << line;
688 else
689 lineStream << line.substr(AtomDataOffset + AtomData.length());
690 while (lineStream.good()) {
691 lineStream >> keyword;
692 //LOG(2, "DEBUG: Checking key " << keyword.substr(0, keyword.find("=")) << ".");
693 if (knownKeys[keyword.substr(0, keyword.find("="))] == TremoloKey::noKey)
694 return false;
695 }
696 //LOG(1, "INFO: " << fields);
697 return true;
698}
699
700std::string FormatParser< tremolo >::getAtomData() const
701{
702 std::stringstream output;
703 std::for_each(usedFields_save.begin(), usedFields_save.end(),
704 output << boost::lambda::_1 << " ");
705 const std::string returnstring(output.str());
706 return returnstring.substr(0, returnstring.find_last_of(" "));
707}
708
709/** Appends the properties per atom to print to .data file by parsing line from
710 * \a atomdata_string.
711 *
712 * We just call \sa FormatParser< tremolo >::parseAtomDataKeysLine().
713 *
714 * @param atomdata_string line to parse with space-separated values
715 */
716void FormatParser< tremolo >::setAtomData(const std::string &atomdata_string)
717{
718 parseAtomDataKeysLine(atomdata_string, 0, usedFields_save);
719}
720
721/** Sets the properties per atom to print to .data file by parsing line from
722 * \a atomdata_string.
723 *
724 * We just call \sa FormatParser< tremolo >::parseAtomDataKeysLine(), however
725 * we clear FormatParser< tremolo >::usedFields_save.
726 *
727 * @param atomdata_string line to parse with space-separated values
728 */
729void FormatParser< tremolo >::resetAtomData(const std::string &atomdata_string)
730{
731 usedFields_save.clear();
732 parseAtomDataKeysLine(atomdata_string, 0, usedFields_save);
733}
734
735
736/**
737 * Reads one data line of a tremolo file and interprets it according to the keys
738 * obtained from the ATOMDATA line.
739 *
740 * \param line to parse as an atom
741 * \param *newmol molecule to add atom to
742 * \param _timestep time step to parse to
743 * \param _addedatom ref to added atom
744 */
745void FormatParser< tremolo >::readAtomDataLine(
746 const std::string &line,
747 molecule *newmol,
748 const size_t _timestep,
749 atom *&_addedatoms)
750{
751 std::stringstream lineStream;
752 atom* newAtom = NULL;
753 atomId_t atomid = -1;
754 if (_timestep == 0) {
755 newAtom = World::getInstance().createAtom();
756 _addedatoms = newAtom;
757 atomid = newAtom->getId();
758 additionalAtomData[atomid] = TremoloAtomInfoContainer(); // fill with default values
759 } else {
760 newAtom = _addedatoms;
761 atomid = newAtom->getId();
762 }
763 TremoloAtomInfoContainer *atomInfo = &additionalAtomData[atomid];
764 TremoloKey::atomDataKey currentField;
765 ConvertTo<double> toDouble;
766 ConvertTo<int> toInt;
767 Vector tempVector;
768 const ParticleRegistry& registry = ParticleRegistry::getConstInstance();
769 const periodentafel& periode = *World::getInstance().getPeriode();
770
771 // setup tokenizer, splitting up white-spaced entries
772 typedef boost::tokenizer<boost::char_separator<char> >
773 tokenizer;
774 boost::char_separator<char> whitespacesep(" \t");
775 tokenizer tokens(line, whitespacesep);
776 ASSERT(tokens.begin() != tokens.end(),
777 "FormatParser< tremolo >::readAtomDataLine - empty string, need at least ' '!");
778 tokenizer::const_iterator tok_iter = tokens.begin();
779 // then associate each token to each file
780 for (usedFields_t::const_iterator it = usedFields_load.begin(); it != usedFields_load.end(); it++) {
781 const std::string keyName = it->substr(0, it->find("="));
782 currentField = knownKeys[keyName];
783 ASSERT(tok_iter != tokens.end(),
784 "FormatParser< tremolo >::readAtomDataLine - too few entries in line '"+line+"'!");
785 const std::string &word = *tok_iter;
786 LOG(4, "INFO: Parsing key " << keyName << " with remaining data " << word);
787 switch (currentField) {
788 case TremoloKey::x :
789 // for the moment, assume there are always three dimensions
790 for (int i=0;i<NDIM;i++) {
791 ASSERT(tok_iter != tokens.end(), "FormatParser< tremolo >::readAtomDataLine() - no value for x["+toString(i)+"]!");
792 LOG(4, "INFO: Parsing key " << keyName << " with next token " << word << " on step " << _timestep);
793 newAtom->setAtStep(i, _timestep, toDouble(word));
794 tok_iter++;
795 }
796 break;
797 case TremoloKey::u :
798 // for the moment, assume there are always three dimensions
799 for (int i=0;i<NDIM;i++) {
800 ASSERT(tok_iter != tokens.end(), "FormatParser< tremolo >::readAtomDataLine() - no value for u["+toString(i)+"]!");
801 LOG(4, "INFO: Parsing key " << keyName << " with next token " << word << " on step " << _timestep);
802 tempVector[i] = toDouble(word);
803 tok_iter++;
804 }
805 newAtom->setAtomicVelocityAtStep(_timestep, tempVector);
806 break;
807 case TremoloKey::F :
808 // for the moment, assume there are always three dimensions
809 for (int i=0;i<NDIM;i++) {
810 ASSERT(tok_iter != tokens.end(), "FormatParser< tremolo >::readAtomDataLine() - no value for F["+toString(i)+"]!");
811 LOG(4, "INFO: Parsing key " << keyName << " with next token " << word << " on step " << _timestep);
812 tempVector[i] = toDouble(word);
813 tok_iter++;
814 }
815 newAtom->setAtomicForceAtStep(_timestep, tempVector);
816 break;
817 case TremoloKey::type :
818 {
819 ASSERT(tok_iter != tokens.end(), "FormatParser< tremolo >::readAtomDataLine() - no value for "+keyName+"!");
820 LOG(4, "INFO: Parsing key " << keyName << " with next token " << word << " on step " << _timestep);
821 std::string elementname;
822 const element * elem = NULL;
823 if (!registry.isPresentByName(word)) {
824 std::string lowercase_word(word);
825 std::transform(word.begin()+1, word.end(), lowercase_word.begin()+1, ::tolower);
826 elem = periode.FindElement(lowercase_word);
827 if (elem == NULL) {
828 // clean up
829 World::getInstance().destroyAtom(newAtom);
830 // give an error
831 ELOG(0, "TremoloParser: tokens " << word << "/" << lowercase_word
832 << " is unknown to neither ParticleRegistry nor Periodentafel.");
833 return;
834 } else {
835 elementname = elem->getSymbol();
836 }
837 } else {
838 const Particle * const p = registry.getByName(word);
839 elementname = p->getElement();
840 elem = periode.FindElement(elementname);
841 }
842 // put type name into container for later use
843 atomInfo->set(currentField, word);
844 LOG(4, "INFO: Parsing element " << (word) << " as " << elementname << " according to KnownTypes.");
845 tok_iter++;
846 if (newAtom->getType() != elem)
847 newAtom->setType(elem);
848 ASSERT(newAtom->getType(), "Type was not set for this atom");
849 break;
850 }
851 case TremoloKey::Id :
852 ASSERT(tok_iter != tokens.end(), "FormatParser< tremolo >::readAtomDataLine() - no value for "+keyName+"!");
853 LOG(4, "INFO: Parsing key " << keyName << " with next token " << word << " on step " << _timestep);
854 if (_timestep == 0) {
855 associateLocaltoGlobalId(toInt(word), atomid);
856 } else {
857 // check association is the same
858 ASSERT( (atomId_t)getGlobalId(toInt(word)) == atomid,
859 "FormatParser< tremolo >::readAtomDataLine() - differing global id "+toString(atomid)
860 +" on timestep "+toString(_timestep));
861 ASSERT( getLocalId(atomid) == toInt(word),
862 "FormatParser< tremolo >::readAtomDataLine() - differing local id "+toString(toInt(word))
863 +" on timestep "+toString(_timestep));
864 }
865 tok_iter++;
866 break;
867 case TremoloKey::neighbors :
868 for (int i=0;i<atoi(it->substr(it->find("=") + 1, 1).c_str());i++) {
869 ASSERT(tok_iter != tokens.end(),
870 "FormatParser< tremolo >::readAtomDataLine() - no value for "+keyName+"!");
871 if (_timestep == 0)
872 LOG(4, "INFO: Parsing key " << keyName << " with next token " << word << " on step " << _timestep);
873 lineStream << word << "\t";
874 tok_iter++;
875 }
876 if (_timestep == 0) {
877 readNeighbors(&lineStream,
878 atoi(it->substr(it->find("=") + 1, 1).c_str()), atomid);
879 }
880 break;
881 case TremoloKey::charge :
882 ASSERT(tok_iter != tokens.end(), "FormatParser< tremolo >::readAtomDataLine() - no value for "+keyName+"!");
883 if (_timestep == 0) {
884 LOG(4, "INFO: Parsing key " << keyName << " with next token " << word << " on step " << _timestep);
885 atomInfo->set(currentField, word);
886 const double newCharge = boost::lexical_cast<double>(word);
887 if (newAtom->getCharge() != newCharge)
888 newAtom->setCharge(newCharge);
889 }
890 tok_iter++;
891 break;
892 default :
893 ASSERT(tok_iter != tokens.end(), "FormatParser< tremolo >::readAtomDataLine() - no value for "+keyName+"!");
894 if (_timestep == 0) {
895 LOG(4, "INFO: Parsing key " << keyName << " with next token " << word << " on step " << _timestep);
896 atomInfo->set(currentField, word);
897 }
898 tok_iter++;
899 break;
900 }
901 }
902 LOG(3, "INFO: Parsed atom " << atomid << ".");
903 if ((newmol != NULL) && (_timestep == 0))
904 newmol->AddAtom(newAtom);
905}
906
907bool FormatParser< tremolo >::saveAtomsInExttypes(
908 std::ostream &output,
909 const std::vector<const atom*> &atoms,
910 const int id) const
911{
912 bool status = true;
913 // parse the file
914 for (std::vector<const atom *>::const_iterator iter = atoms.begin();
915 iter != atoms.end(); ++iter) {
916 const int atomicid = getLocalId((*iter)->getId());
917 if (atomicid == -1)
918 status = false;
919 output << atomicid << "\t" << id << std::endl;
920 }
921
922 return status;
923}
924
925/**
926 * Reads neighbor information for one atom from the input.
927 *
928 * \param line stream where to read the information from
929 * \param numberOfNeighbors number of neighbors to read
930 * \param atomid world id of the atom the information belongs to
931 */
932void FormatParser< tremolo >::readNeighbors(
933 std::stringstream* line,
934 const int numberOfNeighbors,
935 const int atomId) {
936 int neighborId = 0;
937 for (int i = 0; i < numberOfNeighbors; i++) {
938 *line >> neighborId;
939 // 0 is used to fill empty neighbor positions in the tremolo file.
940 if (neighborId > 0) {
941 LOG(4, "INFO: Atom with global id " << atomId
942 << " has neighbour with serial " << neighborId);
943 additionalAtomData[atomId].neighbors.push_back(neighborId);
944 }
945 }
946}
947
948/**
949 * Checks whether the provided name is within \a fields.
950 *
951 * \param fields which usedFields to use
952 * \param fieldName name to check
953 * \return true if the field name is used
954 */
955bool FormatParser< tremolo >::isUsedField(
956 const usedFields_t &fields,
957 const std::string &fieldName) const
958{
959 bool fieldNameExists = false;
960 for (usedFields_t::const_iterator usedField = fields.begin();
961 usedField != fields.end(); usedField++) {
962 if (usedField->substr(0, usedField->find("=")) == fieldName)
963 fieldNameExists = true;
964 }
965
966 return fieldNameExists;
967}
968
969
970/**
971 * Adds the collected neighbor information to the atoms in the world. The atoms
972 * are found by their current ID and mapped to the corresponding atoms with the
973 * Id found in the parsed file.
974 *
975 * @param atoms vector with all newly added (global) atomic ids
976 */
977void FormatParser< tremolo >::processNeighborInformation(
978 const std::vector<atomId_t> &atoms) {
979 if (!isUsedField(usedFields_load, "neighbors")) {
980 return;
981 }
982
983 for (std::vector<atomId_t>::const_iterator iter = atoms.begin(); iter != atoms.end(); ++iter) {
984 ASSERT(additionalAtomData.count(*iter) != 0,
985 "FormatParser< tremolo >::processNeighborInformation() - global id "
986 +toString(*iter)+" unknown in additionalAtomData.");
987 TremoloAtomInfoContainer &currentInfo = additionalAtomData[*iter];
988 ASSERT (!currentInfo.neighbors_processed,
989 "FormatParser< tremolo >::processNeighborInformation() - neighbors of new atom "
990 +toString(*iter)+" are already processed.");
991 for(std::vector<int>::const_iterator neighbor = currentInfo.neighbors.begin();
992 neighbor != currentInfo.neighbors.end(); neighbor++
993 ) {
994 LOG(3, "INFO: Creating bond between ("
995 << *iter
996 << ") and ("
997 << getGlobalId(*neighbor) << "|" << *neighbor << ")");
998 ASSERT(getGlobalId(*neighbor) != -1,
999 "FormatParser< tremolo >::processNeighborInformation() - global id to local id "
1000 +toString(*neighbor)+" is unknown.");
1001 World::getInstance().getAtom(AtomById(*iter))
1002 ->addBond(WorldTime::getTime(), World::getInstance().getAtom(AtomById(getGlobalId(*neighbor))));
1003 }
1004 currentInfo.neighbors_processed = true;
1005 }
1006}
1007
1008/**
1009 * Replaces atom IDs read from the file by the corresponding world IDs. All IDs
1010 * IDs of the input string will be replaced; expected separating characters are
1011 * "-" and ",".
1012 *
1013 * \param string in which atom IDs should be adapted
1014 * \param idgetter function pointer to change the id
1015 *
1016 * \return input string with modified atom IDs
1017 */
1018std::string FormatParser< tremolo >::adaptIdDependentDataString(
1019 const std::string &data,
1020 const boost::function<int (const int)> &idgetter
1021 ) {
1022 // there might be no IDs
1023 if (data == "-") {
1024 return "-";
1025 }
1026
1027 char separator;
1028 int id;
1029 std::stringstream line, result;
1030 line << data;
1031
1032 line >> id;
1033 result << idgetter(id);
1034 while (line.good()) {
1035 line >> separator >> id;
1036 result << separator << idgetter(id);
1037 }
1038
1039 return result.str();
1040}
1041
1042/** Corrects the atom IDs in each imprData entry to the corresponding world IDs
1043 * as they might differ from the originally read IDs.
1044 *
1045 * \param atoms currently parsed in atoms
1046 */
1047void FormatParser< tremolo >::adaptImprData(const std::vector<atomId_t> &atoms) {
1048 if (!isUsedField(usedFields_load, "imprData")) {
1049 return;
1050 }
1051
1052 for (std::vector<atomId_t>::const_iterator iter = atoms.begin(); iter != atoms.end(); ++iter) {
1053 ASSERT(additionalAtomData.count(*iter) != 0,
1054 "FormatParser< tremolo >::processNeighborInformation() - global id "
1055 +toString(*iter)+" unknown in additionalAtomData.");
1056 TremoloAtomInfoContainer &currentInfo = additionalAtomData[*iter];
1057 currentInfo.imprData = adaptIdDependentDataString(currentInfo.imprData, idglobalizer);
1058 }
1059}
1060
1061/** Corrects the atom IDs in each torsion entry to the corresponding world IDs
1062 * as they might differ from the originally read IDs.
1063 *
1064 * \param atoms currently parsed in atoms
1065 */
1066void FormatParser< tremolo >::adaptTorsion(const std::vector<atomId_t> &atoms) {
1067 if (!isUsedField(usedFields_load, "torsion")) {
1068 return;
1069 }
1070
1071 for (std::vector<atomId_t>::const_iterator iter = atoms.begin(); iter != atoms.end(); ++iter) {
1072 ASSERT(additionalAtomData.count(*iter) != 0,
1073 "FormatParser< tremolo >::processNeighborInformation() - global id "
1074 +toString(*iter)+" unknown in additionalAtomData.");
1075 TremoloAtomInfoContainer &currentInfo = additionalAtomData[*iter];
1076 currentInfo.torsion = adaptIdDependentDataString(currentInfo.torsion, idglobalizer);
1077 }
1078}
1079
Note: See TracBrowser for help on using the repository browser.