Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 86.4% 57 / 0 / 66
Functions: -% 0 / 1 / 1
Branches: 74.3% 52 / 0 / 70

OMCompiler/Compiler/NFFrontEnd/NFConnections.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 uniontype NFConnections
37 import Connection = NFConnection;
38 import Connector = NFConnector;
39 import FlatModel = NFFlatModel;
40 import ComponentRef = NFComponentRef;
41 import Equation = NFEquation;
42 import NFPrefixes.ConnectorType;
43
44 protected
45 import Connections = NFConnections;
46 import DAE;
47 import ElementSource;
48 import ExpandExp = NFExpandExp;
49 import Expression = NFExpression;
50 import Flags;
51 import MetaModelica.Dangerous.listReverseInPlace;
52 import Component = NFComponent;
53 import NFInstNode.InstNode;
54 import Type = NFType;
55
56 public
57 uniontype BrokenEdge
58 record BROKEN_EDGE
59 ComponentRef lhs;
60 ComponentRef rhs;
61 DAE.ElementSource source;
62 list<Equation> brokenEquations;
63 end BROKEN_EDGE;
64 end BrokenEdge;
65
66 type BrokenEdges = list<BrokenEdge>;
67
68 record CONNECTIONS
69 list<Connection> connections;
70 list<Connector> flows;
71 BrokenEdges broken;
72 end CONNECTIONS;
73
74 function new
75 output Connections conns = CONNECTIONS({}, {}, {});
76 end new;
77
78 function fromConnectionList
79 input list<Connection> connl;
80 output Connections conns;
81 algorithm
82 ✗ conns := CONNECTIONS(connl, {}, {});
83 end fromConnectionList;
84
85 function addConnection
86 input Connection conn;
87 input output Connections conns;
88 algorithm
89 ✗ conns.connections := conn :: conns.connections;
90 end addConnection;
91
92 function addFlow
93 input Connector conn;
94 input output Connections conns;
95 algorithm
96 19042 conns.flows := conn :: conns.flows;
97 end addFlow;
98
99 function addBroken
100 input BrokenEdges broken;
101 input output Connections conns;
102 algorithm
103 1571 conns.broken := broken;
104 end addBroken;
105
106 function collectConnections
107 input output FlatModel flatModel;
108 input IsDeleted isDeleted;
109 output Connections conns = new();
110
111 partial function IsDeleted
112 input ComponentRef cref;
113 output Boolean res;
114 end IsDeleted;
115 protected
116 ComponentRef lhs, rhs;
117 DAE.ElementSource source;
118 list<Equation> eql = {};
119 Type ty1, ty2;
120 algorithm
121 // Collect all connects.
122
2/2
✓ Branch 0 taken 90207 times.
✓ Branch 1 taken 1573 times.
91780 for eq in flatModel.equations loop
123 eql := match eq
124 case Equation.CONNECT(lhs = Expression.CREF(ty = ty1, cref = lhs),
125 rhs = Expression.CREF(ty = ty2, cref = rhs), source = source)
126 algorithm
127 13348 lhs := ComponentRef.evaluateSubscripts(lhs);
128 13348 rhs := ComponentRef.evaluateSubscripts(rhs);
129 13348 conns.connections := makeConnections(lhs, ty1, rhs, ty2, source, isDeleted, conns.connections);
130 then
131 eql;
132
133 else eq :: eql;
134 end match;
135 end for;
136
137
1/2
✓ Branch 1 taken 1573 times.
✗ Branch 2 not taken.
1573 flatModel.equations := listReverseInPlace(eql);
138 end collectConnections;
139
140 function collectFlows
141 input FlatModel flatModel;
142 input output Connections conns;
143 protected
144 Component comp;
145 Connector c;
146 DAE.ElementSource src;
147 algorithm
148 // Collect all flow variables.
149
2/2
✓ Branch 0 taken 240576 times.
✓ Branch 1 taken 1573 times.
242149 for var in flatModel.variables loop
150 240576 comp := InstNode.component(ComponentRef.node(var.name));
151
152
2/2
✓ Branch 1 taken 19032 times.
✓ Branch 2 taken 221544 times.
240576 if Component.isFlow(comp) then
153 // Add all flow variables as inside connectors, to generate default
154 // equations if they're not connected.
155 19032 src := ElementSource.createElementSource(Component.info(comp));
156 19032 c := Connector.fromFacedCref(var.name, var.ty, NFConnector.Face.INSIDE, src);
157 19032 conns := addFlow(c, conns);
158
159 // Also add outside connectors for flow variables that were added during
160 // augmentation of expandable connectors.
161
2/2
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 19022 times.
19032 if ConnectorType.isAugmented(var.attributes.connectorType) then
162 10 c := Connector.fromFacedCref(var.name, var.ty, NFConnector.Face.OUTSIDE, src);
163 10 conns := addFlow(c, conns);
164 end if;
165 end if;
166 end for;
167 end collectFlows;
168
169 function makeConnections
170 input ComponentRef lhsCref;
171 input Type lhsType;
172 input ComponentRef rhsCref;
173 input Type rhsType;
174 input DAE.ElementSource source;
175 input IsDeleted isDeleted;
176 input output list<Connection> connections = {};
177
178 partial function IsDeleted
179 input ComponentRef cref;
180 output Boolean res;
181 end IsDeleted;
182 protected
183 list<Connector> cl1, cl2;
184 Connector c2;
185 algorithm
186
6/12
✓ Branch 0 taken 13348 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 12610 times.
✓ Branch 4 taken 738 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 12610 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 374 times.
✓ Branch 12 taken 12236 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
13348 if isDeleted(lhsCref) or isDeleted(rhsCref) then
187 1112 return;
188 end if;
189
190
4/4
✓ Branch 2 taken 12230 times.
✓ Branch 3 taken 6 times.
✓ Branch 6 taken 54 times.
✓ Branch 7 taken 12176 times.
12236 if InstNode.isName(ComponentRef.node(lhsCref)) or InstNode.isName(ComponentRef.node(rhsCref)) then
191 // Keep the connectors unexpanded if either connector refers to a not
192 // declared component in an expandable connector, since we can't expand
193 // such connectors here.
194 60 cl1 := {Connector.fromCref(lhsCref, lhsType, source)};
195 120 cl2 := {Connector.fromCref(rhsCref, rhsType, source)};
196 else
197 12176 cl1 := makeConnectors(lhsCref, lhsType, source);
198 12176 cl2 := makeConnectors(rhsCref, rhsType, source);
199 end if;
200
201
2/2
✓ Branch 0 taken 13948 times.
✓ Branch 1 taken 12236 times.
26184 for c1 in cl1 loop
202
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13948 times.
13948 c2 :: cl2 := cl2;
203
204
4/8
✓ Branch 0 taken 13948 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 13948 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 13948 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 13948 times.
✗ Branch 11 not taken.
13948 if not (isDeleted(c1.name) or isDeleted(c2.name)) then
205 13948 connections := Connection.CONNECTION(c1, c2) :: connections;
206 end if;
207 end for;
208 end makeConnections;
209
210 function makeConnectors
211 input ComponentRef cref;
212 input Type ty;
213 input DAE.ElementSource source;
214 output list<Connector> connectors;
215 protected
216 Expression cref_exp;
217 Boolean expanded;
218 algorithm
219
2/2
✓ Branch 1 taken 1224 times.
✓ Branch 2 taken 23128 times.
24352 if not Flags.isSet(Flags.NF_SCALARIZE) then
220 1224 connectors := {Connector.fromCref(cref, ComponentRef.getSubscriptedType(cref), source)};
221 1224 return;
222 end if;
223
224 23128 cref_exp := Expression.CREF(ComponentRef.getSubscriptedType(cref), cref);
225 23128 (cref_exp, expanded) := ExpandExp.expand(cref_exp);
226
227
1/2
✓ Branch 0 taken 23128 times.
✗ Branch 1 not taken.
23128 if expanded then
228 23128 connectors := Connector.fromExp(cref_exp, source);
229 else
230 // Connectors should only have structural parameter subscripts, so it
231 // should always be possible to expand them.
232 ✗ Error.terminate(getInstanceName() + " failed to expand connector `" +
233 ComponentRef.toString(cref) + "\n", ElementSource.getInfo(source));
234 end if;
235 end makeConnectors;
236
237 function split
238 input output Connections conns;
239 algorithm
240 1571 conns.flows := List.mapFlat(conns.flows, Connector.split);
241 conns.connections := List.mapFlat(conns.connections, Connection.split);
242 end split;
243
244 function connectCount
245 input Connector conn;
246 input UnorderedMap<Connector, Integer> connectCounts;
247 output Integer count;
248 algorithm
249 1793 count := UnorderedMap.getOrDefault(conn, connectCounts, 0);
250 end connectCount;
251
252 function scalarize
253 input output Connections conns;
254 input Boolean keepSingleConnectedArrays;
255 protected
256 UnorderedMap<Connector, Integer> connect_counts;
257 list<Connector> flows = {};
258 list<Connection> connections = {};
259 Integer count;
260 algorithm
261
2/2
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 1367 times.
1571 if keepSingleConnectedArrays then
262 204 connect_counts := analyseArrayConnections(conns);
263
264
2/2
✓ Branch 0 taken 649 times.
✓ Branch 1 taken 204 times.
853 for f in conns.flows loop
265 649 count := connectCount(f, connect_counts);
266
267
2/2
✓ Branch 0 taken 576 times.
✓ Branch 1 taken 73 times.
649 if count == 0 then
268 flows := f :: flows;
269 elseif count > 1 or count == -1 then
270 17 flows := listAppend(Connector.scalarize(f), flows);
271 end if;
272 end for;
273
274
2/2
✓ Branch 0 taken 1112 times.
✓ Branch 1 taken 204 times.
1316 for c in conns.connections loop
275
6/6
✓ Branch 1 taken 1058 times.
✓ Branch 2 taken 54 times.
✓ Branch 4 taken 86 times.
✓ Branch 5 taken 972 times.
✓ Branch 7 taken 76 times.
✓ Branch 8 taken 10 times.
1112 if not ConnectorType.isStream(c.lhs.cty) and
276 connectCount(c.lhs, connect_counts) == 1 and connectCount(c.rhs, connect_counts) == 1 then
277 76 connections := c :: connections;
278 else
279 1036 connections := listAppend(Connection.scalarize(c), connections);
280 end if;
281 end for;
282
283 204 conns.flows := listReverseInPlace(flows);
284 conns.connections := listReverseInPlace(connections);
285 else
286 1367 conns.flows := List.mapFlat(conns.flows, Connector.scalarize);
287 conns.connections := List.mapFlat(conns.connections, Connection.scalarize);
288 end if;
289 end scalarize;
290
291 function analyseArrayConnections
292 input Connections conns;
293 output UnorderedMap<Connector, Integer> connectCounts;
294 algorithm
295 204 connectCounts := UnorderedMap.new<Integer>(Connector.hashNoSubs, Connector.isEqualNoSubs,
296 listLength(conns.connections));
297
298
2/2
✓ Branch 0 taken 1112 times.
✓ Branch 1 taken 204 times.
1316 for conn in conns.connections loop
299 1112 analyseArrayConnector(conn.lhs, connectCounts);
300 1112 analyseArrayConnector(conn.rhs, connectCounts);
301 end for;
302 end analyseArrayConnections;
303
304 function analyseArrayConnector
305 input Connector conn;
306 input UnorderedMap<Connector, Integer> connectCounts;
307 protected
308 function update
309 input Option<Integer> count;
310 output Integer outCount;
311 algorithm
312 outCount := match count
313
1/2
✓ Branch 0 taken 87 times.
✗ Branch 1 not taken.
87 case SOME(outCount) then if outCount >= 0 then outCount + 1 else -1;
314 else 1;
315 end match;
316 end update;
317 algorithm
318
2/2
✓ Branch 1 taken 360 times.
✓ Branch 2 taken 1864 times.
2224 if Connector.isArray(conn) then
319 360 UnorderedMap.addUpdate(conn, update, connectCounts);
320 elseif ComponentRef.hasSubscripts(conn.name) then
321 // Always scalarize connector arrays that are partially connected.
322 119 UnorderedMap.add(conn, -1, connectCounts);
323 end if;
324 end analyseArrayConnector;
325
326 function toString
327 input Connections conns;
328 output String str;
329 protected
330 list<String> strl = {};
331 algorithm
332 strl := "FLOWS:" :: strl;
333 ✗ for f in conns.flows loop
334 ✗ strl := Connector.toString(f) :: strl;
335 end for;
336
337 strl := "\nCONNECTIONS:" :: strl;
338 ✗ for c in conns.connections loop
339 ✗ strl := Connection.toString(c) :: strl;
340 end for;
341
342 ✗ strl := listReverseInPlace(strl);
343 ✗ str := stringDelimitList(strl, "\n");
344 end toString;
345
346 function toStringList
347 input Connections conns;
348 output list<list<String>> strl = {};
349 algorithm
350
4/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 2 times.
20 strl := list({Connector.toString(c.lhs), Connector.toString(c.rhs)} for c in conns.connections);
351 end toStringList;
352
353 annotation(__OpenModelica_Interface="nf_frontend");
354 end NFConnections;
355