Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 84.0% 142 / 0 / 169
Functions: -% 0 / 1 / 1
Branches: 72.5% 58 / 0 / 80

OMCompiler/Compiler/NBackEnd/Modules/2_Pre/NBDetectStates.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 NBDetectStates
37 " file: NBDetectStates.mo
38 package: NBDetectStates
39 description: This file contains all functions for the detection of continuous
40 and discrete state variables.
41 "
42
43 public
44 import Module = NBModule;
45
46 protected
47 // Old Frontend Imports
48 import Absyn;
49
50 // New Frontend Imports
51 import Call = NFCall;
52 import ComponentRef = NFComponentRef;
53 import Expression = NFExpression;
54 import Function = NFFunction;
55 import InstNode = NFInstNode.InstNode;
56 import SimplifyExp = NFSimplifyExp;
57 import Type = NFType;
58 import Operator = NFOperator;
59 import Variable = NFVariable;
60 import NFBackendExtension.{StateSelect, VariableKind};
61
62 // Backend imports
63 import BackendDAE = NBackendDAE;
64 import BEquation = NBEquation;
65 import BVariable = NBVariable;
66 import Differentiate = NBDifferentiate;
67 import NBEquation.{Equation, EquationPointers, EqData, EquationAttributes, EquationKind, Iterator, WhenEquationBody, WhenStatement, IfEquationBody};
68 import FunctionAlias = NBFunctionAlias;
69 import BPartition = NBPartition;
70 import NBVariable.{VariablePointers, VarData};
71
72 // Util
73 import StringUtil;
74
75 // =========================================================================
76 // MAIN ROUTINE, PLEASE DO NOT CHANGE
77 // =========================================================================
78 public
79 function main
80 "Wrapper function for any detect states function. This will be
81 called during simulation and gets the corresponding subfunction from
82 Config."
83 extends Module.wrapper;
84 protected
85 Module.detectStatesInterface mainFunc;
86 Module.detectContinuousStatesInterface contFunc;
87 Module.detectDiscreteStatesInterface discFunc;
88 algorithm
89 190 (mainFunc, contFunc, discFunc) := getModule();
90
91 bdae := match bdae
92 local
93 VarData varData "Data containing variable pointers";
94 EqData eqData "Data containing equation pointers";
95 case BackendDAE.MAIN(varData = varData, eqData = eqData)
96 algorithm
97
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
190 (varData, eqData) := mainFunc(varData, eqData, contFunc, discFunc);
98 190 bdae.varData := varData;
99 190 bdae.eqData := eqData;
100 then bdae;
101
102 else algorithm
103 ✗ Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed."});
104 ✗ then fail();
105 end match;
106 end main;
107
108 function getModule
109 "Returns the module function that was chosen by the user."
110 output Module.detectStatesInterface mainFunc;
111 output Module.detectContinuousStatesInterface contFunc;
112 output Module.detectDiscreteStatesInterface discFunc;
113 protected
114 String flag = "default"; //Flags.getConfigString(Flags.DETECT_STATES)
115 algorithm
116 (mainFunc, contFunc, discFunc) := match flag
117 case "default" then (detectStatesDefault, detectContinuousStatesDefault, detectDiscreteStatesDefault);
118 /* ... New detect states modules have to be added here */
119 else fail();
120 end match;
121 end getModule;
122
123 /* =========================================================================
124 SUB ROUTINES
125 ========================================================================= */
126 protected
127 function detectStatesDefault extends Module.detectStatesInterface;
128 protected
129 VariablePointers variables "All variables";
130 EquationPointers equations "System equations";
131 EquationPointers disc_eqns "Discrete equations";
132 EquationPointers init_eqns "Initial equations";
133 EquationPointers removed_eqns "Removed equations";
134 VariablePointers unknowns "Unknowns";
135 VariablePointers knowns "Knowns";
136 VariablePointers initials "Initial unknowns";
137 VariablePointers states "States";
138 VariablePointers derivatives "State derivatives (der(x) -> $DER.x)";
139 VariablePointers algebraics "Algebraic variables";
140 VariablePointers discretes "Discrete variables";
141 VariablePointers discrete_states"Discrete state variables";
142 VariablePointers clocked_states "Clocked state variables";
143 VariablePointers previous "Previous discrete variables (pre(d) -> $PRE.d)";
144 list<Pointer<Equation>> aux_eqns;
145 EqData newEqData;
146 algorithm
147 // introduce sliced state alias before resolving the der() calls
148 190 (varData, eqData) := FunctionAlias.introduceSlicedStateAlias(varData, eqData, NBPartition.Kind.ODE);
149
150 (varData, eqData) := match (varData, eqData)
151 case (BVariable.VAR_DATA_SIM(), BEquation.EQ_DATA_SIM()) algorithm
152
153 // collect continuous states from all equations
154
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
190 (variables, unknowns, knowns, initials, states, derivatives, algebraics, aux_eqns)
155 := continuousFunc(varData.variables, varData.unknowns, varData.knowns, varData.initials, varData.states, varData.derivatives, varData.algebraics, eqData.equations);
156
157 // collect discrete states from discrete equations
158
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
190 (variables, disc_eqns, knowns, initials, discretes, discrete_states, clocked_states, previous)
159 := discreteFunc(varData.variables, eqData.discretes, varData.knowns, varData.initials, varData.discretes, varData.discrete_states, varData.clocked_states, varData.previous, "discrete equations");
160
161 // collect clocked states from clocked equations
162
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
190 (variables, disc_eqns, knowns, initials, discretes, discrete_states, clocked_states, previous)
163 := discreteFunc(variables, eqData.clocked, knowns, initials, discretes, discrete_states, clocked_states, previous, "clocked equations");
164
165 // collect clocked states from continuous equations
166
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
190 (variables, disc_eqns, knowns, initials, discretes, discrete_states, clocked_states, previous)
167 := discreteFunc(variables, eqData.continuous, knowns, initials, discretes, discrete_states, clocked_states, previous, "continuous equations");
168
169 // collect discrete states from initial equations
170
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
190 (variables, init_eqns, knowns, initials, discretes, discrete_states, clocked_states, previous)
171 := discreteFunc(variables, eqData.initials, knowns, initials, discretes, discrete_states, clocked_states, previous, "initial equations");
172
173 // collect pre, edge and change from the removed equations, e.g. when equations that only have reinit
174
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
190 (variables, removed_eqns, knowns, initials, discretes, discrete_states, clocked_states, previous)
175 := discreteFunc(variables, eqData.removed, knowns, initials, discretes, discrete_states, clocked_states, previous, "removed equations");
176
177 // update variable arrays
178 190 varData.variables := variables;
179 190 varData.unknowns := unknowns;
180 190 varData.knowns := knowns;
181 190 varData.initials := initials;
182 190 varData.derivatives := derivatives;
183 190 varData.algebraics := algebraics;
184 190 varData.discretes := discretes;
185 190 varData.discrete_states := discrete_states;
186 190 varData.clocked_states := clocked_states;
187 190 varData.previous := previous;
188 190 varData.states := states;
189
190 // update equation arrays
191 190 newEqData := EqData.addTypedList(eqData, aux_eqns, EqData.EqType.CONTINUOUS, false);
192
193 // detect state order
194 190 EquationPointers.map(EqData.getEquations(newEqData), function stateOrder(state_order = varData.state_order));
195
4/4
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 185 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 2 times.
190 if Flags.isSet(Flags.DUMP_STATESELECTION_INFO) and not UnorderedMap.isEmpty(varData.state_order) then
196 3 print(StringUtil.headline_4("[stateselection] State Order:"));
197 3 print("\t" + UnorderedMap.toString(varData.state_order, ComponentRef.toString, ComponentRef.toString, "\n\t", " --d/dt--> ") + "\n\n");
198 end if;
199 then (varData, newEqData);
200 else (varData, eqData);
201 end match;
202 end detectStatesDefault;
203
204 function detectContinuousStatesDefault extends Module.detectContinuousStatesInterface;
205 protected
206 Pointer<list<Pointer<Variable>>> acc_states = Pointer.create({});
207 Pointer<list<Pointer<Variable>>> acc_derivatives = Pointer.create({});
208 Pointer<list<Pointer<Equation>>> acc_aux_equations = Pointer.create({});
209 Pointer<Integer> uniqueIndex = Pointer.create(0);
210 Differentiate.DifferentiationArguments diffArgs = Differentiate.DifferentiationArguments.default();
211 algorithm
212 // collect all 'natural' states der(x)
213 190 EquationPointers.mapExp(equations, function collectStatesAndDerivatives(acc_states = acc_states, acc_derivatives = acc_derivatives, scalarized = variables.scalarized));
214 // resolve all general der(exp) expressions
215 190 EquationPointers.mapExp(equations, function resolveGeneralDer(acc_states = acc_states, acc_derivatives = acc_derivatives, acc_aux_equations = acc_aux_equations, uniqueIndex = uniqueIndex, diffArgs = diffArgs));
216 // move stuff to their correct arrays
217 190 (variables, unknowns, knowns, initials, states, derivatives, algebraics) := updateStatesAndDerivatives(variables, unknowns, knowns, initials, states, derivatives, algebraics, Pointer.access(acc_states), Pointer.access(acc_derivatives));
218
219 // promote StateSelect.prefer variables if their derivative already exists
220 190 (variables, unknowns, knowns, initials, states, derivatives, algebraics) := promotePreferStates(variables, unknowns, knowns, initials, states, derivatives, algebraics);
221
222 190 aux_eqns := Pointer.access(acc_aux_equations);
223
4/4
✓ Branch 1 taken 185 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 1 time.
190 if Flags.isSet(Flags.DUMP_STATESELECTION_INFO) and not listEmpty(aux_eqns) then
224 1 print(StringUtil.headline_4("[stateselection] (" + intString(listLength(aux_eqns)) + ") Created auxiliary equations:"));
225 1 print(List.toString(aux_eqns, function Equation.pointerToString(str=""), List.Style.NEWLINE_TAB) + "\n\n");
226 end if;
227 end detectContinuousStatesDefault;
228
229 function detectDiscreteStatesDefault extends Module.detectDiscreteStatesInterface;
230 protected
231 Pointer<list<Pointer<Variable>>> acc_discrete_states = Pointer.create({});
232 Pointer<list<Pointer<Variable>>> acc_clocked_states = Pointer.create({});
233 Pointer<list<Pointer<Variable>>> acc_previous = Pointer.create({});
234 algorithm
235 // collect all states on the lhs of a when
236 950 EquationPointers.map(equations, function collectDiscreteStatesFromWhen(acc_discrete_states = acc_discrete_states, acc_previous = acc_previous, scalarized = variables.scalarized));
237 // collect all pre(d)
238 950 EquationPointers.mapExp(equations, function collectPreAndPrevious(acc_previous = acc_previous, acc_clocked_states = acc_clocked_states, scalarized = variables.scalarized));
239 // move stuff to their correct arrays
240 950 (variables, knowns, initials, discretes, discrete_states, clocked_states, previous) := updateDiscreteStatesAndPrevious(variables, knowns, initials, discretes, discrete_states, clocked_states, previous, Pointer.access(acc_discrete_states), Pointer.access(acc_clocked_states), Pointer.access(acc_previous), context);
241 end detectDiscreteStatesDefault;
242
243 function collectStatesAndDerivatives
244 "Collects all states and creates a derivative variable for each."
245 input output Expression exp;
246 input Pointer<list<Pointer<Variable>>> acc_states;
247 input Pointer<list<Pointer<Variable>>> acc_derivatives;
248 input Boolean scalarized;
249 algorithm
250 exp := match exp
251 local
252 Expression res;
253 ComponentRef state_cref, der_cref;
254 Pointer<Variable> state_var, der_var;
255
256 // parse all der(x) calls where x is not a state derivative. those need to be handled by resolveGeneralDer()
257 case Expression.CALL(call = Call.TYPED_CALL(fn = Function.FUNCTION(path = Absyn.IDENT(name = "der")),
258 arguments = {Expression.CREF(cref = state_cref)})) guard(not BVariable.checkCref(state_cref, BVariable.isStateDerivative, sourceInfo()))
259 algorithm
260 185 state_var := BVariable.getVarPointer(state_cref, sourceInfo());
261
262
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 180 times.
185 if not BVariable.isContinuous(state_var, false) then
263 // if the variable is not continuous, its derivative is zero
264 5 res := Expression.makeZero(ComponentRef.getSubscriptedType(state_cref));
265 else
266
2/2
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 140 times.
180 if BVariable.hasDerVar(state_var) then
267 // this derivative was already created -> the variable should already have a pointer to its derivative
268 40 der_cref := BVariable.getPartnerCref(state_cref, BVariable.getVarDer, scalarized);
269 else
270 // create new derivative variable
271 140 (der_cref, der_var) := BVariable.makeDerVar(state_cref, scalarized);
272 140 state_var := BVariable.getVarPointer(state_cref, sourceInfo());
273 140 BVariable.setStateDerivativeVar(state_var, der_var);
274 280 Pointer.update(acc_states, state_var :: Pointer.access(acc_states));
275 140 Pointer.update(acc_derivatives, der_var :: Pointer.access(acc_derivatives));
276 end if;
277 180 res := Expression.fromCref(der_cref);
278 end if;
279 then res;
280
281 else exp;
282 end match;
283 end collectStatesAndDerivatives;
284
285 function resolveGeneralDer
286 "Collects all states and creates a derivative variable for each."
287 input output Expression exp;
288 input Pointer<list<Pointer<Variable>>> acc_states;
289 input Pointer<list<Pointer<Variable>>> acc_derivatives;
290 input Pointer<list<Pointer<Equation>>> acc_aux_equations;
291 input Pointer<Integer> uniqueIndex;
292 input Differentiate.DifferentiationArguments diffArgs;
293 algorithm
294 exp := match exp
295 local
296 ComponentRef state_cref, der_cref;
297 Pointer<Variable> state_var, der_var;
298 Expression arg, returnExp;
299 Pointer<Equation> aux_equation;
300 Differentiate.DifferentiationArguments oDiffArgs;
301
302 case Expression.CALL(call = Call.TYPED_CALL(fn = Function.FUNCTION(path = Absyn.IDENT(name = "der")), arguments = {arg}))
303 algorithm
304
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
6 if Expression.fold(arg, checkAlgebraic, 0) > 1 then
305 // more than one algebraic variable > create auxiliary state
306 3 (state_var, state_cref, der_var, der_cref) := BVariable.makeAuxStateVar(Pointer.access(uniqueIndex), SOME(arg));
307 3 aux_equation := Equation.makeAssignment(Expression.fromCref(state_cref), arg, uniqueIndex, NBVariable.AUXILIARY_STR, Iterator.EMPTY(), EquationAttributes.default(EquationKind.CONTINUOUS, false));
308 3 returnExp := Expression.fromCref(der_cref);
309
310 6 Pointer.update(acc_states, state_var :: Pointer.access(acc_states));
311 3 Pointer.update(acc_derivatives, der_var :: Pointer.access(acc_derivatives));
312 6 Pointer.update(acc_aux_equations, aux_equation :: Pointer.access(acc_aux_equations));
313 else
314 // one or less algebraic variables > differentiate the expression
315 3 (returnExp, oDiffArgs) := Differentiate.differentiateExpression(arg, diffArgs);
316 3 returnExp := SimplifyExp.simplifyDump(returnExp, true, getInstanceName());
317
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 time.
3 if List.hasOneElement(oDiffArgs.new_vars) then
318 2 der_var := listHead(oDiffArgs.new_vars);
319 2 Pointer.update(acc_derivatives, der_var :: Pointer.access(acc_derivatives));
320 4 Pointer.update(acc_states, Util.getOption(BVariable.getVarState(der_var)) :: Pointer.access(acc_states));
321 elseif List.hasSeveralElements(oDiffArgs.new_vars) then
322 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because the number of algebraic variables were miscounted! " +
323 "Expected: 0 or 1, got: " + intString(listLength(oDiffArgs.new_vars))});
324 ✗ fail();
325 end if;
326 end if;
327 then returnExp;
328
329 else exp;
330 end match;
331 end resolveGeneralDer;
332
333 function checkAlgebraic
334 "Needs to be mapped with Expression.fold()
335 counts the number of algebraic variables in an expression.
336 Count state derivatives double to ensure that they get an auxiliary."
337 input Expression exp;
338 input output Integer i;
339 algorithm
340 i := match exp
341 2 case Expression.CREF() guard(BVariable.isStateDerivative(BVariable.getVarPointer(exp.cref, sourceInfo()))) then i + 2;
342 4 case Expression.CREF() guard(BVariable.isAlgebraic(BVariable.getVarPointer(exp.cref, sourceInfo()))) then i + 1;
343 else i;
344 end match;
345 end checkAlgebraic;
346
347 function updateStatesAndDerivatives
348 "Updates the variable pointer arrays with the new information about states and derivatives."
349 input output VariablePointers variables "All variables";
350 input output VariablePointers unknowns "Unknowns";
351 input output VariablePointers knowns "Knowns";
352 input output VariablePointers initials "Initial unknowns";
353 input output VariablePointers states "States";
354 input output VariablePointers derivatives "State derivatives (der(x) -> $DER.x)";
355 input output VariablePointers algebraics "Algebraic variables";
356 input list<Pointer<Variable>> acc_states;
357 input list<Pointer<Variable>> acc_derivatives;
358 algorithm
359 // Add the new derivatives to variables, unknowns and derivative pointer arrays
360 190 variables := VariablePointers.addList(acc_derivatives, variables);
361 190 unknowns := VariablePointers.addList(acc_derivatives, unknowns);
362 190 initials := VariablePointers.addList(acc_derivatives, initials);
363 190 derivatives := VariablePointers.addList(acc_derivatives, derivatives);
364
365 // add states to variables and state pointer array
366 190 variables := VariablePointers.addList(acc_states, variables);
367 190 states := VariablePointers.addList(acc_states, states);
368
369 // remove states from unknowns and algebraics
370 190 unknowns := VariablePointers.removeList(acc_states, unknowns);
371 190 algebraics := VariablePointers.removeList(acc_states, algebraics);
372
373
2/2
✓ Branch 1 taken 185 times.
✓ Branch 2 taken 5 times.
190 if Flags.isSet(Flags.DUMP_STATESELECTION_INFO) then
374 5 print(StringUtil.headline_4("[stateselection] (" + intString(listLength(acc_states)) + ") Natural states before index reduction:"));
375
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if listEmpty(acc_states) then
376 ✗ print("\t<no states>\n\n");
377 else
378 5 print(List.toString(acc_states, BVariable.pointerToString, List.Style.NEWLINE_TAB) + "\n\n");
379 end if;
380 end if;
381 end updateStatesAndDerivatives;
382
383 function collectPreAndPrevious
384 "Collects all pre and previous variables. Only to be used on discrete equations!"
385 input output Expression exp;
386 input Pointer<list<Pointer<Variable>>> acc_previous;
387 input Pointer<list<Pointer<Variable>>> acc_clocked_states;
388 input Boolean scalarized;
389 algorithm
390 exp := match exp
391 local
392 Function.Function fn;
393 Boolean b;
394 list<Expression> args;
395 Expression new_exp, old_exp;
396
397 // the call has an input that is only a boolean. for pre() return the boolean, for edge() and change() always false
398 case Expression.CALL(call = Call.TYPED_CALL(fn = fn, arguments = {Expression.BOOLEAN(b)}))
399 algorithm
400 new_exp := match fn
401 ✗ case Function.FUNCTION(path = Absyn.IDENT(name = "previous")) then Expression.BOOLEAN(b);
402 ✗ case Function.FUNCTION(path = Absyn.IDENT(name = "pre")) then Expression.BOOLEAN(b);
403 case Function.FUNCTION(path = Absyn.IDENT(name = "edge")) then Expression.BOOLEAN(false);
404 case Function.FUNCTION(path = Absyn.IDENT(name = "change")) then Expression.BOOLEAN(false);
405 else exp;
406 end match;
407 then new_exp;
408
409 // the expression is previous(d) -> $PRE.d or previous(not d) -> not $PRE.d
410 // also store the clocked state
411 case Expression.CALL(call = Call.TYPED_CALL(fn = Function.FUNCTION(path = Absyn.IDENT(name = "previous")), arguments = args))
412 algorithm
413 6 (new_exp, old_exp) := preFromArgs(args, acc_previous, scalarized, "previous");
414 () := match old_exp
415 case Expression.CREF() algorithm
416 12 Pointer.update(acc_clocked_states, BVariable.getVarPointer(old_exp.cref, sourceInfo()) :: Pointer.access(acc_clocked_states));
417 then ();
418
419 else algorithm
420 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because previous() can only contain component references, but contained: "
421 + Expression.toString(old_exp)});
422 ✗ then fail();
423 end match;
424 then new_exp;
425
426 // the expression is pre(d) -> $PRE.d or pre(not d) -> not $PRE.d
427 case Expression.CALL(call = Call.TYPED_CALL(fn = Function.FUNCTION(path = Absyn.IDENT(name = "pre")), arguments = args))
428 algorithm
429 100 (new_exp, _) := preFromArgs(args, acc_previous, scalarized, "pre");
430 then new_exp;
431
432 // the expression is edge(d) -> d and not $PRE.d or edge(not d) not d and $PRE.d
433 case Expression.CALL(call = Call.TYPED_CALL(fn = Function.FUNCTION(path = Absyn.IDENT(name = "edge")), arguments = args))
434 algorithm
435 ✗ (new_exp, old_exp) := preFromArgs(args, acc_previous, scalarized, "edge");
436 ✗ then Expression.LBINARY(old_exp, Operator.makeAnd(Expression.typeOf(old_exp)), Expression.logicNegate(new_exp));
437
438 // the expression is change(d) -> d <> $PRE.d or change(not d) not d <> not $PRE.d
439 // (not necessary to have the "not" but works and is most consistent with other cases)
440 case Expression.CALL(call = Call.TYPED_CALL(fn = Function.FUNCTION(path = Absyn.IDENT(name = "change")), arguments = args))
441 algorithm
442 ✗ (new_exp, old_exp) := preFromArgs(args, acc_previous, scalarized, "change");
443 ✗ then Expression.RELATION(old_exp, Operator.makeNotEqual(Expression.typeOf(old_exp)), new_exp, -1);
444
445 else exp;
446 end match;
447 end collectPreAndPrevious;
448
449 function preFromArgs
450 "takes a list of arguments (expected to be only one cref) and creates the pre variable from it.
451 used for pre(), edge(), change()"
452 input list<Expression> args;
453 input Pointer<list<Pointer<Variable>>> acc_previous;
454 input Boolean scalarized;
455 input String context;
456 output Expression new_exp;
457 output Expression old_exp;
458 protected
459 ComponentRef state_cref, pre_cref;
460 Pointer<Variable> state_var;
461 Boolean negated;
462 algorithm
463 (state_var, old_exp, negated) := match args
464 106 case {old_exp as Expression.CREF(cref = state_cref)} then (BVariable.getVarPointer(state_cref, sourceInfo()), old_exp, false);
465 ✗ case {old_exp as Expression.LUNARY(exp = Expression.CREF(cref = state_cref))} then (BVariable.getVarPointer(state_cref, sourceInfo()), old_exp, true);
466 else algorithm
467 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of unexpected expression " + context + "("
468 + List.toString(args, Expression.toString, List.Style.FLAT) + ")."});
469 ✗ then fail();
470 end match;
471 106 pre_cref := getPreVar(state_cref, state_var, acc_previous, scalarized);
472
473 106 new_exp := Expression.fromCref(pre_cref);
474
1/2
✓ Branch 0 taken 106 times.
✗ Branch 1 not taken.
106 if negated then
475 ✗ new_exp := Expression.logicNegate(new_exp);
476 end if;
477 end preFromArgs;
478
479 function updateDiscreteStatesAndPrevious
480 "Updates the variable pointer arrays with the new information about states and derivatives."
481 input output VariablePointers variables "All variables";
482 input output VariablePointers knowns "Knowns";
483 input output VariablePointers initials "initial unknowns";
484 input output VariablePointers discretes "Discrete variables";
485 input output VariablePointers discrete_states "Discrete state variables";
486 input output VariablePointers clocked_states "Clocked state variables";
487 input output VariablePointers previous "Previous (left limit) variables";
488 input list<Pointer<Variable>> acc_discrete_states;
489 input list<Pointer<Variable>> acc_clocked_states;
490 input list<Pointer<Variable>> acc_previous;
491 input String context "only for debugging";
492 algorithm
493 // Add the new derivatives to variables, unknowns and derivative pointer arrays
494 950 variables := VariablePointers.addList(acc_previous, variables);
495 950 knowns := VariablePointers.addList(acc_previous, knowns);
496 950 initials := VariablePointers.addList(acc_previous, initials);
497 950 previous := VariablePointers.addList(acc_previous, previous);
498 950 discrete_states := VariablePointers.addList(acc_discrete_states, discrete_states);
499 950 clocked_states := VariablePointers.addList(acc_clocked_states, clocked_states);
500 // remove discrete states from discretes and remove clocked states from both discretes and discrete states
501 950 discretes := VariablePointers.removeList(acc_discrete_states, discretes);
502 950 discretes := VariablePointers.removeList(acc_clocked_states, discretes);
503 950 discrete_states := VariablePointers.removeList(acc_clocked_states, discrete_states);
504
505
2/2
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 925 times.
950 if Flags.isSet(Flags.DUMP_STATESELECTION_INFO) then
506
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if not listEmpty(acc_discrete_states) then
507 ✗ print(StringUtil.headline_4("[stateselection] Natural discrete states from " + context + ":"));
508 ✗ print(List.toString(acc_discrete_states, BVariable.pointerToString, List.Style.NEWLINE_TAB) + "\n\n");
509 end if;
510
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if not listEmpty(acc_clocked_states) then
511 ✗ print(StringUtil.headline_4("[stateselection] Natural clocked states from " + context + ":"));
512 ✗ print(List.toString(acc_clocked_states, BVariable.pointerToString, List.Style.NEWLINE_TAB) + "\n\n");
513 end if;
514 end if;
515
516
1/2
✓ Branch 1 taken 950 times.
✗ Branch 2 not taken.
950 if Flags.isSet(Flags.DUMP_DISCRETEVARS_INFO) then
517 ✗ if not listEmpty(acc_previous) then
518 ✗ print(StringUtil.headline_4("[discreteinfo] pre() and previous() variables from " + context + ":"));
519 ✗ print(List.toString(acc_previous, BVariable.pointerToString, List.Style.NEWLINE_TAB) + "\n\n");
520 end if;
521 end if;
522
523 end updateDiscreteStatesAndPrevious;
524
525 function collectDiscreteStatesFromWhen
526 "All variables on the LHS in a when equation are considered discrete."
527 input output Equation eqn "outputs equation just to fit the map() interface. does not change.";
528 input Pointer<list<Pointer<Variable>>> acc_discrete_states;
529 input Pointer<list<Pointer<Variable>>> acc_previous;
530 input Boolean scalarized;
531 algorithm
532 () := match eqn
533 case Equation.WHEN_EQUATION() algorithm
534 74 collectDiscreteStatesFromWhenBody(eqn.body, acc_discrete_states, acc_previous, scalarized);
535 then ();
536 case Equation.FOR_EQUATION() algorithm
537
2/2
✓ Branch 0 taken 304 times.
✓ Branch 1 taken 304 times.
608 for b_eqn in eqn.body loop
538 304 collectDiscreteStatesFromWhen(b_eqn, acc_discrete_states, acc_previous, scalarized);
539 end for;
540 then ();
541 case Equation.IF_EQUATION() algorithm
542 5 collectDiscreteStatesFromWhenInIf(eqn.body, acc_discrete_states, acc_previous, scalarized);
543 then ();
544 else ();
545 end match;
546 end collectDiscreteStatesFromWhen;
547
548 function collectDiscreteStatesFromWhenBody
549 "All variables on the LHS in a when equation are considered discrete."
550 input WhenEquationBody body;
551 input Pointer<list<Pointer<Variable>>> acc_discrete_states;
552 input Pointer<list<Pointer<Variable>>> acc_previous;
553 input Boolean scalarized;
554 algorithm
555
2/2
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 74 times.
148 for body_stmt in body.when_stmts loop
556 () := match body_stmt
557 local
558 ComponentRef state_cref;
559 Pointer<Variable> state_var;
560
561 case WhenStatement.ASSIGN(lhs = Expression.CREF(cref = state_cref)) algorithm
562 // the function getPreVar() does all necessary collecting of information
563 // but we don't need the actual pre cref it returns
564 68 state_var := BVariable.getVarPointer(state_cref, sourceInfo());
565 68 BVariable.makeDiscreteStateVar(state_var);
566 68 getPreVar(state_cref, state_var, acc_previous, scalarized);
567 136 Pointer.update(acc_discrete_states, state_var :: Pointer.access(acc_discrete_states));
568 then ();
569
570 else ();
571 end match;
572 end for;
573 end collectDiscreteStatesFromWhenBody;
574
575 function collectDiscreteStatesFromWhenInIf
576 input IfEquationBody body;
577 input Pointer<list<Pointer<Variable>>> acc_discrete_states;
578 input Pointer<list<Pointer<Variable>>> acc_previous;
579 input Boolean scalarized;
580 algorithm
581
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
20 for eqn in body.then_eqns loop
582 10 collectDiscreteStatesFromWhen(Pointer.access(eqn), acc_discrete_states, acc_previous, scalarized);
583 end for;
584
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 5 times.
10 if isSome(body.else_if) then
585 5 collectDiscreteStatesFromWhenInIf(Util.getOption(body.else_if), acc_discrete_states, acc_previous, scalarized);
586 end if;
587 end collectDiscreteStatesFromWhenInIf;
588
589 function getPreVar
590 input ComponentRef var_cref;
591 input Pointer<Variable> var_ptr;
592 input Pointer<list<Pointer<Variable>>> acc_previous;
593 input Boolean scalarized;
594 output ComponentRef pre_cref;
595 protected
596 Option<Pointer<Variable>> pre = BVariable.getVarPre(var_ptr);
597 Pointer<Variable> pre_var;
598 algorithm
599
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 174 times.
✓ Branch 2 taken 81 times.
✓ Branch 3 taken 93 times.
174 if isSome(pre) then
600 93 SOME(pre_var) := pre;
601 93 pre_cref := BVariable.getVarName(pre_var);
602 93 pre_cref := ComponentRef.copySubscripts(var_cref, pre_cref);
603 else
604
1/2
✓ Branch 0 taken 81 times.
✗ Branch 1 not taken.
81 if not scalarized then
605 // prevent the created pre variable from having the subscripts, but add it to the pre_cref
606 81 (pre_cref, pre_var) := BVariable.makePreVar(ComponentRef.stripSubscriptsAll(var_cref));
607 81 pre_cref := ComponentRef.copySubscripts(var_cref, pre_cref);
608 else
609 ✗ (pre_cref, pre_var) := BVariable.makePreVar(var_cref);
610 end if;
611 81 Pointer.update(acc_previous, pre_var :: Pointer.access(acc_previous));
612 end if;
613 end getPreVar;
614
615 public function findDiscreteStatesFromWhenBody
616 "All variables on the LHS in a when equation are considered discrete, add these to acc lists"
617 input WhenEquationBody body;
618 input Pointer<list<Pointer<Variable>>> acc_discrete_states;
619 input Pointer<list<Pointer<Variable>>> acc_previous;
620 algorithm
621
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 for body_stmt in body.when_stmts loop
622 () := match body_stmt
623 local
624 ComponentRef state_cref;
625 Pointer<Variable> state_var, pre_var;
626
627 case WhenStatement.ASSIGN(lhs = Expression.CREF(cref = state_cref)) algorithm
628 1 state_var := BVariable.getVarPointer(state_cref, sourceInfo());
629 () := match BVariable.getVarPre(state_var)
630 case SOME(pre_var) algorithm
631 2 Pointer.update(acc_previous, pre_var :: Pointer.access(acc_previous));
632 then ();
633 else ();
634 end match;
635 2 Pointer.update(acc_discrete_states, state_var :: Pointer.access(acc_discrete_states));
636 then ();
637 else ();
638 end match;
639 end for;
640 end findDiscreteStatesFromWhenBody;
641
642 function stateOrder
643 input output Equation eqn;
644 input UnorderedMap<ComponentRef, ComponentRef> state_order;
645 protected
646 Expression lhs, rhs;
647 algorithm
648 () := match eqn
649 case Equation.SCALAR_EQUATION(lhs = lhs as Expression.CREF(), rhs = rhs as Expression.CREF()) algorithm
650 680 updateStateOrder(lhs.cref, rhs.cref, state_order);
651 then ();
652
653 // ToDo: sliced array/for-loops
654 case Equation.ARRAY_EQUATION(lhs = lhs as Expression.CREF(), rhs = rhs as Expression.CREF()) algorithm
655 219 updateStateOrder(lhs.cref, rhs.cref, state_order);
656 then ();
657
658 case Equation.FOR_EQUATION() algorithm
659
2/2
✓ Branch 0 taken 304 times.
✓ Branch 1 taken 304 times.
608 for b in eqn.body loop
660 304 stateOrder(b, state_order);
661 end for;
662 then ();
663
664 else ();
665 end match;
666 end stateOrder;
667
668 function promotePreferStates
669 "Promotes StateSelect.prefer variables to states if the model has ANY der() calls.
670 Only relevant for variables that have StateSelect.prefer but do NOT occur inside der()
671 calls — those that do occur are already promoted by natural state collection and removed
672 from algebraics before this function runs."
673 input output VariablePointers variables;
674 input output VariablePointers unknowns;
675 input output VariablePointers knowns;
676 input output VariablePointers initials;
677 input output VariablePointers states;
678 input output VariablePointers derivatives;
679 input output VariablePointers algebraics;
680 protected
681 list<Pointer<Variable>> acc_prefer_states = {};
682 list<Pointer<Variable>> acc_prefer_ders = {};
683 ComponentRef der_cref;
684 Pointer<Variable> der_var;
685 algorithm
686 // only promote if the model is dynamic (has at least one der() call)
687
2/2
✓ Branch 1 taken 106 times.
✓ Branch 2 taken 84 times.
190 if VariablePointers.size(states) > 0 then
688
2/2
✓ Branch 1 taken 522 times.
✓ Branch 2 taken 84 times.
606 for alg_ptr in VariablePointers.toList(algebraics) loop
689
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 519 times.
522 if BVariable.isStateSelect(alg_ptr, StateSelect.PREFER) then
690 // this variable has StateSelect.prefer but is not inside any der() call;
691 // create its derivative and promote it to a state
692 3 (der_cref, der_var) := BVariable.makeDerVar(BVariable.getVarName(alg_ptr), variables.scalarized);
693 6 BVariable.setVarKind(alg_ptr, VariableKind.STATE(1, SOME(PointerWeak.downgrade(der_var)), false));
694 acc_prefer_states := alg_ptr :: acc_prefer_states;
695 3 acc_prefer_ders := der_var :: acc_prefer_ders;
696 end if;
697 end for;
698
699
2/2
✓ Branch 0 taken 83 times.
✓ Branch 1 taken 1 time.
84 if not listEmpty(acc_prefer_states) then
700 // update state variable arrays
701 1 states := VariablePointers.addList(acc_prefer_states, states);
702 1 unknowns := VariablePointers.removeList(acc_prefer_states, unknowns);
703 1 algebraics := VariablePointers.removeList(acc_prefer_states, algebraics);
704
705 // update derivative variable arrays (newly created — not yet in any array)
706 1 variables := VariablePointers.addList(acc_prefer_ders, variables);
707 1 unknowns := VariablePointers.addList(acc_prefer_ders, unknowns);
708 1 initials := VariablePointers.addList(acc_prefer_ders, initials);
709 1 derivatives := VariablePointers.addList(acc_prefer_ders, derivatives);
710
711
1/2
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
1 if Flags.isSet(Flags.DUMP_STATESELECTION_INFO) then
712 ✗ print(StringUtil.headline_4("[stateselection] (" + intString(listLength(acc_prefer_states)) + ") Forced states by StateSelect.PREFER:"));
713 ✗ print(List.toString(acc_prefer_states, BVariable.pointerToString, List.Style.NEWLINE_TAB) + "\n\n");
714 end if;
715 end if;
716 end if;
717 end promotePreferStates;
718
719 function updateStateOrder
720 input ComponentRef lhs;
721 input ComponentRef rhs;
722 input UnorderedMap<ComponentRef, ComponentRef> state_order;
723 protected
724 PointerWeak<Variable> state;
725 algorithm
726 () := match (BVariable.getVarKind(BVariable.getVarPointer(lhs, sourceInfo())), BVariable.getVarKind(BVariable.getVarPointer(rhs, sourceInfo())))
727 // a = der(b)
728 case (_, VariableKind.STATE_DER(state = state)) algorithm
729 28 UnorderedMap.add(BVariable.getVarName(PointerWeak.upgrade(state)), ComponentRef.stripSubscriptsAll(lhs), state_order);
730 then ();
731 // der(b) = a
732 case (VariableKind.STATE_DER(state = state), _) algorithm
733 34 UnorderedMap.add(BVariable.getVarName(PointerWeak.upgrade(state)), ComponentRef.stripSubscriptsAll(rhs), state_order);
734 then ();
735 else ();
736 end match;
737 end updateStateOrder;
738
739 annotation(__OpenModelica_Interface="nbackend");
740 end NBDetectStates;
741
742
743