Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 63.0% 274 / 0 / 435
Functions: -% 0 / 1 / 1
Branches: 67.8% 162 / 0 / 239

OMCompiler/Compiler/NSimCode/NSimStrongComponent.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 NSimStrongComponent
37 "file: NSimStrongComponent.mo
38 package: NSimStrongComponent
39 description: This file contains the data types and functions for strong
40 components in simulation code phase.
41 "
42
43 protected
44 // OF imports
45 import AbsynUtil;
46 import BackendExtension = NFBackendExtension;
47 import DAE;
48
49 // NF imports
50 import ComponentRef = NFComponentRef;
51 import ConvertDAE = NFConvertDAE;
52 import Expression = NFExpression;
53 import NFFunction.Function;
54 import Binding = NFBinding;
55 import InstNode = NFInstNode.InstNode;
56 import Operator = NFOperator;
57 import Scalarize = NFScalarize;
58 import Statement = NFStatement;
59 import Subscript = NFSubscript;
60 import Type = NFType;
61 import Dimension = NFDimension;
62 import Variable = NFVariable;
63
64 // old backend imports
65 import OldBackendDAE = BackendDAE;
66
67 // Backend imports
68 import AliasInfo = NBStrongComponent.AliasInfo;
69 import BackendDAE = NBackendDAE;
70 import BEquation = NBEquation;
71 import NBEquation.{Equation, EquationAttributes, EquationKind, EquationPointer, EquationPointers, WhenEquationBody, WhenStatement, IfEquationBody, Iterator, SlicingStatus};
72 import Solve = NBSolve;
73 import StrongComponent = NBStrongComponent;
74 import Partition = NBPartition;
75 import Partitioning = NBPartitioning;
76 import Resizable = NBResizable;
77 import NBPartitioning.{BClock, ClockedInfo};
78 import Tearing = NBTearing;
79 import BVariable = NBVariable;
80 import NBVariable.VariablePointers;
81
82 // Old SimCode imports
83 import OldSimCode = SimCode;
84
85 // SimCode imports
86 import SimCode = NSimCode;
87 import NSimCode.{Identifier, SimCodeIndices};
88 import NSimGenericCall;
89 import NSimGenericCall.SimIterator;
90 import NSimJacobian.SimJacobian;
91 import SimPartition = NSimPartition;
92 import NSimVar.{SimVar, SimVars, VarType};
93
94 // Util imports
95 import Error;
96 import Slice = NBSlice;
97 import StringUtil;
98
99 public
100 uniontype Block
101 "A single blck from BLT transformation."
102
103 record RESIDUAL
104 "Single residual equation of the form
105 0 = exp"
106 Integer index;
107 Integer res_index;
108 Expression exp;
109 DAE.ElementSource source;
110 EquationAttributes attr;
111 end RESIDUAL;
112
113 record ARRAY_RESIDUAL
114 "Single residual array equation of the form
115 0 = exp. Structurally equal to RESIDUAL, but the destinction is important
116 for code generation."
117 Integer index;
118 Integer res_index;
119 Expression exp;
120 DAE.ElementSource source;
121 EquationAttributes attr;
122 end ARRAY_RESIDUAL;
123
124 record FOR_RESIDUAL
125 "for-loop residual equation of the form
126 for {i in 1:n, j in 1:m, ...} loop
127 0 = exp;
128 end for;"
129 Integer index;
130 Integer res_index;
131 list<SimIterator> iterators;
132 Expression exp;
133 DAE.ElementSource source;
134 EquationAttributes attr;
135 end FOR_RESIDUAL;
136
137 record GENERIC_RESIDUAL
138 "a generic residual calling a for loop body function with an index list."
139 Integer index;
140 Integer res_index;
141 list<Integer> scal_indices;
142 list<SimIterator> iterators;
143 Expression exp;
144 DAE.ElementSource source;
145 EquationAttributes attr;
146 end GENERIC_RESIDUAL;
147
148 record SIMPLE_ASSIGN
149 "Simple assignment or solved inner equation of (casual) tearing set
150 (Dynamic Tearing) with constraints on the solvability
151 lhs := rhs"
152 Integer index;
153 ComponentRef lhs "left hand side of equation";
154 Expression rhs;
155 DAE.ElementSource source;
156 // ToDo: this needs to be added for tearing later on
157 //Option<BackendDAE.Constraints> constraints;
158 EquationAttributes attr;
159 end SIMPLE_ASSIGN;
160
161 record ARRAY_ASSIGN
162 "Array assignment where the left hand side can be an array constructor.
163 {a, b, ...} := rhs"
164 Integer index;
165 Expression lhs;
166 Expression rhs;
167 DAE.ElementSource source;
168 EquationAttributes attr;
169 end ARRAY_ASSIGN;
170
171 record RESIZABLE_ASSIGN
172 "a resizable assignment calling a for loop body function."
173 Integer index;
174 Integer call_index;
175 list<SimIterator> iters;
176 DAE.ElementSource source;
177 EquationAttributes attr;
178 end RESIZABLE_ASSIGN;
179
180 record GENERIC_ASSIGN
181 "a generic assignment calling a for loop body function with an index list."
182 Integer index;
183 Integer call_index;
184 list<Integer> scal_indices;
185 DAE.ElementSource source;
186 EquationAttributes attr;
187 end GENERIC_ASSIGN;
188
189 record ENTWINED_ASSIGN
190 "entwined generic assignments calling for loop body functions with an index list and a call order."
191 Integer index;
192 list<Integer> call_order;
193 list<Block> single_calls;
194 DAE.ElementSource source;
195 EquationAttributes attr;
196 end ENTWINED_ASSIGN;
197
198 record ALIAS
199 "Simple alias assignment pointing to the alias equation.
200 - alias of will be -1 at the point of creation and computed afterwards"
201 Integer index;
202 AliasInfo aliasInfo "backend alias info";
203 Integer aliasOf "final alias index";
204 Boolean isDiscrete;
205 end ALIAS;
206
207 record ALGORITHM
208 "An algorithm section."
209 // ToDo: do we need to keep inputs/outputs here?
210 Integer index;
211 list<Statement> stmts;
212 EquationAttributes attr;
213 end ALGORITHM;
214
215 record INVERSE_ALGORITHM
216 "An algorithm section that had to be inverted."
217 Integer index;
218 list<Statement> stmts;
219 list<ComponentRef> knownOutputs "this is a subset of output crefs of the original algorithm, which are already known";
220 Boolean insideNonLinearSystem;
221 EquationAttributes attr;
222 end INVERSE_ALGORITHM;
223
224 record IF
225 "An if section."
226 Integer index;
227 list<tuple<Expression, list<Block>>> branches;
228 DAE.ElementSource source;
229 EquationAttributes attr;
230 end IF;
231
232 record WHEN
233 "A when section."
234 Integer index;
235 Boolean initialCall "true, if top-level branch with initial()";
236 list<ComponentRef> conditions;
237 list<WhenStatement> when_stmts;
238 Option<Block> else_when;
239 DAE.ElementSource source;
240 EquationAttributes attr;
241 end WHEN;
242
243 record LINEAR
244 "Linear algebraic loop."
245 LinearSystem system;
246 Option<LinearSystem> alternativeTearing;
247 end LINEAR;
248
249 record NONLINEAR
250 "Nonlinear algebraic loop."
251 NonlinearSystem system;
252 Option<NonlinearSystem> alternativeTearing;
253 end NONLINEAR;
254
255 record HYBRID
256 "Hybrid system containing both continuous and discrete equations."
257 Integer index;
258 Block continuous;
259 list<SimVar> discreteVars;
260 list<Block> discreteEqs;
261 Integer indexHybridSystem;
262 end HYBRID;
263
264 function toString
265 // ToDo: Update alias string to print actual name. Update structure?
266 input Block blck;
267 input output String str = "";
268 algorithm
269 str := match blck
270 71 case RESIDUAL() then str + "(" + intString(blck.index) + ") 0 = " + Expression.toString(blck.exp) + "\n";
271 ✗ case ARRAY_RESIDUAL() then str + "(" + intString(blck.index) + ") 0 = " + Expression.toString(blck.exp) + "\n";
272 ✗ case FOR_RESIDUAL() then str + "(" + intString(blck.index) + ") For-Loop-Residual:\n" + str + "for " + List.toString(blck.iterators, forTplStr) + " loop\n" + str + " 0 = " + Expression.toString(blck.exp) + ";\n" + str + "end for;\n";
273 ✗ case GENERIC_RESIDUAL() then str + "(" + intString(blck.index) + ") Generic For-Loop-Residual:\n" + str + List.toStringCustom(blck.scal_indices, intString, "slice", "{", ", ", "}", true, 10) + "\n" + str + "for " + List.toString(blck.iterators, forTplStr) + " loop\n" + str + " 0 = " + Expression.toString(blck.exp) + ";\n" + str + "end for;\n";
274 114 case SIMPLE_ASSIGN() then str + "(" + intString(blck.index) + ") " + ComponentRef.toString(blck.lhs) + " := " + Expression.toString(blck.rhs) + "\n";
275 2 case ARRAY_ASSIGN() then str + "(" + intString(blck.index) + ") " + Expression.toString(blck.lhs) + " := " + Expression.toString(blck.rhs) + "\n";
276 6 case RESIZABLE_ASSIGN() then str + "(" + intString(blck.index) + ") " + "resizable call [index " + intString(blck.call_index) + "]\n";
277 ✗ case GENERIC_ASSIGN() then str + "(" + intString(blck.index) + ") " + "single generic call [index " + intString(blck.call_index) + "] " + List.toStringCustom(inList = blck.scal_indices, inPrintFunc = intString, maxLength = 10) + "\n";
278 ✗ case ENTWINED_ASSIGN() then str + List.toStringCustom(blck.single_calls, function toString(str=""), "### entwined call (" + intString(blck.index) + ") ###", "\n ", " ", "");
279 21 case ALIAS() then str + "(" + intString(blck.index) + ") Alias of " + intString(blck.aliasOf) + "\n";
280 10 case ALGORITHM() then str + "(" + intString(blck.index) + ") Algorithm\n" + Statement.toStringList(blck.stmts, str);
281 ✗ case INVERSE_ALGORITHM() then str + "(" + intString(blck.index) + ") Inverse Algorithm\n" + Statement.toStringList(blck.stmts, str) + "\n";
282 ✗ case IF() then str + "(" + intString(blck.index) + ") " + List.toStringCustom(blck.branches, function ifTplStr(str = str), "", str, str + "else ", str + "end if;\n");
283 ✗ case WHEN() then str + "(" + intString(blck.index) + ") " + whenString(blck.conditions, blck.when_stmts, blck.else_when, str);
284 2 case LINEAR() then str + "(" + intString(blck.system.index) + ") " + LinearSystem.toString(blck.system, str);
285 11 case NONLINEAR() then str + "(" + intString(blck.system.index) + ") " + NonlinearSystem.toString(blck.system, str);
286 ✗ case HYBRID() then str + "(" + intString(blck.index) + ") Hybrid\n"; // ToDo!
287 else getInstanceName() + " failed.\n";
288 end match;
289 end toString;
290
291 function forTplStr
292 input SimIterator iter;
293 output String str = SimIterator.toString(iter);
294 end forTplStr;
295
296 function ifTplStr
297 input tuple<Expression, list<Block>> tpl;
298 input output String str;
299 protected
300 Expression condition;
301 list<Block> blcks;
302 algorithm
303 ✗ (condition, blcks) := tpl;
304 ✗ str := "if " + Expression.toString(condition) + " then\n "
305 + List.toString(blcks, function toString(str = str + " "), List.Style.NEWLINE);
306 end ifTplStr;
307
308 function getIndex
309 input Block blck;
310 output Integer index;
311 algorithm
312 index := match blck
313 ✗ case RESIDUAL() then blck.index;
314 ✗ case ARRAY_RESIDUAL() then blck.index;
315 ✗ case FOR_RESIDUAL() then blck.index;
316 4861 case SIMPLE_ASSIGN() then blck.index;
317 524 case ARRAY_ASSIGN() then blck.index;
318 390 case RESIZABLE_ASSIGN() then blck.index;
319 26 case GENERIC_ASSIGN() then blck.index;
320 2 case ENTWINED_ASSIGN() then blck.index;
321 2689 case ALIAS() then blck.index;
322 175 case ALGORITHM() then blck.index;
323 ✗ case INVERSE_ALGORITHM() then blck.index;
324 ✗ case IF() then blck.index;
325 118 case WHEN() then blck.index;
326 ✗ case LINEAR() then blck.system.index;
327 ✗ case NONLINEAR() then blck.system.index;
328 ✗ case HYBRID() then blck.index;
329 else algorithm
330 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for\n" + toString(blck)});
331 ✗ then fail();
332 end match;
333 end getIndex;
334
335 function isDiscrete
336 input Block blck;
337 output Boolean b;
338 algorithm
339 b := match blck
340 local
341 EquationAttributes attr;
342 ✗ case RESIDUAL(attr = attr) then attr.kind == EquationKind.DISCRETE;
343 ✗ case ARRAY_RESIDUAL(attr = attr) then attr.kind == EquationKind.DISCRETE;
344 ✗ case FOR_RESIDUAL(attr = attr) then attr.kind == EquationKind.DISCRETE;
345 19 case SIMPLE_ASSIGN(attr = attr) then attr.kind == EquationKind.DISCRETE;
346 ✗ case ARRAY_ASSIGN(attr = attr) then attr.kind == EquationKind.DISCRETE;
347 1 case RESIZABLE_ASSIGN(attr = attr) then attr.kind == EquationKind.DISCRETE;
348 ✗ case GENERIC_ASSIGN(attr = attr) then attr.kind == EquationKind.DISCRETE;
349 ✗ case ENTWINED_ASSIGN(attr = attr) then attr.kind == EquationKind.DISCRETE;
350 1159 case ALIAS() then blck.isDiscrete;
351 2 case ALGORITHM(attr = attr) then attr.kind == EquationKind.DISCRETE;
352 ✗ case INVERSE_ALGORITHM(attr = attr) then attr.kind == EquationKind.DISCRETE;
353 ✗ case IF(attr = attr) then attr.kind == EquationKind.DISCRETE;
354 ✗ case WHEN(attr = attr) then attr.kind == EquationKind.DISCRETE; // should hopefully always be true
355 else false;
356 end match;
357 end isDiscrete;
358
359 function filterWhen
360 input list<Block> blcks;
361 input output list<Block> out_blcks;
362 input output list<Block> new_blcks;
363 input output SimCodeIndices indices;
364 protected
365 Block blck, new_blck;
366 list<Block> rest;
367 list<Statement> stmts;
368 algorithm
369 (out_blcks, new_blcks, indices) := match blcks
370 58 case WHEN() :: rest then filterWhen(rest, out_blcks, new_blcks, indices);
371 case (blck as ALGORITHM()) :: rest algorithm
372 6 stmts := Statement.filterDiscrete(blck.stmts);
373
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if listEmpty(stmts) then
374 // filtered everything out, skip entire block
375 4 (out_blcks, new_blcks, indices) := filterWhen(rest, out_blcks, new_blcks, indices);
376 elseif List.compareLength(stmts, blck.stmts) <> 0 then
377 // filtered part of it out, create new block
378 2 new_blck := ALGORITHM(indices.equationIndex, stmts, blck.attr);
379 2 indices.equationIndex := indices.equationIndex + 1;
380 2 (out_blcks, new_blcks, indices) := filterWhen(rest, new_blck :: out_blcks, new_blck :: new_blcks, indices);
381 //UnorderedMap.add(Equation.getEqnName(Pointer.create(eqn)), blck, equation_map);
382 else
383 // filtered nothing out, keep block as it is
384 ✗ (out_blcks, new_blcks, indices) := filterWhen(rest, blck :: out_blcks, new_blcks, indices);
385 end if;
386 6 then (out_blcks, new_blcks, indices);
387 1184 case blck :: rest then filterWhen(rest, blck :: out_blcks, new_blcks, indices);
388 else (out_blcks, new_blcks, indices);
389 end match;
390 end filterWhen;
391
392 function map
393 "ToDo: other blocks and cref func"
394 input output Block blck;
395 input expFunc func;
396 partial function expFunc
397 input output Expression exp;
398 end expFunc;
399 algorithm
400 blck := match blck
401 case RESIDUAL() algorithm
402 ✗ blck.exp := Expression.map(blck.exp, func);
403 then blck;
404
405 case SIMPLE_ASSIGN() algorithm
406 ✗ blck.rhs := Expression.map(blck.rhs, func);
407 then blck;
408
409 else blck;
410 end match;
411 end map;
412
413 function listToString
414 input list<Block> blcks;
415 input output String str = "";
416 input String header = "";
417 protected
418 String indent = str;
419 algorithm
420
3/4
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 21 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
34 str := if header <> "" then StringUtil.headline_3(header) else "";
421
2/2
✓ Branch 0 taken 148 times.
✓ Branch 1 taken 34 times.
182 for blck in blcks loop
422 148 str := str + Block.toString(blck, indent);
423 end for;
424 end listToString;
425
426 function createBlocks
427 input list<Partition.Partition> partitions;
428 output list<list<Block>> blcks = {};
429 input output list<Block> all_blcks;
430 input output SimCodeIndices simCodeIndices;
431 input UnorderedMap<ComponentRef, SimVar> simcode_map;
432 input UnorderedMap<ComponentRef, Block> equation_map;
433 protected
434 list<Block> tmp;
435 algorithm
436
2/2
✓ Branch 0 taken 233 times.
✓ Branch 1 taken 374 times.
607 for partition in partitions loop
437 233 (tmp, simCodeIndices) := fromPartition(partition, simCodeIndices, simcode_map, equation_map);
438 blcks := tmp :: blcks;
439 233 all_blcks := listAppend(tmp, all_blcks);
440 end for;
441 374 blcks := listReverse(blcks);
442 end createBlocks;
443
444 function createDiscreteBlocks
445 input list<Partition.Partition> partitions;
446 input output list<list<Block>> blcks;
447 input output list<Block> all_blcks;
448 input output list<Block> event_dependencies;
449 input output SimCodeIndices simCodeIndices;
450 input UnorderedMap<ComponentRef, SimVar> simcode_map;
451 input UnorderedMap<ComponentRef, Block> equation_map;
452 protected
453 list<Block> tmp, new_blcks;
454 algorithm
455
2/2
✓ Branch 0 taken 75 times.
✓ Branch 1 taken 374 times.
449 for partition in partitions loop
456 75 (tmp, simCodeIndices) := fromPartition(partition, simCodeIndices, simcode_map, equation_map);
457 // add all
458 75 all_blcks := listAppend(tmp, all_blcks);
459 // filter all when equations and add to blcks (ode or algebraic)
460 75 (tmp, new_blcks, simCodeIndices) := filterWhen(listReverse(tmp), {}, {}, simCodeIndices);
461 75 all_blcks := listAppend(new_blcks, all_blcks);
462 blcks := tmp :: blcks;
463 // filter all other discrete equations and add to event_dependencies
464
6/6
✓ Branch 1 taken 269 times.
✓ Branch 2 taken 917 times.
✓ Branch 3 taken 1186 times.
✓ Branch 4 taken 75 times.
✓ Branch 5 taken 917 times.
✓ Branch 6 taken 75 times.
1261 tmp := list(blck for blck guard(not isDiscrete(blck)) in tmp);
465 75 event_dependencies := listAppend(tmp, event_dependencies);
466 end for;
467 374 blcks := listReverse(blcks);
468 end createDiscreteBlocks;
469
470 function createInitialBlocks
471 input list<Partition.Partition> partitions;
472 output list<Block> blcks;
473 input output SimCodeIndices simCodeIndices;
474 input UnorderedMap<ComponentRef, SimVar> simcode_map;
475 input UnorderedMap<ComponentRef, Block> equation_map;
476 protected
477 list<Block> tmp;
478 list<list<Block>> tmp_lst = {};
479 algorithm
480
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 194 times.
374 for partition in partitions loop
481 180 (tmp, simCodeIndices) := fromPartition(partition, simCodeIndices, simcode_map, equation_map);
482 tmp_lst := tmp :: tmp_lst;
483 end for;
484 194 blcks := List.flatten(tmp_lst);
485 end createInitialBlocks;
486
487 function createParameterBlocks
488 "creates the blocks of the explicitly solved primary parameter bindings, in evaluation order"
489 input list<StrongComponent> comps;
490 output list<Block> blcks = {};
491 input output SimCodeIndices simCodeIndices;
492 input UnorderedMap<ComponentRef, SimVar> simcode_map;
493 input UnorderedMap<ComponentRef, Block> equation_map;
494 protected
495 Block tmp;
496 Integer index;
497 algorithm
498
2/2
✓ Branch 0 taken 1112 times.
✓ Branch 1 taken 188 times.
1300 for comp in comps loop
499 1112 (tmp, simCodeIndices, index) := fromStrongComponent(comp, simCodeIndices, NBPartition.Kind.INI, simcode_map, equation_map);
500 blcks := tmp :: blcks;
501 end for;
502 188 blcks := listReverse(blcks);
503 end createParameterBlocks;
504
505 function createAttributeBlocks
506 "Creates the assignments of min, max and nominal attributes that are not
507 literals and therefore not part of the init XML, e.g. `Real x(min = p)`.
508 The attributes are evaluated in updateBoundVariableAttributes. Only
509 creates blocks for variables that are SimVars themselves, i.e. array
510 variables if they are not scalarized.
511 The indices are consecutive per attribute in the order of the info file:
512 nominal, min, max."
513 input list<VariablePointers> vars;
514 output list<Block> min_blcks = {};
515 output list<Block> max_blcks = {};
516 output list<Block> nominal_blcks = {};
517 input output SimCodeIndices simCodeIndices;
518 input UnorderedMap<ComponentRef, SimVar> simcode_map;
519 input list<StrongComponent> params "primary parameters, solved before the attributes";
520 protected
521 list<Variable> sim_vars = {};
522 Variable var;
523 UnorderedSet<ComponentRef> bound = UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual);
524 algorithm
525
2/2
✓ Branch 0 taken 1112 times.
✓ Branch 1 taken 188 times.
1300 for comp in params loop
526
2/2
✓ Branch 1 taken 1112 times.
✓ Branch 2 taken 1112 times.
2224 for v in StrongComponent.getVariables(comp) loop
527 1112 UnorderedSet.add(BVariable.getVarName(v), bound);
528 end for;
529 end for;
530
2/2
✓ Branch 0 taken 752 times.
✓ Branch 1 taken 188 times.
940 for var_ptrs in vars loop
531
2/2
✓ Branch 1 taken 2615 times.
✓ Branch 2 taken 752 times.
3367 for var_ptr in VariablePointers.toList(var_ptrs) loop
532 2615 var := Pointer.access(var_ptr);
533
2/2
✓ Branch 1 taken 2039 times.
✓ Branch 2 taken 576 times.
2615 if UnorderedMap.contains(var.name, simcode_map) then
534 sim_vars := var :: sim_vars;
535 end if;
536 end for;
537 end for;
538 188 sim_vars := listReverse(sim_vars);
539
2/2
✓ Branch 0 taken 2039 times.
✓ Branch 1 taken 188 times.
2227 for var in sim_vars loop
540 2039 (nominal_blcks, simCodeIndices) := createAttributeBlock(var, BackendExtension.VariableAttributes.getNominal(var.backendinfo.attributes), nominal_blcks, simCodeIndices, bound);
541 end for;
542
2/2
✓ Branch 0 taken 2039 times.
✓ Branch 1 taken 188 times.
2227 for var in sim_vars loop
543 2039 (min_blcks, simCodeIndices) := createAttributeBlock(var, BackendExtension.VariableAttributes.getMin(var.backendinfo.attributes), min_blcks, simCodeIndices, bound);
544 end for;
545
2/2
✓ Branch 0 taken 2039 times.
✓ Branch 1 taken 188 times.
2227 for var in sim_vars loop
546 2039 (max_blcks, simCodeIndices) := createAttributeBlock(var, BackendExtension.VariableAttributes.getMax(var.backendinfo.attributes), max_blcks, simCodeIndices, bound);
547 end for;
548 188 min_blcks := listReverse(min_blcks);
549 188 max_blcks := listReverse(max_blcks);
550 188 nominal_blcks := listReverse(nominal_blcks);
551 end createAttributeBlocks;
552
553 function createAttributeBlock
554 input Variable var;
555 input Option<Expression> attribute;
556 input output list<Block> blcks;
557 input output SimCodeIndices simCodeIndices;
558 input UnorderedSet<ComponentRef> bound;
559 algorithm
560 _ := match attribute
561 local
562 Expression exp;
563 // attributes depending on parameters of the initialization are unknown at this point
564 case SOME(exp) guard not Expression.isLiteralXML(exp) and not Expression.contains(exp, function isUnknownBeforeInit(bound = bound)) algorithm
565 7 blcks := SIMPLE_ASSIGN(simCodeIndices.equationIndex, var.name, exp, DAE.emptyElementSource,
566 EquationAttributes.default(EquationKind.CONTINUOUS, false)) :: blcks;
567 7 simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1;
568 then ();
569 else ();
570 end match;
571 end createAttributeBlock;
572
573 function isUnknownBeforeInit
574 "true for variables whose value is not known before the initialization"
575 input Expression exp;
576 input UnorderedSet<ComponentRef> bound;
577 output Boolean b;
578 protected
579 Pointer<Variable> var_ptr;
580 Variable var;
581 Option<Expression> value;
582 algorithm
583 b := match exp
584 case Expression.CREF() guard InstNode.isVar(ComponentRef.node(exp.cref)) algorithm
585 8 var_ptr := BVariable.getVarPointer(exp.cref, sourceInfo());
586
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
8 if BVariable.isConst(var_ptr) or UnorderedSet.contains(BVariable.getVarName(var_ptr), bound) then
587 b := false;
588 elseif BVariable.isParamOrConst(var_ptr) then
589 8 var := Pointer.access(var_ptr);
590 8 value := Binding.getExpOpt(var.binding);
591
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
8 if isNone(value) then
592 ✗ value := BackendExtension.VariableAttributes.getStartAttribute(var.backendinfo.attributes);
593 end if;
594 8 b := not Util.applyOptionOrDefault(value, Expression.isLiteralXML, false);
595 else
596 b := true;
597 end if;
598 then b;
599 else false;
600 end match;
601 end isUnknownBeforeInit;
602
603 function createDAEModeBlocks
604 input list<Partition.Partition> partitions;
605 output list<list<Block>> blcks = {};
606 output list<SimVar> vars = {};
607 input output SimCodeIndices simCodeIndices;
608 input UnorderedMap<ComponentRef, SimVar> simcode_map;
609 input UnorderedMap<ComponentRef, Block> equation_map;
610 protected
611 Pointer<SimCodeIndices> indices_ptr;
612 Pointer<list<SimVar>> vars_ptr = Pointer.create({});
613 list<Block> tmp;
614 algorithm
615
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
2 for partition in listReverse(partitions) loop
616 1 indices_ptr := Pointer.create(simCodeIndices);
617 //VariablePointers.map(partition.unknowns, function SimVar.traverseCreate(acc = vars_ptr, indices_ptr = indices_ptr, varType = VarType.RESIDUAL));
618 1 Partition.Partition.mapStrongComponents(partition, function SimVar.createFromResidualComponent(acc = vars_ptr, indices_ptr = indices_ptr, varType = VarType.RESIDUAL));
619 1 (tmp, simCodeIndices) := fromPartition(partition, Pointer.access(indices_ptr), simcode_map, equation_map);
620 blcks := tmp :: blcks;
621 end for;
622 1 vars := listReverse(Pointer.access(vars_ptr));
623 end createDAEModeBlocks;
624
625 function createClockedBlocks
626 input list<Partition.Partition> partitions;
627 output list<SimPartition> baseParts;
628 output list<Block> eventClocks;
629 input output SimCodeIndices simCodeIndices;
630 input UnorderedMap<ComponentRef, SimVar> simcode_map;
631 input UnorderedMap<ComponentRef, Block> equation_map;
632 input ClockedInfo info;
633 protected
634 // type for for double map. base clock -> {sub_clock -> partition}
635 type SimPartitions = list<SimPartition>;
636 UnorderedMap<BClock, SimPartitions> clock_collector = UnorderedMap.new<SimPartitions>(BClock.hash, BClock.isEqual);
637 // set to collect the dependencies of a block
638 list<Block> blcks;
639 list<SimVar> vars;
640 BClock clock, subClock, baseClock;
641 Boolean holdEvents;
642 Option<BClock> baseClock_opt;
643 SimPartition subPart;
644 algorithm
645 // initialize all base clocks
646
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 188 times.
200 for c in UnorderedMap.valueList(info.baseClocks) loop
647 12 UnorderedMap.add(c, {}, clock_collector);
648 end for;
649
650 // create all sub partition blocks and find the base partitions
651
2/2
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 188 times.
206 for partition in listReverse(partitions) loop
652 // create the partition and get all clock dependencies
653 18 (blcks, simCodeIndices) := fromPartition(partition, simCodeIndices, simcode_map, equation_map);
654 18 vars := SimVars.getPartitionVars(partition, simcode_map);
655 18 (clock, baseClock_opt, holdEvents) := Partition.Partition.getClocks(partition);
656
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
18 if isSome(baseClock_opt) then
657 // it is a sub clock
658 18 SOME(baseClock) := baseClock_opt;
659 subClock := clock;
660 else
661 // it is a base clock, use the default sub clock
662 baseClock := clock;
663 subClock := NBPartitioning.DEFAULT_SUB_CLOCK;
664 end if;
665
666 // create and add sub partition
667 18 subPart := SimPartition.createSubPartition(subClock, blcks, vars, holdEvents);
668 36 UnorderedMap.add(baseClock, subPart :: UnorderedMap.getSafe(baseClock, clock_collector, sourceInfo()), clock_collector);
669 end for;
670
671 // create base partitions
672 188 (baseParts, eventClocks, simCodeIndices) := SimPartition.createBasePartitions(clock_collector, simCodeIndices);
673 end createClockedBlocks;
674
675 function createNoReturnBlocks
676 input EquationPointers equations;
677 output list<Block> blcks = {};
678 input output SimCodeIndices simCodeIndices;
679 input Partition.Kind kind;
680 input UnorderedMap<ComponentRef, SimVar> simcode_map;
681 input UnorderedMap<ComponentRef, Block> equation_map;
682 protected
683 Equation eqn;
684 Block tmp;
685 algorithm
686
2/2
✓ Branch 1 taken 163 times.
✓ Branch 2 taken 25 times.
521 for i in 1:ExpandableArray.getLastUsedIndex(equations.eqArr) loop
687
1/2
✓ Branch 1 taken 333 times.
✗ Branch 2 not taken.
333 if ExpandableArray.occupied(i, equations.eqArr) then
688 333 eqn := Pointer.access(ExpandableArray.get(i, equations.eqArr));
689 (tmp, simCodeIndices) := match eqn
690 local
691 ComponentRef cref;
692
693 case Equation.SCALAR_EQUATION(lhs = Expression.CREF(cref = cref))
694 65 then createEquation(NBVariable.getVar(cref, sourceInfo()), eqn, NBSolve.Status.EXPLICIT, simCodeIndices, kind, simcode_map, equation_map);
695
696 case Equation.ARRAY_EQUATION(lhs = Expression.CREF(cref = cref))
697 8 then createEquation(NBVariable.getVar(cref, sourceInfo()), eqn, NBSolve.Status.EXPLICIT, simCodeIndices, kind, simcode_map, equation_map);
698
699 case Equation.RECORD_EQUATION(lhs = Expression.CREF(cref = cref))
700 ✗ then createEquation(NBVariable.getVar(cref, sourceInfo()), eqn, NBSolve.Status.EXPLICIT, simCodeIndices, kind, simcode_map, equation_map);
701
702 case Equation.WHEN_EQUATION()
703 6 then createEquation(NBVariable.DUMMY_VARIABLE, eqn, NBSolve.Status.EXPLICIT, simCodeIndices, kind, simcode_map, equation_map);
704
705 case Equation.ALGORITHM()
706 254 then createAlgorithm(eqn, simCodeIndices, equation_map);
707
708 case Equation.FOR_EQUATION()
709 ✗ then createAlgorithm(eqn, simCodeIndices, equation_map);
710
711 /* ToDo: other equations ... */
712
713 else algorithm
714 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for\n" + Equation.toString(eqn)});
715 ✗ then fail();
716 end match;
717
718 blcks := tmp :: blcks;
719 // list reverse necessary? they are unordered anyway
720 end if;
721 end for;
722 end createNoReturnBlocks;
723
724 function fromPartition
725 input Partition.Partition partition;
726 output list<Block> blcks;
727 input output SimCodeIndices simCodeIndices;
728 input UnorderedMap<ComponentRef, SimVar> simcode_map;
729 input UnorderedMap<ComponentRef, Block> equation_map;
730 algorithm
731 blcks := match partition.strongComponents
732 local
733 array<StrongComponent> comps;
734 Partition.Kind kind;
735 Block tmp;
736 list<Block> result = {};
737 Integer index, alias_index;
738
739 case SOME(comps) algorithm
740 507 kind := Partition.Partition.getKind(partition);
741
2/2
✓ Branch 0 taken 505 times.
✓ Branch 1 taken 2 times.
6521 for i in arrayLength(comps):-1:1 loop
742 6014 (tmp, simCodeIndices, index) := fromStrongComponent(comps[i], simCodeIndices, kind, simcode_map, equation_map);
743 // add it to the alias map. correctly map the alias index if itself is an alias
744 alias_index := match comps[i]
745 local
746 StrongComponent.AliasInfo aliasInfo;
747 2689 case StrongComponent.ALIAS(aliasInfo = aliasInfo) then UnorderedMap.getOrDefault(aliasInfo, simCodeIndices.alias_map, -1);
748 3325 else index;
749 end match;
750 6014 UnorderedMap.add(AliasInfo.ALIAS_INFO(kind, partition.index, i), alias_index, simCodeIndices.alias_map);
751 result := tmp :: result;
752 end for;
753 then result;
754
755 else algorithm
756 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for\n" + Partition.Partition.toString(partition)});
757 ✗ then fail();
758 end match;
759 end fromPartition;
760
761 function blockSource
762 "The DAE.ElementSource of a block, for block kinds that track one."
763 input Block blck;
764 output DAE.ElementSource source;
765 algorithm
766 source := match blck
767 559 case RESIDUAL() then blck.source;
768 ✗ case ARRAY_RESIDUAL() then blck.source;
769 ✗ case FOR_RESIDUAL() then blck.source;
770 ✗ case GENERIC_RESIDUAL() then blck.source;
771 30 case SIMPLE_ASSIGN() then blck.source;
772 ✗ case ARRAY_ASSIGN() then blck.source;
773 ✗ case RESIZABLE_ASSIGN() then blck.source;
774 ✗ case GENERIC_ASSIGN() then blck.source;
775 ✗ case ENTWINED_ASSIGN() then blck.source;
776 ✗ case IF() then blck.source;
777 ✗ case WHEN() then blck.source;
778 else DAE.emptyElementSource;
779 end match;
780 end blockSource;
781
782 function jacobianHasGenericLoopCalls
783 "True if this Jacobian's per-column evaluation uses generic for-loop/array calls."
784 input SimJacobian jac;
785 output Boolean b;
786 algorithm
787 b := match jac
788 22 case SimJacobian.SIM_JAC() then not listEmpty(jac.generic_loop_calls);
789 end match;
790 end jacobianHasGenericLoopCalls;
791
792 function isForOrGenericResidual
793 "True for for-loop/generic-index residual block kinds (unsupported by the linear-system codegen)."
794 input Block blck;
795 output Boolean b;
796 algorithm
797 b := match blck
798 case FOR_RESIDUAL() then true;
799 case GENERIC_RESIDUAL() then true;
800 else false;
801 end match;
802 end isForOrGenericResidual;
803
804 function fromStrongComponent
805 input StrongComponent comp;
806 output Block blck;
807 input output SimCodeIndices simCodeIndices;
808 output Integer index;
809 input Partition.Kind kind;
810 input UnorderedMap<ComponentRef, SimVar> simcode_map;
811 input UnorderedMap<ComponentRef, Block> equation_map;
812 input Boolean entwined = false "a slice of an entwined component, which needs its index list";
813 algorithm
814 (blck, index) := match comp
815 local
816 Tearing strict;
817 NonlinearSystem system;
818 LinearSystem linSystem;
819 list<Block> eqns = {};
820 list<ComponentRef> crefs = {};
821 list<SimVar> linVars = {};
822 Integer sysIndex;
823 Boolean allLinVarsFound;
824 Integer resizable_size "the static size of whole resizable iteration arrays beyond 1 each";
825 Option<SimVar> osimvar;
826 Block tmp;
827 Variable var;
828 Option<SimJacobian> jacobian;
829 EquationPointer eqn_ptr;
830 Equation eqn;
831 SlicingStatus status;
832 ComponentRef var_cref;
833 Integer aliasOf, generic_call_index, residual_index = 0;
834 Block single_call;
835 list<Block> single_calls = {};
836 UnorderedMap<ComponentRef, Integer> entwined_index_map;
837 list<Integer> call_order = {};
838 Identifier ident;
839 list<SimIterator> iters;
840
841 case StrongComponent.SINGLE_COMPONENT() algorithm
842 3807 (tmp, simCodeIndices) := createEquation(Pointer.access(comp.var), Pointer.access(comp.eqn), comp.status, simCodeIndices, kind, simcode_map, equation_map);
843 3807 then (tmp, getIndex(tmp));
844
845 case StrongComponent.MULTI_COMPONENT() algorithm
846 160 (tmp, simCodeIndices) := createEquation(NBVariable.DUMMY_VARIABLE, Pointer.access(Slice.getT(comp.eqn)), comp.status, simCodeIndices, kind, simcode_map, equation_map);
847 160 then (tmp, getIndex(tmp));
848
849 case StrongComponent.SLICED_COMPONENT() guard(Equation.isForEquation(Slice.getT(comp.eqn))) algorithm
850 29 (tmp, simCodeIndices) := createAlgorithm(Pointer.access(Slice.getT(comp.eqn)), simCodeIndices, equation_map);
851 29 then (tmp, getIndex(tmp));
852
853 case StrongComponent.SLICED_COMPONENT() algorithm
854 // just a regular equation solved for a sliced variable
855 // use cref instead of var because it has subscripts!
856 1497 eqn := Pointer.access(Slice.getT(comp.eqn));
857 1497 (tmp, simCodeIndices) := createEquation(Variable.fromCref(comp.var_cref), eqn, comp.status, simCodeIndices, kind, simcode_map, equation_map);
858 1497 then (tmp, getIndex(tmp));
859
860 case StrongComponent.RESIZABLE_COMPONENT() guard(Equation.isForEquation(Slice.getT(comp.eqn))) algorithm
861 // create a resizable equation
862 322 eqn_ptr := Slice.getT(comp.eqn);
863 322 eqn := Pointer.access(eqn_ptr);
864 322 ident := Identifier.IDENTIFIER(eqn_ptr, comp.var_cref, true);
865 322 iters := SimIterator.fromIterator(Equation.getForIterator(eqn));
866 322 generic_call_index := UnorderedMap.tryAdd(ident, UnorderedMap.size(simCodeIndices.generic_call_map), simCodeIndices.generic_call_map);
867 322 tmp := RESIZABLE_ASSIGN(simCodeIndices.equationIndex, generic_call_index, iters, Equation.getSource(eqn), Equation.getAttributes(eqn));
868 322 UnorderedMap.add(Equation.getEqnName(eqn_ptr), tmp, equation_map);
869 322 simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1;
870 322 then (tmp, getIndex(tmp));
871
872 // a slice of a for-equation over a resizable range that contains every
873 // iteration (at the analysis sizes; the call computes the whole body of an
874 // iteration) is the whole loop for every size
875 case StrongComponent.GENERIC_COMPONENT() guard not entwined and coversAllResizableIterations(comp.eqn) algorithm
876 48 eqn_ptr := Slice.getT(comp.eqn);
877 48 eqn := Pointer.access(eqn_ptr);
878 48 ident := Identifier.IDENTIFIER(eqn_ptr, comp.var_cref, true);
879 48 iters := SimIterator.fromIterator(Equation.getForIterator(eqn));
880 48 generic_call_index := UnorderedMap.tryAdd(ident, UnorderedMap.size(simCodeIndices.generic_call_map), simCodeIndices.generic_call_map);
881 48 tmp := RESIZABLE_ASSIGN(simCodeIndices.equationIndex, generic_call_index, iters, Equation.getSource(eqn), Equation.getAttributes(eqn));
882 48 UnorderedMap.add(Equation.getEqnName(eqn_ptr), tmp, equation_map);
883 48 simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1;
884 48 then (tmp, getIndex(tmp));
885
886 // a slice of a for-equation over a resizable range that is a box of
887 // iterations is the loop over symbolic sub-ranges for every size
888 case StrongComponent.GENERIC_COMPONENT() guard not entwined and isSome(restrictedResizableIterator(comp.eqn)) algorithm
889 16 eqn_ptr := Slice.getT(comp.eqn);
890 16 eqn := Pointer.access(eqn_ptr);
891 16 ident := Identifier.IDENTIFIER(eqn_ptr, comp.var_cref, true);
892 16 iters := SimIterator.fromIterator(Util.getOption(restrictedResizableIterator(comp.eqn)));
893 16 generic_call_index := UnorderedMap.tryAdd(ident, UnorderedMap.size(simCodeIndices.generic_call_map), simCodeIndices.generic_call_map);
894 16 tmp := RESIZABLE_ASSIGN(simCodeIndices.equationIndex, generic_call_index, iters, Equation.getSource(eqn), Equation.getAttributes(eqn));
895 16 UnorderedMap.add(Equation.getEqnName(eqn_ptr), tmp, equation_map);
896 16 simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1;
897 16 then (tmp, getIndex(tmp));
898
899 case StrongComponent.GENERIC_COMPONENT() algorithm
900 // create a generic index list call of a for-loop equation
901 26 eqn_ptr := Slice.getT(comp.eqn);
902 26 eqn := Pointer.access(eqn_ptr);
903 26 ident := Identifier.IDENTIFIER(eqn_ptr, comp.var_cref, false);
904 26 generic_call_index := UnorderedMap.tryAdd(ident, UnorderedMap.size(simCodeIndices.generic_call_map), simCodeIndices.generic_call_map);
905 26 tmp := GENERIC_ASSIGN(simCodeIndices.equationIndex, generic_call_index, comp.eqn.indices, Equation.getSource(eqn), Equation.getAttributes(eqn));
906 26 UnorderedMap.add(Equation.getEqnName(eqn_ptr), tmp, equation_map);
907 26 simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1;
908 26 then (tmp, getIndex(tmp));
909
910 case StrongComponent.ENTWINED_COMPONENT() algorithm
911 // create index list calls for entwined equations (position-based dispatch)
912 2 entwined_index_map := UnorderedMap.new<Integer>(ComponentRef.hash, ComponentRef.isEqual);
913
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 for slice in comp.entwined_slices loop
914 6 (single_call, simCodeIndices, _) := fromStrongComponent(slice, simCodeIndices, kind, simcode_map, equation_map, entwined = true);
915 // position = current list length before prepend (0-based, stable after reversal below)
916 6 UnorderedMap.add(getEntwinedEquationName(slice), listLength(single_calls), entwined_index_map);
917 single_calls := single_call :: single_calls;
918 end for;
919 2 single_calls := listReverse(single_calls);
920
2/2
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 2 times.
38 for tpl in listReverse(comp.entwined_tpl_lst) loop
921 36 (eqn_ptr, _) := tpl;
922 36 call_order := UnorderedMap.getSafe(Equation.getEqnName(eqn_ptr), entwined_index_map, sourceInfo()) :: call_order;
923 end for;
924 // todo: eq attributes and source
925 2 tmp := ENTWINED_ASSIGN(simCodeIndices.equationIndex, call_order, single_calls, DAE.emptyElementSource, EquationAttributes.default(EquationKind.CONTINUOUS, false));
926 2 simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1;
927 2 then (tmp, getIndex(tmp));
928
929 case StrongComponent.ALGEBRAIC_LOOP(strict = strict) algorithm
930
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 87 times.
✓ Branch 2 taken 67 times.
✓ Branch 3 taken 20 times.
577 for i in 1:arrayLength(strict.innerEquations) loop
931 403 (tmp, simCodeIndices, _) := fromStrongComponent(strict.innerEquations[i], simCodeIndices, kind, simcode_map, equation_map);
932 eqns := tmp :: eqns;
933 end for;
934
2/2
✓ Branch 0 taken 730 times.
✓ Branch 1 taken 87 times.
817 for slice in strict.residual_eqns loop
935 // kabdelhak: we need to actually slice here -> generic slices are needed for residuals
936 730 (tmp, simCodeIndices, residual_index) := createResidual(slice, simCodeIndices, residual_index, equation_map);
937 eqns := tmp :: eqns;
938 end for;
939 allLinVarsFound := true;
940 resizable_size := 0;
941
2/2
✓ Branch 0 taken 648 times.
✓ Branch 1 taken 87 times.
735 for slice in strict.iteration_vars loop
942 648 var := Pointer.access(Slice.getT(slice));
943
6/6
✓ Branch 0 taken 614 times.
✓ Branch 1 taken 34 times.
✓ Branch 3 taken 26 times.
✓ Branch 4 taken 588 times.
✓ Branch 7 taken 6 times.
✓ Branch 8 taken 20 times.
648 if listEmpty(slice.indices) and Type.isArray(var.ty) and
944 List.any(Type.arrayDims(var.ty), Dimension.isResizable) then
945 // a whole resizable array: its elements are only known at runtime,
946 // the system is sized at runtime (no linear solver, see below)
947 6 crefs := var.name :: crefs;
948 allLinVarsFound := false;
949 6 resizable_size := resizable_size + BVariable.size(Slice.getT(slice), true) - 1;
950 elseif Type.isArray(var.ty) then
951 // the slice indices refer to the resized sizes of resizable dimensions
952
2/2
✓ Branch 1 taken 266 times.
✓ Branch 2 taken 54 times.
320 for scal_var in Scalarize.scalarizeBackendVariable(var, slice.indices, resize = true) loop
953 266 crefs := scal_var.name :: crefs;
954 266 osimvar := UnorderedMap.get(scal_var.name, simcode_map);
955
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 266 times.
✓ Branch 2 taken 211 times.
✓ Branch 3 taken 55 times.
266 if isSome(osimvar) then
956 211 linVars := Util.getOption(osimvar) :: linVars;
957 else
958 allLinVarsFound := false;
959 end if;
960 end for;
961 else
962 588 crefs := var.name :: crefs;
963 588 osimvar := UnorderedMap.get(var.name, simcode_map);
964
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 588 times.
✓ Branch 2 taken 585 times.
✓ Branch 3 taken 3 times.
588 if isSome(osimvar) then
965 585 linVars := Util.getOption(osimvar) :: linVars;
966 else
967 allLinVarsFound := false;
968 end if;
969 end if;
970 end for;
971
972
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 87 times.
✓ Branch 2 taken 85 times.
✓ Branch 3 taken 2 times.
87 if isSome(strict.jac) then
973 85 (jacobian, simCodeIndices) := SimJacobian.create(Util.getOption(strict.jac), simCodeIndices, simcode_map);
974 else
975 jacobian := NONE();
976 end if;
977
978
14/16
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 31 times.
✓ Branch 4 taken 29 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 28 times.
✓ Branch 7 taken 1 time.
✓ Branch 8 taken 27 times.
✓ Branch 9 taken 1 time.
✓ Branch 11 taken 22 times.
✓ Branch 12 taken 5 times.
✓ Branch 15 taken 16 times.
✓ Branch 16 taken 6 times.
✓ Branch 17 taken 16 times.
✗ Branch 18 not taken.
87 if comp.linear and isSome(jacobian) and not comp.homotopy and not comp.mixed
979 and not List.any(eqns, isForOrGenericResidual)
980 and not jacobianHasGenericLoopCalls(Util.getOption(jacobian))
981 and allLinVarsFound then
982 // Linear torn systems with an analytic Jacobian get solved directly (A*x=b)
983 // instead of via Newton (#16458). Homotopy, for-loop/generic residuals,
984 // generic_loop_calls Jacobians, and mixed (discrete-coupled, e.g. ideal-diode
985 // switching networks) systems fall back below -- a one-shot direct solve has
986 // no damping across the discrete state, and coarser NBackend tearing than OB's
987 // for these networks makes that chatter across event iterations instead of
988 // settling (see newInst-newBackend library-testing regressions after #16463).
989
4/4
✓ Branch 1 taken 589 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 589 times.
✓ Branch 4 taken 16 times.
605 linSystem := LINEAR_SYSTEM(
990 index = simCodeIndices.equationIndex,
991 mixed = comp.mixed,
992 torn = true,
993 vars = listReverse(linVars),
994 beqs = {},
995 simJac = {},
996 residual = listReverse(eqns),
997 jacobian = jacobian,
998 sources = list(blockSource(b) for b in listReverse(eqns)),
999 indexSystem = simCodeIndices.linearSystemIndex,
1000 size = listLength(crefs),
1001 partOfJac = false
1002 );
1003 16 simCodeIndices.linearSystemIndex := simCodeIndices.linearSystemIndex + 1;
1004 16 simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1;
1005 16 tmp := LINEAR(linSystem, NONE());
1006 16 sysIndex := linSystem.index;
1007 else
1008 71 system := NONLINEAR_SYSTEM(
1009 index = simCodeIndices.equationIndex,
1010 blcks = listReverse(eqns),
1011 crefs = listReverse(crefs),
1012 indexSystem = simCodeIndices.nonlinearSystemIndex,
1013 size = listLength(crefs) + resizable_size,
1014 jacobian = Pointer.create(jacobian),
1015 homotopy = comp.homotopy,
1016 mixed = comp.mixed,
1017 torn = true
1018 );
1019 71 simCodeIndices.nonlinearSystemIndex := simCodeIndices.nonlinearSystemIndex + 1;
1020 71 simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1;
1021 71 tmp := NONLINEAR(system, NONE());
1022 71 sysIndex := system.index;
1023 end if;
1024 then (tmp, sysIndex);
1025
1026 case StrongComponent.ALIAS() algorithm
1027 2689 aliasOf := UnorderedMap.getOrDefault(comp.aliasInfo, simCodeIndices.alias_map, -1);
1028
4/4
✓ Branch 1 taken 283 times.
✓ Branch 2 taken 2406 times.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 282 times.
2690 tmp := ALIAS(simCodeIndices.equationIndex, comp.aliasInfo, aliasOf,
1029 StrongComponent.isDiscrete(comp) and not StrongComponent.isAlgebraicLoop(comp.original));
1030 2689 simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1;
1031 2689 then (tmp, getIndex(tmp));
1032
1033 case StrongComponent.ENTWINED_COMPONENT() algorithm
1034 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because entwined equations have to be resolved beforehand in Solve.solve(). Failed for:\n"
1035 + StrongComponent.toString(comp)});
1036 ✗ then fail();
1037
1038 else algorithm
1039 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed with unknown reason for\n" + StrongComponent.toString(comp)});
1040 ✗ then fail();
1041 end match;
1042 end fromStrongComponent;
1043
1044 function restrictedResizableIterator
1045 "the iterator of a slice of a for-equation with a scalar body over a
1046 resizable range, restricted to the iterations of the slice (whole if empty)"
1047 input Slice<EquationPointer> slice;
1048 output Option<Iterator> iter = NONE();
1049 protected
1050 Equation eqn = Pointer.access(Slice.getT(slice));
1051 Iterator it;
1052 algorithm
1053
3/4
✓ Branch 1 taken 48 times.
✓ Branch 2 taken 40 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 48 times.
88 if not Flags.getConfigBool(Flags.RESIZABLE_ARRAYS) or not Equation.isForEquation(Slice.getT(slice)) then
1054 40 return;
1055 end if;
1056 48 it := Equation.getForIterator(eqn);
1057
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 48 times.
48 if Iterator.isResizable(it) and Equation.size(Slice.getT(slice), true) == Iterator.size(it, true) then
1058 // an empty slice is the whole loop
1059
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
48 iter := if listEmpty(slice.indices) then SOME(it) else Resizable.restrictIterator(it, slice.indices);
1060 end if;
1061 end restrictedResizableIterator;
1062
1063 function coversAllResizableIterations
1064 "true if the slice of a for-equation over a resizable range contains every
1065 iteration at the analysis sizes. The generated call decodes an index as the
1066 position of an iteration and computes the whole body of it."
1067 input Slice<EquationPointer> slice;
1068 output Boolean b = false;
1069 protected
1070 Equation eqn = Pointer.access(Slice.getT(slice));
1071 Iterator iter;
1072 Integer n;
1073 array<Boolean> seen;
1074 algorithm
1075
2/4
✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 84 times.
84 if not Equation.isForEquation(Slice.getT(slice)) or listEmpty(slice.indices) then
1076 ✗ return;
1077 end if;
1078 84 iter := Equation.getForIterator(eqn);
1079
2/2
✓ Branch 1 taken 20 times.
✓ Branch 2 taken 64 times.
84 if not Iterator.isResizable(iter) then
1080 20 return;
1081 end if;
1082 64 n := Iterator.size(iter, true);
1083
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
64 if n <= 0 then
1084 ✗ return;
1085 end if;
1086 64 seen := arrayCreate(n, false);
1087
2/2
✓ Branch 0 taken 224 times.
✓ Branch 1 taken 64 times.
288 for i in slice.indices loop
1088
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 224 times.
224 arrayUpdate(seen, mod(i, n) + 1, true);
1089 end for;
1090 64 b := Array.all(seen, Util.id);
1091 end coversAllResizableIterations;
1092
1093 function createResidual
1094 input Slice<EquationPointer> slice;
1095 output Block blck;
1096 input output SimCodeIndices simCodeIndices;
1097 input output Integer res_idx;
1098 input UnorderedMap<ComponentRef, Block> equation_map;
1099 protected
1100 Equation eqn = Pointer.access(Slice.getT(slice));
1101 algorithm
1102 blck := match (eqn, slice.indices)
1103 local
1104 Block tmp;
1105 Integer i;
1106 list<Subscript> subs;
1107 Equation body_eqn;
1108
1109 // a scalar equation has size 1, so a slice {1} is the same as no slice
1110 case (BEquation.SCALAR_EQUATION(), _) algorithm
1111 709 tmp := RESIDUAL(simCodeIndices.equationIndex, res_idx, eqn.rhs, eqn.source, eqn.attr);
1112 709 simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1;
1113 709 res_idx := res_idx + 1;
1114 then tmp;
1115
1116 case (BEquation.IF_EQUATION(), _) algorithm
1117 ✗ (tmp, simCodeIndices, res_idx) := createResidual(Slice.SLICE(Pointer.create(IfEquationBody.inline(eqn.body, eqn)), slice.indices), simCodeIndices, res_idx, equation_map);
1118 then tmp;
1119
1120 // unsliced array equation
1121 case (BEquation.ARRAY_EQUATION(), {}) algorithm
1122 7 tmp := ARRAY_RESIDUAL(simCodeIndices.equationIndex, res_idx, eqn.rhs, eqn.source, eqn.attr);
1123 7 simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1;
1124 7 res_idx := res_idx + Equation.size(Slice.getT(slice));
1125 then tmp;
1126
1127 // single slice array equation
1128 case (BEquation.ARRAY_EQUATION(), {i}) algorithm
1129 // get subscripts and apply them to rhs
1130 ✗ subs := list(Subscript.fromExp(Expression.INTEGER(s)) for s in Slice.indexToLocation(i, Equation.sizes(Slice.getT(slice))));
1131 ✗ tmp := ARRAY_RESIDUAL(simCodeIndices.equationIndex, res_idx, Expression.applySubscripts(subs, eqn.rhs), eqn.source, eqn.attr);
1132 ✗ simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1;
1133 ✗ res_idx := res_idx + listLength(slice.indices);
1134 then tmp;
1135
1136 // handle large slice array equation as full slice
1137 // Note: could be improved -> scalarize? find good pattern?
1138 case (BEquation.ARRAY_EQUATION(), _) algorithm
1139 ✗ tmp := ARRAY_RESIDUAL(simCodeIndices.equationIndex, res_idx, eqn.rhs, eqn.source, eqn.attr);
1140 ✗ simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1;
1141 ✗ res_idx := res_idx + Equation.size(Slice.getT(slice));
1142 then tmp;
1143
1144 // for equations have to be split up before. Since they are not causalized
1145 // they can be executed in any order
1146 case (BEquation.FOR_EQUATION(body = {_}), {}) algorithm
1147 14 tmp := FOR_RESIDUAL(simCodeIndices.equationIndex, res_idx, SimIterator.fromIterator(eqn.iter), Util.getOption(Equation.getRHS(eqn)), eqn.source, eqn.attr);
1148 14 simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1;
1149 14 res_idx := res_idx + Equation.size(Slice.getT(slice));
1150 then tmp;
1151
1152 // the generic residual writes one value per index, an array valued body would overflow the residual array
1153 case (BEquation.FOR_EQUATION(body = {body_eqn}), _) guard(Equation.size(Pointer.create(body_eqn)) > 1) algorithm
1154 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " does not support a part of a for equation with an array valued body:\n"
1155 + Slice.toString(slice, function Equation.pointerToString(str = ""))});
1156 ✗ then fail();
1157
1158 // generic residual, for loop could not be fully recovered
1159 case (BEquation.FOR_EQUATION(body = {_}), _) algorithm
1160 ✗ tmp := GENERIC_RESIDUAL(simCodeIndices.equationIndex, res_idx, slice.indices, SimIterator.fromIterator(eqn.iter), Util.getOption(Equation.getRHS(eqn)), eqn.source, eqn.attr);
1161 ✗ simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1;
1162 ✗ res_idx := res_idx + listLength(slice.indices);
1163 then tmp;
1164
1165 // WHEN equations can appear as residuals in event-iteration algebraic loops.
1166 // They are evaluated (not minimized) during the iteration — create a WHEN block.
1167 // res_idx is NOT incremented since this is not a numerical residual.
1168 case (BEquation.WHEN_EQUATION(), _) algorithm
1169 ✗ (tmp, simCodeIndices) := createWhenBody(eqn.body, eqn.source, eqn.attr, simCodeIndices);
1170 then tmp;
1171
1172 // ToDo: add all other cases!
1173
1174 else algorithm
1175 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for\n" + Slice.toString(slice, function Equation.pointerToString(str = ""))});
1176 ✗ then fail();
1177
1178 end match;
1179 730 UnorderedMap.add(Equation.getEqnName(Pointer.create(eqn)), blck, equation_map);
1180 end createResidual;
1181
1182 function createEquation
1183 "Creates a single equation"
1184 input Variable var;
1185 input Equation eqn;
1186 input Solve.Status status;
1187 output Block blck;
1188 input output SimCodeIndices simCodeIndices;
1189 input Partition.Kind kind;
1190 input UnorderedMap<ComponentRef, SimVar> simcode_map;
1191 input UnorderedMap<ComponentRef, Block> equation_map;
1192 algorithm
1193 blck := match (eqn, status)
1194 local
1195 Operator operator;
1196 Expression lhs, rhs;
1197 Block tmp;
1198 list<tuple<Expression, list<Block>>> branches;
1199
1200 case (BEquation.SCALAR_EQUATION(), NBSolve.Status.EXPLICIT) algorithm
1201 4823 tmp := SIMPLE_ASSIGN(simCodeIndices.equationIndex, var.name, eqn.rhs, eqn.source, eqn.attr);
1202 4823 simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1;
1203 then tmp;
1204
1205 case (BEquation.ARRAY_EQUATION(), NBSolve.Status.EXPLICIT) algorithm
1206 // expand scalar rhs to array when lhs is array (implicit broadcast in Modelica)
1207
1/2
✓ Branch 2 taken 532 times.
✗ Branch 3 not taken.
532 rhs := if Type.isArray(Expression.typeOf(eqn.rhs)) then eqn.rhs else Expression.fillType(eqn.ty, eqn.rhs);
1208 532 tmp := ARRAY_ASSIGN(simCodeIndices.equationIndex, eqn.lhs, rhs, eqn.source, eqn.attr);
1209 532 simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1;
1210 then tmp;
1211
1212 case (BEquation.RECORD_EQUATION(), NBSolve.Status.EXPLICIT) algorithm
1213 66 (tmp, simCodeIndices) := createAlgorithm(eqn, simCodeIndices, equation_map);
1214 then tmp;
1215
1216 case (BEquation.FOR_EQUATION(), NBSolve.Status.EXPLICIT) algorithm
1217 1 (tmp, simCodeIndices) := createAlgorithm(eqn, simCodeIndices, equation_map);
1218 then tmp;
1219
1220 case (BEquation.WHEN_EQUATION(), NBSolve.Status.EXPLICIT) algorithm
1221 64 (tmp, simCodeIndices) := createWhenBody(eqn.body, eqn.source, eqn.attr, simCodeIndices);
1222 then tmp;
1223
1224 case (BEquation.IF_EQUATION(), NBSolve.Status.EXPLICIT) algorithm
1225 ✗ (branches, simCodeIndices) := createIfBody(eqn.body, {}, simCodeIndices, kind, simcode_map, equation_map);
1226 ✗ tmp := IF(simCodeIndices.equationIndex, listReverse(branches), eqn.source, eqn.attr);
1227 ✗ simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1;
1228 then tmp;
1229
1230 case (BEquation.ALGORITHM(), NBSolve.Status.EXPLICIT) algorithm
1231 57 tmp := ALGORITHM(simCodeIndices.equationIndex, eqn.alg.statements, eqn.attr);
1232 57 simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1;
1233 then tmp;
1234
1235 // ToDo: add all other cases!
1236
1237 // fallback implicit solving
1238 case (_, NBSolve.Status.IMPLICIT) algorithm
1239 ✗ (tmp, simCodeIndices) := createImplicitEquation(var, eqn, simCodeIndices, kind, simcode_map, equation_map);
1240 then tmp;
1241
1242 else algorithm
1243 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed with status " + Solve.statusString(status) + " for\n" + Equation.toString(eqn)});
1244 ✗ then fail();
1245
1246 end match;
1247 5543 UnorderedMap.add(Equation.getEqnName(Pointer.create(eqn)), blck, equation_map);
1248 end createEquation;
1249
1250 function createImplicitEquation
1251 "Creates a single implicit equation"
1252 input BVariable.Variable var;
1253 input Equation eqn;
1254 output Block blck;
1255 input output SimCodeIndices simCodeIndices;
1256 input Partition.Kind kind;
1257 input UnorderedMap<ComponentRef, SimVar> simcode_map;
1258 input UnorderedMap<ComponentRef, Block> equation_map;
1259 protected
1260 StrongComponent comp;
1261 Integer index;
1262 algorithm
1263 ✗ (comp, index) := Tearing.implicit(
1264 comp = StrongComponent.SINGLE_COMPONENT(Pointer.create(var), Pointer.create(eqn), NBSolve.Status.IMPLICIT),
1265 funcMap = UnorderedMap.new<Function>(AbsynUtil.pathHash, AbsynUtil.pathEqual),
1266 index = simCodeIndices.implicitIndex,
1267 kind = kind
1268 );
1269 ✗ simCodeIndices.implicitIndex := index;
1270 ✗ (blck, simCodeIndices) := fromStrongComponent(comp, simCodeIndices, kind, simcode_map, equation_map);
1271 end createImplicitEquation;
1272
1273 function createWhenBody
1274 input WhenEquationBody body;
1275 output Block blck;
1276 input DAE.ElementSource source;
1277 input EquationAttributes attr;
1278 input output SimCodeIndices simCodeIndices;
1279 protected
1280 list<ComponentRef> conditions;
1281 list<WhenStatement> when_stmts;
1282 Option<WhenEquationBody> else_when;
1283 Block tmp;
1284 Option<Block> else_when_block;
1285 Integer index = simCodeIndices.equationIndex;
1286 algorithm
1287 105 simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1;
1288 105 (conditions, when_stmts, else_when) := WhenEquationBody.getBodyAttributes(body);
1289
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 105 times.
✓ Branch 2 taken 41 times.
✓ Branch 3 taken 64 times.
105 if isSome(else_when) then
1290 41 (tmp, simCodeIndices) := createWhenBody(Util.getOption(else_when), source, attr, simCodeIndices);
1291 else_when_block := SOME(tmp);
1292 else
1293 else_when_block := NONE();
1294 end if;
1295 105 blck := WHEN(index, false, conditions, when_stmts, else_when_block, source, attr);
1296 end createWhenBody;
1297
1298 function createIfBody
1299 input IfEquationBody body;
1300 input output list<tuple<Expression, list<Block>>> branches;
1301 input output SimCodeIndices simCodeIndices;
1302 input Partition.Kind kind;
1303 input UnorderedMap<ComponentRef, SimVar> simcode_map;
1304 input UnorderedMap<ComponentRef, Block> equation_map;
1305 protected
1306 list<StrongComponent> comps;
1307 Block blck;
1308 list<Block> blcks = {};
1309 algorithm
1310 ✗ comps := list(StrongComponent.fromSolvedEquationSlice(Slice.SLICE(eqn, {})) for eqn in body.then_eqns);
1311
1312 ✗ for comp in listReverse(comps) loop
1313 ✗ (blck, simCodeIndices, _) := Block.fromStrongComponent(comp, simCodeIndices, kind, simcode_map, equation_map);
1314 blcks := blck :: blcks;
1315 end for;
1316
1317 ✗ branches := (body.condition, blcks) :: branches;
1318 ✗ if isSome(body.else_if) then
1319 ✗ (branches, simCodeIndices) := createIfBody(Util.getOption(body.else_if), branches, simCodeIndices, kind, simcode_map, equation_map);
1320 end if;
1321 end createIfBody;
1322
1323 function createAlgorithm
1324 input Equation eqn;
1325 output Block blck;
1326 input output SimCodeIndices indices;
1327 input UnorderedMap<ComponentRef, Block> equation_map;
1328 protected
1329 list<Statement> stmts;
1330 algorithm
1331 stmts := match eqn
1332 254 case Equation.ALGORITHM() then eqn.alg.statements;
1333 96 else Equation.toStatement(eqn);
1334 end match;
1335
1336 350 blck := ALGORITHM(indices.equationIndex, stmts, Equation.getAttributes(eqn));
1337 350 indices.equationIndex := indices.equationIndex + 1;
1338 350 UnorderedMap.add(Equation.getEqnName(Pointer.create(eqn)), blck, equation_map);
1339 end createAlgorithm;
1340
1341 function createAssignment
1342 "Creates an assignment equation."
1343 input Equation eqn;
1344 output Block blck;
1345 input output SimCodeIndices simCodeIndices;
1346 algorithm
1347 blck := match eqn
1348 local
1349 Equation qual;
1350 Operator operator;
1351 ComponentRef cref;
1352 Expression lhs, rhs;
1353 Block tmp;
1354
1355 case qual as BEquation.SCALAR_EQUATION(lhs = Expression.CREF(cref = cref))
1356 algorithm
1357 ✗ tmp := SIMPLE_ASSIGN(simCodeIndices.equationIndex, cref, qual.rhs, qual.source, qual.attr);
1358 ✗ simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1;
1359 then tmp;
1360
1361 case qual as BEquation.ARRAY_EQUATION(lhs = Expression.CREF(cref = cref))
1362 algorithm
1363 ✗ tmp := SIMPLE_ASSIGN(simCodeIndices.equationIndex, cref, qual.rhs, qual.source, qual.attr);
1364 ✗ simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1;
1365 then tmp;
1366
1367 // ToDo: add all other cases!
1368
1369 else algorithm
1370 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for\n" + Equation.toString(eqn)});
1371 ✗ then fail();
1372
1373 end match;
1374 end createAssignment;
1375
1376 function collectAlgebraicLoops
1377 input list<list<Block>> blcks;
1378 input output list<Block> linearLoops;
1379 input output list<Block> nonlinearLoops;
1380 input output list<SimJacobian> jacobians;
1381 input output SimCodeIndices simCodeIndices;
1382 input UnorderedMap<ComponentRef, SimVar> simcode_map;
1383 algorithm
1384
2/2
✓ Branch 0 taken 710 times.
✓ Branch 1 taken 565 times.
1275 for blck_lst in blcks loop
1385 710 (linearLoops, nonlinearLoops, jacobians, simCodeIndices) := collectAlgebraicLoopsSingle(blck_lst, linearLoops, nonlinearLoops, jacobians, simCodeIndices, simcode_map);
1386 end for;
1387 end collectAlgebraicLoops;
1388
1389 function collectAlgebraicLoopsSingle
1390 input list<Block> blck_lst;
1391 input output list<Block> linearLoops;
1392 input output list<Block> nonlinearLoops;
1393 input output list<SimJacobian> jacobians;
1394 input output SimCodeIndices simCodeIndices;
1395 input UnorderedMap<ComponentRef, SimVar> simcode_map;
1396 algorithm
1397
5/5
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 69 times.
✓ Branch 2 taken 6176 times.
✓ Branch 3 taken 6261 times.
✓ Branch 4 taken 710 times.
6971 for blck in blck_lst loop
1398 (linearLoops, nonlinearLoops) := match blck
1399 local
1400 Option<SimJacobian> opt_jacobian;
1401 SimJacobian jacobian;
1402
1403 case LINEAR() algorithm
1404
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
16 if isSome(blck.system.jacobian) then
1405 16 jacobians := Util.getOption(blck.system.jacobian) :: jacobians;
1406 end if;
1407 then (blck :: linearLoops, nonlinearLoops);
1408 case NONLINEAR() algorithm
1409 69 opt_jacobian := NonlinearSystem.getJacobian(blck.system);
1410
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 69 times.
✓ Branch 2 taken 69 times.
✗ Branch 3 not taken.
69 if isSome(opt_jacobian) then
1411 69 jacobian := Util.getOption(opt_jacobian);
1412 jacobians := jacobian :: jacobians;
1413 end if;
1414 69 blck.system := NonlinearSystem.setJacobian(blck.system, opt_jacobian);
1415 then (linearLoops, blck :: nonlinearLoops);
1416 else (linearLoops, nonlinearLoops);
1417 end match;
1418 end for;
1419 end collectAlgebraicLoopsSingle;
1420
1421 function convert
1422 input Block blck;
1423 output OldSimCode.SimEqSystem oldBlck;
1424 algorithm
1425 oldBlck := match blck
1426 local
1427 Expression exp;
1428 list<Block> blcks;
1429 list<tuple<DAE.Exp, list<OldSimCode.SimEqSystem>>> oldBranches = {};
1430 list<OldSimCode.SimEqSystem> else_branch = {};
1431
1432 1500 case RESIDUAL() then OldSimCode.SES_RESIDUAL(blck.index, blck.res_index, Expression.toDAE(blck.exp), blck.source, EquationAttributes.convert(blck.attr));
1433 20 case ARRAY_RESIDUAL() then OldSimCode.SES_RESIDUAL(blck.index, blck.res_index, Expression.toDAE(blck.exp), blck.source, EquationAttributes.convert(blck.attr));
1434
4/4
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 31 times.
✓ Branch 2 taken 45 times.
✓ Branch 3 taken 31 times.
76 case FOR_RESIDUAL() then OldSimCode.SES_FOR_RESIDUAL(blck.index, blck.res_index, list(SimIterator.convert(it) for it in blck.iterators), Expression.toDAE(blck.exp), blck.source, EquationAttributes.convert(blck.attr));
1435 ✗ case GENERIC_RESIDUAL() then OldSimCode.SES_GENERIC_RESIDUAL(blck.index, blck.res_index, blck.scal_indices, list(SimIterator.convert(it) for it in blck.iterators), Expression.toDAE(blck.exp), blck.source, EquationAttributes.convert(blck.attr));
1436 7840 case SIMPLE_ASSIGN() then OldSimCode.SES_SIMPLE_ASSIGN(blck.index, ComponentRef.toDAE(blck.lhs), Expression.toDAE(blck.rhs), blck.source, EquationAttributes.convert(blck.attr));
1437 652 case ARRAY_ASSIGN() then OldSimCode.SES_ARRAY_CALL_ASSIGN(blck.index, Expression.toDAE(blck.lhs), Expression.toDAE(blck.rhs), blck.source, EquationAttributes.convert(blck.attr));
1438
4/4
✓ Branch 0 taken 696 times.
✓ Branch 1 taken 598 times.
✓ Branch 2 taken 696 times.
✓ Branch 3 taken 598 times.
1294 case RESIZABLE_ASSIGN() then OldSimCode.SES_RESIZABLE_ASSIGN(blck.index, blck.call_index, list(SimIterator.convert(it) for it in blck.iters), blck.source, EquationAttributes.convert(blck.attr));
1439 59 case GENERIC_ASSIGN() then OldSimCode.SES_GENERIC_ASSIGN(blck.index, blck.call_index, blck.scal_indices, blck.source, EquationAttributes.convert(blck.attr));
1440
4/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 3 times.
12 case ENTWINED_ASSIGN() then OldSimCode.SES_ENTWINED_ASSIGN(blck.index, blck.call_order, list(convert(single_call) for single_call in blck.single_calls), blck.source, EquationAttributes.convert(blck.attr));
1441 case IF() algorithm
1442 ✗ for branch in blck.branches loop
1443 ✗ (exp, blcks) := branch;
1444 ✗ if Expression.isEnd(exp) then
1445 ✗ if listEmpty(else_branch) then
1446 ✗ else_branch := list(convert(blck_) for blck_ in blcks);
1447 else
1448 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because there is
1449 at least two non-conditional branches in:\n" + Block.toString(blck)});
1450 ✗ fail();
1451 end if;
1452 elseif listEmpty(else_branch) then
1453 ✗ oldBranches := (Expression.toDAE(exp), list(convert(blck_) for blck_ in blcks)) :: oldBranches;
1454 else
1455 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because there is a
1456 conditional branch after a non-conditional branch in:\n" + Block.toString(blck)});
1457 ✗ fail();
1458 end if;
1459 end for;
1460 ✗ if listEmpty(else_branch) then
1461 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because there "
1462 + "is no non-conditional branch in:\n" + Block.toString(blck)});
1463 ✗ fail();
1464 end if;
1465 ✗ then OldSimCode.SES_IFEQUATION(
1466 index = blck.index,
1467 ifbranches = listReverse(oldBranches),
1468 elsebranch = else_branch,
1469 source = blck.source,
1470 eqAttr = EquationAttributes.convert(blck.attr)
1471 );
1472
1473
8/8
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 123 times.
✓ Branch 2 taken 132 times.
✓ Branch 3 taken 123 times.
✓ Branch 5 taken 123 times.
✓ Branch 6 taken 123 times.
✓ Branch 7 taken 123 times.
✓ Branch 8 taken 123 times.
378 case WHEN() then OldSimCode.SES_WHEN(
1474 index = blck.index,
1475 conditions = list(ComponentRef.toDAE(cr) for cr in blck.conditions),
1476 initialCall = blck.initialCall,
1477 whenStmtLst = list(WhenStatement.convert(stmt) for stmt in blck.when_stmts),
1478 elseWhen = Util.applyOption(blck.else_when, convert),
1479 source = blck.source,
1480 eqAttr = EquationAttributes.convert(blck.attr)
1481 );
1482
1483 39 case LINEAR() then OldSimCode.SES_LINEAR(LinearSystem.convert(blck.system), NONE(), EquationAttributes.convert(EquationAttributes.default(EquationKind.CONTINUOUS, false)) /* dangerous! */);
1484
1485 166 case NONLINEAR() then OldSimCode.SES_NONLINEAR(NonlinearSystem.convert(blck.system), NONE(), EquationAttributes.convert(EquationAttributes.default(EquationKind.CONTINUOUS, false)) /* dangerous! */);
1486
1487 972 case ALGORITHM() then OldSimCode.SES_ALGORITHM(blck.index, NSimGenericCall.setRelationAsubStatements(ConvertDAE.convertStatements(blck.stmts)), EquationAttributes.convert(blck.attr));
1488
1489 5859 case ALIAS() guard(blck.aliasOf > 0) then OldSimCode.SES_ALIAS(blck.index, blck.aliasOf);
1490
1491 // ToDo: add all the other cases here!
1492
1493
1494 case ALIAS() guard(blck.aliasOf == -1) algorithm
1495 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for following alias block because the index has not been updated:\n" + toString(blck)});
1496 ✗ then fail();
1497
1498 else algorithm
1499 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for\n" + toString(blck)});
1500 ✗ then fail();
1501 end match;
1502 end convert;
1503
1504 function convertList
1505 input list<Block> blck_lst;
1506 output list<OldSimCode.SimEqSystem> oldBlck_lst = list(convert(blck) for blck in blck_lst);
1507 end convertList;
1508
1509 function convertListList
1510 input list<list<Block>> blck_lst_lst;
1511 output list<list<OldSimCode.SimEqSystem>> oldBlck_lst_lst = list(convertList(blck_lst) for blck_lst in blck_lst_lst);
1512 end convertListList;
1513
1514 function fixIndices
1515 input list<Block> blcks;
1516 input output list<Block> acc;
1517 input output SimCodeIndices indices;
1518 algorithm
1519 (acc, indices) := match blcks
1520 local
1521 Block blck;
1522 list<Block> rest;
1523 case blck :: rest algorithm
1524 ✗ (blck, indices) := fixIndex(blck, indices);
1525 ✗ then fixIndices(rest, blck :: acc, indices);
1526 else (acc, indices);
1527 end match;
1528 end fixIndices;
1529
1530 function fixIndex
1531 input output Block blck;
1532 input output SimCodeIndices indices;
1533 algorithm
1534 blck := match blck
1535 local
1536 Block tmp;
1537 list<Block> tmp_lst;
1538
1539 case RESIDUAL() algorithm
1540 ✗ blck.index := indices.equationIndex;
1541 ✗ indices.equationIndex := indices.equationIndex + 1;
1542 then blck;
1543
1544 case ARRAY_RESIDUAL() algorithm
1545 ✗ blck.index := indices.equationIndex;
1546 ✗ indices.equationIndex := indices.equationIndex + 1;
1547 then blck;
1548
1549 case SIMPLE_ASSIGN() algorithm
1550 ✗ blck.index := indices.equationIndex;
1551 ✗ indices.equationIndex := indices.equationIndex + 1;
1552 then blck;
1553
1554 case ARRAY_ASSIGN() algorithm
1555 ✗ blck.index := indices.equationIndex;
1556 ✗ indices.equationIndex := indices.equationIndex + 1;
1557 then blck;
1558
1559 case RESIZABLE_ASSIGN() algorithm
1560 ✗ blck.index := indices.equationIndex;
1561 ✗ indices.equationIndex := indices.equationIndex + 1;
1562 then blck;
1563
1564 case GENERIC_ASSIGN() algorithm
1565 ✗ blck.index := indices.equationIndex;
1566 ✗ indices.equationIndex := indices.equationIndex + 1;
1567 then blck;
1568
1569 case ALIAS() algorithm
1570 ✗ blck.index := indices.equationIndex;
1571 ✗ indices.equationIndex := indices.equationIndex + 1;
1572 then blck;
1573
1574 case ALGORITHM() algorithm
1575 ✗ blck.index := indices.equationIndex;
1576 ✗ indices.equationIndex := indices.equationIndex + 1;
1577 then blck;
1578
1579 case INVERSE_ALGORITHM() algorithm
1580 ✗ blck.index := indices.equationIndex;
1581 ✗ indices.equationIndex := indices.equationIndex + 1;
1582 then blck;
1583
1584 case IF() algorithm
1585 ✗ blck.index := indices.equationIndex;
1586 ✗ indices.equationIndex := indices.equationIndex + 1;
1587 then blck;
1588
1589 case WHEN() algorithm
1590 ✗ blck.index := indices.equationIndex;
1591 ✗ indices.equationIndex := indices.equationIndex + 1;
1592 ✗ if isSome(blck.else_when) then
1593 ✗ (tmp, indices) := fixIndex(Util.getOption(blck.else_when), indices);
1594 ✗ blck.else_when := SOME(tmp);
1595 end if;
1596 then blck;
1597
1598 case LINEAR() algorithm
1599 // TODO (these are not really necessary i suppose)
1600 then blck;
1601
1602 case NONLINEAR() algorithm
1603 // TODO (these are not really necessary i suppose)
1604 then blck;
1605
1606 case HYBRID() algorithm
1607 ✗ (tmp, indices) := fixIndex(blck.continuous, indices);
1608 ✗ (tmp_lst, indices) := fixIndices(blck.discreteEqs, {}, indices);
1609 ✗ blck.continuous := tmp;
1610 ✗ blck.discreteEqs := tmp_lst;
1611 then blck;
1612
1613 else algorithm
1614 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for\n" + toString(blck)});
1615 ✗ then fail();
1616 end match;
1617 end fixIndex;
1618
1619 function collectEntwinedEquations
1620 "collects entwined equations from initial blocks"
1621 input Block blck;
1622 output list<Block> lst;
1623 algorithm
1624 lst := match blck
1625 1 case ENTWINED_ASSIGN() then blck.single_calls;
1626 else {};
1627 end match;
1628 end collectEntwinedEquations;
1629 protected
1630 function whenString
1631 input list<ComponentRef> conditions;
1632 input list<WhenStatement> when_stmts;
1633 input Option<Block> else_when;
1634 input output String str = "";
1635 protected
1636 String indent = str;
1637 algorithm
1638 ✗ str := "when " + List.toString(conditions, ComponentRef.toString) + "\n" +
1639 List.toString(when_stmts, function WhenStatement.toString(str = indent + "\t"), List.Style.NEWLINE) + "\n";
1640 ✗ if isSome(else_when) then
1641 ✗ str := str + indent + "else" + toString(Util.getOption(else_when));
1642 else
1643 ✗ str := str + indent + "end when;\n";
1644 end if;
1645 end whenString;
1646
1647 function getGenericAssignIndex
1648 input Block blck;
1649 output Integer index;
1650 algorithm
1651 index := match blck
1652 ✗ case RESIZABLE_ASSIGN() then blck.call_index;
1653 ✗ case GENERIC_ASSIGN() then blck.call_index;
1654 else algorithm
1655 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for\n" + toString(blck)});
1656 ✗ then fail();
1657 end match;
1658 end getGenericAssignIndex;
1659
1660 function getGenericEquationName
1661 input StrongComponent comp;
1662 output ComponentRef name;
1663 algorithm
1664 name := match comp
1665 ✗ case StrongComponent.GENERIC_COMPONENT() then Equation.getEqnName(Slice.getT(comp.eqn));
1666 else algorithm
1667 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for\n" + StrongComponent.toString(comp)});
1668 ✗ then fail();
1669 end match;
1670 end getGenericEquationName;
1671
1672 function getEntwinedEquationName
1673 "Returns the equation name for any slice type that can appear in an ENTWINED_COMPONENT."
1674 input StrongComponent comp;
1675 output ComponentRef name;
1676 algorithm
1677 name := match comp
1678 ✗ case StrongComponent.SINGLE_COMPONENT() then Equation.getEqnName(comp.eqn);
1679 ✗ case StrongComponent.MULTI_COMPONENT() then Equation.getEqnName(Slice.getT(comp.eqn));
1680 ✗ case StrongComponent.SLICED_COMPONENT() then Equation.getEqnName(Slice.getT(comp.eqn));
1681 6 case StrongComponent.GENERIC_COMPONENT() then Equation.getEqnName(Slice.getT(comp.eqn));
1682 ✗ case StrongComponent.RESIZABLE_COMPONENT() then Equation.getEqnName(Slice.getT(comp.eqn));
1683 else algorithm
1684 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for\n" + StrongComponent.toString(comp)});
1685 ✗ then fail();
1686 end match;
1687 end getEntwinedEquationName;
1688 end Block;
1689
1690 uniontype LinearSystem
1691 record LINEAR_SYSTEM
1692 Integer index;
1693 Boolean mixed;
1694 Boolean torn;
1695 list<SimVar> vars;
1696 list<Expression> beqs; //ToDo what is this? binding expressions?
1697 list<tuple<Integer, Integer, Block>> simJac; // ToDo: is this the old jacobian structure?
1698 /* solver linear tearing system */
1699 list<Block> residual;
1700 Option<SimJacobian> jacobian;
1701 list<DAE.ElementSource> sources;
1702 Integer indexSystem;
1703 Integer size "Number of variables that are solved in this system. Needed because 'crefs' only contains the iteration variables.";
1704 Boolean partOfJac "if TRUE then this system is part of a jacobian matrix";
1705 end LINEAR_SYSTEM;
1706
1707 function toString
1708 input LinearSystem system;
1709 input output String str;
1710 algorithm
1711
3/6
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 2 times.
6 str := "Linear System (size = " + intString(system.size) + ", jacobian = " + boolString(system.partOfJac) + ", mixed = " + boolString(system.mixed) + ", torn = " + boolString(system.torn) + ")\n" + Block.listToString(system.residual, str + "--");
1712 end toString;
1713
1714 function convert
1715 input LinearSystem system;
1716 output OldSimCode.LinearSystem oldSystem;
1717 algorithm
1718 39 oldSystem := OldSimCode.LINEARSYSTEM(
1719 index = system.index,
1720 partOfMixed = system.mixed,
1721 tornSystem = system.torn,
1722 vars = SimVar.convertList(system.vars),
1723 beqs = {},
1724 simJac = {},
1725 residual = Block.convertList(system.residual),
1726 jacobianMatrix = Util.applyOption(system.jacobian, SimJacobian.convert),
1727 sources = system.sources,
1728 indexLinearSystem = system.indexSystem,
1729 nUnknowns = system.size,
1730 partOfJac = system.partOfJac
1731 );
1732 end convert;
1733 end LinearSystem;
1734
1735 uniontype NonlinearSystem
1736 record NONLINEAR_SYSTEM
1737 Integer index;
1738 list<Block> blcks "equations";
1739 list<ComponentRef> crefs "iteration variables";
1740 Integer indexSystem;
1741 Integer size "Number of variables that are solved in this system. Needed because 'crefs' only contains the iteration variables.";
1742 Pointer<Option<SimJacobian>> jacobian;
1743 Boolean homotopy;
1744 Boolean mixed;
1745 Boolean torn;
1746 end NONLINEAR_SYSTEM;
1747
1748 function getJacobian
1749 input NonlinearSystem syst;
1750 output Option<SimJacobian> jacobian = Pointer.access(syst.jacobian);
1751 end getJacobian;
1752
1753 function setJacobian
1754 input output NonlinearSystem syst;
1755 input Option<SimJacobian> jacobian;
1756 algorithm
1757 69 Pointer.update(syst.jacobian, jacobian);
1758 end setJacobian;
1759
1760 function toString
1761 input NonlinearSystem system;
1762 input output String str;
1763 algorithm
1764
4/6
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 4 times.
✓ Branch 7 taken 11 times.
✗ Branch 8 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 11 times.
29 str := "Nonlinear System (size = " + intString(system.size) + ", homotopy = " + boolString(system.homotopy)
1765 + ", mixed = " + boolString(system.mixed) + ", torn = " + boolString(system.torn) + ")\n"
1766 + str + "--" + List.toStringCustom(system.crefs, ComponentRef.toString, "Iteration Vars:", "{", ", ", "}", true, 10) + "\n"
1767 + Block.listToString(system.blcks, str + "--");
1768 end toString;
1769
1770 function convert
1771 input NonlinearSystem system;
1772 output OldSimCode.NonlinearSystem oldSystem;
1773 protected
1774 list<DAE.ComponentRef> crefs = {};
1775 algorithm
1776
2/2
✓ Branch 0 taken 727 times.
✓ Branch 1 taken 166 times.
893 for cref in system.crefs loop
1777 727 crefs := ComponentRef.toDAE(cref) :: crefs;
1778 end for;
1779 166 oldSystem := OldSimCode.NONLINEARSYSTEM(
1780 index = system.index,
1781 eqs = Block.convertList(system.blcks),
1782 crefs = listReverse(crefs),
1783 indexNonLinearSystem = system.indexSystem,
1784 nUnknowns = system.size,
1785 jacobianMatrix = Util.applyOption(Pointer.access(system.jacobian), SimJacobian.convert), // ToDo update this!
1786 homotopySupport = system.homotopy,
1787 mixedSystem = system.mixed,
1788 tornSystem = system.torn,
1789 clockIndex = NONE() // ToDo update this
1790 );
1791 end convert;
1792 end NonlinearSystem;
1793
1794 annotation(__OpenModelica_Interface="nbackend");
1795 end NSimStrongComponent;
1796