author | cniehaus <cniehaus> | 2002-09-15 14:02:04 (UTC) |
---|---|---|
committer | cniehaus <cniehaus> | 2002-09-15 14:02:04 (UTC) |
commit | ffb701b9a482ca30eda8901506c0c39ad8461e4c (patch) (unidiff) | |
tree | 82fa34a6083a48c877f4a7b41c15672832095fbb /noncore/apps/checkbook/kmolcalc.cpp | |
parent | d01f8da912a2bed9de1943d174ec10dba505bf38 (diff) | |
download | opie-ffb701b9a482ca30eda8901506c0c39ad8461e4c.zip opie-ffb701b9a482ca30eda8901506c0c39ad8461e4c.tar.gz opie-ffb701b9a482ca30eda8901506c0c39ad8461e4c.tar.bz2 |
Ok, this is what I have so far. I know it is not really working thus it is
not in the toplevel-Makefile. I am putting as much work in it as possible.
Currently I am doing the kmol-port, after that the PSE-stuff.
Diffstat (limited to 'noncore/apps/checkbook/kmolcalc.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | noncore/apps/checkbook/kmolcalc.cpp | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/noncore/apps/checkbook/kmolcalc.cpp b/noncore/apps/checkbook/kmolcalc.cpp new file mode 100644 index 0000000..e5ab736 --- a/dev/null +++ b/noncore/apps/checkbook/kmolcalc.cpp | |||
@@ -0,0 +1,233 @@ | |||
1 | /* | ||
2 | * kmolcalc.cpp | ||
3 | * | ||
4 | * Copyright (C) 2000 Tomislav Gountchev <tomi@idiom.com> | ||
5 | */ | ||
6 | |||
7 | /** | ||
8 | * KMOLCALC is the calculation engine. It knows about a hashtable of user defined atomic | ||
9 | * weights and group definitions ELSTABLE, and the currently processed formula, stored | ||
10 | * as a list of elements and their coefficients, ELEMENTS. | ||
11 | */ | ||
12 | |||
13 | #include "kmolcalc.h" | ||
14 | #include <qdict.h> | ||
15 | #include <qdir.h> | ||
16 | #include <iostream.h> | ||
17 | |||
18 | |||
19 | /** | ||
20 | * Construct a new calculator object. | ||
21 | */ | ||
22 | KMolCalc::KMolCalc() { | ||
23 | elements = new ElementList; | ||
24 | elstable = NULL; | ||
25 | readElstable(); | ||
26 | } | ||
27 | |||
28 | KMolCalc::~KMolCalc() { | ||
29 | delete elements; | ||
30 | } | ||
31 | |||
32 | void KMolCalc::readElstable() { | ||
33 | weight = -1; // not calculated yet | ||
34 | if (elstable) delete elstable; | ||
35 | elstable = new QDict<SubUnit> (197, TRUE); | ||
36 | elstable->setAutoDelete(TRUE); | ||
37 | QStringList files;// = // KGlobal::dirs()->findAllResources("appdata", "kmolweights"); | ||
38 | // mwfile = locateLocal("data", "kmol")+"/kmolweights"; | ||
39 | QFile f(mwfile); | ||
40 | QString* latest_f = &mwfile; | ||
41 | for (uint i=0; i<files.count(); i++) { | ||
42 | if (QFileInfo(QFile(files[i])).lastModified() > QFileInfo(QFile(*latest_f)).lastModified()) { | ||
43 | latest_f = &files[i]; | ||
44 | } | ||
45 | } | ||
46 | QFile lf(*latest_f); | ||
47 | if (f.exists()) readMwfile(f); | ||
48 | if (!f.exists()) { | ||
49 | readMwfile(lf); | ||
50 | writeElstable(); | ||
51 | } else if (QFileInfo(f).lastModified() < QFileInfo(lf).lastModified()) { | ||
52 | // announce | ||
53 | QMessageBox::information | ||
54 | (0, "Warning:", "Found new global Mw file.\nLocal definitions will be updated.", QMessageBox::Ok); | ||
55 | readMwfile(lf); | ||
56 | writeElstable(); | ||
57 | } | ||
58 | |||
59 | } | ||
60 | |||
61 | |||
62 | /** | ||
63 | * Parse a string S and construct the ElementList this->ELEMENTS, representing the | ||
64 | * composition of S. Returns 0 if successful, or an error code (currently -1) if | ||
65 | * parsing failed. | ||
66 | * The elements is S must be valid element or group symbols, as stored in this->ELSTABLE. | ||
67 | * See help files for correct formula syntax. | ||
68 | */ | ||
69 | QString KMolCalc::readFormula(const QString& s) { | ||
70 | weight = -1; | ||
71 | if (elements) delete elements; | ||
72 | elements = new ElementList; | ||
73 | return KMolCalc::readGroup(s, elements); | ||
74 | } | ||
75 | |||
76 | // read a formula group recursively. Called by readFormula. | ||
77 | QString KMolCalc::readGroup(const QString& s, ElementList* els) { | ||
78 | if (s.isEmpty()) return QString ("Enter a formula."); //ERROR | ||
79 | int sl = s.length(); | ||
80 | int i = 0; | ||
81 | QString errors ("OK"); | ||
82 | bool ok = TRUE; | ||
83 | while (i < sl && ((s[i] <= '9' && s[i] >= '0') || s[i] == '.')) i++; | ||
84 | double prefix = (i == 0 ? 1 : s.left(i).toDouble(&ok)); | ||
85 | if (! ok || i == sl || prefix == 0) return QString ("Bad formula."); // ERROR | ||
86 | ElementList* elstemp = new ElementList; | ||
87 | while (i < sl) { | ||
88 | int j = i; | ||
89 | if (s[i] == '(') { | ||
90 | ElementList* inner = new ElementList; | ||
91 | int level = 1; // count levels of nested ( ). | ||
92 | while (1) { | ||
93 | if (i++ == sl) { | ||
94 | delete inner; | ||
95 | delete elstemp; | ||
96 | return QString ("Bad formula."); //ERROR | ||
97 | } | ||
98 | if (s[i] == '(') level++; | ||
99 | if (s[i] == ')') level--; | ||
100 | if (level == 0) break; | ||
101 | } | ||
102 | errors = KMolCalc::readGroup(s.mid(j+1, i-j-1), inner); | ||
103 | j = ++i; | ||
104 | while (i < sl && ((s[i] <= '9' && s[i] >= '0') || s[i] == '.')) i++; | ||
105 | double suffix = (i == j ? 1 : s.mid(j, i-j).toDouble(&ok)); | ||
106 | if (! ok || suffix == 0) { | ||
107 | delete inner; | ||
108 | delete elstemp; | ||
109 | return QString ("Bad formula."); // ERROR | ||
110 | } | ||
111 | inner->addTo(*elstemp, suffix); | ||
112 | delete inner; | ||
113 | inner = NULL; | ||
114 | } else if ((s[i] >= 'A' && s[i] <= 'Z') || (s[i] >= 'a' && s[i] <= 'z')) { | ||
115 | while (++i < sl && ((s[i] >= 'a' && s[i] <= 'z') || s[i] == '*' || | ||
116 | s[i] == '\'')); | ||
117 | QString elname = s.mid(j, i-j); | ||
118 | j = i; | ||
119 | while (i < sl && ((s[i] <= '9' && s[i] >= '0') || s[i] == '.')) i++; | ||
120 | double suffix = (i == j ? 1 : s.mid(j, i-j).toDouble(&ok)); | ||
121 | if (! ok || suffix == 0) { | ||
122 | delete elstemp; | ||
123 | return QString ("Bad formula."); // ERROR | ||
124 | } | ||
125 | SubUnit* group = elstable->find(elname); | ||
126 | if (group == 0) { | ||
127 | delete elstemp; | ||
128 | return QString ("Undefined symbol: ") + elname; //ERROR | ||
129 | } | ||
130 | group->addTo(*elstemp, suffix); | ||
131 | } else if (s[i] == '+') { | ||
132 | if (elstemp->isEmpty()) { | ||
133 | delete elstemp; | ||
134 | return QString ("Bad formula."); //ERROR | ||
135 | } | ||
136 | elstemp->addTo(*els, prefix); | ||
137 | delete elstemp; | ||
138 | errors = KMolCalc::readGroup(s.mid(i+1, sl-i-1), els); | ||
139 | return errors; | ||
140 | } else { | ||
141 | delete elstemp; | ||
142 | return QString ("Bad formula."); //ERROR | ||
143 | } | ||
144 | } | ||
145 | elstemp->addTo(*els, prefix); | ||
146 | delete elstemp; | ||
147 | return errors; | ||
148 | } | ||
149 | |||
150 | /** | ||
151 | * Calculate and return the molecular weight of the current chemical formula. | ||
152 | */ | ||
153 | double KMolCalc::getWeight() { | ||
154 | if (weight == -1) weight = elements->getWeight(elstable); | ||
155 | return weight; | ||
156 | } | ||
157 | |||
158 | /** | ||
159 | * Return the elemental composition of the current formula, as a string of tab-separated | ||
160 | * element - percentage pairs, separated by newlines. | ||
161 | */ | ||
162 | QString KMolCalc::getEA() { | ||
163 | if (weight == -1) weight = elements->getWeight(elstable); | ||
164 | if (weight == -1) return QString("ERROR: Couldn't get Mw..."); // ERROR | ||
165 | return elements->getEA(elstable, weight); | ||
166 | } | ||
167 | |||
168 | /** | ||
169 | * Return the empirical formula of the current compound as a QString. | ||
170 | */ | ||
171 | QString KMolCalc::getEmpFormula() { | ||
172 | return elements->getEmpFormula(); | ||
173 | } | ||
174 | |||
175 | // Read the element definition file. | ||
176 | void KMolCalc::readMwfile(QFile& f) { | ||
177 | if (! f.open(IO_ReadOnly)) return; //ERROR | ||
178 | QTextStream fs (&f); | ||
179 | QString line; | ||
180 | while (! fs.eof()) { | ||
181 | line = fs.readLine(); | ||
182 | SubUnit* s = SubUnit::makeSubUnit(line); | ||
183 | elstable->replace(s->getName(), s); | ||
184 | } | ||
185 | f.close(); | ||
186 | } | ||
187 | |||
188 | /** | ||
189 | * Save the element definitions file. | ||
190 | */ | ||
191 | void KMolCalc::writeElstable() { | ||
192 | QFile f(mwfile); | ||
193 | if (! f.open(IO_WriteOnly)) return; //ERROR | ||
194 | QTextStream fs (&f); | ||
195 | QString line; | ||
196 | QDictIterator<SubUnit> it(*elstable); | ||
197 | while (it.current()) { | ||
198 | it.current()->writeOut(line); | ||
199 | fs << line << endl; | ||
200 | ++it; | ||
201 | } | ||
202 | f.close(); | ||
203 | } | ||
204 | |||
205 | /** | ||
206 | * Remove a group or element definition from ELSTABLE. | ||
207 | */ | ||
208 | void KMolCalc::undefineGroup (const QString& name) { | ||
209 | elstable->remove (name); | ||
210 | } | ||
211 | |||
212 | /** | ||
213 | * Add a new element name - atomic weight record to the ELSTABLE hashtable. Assumes | ||
214 | * NAME has valid syntax. | ||
215 | |||
216 | */ | ||
217 | void KMolCalc::defineElement (const QString& name, double weight) { | ||
218 | Element* el = new Element(name, weight); | ||
219 | elstable->replace(name, el); | ||
220 | } | ||
221 | |||
222 | /** | ||
223 | * Add a new group definition to the ELSTABLE. Returns 0 if OK, -1 if parsing FORMULA | ||
224 | * fails. Assumes the syntax of grpname is correct. | ||
225 | */ | ||
226 | QString KMolCalc::defineGroup (const QString& grpname, const QString& formula) { | ||
227 | ElementList* els = new ElementList(grpname); | ||
228 | QString error = readGroup(formula, els); | ||
229 | if (error != "OK") return error; | ||
230 | if (els->contains(grpname)) return QString("Can't define a group recursively!\n"); | ||
231 | elstable->replace(grpname, els); | ||
232 | return QString("OK"); | ||
233 | } | ||