Skip to content

Commit

Permalink
Implement unit exponents for scaled units such as d-1 (#7132)
Browse files Browse the repository at this point in the history
This resolves ticket:6345
  • Loading branch information
sjoelund committed Feb 4, 2021
1 parent 6b5a2f4 commit 0f96760
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 9 deletions.
5 changes: 3 additions & 2 deletions OMCompiler/Compiler/runtime/UnitParserExt_omc.cpp
Expand Up @@ -46,8 +46,9 @@ void UnitParserExt_str2unit(const char *inStr, void **nums, void **denoms, void
Unit unit;
UnitRes res = unitParser->str2unit(str,unit);
if (!res.Ok()) {
const char* tokens[1] = {str.c_str()};
c_add_message(NULL,-1, ErrorType_scripting, ErrorLevel_error, gettext("error parsing unit %s"), tokens, 1);
string errmsg = res.toString();
const char* tokens[2] = {errmsg.c_str(),str.c_str()};
c_add_message(NULL,-1, ErrorType_scripting, ErrorLevel_error, gettext("Error parsing unit %s: %s"), tokens, 2);
MMC_THROW();
}

Expand Down
52 changes: 48 additions & 4 deletions OMCompiler/Compiler/runtime/unitparser.cpp
Expand Up @@ -46,6 +46,27 @@

#endif

string UnitRes::toString()
{
switch (result) {
case UNIT_OK: return "OK";
case UNKNOWN_TOKEN: return "Unknown token";
case UNKNOWN_IDENT: return "Unknown ident";
case PARSE_ERROR: return "Parse error";
case UNIT_OFFSET_ERROR: return "Offset error";
case UNIT_EXPONENT_NOT_INT: return "Exponent is not an integer";
case UNIT_WRONG_BASE: return "Wrong base";
case UNIT_NOT_FOUND: return "Unit not found";
case PREFIX_NOT_FOUND: return "Prefix not found";
case INVALID_INT: return "Invalid integer";
case PREFIX_NOT_ALLOWED: return "Prefix not allowed";
case BASE_ALREADY_DEFINED: return "Base already defined";
case ERROR_ADDING_UNIT: return "Error adding unit";
case UNITS_DEFINED_WITH_DIFFERENT_EXPR:
default: return "Unknown error";
}
}

/***************************************************************************************/
/* CLASS: Rational */
/***************************************************************************************/
Expand Down Expand Up @@ -128,6 +149,29 @@ Rational Rational::div(Rational q1, Rational q2) {
return simplify(Rational(q1.num * q2.denom, q1.denom * q2.num));
}

static mmc_sint_t powint64(mmc_sint_t base, mmc_sint_t exp) {
int res = 1;
while (exp) {
if (exp & 1) {
res *= base;
}
exp >>= 1;
base *= base;
}
return res;
}

Rational Rational::pow(Rational q1, Rational q2) {
if (q2.denom != 1) {
MMC_THROW();
}
if (q2.num < 0) {
return simplify(Rational(powint64(q1.denom, -q2.num), powint64(q1.num, -q2.num)));
} else {
return simplify(Rational(powint64(q1.num, q2.num), powint64(q1.denom, q2.num)));
}
}

Rational Rational::simplify(const Rational q) {
mmc_sint_t gcd = Rational::gcd(q.num, q.denom);
Rational q2(Rational(q.num / gcd, q.denom / gcd));
Expand Down Expand Up @@ -221,11 +265,12 @@ UnitRes Unit::pow(Unit u, const Rational e, Unit& ur) {
if (!u.offset.isZero())
return UnitRes(UnitRes::UNIT_OFFSET_ERROR);

if (!u.scaleFactor.is(1))
return UnitRes(UnitRes::UNIT_SCALE_ERROR);
if (e.denom != 1)
return UnitRes(UnitRes::UNIT_EXPONENT_NOT_INT);

ur = u;
ur.prefixExpo = Rational::mul(u.prefixExpo, e);
ur.scaleFactor = Rational::pow(u.scaleFactor, e);
ur.unitVec.clear();
for (unsigned int i = 0; i < u.unitVec.size(); i++) {
ur.unitVec.push_back(Rational::mul(u.unitVec[i], e));
Expand Down Expand Up @@ -916,8 +961,7 @@ UnitRes UnitParser::parseFactor(Scanner& scan, Unit& unit) {
scan.setpos(scanpostemp);
return UnitRes(UnitRes::UNIT_OK);
} else {
Unit::pow(u1, q, unit);
return UnitRes(UnitRes::UNIT_OK);
res = Unit::pow(u1, q, unit);
return res;
}

Expand Down
4 changes: 3 additions & 1 deletion OMCompiler/Compiler/runtime/unitparser.h
Expand Up @@ -61,6 +61,7 @@ class Rational{
static Rational add(Rational q1, Rational q2);
static Rational mul(Rational q1, Rational q2);
static Rational div(Rational q1, Rational q2);
static Rational pow(Rational q1, Rational q2);
static mmc_sint_t gcd(mmc_sint_t a, mmc_sint_t b);

};
Expand All @@ -75,7 +76,7 @@ struct UnitRes{
UNKNOWN_IDENT,
PARSE_ERROR,
UNIT_OFFSET_ERROR,
UNIT_SCALE_ERROR,
UNIT_EXPONENT_NOT_INT,
UNIT_WRONG_BASE, //Need to be base 10 for exponent prefixes
UNIT_NOT_FOUND,
PREFIX_NOT_FOUND,
Expand All @@ -93,6 +94,7 @@ struct UnitRes{
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
string toString();
};

class Unit{
Expand Down
7 changes: 5 additions & 2 deletions testsuite/openmodelica/interactive-API/ConvertUnits.mos
Expand Up @@ -9,6 +9,7 @@ convertUnits("degF","degC");getErrorString();
convertUnits("K","Unknown");getErrorString();
convertUnits("Pa","mmHg");getErrorString();
convertUnits("m3/Pa","ml/mmHg");getErrorString();
convertUnits("s-1","d-1");getErrorString();

getDerivedUnits("K");getErrorString();
getDerivedUnits("W");getErrorString();
Expand All @@ -27,19 +28,21 @@ getDerivedUnits("n");getErrorString();
// (true,1.8,31.99999999999994)
// ""
// (false,1.0,0.0)
// "Error: error parsing unit Unknown
// "Error: Error parsing unit Unknown: Prefix not found
// "
// (true,133.322387415,0.0)
// ""
// (true,7.500615758456563e-09,0.0)
// ""
// (true,1.157407407407407e-05,0.0)
// ""
// {"degC","degF","degRk"}
// ""
// {"VA","var"}
// ""
// {"bar","inWG","mmHg","psi"}
// ""
// {}
// "Error: error parsing unit n
// "Error: Error parsing unit n: Unit not found
// "
// endResult

0 comments on commit 0f96760

Please sign in to comment.