-
Notifications
You must be signed in to change notification settings - Fork 298
/
unitparser.h
328 lines (248 loc) · 10 KB
/
unitparser.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
/*
* This file is part of OpenModelica.
*
* Copyright (c) 1998-2010, Linköpings University,
* Department of Computer and Information Science,
* SE-58183 Linköping, Sweden.
*
* All rights reserved.
*
* THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THIS OSMC PUBLIC
* LICENSE (OSMC-PL). ANY USE, REPRODUCTION OR DISTRIBUTION OF
* THIS PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THE OSMC
* PUBLIC LICENSE.
*
* The OpenModelica software and the Open Source Modelica
* Consortium (OSMC) Public License (OSMC-PL) are obtained
* from Linköpings University, either from the above address,
* from the URL: http://www.ida.liu.se/projects/OpenModelica
* and in the OpenModelica distribution.
*
* This program is distributed WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
* IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS
* OF OSMC-PL.
*
* See the full OSMC Public License conditions for more details.
*
*/
#ifndef _UNITPARSER_H
#define _UNITPARSER_H
#include <vector>
#include <string>
#include <map>
#include <list>
#include <set>
#include "util/omc_msvc.h" /* For round() */
#include "meta/meta_modelica.h"
using namespace std;
class Rational{
public:
Rational(mmc_sint_t numerator=0, mmc_sint_t denominator=1);
Rational(const Rational& r);
virtual ~Rational(){;}
mmc_sint_t num; //numerator
mmc_sint_t denom; //denominator
bool isZero();
bool is(mmc_sint_t numerator, mmc_sint_t denominator=1);
string toString(); //e.g. "(7/9)". If denominator is one, only numerator is printed, e.g. "7".
double toReal();
void rationalize(double r);
void fixsign();
bool equal(Rational r) {return r.num==num && r.denom==denom;}
static Rational simplify(const Rational q);
static Rational sub(Rational q1, Rational q2);
static Rational add(Rational q1, Rational q2);
static Rational mul(Rational q1, Rational q2);
static Rational div(Rational q1, Rational q2);
static mmc_sint_t gcd(mmc_sint_t a, mmc_sint_t b);
};
struct UnitRes{
UnitRes() : result(UNIT_OK), charNo(0) {;}
enum ResVal{
UNIT_OK,
UNKNOWN_TOKEN,
UNKNOWN_IDENT,
PARSE_ERROR,
UNIT_OFFSET_ERROR,
UNIT_SCALE_ERROR,
UNIT_WRONG_BASE, //Need to be base 10 for exponent prefixes
UNIT_NOT_FOUND,
PREFIX_NOT_FOUND,
INVALID_INT,
PREFIX_NOT_ALLOWED, //Some units e.g. "kg" are not allowed to have prefix. See SI-brochure v8, page 122, sec. 3.2
BASE_ALREADY_DEFINED,
ERROR_ADDING_UNIT,
UNITS_DEFINED_WITH_DIFFERENT_EXPR
};
UnitRes(ResVal res, unsigned int charNumber = 0) : result(res), charNo(charNumber) {;}
virtual ~UnitRes(){;}
bool Ok() {return result == UNIT_OK;}
ResVal result; //Result enum
unsigned int charNo; //If error, charcter number in string where the error is
string message; //String message. E.g. for UNKNOWN_IDENT, the identifier is given
};
class Unit{
public:
Unit(mmc_sint_t pExp=0, mmc_sint_t sFact=1, mmc_sint_t off=0,double w = 1.0,bool b=false) :
prefixExpo(Rational(pExp)), scaleFactor(Rational(sFact)), offset(Rational(off)), prefixAllowed(true), weight(w) {;}
/** Vector stating exponents to the unit vector */
vector<Rational> unitVec;
/** Exponent value for the prefix. E.g. if [mm] is defined, it is 10^-3*[m], e.g. prefixExpo = -3 */
Rational prefixExpo;
/** Scalar factor including both SI prefix and unit scalar factors (e.g. feet -> meter) */
Rational scaleFactor;
/** Offset to base unit. E.g. celcius have offset 273.15 (i.e. add 273.15 to the value to get it in Kelvin) */
Rational offset;
/** Unit type parameter vector. The strings include a prepend apostrophe ,e.g. "'p" */
map<string,Rational> typeParamVec;
/** The quantity name, if known. */
string quantityName;
/** The unit name, if known. */
string unitName;
/** The unit symbol, if known. */
string unitSymbol;
/* Returns true if both the unitVec only contains zero exponents, and there are no type parameters */
bool isDimensionless();
/* Returns true if the unit is a base unit. If it is a derived unit, false is returned. */
bool isBaseUnit();
/** Internal variable for handling kg units */
bool prefixAllowed;
/** Weight used for pretty printing algorithm */
double weight;
/* Division of two unit vectors */
static UnitRes div(Unit u1, Unit u2, Unit& ur);
/* Multiplication of two unit vectors */
static UnitRes mul(Unit u1, Unit u2, Unit& ur);
/* Exponent power on a unit vector */
static UnitRes pow(Unit u, const Rational e, Unit& ur);
/** Checks if the unit is equal to another unit, without comparing weights */
bool equalNoWeight(const Unit& u);
private:
static UnitRes paramutil(Unit u1, Unit u2, Unit& ur, bool mulop);
};
class Base{
public:
Base(string q, string un, string us, bool p, double w=1.0) : quantityName(q),
unitName(un), unitSymbol(us), prefixAllowed(p),weight(w) {;}
string quantityName;
string unitName;
string unitSymbol;
bool prefixAllowed;
double weight /*weight for pretty printing algorithm*/;
};
/* Scanner for a unit type string */
class Scanner{
public:
Scanner(string str);
virtual ~Scanner();
enum TokenType{
TOK_DIV, //Div '/'
TOK_LPARAN, //Left parentheses '('
TOK_RPARAN, //Right parantheses ')'
TOK_DOT, //Dot character '.'
TOK_EXPO, //Exponent '^'
TOK_ID, //Identfier starting with only ascii characters. tokstr contains the string.
TOK_PARAM, //Unit type parameter. An identifier starting with an apostrophe. tokstr contains the string.
TOK_INT, //Integer. tokstr contains the string representation of the integer value.
TOK_UNKNOWN, //Unknown token
TOK_EOS, //End of string
};
/* Returns the next token in the string, or TOK_EOF if it is the last one.
If the token consist of a specific string 'tokstr'. If TOK_UNKNOWN is returned,
method getPos() can be called to get the integer index to the unknown token */
TokenType getToken(string& tokstr);
TokenType peekToken(string& tokstr);
unsigned int getPos();
unsigned int getLastPos();
bool isTextChar(unsigned int i);
bool isEOS(unsigned int i);
bool isDigit(unsigned int i);
unsigned int getpos() {return _index;}
void setpos(unsigned int pos) {_index = pos;}
bool finished();
private:
Scanner::TokenType getTokenInternal(string& tokstr, unsigned int& index);
string _str;
unsigned int _index;
unsigned int _lastindex;
};
class DerivedInfo{
public:
DerivedInfo(string qn, string un, string usym, string ustr, Rational pe, Rational sf, Rational o, bool pa, double w)
: quantityName(qn), unitName(un), unitSymbol(usym), unitStrExp(ustr), prefixExpo(pe), scaleFactor(sf),
offset(o),prefixAllowed(pa), weight(w) {;}
string quantityName;
string unitName;
string unitSymbol;
string unitStrExp;
Rational prefixExpo;
Rational scaleFactor;
Rational offset;
bool prefixAllowed;
double weight;
};
class UnitParser{
public:
UnitParser();
virtual ~UnitParser();
/** Add prefix symbols. E.g. "m" has exponent -3, (m=10^-3) */
void addPrefix(const string symbol, Rational exponent);
void* allUnitSymbols();
/**
Add a base quantity/unit
@param prefixAllowed Normally set to true. Should be false for [kg], since we are not allowed to prefix this base unit.
Should instead prefix the "derived unit [g]
*/
void addBase(const string quantityName, const string unitName,
const string unitSymbol, bool prefixAllowed);
/** Add a derived quantity/unit */
void addDerived(const string quantityName, const string unitName, const string unitSymbol,
const string unitStrExp, Rational prefixExpo, Rational scaleFactor, Rational offset, bool prefixAllowed, double weight=1.0);
/** Multiply the weight factor to an existing unit symbol. If the symbol does not exist, nothing is updated */
void accumulateWeight(const string unitSymbol, double weight);
/** Call this method after adding all base and derived unit. */
UnitRes commit();
/** Convert a unit vector to a unit text string (unparse) */
string unit2str(Unit unit);
/** Convert a unit vector to a unit text string (unparse) - using MIP algorithm to select most appropriate units */
string prettyPrintUnit2str(Unit unit);
/** Convert a unit text string to a unit vector type (parse) */
UnitRes str2unit(const string unitstr, Unit& unit);
/** Init prefixes without init units */
void initPrefixes();
/** Initiates the standard base and derived SI units according to the SI brochure, 8th edition, 2006*/
void initSIUnits();
private:
/** Add a derived quantity/unit */
UnitRes addDerivedInternal(const string quantityName, const string unitName, const string unitSymbol,
const string unitStrExp, Rational prefixExpo, Rational scaleFactor, Rational offset, bool prefixAllowed, double weight);
/** Prefixes */
map<string,Rational> _prefix;
/** A temp cash of the derived unit */
list<DerivedInfo> _tempDerived;
/** Base quantities and units(vector of names) */
vector<Base> _base;
/** Mapping from unit symbol to unit definitions. Includes both base and derived units. */
map<string,Unit> _units;
/* Set to keep track of which derived units have already been visisted in the minimizeDerivedUnits method*/
set<int> _derivedUnitsVisited;
/** Parse */
UnitRes parseExpression(Scanner& scan, Unit& unit);
UnitRes parseNumerator(Scanner& scan, Unit& unit);
UnitRes parseDenominator(Scanner& scan, Unit& unit);
UnitRes parseFactors(Scanner& scan, Unit& unit);
UnitRes parseFactor(Scanner& scan, Unit& unit);
UnitRes parseSymbol(Scanner& scan, Unit& unit);
UnitRes parseRational(Scanner& scan, Rational& q);
/* MIP */
Unit solveMIP(Unit,bool innerCall=false);
/* Help function to MIP */
Unit minimizeDerivedUnits(Unit unit,Unit origUnit,double factor);
void increaseNthUnitWeight(int indx,double factor);
void resetNthUnitWeight(int indx,double factor);
int actualNumDerived(Unit unit);
};
extern void TestScanner();
#endif /* _UNITPARSER_H */