Skip to content

Commit

Permalink
Improve unit string handling in unit checker (#9446)
Browse files Browse the repository at this point in the history
- Evaluate the unit string expression in case it's not a literal string.
- Use the first element in case the unit string expression is an array,
  since that happens for array variables and we currently assume all
  array elements have the same unit.

Fixes #5685.
  • Loading branch information
perost committed Sep 28, 2022
1 parent 6de767e commit 6314a69
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 16 deletions.
53 changes: 37 additions & 16 deletions OMCompiler/Compiler/NFFrontEnd/NFUnitCheck.mo
Expand Up @@ -15,6 +15,7 @@ import FunctionTree = NFFlatten.FunctionTree;

protected
import ComponentRef = NFComponentRef;
import Ceval = NFCeval;
import ElementSource;
import Equation = NFEquation;
import ExecStat.execStat;
Expand Down Expand Up @@ -63,7 +64,7 @@ algorithm
fn_cache := UnorderedMap.new<Functionargs>(stringHashDjb2Mod, stringEq);

for v in flatModel.variables loop
convertUnitString2unit(v, htCr2U1, htS2U, htU2S);
convertUnitStringToUnit(v, htCr2U1, htS2U, htU2S);
end for;

htCr2U2 := UnorderedMap.copy(htCr2U1);
Expand Down Expand Up @@ -983,7 +984,7 @@ algorithm
UnorderedMap.tryAdd(unit, name, htU2S);
end addUnit2HtU2S;

function convertUnitString2unit
function convertUnitStringToUnit
"converts String to unit"
input Variable var;
input Unit.CrefToUnitTable htCr2U;
Expand All @@ -997,25 +998,45 @@ protected
algorithm
unit_binding := Variable.lookupTypeAttribute("unit", var);
unit_exp := Binding.typedExp(unit_binding);
unit_string := if isSome(unit_exp) then getUnitStringFromExp(Util.getOption(unit_exp)) else "";

() := match unit_exp
case SOME(Expression.STRING(value = unit_string))
guard not stringEmpty(unit_string)
algorithm
unit := parse(unit_string, var.name, htS2U, htU2S, var.info);
UnorderedMap.add(var.name, unit, htCr2U);
then
();
if stringEmpty(unit_string) then
UnorderedMap.add(var.name, Unit.MASTER({var.name}), htCr2U);
addUnit2HtS2U("-", Unit.MASTER({var.name}), htS2U);
addUnit2HtU2S("-", Unit.MASTER({var.name}), htU2S);
else
unit := parse(unit_string, var.name, htS2U, htU2S, var.info);
UnorderedMap.add(var.name, unit, htCr2U);
end if;
end convertUnitStringToUnit;

else
function getUnitStringFromExp
input Expression unitExp;
output String unitString;
protected
Expression exp;
algorithm
unitString := match unitExp
// A literal string expression, return the string.
case Expression.STRING() then unitExp.value;

// A literal array. This happens for array variables, assume each variable
// has the same unit for now.
case Expression.ARRAY(literal = true)
guard Expression.isLiteral(unitExp) and not Expression.isEmptyArray(unitExp)
then getUnitStringFromExp(Expression.arrayFirstScalar(unitExp));

// A non-literal expression, evaluate it and try again if it could be evaluated.
case _
guard not Expression.isLiteral(unitExp)
algorithm
UnorderedMap.add(var.name, Unit.MASTER({var.name}), htCr2U);
addUnit2HtS2U("-", Unit.MASTER({var.name}), htS2U);
addUnit2HtU2S("-", Unit.MASTER({var.name}), htU2S);
exp := Ceval.tryEvalExp(unitExp);
then
();
if Expression.isLiteral(exp) then getUnitStringFromExp(exp) else "";

else "";
end match;
end convertUnitString2unit;
end getUnitStringFromExp;

protected function parse "author: lochel"
input String unitString;
Expand Down
1 change: 1 addition & 0 deletions testsuite/simulation/modelica/unitcheck/Makefile
Expand Up @@ -21,6 +21,7 @@ UnitCheck17.mos \
UnitCheck18.mos \
UnitCheck19.mos \
UnitCheck20.mos \
UnitCheck21.mos \
ticket3631.mos \


Expand Down
83 changes: 83 additions & 0 deletions testsuite/simulation/modelica/unitcheck/UnitCheck21.mos
@@ -0,0 +1,83 @@
// name: UnitCheck21
// keywords: initialization
// status: correct
// cflags: -d=newInst --unitChecking -d=dumpUnits

loadString("
model UnitCheck21
type MassFlowRate = Real(unit = \"kg/s\");
type Volume = Real(unit = \"m3\");
type Density = Real(unit = \"kg/m3\");

parameter Integer N = 2;
MassFlowRate w[N];
Volume V[N];
Density rho[N];
Volume V1;
MassFlowRate w1;
Density rho1;
equation
rho1*der(V1) = w1; // Correct equation
der(V1) = w1; // Dimensionally inconsistent
rho[1]*der(V[1]) = w[1]; // Correct equation
der(V[1]) = w[1]; // Dimensionally inconsistent
der(V) = w; // Dimensionally inconsistent
for i in 1:N loop
der(V[i]) = w[i]; // Dimensionally inconsistent
end for;
end UnitCheck21;
"); getErrorString();

instantiateModel(UnitCheck21); getErrorString();

// Result:
// true
// ""
// (N, MASTER(N))
// (w, 1000.0 * s^(-1) * g^(1))
// (V, 1.0 * m^(3))
// (rho, 1000.0 * m^(-3) * g^(1))
// (V1, 1.0 * m^(3))
// (w1, 1000.0 * s^(-1) * g^(1))
// (rho1, 1000.0 * m^(-3) * g^(1))
// ######## UnitCheck COMPLETED ########
// "class UnitCheck21
// final parameter Integer N = 2;
// Real w[1](unit = \"kg/s\");
// Real w[2](unit = \"kg/s\");
// Real V[1](unit = \"m3\");
// Real V[2](unit = \"m3\");
// Real rho[1](unit = \"kg/m3\");
// Real rho[2](unit = \"kg/m3\");
// Real V1(unit = \"m3\");
// Real w1(unit = \"kg/s\");
// Real rho1(unit = \"kg/m3\");
// equation
// rho1 * der(V1) = w1;
// der(V1) = w1;
// rho[1] * der(V[1]) = w[1];
// der(V[1]) = w[1];
// der(V[1]) = w[1];
// der(V[2]) = w[2];
// der(V[1]) = w[1];
// der(V[2]) = w[2];
// end UnitCheck21;
// "
// "[<interactive>:16:5-16:17:writable] Warning: The following equation is INCONSISTENT due to specified unit information: der(V1) = w1
// Warning: The units of following sub-expressions need to be equal:
// - sub-expression \"w1\" has unit \"kg/s\"
// - sub-expression \"der(V1)\" has unit \"m3.s-1\"
// [<interactive>:18:5-18:21:writable] Warning: The following equation is INCONSISTENT due to specified unit information: der(V[1]) = w[1]
// Warning: The units of following sub-expressions need to be equal:
// - sub-expression \"w[1]\" has unit \"kg/s\"
// - sub-expression \"der(V[1])\" has unit \"m3.s-1\"
// [<interactive>:21:7-21:23:writable] Warning: The following equation is INCONSISTENT due to specified unit information: der(V[1]) = w[1]
// Warning: The units of following sub-expressions need to be equal:
// - sub-expression \"w[1]\" has unit \"kg/s\"
// - sub-expression \"der(V[1])\" has unit \"m3.s-1\"
// [<interactive>:21:7-21:23:writable] Warning: The following equation is INCONSISTENT due to specified unit information: der(V[2]) = w[2]
// Warning: The units of following sub-expressions need to be equal:
// - sub-expression \"w[2]\" has unit \"kg/s\"
// - sub-expression \"der(V[2])\" has unit \"m3.s-1\"
// "
// endResult

0 comments on commit 6314a69

Please sign in to comment.