Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 82.4% 605 / 0 / 734
Functions: -% 0 / 1 / 1
Branches: 64.1% 323 / 0 / 504

OMCompiler/Compiler/BackEnd/SynchronousFeatures.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 SynchronousFeatures
37 " file: SynchronousFeatures.mo
38 package: SynchronousFeatures
39 description: This package contains functions that belong to synchronous features.
40 - base-clock partitioning
41 - sub-clock partitioning"
42
43
44 public import Absyn;
45 public import BackendDAE;
46 public import DAE;
47
48 protected
49
50 import BackendDAEOptimize;
51 import BackendDAEUtil;
52 import BackendDump;
53 import BackendEquation;
54 import BackendVariable;
55 import ComponentReference;
56 protected import ComponentReferenceBasics;
57 import DAEDump;
58 import DAEUtil;
59 import Error;
60 import ErrorTypes;
61 import Expression;
62 import Flags;
63 import HashTable;
64 import List;
65 import MMath;
66 import StringUtil;
67 import Types;
68 import Util;
69 import MetaModelica.Dangerous.listReverseInPlace;
70
71
72 // =============================================================================
73 // clock partitioning
74 //
75 // =============================================================================
76
77 public function clockPartitioning
78 "Finds independent partitions of the equation system by base-clock partitioning and TLM."
79 input BackendDAE.BackendDAE inDAE;
80 output BackendDAE.BackendDAE outDAE;
81 algorithm
82 outDAE := match inDAE
83 local
84 BackendDAE.EqSystem syst;
85 BackendDAE.Shared shared;
86
87 case BackendDAE.DAE({syst}, shared)
88 1069 then clockPartitioning1(syst, shared);
89
90 // TODO: Improve support for partitioned systems of equations
91 else algorithm
92 ✗ BackendDAE.DAE({syst}, shared) := BackendDAEOptimize.collapseIndependentBlocks(inDAE);
93 ✗ then clockPartitioning1(syst, shared);
94 end match;
95 end clockPartitioning;
96
97 public function synchronousFeatures
98 input BackendDAE.BackendDAE inDAE;
99 output BackendDAE.BackendDAE outDAE;
100 protected
101 BackendDAE.EqSystems systs, contSysts, clockedSysts;
102 BackendDAE.Shared shared;
103 algorithm
104 1077 (clockedSysts, contSysts) := List.splitOnTrue(inDAE.eqs, BackendDAEUtil.isClockedSyst);
105
106
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 1038 times.
1077 if not listEmpty(clockedSysts) then
107 39 shared := inDAE.shared;
108
109 39 (clockedSysts, shared) := treatClockedStates(clockedSysts, shared);
110
111 39 systs := listAppend(contSysts, clockedSysts);
112 39 outDAE := BackendDAE.DAE(systs, shared);
113
114
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 36 times.
39 if Flags.isSet(Flags.DUMP_SYNCHRONOUS) then
115 3 print("synchronous features post-phase: synchronousFeatures\n\n");
116 3 BackendDump.dumpEqSystems(systs, "clock partitioning");
117 3 BackendDump.dumpBasePartitions(shared.partitionsInfo.basePartitions, "Base clocks");
118 3 BackendDump.dumpSubPartitions(shared.partitionsInfo.subPartitions, "Sub clocks");
119 end if;
120 else
121 outDAE := inDAE;
122 end if;
123 end synchronousFeatures;
124
125 public function contPartitioning
126 input BackendDAE.BackendDAE inDAE;
127 output BackendDAE.BackendDAE outDAE;
128 protected
129 BackendDAE.EqSystems systs, clockedSysts, clockedSysts1;
130 BackendDAE.Shared shared;
131 BackendDAE.EqSystem syst;
132 list<BackendDAE.Equation> unpartRemEqs;
133 algorithm
134 219 (clockedSysts, systs) := List.splitOnTrue(inDAE.eqs, BackendDAEUtil.isClockedSyst);
135 219 shared := inDAE.shared;
136
137
1/2
✓ Branch 0 taken 219 times.
✗ Branch 1 not taken.
219 if not listEmpty(systs) then
138
2/4
✗ Branch 2 not taken.
✓ Branch 3 taken 219 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 219 times.
219 BackendDAE.DAE({syst}, shared) := BackendDAEOptimize.collapseIndependentBlocks(BackendDAE.DAE(systs, shared));
139 219 (systs, clockedSysts1, unpartRemEqs) := baseClockPartitioning(syst, shared);
140
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 219 times.
219 assert(listEmpty(clockedSysts1), "Get clocked system in SynchronousFeatures.addContVarsEqs");
141 219 shared.removedEqs := BackendEquation.addList(unpartRemEqs, shared.removedEqs);
142 end if;
143
144 219 outDAE := BackendDAE.DAE(listAppend(systs, clockedSysts), shared);
145 end contPartitioning;
146
147 protected function clockPartitioning1
148 input BackendDAE.EqSystem inSyst;
149 input BackendDAE.Shared inShared;
150 output BackendDAE.BackendDAE outDAE;
151 protected
152 BackendDAE.EqSystem syst;
153 list<BackendDAE.EqSystem> contSysts, clockedSysts;
154 BackendDAE.Shared shared = inShared;
155 list<BackendDAE.EqSystem> systs;
156 list<DAE.ComponentRef> holdComps;
157 list<BackendDAE.Equation> unpartRemEqs;
158 algorithm
159 1069 syst := substitutePartitionOpExps(inSyst, inShared);
160 1069 (contSysts, clockedSysts, unpartRemEqs) := baseClockPartitioning(syst, shared);
161
162 1068 (contSysts, holdComps) := removeHoldExpsSyst(contSysts);
163
164 1068 (clockedSysts, shared) := subClockPartitioning1(clockedSysts, shared, holdComps);
165
166 1068 unpartRemEqs := createBoolClockWhenClauses(shared, unpartRemEqs);
167 1068 shared.removedEqs := BackendEquation.addList(unpartRemEqs, shared.removedEqs);
168
169 1068 systs := listAppend(contSysts, clockedSysts);
170 1068 outDAE := BackendDAE.DAE(systs, shared);
171
172
2/2
✓ Branch 0 taken 1029 times.
✓ Branch 1 taken 39 times.
1068 if not listEmpty(clockedSysts) then
173
2/2
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 3 times.
39 if Flags.isSet(Flags.DUMP_SYNCHRONOUS) then
174 3 print("synchronous features pre-phase: synchronousFeatures\n\n");
175 3 BackendDump.dumpEqSystems(systs, "clock partitioning");
176 3 BackendDump.dumpBasePartitions(shared.partitionsInfo.basePartitions, "Base clocks");
177 3 BackendDump.dumpSubPartitions(shared.partitionsInfo.subPartitions, "Sub clocks");
178 end if;
179 end if;
180 end clockPartitioning1;
181
182 protected function createBoolClockWhenClauses
183 input BackendDAE.Shared inShared;
184 input list<BackendDAE.Equation> inRemovedEqs;
185 output list<BackendDAE.Equation> outRemovedEqs = inRemovedEqs;
186 protected
187 BackendDAE.BasePartition basePartition;
188 algorithm
189
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1068 times.
✓ Branch 2 taken 1029 times.
✓ Branch 3 taken 39 times.
2182 for i in 1:arrayLength(inShared.partitionsInfo.basePartitions) loop
190 46 basePartition := inShared.partitionsInfo.basePartitions[i];
191 outRemovedEqs := match basePartition.clock
192 local
193 DAE.Exp c, e;
194 BackendDAE.WhenEquation whenEq;
195 BackendDAE.Equation eq;
196 case DAE.EVENT_CLOCK(c, _)
197 algorithm
198 22 e := DAE.CALL(Absyn.IDENT("$_clkfire"), {DAE.ICONST(i)}, DAE.callAttrBuiltinOther);
199 22 whenEq := BackendDAE.WHEN_STMTS(c, {BackendDAE.NORETCALL(e, DAE.emptyElementSource)}, NONE());
200 11 eq := BackendDAE.WHEN_EQUATION(0, whenEq, DAE.emptyElementSource, BackendDAE.EQ_ATTR_DEFAULT_DYNAMIC);
201 then eq::outRemovedEqs;
202 else outRemovedEqs;
203 end match;
204 end for;
205 end createBoolClockWhenClauses;
206
207 public function getBoolClockWhenClauses
208 "Collect event-clock when equations"
209 input output BackendDAE.Equation eq;
210 input output list<BackendDAE.Equation> eqLst;
211 algorithm
212
2/2
✓ Branch 1 taken 695 times.
✓ Branch 2 taken 11 times.
706 if hasBoolClockWhenClause(eq) then
213 eqLst := eq::eqLst;
214 end if;
215 end getBoolClockWhenClauses;
216
217 protected function hasBoolClockWhenClause
218 "Returns true if equation is a event-clock when equation with a $_clkfire call."
219 input BackendDAE.Equation eqn;
220 output Boolean hasBool=false;
221 algorithm
222 () := match eqn
223 case BackendDAE.WHEN_EQUATION(
224 size = 0,
225 whenEquation = BackendDAE.WHEN_STMTS(
226 whenStmtLst={BackendDAE.NORETCALL(
227 exp=DAE.CALL(path=Absyn.IDENT("$_clkfire")))}))
228 algorithm
229 hasBool := true;
230 then ();
231 else ();
232 end match;
233 end hasBoolClockWhenClause;
234
235 protected function treatClockedStates
236 "Convert continuous equations in clocked partitions to clocked equations
237 and call markClockedStates. author: rfranke"
238 input list<BackendDAE.EqSystem> inSysts;
239 input BackendDAE.Shared inShared;
240 output list<BackendDAE.EqSystem> outSysts = {};
241 output BackendDAE.Shared shared = inShared;
242 algorithm
243
4/4
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 39 times.
✓ Branch 2 taken 61 times.
✓ Branch 3 taken 39 times.
100 outSysts := list(
244 match syst
245 local
246 BackendDAE.EquationArray eqs;
247 Integer idx;
248 BackendDAE.SubPartition subPartition;
249 String solverMethod;
250 list<BackendDAE.Equation> lstEqs = {};
251 BackendDAE.Equation eq;
252 list<DAE.ComponentRef> derVars = {};
253 BackendDAE.Var var;
254 DAE.Exp exp, exp2;
255 DAE.Type ty;
256 case BackendDAE.EQSYSTEM(orderedEqs = eqs)
257 algorithm
258
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
61 BackendDAE.CLOCKED_PARTITION(idx) := syst.partitionKind;
259 61 subPartition := shared.partitionsInfo.subPartitions[idx];
260 61 solverMethod := BackendDump.optionString(getSubClockSolverOpt(subPartition.clock));
261 // check solverMethod
262
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 61 times.
61 if StringUtil.startsWith(solverMethod, "Explicit") then
263 ✗ if solverMethod <> "ExplicitEuler" then
264 ✗ Error.addMessage(Error.CLOCK_SOLVERMETHOD, {"ExplicitEuler", solverMethod});
265 solverMethod := "ExplicitEuler";
266 end if;
267 elseif stringLength(solverMethod) > 0 and solverMethod <> "ImplicitEuler"
268 and solverMethod <> "SemiImplicitEuler" and solverMethod <> "ImplicitTrapezoid" then
269 ✗ Error.addMessage(Error.CLOCK_SOLVERMETHOD, {"ImplicitEuler", solverMethod});
270 solverMethod := "ImplicitEuler";
271 end if;
272 // replace der(x) with $DER.x and collect derVars x
273
1/2
✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
586 for i in 1:BackendEquation.getNumberOfEquations(eqs) loop
274 525 eq := BackendEquation.get(eqs, i);
275 525 (eq, (derVars, _)) := BackendEquation.traverseExpsOfEquation(eq, getDerVars1, (derVars, BackendEquation.getForEquationIterIdent(eq)));
276 lstEqs := eq :: lstEqs;
277 end for;
278 // add all $DER.x as additional variables
279
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 61 times.
65 for derVar in derVars loop
280 4 var := listGet(BackendVariable.getVar(derVar, syst.orderedVars), 1);
281 4 var := BackendDAE.VAR(ComponentReference.crefPrefixDer(derVar), BackendDAE.VARIABLE(), DAE.BIDIR(), DAE.NON_PARALLEL(), var.varType, NONE(), NONE(), var.arryDim, DAE.emptyElementSource, NONE(), NONE(), NONE(), NONE(), DAE.NON_CONNECTOR(), DAE.NOT_INNER_OUTER(), false, false, false);
282 4 syst.orderedVars := BackendVariable.addVar(var, syst.orderedVars);
283 end for;
284 // add defining equations for $DER.x, depending on solverMethod
285
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 61 times.
65 for derVar in derVars loop
286 4 var := listGet(BackendVariable.getVar(derVar, syst.orderedVars), 1);
287 4 ty := var.varType;
288 // add forIter subscript and use element type if var is array
289 derVar := match var.varType
290 case DAE.T_ARRAY(ty = ty)
291 1 then ComponentReference.crefApplySubs(derVar, {DAE.INDEX(DAE.CREF(DAE.CREF_IDENT("i", DAE.T_INTEGER_DEFAULT, {}), DAE.T_INTEGER_DEFAULT))});
292 else derVar;
293 end match;
294 8 exp := DAE.CALL(Absyn.IDENT(name = "der"), {DAE.CREF(derVar, ty)}, DAE.callAttrBuiltinImpureReal);
295 4 exp := substituteFiniteDifference(exp);
296 4 exp2 := DAE.CREF(ComponentReference.crefPrefixDer(derVar), ty);
297
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 time.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
4 if solverMethod == "ExplicitEuler" then
298 // introduce states to delay derivatives; see MLS 3.3, section 16.8.2 Solver Methods
299 ✗ exp2 := DAE.CALL(Absyn.IDENT(name = "previous"), {exp2}, DAE.callAttrBuiltinImpureReal);
300 elseif solverMethod == "ImplicitTrapezoid" then
301 // evaluate derivatives at beginning and end of interval; see MLS 3.3, section 16.8.2 Solver Methods
302 ✗ exp2 := DAE.BINARY(exp2, DAE.ADD(DAE.T_REAL_DEFAULT),
303 DAE.CALL(Absyn.IDENT(name = "previous"), {exp2}, DAE.callAttrBuiltinImpureReal));
304 ✗ exp2 := DAE.BINARY(DAE.RCONST(0.5), DAE.MUL(DAE.T_REAL_DEFAULT), exp2);
305 end if;
306 // clocked continuous states are fixed at first tick
307 4 exp2 := DAE.IFEXP(DAE.CALL(Absyn.IDENT(name = "firstTick"), {}, DAE.callAttrBuiltinImpureBool),
308 DAE.RCONST(0), exp2);
309 // create for-equation or regular equation
310 eq := match var.varType
311 local
312 DAE.Dimension dim;
313 case DAE.T_ARRAY(dims = {dim})
314 1 then BackendDAE.FOR_EQUATION(
315 DAE.CREF(DAE.CREF_IDENT("i", DAE.T_INTEGER_DEFAULT, {}), DAE.T_INTEGER_DEFAULT),
316 DAE.ICONST(1), DAEUtil.dimExp(dim),
317 BackendDAE.EQUATION(exp, exp2, var.source, BackendDAE.EQ_ATTR_DEFAULT_DYNAMIC),
318 var.source, BackendDAE.EQ_ATTR_DEFAULT_DYNAMIC);
319 3 else BackendDAE.EQUATION(exp, exp2, var.source, BackendDAE.EQ_ATTR_DEFAULT_DYNAMIC);
320 end match;
321 lstEqs := eq :: lstEqs;
322 end for;
323 61 syst.orderedEqs := BackendEquation.listEquation(listReverse(lstEqs));
324
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
61 if solverMethod == "SemiImplicitEuler" then
325 // access previous values of clocked continuous states
326 ✗ for i in 1:BackendEquation.getNumberOfEquations(eqs) loop
327 ✗ eq := BackendEquation.get(eqs, i);
328 ✗ (eq, _) := BackendEquation.traverseExpsOfEquation(eq, shiftDerVars1, derVars);
329 ✗ eqs := BackendEquation.setAtIndex(eqs, i, eq);
330 end for;
331 end if;
332 61 shared := markClockedStates(syst, shared, derVars);
333 61 then BackendDAEUtil.clearEqSyst(syst);
334 end match
335 for syst in inSysts);
336 end treatClockedStates;
337
338 protected function getDerVars1 "helper to getDerVars"
339 input DAE.Exp inExp;
340 input tuple<list<DAE.ComponentRef>, Option<DAE.Ident>> inDerVars;
341 output DAE.Exp outExp;
342 output tuple<list<DAE.ComponentRef>, Option<DAE.Ident>> outDerVars;
343 algorithm
344 1050 (outExp, outDerVars) := Expression.traverseExpBottomUp(inExp, getDerVars, inDerVars);
345 end getDerVars1;
346
347 protected function getDerVars
348 "Get all crefs that appear in a der() operator and replace der(x) with $DER.x.
349 author: rfranke"
350 input DAE.Exp inExp;
351 input tuple<list<DAE.ComponentRef>, Option<DAE.Ident>> inDerVars;
352 output DAE.Exp outExp;
353 output tuple<list<DAE.ComponentRef>, Option<DAE.Ident>> outDerVars = inDerVars;
354 algorithm
355 outExp := match inExp
356 local
357 list<DAE.ComponentRef> derVars;
358 Option<DAE.Ident> optForIter;
359 DAE.Ident forIter;
360 DAE.ComponentRef x;
361 DAE.Type ty;
362 DAE.Exp der_x;
363 case DAE.CALL(path = Absyn.IDENT(name = "der"),
364 expLst = {DAE.CREF(componentRef = x, ty = ty)})
365 algorithm
366 // build $DER.x
367 4 der_x := DAE.CREF(ComponentReference.crefPrefixDer(x), ty);
368 // strip optional forIter and append x to derVars
369 4 (derVars, optForIter) := inDerVars;
370 () := match optForIter
371 case SOME(forIter)
372 algorithm
373 1 x := ComponentReference.crefStripIterSub(x, forIter);
374 then ();
375 else ();
376 end match;
377
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if not ComponentReferenceBasics.crefInLst(x, derVars) then
378 derVars := x :: derVars;
379 end if;
380 4 outDerVars := (derVars, optForIter);
381 then der_x;
382 else inExp;
383 end match;
384 end getDerVars;
385
386 protected function shiftDerVars1 "helper to shiftDerVars"
387 input DAE.Exp inExp;
388 input list<DAE.ComponentRef> inDerVars;
389 output DAE.Exp outExp;
390 output list<DAE.ComponentRef> outDerVars;
391 algorithm
392 ✗ (outExp, outDerVars) := Expression.traverseExpBottomUp(inExp, shiftDerVars, inDerVars);
393 end shiftDerVars1;
394
395 protected function shiftDerVars
396 "Apply previous() operator to all inDerVars.
397 author: rfranke"
398 input DAE.Exp inExp;
399 input list<DAE.ComponentRef> inDerVars;
400 output DAE.Exp outExp;
401 output list<DAE.ComponentRef> outDerVars = inDerVars;
402 algorithm
403 outExp := match inExp
404 local
405 List<DAE.Exp> expLst;
406 DAE.CallAttributes attr;
407 DAE.ComponentRef x;
408 DAE.Exp exp;
409 // introduce previous()
410 case DAE.CREF(componentRef = x)
411 guard ComponentReferenceBasics.crefInLst(x, inDerVars)
412 algorithm
413 ✗ exp := DAE.CALL(Absyn.IDENT(name = "previous"), {inExp}, DAE.callAttrBuiltinImpureReal);
414 then exp;
415 // check for possibly introduced der(previous())
416 case DAE.CALL(path = Absyn.IDENT(name = "der"),
417 expLst = {DAE.CALL(path = Absyn.IDENT(name = "previous"), expLst = expLst)},
418 attr = attr as DAE.CALL_ATTR())
419 algorithm
420 ✗ exp := DAE.CALL(Absyn.IDENT(name = "der"), expLst, attr);
421 then exp;
422 // check for possibly introduced previous(previous())
423 case DAE.CALL(path = Absyn.IDENT(name = "previous"),
424 expLst = {DAE.CALL(path = Absyn.IDENT(name = "previous"), expLst = expLst)},
425 attr = attr as DAE.CALL_ATTR())
426 algorithm
427 ✗ exp := DAE.CALL(Absyn.IDENT(name = "previous"), expLst, attr);
428 then exp;
429 // do nothing per default
430 else inExp;
431 end match;
432 end shiftDerVars;
433
434 protected function substituteFiniteDifference1 "helper to substituteFiniteDifference"
435 input DAE.Exp inExp;
436 input list<DAE.ComponentRef> inDerVars;
437 output DAE.Exp outExp;
438 output list<DAE.ComponentRef> outDerVars;
439 algorithm
440 ✗ (outExp, outDerVars) := Expression.traverseExpBottomUp(inExp, substituteFiniteDifference, inDerVars);
441 end substituteFiniteDifference1;
442
443 protected function substituteFiniteDifference
444 "Convert continous-time to clocked expression by replacing
445 der(x) -> (x - previous(x)) / interval().
446 author: rfranke"
447 input DAE.Exp inExp;
448 input list<DAE.ComponentRef> inDerVars = {};
449 output DAE.Exp outExp;
450 output list<DAE.ComponentRef> outDerVars;
451 algorithm
452 (outExp, outDerVars) := match inExp
453 local
454 List<DAE.Exp> expLst;
455 DAE.CallAttributes attr;
456 DAE.ComponentRef x;
457 DAE.Type ty;
458 DAE.Exp exp;
459 case DAE.CALL(path = Absyn.IDENT(name = "der"),
460 expLst = expLst as {DAE.CREF(componentRef = x)},
461 attr = attr as DAE.CALL_ATTR(ty = ty))
462 algorithm
463 4 exp := DAE.CALL(Absyn.IDENT(name = "previous"), expLst, attr);
464 4 exp := DAE.BINARY(DAE.CREF(x, ty), DAE.SUB(DAE.T_REAL_DEFAULT), exp);
465 4 exp := DAE.BINARY(exp, DAE.DIV(DAE.T_REAL_DEFAULT),
466 DAE.CALL(Absyn.IDENT(name = "interval"), {},
467 DAE.callAttrBuiltinImpureReal));
468 then (exp, x :: inDerVars);
469 else (inExp, inDerVars);
470 end match;
471 end substituteFiniteDifference;
472
473 protected function markClockedStates
474 "Collect discrete states and mark them for further processing.
475 Use VarKind CLOCKED_STATE. Moreover set the isStartFixed flag,
476 the fixed attribute and list the crefs of all discrete states in
477 outShared.partitionsInfo.subPartitions[subPartIdx].prevVars."
478 input BackendDAE.EqSystem inSyst;
479 input BackendDAE.Shared inShared;
480 input list<DAE.ComponentRef> derVars;
481 output BackendDAE.Shared outShared = inShared;
482 protected
483 BackendDAE.Equation eq;
484 list<DAE.ComponentRef> prevVars = {};
485 array<Boolean> isPrevVarArr, isDerVarArr;
486 list<Integer> varIxs;
487 BackendDAE.Var var;
488 Integer idx;
489 BackendDAE.SubPartition subPartition;
490 algorithm
491
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
61 BackendDAE.CLOCKED_PARTITION(idx) := inSyst.partitionKind;
492 61 subPartition := outShared.partitionsInfo.subPartitions[idx];
493
494 61 isPrevVarArr := arrayCreate(BackendVariable.varsSize(inSyst.orderedVars), false);
495 61 isDerVarArr := arrayCreate(BackendVariable.varsSize(inSyst.orderedVars), false);
496
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 61 times.
65 for cr in derVars loop
497 4 varIxs := getVarIxs(cr, inSyst.orderedVars);
498
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
8 for idx in varIxs loop
499 4 arrayUpdate(isDerVarArr, idx, true);
500 end for;
501 end for;
502
1/2
✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
61 for i in 1:BackendEquation.getNumberOfEquations(inSyst.orderedEqs) loop
503 529 eq := BackendEquation.get(inSyst.orderedEqs, i);
504 529 (_, (prevVars, _)) := BackendEquation.traverseExpsOfEquation(eq, collectPrevVars, (prevVars, BackendEquation.getForEquationIterIdent(eq)));
505 end for;
506
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 61 times.
61 for i in 1:BackendEquation.getNumberOfEquations(inSyst.removedEqs) loop
507 ✗ eq := BackendEquation.get(inSyst.removedEqs, i);
508 ✗ (_, (prevVars, _)) := BackendEquation.traverseExpsOfEquation(eq, collectPrevVars, (prevVars, BackendEquation.getForEquationIterIdent(eq)));
509 end for;
510
511
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 59 times.
61 if not Flags.isSet(Flags.NF_SCALARIZE) then
512
4/4
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 35 times.
✓ Branch 3 taken 2 times.
37 prevVars := list(ComponentReferenceBasics.crefStripLastSubs(cr) for cr in prevVars);
513 end if;
514
515
2/2
✓ Branch 0 taken 281 times.
✓ Branch 1 taken 61 times.
342 for cr in prevVars loop
516 281 varIxs := getVarIxs(cr, inSyst.orderedVars);
517
2/2
✓ Branch 1 taken 281 times.
✓ Branch 2 taken 281 times.
562 for idx in varIxs loop
518 281 arrayUpdate(isPrevVarArr, idx, true);
519 end for;
520 end for;
521 prevVars := {};
522
1/2
✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
590 for i in 1:arrayLength(isPrevVarArr) loop
523
2/2
✓ Branch 1 taken 197 times.
✓ Branch 2 taken 332 times.
529 if isPrevVarArr[i] then
524 197 var := BackendVariable.getVarAt(inSyst.orderedVars, i);
525 197 var := BackendVariable.setVarKind(var, BackendDAE.CLOCKED_STATE(
526 previousName = ComponentReference.crefPrefixPrevious(var.varName),
527 isStartFixed = isDerVarArr[i]));
528 197 var := BackendVariable.setVarFixed(var, true);
529 197 BackendVariable.setVarAt(inSyst.orderedVars, i, var);
530 197 prevVars := var.varName::prevVars;
531 end if;
532 end for;
533
534 61 subPartition.prevVars := prevVars;
535 61 arrayUpdate(outShared.partitionsInfo.subPartitions, idx, subPartition);
536 end markClockedStates;
537
538 protected function collectPrevVars
539 input DAE.Exp inExp;
540 input tuple<list<DAE.ComponentRef>, Option<DAE.Ident>> inPrevVars;
541 output DAE.Exp outExp;
542 output tuple<list<DAE.ComponentRef>, Option<DAE.Ident>> outPrevVars;
543 algorithm
544 1058 (outExp, outPrevVars) := Expression.traverseExpBottomUp(inExp, collectPrevVars1, inPrevVars);
545 end collectPrevVars;
546
547 protected function collectPrevVars1
548 "Append cref found in previous(cref) to outPrevVars.
549 Optionally strip for iterator to get array variable (no NF_SCALARIZE)."
550 input DAE.Exp inExp;
551 input tuple<list<DAE.ComponentRef>, Option<DAE.Ident>> inPrevVars;
552 output DAE.Exp outExp = inExp;
553 output tuple<list<DAE.ComponentRef>, Option<DAE.Ident>> outPrevVars;
554 algorithm
555 outPrevVars := match inExp
556 local
557 list<DAE.ComponentRef> inPrevCompRefs;
558 Option<DAE.Ident> inForIter;
559 DAE.Ident forIter;
560 DAE.ComponentRef cr;
561 case DAE.CALL(path=Absyn.IDENT("previous"), expLst={DAE.CREF(cr, _)})
562 algorithm
563 281 (inPrevCompRefs, inForIter) := inPrevVars;
564 () := match inForIter
565 case SOME(forIter)
566 algorithm
567 5 cr := ComponentReference.crefStripIterSub(cr, forIter);
568 then ();
569 else ();
570 end match;
571 281 then (cr :: inPrevCompRefs, inForIter);
572 else inPrevVars;
573 end match;
574 end collectPrevVars1;
575
576 protected function subClockPartitioning1
577 "Do subclock partitioning and inferencing and create clocked partitions and base clocks array."
578 input list<BackendDAE.EqSystem> inSysts;
579 input BackendDAE.Shared inShared;
580 input list<DAE.ComponentRef> inHoldComps;
581 output list<BackendDAE.EqSystem> outSysts = {};
582 output BackendDAE.Shared outShared = inShared;
583 protected
584 DAE.ClockKind baseClock;
585 HashTable.HashTable varsPartition;
586 Integer i, j, n, nBaseClocks;
587 DAE.ComponentRef cr;
588 array<Boolean> hasHoldOperator;
589 list<BackendDAE.EqSystem> systs;
590 list<BackendDAE.SubClock> lstSubClocks1, lstSubClocks = {};
591 BackendDAE.PartitionsInfo partitionsInfo;
592 array<BackendDAE.BasePartition> basePartitions;
593 array<BackendDAE.SubPartition> subPartitions;
594 algorithm
595 1068 nBaseClocks := listLength(inSysts);
596 1068 basePartitions := arrayCreate(nBaseClocks, BackendDAE.BASE_PARTITION(DAE.INFERRED_CLOCK(), 0));
597 1068 varsPartition := HashTable.emptyHashTable();
598
599 i := 0; j := 1;
600
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 1068 times.
1114 for syst in inSysts loop
601 46 (systs, baseClock, lstSubClocks1) := subClockPartitioning(syst, outShared, i);
602 46 n := listLength(systs);
603 46 arrayUpdate(basePartitions, j, BackendDAE.BASE_PARTITION(baseClock, n));
604 46 outSysts := List.append_reverse(systs, outSysts);
605 46 lstSubClocks := List.append_reverse(lstSubClocks1, lstSubClocks);
606 46 i := i + n;
607 46 j := j + 1;
608 end for;
609 1068 outSysts := listReverseInPlace(outSysts);
610 1068 lstSubClocks := listReverseInPlace(lstSubClocks);
611
612 1068 hasHoldOperator := arrayCreate(listLength(lstSubClocks), false);
613 //Create hash cr -> subpartition index
614 i := 1;
615
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 1068 times.
1129 for syst in outSysts loop
616
1/2
✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
586 for j in 1:BackendVariable.varsSize(syst.orderedVars) loop
617 525 BackendDAE.VAR(varName=cr) := BackendVariable.getVarAt(syst.orderedVars, j);
618 525 varsPartition := BaseHashTable.add((cr, i), varsPartition);
619 end for;
620 61 i := i + 1;
621 end for;
622 //Detect subpartitions whose variables are used in hold operator
623
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1068 times.
1083 for cr in inHoldComps loop
624 15 i := BaseHashTable.get(cr, varsPartition);
625 15 arrayUpdate(hasHoldOperator, i, true);
626 end for;
627
628 i := 1;
629 1068 subPartitions := arrayCreate( listLength(lstSubClocks),
630 BackendDAE.SUB_PARTITION(BackendDAE.DEFAULT_SUBCLOCK, false, {}) );
631
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 1068 times.
1129 for subclock in lstSubClocks loop
632 61 arrayUpdate(subPartitions, i, BackendDAE.SUB_PARTITION(subclock, hasHoldOperator[i], {}));
633 61 i := i + 1;
634 end for;
635
636 partitionsInfo := outShared.partitionsInfo;
637 1068 partitionsInfo.basePartitions := basePartitions;
638 partitionsInfo.subPartitions := subPartitions;
639
1/2
✓ Branch 0 taken 1068 times.
✗ Branch 1 not taken.
1068 outShared.partitionsInfo := partitionsInfo;
640 end subClockPartitioning1;
641
642 protected function removeHoldExpsSyst
643 "Collect clocked variable, which used in continuous partition.
644 Replace expression hold(expr_i) -> $getPart(expr_i)."
645 input list<BackendDAE.EqSystem> inSysts;
646 output list<BackendDAE.EqSystem> outSysts = {};
647 output list<DAE.ComponentRef> outHoldComps = {};
648 algorithm
649
2/2
✓ Branch 0 taken 18954 times.
✓ Branch 1 taken 1068 times.
20022 for syst1 in inSysts loop
650 syst1 := match syst1
651 local
652 BackendDAE.EquationArray eqs;
653 BackendDAE.EqSystem syst;
654 list<BackendDAE.Equation> lstEqs;
655 Integer i;
656 BackendDAE.Equation eq;
657 case syst as BackendDAE.EQSYSTEM(orderedEqs = eqs)
658 algorithm
659 lstEqs := {};
660
2/2
✓ Branch 1 taken 18284 times.
✓ Branch 2 taken 670 times.
176673 for i in 1:BackendEquation.getNumberOfEquations(eqs) loop
661 157719 eq := BackendEquation.get(eqs, i);
662 157719 (eq, outHoldComps) := BackendEquation.traverseExpsOfEquation(eq, removeHoldExp1, outHoldComps);
663 lstEqs := eq::lstEqs;
664 end for;
665 18954 syst.orderedEqs := BackendEquation.listEquation(listReverse(lstEqs));
666 then syst;
667 end match;
668 18954 outSysts := BackendDAEUtil.clearEqSyst(syst1) :: outSysts;
669 end for;
670 end removeHoldExpsSyst;
671
672 protected function removeHoldExp1
673 input DAE.Exp inExp;
674 input list<DAE.ComponentRef> inComps;
675 output DAE.Exp outExp;
676 output list<DAE.ComponentRef> outComps;
677 algorithm
678 317809 (outExp, outComps) := Expression.traverseExpBottomUp(inExp, removeHoldExp, inComps);
679 end removeHoldExp1;
680
681 protected function removeHoldExp
682 input DAE.Exp inExp;
683 input list<DAE.ComponentRef> inComps;
684 output DAE.Exp outExp;
685 output list<DAE.ComponentRef> outComps;
686 algorithm
687 (outExp, outComps) := match inExp
688 local
689 DAE.Exp e;
690 DAE.ComponentRef cr;
691 case DAE.CALL(Absyn.IDENT("hold"), {e}, _)
692
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
15 algorithm DAE.CREF(cr, _) := e;
693 15 then (substGetPartition(e), cr::inComps);
694 else (inExp, inComps);
695 end match;
696 end removeHoldExp;
697
698 protected function getSubPartitionAdjacency
699 "gets the adjacency matrix for the sub clock partitions and a dependency graph which is used to determine the execution order.
700 The edge weights are the sub-clocks resulting from the sub clock interfaces.
701 The sub clock interfaces are both original and inverted to get from one partition to another.
702 The dependency graph is based on the causality of the sub partition interface functions.
703 author: vwaurich 2017-06"
704 input Integer numPartitions;
705 input Integer baseClockEq;
706 input list<Integer> subPartitionInterfaceEqs;
707 input array<Integer> eqPartMap;
708 input array<Integer> varPartMap;
709 input array<Boolean> clockedVarsMask;
710 input BackendDAE.EquationArray eqs;
711 input BackendDAE.Variables vars;
712 output array<list<tuple<Integer,BackendDAE.SubClock>>> partAdjacency;//idx: partition, entries: connections to other partitions with subclocks
713 output array<Integer> order;
714 protected
715 Boolean infered;
716 Integer part, part1, part2, var1, var2;
717 list<Integer> partLst,orderLst;
718 BackendDAE.SubClock subClk1,subClk2;
719 array<Integer> partitionParents;
720 array<Boolean> partitionParentsVisited;
721 array<Boolean> partitionInterfacesClockVars;
722 algorithm
723 //build adjacency matrix for subclock partitions and dependency (parent) graph
724 46 partAdjacency := arrayCreate(numPartitions,{});
725 46 partitionParents := arrayCreate(numPartitions,-1);
726 46 partitionInterfacesClockVars := arrayCreate(numPartitions,false);
727
2/2
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 46 times.
67 for subPartEq in subPartitionInterfaceEqs loop
728 //part1,subClk1 is the output of the sub partition interface function calls, this is used for ordering
729 21 (infered,part1,var1,subClk1,part2,var2,subClk2) := getConnectedSubPartitions(BackendEquation.get(eqs,subPartEq),varPartMap,vars);
730 //for adjacency relations, check only concrete sub partition interfaces not infered ones
731
2/4
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
✗ Branch 3 not taken.
21 if part1 <> 0 and part2 <> 0 then
732 21 addPartAdjacencyEdge(part1,subClk1,part2,subClk2,partAdjacency);
733 end if;
734 //reset previously obtained opposite parent relation if it interfaces clock-variables
735 //this is to prefer signal flow relations over clock relations in case of conflicts
736
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
21 if partitionParents[part2] == part1 and partitionInterfacesClockVars[part2] then
737 ✗ partitionParents[part2] := -1;
738 end if;
739
3/4
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 15 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 6 times.
21 partitionInterfacesClockVars[part1] := not (clockedVarsMask[var1] and clockedVarsMask[var2]);
740 //avoid mutually dependent parents that would result in stack overflow later on
741
1/2
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
21 if partitionParents[part2] <> part1 then
742 21 partitionParents[part1] := part2;
743 end if;
744 end for;
745
746 //get the order
747 46 partLst := List.intRange(numPartitions);
748 46 partitionParentsVisited := arrayCreate(numPartitions,false);
749 orderLst := {};
750
2/2
✓ Branch 0 taken 93 times.
✓ Branch 1 taken 46 times.
139 while not listEmpty(partLst) loop
751 93 part::partLst := partLst;
752
2/2
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 80 times.
93 if not partitionParentsVisited[part] then
753 //partition without parent, not yet visited
754
3/4
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 46 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 34 times.
80 if partitionParents[part] == -1 or partitionParents[part] == part then
755 orderLst := part::orderLst;
756 46 partitionParentsVisited[part] := true;
757 //partition with parents, parent visited
758 elseif partitionParentsVisited[partitionParents[part]] then
759 orderLst := part::orderLst;
760 21 partitionParentsVisited[part] := true;
761 //partition with parents, parent not yet visited
762 else
763 partLst := part::partLst;
764 13 partLst := partitionParents[part]::partLst;
765 end if;
766 end if;
767 end while;
768 46 order := listArray(listReverse(orderLst));
769 end getSubPartitionAdjacency;
770
771 protected function getSubClockForClkConstructor
772 "gets the corresponding subclock between 2 clock constructors
773 author: vwaurich 2017-06"
774 input DAE.ClockKind refClock;
775 input DAE.ClockKind clk;
776 output BackendDAE.SubClock subClk;
777 algorithm
778 subClk := match(refClock,clk)
779 local
780 Integer i1,i2,i3,i4;
781 Real r1,r2;
782 case(DAE.RATIONAL_CLOCK(DAE.ICONST(i1),DAE.ICONST(i2)), DAE.INFERRED_CLOCK())
783 ✗ then BackendDAE.SUBCLOCK(MMath.RATIONAL(i2,i1), MMath.RAT0,NONE());
784 case(DAE.RATIONAL_CLOCK(DAE.ICONST(i1),DAE.ICONST(i2)), DAE.RATIONAL_CLOCK(DAE.ICONST(i3),DAE.ICONST(i4)))
785 4 then BackendDAE.SUBCLOCK(MMath.divRational(MMath.RATIONAL(i2,i1),MMath.RATIONAL(i4,i3)),MMath.RAT0,NONE());
786 case(DAE.REAL_CLOCK(DAE.RCONST(r1)), DAE.INFERRED_CLOCK())
787 ✗ then BackendDAE.SUBCLOCK(MMath.RATIONAL(1, realInt(1.0/r1)), MMath.RAT0, NONE());
788 case(DAE.REAL_CLOCK(DAE.RCONST(r1)), DAE.REAL_CLOCK(DAE.RCONST(r2)))
789 ✗ then BackendDAE.SUBCLOCK(MMath.divRational(MMath.RATIONAL(1, realInt(1.0/r1)),MMath.RATIONAL(1,realInt(1.0/r2))), MMath.RAT0, NONE());
790 else
791 algorithm
792 //Please add the missing cases.
793 ✗ Error.addInternalError(getInstanceName() + " failed.\n", sourceInfo());
794 ✗ then fail();
795 end match;
796 end getSubClockForClkConstructor;
797
798 protected function setSolverSubClock
799 "if the base clock is a solver clock, put the solver in the subclock and clean the base clock from the solver clock
800 author: vwaurich 2017-06"
801 input DAE.ClockKind baseClkIn;
802 input BackendDAE.SubClock inSubClock;
803 output DAE.ClockKind baseClkOut;
804 output BackendDAE.SubClock outSubClock;
805 algorithm
806 (baseClkOut, outSubClock) := match baseClkIn
807 local
808 String solver;
809 DAE.ClockKind clk;
810 case DAE.SOLVER_CLOCK(c = DAE.CLKCONST(clk=clk), solverMethod=DAE.SCONST(solver)) algorithm
811
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
4 outSubClock := setSubClockSolver(inSubClock, if solver == "" then NONE() else SOME(solver));
812 then (clk, outSubClock);
813 else (baseClkIn, inSubClock);
814 end match;
815 end setSolverSubClock;
816
817 protected function findSubClocks
818 "gets the sub clocks for each partition by coloring the partition adjacency starting by the real and bool clocks.
819 author: vwaurich 2017-06"
820 input Integer numPartitions;
821 input Integer baseClockEq;
822 input DAE.ClockKind baseClk;
823 input list<Integer> baseClockConstructors;
824 input list<Integer> subPartitionInterfaceEqs;
825 input array<Integer> eqPartMap;
826 input array<Integer> varPartMap;
827 input BackendDAE.EquationArray eqs;
828 input array<list<tuple<Integer,BackendDAE.SubClock>>> partAdjacency;//idx: partition, entries: connections to other partitions with subclocks
829 output DAE.ClockKind baseClkOut;
830 output array<BackendDAE.SubClock> outSubClocks;
831 protected
832 Integer part1,part2;
833 list<Integer> partLst;
834 BackendDAE.SubClock subClk1,subClk2;
835 DAE.ClockKind clk;
836 array<Boolean> partIsAssigned;
837 list<tuple<Integer,BackendDAE.SubClock>> adjParts;
838 algorithm
839 46 outSubClocks := arrayCreate(numPartitions,BackendDAE.DEFAULT_SUBCLOCK);
840 46 partIsAssigned := arrayCreate(numPartitions, false); //mark which partition is assigned
841
842 //if there are multiple clock constructors in the sub partition, refer them to the base clock, ignore infered clocks
843
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 46 times.
154 for clockEq in baseClockConstructors loop
844
4/4
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 40 times.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 43 times.
108 if not intEq(baseClockEq, clockEq) and not intEq(baseClockEq,-1) then
845 25 part1 := arrayGet(eqPartMap,clockEq);
846 25 clk := getBaseClock(BackendEquation.get(eqs,clockEq));
847
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 21 times.
25 if not isInferedBaseClock(clk) then
848 4 subClk1 := getSubClockForClkConstructor(baseClk, clk);
849 4 arrayUpdate(outSubClocks, part1, subClk1);
850 4 arrayUpdate(partIsAssigned, part1, true);
851 end if;
852 end if;
853 end for;
854
855 //assign subclock partitions
856
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 40 times.
46 if isInferedBaseClock(baseClk) then
857 baseClkOut := baseClk;
858 6 partLst := List.intRange(numPartitions); //traverse all partitions, start with base clock partition
859 else
860 40 part1 := arrayGet(eqPartMap,baseClockEq);
861 40 partLst := part1::List.intRange(numPartitions); //traverse all partitions, start with base clock partition
862 //if the baseClk is a solver clock, set the corresponding subClock solver
863 40 (baseClkOut, subClk1) := setSolverSubClock(baseClk, outSubClocks[part1]);
864 40 arrayUpdate(outSubClocks, part1, subClk1); //set the solver clock
865 40 arrayUpdate(partIsAssigned, part1, true);
866 end if;
867
868
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 46 times.
170 while not listEmpty(partLst) loop
869 124 part1::partLst := partLst;
870 124 adjParts := arrayGet(partAdjacency, part1);
871 //check adjacent partitions
872
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 80 times.
204 for adjPart in adjParts loop
873 80 part2 := Util.tuple21(adjPart);
874
2/2
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 63 times.
80 if not arrayGet(partIsAssigned, part2) then
875 17 subClk1 := arrayGet(outSubClocks, part1);
876 17 subClk2 := Util.tuple22(adjPart);
877 17 subClk2 := computeAbsoluteSubClock(subClk1,subClk2);
878
1/2
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
17 if not isInferedSubClock(subClk2) then
879 17 arrayUpdate(outSubClocks, part2, subClk2);
880 17 arrayUpdate(partIsAssigned, part2, true);
881 partLst := part2::partLst;
882 end if;
883 end if;
884 end for;
885 end while;
886 end findSubClocks;
887
888 protected function computeAbsoluteSubClock
889 "merges 2 subsequent sub clocks.
890 author: vwaurich 2017-06"
891 input BackendDAE.SubClock preClock;//the known subpartition clock
892 input BackendDAE.SubClock subSeqClock; //the sub partitin clock which shall be determined
893 output BackendDAE.SubClock subClk = BackendDAE.DEFAULT_SUBCLOCK;
894 algorithm
895 subClk := match(preClock, subSeqClock)
896 local
897 MMath.Rational f1,f2;
898 MMath.Rational s1,s2;
899 Option<String> solver1,solver2;
900 case(BackendDAE.SUBCLOCK(f1,s1,solver1), BackendDAE.SUBCLOCK(f2,s2,solver2))
901 algorithm
902 17 solver1 := mergeSolver(solver1,solver2);
903 17 then BackendDAE.SUBCLOCK(MMath.divRational(f1, f2), MMath.addRational(MMath.multRational(s1, f2), s2), solver1);
904 case(BackendDAE.SUBCLOCK(_,_,_),BackendDAE.INFERED_SUBCLOCK())
905 then subSeqClock;
906 else
907 algorithm
908 ✗ Error.addInternalError(getInstanceName() + " failed.\n", sourceInfo());
909 ✗ then fail();
910 end match;
911 end computeAbsoluteSubClock;
912
913 protected function mergeSolver
914 "merges the solver methods of 2 sub clocks.
915 author: vwaurich 2017-06"
916 input Option<String> solver1;
917 input Option<String> solver2;
918 output Option<String> sOut;
919 algorithm
920 sOut := match(solver1,solver2)
921 local
922 String s1,s2;
923 case(NONE(),SOME(s2))
924 then SOME(s2);
925 case(SOME(s1),NONE())
926 then SOME(s1);
927 case(SOME(s1),SOME(s2))
928 algorithm
929 ✗ if not stringEq(s1,s2) then Error.addCompilerNotification("Infered sub clock partitions have different solvers:"+s1+" <->"+s2+".\n"); end if;
930 then SOME(s1);
931 else
932 then NONE();
933 end match;
934 end mergeSolver;
935
936 protected function addPartAdjacencyEdge
937 "add an edge between 2 partitions in the partition adjacency matrix.
938 author: vwaurich 2017-06"
939 input Integer part1;
940 input BackendDAE.SubClock sub1;
941 input Integer part2;
942 input BackendDAE.SubClock sub2;
943 input array<list<tuple<Integer,BackendDAE.SubClock>>> partAdjacency;
944 protected
945 list<tuple<Integer,BackendDAE.SubClock>> partEdges;
946 algorithm
947
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 if intGt(part1,0) and intGt(part2,0) then
948 //from first partition to secod partition
949 21 partEdges := arrayGet(partAdjacency,part1);
950
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 21 times.
29 for edge in partEdges loop
951 //there is already a connection to this partition
952 8 if intEq(Util.tuple21(edge),part2) then
953 //if not subClkEqual(Util.tuple22(edge),sub2) then Error.addCompilerNotification("Multiple subclock-interfaces between sub clock partitions.\n");end if;
954 end if;
955 end for;
956 42 arrayUpdate(partAdjacency,part1,(part2,sub1)::partEdges);
957 //from second partition to first partition
958 21 partEdges := arrayGet(partAdjacency,part2);
959 42 arrayUpdate(partAdjacency,part2,(part1,sub2)::partEdges);
960 end if;
961 end addPartAdjacencyEdge;
962
963 protected function setSubClockFactor
964 "sets the factor of a sub clock
965 author: vwaurich 2017-06"
966 input BackendDAE.SubClock subClk;
967 input MMath.Rational factor;
968 output BackendDAE.SubClock subClkOut;
969 algorithm
970 subClkOut := match subClk
971 local
972 MMath.Rational shift;
973 Option<String> solver;
974 case BackendDAE.SUBCLOCK(_,shift,solver)
975 18 then BackendDAE.SUBCLOCK(factor,shift,solver);
976 else
977 then subClk;
978 end match;
979 end setSubClockFactor;
980
981 protected function getSubClockFactor
982 "gets the factor of a sub clock
983 author: vwaurich 2017-06"
984 input BackendDAE.SubClock subClk;
985 output MMath.Rational factor;
986 algorithm
987 factor := match subClk
988 local
989 case BackendDAE.SUBCLOCK(factor,_,_)
990 then factor;
991 else
992 then MMath.RAT1;
993 end match;
994 end getSubClockFactor;
995
996 protected function getSubClockShift
997 "gets the shift value of a sub clock
998 author: vwaurich 2017-06"
999 input BackendDAE.SubClock subClk;
1000 output MMath.Rational shift;
1001 algorithm
1002 shift := match subClk
1003 local
1004 case BackendDAE.SUBCLOCK(_,shift,_)
1005 then shift;
1006 else
1007 then MMath.RAT0;
1008 end match;
1009 end getSubClockShift;
1010
1011 protected function getSubClockSolverOpt
1012 "gets the solver method option of a sub clock
1013 author: vwaurich 2017-06"
1014 input BackendDAE.SubClock subClk;
1015 output Option<String> solver;
1016 algorithm
1017 solver := match subClk
1018 local
1019 case BackendDAE.SUBCLOCK(_,_,solver)
1020 then solver;
1021 else
1022 then NONE();
1023 end match;
1024 end getSubClockSolverOpt;
1025
1026 protected function setSubClockShift
1027 "sets the shift value of a sub clock
1028 author: vwaurich 2017-06"
1029 input BackendDAE.SubClock subClk;
1030 input MMath.Rational shift;
1031 output BackendDAE.SubClock subClkOut;
1032 algorithm
1033 subClkOut := match subClk
1034 local
1035 MMath.Rational factor;
1036 Option<String> solver;
1037 case BackendDAE.SUBCLOCK(factor,_,solver)
1038 16 then BackendDAE.SUBCLOCK(factor,shift,solver);
1039 else
1040 then subClk;
1041 end match;
1042 end setSubClockShift;
1043
1044 protected function setSubClockSolver
1045 "sets the solver method option of a sub clock
1046 author: vwaurich 2017-06"
1047 input BackendDAE.SubClock subClk;
1048 input Option<String> solver;
1049 output BackendDAE.SubClock subClkOut;
1050 algorithm
1051 subClkOut := match subClk
1052 local
1053 MMath.Rational factor,shift;
1054 case BackendDAE.SUBCLOCK(factor,shift,_)
1055 2 then BackendDAE.SUBCLOCK(factor,shift,solver);
1056 else
1057 then subClk;
1058 end match;
1059 end setSubClockSolver;
1060
1061 protected function getConnectedSubPartitions
1062 "get the connected partitions and the transformating sub clock for a sub partition interface equation.
1063 used to build the sub clock partition adjacency
1064 author: vwaurich 2017-06"
1065 input BackendDAE.Equation eq;
1066 input array<Integer> varPartMap;
1067 input BackendDAE.Variables vars;
1068 output Boolean infered = false;
1069 output Integer part1;
1070 output Integer var1=-1;
1071 output BackendDAE.SubClock sub1;
1072 output Integer part2;
1073 output Integer var2=-1;
1074 output BackendDAE.SubClock sub2;
1075 algorithm
1076 sub1 := BackendDAE.DEFAULT_SUBCLOCK;
1077 sub2 := BackendDAE.DEFAULT_SUBCLOCK;
1078 (part1, var1, part2, var2) := match eq
1079 local
1080 Integer v1,v2,p1,p2;
1081 Integer factor,counter,resolution;
1082 String solver;
1083 DAE.ComponentRef cref1,cref2;
1084 case BackendDAE.EQUATION(exp=DAE.CREF(componentRef=cref1), scalar=DAE.CALL(path=Absyn.IDENT("superSample"),expLst={DAE.CREF(componentRef=cref2),DAE.ICONST(factor)}))
1085 algorithm
1086 8 infered := intEq(factor,0);//the sub clock has to be infered
1087
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
8 (_,{v1}) := BackendVariable.getVar(cref1,vars);
1088 8 p1 := varPartMap[v1];
1089
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
8 (_,{v2}) := BackendVariable.getVar(cref2,vars);
1090 8 p2 := varPartMap[v2];
1091
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if infered then
1092 sub1 := BackendDAE.INFERED_SUBCLOCK();
1093 sub2 := BackendDAE.INFERED_SUBCLOCK();
1094 else
1095 4 sub1 := setSubClockFactor(sub1, MMath.divRational(MMath.RAT1, MMath.RATIONAL(factor,1)));
1096 4 sub2 := setSubClockFactor(sub2,MMath.RATIONAL(factor,1));
1097 end if;
1098 then (p1,v1,p2,v2);
1099 case BackendDAE.EQUATION(exp=DAE.CREF(componentRef=cref1), scalar=DAE.CALL(path=Absyn.IDENT("subSample"),expLst={DAE.CREF(componentRef=cref2),DAE.ICONST(factor)}))
1100 algorithm
1101 5 infered := intEq(factor,0);//the sub clock has to be infered
1102
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
5 (_,{v1}) := BackendVariable.getVar(cref1,vars);
1103 5 p1 := varPartMap[v1];
1104
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
5 (_,{v2}) := BackendVariable.getVar(cref2,vars);
1105 5 p2 := varPartMap[v2];
1106
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if infered then
1107 sub1 := BackendDAE.INFERED_SUBCLOCK();
1108 sub2 := BackendDAE.INFERED_SUBCLOCK();
1109 else
1110 5 sub1 := setSubClockFactor(sub1, MMath.RATIONAL(factor,1));
1111 5 sub2 := setSubClockFactor(sub2, MMath.divRational(MMath.RAT1, MMath.RATIONAL(factor,1)));
1112 end if;
1113 then (p1,v1,p2,v2);
1114 case BackendDAE.EQUATION(exp=DAE.CREF(componentRef=cref1), scalar=DAE.CALL(path=Absyn.IDENT("shiftSample"),expLst={DAE.CREF(componentRef=cref2),DAE.ICONST(counter),DAE.ICONST(resolution)}))
1115 algorithm
1116
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
5 (_,{v1}) := BackendVariable.getVar(cref1,vars);
1117 5 p1 := varPartMap[v1];
1118
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
5 (_,{v2}) := BackendVariable.getVar(cref2,vars);
1119 5 p2 := varPartMap[v2];
1120 5 sub1 := setSubClockShift(sub1, MMath.subRational(MMath.RAT0, MMath.RATIONAL(counter, resolution)));
1121 5 sub2 := setSubClockShift(sub2,MMath.RATIONAL(counter,resolution));
1122 then (p1,v1,p2,v2);
1123 case BackendDAE.EQUATION(exp=DAE.CREF(componentRef=cref1), scalar=DAE.CALL(path=Absyn.IDENT("backSample"),expLst={DAE.CREF(componentRef=cref2),DAE.ICONST(counter),DAE.ICONST(resolution)}))
1124 algorithm
1125
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
3 (_,{v1}) := BackendVariable.getVar(cref1,vars);
1126 3 p1 := varPartMap[v1];
1127
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
3 (_,{v2}) := BackendVariable.getVar(cref2,vars);
1128 3 p2 := varPartMap[v2];
1129 3 sub1 := setSubClockShift(sub1, MMath.RATIONAL(counter,resolution));
1130 3 sub2 := setSubClockShift(sub2, MMath.subRational(MMath.RAT0, MMath.RATIONAL(counter, resolution)));
1131 then (p1,v1,p2,v2);
1132 case BackendDAE.EQUATION(exp=DAE.CREF(componentRef=cref1), scalar=DAE.CLKCONST(clk=DAE.SOLVER_CLOCK(c=DAE.CREF(componentRef=cref2), solverMethod=DAE.SCONST(solver))))
1133 algorithm
1134 ✗ (_,{v1}) := BackendVariable.getVar(cref1,vars);
1135 ✗ p1 := varPartMap[v1];
1136 ✗ (_,{v2}) := BackendVariable.getVar(cref2,vars);
1137 ✗ p2 := varPartMap[v2];
1138 ✗ sub1 := setSubClockSolver(sub1, SOME(solver));
1139 ✗ sub2 := setSubClockSolver(sub2, SOME(solver));
1140 then (p1,v1,p2,v2);
1141
1142 else
1143 then (-1,-1,-1,-1);
1144 end match;
1145 end getConnectedSubPartitions;
1146
1147 protected function chooseBaseClock
1148 "among all clock constructors, choose one as a base clock. No particular strategy applied.
1149 author: vwaurich 2017-06"
1150 input list<Integer> clockEqs;
1151 input Integer numPartitions;
1152 input array<Integer> eqPartMap;
1153 input BackendDAE.EquationArray eqs;
1154 output DAE.ClockKind outBaseClock = DAE.INFERRED_CLOCK();
1155 output Integer baseClockEqIdx = -1;
1156 protected
1157 array<BackendDAE.SubClock> subClkPartMap;
1158 BackendDAE.Equation eq;
1159 algorithm
1160 //find baseClock, take the last, if there are several
1161 46 subClkPartMap := arrayCreate(numPartitions, BackendDAE.DEFAULT_SUBCLOCK);
1162
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 46 times.
154 for clockEq in clockEqs loop
1163 108 eq := BackendEquation.get(eqs,clockEq);
1164
2/2
✓ Branch 1 taken 44 times.
✓ Branch 2 taken 64 times.
108 if isBaseClockEq(eq) then
1165 44 outBaseClock := getBaseClock(eq);
1166 baseClockEqIdx := clockEq;
1167 end if;
1168 end for;
1169 end chooseBaseClock;
1170
1171 protected function isBaseClockEq
1172 input BackendDAE.Equation eq;
1173 output Boolean isBaseClock;
1174 algorithm
1175 isBaseClock := match eq
1176 local
1177 DAE.ClockKind clk;
1178 case BackendDAE.EQUATION(exp=DAE.CREF(),scalar=DAE.CLKCONST(clk=DAE.INFERRED_CLOCK()))
1179 algorithm
1180 then false;
1181 case BackendDAE.EQUATION(exp=DAE.CREF(),scalar=DAE.CLKCONST())
1182 algorithm
1183 then true;
1184 else
1185 then false;
1186 end match;
1187 end isBaseClockEq;
1188
1189 protected function getBaseClock
1190 input BackendDAE.Equation eq;
1191 output DAE.ClockKind baseClk;
1192 algorithm
1193 baseClk := match eq
1194 local
1195 DAE.ClockKind clk;
1196 case BackendDAE.EQUATION(exp=DAE.CREF(),scalar=DAE.CLKCONST(clk=DAE.INFERRED_CLOCK()))
1197 algorithm
1198 then DAE.INFERRED_CLOCK();
1199 case BackendDAE.EQUATION(exp=DAE.CREF(),scalar=DAE.CLKCONST(clk=clk))
1200 algorithm
1201 then clk;
1202 else
1203 algorithm
1204 then DAE.INFERRED_CLOCK();
1205 end match;
1206 end getBaseClock;
1207
1208 protected function removeEdge
1209 "removes edges in adjacency matrices betwenn equation and variable
1210 author: vwaurich 2017-06"
1211 input Integer eq;
1212 input Integer var;
1213 input BackendDAE.AdjacencyMatrix m;
1214 input BackendDAE.AdjacencyMatrixT mT;
1215 protected
1216 list<Integer> row;
1217 algorithm
1218 21 row := arrayGet(m,eq);
1219 21 row := List.deleteMemberOnTrue(var,row,intEq);
1220 21 arrayUpdate(m,eq,row);
1221 21 row := arrayGet(mT,var);
1222 21 row := List.deleteMemberOnTrue(eq,row,intEq);
1223 21 arrayUpdate(mT,var,row);
1224 end removeEdge;
1225
1226 protected function findBaseClockInterfaces
1227 "gets all equations which define a base clock and all equations which separate sub partitions.
1228 author: vwaurich 2017-06"
1229 input BackendDAE.EquationArray eqs;
1230 input BackendDAE.Variables vars;
1231 input BackendDAE.AdjacencyMatrix m;
1232 input BackendDAE.AdjacencyMatrixT mT;
1233 output list<Integer> clockEqs={};
1234 output list<Integer> subClockInterfaceEqIdxs={};
1235 output list<BackendDAE.Equation> subClockInterfaceEqs = {};
1236 protected
1237 Integer eqIdx;
1238 BackendDAE.Equation eq;
1239 algorithm
1240
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 46 times.
743 for eqIdx in 1:BackendEquation.getNumberOfEquations(eqs) loop
1241 697 eq := BackendEquation.get(eqs,eqIdx);
1242 697 (clockEqs, subClockInterfaceEqIdxs, subClockInterfaceEqs) := findBaseClockInterfaces1(eq, eqIdx, eqs, vars, m, mT, clockEqs, subClockInterfaceEqIdxs, subClockInterfaceEqs);
1243 end for;
1244 end findBaseClockInterfaces;
1245
1246 protected function findBaseClockInterfaces1
1247 "adds the equation to the lost of base clock defining eqs or to the equations which separate sub partitions
1248 author: vwaurich 2017-06"
1249 input BackendDAE.Equation eq;
1250 input Integer eqIdx;
1251 input BackendDAE.EquationArray eqs;
1252 input BackendDAE.Variables vars;
1253 input BackendDAE.AdjacencyMatrix m;
1254 input BackendDAE.AdjacencyMatrixT mT;
1255 input list<Integer> clockEqsIn;
1256 input list<Integer> subClockInterfaceEqIdxsIn;
1257 input list<BackendDAE.Equation> subClockInterfaceEqsIn;
1258 output list<Integer> clockEqsOut;
1259 output list<Integer> subClockInterfaceEqIdxsOut;
1260 output list<BackendDAE.Equation> subClockInterfaceEqsOut;
1261 algorithm
1262 (clockEqsOut, subClockInterfaceEqIdxsOut, subClockInterfaceEqsOut) := match eq
1263 local
1264 DAE.ComponentRef cref1;
1265 Integer varIdx;
1266 list<DAE.Exp> expLst;
1267 case BackendDAE.EQUATION(scalar=DAE.CLKCONST(clk=DAE.INFERRED_CLOCK()))
1268 algorithm
1269 then (eqIdx::clockEqsIn, subClockInterfaceEqIdxsIn, subClockInterfaceEqsIn);
1270
1271 case BackendDAE.EQUATION(scalar=DAE.CLKCONST(clk=DAE.RATIONAL_CLOCK(_)))
1272 algorithm
1273 then (eqIdx::clockEqsIn, subClockInterfaceEqIdxsIn,subClockInterfaceEqsIn);
1274
1275 case BackendDAE.EQUATION(scalar=DAE.CLKCONST(clk=DAE.REAL_CLOCK(_)))
1276 algorithm
1277 then (eqIdx::clockEqsIn, subClockInterfaceEqIdxsIn,subClockInterfaceEqsIn);
1278
1279 case BackendDAE.EQUATION(scalar=DAE.CLKCONST(clk=DAE.EVENT_CLOCK(_)))
1280 algorithm
1281 then (eqIdx::clockEqsIn, subClockInterfaceEqIdxsIn,subClockInterfaceEqsIn);
1282
1283 //solver clocks can act as subpartitioninterfaces since they assign a solver to another clock
1284 case BackendDAE.EQUATION(scalar=DAE.CLKCONST(clk=DAE.SOLVER_CLOCK(DAE.CREF(_),_)))
1285 algorithm
1286 then (clockEqsIn, eqIdx::subClockInterfaceEqIdxsIn, eq::subClockInterfaceEqsIn);
1287
1288 case BackendDAE.EQUATION(scalar=DAE.CLKCONST(clk=DAE.SOLVER_CLOCK(DAE.CLKCONST(_),_)))
1289 algorithm
1290 then (eqIdx::clockEqsIn, subClockInterfaceEqIdxsIn,subClockInterfaceEqsIn);
1291
1292 case BackendDAE.EQUATION(scalar=DAE.CALL(path=Absyn.IDENT("superSample"), expLst={DAE.CREF(componentRef=cref1),_}))
1293 algorithm
1294
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
8 (_,{varIdx}) := BackendVariable.getVar(cref1,vars);
1295 8 removeEdge(eqIdx,varIdx,m,mT);
1296 then (clockEqsIn, eqIdx::subClockInterfaceEqIdxsIn, eq::subClockInterfaceEqsIn);
1297
1298 case BackendDAE.EQUATION(scalar=DAE.CALL(path=Absyn.IDENT("subSample"), expLst={DAE.CREF(componentRef=cref1),_}))
1299 algorithm
1300
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
5 (_,{varIdx}) := BackendVariable.getVar(cref1,vars);
1301 5 removeEdge(eqIdx,varIdx,m,mT);
1302 then (clockEqsIn, eqIdx::subClockInterfaceEqIdxsIn, eq::subClockInterfaceEqsIn);
1303
1304 //shiftSample with 3 arguments
1305 case BackendDAE.EQUATION(scalar=DAE.CALL(path=Absyn.IDENT("shiftSample"), expLst={DAE.CREF(componentRef=cref1),_,_}))
1306 algorithm
1307
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
5 (_,{varIdx}) := BackendVariable.getVar(cref1,vars);
1308 5 removeEdge(eqIdx,varIdx,m,mT);
1309 then (clockEqsIn, eqIdx::subClockInterfaceEqIdxsIn, eq::subClockInterfaceEqsIn);
1310
1311 //shiftSample with 2 arguments
1312 case BackendDAE.EQUATION(scalar=DAE.CALL(path=Absyn.IDENT("shiftSample"), expLst={DAE.CREF(componentRef=cref1),_}))
1313 algorithm
1314 ✗ (_,{varIdx}) := BackendVariable.getVar(cref1,vars);
1315 ✗ removeEdge(eqIdx,varIdx,m,mT);
1316 then (clockEqsIn, eqIdx::subClockInterfaceEqIdxsIn, eq::subClockInterfaceEqsIn);
1317
1318 //Backsample with 3 arguments
1319 case BackendDAE.EQUATION(scalar=DAE.CALL(path=Absyn.IDENT("backSample"), expLst={DAE.CREF(componentRef=cref1),_,_}))
1320 algorithm
1321
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
3 (_,{varIdx}) := BackendVariable.getVar(cref1,vars);
1322 3 removeEdge(eqIdx,varIdx,m,mT);
1323 then (clockEqsIn, eqIdx::subClockInterfaceEqIdxsIn, eq::subClockInterfaceEqsIn);
1324
1325 //Backsample with 2 arguments
1326 case BackendDAE.EQUATION(scalar=DAE.CALL(path=Absyn.IDENT("backSample"), expLst={DAE.CREF(componentRef=cref1),_}))
1327 algorithm
1328 ✗ (_,{varIdx}) := BackendVariable.getVar(cref1,vars);
1329 ✗ removeEdge(eqIdx,varIdx,m,mT);
1330 then (clockEqsIn, eqIdx::subClockInterfaceEqIdxsIn, eq::subClockInterfaceEqsIn);
1331
1332 case BackendDAE.EQUATION()
1333 algorithm
1334 //print("Thats also not a base clock "+BackendDump.equationString(eq)+"\n");
1335 then (clockEqsIn, subClockInterfaceEqIdxsIn, subClockInterfaceEqsIn);
1336 else
1337 algorithm
1338 then (clockEqsIn, subClockInterfaceEqIdxsIn, subClockInterfaceEqsIn);
1339 end match;
1340 end findBaseClockInterfaces1;
1341
1342 protected function findHighestWhenPrefixIdx
1343 "since new $whenClk vars are introduced, determine the highest index to avopid duplicates.
1344 author: vwaurich 2017-06"
1345 input BackendDAE.Var inVar;
1346 input Integer idxIn;
1347 output BackendDAE.Var outVar = inVar;
1348 output Integer idxOut = idxIn;
1349 protected
1350 DAE.ComponentRef name;
1351 list<String> chars, chars1, chars2;
1352 algorithm
1353 637 name := inVar.varName;
1354 637 chars := stringListStringChar(ComponentReference.crefStr(name));
1355
2/2
✓ Branch 1 taken 234 times.
✓ Branch 2 taken 403 times.
637 if intGt(listLength(chars),9) then
1356 403 (chars1,chars2) := List.split(chars,8);
1357
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 403 times.
✓ Branch 5 taken 403 times.
✗ Branch 6 not taken.
403 if stringEq(stringDelimitList(chars1,""), BackendDAE.WHENCLK_PRREFIX) then
1358 ✗ idxOut := intMax(idxIn, stringInt(stringDelimitList(chars2,"")));
1359 end if;
1360 end if;
1361 end findHighestWhenPrefixIdx;
1362
1363 protected function replaceSampledClocks
1364 "Clock contructors inside samples are added as an additional equation in order to separate clocks and dynamic equations if they are still marked as BackendDAE.DYNAMIC_EQUATION.
1365 author: vwaurich 2017-06"
1366 input BackendDAE.EquationArray eqsIn;
1367 input BackendDAE.Variables varsIn;
1368 output BackendDAE.EquationArray eqsOut;
1369 output BackendDAE.Variables varsOut;
1370 protected
1371 Integer prefIdx;
1372 BackendDAE.EquationArray eqs;
1373 list<BackendDAE.Equation> newEqs;
1374 list<BackendDAE.Var> newVars;
1375 algorithm
1376 //get the max $whenclk-Variable in the system in order to use a higher index
1377 46 prefIdx := BackendVariable.traverseBackendDAEVars(varsIn,findHighestWhenPrefixIdx,1);
1378 46 (eqs,(_, _,newEqs, newVars)) := BackendEquation.traverseEquationArray_WithUpdate(eqsIn, replaceSampledClocks1, (varsIn,prefIdx+1,{},{}));
1379 46 eqsOut := BackendEquation.addList(newEqs, eqs);
1380 46 varsOut := BackendVariable.addVars(newVars, varsIn);
1381 end replaceSampledClocks;
1382
1383 protected function replaceSampledClocks1
1384 "author: vwaurich 2017-06"
1385 input BackendDAE.Equation eqIn;
1386 input tuple<BackendDAE.Variables, Integer, list<BackendDAE.Equation>, list<BackendDAE.Var>> tplIn;
1387 output BackendDAE.Equation eqOut;
1388 output tuple<BackendDAE.Variables, Integer, list<BackendDAE.Equation>, list<BackendDAE.Var>> tplOut;
1389 algorithm
1390 (eqOut, tplOut) := match(eqIn,tplIn)
1391 local
1392 Integer suffixIdx,suffixIdx0;
1393 BackendDAE.EquationAttributes attr;
1394 BackendDAE.Variables vars;
1395 DAE.Exp e1,e2;
1396 DAE.ElementSource source;
1397 list<BackendDAE.Equation> newEqs;
1398 list<BackendDAE.Var> newVars;
1399 list<Integer> dimSize;
1400 Option<Integer> recordSize;
1401 case(BackendDAE.EQUATION(e1, e2, source, BackendDAE.EQUATION_ATTRIBUTES(kind=BackendDAE.DYNAMIC_EQUATION())),(vars, suffixIdx0, newEqs, newVars))
1402 algorithm
1403 524 (e1,(newEqs, newVars, suffixIdx)) := Expression.traverseExpTopDown(e1, replaceSampledClocks2, (newEqs, newVars, suffixIdx0));
1404 524 (e2,(newEqs, newVars, suffixIdx)) := Expression.traverseExpTopDown(e2, replaceSampledClocks2, (newEqs, newVars, suffixIdx));
1405
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 464 times.
524 if intEq(suffixIdx-suffixIdx0, 1) then
1406 60 attr := BackendEquation.defaultClockedEqAttr(suffixIdx0);
1407 else
1408 attr := BackendDAE.EQ_ATTR_DEFAULT_DYNAMIC;
1409 end if;
1410 524 then (BackendDAE.EQUATION(e1,e2,source,attr),(vars, suffixIdx, newEqs, newVars));
1411 case(BackendDAE.ARRAY_EQUATION(dimSize, e1, e2, source, BackendDAE.EQUATION_ATTRIBUTES(kind=BackendDAE.DYNAMIC_EQUATION()), recordSize),(vars, suffixIdx0, newEqs, newVars))
1412 algorithm
1413 ✗ (e1,(newEqs, newVars, suffixIdx)) := Expression.traverseExpTopDown(e1, replaceSampledClocks2, (newEqs, newVars, suffixIdx0));
1414 ✗ (e2,(newEqs, newVars, suffixIdx)) := Expression.traverseExpTopDown(e2, replaceSampledClocks2, (newEqs, newVars, suffixIdx));
1415 ✗ if intEq(suffixIdx - suffixIdx0, 1) then
1416 ✗ attr := BackendEquation.defaultClockedEqAttr(suffixIdx0);
1417 else
1418 attr := BackendDAE.EQ_ATTR_DEFAULT_DYNAMIC;
1419 end if;
1420 ✗ then (BackendDAE.ARRAY_EQUATION(dimSize, e1, e2, source, attr, recordSize), (vars, suffixIdx, newEqs, newVars));
1421 else
1422 algorithm
1423 then (eqIn,tplIn);
1424 end match;
1425 end replaceSampledClocks1;
1426
1427 protected function replaceSampledClocks2
1428 "author: vwaurich 2017-06"
1429 input DAE.Exp inExp;
1430 input tuple<list<BackendDAE.Equation>, list<BackendDAE.Var>, Integer> tplIn;//<addEq, addVar, suffixIdx>
1431 output DAE.Exp outExp;
1432 output Boolean cont;
1433 output tuple<list<BackendDAE.Equation>, list<BackendDAE.Var>, Integer> tplOut;//<addEq, addVar, suffixIdx>
1434 algorithm
1435 (outExp,cont, tplOut) := match(inExp,tplIn)
1436 local
1437 Integer suffixIdx;
1438 DAE.ComponentRef cr;
1439 DAE.Exp varExp, clk;
1440 BackendDAE.Equation addEq;
1441 BackendDAE.Var addVar;
1442 list<BackendDAE.Equation> newEqs;
1443 list<BackendDAE.Var> newVars;
1444 case(DAE.CALL(path=Absyn.IDENT("sample"), expLst={varExp as DAE.CREF(_), clk as DAE.CLKCONST(_)}),(newEqs,newVars,suffixIdx))
1445 algorithm
1446 60 cr := DAE.CREF_IDENT(BackendDAE.WHENCLK_PRREFIX + intString(suffixIdx), DAE.T_CLOCK_DEFAULT, {});
1447 60 addVar := BackendVariable.makeVar(cr);
1448 60 addEq := BackendDAE.EQUATION(Expression.crefToExp(cr), clk, DAE.emptyElementSource, BackendDAE.EQ_ATTR_DEFAULT_DYNAMIC);
1449 60 then(substGetPartition(varExp), false, (addEq::newEqs, addVar::newVars, suffixIdx+1));
1450 else
1451 then (inExp, true, tplIn);
1452 end match;
1453 end replaceSampledClocks2;
1454
1455 protected function subClockPartitioning
1456 "Does sub-partitioning for base partition and get base clock
1457 and vars, equations and sub-clocks of subpartitions.
1458 author: vwaurich 2017-06"
1459 input BackendDAE.EqSystem inEqSystem;
1460 input BackendDAE.Shared inShared;
1461 input Integer off;
1462 output list<BackendDAE.EqSystem> outSysts;
1463 output DAE.ClockKind outBaseClock;
1464 output list<BackendDAE.SubClock> outSubClocks;
1465 protected
1466 AvlTreePathFunction.Tree funcs;
1467 BackendDAE.EquationArray eqs, remEqs, clockEqs;
1468 BackendDAE.Variables vars, clockVars;
1469 BackendDAE.AdjacencyMatrix m, mT, rm, rmT;
1470 Integer partitionsCnt;
1471 array<Integer> remEqPartMap;
1472 list<BackendDAE.Equation> newClockEqs;
1473 list<BackendDAE.Var> newClockVars;
1474 array<Option<Boolean>> contPartitions;
1475 array<Integer> subclksCnt;
1476 array<Integer> order;
1477 array<BackendDAE.SubClock> subclocks;
1478 array<Boolean> clockedEqsMask, clockedVarsMask, usedVars, usedRemovedVars;
1479
1480 Integer baseClockEqIdx,eqIdx,varIdx;
1481 list<Integer> baseClockEquations, subClockInterfaceEqIdxs;
1482 list<BackendDAE.Equation> subClockInterfaceEqs;
1483 array<Integer> varPartMap, eqPartMap;
1484 array<list<tuple<Integer,BackendDAE.SubClock>>> partAdjacency;//idx: partition, entries: connections to other partitions with subclocks
1485 BackendDAE.EqSystem sys;
1486 algorithm
1487 46 funcs := BackendDAEUtil.getFunctions(inShared);
1488 46 BackendDAE.EQSYSTEM(orderedVars = vars, orderedEqs = eqs, removedEqs = remEqs) := inEqSystem;
1489
1490 //separate clock-constructors from dynamic equations, e.g. x = sample(time, Clock(0.1)) -> x=time [clocked(whenclk1)]; whenclk1=Clock(0.1);
1491 46 (eqs,vars) := replaceSampledClocks(eqs,vars);
1492 46 sys := BackendDAEUtil.setEqSystVars(inEqSystem, vars);
1493 46 sys := BackendDAEUtil.setEqSystEqs(sys, eqs);
1494
1495 //get adjacency matrix
1496 92 (sys, m, mT) := BackendDAEUtil.getAdjacencyMatrix(sys, BackendDAE.SUBCLOCK_IDX(), SOME(funcs), BackendDAEUtil.isInitializationDAE(inShared));
1497
1498 //find baseclocks and sub partition interfaces, remove edges in adjacency matrices for sub partition interfaces
1499 46 (baseClockEquations, subClockInterfaceEqIdxs, subClockInterfaceEqs) := findBaseClockInterfaces(eqs,vars,m,mT);
1500 //print("all baseClockEquations "+stringDelimitList(List.map(baseClockEquations,intString),", ")+"\n");
1501 //print("all subClockInterfaceEqIdxs "+stringDelimitList(List.map(subClockInterfaceEqIdxs,intString),", ")+"\n");
1502 //BackendDump.dumpBipartiteGraphEqSystem(sys, inShared, "Synchronous_"+intString(off));
1503
1504 //old implementation, used for partitioning
1505 46 (clockEqs, clockedEqsMask) := splitClockEqs(eqs); //masks false if clock equation
1506 46 (clockVars, clockedVarsMask) := splitClockVars(vars);
1507 92 (rm, rmT) := BackendDAEUtil.removedAdjacencyMatrix(sys, BackendDAE.SUBCLOCK_IDX(), SOME(funcs), BackendDAEUtil.isInitializationDAE(inShared));
1508
1509 //partitioning of equations and variables
1510 46 remEqPartMap := arrayCreate(arrayLength(rm), 0);
1511
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
92 eqPartMap := arrayCreate(arrayLength(m), 0);
1512
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
92 varPartMap := arrayCreate(arrayLength(mT), 0);
1513
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
92 usedRemovedVars := arrayCreate(arrayLength(rmT), false);
1514
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
92 usedVars := arrayCreate(arrayLength(mT), false);
1515 46 partitionsCnt := partitionIndependentBlocksMasked(m, mT, rm, rmT, arrayCreate(BackendEquation.getNumberOfEquations(eqs), true), eqPartMap, varPartMap, remEqPartMap, usedVars, usedRemovedVars);
1516 /*
1517 print("eqPartMap "+stringDelimitList(List.mapArray(eqPartMap,intString)," | ")+"\n");
1518 print("varPartMap "+stringDelimitList(List.mapArray(varPartMap,intString)," | ")+"\n");
1519 print("partitionsCnt :"+intString(partitionsCnt)+"\n");
1520 varAtts := {};
1521 eqAtts := {};
1522 for i in 1:arrayLength(eqPartMap) loop
1523 print("eq "+intString(i)+" is partition "+intString(arrayGet(eqPartMap,i))+"\n");
1524 eqAtts := (false, "p"+intString(arrayGet(eqPartMap,i)))::eqAtts;
1525 end for;
1526 for i in 1:arrayLength(varPartMap) loop
1527 print("var "+intString(i)+" is partition "+intString(arrayGet(varPartMap,i))+"\n");
1528 varAtts := (false, "p"+intString(arrayGet(varPartMap,i)))::varAtts;
1529 end for;
1530 BackendDump.dumpBipartiteGraphStrongComponent2(vars,eqs,m,listReverse(varAtts),listReverse(eqAtts),"BipartiteGraph_SynchronousPart_"+intString(off));
1531 */
1532
1533 //find the defining base clock
1534 46 (outBaseClock,baseClockEqIdx) := chooseBaseClock(baseClockEquations, partitionsCnt, eqPartMap, eqs);
1535 //print("base clock equation "+intString(baseClockEqIdx)+" "+DAEDump.clockKindString(outBaseClock)+"\n");
1536
1537 // and get adjacency matrix for subpartitions, remove the sample()-vars first since they are not handled as connections (necessary to get the right order)
1538 46 (partAdjacency,order) := getSubPartitionAdjacency(partitionsCnt, baseClockEqIdx, subClockInterfaceEqIdxs, eqPartMap, varPartMap, clockedVarsMask, eqs, vars);
1539 //print("order "+stringDelimitList(List.mapArray(order,intString)," | ")+"\n");
1540
1541 //Detect clocked continuous partitions and create new subclock equations
1542 92 (m, mT) := BackendDAEUtil.adjacencyMatrixMasked(inEqSystem, BackendDAE.SUBCLOCK_IDX(), clockedEqsMask, SOME(funcs), BackendDAEUtil.isInitializationDAE(inShared));
1543 46 (newClockEqs, newClockVars, contPartitions, subclksCnt)
1544 := collectSubclkInfo(eqs, inEqSystem.removedEqs, partitionsCnt, eqPartMap, remEqPartMap, vars, mT);
1545
1546 //propagate subclocks across the system, consider solver clocks
1547 46 (outBaseClock, subclocks) := findSubClocks(partitionsCnt, baseClockEqIdx, outBaseClock, baseClockEquations, subClockInterfaceEqIdxs, eqPartMap, varPartMap, eqs, partAdjacency);
1548 /*
1549 for i in 1:arrayLength(subclocks) loop
1550 print("partition "+intString(i)+" has subClock "+BackendDump.subClockString(arrayGet(subclocks,i))+"\n");
1551 end for;
1552 */
1553
1554 //dont consider the clock-contructor calls as equations for the system
1555
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
743 for eqIdx in 1:arrayLength(clockedEqsMask) loop
1556
2/2
✓ Branch 1 taken 172 times.
✓ Branch 2 taken 525 times.
697 if not arrayGet(clockedEqsMask,eqIdx) then arrayUpdate(eqPartMap,eqIdx,0); end if;
1557 end for;
1558
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
742 for varIdx in 1:arrayLength(clockedVarsMask) loop
1559
2/2
✓ Branch 1 taken 171 times.
✓ Branch 2 taken 525 times.
696 if not arrayGet(clockedVarsMask,varIdx) then arrayUpdate(varPartMap,varIdx,0); end if;
1560 end for;
1561
1562 //get the equations and variables for the subpartitions
1563 46 (outSysts, outSubClocks) := orderSubPartitions(partitionsCnt, subclocks, order, eqPartMap, varPartMap, remEqPartMap, eqs, vars, remEqs, inShared, off);
1564 //print("outSubClocks: \n"+stringDelimitList(List.map(outSubClocks,BackendDump.subClockString),"\n")+"\n");
1565 //BackendDump.dumpEqSystems(outSysts, "outSysts");
1566 //BackendDump.dumpBipartiteGraphEqSystem(listHead(outSysts), inShared, "SynchronousDone"+intString(off));
1567 end subClockPartitioning;
1568
1569 protected function orderSubPartitions
1570 "collects equations and vars for subpartitions, brings them in the execution order and merges subsequent partitions with the same sub clock.
1571 author: vwaurich 2017-06"
1572 input Integer numParts;
1573 input array<BackendDAE.SubClock> subclocks;
1574 input array<Integer> order;
1575 input array<Integer> eqPartMap;
1576 input array<Integer> varPartMap;
1577 input array<Integer> remEqPartMap;
1578 input BackendDAE.EquationArray eqs;
1579 input BackendDAE.Variables vars;
1580 input BackendDAE.EquationArray remEqs;
1581 input BackendDAE.Shared shared;
1582 input Integer partitionOffset;
1583 output list<BackendDAE.EqSystem> systs = {};
1584 output list<BackendDAE.SubClock> subClksOut = {};
1585 protected
1586 Boolean considerRemovedEqs;
1587 Integer part;
1588 list<Integer> mergedParts;
1589 array<list<Integer>> partVarMap,partEqMap,partRemEqMap;
1590 BackendDAE.EqSystem sys;
1591 BackendDAE.SubClock clk,clk2;
1592 list<BackendDAE.Equation> eqLst, remEqLst;
1593 list<BackendDAE.Var> varLst;
1594 list<list<Integer>> mergedOrder;
1595 algorithm
1596 considerRemovedEqs := intGe(arrayLength(remEqPartMap),1);
1597
1598 //build mapping between partition and variables
1599 46 partVarMap := arrayCreate(numParts, {});
1600
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
742 for varIdx in 1:arrayLength(varPartMap) loop
1601 696 part := arrayGet(varPartMap,varIdx);
1602
2/2
✓ Branch 0 taken 525 times.
✓ Branch 1 taken 171 times.
696 if part > 0 then
1603 525 arrayUpdate(partVarMap, part, listAppend(partVarMap[part], {varIdx}));//array append list at idx
1604 end if;
1605 end for;
1606
1607 //build mapping between partitions and equations
1608 46 partEqMap := arrayCreate(numParts, {});
1609
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
743 for eqIdx in 1:arrayLength(eqPartMap) loop
1610 697 part := arrayGet(eqPartMap,eqIdx);
1611
2/2
✓ Branch 0 taken 525 times.
✓ Branch 1 taken 172 times.
697 if part > 0 then
1612 525 arrayUpdate(partEqMap, part, listAppend(partEqMap[part], {eqIdx}));//array append list at idx
1613 end if;
1614 end for;
1615
1616 //build mapping between partitions and removed equations
1617 46 partRemEqMap := arrayCreate(numParts, {});
1618
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 if considerRemovedEqs then
1619 ✗ for reqIdx in 1:arrayLength(partRemEqMap) loop
1620 ✗ part := arrayGet(remEqPartMap,reqIdx);
1621 ✗ if part > 0 then
1622 ✗ arrayUpdate(partRemEqMap, part, listAppend(partRemEqMap[part], {reqIdx}));//array append list at idx
1623 end if;
1624 end for;
1625 end if;
1626
1627 //merge partitions in subsequent order with same subclocks
1628 mergedOrder := {};
1629 mergedParts :={};
1630 46 clk := arrayGet(subclocks,order[1]);
1631
2/2
✓ Branch 1 taken 67 times.
✓ Branch 2 taken 46 times.
113 for part in order loop
1632 67 clk2 := arrayGet(subclocks,part);
1633
2/2
✓ Branch 1 taken 46 times.
✓ Branch 2 taken 21 times.
67 if subClkEqual(clk,clk2) then
1634 //these 2 partitions have the same subclock, put them in one partition
1635 mergedParts := part::mergedParts;
1636 else
1637 //this partition has a different subclock
1638 21 mergedOrder := listReverse(mergedParts)::mergedOrder;
1639 mergedParts := {part};
1640 21 clk := arrayGet(subclocks,part);
1641 end if;
1642 end for;
1643 46 mergedOrder := listReverse(mergedParts)::mergedOrder;
1644 46 mergedOrder := listReverse(mergedOrder);
1645
1646 part := 1;
1647 //build equation systems for ordered sub partitions
1648
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 46 times.
113 for mergedParts in mergedOrder loop
1649 eqLst := {};
1650 varLst := {};
1651 remEqLst := {};
1652
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 67 times.
134 for partIdx in mergedParts loop
1653
2/2
✓ Branch 1 taken 525 times.
✓ Branch 2 taken 67 times.
592 for e in arrayGet(partEqMap, partIdx) loop
1654 525 eqLst := BackendEquation.get(eqs,e)::eqLst;
1655 end for;
1656
2/2
✓ Branch 1 taken 525 times.
✓ Branch 2 taken 67 times.
592 for v in arrayGet(partVarMap, partIdx) loop
1657 525 varLst := BackendVariable.getVarAt(vars,v)::varLst;
1658 end for;
1659
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 67 times.
67 for r in arrayGet(partRemEqMap, partIdx) loop
1660 ✗ remEqLst := BackendEquation.get(remEqs,r)::remEqLst;
1661 end for;
1662 67 clk := arrayGet(subclocks,partIdx);
1663 end for;
1664
3/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
67 if not listEmpty(eqLst) or not listEmpty(remEqLst) then
1665 61 (sys, _) := createEqSystem(listReverse(eqLst), listReverse(varLst), remEqLst, (true, true));
1666 //sys := BackendDAEUtil.sortEqnsDAEWork(sys,shared);
1667 122 sys.partitionKind := BackendDAE.CLOCKED_PARTITION(partitionOffset+part);
1668 subClksOut := clk::subClksOut;
1669 systs := sys::systs;
1670 61 part := part+1;
1671 end if;
1672 end for;
1673 //reverse system order due to listappending
1674 46 systs := listReverse(systs);
1675 46 subClksOut := listReverse(subClksOut);
1676 end orderSubPartitions;
1677
1678 protected function isInferedSubClock
1679 input BackendDAE.SubClock subClk;
1680 output Boolean isInfered;
1681 algorithm
1682 isInfered := match subClk
1683 case BackendDAE.INFERED_SUBCLOCK()
1684 then true;
1685 else
1686 false;
1687 end match;
1688 end isInferedSubClock;
1689
1690 protected function isInferedBaseClock
1691 input DAE.ClockKind subClk;
1692 output Boolean isInfered;
1693 algorithm
1694 isInfered := match subClk
1695 case DAE.INFERRED_CLOCK()
1696 then true;
1697 else
1698 false;
1699 end match;
1700 end isInferedBaseClock;
1701
1702 protected function setFactor
1703 input MMath.Rational oldVal;
1704 input MMath.Rational newVal;
1705 output MMath.Rational outVal;
1706 algorithm
1707 outVal := match (oldVal, newVal)
1708 case (MMath.RATIONAL(1, 1), _) then newVal;
1709 case (_, MMath.RATIONAL(1, 1)) then oldVal;
1710 else
1711 algorithm
1712 ✗ if not MMath.equals(oldVal, newVal) then
1713 ✗ Error.addMessage(Error.SUBCLOCK_CONFLICT, {"factor", MMath.rationalString(oldVal), MMath.rationalString(newVal)});
1714 ✗ fail();
1715 end if;
1716 then newVal;
1717 end match;
1718 end setFactor;
1719
1720 protected function setShift
1721 input MMath.Rational oldVal;
1722 input MMath.Rational newVal;
1723 output MMath.Rational outVal;
1724 algorithm
1725 outVal := match (oldVal, newVal)
1726 case (MMath.RATIONAL(0, _), _) then newVal;
1727 case (_, MMath.RATIONAL(0, _)) then oldVal;
1728 else
1729 algorithm
1730 ✗ if not MMath.equals(oldVal, newVal) then
1731 ✗ Error.addMessage(Error.SUBCLOCK_CONFLICT, {"shift", MMath.rationalString(oldVal), MMath.rationalString(newVal)});
1732 ✗ fail();
1733 end if;
1734 then newVal;
1735 end match;
1736 end setShift;
1737
1738 protected function collectSubclkInfoExp
1739 input DAE.Exp inExp;
1740 input tuple< list<BackendDAE.Equation>, list<BackendDAE.Var>, array<Option<Boolean>>, SourceInfo,
1741 array<Integer>, Integer, array<Integer>, BackendDAE.Variables, BackendDAE.AdjacencyMatrix > inTpl;
1742 output DAE.Exp outExp;
1743 output tuple< list<BackendDAE.Equation>, list<BackendDAE.Var>, array<Option<Boolean>>, SourceInfo,
1744 array<Integer>, Integer, array<Integer>, BackendDAE.Variables, BackendDAE.AdjacencyMatrix > outTpl;
1745 protected
1746 list<BackendDAE.Equation> newEqs;
1747 list<BackendDAE.Var> newVars;
1748 array<Option<Boolean>> contPartitions;
1749 Integer partitionIdx;
1750 array<Integer> partitions;
1751 BackendDAE.Variables vars;
1752 BackendDAE.AdjacencyMatrix mT;
1753 Absyn.Path path;
1754 list<DAE.Exp> expLst;
1755 DAE.CallAttributes attr;
1756 array<Integer> clksCnt;
1757 Integer clkCnt;
1758 SourceInfo source;
1759 algorithm
1760 4245 (newEqs, newVars, contPartitions, source, clksCnt, partitionIdx, partitions, vars, mT) := inTpl;
1761 4245 clkCnt := arrayGet(clksCnt, partitionIdx);
1762 (outExp, newEqs, newVars, clkCnt) := match inExp
1763 case DAE.CALL(path, expLst, attr)
1764 433 then
1765 collectSubclkInfoCall( path, expLst, attr, newEqs, newVars, contPartitions, partitionIdx, clkCnt,
1766 partitions, vars, mT, source );
1767 3812 else
1768 (inExp, newEqs, newVars, clkCnt);
1769 end match;
1770 4245 arrayUpdate(clksCnt, partitionIdx, clkCnt);
1771 4245 outTpl := (newEqs, newVars, contPartitions, source, clksCnt, partitionIdx, partitions, vars, mT);
1772 end collectSubclkInfoExp;
1773
1774 protected function createSubClockVar
1775 input Integer inPartitionIdx;
1776 input Integer inClkCnt;
1777 input Absyn.Path inPath;
1778 input list<DAE.Exp> inExpLst;
1779 input DAE.CallAttributes inAttr;
1780 input array<Integer> inPartitions;
1781 input BackendDAE.Variables inVars;
1782 input BackendDAE.AdjacencyMatrix mT;
1783 output BackendDAE.Var outVar;
1784 output BackendDAE.Equation outEq;
1785 protected
1786 DAE.ComponentRef cr;
1787 list<Integer> varIxs;
1788 Integer i;
1789 DAE.Exp e, subclk;
1790 algorithm
1791 ✗ DAE.CREF(componentRef = cr) := listHead(inExpLst);
1792 ✗ (_, varIxs) := BackendVariable.getVar(cr, inVars);
1793 ✗ i := listHead(varIxs);
1794 ✗ i := listHead(arrayGet(mT, i)) "Equation idx, containing var";
1795 ✗ i := arrayGet(inPartitions, i) "Partitions, from which var get";
1796 ✗ subclk := DAE.CREF(getSubClkName(i, 1), DAE.T_CLOCK_DEFAULT);
1797 ✗ e := DAE.CALL(inPath, subclk::listRest(inExpLst), inAttr);
1798 ✗ (outVar, outEq) := createSubClock(inPartitionIdx, inClkCnt, e);
1799 end createSubClockVar;
1800
1801 protected function setContClockedPartition
1802 input Boolean inIsContClockedPartition;
1803 input Integer inPartitionIdx;
1804 input array<Option<Boolean>> inContPartitions;
1805 input SourceInfo source;
1806 protected
1807 Option<Boolean> isContClockedPartition;
1808 Boolean isContClockedPrevPartition;
1809 algorithm
1810 299 isContClockedPartition := arrayGet(inContPartitions, inPartitionIdx);
1811 isContClockedPartition := match isContClockedPartition
1812
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 2 times.
37 case NONE() then
1813 SOME(inIsContClockedPartition);
1814
2/2
✓ Branch 0 taken 258 times.
✓ Branch 1 taken 4 times.
262 case SOME(isContClockedPrevPartition) then
1815 SOME(inIsContClockedPartition or isContClockedPrevPartition);
1816 end match;
1817 299 arrayUpdate(inContPartitions, inPartitionIdx, isContClockedPartition);
1818 end setContClockedPartition;
1819
1820 protected function collectSubclkInfoCall
1821 input Absyn.Path inPath;
1822 input list<DAE.Exp> inExpLst;
1823 input DAE.CallAttributes inAttr;
1824 input list<BackendDAE.Equation> inNewEqs;
1825 input list<BackendDAE.Var> inNewVars;
1826 input array<Option<Boolean>> inContPartitions;
1827 input Integer inPartitionIdx;
1828 input Integer inClkCnt;
1829 input array<Integer> inPartitions;
1830 input BackendDAE.Variables inVars;
1831 input BackendDAE.AdjacencyMatrix mT;
1832 input SourceInfo source;
1833 output DAE.Exp outExp;
1834 output list<BackendDAE.Equation> outNewEqs;
1835 output list<BackendDAE.Var> outNewVars;
1836 output Integer outClkCnt;
1837 algorithm
1838 (outExp, outNewEqs, outNewVars, outClkCnt) := match (inPath, listLength(inExpLst))
1839 local
1840 BackendDAE.Var var;
1841 BackendDAE.Equation eq;
1842 case (Absyn.IDENT("der"), _)
1843 algorithm
1844 4 setContClockedPartition(true, inPartitionIdx, inContPartitions, source);
1845 4 then
1846 (DAE.CALL(inPath, inExpLst, inAttr), inNewEqs, inNewVars, inClkCnt);
1847 case (Absyn.IDENT("delay"), _)
1848 algorithm
1849 ✗ setContClockedPartition(true, inPartitionIdx, inContPartitions, source);
1850 ✗ then
1851 (DAE.CALL(inPath, inExpLst, inAttr), inNewEqs, inNewVars, inClkCnt);
1852 case (Absyn.IDENT("spatialDistribution"), _)
1853 algorithm
1854 ✗ setContClockedPartition(true, inPartitionIdx, inContPartitions, source);
1855 ✗ then
1856 (DAE.CALL(inPath, inExpLst, inAttr), inNewEqs, inNewVars, inClkCnt);
1857 case (Absyn.IDENT("initial"), _)
1858 algorithm
1859 ✗ setContClockedPartition(true, inPartitionIdx, inContPartitions, source);
1860 ✗ then
1861 (DAE.CALL(inPath, inExpLst, inAttr), inNewEqs, inNewVars, inClkCnt);
1862 case (Absyn.IDENT("terminal"), _)
1863 algorithm
1864 ✗ setContClockedPartition(true, inPartitionIdx, inContPartitions, source);
1865 ✗ then
1866 (DAE.CALL(inPath, inExpLst, inAttr), inNewEqs, inNewVars, inClkCnt);
1867 case (Absyn.IDENT("smooth"), _)
1868 algorithm
1869 ✗ setContClockedPartition(true, inPartitionIdx, inContPartitions, source);
1870 ✗ then
1871 (DAE.CALL(inPath, inExpLst, inAttr), inNewEqs, inNewVars, inClkCnt);
1872 case (Absyn.IDENT("sample"), 3)
1873 algorithm
1874 ✗ setContClockedPartition(true, inPartitionIdx, inContPartitions, source);
1875 ✗ then
1876 (DAE.CALL(inPath, inExpLst, inAttr), inNewEqs, inNewVars, inClkCnt);
1877 case (Absyn.IDENT("pre"), _)
1878 algorithm
1879 ✗ setContClockedPartition(true, inPartitionIdx, inContPartitions, source);
1880 ✗ then
1881 (DAE.CALL(inPath, inExpLst, inAttr), inNewEqs, inNewVars, inClkCnt);
1882 case (Absyn.IDENT("edge"), _)
1883 algorithm
1884 ✗ setContClockedPartition(true, inPartitionIdx, inContPartitions, source);
1885 ✗ then
1886 (DAE.CALL(inPath, inExpLst, inAttr), inNewEqs, inNewVars, inClkCnt);
1887 case (Absyn.IDENT("change"), _)
1888 algorithm
1889 ✗ setContClockedPartition(true, inPartitionIdx, inContPartitions, source);
1890 ✗ then
1891 (DAE.CALL(inPath, inExpLst, inAttr), inNewEqs, inNewVars, inClkCnt);
1892 case (Absyn.IDENT("reinit"), _)
1893 algorithm
1894 ✗ setContClockedPartition(true, inPartitionIdx, inContPartitions, source);
1895 ✗ then
1896 (DAE.CALL(inPath, inExpLst, inAttr), inNewEqs, inNewVars, inClkCnt);
1897
1898 case (Absyn.IDENT("previous"), _)
1899 algorithm
1900 277 setContClockedPartition(false, inPartitionIdx, inContPartitions, source);
1901 277 then
1902 (DAE.CALL(inPath, inExpLst, inAttr), inNewEqs, inNewVars, inClkCnt);
1903 case (Absyn.IDENT("firstTick"), _)
1904 algorithm
1905 4 setContClockedPartition(false, inPartitionIdx, inContPartitions, source);
1906 4 then
1907 // Note: remove optional argument (inExpLst) to avoid algebraic loop
1908 (DAE.CALL(inPath, {}, inAttr), inNewEqs, inNewVars, inClkCnt);
1909 case (Absyn.IDENT("interval"), _)
1910 algorithm
1911 14 setContClockedPartition(false, inPartitionIdx, inContPartitions, source);
1912 14 then
1913 // Note: remove optional argument (inExpLst) to avoid algebraic loop
1914 (DAE.CALL(inPath, {}, inAttr), inNewEqs, inNewVars, inClkCnt);
1915
1916 case (Absyn.IDENT("sample"), 2)
1917 algorithm
1918 29 (var, eq) := createSubClock(inPartitionIdx, inClkCnt, listGet(inExpLst, 2));
1919 58 then
1920 (substGetPartition(listGet(inExpLst, 1)), eq::inNewEqs, var::inNewVars, inClkCnt + 1);
1921 case (Absyn.IDENT("subSample"), 2)
1922 5 then
1923 (substGetPartition(listGet(inExpLst, 1)), inNewEqs, inNewVars, inClkCnt + 1);
1924
1925 case (Absyn.IDENT("superSample"), 2)
1926 8 then
1927 (substGetPartition(listGet(inExpLst, 1)), inNewEqs, inNewVars, inClkCnt + 1);
1928
1929
1930 case (Absyn.IDENT("shiftSample"), 3)
1931 5 then
1932 (substGetPartition(listGet(inExpLst, 1)), inNewEqs, inNewVars, inClkCnt + 1);
1933
1934 case (Absyn.IDENT("backSample"), 3)
1935 3 then
1936 (substGetPartition(listGet(inExpLst, 1)), inNewEqs, inNewVars, inClkCnt + 1);
1937
1938 case (Absyn.IDENT("noClock"), 1)
1939 ✗ then
1940 (substGetPartition(listGet(inExpLst, 1)), inNewEqs, inNewVars, inClkCnt);
1941 84 else
1942 (DAE.CALL(inPath, inExpLst, inAttr), inNewEqs, inNewVars, inClkCnt);
1943 end match;
1944 end collectSubclkInfoCall;
1945
1946 protected function createSubClockVarFactor
1947 input Integer inPartitionIdx;
1948 input Integer inClkCnt;
1949 input Absyn.Path inPath;
1950 input list<DAE.Exp> inExpLst;
1951 input DAE.CallAttributes inAttr;
1952 input array<Integer> inPartitions;
1953 input BackendDAE.Variables inVars;
1954 input BackendDAE.AdjacencyMatrix mT;
1955 input list<BackendDAE.Equation> inNewEqs;
1956 input list<BackendDAE.Var> inNewVars;
1957 output DAE.Exp outExp;
1958 output list<BackendDAE.Equation> outNewEqs = inNewEqs;
1959 output list<BackendDAE.Var> outNewVars = inNewVars;
1960 output Integer outClkCnt = inClkCnt;
1961 algorithm
1962 ✗ outExp := substGetPartition(listHead(inExpLst));
1963 //To do this, the eqPartMap has to exclude the subPartition interfaces. Anyway, its not used anymore
1964 /*
1965 (outExp, outNewEqs, outNewVars, outClkCnt) := match listGet(inExpLst, 2)
1966 local
1967 BackendDAE.Var var;
1968 BackendDAE.Equation eq;
1969 case DAE.ICONST(0)
1970 then (e, inNewEqs, inNewVars, inClkCnt);
1971 else
1972 algorithm
1973 (var, eq) = createSubClockVar(inPartitionIdx, inClkCnt, inPath, inExpLst, inAttr, inPartitions, inVars, mT);
1974 then
1975 (e, eq::inNewEqs, var::inNewVars, inClkCnt + 1);
1976 end match;
1977 */
1978 end createSubClockVarFactor;
1979
1980 protected function substGetPartition
1981 input DAE.Exp inExp;
1982 output DAE.Exp outExp;
1983 protected
1984 DAE.CallAttributes attrs;
1985 algorithm
1986 125 attrs := DAE.CALL_ATTR(Expression.typeof(inExp), false, true, true, false, DAE.NO_INLINE(), DAE.NO_TAIL(), DAE.NoReturn.RETURNS);
1987 125 outExp := DAE.CALL(Absyn.IDENT("$getPart"), {inExp}, attrs);
1988 end substGetPartition;
1989
1990 protected function getSubClkName
1991 input Integer inPartitionIdx;
1992 input Integer inClkIdx;
1993 input DAE.Type inTy = DAE.T_CLOCK_DEFAULT;
1994 output DAE.ComponentRef outRef;
1995 protected
1996 String name;
1997 algorithm
1998 140 name := "$subclk" + intString(inPartitionIdx) + "_" + intString(inClkIdx);
1999 140 outRef := DAE.CREF_IDENT(name, inTy, {});
2000 end getSubClkName;
2001
2002 protected function createSubClock
2003 input Integer inPartitionIdx;
2004 input Integer inCnt;
2005 input DAE.Exp inExp;
2006 output BackendDAE.Var outVar;
2007 output BackendDAE.Equation outEq;
2008 protected
2009 DAE.Type ty;
2010 DAE.ComponentRef cr;
2011 algorithm
2012 ty := DAE.T_CLOCK_DEFAULT;
2013 140 cr := getSubClkName(inPartitionIdx, inCnt, ty);
2014 140 (outVar, outEq) := createEqVarPair(cr, ty, inExp);
2015 end createSubClock;
2016
2017 protected function collectSubclkInfo
2018 "Create new clock equations and variables from equations:
2019 - r = sample(e, clk) -- clockVar: $subclki_n; clockEq: $subclki_n = clk; eq: r = $getPart(e);
2020 - r = subSample(e, e1) -- clockVar: $subclki_n; clockEq: $subclki_n = subSample($subclkj_1, e1); eq: r = $getPart(e);
2021 - r = shiftSample(e, e1, e2) -- clockVar: $subclki_n; clockEq: $subclki_n = shiftSample($subclkj_1, e1, e2); eq: r = $getPart(e);
2022 - r = backSample(e, e1, e2) -- clockVar: $subclki_n; clockEq: $subclki_n = backSample($subclkj_1, e1, e2); eq: r = $getPart(e);
2023 - r = noClock(e) -- eq: r = $getPart(e);
2024 where subclki_n -- n subclock of partition, which r expression belongs;
2025 subclkj_n -- n subclock of partition, which e expression belongs;
2026 clockVar, clockEq -- new clock variables and equations;
2027 eq -- replaced equation.
2028 Detect clocked continuous partitions according the rule:
2029 If equation contains operator der, delay, spatialDistribution, event related operators
2030 , or when clause, it is a clocked continuous equation.
2031 If a clocked partition is not a clocked continuous partition and it contains operator previous
2032 , or interval, it is a clocked discrete equation."
2033 input BackendDAE.EquationArray inEqs;
2034 input BackendDAE.EquationArray inRemovedEqs;
2035 input Integer inPartitionCnt;
2036 input array<Integer> inPartitions;
2037 input array<Integer> inReqsPartitions;
2038 input BackendDAE.Variables inVars;
2039 input BackendDAE.AdjacencyMatrix mT;
2040 output list<BackendDAE.Equation> outNewEqs;
2041 output list<BackendDAE.Var> outNewVars;
2042 output array<Option<Boolean>> outContPartitions;
2043 output array<Integer> oClksCnt;
2044 protected
2045 BackendDAE.Equation eq;
2046 Integer i, j, cnt;
2047 BackendDAE.Equation eq;
2048 DAE.ComponentRef cr;
2049 BackendDAE.Var var;
2050 array<list<Integer>> partitionsWhenClocks;
2051 algorithm
2052 46 outContPartitions := arrayCreate(inPartitionCnt, NONE());
2053 46 partitionsWhenClocks := arrayCreate(inPartitionCnt, {});
2054 46 oClksCnt := arrayCreate(inPartitionCnt, 1);
2055
2056 46 (outNewEqs, outNewVars) := collectEquationArrayClocks (
2057 inEqs, inPartitionCnt, inPartitions, partitionsWhenClocks, oClksCnt,
2058 outContPartitions, inVars, mT, {}, {}
2059 );
2060 46 (outNewEqs, outNewVars) := collectEquationArrayClocks (
2061 inRemovedEqs, inPartitionCnt, inReqsPartitions, partitionsWhenClocks, oClksCnt,
2062 outContPartitions, inVars, mT, outNewEqs, outNewVars
2063 );
2064
2065
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
113 for i in 1:inPartitionCnt loop
2066
2/2
✓ Branch 1 taken 105 times.
✓ Branch 2 taken 67 times.
172 for j in arrayGet(partitionsWhenClocks, i) loop
2067 //For each when clock j in partition i create equation "$subclki_n = $whenclkj"
2068 105 cnt := arrayGet(oClksCnt, i);
2069 105 cr := DAE.CREF_IDENT(BackendDAE.WHENCLK_PRREFIX + intString(j), DAE.T_CLOCK_DEFAULT, {});
2070 105 (var, eq) := createSubClock(i, cnt, DAE.CREF(cr, DAE.T_CLOCK_DEFAULT));
2071 105 outNewEqs := eq::outNewEqs;
2072 105 outNewVars := var::outNewVars;
2073 105 arrayUpdate(oClksCnt, i, cnt + 1);
2074 end for;
2075 //If no subclock for partition i is detected, create new one "$subclki_1 = Clock()"
2076
2/2
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 61 times.
67 if arrayGet(oClksCnt, i) == 1 then
2077 6 (var, eq) := createSubClock(i, 1, DAE.CLKCONST(DAE.INFERRED_CLOCK()));
2078 6 outNewEqs := eq::outNewEqs;
2079 6 outNewVars := var::outNewVars;
2080 6 arrayUpdate(oClksCnt, i, 2);
2081 end if;
2082 end for;
2083 end collectSubclkInfo;
2084
2085 protected function collectEquationArrayClocks
2086 input BackendDAE.EquationArray eqs;
2087 input Integer partitionsCnt;
2088 input array<Integer> partitions;
2089 input array<list<Integer>> partitionsWhenClocks;
2090 input array<Integer> clksCnt;
2091 input array<Option<Boolean>> contPartitions;
2092 input BackendDAE.Variables inVars;
2093 input BackendDAE.AdjacencyMatrix mT;
2094 input list<BackendDAE.Equation> inNewEqs;
2095 input list<BackendDAE.Var> inNewVars;
2096 output list<BackendDAE.Equation> outNewEqs = inNewEqs;
2097 output list<BackendDAE.Var> outNewVars = inNewVars;
2098 protected
2099 BackendDAE.Equation eq;
2100 BackendDAE.EquationAttributes eqAttr;
2101 Integer partitionIdx;
2102 SourceInfo source;
2103 algorithm
2104
2/2
✓ Branch 1 taken 46 times.
✓ Branch 2 taken 46 times.
789 for i in 1:BackendEquation.getNumberOfEquations(eqs) loop
2105 697 eq := BackendEquation.get(eqs, i);
2106 697 partitionIdx := arrayGet(partitions, i);
2107 697 DAE.SOURCE(info = source) := BackendEquation.equationSource(eq);
2108
2109
1/2
✓ Branch 0 taken 697 times.
✗ Branch 1 not taken.
697 if partitionIdx <>0 then
2110 697 eqAttr := BackendEquation.getEquationAttributes(eq);
2111 eqAttr := match eqAttr
2112 local
2113 Integer whenIdx;
2114 list<Integer> partitionsWhenClocksLst;
2115 case BackendDAE.EQUATION_ATTRIBUTES(kind=BackendDAE.CLOCKED_EQUATION(whenIdx))
2116 algorithm
2117 127 partitionsWhenClocksLst := partitionsWhenClocks[partitionIdx];
2118
3/4
✓ Branch 0 taken 127 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 105 times.
✓ Branch 4 taken 22 times.
127 if whenIdx <> 0 and List.notMember(whenIdx, partitionsWhenClocksLst) then
2119 105 arrayUpdate(partitionsWhenClocks, partitionIdx, whenIdx::partitionsWhenClocksLst);
2120 end if;
2121 127 eqAttr.kind := BackendDAE.DYNAMIC_EQUATION();
2122 then eqAttr;
2123 else eqAttr;
2124 end match;
2125 697 eq := BackendEquation.setEquationAttributes(eq, eqAttr);
2126
2127 697 (eq, (outNewEqs, outNewVars, _, _, _, _, _, _, _))
2128 := BackendEquation.traverseExpsOfEquation (
2129 eq, collectSubclkInfoExp1, ( outNewEqs, outNewVars, contPartitions, source,
2130 clksCnt, partitionIdx, partitions, inVars, mT ) );
2131 697 BackendEquation.setAtIndex(eqs, i, eq);
2132 end if;
2133 end for;
2134 end collectEquationArrayClocks;
2135
2136 protected function collectSubclkInfoExp1
2137 input DAE.Exp inExp;
2138 input tuple< list<BackendDAE.Equation>, list<BackendDAE.Var>, array<Option<Boolean>>, SourceInfo,
2139 array<Integer>, Integer, array<Integer>, BackendDAE.Variables, BackendDAE.AdjacencyMatrix > inTpl;
2140 output DAE.Exp outExp;
2141 output tuple< list<BackendDAE.Equation>, list<BackendDAE.Var>, array<Option<Boolean>>, SourceInfo,
2142 array<Integer>, Integer, array<Integer>, BackendDAE.Variables, BackendDAE.AdjacencyMatrix > outTpl;
2143 algorithm
2144 1394 (outExp, outTpl) := Expression.traverseExpBottomUp(inExp, collectSubclkInfoExp, inTpl);
2145 end collectSubclkInfoExp1;
2146
2147 protected function splitClockEqs
2148 input BackendDAE.EquationArray inEqs;
2149 output BackendDAE.EquationArray outClockEqs;
2150 output array<Boolean> outClockEqsMask;
2151 protected
2152 list<BackendDAE.Equation> clockEqs = {};
2153 BackendDAE.Equation eq;
2154 Integer i;
2155 algorithm
2156 46 outClockEqsMask := arrayCreate(BackendEquation.getNumberOfEquations(inEqs), true);
2157
1/2
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
743 for i in 1:BackendEquation.getNumberOfEquations(inEqs) loop
2158 697 eq := BackendEquation.get(inEqs, i);
2159
2/2
✓ Branch 1 taken 172 times.
✓ Branch 2 taken 525 times.
697 if isClockEquation(eq) then
2160 clockEqs := eq::clockEqs;
2161 172 arrayUpdate(outClockEqsMask, i, false);
2162 end if;
2163 end for;
2164 46 outClockEqs := BackendEquation.listEquation(clockEqs);
2165 end splitClockEqs;
2166
2167 protected function splitClockVars
2168 input BackendDAE.Variables inVars;
2169 output BackendDAE.Variables outClockVars;
2170 output array<Boolean> outClockVarsMask;
2171 protected
2172 list<BackendDAE.Var> clockVars = {};
2173 BackendDAE.Var var;
2174 algorithm
2175 46 outClockVarsMask := arrayCreate(BackendVariable.varsSize(inVars), true);
2176
1/2
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
742 for i in 1:BackendVariable.varsSize(inVars) loop
2177 696 var := BackendVariable.getVarAt(inVars, i);
2178
2/2
✓ Branch 1 taken 171 times.
✓ Branch 2 taken 525 times.
696 if Types.isClockOrSubTypeClock(var.varType) then
2179 clockVars := var :: clockVars;
2180 171 arrayUpdate(outClockVarsMask, i, false);
2181 end if;
2182 end for;
2183 46 outClockVars := BackendVariable.listVar(clockVars);
2184 end splitClockVars;
2185
2186 protected function substitutePartitionOpExps
2187 "Each non-trivial expression (non-literal, non-constant, non-parameter, non-variable), expr_i, appearing
2188 as first argument of any clock conversion operator or in base clock constructor is recursively replaced by a unique variable, $var_i,
2189 and the equation $var_i = expr_i is added to the equation set.
2190 Also when clauses are created for event clocks."
2191 input BackendDAE.EqSystem inSyst;
2192 input BackendDAE.Shared inShared;
2193 output BackendDAE.EqSystem outSyst = inSyst;
2194 protected
2195 list<BackendDAE.Equation> newEqs = {};
2196 list<BackendDAE.Var> newVars = {};
2197 Integer cnt = 1;
2198 algorithm
2199
2/2
✓ Branch 2 taken 158348 times.
✓ Branch 3 taken 1069 times.
159417 for eq in BackendEquation.equationList(inSyst.orderedEqs) loop
2200 158348 (eq, (newEqs, newVars, cnt, _)) := BackendEquation.traverseExpsOfEquation(eq, substitutePartitionOpExp, (newEqs, newVars, cnt, inShared));
2201 newEqs := eq::newEqs;
2202 end for;
2203 1069 outSyst.orderedEqs := BackendEquation.listEquation(listReverse(newEqs));
2204 outSyst.orderedVars := BackendVariable.addVars(newVars, inSyst.orderedVars);
2205 1069 outSyst := BackendDAEUtil.clearEqSyst(outSyst);
2206 end substitutePartitionOpExps;
2207
2208 protected function substitutePartitionOpExp
2209 input DAE.Exp inExp;
2210 input tuple<list<BackendDAE.Equation>,list<BackendDAE.Var>, Integer, BackendDAE.Shared> inTpl;
2211 output DAE.Exp outExp;
2212 output tuple<list<BackendDAE.Equation>,list<BackendDAE.Var>, Integer, BackendDAE.Shared> outTpl;
2213 algorithm
2214 319067 (outExp, outTpl) := Expression.traverseExpBottomUp(inExp, substitutePartitionOpExp1, inTpl);
2215 end substitutePartitionOpExp;
2216
2217 protected function substitutePartitionOpExp1
2218 input DAE.Exp inExp;
2219 input tuple<list<BackendDAE.Equation>,list<BackendDAE.Var>, Integer, BackendDAE.Shared> inTpl;
2220 output DAE.Exp outExp;
2221 output tuple<list<BackendDAE.Equation>,list<BackendDAE.Var>, Integer, BackendDAE.Shared> outTpl;
2222 protected
2223 Absyn.Path path;
2224 BackendDAE.Shared shared;
2225 DAE.CallAttributes attr;
2226 DAE.ClockKind clk;
2227 Integer cnt;
2228 list<BackendDAE.Equation> newEqs;
2229 list<BackendDAE.Var> newVars;
2230 list<DAE.Exp> exps;
2231 algorithm
2232
3/3
✓ Branch 0 taken 125 times.
✓ Branch 1 taken 35643 times.
✓ Branch 2 taken 1241957 times.
1277725 (newEqs, newVars, cnt, shared) := inTpl;
2233 (outExp, outTpl) := match inExp
2234 case DAE.CLKCONST(clk) algorithm
2235 125 (clk, newEqs, newVars, cnt) := substClock(clk, newEqs, newVars, cnt, shared);
2236 125 then (DAE.CLKCONST(clk), (newEqs, newVars, cnt, shared));
2237
2238 case DAE.CALL(path=path, expLst=exps, attr=attr)
2239 35643 then substituteExpsCall(path, exps, attr, newEqs, newVars, cnt, shared);
2240
2241 1241957 else (inExp, inTpl);
2242 end match;
2243 end substitutePartitionOpExp1;
2244
2245 protected function substClock
2246 input DAE.ClockKind inClk;
2247 input list<BackendDAE.Equation> inNewEqs;
2248 input list<BackendDAE.Var> inNewVars;
2249 input Integer inCnt;
2250 input BackendDAE.Shared inShared;
2251 output DAE.ClockKind outClk;
2252 output list<BackendDAE.Equation> outNewEqs;
2253 output list<BackendDAE.Var> outNewVars;
2254 output Integer outCnt;
2255 protected
2256 DAE.Exp e, i, f;
2257 Integer cnt;
2258 list<BackendDAE.Equation> eqs;
2259 list<BackendDAE.Var> vars;
2260 algorithm
2261 (outClk, outNewEqs, outNewVars, outCnt) := match inClk
2262 case DAE.EVENT_CLOCK(e, f) algorithm
2263
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
11 ({e}, eqs, vars, cnt) := substExp({e}, inNewEqs, inNewVars, inCnt);
2264 11 then (DAE.EVENT_CLOCK(e, f), eqs, vars, cnt);
2265
2266 case DAE.REAL_CLOCK(e) algorithm
2267 15 (e, eqs, vars, cnt) := substClockExp(e, inNewEqs, inNewVars, inCnt, inShared);
2268 15 then (DAE.REAL_CLOCK(e), eqs, vars, cnt);
2269
2270 case DAE.RATIONAL_CLOCK(e, i) algorithm
2271 17 (e, eqs, vars, cnt) := substClockExp(e, inNewEqs, inNewVars, inCnt, inShared);
2272 17 then (DAE.RATIONAL_CLOCK(e, i), eqs, vars, cnt);
2273
2274 else (inClk, inNewEqs, inNewVars, inCnt);
2275 end match;
2276 end substClock;
2277
2278 protected function isKnownOrConstantExp "author: lochel
2279 Returns true if the given expression is constant or at least known (parameter dependent)."
2280 input DAE.Exp inExp;
2281 input BackendDAE.Variables inKnownVars;
2282 output Boolean outKnown;
2283 algorithm
2284 32 (_, (outKnown, _)) := Expression.traverseExpTopDown(inExp, isKnownOrConstantExp_traverser, (true, inKnownVars));
2285 end isKnownOrConstantExp;
2286
2287 protected function isKnownOrConstantExp_traverser
2288 input DAE.Exp inExp;
2289 input tuple<Boolean, BackendDAE.Variables> inTpl;
2290 output DAE.Exp outExp = inExp;
2291 output Boolean outContinue;
2292 output tuple<Boolean, BackendDAE.Variables> outTpl;
2293 protected
2294 BackendDAE.Variables globalKnownVars;
2295 Boolean isKnown;
2296 algorithm
2297
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 32 times.
34 (isKnown, globalKnownVars) := inTpl;
2298 isKnown := match inExp
2299 local
2300 DAE.ComponentRef componentRef;
2301 case DAE.CALL() then false;
2302 2 case DAE.CREF(componentRef=componentRef) then BackendVariable.containsCref(componentRef, globalKnownVars);
2303 else isKnown;
2304 end match;
2305
2306
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 32 times.
36 outTpl := (isKnown, globalKnownVars);
2307 outContinue := isKnown;
2308 end isKnownOrConstantExp_traverser;
2309
2310 protected function substClockExp
2311 input DAE.Exp inExp;
2312 input list<BackendDAE.Equation> inNewEqs;
2313 input list<BackendDAE.Var> inNewVars;
2314 input Integer inCnt;
2315 input BackendDAE.Shared inShared;
2316 output DAE.Exp outExp;
2317 output list<BackendDAE.Equation> outNewEqs;
2318 output list<BackendDAE.Var> outNewVars;
2319 output Integer outCnt;
2320 algorithm
2321
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 30 times.
32 if isKnownOrConstantExp(inExp, inShared.globalKnownVars) then
2322 outExp := inExp;
2323 outNewEqs := inNewEqs;
2324 outNewVars := inNewVars;
2325 outCnt := inCnt;
2326 else
2327
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
2 ({outExp}, outNewEqs, outNewVars, outCnt) := substExp({inExp}, inNewEqs, inNewVars, inCnt);
2328 end if;
2329 end substClockExp;
2330
2331 protected function substituteExpsCall
2332 input Absyn.Path inPath;
2333 input list<DAE.Exp> inExps;
2334 input DAE.CallAttributes inAttr;
2335 input list<BackendDAE.Equation> inEqs;
2336 input list<BackendDAE.Var> inVars;
2337 input Integer inCnt;
2338 input BackendDAE.Shared inShared;
2339 output DAE.Exp outExp;
2340 output tuple<list<BackendDAE.Equation>,list<BackendDAE.Var>, Integer, BackendDAE.Shared> outTpl;
2341 protected
2342 Boolean replace;
2343 list<DAE.Exp> exps;
2344 list<BackendDAE.Equation> eqs;
2345 list<BackendDAE.Var> vars;
2346 Integer cnt;
2347 algorithm
2348 replace := match (inPath, listLength(inExps))
2349 case (Absyn.IDENT("hold"), 1) then true;
2350 case (Absyn.IDENT("sample"), 2) then true;
2351 case (Absyn.IDENT("subSample"), 2) then true;
2352 case (Absyn.IDENT("superSample"), 2) then true;
2353 case (Absyn.IDENT("shiftSample"), 3) then true;
2354 case (Absyn.IDENT("backSample"), 3) then true;
2355 case (Absyn.IDENT("noClock"), 1) then true;
2356 else false;
2357 end match;
2358 35643 (exps, eqs, vars, cnt) :=
2359 if replace then substExp(inExps, inEqs, inVars, inCnt)
2360 else (inExps, inEqs, inVars, inCnt);
2361 35643 outExp := DAE.CALL(inPath, exps, inAttr);
2362 35643 outTpl := (eqs, vars, cnt, inShared);
2363 end substituteExpsCall;
2364
2365 protected function createVar
2366 input DAE.ComponentRef inComp;
2367 input DAE.Type inType;
2368 output BackendDAE.Var outVar;
2369 algorithm
2370 151 outVar := BackendDAE.VAR (
2371 varName = inComp, varKind = BackendDAE.VARIABLE(),
2372 varDirection = DAE.BIDIR(), varParallelism = DAE.NON_PARALLEL(),
2373 varType = inType, bindExp = NONE(), tplExp = NONE(),
2374 arryDim = {}, source = DAE.emptyElementSource,
2375 values = DAEUtil.setProtectedAttr(DAEUtil.getEmptyVarAttr(inType), true), tearingSelectOption = SOME(BackendDAE.DEFAULT()),
2376 hideResult = NONE(),
2377 comment = NONE(), connectorType = DAE.NON_CONNECTOR(),
2378 innerOuter = DAE.NOT_INNER_OUTER(), unreplaceable = false, initNonlinear = false, encrypted = false);
2379 end createVar;
2380
2381 protected function createEqVarPair
2382 input DAE.ComponentRef inComp;
2383 input DAE.Type inType;
2384 input DAE.Exp inExp;
2385 output BackendDAE.Var outVar;
2386 output BackendDAE.Equation outEq;
2387 algorithm
2388 151 outVar := createVar(inComp, inType);
2389 151 outEq := BackendDAE.EQUATION( exp = DAE.CREF(componentRef = inComp, ty = inType), scalar = inExp,
2390 source = DAE.emptyElementSource, attr = BackendDAE.EQ_ATTR_DEFAULT_DYNAMIC );
2391 end createEqVarPair;
2392
2393 protected function substExp
2394 input list<DAE.Exp> inExps;
2395 input list<BackendDAE.Equation> inEqs;
2396 input list<BackendDAE.Var> inVars;
2397 input Integer inCnt;
2398 output tuple<list<DAE.Exp>, list<BackendDAE.Equation>, list<BackendDAE.Var>, Integer> outTpl;
2399 protected
2400 Boolean create;
2401 DAE.Exp e;
2402 algorithm
2403 138 e := listHead(inExps);
2404 create := match e
2405 case DAE.CREF() then false;
2406 case DAE.RCONST() then false;
2407 case DAE.SCONST() then false;
2408 case DAE.BCONST() then false;
2409 case DAE.ENUM_LITERAL() then false;
2410 case DAE.CLKCONST() then true;
2411 else true;
2412 end match;
2413 outTpl := match create
2414 local
2415 DAE.ComponentRef cr;
2416 DAE.Type ty;
2417 BackendDAE.Equation eq;
2418 BackendDAE.Var var;
2419 case true
2420 algorithm
2421 11 ty := Expression.typeof(e);
2422 11 cr := DAE.CREF_IDENT("$var" + intString(inCnt), ty, {});
2423 11 (var, eq) := createEqVarPair(cr, ty, e);
2424 33 then (DAE.CREF(cr, ty)::listRest(inExps), eq::inEqs, var::inVars, inCnt + 1);
2425 case false
2426 127 then (inExps, inEqs, inVars, inCnt);
2427 end match;
2428 end substExp;
2429
2430 protected function getVarIxs
2431 input DAE.ComponentRef inComp;
2432 input BackendDAE.Variables inVariables;
2433 output list<Integer> outIntegerLst;
2434 algorithm
2435 outIntegerLst := matchcontinue inComp
2436 local
2437 list<Integer> ixs;
2438 case _
2439 algorithm
2440 421 (_, ixs) := BackendVariable.getVar(inComp, inVariables);
2441 356 then ixs;
2442 else
2443 then {};
2444 end matchcontinue;
2445 end getVarIxs;
2446
2447 protected function baseClockPartitioning
2448 "Do base clock partitioning and detect kind of new partitions(clocked or continuous)."
2449 input BackendDAE.EqSystem inSyst;
2450 input BackendDAE.Shared inShared;
2451 output list<BackendDAE.EqSystem> outContSysts = {};
2452 output list<BackendDAE.EqSystem> outClockedSysts = {};
2453 output list<BackendDAE.Equation> outUnpartRemEqs;
2454 protected
2455 BackendDAE.Variables vars;
2456 BackendDAE.EquationArray eqs;
2457 AvlTreePathFunction.Tree funcs;
2458 BackendDAE.AdjacencyMatrix m, mT, rm, rmT;
2459 BackendDAE.EqSystem syst;
2460 BackendDAE.EqSystems systs;
2461 Integer partitionCnt, i, j;
2462 DAE.ComponentRef cr;
2463 list<Integer> varIxs;
2464 BackendDAE.EqSystem syst;
2465 array<Integer> eqPartMap, varPartMap, reqsPartition;
2466 array<Boolean> varsPartition, rvarsPartition;
2467 BackendDAE.Equation eq;
2468 list<tuple<DAE.ComponentRef, Boolean>> refsInfo;
2469 tuple<DAE.ComponentRef, Boolean> refInfo;
2470 Option<Boolean> partitionType;
2471 Boolean isClocked, isInitial;
2472 array<Option<Boolean>> clockedEqs, clockedVars, clockedPartitions;
2473 SourceInfo info;
2474 algorithm
2475 1288 funcs := BackendDAEUtil.getFunctions(inShared);
2476 1288 isInitial := BackendDAEUtil.isInitializationDAE(inShared);
2477 1288 (syst, m, mT) := BackendDAEUtil.getAdjacencyMatrixfromOption(inSyst, BackendDAE.BASECLOCK_IDX(), SOME(funcs), isInitial);
2478 1288 (rm, rmT) := BackendDAEUtil.removedAdjacencyMatrix(inSyst, BackendDAE.BASECLOCK_IDX(), SOME(funcs), isInitial);
2479
2480 1288 BackendDAE.EQSYSTEM(orderedVars = vars, orderedEqs = eqs) := syst;
2481
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1288 times.
2576 eqPartMap := arrayCreate(arrayLength(m), 0);
2482
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1288 times.
2576 varPartMap := arrayCreate(arrayLength(mT), 0);
2483
2484 1288 reqsPartition := arrayCreate(arrayLength(rm), 0);
2485
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1288 times.
2576 varsPartition := arrayCreate(arrayLength(mT), false);
2486
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1288 times.
2576 rvarsPartition := arrayCreate(arrayLength(rmT), false);
2487
2488 1288 partitionCnt := partitionIndependentBlocks0(m, mT, rm, rmT, eqPartMap, varPartMap, reqsPartition, varsPartition, rvarsPartition);
2489
2490
2/2
✓ Branch 0 taken 480 times.
✓ Branch 1 taken 808 times.
1288 if partitionCnt > 1 then
2491 480 (systs, outUnpartRemEqs) := partitionIndependentBlocksSplitBlocks(partitionCnt, syst, eqPartMap, reqsPartition, mT, rmT, false, funcs, BackendDAEUtil.isInitializationDAE(inShared));
2492 else
2493 808 (systs, outUnpartRemEqs) := ({syst}, {});
2494 end if;
2495
2496 //Partitioning finished
2497 1287 clockedEqs := arrayCreate(BackendEquation.getNumberOfEquations(eqs), NONE());
2498 1287 clockedVars := arrayCreate(BackendVariable.varsSize(vars), NONE());
2499 1287 clockedPartitions := arrayCreate(if partitionCnt > 0 then partitionCnt else 1, NONE());
2500 //Detect clocked equations and variables
2501 j := 0;
2502
2/2
✓ Branch 1 taken 170062 times.
✓ Branch 2 taken 1287 times.
171349 for eq in BackendEquation.equationList(eqs) loop
2503 170062 j := j+1;
2504 170062 (partitionType, refsInfo) := detectEqPartition(eq);
2505 170062 info := BackendEquation.equationInfo(eq);
2506 170062 arrayUpdate(clockedEqs, j, setClockedPartition(partitionType, arrayGet(clockedEqs, j), NONE(), info));
2507
2/2
✓ Branch 0 taken 136 times.
✓ Branch 1 taken 170062 times.
170198 for refInfo in refsInfo loop
2508 136 (cr, isClocked) := refInfo;
2509 136 varIxs := getVarIxs(cr, vars);
2510
2/2
✓ Branch 1 taken 71 times.
✓ Branch 2 taken 136 times.
207 for i in varIxs loop
2511
2/2
✓ Branch 1 taken 35 times.
✓ Branch 2 taken 36 times.
142 arrayUpdate(clockedVars, i, setClockedPartition(SOME(isClocked), arrayGet(clockedVars, i), SOME(cr), info));
2512 end for;
2513 end for;
2514 end for;
2515 //Clocked vars should belong to clocked equation
2516
2/2
✓ Branch 0 taken 1263 times.
✓ Branch 1 taken 24 times.
219758 for i in 1:arrayLength(clockedVars) loop
2517 218471 partitionType := arrayGet(clockedVars, i);
2518 218471 cr := BackendVariable.varCref(BackendVariable.getVarAt(vars, i));
2519
2/2
✓ Branch 1 taken 476112 times.
✓ Branch 2 taken 218471 times.
694583 for j in arrayGet(mT, i) loop
2520 476112 info := BackendEquation.equationInfo(BackendEquation.get(eqs, j));
2521 476112 arrayUpdate(clockedEqs, j, setClockedPartition(partitionType, arrayGet(clockedEqs, j), SOME(cr), info));
2522 end for;
2523 end for;
2524 //Detect clocked partitions (clocked equations should belong to clocked partitions)
2525
2/2
✓ Branch 0 taken 1263 times.
✓ Branch 1 taken 24 times.
171349 for i in 1:arrayLength(clockedEqs) loop
2526 170062 partitionType := arrayGet(clockedEqs, i);
2527 170062 info := BackendEquation.equationInfo(BackendEquation.get(eqs, i));
2528 170062 j := arrayGet(eqPartMap, i);
2529 170062 arrayUpdate(clockedPartitions, j, setClockedPartition(partitionType, arrayGet(clockedPartitions, j), NONE(), info));
2530 end for;
2531
2532 i := 1;
2533
2/2
✓ Branch 1 taken 19433 times.
✓ Branch 2 taken 1287 times.
20720 for syst in systs loop
2534 (outContSysts, outClockedSysts) := match arrayGet(clockedPartitions, i)
2535 case SOME(false)
2536 29 then (setSystPartition(syst, BackendDAE.CONTINUOUS_TIME_PARTITION()) :: outContSysts, outClockedSysts);
2537 /* Other partitions where none of the variables in the partition are associated with any of the operators above have an
2538 * unspecified partition kind and are considered continuous-time partitions. */
2539 case NONE()
2540 19358 then (setSystPartition(syst, BackendDAE.UNSPECIFIED_PARTITION()) :: outContSysts, outClockedSysts);
2541 case SOME(true) then (outContSysts, syst :: outClockedSysts);
2542 end match;
2543 19433 i := i + 1;
2544 end for;
2545 end baseClockPartitioning;
2546
2547 protected function isClockExp
2548 input DAE.Exp inExp;
2549 output Boolean out;
2550 algorithm
2551 170378 out := Types.isClockOrSubTypeClock(Expression.typeof(inExp));
2552 end isClockExp;
2553
2554 protected function isClockEquation
2555 input BackendDAE.Equation inEq;
2556 output Boolean out;
2557 algorithm
2558 out := match inEq
2559 local
2560 DAE.Exp e;
2561 list<list<BackendDAE.Equation>> trueEqs;
2562 list<BackendDAE.Equation> falseEqs, listEqs;
2563 BackendDAE.Equation eq;
2564 SourceInfo info;
2565 154077 case BackendDAE.EQUATION(scalar = e) then isClockExp(e);
2566 14528 case BackendDAE.ARRAY_EQUATION(right = e) then isClockExp(e);
2567 15 case BackendDAE.FOR_EQUATION(body = eq) then isClockEquation(eq);
2568 170 case BackendDAE.SOLVED_EQUATION(exp = e) then isClockExp(e);
2569 ✗ case BackendDAE.RESIDUAL_EQUATION(exp = e) then isClockExp(e);
2570 case BackendDAE.ALGORITHM() then false;
2571 case BackendDAE.WHEN_EQUATION(whenEquation=BackendDAE.WHEN_STMTS(whenStmtLst={BackendDAE.ASSIGN(right=e)}))
2572 algorithm
2573
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 849 times.
849 if isClockExp(e) then
2574 ✗ DAE.SOURCE(info = info) := BackendEquation.equationSource(inEq);
2575 ✗ Error.addSourceMessageAndFail(Error.INVALID_CLOCK_EQUATION, {}, info);
2576 end if;
2577 then false;
2578 case BackendDAE.WHEN_EQUATION(whenEquation=BackendDAE.WHEN_STMTS(whenStmtLst={BackendDAE.REINIT(value=e)}))
2579 algorithm
2580 ✗ if isClockExp(e) then
2581 ✗ DAE.SOURCE(info = info) := BackendEquation.equationSource(inEq);
2582 ✗ Error.addSourceMessageAndFail(Error.INVALID_CLOCK_EQUATION, {}, info);
2583 end if;
2584 then false;
2585 754 case BackendDAE.COMPLEX_EQUATION(right = e) then isClockExp(e);
2586 case BackendDAE.IF_EQUATION(eqnstrue = trueEqs, eqnsfalse = falseEqs)
2587 algorithm
2588 ✗ for listEqs in trueEqs loop
2589 ✗ for eq in listEqs loop
2590 ✗ if isClockEquation(eq) then
2591 ✗ DAE.SOURCE(info = info) := BackendEquation.equationSource(eq);
2592 ✗ Error.addSourceMessageAndFail(Error.INVALID_CLOCK_EQUATION, {}, info);
2593 end if;
2594 end for;
2595 end for;
2596 ✗ for eq in falseEqs loop
2597 ✗ if isClockEquation(eq) then
2598 ✗ DAE.SOURCE(info = info) := BackendEquation.equationSource(eq);
2599 ✗ Error.addSourceMessageAndFail(Error.INVALID_CLOCK_EQUATION, {}, info);
2600 end if;
2601 end for;
2602 then false;
2603 else
2604 algorithm
2605 ✗ Error.addInternalError(getInstanceName() + " failed.\n", sourceInfo());
2606 ✗ then fail();
2607 end match;
2608 end isClockEquation;
2609
2610 protected function detectEqPartition
2611 "Detect clocked equation and variables according the rule:
2612 - variable u in sample(u) and a variable y in y = hold(ud) is in a continuous-time partition;
2613 - variables u and y in y = sample(uc), y = subSample(u), y = superSample(u), y =
2614 shiftSample(u), y = backSample(u), y = previous(u), are in a clocked partition;
2615 - equations in a clocked when clause in a clocked partition;"
2616 input BackendDAE.Equation inEq;
2617 output Option<Boolean> outPartitionType;
2618 output list<tuple<DAE.ComponentRef, Boolean>> refsInfo;
2619 protected
2620 Option<Boolean> partitionType;
2621 Boolean isClockEq;
2622 SourceInfo info;
2623 algorithm
2624 partitionType := match BackendEquation.getEquationAttributes(inEq)
2625 local
2626 case BackendDAE.EQUATION_ATTRIBUTES(kind = BackendDAE.CLOCKED_EQUATION())
2627 then SOME(true);
2628 else NONE();
2629 end match;
2630 170062 info := BackendEquation.equationInfo(inEq);
2631 170062 (_, (partitionType, refsInfo, _)) :=
2632 BackendEquation.traverseExpsOfEquation(inEq, detectEqPartitionExp, (partitionType, {}, info));
2633 170062 isClockEq := isClockEquation(inEq);
2634
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 169950 times.
170062 outPartitionType := if isClockEq then setClockedPartition(SOME(true), partitionType, NONE(), info)
2635 else partitionType;
2636 end detectEqPartition;
2637
2638 protected function printPartitionType
2639 input Option<Boolean> isClockedPartition;
2640 output String out;
2641 algorithm
2642 out := match isClockedPartition
2643 case SOME(false) then "CONT_PARTITION";
2644 case SOME(true) then "CLOCKED_PARTITION";
2645 else "UNSPECIFIED_PARTITION";
2646 end match;
2647 end printPartitionType;
2648
2649 protected function detectEqPartitionExp
2650 input DAE.Exp inExp;
2651 input tuple<Option<Boolean>, list<tuple<DAE.ComponentRef, Boolean>>, SourceInfo> inTpl;
2652 output DAE.Exp outExp;
2653 output tuple<Option<Boolean>, list<tuple<DAE.ComponentRef, Boolean>>, SourceInfo> outTpl;
2654 algorithm
2655 344843 (outExp, outTpl) := Expression.traverseExpTopDown(inExp, detectEqPartitionExp1, inTpl);
2656 end detectEqPartitionExp;
2657
2658 protected function detectEqPartitionExp1
2659 input DAE.Exp inExp;
2660 input tuple<Option<Boolean>, list<tuple<DAE.ComponentRef, Boolean>>, SourceInfo> inTpl;
2661 output DAE.Exp outExp = inExp;
2662 output Boolean cont;
2663 output tuple<Option<Boolean>, list<tuple<DAE.ComponentRef, Boolean>>, SourceInfo> outTpl;
2664 protected
2665 list<tuple<DAE.ComponentRef, Boolean>> refs;
2666 Option<Boolean> partition;
2667 SourceInfo info;
2668 algorithm
2669 1425398 (partition, refs, info) := inTpl;
2670 (partition, refs, cont) := match inExp
2671 local
2672 Absyn.Path path;
2673 list<DAE.Exp> exps;
2674 DAE.Exp e;
2675 DAE.ComponentRef cr;
2676 case DAE.CLKCONST(DAE.EVENT_CLOCK(e, _))
2677 algorithm
2678
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 DAE.CREF(cr, _) := e;
2679 22 then (partition, (cr, false)::refs, false);
2680 case DAE.CALL(path = path, expLst = exps)
2681 40700 then detectEqPartitionCall(path, exps, refs, partition, info);
2682 1384687 else (partition, refs, true);
2683 end match;
2684 1425398 outTpl := (partition, refs, info);
2685 end detectEqPartitionExp1;
2686
2687 protected function detectEqPartitionCall
2688 input Absyn.Path inPath;
2689 input list<DAE.Exp> inExps;
2690 input list<tuple<DAE.ComponentRef, Boolean>> inRefs;
2691 input Option<Boolean> inPartition;
2692 input SourceInfo info;
2693 output Option<Boolean> outPartition;
2694 output list<tuple<DAE.ComponentRef, Boolean>> outRefs;
2695 output Boolean cont;
2696 algorithm
2697 (outPartition, outRefs, cont) := match (inPath, inExps)
2698 local
2699 DAE.Exp e;
2700 case (Absyn.IDENT("hold"), {e})
2701 15 then detectEqPartitionCall1(false, true, inPartition, e, inRefs, info);
2702 case (Absyn.IDENT("sample"), {e, _})
2703 89 then detectEqPartitionCall1(true, false, inPartition, e, inRefs, info);
2704 case (Absyn.IDENT("subSample"), {e, _})
2705 5 then detectEqPartitionCall1(true, true, inPartition, e, inRefs, info);
2706 case (Absyn.IDENT("superSample"), {e, _})
2707 8 then detectEqPartitionCall1(true, true, inPartition, e, inRefs, info);
2708 case (Absyn.IDENT("shiftSample"), {e, _, _})
2709 5 then detectEqPartitionCall1(true, true, inPartition, e, inRefs, info);
2710 case (Absyn.IDENT("backSample"), {e, _, _})
2711 3 then detectEqPartitionCall1(true, true, inPartition, e, inRefs, info);
2712 case (Absyn.IDENT("noClock"), {e})
2713 ✗ then detectEqPartitionCall1(true, true, inPartition, e, inRefs, info);
2714 40575 else (inPartition, inRefs, true);
2715 end match;
2716 end detectEqPartitionCall;
2717
2718 protected function detectEqPartitionCall1
2719 input Boolean expClocked;
2720 input Boolean refClocked;
2721 input Option<Boolean> inPartition;
2722 input DAE.Exp inExp;
2723 input list<tuple<DAE.ComponentRef, Boolean>> inRefs;
2724 input SourceInfo info;
2725 output Option<Boolean> outPartition;
2726 output list<tuple<DAE.ComponentRef, Boolean>> outRefs;
2727 output Boolean cont = false;
2728 algorithm
2729 (outPartition, outRefs) := match inExp
2730 local
2731 DAE.ComponentRef cr;
2732 case DAE.CREF(cr, _)
2733 algorithm
2734
4/4
✓ Branch 0 taken 89 times.
✓ Branch 1 taken 36 times.
✓ Branch 3 taken 15 times.
✓ Branch 4 taken 110 times.
464 then (setClockedPartition(SOME(expClocked), inPartition, NONE(), info), (cr, refClocked)::inRefs);
2735 else
2736 algorithm
2737 ✗ Error.addInternalError(getInstanceName() + " failed.\n", sourceInfo());
2738 ✗ then fail();
2739 end match;
2740 end detectEqPartitionCall1;
2741
2742 protected function setSystPartition
2743 input BackendDAE.EqSystem inSyst;
2744 input BackendDAE.BaseClockPartitionKind inPartitionKind;
2745 output BackendDAE.EqSystem outSyst;
2746 algorithm
2747 outSyst := match inSyst
2748 local
2749 BackendDAE.EqSystem syst;
2750 case syst as BackendDAE.EQSYSTEM()
2751 algorithm
2752 19387 syst.partitionKind := inPartitionKind;
2753 then syst;
2754 end match;
2755 end setSystPartition;
2756
2757 protected function getPartitionConflictError
2758 input Option<DAE.ComponentRef> inComp;
2759 output ErrorTypes.Message msg;
2760 output ErrorTypes.MessageTokens tokens;
2761 algorithm
2762 (msg, tokens) := match inComp
2763 local DAE.ComponentRef cr;
2764 ✗ case SOME(cr) then ( Error.CONT_CLOCKED_PARTITION_CONFLICT_VAR,
2765 {ComponentReferenceBasics.printComponentRefStr(cr)} );
2766 else (Error.CONT_CLOCKED_PARTITION_CONFLICT_EQ, {});
2767 end match;
2768 end getPartitionConflictError;
2769
2770 protected function setClockedPartition
2771 input Option<Boolean> inNewPartitionType;
2772 input Option<Boolean> inOldPartitionType;
2773 input Option<DAE.ComponentRef> inComp;
2774 input SourceInfo info;
2775 output Option<Boolean> outPartitionType;
2776 algorithm
2777 outPartitionType := match (inOldPartitionType, inNewPartitionType)
2778 local
2779 Boolean newVal, oldVal;
2780 ErrorTypes.Message msg;
2781 ErrorTypes.MessageTokens tokens;
2782 case (NONE(), _) then inNewPartitionType;
2783 case (_, NONE()) then inOldPartitionType;
2784 case (SOME(oldVal), SOME(newVal)) guard (oldVal == newVal)
2785 then inNewPartitionType;
2786 else
2787 algorithm
2788 ✗ (msg, tokens) := getPartitionConflictError(inComp);
2789 ✗ Error.addSourceMessage(msg, tokens, info);
2790 ✗ then fail();
2791 end match;
2792 end setClockedPartition;
2793
2794 public function partitionIndependentBlocks0
2795 input BackendDAE.AdjacencyMatrix m;
2796 input BackendDAE.AdjacencyMatrixT mT;
2797 input BackendDAE.AdjacencyMatrix rm;
2798 input BackendDAE.AdjacencyMatrixT rmT;
2799 input array<Integer> eqPartMap,varPartMap, rixs;
2800 input array<Boolean> vars, rvars;
2801 output Integer on = 0;
2802 algorithm
2803
2/2
✓ Branch 0 taken 2361 times.
✓ Branch 1 taken 47 times.
296093 for i in arrayLength(m):-1:1 loop
2804
2/2
✓ Branch 1 taken 66205 times.
✓ Branch 2 taken 227480 times.
293685 on := if partitionIndependentBlocksWork(i, false, on + 1, m, mT, rm, rmT, eqPartMap, varPartMap, rixs, vars, rvars) then on + 1 else on;
2805 end for;
2806
2/2
✓ Branch 0 taken 1972 times.
✓ Branch 1 taken 436 times.
5692 for i in arrayLength(rm):-1:1 loop
2807
2/2
✓ Branch 1 taken 1577 times.
✓ Branch 2 taken 1707 times.
3284 on := if partitionIndependentBlocksWork(i, true, on + 1, m, mT, rm, rmT, eqPartMap, varPartMap, rixs, vars, rvars) then on + 1 else on;
2808 end for;
2809 end partitionIndependentBlocks0;
2810
2811 protected function partitionIndependentBlocks
2812 input BackendDAE.AdjacencyMatrix m;
2813 input BackendDAE.AdjacencyMatrixT mT;
2814 input array<Integer> eqPartMap; //partitions
2815 input array<Integer> varPartMap; //usedVars, usedRemovedVars
2816 output Integer on = 0;
2817 algorithm
2818 ✗ for eq in arrayLength(m):-1:1 loop
2819 ✗ print("check eq "+intString(eq)+"\n");
2820 ✗ if not intEq(arrayGet(eqPartMap,eq),-2) then //marked with -2 means that it is a sub partition interface
2821 ✗ on := if partitionIndependentBlocks2(eq, on+1, m, mT, eqPartMap, varPartMap) then on+1 else on;
2822 end if;
2823 end for;
2824 end partitionIndependentBlocks;
2825
2826
2827 protected function partitionIndependentBlocks2
2828 input Integer eqIdx;
2829 input Integer partIdx;
2830 input BackendDAE.AdjacencyMatrix m;
2831 input BackendDAE.AdjacencyMatrixT mT;
2832 input array<Integer> eqPartMap;
2833 input array<Integer> varPartMap;
2834 output Boolean ochange;
2835 algorithm
2836 ✗ ochange := arrayGet(eqPartMap, eqIdx) == -1;
2837 ✗ if ochange then
2838 ✗ arrayUpdate(eqPartMap, eqIdx, partIdx);
2839 ✗ for var in arrayGet(m, eqIdx) loop
2840 ✗ if not intGt(arrayGet(varPartMap, intAbs(var)),0) then
2841 ✗ arrayUpdate(varPartMap, intAbs(var), partIdx);
2842 ✗ for newEq in arrayGet(mT, intAbs(var)) loop
2843 ✗ partitionIndependentBlocks2(intAbs(newEq), partIdx, m, mT, eqPartMap, varPartMap);
2844 end for;
2845 end if;
2846 end for;
2847 end if;
2848 end partitionIndependentBlocks2;
2849
2850 protected function partitionIndependentBlocksMasked
2851 input BackendDAE.AdjacencyMatrix m;
2852 input BackendDAE.AdjacencyMatrixT mT;
2853 input BackendDAE.AdjacencyMatrix rm;
2854 input BackendDAE.AdjacencyMatrixT rmT;
2855 input array<Boolean> mask; //clockedEqsMask
2856 input array<Integer> eqPartMap, varPartMap, remEqPartMap; //eqPartMap, varPartMap, remEqPartMap
2857 input array<Boolean> vars, rvars; //usedVars, usedRemovedVars
2858 output Integer on;
2859 algorithm
2860 on := 0;
2861
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
743 for i in arrayLength(m):-1:1 loop
2862
1/2
✓ Branch 1 taken 697 times.
✗ Branch 2 not taken.
697 if mask[i] then
2863
2/2
✓ Branch 1 taken 67 times.
✓ Branch 2 taken 630 times.
697 if partitionIndependentBlocksWork(i, false, on + 1, m, mT, rm, rmT, eqPartMap, varPartMap, remEqPartMap, vars, rvars) then
2864 on := on + 1;
2865 end if;
2866 end if;
2867 end for;
2868
1/2
✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
46 for i in arrayLength(rm):-1:1 loop
2869 ✗ if partitionIndependentBlocksWork(i, true, on + 1, m, mT, rm, rmT, eqPartMap, varPartMap, remEqPartMap, vars, rvars) then
2870 on := on + 1;
2871 end if;
2872 end for;
2873 end partitionIndependentBlocksMasked;
2874
2875 protected function partitionIndependentBlocksWork
2876 input Integer idx;
2877 input Boolean isRemovedIdx;
2878
2879 input Integer partIdx;
2880 input BackendDAE.AdjacencyMatrix m;
2881 input BackendDAE.AdjacencyMatrixT mT;
2882 input BackendDAE.AdjacencyMatrix rm;
2883 input BackendDAE.AdjacencyMatrixT rmT;
2884 input array<Integer> eqPartMap, varPartMap, rixs;
2885 input array<Boolean> vars, rvars;
2886 output Boolean ochange;
2887 protected
2888 Integer eqIdx, rmIdx;
2889 list<Integer> workListEq = {}, workListRm = {};
2890 algorithm
2891 ochange := false;
2892
2/2
✓ Branch 0 taken 3284 times.
✓ Branch 1 taken 294382 times.
297666 if isRemovedIdx then
2893
2/2
✓ Branch 1 taken 1577 times.
✓ Branch 2 taken 1707 times.
3284 if arrayGet(rixs, idx) == 0 then
2894 1577 arrayUpdate(rixs, idx, partIdx);
2895 workListRm := {idx};
2896 ochange := true;
2897 end if;
2898 else
2899
2/2
✓ Branch 1 taken 66272 times.
✓ Branch 2 taken 228110 times.
294382 if arrayGet(eqPartMap, idx) == 0 then
2900 66272 arrayUpdate(eqPartMap, idx, partIdx);
2901 workListEq := {idx};
2902 ochange := true;
2903 end if;
2904 end if;
2905
2/2
✓ Branch 0 taken 229817 times.
✓ Branch 1 taken 67849 times.
297666 if not ochange then
2906 229817 return;
2907 end if;
2908
2909
4/4
✓ Branch 0 taken 71133 times.
✓ Branch 1 taken 294382 times.
✓ Branch 2 taken 3284 times.
✓ Branch 3 taken 67849 times.
365515 while not (listEmpty(workListEq) and listEmpty(workListRm)) loop
2910
2/2
✓ Branch 0 taken 294382 times.
✓ Branch 1 taken 3284 times.
297666 if not listEmpty(workListEq) then
2911 294382 eqIdx :: workListEq := workListEq;
2912
2/2
✓ Branch 1 taken 294382 times.
✓ Branch 2 taken 788652 times.
1083034 for varIdx in arrayGet(m, eqIdx) loop
2913
2/2
✓ Branch 1 taken 350775 times.
✓ Branch 2 taken 437877 times.
788652 if not arrayGet(vars, intAbs(varIdx)) then
2914 350775 arrayUpdate(vars, intAbs(varIdx), true);
2915 350775 arrayUpdate(varPartMap, intAbs(varIdx), partIdx);
2916
2/2
✓ Branch 1 taken 788652 times.
✓ Branch 2 taken 350775 times.
1139427 for nextEqIdx in arrayGet(mT, intAbs(varIdx)) loop
2917
2/2
✓ Branch 1 taken 228079 times.
✓ Branch 2 taken 560573 times.
788652 if arrayGet(eqPartMap, intAbs(nextEqIdx)) == 0 then
2918 workListEq := intAbs(nextEqIdx) :: workListEq;
2919 228079 arrayUpdate(eqPartMap, intAbs(nextEqIdx), partIdx);
2920 end if;
2921 end for;
2922
2/2
✓ Branch 1 taken 2304 times.
✓ Branch 2 taken 350775 times.
353079 for nextEqIdx in arrayGet(rmT, intAbs(varIdx)) loop
2923
2/2
✓ Branch 1 taken 1706 times.
✓ Branch 2 taken 598 times.
2304 if arrayGet(rixs, intAbs(nextEqIdx)) == 0 then
2924 workListRm := intAbs(nextEqIdx) :: workListRm;
2925 1706 arrayUpdate(rixs, intAbs(nextEqIdx), partIdx);
2926 end if;
2927 end for;
2928 end if;
2929 end for;
2930 else
2931
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3284 times.
3284 rmIdx :: workListRm := workListRm;
2932
2/2
✓ Branch 1 taken 3284 times.
✓ Branch 2 taken 2304 times.
5588 for varIdx in arrayGet(rm, rmIdx) loop
2933
2/2
✓ Branch 1 taken 2053 times.
✓ Branch 2 taken 251 times.
2304 if not arrayGet(rvars, intAbs(varIdx)) then
2934 2053 arrayUpdate(rvars, intAbs(varIdx), true);
2935
2/2
✓ Branch 1 taken 7521 times.
✓ Branch 2 taken 2053 times.
9574 for nextEqIdx in arrayGet(mT, intAbs(varIdx)) loop
2936
2/2
✓ Branch 1 taken 31 times.
✓ Branch 2 taken 7490 times.
7521 if arrayGet(eqPartMap, intAbs(nextEqIdx)) == 0 then
2937 workListEq := intAbs(nextEqIdx) :: workListEq;
2938 31 arrayUpdate(eqPartMap, intAbs(nextEqIdx), partIdx);
2939 end if;
2940 end for;
2941
2/2
✓ Branch 1 taken 2304 times.
✓ Branch 2 taken 2053 times.
4357 for nextEqIdx in arrayGet(rmT, intAbs(varIdx)) loop
2942
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 2303 times.
2304 if arrayGet(rixs, intAbs(nextEqIdx)) == 0 then
2943 workListRm := intAbs(nextEqIdx) :: workListRm;
2944 1 arrayUpdate(rixs, intAbs(nextEqIdx), partIdx);
2945 end if;
2946 end for;
2947 end if;
2948 end for;
2949 end if;
2950 end while;
2951 end partitionIndependentBlocksWork;
2952
2953 public function partitionIndependentBlocksSplitBlocks
2954 "Partitions the independent blocks into list<array<...>> by first constructing
2955 an array<list<...>> structure for the algorithm complexity"
2956 input Integer n;
2957 input BackendDAE.EqSystem inSyst;
2958 input array<Integer> ixs;
2959 input array<Integer> rixs;
2960 input BackendDAE.AdjacencyMatrix mT;
2961 input BackendDAE.AdjacencyMatrix rmT;
2962 input Boolean throwNoError;
2963 input AvlTreePathFunction.Tree funcs;
2964 input Boolean isInitial;
2965 output list<BackendDAE.EqSystem> systs = {};
2966 output list<BackendDAE.Equation> unpartRemovedEqs;
2967 output array<Integer> varPartMap;
2968 protected
2969 array<list<BackendDAE.Equation>> ea, rea;
2970 array<list<BackendDAE.Var>> va;
2971 Integer i1, i2;
2972 Boolean b, b1 = true;
2973 BackendDAE.EqSystem syst;
2974 array<Integer> varsPartition;
2975 list<BackendDAE.Var> lstVars;
2976 algorithm
2977 1242 ea := arrayCreate(n, {});
2978 1242 rea := arrayCreate(n, {});
2979 1242 va := arrayCreate(n, {});
2980 1242 varPartMap := arrayCreate(n, -1);
2981 1242 i1 := BackendEquation.equationArraySize(inSyst.orderedEqs);
2982 1242 i2 := BackendVariable.varsSize(inSyst.orderedVars);
2983
2984
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1242 times.
1242 if i1 <> i2 and not throwNoError then
2985 ✗ Error.addSourceMessage(if i1 > i2 then Error.OVERDET_EQN_SYSTEM else Error.UNDERDET_EQN_SYSTEM, {String(i1), String(i2)}, Absyn.dummyInfo);
2986 ✗ BackendDAEUtil.checkAdjacencyMatrixSolvability(inSyst, funcs, isInitial);
2987 ✗ fail();
2988 end if;
2989
2990 1242 partitionEquations(inSyst.orderedEqs, ixs, ea);
2991 1242 unpartRemovedEqs := partitionEquations(inSyst.removedEqs, rixs, rea);
2992
2993 1242 varsPartition := arrayCreate(BackendVariable.varsSize(inSyst.orderedVars), 0);
2994
1/2
✓ Branch 1 taken 1242 times.
✗ Branch 2 not taken.
317428 for i in 1:BackendVariable.varsSize(inSyst.orderedVars) loop
2995 316186 setVarPartition(varsPartition, i, mT[i], ixs);
2996 316186 setVarPartition(varsPartition, i, rmT[i], rixs);
2997 end for;
2998
1/2
✓ Branch 0 taken 1242 times.
✗ Branch 1 not taken.
317428 for i in arrayLength(varsPartition):-1:1 loop
2999
2/2
✓ Branch 1 taken 316185 times.
✓ Branch 2 taken 1 time.
316186 if varsPartition[i] <> 0 then
3000 316185 lstVars := va[varsPartition[i]];
3001 632370 arrayUpdate(va, varsPartition[i], BackendVariable.getVarAt(inSyst.orderedVars, i)::lstVars);
3002 end if;
3003 end for;
3004
3005
1/2
✓ Branch 0 taken 1242 times.
✗ Branch 1 not taken.
1242 for i in 1:n loop
3006
2/2
✓ Branch 0 taken 18626 times.
✓ Branch 1 taken 48034 times.
85286 (syst, (b, _)) := createEqSystem(ea[i], va[i], rea[i], (true, throwNoError));
3007 systs := syst :: systs;
3008 66659 b1 := b1 and b;
3009 end for;
3010
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1241 times.
1241 true := throwNoError or b1;
3011 1241 systs := listReverse(systs);
3012 end partitionIndependentBlocksSplitBlocks;
3013
3014 protected function setVarPartition
3015 input array<Integer> varsPartition;
3016 input Integer i;
3017 input list<Integer> eqsIxs;
3018 input array<Integer> eqsPartitions;
3019 protected
3020 Integer partitionIdx;
3021 algorithm
3022
2/2
✓ Branch 0 taken 705438 times.
✓ Branch 1 taken 632372 times.
1337810 for eq in eqsIxs loop
3023 705438 partitionIdx := eqsPartitions[eq];
3024
1/2
✓ Branch 0 taken 705438 times.
✗ Branch 1 not taken.
705438 if partitionIdx <> 0 then
3025
3/4
✓ Branch 1 taken 389253 times.
✓ Branch 2 taken 316185 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 389253 times.
705438 assert(varsPartition[i] == 0 or varsPartition[i] == partitionIdx, "SynchronousFeatures.setVarPartition failed");
3026 705438 arrayUpdate(varsPartition, i, partitionIdx);
3027 end if;
3028 end for;
3029 end setVarPartition;
3030
3031 protected function createEqSystem
3032 input list<BackendDAE.Equation> el;
3033 input list<BackendDAE.Var> vl;
3034 input list<BackendDAE.Equation> rel;
3035 input tuple<Boolean, Boolean> iTpl;
3036 output BackendDAE.EqSystem syst;
3037 output tuple<Boolean, Boolean> oTpl;
3038 protected
3039 BackendDAE.EquationArray arr, remArr;
3040 BackendDAE.Variables vars;
3041 Integer i1, i2;
3042 String s1, s2, s3, s4;
3043 list<String> crs;
3044 Boolean success, throwNoError;
3045 algorithm
3046 66721 (success, throwNoError) := iTpl;
3047 66721 vars := BackendVariable.listVar1(vl);
3048 66721 arr := BackendEquation.listEquation(el);
3049 66721 remArr := BackendEquation.listEquation(rel);
3050 66721 i1 := BackendEquation.equationArraySize(arr);
3051 66721 i2 := BackendVariable.varsSize(vars);
3052
3053 // Can this even be triggered? We check that all variables are defined somewhere, so everything should be balanced already?
3054
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 66720 times.
66721 if i1 <> i2 and not throwNoError then
3055 1 s1 := intString(i1);
3056 1 s2 := intString(i2);
3057 1 crs := List.mapMap(vl, BackendVariable.varCref, ComponentReferenceBasics.printComponentRefStr);
3058 1 s3 := stringDelimitList(crs, "\n");
3059 1 s4 := BackendDump.dumpEqnsStr(el);
3060 1 Error.addSourceMessage(Error.IMBALANCED_EQUATIONS, {s1, s2, s3, s4}, Absyn.dummyInfo);
3061 1 fail();
3062 end if;
3063
3064 66720 syst := BackendDAEUtil.createEqSystem(vars, arr, {}, BackendDAE.UNKNOWN_PARTITION(), remArr);
3065 66720 success := success and i1==i2;
3066
4/4
✓ Branch 0 taken 18625 times.
✓ Branch 1 taken 48095 times.
✓ Branch 2 taken 379 times.
✓ Branch 3 taken 66341 times.
85724 oTpl := (success, throwNoError);
3067 end createEqSystem;
3068
3069 protected function partitionEquations
3070 input BackendDAE.EquationArray arr;
3071 input array<Integer> ixs;
3072 input array<list<BackendDAE.Equation>> ea;
3073 output list<BackendDAE.Equation> restEqs = {};
3074 protected
3075 Integer ix;
3076 list<BackendDAE.Equation> lst;
3077 BackendDAE.Equation eq;
3078 algorithm
3079
2/2
✓ Branch 1 taken 925 times.
✓ Branch 2 taken 1559 times.
272304 for i in BackendEquation.getNumberOfEquations(arr):-1:1 loop
3080 269820 ix := ixs[i];
3081 269820 eq := BackendEquation.get(arr, i);
3082
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 269820 times.
269820 if ix == 0 then
3083 restEqs := eq::restEqs;
3084 else
3085 269820 lst := ea[ix];
3086 lst := eq::lst;
3087 // print("adding eq " + intString(n) + " to group " + intString(ix) + "\n");
3088 269820 arrayUpdate(ea, ix, lst);
3089 end if;
3090 end for;
3091 end partitionEquations;
3092
3093 protected function subClkEqual
3094 "outputs true if 2 subclocks are equal
3095 vwaurich 2017-06"
3096 input BackendDAE.SubClock sc1;
3097 input BackendDAE.SubClock sc2;
3098 output Boolean isEqual;
3099 algorithm
3100 isEqual := match(sc1,sc2)
3101 local
3102 case(BackendDAE.INFERED_SUBCLOCK(), BackendDAE.INFERED_SUBCLOCK())
3103 then true;
3104 case(BackendDAE.SUBCLOCK(), BackendDAE.SUBCLOCK())
3105
5/6
✓ Branch 1 taken 54 times.
✓ Branch 2 taken 13 times.
✓ Branch 4 taken 46 times.
✓ Branch 5 taken 8 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 46 times.
67 then MMath.equals(sc1.factor,sc2.factor) and MMath.equals(sc1. shift,sc2. shift) and Util.optionEqual(sc1.solver,sc2.solver,stringEqual);
3106 else
3107 then false;
3108 end match;
3109 end subClkEqual;
3110
3111 protected function subClockTreeString
3112 input array<tuple<BackendDAE.SubClock, Integer>> treeIn;
3113 output String sOut="";
3114 protected
3115 tuple<BackendDAE.SubClock, Integer> tpl;
3116 BackendDAE.SubClock subClock;
3117 Integer i,idx=1;
3118 algorithm
3119 ✗ for tpl in treeIn loop
3120 ✗ (subClock,i) := tpl;
3121 ✗ sOut := intString(idx)+": ["+intString(i)+"]: "+BackendDump.subClockString(subClock)+"\n"+sOut;
3122 ✗ idx:=idx+1;
3123 end for;
3124 end subClockTreeString;
3125
3126 annotation(__OpenModelica_Interface="backend");
3127 end SynchronousFeatures;
3128