Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 79.5% 252 / 0 / 317
Functions: -% 0 / 1 / 1
Branches: 84.8% 195 / 0 / 230

OMCompiler/Compiler/NBackEnd/Modules/1_Main/NBPartitioning.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 NBPartitioning
37 "file: NBPartitioning.mo
38 package: NBPartitioning
39 description: This file contains the functions for the partitioning module.
40 "
41
42 public
43 import Module = NBModule;
44
45 protected
46 // NF
47 import NFBackendExtension.{BackendInfo, VariableKind};
48 import Call = NFCall;
49 import ClockKind = NFClockKind;
50 import ComponentRef = NFComponentRef;
51 import Expression = NFExpression;
52 import NFFunction.Function;
53 import Type = NFType;
54 import Variable = NFVariable;
55
56 // Backend
57 import Adjacency = NBAdjacency;
58 import BackendDAE = NBackendDAE;
59 import Causalize = NBCausalize;
60 import BEquation = NBEquation;
61 import NBEquation.{Equation, EquationPointer, EquationPointers, EqData, EquationKind, WhenEquationBody, WhenStatement};
62 import Matching = NBMatching;
63 import Sorting = NBSorting;
64 import StrongComponent = NBStrongComponent;
65 import Partition = NBPartition;
66 import BVariable = NBVariable;
67 import NBVariable.{VariablePointer, VariablePointers, VarData};
68
69 // Util
70 import MetaModelica.Dangerous;
71 import DoubleEnded;
72 import Rational;
73 import NBBackendUtil;
74 import PointerWeak;
75 import UnorderedMap;
76 import UnorderedSet;
77
78 // Old imports
79 import OldDAE = DAE;
80 import OldBackendDAE = BackendDAE;
81
82 public
83 uniontype BClock
84 record BASE_CLOCK
85 ClockKind clock;
86 end BASE_CLOCK;
87
88 record SUB_CLOCK
89 Rational factor;
90 Rational shift;
91 Option<String> solver;
92 end SUB_CLOCK;
93
94 record INFERRED_CLOCK
95 ComponentRef base_ref;
96 end INFERRED_CLOCK;
97
98 function toString
99 input BClock clock;
100 output String str;
101 algorithm
102 str := match clock
103 85 case BASE_CLOCK() then ClockKind.toDebugString(clock.clock);
104 72 case SUB_CLOCK() then "SUB_CLOCK(" + Rational.toString(clock.factor) + ", " + Rational.toString(clock.shift) + ")";
105 ✗ case INFERRED_CLOCK() then "INFERRED_CLOCK(" + ComponentRef.toString(clock.base_ref) + ")";
106 else "UNKNOWN_CLOCK()";
107 end match;
108 end toString;
109
110 function hash
111 input BClock clock;
112 output Integer i = stringHashDjb2(toString(clock));
113 end hash;
114
115 function isEqual
116 input BClock clock1;
117 input BClock clock2;
118 output Boolean b;
119 algorithm
120 b := match (clock1, clock2)
121 57 case (BASE_CLOCK(), BASE_CLOCK()) then ClockKind.compare(clock1.clock, clock2.clock) == 0;
122
4/6
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 3 times.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 14 times.
17 case (SUB_CLOCK(), SUB_CLOCK()) then Rational.isEqual(clock1.factor, clock2.factor) and Rational.isEqual(clock1.shift, clock2.shift) and Util.optionEqual(clock1.solver, clock2.solver, stringEq);
123 ✗ case (INFERRED_CLOCK(), INFERRED_CLOCK()) then ComponentRef.isEqual(clock1.base_ref, clock2.base_ref);
124 else false;
125 end match;
126 end isEqual;
127
128 function add
129 input Equation eqn;
130 input ClockedInfo info;
131 algorithm
132 () := match (Equation.getLHS(eqn), Equation.getRHS(eqn))
133 local
134 ComponentRef clock_name;
135 Expression exp;
136
137 case (SOME(Expression.CREF(cref = clock_name)), SOME(exp))
138 guard(Expression.isClockOrSampleFunction(exp)) algorithm
139 27 create(clock_name, exp, info);
140 then ();
141
142 case (SOME(exp), SOME(Expression.CREF(cref = clock_name)))
143 guard(Expression.isClockOrSampleFunction(exp)) algorithm
144 ✗ create(clock_name, exp, info);
145 then ();
146
147 else ();
148 end match;
149 end add;
150
151 function isBaseClock
152 input BClock clock;
153 output Boolean b;
154 algorithm
155 b := match clock case BASE_CLOCK() then true; else false; end match;
156 end isBaseClock;
157
158 function isInferredClock
159 input BClock clock;
160 output Boolean b;
161 algorithm
162 b := match clock
163 case BASE_CLOCK(clock = ClockKind.INFERRED_CLOCK()) then true;
164 case INFERRED_CLOCK() then true;
165 else false;
166 end match;
167 end isInferredClock;
168
169 function isEventClock
170 input BClock clock;
171 output Boolean b;
172 algorithm
173 b := match clock case BASE_CLOCK(clock = ClockKind.EVENT_CLOCK()) then true; else false; end match;
174 end isEventClock;
175
176 function baseClockInferrence
177 input output BClock clock;
178 input UnorderedMap<ComponentRef, BClock> base_clock_inferrence;
179 algorithm
180 clock := match clock
181 local
182 BClock base_clock;
183 case INFERRED_CLOCK() algorithm
184 ✗ base_clock := UnorderedMap.getSafe(clock.base_ref, base_clock_inferrence, sourceInfo());
185 ✗ then baseClockInferrence(base_clock, base_clock_inferrence);
186 case BClock.BASE_CLOCK(clock = ClockKind.INFERRED_CLOCK()) then DEFAULT_BASE_CLOCK;
187 else clock;
188 end match;
189 end baseClockInferrence;
190
191 function convertBase
192 input BClock clock;
193 output OldDAE.ClockKind oldClock;
194 algorithm
195 oldClock := match clock
196 11 case BASE_CLOCK() then ClockKind.toDAE(clock.clock);
197 else algorithm
198 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for non-base clock: " + toString(clock)});
199 ✗ then fail();
200 end match;
201 end convertBase;
202
203 function convertSub
204 input BClock clock;
205 output OldBackendDAE.SubClock oldClock;
206 algorithm
207 oldClock := match clock
208 18 case SUB_CLOCK() then OldBackendDAE.SUBCLOCK(
209 factor = NBBackendUtil.convertRational(clock.factor),
210 shift = NBBackendUtil.convertRational(clock.shift),
211 solver = clock.solver);
212 else algorithm
213 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for non-sub clock: " + toString(clock)});
214 ✗ then fail();
215 end match;
216 end convertSub;
217
218 function toExp
219 input BClock clock;
220 output Expression exp;
221 algorithm
222 exp := match clock
223 2 case BASE_CLOCK() then Expression.CLKCONST(clock.clock);
224 else algorithm
225 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for non-base clock: " + toString(clock)});
226 ✗ then fail();
227 end match;
228 end toExp;
229
230 protected
231 function create
232 input ComponentRef clock_name;
233 input Expression exp;
234 input ClockedInfo info;
235 protected
236 BClock clock;
237 Option<ComponentRef> baseClock;
238 Pointer<Variable> clock_var;
239 algorithm
240 try
241 // parse the clock and see if it depends on another clock
242 27 (clock, baseClock) := fromExp(exp);
243
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 15 times.
27 if isSome(baseClock) then
244 // sub clock
245 15 UnorderedMap.add(clock_name, clock, info.subClocks);
246 15 UnorderedMap.add(clock_name, Util.getOption(baseClock), info.subToBase);
247 else
248 // base clock
249 12 UnorderedMap.add(clock_name, clock, info.baseClocks);
250 end if;
251
252 // if this is from the equation block and not from variable binding, the variable needs to updated
253 // such that the clock can be found for the partitioning clocked association
254 27 clock_var := BVariable.getVarPointer(clock_name, sourceInfo());
255
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 24 times.
27 if not BVariable.isClockOrClocked(clock_var) then
256 3 BVariable.setVarKind(clock_var, VariableKind.CLOCKED());
257 end if;
258 else
259 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for " + ComponentRef.toString(clock_name) + "."});
260 ✗ fail();
261 end try;
262 end create;
263
264 function fromExp
265 input Expression exp;
266 output BClock subClock;
267 output Option<ComponentRef> baseClock;
268 algorithm
269 (subClock, baseClock) := match exp
270 local
271 Call call;
272
273 case Expression.CLKCONST() algorithm
274 12 then (BASE_CLOCK(exp.clk), NONE());
275
276 case Expression.CREF() algorithm
277 15 then (DEFAULT_SUB_CLOCK, SOME(exp.cref));
278
279 case Expression.CALL(call = call as Call.TYPED_CALL()) algorithm
280 (baseClock, subClock) := match (AbsynUtil.pathString(Function.nameConsiderBuiltin(call.fn)), Call.arguments(call))
281 local
282 Expression e;
283 Integer i1, i2;
284
285 // sample: default subclock sampling
286 case ("sample", {_, e}) algorithm
287 6 (subClock, baseClock) := fromExp(e);
288 6 then (baseClock, subClock);
289
290 // subclock: subset sampling
291 case ("subSample", {e, Expression.INTEGER(i1)}) algorithm
292 5 (subClock, baseClock) := fromExp(e);
293 5 subClock := updateSubClock(subClock, SUB_CLOCK(Rational.RATIONAL(i1, 1), Rational.ZERO, NONE()));
294 5 then (baseClock, subClock);
295
296 // subclock: super sampling
297 case ("superSample", {e, Expression.INTEGER(i1)}) algorithm
298 2 (subClock, baseClock) := fromExp(e);
299 2 subClock := updateSubClock(subClock, SUB_CLOCK(Rational.RATIONAL(1, i1), Rational.ZERO, NONE()));
300 2 then (baseClock, subClock);
301
302 // subclock: shift sampling (default 3rd argument = 1)
303 case ("shiftSample", {e, Expression.INTEGER(i1)}) algorithm
304 ✗ (subClock, baseClock) := fromExp(e);
305 ✗ subClock := updateSubClock(subClock, SUB_CLOCK(Rational.ONE, Rational.RATIONAL(i1, 1), NONE()));
306 ✗ then (baseClock, subClock);
307
308 // subclock: shift sampling
309 case ("shiftSample", {e, Expression.INTEGER(i1), Expression.INTEGER(i2)}) algorithm
310 2 (subClock, baseClock) := fromExp(e);
311 2 subClock := updateSubClock(subClock, SUB_CLOCK(Rational.ONE, Rational.RATIONAL(i1, i2), NONE()));
312 2 then (baseClock, subClock);
313
314 // subclock: back sampling (default 3rd argument = 1)
315 case ("backSample", {e, Expression.INTEGER(i1)}) algorithm
316 ✗ (subClock, baseClock) := fromExp(e);
317 ✗ subClock := updateSubClock(subClock, SUB_CLOCK(Rational.ONE, Rational.RATIONAL(-i1, 1), NONE()));
318 ✗ then (baseClock, subClock);
319
320 // subclock: back sampling
321 case ("backSample", {e, Expression.INTEGER(i1), Expression.INTEGER(i2)}) algorithm
322 1 (subClock, baseClock) := fromExp(e);
323 1 subClock := updateSubClock(subClock, SUB_CLOCK(Rational.ONE, Rational.RATIONAL(-i1, i2), NONE()));
324 1 then (baseClock, subClock);
325
326 else algorithm
327 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for exp with unhandled call: " + Expression.toString(exp) + "."});
328 ✗ then fail();
329 end match;
330 then (subClock, baseClock);
331
332 else algorithm
333 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for exp with unhandled expression kind: " + Expression.toString(exp) + "."});
334 ✗ then fail();
335 end match;
336 end fromExp;
337
338 public
339 function updateSubClock
340 "adding the sub clock src to the sub clock dest. not symmetrical/commutative"
341 input output BClock dest;
342 input BClock src;
343 algorithm
344 dest := match (dest, src)
345 case (SUB_CLOCK(), SUB_CLOCK()) algorithm
346 18 dest.shift := Rational.add(dest.shift, Rational.mul(src.shift, dest.factor));
347 18 dest.factor := Rational.mul(dest.factor, src.factor);
348 then dest;
349 else algorithm
350 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for " + toString(dest) + " and " + toString(src) + " because of incorrect clock types."});
351 ✗ then fail();
352 end match;
353 end updateSubClock;
354 end BClock;
355
356 constant BClock DEFAULT_BASE_CLOCK = BASE_CLOCK(ClockKind.REAL_CLOCK(Expression.REAL(1.0)));
357 constant BClock DEFAULT_SUB_CLOCK = SUB_CLOCK(Rational.ONE, Rational.ZERO, NONE());
358 type CrefLst = list<ComponentRef>;
359
360 uniontype ClockedInfo
361 record CLOCKED_INFO
362 UnorderedMap<ComponentRef, BClock> baseClocks;
363 UnorderedMap<ComponentRef, BClock> subClocks;
364 UnorderedMap<ComponentRef, ComponentRef> subToBase;
365 UnorderedMap<ComponentRef, CrefLst> baseToSub;
366 end CLOCKED_INFO;
367
368 function new
369 output ClockedInfo info = CLOCKED_INFO(
370 baseClocks = UnorderedMap.new<BClock>(ComponentRef.hash, ComponentRef.isEqual),
371 subClocks = UnorderedMap.new<BClock>(ComponentRef.hash, ComponentRef.isEqual),
372 subToBase = UnorderedMap.new<ComponentRef>(ComponentRef.hash, ComponentRef.isEqual),
373 baseToSub = UnorderedMap.new<CrefLst>(ComponentRef.hash, ComponentRef.isEqual));
374 end new;
375
376 function toString
377 input ClockedInfo info;
378 output String str = "";
379 algorithm
380
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 if not isEmpty(info) then
381 ✗ str := StringUtil.headline_2("Clocked Info") + "\n";
382 ✗ str := str + StringUtil.headline_3("Base Clocks") + UnorderedMap.toString(info.baseClocks, ComponentRef.toString, BClock.toString) + "\n\n";
383 ✗ str := str + StringUtil.headline_3("Sub Clocks") + UnorderedMap.toString(info.subClocks, ComponentRef.toString, BClock.toString) + "\n\n";
384 ✗ str := str + StringUtil.headline_3("Sub to Base Clocks") + UnorderedMap.toString(info.subToBase, ComponentRef.toString, ComponentRef.toString) + "\n\n";
385 ✗ str := str + StringUtil.headline_3("Base to Sub Clocks") + UnorderedMap.toString(info.baseToSub, ComponentRef.toString, ComponentRef.listToString) + "\n";
386 end if;
387 end toString;
388
389 function isEmpty
390 input ClockedInfo info;
391 output Boolean b = UnorderedMap.isEmpty(info.baseClocks);
392 end isEmpty;
393
394 function resolveSubClocks
395 input ClockedInfo info;
396 input UnorderedMap<ComponentRef, ComponentRef> clock_map;
397 algorithm
398 // resolve the implicit clock map
399
2/2
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 190 times.
214 for cref in UnorderedMap.keyList(clock_map) loop
400 24 resolveImplicitSubClock(cref, info, clock_map);
401 end for;
402
403 // update sub to base clock
404
2/2
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 190 times.
205 for sub_clock in UnorderedMap.keyList(info.subClocks) loop
405 15 resolveSubClock(sub_clock, info, clock_map);
406 end for;
407
408 // update base to sub clocks
409
2/2
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 190 times.
206 for sub_clock in UnorderedMap.keyList(info.subClocks) loop
410 16 addSubClock(sub_clock, info);
411 end for;
412 end resolveSubClocks;
413
414 function baseClockCount
415 input ClockedInfo info;
416 input Boolean countInferred = false;
417 output Integer count = UnorderedMap.size(info.baseClocks);
418 algorithm
419
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 188 times.
188 if not countInferred then
420 188 count := count - List.count(UnorderedMap.valueList(info.baseClocks), BClock.isInferredClock);
421 end if;
422 end baseClockCount;
423
424 function subClockCount
425 input ClockedInfo info;
426 output Integer count = UnorderedMap.size(info.subClocks);
427 end subClockCount;
428
429 protected
430 function resolveImplicitSubClock
431 "implicite sub clocks are signals that are clocked but not defined by a sampling function themselves.
432 they infer their clock by the partition they are in. this function resolves each implicit clock to it's
433 root clock that has a sample function definition"
434 input ComponentRef key;
435 input ClockedInfo info;
436 input UnorderedMap<ComponentRef, ComponentRef> clock_map;
437 output ComponentRef clock = key;
438 algorithm
439
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
24 if UnorderedMap.contains(key, clock_map) then
440 24 clock := UnorderedMap.getSafe(key, clock_map, sourceInfo());
441
3/4
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 8 times.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
24 if not (UnorderedMap.contains(clock, info.subClocks) or UnorderedMap.contains(clock, info.baseClocks)) then
442 ✗ clock := resolveImplicitSubClock(clock, info, clock_map);
443 ✗ UnorderedMap.add(key, clock, clock_map);
444 end if;
445 end if;
446 end resolveImplicitSubClock;
447
448 function resolveSubClock
449 input ComponentRef clock_name;
450 input ClockedInfo info;
451 input UnorderedMap<ComponentRef, ComponentRef> clock_map;
452 output ComponentRef base_clock;
453 protected
454 ComponentRef implicit_clock, parent_clock = UnorderedMap.getSafe(clock_name, info.subToBase, sourceInfo());
455 Option<ComponentRef> implicit_clock_opt = NONE();
456 BClock dest, src;
457 algorithm
458
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 15 times.
23 if UnorderedMap.contains(parent_clock, info.baseClocks) then
459 // just a base clock
460 base_clock := parent_clock;
461 else
462 // not a base, update necessary
463
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 7 times.
8 if not UnorderedMap.contains(parent_clock, info.subClocks) then
464 // neither base nor sub clock --> implicit clock. map it
465 implicit_clock_opt := SOME(parent_clock);
466 1 parent_clock := UnorderedMap.getSafe(parent_clock, clock_map, sourceInfo());
467 end if;
468 8 base_clock := resolveSubClock(parent_clock, info, clock_map);
469
470 // update the sub clock and add the new base clock
471 8 dest := UnorderedMap.getSafe(parent_clock, info.subClocks, sourceInfo());
472 8 src := UnorderedMap.getSafe(clock_name, info.subClocks, sourceInfo());
473 8 UnorderedMap.add(clock_name, BClock.updateSubClock(dest, src), info.subClocks);
474 8 UnorderedMap.add(clock_name, base_clock, info.subToBase);
475
476 // also update and add the implicit clock
477
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 7 times.
8 if isSome(implicit_clock_opt) then
478 1 SOME(implicit_clock) := implicit_clock_opt;
479 // add the implicit clock as a sub clock
480 1 UnorderedMap.add(implicit_clock, dest, info.subClocks);
481 1 UnorderedMap.add(implicit_clock, base_clock, info.subToBase);
482 end if;
483 end if;
484 end resolveSubClock;
485
486 function addSubClock
487 input ComponentRef clock_name;
488 input ClockedInfo info;
489 protected
490 ComponentRef base_clock = UnorderedMap.getSafe(clock_name, info.subToBase, sourceInfo());
491 List<ComponentRef> current_clocks;
492 algorithm
493 16 current_clocks := UnorderedMap.getOrDefault(base_clock, info.baseToSub, {});
494 16 UnorderedMap.add(base_clock, clock_name :: current_clocks, info.baseToSub);
495 end addSubClock;
496 end ClockedInfo;
497
498 // =========================================================================
499 // MAIN ROUTINE, PLEASE DO NOT CHANGE
500 // =========================================================================
501 function main
502 "Wrapper function for any partitioning function. This will be
503 called during simulation and gets the corresponding subfunction from
504 Config."
505 extends Module.wrapper;
506 input Partition.Kind kind;
507 protected
508 Module.partitioningInterface func;
509 algorithm
510 378 func := getModule();
511
512 bdae := match (kind, bdae)
513 local
514 VariablePointers variables, clocks;
515 EquationPointers equations, clocked;
516
517 case (NBPartition.Kind.ODE, BackendDAE.MAIN(
518 varData = BVariable.VAR_DATA_SIM(unknowns = variables, clocks = clocks),
519 eqData = BEquation.EQ_DATA_SIM(simulation = equations, clocked = clocked)))
520 algorithm
521
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
190 bdae.ode := func(kind, variables, equations, clocks, clocked, bdae.clockedInfo);
522
5/6
✗ Branch 1 not taken.
✓ Branch 2 taken 329 times.
✓ Branch 3 taken 329 times.
✓ Branch 4 taken 190 times.
✓ Branch 5 taken 329 times.
✓ Branch 6 taken 190 times.
709 bdae.ode := list(sys for sys guard(not Partition.Partition.isEmpty(sys)) in bdae.ode);
523 // remove all inferred clocks from discrete vars and equations after partitioning
524 190 bdae.varData := VarData.removeTypedCheck(bdae.varData, BVariable.isClock, VarData.VarType.DISCRETE);
525 190 bdae.eqData := EqData.removeTypedCheck(bdae.eqData, Equation.isTypeClock, EqData.EqType.DISCRETE);
526 then bdae;
527
528 case (_, BackendDAE.MAIN(
529 varData = BVariable.VAR_DATA_SIM(initials = variables, clocks = clocks),
530 eqData = BEquation.EQ_DATA_SIM(initials = equations, clocked = clocked)))
531 guard(Partition.kindIsInitial(kind))
532 algorithm
533 188 bdae.init := partitioningNone(kind, variables, equations, clocks, clocked, bdae.clockedInfo);
534
6/6
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 175 times.
✓ Branch 3 taken 188 times.
✓ Branch 4 taken 188 times.
✓ Branch 5 taken 175 times.
✓ Branch 6 taken 188 times.
564 bdae.init := list(sys for sys guard(not Partition.Partition.isEmpty(sys)) in bdae.init);
535 then bdae;
536
537 else algorithm
538 ✗ Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed."});
539 ✗ then fail();
540 end match;
541 end main;
542
543 function getModule
544 "Returns the module function that was chosen by the user."
545 output Module.partitioningInterface func;
546 protected
547 String flag = "clocked"; //Flags.getConfigString(Flags.PARTITIONING)
548 algorithm
549 func := match flag
550 case "default" then (partitioningClocked);
551 case "clocked" then (partitioningClocked);
552 case "none" then (partitioningNone);
553 /* ... New detect states modules have to be added here */
554 else fail();
555 end match;
556 end getModule;
557
558 function categorize
559 "creates ODE, ALG, ODE_EVT, ALG_EVT partitions from ODE by checking
560 if it contains discrete equations or state equations.
561 Should be evoked just before jacobian at the very end."
562 extends Module.wrapper;
563 algorithm
564 bdae := match bdae
565 local
566 DoubleEnded.MutableList<Partition.Partition> ode = DoubleEnded.MutableList.fromList({});
567 DoubleEnded.MutableList<Partition.Partition> alg = DoubleEnded.MutableList.fromList({});
568 DoubleEnded.MutableList<Partition.Partition> ode_evt = DoubleEnded.MutableList.fromList({});
569 DoubleEnded.MutableList<Partition.Partition> alg_evt = DoubleEnded.MutableList.fromList({});
570 DoubleEnded.MutableList<Partition.Partition> clocked = DoubleEnded.MutableList.fromList({});
571
572 case BackendDAE.MAIN() algorithm
573
2/2
✓ Branch 0 taken 327 times.
✓ Branch 1 taken 188 times.
515 for syst in bdae.ode loop
574 327 Partition.Partition.categorize(syst, ode, alg, ode_evt, alg_evt, clocked);
575 end for;
576 188 bdae.ode := DoubleEnded.MutableList.toListAndClear(ode);
577 188 bdae.algebraic := DoubleEnded.MutableList.toListAndClear(alg);
578 188 bdae.ode_event := DoubleEnded.MutableList.toListAndClear(ode_evt);
579 188 bdae.alg_event := DoubleEnded.MutableList.toListAndClear(alg_evt);
580 188 bdae.clocked := DoubleEnded.MutableList.toListAndClear(clocked);
581 then bdae;
582
583 else algorithm
584 ✗ Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed."});
585 ✗ then fail();
586 end match;
587 end categorize;
588
589 function extractClocksEqn
590 input output Equation eqn;
591 input UnorderedMap<BClock, ComponentRef> clck_coll;
592 input UnorderedMap<BClock, ComponentRef> infr_coll;
593 input Pointer<list<Pointer<Variable>>> new_clocks;
594 input Pointer<list<Pointer<Variable>>> new_infers;
595 input Pointer<Integer> idx;
596 algorithm
597 eqn := match eqn
598 case Equation.WHEN_EQUATION() algorithm
599 67 eqn.body := Util.getOption(extractClocksWhenCond(SOME(eqn.body), clck_coll, infr_coll, new_clocks, new_infers, idx));
600 then eqn;
601 else eqn;
602 end match;
603 4145 eqn := Equation.map(eqn, function extractClocks(clck_coll = clck_coll, infr_coll = infr_coll, new_clocks = new_clocks, new_infers = new_infers, idx = idx, when_cond = false));
604 end extractClocksEqn;
605
606 function extractClocksWhenCond
607 input output Option<WhenEquationBody> body_opt;
608 input UnorderedMap<BClock, ComponentRef> clck_coll;
609 input UnorderedMap<BClock, ComponentRef> infr_coll;
610 input Pointer<list<Pointer<Variable>>> new_clocks;
611 input Pointer<list<Pointer<Variable>>> new_infers;
612 input Pointer<Integer> idx;
613 algorithm
614 body_opt := match body_opt
615 local
616 WhenEquationBody body;
617 case SOME(body) algorithm
618 234 body.condition := Expression.map(body.condition, function extractClocks(clck_coll = clck_coll, infr_coll = infr_coll, new_clocks = new_clocks, new_infers = new_infers, idx = idx, when_cond = true));
619 117 body.else_when := extractClocksWhenCond(body.else_when, clck_coll, infr_coll, new_clocks, new_infers, idx);
620 then SOME(body);
621 else body_opt;
622 end match;
623 end extractClocksWhenCond;
624
625 function extractClocks
626 "replace clock constructors in expressions with variables"
627 input output Expression exp;
628 input UnorderedMap<BClock, ComponentRef> clck_coll;
629 input UnorderedMap<BClock, ComponentRef> infr_coll;
630 input Pointer<list<Pointer<Variable>>> new_clocks;
631 input Pointer<list<Pointer<Variable>>> new_infers;
632 input Pointer<Integer> idx;
633 input Boolean when_cond;
634 algorithm
635 exp := match exp
636 local
637 BClock clock;
638 Pointer<Variable> clock_var;
639 ComponentRef clock_name;
640
641 case Expression.CLKCONST() guard(when_cond or not ClockKind.isInferred(exp.clk)) algorithm
642 2 clock := BClock.BASE_CLOCK(exp.clk);
643
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if UnorderedMap.contains(clock, clck_coll) then
644 // clock already exists
645 ✗ clock_name := UnorderedMap.getSafe(clock, clck_coll, sourceInfo());
646 elseif UnorderedMap.contains(clock, infr_coll) then
647 ✗ clock_name := UnorderedMap.getSafe(clock, infr_coll, sourceInfo());
648 else
649 // new clock
650 2 (clock_var, clock_name) := BVariable.makeClockVar(Pointer.access(idx), Expression.typeOf(exp));
651
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if BClock.isInferredClock(clock) then
652 ✗ UnorderedMap.add(clock, clock_name, infr_coll);
653 ✗ Pointer.update(new_infers, clock_var :: Pointer.access(new_infers));
654 else
655 2 UnorderedMap.add(clock, clock_name, clck_coll);
656 4 Pointer.update(new_clocks, clock_var :: Pointer.access(new_clocks));
657 end if;
658 2 Pointer.update(idx, Pointer.access(idx) + 1);
659 end if;
660 2 then Expression.fromCref(clock_name);
661
662 else exp;
663 end match;
664 end extractClocks;
665
666 protected
667 type ClusterElementType = enumeration(EQUATION, VARIABLE);
668
669 uniontype Cluster
670 record CLUSTER
671 UnorderedSet<ComponentRef> variables "set of all variables in this cluster";
672 UnorderedSet<ComponentRef> eqn_idnts "set of all equations in this cluster";
673 end CLUSTER;
674
675 function toString
676 input Cluster cluster;
677 output String str;
678 algorithm
679 ✗ str := "### Cluster Variables:\n" + UnorderedSet.toString(cluster.variables, ComponentRef.toString)
680 + "\n### Cluster Equation Identifiers:\n" + UnorderedSet.toString(cluster.eqn_idnts, ComponentRef.toString);
681 end toString;
682
683 function addElement
684 input Option<Cluster> cluster_opt;
685 input ComponentRef cref;
686 input ClusterElementType ty;
687 output Cluster cluster;
688 algorithm
689 cluster := match cluster_opt
690 case SOME(cluster) then cluster;
691 330 else CLUSTER(
692 variables = UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual),
693 eqn_idnts = UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual));
694 end match;
695
696 cluster := match ty
697 case ClusterElementType.VARIABLE algorithm
698 2554 UnorderedSet.add(cref, cluster.variables);
699 then cluster;
700 case ClusterElementType.EQUATION algorithm
701 3062 UnorderedSet.add(cref, cluster.eqn_idnts);
702 then cluster;
703 else algorithm
704 ✗ Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed for " + ComponentRef.toString(cref) + " because of unknown cluster element type."});
705 ✗ then fail();
706 end match;
707 end addElement;
708
709 function addToClockMap
710 "finds the first clock in the map and adds cref->clock for all crefs in this cluster.
711 Note: does not check if there are different clocks that contradict, this check will be done later.
712 this is only for naive clock inference that will be checked for consistency later."
713 input Cluster cluster;
714 input EquationPointers equations;
715 input ClockedInfo info;
716 input UnorderedMap<ComponentRef, ComponentRef> clock_map;
717 protected
718 function findClock
719 "finds the first clock/clocked signal and skips everything afterwards"
720 input output Expression exp;
721 input ClockedInfo info;
722 input Pointer<Option<ComponentRef>> clock_ptr;
723 protected
724 Option<ComponentRef> clock_opt = Pointer.access(clock_ptr);
725 algorithm
726 exp := match (exp, clock_opt)
727 // already found clock, do nothing
728 case (_, SOME(_)) then exp;
729
730 case (Expression.CREF(), NONE()) guard(BVariable.isClockOrClocked(BVariable.getVarPointer(exp.cref, sourceInfo()))) algorithm
731 // add the clock cref
732 19 Pointer.update(clock_ptr, SOME(exp.cref));
733 then exp;
734
735 // do nothing on clock sampling functions as they do not imply a clock for this cluster
736 case (Expression.CALL(), _) guard(Expression.isClockOrSampleFunction(exp)) then exp;
737
738 // go deeper
739 21308 else Expression.mapShallow(exp, function findClock(info = info, clock_ptr = clock_ptr));
740 end match;
741 end findClock;
742 Pointer<Option<ComponentRef>> clock_ptr = Pointer.create(NONE());
743 Option<ComponentRef> clock_opt = NONE();
744 ComponentRef clock;
745 algorithm
746 // search all equations until first clock/clocked signal is found
747
2/2
✓ Branch 1 taken 3058 times.
✓ Branch 2 taken 311 times.
3369 for eqn_name in UnorderedSet.toList(cluster.eqn_idnts) loop
748 3058 Equation.map(Pointer.access(EquationPointers.getEqnByName(equations, eqn_name)), function findClock(info = info, clock_ptr = clock_ptr), NONE(), Expression.fakeMap);
749 3058 clock_opt := Pointer.access(clock_ptr);
750
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3058 times.
✓ Branch 2 taken 3039 times.
✓ Branch 3 taken 19 times.
3058 if isSome(clock_opt) then break; end if;
751 end for;
752
753 // if a clock/clocked signal was found, add all a mapping for each variable in the cluster to the clock
754
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 330 times.
✓ Branch 2 taken 19 times.
✓ Branch 3 taken 311 times.
330 if isSome(clock_opt) then
755 19 SOME(clock) := clock_opt;
756
2/2
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 19 times.
43 for var_name in UnorderedSet.toList(cluster.variables) loop
757 24 UnorderedMap.add(var_name, clock, clock_map);
758 end for;
759 end if;
760 end addToClockMap;
761
762 function toPartition
763 input Cluster cluster;
764 input VariablePointers variables;
765 input EquationPointers equations;
766 input Partition.Kind kind;
767 input ClockedInfo info;
768 input UnorderedSet<ComponentRef> held_crefs;
769 input UnorderedSet<ComponentRef> infer_del;
770 output Partition.Partition partition;
771 protected
772 list<ComponentRef> cvars = UnorderedSet.toList(cluster.variables);
773 list<ComponentRef> cidnt = UnorderedSet.toList(cluster.eqn_idnts);
774 Partition.Association association;
775 list<Pointer<Variable>> var_lst, filtered_vars;
776 list<Pointer<Equation>> eqn_lst;
777 VariablePointers partVariables;
778 EquationPointers partEquations;
779 UnorderedSet<ComponentRef> inferred_clocks = UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual);
780 algorithm
781 // find all variables and equations
782
4/4
✓ Branch 0 taken 2554 times.
✓ Branch 1 taken 330 times.
✓ Branch 2 taken 2554 times.
✓ Branch 3 taken 330 times.
2884 var_lst := list(BVariable.getVarPointer(cref, sourceInfo()) for cref in cvars);
783
5/6
✗ Branch 1 not taken.
✓ Branch 2 taken 2554 times.
✓ Branch 3 taken 2554 times.
✓ Branch 4 taken 330 times.
✓ Branch 5 taken 2554 times.
✓ Branch 6 taken 330 times.
2884 filtered_vars := list(var for var guard(VariablePointers.contains(var, variables)) in var_lst);
784
4/4
✓ Branch 0 taken 3062 times.
✓ Branch 1 taken 330 times.
✓ Branch 2 taken 3062 times.
✓ Branch 3 taken 330 times.
3392 eqn_lst := list(EquationPointers.getEqnByName(equations, name) for name in cidnt);
785
786 // create variable and equation arrays
787 330 partVariables := VariablePointers.fromList(filtered_vars);
788 330 partEquations := EquationPointers.fromList(eqn_lst);
789
790 // create the association (clocked/continuous)
791 330 association := Partition.Association.create(partEquations, kind, info, infer_del);
792
793 // replace the clocked functions, inline clocked when equations and set equations to clocked
794 330 partEquations := EquationPointers.mapExp(partEquations, function replaceClockedFunctions(held_crefs = held_crefs));
795
2/2
✓ Branch 1 taken 19 times.
✓ Branch 2 taken 311 times.
330 if Partition.Association.isClocked(association) then
796 // remove the inferred clocks
797 19 partVariables := VariablePointers.mapRemovePtr(partVariables, function collectInferredClock(inferred_clocks = inferred_clocks));
798 19 partEquations := EquationPointers.mapRemovePtr(partEquations, function removeInferredClock(inferred_clocks = inferred_clocks));
799 // replace clocked when equations and make all variables clocked
800 19 partEquations := EquationPointers.map(partEquations, replaceClockedWhen);
801 19 partVariables := VariablePointers.mapPtr(partVariables, function BVariable.setVarKind(varKind = VariableKind.CLOCKED()));
802
803 // if the partition will be removed add all unused inferred clocks
804
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
19 if EquationPointers.size(partEquations) == 0 then
805 ✗ UnorderedSet.merge(infer_del, inferred_clocks);
806 end if;
807 end if;
808
809 330 partition := Partition.PARTITION(
810 index = 0,
811 association = association,
812 unknowns = partVariables,
813 daeUnknowns = NONE(),
814 equations = partEquations,
815 adjacencyMatrix = NONE(),
816 matching = NONE(),
817 strongComponents = NONE()
818 );
819 end toPartition;
820
821 protected
822 function collectInferredClock
823 input Pointer<Variable> var;
824 input UnorderedSet<ComponentRef> inferred_clocks;
825 output Boolean delete = BVariable.isClock(var);
826 algorithm
827
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 if delete then
828 ✗ UnorderedSet.add(BVariable.getVarName(var), inferred_clocks);
829 end if;
830 end collectInferredClock;
831
832 function removeInferredClock
833 input Pointer<Equation> eqn;
834 input UnorderedSet<ComponentRef> inferred_clocks;
835 output Boolean delete;
836 algorithm
837 delete := match Pointer.access(eqn)
838 local
839 ComponentRef lhs;
840 16 case Equation.SCALAR_EQUATION(lhs = Expression.CREF(cref = lhs)) then UnorderedSet.contains(lhs, inferred_clocks);
841 else false;
842 end match;
843 end removeInferredClock;
844 end Cluster;
845
846 // Perhaps this deserves its own place in Util/*.mo
847 uniontype DisjointSetForest
848 "Custom implementation of disjoint-set data structure with constant number of elements."
849 record FOREST
850 Pointer<array<Integer>> parent;
851 Pointer<array<Integer>> rank;
852 end FOREST;
853
854 function new
855 "Creates n disjoit subsets of size 1."
856 input Integer n;
857 output DisjointSetForest dsf;
858 algorithm
859
2/2
✓ Branch 0 taken 3062 times.
✓ Branch 1 taken 190 times.
3252 dsf := FOREST(
860 parent = Pointer.create(listArray(list(i for i in 1:n))),
861 rank = Pointer.create(arrayCreate(n, 0))
862 );
863 end new;
864
865 function find
866 input DisjointSetForest dsf;
867 input output Integer index;
868 protected
869 array<Integer> parent = Pointer.access(dsf.parent);
870 algorithm
871
2/2
✓ Branch 1 taken 3587 times.
✓ Branch 2 taken 20046 times.
23633 while index <> parent[index] loop
872 3587 parent[index] := parent[parent[index]] "path halving";
873 3587 index := parent[index];
874 end while;
875 20046 Pointer.update(dsf.parent, parent);
876 end find;
877
878 function unite
879 input DisjointSetForest dsf;
880 input list<Integer> indices;
881 output Integer root;
882 protected
883 list<Integer> roots = list(find(dsf, i) for i in indices);
884 array<Integer> parent = Pointer.access(dsf.parent);
885 array<Integer> rank = Pointer.access(dsf.rank);
886 Integer maxRank;
887 Boolean tied = false;
888 algorithm
889 // find root with highest rank
890 3062 root := listHead(roots);
891 3062 maxRank := rank[root];
892
2/2
✓ Branch 1 taken 4153 times.
✓ Branch 2 taken 3062 times.
7215 for r in listRest(roots) loop
893
2/2
✓ Branch 0 taken 2804 times.
✓ Branch 1 taken 1349 times.
4153 if r <> root then
894
2/2
✓ Branch 1 taken 801 times.
✓ Branch 2 taken 2003 times.
2804 if rank[r] > maxRank then
895 root := r;
896 maxRank := rank[root];
897 tied := false;
898 elseif rank[r] == maxRank then
899 tied := true;
900 end if;
901 end if;
902 end for;
903
904 // update parents
905
2/2
✓ Branch 1 taken 7215 times.
✓ Branch 2 taken 3062 times.
10277 for r in roots loop
906 7215 parent[find(dsf, r)] := root;
907 end for;
908
909 // if necessary increment rank
910
2/2
✓ Branch 0 taken 363 times.
✓ Branch 1 taken 2699 times.
3062 if tied then
911 363 rank[root] := rank[root] + 1;
912 end if;
913
914 3062 Pointer.update(dsf.parent, parent);
915 3062 Pointer.update(dsf.rank, rank);
916 end unite;
917 end DisjointSetForest;
918
919 function partitioningNone extends Module.partitioningInterface;
920 protected
921 VariablePointers clone_vars;
922 EquationPointers clone_eqns;
923 algorithm
924 188 clone_vars := VariablePointers.clone(variables);
925 188 clone_eqns := EquationPointers.clone(equations);
926 188 partitions := {Partition.PARTITION(
927 index = 1,
928 association = Partition.Association.CONTINUOUS(kind, NONE(), NONE(), NONE(), NONE(), NONE()),
929 unknowns = clone_vars,
930 daeUnknowns = NONE(),
931 equations = clone_eqns,
932 adjacencyMatrix = NONE(),
933 matching = NONE(),
934 strongComponents = NONE()
935 )};
936 end partitioningNone;
937
938 function partitioningClocked
939 "partitions all individual partitions and collects the clocked partitions and clocks/subclocks"
940 extends Module.partitioningInterface;
941 protected
942 DisjointSetForest eqn_dsf = DisjointSetForest.new(ExpandableArray.getLastUsedIndex(equations.eqArr));
943 array<Integer> var_map = arrayCreate(ExpandableArray.getLastUsedIndex(variables.varArr), -1);
944 Pointer<Equation> eqn;
945 Pointer<Variable> var;
946 UnorderedSet<ComponentRef> var_crefs;
947 list<Integer> var_indices;
948 Integer part_idx;
949 UnorderedMap<Integer, Cluster> cluster_map = UnorderedMap.new<Cluster>(Util.id, intEq);
950 ComponentRef name_cref;
951 array<Boolean> marked_vars;
952 list<Pointer<Variable>> single_vars;
953 UnorderedSet<ComponentRef> held_crefs = UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual);
954 // maps each cref to the clock it is listening to
955 UnorderedMap<ComponentRef, ComponentRef> clock_map = UnorderedMap.new<ComponentRef>(ComponentRef.hash, ComponentRef.isEqual);
956 UnorderedSet<ComponentRef> infer_del = UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual);
957 Pointer<Integer> index = Pointer.create(1);
958 algorithm
959 // parse clock assignments
960
2/2
✓ Branch 1 taken 15 times.
✓ Branch 2 taken 190 times.
205 for eq_idx in UnorderedMap.valueList(clocked.map) loop
961
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if eq_idx > 0 then
962 15 eqn := EquationPointers.getEqnAt(clocked, eq_idx);
963 15 BClock.add(Pointer.access(eqn), info);
964 end if;
965 end for;
966
967 // other equations - collect all variables and check for clocked signals
968
2/2
✓ Branch 1 taken 3062 times.
✓ Branch 2 taken 190 times.
3252 for eq_idx in UnorderedMap.valueList(equations.map) loop
969
1/2
✓ Branch 0 taken 3062 times.
✗ Branch 1 not taken.
3062 if eq_idx > 0 then
970 3062 eqn := EquationPointers.getEqnAt(equations, eq_idx);
971 3062 BClock.add(Pointer.access(eqn), info);
972
973 // collect all crefs in equation
974 3062 var_crefs := UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual);
975 3062 Equation.map(Pointer.access(eqn), function collectPartitioningCrefs(var_crefs = var_crefs), NONE(), Expression.fakeMap);
976
977 // find all indices of connected variables
978
4/4
✓ Branch 1 taken 6998 times.
✓ Branch 2 taken 3062 times.
✓ Branch 3 taken 6998 times.
✓ Branch 4 taken 3062 times.
10060 var_indices := list(VariablePointers.getVarIndex(variables, cref) for cref in UnorderedSet.toList(var_crefs));
979 // filter indices of non existant variables (e.g. time)
980
6/6
✓ Branch 0 taken 291 times.
✓ Branch 1 taken 6707 times.
✓ Branch 2 taken 6998 times.
✓ Branch 3 taken 3062 times.
✓ Branch 4 taken 6707 times.
✓ Branch 5 taken 3062 times.
10060 var_indices := list(i for i guard(i > 0) in var_indices);
981
982 // unite current equation and all variables that already belong to a partition
983
6/6
✓ Branch 1 taken 2554 times.
✓ Branch 2 taken 4153 times.
✓ Branch 3 taken 6707 times.
✓ Branch 4 taken 3062 times.
✓ Branch 5 taken 4153 times.
✓ Branch 6 taken 3062 times.
9769 part_idx := DisjointSetForest.unite(eqn_dsf, eq_idx :: list(var_map[j] for j guard(var_map[j] > 0) in var_indices));
984
985 // update connected variable partition indices
986
2/2
✓ Branch 1 taken 6707 times.
✓ Branch 2 taken 3062 times.
9769 for i in var_indices loop
987 6707 var_map[i] := part_idx;
988 end for;
989 end if;
990 end for;
991
992 // find and report variables that could not be assigned to a partition (exclude clocks)
993
5/6
✓ Branch 1 taken 2554 times.
✓ Branch 2 taken 190 times.
✓ Branch 3 taken 2554 times.
✓ Branch 4 taken 190 times.
✓ Branch 6 taken 2554 times.
✗ Branch 7 not taken.
2744 marked_vars := listArray(list(var_map[var_idx] < 0 for var_idx in UnorderedMap.valueList(variables.map)));
994
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 190 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 190 times.
190 single_vars := list(var_ptr for var_ptr in VariablePointers.getMarkedVars(variables, marked_vars));
995
996
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
190 if not listEmpty(single_vars) then
997 ✗ Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " (" + Partition.Partition.kindToString(kind)
998 + ") failed because the following variables could not be assigned to a partition:\n {"
999 + stringDelimitList(list(BVariable.toString(Pointer.access(var_ptr)) for var_ptr in single_vars), "\n") + "}"});
1000 ✗ fail();
1001 end if;
1002
1003 // collect cluster equations
1004
2/2
✓ Branch 1 taken 3062 times.
✓ Branch 2 taken 190 times.
3252 for eq_idx in UnorderedMap.valueList(equations.map) loop
1005
1/2
✓ Branch 0 taken 3062 times.
✗ Branch 1 not taken.
3062 if eq_idx > 0 then
1006 // add the equation
1007 3062 eqn := EquationPointers.getEqnAt(equations, eq_idx);
1008 3062 name_cref := Equation.getEqnName(eqn);
1009 3062 part_idx := DisjointSetForest.find(eqn_dsf, eq_idx);
1010 3062 UnorderedMap.addUpdate(part_idx, function Cluster.addElement(cref = name_cref, ty = ClusterElementType.EQUATION), cluster_map);
1011 end if;
1012 end for;
1013
1014 // collect cluster variables
1015
2/2
✓ Branch 1 taken 2554 times.
✓ Branch 2 taken 190 times.
2744 for var_idx in UnorderedMap.valueList(variables.map) loop
1016
1/2
✓ Branch 0 taken 2554 times.
✗ Branch 1 not taken.
2554 if var_idx > 0 then
1017 2554 var := VariablePointers.getVarAt(variables, var_idx);
1018 2554 name_cref := BVariable.getVarName(var);
1019 2554 part_idx := DisjointSetForest.find(eqn_dsf, var_map[var_idx]);
1020 2554 UnorderedMap.addUpdate(part_idx, function Cluster.addElement(cref = name_cref, ty = ClusterElementType.VARIABLE), cluster_map);
1021 end if;
1022 end for;
1023
1024
2/2
✓ Branch 1 taken 330 times.
✓ Branch 2 taken 190 times.
520 for cluster in UnorderedMap.valueList(cluster_map) loop
1025 330 Cluster.addToClockMap(cluster, equations, info, clock_map);
1026 end for;
1027
1028 // resolve inner sub clock dependencies
1029 190 ClockedInfo.resolveSubClocks(info, clock_map);
1030
1031 // get the actual partitions from the clusters and split continuous/clocked
1032
4/4
✓ Branch 1 taken 330 times.
✓ Branch 2 taken 190 times.
✓ Branch 3 taken 330 times.
✓ Branch 4 taken 190 times.
520 partitions := list(Cluster.toPartition(cl, variables, equations, kind, info, held_crefs, infer_del) for cl in UnorderedMap.valueList(cluster_map));
1033 // update the partitions if one of their variables is in a hold() function
1034
4/4
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 190 times.
✓ Branch 2 taken 330 times.
✓ Branch 3 taken 190 times.
520 partitions := list(Partition.Partition.updateHeldVars(part, held_crefs) for part in partitions);
1035 // merge all clocked partitions with equal base and sub clock and find the proper order
1036
5/6
✗ Branch 2 not taken.
✓ Branch 3 taken 329 times.
✓ Branch 4 taken 329 times.
✓ Branch 5 taken 190 times.
✓ Branch 6 taken 329 times.
✓ Branch 7 taken 190 times.
519 partitions := list(Partition.Partition.setIndex(partition, index) for partition guard(not Partition.Partition.isEmpty(partition)) in sortAndMergeClockedPartitions(partitions, info));
1037
1038 // remove the unused inferred clocks from clock structure
1039
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 190 times.
190 for unused_infer in UnorderedSet.toList(infer_del) loop
1040 ✗ UnorderedMap.remove(unused_infer, info.baseClocks);
1041 ✗ UnorderedMap.remove(unused_infer, info.baseToSub);
1042 end for;
1043
1044
1045
2/2
✓ Branch 1 taken 189 times.
✓ Branch 2 taken 1 time.
190 if Flags.isSet(Flags.DUMP_SYNCHRONOUS) then
1046 1 print(StringUtil.headline_1("[dumpSynchronous] Partitioning result:") + "\n" + List.toString(partitions, function Partition.Partition.toString(level = 2), List.Style.NEWLINE) + "\n");
1047 1 print(ClockedInfo.toString(info));
1048 end if;
1049 end partitioningClocked;
1050
1051 function sortAndMergeClockedPartitions
1052 input output list<Partition.Partition> partitions;
1053 input ClockedInfo info;
1054 protected
1055 list<Partition.Partition> clocked_partitions;
1056 list<list<Partition.Partition>> new_clocked = {};
1057 // type for for double map. base clock -> {sub_clock -> partition}
1058 type SubMap = UnorderedMap<BClock, Partition.Partition>;
1059 UnorderedMap<BClock, SubMap> clock_collector = UnorderedMap.new<SubMap>(BClock.hash, BClock.isEqual);
1060 UnorderedMap<ComponentRef, BClock> base_clock_inferrence = UnorderedMap.new<BClock>(ComponentRef.hash, ComponentRef.isEqual);
1061 BClock clock, baseClock, subClock;
1062 Option<BClock> baseClock_opt;
1063 SubMap subClockMap "maps sub clock to it's partition for current base clock";
1064 Partition.Partition new_part;
1065 algorithm
1066 // filter all clocked partitions
1067 190 (clocked_partitions, partitions) := List.splitOnTrue(partitions, Partition.Partition.isClocked);
1068
1069 // initialize for all base clocks
1070
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 190 times.
202 for baseClock in UnorderedMap.valueList(info.baseClocks) loop
1071 12 UnorderedMap.add(baseClock, UnorderedMap.new<Partition.Partition>(BClock.hash, BClock.isEqual), clock_collector);
1072 end for;
1073
1074 // collect the base clock inferrence data to correctly associate the inferred clocks
1075
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 190 times.
209 for partition in clocked_partitions loop
1076 19 (clock, baseClock_opt, _) := Partition.Partition.getClocks(partition);
1077 clock := match baseClock_opt
1078 case SOME(clock) then clock;
1079 else clock;
1080 end match;
1081
2/2
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 19 times.
43 for var in VariablePointers.toList(partition.unknowns) loop
1082 24 UnorderedMap.add(BVariable.getVarName(var), clock, base_clock_inferrence);
1083 end for;
1084 end for;
1085
1086 // merge clocked partitions by baseclock, subclock
1087
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 190 times.
209 for partition in clocked_partitions loop
1088 19 (clock, baseClock_opt, _) := Partition.Partition.getClocks(partition);
1089
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 15 times.
19 if isSome(baseClock_opt) then
1090 // it is a sub clock
1091 15 SOME(baseClock) := baseClock_opt;
1092 15 baseClock := BClock.baseClockInferrence(baseClock, base_clock_inferrence);
1093 subClock := clock;
1094 else
1095 // it is a base clock, use the default sub clock
1096 4 baseClock := BClock.baseClockInferrence(clock, base_clock_inferrence);
1097 subClock := DEFAULT_SUB_CLOCK;
1098 end if;
1099 19 partition := Partition.Partition.setClocks(partition, subClock, SOME(baseClock));
1100 19 subClockMap := UnorderedMap.getSafe(baseClock, clock_collector, sourceInfo());
1101 new_part := match UnorderedMap.get(subClock, subClockMap)
1102 2 case SOME(new_part) then Partition.Partition.merge(new_part, partition, true);
1103 else partition;
1104 end match;
1105 19 UnorderedMap.add(subClock, new_part, subClockMap);
1106 end for;
1107
1108 // recollect all clocked partitions and sort the sub partitions. resolve potential artifical algebraic loops
1109
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 190 times.
202 for tpl in UnorderedMap.toList(clock_collector) loop
1110 12 (baseClock, subClockMap) := tpl;
1111 12 new_clocked := sortClockedPartitions(UnorderedMap.valueList(subClockMap)) :: new_clocked;
1112 end for;
1113
1114 // append all clocked partitions in the end and apply proper indexing
1115
4/4
✓ Branch 2 taken 202 times.
✓ Branch 3 taken 190 times.
✓ Branch 4 taken 202 times.
✓ Branch 5 taken 190 times.
392 partitions := listAppend(partition for partition in listReverse(partitions :: new_clocked));
1116 end sortAndMergeClockedPartitions;
1117
1118 function sortClockedPartitions
1119 "use tarjan to sort sub partitions that rely on order. if an artificial algebraic loop occurs,
1120 break up the partitions such that the loop does not occur anymore. Actual algebraic loops with
1121 different clocks are forbidden by Section 16.7.4 in the Modelica Specification Version 3.7,
1122 therefore an issue will be raised in that case."
1123 input list<Partition.Partition> unsorted;
1124 output list<Partition.Partition> sorted = {};
1125 protected
1126 Integer n = listLength(unsorted);
1127 array<Partition.Partition> partitions = listArray(listReverse(unsorted));
1128 Adjacency.IntMatrix.Builder m = Adjacency.IntMatrix.newBuilder(n);
1129 // create a trivial matching for an artificially matched bipartite graph (tarjan implementation needs it)
1130 Matching matching = Matching.trivial(n);
1131 UnorderedMap<BClock, Integer> index_map = UnorderedMap.new<Integer>(BClock.hash, BClock.isEqual);
1132 list<list<Integer>> partition_order;
1133 Integer j;
1134 algorithm
1135 // prepare the clock to partition index map
1136
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1 time.
29 for i in 1:n loop
1137 17 UnorderedMap.add(Partition.Partition.getClocks(partitions[i]), i, index_map);
1138 end for;
1139
1140 // fill the adjacency matrix
1141
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1 time.
29 for i in 1:n loop
1142
2/2
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 17 times.
22 for clock in UnorderedSet.toList(Partition.Partition.getClockDependencies(partitions[i])) loop
1143 5 j := UnorderedMap.getSafe(clock, index_map, sourceInfo());
1144 5 Adjacency.IntMatrix.builderAdd(m, i, j);
1145 end for;
1146 end for;
1147
1148 // use tarjan to sort the artificial bipartite graph
1149 12 partition_order := Sorting.tarjanScalar(Adjacency.IntMatrix.fromBuilder(m, n), matching);
1150
1151 // use the strong components to sort partitions. no algebraic loops allowed
1152
2/2
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 12 times.
28 for comp in listReverse(partition_order) loop
1153 sorted := match comp
1154 local
1155 UnorderedMap<VariablePointer, BClock> var_clock_map;
1156 Partition.Partition part;
1157 list<StrongComponent> sub_comps;
1158 list<Pointer<Variable>> sub_comp_vars;
1159 list<Pointer<Equation>> sub_comp_eqns;
1160 Option<tuple<list<Pointer<Variable>>, list<Pointer<Equation>>, BClock>> collector;
1161 UnorderedSet<BClock> var_clocks;
1162 Option<BClock> baseClock;
1163
1164 list<Pointer<Variable>> vars;
1165 list<Pointer<Equation>> eqns;
1166 BClock clock, new_clock;
1167
1168 // standard non loop partition
1169 15 case {j} then partitions[j] :: sorted;
1170
1171 // multiple partitions form an artificial algebraic loop
1172 else algorithm
1173 // save which variable listens to which clock
1174 1 var_clock_map := UnorderedMap.new<BClock>(BVariable.hash, BVariable.equalName);
1175
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
3 for i in comp loop
1176 2 part := partitions[i];
1177
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2 times.
6 for var in VariablePointers.toList(part.unknowns) loop
1178 4 UnorderedMap.add(var, Partition.Partition.getClocks(part), var_clock_map);
1179 end for;
1180 end for;
1181
1182 // merge all partitions (allow different clocks)
1183
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 j :: comp := comp;
1184 1 part := partitions[j];
1185
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 for i in comp loop
1186 1 part := Partition.Partition.merge(part, partitions[i], false);
1187 end for;
1188
1189 // all base clocks have to be equal, just get any of them
1190 1 (_, baseClock, _) := Partition.Partition.getClocks(part);
1191
1192 // causalize
1193 1 (_, sub_comps) := Causalize.simple(part.unknowns, part.equations, Partition.Partition.getKind(part));
1194
1195 // split the resulting strong components into partitions by clocks
1196 collector := NONE();
1197
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1 time.
5 for sub_comp in listReverse(sub_comps) loop
1198 4 sub_comp_vars := StrongComponent.getVariables(sub_comp);
1199 4 sub_comp_eqns := StrongComponent.getEquations(sub_comp);
1200 4 var_clocks := UnorderedSet.new(BClock.hash, BClock.isEqual);
1201
1202
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 for var in sub_comp_vars loop
1203 4 UnorderedSet.add(UnorderedMap.getSafe(var, var_clock_map, sourceInfo()), var_clocks);
1204 end for;
1205
1206 // update the collector, either 1) make new collector, 2) add to existing collector 3) finalize partition and make new collector
1207 collector := match (collector, UnorderedSet.toList(var_clocks))
1208 // 1) no previous collector, make new one
1209 1 case (NONE(), {new_clock}) then SOME((sub_comp_vars, sub_comp_eqns, new_clock));
1210
1211 // previous collector, check if still same clock
1212 case (SOME((vars, eqns, clock)), {new_clock}) algorithm
1213
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 2 times.
3 if BClock.isEqual(clock, new_clock) then
1214 // 2) same clock, just append to partition
1215 1 collector := SOME((listAppend(sub_comp_vars, vars), listAppend(sub_comp_eqns, eqns), clock));
1216 else
1217 // 3) new clock, split partition
1218 // ToDo: keep sorting and reuse later
1219 2 part := Partition.PARTITION(0, Partition.Association.CLOCKED(clock, baseClock, UnorderedSet.new(BClock.hash, BClock.isEqual), false),
1220 VariablePointers.fromList(vars), NONE(), EquationPointers.fromList(eqns), NONE(), NONE(), NONE());
1221 sorted := part :: sorted;
1222
1223 // open new collector
1224 2 collector := SOME((sub_comp_vars, sub_comp_eqns, new_clock));
1225 end if;
1226 then collector;
1227
1228 else algorithm
1229 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for sub-partitions with cyclic dependency that could not be resolved:\n"
1230 + "There are contradicting sub-clocks: " + List.toString(UnorderedSet.toList(var_clocks), BClock.toString) + " in strong component:\n"
1231 + StrongComponent.toString(sub_comp)});
1232 ✗ then fail();
1233 end match;
1234 end for;
1235
1236 // finalize last partition
1237
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
1 if isSome(collector) then
1238 1 SOME((vars, eqns, clock)) := collector;
1239 1 part := Partition.PARTITION(0, Partition.Association.CLOCKED(clock, baseClock, UnorderedSet.new(BClock.hash, BClock.isEqual), false),
1240 VariablePointers.fromList(vars), NONE(), EquationPointers.fromList(eqns), NONE(), NONE(), NONE());
1241 sorted := part :: sorted;
1242 end if;
1243 then sorted;
1244 end match;
1245 end for;
1246 end sortClockedPartitions;
1247
1248 function collectPartitioningCrefs
1249 input output Expression exp;
1250 input UnorderedSet<ComponentRef> var_crefs;
1251 algorithm
1252 exp := match exp
1253 local
1254 Expression newExp;
1255 Call call;
1256 Expression arg;
1257 list<ComponentRef> children;
1258 ComponentRef stripped;
1259
1260 // clocked partitioning special rules
1261 case Expression.CALL(call = call as Call.TYPED_CALL()) algorithm
1262 newExp := match AbsynUtil.pathString(Function.nameConsiderBuiltin(call.fn))
1263 // skip these as they do not cause dependency
1264 case "subSample" then exp;
1265 case "superSample" then exp;
1266 case "shiftSample" then exp;
1267 case "backSample" then exp;
1268 case "previous" then exp;
1269 case "hold" then exp;
1270 // sample can have dependencies
1271 case "sample" algorithm
1272 arg := match Call.arguments(exp.call)
1273 // not collected samples have 2 arguments
1274 case {_, arg} then arg;
1275 // collected samples have 3 arguments
1276 case {_, _, arg} then arg;
1277 else algorithm
1278 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for: " + Expression.toString(exp) + "."});
1279 ✗ then fail();
1280 end match;
1281 29 then Expression.mapShallow(arg, function collectPartitioningCrefs(var_crefs = var_crefs));
1282 720 else Expression.mapShallow(exp, function collectPartitioningCrefs(var_crefs = var_crefs));
1283 end match;
1284 then newExp;
1285
1286 // get all variable crefs for this cref and add to set
1287 case Expression.CREF() algorithm
1288 // extract potential record children
1289 children := match BVariable.getVar(exp.cref, sourceInfo())
1290 local
1291 list<PointerWeak<Variable>> children_vars;
1292 case Variable.VARIABLE(backendinfo = BackendInfo.BACKEND_INFO(varKind = VariableKind.RECORD(children = children_vars)))
1293
4/4
✓ Branch 0 taken 75 times.
✓ Branch 1 taken 31 times.
✓ Branch 2 taken 75 times.
✓ Branch 3 taken 31 times.
106 then list(BVariable.getVarName(PointerWeak.upgrade(var)) for var in children_vars);
1294 9680 else {exp.cref};
1295 end match;
1296
1297
2/2
✓ Branch 0 taken 9755 times.
✓ Branch 1 taken 9711 times.
19466 for child in children loop
1298 // check if cref has to be considered as a dependency
1299 9755 stripped := ComponentRef.stripSubscriptsAll(child);
1300
2/2
✓ Branch 1 taken 8087 times.
✓ Branch 2 taken 1668 times.
9755 if not BVariable.checkCref(stripped, BVariable.isParamOrConst, sourceInfo()) then
1301 8087 addCrefToSet(stripped, var_crefs);
1302 end if;
1303 end for;
1304 then exp;
1305
1306 7547 else Expression.mapShallow(exp, function collectPartitioningCrefs(var_crefs = var_crefs));
1307 end match;
1308 end collectPartitioningCrefs;
1309
1310 function addCrefToSet
1311 input ComponentRef cref;
1312 input UnorderedSet<ComponentRef> set;
1313 protected
1314 Pointer<Variable> var_ptr = BVariable.getVarPointer(cref, sourceInfo());
1315 algorithm
1316 // states and there derivatives belong to one partition
1317 // discrete states and there pre value also
1318
2/2
✓ Branch 1 taken 401 times.
✓ Branch 2 taken 7686 times.
8087 if BVariable.isState(var_ptr) then
1319 401 UnorderedSet.add(BVariable.getPartnerCref(cref, BVariable.getVarDer), set);
1320 elseif BVariable.isPrevious(var_ptr) then
1321 74 UnorderedSet.add(BVariable.getPartnerCref(cref, BVariable.getVarPre), set);
1322 else
1323 7612 UnorderedSet.add(cref, set);
1324 end if;
1325 end addCrefToSet;
1326
1327 function replaceClockedFunctions
1328 "replaces sample() and hold() calls using clocks as condition with the $getPart function"
1329 input output Expression exp;
1330 input UnorderedSet<ComponentRef> held_crefs;
1331 function replaceSample
1332 input output Expression exp;
1333 input Call call;
1334 input Boolean basic;
1335 protected
1336 Expression arg1, arg2;
1337 algorithm
1338 {arg1, arg2} := match Call.arguments(call)
1339 // not collected samples have 2 arguments
1340 case {arg1, arg2} then {arg1, arg2};
1341 // collected samples have 3 arguments
1342 case {_, arg1, arg2} guard(basic) then {arg1, arg2};
1343 // non basic with 3 arguments only care for the first argument as signal
1344 case {arg1, arg2, _} then {arg1, arg2};
1345 else algorithm
1346 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for: " + Expression.toString(exp) + "."});
1347 ✗ then fail();
1348 end match;
1349 // if it's the basic sample operator, the second argument is supposed to be the clock, otherwise the first
1350
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 6 times.
35 if basic then
1351
2/2
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 22 times.
29 exp := if Type.isClock(Expression.typeOf(arg2)) then replaceClockedFunctionExp(arg1) else exp;
1352 else
1353 6 exp := replaceClockedFunctionExp(arg1);
1354 end if;
1355 end replaceSample;
1356 algorithm
1357 exp := match exp
1358 local
1359 Expression newExp, arg;
1360 Call call;
1361
1362 case Expression.CALL(call = call as Call.TYPED_CALL()) algorithm
1363 newExp := match AbsynUtil.pathString(Function.nameConsiderBuiltin(call.fn))
1364 // sample cases
1365 29 case "sample" then replaceSample(exp, call, true);
1366 4 case "subSample" then replaceSample(exp, call, false);
1367 1 case "superSample" then replaceSample(exp, call, false);
1368 ✗ case "shiftSample" then replaceSample(exp, call, false);
1369 1 case "backSample" then replaceSample(exp, call, false);
1370
1371 // hold case
1372 case "hold" algorithm
1373 arg := match Call.arguments(exp.call)
1374 // hold can only have one argument
1375 case {arg as Expression.CREF()} algorithm
1376 ✗ UnorderedSet.add(arg.cref, held_crefs);
1377 then arg;
1378 else algorithm
1379 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for: " + Expression.toString(exp) + "."});
1380 ✗ then fail();
1381 end match;
1382 ✗ then replaceClockedFunctionExp(arg);
1383
1384 else exp;
1385 end match;
1386 then newExp;
1387 else exp;
1388 end match;
1389 end replaceClockedFunctions;
1390
1391 function replaceClockedFunctionExp
1392 input output Expression exp;
1393 protected
1394 Function func;
1395 algorithm
1396 func := match Expression.typeOf(exp)
1397 13 case Type.REAL() then NFBuiltinFuncs.GET_PART_REAL;
1398 ✗ case Type.INTEGER() then NFBuiltinFuncs.GET_PART_INT;
1399 ✗ case Type.BOOLEAN() then NFBuiltinFuncs.GET_PART_BOOL;
1400 ✗ case Type.CLOCK() then NFBuiltinFuncs.GET_PART_CLOCK;
1401 else algorithm
1402 ✗ Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed. " + Expression.toString(exp) + " is of type "
1403 + Type.toString(Expression.typeOf(exp)) + ", only real, integer, boolean and clock are allowed."});
1404 ✗ then fail();
1405 end match;
1406 13 exp := Expression.CALL(Call.makeTypedCall(
1407 fn = func,
1408 args = {exp},
1409 variability = Expression.variability(exp),
1410 purity = NFPrefixes.Purity.PURE
1411 ));
1412 end replaceClockedFunctionExp;
1413
1414 function replaceClockedWhen
1415 "replace clocked when equations in clocked partitions with their body statement.
1416 only works for split up when equations with a single statement and no else when."
1417 input output Equation eqn;
1418 algorithm
1419 eqn := match eqn
1420 local
1421 Expression cond;
1422 WhenStatement stmt;
1423
1424 case Equation.WHEN_EQUATION(body = WhenEquationBody.WHEN_EQUATION_BODY(condition = cond, when_stmts = {stmt}, else_when = NONE()))
1425 guard(Type.isClock(Expression.typeOf(cond)))
1426 8 then WhenStatement.toEquation(stmt, eqn.attr, false);
1427
1428 else eqn;
1429 end match;
1430 end replaceClockedWhen;
1431
1432 annotation(__OpenModelica_Interface="nbackend");
1433 end NBPartitioning;
1434