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 |