Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 83.9% 449 / 0 / 535
Functions: -% 0 / 1 / 1
Branches: 73.2% 221 / 0 / 302

OMCompiler/Compiler/FrontEnd/ConnectUtil.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 ConnectUtil
37 " file: ConnectUtil.mo
38 package: ConnectUtil
39 description: Connection set management
40
41
42 Connections generate connection sets (datatype SET is described in Connect)
43 which are constructed during instantiation. When a connection
44 set is generated, it is used to create a number of equations.
45 The kind of equations created depends on the type of the set.
46
47 ConnectUtil.mo is called from Inst.mo and is responsible for
48 creation of all connect-equations later passed to the DAE module
49 in DAEUtil.mo."
50
51 // public imports
52 public
53 import Absyn;
54 import AbsynUtil;
55 import SCode;
56 import ClassInf;
57 import Config;
58 import DAE.Connect;
59 import DAE;
60 import FCore;
61 import InnerOuter;
62 import ConnectionGraph;
63
64 // protected imports
65 protected
66 import ComponentReference;
67 protected import ComponentReferenceBasics;
68 import DAEUtil;
69 import Debug;
70 import ElementSource;
71 import Error;
72 import Expression;
73 protected import ExpressionBasics;
74 import ExpressionDump;
75 import ExpressionSimplify;
76 import Flags;
77 import List;
78 import Lookup;
79 import PrefixUtil;
80 import SCodeUtil;
81 import System;
82 import Types;
83 import Util;
84 import Values;
85 import Global;
86
87 // Import some types from Connect.
88 import DAE.Connect.{Face,ConnectorType,ConnectorElement,SetTrieNode,SetTrie,SetConnection,OuterConnect,Sets,Set};
89
90 // Set graph represented as an adjacency list.
91 protected type SetGraph = array<list<Integer>>;
92
93 public function newSet
94 "This function creates a 'new' set for the given prefix. This means that it
95 makes a set with a new empty trie, but copies the set count and connection
96 crefs from the old set. This is done because we don't need to propagate
97 connections down in the instance hierarchy, but the list of connection crefs
98 needs to be propagated to be able to evaluate the cardinality operator. See
99 comments in addSet below for how the sets are merged later."
100 input DAE.Prefix prefix;
101 input output Sets sets;
102 protected
103 String pstr;
104 Integer sc;
105 DAE.ComponentRef cr;
106 algorithm
107 923777 Sets.SETS(setCount = sc) := sets;
108
109 try
110 923777 cr := PrefixUtil.prefixFirstCref(prefix);
111 544025 pstr := ComponentReferenceBasics.printComponentRefStr(cr);
112 else
113 cr := DAE.WILD();
114 pstr := "";
115 end try;
116
117 923777 sets := Sets.SETS(SetTrieNode.SET_TRIE_NODE(pstr, cr, {}, 0), sc, {}, {});
118 end newSet;
119
120 public function addSet
121 "This function adds a child set to a parent set."
122 input Sets parentSets;
123 input Sets childSets;
124 output Sets sets;
125 algorithm
126 sets := matchcontinue(parentSets, childSets)
127 local
128 list<SetConnection> c1, c2;
129 list<OuterConnect> o1, o2;
130 Integer sc;
131 SetTrieNode node;
132
133 // If the child set is empty we don't need to add it.
134 case (_, _) guard isEmptySet(childSets)
135 then parentSets;
136
137 // If both sets are nameless, i.e. a top scope set, just return the child
138 // set as it is. This is to avoid getting nestled top scope sets in some
139 // cases, and the child should be a superset of the parent.
140 case (Sets.SETS(sets = SetTrieNode.SET_TRIE_NODE(cref = DAE.WILD())),
141 Sets.SETS(sets = SetTrieNode.SET_TRIE_NODE(cref = DAE.WILD())))
142 then childSets;
143
144 // Check if the node already exists. In that case it's probably due to
145 // multiple inheritance and we should ignore it.
146 case (Sets.SETS(sets = node as SetTrieNode.SET_TRIE_NODE()),
147 Sets.SETS())
148 algorithm
149 6023 setTrieGetNode(setTrieNodeName(childSets.sets), node.nodes);
150 then
151 parentSets;
152
153 // In the normal case we add the trie on the child sets to the parent, and
154 // also merge their lists of outer connects.
155 case (Sets.SETS(node as SetTrieNode.SET_TRIE_NODE(), _, c1, o1),
156 Sets.SETS(_, sc, c2, o2))
157 algorithm
158 6010 c1 := listAppend(c2, c1);
159 6010 o1 := listAppend(o2, o1);
160 12020 node.nodes := childSets.sets :: node.nodes;
161 6010 then
162 Sets.SETS(node, sc, c1, o1);
163
164 end matchcontinue;
165 end addSet;
166
167 protected function isEmptySet
168 "Check if a given set is empty."
169 input Sets sets;
170 output Boolean isEmpty;
171 algorithm
172 isEmpty := match sets
173 case Sets.SETS(sets = SetTrieNode.SET_TRIE_NODE(nodes = {}),
174 connections = {}, outerConnects = {}) then true;
175 else false;
176 end match;
177 end isEmptySet;
178
179 public function addConnection
180 "Adds a new connection by looking up both the given connector elements in the
181 set trie and merging the sets together."
182 input output Sets sets;
183 input DAE.ComponentRef cref1;
184 input Face face1;
185 input DAE.ComponentRef cref2;
186 input Face face2;
187 input DAE.ConnectorType connectorType;
188 input DAE.ElementSource source;
189 protected
190 ConnectorElement e1, e2;
191 ConnectorType ty;
192 algorithm
193 28041 ty := makeConnectorType(connectorType);
194 28041 e1 := findElement(cref1, face1, ty, source, sets);
195 28041 e2 := findElement(cref2, face2, ty, source, sets);
196 28041 sets := mergeSets(e1, e2, sets);
197 end addConnection;
198
199 protected function getConnectCount
200 input DAE.ComponentRef cref;
201 input SetTrie trie;
202 output Integer count;
203 protected
204 SetTrieNode node;
205 algorithm
206 try
207 760 node := setTrieGet(cref, trie, false);
208
209 count := match node
210 683 case SetTrieNode.SET_TRIE_NODE() then node.connectCount;
211 ✗ case SetTrieNode.SET_TRIE_LEAF() then node.connectCount;
212 end match;
213 else
214 count := 0;
215 end try;
216 end getConnectCount;
217
218 public function addArrayConnection
219 "Connects two arrays of connectors."
220 input output Sets sets;
221 input DAE.ComponentRef cref1;
222 input Face face1;
223 input DAE.ComponentRef cref2;
224 input Face face2;
225 input DAE.ElementSource source;
226 input DAE.ConnectorType connectorType;
227 protected
228 list<DAE.ComponentRef> crefs1, crefs2;
229 DAE.ComponentRef cr2;
230 algorithm
231 4359 crefs1 := ComponentReference.expandCref(cref1, false);
232 4359 crefs2 := ComponentReference.expandCref(cref2, false);
233
234
2/2
✓ Branch 0 taken 17638 times.
✓ Branch 1 taken 4359 times.
21997 for cr1 in crefs1 loop
235
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17638 times.
17638 cr2 :: crefs2 := crefs2;
236 17638 sets := addConnection(sets, cr1, face1, cr2, face2, connectorType, source);
237 end for;
238 end addArrayConnection;
239
240 protected function makeConnectorType
241 "Creates a connector type from the flow or stream prefix given."
242 input DAE.ConnectorType connectorType;
243 output ConnectorType ty;
244 protected
245 Option<DAE.ComponentRef> flowName;
246 algorithm
247 ty := match connectorType
248 case DAE.POTENTIAL() then ConnectorType.EQU();
249 case DAE.FLOW() then ConnectorType.FLOW();
250 81 case DAE.STREAM(flowName) then ConnectorType.STREAM(flowName);
251 case DAE.NON_CONNECTOR() then ConnectorType.NO_TYPE();
252 else
253 algorithm
254 ✗ Error.addMessage(Error.INTERNAL_ERROR,
255 {"ConnectUtil.makeConnectorType: invalid connector type."});
256 ✗ then
257 fail();
258 end match;
259 end makeConnectorType;
260
261 public function addConnectorVariablesFromDAE
262 "If the class state indicates a connector, this function adds all flow
263 variables in the dae as inside connectors to the connection sets."
264 input Boolean ignore;
265 input ClassInf.State classState;
266 input DAE.Prefix prefix;
267 input list<DAE.Var> vars;
268 input SourceInfo info;
269 input DAE.ElementSource elementSource;
270 input output Sets sets;
271 algorithm
272 sets := match classState
273 local
274 Absyn.Path class_path;
275 list<DAE.Var> streams, flows;
276
277 case ClassInf.CONNECTOR(path = class_path, isExpandable = false) guard not ignore
278 algorithm
279 // Check balance of non expandable connectors.
280 4386 checkConnectorBalance(vars, class_path, info);
281
282 // Add flow variables as inside connectors, unless disabled by flag.
283
1/2
✓ Branch 1 taken 4386 times.
✗ Branch 2 not taken.
4386 if not Flags.isSet(Flags.DISABLE_SINGLE_FLOW_EQ) then
284 4386 (flows, streams) := getStreamAndFlowVariables(vars);
285 4386 sets := List.fold2(flows, addFlowVariableFromDAE, elementSource, prefix, sets);
286 4386 sets := addStreamFlowAssociations(sets, prefix, streams, flows);
287 end if;
288 then
289 sets;
290
291 else sets;
292 end match;
293 end addConnectorVariablesFromDAE;
294
295 protected function addFlowVariableFromDAE
296 "Adds a flow variable from the DAE to the sets as an inside flow variable."
297 input DAE.Var variable;
298 input DAE.ElementSource elementSource;
299 input DAE.Prefix prefix;
300 input output Sets sets;
301 protected
302 list<DAE.ComponentRef> crefs;
303 algorithm
304 5005 crefs := daeVarToCrefs(variable);
305
306
2/2
✓ Branch 0 taken 9637 times.
✓ Branch 1 taken 5005 times.
14642 for cr in crefs loop
307 9637 sets := addInsideFlowVariable(sets, cr, elementSource, prefix);
308 end for;
309 end addFlowVariableFromDAE;
310
311 public function isExpandable
312 input DAE.ComponentRef name;
313 output Boolean expandableConnector;
314 algorithm
315 expandableConnector := match name
316 case DAE.CREF_IDENT()
317 127264 then Types.isExpandableConnector(name.identType);
318
319 case DAE.CREF_QUAL()
320
4/4
✓ Branch 1 taken 340019 times.
✓ Branch 2 taken 6211 times.
✓ Branch 4 taken 10355 times.
✓ Branch 5 taken 329664 times.
346230 then Types.isExpandableConnector(name.identType) or
321 isExpandable(name.componentRef);
322
323 else false;
324
325 end match;
326 end isExpandable;
327
328 protected function daeHasExpandableConnectors
329 "Checks if a DAE contains any expandable connectors."
330 input DAE.DAElist DAE;
331 output Boolean hasExpandable;
332 protected
333 list<DAE.Element> vars;
334 algorithm
335
2/2
✓ Branch 1 taken 125 times.
✓ Branch 2 taken 914 times.
1039 if System.getHasExpandableConnectors() then
336 125 DAE.DAE(vars) := DAE;
337 125 hasExpandable := List.any(vars, isVarExpandable);
338 else
339 hasExpandable := false;
340 end if;
341 end daeHasExpandableConnectors;
342
343 protected function isVarExpandable
344 input DAE.Element var;
345 output Boolean isExpandable;
346 algorithm
347 isExpandable := match var
348 98601 case DAE.VAR() then isExpandable(var.componentRef);
349 else false;
350 end match;
351 end isVarExpandable;
352
353 protected function getExpandableVariablesWithNoBinding
354 "@author: adrpo
355 Goes through a list of expandable variables
356 THAT HAVE NO BINDING and returns their crefs"
357 input list<DAE.Element> variables;
358 output list<DAE.ComponentRef> potential = {};
359 protected
360 DAE.ComponentRef name;
361 algorithm
362
2/2
✓ Branch 0 taken 13320 times.
✓ Branch 1 taken 7 times.
13327 for var in variables loop
363 () := match var
364 // do not return the ones that have a binding as they are used
365 // TODO: actually only if their binding is not another expandable??!!
366 case DAE.VAR(componentRef = name, binding = NONE())
367 algorithm
368
2/2
✓ Branch 1 taken 2084 times.
✓ Branch 2 taken 5319 times.
7403 if isExpandable(name) then
369 potential := name :: potential;
370 end if;
371 then
372 ();
373
374 else ();
375 end match;
376 end for;
377 end getExpandableVariablesWithNoBinding;
378
379 protected function getStreamAndFlowVariables
380 "Goes through a list of variables and filters out all flow and stream
381 variables into separate lists."
382 input list<DAE.Var> variables;
383 output list<DAE.Var> flows = {};
384 output list<DAE.Var> streams = {};
385 algorithm
386
2/2
✓ Branch 0 taken 11921 times.
✓ Branch 1 taken 4386 times.
16307 for var in variables loop
387 () := match var
388 case DAE.TYPES_VAR(attributes = DAE.ATTR(connectorType = DAE.FLOW()))
389 algorithm
390 flows := var :: flows;
391 then
392 ();
393
394 case DAE.TYPES_VAR(attributes = DAE.ATTR(connectorType = DAE.STREAM()))
395 algorithm
396 streams := var :: streams;
397 then
398 ();
399
400 else ();
401 end match;
402 end for;
403 end getStreamAndFlowVariables;
404
405 protected function addStreamFlowAssociations
406 "Adds information to the connection sets about which flow variables each
407 stream variable is associated to."
408 input output Sets sets;
409 input DAE.Prefix prefix;
410 input list<DAE.Var> streamVars;
411 input list<DAE.Var> flowVars;
412 protected
413 DAE.Var flow_var;
414 DAE.ComponentRef flow_cr;
415 list<DAE.ComponentRef> stream_crs;
416 algorithm
417 // No stream variables => not a stream connector.
418
2/2
✓ Branch 0 taken 4265 times.
✓ Branch 1 taken 121 times.
4386 if listEmpty(streamVars) then
419 4265 return;
420 end if;
421
422 // Stream variables and exactly one flow => add associations.
423
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 121 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 121 times.
121 {flow_var} := flowVars;
424
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 121 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 121 times.
121 {flow_cr} := daeVarToCrefs(flow_var);
425 121 flow_cr := PrefixUtil.prefixCrefNoContext(prefix, flow_cr);
426
427
2/2
✓ Branch 0 taken 321 times.
✓ Branch 1 taken 121 times.
442 for stream_var in streamVars loop
428 321 stream_crs := daeVarToCrefs(stream_var);
429
430
2/2
✓ Branch 0 taken 174 times.
✓ Branch 1 taken 321 times.
495 for stream_cr in stream_crs loop
431 174 sets := addStreamFlowAssociation(stream_cr, flow_cr, sets);
432 end for;
433 end for;
434 end addStreamFlowAssociations;
435
436 protected function daeVarToCrefs
437 "Converts a DAE.Var to a list of crefs."
438 input DAE.Var var;
439 output list<DAE.ComponentRef> crefs;
440 protected
441 String name;
442 DAE.Type ty;
443 list<DAE.ComponentRef> crs;
444 DAE.Dimensions dims;
445 DAE.ComponentRef cr;
446 algorithm
447 5447 DAE.TYPES_VAR(name = name, ty = ty) := var;
448 5447 ty := Types.derivedBasicType(ty);
449
450 crefs := match ty
451 // Scalar
452 2924 case DAE.T_REAL() then {DAE.CREF_IDENT(name, ty, {})};
453
454 // Complex type
455 case DAE.T_COMPLEX()
456 algorithm
457 ✗ crs := listAppend(daeVarToCrefs(v) for v in listReverse(ty.varLst));
458 ✗ cr := DAE.CREF_IDENT(name, DAE.T_REAL_DEFAULT, {});
459 ✗ then
460 list(ComponentReference.joinCrefs(cr, c) for c in crs);
461
462 // Array
463 case DAE.T_ARRAY()
464 algorithm
465 2523 dims := TypesDump.getDimensions(ty);
466 2523 cr := DAE.CREF_IDENT(name, ty, {});
467 2523 then
468 expandArrayCref(cr, dims);
469
470 else
471 algorithm
472 ✗ Error.addInternalError("Unknown var " + name +
473 " in ConnectUtil.daeVarToCrefs", sourceInfo());
474 ✗ then
475 fail();
476
477 end match;
478 end daeVarToCrefs;
479
480 protected function expandArrayCref
481 "This function takes an array cref and a list of dimensions, and generates all
482 scalar crefs by expanding the dimensions into subscripts."
483 input DAE.ComponentRef cref;
484 input DAE.Dimensions dims;
485 input list<DAE.ComponentRef> accumCrefs = {};
486 output list<DAE.ComponentRef> crefs;
487 algorithm
488 crefs := matchcontinue dims
489 local
490 DAE.Dimension dim;
491 DAE.Dimensions rest_dims;
492 DAE.Exp idx;
493 DAE.ComponentRef cr;
494 list<DAE.ComponentRef> crs;
495
496 case {} then cref :: accumCrefs;
497
498 case dim :: rest_dims
499 algorithm
500 9531 (idx, dim) := getNextIndex(dim);
501 14016 cr := ComponentReference.subscriptCref(cref, {DAE.INDEX(idx)});
502 7008 crs := expandArrayCref(cr, rest_dims, accumCrefs);
503 7008 crs := expandArrayCref(cref, dim :: rest_dims, crs);
504 then
505 crs;
506
507 else accumCrefs;
508
509 end matchcontinue;
510 end expandArrayCref;
511
512 protected function reverseEnumType
513 "Reverses the order of the literals in an enumeration dimension, or just
514 returns the given dimension if it's not an enumeration. This is used by
515 getNextIndex that starts from the end, so that it can take the first literal
516 in the list instead of the last (more efficient)."
517 input output DAE.Dimension dim;
518 algorithm
519 () := match dim
520 case DAE.DIM_ENUM()
521 algorithm
522 ✗ dim.literals := listReverse(dim.literals);
523 then
524 ();
525
526 else ();
527 end match;
528 end reverseEnumType;
529
530 protected function getNextIndex
531 "Returns the next index given a dimension, and updates the dimension. Fails
532 when there are no indices left."
533 input DAE.Dimension dim;
534 output DAE.Exp nextIndex;
535 output DAE.Dimension restDim;
536 algorithm
537 (nextIndex, restDim) := match dim
538 local
539 Integer new_idx, dim_size;
540 Absyn.Path p, ep;
541 String l;
542 list<String> l_rest;
543
544 2523 case DAE.DIM_INTEGER(integer = 0) then fail();
545 ✗ case DAE.DIM_ENUM(size = 0) then fail();
546
547 case DAE.DIM_INTEGER(integer = new_idx)
548 algorithm
549 7008 dim_size := new_idx - 1;
550 7008 then
551 (DAE.ICONST(new_idx), DAE.DIM_INTEGER(dim_size));
552
553 // Assumes that the enum has been reversed with reverseEnumType.
554 case DAE.DIM_ENUM(p, l :: l_rest, new_idx)
555 algorithm
556 ✗ ep := AbsynUtil.joinPaths(p, Absyn.IDENT(l));
557 ✗ dim_size := new_idx - 1;
558 ✗ then
559 (DAE.ENUM_LITERAL(ep, new_idx), DAE.DIM_ENUM(p, l_rest, dim_size));
560 end match;
561 end getNextIndex;
562
563 protected function addInsideFlowVariable
564 "Adds a single inside flow variable to the connection sets."
565 input output Sets sets;
566 input DAE.ComponentRef cref;
567 input DAE.ElementSource source;
568 input DAE.Prefix prefix;
569 protected
570 ConnectorElement e;
571 algorithm
572 try
573 // Check if it exists in the sets already.
574 9637 setTrieGetElement(cref, Face.INSIDE(), sets.sets);
575 else
576 // Otherwise, add a new set for it.
577 9637 sets.setCount := sets.setCount + 1;
578 9637 e := newElement(cref, Face.INSIDE(), ConnectorType.FLOW(), source, sets.setCount);
579 9637 sets.sets := setTrieAdd(e, sets.sets);
580 end try;
581 end addInsideFlowVariable;
582
583 protected function addStreamFlowAssociation
584 "Adds an association between a stream variable and a flow."
585 input DAE.ComponentRef streamCref;
586 input DAE.ComponentRef flowCref;
587 input output Sets sets;
588 algorithm
589 174 sets := updateSetLeaf(sets, streamCref, flowCref, addStreamFlowAssociation2);
590 end addStreamFlowAssociation;
591
592 protected function addStreamFlowAssociation2
593 "Helper function to addSTreamFlowAssocication, sets the flow association in a
594 leaf node."
595 input DAE.ComponentRef flowCref;
596 input output SetTrieNode node;
597 algorithm
598 () := match node
599 case SetTrieNode.SET_TRIE_LEAF()
600 algorithm
601 174 node.flowAssociation := SOME(flowCref);
602 then
603 ();
604 end match;
605 end addStreamFlowAssociation2;
606
607 protected function getStreamFlowAssociation
608 "Returns the associated flow variable for a stream variable."
609 input DAE.ComponentRef streamCref;
610 input Sets sets;
611 output DAE.ComponentRef flowCref;
612 algorithm
613
3/6
✗ Branch 1 not taken.
✓ Branch 2 taken 18 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 18 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 18 times.
18 SetTrieNode.SET_TRIE_LEAF(flowAssociation = SOME(flowCref)) :=
614 setTrieGet(streamCref, sets.sets, false);
615 end getStreamFlowAssociation;
616
617 public function addOuterConnection
618 "Adds a connection with a reference to an outer connector These are added to a
619 special list, such that they can be moved up in the instance hierarchy to a
620 place where both instances are defined."
621 input DAE.Prefix scope;
622 input output Sets sets;
623 input DAE.ComponentRef cr1;
624 input DAE.ComponentRef cr2;
625 input Absyn.InnerOuter io1;
626 input Absyn.InnerOuter io2;
627 input Face f1;
628 input Face f2;
629 input DAE.ElementSource source;
630 protected
631 OuterConnect new_oc;
632 algorithm
633 // Only add a new outer connection if it doesn't already exist in the list.
634
1/2
✗ Branch 3 not taken.
✓ Branch 4 taken 10 times.
10 if not List.any(sets.outerConnects, function outerConnectionMatches(cr1 = cr1, cr2 = cr2)) then
635 10 new_oc := OuterConnect.OUTERCONNECT(scope, cr1, io1, f1, cr2, io2, f2, source);
636 20 sets.outerConnects := new_oc :: sets.outerConnects;
637 end if;
638 end addOuterConnection;
639
640 protected function outerConnectionMatches
641 "Returns true if Connect.OuterConnect matches the two component references
642 passed as argument."
643 input OuterConnect oc;
644 input DAE.ComponentRef cr1;
645 input DAE.ComponentRef cr2;
646 output Boolean matches;
647 algorithm
648 matches := match oc
649 case OuterConnect.OUTERCONNECT()
650
2/8
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 time.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
1 then ComponentReferenceBasics.crefEqual(oc.cr1,cr1) and ComponentReferenceBasics.crefEqual(oc.cr2,cr2) or
651 ComponentReferenceBasics.crefEqual(oc.cr1,cr2) and ComponentReferenceBasics.crefEqual(oc.cr2,cr1);
652 end match;
653 end outerConnectionMatches;
654
655 public function addOuterConnectToSets
656 "Adds an outer connection to all sets where a corresponding inner definition
657 is present. For instance, if a connection set contains {world.v, topPin.v} and
658 we have an outer connection connect(world, a2.aPin), the connection is added
659 to the sets, resulting in {world.v, topPin.v, a2.aPin.v}. Returns the updated
660 sets and a boolean that indicates if anything was added or not."
661 input DAE.ComponentRef cref1;
662 input DAE.ComponentRef cref2;
663 input Absyn.InnerOuter io1;
664 input Absyn.InnerOuter io2;
665 input Face face1;
666 input Face face2;
667 input output Sets sets;
668 input SourceInfo inInfo;
669 output Boolean added;
670 protected
671 Boolean is_outer1, is_outer2;
672 algorithm
673 10 is_outer1 := AbsynUtil.isOuter(io1);
674 10 is_outer2 := AbsynUtil.isOuter(io2);
675
676 added := match(is_outer1, is_outer2)
677 // Both are outer => error.
678 case (true, true)
679 algorithm
680 ✗ Error.addSourceMessage(Error.UNSUPPORTED_LANGUAGE_FEATURE,
681 {"Connections where both connectors are outer references", "No suggestion"}, inInfo);
682 then
683 false;
684
685 // Both are inner => do nothing.
686 case (false, false) then false;
687
688 // The first is outer and the second inner, call addOuterConnectToSets2.
689 case (true, false)
690 algorithm
691 4 (sets, added) := addOuterConnectToSets2(cref1, cref2, face1, face2, sets);
692 4 then
693 added;
694
695 // The first is inner and the second outer, call addOuterConnectToSets2 with
696 // reversed order on the components compared to above.
697 case (false, true)
698 algorithm
699 2 (sets, added) := addOuterConnectToSets2(cref2, cref1, face2, face1, sets);
700 2 then
701 added;
702 end match;
703 end addOuterConnectToSets;
704
705 protected function addOuterConnectToSets2
706 "Helper function to addOuterConnectToSets. Tries to add connections between
707 the inner and outer components."
708 input DAE.ComponentRef outerCref;
709 input DAE.ComponentRef innerCref;
710 input Face outerFace;
711 input Face innerFace;
712 input output Sets sets;
713 output Boolean added;
714 protected
715 SetTrieNode node;
716 list<ConnectorElement> outer_els, inner_els;
717 Integer sc;
718 algorithm
719 try
720 // Find the trie node for the outer component.
721 6 node := setTrieGet(outerCref, sets.sets, true);
722 // Collect all connector elements in the node.
723 4 outer_els := collectOuterElements(node, outerFace);
724 // Find or create inner elements corresponding to the outer elements.
725
4/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 2 times.
10 inner_els := list(findInnerElement(oe, innerCref, innerFace, sets) for oe in outer_els);
726 // Merge the inner and outer sets pairwise from the two lists.
727 2 sc := sets.setCount;
728 2 sets := List.threadFold(outer_els, inner_els, mergeSets, sets);
729 // Check if the number of sets changed.
730 2 added := sc <> sets.setCount;
731 else
732 added := false;
733 end try;
734 end addOuterConnectToSets2;
735
736 protected function collectOuterElements
737 "Collects all connector elements with a certain face from a trie node."
738 input SetTrieNode node;
739 input Face face;
740 output list<ConnectorElement> outerElements;
741 algorithm
742 outerElements := match node
743 case SetTrieNode.SET_TRIE_NODE()
744 4 then List.mapFlat(node.nodes, function collectOuterElements2(face = face, prefix = NONE()));
745
746 ✗ else collectOuterElements2(node, face, NONE());
747 end match;
748 end collectOuterElements;
749
750 protected function collectOuterElements2
751 "Helper function to collectOuterElements."
752 input SetTrieNode node;
753 input Face face;
754 input Option<DAE.ComponentRef> prefix;
755 output list<ConnectorElement> outerElements;
756 algorithm
757 outerElements := match node
758 local
759 DAE.ComponentRef cr;
760 list<SetTrieNode> nodes;
761 ConnectorElement e;
762
763 case SetTrieNode.SET_TRIE_NODE(cref = cr)
764 algorithm
765 ✗ cr := optPrefixCref(prefix, cr);
766 ✗ then
767 List.mapFlat(node.nodes, function collectOuterElements2(face = face, prefix = SOME(cr)));
768
769 case SetTrieNode.SET_TRIE_LEAF()
770 algorithm
771 10 e := setTrieGetLeafElement(node, face);
772 cr := getElementName(e);
773 8 e := setElementName(e, optPrefixCref(prefix, cr));
774 then
775 {e};
776
777 end match;
778 end collectOuterElements2;
779
780 protected function findInnerElement
781 "Finds or creates an inner element based on a given outer element."
782 input ConnectorElement outerElement;
783 input DAE.ComponentRef innerCref;
784 input Face innerFace;
785 input Sets sets;
786 output ConnectorElement innerElement;
787 protected
788 DAE.ComponentRef name;
789 ConnectorType ty;
790 DAE.ElementSource src;
791 algorithm
792 8 ConnectorElement.CONNECTOR_ELEMENT(name = name, ty = ty, source = src) := outerElement;
793 8 name := ComponentReference.joinCrefs(innerCref, name);
794 8 innerElement := findElement(name, innerFace, ty, src, sets);
795 end findInnerElement;
796
797 protected function optPrefixCref
798 "Appends an optional prefix to a cref."
799 input Option<DAE.ComponentRef> prefix;
800 input output DAE.ComponentRef cref;
801 algorithm
802 cref := match prefix
803 local
804 DAE.ComponentRef cr;
805
806 case NONE() then cref;
807 ✗ case SOME(cr) then ComponentReference.joinCrefs(cr, cref);
808
809 end match;
810 end optPrefixCref;
811
812 protected function findElement
813 "Tries to find a connector element in the sets given a cref and a face. If no
814 element can be found it creates a new one."
815 input DAE.ComponentRef cref;
816 input Face face;
817 input ConnectorType ty;
818 input DAE.ElementSource source;
819 input Sets sets;
820 output ConnectorElement element;
821 algorithm
822 try
823 56263 element := setTrieGetElement(cref, face, sets.sets);
824 else
825 34425 element := newElement(cref, face, ty, source, Connect.NEW_SET);
826 end try;
827 end findElement;
828
829 protected function newElement
830 "Creates a new connector element."
831 input DAE.ComponentRef cref;
832 input Face face;
833 input ConnectorType ty;
834 input DAE.ElementSource source;
835 input Integer set;
836 output ConnectorElement element;
837 algorithm
838 44062 element := ConnectorElement.CONNECTOR_ELEMENT(cref, face, ty, source, set);
839 end newElement;
840
841 protected function isNewElement
842 "Checks if the element is new, i.e. hasn't been assigned to a set yet."
843 input ConnectorElement element;
844 output Boolean isNew;
845 protected
846 Integer set;
847 algorithm
848 56271 ConnectorElement.CONNECTOR_ELEMENT(set = set) := element;
849 28049 isNew := set == Connect.NEW_SET;
850 end isNewElement;
851
852 protected function getElementSetIndex
853 "Returns the set index of a connector element."
854 input ConnectorElement inElement;
855 output Integer outIndex;
856 algorithm
857 7309 ConnectorElement.CONNECTOR_ELEMENT(set = outIndex) := inElement;
858 end getElementSetIndex;
859
860 protected function setElementSetIndex
861 "Sets the set index of a connector element."
862 input output ConnectorElement element;
863 input Integer index;
864 algorithm
865 34407 element.set := index;
866 end setElementSetIndex;
867
868 protected function getElementName
869 "Returns the name of a connector element."
870 input ConnectorElement element;
871 output DAE.ComponentRef name;
872 algorithm
873 8 ConnectorElement.CONNECTOR_ELEMENT(name = name) := element;
874 end getElementName;
875
876 protected function setElementName
877 "Sets the name of a connector element."
878 input output ConnectorElement element;
879 input DAE.ComponentRef name;
880 algorithm
881 44052 element.name := name;
882 end setElementName;
883
884 protected function getElementSource
885 "Returns the element source of a connector element."
886 input ConnectorElement element;
887 output DAE.ElementSource source;
888 algorithm
889 5528 ConnectorElement.CONNECTOR_ELEMENT(source = source) := element;
890 end getElementSource;
891
892 protected function setTrieNewLeaf
893 "Creates a new trie leaf."
894 input String id;
895 input ConnectorElement element;
896 output SetTrieNode leaf;
897 algorithm
898 leaf := match element
899 case ConnectorElement.CONNECTOR_ELEMENT(face = Face.INSIDE())
900 ✗ then SetTrieNode.SET_TRIE_LEAF(id, SOME(element), NONE(), NONE(), 0);
901
902 case ConnectorElement.CONNECTOR_ELEMENT(face = Face.OUTSIDE())
903 ✗ then SetTrieNode.SET_TRIE_LEAF(id, NONE(), SOME(element), NONE(), 0);
904
905 end match;
906 end setTrieNewLeaf;
907
908 protected function setTrieNewNode
909 "Creates a new trie node."
910 input DAE.ComponentRef cref;
911 input ConnectorElement element;
912 output SetTrieNode node;
913 algorithm
914 node := match cref
915 local
916 String id;
917 DAE.ComponentRef cr;
918
919 // A simple identifier, just create a new leaf.
920 case DAE.CREF_IDENT()
921 algorithm
922 ✗ id := ComponentReferenceBasics.printComponentRefStr(cref);
923 ✗ then
924 setTrieNewLeaf(id, setElementName(element, cref));
925
926 // A qualified identifier, call this function recursively.
927 // I.e. a.b.c becomes NODE(a, {NODE(b, {NODE(c)})});
928 case DAE.CREF_QUAL()
929 algorithm
930 ✗ cr := ComponentReferenceBasics.crefFirstCref(cref);
931 ✗ id := ComponentReferenceBasics.printComponentRefStr(cr);
932 ✗ node := setTrieNewNode(cref.componentRef, element);
933 ✗ then
934 SetTrieNode.SET_TRIE_NODE(id, cr, {node}, 0);
935
936 end match;
937 end setTrieNewNode;
938
939 protected function setTrieNodeName
940 input SetTrieNode node;
941 output String name;
942 algorithm
943 name := match node
944 619381 case SetTrieNode.SET_TRIE_NODE() then node.name;
945 401776 case SetTrieNode.SET_TRIE_LEAF() then node.name;
946 end match;
947 end setTrieNodeName;
948
949 protected function mergeSets
950 "Merges two sets."
951 input ConnectorElement element1;
952 input ConnectorElement element2;
953 input output Sets sets;
954 protected
955 Boolean new1, new2;
956 algorithm
957 new1 := isNewElement(element1);
958 new2 := isNewElement(element2);
959 28049 sets := mergeSets2(element1, element2, new1, new2, sets);
960 end mergeSets;
961
962 protected function mergeSets2
963 "Helper function to mergeSets, dispatches to the correct function based on if
964 the elements are new or not."
965 input ConnectorElement element1;
966 input ConnectorElement element2;
967 input Boolean isNew1;
968 input Boolean isNew2;
969 input output Sets sets;
970 algorithm
971 sets := match(isNew1, isNew2)
972 // Both elements are new, add them to a new set.
973 13667 case (true, true) then addNewSet(element1, element2, sets);
974
975 // The first is new and the second old, add the first to the same set as the
976 // second.
977 1839 case (true, false) then addToSet(element1, element2, sets);
978
979 // The second is new and the first old, add the second to the same set as
980 // the first.
981 5234 case (false, true) then addToSet(element2, element1, sets);
982
983 // Both sets are old, add a connection between their sets.
984 7309 case (false, false) then connectSets(element1, element2, sets);
985 end match;
986 end mergeSets2;
987
988 protected function addNewSet
989 "Adds a new set containing the given two elements to the sets."
990 input ConnectorElement element1;
991 input ConnectorElement element2;
992 input output Sets sets;
993 protected
994 SetTrie node;
995 Integer sc;
996 ConnectorElement e1, e2;
997 algorithm
998 13667 sc := sets.setCount + 1;
999 13667 e1 := setElementSetIndex(element1, sc);
1000 13667 e2 := setElementSetIndex(element2, sc);
1001 13667 node := sets.sets;
1002 13667 node := setTrieAdd(e1, node);
1003 13667 sets.sets := setTrieAdd(e2, node);
1004 sets.setCount := sc;
1005 end addNewSet;
1006
1007 protected function addToSet
1008 "Adds the first connector element to the same set as the second."
1009 input ConnectorElement element;
1010 input ConnectorElement set;
1011 input output Sets sets;
1012 protected
1013 Integer index;
1014 ConnectorElement e;
1015 algorithm
1016 index := getElementSetIndex(set);
1017 7073 e := setElementSetIndex(element, index);
1018 7073 sets.sets := setTrieAdd(e, sets.sets);
1019 end addToSet;
1020
1021 protected function connectSets
1022 "Connects two sets."
1023 input ConnectorElement element1;
1024 input ConnectorElement element2;
1025 input output Sets sets;
1026 protected
1027 Integer set1, set2;
1028 algorithm
1029 set1 := getElementSetIndex(element1);
1030 set2 := getElementSetIndex(element2);
1031
1032 // Add a new connection if the elements don't belong to the same set already.
1033
2/2
✓ Branch 0 taken 3196 times.
✓ Branch 1 taken 4113 times.
7309 if set1 <> set2 then
1034 8226 sets.connections := (set1, set2) :: sets.connections;
1035 end if;
1036 end connectSets;
1037
1038 protected function setTrieGetElement
1039 "Fetches a connector element from the trie given a cref and a face."
1040 input DAE.ComponentRef cref;
1041 input Face face;
1042 input SetTrie trie;
1043 output ConnectorElement element;
1044 protected
1045 SetTrieNode node;
1046 algorithm
1047 65900 node := setTrieGet(cref, trie, false);
1048 30789 element := setTrieGetLeafElement(node, face);
1049 end setTrieGetElement;
1050
1051 protected function setTrieAddLeafElement
1052 "Adds a connector element to a trie leaf."
1053 input ConnectorElement element;
1054 input output SetTrieNode node;
1055 algorithm
1056 () := match node
1057 case SetTrieNode.SET_TRIE_LEAF()
1058 algorithm
1059 () := match element.face
1060 case Face.INSIDE()
1061 algorithm
1062 34575 node.insideElement := SOME(element);
1063 then
1064 ();
1065
1066 case Face.OUTSIDE()
1067 algorithm
1068 9469 node.outsideElement := SOME(element);
1069 then
1070 ();
1071 end match;
1072 then
1073 ();
1074 end match;
1075 end setTrieAddLeafElement;
1076
1077 protected function setTrieGetLeafElement
1078 "Returns the connector element of a trie leaf, given a face."
1079 input SetTrieNode node;
1080 input Face face;
1081 output ConnectorElement element;
1082 algorithm
1083 element := match(face, node)
1084 local
1085 ConnectorElement e;
1086
1087 case (Face.INSIDE(), SetTrieNode.SET_TRIE_LEAF(insideElement = SOME(e))) then e;
1088 case (Face.OUTSIDE(), SetTrieNode.SET_TRIE_LEAF(outsideElement = SOME(e))) then e;
1089 end match;
1090 end setTrieGetLeafElement;
1091
1092 protected function setTrieAdd
1093 "Adds a connector element to the trie."
1094 input ConnectorElement element;
1095 input output SetTrie trie;
1096 protected
1097 DAE.ComponentRef cref, el_cr;
1098 ConnectorElement el;
1099 algorithm
1100 cref := getElementName(element);
1101 44044 el_cr := ComponentReferenceBasics.crefLastCref(cref);
1102 44044 el := setElementName(element, el_cr);
1103 44044 trie := setTrieUpdate(cref, el, trie, setTrieAddLeafElement);
1104 end setTrieAdd;
1105
1106 protected function updateSetLeaf<Arg>
1107 "Updates a trie leaf in the sets with the given update function."
1108 input output Sets sets;
1109 input DAE.ComponentRef cref;
1110 input Arg arg;
1111 input UpdateFunc updateFunc;
1112
1113 partial function UpdateFunc
1114 input Arg arg;
1115 input output SetTrieNode node;
1116 end UpdateFunc;
1117 algorithm
1118 174 sets.sets := setTrieUpdate(cref, arg, sets.sets, updateFunc);
1119 end updateSetLeaf;
1120
1121 protected function setTrieUpdate<Arg>
1122 "Updates a trie leaf in the trie with the given update function."
1123 input DAE.ComponentRef cref;
1124 input Arg arg;
1125 input output SetTrie trie;
1126 input UpdateFunc updateFunc;
1127
1128 partial function UpdateFunc
1129 input Arg arg;
1130 input output SetTrieNode node;
1131 end UpdateFunc;
1132 algorithm
1133 () := match(cref, trie)
1134 local
1135 String id;
1136
1137 case (DAE.CREF_QUAL(), SetTrieNode.SET_TRIE_NODE())
1138 algorithm
1139 81826 id := ComponentReferenceBasics.printComponentRef2Str(cref.ident, cref.subscriptLst);
1140 81826 trie.nodes := setTrieUpdateNode(id, cref, cref.componentRef, arg, updateFunc, trie.nodes);
1141 then
1142 ();
1143
1144 case (DAE.CREF_IDENT(), SetTrieNode.SET_TRIE_NODE())
1145 algorithm
1146 48269 id := ComponentReferenceBasics.printComponentRef2Str(cref.ident, cref.subscriptLst);
1147 48269 trie.nodes := setTrieUpdateLeaf(id, arg, trie.nodes, updateFunc);
1148 then
1149 ();
1150
1151 end match;
1152 end setTrieUpdate;
1153
1154 protected function setTrieUpdateNode<Arg>
1155 "Helper function to setTrieUpdate, updates a node in the trie."
1156 input String id;
1157 input DAE.ComponentRef wholeCref;
1158 input DAE.ComponentRef cref;
1159 input Arg arg;
1160 input UpdateFunc updateFunc;
1161 input output list<SetTrieNode> nodes;
1162
1163 partial function UpdateFunc
1164 input Arg arg;
1165 input output SetTrieNode node;
1166 end UpdateFunc;
1167 protected
1168 SetTrieNode node2;
1169 Integer n=1;
1170 algorithm
1171
2/2
✓ Branch 0 taken 444071 times.
✓ Branch 1 taken 2199 times.
446270 for node in nodes loop
1172
6/6
✓ Branch 1 taken 421328 times.
✓ Branch 2 taken 22743 times.
✓ Branch 4 taken 169234 times.
✓ Branch 5 taken 252094 times.
✓ Branch 8 taken 79627 times.
✓ Branch 9 taken 89607 times.
444071 if setTrieIsNode(node) and setTrieNodeName(node) == id then
1173 79627 node2 := setTrieUpdate(cref, arg, node, updateFunc);
1174 79627 nodes := List.replaceAt(node2, n, nodes); // Can be slow in memory and time
1175 79627 return;
1176 else
1177 364444 n := n+1;
1178 end if;
1179 end for;
1180
1181 2199 nodes := setTrieUpdateNode2(wholeCref, arg, updateFunc, nodes);
1182 end setTrieUpdateNode;
1183
1184 protected function setTrieUpdateNode2<Arg>
1185 "Helper function to setTrieUpdateNode."
1186 input DAE.ComponentRef cref;
1187 input Arg arg;
1188 input UpdateFunc updateFunc;
1189 input output list<SetTrieNode> nodes;
1190
1191 partial function UpdateFunc
1192 input Arg arg;
1193 input output SetTrieNode node;
1194 end UpdateFunc;
1195 algorithm
1196 nodes := match cref
1197 local
1198 String id;
1199 DAE.ComponentRef cr;
1200 SetTrieNode node;
1201 list<SetTrieNode> child_nodes;
1202
1203 case DAE.CREF_IDENT()
1204 algorithm
1205 2199 id := ComponentReferenceBasics.printComponentRefStr(cref);
1206 2199 node := SetTrieNode.SET_TRIE_LEAF(id, NONE(), NONE(), NONE(), 0);
1207
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2199 times.
2199 node := updateFunc(arg, node);
1208 then
1209 node :: nodes;
1210
1211 case DAE.CREF_QUAL()
1212 algorithm
1213 2389 cr := ComponentReferenceBasics.crefFirstCref(cref);
1214 2389 id := ComponentReferenceBasics.printComponentRefStr(cr);
1215 2389 child_nodes := setTrieUpdateNode2(cref.componentRef, arg, updateFunc, {});
1216 2389 then
1217 SetTrieNode.SET_TRIE_NODE(id, cr, child_nodes, 0) :: nodes;
1218
1219 end match;
1220 end setTrieUpdateNode2;
1221
1222 protected function setTrieUpdateLeaf<Arg>
1223 "Helper funtion to setTrieUpdate, updates a trie leaf."
1224 input String id;
1225 input Arg arg;
1226 input output list<SetTrieNode> nodes;
1227 input UpdateFunc updateFunc;
1228
1229 partial function UpdateFunc
1230 input Arg arg;
1231 input output SetTrieNode node;
1232 end UpdateFunc;
1233 protected
1234 Integer n = 1;
1235 algorithm
1236
2/2
✓ Branch 0 taken 306913 times.
✓ Branch 1 taken 33086 times.
339999 for node in nodes loop
1237
4/4
✓ Branch 1 taken 117659 times.
✓ Branch 2 taken 189254 times.
✓ Branch 5 taken 15183 times.
✓ Branch 6 taken 102476 times.
306913 if setTrieNodeName(node) == id then
1238 // Found matching leaf, update it.
1239
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15183 times.
15183 nodes := List.replaceAt(updateFunc(arg, node), n, nodes); // Can be slow in time and memory...
1240 15183 return;
1241 end if;
1242
1243 291730 n := n+1;
1244 end for;
1245
1246 // Is slow in time; need to do a linear search. Cheap in memory (single cons)
1247
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 33086 times.
33086 nodes := updateFunc(arg, Connect.SET_TRIE_LEAF(id, NONE(), NONE(), NONE(), 0)) :: nodes;
1248 end setTrieUpdateLeaf;
1249
1250 public function traverseSets<Arg>
1251 "Traverses the trie leaves in a sets."
1252 input output Sets sets;
1253 input output Arg arg;
1254 input UpdateFunc updateFunc;
1255
1256 partial function UpdateFunc
1257 input output SetTrieNode node;
1258 input output Arg arg;
1259 end UpdateFunc;
1260 protected
1261 SetTrieNode node;
1262 algorithm
1263 ✗ (node, arg) := setTrieTraverseLeaves(sets.sets, updateFunc, arg);
1264 ✗ sets.sets := node;
1265 end traverseSets;
1266
1267 protected function setTrieTraverseLeaves<Arg>
1268 "Traverses the leaves of a trie."
1269 input output SetTrieNode node;
1270 input UpdateFunc updateFunc;
1271 input output Arg arg;
1272
1273 partial function UpdateFunc
1274 input output SetTrieNode node;
1275 input output Arg arg;
1276 end UpdateFunc;
1277 algorithm
1278 () := match node
1279 local
1280 list<SetTrieNode> nodes;
1281
1282 case SetTrieNode.SET_TRIE_NODE()
1283 algorithm
1284 ✗ (nodes, arg) := List.map1Fold(node.nodes, setTrieTraverseLeaves, updateFunc, arg);
1285 ✗ node.nodes := nodes;
1286 then
1287 ();
1288
1289 case SetTrieNode.SET_TRIE_LEAF()
1290 algorithm
1291 ✗ (node, arg) := updateFunc(node, arg);
1292 then
1293 ();
1294
1295 end match;
1296 end setTrieTraverseLeaves;
1297
1298 protected function setTrieGet
1299 "Fetches a node from the trie given a cref to search for. If inMatchPrefix is
1300 true it also matches a prefix of the cref if the full cref couldn't be found."
1301 input DAE.ComponentRef cref;
1302 input SetTrie trie;
1303 input Boolean matchPrefix;
1304 output SetTrieNode leaf;
1305 protected
1306 list<SetTrieNode> nodes;
1307 String subs_str, id_subs, id_nosubs;
1308 algorithm
1309
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 179018 times.
179018 SetTrieNode.SET_TRIE_NODE(nodes = nodes) := trie;
1310
1311 179018 id_nosubs := ComponentReferenceBasics.crefFirstIdent(cref);
1312 179018 subs_str := List.toStringCustom(ComponentReference.crefFirstSubs(cref),
1313 ExpressionBasics.printSubscriptStr, "", "[", ",", "]", false);
1314 179018 id_subs := id_nosubs + subs_str;
1315
1316 try
1317 // Try to look up the identifier with subscripts, in case single array
1318 // elements have been added to the trie.
1319 179018 leaf := setTrieGetNode(id_subs, nodes);
1320 else
1321 // If the above fails, try again without the subscripts in case a whole
1322 // array has been added to the trie.
1323 35190 leaf := setTrieGetNode(id_nosubs, nodes);
1324 end try;
1325
1326 // If the cref is qualified, continue to look up the rest of the cref in node
1327 // we just found.
1328
2/2
✓ Branch 1 taken 112334 times.
✓ Branch 2 taken 31494 times.
143828 if not ComponentReference.crefIsIdent(cref) then
1329 try
1330 112334 leaf := setTrieGet(ComponentReference.crefRest(cref), leaf, matchPrefix);
1331 else
1332 // Look up failed, return the previously found node if prefix matching is
1333 // turned on and the node we found is a leaf.
1334
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 53443 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
53446 true := matchPrefix and not setTrieIsNode(leaf);
1335 end try;
1336 end if;
1337 end setTrieGet;
1338
1339 protected function setTrieGetNode
1340 "Returns a node with a given name from a list of nodes, or fails if no such
1341 node exists in the list."
1342 input String id;
1343 input list<SetTrieNode> nodes;
1344 output SetTrieNode node;
1345 algorithm
1346 220231 node := List.getMemberOnTrue(id, nodes, setTrieNodeNamed);
1347 end setTrieGetNode;
1348
1349 protected function setTrieNodeNamed
1350 "Returns true if the given node has the same name as the given string,
1351 otherwise false."
1352 input String id;
1353 input SetTrieNode node;
1354 output Boolean isNamed;
1355 algorithm
1356 isNamed := match node
1357
4/4
✓ Branch 0 taken 250887 times.
✓ Branch 1 taken 415247 times.
✓ Branch 3 taken 137853 times.
✓ Branch 4 taken 113034 times.
666134 case SetTrieNode.SET_TRIE_NODE() then id == node.name;
1358
4/4
✓ Branch 0 taken 179656 times.
✓ Branch 1 taken 700576 times.
✓ Branch 3 taken 148849 times.
✓ Branch 4 taken 30807 times.
880232 case SetTrieNode.SET_TRIE_LEAF() then id == node.name;
1359 else false;
1360 end match;
1361 end setTrieNodeNamed;
1362
1363 protected function setTrieGetLeaf
1364 "Returns a leaf node with a given name from a list of nodes, or fails if no
1365 such node exists in the list."
1366 input String id;
1367 input list<SetTrieNode> nodes;
1368 output SetTrieNode node;
1369 algorithm
1370 ✗ node := List.getMemberOnTrue(id, nodes, setTrieLeafNamed);
1371 end setTrieGetLeaf;
1372
1373 protected function setTrieLeafNamed
1374 "Returns true if the given leaf node has the same name as the given string,
1375 otherwise false."
1376 input String id;
1377 input SetTrieNode node;
1378 output Boolean isNamed;
1379 algorithm
1380 isNamed := match node
1381 ✗ case SetTrieNode.SET_TRIE_LEAF() then id == node.name;
1382 else false;
1383 end match;
1384 end setTrieLeafNamed;
1385
1386 protected function setTrieIsNode
1387 input SetTrieNode node;
1388 output Boolean isNode;
1389 algorithm
1390 isNode := match node
1391 case SetTrieNode.SET_TRIE_NODE() then true;
1392 else false;
1393 end match;
1394 end setTrieIsNode;
1395
1396 public function equations
1397 "Generates equations from a connection set and evaluates stream operators if
1398 called from the top scope, otherwise does nothing."
1399 input Boolean topScope;
1400 input Sets sets;
1401 input output DAE.DAElist DAE;
1402 input ConnectionGraph.ConnectionGraph connectionGraph;
1403 input String modelNameQualified;
1404 protected
1405 list<Set> set_list;
1406 array<Set> set_array;
1407 DAE.DAElist dae, dae2;
1408 ConnectionGraph.DaeEdges broken, connected;
1409 algorithm
1410 898893 setGlobalRoot(Global.isInStream, NONE());
1411
2/2
✓ Branch 0 taken 897854 times.
✓ Branch 1 taken 1039 times.
898893 if not topScope then
1412 897854 return;
1413 end if;
1414
1415 //print(printSetsStr(inSets) + "\n");
1416 1039 set_array := generateSetArray(sets);
1417 1039 set_list := arrayList(set_array);
1418 //print("Sets:\n");
1419 //print(stringDelimitList(List.map(sets, printSetStr), "\n") + "\n");
1420
1421
2/2
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 1032 times.
1039 if daeHasExpandableConnectors(DAE) then
1422 7 (set_list, dae) := removeUnusedExpandableVariablesAndConnections(set_list, DAE);
1423 else
1424 1032 dae := DAE;
1425 end if;
1426
1427 // send in the connection graph and build the connected/broken connects
1428 // we do this here so we do it once and not for every EQU set.
1429 1039 (dae, connected, broken) := ConnectionGraph.handleOverconstrainedConnections(
1430 connectionGraph, modelNameQualified, dae);
1431
1432 // adrpo: FIXME: maybe we should just remove them from the sets then send the
1433 // updates sets further
1434 1039 dae2 := equationsDispatch(listReverse(set_list), connected, broken);
1435 1039 DAE := DAEUtil.joinDaes(dae, dae2);
1436 1039 DAE := evaluateConnectionOperators(sets, set_array, DAE);
1437 // add the equality constraint equations to the dae.
1438 1039 DAE := ConnectionGraph.addBrokenEqualityConstraintEquations(DAE, broken);
1439 end equations;
1440
1441 protected function getExpandableEquSetsAsCrefs
1442 "@author: adrpo
1443 returns only the sets containing expandable connectors"
1444 input list<Set> sets;
1445 output list<list<DAE.ComponentRef>> crefSets = {};
1446 protected
1447 list<DAE.ComponentRef> cref_set;
1448 algorithm
1449
2/2
✓ Branch 0 taken 3191 times.
✓ Branch 1 taken 7 times.
3198 for set in sets loop
1450 () := match set
1451 case Set.SET(ty = ConnectorType.EQU())
1452 algorithm
1453 2195 cref_set := getAllEquCrefs({set});
1454
1455
2/2
✓ Branch 1 taken 1052 times.
✓ Branch 2 taken 1143 times.
2195 if List.applyAndFold(cref_set, boolOr, isExpandable, false) then
1456 crefSets := cref_set :: crefSets;
1457 end if;
1458 then
1459 ();
1460
1461 else ();
1462 end match;
1463 end for;
1464 end getExpandableEquSetsAsCrefs;
1465
1466 protected function removeCrefsFromSets
1467 input output list<Set> sets;
1468 input list<DAE.ComponentRef> nonUsefulExpandable;
1469 algorithm
1470 7 sets := List.select1(sets, removeCrefsFromSets2, nonUsefulExpandable);
1471 end removeCrefsFromSets;
1472
1473 protected function removeCrefsFromSets2
1474 input Set set;
1475 input list<DAE.ComponentRef> nonUsefulExpandable;
1476 output Boolean isInSet;
1477 protected
1478 list<DAE.ComponentRef> setCrefs, lst;
1479 algorithm
1480 3191 setCrefs := getAllEquCrefs({set});
1481 3191 lst := List.intersectionOnTrue(setCrefs, nonUsefulExpandable, ComponentReferenceBasics.crefEqualNoStringCompare);
1482 3191 isInSet := listEmpty(lst);
1483 end removeCrefsFromSets2;
1484
1485 function mergeEquSetsAsCrefs
1486 input output list<list<DAE.ComponentRef>> setsAsCrefs;
1487 algorithm
1488 setsAsCrefs := match setsAsCrefs
1489 local
1490 list<DAE.ComponentRef> set;
1491 list<list<DAE.ComponentRef>> rest, sets;
1492
1493 case {} then {};
1494 case {set} then {set};
1495 case set::rest
1496 algorithm
1497 509 (set, rest) := mergeWithRest(set, rest);
1498 509 sets := mergeEquSetsAsCrefs(rest);
1499 then
1500 set::sets;
1501 end match;
1502 end mergeEquSetsAsCrefs;
1503
1504 protected function mergeWithRest
1505 input output list<DAE.ComponentRef> set;
1506 input output list<list<DAE.ComponentRef>> sets;
1507 input list<list<DAE.ComponentRef>> acc = {};
1508 algorithm
1509 (set, sets) := match (set, sets)
1510 local
1511 list<DAE.ComponentRef> set1, set2;
1512 list<list<DAE.ComponentRef>> rest;
1513 Boolean b;
1514 509 case (_, {}) then (set, listReverse(acc));
1515 case (set1, set2::rest)
1516 algorithm
1517 // Could be faster if we had a function for intersectionExist in a set
1518 57129 b := listEmpty(List.intersectionOnTrue(set1, set2, ComponentReferenceBasics.crefEqualNoStringCompare));
1519
2/2
✓ Branch 0 taken 796 times.
✓ Branch 1 taken 56333 times.
57129 set := if not b then List.unionOnTrue(set1, set2, ComponentReferenceBasics.crefEqualNoStringCompare) else set1;
1520 57129 (set, rest) := mergeWithRest(set, rest, List.consOnTrue(b, set2, acc));
1521 then (set, rest);
1522 end match;
1523 end mergeWithRest;
1524
1525 protected function getOnlyExpandableConnectedCrefs
1526 input list<list<DAE.ComponentRef>> sets;
1527 output list<DAE.ComponentRef> usefulConnectedExpandable = {};
1528 algorithm
1529
2/2
✓ Branch 0 taken 256 times.
✓ Branch 1 taken 7 times.
263 for set in sets loop
1530
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 256 times.
256 if allCrefsAreExpandable(set) then
1531 ✗ usefulConnectedExpandable := listAppend(set, usefulConnectedExpandable);
1532 end if;
1533 end for;
1534 end getOnlyExpandableConnectedCrefs;
1535
1536 public function allCrefsAreExpandable
1537 input list<DAE.ComponentRef> connects;
1538 output Boolean allAreExpandable;
1539 algorithm
1540
1/2
✓ Branch 0 taken 1496 times.
✗ Branch 1 not taken.
1496 for cr in connects loop
1541
2/2
✓ Branch 1 taken 256 times.
✓ Branch 2 taken 1240 times.
1496 if not isExpandable(cr) then
1542 allAreExpandable := false;
1543 256 return;
1544 end if;
1545 end for;
1546
1547 allAreExpandable := true;
1548 end allCrefsAreExpandable;
1549
1550 protected function generateSetArray
1551 "Generates an array of sets from a connection set."
1552 input Sets sets;
1553 output array<Set> setArray;
1554 algorithm
1555 // Create a new array.
1556 1039 setArray := arrayCreate(sets.setCount, Set.SET(ConnectorType.NO_TYPE(), {}));
1557 // Add connection pointers to the array.
1558 1039 setArray := setArrayAddConnections(sets.connections, sets.setCount, setArray);
1559 // Fill the array with sets.
1560 1039 setArray := generateSetArray2(sets.sets, {}, setArray);
1561 end generateSetArray;
1562
1563 protected function setArrayAddConnections
1564 "The connection set maintains a list of connections, but when we generate the
1565 set array which is used to generate the equations we want to merge these sets.
1566 This function adds pointers to the array, so that when we fill it with
1567 generateSetArray2 we can follow the pointers to the correct sets. I.e. if sets
1568 1 and 2 are connected we might add a pointer from 2 to 1, so that all elements
1569 that belongs to set 2 are instead added to set 1. To make sure that we get
1570 correct pointers we build a graph and use an algorithm to find the strongly
1571 connected components in it."
1572 input list<SetConnection> connections;
1573 input Integer setCount;
1574 input output array<Set> sets;
1575 protected
1576 SetGraph graph;
1577 algorithm
1578 // Create a new graph, represented as an adjacency list.
1579 1039 graph := arrayCreate(setCount, {});
1580 // Add the connections to the graph.
1581
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1039 times.
1039 graph := List.fold(connections, addConnectionToGraph, graph);
1582
1583 // Add the connections to the array with help from the graph.
1584
2/2
✓ Branch 0 taken 887 times.
✓ Branch 1 taken 152 times.
24220 for i in 1:arrayLength(graph) loop
1585 23181 (sets, graph) := setArrayAddConnection(i, graph[i], sets, graph);
1586 end for;
1587 end setArrayAddConnections;
1588
1589 protected function addConnectionToGraph
1590 "Adds a connection to the set graph."
1591 input SetConnection connection;
1592 input output SetGraph graph;
1593 protected
1594 Integer set1, set2;
1595 list<Integer> node1, node2;
1596 algorithm
1597 4110 (set1, set2) := connection;
1598 4110 node1 := arrayGet(graph, set1);
1599 4110 graph := arrayUpdate(graph, set1, set2 :: node1);
1600 4110 node2 := arrayGet(graph, set2);
1601 4110 graph := arrayUpdate(graph, set2, set1 :: node2);
1602 end addConnectionToGraph;
1603
1604 protected function setArrayAddConnection
1605 "Helper function to setArrayAddConnections, adds a connection pointer to the
1606 set array."
1607 input Integer set;
1608 input list<Integer> edges;
1609 input output array<Set> sets;
1610 input output SetGraph graph;
1611 protected
1612 list<Integer> edge_lst;
1613 algorithm
1614
2/2
✓ Branch 0 taken 8220 times.
✓ Branch 1 taken 27515 times.
35735 for e in edges loop
1615
2/2
✓ Branch 0 taken 4334 times.
✓ Branch 1 taken 3886 times.
8220 if e <> set then
1616 // Create a pointer to the given set.
1617 4334 sets := setArrayAddConnection2(e, set, sets);
1618 4334 edge_lst := graph[e];
1619 4334 graph[e] := {};
1620 4334 (sets, graph) := setArrayAddConnection(set, edge_lst, sets, graph);
1621 end if;
1622 end for;
1623 end setArrayAddConnection;
1624
1625 protected function setArrayAddConnection2
1626 "Helper function to setArrayAddConnection, adds a pointer from the given
1627 pointer to the pointee."
1628 input Integer setPointer;
1629 input Integer setPointee;
1630 input output array<Set> sets;
1631 protected
1632 Set set;
1633 algorithm
1634 4334 set := sets[setPointee];
1635
1636 sets := match set
1637 // If the set pointed at is a real set, add a pointer to it.
1638 case Set.SET()
1639 4334 then arrayUpdate(sets, setPointer, Set.SET_POINTER(setPointee));
1640
1641 // If the set pointed at is itself a pointer, follow the pointer until a
1642 // real set is found (path compression).
1643 case Set.SET_POINTER()
1644 ✗ then setArrayAddConnection2(setPointer, set.index, sets);
1645 end match;
1646 end setArrayAddConnection2;
1647
1648 protected function generateSetArray2
1649 "This function fills the set array with the sets from the set trie."
1650 input SetTrie sets;
1651 input list<DAE.ComponentRef> prefix;
1652 input output array<Set> setArray;
1653 algorithm
1654 setArray := match sets
1655 local
1656 Option<ConnectorElement> ie, oe;
1657 Option<DAE.ComponentRef> prefix_cr, flow_cr;
1658
1659 case SetTrieNode.SET_TRIE_NODE(cref = DAE.WILD())
1660 1039 then List.fold1(sets.nodes, generateSetArray2, prefix, setArray);
1661
1662 case SetTrieNode.SET_TRIE_NODE()
1663 8313 then List.fold1(sets.nodes, generateSetArray2, sets.cref :: prefix, setArray);
1664
1665 case SetTrieNode.SET_TRIE_LEAF(insideElement = ie, outsideElement = oe,
1666 flowAssociation = flow_cr)
1667 algorithm
1668 35089 ie := insertFlowAssociationInStreamElement(ie, flow_cr);
1669 35089 oe := insertFlowAssociationInStreamElement(oe, flow_cr);
1670 35089 prefix_cr := buildElementPrefix(prefix);
1671 35089 setArray := setArrayAddElement(ie, prefix_cr, setArray);
1672 35089 setArray := setArrayAddElement(oe, prefix_cr, setArray);
1673 then
1674 setArray;
1675
1676 else setArray;
1677 end match;
1678 end generateSetArray2;
1679
1680 protected function insertFlowAssociationInStreamElement
1681 "If the given element is a stream element, sets the associated flow. Otherwise
1682 does nothing."
1683 input output Option<ConnectorElement> element;
1684 input Option<DAE.ComponentRef> flowCref;
1685 protected
1686 ConnectorElement el;
1687 algorithm
1688
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 70178 times.
✓ Branch 2 taken 43876 times.
✓ Branch 3 taken 26302 times.
70178 if isSome(element) then
1689 43876 SOME(el) := element;
1690
1691 element := match el
1692 case ConnectorElement.CONNECTOR_ELEMENT(ty = ConnectorType.STREAM(NONE()))
1693 algorithm
1694 288 el.ty := ConnectorType.STREAM(flowCref);
1695 then
1696 SOME(el);
1697
1698 else element;
1699 end match;
1700 end if;
1701 end insertFlowAssociationInStreamElement;
1702
1703 protected function setArrayAddElement
1704 "Adds a connector element to the set array."
1705 input Option<ConnectorElement> element;
1706 input Option<DAE.ComponentRef> prefix;
1707 input output array<Set> sets;
1708 algorithm
1709 sets := match (element, prefix)
1710 local
1711 ConnectorElement el;
1712 DAE.ComponentRef prefix_cr;
1713
1714 // No element, do nothing.
1715 case (NONE(), _) then sets;
1716
1717 // An element but no prefix, add the element as it is.
1718 case (SOME(el as ConnectorElement.CONNECTOR_ELEMENT()), NONE())
1719 21 then setArrayUpdate(sets, el.set, el);
1720
1721 // Both an element and a prefix, add the prefix to the element before adding
1722 // it to the array.
1723 case (SOME(el as ConnectorElement.CONNECTOR_ELEMENT()), SOME(prefix_cr))
1724 algorithm
1725 43855 el.name := ComponentReference.joinCrefs(prefix_cr, el.name);
1726 43855 then
1727 setArrayUpdate(sets, el.set, el);
1728
1729 end match;
1730 end setArrayAddElement;
1731
1732 protected function buildElementPrefix
1733 "Helper function to generateSetArray2, build a prefix from a list of crefs."
1734 input list<DAE.ComponentRef> prefix;
1735 output Option<DAE.ComponentRef> cref;
1736 protected
1737 DAE.ComponentRef cr;
1738 String id;
1739 list<DAE.Subscript> subs;
1740 algorithm
1741 // If a connector that extends a basic type is used on the top level we
1742 // don't have a prefix.
1743
2/2
✓ Branch 0 taken 35068 times.
✓ Branch 1 taken 21 times.
35089 if listEmpty(prefix) then
1744 cref := NONE();
1745 else
1746 35068 cr := listHead(prefix);
1747
2/2
✓ Branch 1 taken 73562 times.
✓ Branch 2 taken 35068 times.
108630 for c in listRest(prefix) loop
1748
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 73562 times.
73562 DAE.CREF_IDENT(ident = id, subscriptLst = subs) := c;
1749 73562 cr := DAE.CREF_QUAL(id, DAE.T_UNKNOWN_DEFAULT, subs, cr);
1750 end for;
1751
1752 cref := SOME(cr);
1753 end if;
1754 end buildElementPrefix;
1755
1756 protected function setArrayUpdate
1757 "Updates the element at a given index in the set array."
1758 input output array<Set> sets;
1759 input Integer index;
1760 input ConnectorElement element;
1761 protected
1762 Set set;
1763 list<ConnectorElement> el;
1764 algorithm
1765 48129 set := sets[index];
1766
1767 sets := match (set, element)
1768 case (Set.SET(), ConnectorElement.CONNECTOR_ELEMENT())
1769 algorithm
1770
4/4
✓ Branch 1 taken 43846 times.
✓ Branch 2 taken 30 times.
✓ Branch 4 taken 31539 times.
✓ Branch 5 taken 12307 times.
43876 if Config.orderConnections() and isEquType(element.ty) then
1771 // Sort the elements if orderConnections is true and the set is an equality set.
1772 31539 el := List.mergeSorted({element}, set.elements, equSetElementLess);
1773 else
1774 // Other sets, just add them.
1775 12337 el := element :: set.elements;
1776 end if;
1777 43876 then
1778 arrayUpdate(sets, index, Set.SET(element.ty, el));
1779
1780 // A pointer, follow the pointer.
1781 case (Set.SET_POINTER(), _)
1782 4253 then setArrayUpdate(sets, set.index, element);
1783
1784 end match;
1785 end setArrayUpdate;
1786
1787 protected function equSetElementLess
1788 "Comparison function used by setArrayUpdate2 to order equ sets."
1789 input ConnectorElement element1;
1790 input ConnectorElement element2;
1791 output Boolean isLess;
1792 algorithm
1793 24755 isLess := ComponentReferenceBasics.crefSortFunc(element2.name, element1.name);
1794 end equSetElementLess;
1795
1796 protected function setArrayGet
1797 "Returns the set on a given index in the set array."
1798 input array<Set> setArray;
1799 input Integer index;
1800 output Set set;
1801 algorithm
1802 155 set := setArray[index];
1803
1804 set := match set
1805 case Set.SET() then set;
1806 ✗ case Set.SET_POINTER() then setArrayGet(setArray, set.index);
1807 end match;
1808 end setArrayGet;
1809
1810 protected function equationsDispatch
1811 "Dispatches to the correct equation generating function based on the type of
1812 the given set."
1813 input list<Set> sets;
1814 input ConnectionGraph.DaeEdges connected;
1815 input ConnectionGraph.DaeEdges broken;
1816 output DAE.DAElist DAE = DAE.emptyDae;
1817 protected
1818 list<ConnectorElement> eql;
1819 list<list<ConnectorElement>> eqll;
1820 Real flowThreshold = Flags.getConfigReal(Flags.FLOW_THRESHOLD);
1821 algorithm
1822
2/2
✓ Branch 0 taken 23181 times.
✓ Branch 1 taken 1039 times.
24220 for set in sets loop
1823 DAE := match set
1824 // A set pointer left from generateSetList, ignore it.
1825 case Set.SET_POINTER() then DAE;
1826
1827 case Set.SET(ty = ConnectorType.EQU())
1828 algorithm
1829 // Here we do some overconstrained connection breaking.
1830 13478 eqll := ConnectionGraph.removeBrokenConnects(set.elements, connected, broken);
1831
2/2
✓ Branch 0 taken 13478 times.
✓ Branch 1 taken 13478 times.
26956 for eql in eqll loop
1832 13478 DAE := DAEUtil.joinDaes(generateEquEquations(eql), DAE);
1833 end for;
1834 then
1835 DAE;
1836
1837 case Set.SET(ty = ConnectorType.FLOW(), elements = eql)
1838 5528 then DAEUtil.joinDaes(generateFlowEquations(eql), DAE);
1839
1840 case Set.SET(ty = ConnectorType.STREAM(), elements = eql)
1841 67 then DAEUtil.joinDaes(generateStreamEquations(eql, flowThreshold), DAE);
1842
1843 // Should never happen.
1844 case Set.SET(ty = ConnectorType.NO_TYPE())
1845 algorithm
1846 ✗ Error.addMessage(Error.INTERNAL_ERROR,
1847 {"ConnectUtil.equationsDispatch failed on connection set with no type."});
1848 ✗ then
1849 fail();
1850
1851 else
1852 algorithm
1853 ✗ Error.addMessage(Error.INTERNAL_ERROR,
1854 {"ConnectUtil.equationsDispatch failed because of unknown reason."});
1855 ✗ then
1856 fail();
1857
1858 end match;
1859 end for;
1860 end equationsDispatch;
1861
1862 protected function generateEquEquations
1863 "A non-flow connection set contains a number of components. Generating the
1864 equations from this set means equating all the components. For n components,
1865 this will give n-1 equations. For example, if the set contains the components
1866 X, Y.A and Z.B, the equations generated will be X = Y.A and X = Z.B. The
1867 order of the equations depends on whether the compiler flag orderConnections
1868 is true or false."
1869 input list<ConnectorElement> elements;
1870 output DAE.DAElist DAE = DAE.emptyDae;
1871 protected
1872 list<DAE.Element> eql = {};
1873 ConnectorElement e1;
1874 DAE.ElementSource src;
1875 DAE.ComponentRef x, y;
1876 algorithm
1877
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13478 times.
13478 if listEmpty(elements) then
1878 ✗ return;
1879 end if;
1880
1881 13478 e1 := listHead(elements);
1882
1883
2/2
✓ Branch 1 taken 13473 times.
✓ Branch 2 taken 5 times.
13478 if Config.orderConnections() then
1884
2/2
✓ Branch 1 taken 18054 times.
✓ Branch 2 taken 13473 times.
31527 for e2 in listRest(elements) loop
1885 18054 src := ElementSource.mergeSources(e1.source, e2.source);
1886 18054 src := ElementSource.addElementSourceConnect(src, (e1.name, e2.name));
1887 18054 eql := DAE.EQUEQUATION(e1.name, e2.name, src) :: eql;
1888 end for;
1889 else
1890
2/2
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 5 times.
10 for e2 in listRest(elements) loop
1891 5 (x, y) := Util.swap(shouldFlipEquEquation(e1.name, e1.source), e1.name, e2.name);
1892 5 src := ElementSource.mergeSources(e1.source, e2.source);
1893 5 src := ElementSource.addElementSourceConnect(src, (x, y));
1894 5 eql := DAE.EQUEQUATION(x, y, src) :: eql;
1895 e1 := e2;
1896 end for;
1897 end if;
1898
1899 13478 DAE := DAE.DAE(listReverse(eql));
1900 end generateEquEquations;
1901
1902 protected function shouldFlipEquEquation
1903 "If the flag +orderConnections=false is used, then we should keep the order of
1904 the connector elements as they occur in the connection (if possible). In that
1905 case we check if the cref of the first argument to the first connection
1906 stored in the element source is a prefix of the connector element cref. If
1907 it isn't, indicate that we should flip the generated equation."
1908 input DAE.ComponentRef lhsCref;
1909 input DAE.ElementSource lhsSource;
1910 output Boolean shouldFlip;
1911 algorithm
1912 shouldFlip := match lhsSource
1913 local
1914 DAE.ComponentRef lhs;
1915
1916 case DAE.SOURCE(connectEquationOptLst = (lhs, _) :: _)
1917 5 then not ComponentReferenceBasics.crefPrefixOf(lhs, lhsCref);
1918
1919 else false;
1920 end match;
1921 end shouldFlipEquEquation;
1922
1923 protected function generateFlowEquations
1924 "Generating equations from a flow connection set is a little trickier that
1925 from a non-flow set. Only one equation is generated, but it has to consider
1926 whether the components were inside or outside connectors. This function
1927 creates a sum expression of all components (some of which will be negated),
1928 and the returns the equation where this sum is equal to 0.0."
1929 input list<ConnectorElement> elements;
1930 output DAE.DAElist DAE;
1931 protected
1932 DAE.Exp sum;
1933 DAE.ElementSource src;
1934 algorithm
1935 5528 sum := makeFlowExp(listHead(elements));
1936 5528 src := getElementSource(listHead(elements));
1937
1938
2/2
✓ Branch 1 taken 6655 times.
✓ Branch 2 taken 5528 times.
12183 for e in listRest(elements) loop
1939 6655 sum := Expression.makeRealAdd(sum, makeFlowExp(e));
1940 6655 src := ElementSource.mergeSources(src, e.source);
1941 end for;
1942
1943 11056 DAE := DAE.DAE({DAE.EQUATION(sum, DAE.RCONST(0.0), src)});
1944 end generateFlowEquations;
1945
1946 protected function makeFlowExp
1947 "Creates an expression from a connector element, which is the element itself
1948 if it's an inside connector, or negated if it's outside."
1949 input ConnectorElement element;
1950 output DAE.Exp exp;
1951 algorithm
1952 12183 exp := Expression.crefExp(element.name);
1953
1954
2/2
✓ Branch 1 taken 9599 times.
✓ Branch 2 taken 2584 times.
12183 if isOutsideElement(element) then
1955 2584 exp := Expression.negateReal(exp);
1956 end if;
1957 end makeFlowExp;
1958
1959 public function increaseConnectRefCount
1960 input DAE.ComponentRef lhsCref;
1961 input DAE.ComponentRef rhsCref;
1962 input output Sets sets;
1963 protected
1964 list<DAE.ComponentRef> crefs;
1965 algorithm
1966
2/2
✓ Branch 1 taken 6072 times.
✓ Branch 2 taken 2881 times.
8953 if System.getUsesCardinality() then
1967 2881 crefs := ComponentReference.expandCref(lhsCref, false);
1968 2881 sets.sets := increaseConnectRefCount2(crefs, sets.sets);
1969 2881 crefs := ComponentReference.expandCref(rhsCref, false);
1970 2881 sets.sets := increaseConnectRefCount2(crefs, sets.sets);
1971 end if;
1972 end increaseConnectRefCount;
1973
1974 public function increaseConnectRefCount2
1975 input list<DAE.ComponentRef> crefs;
1976 input output SetTrie sets;
1977 algorithm
1978
2/2
✓ Branch 0 taken 6250 times.
✓ Branch 1 taken 5762 times.
12012 for cr in crefs loop
1979 6250 sets := setTrieUpdate(cr, 1, sets, increaseRefCount);
1980 end for;
1981 end increaseConnectRefCount2;
1982
1983 protected function increaseRefCount
1984 input Integer amount;
1985 input output SetTrieNode node;
1986 algorithm
1987 () := match node
1988 case SetTrieNode.SET_TRIE_NODE()
1989 algorithm
1990 3324 node.connectCount := node.connectCount + amount;
1991 then
1992 ();
1993
1994 case SetTrieNode.SET_TRIE_LEAF()
1995 algorithm
1996 2926 node.connectCount := node.connectCount + amount;
1997 then
1998 ();
1999 end match;
2000 end increaseRefCount;
2001
2002 protected function generateStreamEquations
2003 "Generates the equations for a stream connection set."
2004 input list<ConnectorElement> elements;
2005 input Real flowThreshold;
2006 output DAE.DAElist DAE;
2007 algorithm
2008 DAE := match elements
2009 local
2010 DAE.ComponentRef cr1, cr2;
2011 DAE.ElementSource src1, src2, src;
2012 DAE.DAElist dae;
2013 DAE.Exp cref1, cref2, e1, e2;
2014 list<ConnectorElement> inside, outside;
2015
2016 // Unconnected stream connector, do nothing!
2017 case {ConnectorElement.CONNECTOR_ELEMENT(face = Face.INSIDE())}
2018 then DAE.emptyDae;
2019
2020 // Both inside, do nothing!
2021 case {ConnectorElement.CONNECTOR_ELEMENT(face = Face.INSIDE()),
2022 ConnectorElement.CONNECTOR_ELEMENT(face = Face.INSIDE())}
2023 then DAE.emptyDae;
2024
2025 // Both outside:
2026 // cr1 = inStream(cr2);
2027 // cr2 = inStream(cr1);
2028 case {ConnectorElement.CONNECTOR_ELEMENT(name = cr1, face = Face.OUTSIDE(), source = src1),
2029 ConnectorElement.CONNECTOR_ELEMENT(name = cr2, face = Face.OUTSIDE(), source = src2)}
2030 algorithm
2031 4 cref1 := Expression.crefExp(cr1);
2032 4 cref2 := Expression.crefExp(cr2);
2033 4 e1 := makeInStreamCall(cref2);
2034 4 e2 := makeInStreamCall(cref1);
2035 4 src := ElementSource.mergeSources(src1, src2);
2036 8 dae := DAE.DAE({
2037 DAE.EQUATION(cref1, e1, src),
2038 DAE.EQUATION(cref2, e2, src)});
2039 then
2040 dae;
2041
2042 // One inside, one outside:
2043 // cr1 = cr2;
2044 case {ConnectorElement.CONNECTOR_ELEMENT(name = cr1, source = src1),
2045 ConnectorElement.CONNECTOR_ELEMENT(name = cr2, source = src2)}
2046 algorithm
2047 12 src := ElementSource.mergeSources(src1, src2);
2048 12 e1 := Expression.crefExp(cr1);
2049 12 e2 := Expression.crefExp(cr2);
2050 24 dae := DAE.DAE({DAE.EQUATION(e1,e2,src)});
2051 then
2052 dae;
2053
2054 // The general case with N inside connectors and M outside:
2055 else
2056 algorithm
2057 8 (outside, inside) := List.splitOnTrue(elements, isOutsideElement);
2058 8 dae := streamEquationGeneral(outside, inside, flowThreshold);
2059 then
2060 dae;
2061
2062 end match;
2063 end generateStreamEquations;
2064
2065 protected function isOutsideElement
2066 "Returns true if the connector element belongs to an outside connector."
2067 input ConnectorElement element;
2068 output Boolean isOutside;
2069 algorithm
2070 isOutside := match element
2071 case ConnectorElement.CONNECTOR_ELEMENT(face = Face.OUTSIDE()) then true;
2072 else false;
2073 end match;
2074 end isOutsideElement;
2075
2076 protected function isZeroFlowMinMax
2077 "Returns true if the given flow attribute of a connector is zero."
2078 input DAE.ComponentRef streamCref;
2079 input ConnectorElement element;
2080 output Boolean isZero;
2081 algorithm
2082
2/2
✓ Branch 1 taken 198 times.
✓ Branch 2 taken 173 times.
371 if compareCrefStreamSet(streamCref, element) then
2083 isZero := false;
2084 elseif isOutsideElement(element) then
2085 16 isZero := isZeroFlow(element, "max");
2086 else
2087 182 isZero := isZeroFlow(element, "min");
2088 end if;
2089 end isZeroFlowMinMax;
2090
2091 protected function isZeroFlow
2092 "Returns true if the given flow attribute of a connector is zero."
2093 input ConnectorElement element;
2094 input String attr;
2095 output Boolean isZero;
2096 protected
2097 DAE.Type ty;
2098 Option<DAE.Exp> attr_oexp;
2099 DAE.Exp flow_exp, attr_exp;
2100 algorithm
2101 198 flow_exp := flowExp(element);
2102 198 ty := Expression.typeof(flow_exp);
2103 198 attr_oexp := Types.lookupAttributeExp(Types.getAttributes(ty), attr);
2104
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 198 times.
✓ Branch 2 taken 180 times.
✓ Branch 3 taken 18 times.
198 if isSome(attr_oexp) then
2105 180 SOME(attr_exp) := attr_oexp;
2106 180 isZero := Expression.isZero(attr_exp);
2107 else
2108 isZero := false;
2109 end if;
2110 end isZeroFlow;
2111
2112 protected function streamEquationGeneral
2113 "Generates an equation for an outside stream connector element."
2114 input list<ConnectorElement> outsideElements;
2115 input list<ConnectorElement> insideElements;
2116 input Real flowThreshold;
2117 output DAE.DAElist DAE;
2118 protected
2119 list<ConnectorElement> outside;
2120 DAE.Exp cref_exp, res;
2121 DAE.ElementSource src;
2122 DAE.ComponentRef name;
2123 list<DAE.Element> eql = {};
2124 algorithm
2125
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 8 times.
11 for e in outsideElements loop
2126 3 cref_exp := Expression.crefExp(e.name);
2127 3 outside := removeStreamSetElement(e.name, outsideElements);
2128 3 res := streamSumEquationExp(outside, insideElements, flowThreshold);
2129 3 src := ElementSource.addAdditionalComment(e.source, " equation generated by stream handling");
2130 3 eql := DAE.EQUATION(cref_exp, res, src) :: eql;
2131 end for;
2132
2133 8 DAE := DAE.DAE(eql);
2134 end streamEquationGeneral;
2135
2136 protected function streamSumEquationExp
2137 "Generates the sum expression used by stream connector equations, given M
2138 outside connectors and N inside connectors:
2139
2140 (sum(max(-flow_exp[i], eps) * stream_exp[i] for i in N) +
2141 sum(max( flow_exp[i], eps) * inStream(stream_exp[i]) for i in M)) /
2142 (sum(max(-flow_exp[i], eps) for i in N) +
2143 sum(max( flow_exp[i], eps) for i in M))
2144
2145 where eps = inFlowThreshold.
2146 "
2147 input list<ConnectorElement> outsideElements;
2148 input list<ConnectorElement> insideElements;
2149 input Real flowThreshold;
2150 output DAE.Exp sumExp;
2151 protected
2152 DAE.Exp outside_sum1, outside_sum2, inside_sum1, inside_sum2;
2153 algorithm
2154
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 3 times.
32 if listEmpty(outsideElements) then
2155 // No outside components.
2156 29 inside_sum1 := sumMap(insideElements, sumInside1, flowThreshold);
2157 29 inside_sum2 := sumMap(insideElements, sumInside2, flowThreshold);
2158 29 sumExp := Expression.expDiv(inside_sum1, inside_sum2);
2159 elseif listEmpty(insideElements) then
2160 // No inside components.
2161 3 outside_sum1 := sumMap(outsideElements, sumOutside1, flowThreshold);
2162 3 outside_sum2 := sumMap(outsideElements, sumOutside2, flowThreshold);
2163 3 sumExp := Expression.expDiv(outside_sum1, outside_sum2);
2164 else
2165 // Both outside and inside components.
2166 ✗ outside_sum1 := sumMap(outsideElements, sumOutside1, flowThreshold);
2167 ✗ outside_sum2 := sumMap(outsideElements, sumOutside2, flowThreshold);
2168 ✗ inside_sum1 := sumMap(insideElements, sumInside1, flowThreshold);
2169 ✗ inside_sum2 := sumMap(insideElements, sumInside2, flowThreshold);
2170 ✗ sumExp := Expression.expDiv(Expression.expAdd(outside_sum1, inside_sum1),
2171 Expression.expAdd(outside_sum2, inside_sum2));
2172 end if;
2173 end streamSumEquationExp;
2174
2175 protected function sumMap
2176 "Creates a sum expression by applying the given function on the list of
2177 elements and summing up the resulting expressions."
2178 input list<ConnectorElement> elements;
2179 input FuncType func;
2180 input Real flowThreshold;
2181 output DAE.Exp exp;
2182
2183 partial function FuncType
2184 input ConnectorElement element;
2185 input Real flowThreshold;
2186 output DAE.Exp exp;
2187 end FuncType;
2188 algorithm
2189
8/10
✓ Branch 1 taken 128 times.
✓ Branch 2 taken 64 times.
✓ Branch 3 taken 128 times.
✓ Branch 4 taken 64 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 128 times.
✓ Branch 11 taken 64 times.
✓ Branch 12 taken 64 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 64 times.
192 exp := Expression.expAdd(func(e, flowThreshold) for e in listReverse(elements));
2190 end sumMap;
2191
2192 protected function streamFlowExp
2193 "Returns the stream and flow component in a stream set element as expressions."
2194 input ConnectorElement element;
2195 output DAE.Exp streamExp;
2196 output DAE.Exp flowExp;
2197 protected
2198 DAE.ComponentRef flow_cr;
2199 algorithm
2200
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 93 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 93 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 93 times.
93 ConnectorElement.CONNECTOR_ELEMENT(ty = ConnectorType.STREAM(SOME(flow_cr))) := element;
2201 93 streamExp := Expression.crefExp(element.name);
2202 93 flowExp := Expression.crefExp(flow_cr);
2203 end streamFlowExp;
2204
2205 protected function flowExp
2206 "Returns the flow component in a stream set element as an expression."
2207 input ConnectorElement element;
2208 output DAE.Exp flowExp;
2209 protected
2210 DAE.ComponentRef flow_cr;
2211 algorithm
2212
3/6
✗ Branch 0 not taken.
✓ Branch 1 taken 262 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 262 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 262 times.
262 ConnectorElement.CONNECTOR_ELEMENT(ty = ConnectorType.STREAM(SOME(flow_cr))) := element;
2213 262 flowExp := Expression.crefExp(flow_cr);
2214 end flowExp;
2215
2216 protected function sumOutside1
2217 "Helper function to streamSumEquationExp. Returns the expression
2218 max(flow_exp, eps) * inStream(stream_exp)
2219 given a stream set element."
2220 input ConnectorElement element;
2221 input Real flowThreshold;
2222 output DAE.Exp exp;
2223 protected
2224 DAE.Exp stream_exp, flow_exp, flow_threshold;
2225 algorithm
2226 6 (stream_exp, flow_exp) := streamFlowExp(element);
2227 6 flow_threshold := DAE.RCONST(flowThreshold);
2228 6 exp := Expression.expMul(makePositiveMaxCall(flow_exp, flow_threshold),
2229 makeInStreamCall(stream_exp));
2230 end sumOutside1;
2231
2232 protected function sumInside1
2233 "Helper function to streamSumEquationExp. Returns the expression
2234 max(-flow_exp, eps) * stream_exp
2235 given a stream set element."
2236 input ConnectorElement element;
2237 input Real flowThreshold;
2238 output DAE.Exp exp;
2239 protected
2240 DAE.Exp stream_exp, flow_exp, flow_threshold;
2241 DAE.Type flowTy;
2242 algorithm
2243 58 (stream_exp, flow_exp) := streamFlowExp(element);
2244 58 flowTy := Expression.typeof(flow_exp);
2245 58 flow_exp := DAE.UNARY(DAE.UMINUS(flowTy), flow_exp);
2246 58 flow_threshold := DAE.RCONST(flowThreshold);
2247 58 exp := Expression.expMul(makePositiveMaxCall(flow_exp, flow_threshold), stream_exp);
2248 end sumInside1;
2249
2250 protected function sumOutside2
2251 "Helper function to streamSumEquationExp. Returns the expression
2252 max(flow_exp, eps)
2253 given a stream set element."
2254 input ConnectorElement element;
2255 input Real flowThreshold;
2256 output DAE.Exp exp;
2257 protected
2258 DAE.Exp flow_exp;
2259 algorithm
2260 6 flow_exp := flowExp(element);
2261 6 exp := makePositiveMaxCall(flow_exp, DAE.RCONST(flowThreshold));
2262 end sumOutside2;
2263
2264 protected function sumInside2
2265 "Helper function to streamSumEquationExp. Returns the expression
2266 max(-flow_exp, eps)
2267 given a stream set element."
2268 input ConnectorElement element;
2269 input Real flowThreshold;
2270 output DAE.Exp exp;
2271 protected
2272 DAE.Exp flow_exp;
2273 DAE.Type flowTy;
2274 algorithm
2275 58 flow_exp := flowExp(element);
2276 58 flowTy := Expression.typeof(flow_exp);
2277 58 flow_exp := DAE.UNARY(DAE.UMINUS(flowTy), flow_exp);
2278 58 exp := makePositiveMaxCall(flow_exp, DAE.RCONST(flowThreshold));
2279 end sumInside2;
2280
2281 public function faceEqual "Test for face equality."
2282 input Face face1;
2283 input Face face2;
2284 output Boolean sameFaces = valueConstructor(face1) == valueConstructor(face2);
2285 end faceEqual;
2286
2287 protected function makeInStreamCall
2288 "Creates an inStream call expression."
2289 input DAE.Exp streamExp;
2290 output DAE.Exp inStreamCall;
2291 annotation(__OpenModelica_EarlyInline = true);
2292 protected
2293 DAE.Type ty;
2294 algorithm
2295 14 ty := Expression.typeof(streamExp);
2296 14 inStreamCall := Expression.makeBuiltinCall("inStream", {streamExp}, ty, false);
2297 end makeInStreamCall;
2298
2299 protected function makePositiveMaxCall
2300 "Generates a max(flow_exp, eps) call."
2301 input DAE.Exp flowExp;
2302 input DAE.Exp flowThreshold;
2303 output DAE.Exp positiveMaxCall;
2304 annotation(__OpenModelica_EarlyInline = true);
2305 protected
2306 DAE.Type ty;
2307 Option<DAE.Exp> nominal_oexp;
2308 DAE.Exp nominal_exp, flow_threshold;
2309 algorithm
2310 128 ty := Expression.typeof(flowExp);
2311 128 nominal_oexp := Types.lookupAttributeExp(Types.getAttributes(ty), "nominal");
2312
2313
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 128 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 128 times.
128 if isSome(nominal_oexp) then
2314 ✗ SOME(nominal_exp) := nominal_oexp;
2315 ✗ flow_threshold := Expression.expMul(flowThreshold, nominal_exp);
2316 else
2317 flow_threshold := flowThreshold;
2318 end if;
2319
2320 128 positiveMaxCall :=
2321 DAE.CALL(Absyn.IDENT("$OMC$PositiveMax"), {flowExp, flow_threshold},
2322 DAE.CALL_ATTR(
2323 ty,
2324 false,
2325 true,
2326 false,
2327 false,
2328 DAE.NO_INLINE(),
2329 DAE.NO_TAIL(),
2330 DAE.NoReturn.RETURNS));
2331
2332 128 setGlobalRoot(Global.isInStream, SOME(true));
2333 end makePositiveMaxCall;
2334
2335 protected function evaluateConnectionOperators
2336 "Evaluates connection operators inStream, actualStream and cardinality in the
2337 given DAE."
2338 input Sets sets;
2339 input array<Set> setArray;
2340 input output DAE.DAElist DAE;
2341 protected
2342 Real flow_threshold;
2343 Boolean has_cardinality = System.getUsesCardinality();
2344 algorithm
2345 // Only do this phase if we have any connection operators.
2346
4/4
✓ Branch 1 taken 913 times.
✓ Branch 2 taken 126 times.
✓ Branch 3 taken 894 times.
✓ Branch 4 taken 19 times.
1039 if System.getHasStreamConnectors() or has_cardinality then
2347 145 flow_threshold := Flags.getConfigReal(Flags.FLOW_THRESHOLD);
2348
2/2
✓ Branch 1 taken 95 times.
✓ Branch 2 taken 50 times.
240 DAE := DAEUtil.traverseDAE(DAE, AvlTreePathFunction.Tree.EMPTY(),
2349 function evaluateConnectionOperators2(
2350 hasCardinality = has_cardinality,
2351 setArray = setArray,
2352 flowThreshold = flow_threshold), sets);
2353 145 DAE := simplifyDAEElements(has_cardinality, DAE);
2354 end if;
2355 end evaluateConnectionOperators;
2356
2357 protected function evaluateConnectionOperators2
2358 "Helper function to evaluateConnectionOperators."
2359 input output DAE.Exp exp;
2360 input output Sets sets;
2361 input array<Set> setArray;
2362 input Boolean hasCardinality;
2363 input Real flowThreshold;
2364 protected
2365 Boolean changed;
2366 algorithm
2367 410654 (exp, changed) := Expression.traverseExpBottomUp(exp,
2368 function evaluateConnectionOperatorsExp(
2369 sets = sets,
2370 setArray = setArray,
2371 flowThreshold = flowThreshold), false);
2372
2373 // Only apply simplify if the expression changed *AND* we have cardinality.
2374
2/2
✓ Branch 0 taken 409982 times.
✓ Branch 1 taken 672 times.
410654 if changed and hasCardinality then
2375 672 exp := ExpressionSimplify.simplify(exp);
2376 end if;
2377 end evaluateConnectionOperators2;
2378
2379 protected function evaluateConnectionOperatorsExp
2380 "Helper function to evaluateConnectionOperators2. Checks if the given
2381 expression is a call to inStream or actualStream, and if so calls the
2382 appropriate function in ConnectUtil to evaluate the call."
2383 input output DAE.Exp exp;
2384 input Sets sets;
2385 input array<Set> setArray;
2386 input Real flowThreshold;
2387 input output Boolean changed;
2388 algorithm
2389 (exp, changed) := match exp
2390 local
2391 DAE.ComponentRef cr;
2392 DAE.Exp e;
2393
2394 case DAE.CALL(path = Absyn.IDENT("inStream"),
2395 expLst = {DAE.CREF(componentRef = cr)})
2396 algorithm
2397 140 e := evaluateInStream(cr, sets, setArray, flowThreshold);
2398 //print("Evaluated inStream(" + ExpressionDump.dumpExpStr(DAE.CREF(cr, ty), 0) + ") ->\n" + ExpressionDump.dumpExpStr(e, 0) + "\n");
2399 then
2400 (e, true);
2401
2402 case DAE.CALL(path = Absyn.IDENT("actualStream"),
2403 expLst = {DAE.CREF(componentRef = cr)})
2404 algorithm
2405 18 e := evaluateActualStream(cr, sets, setArray, flowThreshold);
2406 //print("Evaluated actualStream(" + ExpressionDump.dumpExpStr(DAE.CREF(cr, ty), 0) + ") ->\n" + ExpressionDump.dumpExpStr(e, 0) + "\n");
2407 then
2408 (e, true);
2409
2410 case DAE.CALL(path = Absyn.IDENT("cardinality"),
2411 expLst = {DAE.CREF(componentRef = cr)})
2412 algorithm
2413 760 e := evaluateCardinality(cr, sets);
2414 then
2415 (e, true);
2416
2417 else (exp, changed);
2418
2419 end match;
2420 end evaluateConnectionOperatorsExp;
2421
2422 protected function mkArrayIfNeeded
2423 "@author: adrpo
2424 does an array out of exp if needed"
2425 input DAE.Type ty;
2426 input output DAE.Exp exp;
2427 algorithm
2428 ✗ exp := Expression.arrayFill(TypesDump.getDimensions(ty), exp);
2429 end mkArrayIfNeeded;
2430
2431 protected function evaluateInStream
2432 "This function evaluates the inStream operator for a component reference,
2433 given the connection sets."
2434 input DAE.ComponentRef streamCref;
2435 input Sets sets;
2436 input array<Set> setArray;
2437 input Real flowThreshold;
2438 output DAE.Exp exp;
2439 protected
2440 ConnectorElement e;
2441 list<ConnectorElement> sl;
2442 Integer set;
2443 algorithm
2444 try
2445 173 e := findElement(streamCref, Face.INSIDE(), ConnectorType.STREAM(NONE()),
2446 DAE.emptyElementSource, sets);
2447
2448
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 155 times.
173 if isNewElement(e) then
2449 // A new element means that the stream element couldn't be found in the sets
2450 // => unconnected stream connector.
2451 sl := {e};
2452 else
2453 // Otherwise, fetch the set that the element belongs to and evaluate the
2454 // inStream call.
2455 ConnectorElement.CONNECTOR_ELEMENT(set = set) := e;
2456
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 155 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 155 times.
155 Set.SET(ty = ConnectorType.STREAM(), elements = sl) :=
2457 setArrayGet(setArray, set);
2458 end if;
2459
2460 173 exp := generateInStreamExp(streamCref, sl, sets, setArray, flowThreshold);
2461 else
2462 ✗ true := Flags.isSet(Flags.FAILTRACE);
2463 ✗ Debug.traceln("- ConnectUtil.evaluateInStream failed for " +
2464 ComponentReference.crefStr(streamCref) + "\n");
2465 ✗ fail();
2466 end try;
2467 end evaluateInStream;
2468
2469 protected function generateInStreamExp
2470 "Helper function to evaluateInStream. Generates an expression for inStream
2471 given a connection set."
2472 input DAE.ComponentRef streamCref;
2473 input list<ConnectorElement> streams;
2474 input Sets sets;
2475 input array<Set> setArray;
2476 input Real flowThreshold;
2477 output DAE.Exp exp;
2478 protected
2479 list<ConnectorElement> reducedStreams;
2480 algorithm
2481 173 reducedStreams := List.filterOnFalse(streams, function isZeroFlowMinMax(streamCref = streamCref));
2482
2483 exp := match reducedStreams
2484 local
2485 DAE.ComponentRef c;
2486 Face f1, f2;
2487 DAE.Exp e, expr;
2488 list<ConnectorElement> inside, outside;
2489
2490 // Unconnected stream connector:
2491 // inStream(c) = c;
2492 case {ConnectorElement.CONNECTOR_ELEMENT(name = c, face = Face.INSIDE())}
2493 26 then Expression.crefExp(c);
2494
2495 // Two inside connected stream connectors:
2496 // inStream(c1) = c2;
2497 // inStream(c2) = c1;
2498 case {ConnectorElement.CONNECTOR_ELEMENT(face = Face.INSIDE()),
2499 ConnectorElement.CONNECTOR_ELEMENT(face = Face.INSIDE())}
2500 algorithm
2501
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 102 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 102 times.
102 {ConnectorElement.CONNECTOR_ELEMENT(name = c)} :=
2502 removeStreamSetElement(streamCref, reducedStreams);
2503 102 e := Expression.crefExp(c);
2504 then
2505 e;
2506
2507 // One inside, one outside connected stream connector:
2508 // inStream(c1) = inStream(c2);
2509 case {ConnectorElement.CONNECTOR_ELEMENT(face = f1),
2510 ConnectorElement.CONNECTOR_ELEMENT(face = f2)} guard not faceEqual(f1, f2)
2511 algorithm
2512
2/4
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16 times.
16 {ConnectorElement.CONNECTOR_ELEMENT(name = c)} :=
2513 removeStreamSetElement(streamCref, reducedStreams);
2514 16 e := evaluateInStream(c, sets, setArray, flowThreshold);
2515 then
2516 e;
2517
2518 // The general case:
2519 else
2520 algorithm
2521 29 (outside, inside) := List.splitOnTrue(reducedStreams, isOutsideElement);
2522 29 inside := removeStreamSetElement(streamCref, inside);
2523 29 e := streamSumEquationExp(outside, inside, flowThreshold);
2524
1/2
✓ Branch 0 taken 29 times.
✗ Branch 1 not taken.
29 if not listEmpty(inside) then
2525 29 expr := streamFlowExp(listHead(inside));
2526 29 e := Expression.makePureBuiltinCall("$OMC$inStreamDiv", {e, expr}, Expression.typeof(e));
2527 end if;
2528 // Evaluate any inStream calls that were generated.
2529 29 e := evaluateConnectionOperators2(e, sets, setArray, false, flowThreshold);
2530 then
2531 e;
2532 end match;
2533 end generateInStreamExp;
2534
2535 protected function evaluateActualStream
2536 "This function evaluates the actualStream operator for a component reference,
2537 given the connection sets."
2538 input DAE.ComponentRef streamCref;
2539 input Sets sets;
2540 input array<Set> setArray;
2541 input Real flowThreshold;
2542 output DAE.Exp exp;
2543 protected
2544 DAE.ComponentRef flow_cr;
2545 DAE.Exp flow_exp, stream_exp, instream_exp, rel_exp;
2546 DAE.Type ety;
2547 Integer flow_dir;
2548 algorithm
2549 18 flow_cr := getStreamFlowAssociation(streamCref, sets);
2550 18 ety := ComponentReference.crefLastType(flow_cr);
2551 18 flow_dir := evaluateFlowDirection(ety);
2552
2553 // Select a branch if we know the flow direction, otherwise generate the whole
2554 // if-equation.
2555
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 17 times.
18 if flow_dir == 1 then
2556 1 rel_exp := evaluateInStream(streamCref, sets, setArray, flowThreshold);
2557 elseif flow_dir == -1 then
2558 1 rel_exp := Expression.crefExp(streamCref);
2559 else
2560 16 flow_exp := Expression.crefExp(flow_cr);
2561 16 stream_exp := Expression.crefExp(streamCref);
2562 16 instream_exp := evaluateInStream(streamCref, sets, setArray, flowThreshold);
2563 16 rel_exp := DAE.IFEXP(
2564 DAE.RELATION(flow_exp, DAE.GREATER(ety), DAE.RCONST(0.0), -1, NONE()),
2565 instream_exp, stream_exp);
2566 end if;
2567
2568 // actualStream(stream_var) = smooth(0, if flow_var > 0 then inStream(stream_var)
2569 // else stream_var);
2570 18 exp := DAE.CALL(Absyn.IDENT("smooth"), {DAE.ICONST(0), rel_exp},
2571 DAE.callAttrBuiltinReal);
2572 end evaluateActualStream;
2573
2574 protected function evaluateFlowDirection
2575 "Checks the min/max attributes of a flow variables type to try and determine
2576 the flow direction. If the flow is positive 1 is returned, if it is negative
2577 -1, otherwise 0 if the direction can't be decided."
2578 input DAE.Type ty;
2579 output Integer direction = 0;
2580 protected
2581 list<DAE.Var> attr;
2582 Option<Values.Value> min_oval, max_oval;
2583 Real min_val, max_val;
2584 algorithm
2585 18 attr := Types.getAttributes(ty);
2586
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 16 times.
18 if listEmpty(attr) then return; end if;
2587
2588 16 min_oval := Types.lookupAttributeValue(attr, "min");
2589 16 max_oval := Types.lookupAttributeValue(attr, "max");
2590
2591 direction := match (min_oval, max_oval)
2592 // No attributes, flow direction can't be decided.
2593 case (NONE(), NONE()) then 0;
2594 // Flow is positive if min is positive.
2595 case (SOME(Values.REAL(min_val)), NONE())
2596 ✗ then if min_val >= 0 then 1 else 0;
2597 // Flow is negative if max is negative.
2598 case (NONE(), SOME(Values.REAL(max_val)))
2599 ✗ then if max_val <= 0 then -1 else 0;
2600 // Flow is positive if both min and max are positive, negative if they are
2601 // both negative, otherwise undecideable.
2602 case (SOME(Values.REAL(min_val)), SOME(Values.REAL(max_val)))
2603
6/8
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 14 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 time.
16 then
2604 if min_val >= 0 and max_val >= min_val then 1
2605 elseif max_val <= 0 and min_val <= max_val then -1
2606 else 0;
2607 else 0;
2608 end match;
2609 end evaluateFlowDirection;
2610
2611 protected function evaluateCardinality
2612 input DAE.ComponentRef cref;
2613 input Sets sets;
2614 output DAE.Exp exp;
2615 algorithm
2616 760 exp := DAE.ICONST(getConnectCount(cref, sets.sets));
2617 end evaluateCardinality;
2618
2619 protected function simplifyDAEElements
2620 "run this only if we have cardinality"
2621 input Boolean hasCardinality;
2622 input output DAE.DAElist DAE;
2623 algorithm
2624
2/2
✓ Branch 0 taken 95 times.
✓ Branch 1 taken 50 times.
145 if hasCardinality then
2625 50 DAE := DAE.DAE(List.mapFlat(DAE.elementLst, simplifyDAEElement));
2626 end if;
2627 end simplifyDAEElements;
2628
2629 protected function simplifyDAEElement
2630 input DAE.Element element;
2631 output list<DAE.Element> elements;
2632 algorithm
2633 elements := matchcontinue element
2634 local
2635 list<DAE.Exp> conds;
2636 list<list<DAE.Element>> branches;
2637 list<DAE.Element> else_branch;
2638
2639 case DAE.IF_EQUATION(conds, branches, else_branch)
2640 371 then simplifyDAEIfEquation(conds, branches, else_branch);
2641
2642 case DAE.INITIAL_IF_EQUATION(conds, branches, else_branch)
2643 3 then simplifyDAEIfEquation(conds, branches, else_branch);
2644
2645 case DAE.ASSERT(condition = DAE.BCONST(true)) then {};
2646
2647 else {element};
2648
2649 end matchcontinue;
2650 end simplifyDAEElement;
2651
2652 protected function simplifyDAEIfEquation
2653 input list<DAE.Exp> conditions;
2654 input list<list<DAE.Element>> branches;
2655 input list<DAE.Element> elseBranch;
2656 output list<DAE.Element> elements;
2657 protected
2658 Boolean cond_value;
2659 list<list<DAE.Element>> rest_branches = branches;
2660 algorithm
2661
2/2
✓ Branch 0 taken 376 times.
✓ Branch 1 taken 19 times.
395 for cond in conditions loop
2662
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 366 times.
376 DAE.BCONST(cond_value) := cond;
2663
2664 // Condition is true, substitute if-equation with the branch contents.
2665
2/2
✓ Branch 0 taken 345 times.
✓ Branch 1 taken 21 times.
366 if cond_value == true then
2666 345 elements := listReverse(listHead(rest_branches));
2667 345 return;
2668 end if;
2669
2670 // Condition is false, discard the branch and continue with the other branches.
2671 21 rest_branches := listRest(rest_branches);
2672 end for;
2673
2674 // All conditions were false, substitute if-equation with else-branch contents.
2675 19 elements := listReverse(elseBranch);
2676 end simplifyDAEIfEquation;
2677
2678 protected function removeStreamSetElement
2679 "This function removes the given cref from a connection set."
2680 input DAE.ComponentRef cref;
2681 input output list<ConnectorElement> elements;
2682 algorithm
2683 150 elements := List.deleteMemberOnTrue(cref, elements, compareCrefStreamSet);
2684 end removeStreamSetElement;
2685
2686 protected function compareCrefStreamSet
2687 "Helper function to removeStreamSetElement. Checks if the cref in a stream set
2688 element matches the given cref."
2689 input DAE.ComponentRef cref;
2690 input ConnectorElement element;
2691 output Boolean matches;
2692 algorithm
2693 594 matches := ComponentReferenceBasics.crefEqualNoStringCompare(cref, element.name);
2694 end compareCrefStreamSet;
2695
2696 public function componentFace
2697 "This function determines whether a component
2698 reference refers to an inner or outer connector:
2699 Rules:
2700 qualified cref and connector => OUTSIDE
2701 non-qualifed cref => OUTSIDE
2702 qualified cref and non-connector => INSIDE
2703
2704 Modelica Specification 4.0
2705 Section: 9.1.2 Inside and Outside Connectors
2706 In an element instance M, each connector element of M is called an outside connector with respect to M.
2707 All other connector elements that are hierarchically inside M, but not in one of the outside connectors
2708 of M, is called an inside connector with respect to M. This is done **BEFORE** resolving outer elements
2709 to corresponding inner ones."
2710 input FCore.Graph env;
2711 input DAE.ComponentRef componentRef;
2712 output Face face;
2713 algorithm
2714 face := matchcontinue componentRef
2715 local
2716 DAE.Ident id;
2717
2718 // is a non-qualified cref => OUTSIDE
2719 case DAE.CREF_IDENT() then Face.OUTSIDE();
2720
2721 // is a qualified cref and is a connector => OUTSIDE
2722 case DAE.CREF_QUAL(ident = id)
2723 algorithm
2724
4/4
✓ Branch 3 taken 124 times.
✓ Branch 4 taken 18472 times.
✓ Branch 5 taken 12183 times.
✓ Branch 6 taken 6289 times.
18596 (_, _, DAE.T_COMPLEX(complexClassType=ClassInf.CONNECTOR(_,_)),_,_,_,_,_,_)
2725 := Lookup.lookupVar(FCore.emptyCache(), env,
2726 ComponentReferenceBasics.makeCrefIdent(id, DAE.T_UNKNOWN_DEFAULT,{}));
2727 then Face.OUTSIDE();
2728
2729 // is a qualified cref and is NOT a connector => INSIDE
2730 case DAE.CREF_QUAL() then Face.INSIDE();
2731 end matchcontinue;
2732 end componentFace;
2733
2734 public function componentFaceType
2735 "Author: BZ, 2008-12
2736 Same functionalty as componentFace, with the difference that
2737 this function checks ident-type rather then env->lookup ==> type.
2738 Rules:
2739 qualified cref and connector => OUTSIDE
2740 non-qualifed cref => OUTSIDE
2741 qualified cref and non-connector => INSIDE
2742
2743 Modelica Specification 4.0
2744 Section: 9.1.2 Inside and Outside Connectors
2745 In an element instance M, each connector element of M is called an outside connector with respect to M.
2746 All other connector elements that are hierarchically inside M, but not in one of the outside connectors
2747 of M, is called an inside connector with respect to M. This is done **BEFORE** resolving outer elements
2748 to corresponding inner ones."
2749 input DAE.ComponentRef inComponentRef;
2750 output Face outFace;
2751 algorithm
2752 outFace := match inComponentRef
2753 // is a non-qualified cref => OUTSIDE
2754 case DAE.CREF_IDENT() then Face.OUTSIDE();
2755 // is a qualified cref and is a connector => OUTSIDE
2756 case DAE.CREF_QUAL(identType = DAE.T_COMPLEX(complexClassType=ClassInf.CONNECTOR(_,_))) then Face.OUTSIDE();
2757 // is a qualified cref and is an array of connectors => OUTSIDE
2758 case DAE.CREF_QUAL(identType = DAE.T_ARRAY(ty = DAE.T_COMPLEX(complexClassType=ClassInf.CONNECTOR(_,_)))) then Face.OUTSIDE();
2759 // is a qualified cref and is NOT a connector => INSIDE
2760 case DAE.CREF_QUAL() then Face.INSIDE();
2761 end match;
2762 end componentFaceType;
2763
2764 public function checkConnectorBalance
2765 "Checks if a connector class is balanced or not, according to the rules in the
2766 Modelica 3.2 specification."
2767 input list<DAE.Var> vars;
2768 input Absyn.Path path;
2769 input SourceInfo info;
2770 protected
2771 Integer potentials, flows, streams;
2772 algorithm
2773 4386 (potentials, flows, streams) := countConnectorVars(vars);
2774
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4386 times.
4386 true := checkConnectorBalance2(potentials, flows, streams, path, info);
2775 //print(AbsynUtil.pathString(path) + " has:\n\t" +
2776 // String(potentials) + " potential variables\n\t" +
2777 // String(flows) + " flow variables\n\t" +
2778 // String(streams) + " stream variables\n\n");
2779 end checkConnectorBalance;
2780
2781 protected function checkConnectorBalance2
2782 input Integer potentialVars;
2783 input Integer flowVars;
2784 input Integer streamVars;
2785 input Absyn.Path path;
2786 input SourceInfo info;
2787 output Boolean isBalanced = true;
2788 protected
2789 String flow_str, potential_str, class_str;
2790 algorithm
2791 // Don't check connector balance for language version 2.x and earlier.
2792
2/2
✓ Branch 1 taken 399 times.
✓ Branch 2 taken 4001 times.
4400 if Config.languageStandardAtMost(Config.LanguageStandard._2_x) then
2793 399 return;
2794 end if;
2795
2796 // Modelica 3.2 section 9.3.1:
2797 // For each non-partial connector class the number of flow variables shall
2798 // be equal to the number of variables that are neither parameter, constant,
2799 // input, output, stream nor flow.
2800
2/2
✓ Branch 0 taken 148 times.
✓ Branch 1 taken 3853 times.
4001 if potentialVars <> flowVars then
2801 148 flow_str := String(flowVars);
2802 148 potential_str := String(potentialVars);
2803 148 class_str := AbsynUtil.pathString(path);
2804 148 Error.addSourceMessage(Error.UNBALANCED_CONNECTOR, {class_str, potential_str, flow_str}, info);
2805
2806 // This should be a hard error, but there are models that contain such
2807 // connectors. So we print an error but return that the connector is balanced.
2808 end if;
2809
2810 // Modelica 3.2 section 15.1:
2811 // A stream connector must have exactly one scalar variable with the flow prefix.
2812
1/2
✓ Branch 0 taken 4001 times.
✗ Branch 1 not taken.
4001 if streamVars > 0 and flowVars <> 1 then
2813 ✗ flow_str := String(flowVars);
2814 ✗ class_str := AbsynUtil.pathString(path);
2815 ✗ Error.addSourceMessage(Error.MISMATCHED_FLOW_IN_STREAM_CONNECTOR, {class_str, flow_str}, info);
2816 isBalanced := false;
2817 end if;
2818 end checkConnectorBalance2;
2819
2820 protected function countConnectorVars
2821 "Given a list of connector variables, this function counts how many potential,
2822 flow and stream variables it contains."
2823 input list<DAE.Var> vars;
2824 output Integer potentialVars = 0;
2825 output Integer flowVars = 0;
2826 output Integer streamVars = 0;
2827 protected
2828 DAE.Type ty, ty2;
2829 DAE.Attributes attr;
2830 Integer n, p, f, s;
2831 algorithm
2832
2/2
✓ Branch 0 taken 12051 times.
✓ Branch 1 taken 4451 times.
16502 for var in vars loop
2833 12051 DAE.TYPES_VAR(ty = ty, attributes = attr) := var;
2834 12051 ty2 := Types.arrayElementType(ty);
2835
2836 // Check if we have a connector inside a connector.
2837
2/2
✓ Branch 1 taken 65 times.
✓ Branch 2 taken 11986 times.
12051 if Types.isConnector(ty2) then
2838 // If we have an array of connectors, count the elements.
2839
4/4
✓ Branch 1 taken 55 times.
✓ Branch 2 taken 65 times.
✓ Branch 3 taken 55 times.
✓ Branch 4 taken 65 times.
120 n := product(dim for dim in Types.getDimensionSizes(ty));
2840 // Count the number of different variables inside the connector, and then
2841 // multiply those numbers with the dimensions of the array.
2842 65 (p, f, s) := countConnectorVars(Types.getConnectorVars(ty2));
2843
2844 // If the variable is input/output we don't count potential variables.
2845
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 65 times.
65 if AbsynUtil.isInputOrOutput(DAEUtil.getAttrDirection(attr)) then
2846 p := 0;
2847 end if;
2848
2849 65 potentialVars := potentialVars + p * n;
2850 65 flowVars := flowVars + f * n;
2851 65 streamVars := streamVars + s * n;
2852 else
2853 () := match attr
2854 // A flow variable.
2855 case DAE.ATTR(connectorType = DAE.FLOW())
2856 algorithm
2857 5070 flowVars := flowVars + sizeOfType(var.ty);
2858 then
2859 ();
2860
2861 // A stream variable.
2862 case DAE.ATTR(connectorType = DAE.STREAM())
2863 algorithm
2864 321 streamVars := streamVars + sizeOfType(var.ty);
2865 then
2866 ();
2867
2868 // A potential variable.
2869 case DAE.ATTR(direction = Absyn.BIDIR(), variability = SCode.VAR())
2870 algorithm
2871 5782 potentialVars := potentialVars + sizeOfType(var.ty);
2872 then
2873 ();
2874
2875 else ();
2876 end match;
2877 end if;
2878 end for;
2879 end countConnectorVars;
2880
2881 protected function sizeOfVariableList
2882 "Calls sizeOfVariable on a list of variables, and adds up the results."
2883 input list<DAE.Var> vars;
2884 output Integer size = 0;
2885 algorithm
2886 ✗ for var in vars loop
2887 ✗ size := size + sizeOfType(var.ty);
2888 end for;
2889 end sizeOfVariableList;
2890
2891 protected function sizeOfType
2892 "Different types of variables have different size, for example arrays. This
2893 function checks the size of one variable."
2894 input DAE.Type ty;
2895 output Integer size;
2896 algorithm
2897 size := match ty
2898 local
2899 Integer n;
2900 DAE.Type t;
2901 list<DAE.Var> v;
2902
2903 // Scalar values consist of one element.
2904 case DAE.T_INTEGER() then 1;
2905 case DAE.T_REAL() then 1;
2906 case DAE.T_STRING() then 1;
2907 case DAE.T_BOOL() then 1;
2908 case DAE.T_ENUMERATION() then 1;
2909 // The size of an array is its dimension multiplied with the size of its type.
2910 case DAE.T_ARRAY()
2911
6/8
✓ Branch 0 taken 3779 times.
✓ Branch 1 taken 3779 times.
✓ Branch 2 taken 3779 times.
✓ Branch 3 taken 3779 times.
✓ Branch 5 taken 3779 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 3779 times.
7558 then intMul(Expression.dimensionSize(dim) for dim in ty.dims) * sizeOfType(ty.ty);
2912 // The size of a complex type without an equalityConstraint (such as a
2913 // record), is the sum of the sizes of its components.
2914 case DAE.T_COMPLEX(varLst = v, equalityConstraint = NONE())
2915 ✗ then sizeOfVariableList(v);
2916 // The size of a complex type with an equalityConstraint function is
2917 // determined by the size of the return value of that function.
2918 case DAE.T_COMPLEX(equalityConstraint = SOME((_, n, _))) then n;
2919 // The size of a basic subtype with equality constraint is ZERO.
2920 case DAE.T_SUBTYPE_BASIC(equalityConstraint = SOME(_)) then 0;
2921 // The size of a basic subtype is the size of the extended type.
2922 1 case DAE.T_SUBTYPE_BASIC(complexType = t) then sizeOfType(t);
2923 // Anything we forgot?
2924 else
2925 algorithm
2926 ✗ true := Flags.isSet(Flags.FAILTRACE);
2927 ✗ Debug.traceln("- ConnectUtil.sizeOfType failed on " + TypesDump.printTypeStr(ty));
2928 ✗ then
2929 fail();
2930 end match;
2931 end sizeOfType;
2932
2933 public function checkShortConnectorDef
2934 "Checks a short connector definition that has extended a basic type, i.e.
2935 connector C = Real;."
2936 input ClassInf.State state;
2937 input SCode.Attributes attributes;
2938 input SourceInfo info;
2939 output Boolean isValid;
2940 algorithm
2941 isValid := match(state, attributes)
2942 local
2943 Integer pv = 0, fv = 0, sv = 0;
2944 SCode.ConnectorType ct;
2945
2946 // Extended from bidirectional basic type, which means that it can't be
2947 // balanced.
2948 case (ClassInf.CONNECTOR(),
2949 SCode.ATTR(connectorType = ct, direction = Absyn.BIDIR()))
2950 algorithm
2951 // The connector might be either flow, stream or neither.
2952 // This will set either fv, sv, or pv to 1, and the rest to 0, and
2953 // checkConnectorBalance2 will then be called to provide the appropriate
2954 // error message (or might actually succeed if +std=2.x or 1.x).
2955
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 if SCodeUtil.flowBool(ct) then
2956 fv := 1;
2957 elseif SCodeUtil.streamBool(ct) then
2958 sv := 1;
2959 else
2960 pv := 1;
2961 end if;
2962 14 then
2963 checkConnectorBalance2(pv, fv, sv, state.path, info);
2964
2965 // All other cases are ok.
2966 else true;
2967 end match;
2968 end checkShortConnectorDef;
2969
2970 public function isReferenceInConnects
2971 input list<ConnectorElement> connects;
2972 input DAE.ComponentRef cref;
2973 output Boolean isThere = false;
2974 algorithm
2975
2/2
✓ Branch 0 taken 1068 times.
✓ Branch 1 taken 366 times.
1434 for ce in connects loop
2976
2/2
✓ Branch 1 taken 48 times.
✓ Branch 2 taken 1020 times.
1068 if ComponentReferenceBasics.crefPrefixOf(cref, ce.name) then
2977 isThere := true;
2978 48 return;
2979 end if;
2980 end for;
2981 end isReferenceInConnects;
2982
2983 public function removeReferenceFromConnects
2984 input output list<ConnectorElement> connects;
2985 input DAE.ComponentRef cref;
2986 output Boolean wasRemoved;
2987 protected
2988 Option<ConnectorElement> oe;
2989 algorithm
2990 12 (connects, oe) := List.deleteMemberOnTrue(cref, connects,
2991 removeReferenceFromConnects2);
2992
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
12 wasRemoved := isSome(oe);
2993 end removeReferenceFromConnects;
2994
2995 protected function removeReferenceFromConnects2
2996 input DAE.ComponentRef cref;
2997 input ConnectorElement element;
2998 output Boolean matches;
2999 algorithm
3000 24 matches := ComponentReferenceBasics.crefPrefixOf(cref, element.name);
3001 end removeReferenceFromConnects2;
3002
3003 public function printSetsStr
3004 "Prints a Sets to a String."
3005 input Sets sets;
3006 output String string;
3007 algorithm
3008 ✗ string := String(sets.setCount) + " sets:\n";
3009 ✗ string := string + printSetTrieStr(sets.sets, "\t");
3010 ✗ string := string + "Connected sets:\n";
3011 ✗ string := string + printSetConnections(sets.connections) + "\n";
3012 end printSetsStr;
3013
3014 protected function printSetTrieStr
3015 "Prints a SetTrie to a String."
3016 input SetTrie trie;
3017 input String accumName;
3018 output String string;
3019 algorithm
3020 string := match trie
3021 local
3022 String name, res;
3023
3024 case SetTrieNode.SET_TRIE_LEAF()
3025 algorithm
3026 ✗ res := accumName + "." + trie.name + ":";
3027 ✗ res := res + printLeafElementStr(trie.insideElement);
3028 ✗ res := res + printLeafElementStr(trie.outsideElement);
3029 ✗ res := res + printOptFlowAssociation(trie.flowAssociation) + "\n";
3030 then
3031 res;
3032
3033 case SetTrieNode.SET_TRIE_NODE(name = "")
3034 ✗ then stringAppendList(List.map1(trie.nodes, printSetTrieStr, accumName));
3035
3036 case SetTrieNode.SET_TRIE_NODE()
3037 algorithm
3038 ✗ name := accumName + "." + trie.name;
3039 ✗ res := stringAppendList(List.map1(trie.nodes, printSetTrieStr, name));
3040 then
3041 res;
3042
3043 end match;
3044 end printSetTrieStr;
3045
3046 protected function printLeafElementStr
3047 "Prints an optional connector element to a String."
3048 input Option<ConnectorElement> element;
3049 output String string;
3050 algorithm
3051 string := match element
3052 local
3053 ConnectorElement e;
3054 String res;
3055
3056 case SOME(e as ConnectorElement.CONNECTOR_ELEMENT())
3057 algorithm
3058 ✗ res := " " + printFaceStr(e.face) + " ";
3059 ✗ res := res + printConnectorTypeStr(e.ty) + " [" + String(e.set) + "]";
3060 then
3061 res;
3062
3063 else "";
3064
3065 end match;
3066 end printLeafElementStr;
3067
3068 public function printElementStr
3069 "Prints a connector element to a String."
3070 input ConnectorElement element;
3071 output String string;
3072 algorithm
3073 ✗ string := ComponentReferenceBasics.printComponentRefStr(element.name) + " ";
3074 ✗ string := string + printFaceStr(element.face) + " ";
3075 ✗ string := string + printConnectorTypeStr(element.ty) + " [" + String(element.set) + "]";
3076 end printElementStr;
3077
3078 public function printFaceStr
3079 "Prints the Face to a String."
3080 input Face face;
3081 output String string;
3082 algorithm
3083 string := match face
3084 case Face.INSIDE() then "inside";
3085 case Face.OUTSIDE() then "outside";
3086 case Face.NO_FACE() then "unknown";
3087 end match;
3088 end printFaceStr;
3089
3090 protected function printConnectorTypeStr
3091 "Prints the connector type to a String."
3092 input ConnectorType ty;
3093 output String string;
3094 algorithm
3095 string := match ty
3096 case ConnectorType.EQU() then "equ";
3097 case ConnectorType.FLOW() then "flow";
3098 case ConnectorType.STREAM() then "stream";
3099 end match;
3100 end printConnectorTypeStr;
3101
3102 protected function printOptFlowAssociation
3103 "Print an optional flow association to a String."
3104 input Option<DAE.ComponentRef> cref;
3105 output String string;
3106 algorithm
3107 string := match cref
3108 local
3109 DAE.ComponentRef cr;
3110
3111 case NONE()
3112 then "";
3113
3114 case SOME(cr)
3115 ✗ then " associated flow: " + ComponentReferenceBasics.printComponentRefStr(cr);
3116
3117 end match;
3118 end printOptFlowAssociation;
3119
3120 protected function printSetConnections
3121 "Prints a list of set connection to a String."
3122 input list<SetConnection> connections;
3123 output String string;
3124 algorithm
3125 ✗ string := stringAppendList(List.map(connections, printSetConnection));
3126 end printSetConnections;
3127
3128 protected function printSetConnection
3129 "Prints a set connection to a String."
3130 input SetConnection connection;
3131 output String string;
3132 protected
3133 Integer set1, set2;
3134 algorithm
3135 ✗ (set1, set2) := connection;
3136 ✗ string := "\t" + String(set1) + " connected to " + intString(set2) + "\n";
3137 end printSetConnection;
3138
3139 protected function printSetStr
3140 "Prints a Set to a String."
3141 input Set set;
3142 output String string;
3143 algorithm
3144 string := match set
3145 case Set.SET()
3146 ✗ then stringDelimitList(List.map(set.elements, printElementStr), ", ");
3147
3148 case Set.SET_POINTER()
3149 ✗ then "pointer to set " + intString(set.index);
3150 end match;
3151 end printSetStr;
3152
3153 protected function getAllEquCrefs
3154 "@author: adrpo
3155 return all crefs present in EQU sets"
3156 input list<Set> sets;
3157 output list<DAE.ComponentRef> crefs = {};
3158 algorithm
3159
2/2
✓ Branch 0 taken 8577 times.
✓ Branch 1 taken 5393 times.
13970 for set in sets loop
3160 () := match set
3161 case Set.SET(ty = ConnectorType.EQU())
3162 algorithm
3163
2/2
✓ Branch 0 taken 18582 times.
✓ Branch 1 taken 6585 times.
25167 for e in set.elements loop
3164 18582 crefs := e.name :: crefs;
3165 end for;
3166 then
3167 ();
3168
3169 else ();
3170 end match;
3171 end for;
3172 end getAllEquCrefs;
3173
3174 protected function removeUnusedExpandableVariablesAndConnections
3175 "@author: adrpo
3176 this function will remove all unconnected/unused/unnecessary expandable variables and connections from the DAE.
3177 NOTE that this is not so obvious:
3178 1. collect all expandable variables crefs
3179 2. collect all expandable crefs used in the DAE (with the expandable variables THAT HAVE NO BINDING removed)
3180 3. get all expandable crefs that are connected ONLY with expandable
3181 4. substract: (3)-(2)
3182 5. remove (4) from the DAE and connection sets
3183 6. get all the connected potential variables
3184 7. substract (2) from (1)
3185 8. substract (6) from (7)
3186 9. remove (8) from the DAE (5)"
3187 input output list<Set> sets;
3188 input output DAE.DAElist DAE;
3189 protected
3190 list<DAE.Element> elems;
3191 list<DAE.ComponentRef> expandableVars, unnecessary, usedInDAE, onlyExpandableConnected, equVars;
3192 DAE.DAElist dae;
3193 list<list<DAE.ComponentRef>> setsAsCrefs;
3194 algorithm
3195 7 DAE.DAE(elems) := DAE;
3196
3197 // 1 - get all expandable crefs
3198 7 expandableVars := getExpandableVariablesWithNoBinding(elems);
3199 // print("All expandable (1):\n " + stringDelimitList(List.map(expandableVars, ComponentReferenceBasics.printComponentRefStr), "\n ") + "\n");
3200
3201 // 2 - remove all expandable without binding from the dae
3202 7 dae := DAEUtil.removeVariables(DAE, expandableVars);
3203 // 2 - get all expandable crefs used in the dae (without the expandable vars)
3204 7 usedInDAE := getAllExpandableCrefsFromDAE(dae);
3205 // print("Used in the DAE (2):\n " + stringDelimitList(List.map(usedInDAE, ComponentReferenceBasics.printComponentRefStr), "\n ") + "\n");
3206
3207 // 3 - get all expandable crefs that are connected ONLY with expandable
3208 7 setsAsCrefs := getExpandableEquSetsAsCrefs(sets);
3209 7 setsAsCrefs := mergeEquSetsAsCrefs(setsAsCrefs);
3210 // TODO! FIXME! maybe we should do fixpoint here??
3211 7 setsAsCrefs := mergeEquSetsAsCrefs(setsAsCrefs);
3212 7 onlyExpandableConnected := getOnlyExpandableConnectedCrefs(setsAsCrefs);
3213 // print("All expandable - expandable connected (3):\n " + stringDelimitList(List.map(onlyExpandableConnected, ComponentReferenceBasics.printComponentRefStr), "\n ") + "\n");
3214
3215 // 4 - subtract (2) from (3)
3216 7 unnecessary := List.setDifferenceOnTrue(onlyExpandableConnected, usedInDAE, ComponentReferenceBasics.crefEqualWithoutSubs);
3217 // print("REMOVE: (3)-(2):\n " + stringDelimitList(List.map(unnecessary, ComponentReferenceBasics.printComponentRefStr), "\n ") + "\n");
3218
3219 // 5 - remove unnecessary variables form the DAE
3220 7 DAE := DAEUtil.removeVariables(DAE, unnecessary);
3221 // 5 - remove unnecessary variables form the connection sets
3222 7 sets := removeCrefsFromSets(sets, unnecessary);
3223
3224 7 equVars := getAllEquCrefs(sets);
3225 // print("(6):\n " + stringDelimitList(List.map(equVars, ComponentReferenceBasics.printComponentRefStr), "\n ") + "\n");
3226 7 expandableVars := List.setDifferenceOnTrue(expandableVars, usedInDAE, ComponentReferenceBasics.crefEqualWithoutSubs);
3227 // print("(1)-(2)=(7):\n " + stringDelimitList(List.map(equVars, ComponentReferenceBasics.printComponentRefStr), "\n ") + "\n");
3228 7 unnecessary := List.setDifferenceOnTrue(expandableVars, equVars, ComponentReferenceBasics.crefEqualWithoutSubs);
3229 // print("REMOVE: (7)-(6):\n " + stringDelimitList(List.map(unnecessary, ComponentReferenceBasics.printComponentRefStr), "\n ") + "\n");
3230 7 DAE := DAEUtil.removeVariables(DAE, unnecessary);
3231 end removeUnusedExpandableVariablesAndConnections;
3232
3233 protected function isEquType
3234 input ConnectorType ty;
3235 output Boolean isEqu;
3236 algorithm
3237 isEqu := match ty
3238 case ConnectorType.EQU() then true;
3239 else false;
3240 end match;
3241 end isEquType;
3242
3243 public function topLevelInput "author: PA
3244 if variable is input declared at the top level of the model,
3245 or if it is an input in a connector instance at top level return true."
3246 input DAE.ComponentRef componentRef;
3247 input DAE.VarDirection varDirection;
3248 input DAE.ConnectorType connectorType;
3249 input DAE.VarVisibility visibility = DAE.PUBLIC();
3250 output Boolean isTopLevel;
3251 protected
3252 // the new frontend only keeps top level inputs, obsoleting bogus check for DAE.CREF_IDENT
3253 Boolean newInst = Flags.isSet(Flags.SCODE_INST);
3254 algorithm
3255 isTopLevel := match (varDirection, componentRef, visibility, newInst)
3256 case ( _, _, DAE.PROTECTED(), _) then false;
3257 case (DAE.INPUT(), _, _, true) then true;
3258 case (DAE.INPUT(), DAE.CREF_IDENT(), _, _) then true;
3259 case (DAE.INPUT(), _, _, _)
3260 guard(faceEqual(componentFaceType(componentRef), Face.OUTSIDE()))
3261 ✗ then topLevelConnectorType(connectorType);
3262 else false;
3263 end match;
3264 end topLevelInput;
3265
3266 protected function topLevelConnectorType
3267 input DAE.ConnectorType inConnectorType;
3268 output Boolean isTopLevel;
3269 algorithm
3270 isTopLevel := match inConnectorType
3271 case DAE.FLOW() then true;
3272 case DAE.POTENTIAL() then true;
3273 else false;
3274 end match;
3275 end topLevelConnectorType;
3276
3277 public function getAllExpandableCrefsFromDAE
3278 "@author: adrpo
3279 collect all crefs from the DAE"
3280 input DAE.DAElist inDAE;
3281 output list<DAE.ComponentRef> outCrefs;
3282 protected
3283 list<DAE.Element> elts;
3284 algorithm
3285 7 DAE.DAE(elts) := inDAE;
3286 7 (_, (_, outCrefs)) := DAEUtil.traverseDAEElementList(elts, Expression.traverseSubexpressionsHelper, (collectAllExpandableCrefsInExp, {}));
3287 end getAllExpandableCrefsFromDAE;
3288
3289 protected function collectAllExpandableCrefsInExp "collect all crefs from expression"
3290 input DAE.Exp exp;
3291 input list<DAE.ComponentRef> acc;
3292 output DAE.Exp outExp;
3293 output list<DAE.ComponentRef> outCrefs;
3294 algorithm
3295 (outExp,outCrefs) := match exp
3296 local
3297 DAE.ComponentRef cr;
3298
3299 case DAE.CREF(componentRef = cr)
3300 19781 then (exp,List.consOnTrue(isExpandable(cr),cr,acc));
3301
3302 else (exp,acc);
3303
3304 end match;
3305 end collectAllExpandableCrefsInExp;
3306
3307 annotation(__OpenModelica_Interface="frontend");
3308 end ConnectUtil;
3309