source: src/Formula.cpp@ d9f51c

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since d9f51c was 38e075, checked in by Tillmann Crueger <crueger@…>, 15 years ago

Added one more error condition for formula parsing

  • Property mode set to 100644
File size: 14.2 KB
Line 
1/*
2 * Formula.cpp
3 *
4 * Created on: Jul 21, 2010
5 * Author: crueger
6 */
7
8#include "Formula.hpp"
9
10#include <sstream>
11
12#include "World.hpp"
13#include "periodentafel.hpp"
14#include "element.hpp"
15#include "Helpers/Assert.hpp"
16#include "Helpers/Range.hpp"
17
18using namespace std;
19
20Formula::Formula() :
21 numElements(0)
22{}
23
24Formula::Formula(const Formula &src) :
25 elementCounts(src.elementCounts),
26 numElements(src.numElements)
27{}
28
29Formula::Formula(const string &formula) :
30 numElements(0)
31{
32 fromString(formula);
33}
34
35Formula::~Formula()
36{}
37
38Formula &Formula::operator=(const Formula &rhs){
39 // No self-assignment check needed
40 elementCounts=rhs.elementCounts;
41 numElements=rhs.numElements;
42 return *this;
43}
44
45std::string Formula::toString() const{
46 stringstream sstr;
47 for(const_iterator iter=end();iter!=begin();){
48 --iter;
49 sstr << (*iter).first->symbol;
50 if((*iter).second>1)
51 sstr << (*iter).second;
52 }
53 return sstr.str();
54}
55
56void Formula::fromString(const std::string &formula) throw(ParseError){
57 // make this transactional, in case an error is thrown
58 Formula res;
59 string::const_iterator begin = formula.begin();
60 string::const_iterator end = formula.end();
61 res.parseFromString(begin,end,static_cast<char>(0));
62 (*this)=res;
63}
64
65int Formula::parseMaybeNumber(string::const_iterator &it,string::const_iterator &end) throw(ParseError){
66 static const range<char> Numbers = makeRange('0',static_cast<char>('9'+1));
67 int count = 0;
68 while(it!=end && Numbers.isInRange(*it))
69 count = (count*10) + ((*it++)-Numbers.first);
70 // one is implicit
71 count = (count!=0)?count:1;
72 return count;
73}
74
75void Formula::parseFromString(string::const_iterator &it,string::const_iterator &end,char delimiter) throw(ParseError){
76 // some constants needed for parsing... Assumes ASCII, change if other encodings are used
77 static const range<char> CapitalLetters = makeRange('A',static_cast<char>('Z'+1));
78 static const range<char> SmallLetters = makeRange('a',static_cast<char>('z'+1));
79 map<char,char> delimiters;
80 delimiters['('] = ')';
81 delimiters['['] = ']';
82 // clean the formula
83 clear();
84 for(/*send from above*/;it!=end && *it!=delimiter;/*updated in loop*/){
85 // we might have a sub formula
86 if(delimiters.count(*it)){
87 Formula sub;
88 char nextdelim=delimiters[*it];
89 sub.parseFromString(++it,end,nextdelim);
90 if(!sub.getElementCount()){
91 throw(ParseError(__FILE__,__LINE__));
92 }
93 int count = parseMaybeNumber(++it,end);
94 addFormula(sub,count);
95 continue;
96 }
97 string shorthand;
98 // Atom names start with a capital letter
99 if(!CapitalLetters.isInRange(*it))
100 throw(ParseError(__FILE__,__LINE__));
101 shorthand+=(*it++);
102 // the rest of the name follows
103 while(it!=end && SmallLetters.isInRange(*it))
104 shorthand+=(*it++);
105 int count = parseMaybeNumber(it,end);
106 // test if the shorthand exists
107 if(!World::getInstance().getPeriode()->FindElement(shorthand))
108 throw(ParseError(__FILE__,__LINE__));
109 // done, we can get the next one
110 addElements(shorthand,count);
111 }
112 if(it==end && delimiter!=0){
113 throw(ParseError(__FILE__,__LINE__));
114 }
115}
116
117bool Formula::checkOut(ostream *output) const{
118 bool result = true;
119 int No = 1;
120
121 if (output != NULL) {
122 *output << "# Ion type data (PP = PseudoPotential, Z = atomic number)" << endl;
123 *output << "#Ion_TypeNr.\tAmount\tZ\tRGauss\tL_Max(PP)L_Loc(PP)IonMass\t# chemical name, symbol" << endl;
124 for(const_iterator iter=begin(); iter!=end();++iter){
125 (*iter).first->No = No;
126 result = result && (*iter).first->Checkout(output, No++, (*iter).second);
127 }
128 return result;
129 } else
130 return false;
131}
132
133unsigned int Formula::getElementCount() const{
134 return numElements;
135}
136
137bool Formula::hasElement(const element *element) const{
138 ASSERT(element,"Invalid pointer in Formula::hasElement(element*)");
139 return hasElement(element->getNumber());
140}
141
142bool Formula::hasElement(atomicNumber_t Z) const{
143 ASSERT(Z>0,"Invalid atomic Number");
144 ASSERT(World::getInstance().getPeriode()->FindElement(Z),"No Element with this number in Periodentafel");
145 return elementCounts.size()>=Z && elementCounts[Z-1];
146}
147
148bool Formula::hasElement(const string &shorthand) const{
149 element * element = World::getInstance().getPeriode()->FindElement(shorthand);
150 return hasElement(element);
151}
152
153void Formula::operator+=(const element *element){
154 ASSERT(element,"Invalid pointer in increment of Formula");
155 operator+=(element->getNumber());
156}
157
158void Formula::operator+=(atomicNumber_t Z){
159 ASSERT(Z>0,"Invalid atomic Number");
160 ASSERT(World::getInstance().getPeriode()->FindElement(Z),"No Element with this number in Periodentafel");
161 elementCounts.resize(max<atomicNumber_t>(Z,elementCounts.size()),0); // No-op when we already have the right size
162 // might need to update number of elements
163 if(!elementCounts[Z-1]){
164 numElements++;
165 }
166 elementCounts[Z-1]++; // atomic numbers start at 1
167}
168
169void Formula::operator+=(const string &shorthand){
170 element * element = World::getInstance().getPeriode()->FindElement(shorthand);
171 operator+=(element);
172}
173
174void Formula::operator-=(const element *element){
175 ASSERT(element,"Invalid pointer in decrement of Formula");
176 operator-=(element->getNumber());
177}
178
179void Formula::operator-=(atomicNumber_t Z){
180 ASSERT(Z>0,"Invalid atomic Number");
181 ASSERT(World::getInstance().getPeriode()->FindElement(Z),"No Element with this number in Periodentafel");
182 ASSERT(elementCounts.size()>=Z && elementCounts[Z-1], "Element not in Formula upon decrement");
183 elementCounts[Z-1]--; // atomic numbers start at 1
184 // might need to update number of elements
185 if(!elementCounts[Z-1]){
186 numElements--;
187 // resize the Array if this was at the last position
188 if(Z==elementCounts.size()){
189 // find the first element from the back that is not equal to zero
190 set_t::reverse_iterator riter = find_if(elementCounts.rbegin(),
191 elementCounts.rend(),
192 bind1st(not_equal_to<mapped_type>(),0));
193 // see how many elements are in this range
194 set_t::reverse_iterator::difference_type diff = riter - elementCounts.rbegin();
195 elementCounts.resize(elementCounts.size()-diff);
196 }
197 }
198}
199
200void Formula::operator-=(const string &shorthand){
201 element * element = World::getInstance().getPeriode()->FindElement(shorthand);
202 operator-=(element);
203}
204
205void Formula::addElements(const element *element,unsigned int count){
206 ASSERT(element,"Invalid pointer in Formula::addElements(element*)");
207 addElements(element->getNumber(),count);
208}
209
210void Formula::addElements(atomicNumber_t Z,unsigned int count){
211 if(count==0) return;
212 ASSERT(Z>0,"Invalid atomic Number");
213 ASSERT(World::getInstance().getPeriode()->FindElement(Z),"No Element with this number in Periodentafel");
214 elementCounts.resize(max<atomicNumber_t>(Z,elementCounts.size()),0); // No-op when we already have the right size
215 // might need to update number of elements
216 if(!elementCounts[Z-1]){
217 numElements++;
218 }
219 elementCounts[Z-1]+=count;
220}
221
222void Formula::addElements(const string &shorthand,unsigned int count){
223 element * element = World::getInstance().getPeriode()->FindElement(shorthand);
224 addElements(element,count);
225}
226
227void Formula::addFormula(const Formula &formula,unsigned int n){
228 for(Formula::const_iterator iter=formula.begin();iter!=formula.end();++iter){
229 this->addElements(iter->first,iter->second*n);
230 }
231}
232
233const unsigned int Formula::operator[](const element *element) const{
234 ASSERT(element,"Invalid pointer in access of Formula");
235 return operator[](element->getNumber());
236}
237
238const unsigned int Formula::operator[](atomicNumber_t Z) const{
239 ASSERT(Z>0,"Invalid atomic Number");
240 ASSERT(World::getInstance().getPeriode()->FindElement(Z),"No Element with this number in Periodentafel");
241 if(elementCounts.size()<Z)
242 return 0;
243 return elementCounts[Z-1]; // atomic numbers start at 1
244}
245
246const unsigned int Formula::operator[](string shorthand) const{
247 element * element = World::getInstance().getPeriode()->FindElement(shorthand);
248 return operator[](element);
249}
250
251bool Formula::operator==(const Formula &rhs) const{
252 // quick check... number of elements used
253 if(numElements != rhs.numElements){
254 return false;
255 }
256 // second quick check, size of vectors (== last element in formula)
257 if(elementCounts.size()!=rhs.elementCounts.size()){
258 return false;
259 }
260 // slow check: all elements
261 // direct access to internal structure means all element-counts have to be compared
262 // this avoids access to periodentafel to find elements though and is probably faster
263 // in total
264 return equal(elementCounts.begin(),
265 elementCounts.end(),
266 rhs.elementCounts.begin());
267}
268
269bool Formula::operator!=(const Formula &rhs) const{
270 return !operator==(rhs);
271}
272
273Formula::iterator Formula::begin(){
274 return iterator(elementCounts,0);
275}
276Formula::const_iterator Formula::begin() const{
277 // this is the only place where this is needed, so this is better than making it mutable
278 return const_iterator(const_cast<set_t&>(elementCounts),0);
279}
280Formula::iterator Formula::end(){
281 return iterator(elementCounts);
282}
283Formula::const_iterator Formula::end() const{
284 // this is the only place where this is needed, so this is better than making it mutable
285 return const_iterator(const_cast<set_t&>(elementCounts));
286}
287
288void Formula::clear(){
289 elementCounts.clear();
290 numElements = 0;
291}
292
293/**************** Iterator structure ********************/
294
295template <class result_type>
296Formula::_iterator<result_type>::_iterator(set_t &_set) :
297 set(&_set)
298{
299 pos=set->size();
300}
301
302template <class result_type>
303Formula::_iterator<result_type>::_iterator(set_t &_set,size_t _pos) :
304 set(&_set),pos(_pos)
305{
306 ASSERT(pos<=set->size(),"invalid position in iterator construction");
307 while(pos<set->size() && (*set)[pos]==0) ++pos;
308}
309
310template <class result_type>
311Formula::_iterator<result_type>::_iterator(const _iterator &rhs) :
312 set(rhs.set),pos(rhs.pos)
313{}
314
315template <class result_type>
316Formula::_iterator<result_type>::~_iterator(){}
317
318template <class result_type>
319Formula::_iterator<result_type>&
320Formula::_iterator<result_type>::operator=(const _iterator<result_type> &rhs){
321 set=rhs.set;
322 pos=rhs.pos;
323 return *this;
324}
325
326template <class result_type>
327bool
328Formula::_iterator<result_type>::operator==(const _iterator<result_type> &rhs){
329 return set==rhs.set && pos==rhs.pos;
330}
331
332template <class result_type>
333bool
334Formula::_iterator<result_type>::operator!=(const _iterator<result_type> &rhs){
335 return !operator==(rhs);
336}
337
338template <class result_type>
339Formula::_iterator<result_type>
340Formula::_iterator<result_type>::operator++(){
341 ASSERT(pos!=set->size(),"Incrementing Formula::iterator beyond end");
342 pos++;
343 while(pos<set->size() && (*set)[pos]==0) ++pos;
344 return *this;
345}
346
347template <class result_type>
348Formula::_iterator<result_type>
349Formula::_iterator<result_type>::operator++(int){
350 Formula::_iterator<result_type> retval = *this;
351 ++(*this);
352 return retval;
353}
354
355template <class result_type>
356Formula::_iterator<result_type>
357Formula::_iterator<result_type>::operator--(){
358 ASSERT(pos!=0,"Decrementing Formula::iterator beyond begin");
359 pos--;
360 while(pos>0 && (*set)[pos]==0) --pos;
361 return *this;
362}
363
364template <class result_type>
365Formula::_iterator<result_type>
366Formula::_iterator<result_type>::operator--(int){
367 Formula::_iterator<result_type> retval = *this;
368 --(*this);
369 return retval;
370}
371
372template <class result_type>
373result_type
374Formula::_iterator<result_type>::operator*(){
375 element *element = World::getInstance().getPeriode()->FindElement(pos+1);
376 ASSERT(element,"Element with position of iterator not found");
377 return make_pair(element,(*set)[pos]);
378}
379
380template <class result_type>
381result_type*
382Formula::_iterator<result_type>::operator->(){
383 // no one can keep this value around, so a static is ok to avoid temporaries
384 static value_type value=make_pair(reinterpret_cast<element*>(0),0); // no default constructor for std::pair
385 element *element = World::getInstance().getPeriode()->FindElement(pos+1);
386 ASSERT(element,"Element with position of iterator not found");
387 value = make_pair(element,(*set)[pos]);
388 return &value;
389}
390
391// explicit instantiation of all iterator template methods
392// this is quite ugly, but there is no better way unless we expose iterator implementation
393
394// instantiate Formula::iterator
395template Formula::iterator::_iterator(set_t&);
396template Formula::iterator::_iterator(set_t&,size_t);
397template Formula::iterator::_iterator(const Formula::iterator&);
398template Formula::iterator::~_iterator();
399template Formula::iterator &Formula::iterator::operator=(const Formula::iterator&);
400template bool Formula::iterator::operator==(const Formula::iterator&);
401template bool Formula::iterator::operator!=(const Formula::iterator&);
402template Formula::iterator Formula::iterator::operator++();
403template Formula::iterator Formula::iterator::operator++(int);
404template Formula::iterator Formula::iterator::operator--();
405template Formula::iterator Formula::iterator::operator--(int);
406template Formula::value_type Formula::iterator::operator*();
407template Formula::value_type *Formula::iterator::operator->();
408
409// instantiate Formula::const_iterator
410template Formula::const_iterator::_iterator(set_t&);
411template Formula::const_iterator::_iterator(set_t&,size_t);
412template Formula::const_iterator::_iterator(const Formula::const_iterator&);
413template Formula::const_iterator::~_iterator();
414template Formula::const_iterator &Formula::const_iterator::operator=(const Formula::const_iterator&);
415template bool Formula::const_iterator::operator==(const Formula::const_iterator&);
416template bool Formula::const_iterator::operator!=(const Formula::const_iterator&);
417template Formula::const_iterator Formula::const_iterator::operator++();
418template Formula::Formula::const_iterator Formula::const_iterator::operator++(int);
419template Formula::Formula::const_iterator Formula::const_iterator::operator--();
420template Formula::Formula::const_iterator Formula::const_iterator::operator--(int);
421template const Formula::value_type Formula::const_iterator::operator*();
422template const Formula::value_type *Formula::const_iterator::operator->();
423
424/********************** I/O of Formulas ************************************************/
425
426std::ostream &operator<<(std::ostream &ost,const Formula &formula){
427 ost << formula.toString();
428 return ost;
429}
Note: See TracBrowser for help on using the repository browser.