Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 88.3% 271 / 0 / 307
Functions: -% 0 / 1 / 1
Branches: 80.0% 160 / 0 / 200

OMCompiler/Compiler/NFFrontEnd/NFUnitCheck.mo
Line Branch Exec Source
1 /*
2 * This file is part of OpenModelica.
3 *
4 * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC),
5 * c/o Linköpings universitet, Department of Computer and Information Science,
6 * SE-58183 Linköping, Sweden.
7 *
8 * All rights reserved.
9 *
10 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR
11 * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8.
12 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
13 * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL
14 * VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
15 *
16 * The OpenModelica software and the OSMC (Open Source Modelica Consortium)
17 * Public License (OSMC-PL) are obtained from OSMC, either from the above
18 * address, from the URLs:
19 * http://www.openmodelica.org or
20 * https://github.com/OpenModelica/ or
21 * http://www.ida.liu.se/projects/OpenModelica,
22 * and in the OpenModelica distribution.
23 *
24 * GNU AGPL version 3 is obtained from:
25 * https://www.gnu.org/licenses/licenses.html#GPL
26 *
27 * This program is distributed WITHOUT ANY WARRANTY; without
28 * even the implied warranty of MERCHANTABILITY or FITNESS
29 * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
30 * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
31 *
32 * See the full OSMC Public License conditions for more details.
33 *
34 */
35
36 encapsulated package NFUnitCheck
37 " file: NFUnitCheck.mo
38 package: UnitCheck
39 description: This package provides everything for advanced unit checking:
40 - for all variables unspecified units get calculated if possible
41 - inconsistent equations get reported in a user friendly way
42 authors: Jan Hagemann and Lennart Ochel (FH Bielefeld, Germany)"
43
44 public
45 import Absyn;
46 import AbsynUtil;
47 //import DAE;
48 import FlatModel = NFFlatModel;
49 import FunctionTree = NFFlatten.FunctionTree;
50
51 protected
52 import ComponentRef = NFComponentRef;
53 import Ceval = NFCeval;
54 import ElementSource;
55 import Equation = NFEquation;
56 import ExecStat.execStat;
57 import Expression = NFExpression;
58 import Binding = NFBinding;
59 import Call = NFCall;
60 import Component = NFComponent;
61 import NFFunction.Function;
62 import NFInstNode.InstNode;
63 import Operator = NFOperator;
64 import SimplifyExp = NFSimplifyExp;
65 import Type = NFType;
66 import Unit = NFUnit;
67 import Variable = NFVariable;
68 import Variability = NFPrefixes.Variability;
69
70 uniontype Functionargs
71 record FUNCTIONUNITS
72 String name;
73 list<String> invars;
74 list<String> outvars;
75 list<String> inunits;
76 list<String> outunits;
77 end FUNCTIONUNITS;
78 end Functionargs;
79
80 type FunctionUnitCache = UnorderedMap<String, Functionargs>;
81
82 public
83 function checkUnits
84 input output FlatModel flatModel;
85 protected
86 Unit.CrefToUnitTable htCr2U1, htCr2U2;
87 Unit.StringToUnitTable htS2U;
88 Unit.UnitToStringTable htU2S;
89 FunctionUnitCache fn_cache;
90 algorithm
91
4/4
✓ Branch 1 taken 1564 times.
✓ Branch 2 taken 12 times.
✓ Branch 4 taken 1496 times.
✓ Branch 5 taken 68 times.
1576 if not (Flags.getConfigBool(Flags.UNIT_CHECKING) or Flags.getConfigBool(Flags.CHECK_MODEL)) then
92 1496 return;
93 end if;
94
95 try
96 80 htCr2U1 := Unit.newCrefUnitTable(Util.nextPrime(integer(10 + 1.4*listLength(flatModel.variables))));
97 80 htS2U := Unit.getKnownUnits();
98 80 htU2S := Unit.getKnownUnitsInverse();
99 80 fn_cache := UnorderedMap.new<Functionargs>(stringHashDjb2, stringEq);
100
101
2/2
✓ Branch 0 taken 48367 times.
✓ Branch 1 taken 80 times.
48447 for v in flatModel.variables loop
102 48367 convertUnitStringToUnit(v, htCr2U1, htS2U, htU2S);
103 end for;
104
105 80 htCr2U2 := UnorderedMap.copy(htCr2U1);
106 80 htCr2U2 := checkModelConsistency(flatModel.variables, flatModel.equations,
107 flatModel.initialEquations, htCr2U2, htS2U, htU2S, fn_cache);
108
109
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 68 times.
80 if Flags.isSet(Flags.DUMP_UNIT) then
110 12 print(UnorderedMap.toString(htCr2U2, ComponentRef.toString, Unit.unit2string));
111 12 print("\n######## UnitCheck COMPLETED ########\n");
112 end if;
113
114 80 notification(htCr2U1, htCr2U2, htU2S);
115
116 80 flatModel := updateModel(flatModel, htCr2U2, htU2S);
117 else
118 ✗ Error.addInternalError(getInstanceName() + ": unit check module failed", sourceInfo());
119 end try;
120
121 80 execStat(getInstanceName());
122 end checkUnits;
123
124 protected
125 function updateModel
126 "Updates all variables without units with their calculated units."
127 input output FlatModel flatModel;
128 input Unit.CrefToUnitTable htCr2U;
129 input Unit.UnitToStringTable htU2S;
130 algorithm
131
4/4
✓ Branch 0 taken 48367 times.
✓ Branch 1 taken 80 times.
✓ Branch 2 taken 48367 times.
✓ Branch 3 taken 80 times.
48447 flatModel.variables := list(updateVariable(v, htCr2U, htU2S) for v in flatModel.variables);
132 end updateModel;
133
134 function updateVariable
135 "Updates a variable without unit with its calculated unit."
136 input output Variable var;
137 input Unit.CrefToUnitTable htCr2U;
138 input Unit.UnitToStringTable htU2S;
139 protected
140 String name, unit_str;
141 Binding binding;
142 Integer unit_idx = 0;
143 Unit.Unit unit;
144 algorithm
145
2/2
✓ Branch 1 taken 17513 times.
✓ Branch 2 taken 30854 times.
48367 if Type.isReal(var.ty) then
146
2/2
✓ Branch 0 taken 22452 times.
✓ Branch 1 taken 3926 times.
26378 for attr in var.typeAttributes loop
147 22452 (name, binding) := attr;
148 22452 unit_idx := unit_idx + 1;
149
150
3/4
✓ Branch 0 taken 13587 times.
✓ Branch 1 taken 8865 times.
✓ Branch 3 taken 13587 times.
✗ Branch 4 not taken.
22452 if name == "unit" then
151
1/2
✓ Branch 1 taken 13587 times.
✗ Branch 2 not taken.
13587 if Binding.isBound(binding) then
152 // Variable already has a unit, keep it.
153 13587 return;
154 else
155 // Variable has an empty unit, replace it.
156 ✗ var.typeAttributes := listDelete(var.typeAttributes, unit_idx);
157 ✗ break;
158 end if;
159 end if;
160 end for;
161
162 try
163 // Look up the variable's unit in the table.
164 3926 unit := UnorderedMap.getOrFail(var.name, htCr2U);
165
166
2/2
✓ Branch 1 taken 453 times.
✓ Branch 2 taken 3473 times.
3926 if Unit.isUnit(unit) then
167 // Add the unit string to the variable's type attributes.
168 453 unit_str := Unit.unitString(unit, htU2S);
169 453 binding := Binding.makeFlat(Expression.STRING(unit_str), Variability.CONSTANT, NFBinding.Source.GENERATED);
170 906 var.typeAttributes := ("unit", binding) :: var.typeAttributes;
171 end if;
172 else
173 end try;
174 end if;
175 end updateVariable;
176
177 function notification "dumps the calculated units"
178 input Unit.CrefToUnitTable inHtCr2U1;
179 input Unit.CrefToUnitTable inHtCr2U2;
180 input Unit.UnitToStringTable inHtU2S;
181 protected
182 String str;
183 list<tuple<ComponentRef, Unit.Unit>> lt1;
184 algorithm
185 80 lt1 := UnorderedMap.toList(inHtCr2U1);
186 80 str := notification2(lt1, inHtCr2U2, inHtU2S);
187
5/6
✓ Branch 1 taken 68 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 6 times.
✓ Branch 6 taken 6 times.
✗ Branch 7 not taken.
80 if Flags.isSet(Flags.DUMP_UNIT) and str<>"" then
188 6 Error.addCompilerNotification(str);
189 end if;
190 end notification;
191
192 protected function notification2 "help-function"
193 input list<tuple<ComponentRef, Unit.Unit>> inLt1;
194 input Unit.CrefToUnitTable inHtCr2U2;
195 input Unit.UnitToStringTable inHtU2S;
196 output String outS;
197 protected
198 ComponentRef cr1 = ComponentRef.EMPTY();
199 Real factor=0, offset=0;
200 Integer s=0, m=0, g=0, A=0, K=0, mol=0, cd=0;
201 algorithm
202
2/2
✓ Branch 0 taken 48367 times.
✓ Branch 1 taken 80 times.
48447 outS := stringAppendList(list(
203 // We already assigned the variables before
204 "\"" + ComponentRef.toString(cr1) + "\" has the Unit \"" + Unit.unitString(Unit.UNIT(s, m, g, A, K, mol, cd, factor, offset), inHtU2S) + "\"\n"
205 // Do the filtering and unboxing stuff at the same time; then we only need one hashtable call
206 // And we only use a try-block for MASTER nodes
207 for t1 guard match t1 local Boolean b; case (cr1,Unit.MASTER()) algorithm
208 b := false;
209 try
210
2/2
✓ Branch 2 taken 17425 times.
✓ Branch 3 taken 471 times.
17896 Unit.UNIT(s, m, g, A, K, mol, cd, factor, offset) :=
211 UnorderedMap.getOrFail(ComponentRef.stripSubscripts(cr1), inHtCr2U2);
212 b := true;
213 else
214 end try;
215 then b; else false; end match in inLt1
216 ));
217 end notification2;
218
219 function checkModelConsistency
220 input list<Variable> variables;
221 input list<Equation> equations;
222 input list<Equation> initialEquations;
223 input output Unit.CrefToUnitTable htCr2U;
224 input Unit.StringToUnitTable htS2U;
225 input Unit.UnitToStringTable htU2S;
226 input FunctionUnitCache fnCache;
227 protected
228 Boolean dump_eq_unit = Flags.isSet(Flags.DUMP_EQ_UNIT_STRUCT);
229 algorithm
230
2/2
✓ Branch 0 taken 48367 times.
✓ Branch 1 taken 80 times.
48447 for v in variables loop
231 48367 foldBindingExp(v, htCr2U, htS2U, htU2S, fnCache, dump_eq_unit);
232
233
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48367 times.
48367 for c in v.children loop
234 ✗ foldBindingExp(c, htCr2U, htS2U, htU2S, fnCache, dump_eq_unit);
235 end for;
236 end for;
237
238
2/2
✓ Branch 0 taken 43405 times.
✓ Branch 1 taken 80 times.
43485 for eq in equations loop
239 43405 foldEquation(eq, htCr2U, htS2U, htU2S, fnCache, dump_eq_unit);
240 end for;
241
242
2/2
✓ Branch 0 taken 139 times.
✓ Branch 1 taken 80 times.
219 for ieq in initialEquations loop
243 139 foldEquation(ieq, htCr2U, htS2U, htU2S, fnCache, dump_eq_unit);
244 end for;
245 end checkModelConsistency;
246
247 function foldBindingExp
248 input Variable var;
249 input Unit.CrefToUnitTable htCr2U;
250 input Unit.StringToUnitTable htS2U;
251 input Unit.UnitToStringTable htU2S;
252 input FunctionUnitCache fnCache;
253 input Boolean dumpEqInitStruct;
254 protected
255 Expression binding_exp;
256 Equation eq;
257 algorithm
258
4/4
✓ Branch 1 taken 30854 times.
✓ Branch 2 taken 17513 times.
✓ Branch 4 taken 4493 times.
✓ Branch 5 taken 13020 times.
48367 if Type.isReal(var.ty) and Binding.isBound(var.binding) then
259 13020 binding_exp := Binding.getTypedExp(var.binding);
260 13020 eq := Equation.makeEquality(Expression.fromCref(var.name), binding_exp, var.ty,
261 ElementSource.createElementSource(var.info));
262 13020 foldEquation(eq, htCr2U, htS2U, htU2S, fnCache, dumpEqInitStruct);
263 end if;
264 end foldBindingExp;
265
266 function foldEquation
267 "Folds the equation or returns the error message of inconsistent equations."
268 input Equation eq;
269 input Unit.CrefToUnitTable htCr2U;
270 input Unit.StringToUnitTable htS2U;
271 input Unit.UnitToStringTable htU2S;
272 input FunctionUnitCache fnCache;
273 input Boolean dumpEqInitStruct;
274 protected
275 list<list<tuple<Expression, Unit.Unit>>> inconsistent_units;
276 algorithm
277 56564 inconsistent_units := foldEquation2(eq, dumpEqInitStruct, htCr2U, htS2U, htU2S, fnCache);
278
279
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 56564 times.
56572 for u in inconsistent_units loop
280 8 Errorfunction(u, eq, htU2S);
281 end for;
282 end foldEquation;
283
284 function foldEquation2 "help function to foldEquation"
285 input Equation eq;
286 input Boolean dumpEqInitStruct;
287 input Unit.CrefToUnitTable htCr2U;
288 input Unit.StringToUnitTable htS2U;
289 input Unit.UnitToStringTable htU2S;
290 input FunctionUnitCache fnCache;
291 output list<list<tuple<Expression, Unit.Unit>>> inconsistentUnits;
292 algorithm
293 inconsistentUnits := match eq
294 local
295 list<list<tuple<Expression, Unit.Unit>>> icu1, icu2;
296 Expression lhs, rhs, temp;
297 String fn_name, formal_args, formal_var;
298 list<String> out_vars, out_units;
299 Unit.Unit unit1, unit2;
300 list<Equation> eql;
301 Boolean b;
302
303 case Equation.EQUALITY(lhs = lhs as Expression.TUPLE(),
304 rhs = rhs as Expression.CALL())
305 guard not Function.isBuiltin(Call.typedFunction(rhs.call))
306 algorithm
307 1 fn_name := AbsynUtil.pathString(AbsynUtil.makeNotFullyQualified(Call.functionName(rhs.call)));
308 1 (_, out_vars, _, out_units) := getCallUnits(fn_name, rhs.call, fnCache);
309 1 icu1 := foldCallArg1(lhs.elements, htCr2U, htS2U, htU2S, fnCache, Unit.MASTER({}), out_units, out_vars, fn_name);
310 1 (_, icu2) := insertUnitInEquation(rhs, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
311 1 then
312 List.append_reverse(icu1, icu2);
313
314 case Equation.EQUALITY(rhs = rhs as Expression.CALL())
315 guard not Function.isBuiltin(Call.typedFunction(rhs.call))
316 algorithm
317 1946 fn_name := AbsynUtil.pathString(AbsynUtil.makeNotFullyQualified(Call.functionName(rhs.call)));
318 1946 (_, out_vars, _, out_units) := getCallUnits(fn_name, rhs.call, fnCache);
319 1946 unit1 := insertUnitInEquation(eq.lhs, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
320 1946 formal_args := listHead(out_units);
321 1946 formal_var := listHead(out_vars);
322
323
4/4
✓ Branch 0 taken 1908 times.
✓ Branch 1 taken 38 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1906 times.
1946 unit2 := if formal_args == "NONE" then Unit.MASTER({}) else Unit.parseUnitString(formal_args, htS2U, Equation.info(eq));
324
325 1946 b := unitTypesEqual(unit1, unit2, htCr2U);
326
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1946 times.
1946 if b then
327 icu1 := {};
328 else
329 ✗ icu1 := {{(eq.lhs, unit1), (makeNewCref(formal_var, fn_name), unit2)}};
330 end if;
331
332 1946 (_, icu2) := insertUnitInEquation(rhs, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
333 1946 then
334 List.append_reverse(icu1, icu2);
335
336 case Equation.EQUALITY()
337 algorithm
338 53324 temp := Expression.BINARY(eq.rhs, Operator.makeSub(Type.REAL()), eq.lhs);
339
340
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53324 times.
53324 if dumpEqInitStruct then
341 ✗ print(Expression.toString(temp));
342 ✗ print("--------------------\n");
343 end if;
344
345 53324 (_, inconsistentUnits) := insertUnitInEquation(temp, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
346 53324 then
347 inconsistentUnits;
348
349 case Equation.WHEN(branches = Equation.Branch.BRANCH(body = eql) :: _)
350 algorithm
351 3 inconsistentUnits := {};
352
353
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 3 times.
8 for e in eql loop
354 5 icu1 := foldEquation2(e, dumpEqInitStruct, htCr2U, htS2U, htU2S, fnCache);
355 5 inconsistentUnits := List.append_reverse(icu1, inconsistentUnits);
356 end for;
357 3 then
358 inconsistentUnits;
359
360 case Equation.NORETCALL()
361 algorithm
362 ✗ (_, inconsistentUnits) := insertUnitInEquation(eq.exp, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
363 ✗ then
364 inconsistentUnits;
365
366 else {};
367 end match;
368 end foldEquation2;
369
370 function makeNewCref
371 input String paramName;
372 input String fnName;
373 output Expression outExp;
374 algorithm
375 4 outExp := Expression.CREF(Type.UNKNOWN(),
376 ComponentRef.prefixCref(InstNode.NAME_NODE(paramName), Type.UNKNOWN(), {},
377 ComponentRef.fromNode(InstNode.NAME_NODE(fnName + "()"), Type.UNKNOWN())));
378 end makeNewCref;
379
380 function insertUnitInEquation
381 "Inserts the units in the equation and checks if the equation is consistent or not."
382 input Expression eq;
383 input output Unit.Unit unit;
384 input Unit.CrefToUnitTable htCr2U;
385 input Unit.StringToUnitTable htS2U;
386 input Unit.UnitToStringTable htU2S;
387 input FunctionUnitCache fnCache;
388 output list<list<tuple<Expression, Unit.Unit>>> inconsistentUnits;
389 protected
390 import NFOperator.Op;
391 algorithm
392 (unit, inconsistentUnits) := matchcontinue eq
393 local
394 Expression exp1, exp2;
395 Unit.Unit unit1, unit2, op_unit;
396 list<list<tuple<Expression, Unit.Unit>>> icu1, icu2;
397 list<ComponentRef> vars;
398 Integer i;
399 Boolean b;
400
401 // n-ary sums and products are checked in their binary form
402 case Expression.MULTARY()
403 5843 then insertUnitInEquation(SimplifyExp.splitMultary(eq), unit, htCr2U, htS2U, htU2S, fnCache);
404
405 // SUB equal summands
406 case Expression.BINARY(exp1, Operator.OPERATOR(op = Op.SUB), exp2)
407 algorithm
408
2/2
✓ Branch 1 taken 28777 times.
✓ Branch 2 taken 26227 times.
55008 (unit2 as Unit.UNIT(), icu2) := insertUnitInEquation(exp2, unit, htCr2U, htS2U, htU2S, fnCache);
409 26227 (unit1, icu1) := insertUnitInEquation(exp1, unit2, htCr2U, htS2U, htU2S, fnCache);
410
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 26223 times.
26227 (true, op_unit) := unitTypesEqual(unit1, unit2, htCr2U);
411 26223 then
412 (op_unit, List.append_reverse(icu1, icu2));
413
414 // SUB equal summands
415 case Expression.BINARY(exp1, Operator.OPERATOR(op = Op.SUB), exp2)
416 algorithm
417 28781 (unit1, icu2) := insertUnitInEquation(exp1, unit, htCr2U, htS2U, htU2S, fnCache);
418 28781 (unit2, icu1) := insertUnitInEquation(exp2, unit1, htCr2U, htS2U, htU2S, fnCache);
419
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 28775 times.
28781 (true, op_unit) := unitTypesEqual(unit1, unit2, htCr2U);
420 28775 then
421 (op_unit, List.append_reverse(icu1, icu2));
422
423 // SUB unequal summands
424 case Expression.BINARY(exp1, Operator.OPERATOR(op = Op.SUB), exp2)
425 algorithm
426
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
8 (unit2 as Unit.UNIT(), icu2) := insertUnitInEquation(exp2, unit, htCr2U, htS2U, htU2S, fnCache);
427 6 (unit1, icu1) := insertUnitInEquation(exp1, unit2, htCr2U, htS2U, htU2S, fnCache);
428
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
6 (false, _) := unitTypesEqual(unit1, unit2, htCr2U);
429 12 then
430 (Unit.MASTER({}), {(exp1, unit1), (exp2, unit2)} :: List.append_reverse(icu1, icu2));
431
432 // SUB unequal summands
433 case Expression.BINARY(exp1, Operator.OPERATOR(op = Op.SUB), exp2)
434 algorithm
435 2 (unit1, icu2) := insertUnitInEquation(exp1, unit, htCr2U, htS2U, htU2S, fnCache);
436 2 (unit2, icu1) := insertUnitInEquation(exp2, unit1, htCr2U, htS2U, htU2S, fnCache);
437
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 (false, _) := unitTypesEqual(unit1, unit2, htCr2U);
438 ✗ then
439 (Unit.MASTER({}), {(exp1, unit1), (exp2, unit2)} :: List.append_reverse(icu1, icu2));
440
441 // ADD equal summands
442 case Expression.BINARY(exp1, Operator.OPERATOR(op = Op.ADD), exp2)
443 algorithm
444
2/2
✓ Branch 1 taken 2698 times.
✓ Branch 2 taken 8344 times.
11042 (unit2 as Unit.UNIT(), icu2) := insertUnitInEquation(exp2, unit, htCr2U, htS2U, htU2S, fnCache);
445 8344 (unit1, icu1) := insertUnitInEquation(exp1, unit2, htCr2U, htS2U, htU2S, fnCache);
446
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 8344 times.
8344 (true, op_unit) := unitTypesEqual(unit1, unit2, htCr2U);
447 8344 then
448 (op_unit, List.append_reverse(icu1, icu2));
449
450 // ADD equal summands
451 case Expression.BINARY(exp1, Operator.OPERATOR(op = Op.ADD), exp2)
452 algorithm
453 2698 (unit1, icu2) := insertUnitInEquation(exp1, unit, htCr2U, htS2U, htU2S, fnCache);
454 2698 (unit2, icu1) := insertUnitInEquation(exp2, unit1, htCr2U, htS2U, htU2S, fnCache);
455
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2698 times.
2698 (true, op_unit) := unitTypesEqual(unit1, unit2, htCr2U);
456 2698 then
457 (op_unit, List.append_reverse(icu1, icu2));
458
459 // ADD unequal summands
460 case Expression.BINARY(exp1, Operator.OPERATOR(op = Op.ADD), exp2)
461 algorithm
462 ✗ (unit2 as Unit.UNIT(), icu2) := insertUnitInEquation(exp2, unit, htCr2U, htS2U, htU2S, fnCache);
463 ✗ (unit1, icu1) := insertUnitInEquation(exp1, unit2, htCr2U, htS2U, htU2S, fnCache);
464 ✗ (false, _) := unitTypesEqual(unit1, unit2, htCr2U);
465 ✗ then
466 (Unit.MASTER({}), {(exp1, unit1), (exp2, unit2)} :: List.append_reverse(icu1, icu2));
467
468 // ADD unequal summands
469 case Expression.BINARY(exp1, Operator.OPERATOR(op = Op.ADD), exp2)
470 algorithm
471 ✗ (unit1, icu2) := insertUnitInEquation(exp1, unit, htCr2U, htS2U, htU2S, fnCache);
472 ✗ (unit2, icu1) := insertUnitInEquation(exp2, unit1, htCr2U, htS2U, htU2S, fnCache);
473 ✗ (false, _) := unitTypesEqual(unit1, unit2, htCr2U);
474 ✗ then
475 (Unit.MASTER({}), {(exp1, unit1), (exp2, unit2)} :: List.append_reverse(icu1, icu2));
476
477 // MUL
478 case Expression.BINARY(exp1, Operator.OPERATOR(op = Op.MUL), exp2)
479 algorithm
480
2/2
✓ Branch 1 taken 3931 times.
✓ Branch 2 taken 1988 times.
6968 (unit1 as Unit.UNIT(), icu1) := insertUnitInEquation(exp1, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
481
2/2
✓ Branch 1 taken 1049 times.
✓ Branch 2 taken 939 times.
1988 (unit2 as Unit.UNIT(), icu2) := insertUnitInEquation(exp2, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
482 939 op_unit := Unit.unitMul(unit1, unit2);
483 939 insertUnitString(op_unit, htS2U, htU2S);
484 939 then
485 (op_unit, List.append_reverse(icu1, icu2));
486
487 case Expression.BINARY(exp1, Operator.OPERATOR(op = Op.MUL), exp2)
488 guard Unit.isMaster(unit)
489 algorithm
490
2/2
✓ Branch 1 taken 880 times.
✓ Branch 2 taken 3247 times.
4573 (Unit.MASTER(), icu1) := insertUnitInEquation(exp1, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
491
2/2
✓ Branch 1 taken 446 times.
✓ Branch 2 taken 2801 times.
3247 (Unit.UNIT(), icu2) := insertUnitInEquation(exp2, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
492 2801 then
493 (Unit.MASTER({}), List.append_reverse(icu1, icu2));
494
495 case Expression.BINARY(exp1, Operator.OPERATOR(op = Op.MUL), exp2)
496 guard Unit.isUnit(unit)
497 algorithm
498
2/2
✓ Branch 1 taken 170 times.
✓ Branch 2 taken 683 times.
886 (Unit.MASTER(varList = vars), icu1) := insertUnitInEquation(exp1, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
499
2/2
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 650 times.
683 (unit2 as Unit.UNIT(), icu2) := insertUnitInEquation(exp2, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
500 650 op_unit := Unit.unitDiv(unit, unit2);
501 650 List.map2_0(vars, updateHtCr2U, op_unit, htCr2U);
502 650 insertUnitString(op_unit, htS2U, htU2S);
503 650 then
504 (unit, List.append_reverse(icu1, icu2));
505
506 case Expression.BINARY(exp1, Operator.OPERATOR(op = Op.MUL), exp2)
507 guard Unit.isMaster(unit)
508 algorithm
509
2/2
✓ Branch 1 taken 446 times.
✓ Branch 2 taken 880 times.
1326 (Unit.UNIT(), icu1) := insertUnitInEquation(exp1, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
510
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 880 times.
880 (Unit.MASTER(), icu2) := insertUnitInEquation(exp2, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
511 880 then
512 (Unit.MASTER({}), List.append_reverse(icu1, icu2));
513
514 case Expression.BINARY(exp1, Operator.OPERATOR(op = Op.MUL), exp2)
515 guard Unit.isUnit(unit)
516 algorithm
517
2/2
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 169 times.
203 (unit2 as Unit.UNIT(), icu1) := insertUnitInEquation(exp1, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
518
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 169 times.
169 (Unit.MASTER(varList = vars), icu2) := insertUnitInEquation(exp2, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
519 169 op_unit := Unit.unitDiv(unit, unit2);
520 169 List.map2_0(vars, updateHtCr2U, op_unit, htCr2U);
521 169 insertUnitString(op_unit, htS2U, htU2S);
522 169 then
523 (unit, List.append_reverse(icu1, icu2));
524
525 case Expression.BINARY(exp1, Operator.OPERATOR(op = Op.MUL), exp2)
526 algorithm
527
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 479 times.
480 (Unit.MASTER(), icu1) := insertUnitInEquation(exp1, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
528
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 479 times.
479 (Unit.MASTER(), icu2) := insertUnitInEquation(exp2, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
529 479 then
530 (Unit.MASTER({}), List.append_reverse(icu1, icu2));
531
532 // DIV
533 case Expression.BINARY(exp1, Operator.OPERATOR(op = Op.DIV), exp2)
534 algorithm
535
2/2
✓ Branch 1 taken 477 times.
✓ Branch 2 taken 593 times.
1427 (unit1 as Unit.UNIT(), icu1) := insertUnitInEquation(exp1, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
536
2/2
✓ Branch 1 taken 357 times.
✓ Branch 2 taken 236 times.
593 (unit2 as Unit.UNIT(), icu2) := insertUnitInEquation(exp2, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
537 236 op_unit := Unit.unitDiv(unit1, unit2);
538 236 insertUnitString(op_unit, htS2U, htU2S);
539 236 then
540 (op_unit, List.append_reverse(icu1, icu2));
541
542 case Expression.BINARY(exp1, Operator.OPERATOR(op = Op.DIV), exp2)
543 guard Unit.isMaster(unit)
544 algorithm
545
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 48 times.
97 (Unit.MASTER(), icu1) := insertUnitInEquation(exp1, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
546
2/2
✓ Branch 1 taken 39 times.
✓ Branch 2 taken 9 times.
48 (Unit.UNIT(), icu2) := insertUnitInEquation(exp2, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
547 9 inconsistentUnits := List.append_reverse(icu1, icu2);
548 9 then
549 (Unit.MASTER({}), List.append_reverse(icu1, icu2));
550
551 case Expression.BINARY(exp1, Operator.OPERATOR(op = Op.DIV), exp2)
552 guard Unit.isUnit(unit)
553 algorithm
554
2/2
✓ Branch 1 taken 347 times.
✓ Branch 2 taken 429 times.
1203 (Unit.MASTER(varList = vars), icu1) := insertUnitInEquation(exp1, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
555
2/2
✓ Branch 1 taken 427 times.
✓ Branch 2 taken 2 times.
429 (unit2 as Unit.UNIT(), icu2) := insertUnitInEquation(exp2, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
556 2 op_unit := Unit.unitMul(unit, unit2);
557 2 List.map2_0(vars, updateHtCr2U, op_unit, htCr2U);
558 2 insertUnitString(op_unit, htS2U, htU2S);
559 2 then
560 (unit, List.append_reverse(icu1, icu2));
561
562 case Expression.BINARY(exp1, Operator.OPERATOR(op = Op.DIV), exp2)
563 guard Unit.isMaster(unit)
564 algorithm
565
2/2
✓ Branch 1 taken 39 times.
✓ Branch 2 taken 10 times.
49 (Unit.UNIT(), icu1) := insertUnitInEquation(exp1, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
566
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
10 (Unit.MASTER(), icu2) := insertUnitInEquation(exp2, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
567 10 then
568 (Unit.MASTER({}), List.append_reverse(icu1, icu2));
569
570 case Expression.BINARY(exp1, Operator.OPERATOR(op = Op.DIV), exp2)
571 guard Unit.isUnit(unit)
572 algorithm
573
2/2
✓ Branch 1 taken 427 times.
✓ Branch 2 taken 347 times.
774 (unit2 as Unit.UNIT(), icu1) := insertUnitInEquation(exp1, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
574
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 347 times.
347 (Unit.MASTER(varList = vars), icu2) := insertUnitInEquation(exp2, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
575 347 op_unit := Unit.unitDiv(unit2, unit);
576 347 List.map2_0(vars, updateHtCr2U, op_unit, htCr2U);
577 347 insertUnitString(op_unit, htS2U, htU2S);
578 347 then
579 (unit, List.append_reverse(icu1, icu2));
580
581 case Expression.BINARY(exp1, Operator.OPERATOR(op = Op.DIV), exp2)
582 algorithm
583
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 466 times.
466 (Unit.MASTER(), icu1) := insertUnitInEquation(exp1, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
584
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 466 times.
466 (Unit.MASTER(), icu2) := insertUnitInEquation(exp2, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
585 466 then
586 (Unit.MASTER({}), List.append_reverse(icu1, icu2));
587
588 // POW
589 case Expression.BINARY(exp1, Operator.OPERATOR(op = Op.POW), exp2 as Expression.REAL())
590 algorithm
591
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 630 times.
631 (unit1 as Unit.UNIT(), icu1) := insertUnitInEquation(exp1, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
592
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 630 times.
630 i := realInt(exp2.value);
593
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 630 times.
630 true := realEq(exp2.value, i);
594 630 op_unit := Unit.unitPow(unit1, i);
595 630 insertUnitString(op_unit, htS2U, htU2S);
596 630 then
597 (op_unit, icu1);
598
599 case Expression.BINARY(exp1, Operator.OPERATOR(op = Op.POW), exp2 as Expression.REAL())
600 guard Unit.isUnit(unit)
601 algorithm
602
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
1 (Unit.MASTER(varList = vars), icu1) := insertUnitInEquation(exp1, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
603 1 op_unit := Unit.unitRoot(unit, exp2.value);
604 1 List.map2_0(vars, updateHtCr2U, op_unit, htCr2U);
605 1 insertUnitString(op_unit, htS2U, htU2S);
606 1 then
607 (unit, icu1);
608
609 case Expression.BINARY(exp1, Operator.OPERATOR(op = Op.POW), Expression.REAL())
610 algorithm
611 ✗ (_, icu1) := insertUnitInEquation(exp1, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
612 ✗ then
613 (Unit.MASTER({}), icu1);
614
615 // Call
616 case Expression.CALL()
617 algorithm
618 8867 (op_unit, icu1) := insertUnitInEquationCall(eq.call, unit, htCr2U, htS2U, htU2S, fnCache);
619 then
620 (op_unit, icu1);
621
622 case Expression.IF()
623 algorithm
624 296 (unit1, icu1) := insertUnitInEquation(eq.trueBranch, unit, htCr2U, htS2U, htU2S, fnCache);
625 296 (unit2, icu2) := insertUnitInEquation(eq.falseBranch, unit1, htCr2U, htS2U, htU2S, fnCache);
626 296 (b, op_unit) := unitTypesEqual(unit1, unit2, htCr2U);
627 296 inconsistentUnits := List.append_reverse(icu1, icu2);
628
629
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 296 times.
296 if not b then
630 ✗ inconsistentUnits := {(eq.trueBranch, unit1), (eq.falseBranch, unit2)} :: inconsistentUnits;
631 ✗ op_unit := Unit.MASTER({});
632 end if;
633 296 then
634 (op_unit, inconsistentUnits);
635
636 case Expression.RELATION()
637 algorithm
638 ✗ (unit1, icu1) := insertUnitInEquation(eq.exp1, unit, htCr2U, htS2U, htU2S, fnCache);
639 ✗ (unit2, icu2) := insertUnitInEquation(eq.exp2, unit, htCr2U, htS2U, htU2S, fnCache);
640 ✗ (b, op_unit) := unitTypesEqual(unit1, unit2, htCr2U);
641 ✗ inconsistentUnits := List.append_reverse(icu1, icu2);
642
643 ✗ if not b then
644 ✗ inconsistentUnits := {(eq.exp1, unit1), (eq.exp2, unit2)} :: inconsistentUnits;
645 ✗ op_unit := Unit.MASTER({});
646 end if;
647 ✗ then
648 (op_unit, inconsistentUnits);
649
650 case Expression.UNARY(operator = Operator.OPERATOR(op = Op.UMINUS))
651 algorithm
652 3676 (op_unit, icu1) := insertUnitInEquation(eq.exp, unit, htCr2U, htS2U, htU2S, fnCache);
653 then
654 (op_unit, icu1);
655
656 case Expression.CREF()
657 guard ComponentRef.isTime(eq.cref)
658 algorithm
659 99 op_unit := NFUnit.SECOND;
660 99 addUnit2HtS2U("time", op_unit, htS2U);
661 99 addUnit2HtU2S("time", op_unit, htU2S);
662 99 then
663 (op_unit, {});
664
665 case Expression.CREF(ty = Type.REAL())
666 102185 then (UnorderedMap.getOrFail(ComponentRef.stripSubscripts(eq.cref), htCr2U), {});
667
668 77999 else (Unit.MASTER({}), {});
669 end matchcontinue;
670 end insertUnitInEquation;
671
672 function insertUnitInEquationCall
673 "Inserts the units in the equation and checks if the equation is consistent or not."
674 input Call call;
675 input output Unit.Unit unit;
676 input Unit.CrefToUnitTable htCr2U;
677 input Unit.StringToUnitTable htS2U;
678 input Unit.UnitToStringTable htU2S;
679 input FunctionUnitCache fnCache;
680 output list<list<tuple<Expression, Unit.Unit>>> inconsistentUnits;
681 protected
682 Absyn.Path fn_path;
683 String fn_name;
684 list<Expression> call_args;
685 Unit.Unit op_unit;
686 list<ComponentRef> vars;
687 list<String> var_names, unit_names;
688 algorithm
689 8867 fn_path := Call.functionName(call);
690 8867 call_args := Call.arguments(call);
691
692 (unit, inconsistentUnits) := matchcontinue fn_path
693 case Absyn.IDENT("pre")
694 algorithm
695 7 (op_unit, inconsistentUnits) :=
696 insertUnitInEquation(listHead(call_args), unit, htCr2U, htS2U, htU2S, fnCache);
697 7 then
698 (Unit.MASTER({}), inconsistentUnits);
699
700 case Absyn.IDENT("der")
701 algorithm
702 1233 (op_unit, inconsistentUnits) :=
703 insertUnitInEquation(listHead(call_args), Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
704
705
2/2
✓ Branch 1 taken 511 times.
✓ Branch 2 taken 722 times.
1233 if Unit.isUnit(op_unit) then
706 511 op_unit := Unit.unitDiv(op_unit, NFUnit.SECOND);
707 511 insertUnitString(op_unit, htS2U, htU2S);
708 elseif Unit.isUnit(unit) then
709
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 Unit.MASTER(varList = vars) := op_unit;
710 2 op_unit := Unit.unitMul(unit, NFUnit.SECOND);
711 2 List.map2_0(vars, updateHtCr2U, op_unit, htCr2U);
712 2 insertUnitString(op_unit, htS2U, htU2S);
713 else
714 op_unit := Unit.MASTER({});
715 end if;
716 1233 then
717 (op_unit, inconsistentUnits);
718
719 case Absyn.IDENT("sqrt")
720 algorithm
721 88 (op_unit, inconsistentUnits) :=
722 insertUnitInEquation(listHead(call_args), Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
723
724
2/2
✓ Branch 1 taken 19 times.
✓ Branch 2 taken 69 times.
88 if Unit.isUnit(op_unit) then
725 19 op_unit := Unit.unitRoot(op_unit, 2.0);
726 19 insertUnitString(op_unit, htS2U, htU2S);
727 elseif Unit.isUnit(unit) then
728
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 Unit.MASTER(varList = vars) := op_unit;
729 50 op_unit := Unit.unitPow(unit, 2);
730 50 List.map2_0(vars, updateHtCr2U, op_unit, htCr2U);
731 50 insertUnitString(op_unit, htS2U, htU2S);
732 50 op_unit := unit;
733 else
734 op_unit := Unit.MASTER({});
735 end if;
736 88 then
737 (op_unit, inconsistentUnits);
738
739 case Absyn.IDENT()
740 guard Function.isBuiltin(Call.typedFunction(call))
741 algorithm
742 3523 inconsistentUnits := foldCallArg(call_args, htCr2U, htS2U, htU2S, fnCache);
743 then
744 (Unit.MASTER({}), inconsistentUnits);
745
746 case _
747 algorithm
748 4016 fn_name := AbsynUtil.pathString(AbsynUtil.makeNotFullyQualified(fn_path));
749 4016 (var_names, _, unit_names) := getCallUnits(fn_name, call, fnCache);
750 4016 inconsistentUnits := foldCallArg1(call_args, htCr2U, htS2U, htU2S, fnCache, unit, unit_names, var_names, fn_name);
751 then
752 (Unit.MASTER({}), inconsistentUnits);
753
754 else (Unit.MASTER({}), {});
755 end matchcontinue;
756 end insertUnitInEquationCall;
757
758 function insertUnitString
759 input Unit.Unit unit;
760 input Unit.StringToUnitTable htS2U;
761 input Unit.UnitToStringTable htU2S;
762 protected
763 String unit_str;
764 algorithm
765 3556 unit_str := Unit.unitString(unit, htU2S);
766 3556 addUnit2HtS2U(unit_str, unit, htS2U);
767 3556 addUnit2HtU2S(unit_str, unit, htU2S);
768 end insertUnitString;
769
770 function getCallUnits
771 input String fnName;
772 input Call call;
773 input FunctionUnitCache fnCache;
774 output list<String> inputVars;
775 output list<String> outputVars;
776 output list<String> inputUnits;
777 output list<String> outputUnits;
778 protected
779 Option<Functionargs> opt_args;
780 Functionargs args;
781 algorithm
782 5963 opt_args := UnorderedMap.get(fnName, fnCache);
783
784
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 5963 times.
✓ Branch 2 taken 508 times.
✓ Branch 3 taken 5455 times.
5963 if isSome(opt_args) then
785 5455 SOME(args) := opt_args;
786 else
787 508 args := parseFunctionUnits(fnName, Call.typedFunction(call));
788 508 UnorderedMap.addUnique(fnName, args, fnCache);
789 end if;
790
791
2/2
✓ Branch 0 taken 1947 times.
✓ Branch 1 taken 4016 times.
5963 Functionargs.FUNCTIONUNITS(_, inputVars, outputVars, inputUnits, outputUnits) := args;
792 end getCallUnits;
793
794 function parseFunctionUnits
795 input String funcName;
796 input Function func;
797 output Functionargs outArgs;
798 protected
799 list<String> in_units, out_units, in_args, out_args;
800 algorithm
801
4/4
✓ Branch 0 taken 959 times.
✓ Branch 1 taken 508 times.
✓ Branch 2 taken 959 times.
✓ Branch 3 taken 508 times.
1467 in_units := list(Component.getUnitAttribute(InstNode.component(p), "NONE") for p in func.inputs);
802
4/4
✓ Branch 0 taken 509 times.
✓ Branch 1 taken 508 times.
✓ Branch 2 taken 509 times.
✓ Branch 3 taken 508 times.
1017 out_units := list(Component.getUnitAttribute(InstNode.component(InstNode.fromHandle(p)), "NONE") for p in func.outputs);
803
4/4
✓ Branch 0 taken 959 times.
✓ Branch 1 taken 508 times.
✓ Branch 2 taken 959 times.
✓ Branch 3 taken 508 times.
1467 in_args := list(InstNode.name(p) for p in func.inputs);
804
4/4
✓ Branch 0 taken 509 times.
✓ Branch 1 taken 508 times.
✓ Branch 2 taken 509 times.
✓ Branch 3 taken 508 times.
1017 out_args := list(InstNode.name(InstNode.fromHandle(p)) for p in func.outputs);
805 508 outArgs := FUNCTIONUNITS(funcName, in_args, out_args, in_units, out_units);
806 end parseFunctionUnits;
807
808 function unitTypesEqual
809 "Checks equality of two units."
810 input Unit.Unit unit1;
811 input Unit.Unit unit2;
812 input Unit.CrefToUnitTable htCr2U;
813 output Boolean isEqual;
814 output Unit.Unit outUnit;
815 algorithm
816 (isEqual, outUnit) := match (unit1, unit2)
817 local
818 list<ComponentRef> vars1, vars2;
819 String s1, s2;
820
821 case (Unit.UNIT(), Unit.UNIT())
822 25029 then
823 (Unit.isEqual(unit1, unit2), unit1);
824
825 case (Unit.UNIT(), Unit.MASTER(varList = vars2))
826 algorithm
827 1172 List.map2_0(vars2, updateHtCr2U, unit1, htCr2U);
828 then
829 (true, unit1);
830
831 case (Unit.MASTER(varList = vars1), Unit.UNIT())
832 algorithm
833 10324 List.map2_0(vars1, updateHtCr2U, unit2, htCr2U);
834 then
835 (true, unit2);
836
837 case (Unit.MASTER(varList = vars1), Unit.MASTER(varList = vars2))
838 38987 then
839 (true, Unit.MASTER(List.append_reverse(vars1, vars2)));
840
841 case (Unit.UNKNOWN(unit = s1), Unit.UNKNOWN(unit = s2))
842
2/4
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 36 times.
36 then (s1 == s2, unit1);
843
844 case (Unit.UNKNOWN(), _) then (true, unit1);
845 case (_, Unit.UNKNOWN()) then (true, unit2);
846 else (false, unit1);
847 end match;
848 end unitTypesEqual;
849
850 function updateHtCr2U
851 input ComponentRef cref;
852 input Unit.Unit unit;
853 input Unit.CrefToUnitTable htCr2U;
854 algorithm
855 479 UnorderedMap.tryAdd(NFUnit.UPDATECREF, Unit.MASTER({}), htCr2U);
856 479 UnorderedMap.add(cref, unit, htCr2U);
857 end updateHtCr2U;
858
859 protected function Errorfunction "returns the inconsistent Equation with sub-expression"
860 input list<tuple<Expression, Unit.Unit>> inexpList;
861 input Equation inEq;
862 input Unit.UnitToStringTable inHtU2S;
863 algorithm
864 () := match inexpList
865 local
866 String s, s1, s2;
867 list<tuple<Expression, Unit.Unit>> expList;
868 SourceInfo info;
869 case expList
870 algorithm
871 8 info:=Equation.info(inEq);
872 8 s := Equation.toString(inEq);
873 8 s1 := Errorfunction2(expList, inHtU2S);
874 8 s2:="The following equation is INCONSISTENT due to specified unit information: " + s +"\n";
875 8 Error.addSourceMessage(Error.COMPILER_WARNING,{s2},info);
876 8 Error.addCompilerWarning("The units of following sub-expressions need to be equal:\n" + s1);
877
878 /*
879 Error.addCompilerWarning("The following NEWFRONTEND UNIT CHECK equation is INCONSISTENT due to specified unit information: " + s + "\n" +
880 "The units of following sub-expressions need to be equal:\n" + s1 );*/
881 then ();
882 end match;
883 end Errorfunction;
884
885 protected function Errorfunction2 "help-function"
886 input list<tuple<Expression, Unit.Unit>> inexpList;
887 input Unit.UnitToStringTable inHtU2S;
888 output String outS;
889 algorithm
890 outS := match inexpList
891 local
892 list<tuple<Expression, Unit.Unit>> expList;
893 Expression exp;
894 Unit.Unit ut;
895 String s, s1, s2;
896
897 case (exp, ut)::{} algorithm
898 8 s := Expression.toString(exp);
899 8 s1 := Unit.unitString(ut, inHtU2S);
900 8 s := "- sub-expression \"" + s + "\" has unit \"" + s1 + "\"";
901 then s;
902
903 case (exp, ut)::expList algorithm
904 8 s := Expression.toString(exp);
905 8 s1 := Unit.unitString(ut, inHtU2S);
906 8 s2 := Errorfunction2(expList, inHtU2S);
907 8 s := "- sub-expression \"" + s + "\" has unit \"" + s1 + "\"\n" + s2;
908 then s;
909 end match;
910 end Errorfunction2;
911
912
913 protected function foldCallArg "help-function for CALL case in function insertUnitInEquation"
914 input list<Expression> args;
915 input Unit.CrefToUnitTable htCr2U;
916 input Unit.StringToUnitTable htS2U;
917 input Unit.UnitToStringTable htU2S;
918 input FunctionUnitCache fnCache;
919 output list<list<tuple<Expression, Unit.Unit>>> inconsistentUnits = {};
920 protected
921 list<list<tuple<Expression, Unit.Unit>>> icu;
922 algorithm
923
2/2
✓ Branch 0 taken 6976 times.
✓ Branch 1 taken 3523 times.
10499 for exp in args loop
924 6976 (_, icu) :=
925 insertUnitInEquation(exp, Unit.MASTER({}), htCr2U, htS2U, htU2S, fnCache);
926 6976 inconsistentUnits := List.append_reverse(icu, inconsistentUnits);
927 end for;
928
929 3523 inconsistentUnits := listReverse(inconsistentUnits);
930 end foldCallArg;
931
932 function foldCallArg1
933 "Help function for CALL case in userdefinde top level function insertUnitInEquation"
934 input list<Expression> args;
935 input Unit.CrefToUnitTable htCr2U;
936 input Unit.StringToUnitTable htS2U;
937 input Unit.UnitToStringTable htU2S;
938 input FunctionUnitCache fnCache;
939 input Unit.Unit inUnit;
940 input list<String> units;
941 input list<String> vars;
942 input String fnName;
943 output list<list<tuple<Expression, Unit.Unit>>> inconsistentUnits = {};
944 protected
945 String unit, var;
946 list<String> rest_units = units, rest_vars = vars;
947 Unit.Unit op_unit, op_unit2;
948 list<list<tuple<Expression, Unit.Unit>>> icu;
949 Expression temp;
950 Boolean b;
951 algorithm
952
2/2
✓ Branch 0 taken 7333 times.
✓ Branch 1 taken 4017 times.
11350 for arg in args loop
953
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7333 times.
7333 var :: rest_vars := rest_vars;
954
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7333 times.
7333 unit :: rest_units := rest_units;
955
956 7333 (op_unit, icu) := insertUnitInEquation(arg, inUnit, htCr2U, htS2U, htU2S, fnCache);
957
958
4/4
✓ Branch 0 taken 6936 times.
✓ Branch 1 taken 397 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 6934 times.
7333 if unit == "NONE" then
959 op_unit2 := Unit.MASTER({});
960 else
961 399 op_unit2 := Unit.parseUnitString(unit, htS2U);
962 end if;
963
964 7333 (b, op_unit) := unitTypesEqual(op_unit, op_unit2, htCr2U);
965
966
2/2
✓ Branch 0 taken 7329 times.
✓ Branch 1 taken 4 times.
7333 if b then
967 7329 icu := {};
968 else
969 4 temp := makeNewCref(var, fnName);
970 8 icu := {{(arg, op_unit), (temp, op_unit2)}};
971 end if;
972
973 7333 inconsistentUnits := List.append_reverse(icu, inconsistentUnits);
974 end for;
975 end foldCallArg1;
976
977 protected function addUnit2HtS2U
978 input String name;
979 input Unit.Unit unit;
980 input Unit.StringToUnitTable inHtS2U;
981 algorithm
982 22140 UnorderedMap.add(name, unit, inHtS2U);
983 end addUnit2HtS2U;
984
985 protected function addUnit2HtU2S
986 input String name;
987 input Unit.Unit unit;
988 input Unit.UnitToStringTable htU2S;
989 algorithm
990 22140 UnorderedMap.tryAdd(unit, name, htU2S);
991 end addUnit2HtU2S;
992
993 function convertUnitStringToUnit
994 "converts String to unit"
995 input Variable var;
996 input Unit.CrefToUnitTable htCr2U;
997 input Unit.StringToUnitTable htS2U;
998 input Unit.UnitToStringTable htU2S;
999 protected
1000 Binding unit_binding;
1001 Option<Expression> unit_exp;
1002 String unit_string;
1003 Unit.Unit unit;
1004 algorithm
1005 48367 unit_binding := Variable.lookupTypeAttribute("unit", var);
1006 48367 unit_exp := Binding.typedExp(unit_binding);
1007
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 48367 times.
✓ Branch 2 taken 30472 times.
✓ Branch 3 taken 17895 times.
48367 unit_string := if isSome(unit_exp) then getUnitStringFromExp(Util.getOption(unit_exp)) else "";
1008
1009
2/2
✓ Branch 0 taken 17896 times.
✓ Branch 1 taken 30471 times.
48367 if stringEmpty(unit_string) then
1010 17896 UnorderedMap.add(var.name, Unit.MASTER({var.name}), htCr2U);
1011 17896 addUnit2HtS2U("-", Unit.MASTER({var.name}), htS2U);
1012 17896 addUnit2HtU2S("-", Unit.MASTER({var.name}), htU2S);
1013 else
1014 30471 unit := parse(unit_string, var.name, htS2U, htU2S, var.info);
1015 30471 UnorderedMap.add(var.name, unit, htCr2U);
1016 end if;
1017 end convertUnitStringToUnit;
1018
1019 function getUnitStringFromExp
1020 input Expression unitExp;
1021 output String unitString;
1022 protected
1023 Expression exp;
1024 algorithm
1025 unitString := match unitExp
1026 // A literal string expression, return the string.
1027 30472 case Expression.STRING() then unitExp.value;
1028
1029 // A literal array. This happens for array variables, assume each variable
1030 // has the same unit for now.
1031 case Expression.ARRAY(literal = true)
1032 guard Expression.isLiteral(unitExp) and not Type.isEmptyArray(Expression.typeOf(unitExp))
1033 ✗ then getUnitStringFromExp(Expression.arrayFirstScalar(unitExp));
1034
1035 // A fill call. Will generate an array where all elements are the same, so
1036 // no need to evaluate it.
1037 case Expression.CALL(Call.TYPED_CALL(arguments = exp :: _))
1038 guard Call.isNamed(unitExp.call, "fill")
1039 15086 then getUnitStringFromExp(exp);
1040
1041 // A non-literal expression, evaluate it and try again if it could be evaluated.
1042 case _
1043 guard not Expression.isLiteral(unitExp)
1044 algorithm
1045 ✗ exp := Ceval.tryEvalExp(unitExp);
1046 ✗ then
1047 if Expression.isLiteral(exp) then getUnitStringFromExp(exp) else "";
1048
1049 else "";
1050 end match;
1051 end getUnitStringFromExp;
1052
1053 protected function parse "author: lochel"
1054 input String unitString;
1055 input ComponentRef cref;
1056 input Unit.StringToUnitTable htS2U;
1057 input Unit.UnitToStringTable htU2S;
1058 input SourceInfo info;
1059 output Unit.Unit unit;
1060 algorithm
1061
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30471 times.
30471 if stringEmpty(unitString) then
1062 ✗ unit := Unit.MASTER({cref});
1063 ✗ return;
1064 end if;
1065 try
1066 30471 unit := UnorderedMap.getOrFail(unitString, htS2U);
1067 else
1068 try
1069 589 unit := Unit.parseUnitString(unitString, htS2U, info);
1070 else
1071 ✗ unit := Unit.UNKNOWN(unitString);
1072 end try;
1073 589 addUnit2HtS2U(unitString, unit, htS2U);
1074 589 addUnit2HtU2S(unitString, unit, htU2S);
1075 end try;
1076 end parse;
1077
1078 annotation(__OpenModelica_Interface="nf_frontend");
1079 end NFUnitCheck;
1080