Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 43.2% 126 / 0 / 292
Functions: -% 0 / 1 / 1
Branches: 41.2% 61 / 0 / 148

OMCompiler/Compiler/FrontEnd/ConnectionGraph.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 ConnectionGraph
37 " file: ConnectionGraph.mo
38 package: ConnectionGraph
39 description: Constant propagation of expressions
40
41
42 This module contains a connection breaking algorithm and
43 related data structures. The input of the algorithm is
44 collected to ConnectionGraph record during instantiation.
45 The entry point to the algorithm is findResultGraph.
46
47 The algorithm is implemented using a disjoint-set
48 data structure that represents the components of
49 elements so far connected.
50 Each component has an unique canonical element.
51 The data structure is implemented by a hash table, that
52 contains an entry for each non-canonical element so that
53 a path beginning from some element eventually ends to the
54 canonical element of the same component.
55
56 Roots are represented as connections to dummy root
57 element. In this way, all elements will be in the
58 same component after the algorithm finishes assuming
59 that the model is valid.
60
61 TODO! FIXME! adrpo 2014-10-05
62 - non standard operators: Connections.uniqueRoot and Connections.uniqueRootIndices are only partially implemented
63 - Connections.uniqueRoot currently does nothing, only collects information
64 - Connections.uniqueRootIndices needs to be implemented, it returns an array of ones (1) of size of first input
65 - See specification for these here (Modelica_StateGraph2):
66 https://github.com/modelica/Modelica_StateGraph2 and
67 https://trac.modelica.org/Modelica/ticket/984 and
68 http://www.ep.liu.se/ecp/043/041/ecp09430108.pdf
69 - any takers for the actual implementation? :)
70
71 "
72
73 public import Absyn;
74 public import DAE;
75 public import DAEUtil;
76 public import HashTable;
77 public import HashTable3;
78 public import HashTableCG;
79 public import DAE.Connect;
80
81
82 public type Edge = tuple<DAE.ComponentRef,DAE.ComponentRef> "an edge is a tuple with two component references";
83 public type Edges = list<Edge> "A list of edges";
84
85 public type DaeEdge = tuple<DAE.ComponentRef,DAE.ComponentRef,list<DAE.Element>>
86 "a tuple with two crefs and dae elements for equatityConstraint function call";
87 public type DaeEdges = list<DaeEdge>
88 "A list of edges, each edge associated with two lists of DAE elements
89 (these elements represent equations to be added if the edge
90 is broken)";
91
92 public type DefiniteRoot = DAE.ComponentRef "root defined with Connection.root";
93 public type DefiniteRoots = list<DAE.ComponentRef> "roots defined with Connection.root";
94 public type UniqueRoots = list<tuple<DAE.ComponentRef,DAE.Exp>> "roots defined with Connection.uniqueRoot";
95
96 public type PotentialRoot = tuple<DAE.ComponentRef,Real> "potential root defined with Connections.potentialRoot";
97 public type PotentialRoots = list<tuple<DAE.ComponentRef,Real>> "potential roots defined with Connections.potentialRoot";
98
99 public
100 uniontype ConnectionGraph "Input structure for connection breaking algorithm. It is collected during instantiation phase."
101 record GRAPH
102 Boolean updateGraph;
103 DefiniteRoots definiteRoots "Roots defined with Connection.root";
104 PotentialRoots potentialRoots "Roots defined with Connection.potentialRoot";
105 UniqueRoots uniqueRoots "Roots defined with Connection.uniqueRoot";
106 Edges branches "Edges defined with Connection.branch";
107 DaeEdges connections "Edges defined with connect statement";
108 end GRAPH;
109 end ConnectionGraph;
110
111 public constant ConnectionGraph EMPTY = GRAPH( true, {}, {}, {}, {}, {} ) "Initial connection graph with no edges in it.";
112
113 public constant ConnectionGraph NOUPDATE_EMPTY = GRAPH( false, {}, {}, {}, {}, {} ) "Initial connection graph with updateGraph set to false.";
114
115 public function handleOverconstrainedConnections
116 "author: adrpo
117 this function gets the connection graph and the existing DAE and:
118 - returns a list of broken connects and one list of connected connects
119 - evaluates Connections.isRoot in the input DAE
120 - evaluates Connections.uniqueRootIndices in the input DAE
121 - evaluates the rooted operator in the input DAE"
122 input ConnectionGraph inGraph;
123 input String modelNameQualified;
124 input DAE.DAElist inDAE;
125 output DAE.DAElist outDAE;
126 output DaeEdges outConnected;
127 output DaeEdges outBroken;
128 algorithm
129 (outDAE, outConnected, outBroken) := matchcontinue(inGraph, inDAE)
130 local
131 ConnectionGraph graph;
132 list<DAE.Element> elts;
133 list<DAE.ComponentRef> roots;
134 DaeEdges broken, connected;
135
136 // empty graph gives you the same dae
137 case (GRAPH(_, {}, {}, {}, {}, {}), _) then (inDAE, {}, {});
138
139 // handle the connection braking
140 case (graph, DAE.DAE(elts))
141 algorithm
142
143
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
19 if Flags.isSet(Flags.CGRAPH) then
144 ✗ Debug.traceln("Summary: \n\t" +
145 "Nr Roots: " + intString(listLength(getDefiniteRoots(graph))) + "\n\t" +
146 "Nr Potential Roots: " + intString(listLength(getPotentialRoots(graph))) + "\n\t" +
147 "Nr Unique Roots: " + intString(listLength(getUniqueRoots(graph))) + "\n\t" +
148 "Nr Branches: " + intString(listLength(getBranches(graph))) + "\n\t" +
149 "Nr Connections: " + intString(listLength(getConnections(graph))));
150 end if;
151
152 19 (roots, connected, broken) := findResultGraph(graph, modelNameQualified);
153
154
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
19 if Flags.isSet(Flags.CGRAPH) then
155 ✗ Debug.traceln("Roots: " + stringDelimitList(List.map(roots, ComponentReferenceBasics.printComponentRefStr), ", "));
156 ✗ Debug.traceln("Broken connections: " + stringDelimitList(List.map1(broken, printConnectionStr, "broken"), ", "));
157 ✗ Debug.traceln("Allowed connections: " + stringDelimitList(List.map1(connected, printConnectionStr, "allowed"), ", "));
158 end if;
159
160 19 elts := evalConnectionsOperators(roots, connected, graph, elts);
161 19 then
162 (DAE.DAE(elts), connected, broken);
163
164 // handle the connection breaking
165 else
166 algorithm
167 ✗ true := Flags.isSet(Flags.CGRAPH);
168 ✗ Debug.traceln("- ConnectionGraph.handleOverconstrainedConnections failed for model: " + modelNameQualified);
169 ✗ then
170 fail();
171 end matchcontinue;
172 end handleOverconstrainedConnections;
173
174 public function addDefiniteRoot
175 "Adds a new definite root to ConnectionGraph"
176 input ConnectionGraph inGraph;
177 input DAE.ComponentRef inRoot;
178 output ConnectionGraph outGraph;
179 algorithm
180 outGraph := match(inGraph, inRoot)
181 local
182 Boolean updateGraph;
183 DAE.ComponentRef root;
184 DefiniteRoots definiteRoots;
185 PotentialRoots potentialRoots;
186 UniqueRoots uniqueRoots;
187 Edges branches;
188 DaeEdges connections;
189
190 case (GRAPH(updateGraph = updateGraph,definiteRoots = definiteRoots,potentialRoots = potentialRoots,uniqueRoots = uniqueRoots,branches = branches,connections = connections), root)
191 algorithm
192
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
20 if Flags.isSet(Flags.CGRAPH) then
193 ✗ Debug.traceln("- ConnectionGraph.addDefiniteRoot(" + ComponentReferenceBasics.printComponentRefStr(root) + ")");
194 end if;
195
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 then
196 GRAPH(updateGraph,root::definiteRoots,potentialRoots,uniqueRoots,branches,connections);
197 end match;
198 end addDefiniteRoot;
199
200 public function addPotentialRoot
201 "Adds a new potential root to ConnectionGraph"
202 input ConnectionGraph inGraph;
203 input DAE.ComponentRef inRoot;
204 input Real inPriority;
205 output ConnectionGraph outGraph;
206 algorithm
207 outGraph := match(inGraph, inRoot, inPriority)
208 local
209 Boolean updateGraph;
210 DAE.ComponentRef root;
211 Real priority;
212 DefiniteRoots definiteRoots;
213 PotentialRoots potentialRoots;
214 UniqueRoots uniqueRoots;
215 Edges branches;
216 DaeEdges connections;
217
218 case (GRAPH(updateGraph = updateGraph,definiteRoots = definiteRoots,potentialRoots = potentialRoots,uniqueRoots = uniqueRoots,branches = branches,connections = connections), root, priority)
219 algorithm
220
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 150 times.
150 if Flags.isSet(Flags.CGRAPH) then
221 ✗ Debug.traceln("- ConnectionGraph.addPotentialRoot(" + ComponentReferenceBasics.printComponentRefStr(root) + ", " + realString(priority) + ")");
222 end if;
223
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 150 times.
300 then
224 GRAPH(updateGraph,definiteRoots,(root,priority)::potentialRoots,uniqueRoots,branches,connections);
225 end match;
226 end addPotentialRoot;
227
228 public function addUniqueRoots
229 "Adds a new definite root to ConnectionGraph"
230 input ConnectionGraph inGraph;
231 input DAE.Exp inRoots;
232 input DAE.Exp inMessage;
233 output ConnectionGraph outGraph;
234 algorithm
235 outGraph := match(inGraph, inRoots)
236 local
237 Boolean updateGraph;
238 DAE.ComponentRef root;
239 DefiniteRoots definiteRoots;
240 PotentialRoots potentialRoots;
241 UniqueRoots uniqueRoots;
242 Edges branches;
243 DaeEdges connections;
244 ConnectionGraph graph;
245 DAE.Type ty;
246 Boolean scalar;
247 list<DAE.Exp> rest;
248
249 // just one component reference
250 case (GRAPH(updateGraph = updateGraph,definiteRoots = definiteRoots,potentialRoots = potentialRoots,uniqueRoots = uniqueRoots,
251 branches = branches,connections = connections), DAE.CREF(root, _))
252 algorithm
253 ✗ if Flags.isSet(Flags.CGRAPH) then
254 ✗ Debug.traceln("- ConnectionGraph.addUniqueRoots(" + ComponentReferenceBasics.printComponentRefStr(root) + ", " + ExpressionBasics.printExpStr(inMessage) + ")");
255 end if;
256 ✗ then
257 GRAPH(updateGraph,definiteRoots,potentialRoots,(root,inMessage)::uniqueRoots,branches,connections);
258
259 // array of component references, empty case
260 case (GRAPH(), DAE.ARRAY(_, _, {}))
261 then
262 inGraph;
263
264 // array of component references, something still there
265 case (GRAPH(updateGraph = updateGraph,definiteRoots = definiteRoots,potentialRoots = potentialRoots,uniqueRoots = uniqueRoots,
266 branches = branches,connections = connections), DAE.ARRAY(ty, scalar, DAE.CREF(root, _)::rest))
267 algorithm
268 ✗ if Flags.isSet(Flags.CGRAPH) then
269 ✗ Debug.traceln("- ConnectionGraph.addUniqueRoots(" + ComponentReferenceBasics.printComponentRefStr(root) + ", " + ExpressionBasics.printExpStr(inMessage) + ")");
270 end if;
271 ✗ graph := GRAPH(updateGraph,definiteRoots,potentialRoots,(root,inMessage)::uniqueRoots,branches,connections);
272 ✗ graph := addUniqueRoots(graph, DAE.ARRAY(ty, scalar, rest), inMessage);
273 then
274 graph;
275
276 case (_, _)
277 algorithm
278 // TODO! FIXME! print some meaningful error message here that the input is not an array of roots or a cref
279 then
280 inGraph;
281
282 end match;
283 end addUniqueRoots;
284
285 public function addBranch
286 "Adds a new branch to ConnectionGraph"
287 input ConnectionGraph inGraph;
288 input DAE.ComponentRef inRef1;
289 input DAE.ComponentRef inRef2;
290 output ConnectionGraph outGraph;
291 algorithm
292 outGraph := match(inGraph, inRef1, inRef2)
293 local
294 Boolean updateGraph;
295 DAE.ComponentRef ref1;
296 DAE.ComponentRef ref2;
297 DefiniteRoots definiteRoots;
298 PotentialRoots potentialRoots;
299 UniqueRoots uniqueRoots;
300 Edges branches;
301 DaeEdges connections;
302
303 case (GRAPH(updateGraph = updateGraph, definiteRoots = definiteRoots,potentialRoots = potentialRoots,uniqueRoots = uniqueRoots,branches = branches,connections = connections), ref1, ref2)
304 algorithm
305
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 308 times.
308 if Flags.isSet(Flags.CGRAPH) then
306 ✗ Debug.traceln("- ConnectionGraph.addBranch(" + ComponentReferenceBasics.printComponentRefStr(ref1) + ", " + ComponentReferenceBasics.printComponentRefStr(ref2) + ")");
307 end if;
308
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 308 times.
616 then
309 GRAPH(updateGraph, definiteRoots,potentialRoots,uniqueRoots,(ref1,ref2)::branches,connections);
310 end match;
311 end addBranch;
312
313 public function addConnection
314 "Adds a new connection to ConnectionGraph"
315 input ConnectionGraph inGraph;
316 input DAE.ComponentRef inRef1;
317 input DAE.ComponentRef inRef2;
318 input list<DAE.Element> inDae;
319 output ConnectionGraph outGraph;
320 algorithm
321 outGraph := match(inGraph, inRef1, inRef2,inDae)
322 local
323 Boolean updateGraph;
324 DAE.ComponentRef ref1;
325 DAE.ComponentRef ref2;
326 list<DAE.Element> dae;
327 DefiniteRoots definiteRoots;
328 PotentialRoots potentialRoots;
329 UniqueRoots uniqueRoots;
330 Edges branches;
331 DaeEdges connections;
332
333 case (GRAPH(updateGraph = updateGraph, definiteRoots = definiteRoots, potentialRoots = potentialRoots, uniqueRoots = uniqueRoots, branches = branches, connections = connections), ref1, ref2, dae)
334 algorithm
335
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 806 times.
806 if Flags.isSet(Flags.CGRAPH) then
336 ✗ Debug.trace("- ConnectionGraph.addConnection(" + ComponentReferenceBasics.printComponentRefStr(ref1) + ", " + ComponentReferenceBasics.printComponentRefStr(ref2) + ")\n");
337 end if;
338
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 806 times.
1612 then GRAPH(updateGraph, definiteRoots, potentialRoots, uniqueRoots, branches, (ref1,ref2,dae)::connections);
339 end match;
340 end addConnection;
341
342 // ************************************* //
343 // ********* protected section ********* //
344 // ************************************* //
345
346 protected import BaseHashTable;
347 protected import ComponentReference;
348 protected import ComponentReferenceBasics;
349 protected import ConnectUtil;
350 protected import Debug;
351 protected import Flags;
352 protected import List;
353 protected import Util;
354 protected import System;
355 protected import IOStream;
356 protected import Settings;
357 protected import ExpressionBasics;
358
359 protected function canonical
360 "Returns the canonical element of the component where input element belongs to.
361 See explanation at the top of file."
362 input HashTableCG.HashTable inPartition;
363 input DAE.ComponentRef inRef;
364 //output HashTableCG.HashTable outPartition;
365 output DAE.ComponentRef outCanonical;
366 algorithm
367 (/*outPartition,*/outCanonical) := matchcontinue(inPartition, inRef)
368 local
369 HashTableCG.HashTable partition;
370 DAE.ComponentRef ref, parent, parentCanonical;
371
372 case (partition, ref)
373 algorithm
374 13158 parent := BaseHashTable.get(ref, partition);
375 9020 parentCanonical := canonical(partition, parent);
376 //fprintln(Flags.CGRAPH,
377 // "- ConnectionGraph.canonical_case1(" + ComponentReferenceBasics.printComponentRefStr(ref) + ") = " +
378 // ComponentReferenceBasics.printComponentRefStr(parentCanonical));
379 //partition2 = BaseHashTable.add((ref, parentCanonical), partition);
380 then parentCanonical;
381
382 case (_,ref)
383 algorithm
384 //fprintln(Flags.CGRAPH,
385 // "- ConnectionGraph.canonical_case2(" + ComponentReferenceBasics.printComponentRefStr(ref) + ") = " +
386 // ComponentReferenceBasics.printComponentRefStr(ref));
387 then ref;
388 end matchcontinue;
389 end canonical;
390
391 protected function areInSameComponent
392 "Tells whether the elements belong to the same component.
393 See explanation at the top of file."
394 input HashTableCG.HashTable inPartition;
395 input DAE.ComponentRef inRef1;
396 input DAE.ComponentRef inRef2;
397 output Boolean outResult;
398 algorithm
399 // canonical(inPartition,inRef1) = canonical(inPartition,inRef2);
400 outResult := matchcontinue(inPartition,inRef1,inRef2)
401 local
402 HashTableCG.HashTable partition;
403 DAE.ComponentRef ref1, ref2, canon1,canon2;
404
405 case(partition,ref1,ref2)
406 algorithm
407 ✗ canon1 := canonical(partition,ref1);
408 ✗ canon2 := canonical(partition,ref2);
409 ✗ true := ComponentReferenceBasics.crefEqualNoStringCompare(canon1, canon2);
410 then true;
411 else false;
412 end matchcontinue;
413 end areInSameComponent;
414
415
416 protected function connectBranchComponents
417 "Tries to connect two components whose elements are given. Depending
418 on wheter the connection success or not (i.e are the components already
419 connected), adds either inConnectionDae or inBreakDae to the list of
420 DAE elements."
421 input HashTableCG.HashTable inPartition;
422 input DAE.ComponentRef inRef1;
423 input DAE.ComponentRef inRef2;
424 output HashTableCG.HashTable outPartition;
425 algorithm
426 outPartition := matchcontinue(inPartition,inRef1,inRef2)
427 local
428 HashTableCG.HashTable partition;
429 DAE.ComponentRef ref1, ref2, canon1, canon2;
430
431 // can connect them
432 case(partition,ref1,ref2)
433 algorithm
434 307 canon1 := canonical(partition,ref1);
435 307 canon2 := canonical(partition,ref2);
436
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 307 times.
307 (partition, true) := connectCanonicalComponents(partition,canon1,canon2);
437 then partition;
438
439 // cannot connect them
440 case(partition,_,_)
441 algorithm
442 then partition;
443 end matchcontinue;
444 end connectBranchComponents;
445
446 protected function connectComponents
447 "Tries to connect two components whose elements are given. Depending
448 on wheter the connection success or not (i.e are the components already
449 connected), adds either inConnectionDae or inBreakDae to the list of
450 DAE elements."
451 input HashTableCG.HashTable inPartition;
452 input DaeEdge inDaeEdge;
453 output HashTableCG.HashTable outPartition;
454 output DaeEdges outConnectedConnections;
455 output DaeEdges outBrokenConnections;
456 algorithm
457 (outPartition,outConnectedConnections,outBrokenConnections) := matchcontinue(inPartition,inDaeEdge)
458 local
459 HashTableCG.HashTable partition;
460 DAE.ComponentRef ref1, ref2, canon1, canon2;
461
462 // leave the connect(ref1,ref2)
463 case(partition,(ref1,_,_))
464 algorithm
465
1/2
✓ Branch 0 taken 806 times.
✗ Branch 1 not taken.
806 failure(canonical(partition,ref1)); // no parent
466 ✗ then (partition, {inDaeEdge}, {});
467
468 // leave the connect(ref1,ref2)
469 case(partition,(_,ref2,_))
470 algorithm
471
1/2
✓ Branch 0 taken 806 times.
✗ Branch 1 not taken.
806 failure(canonical(partition,ref2)); // no parent
472 ✗ then (partition, {inDaeEdge}, {});
473
474 // leave the connect(ref1,ref2)
475 case(partition,(ref1,ref2,_))
476 algorithm
477 806 canon1 := canonical(partition,ref1);
478 806 canon2 := canonical(partition,ref2);
479
2/2
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 805 times.
806 (partition, true) := connectCanonicalComponents(partition,canon1,canon2);
480 then (partition, {inDaeEdge}, {});
481
482 // break the connect(ref1, ref2)
483 case(partition,(ref1,ref2,_))
484 algorithm
485 // debug print
486
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
1 if Flags.isSet(Flags.CGRAPH) then
487 ✗ Debug.trace("- ConnectionGraph.connectComponents: should remove equations generated from: connect(" +
488 ComponentReferenceBasics.printComponentRefStr(ref1) + ", " +
489 ComponentReferenceBasics.printComponentRefStr(ref2) + ") and add {0, ..., 0} = equalityConstraint(cr1, cr2) instead.\n");
490 end if;
491 1 then (partition, {}, {inDaeEdge});
492 end matchcontinue;
493 end connectComponents;
494
495 protected function connectCanonicalComponents
496 "Tries to connect two components whose canonical elements are given.
497 Helper function for connectionComponents."
498 input HashTableCG.HashTable inPartition;
499 input DAE.ComponentRef inRef1;
500 input DAE.ComponentRef inRef2;
501 output HashTableCG.HashTable outPartition;
502 output Boolean outReallyConnected;
503 algorithm
504 (outPartition,outReallyConnected) := matchcontinue(inPartition,inRef1,inRef2)
505 local
506 HashTableCG.HashTable partition;
507 DAE.ComponentRef ref1, ref2;
508
509 // they are the same
510 case(partition,ref1,ref2)
511 algorithm
512
2/2
✓ Branch 1 taken 1113 times.
✓ Branch 2 taken 150 times.
1263 true := ComponentReferenceBasics.crefEqualNoStringCompare(ref1, ref2);
513 then (partition, false);
514
515 // not the same, add it
516 case(partition,ref1,ref2)
517 algorithm
518 1113 partition := BaseHashTable.add((ref1,ref2), partition);
519 then (partition, true);
520 end matchcontinue;
521 end connectCanonicalComponents;
522
523 protected function addRootsToTable
524 "Adds a root the the graph. This is implemented by connecting the root to inFirstRoot element."
525 input HashTableCG.HashTable inTable;
526 input list<DAE.ComponentRef> inRoots;
527 input DAE.ComponentRef inFirstRoot;
528 output HashTableCG.HashTable outTable;
529 algorithm
530 outTable := match(inTable, inRoots, inFirstRoot)
531 local
532 HashTableCG.HashTable table;
533 DAE.ComponentRef root, firstRoot;
534 list<DAE.ComponentRef> tail;
535
536 case(table, (root::tail), firstRoot)
537 algorithm
538 20 table := BaseHashTable.add((root,firstRoot), table);
539 20 table := addRootsToTable(table, tail, firstRoot);
540 then table;
541 case(table, {}, _) then table;
542 end match;
543 end addRootsToTable;
544
545 protected function resultGraphWithRoots
546 "Creates an initial graph with given definite roots."
547 input list<DAE.ComponentRef> roots;
548 output HashTableCG.HashTable outTable;
549 protected
550 HashTableCG.HashTable table0;
551 DAE.ComponentRef dummyRoot;
552 algorithm
553 19 dummyRoot := ComponentReferenceBasics.makeCrefIdent("__DUMMY_ROOT", DAE.T_INTEGER_DEFAULT, {});
554 19 table0 := HashTableCG.emptyHashTable();
555 19 outTable := addRootsToTable(table0, roots, dummyRoot);
556 end resultGraphWithRoots;
557
558 protected function addBranchesToTable
559 "Adds all branches to the graph."
560 input HashTableCG.HashTable inTable;
561 input Edges inBranches;
562 output HashTableCG.HashTable outTable;
563 algorithm
564 outTable := match(inTable, inBranches)
565 local
566 HashTableCG.HashTable table, table1, table2;
567 DAE.ComponentRef ref1, ref2;
568 Edges tail;
569
570 case(table, ((ref1,ref2)::tail))
571 algorithm
572 307 table1 := connectBranchComponents(table, ref1, ref2);
573 307 table2 := addBranchesToTable(table1, tail);
574 then table2;
575 case(table, {}) then table;
576 end match;
577 end addBranchesToTable;
578
579 protected function ord
580 "An ordering function for potential roots."
581 input PotentialRoot inEl1;
582 input PotentialRoot inEl2;
583 output Boolean outBoolean;
584 algorithm
585 outBoolean := matchcontinue(inEl1, inEl2)
586 local
587 Real r1, r2;
588 DAE.ComponentRef c1, c2;
589 String s1, s2;
590
591 case((c1,r1), (c2,r2)) // if equal order by cref
592 algorithm
593
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 373 times.
373 true := realEq(r1, r2);
594 373 s1 := ComponentReferenceBasics.printComponentRefStr(c1);
595 373 s2 := ComponentReferenceBasics.printComponentRefStr(c2);
596
2/2
✓ Branch 1 taken 244 times.
✓ Branch 2 taken 129 times.
373 1 := stringCompare(s1, s2);
597 then
598 true;
599
600 case((_,r1), (_,r2))
601 244 then r1 > r2;
602 end matchcontinue;
603 end ord;
604
605 protected function addPotentialRootsToTable
606 "Adds all potential roots to graph."
607 input HashTableCG.HashTable inTable;
608 input PotentialRoots inPotentialRoots;
609 input DefiniteRoots inRoots;
610 input DAE.ComponentRef inFirstRoot;
611 output HashTableCG.HashTable outTable;
612 output DefiniteRoots outRoots;
613 algorithm
614 (outTable,outRoots) := matchcontinue(inTable, inPotentialRoots, inRoots, inFirstRoot)
615 local
616 HashTableCG.HashTable table;
617 DAE.ComponentRef potentialRoot, firstRoot, canon1, canon2;
618 DefiniteRoots roots, finalRoots;
619 PotentialRoots tail;
620
621 19 case(table, {}, roots, _) then (table,roots);
622 case(table, ((potentialRoot,_)::tail), roots, firstRoot)
623 algorithm
624 150 canon1 := canonical(table, potentialRoot);
625 150 canon2 := canonical(table, firstRoot);
626
2/2
✓ Branch 1 taken 149 times.
✓ Branch 2 taken 1 time.
150 (table, true) := connectCanonicalComponents(table, canon1, canon2);
627 1 (table, finalRoots) := addPotentialRootsToTable(table, tail, potentialRoot::roots, firstRoot);
628 then (table, finalRoots);
629 case(table, (_::tail), roots, firstRoot)
630 algorithm
631 149 (table, finalRoots) := addPotentialRootsToTable(table, tail, roots, firstRoot);
632 then (table, finalRoots);
633 end matchcontinue;
634 end addPotentialRootsToTable;
635
636 protected function addConnections
637 "Adds all connections to graph."
638 input HashTableCG.HashTable inTable;
639 input DaeEdges inConnections;
640 output HashTableCG.HashTable outTable;
641 output DaeEdges outConnectedConnections;
642 output DaeEdges outBrokenConnections;
643 algorithm
644 (outTable, outConnectedConnections, outBrokenConnections) := match(inTable, inConnections)
645 local
646 HashTableCG.HashTable table;
647 DaeEdges tail;
648 DaeEdges broken1,broken2,broken,connected1,connected2,connected;
649 DaeEdge e;
650
651 // empty case
652 case(table, {}) then (table, {}, {});
653 // normal case
654 case(table, e::tail)
655 algorithm
656 806 (table, connected1, broken1) := connectComponents(table, e);
657 806 (table, connected2, broken2) := addConnections(table, tail);
658 806 connected := listAppend(connected1, connected2);
659 806 broken := listAppend(broken1, broken2);
660 then (table, connected, broken);
661 end match;
662 end addConnections;
663
664 protected function findResultGraph
665 "Given ConnectionGraph structure, breaks all connections,
666 determines roots and generates a list of dae elements."
667 input ConnectionGraph inGraph;
668 input String modelNameQualified;
669 output DefiniteRoots outRoots;
670 output DaeEdges outConnectedConnections;
671 output DaeEdges outBrokenConnections;
672 algorithm
673 (outRoots, outConnectedConnections, outBrokenConnections) := match inGraph
674 local
675 DefiniteRoots definiteRoots, finalRoots;
676 PotentialRoots potentialRoots, orderedPotentialRoots;
677 UniqueRoots uniqueRoots;
678 Edges branches;
679 DaeEdges connections, broken, connected;
680 HashTableCG.HashTable table;
681 DAE.ComponentRef dummyRoot;
682 String brokenConnectsViaGraphViz;
683 list<String> userBrokenLst;
684 list<list<String>> userBrokenLstLst;
685 list<tuple<String,String>> userBrokenTplLst;
686
687 // deal with empty connection graph
688 case GRAPH(definiteRoots = {}, potentialRoots = {}, uniqueRoots = {}, branches = {}, connections = {})
689 then ({}, {}, {});
690
691 // we have something in the connection graph
692 case GRAPH(definiteRoots = definiteRoots, potentialRoots = potentialRoots, uniqueRoots = uniqueRoots,
693 branches = branches, connections = connections)
694 algorithm
695 // reverse the conenction list to have them as in the model
696 19 connections := listReverse(connections);
697 // add definite roots to the table
698 19 table := resultGraphWithRoots(definiteRoots);
699 // add branches to the table
700 19 table := addBranchesToTable(table, branches);
701 // order potential roots in the order or priority
702 19 orderedPotentialRoots := List.sort(potentialRoots, ord);
703
704
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 19 times.
19 if Flags.isSet(Flags.CGRAPH) then
705 ✗ Debug.traceln("Ordered Potential Roots: " + stringDelimitList(List.map(orderedPotentialRoots, printPotentialRootTuple), ", "));
706 end if;
707
708 // add connections to the table and return the broken/connected connections
709 19 (table, connected, broken) := addConnections(table, connections);
710
711 // create a dummy root
712 19 dummyRoot := ComponentReferenceBasics.makeCrefIdent("__DUMMY_ROOT", DAE.T_INTEGER_DEFAULT, {});
713 // select final roots
714 19 (table, finalRoots) := addPotentialRootsToTable(table, orderedPotentialRoots, definiteRoots, dummyRoot);
715
716 // generate the graphviz representation and display
717 19 brokenConnectsViaGraphViz := generateGraphViz(modelNameQualified, definiteRoots, potentialRoots, uniqueRoots, branches, connections, finalRoots, broken);
718
719
2/4
✓ Branch 0 taken 19 times.
✗ Branch 1 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 19 times.
19 if stringEq(brokenConnectsViaGraphViz, "")
720 then
721 // if brokenConnectsViaGraphViz is empty, the user wants to use the current breaking!
722 else
723 // interpret brokenConnectsViaGraphViz and pass it to the breaking algorithm again
724 // graphviz returns the broken connects as: cr1|cr2#cr3|cr4#
725 ✗ userBrokenLst := Util.stringSplitAtChar(brokenConnectsViaGraphViz, "#");
726 ✗ userBrokenLstLst := List.map1(userBrokenLst, Util.stringSplitAtChar, "|");
727 ✗ userBrokenTplLst := makeTuple(userBrokenLstLst);
728 ✗ Debug.traceln("User selected the following connect edges for breaking:\n\t" + stringDelimitList(List.map(userBrokenTplLst, printTupleStr), "\n\t"));
729 // print("\nBefore ordering:\n");
730 ✗ printDaeEdges(connections);
731 // order the connects with the input given by the user!
732 ✗ connections := orderConnectsGuidedByUser(connections, userBrokenTplLst);
733 // reverse the reverse! uh oh!
734 ✗ connections := listReverse(connections);
735 ✗ print("\nAfer ordering:\n");
736 // printDaeEdges(connections);
737 // call findResultGraph again with ordered connects!
738 ✗ (finalRoots, connected, broken) :=
739 findResultGraph(GRAPH(false, definiteRoots, potentialRoots, uniqueRoots, branches, connections), modelNameQualified);
740 end if;
741
742 19 then
743 (finalRoots, connected, broken);
744
745 end match;
746 end findResultGraph;
747
748 protected function orderConnectsGuidedByUser
749 input DaeEdges inConnections;
750 input list<tuple<String,String>> inUserSelectedBreaking;
751 output DaeEdges outOrderedConnections;
752 protected
753 DaeEdges front = {};
754 DaeEdges back = {};
755 DAE.ComponentRef c1, c2;
756 String sc1,sc2;
757 algorithm
758 ✗ for e in inConnections loop
759 ✗ (c1, c2, _) := e;
760 ✗ sc1 := ComponentReferenceBasics.printComponentRefStr(c1);
761 ✗ sc2 := ComponentReferenceBasics.printComponentRefStr(c2);
762
763 ✗ if listMember((sc1, sc2), inUserSelectedBreaking) or listMember((sc2, sc1), inUserSelectedBreaking) then
764 // put them at the end to be tried last (more chance to be broken)
765 ✗ back := e::back;
766 else
767 // put them at the front to be tried first (less chance to be broken)
768 front := e::front;
769 end if;
770 end for;
771 ✗ outOrderedConnections := List.append_reverse(front, back);
772 end orderConnectsGuidedByUser;
773
774 protected function printTupleStr
775 input tuple<String,String> inTpl;
776 output String out;
777 algorithm
778 out := match inTpl
779 local
780 String c1,c2;
781 ✗ case (c1,c2) then c1 + " -- " + c2;
782 end match;
783 end printTupleStr;
784
785 protected function makeTuple
786 input list<list<String>> inLstLst;
787 output list<tuple<String,String>> outLst;
788 algorithm
789 outLst := matchcontinue inLstLst
790 local
791 String c1,c2;
792 list<list<String>> rest;
793 list<tuple<String,String>> lst;
794 list<String> bad;
795
796 // empty case
797 case {} then {};
798 // somthing case
799 case {c1,c2}::rest
800 algorithm
801 ✗ lst := makeTuple(rest);
802 ✗ then
803 (c1,c2)::lst;
804 // ignore empty strings
805 case {""}::rest
806 algorithm
807 ✗ lst := makeTuple(rest);
808 then
809 lst;
810 // ignore empty list
811 case {}::rest
812 algorithm
813 ✗ lst := makeTuple(rest);
814 then
815 lst;
816 // somthing case
817 case bad::rest
818 algorithm
819 ✗ Debug.traceln("The following output from GraphViz OpenModelica assistant cannot be parsed:" +
820 stringDelimitList(bad, ", ") +
821 "\nExpected format from GrapViz: cref1|cref2#cref3|cref4#. Ignoring malformed input.");
822 ✗ lst := makeTuple(rest);
823 then
824 lst;
825 end matchcontinue;
826 end makeTuple;
827
828 protected function printPotentialRootTuple
829 input PotentialRoot potentialRoot;
830 output String outStr;
831 algorithm
832 outStr := match potentialRoot
833 local
834 DAE.ComponentRef cr;
835 Real priority;
836 String str;
837 case (cr, priority)
838 algorithm
839 ✗ str := ComponentReferenceBasics.printComponentRefStr(cr) + "(" + realString(priority) + ")";
840 then str;
841 end match;
842 end printPotentialRootTuple;
843
844 protected function setRootDistance
845 input list<DAE.ComponentRef> finalRoots;
846 input HashTable3.HashTable table;
847 input Integer distance;
848 input list<DAE.ComponentRef> nextLevel;
849 input HashTable.HashTable irooted;
850 output HashTable.HashTable orooted;
851 algorithm
852 orooted := matchcontinue(finalRoots, nextLevel)
853 local
854 HashTable.HashTable rooted;
855 list<DAE.ComponentRef> rest,next;
856 DAE.ComponentRef cr;
857 case({}, {}) then irooted;
858 case({}, _)
859 792 then
860 setRootDistance(nextLevel,table,distance+1,{},irooted);
861 case(cr::rest, _)
862 algorithm
863
2/2
✓ Branch 1 taken 1112 times.
✓ Branch 2 taken 1133 times.
2245 false := BaseHashTable.hasKey(cr, irooted);
864 1133 rooted := BaseHashTable.add((cr,distance),irooted);
865 1133 next := BaseHashTable.get(cr, table);
866 //print("- ConnectionGraph.setRootDistance: Set Distance " +
867 // ComponentReferenceBasics.printComponentRefStr(cr) + " , " + intString(distance) + "\n");
868 //print("- ConnectionGraph.setRootDistance: add " +
869 // stringDelimitList(List.map(next,ComponentReferenceBasics.printComponentRefStr),"\n") + " to the queue\n");
870 1132 next := listAppend(nextLevel,next);
871 1132 then
872 setRootDistance(rest,table,distance,next,rooted);
873 case(cr::rest, _)
874 algorithm
875
2/2
✓ Branch 1 taken 1112 times.
✓ Branch 2 taken 1 time.
1113 false := BaseHashTable.hasKey(cr, irooted);
876 1 rooted := BaseHashTable.add((cr,distance),irooted);
877 //print("- ConnectionGraph.setRootDistance: Set Distance " +
878 // ComponentReferenceBasics.printComponentRefStr(cr) + " , " + intString(distance) + "\n");
879 1 then
880 setRootDistance(rest,table,distance,nextLevel,rooted);
881 /* case(cr::rest,_,_,_,_)
882 algorithm
883 i = BaseHashTable.get(cr, irooted);
884 print("- ConnectionGraph.setRootDistance: found " +
885 ComponentReferenceBasics.printComponentRefStr(cr) + " twice, value is " + intString(i) + "\n");
886 then
887 setRootDistance(rest,table,distance,nextLevel,irooted);
888 */
889 case (_::rest, _)
890 //equation
891 // print("- ConnectionGraph.setRootDistance: cannot found " + ComponentReferenceBasics.printComponentRefStr(cr) + "\n");
892 1112 then
893 setRootDistance(rest,table,distance,nextLevel,irooted);
894 end matchcontinue;
895 end setRootDistance;
896
897 protected function addBranches
898 input Edge edge;
899 input HashTable3.HashTable itable;
900 output HashTable3.HashTable otable;
901 protected
902 DAE.ComponentRef cref1,cref2;
903 algorithm
904 307 (cref1,cref2) := edge;
905 307 otable := addConnectionRooted(cref1,cref2,itable);
906 307 otable := addConnectionRooted(cref2,cref1,otable);
907 end addBranches;
908
909 protected function addConnectionsRooted
910 input DaeEdge connection;
911 input HashTable3.HashTable itable;
912 output HashTable3.HashTable otable;
913 protected
914 DAE.ComponentRef cref1,cref2;
915 algorithm
916 805 (cref1,cref2,_) := connection;
917 805 otable := addConnectionRooted(cref1,cref2,itable);
918 805 otable := addConnectionRooted(cref2,cref1,otable);
919 end addConnectionsRooted;
920
921 protected function addConnectionRooted
922 input DAE.ComponentRef cref1;
923 input DAE.ComponentRef cref2;
924 input HashTable3.HashTable itable;
925 output HashTable3.HashTable otable;
926 algorithm
927 otable := match itable
928 local
929 HashTable3.HashTable table;
930 list<DAE.ComponentRef> crefs;
931
932 case _
933 algorithm
934 crefs := matchcontinue()
935 2224 case () then BaseHashTable.get(cref1,itable);
936 else {};
937 end matchcontinue;
938 2224 table := BaseHashTable.add((cref1,cref2::crefs),itable);
939 then
940 table;
941
942 end match;
943 end addConnectionRooted;
944
945 protected function evalConnectionsOperators
946 "evaluation of Connections.rooted, Connections.isRoot, Connections.uniqueRootIndices
947 - replaces all [Connections.]rooted calls by true or false depending on wheter branche frame_a or frame_b is closer to root
948 - return true or false for Connections.isRoot operator if is a root or not
949 - return an array of indices for Connections.uniqueRootIndices, see Modelica_StateGraph2
950 See Modelica_StateGraph2:
951 https://github.com/modelica/Modelica_StateGraph2 and
952 https://trac.modelica.org/Modelica/ticket/984 and
953 http://www.ep.liu.se/ecp/043/041/ecp09430108.pdf
954 for a specification of this operator"
955 input list<DAE.ComponentRef> inRoots;
956 input DaeEdges connected "the connections of the spanning tree";
957 input ConnectionGraph graph;
958 input list<DAE.Element> inDae;
959 output list<DAE.Element> outDae;
960 algorithm
961 outDae := match inDae
962 local
963 HashTable.HashTable rooted;
964 HashTable3.HashTable table;
965 Edges branches;
966
967 case {} then {};
968
969 else
970 algorithm
971 // built table
972 19 table := HashTable3.emptyHashTable();
973 // add branches to table
974 19 branches := getBranches(graph);
975 19 table := List.fold(branches,addBranches,table);
976 // add connections to table
977 19 table := List.fold(connected,addConnectionsRooted,table);
978 // get distanste to root
979 // print("Roots: " + stringDelimitList(List.map(inRoots,ComponentReferenceBasics.printComponentRefStr),"\n") + "\n");
980 // BaseHashTable.dumpHashTable(table);
981 19 rooted := setRootDistance(inRoots,table,0,{},HashTable.emptyHashTable());
982 // BaseHashTable.dumpHashTable(rooted);
983 19 (outDae, _) := DAEUtil.traverseDAEElementList(inDae, evalConnectionsOperatorsHelper, (rooted,inRoots,graph));
984 then outDae;
985
986 end match;
987 end evalConnectionsOperators;
988
989 protected function evalConnectionsOperatorsHelper
990 "Helper function for evaluation of Connections.rooted, Connections.isRoot, Connections.uniqueRootIndices"
991 input DAE.Exp inExp;
992 input tuple<HashTable.HashTable,list<DAE.ComponentRef>,ConnectionGraph> inRoots;
993 output DAE.Exp outExp;
994 output tuple<HashTable.HashTable,list<DAE.ComponentRef>,ConnectionGraph> outRoots;
995 algorithm
996 (outExp,outRoots) := matchcontinue (inExp,inRoots)
997 local
998 ConnectionGraph graph;
999 DAE.Exp exp, uroots, nodes, message;
1000 HashTable.HashTable rooted;
1001 DAE.ComponentRef cref,cref1;
1002 Boolean result;
1003 Edges branches;
1004 list<DAE.ComponentRef> roots;
1005 list<DAE.Exp> lst;
1006
1007 // handle rooted - with zero size array
1008 case (DAE.CALL(path=Absyn.IDENT("rooted"), expLst={DAE.ARRAY(array = {})}), (rooted,roots,graph))
1009 algorithm
1010 ✗ if Flags.isSet(Flags.CGRAPH) then
1011 ✗ Debug.traceln("- ConnectionGraph.evalConnectionsOperatorsHelper: " + ExpressionBasics.printExpStr(inExp) + " = false");
1012 end if;
1013 ✗ then
1014 (DAE.BCONST(false), (rooted,roots,graph));
1015
1016 // handle rooted
1017 case (DAE.CALL(path=Absyn.IDENT("rooted"), expLst={DAE.CREF(componentRef = cref)}), (rooted,roots,graph))
1018 algorithm
1019 // find partner in branches
1020 128 branches := getBranches(graph);
1021 128 cref1 := getEdge(cref,branches);
1022 // print("- ConnectionGraph.evalConnectionsOperatorsHelper: Found Branche Partner " +
1023 // ComponentReferenceBasics.printComponentRefStr(cref) + ", " + ComponentReferenceBasics.printComponentRefStr(cref1) + "\n");
1024
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 128 times.
128 if Flags.isSet(Flags.CGRAPH) then
1025 ✗ Debug.traceln("- ConnectionGraph.evalConnectionsOperatorsHelper: Found Branche Partner " +
1026 ComponentReferenceBasics.printComponentRefStr(cref) + ", " + ComponentReferenceBasics.printComponentRefStr(cref1));
1027 end if;
1028 128 result := getRooted(cref,cref1,rooted);
1029 //print("- ConnectionGraph.evalRootedAndIsRootHelper: " +
1030 // ComponentReferenceBasics.printComponentRefStr(cref) + " is " + boolString(result) + " rooted\n");
1031
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 128 times.
128 if Flags.isSet(Flags.CGRAPH) then
1032 ✗ Debug.traceln("- ConnectionGraph.evalConnectionsOperatorsHelper: " + ExpressionBasics.printExpStr(inExp) + " = " + boolString(result));
1033 end if;
1034
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 126 times.
130 then (DAE.BCONST(result), (rooted,roots,graph));
1035
1036 // no roots, same exp
1037 ✗ case (exp, (rooted,roots as {},graph)) then (exp, (rooted,roots,graph));
1038
1039 // deal with Connections.isRoot - with zero size array
1040 case (DAE.CALL(path=Absyn.QUALIFIED("Connections", Absyn.IDENT("isRoot")), expLst={DAE.ARRAY(array = {})}), (rooted,roots,graph))
1041 algorithm
1042 ✗ if Flags.isSet(Flags.CGRAPH) then
1043 ✗ Debug.traceln("- ConnectionGraph.evalConnectionsOperatorsHelper: " + ExpressionBasics.printExpStr(inExp) + " = false");
1044 end if;
1045 ✗ then
1046 (DAE.BCONST(false), (rooted,roots,graph));
1047
1048 // deal with NOT Connections.isRoot - with zero size array
1049 case (DAE.LUNARY(DAE.NOT(_), DAE.CALL(path=Absyn.QUALIFIED("Connections", Absyn.IDENT("isRoot")), expLst={DAE.ARRAY(array = {})})), (rooted,roots,graph))
1050 algorithm
1051 ✗ if Flags.isSet(Flags.CGRAPH) then
1052 ✗ Debug.traceln("- ConnectionGraph.evalConnectionsOperatorsHelper: " + ExpressionBasics.printExpStr(inExp) + " = false");
1053 end if;
1054 ✗ then
1055 (DAE.BCONST(false), (rooted,roots,graph));
1056
1057 // deal with Connections.isRoot
1058 case (DAE.CALL(path=Absyn.QUALIFIED("Connections", Absyn.IDENT("isRoot")), expLst={DAE.CREF(componentRef = cref)}), (rooted,roots,graph))
1059 algorithm
1060 ✗ result := List.isMemberOnTrue(cref, roots, ComponentReferenceBasics.crefEqualNoStringCompare);
1061 ✗ if Flags.isSet(Flags.CGRAPH) then
1062 ✗ Debug.traceln("- ConnectionGraph.evalConnectionsOperatorsHelper: " + ExpressionBasics.printExpStr(inExp) + " = " + boolString(result));
1063 end if;
1064 ✗ then (DAE.BCONST(result), (rooted,roots,graph));
1065
1066 // deal with NOT Connections.isRoot
1067 case (DAE.LUNARY(DAE.NOT(_), DAE.CALL(path=Absyn.QUALIFIED("Connections", Absyn.IDENT("isRoot")), expLst={DAE.CREF(componentRef = cref)})), (rooted,roots,graph))
1068 algorithm
1069 151 result := List.isMemberOnTrue(cref, roots, ComponentReferenceBasics.crefEqualNoStringCompare);
1070 result := boolNot(result);
1071
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 151 times.
151 if Flags.isSet(Flags.CGRAPH) then
1072 ✗ Debug.traceln("- ConnectionGraph.evalConnectionsOperatorsHelper: " + ExpressionBasics.printExpStr(inExp) + " = " + boolString(result));
1073 end if;
1074
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 149 times.
153 then (DAE.BCONST(result), (rooted,roots,graph));
1075
1076 // deal with Connections.uniqueRootIndices, TODO! FIXME! actually implement this
1077 case (DAE.CALL(path=Absyn.QUALIFIED("Connections", Absyn.IDENT("uniqueRootIndices")),
1078 expLst={uroots as DAE.ARRAY(array = lst),nodes,message}), (rooted,roots,graph))
1079 algorithm
1080 ✗ if Flags.isSet(Flags.CGRAPH) then
1081 ✗ Debug.traceln("- ConnectionGraph.evalConnectionsOperatorsHelper: Connections.uniqueRootsIndicies(" +
1082 ExpressionBasics.printExpStr(uroots) + "," +
1083 ExpressionBasics.printExpStr(nodes) + "," +
1084 ExpressionBasics.printExpStr(message) + ")");
1085 end if;
1086 ✗ lst := List.fill(DAE.ICONST(1), listLength(lst)); // TODO! FIXME! actually implement this correctly
1087 ✗ then
1088 (DAE.ARRAY(DAE.T_INTEGER_DEFAULT, false, lst), (rooted,roots,graph));
1089
1090 // no replacement needed
1091 else (inExp, inRoots);
1092 // fprintln(Flags.CGRAPH, ExpressionBasics.printExpStr(exp) + " not found in roots!");
1093 end matchcontinue;
1094 end evalConnectionsOperatorsHelper;
1095
1096 protected function getRooted
1097 input DAE.ComponentRef cref1;
1098 input DAE.ComponentRef cref2;
1099 input HashTable.HashTable rooted;
1100 output Boolean result;
1101 algorithm
1102 result := matchcontinue rooted
1103 local
1104 Integer i1,i2;
1105 case _
1106 algorithm
1107 128 i1 := BaseHashTable.get(cref1,rooted);
1108 128 i2 := BaseHashTable.get(cref2,rooted);
1109 128 then
1110 intLt(i1,i2);
1111 // in faile case return true
1112 else
1113 then
1114 true;
1115 end matchcontinue;
1116 end getRooted;
1117
1118 protected function getEdge
1119 "return the Edge partner of a edge, fails if not found"
1120 input DAE.ComponentRef cr;
1121 input Edges edges;
1122 output DAE.ComponentRef ocr;
1123 algorithm
1124 ocr := matchcontinue edges
1125 local
1126 Edges rest;
1127 DAE.ComponentRef cref1,cref2;
1128 case (cref1,cref2)::_
1129 algorithm
1130 3464 cref1 := getEdge1(cr,cref1,cref2);
1131 then
1132 cref1;
1133 case _::rest
1134 3336 then
1135 getEdge(cr,rest);
1136 end matchcontinue;
1137 end getEdge;
1138
1139 protected function getEdge1
1140 "return the Edge partner of a edge, fails if not found"
1141 input DAE.ComponentRef cr;
1142 input DAE.ComponentRef cref1;
1143 input DAE.ComponentRef cref2;
1144 output DAE.ComponentRef ocr;
1145 algorithm
1146 ocr := matchcontinue cref2
1147 case _
1148 algorithm
1149
2/2
✓ Branch 1 taken 3336 times.
✓ Branch 2 taken 128 times.
3464 true := ComponentReferenceBasics.crefEqualNoStringCompare(cr,cref1);
1150 then
1151 cref2;
1152 else
1153 algorithm
1154
1/2
✓ Branch 1 taken 3336 times.
✗ Branch 2 not taken.
3336 true := ComponentReferenceBasics.crefEqualNoStringCompare(cr,cref2);
1155 then
1156 cref1;
1157 end matchcontinue;
1158 end getEdge1;
1159
1160 protected function printConnectionStr
1161 "prints the connection str"
1162 input DaeEdge connectTuple;
1163 input String ty;
1164 output String outStr;
1165 algorithm
1166 outStr := match connectTuple
1167 local
1168 DAE.ComponentRef c1, c2;
1169 String str;
1170
1171 case (c1, c2, _)
1172 algorithm
1173 ✗ str := ty + "(" +
1174 ComponentReferenceBasics.printComponentRefStr(c1) +
1175 ", " +
1176 ComponentReferenceBasics.printComponentRefStr(c2) +
1177 ")";
1178 then str;
1179 end match;
1180 end printConnectionStr;
1181
1182 protected function printEdges
1183 "Prints a list of edges to stdout."
1184 input Edges inEdges;
1185 algorithm
1186 () := match inEdges
1187 local
1188 DAE.ComponentRef c1, c2;
1189 Edges tail;
1190
1191 case {} then ();
1192 case (c1, c2) :: tail
1193 algorithm
1194 ✗ print(" ");
1195 ✗ print(ComponentReferenceBasics.printComponentRefStr(c1));
1196 ✗ print(" -- ");
1197 ✗ print(ComponentReferenceBasics.printComponentRefStr(c2));
1198 ✗ print("\n");
1199 ✗ printEdges(tail);
1200 then ();
1201 end match;
1202 end printEdges;
1203
1204 protected function printDaeEdges
1205 "Prints a list of dae edges to stdout."
1206 input DaeEdges inEdges;
1207 algorithm
1208 () := match inEdges
1209 local
1210 DAE.ComponentRef c1, c2;
1211 DaeEdges tail;
1212
1213 case {} then ();
1214
1215 case (c1, c2, _) :: tail
1216 algorithm
1217 ✗ print(" ");
1218 ✗ print(ComponentReferenceBasics.printComponentRefStr(c1));
1219 ✗ print(" -- ");
1220 ✗ print(ComponentReferenceBasics.printComponentRefStr(c2));
1221 ✗ print("\n");
1222 ✗ printDaeEdges(tail);
1223 then ();
1224 end match;
1225 end printDaeEdges;
1226
1227 protected function printConnectionGraph
1228 "Prints the content of ConnectionGraph structure."
1229 input ConnectionGraph inGraph;
1230 algorithm
1231 () := match inGraph
1232 local
1233 DaeEdges connections;
1234 Edges branches;
1235
1236 case GRAPH(connections = connections, branches = branches)
1237 algorithm
1238 ✗ print("Connections:\n");
1239 ✗ printDaeEdges(connections);
1240 ✗ print("Branches:\n");
1241 ✗ printEdges(branches);
1242 then ();
1243 end match;
1244 end printConnectionGraph;
1245
1246 protected function getDefiniteRoots
1247 "Accessor for ConnectionGraph.definiteRoots."
1248 input ConnectionGraph inGraph;
1249 output DefiniteRoots outResult;
1250 algorithm
1251 outResult := match inGraph
1252 local
1253 DefiniteRoots result;
1254 case GRAPH(definiteRoots = result) then result;
1255 end match;
1256 end getDefiniteRoots;
1257
1258 protected function getUniqueRoots
1259 "Accessor for ConnectionGraph.uniqueRoots."
1260 input ConnectionGraph inGraph;
1261 output UniqueRoots outResult;
1262 algorithm
1263 outResult := match inGraph
1264 local
1265 UniqueRoots result;
1266 case GRAPH(uniqueRoots = result) then result;
1267 end match;
1268 end getUniqueRoots;
1269
1270 protected function getPotentialRoots
1271 "Accessor for ConnectionGraph.potentialRoots."
1272 input ConnectionGraph inGraph;
1273 output PotentialRoots outResult;
1274 algorithm
1275 outResult := match inGraph
1276 local PotentialRoots result;
1277 case GRAPH(potentialRoots = result) then result;
1278 end match;
1279 end getPotentialRoots;
1280
1281 protected function getBranches
1282 "Accessor for ConnectionGraph.branches."
1283 input ConnectionGraph inGraph;
1284 output Edges outResult;
1285 algorithm
1286 outResult := match inGraph
1287 local Edges result;
1288 case GRAPH(branches = result) then result;
1289 end match;
1290 end getBranches;
1291
1292 protected function getConnections
1293 "Accessor for ConnectionGraph.connections."
1294 input ConnectionGraph inGraph;
1295 output DaeEdges outResult;
1296 algorithm
1297 outResult := match inGraph
1298 local DaeEdges result;
1299 case GRAPH(connections = result) then result;
1300 end match;
1301 end getConnections;
1302
1303 public function merge
1304 "merge two ConnectionGraphs"
1305 input ConnectionGraph inGraph1;
1306 input ConnectionGraph inGraph2;
1307 output ConnectionGraph outGraph;
1308 algorithm
1309 outGraph := match(inGraph1, inGraph2)
1310 local
1311 Boolean updateGraph, updateGraph1, updateGraph2;
1312 DefiniteRoots definiteRoots, definiteRoots1, definiteRoots2;
1313 UniqueRoots uniqueRoots, uniqueRoots1, uniqueRoots2;
1314 PotentialRoots potentialRoots, potentialRoots1, potentialRoots2;
1315 Edges branches, branches1, branches2;
1316 DaeEdges connections, connections1, connections2;
1317
1318 // left is empty, return right
1319 case (_, GRAPH(definiteRoots = {},potentialRoots = {},uniqueRoots = {},branches = {},connections = {}))
1320 then
1321 inGraph1;
1322
1323 // right is empty, return left
1324 case (GRAPH(definiteRoots = {},potentialRoots = {},uniqueRoots = {},branches = {},connections = {}), _)
1325 then
1326 inGraph2;
1327
1328 // they are equal, return any
1329 case (_, _) guard valueEq(inGraph1, inGraph2)
1330 then
1331 inGraph1;
1332
1333 // they are NOT equal, merge them
1334 case (GRAPH(updateGraph = updateGraph1, definiteRoots = definiteRoots1, potentialRoots = potentialRoots1, uniqueRoots=uniqueRoots1,
1335 branches = branches1, connections = connections1),
1336 GRAPH(updateGraph = updateGraph2, definiteRoots = definiteRoots2, potentialRoots = potentialRoots2, uniqueRoots=uniqueRoots2,
1337 branches = branches2,connections = connections2))
1338 algorithm
1339 ✗ if Flags.isSet(Flags.CGRAPH) then
1340 ✗ Debug.trace("- ConnectionGraph.merge()\n");
1341 end if;
1342 ✗ updateGraph := boolOr(updateGraph1, updateGraph2);
1343 ✗ definiteRoots := List.union(definiteRoots1, definiteRoots2);
1344 ✗ potentialRoots := List.union(potentialRoots1, potentialRoots2);
1345 ✗ uniqueRoots := List.union(uniqueRoots1, uniqueRoots2);
1346 ✗ branches := List.union(branches1, branches2);
1347 ✗ connections := List.union(connections1, connections2);
1348 ✗ then
1349 GRAPH(updateGraph,definiteRoots,potentialRoots,uniqueRoots,branches,connections);
1350 end match;
1351 end merge;
1352
1353 /***********************************************************************************************************************/
1354 /******************************************* GraphViz generation *******************************************************/
1355 /***********************************************************************************************************************/
1356
1357 protected function graphVizEdge
1358 input Edge inEdge;
1359 output String out;
1360 algorithm
1361 out := match inEdge
1362 local DAE.ComponentRef c1, c2; String strEdge;
1363 case (c1, c2)
1364 algorithm
1365 ✗ strEdge := "\"" + ComponentReferenceBasics.printComponentRefStr(c1) + "\" -- \"" + ComponentReferenceBasics.printComponentRefStr(c2) + "\"" +
1366 " [color = blue, dir = \"none\", fontcolor=blue, label = \"branch\"];\n\t";
1367 then strEdge;
1368 end match;
1369 end graphVizEdge;
1370
1371 protected function graphVizDaeEdge
1372 input DaeEdge inDaeEdge;
1373 input DaeEdges inBrokenDaeEdges;
1374 output String out;
1375 algorithm
1376 out := match inDaeEdge
1377 local
1378 DAE.ComponentRef c1, c2;
1379 String sc1, sc2, strDaeEdge, label, labelFontSize, decorate, color, style, fontColor;
1380 Boolean isBroken;
1381
1382 case (c1, c2, _)
1383 algorithm
1384 ✗ isBroken := listMember(inDaeEdge, inBrokenDaeEdges);
1385 ✗ label := if isBroken then "[[broken connect]]" else "connect";
1386 ✗ color := if isBroken then "red" else "green";
1387 ✗ style := if isBroken then "\"bold, dashed\"" else "solid";
1388 ✗ decorate := boolString(isBroken);
1389 fontColor := if isBroken then "red" else "green";
1390 ✗ labelFontSize := if isBroken then "labelfontsize = 20.0, " else "";
1391 ✗ sc1 := ComponentReferenceBasics.printComponentRefStr(c1);
1392 ✗ sc2 := ComponentReferenceBasics.printComponentRefStr(c2);
1393 ✗ strDaeEdge := stringAppendList({
1394 "\"", sc1, "\" -- \"", sc2, "\" [",
1395 "dir = \"none\", ",
1396 "style = ", style, ", ",
1397 "decorate = ", decorate, ", ",
1398 "color = ", color , ", ",
1399 labelFontSize,
1400 "fontcolor = ", fontColor , ", ",
1401 "label = \"", label ,"\"",
1402 "];\n\t"});
1403 then strDaeEdge;
1404 end match;
1405 end graphVizDaeEdge;
1406
1407 protected function graphVizDefiniteRoot
1408 input DefiniteRoot inDefiniteRoot;
1409 input DefiniteRoots inFinalRoots;
1410 output String out;
1411 algorithm
1412 out := match inDefiniteRoot
1413 local DAE.ComponentRef c; String strDefiniteRoot; Boolean isSelectedRoot;
1414 case c
1415 algorithm
1416 ✗ isSelectedRoot := listMember(c, inFinalRoots);
1417 ✗ strDefiniteRoot := "\"" + ComponentReferenceBasics.printComponentRefStr(c) + "\"" +
1418 " [fillcolor = red, rank = \"source\", label = " + "\"" + ComponentReferenceBasics.printComponentRefStr(c) + "\", " +
1419 (if isSelectedRoot then "shape=polygon, sides=8, distortion=\"0.265084\", orientation=26, skew=\"0.403659\"" else "shape=box") +
1420 "];\n\t";
1421 then strDefiniteRoot;
1422 end match;
1423 end graphVizDefiniteRoot;
1424
1425 protected function graphVizPotentialRoot
1426 input PotentialRoot inPotentialRoot;
1427 input DefiniteRoots inFinalRoots;
1428 output String out;
1429 algorithm
1430 out := match inPotentialRoot
1431 local DAE.ComponentRef c; Real priority; String strPotentialRoot; Boolean isSelectedRoot;
1432 case (c, priority)
1433 algorithm
1434 ✗ isSelectedRoot := listMember(c, inFinalRoots);
1435 ✗ strPotentialRoot := "\"" + ComponentReferenceBasics.printComponentRefStr(c) + "\"" +
1436 " [fillcolor = orangered, rank = \"min\" label = " + "\"" + ComponentReferenceBasics.printComponentRefStr(c) + "\\n" + realString(priority) + "\", " +
1437 (if isSelectedRoot then "shape=ploygon, sides=7, distortion=\"0.265084\", orientation=26, skew=\"0.403659\"" else "shape=box") +
1438 "];\n\t";
1439 then strPotentialRoot;
1440 end match;
1441 end graphVizPotentialRoot;
1442
1443 protected function generateGraphViz
1444 "@author: adrpo
1445 Generate a graphviz file out of the connection graph"
1446 input String modelNameQualified;
1447 input DefiniteRoots definiteRoots;
1448 input PotentialRoots potentialRoots;
1449 input UniqueRoots uniqueRoots;
1450 input Edges branches;
1451 input DaeEdges connections;
1452 input DefiniteRoots finalRoots;
1453 input DaeEdges broken;
1454 output String brokenConnectsViaGraphViz;
1455 algorithm
1456 brokenConnectsViaGraphViz := matchcontinue broken
1457 local
1458 String fileName, i, nrDR, nrPR, nrUR, nrBR, nrCO, nrFR, nrBC, timeStr, infoNodeStr, brokenConnects;
1459 Real tStart, tEnd, t;
1460 IOStream.IOStream graphVizStream;
1461 list<String> infoNode;
1462
1463 // don't do anything if we don't have -d=cgraphGraphVizFile or -d=cgraphGraphVizShow
1464 case _
1465 algorithm
1466
2/4
✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 19 times.
19 false := boolOr(Flags.isSet(Flags.CGRAPH_GRAPHVIZ_FILE), Flags.isSet(Flags.CGRAPH_GRAPHVIZ_SHOW));
1467 then
1468 "";
1469
1470 case _
1471 algorithm
1472 ✗ tStart := clock();
1473 i := "\t";
1474 ✗ fileName := stringAppend(modelNameQualified, ".gv");
1475 // create a stream
1476 ✗ graphVizStream := IOStream.create(fileName, IOStream.LIST());
1477 ✗ nrDR := intString(listLength(definiteRoots));
1478 ✗ nrPR := intString(listLength(potentialRoots));
1479 ✗ nrUR := intString(listLength(uniqueRoots));
1480 ✗ nrBR := intString(listLength(branches));
1481 ✗ nrCO := intString(listLength(connections));
1482 ✗ nrFR := intString(listLength(finalRoots));
1483 ✗ nrBC := intString(listLength(broken));
1484
1485 infoNode :=
1486 {
1487 "// Generated by OpenModelica. \n",
1488 "// Overconstrained connection graph for model: \n// ", modelNameQualified, "\n",
1489 "// \n",
1490 "// Summary: \n",
1491 "// Roots: ", nrDR, "\n",
1492 "// Potential Roots: ", nrPR, "\n",
1493 "// Unique Roots: ", nrUR, "\n",
1494 "// Branches: ", nrBR, "\n",
1495 "// Connections: ", nrCO, "\n",
1496 "// Final Roots: ", nrFR, "\n",
1497 "// Broken Connections: ", nrBC, "\n"
1498 };
1499 ✗ infoNodeStr := stringAppendList(infoNode);
1500 // replace \n with \\l (left align), replace \t with " "
1501 ✗ infoNodeStr := System.stringReplace(infoNodeStr, "\n", "\\l"); infoNodeStr := System.stringReplace(infoNodeStr, "\t", " ");
1502 // replace / with ""
1503 ✗ infoNodeStr := System.stringReplace(infoNodeStr, "/", "");
1504
1505 // output header
1506 ✗ graphVizStream := IOStream.appendList(graphVizStream,infoNode);
1507 // output command to be used
1508 // output graphviz header
1509 ✗ graphVizStream := IOStream.appendList(graphVizStream,{"\n\n"});
1510 ✗ graphVizStream := IOStream.appendList(graphVizStream, {"graph \"", modelNameQualified, "\"\n{\n\n"});
1511
1512 // output global settings
1513 ✗ graphVizStream := IOStream.appendList(graphVizStream, {i, "overlap=false;\n"});
1514 ✗ graphVizStream := IOStream.appendList(graphVizStream, {i, "layout=dot;\n\n"});
1515
1516 // output settings for nodes
1517 ✗ graphVizStream := IOStream.appendList(graphVizStream, {i, "node [",
1518 "fillcolor = \"lightsteelblue1\", ",
1519 "shape = box, ",
1520 "style = \"bold, filled\", ",
1521 "rank = \"max\"","]\n\n"});
1522 // output settings for edges
1523 ✗ graphVizStream := IOStream.appendList(graphVizStream, {i, "edge [",
1524 "color = \"black\", ",
1525 "style = bold",
1526 "]\n\n"});
1527
1528 // output summary node
1529 ✗ graphVizStream := IOStream.appendList(graphVizStream, {i, "graph [fontsize=20, fontname = \"Courier Bold\" label= \"\\n\\n", infoNodeStr, "\", size=\"6,6\"];\n", i});
1530
1531 // output definite roots
1532 ✗ graphVizStream := IOStream.appendList(graphVizStream, {"\n", i, "// Definite Roots (Connections.root)", "\n", i});
1533 ✗ graphVizStream := IOStream.appendList(graphVizStream, List.map1(definiteRoots, graphVizDefiniteRoot, finalRoots));
1534 // output potential roots
1535 ✗ graphVizStream := IOStream.appendList(graphVizStream, {"\n", i, "// Potential Roots (Connections.potentialRoot)", "\n", i});
1536 ✗ graphVizStream := IOStream.appendList(graphVizStream, List.map1(potentialRoots, graphVizPotentialRoot, finalRoots));
1537
1538 // output branches
1539 ✗ graphVizStream := IOStream.appendList(graphVizStream, {"\n", i, "// Branches (Connections.branch)", "\n", i});
1540 ✗ graphVizStream := IOStream.appendList(graphVizStream, List.map(branches, graphVizEdge));
1541
1542 // output connections
1543 ✗ graphVizStream := IOStream.appendList(graphVizStream, {"\n", i, "// Connections (connect)", "\n", i});
1544 ✗ graphVizStream := IOStream.appendList(graphVizStream, List.map1(connections, graphVizDaeEdge, broken));
1545
1546 // output graphviz footer
1547 ✗ graphVizStream := IOStream.appendList(graphVizStream, {"\n}\n"});
1548 ✗ tEnd := clock();
1549 ✗ t := tEnd - tStart;
1550 ✗ timeStr := realString(t);
1551 ✗ graphVizStream := IOStream.appendList(graphVizStream, {"\n\n\n// graph generation took: ", timeStr, " seconds\n"});
1552 ✗ System.writeFile(fileName, IOStream.string(graphVizStream));
1553 ✗ Debug.traceln("GraphViz with connection graph for model: " + modelNameQualified + " was writen to file: " + fileName);
1554 ✗ brokenConnects := showGraphViz(fileName, modelNameQualified);
1555 then
1556 brokenConnects;
1557
1558 end matchcontinue;
1559 end generateGraphViz;
1560
1561 protected function showGraphViz
1562 input String fileNameGraphViz;
1563 input String modelNameQualified;
1564 output String brokenConnectsViaGraphViz;
1565 algorithm
1566 brokenConnectsViaGraphViz := matchcontinue modelNameQualified
1567 local
1568 String leftyCMD, fileNameTraceRemovedConnections, omhome, brokenConnects;
1569 Integer leftyExitStatus;
1570
1571 // do not start graphviz if we don't have -d=cgraphGraphVizShow
1572 case _
1573 algorithm
1574 ✗ false := Flags.isSet(Flags.CGRAPH_GRAPHVIZ_SHOW);
1575 then
1576 "";
1577
1578 else
1579 algorithm
1580 ✗ fileNameTraceRemovedConnections := modelNameQualified + "_removed_connections.txt";
1581 ✗ Debug.traceln("Tyring to start GraphViz *lefty* to visualize the graph. You need to have lefty in your PATH variable");
1582 ✗ Debug.traceln("Make sure you quit GraphViz *lefty* via Right Click->quit to be sure the process will be exited.");
1583 ✗ Debug.traceln("If you quit the GraphViz *lefty* window via X, please kill the process in task manager to continue.");
1584 ✗ omhome := Settings.getInstallationDirectoryPath();
1585 ✗ omhome := System.stringReplace(omhome, "\"", "");
1586 // omhome = System.stringReplace(omhome, "\\", "/");
1587
1588 // create a lefty command and execute it
1589 ✗ leftyCMD := "load('" + omhome + "/share/omc/scripts/openmodelica.lefty');" + "openmodelica.init();openmodelica.createviewandgraph('" +
1590 fileNameGraphViz + "','file',null,null);txtview('off');";
1591 ✗ Debug.traceln("Running command: " + "lefty -e " + leftyCMD + " > " + fileNameTraceRemovedConnections);
1592 // execute lefty
1593 ✗ leftyExitStatus := System.systemCall("lefty -e " + leftyCMD, fileNameTraceRemovedConnections);
1594 // show the exit status
1595 ✗ Debug.traceln("GraphViz *lefty* exited with status:" + intString(leftyExitStatus));
1596 ✗ brokenConnects := System.readFile(fileNameTraceRemovedConnections);
1597 ✗ Debug.traceln("GraphViz OpenModelica assistant returned the following broken connects: " + brokenConnects);
1598 then
1599 brokenConnects;
1600 end matchcontinue;
1601 end showGraphViz;
1602
1603 public function removeBrokenConnects
1604 "@author adrpo:
1605 this function BROKEN removes the connects from the connection set
1606 and keeps the CONNECTED ones.
1607 Basically is implmented like this:
1608 1. remove all the broken connects from the inConnects -> newConnects
1609 2. add all the connected connects BACK to newConnects"
1610 input list<Connect.ConnectorElement> inConnects;
1611 input DaeEdges inConnected;
1612 input DaeEdges inBroken;
1613 output list<list<Connect.ConnectorElement>> outConnects "we return a list of lists of elements as a particular connection set might be broken into several!";
1614 algorithm
1615 outConnects := match inBroken
1616 local
1617 list<DAE.ComponentRef> toRemove, toKeep, intersect;
1618 list<Connect.ConnectorElement> cset;
1619 list<list<Connect.ConnectorElement>> csets;
1620
1621 // if we have no broken then we don't care!
1622 case {} then {inConnects};
1623
1624 // if we have nothing toRemove then we don't care!
1625 case _
1626 algorithm
1627 198 toRemove := filterFromSet(inConnects, inBroken, {}, "removed");
1628
1629
2/2
✓ Branch 0 taken 186 times.
✓ Branch 1 taken 12 times.
198 if listEmpty(toRemove)
1630 then
1631 csets := {inConnects};
1632 else
1633 12 toKeep := filterFromSet(inConnects, inConnected, {}, "allowed");
1634 12 intersect := List.intersectionOnTrue(toRemove, toKeep, ComponentReferenceBasics.crefEqualNoStringCompare);
1635
1636
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 if Flags.isSet(Flags.CGRAPH)
1637 then
1638 ✗ Debug.traceln("- ConnectionGraph.removeBrokenConnects: CS: " +
1639 stringDelimitList(List.map(inConnects, ConnectUtil.printElementStr), "\n"));
1640 ✗ Debug.traceln("- ConnectionGraph.removeBrokenConnects: keep: " +
1641 stringDelimitList(List.map(toKeep, ComponentReferenceBasics.printComponentRefStr), ", "));
1642 ✗ Debug.traceln("- ConnectionGraph.removeBrokenConnects: delete: " +
1643 stringDelimitList(List.map(toRemove, ComponentReferenceBasics.printComponentRefStr), ", "));
1644 ✗ Debug.traceln("- ConnectionGraph.removeBrokenConnects: allow = remove - keep: " +
1645 stringDelimitList(List.map(intersect, ComponentReferenceBasics.printComponentRefStr), ", "));
1646 end if;
1647
1648 12 toRemove := List.setDifference(toRemove, intersect);
1649
1650
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 if Flags.isSet(Flags.CGRAPH) then
1651 ✗ Debug.traceln("- ConnectionGraph.removeBrokenConnects: allow - delete: " +
1652 stringDelimitList(List.map(toRemove, ComponentReferenceBasics.printComponentRefStr), ", "));
1653 end if;
1654
1655 12 cset := removeFromConnects(inConnects, toRemove);
1656 12 csets := splitSetByAllowed(cset, inConnected);
1657 /*
1658 if Flags.isSet(Flags.CGRAPH) then
1659 for cset in csets loop
1660 Debug.traceln("- ConnectionGraph.removeBrokenConnects: FINALCS: -------");
1661 Debug.traceln("- ConnectionGraph.removeBrokenConnects: FINALCS: " +
1662 stringDelimitList(List.map(inConnects, ConnectUtil.printElementStr), "\n"));
1663 Debug.traceln("- ConnectionGraph.removeBrokenConnects: FINALCS: -------");
1664 end for;
1665 end if;
1666 */
1667 end if;
1668
1669 then csets;
1670
1671 end match;
1672 end removeBrokenConnects;
1673
1674 protected function splitSetByAllowed
1675 input list<Connect.ConnectorElement> inConnects;
1676 input DaeEdges inConnected;
1677 output list<list<Connect.ConnectorElement>> outConnects "we return a list of lists of elements as a particular connection set might be broken into several!";
1678 protected
1679 list<Connect.ConnectorElement> cset;
1680 list<list<Connect.ConnectorElement>> csets;
1681 DaeEdge e;
1682 DAE.ComponentRef cr1, cr2;
1683 Connect.ConnectorElement ce;
1684 algorithm
1685 csets := {};
1686
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 12 times.
204 for e in inConnected loop
1687 cset := {};
1688 192 (cr1, cr2, _) := e;
1689
2/2
✓ Branch 0 taken 384 times.
✓ Branch 1 taken 192 times.
576 for ce in inConnects loop
1690
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 372 times.
384 if ComponentReferenceBasics.crefPrefixOf(cr1, ce.name) then
1691 cset := ce::cset;
1692 end if;
1693
2/2
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 372 times.
384 if ComponentReferenceBasics.crefPrefixOf(cr2, ce.name) then
1694 cset := ce::cset;
1695 end if;
1696 end for;
1697
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 180 times.
192 if not listEmpty(cset)
1698 then
1699 csets := cset::csets;
1700 end if;
1701 end for;
1702 outConnects := csets;
1703 end splitSetByAllowed;
1704
1705 protected function filterFromSet
1706 "@author: adrpo
1707 given an EQU set filter the given DaeEdges"
1708 input list<Connect.ConnectorElement> inConnects;
1709 input DaeEdges inFilter;
1710 input list<DAE.ComponentRef> inAcc;
1711 input String msg;
1712 output list<DAE.ComponentRef> filteredCrefs;
1713 algorithm
1714 filteredCrefs := matchcontinue inFilter
1715 local
1716 DAE.ComponentRef c1, c2;
1717 DaeEdges rest;
1718 list<DAE.ComponentRef> filtered;
1719
1720 210 case {} then List.unique(inAcc);
1721
1722 // both are there and append crefs to the filter list!
1723 case (c1, c2, _)::rest
1724 algorithm
1725
2/2
✓ Branch 1 taken 366 times.
✓ Branch 2 taken 24 times.
390 true := ConnectUtil.isReferenceInConnects(inConnects, c1);
1726
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
24 true := ConnectUtil.isReferenceInConnects(inConnects, c2);
1727
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 24 times.
24 if Flags.isSet(Flags.CGRAPH) then
1728 ✗ Debug.traceln("- ConnectionGraph.filterFromSet: " + msg + " connect(" + ComponentReferenceBasics.printComponentRefStr(c1) + ", " + ComponentReferenceBasics.printComponentRefStr(c2) + ")");
1729 end if;
1730 24 filtered := filterFromSet(inConnects, rest, c1::c2::inAcc, msg);
1731 then
1732 filtered;
1733
1734 // some are not there, move forward ...
1735 case _::rest
1736 algorithm
1737 366 filtered := filterFromSet(inConnects, rest, inAcc, msg);
1738 then
1739 filtered;
1740 end matchcontinue;
1741 end filterFromSet;
1742
1743 protected function removeFromConnects
1744 input list<Connect.ConnectorElement> inConnects;
1745 input list<DAE.ComponentRef> inToRemove;
1746 output list<Connect.ConnectorElement> outConnects;
1747 algorithm
1748 outConnects := match(inConnects, inToRemove)
1749 local
1750 DAE.ComponentRef c;
1751 list<DAE.ComponentRef> rest;
1752 list<Connect.ConnectorElement> cset;
1753
1754 case (_, {}) then inConnects;
1755
1756 case (cset, c::rest)
1757 algorithm
1758
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 (cset, true) := ConnectUtil.removeReferenceFromConnects(cset, c);
1759 12 cset := removeFromConnects(cset, rest);
1760 then
1761 cset;
1762 end match;
1763 end removeFromConnects;
1764
1765 public function addBrokenEqualityConstraintEquations
1766 "@author: adrpo
1767 adds all the equalityConstraint equations from broken connections"
1768 input DAE.DAElist inDAE;
1769 input DaeEdges inBroken;
1770 output DAE.DAElist outDAE;
1771 algorithm
1772 outDAE := match inBroken
1773 local
1774 list<DAE.Element> equalityConstraintElements;
1775 DAE.DAElist dae;
1776
1777 case {} then inDAE;
1778
1779 else
1780 algorithm
1781 1 equalityConstraintElements := List.flatten(List.map(inBroken, Util.tuple33));
1782 1 dae := DAEUtil.joinDaes(DAE.DAE(equalityConstraintElements), inDAE);
1783 then
1784 dae;
1785
1786 end match;
1787 end addBrokenEqualityConstraintEquations;
1788
1789 annotation(__OpenModelica_Interface="frontend");
1790 end ConnectionGraph;
1791