OMCompiler/Compiler/NSimCode/NSimStrongComponent.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 NSimStrongComponent | ||
| 37 | "file: NSimStrongComponent.mo | ||
| 38 | package: NSimStrongComponent | ||
| 39 | description: This file contains the data types and functions for strong | ||
| 40 | components in simulation code phase. | ||
| 41 | " | ||
| 42 | |||
| 43 | protected | ||
| 44 | // OF imports | ||
| 45 | import AbsynUtil; | ||
| 46 | import BackendExtension = NFBackendExtension; | ||
| 47 | import DAE; | ||
| 48 | |||
| 49 | // NF imports | ||
| 50 | import ComponentRef = NFComponentRef; | ||
| 51 | import ConvertDAE = NFConvertDAE; | ||
| 52 | import Expression = NFExpression; | ||
| 53 | import NFFunction.Function; | ||
| 54 | import Binding = NFBinding; | ||
| 55 | import InstNode = NFInstNode.InstNode; | ||
| 56 | import Operator = NFOperator; | ||
| 57 | import Scalarize = NFScalarize; | ||
| 58 | import Statement = NFStatement; | ||
| 59 | import Subscript = NFSubscript; | ||
| 60 | import Type = NFType; | ||
| 61 | import Dimension = NFDimension; | ||
| 62 | import Variable = NFVariable; | ||
| 63 | |||
| 64 | // old backend imports | ||
| 65 | import OldBackendDAE = BackendDAE; | ||
| 66 | |||
| 67 | // Backend imports | ||
| 68 | import AliasInfo = NBStrongComponent.AliasInfo; | ||
| 69 | import BackendDAE = NBackendDAE; | ||
| 70 | import BEquation = NBEquation; | ||
| 71 | import NBEquation.{Equation, EquationAttributes, EquationKind, EquationPointer, EquationPointers, WhenEquationBody, WhenStatement, IfEquationBody, Iterator, SlicingStatus}; | ||
| 72 | import Solve = NBSolve; | ||
| 73 | import StrongComponent = NBStrongComponent; | ||
| 74 | import Partition = NBPartition; | ||
| 75 | import Partitioning = NBPartitioning; | ||
| 76 | import Resizable = NBResizable; | ||
| 77 | import NBPartitioning.{BClock, ClockedInfo}; | ||
| 78 | import Tearing = NBTearing; | ||
| 79 | import BVariable = NBVariable; | ||
| 80 | import NBVariable.VariablePointers; | ||
| 81 | |||
| 82 | // Old SimCode imports | ||
| 83 | import OldSimCode = SimCode; | ||
| 84 | |||
| 85 | // SimCode imports | ||
| 86 | import SimCode = NSimCode; | ||
| 87 | import NSimCode.{Identifier, SimCodeIndices}; | ||
| 88 | import NSimGenericCall; | ||
| 89 | import NSimGenericCall.SimIterator; | ||
| 90 | import NSimJacobian.SimJacobian; | ||
| 91 | import SimPartition = NSimPartition; | ||
| 92 | import NSimVar.{SimVar, SimVars, VarType}; | ||
| 93 | |||
| 94 | // Util imports | ||
| 95 | import Error; | ||
| 96 | import Slice = NBSlice; | ||
| 97 | import StringUtil; | ||
| 98 | |||
| 99 | public | ||
| 100 | uniontype Block | ||
| 101 | "A single blck from BLT transformation." | ||
| 102 | |||
| 103 | record RESIDUAL | ||
| 104 | "Single residual equation of the form | ||
| 105 | 0 = exp" | ||
| 106 | Integer index; | ||
| 107 | Integer res_index; | ||
| 108 | Expression exp; | ||
| 109 | DAE.ElementSource source; | ||
| 110 | EquationAttributes attr; | ||
| 111 | end RESIDUAL; | ||
| 112 | |||
| 113 | record ARRAY_RESIDUAL | ||
| 114 | "Single residual array equation of the form | ||
| 115 | 0 = exp. Structurally equal to RESIDUAL, but the destinction is important | ||
| 116 | for code generation." | ||
| 117 | Integer index; | ||
| 118 | Integer res_index; | ||
| 119 | Expression exp; | ||
| 120 | DAE.ElementSource source; | ||
| 121 | EquationAttributes attr; | ||
| 122 | end ARRAY_RESIDUAL; | ||
| 123 | |||
| 124 | record FOR_RESIDUAL | ||
| 125 | "for-loop residual equation of the form | ||
| 126 | for {i in 1:n, j in 1:m, ...} loop | ||
| 127 | 0 = exp; | ||
| 128 | end for;" | ||
| 129 | Integer index; | ||
| 130 | Integer res_index; | ||
| 131 | list<SimIterator> iterators; | ||
| 132 | Expression exp; | ||
| 133 | DAE.ElementSource source; | ||
| 134 | EquationAttributes attr; | ||
| 135 | end FOR_RESIDUAL; | ||
| 136 | |||
| 137 | record GENERIC_RESIDUAL | ||
| 138 | "a generic residual calling a for loop body function with an index list." | ||
| 139 | Integer index; | ||
| 140 | Integer res_index; | ||
| 141 | list<Integer> scal_indices; | ||
| 142 | list<SimIterator> iterators; | ||
| 143 | Expression exp; | ||
| 144 | DAE.ElementSource source; | ||
| 145 | EquationAttributes attr; | ||
| 146 | end GENERIC_RESIDUAL; | ||
| 147 | |||
| 148 | record SIMPLE_ASSIGN | ||
| 149 | "Simple assignment or solved inner equation of (casual) tearing set | ||
| 150 | (Dynamic Tearing) with constraints on the solvability | ||
| 151 | lhs := rhs" | ||
| 152 | Integer index; | ||
| 153 | ComponentRef lhs "left hand side of equation"; | ||
| 154 | Expression rhs; | ||
| 155 | DAE.ElementSource source; | ||
| 156 | // ToDo: this needs to be added for tearing later on | ||
| 157 | //Option<BackendDAE.Constraints> constraints; | ||
| 158 | EquationAttributes attr; | ||
| 159 | end SIMPLE_ASSIGN; | ||
| 160 | |||
| 161 | record ARRAY_ASSIGN | ||
| 162 | "Array assignment where the left hand side can be an array constructor. | ||
| 163 | {a, b, ...} := rhs" | ||
| 164 | Integer index; | ||
| 165 | Expression lhs; | ||
| 166 | Expression rhs; | ||
| 167 | DAE.ElementSource source; | ||
| 168 | EquationAttributes attr; | ||
| 169 | end ARRAY_ASSIGN; | ||
| 170 | |||
| 171 | record RESIZABLE_ASSIGN | ||
| 172 | "a resizable assignment calling a for loop body function." | ||
| 173 | Integer index; | ||
| 174 | Integer call_index; | ||
| 175 | list<SimIterator> iters; | ||
| 176 | DAE.ElementSource source; | ||
| 177 | EquationAttributes attr; | ||
| 178 | end RESIZABLE_ASSIGN; | ||
| 179 | |||
| 180 | record GENERIC_ASSIGN | ||
| 181 | "a generic assignment calling a for loop body function with an index list." | ||
| 182 | Integer index; | ||
| 183 | Integer call_index; | ||
| 184 | list<Integer> scal_indices; | ||
| 185 | DAE.ElementSource source; | ||
| 186 | EquationAttributes attr; | ||
| 187 | end GENERIC_ASSIGN; | ||
| 188 | |||
| 189 | record ENTWINED_ASSIGN | ||
| 190 | "entwined generic assignments calling for loop body functions with an index list and a call order." | ||
| 191 | Integer index; | ||
| 192 | list<Integer> call_order; | ||
| 193 | list<Block> single_calls; | ||
| 194 | DAE.ElementSource source; | ||
| 195 | EquationAttributes attr; | ||
| 196 | end ENTWINED_ASSIGN; | ||
| 197 | |||
| 198 | record ALIAS | ||
| 199 | "Simple alias assignment pointing to the alias equation. | ||
| 200 | - alias of will be -1 at the point of creation and computed afterwards" | ||
| 201 | Integer index; | ||
| 202 | AliasInfo aliasInfo "backend alias info"; | ||
| 203 | Integer aliasOf "final alias index"; | ||
| 204 | Boolean isDiscrete; | ||
| 205 | end ALIAS; | ||
| 206 | |||
| 207 | record ALGORITHM | ||
| 208 | "An algorithm section." | ||
| 209 | // ToDo: do we need to keep inputs/outputs here? | ||
| 210 | Integer index; | ||
| 211 | list<Statement> stmts; | ||
| 212 | EquationAttributes attr; | ||
| 213 | end ALGORITHM; | ||
| 214 | |||
| 215 | record INVERSE_ALGORITHM | ||
| 216 | "An algorithm section that had to be inverted." | ||
| 217 | Integer index; | ||
| 218 | list<Statement> stmts; | ||
| 219 | list<ComponentRef> knownOutputs "this is a subset of output crefs of the original algorithm, which are already known"; | ||
| 220 | Boolean insideNonLinearSystem; | ||
| 221 | EquationAttributes attr; | ||
| 222 | end INVERSE_ALGORITHM; | ||
| 223 | |||
| 224 | record IF | ||
| 225 | "An if section." | ||
| 226 | Integer index; | ||
| 227 | list<tuple<Expression, list<Block>>> branches; | ||
| 228 | DAE.ElementSource source; | ||
| 229 | EquationAttributes attr; | ||
| 230 | end IF; | ||
| 231 | |||
| 232 | record WHEN | ||
| 233 | "A when section." | ||
| 234 | Integer index; | ||
| 235 | Boolean initialCall "true, if top-level branch with initial()"; | ||
| 236 | list<ComponentRef> conditions; | ||
| 237 | list<WhenStatement> when_stmts; | ||
| 238 | Option<Block> else_when; | ||
| 239 | DAE.ElementSource source; | ||
| 240 | EquationAttributes attr; | ||
| 241 | end WHEN; | ||
| 242 | |||
| 243 | record LINEAR | ||
| 244 | "Linear algebraic loop." | ||
| 245 | LinearSystem system; | ||
| 246 | Option<LinearSystem> alternativeTearing; | ||
| 247 | end LINEAR; | ||
| 248 | |||
| 249 | record NONLINEAR | ||
| 250 | "Nonlinear algebraic loop." | ||
| 251 | NonlinearSystem system; | ||
| 252 | Option<NonlinearSystem> alternativeTearing; | ||
| 253 | end NONLINEAR; | ||
| 254 | |||
| 255 | record HYBRID | ||
| 256 | "Hybrid system containing both continuous and discrete equations." | ||
| 257 | Integer index; | ||
| 258 | Block continuous; | ||
| 259 | list<SimVar> discreteVars; | ||
| 260 | list<Block> discreteEqs; | ||
| 261 | Integer indexHybridSystem; | ||
| 262 | end HYBRID; | ||
| 263 | |||
| 264 | function toString | ||
| 265 | // ToDo: Update alias string to print actual name. Update structure? | ||
| 266 | input Block blck; | ||
| 267 | input output String str = ""; | ||
| 268 | algorithm | ||
| 269 | str := match blck | ||
| 270 | 71 | case RESIDUAL() then str + "(" + intString(blck.index) + ") 0 = " + Expression.toString(blck.exp) + "\n"; | |
| 271 | ✗ | case ARRAY_RESIDUAL() then str + "(" + intString(blck.index) + ") 0 = " + Expression.toString(blck.exp) + "\n"; | |
| 272 | ✗ | case FOR_RESIDUAL() then str + "(" + intString(blck.index) + ") For-Loop-Residual:\n" + str + "for " + List.toString(blck.iterators, forTplStr) + " loop\n" + str + " 0 = " + Expression.toString(blck.exp) + ";\n" + str + "end for;\n"; | |
| 273 | ✗ | case GENERIC_RESIDUAL() then str + "(" + intString(blck.index) + ") Generic For-Loop-Residual:\n" + str + List.toStringCustom(blck.scal_indices, intString, "slice", "{", ", ", "}", true, 10) + "\n" + str + "for " + List.toString(blck.iterators, forTplStr) + " loop\n" + str + " 0 = " + Expression.toString(blck.exp) + ";\n" + str + "end for;\n"; | |
| 274 | 114 | case SIMPLE_ASSIGN() then str + "(" + intString(blck.index) + ") " + ComponentRef.toString(blck.lhs) + " := " + Expression.toString(blck.rhs) + "\n"; | |
| 275 | 2 | case ARRAY_ASSIGN() then str + "(" + intString(blck.index) + ") " + Expression.toString(blck.lhs) + " := " + Expression.toString(blck.rhs) + "\n"; | |
| 276 | 6 | case RESIZABLE_ASSIGN() then str + "(" + intString(blck.index) + ") " + "resizable call [index " + intString(blck.call_index) + "]\n"; | |
| 277 | ✗ | case GENERIC_ASSIGN() then str + "(" + intString(blck.index) + ") " + "single generic call [index " + intString(blck.call_index) + "] " + List.toStringCustom(inList = blck.scal_indices, inPrintFunc = intString, maxLength = 10) + "\n"; | |
| 278 | ✗ | case ENTWINED_ASSIGN() then str + List.toStringCustom(blck.single_calls, function toString(str=""), "### entwined call (" + intString(blck.index) + ") ###", "\n ", " ", ""); | |
| 279 | 21 | case ALIAS() then str + "(" + intString(blck.index) + ") Alias of " + intString(blck.aliasOf) + "\n"; | |
| 280 | 10 | case ALGORITHM() then str + "(" + intString(blck.index) + ") Algorithm\n" + Statement.toStringList(blck.stmts, str); | |
| 281 | ✗ | case INVERSE_ALGORITHM() then str + "(" + intString(blck.index) + ") Inverse Algorithm\n" + Statement.toStringList(blck.stmts, str) + "\n"; | |
| 282 | ✗ | case IF() then str + "(" + intString(blck.index) + ") " + List.toStringCustom(blck.branches, function ifTplStr(str = str), "", str, str + "else ", str + "end if;\n"); | |
| 283 | ✗ | case WHEN() then str + "(" + intString(blck.index) + ") " + whenString(blck.conditions, blck.when_stmts, blck.else_when, str); | |
| 284 | 2 | case LINEAR() then str + "(" + intString(blck.system.index) + ") " + LinearSystem.toString(blck.system, str); | |
| 285 | 11 | case NONLINEAR() then str + "(" + intString(blck.system.index) + ") " + NonlinearSystem.toString(blck.system, str); | |
| 286 | ✗ | case HYBRID() then str + "(" + intString(blck.index) + ") Hybrid\n"; // ToDo! | |
| 287 | else getInstanceName() + " failed.\n"; | ||
| 288 | end match; | ||
| 289 | end toString; | ||
| 290 | |||
| 291 | function forTplStr | ||
| 292 | input SimIterator iter; | ||
| 293 | output String str = SimIterator.toString(iter); | ||
| 294 | end forTplStr; | ||
| 295 | |||
| 296 | function ifTplStr | ||
| 297 | input tuple<Expression, list<Block>> tpl; | ||
| 298 | input output String str; | ||
| 299 | protected | ||
| 300 | Expression condition; | ||
| 301 | list<Block> blcks; | ||
| 302 | algorithm | ||
| 303 | ✗ | (condition, blcks) := tpl; | |
| 304 | ✗ | str := "if " + Expression.toString(condition) + " then\n " | |
| 305 | + List.toString(blcks, function toString(str = str + " "), List.Style.NEWLINE); | ||
| 306 | end ifTplStr; | ||
| 307 | |||
| 308 | function getIndex | ||
| 309 | input Block blck; | ||
| 310 | output Integer index; | ||
| 311 | algorithm | ||
| 312 | index := match blck | ||
| 313 | ✗ | case RESIDUAL() then blck.index; | |
| 314 | ✗ | case ARRAY_RESIDUAL() then blck.index; | |
| 315 | ✗ | case FOR_RESIDUAL() then blck.index; | |
| 316 | 4861 | case SIMPLE_ASSIGN() then blck.index; | |
| 317 | 524 | case ARRAY_ASSIGN() then blck.index; | |
| 318 | 390 | case RESIZABLE_ASSIGN() then blck.index; | |
| 319 | 26 | case GENERIC_ASSIGN() then blck.index; | |
| 320 | 2 | case ENTWINED_ASSIGN() then blck.index; | |
| 321 | 2689 | case ALIAS() then blck.index; | |
| 322 | 175 | case ALGORITHM() then blck.index; | |
| 323 | ✗ | case INVERSE_ALGORITHM() then blck.index; | |
| 324 | ✗ | case IF() then blck.index; | |
| 325 | 118 | case WHEN() then blck.index; | |
| 326 | ✗ | case LINEAR() then blck.system.index; | |
| 327 | ✗ | case NONLINEAR() then blck.system.index; | |
| 328 | ✗ | case HYBRID() then blck.index; | |
| 329 | else algorithm | ||
| 330 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for\n" + toString(blck)}); | |
| 331 | ✗ | then fail(); | |
| 332 | end match; | ||
| 333 | end getIndex; | ||
| 334 | |||
| 335 | function isDiscrete | ||
| 336 | input Block blck; | ||
| 337 | output Boolean b; | ||
| 338 | algorithm | ||
| 339 | b := match blck | ||
| 340 | local | ||
| 341 | EquationAttributes attr; | ||
| 342 | ✗ | case RESIDUAL(attr = attr) then attr.kind == EquationKind.DISCRETE; | |
| 343 | ✗ | case ARRAY_RESIDUAL(attr = attr) then attr.kind == EquationKind.DISCRETE; | |
| 344 | ✗ | case FOR_RESIDUAL(attr = attr) then attr.kind == EquationKind.DISCRETE; | |
| 345 | 19 | case SIMPLE_ASSIGN(attr = attr) then attr.kind == EquationKind.DISCRETE; | |
| 346 | ✗ | case ARRAY_ASSIGN(attr = attr) then attr.kind == EquationKind.DISCRETE; | |
| 347 | 1 | case RESIZABLE_ASSIGN(attr = attr) then attr.kind == EquationKind.DISCRETE; | |
| 348 | ✗ | case GENERIC_ASSIGN(attr = attr) then attr.kind == EquationKind.DISCRETE; | |
| 349 | ✗ | case ENTWINED_ASSIGN(attr = attr) then attr.kind == EquationKind.DISCRETE; | |
| 350 | 1159 | case ALIAS() then blck.isDiscrete; | |
| 351 | 2 | case ALGORITHM(attr = attr) then attr.kind == EquationKind.DISCRETE; | |
| 352 | ✗ | case INVERSE_ALGORITHM(attr = attr) then attr.kind == EquationKind.DISCRETE; | |
| 353 | ✗ | case IF(attr = attr) then attr.kind == EquationKind.DISCRETE; | |
| 354 | ✗ | case WHEN(attr = attr) then attr.kind == EquationKind.DISCRETE; // should hopefully always be true | |
| 355 | else false; | ||
| 356 | end match; | ||
| 357 | end isDiscrete; | ||
| 358 | |||
| 359 | function filterWhen | ||
| 360 | input list<Block> blcks; | ||
| 361 | input output list<Block> out_blcks; | ||
| 362 | input output list<Block> new_blcks; | ||
| 363 | input output SimCodeIndices indices; | ||
| 364 | protected | ||
| 365 | Block blck, new_blck; | ||
| 366 | list<Block> rest; | ||
| 367 | list<Statement> stmts; | ||
| 368 | algorithm | ||
| 369 | (out_blcks, new_blcks, indices) := match blcks | ||
| 370 | 58 | case WHEN() :: rest then filterWhen(rest, out_blcks, new_blcks, indices); | |
| 371 | case (blck as ALGORITHM()) :: rest algorithm | ||
| 372 | 6 | stmts := Statement.filterDiscrete(blck.stmts); | |
| 373 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
|
6 | if listEmpty(stmts) then |
| 374 | // filtered everything out, skip entire block | ||
| 375 | 4 | (out_blcks, new_blcks, indices) := filterWhen(rest, out_blcks, new_blcks, indices); | |
| 376 | elseif List.compareLength(stmts, blck.stmts) <> 0 then | ||
| 377 | // filtered part of it out, create new block | ||
| 378 | 2 | new_blck := ALGORITHM(indices.equationIndex, stmts, blck.attr); | |
| 379 | 2 | indices.equationIndex := indices.equationIndex + 1; | |
| 380 | 2 | (out_blcks, new_blcks, indices) := filterWhen(rest, new_blck :: out_blcks, new_blck :: new_blcks, indices); | |
| 381 | //UnorderedMap.add(Equation.getEqnName(Pointer.create(eqn)), blck, equation_map); | ||
| 382 | else | ||
| 383 | // filtered nothing out, keep block as it is | ||
| 384 | ✗ | (out_blcks, new_blcks, indices) := filterWhen(rest, blck :: out_blcks, new_blcks, indices); | |
| 385 | end if; | ||
| 386 | 6 | then (out_blcks, new_blcks, indices); | |
| 387 | 1184 | case blck :: rest then filterWhen(rest, blck :: out_blcks, new_blcks, indices); | |
| 388 | else (out_blcks, new_blcks, indices); | ||
| 389 | end match; | ||
| 390 | end filterWhen; | ||
| 391 | |||
| 392 | function map | ||
| 393 | "ToDo: other blocks and cref func" | ||
| 394 | input output Block blck; | ||
| 395 | input expFunc func; | ||
| 396 | partial function expFunc | ||
| 397 | input output Expression exp; | ||
| 398 | end expFunc; | ||
| 399 | algorithm | ||
| 400 | blck := match blck | ||
| 401 | case RESIDUAL() algorithm | ||
| 402 | ✗ | blck.exp := Expression.map(blck.exp, func); | |
| 403 | then blck; | ||
| 404 | |||
| 405 | case SIMPLE_ASSIGN() algorithm | ||
| 406 | ✗ | blck.rhs := Expression.map(blck.rhs, func); | |
| 407 | then blck; | ||
| 408 | |||
| 409 | else blck; | ||
| 410 | end match; | ||
| 411 | end map; | ||
| 412 | |||
| 413 | function listToString | ||
| 414 | input list<Block> blcks; | ||
| 415 | input output String str = ""; | ||
| 416 | input String header = ""; | ||
| 417 | protected | ||
| 418 | String indent = str; | ||
| 419 | algorithm | ||
| 420 |
3/4✓ Branch 0 taken 13 times.
✓ Branch 1 taken 21 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
|
34 | str := if header <> "" then StringUtil.headline_3(header) else ""; |
| 421 |
2/2✓ Branch 0 taken 148 times.
✓ Branch 1 taken 34 times.
|
182 | for blck in blcks loop |
| 422 | 148 | str := str + Block.toString(blck, indent); | |
| 423 | end for; | ||
| 424 | end listToString; | ||
| 425 | |||
| 426 | function createBlocks | ||
| 427 | input list<Partition.Partition> partitions; | ||
| 428 | output list<list<Block>> blcks = {}; | ||
| 429 | input output list<Block> all_blcks; | ||
| 430 | input output SimCodeIndices simCodeIndices; | ||
| 431 | input UnorderedMap<ComponentRef, SimVar> simcode_map; | ||
| 432 | input UnorderedMap<ComponentRef, Block> equation_map; | ||
| 433 | protected | ||
| 434 | list<Block> tmp; | ||
| 435 | algorithm | ||
| 436 |
2/2✓ Branch 0 taken 233 times.
✓ Branch 1 taken 374 times.
|
607 | for partition in partitions loop |
| 437 | 233 | (tmp, simCodeIndices) := fromPartition(partition, simCodeIndices, simcode_map, equation_map); | |
| 438 | blcks := tmp :: blcks; | ||
| 439 | 233 | all_blcks := listAppend(tmp, all_blcks); | |
| 440 | end for; | ||
| 441 | 374 | blcks := listReverse(blcks); | |
| 442 | end createBlocks; | ||
| 443 | |||
| 444 | function createDiscreteBlocks | ||
| 445 | input list<Partition.Partition> partitions; | ||
| 446 | input output list<list<Block>> blcks; | ||
| 447 | input output list<Block> all_blcks; | ||
| 448 | input output list<Block> event_dependencies; | ||
| 449 | input output SimCodeIndices simCodeIndices; | ||
| 450 | input UnorderedMap<ComponentRef, SimVar> simcode_map; | ||
| 451 | input UnorderedMap<ComponentRef, Block> equation_map; | ||
| 452 | protected | ||
| 453 | list<Block> tmp, new_blcks; | ||
| 454 | algorithm | ||
| 455 |
2/2✓ Branch 0 taken 75 times.
✓ Branch 1 taken 374 times.
|
449 | for partition in partitions loop |
| 456 | 75 | (tmp, simCodeIndices) := fromPartition(partition, simCodeIndices, simcode_map, equation_map); | |
| 457 | // add all | ||
| 458 | 75 | all_blcks := listAppend(tmp, all_blcks); | |
| 459 | // filter all when equations and add to blcks (ode or algebraic) | ||
| 460 | 75 | (tmp, new_blcks, simCodeIndices) := filterWhen(listReverse(tmp), {}, {}, simCodeIndices); | |
| 461 | 75 | all_blcks := listAppend(new_blcks, all_blcks); | |
| 462 | blcks := tmp :: blcks; | ||
| 463 | // filter all other discrete equations and add to event_dependencies | ||
| 464 |
6/6✓ Branch 1 taken 269 times.
✓ Branch 2 taken 917 times.
✓ Branch 3 taken 1186 times.
✓ Branch 4 taken 75 times.
✓ Branch 5 taken 917 times.
✓ Branch 6 taken 75 times.
|
1261 | tmp := list(blck for blck guard(not isDiscrete(blck)) in tmp); |
| 465 | 75 | event_dependencies := listAppend(tmp, event_dependencies); | |
| 466 | end for; | ||
| 467 | 374 | blcks := listReverse(blcks); | |
| 468 | end createDiscreteBlocks; | ||
| 469 | |||
| 470 | function createInitialBlocks | ||
| 471 | input list<Partition.Partition> partitions; | ||
| 472 | output list<Block> blcks; | ||
| 473 | input output SimCodeIndices simCodeIndices; | ||
| 474 | input UnorderedMap<ComponentRef, SimVar> simcode_map; | ||
| 475 | input UnorderedMap<ComponentRef, Block> equation_map; | ||
| 476 | protected | ||
| 477 | list<Block> tmp; | ||
| 478 | list<list<Block>> tmp_lst = {}; | ||
| 479 | algorithm | ||
| 480 |
2/2✓ Branch 0 taken 180 times.
✓ Branch 1 taken 194 times.
|
374 | for partition in partitions loop |
| 481 | 180 | (tmp, simCodeIndices) := fromPartition(partition, simCodeIndices, simcode_map, equation_map); | |
| 482 | tmp_lst := tmp :: tmp_lst; | ||
| 483 | end for; | ||
| 484 | 194 | blcks := List.flatten(tmp_lst); | |
| 485 | end createInitialBlocks; | ||
| 486 | |||
| 487 | function createParameterBlocks | ||
| 488 | "creates the blocks of the explicitly solved primary parameter bindings, in evaluation order" | ||
| 489 | input list<StrongComponent> comps; | ||
| 490 | output list<Block> blcks = {}; | ||
| 491 | input output SimCodeIndices simCodeIndices; | ||
| 492 | input UnorderedMap<ComponentRef, SimVar> simcode_map; | ||
| 493 | input UnorderedMap<ComponentRef, Block> equation_map; | ||
| 494 | protected | ||
| 495 | Block tmp; | ||
| 496 | Integer index; | ||
| 497 | algorithm | ||
| 498 |
2/2✓ Branch 0 taken 1112 times.
✓ Branch 1 taken 188 times.
|
1300 | for comp in comps loop |
| 499 | 1112 | (tmp, simCodeIndices, index) := fromStrongComponent(comp, simCodeIndices, NBPartition.Kind.INI, simcode_map, equation_map); | |
| 500 | blcks := tmp :: blcks; | ||
| 501 | end for; | ||
| 502 | 188 | blcks := listReverse(blcks); | |
| 503 | end createParameterBlocks; | ||
| 504 | |||
| 505 | function createAttributeBlocks | ||
| 506 | "Creates the assignments of min, max and nominal attributes that are not | ||
| 507 | literals and therefore not part of the init XML, e.g. `Real x(min = p)`. | ||
| 508 | The attributes are evaluated in updateBoundVariableAttributes. Only | ||
| 509 | creates blocks for variables that are SimVars themselves, i.e. array | ||
| 510 | variables if they are not scalarized. | ||
| 511 | The indices are consecutive per attribute in the order of the info file: | ||
| 512 | nominal, min, max." | ||
| 513 | input list<VariablePointers> vars; | ||
| 514 | output list<Block> min_blcks = {}; | ||
| 515 | output list<Block> max_blcks = {}; | ||
| 516 | output list<Block> nominal_blcks = {}; | ||
| 517 | input output SimCodeIndices simCodeIndices; | ||
| 518 | input UnorderedMap<ComponentRef, SimVar> simcode_map; | ||
| 519 | input list<StrongComponent> params "primary parameters, solved before the attributes"; | ||
| 520 | protected | ||
| 521 | list<Variable> sim_vars = {}; | ||
| 522 | Variable var; | ||
| 523 | UnorderedSet<ComponentRef> bound = UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual); | ||
| 524 | algorithm | ||
| 525 |
2/2✓ Branch 0 taken 1112 times.
✓ Branch 1 taken 188 times.
|
1300 | for comp in params loop |
| 526 |
2/2✓ Branch 1 taken 1112 times.
✓ Branch 2 taken 1112 times.
|
2224 | for v in StrongComponent.getVariables(comp) loop |
| 527 | 1112 | UnorderedSet.add(BVariable.getVarName(v), bound); | |
| 528 | end for; | ||
| 529 | end for; | ||
| 530 |
2/2✓ Branch 0 taken 752 times.
✓ Branch 1 taken 188 times.
|
940 | for var_ptrs in vars loop |
| 531 |
2/2✓ Branch 1 taken 2615 times.
✓ Branch 2 taken 752 times.
|
3367 | for var_ptr in VariablePointers.toList(var_ptrs) loop |
| 532 | 2615 | var := Pointer.access(var_ptr); | |
| 533 |
2/2✓ Branch 1 taken 2039 times.
✓ Branch 2 taken 576 times.
|
2615 | if UnorderedMap.contains(var.name, simcode_map) then |
| 534 | sim_vars := var :: sim_vars; | ||
| 535 | end if; | ||
| 536 | end for; | ||
| 537 | end for; | ||
| 538 | 188 | sim_vars := listReverse(sim_vars); | |
| 539 |
2/2✓ Branch 0 taken 2039 times.
✓ Branch 1 taken 188 times.
|
2227 | for var in sim_vars loop |
| 540 | 2039 | (nominal_blcks, simCodeIndices) := createAttributeBlock(var, BackendExtension.VariableAttributes.getNominal(var.backendinfo.attributes), nominal_blcks, simCodeIndices, bound); | |
| 541 | end for; | ||
| 542 |
2/2✓ Branch 0 taken 2039 times.
✓ Branch 1 taken 188 times.
|
2227 | for var in sim_vars loop |
| 543 | 2039 | (min_blcks, simCodeIndices) := createAttributeBlock(var, BackendExtension.VariableAttributes.getMin(var.backendinfo.attributes), min_blcks, simCodeIndices, bound); | |
| 544 | end for; | ||
| 545 |
2/2✓ Branch 0 taken 2039 times.
✓ Branch 1 taken 188 times.
|
2227 | for var in sim_vars loop |
| 546 | 2039 | (max_blcks, simCodeIndices) := createAttributeBlock(var, BackendExtension.VariableAttributes.getMax(var.backendinfo.attributes), max_blcks, simCodeIndices, bound); | |
| 547 | end for; | ||
| 548 | 188 | min_blcks := listReverse(min_blcks); | |
| 549 | 188 | max_blcks := listReverse(max_blcks); | |
| 550 | 188 | nominal_blcks := listReverse(nominal_blcks); | |
| 551 | end createAttributeBlocks; | ||
| 552 | |||
| 553 | function createAttributeBlock | ||
| 554 | input Variable var; | ||
| 555 | input Option<Expression> attribute; | ||
| 556 | input output list<Block> blcks; | ||
| 557 | input output SimCodeIndices simCodeIndices; | ||
| 558 | input UnorderedSet<ComponentRef> bound; | ||
| 559 | algorithm | ||
| 560 | _ := match attribute | ||
| 561 | local | ||
| 562 | Expression exp; | ||
| 563 | // attributes depending on parameters of the initialization are unknown at this point | ||
| 564 | case SOME(exp) guard not Expression.isLiteralXML(exp) and not Expression.contains(exp, function isUnknownBeforeInit(bound = bound)) algorithm | ||
| 565 | 7 | blcks := SIMPLE_ASSIGN(simCodeIndices.equationIndex, var.name, exp, DAE.emptyElementSource, | |
| 566 | EquationAttributes.default(EquationKind.CONTINUOUS, false)) :: blcks; | ||
| 567 | 7 | simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1; | |
| 568 | then (); | ||
| 569 | else (); | ||
| 570 | end match; | ||
| 571 | end createAttributeBlock; | ||
| 572 | |||
| 573 | function isUnknownBeforeInit | ||
| 574 | "true for variables whose value is not known before the initialization" | ||
| 575 | input Expression exp; | ||
| 576 | input UnorderedSet<ComponentRef> bound; | ||
| 577 | output Boolean b; | ||
| 578 | protected | ||
| 579 | Pointer<Variable> var_ptr; | ||
| 580 | Variable var; | ||
| 581 | Option<Expression> value; | ||
| 582 | algorithm | ||
| 583 | b := match exp | ||
| 584 | case Expression.CREF() guard InstNode.isVar(ComponentRef.node(exp.cref)) algorithm | ||
| 585 | 8 | var_ptr := BVariable.getVarPointer(exp.cref, sourceInfo()); | |
| 586 |
2/4✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
|
8 | if BVariable.isConst(var_ptr) or UnorderedSet.contains(BVariable.getVarName(var_ptr), bound) then |
| 587 | b := false; | ||
| 588 | elseif BVariable.isParamOrConst(var_ptr) then | ||
| 589 | 8 | var := Pointer.access(var_ptr); | |
| 590 | 8 | value := Binding.getExpOpt(var.binding); | |
| 591 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
|
8 | if isNone(value) then |
| 592 | ✗ | value := BackendExtension.VariableAttributes.getStartAttribute(var.backendinfo.attributes); | |
| 593 | end if; | ||
| 594 | 8 | b := not Util.applyOptionOrDefault(value, Expression.isLiteralXML, false); | |
| 595 | else | ||
| 596 | b := true; | ||
| 597 | end if; | ||
| 598 | then b; | ||
| 599 | else false; | ||
| 600 | end match; | ||
| 601 | end isUnknownBeforeInit; | ||
| 602 | |||
| 603 | function createDAEModeBlocks | ||
| 604 | input list<Partition.Partition> partitions; | ||
| 605 | output list<list<Block>> blcks = {}; | ||
| 606 | output list<SimVar> vars = {}; | ||
| 607 | input output SimCodeIndices simCodeIndices; | ||
| 608 | input UnorderedMap<ComponentRef, SimVar> simcode_map; | ||
| 609 | input UnorderedMap<ComponentRef, Block> equation_map; | ||
| 610 | protected | ||
| 611 | Pointer<SimCodeIndices> indices_ptr; | ||
| 612 | Pointer<list<SimVar>> vars_ptr = Pointer.create({}); | ||
| 613 | list<Block> tmp; | ||
| 614 | algorithm | ||
| 615 |
2/2✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
|
2 | for partition in listReverse(partitions) loop |
| 616 | 1 | indices_ptr := Pointer.create(simCodeIndices); | |
| 617 | //VariablePointers.map(partition.unknowns, function SimVar.traverseCreate(acc = vars_ptr, indices_ptr = indices_ptr, varType = VarType.RESIDUAL)); | ||
| 618 | 1 | Partition.Partition.mapStrongComponents(partition, function SimVar.createFromResidualComponent(acc = vars_ptr, indices_ptr = indices_ptr, varType = VarType.RESIDUAL)); | |
| 619 | 1 | (tmp, simCodeIndices) := fromPartition(partition, Pointer.access(indices_ptr), simcode_map, equation_map); | |
| 620 | blcks := tmp :: blcks; | ||
| 621 | end for; | ||
| 622 | 1 | vars := listReverse(Pointer.access(vars_ptr)); | |
| 623 | end createDAEModeBlocks; | ||
| 624 | |||
| 625 | function createClockedBlocks | ||
| 626 | input list<Partition.Partition> partitions; | ||
| 627 | output list<SimPartition> baseParts; | ||
| 628 | output list<Block> eventClocks; | ||
| 629 | input output SimCodeIndices simCodeIndices; | ||
| 630 | input UnorderedMap<ComponentRef, SimVar> simcode_map; | ||
| 631 | input UnorderedMap<ComponentRef, Block> equation_map; | ||
| 632 | input ClockedInfo info; | ||
| 633 | protected | ||
| 634 | // type for for double map. base clock -> {sub_clock -> partition} | ||
| 635 | type SimPartitions = list<SimPartition>; | ||
| 636 | UnorderedMap<BClock, SimPartitions> clock_collector = UnorderedMap.new<SimPartitions>(BClock.hash, BClock.isEqual); | ||
| 637 | // set to collect the dependencies of a block | ||
| 638 | list<Block> blcks; | ||
| 639 | list<SimVar> vars; | ||
| 640 | BClock clock, subClock, baseClock; | ||
| 641 | Boolean holdEvents; | ||
| 642 | Option<BClock> baseClock_opt; | ||
| 643 | SimPartition subPart; | ||
| 644 | algorithm | ||
| 645 | // initialize all base clocks | ||
| 646 |
2/2✓ Branch 1 taken 12 times.
✓ Branch 2 taken 188 times.
|
200 | for c in UnorderedMap.valueList(info.baseClocks) loop |
| 647 | 12 | UnorderedMap.add(c, {}, clock_collector); | |
| 648 | end for; | ||
| 649 | |||
| 650 | // create all sub partition blocks and find the base partitions | ||
| 651 |
2/2✓ Branch 1 taken 18 times.
✓ Branch 2 taken 188 times.
|
206 | for partition in listReverse(partitions) loop |
| 652 | // create the partition and get all clock dependencies | ||
| 653 | 18 | (blcks, simCodeIndices) := fromPartition(partition, simCodeIndices, simcode_map, equation_map); | |
| 654 | 18 | vars := SimVars.getPartitionVars(partition, simcode_map); | |
| 655 | 18 | (clock, baseClock_opt, holdEvents) := Partition.Partition.getClocks(partition); | |
| 656 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
|
18 | if isSome(baseClock_opt) then |
| 657 | // it is a sub clock | ||
| 658 | 18 | SOME(baseClock) := baseClock_opt; | |
| 659 | subClock := clock; | ||
| 660 | else | ||
| 661 | // it is a base clock, use the default sub clock | ||
| 662 | baseClock := clock; | ||
| 663 | subClock := NBPartitioning.DEFAULT_SUB_CLOCK; | ||
| 664 | end if; | ||
| 665 | |||
| 666 | // create and add sub partition | ||
| 667 | 18 | subPart := SimPartition.createSubPartition(subClock, blcks, vars, holdEvents); | |
| 668 | 36 | UnorderedMap.add(baseClock, subPart :: UnorderedMap.getSafe(baseClock, clock_collector, sourceInfo()), clock_collector); | |
| 669 | end for; | ||
| 670 | |||
| 671 | // create base partitions | ||
| 672 | 188 | (baseParts, eventClocks, simCodeIndices) := SimPartition.createBasePartitions(clock_collector, simCodeIndices); | |
| 673 | end createClockedBlocks; | ||
| 674 | |||
| 675 | function createNoReturnBlocks | ||
| 676 | input EquationPointers equations; | ||
| 677 | output list<Block> blcks = {}; | ||
| 678 | input output SimCodeIndices simCodeIndices; | ||
| 679 | input Partition.Kind kind; | ||
| 680 | input UnorderedMap<ComponentRef, SimVar> simcode_map; | ||
| 681 | input UnorderedMap<ComponentRef, Block> equation_map; | ||
| 682 | protected | ||
| 683 | Equation eqn; | ||
| 684 | Block tmp; | ||
| 685 | algorithm | ||
| 686 |
2/2✓ Branch 1 taken 163 times.
✓ Branch 2 taken 25 times.
|
521 | for i in 1:ExpandableArray.getLastUsedIndex(equations.eqArr) loop |
| 687 |
1/2✓ Branch 1 taken 333 times.
✗ Branch 2 not taken.
|
333 | if ExpandableArray.occupied(i, equations.eqArr) then |
| 688 | 333 | eqn := Pointer.access(ExpandableArray.get(i, equations.eqArr)); | |
| 689 | (tmp, simCodeIndices) := match eqn | ||
| 690 | local | ||
| 691 | ComponentRef cref; | ||
| 692 | |||
| 693 | case Equation.SCALAR_EQUATION(lhs = Expression.CREF(cref = cref)) | ||
| 694 | 65 | then createEquation(NBVariable.getVar(cref, sourceInfo()), eqn, NBSolve.Status.EXPLICIT, simCodeIndices, kind, simcode_map, equation_map); | |
| 695 | |||
| 696 | case Equation.ARRAY_EQUATION(lhs = Expression.CREF(cref = cref)) | ||
| 697 | 8 | then createEquation(NBVariable.getVar(cref, sourceInfo()), eqn, NBSolve.Status.EXPLICIT, simCodeIndices, kind, simcode_map, equation_map); | |
| 698 | |||
| 699 | case Equation.RECORD_EQUATION(lhs = Expression.CREF(cref = cref)) | ||
| 700 | ✗ | then createEquation(NBVariable.getVar(cref, sourceInfo()), eqn, NBSolve.Status.EXPLICIT, simCodeIndices, kind, simcode_map, equation_map); | |
| 701 | |||
| 702 | case Equation.WHEN_EQUATION() | ||
| 703 | 6 | then createEquation(NBVariable.DUMMY_VARIABLE, eqn, NBSolve.Status.EXPLICIT, simCodeIndices, kind, simcode_map, equation_map); | |
| 704 | |||
| 705 | case Equation.ALGORITHM() | ||
| 706 | 254 | then createAlgorithm(eqn, simCodeIndices, equation_map); | |
| 707 | |||
| 708 | case Equation.FOR_EQUATION() | ||
| 709 | ✗ | then createAlgorithm(eqn, simCodeIndices, equation_map); | |
| 710 | |||
| 711 | /* ToDo: other equations ... */ | ||
| 712 | |||
| 713 | else algorithm | ||
| 714 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for\n" + Equation.toString(eqn)}); | |
| 715 | ✗ | then fail(); | |
| 716 | end match; | ||
| 717 | |||
| 718 | blcks := tmp :: blcks; | ||
| 719 | // list reverse necessary? they are unordered anyway | ||
| 720 | end if; | ||
| 721 | end for; | ||
| 722 | end createNoReturnBlocks; | ||
| 723 | |||
| 724 | function fromPartition | ||
| 725 | input Partition.Partition partition; | ||
| 726 | output list<Block> blcks; | ||
| 727 | input output SimCodeIndices simCodeIndices; | ||
| 728 | input UnorderedMap<ComponentRef, SimVar> simcode_map; | ||
| 729 | input UnorderedMap<ComponentRef, Block> equation_map; | ||
| 730 | algorithm | ||
| 731 | blcks := match partition.strongComponents | ||
| 732 | local | ||
| 733 | array<StrongComponent> comps; | ||
| 734 | Partition.Kind kind; | ||
| 735 | Block tmp; | ||
| 736 | list<Block> result = {}; | ||
| 737 | Integer index, alias_index; | ||
| 738 | |||
| 739 | case SOME(comps) algorithm | ||
| 740 | 507 | kind := Partition.Partition.getKind(partition); | |
| 741 |
2/2✓ Branch 0 taken 505 times.
✓ Branch 1 taken 2 times.
|
6521 | for i in arrayLength(comps):-1:1 loop |
| 742 | 6014 | (tmp, simCodeIndices, index) := fromStrongComponent(comps[i], simCodeIndices, kind, simcode_map, equation_map); | |
| 743 | // add it to the alias map. correctly map the alias index if itself is an alias | ||
| 744 | alias_index := match comps[i] | ||
| 745 | local | ||
| 746 | StrongComponent.AliasInfo aliasInfo; | ||
| 747 | 2689 | case StrongComponent.ALIAS(aliasInfo = aliasInfo) then UnorderedMap.getOrDefault(aliasInfo, simCodeIndices.alias_map, -1); | |
| 748 | 3325 | else index; | |
| 749 | end match; | ||
| 750 | 6014 | UnorderedMap.add(AliasInfo.ALIAS_INFO(kind, partition.index, i), alias_index, simCodeIndices.alias_map); | |
| 751 | result := tmp :: result; | ||
| 752 | end for; | ||
| 753 | then result; | ||
| 754 | |||
| 755 | else algorithm | ||
| 756 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for\n" + Partition.Partition.toString(partition)}); | |
| 757 | ✗ | then fail(); | |
| 758 | end match; | ||
| 759 | end fromPartition; | ||
| 760 | |||
| 761 | function blockSource | ||
| 762 | "The DAE.ElementSource of a block, for block kinds that track one." | ||
| 763 | input Block blck; | ||
| 764 | output DAE.ElementSource source; | ||
| 765 | algorithm | ||
| 766 | source := match blck | ||
| 767 | 559 | case RESIDUAL() then blck.source; | |
| 768 | ✗ | case ARRAY_RESIDUAL() then blck.source; | |
| 769 | ✗ | case FOR_RESIDUAL() then blck.source; | |
| 770 | ✗ | case GENERIC_RESIDUAL() then blck.source; | |
| 771 | 30 | case SIMPLE_ASSIGN() then blck.source; | |
| 772 | ✗ | case ARRAY_ASSIGN() then blck.source; | |
| 773 | ✗ | case RESIZABLE_ASSIGN() then blck.source; | |
| 774 | ✗ | case GENERIC_ASSIGN() then blck.source; | |
| 775 | ✗ | case ENTWINED_ASSIGN() then blck.source; | |
| 776 | ✗ | case IF() then blck.source; | |
| 777 | ✗ | case WHEN() then blck.source; | |
| 778 | else DAE.emptyElementSource; | ||
| 779 | end match; | ||
| 780 | end blockSource; | ||
| 781 | |||
| 782 | function jacobianHasGenericLoopCalls | ||
| 783 | "True if this Jacobian's per-column evaluation uses generic for-loop/array calls." | ||
| 784 | input SimJacobian jac; | ||
| 785 | output Boolean b; | ||
| 786 | algorithm | ||
| 787 | b := match jac | ||
| 788 | 22 | case SimJacobian.SIM_JAC() then not listEmpty(jac.generic_loop_calls); | |
| 789 | end match; | ||
| 790 | end jacobianHasGenericLoopCalls; | ||
| 791 | |||
| 792 | function isForOrGenericResidual | ||
| 793 | "True for for-loop/generic-index residual block kinds (unsupported by the linear-system codegen)." | ||
| 794 | input Block blck; | ||
| 795 | output Boolean b; | ||
| 796 | algorithm | ||
| 797 | b := match blck | ||
| 798 | case FOR_RESIDUAL() then true; | ||
| 799 | case GENERIC_RESIDUAL() then true; | ||
| 800 | else false; | ||
| 801 | end match; | ||
| 802 | end isForOrGenericResidual; | ||
| 803 | |||
| 804 | function fromStrongComponent | ||
| 805 | input StrongComponent comp; | ||
| 806 | output Block blck; | ||
| 807 | input output SimCodeIndices simCodeIndices; | ||
| 808 | output Integer index; | ||
| 809 | input Partition.Kind kind; | ||
| 810 | input UnorderedMap<ComponentRef, SimVar> simcode_map; | ||
| 811 | input UnorderedMap<ComponentRef, Block> equation_map; | ||
| 812 | input Boolean entwined = false "a slice of an entwined component, which needs its index list"; | ||
| 813 | algorithm | ||
| 814 | (blck, index) := match comp | ||
| 815 | local | ||
| 816 | Tearing strict; | ||
| 817 | NonlinearSystem system; | ||
| 818 | LinearSystem linSystem; | ||
| 819 | list<Block> eqns = {}; | ||
| 820 | list<ComponentRef> crefs = {}; | ||
| 821 | list<SimVar> linVars = {}; | ||
| 822 | Integer sysIndex; | ||
| 823 | Boolean allLinVarsFound; | ||
| 824 | Integer resizable_size "the static size of whole resizable iteration arrays beyond 1 each"; | ||
| 825 | Option<SimVar> osimvar; | ||
| 826 | Block tmp; | ||
| 827 | Variable var; | ||
| 828 | Option<SimJacobian> jacobian; | ||
| 829 | EquationPointer eqn_ptr; | ||
| 830 | Equation eqn; | ||
| 831 | SlicingStatus status; | ||
| 832 | ComponentRef var_cref; | ||
| 833 | Integer aliasOf, generic_call_index, residual_index = 0; | ||
| 834 | Block single_call; | ||
| 835 | list<Block> single_calls = {}; | ||
| 836 | UnorderedMap<ComponentRef, Integer> entwined_index_map; | ||
| 837 | list<Integer> call_order = {}; | ||
| 838 | Identifier ident; | ||
| 839 | list<SimIterator> iters; | ||
| 840 | |||
| 841 | case StrongComponent.SINGLE_COMPONENT() algorithm | ||
| 842 | 3807 | (tmp, simCodeIndices) := createEquation(Pointer.access(comp.var), Pointer.access(comp.eqn), comp.status, simCodeIndices, kind, simcode_map, equation_map); | |
| 843 | 3807 | then (tmp, getIndex(tmp)); | |
| 844 | |||
| 845 | case StrongComponent.MULTI_COMPONENT() algorithm | ||
| 846 | 160 | (tmp, simCodeIndices) := createEquation(NBVariable.DUMMY_VARIABLE, Pointer.access(Slice.getT(comp.eqn)), comp.status, simCodeIndices, kind, simcode_map, equation_map); | |
| 847 | 160 | then (tmp, getIndex(tmp)); | |
| 848 | |||
| 849 | case StrongComponent.SLICED_COMPONENT() guard(Equation.isForEquation(Slice.getT(comp.eqn))) algorithm | ||
| 850 | 29 | (tmp, simCodeIndices) := createAlgorithm(Pointer.access(Slice.getT(comp.eqn)), simCodeIndices, equation_map); | |
| 851 | 29 | then (tmp, getIndex(tmp)); | |
| 852 | |||
| 853 | case StrongComponent.SLICED_COMPONENT() algorithm | ||
| 854 | // just a regular equation solved for a sliced variable | ||
| 855 | // use cref instead of var because it has subscripts! | ||
| 856 | 1497 | eqn := Pointer.access(Slice.getT(comp.eqn)); | |
| 857 | 1497 | (tmp, simCodeIndices) := createEquation(Variable.fromCref(comp.var_cref), eqn, comp.status, simCodeIndices, kind, simcode_map, equation_map); | |
| 858 | 1497 | then (tmp, getIndex(tmp)); | |
| 859 | |||
| 860 | case StrongComponent.RESIZABLE_COMPONENT() guard(Equation.isForEquation(Slice.getT(comp.eqn))) algorithm | ||
| 861 | // create a resizable equation | ||
| 862 | 322 | eqn_ptr := Slice.getT(comp.eqn); | |
| 863 | 322 | eqn := Pointer.access(eqn_ptr); | |
| 864 | 322 | ident := Identifier.IDENTIFIER(eqn_ptr, comp.var_cref, true); | |
| 865 | 322 | iters := SimIterator.fromIterator(Equation.getForIterator(eqn)); | |
| 866 | 322 | generic_call_index := UnorderedMap.tryAdd(ident, UnorderedMap.size(simCodeIndices.generic_call_map), simCodeIndices.generic_call_map); | |
| 867 | 322 | tmp := RESIZABLE_ASSIGN(simCodeIndices.equationIndex, generic_call_index, iters, Equation.getSource(eqn), Equation.getAttributes(eqn)); | |
| 868 | 322 | UnorderedMap.add(Equation.getEqnName(eqn_ptr), tmp, equation_map); | |
| 869 | 322 | simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1; | |
| 870 | 322 | then (tmp, getIndex(tmp)); | |
| 871 | |||
| 872 | // a slice of a for-equation over a resizable range that contains every | ||
| 873 | // iteration (at the analysis sizes; the call computes the whole body of an | ||
| 874 | // iteration) is the whole loop for every size | ||
| 875 | case StrongComponent.GENERIC_COMPONENT() guard not entwined and coversAllResizableIterations(comp.eqn) algorithm | ||
| 876 | 48 | eqn_ptr := Slice.getT(comp.eqn); | |
| 877 | 48 | eqn := Pointer.access(eqn_ptr); | |
| 878 | 48 | ident := Identifier.IDENTIFIER(eqn_ptr, comp.var_cref, true); | |
| 879 | 48 | iters := SimIterator.fromIterator(Equation.getForIterator(eqn)); | |
| 880 | 48 | generic_call_index := UnorderedMap.tryAdd(ident, UnorderedMap.size(simCodeIndices.generic_call_map), simCodeIndices.generic_call_map); | |
| 881 | 48 | tmp := RESIZABLE_ASSIGN(simCodeIndices.equationIndex, generic_call_index, iters, Equation.getSource(eqn), Equation.getAttributes(eqn)); | |
| 882 | 48 | UnorderedMap.add(Equation.getEqnName(eqn_ptr), tmp, equation_map); | |
| 883 | 48 | simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1; | |
| 884 | 48 | then (tmp, getIndex(tmp)); | |
| 885 | |||
| 886 | // a slice of a for-equation over a resizable range that is a box of | ||
| 887 | // iterations is the loop over symbolic sub-ranges for every size | ||
| 888 | case StrongComponent.GENERIC_COMPONENT() guard not entwined and isSome(restrictedResizableIterator(comp.eqn)) algorithm | ||
| 889 | 16 | eqn_ptr := Slice.getT(comp.eqn); | |
| 890 | 16 | eqn := Pointer.access(eqn_ptr); | |
| 891 | 16 | ident := Identifier.IDENTIFIER(eqn_ptr, comp.var_cref, true); | |
| 892 | 16 | iters := SimIterator.fromIterator(Util.getOption(restrictedResizableIterator(comp.eqn))); | |
| 893 | 16 | generic_call_index := UnorderedMap.tryAdd(ident, UnorderedMap.size(simCodeIndices.generic_call_map), simCodeIndices.generic_call_map); | |
| 894 | 16 | tmp := RESIZABLE_ASSIGN(simCodeIndices.equationIndex, generic_call_index, iters, Equation.getSource(eqn), Equation.getAttributes(eqn)); | |
| 895 | 16 | UnorderedMap.add(Equation.getEqnName(eqn_ptr), tmp, equation_map); | |
| 896 | 16 | simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1; | |
| 897 | 16 | then (tmp, getIndex(tmp)); | |
| 898 | |||
| 899 | case StrongComponent.GENERIC_COMPONENT() algorithm | ||
| 900 | // create a generic index list call of a for-loop equation | ||
| 901 | 26 | eqn_ptr := Slice.getT(comp.eqn); | |
| 902 | 26 | eqn := Pointer.access(eqn_ptr); | |
| 903 | 26 | ident := Identifier.IDENTIFIER(eqn_ptr, comp.var_cref, false); | |
| 904 | 26 | generic_call_index := UnorderedMap.tryAdd(ident, UnorderedMap.size(simCodeIndices.generic_call_map), simCodeIndices.generic_call_map); | |
| 905 | 26 | tmp := GENERIC_ASSIGN(simCodeIndices.equationIndex, generic_call_index, comp.eqn.indices, Equation.getSource(eqn), Equation.getAttributes(eqn)); | |
| 906 | 26 | UnorderedMap.add(Equation.getEqnName(eqn_ptr), tmp, equation_map); | |
| 907 | 26 | simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1; | |
| 908 | 26 | then (tmp, getIndex(tmp)); | |
| 909 | |||
| 910 | case StrongComponent.ENTWINED_COMPONENT() algorithm | ||
| 911 | // create index list calls for entwined equations (position-based dispatch) | ||
| 912 | 2 | entwined_index_map := UnorderedMap.new<Integer>(ComponentRef.hash, ComponentRef.isEqual); | |
| 913 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
|
8 | for slice in comp.entwined_slices loop |
| 914 | 6 | (single_call, simCodeIndices, _) := fromStrongComponent(slice, simCodeIndices, kind, simcode_map, equation_map, entwined = true); | |
| 915 | // position = current list length before prepend (0-based, stable after reversal below) | ||
| 916 | 6 | UnorderedMap.add(getEntwinedEquationName(slice), listLength(single_calls), entwined_index_map); | |
| 917 | single_calls := single_call :: single_calls; | ||
| 918 | end for; | ||
| 919 | 2 | single_calls := listReverse(single_calls); | |
| 920 |
2/2✓ Branch 1 taken 36 times.
✓ Branch 2 taken 2 times.
|
38 | for tpl in listReverse(comp.entwined_tpl_lst) loop |
| 921 | 36 | (eqn_ptr, _) := tpl; | |
| 922 | 36 | call_order := UnorderedMap.getSafe(Equation.getEqnName(eqn_ptr), entwined_index_map, sourceInfo()) :: call_order; | |
| 923 | end for; | ||
| 924 | // todo: eq attributes and source | ||
| 925 | 2 | tmp := ENTWINED_ASSIGN(simCodeIndices.equationIndex, call_order, single_calls, DAE.emptyElementSource, EquationAttributes.default(EquationKind.CONTINUOUS, false)); | |
| 926 | 2 | simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1; | |
| 927 | 2 | then (tmp, getIndex(tmp)); | |
| 928 | |||
| 929 | case StrongComponent.ALGEBRAIC_LOOP(strict = strict) algorithm | ||
| 930 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 87 times.
✓ Branch 2 taken 67 times.
✓ Branch 3 taken 20 times.
|
577 | for i in 1:arrayLength(strict.innerEquations) loop |
| 931 | 403 | (tmp, simCodeIndices, _) := fromStrongComponent(strict.innerEquations[i], simCodeIndices, kind, simcode_map, equation_map); | |
| 932 | eqns := tmp :: eqns; | ||
| 933 | end for; | ||
| 934 |
2/2✓ Branch 0 taken 730 times.
✓ Branch 1 taken 87 times.
|
817 | for slice in strict.residual_eqns loop |
| 935 | // kabdelhak: we need to actually slice here -> generic slices are needed for residuals | ||
| 936 | 730 | (tmp, simCodeIndices, residual_index) := createResidual(slice, simCodeIndices, residual_index, equation_map); | |
| 937 | eqns := tmp :: eqns; | ||
| 938 | end for; | ||
| 939 | allLinVarsFound := true; | ||
| 940 | resizable_size := 0; | ||
| 941 |
2/2✓ Branch 0 taken 648 times.
✓ Branch 1 taken 87 times.
|
735 | for slice in strict.iteration_vars loop |
| 942 | 648 | var := Pointer.access(Slice.getT(slice)); | |
| 943 |
6/6✓ Branch 0 taken 614 times.
✓ Branch 1 taken 34 times.
✓ Branch 3 taken 26 times.
✓ Branch 4 taken 588 times.
✓ Branch 7 taken 6 times.
✓ Branch 8 taken 20 times.
|
648 | if listEmpty(slice.indices) and Type.isArray(var.ty) and |
| 944 | List.any(Type.arrayDims(var.ty), Dimension.isResizable) then | ||
| 945 | // a whole resizable array: its elements are only known at runtime, | ||
| 946 | // the system is sized at runtime (no linear solver, see below) | ||
| 947 | 6 | crefs := var.name :: crefs; | |
| 948 | allLinVarsFound := false; | ||
| 949 | 6 | resizable_size := resizable_size + BVariable.size(Slice.getT(slice), true) - 1; | |
| 950 | elseif Type.isArray(var.ty) then | ||
| 951 | // the slice indices refer to the resized sizes of resizable dimensions | ||
| 952 |
2/2✓ Branch 1 taken 266 times.
✓ Branch 2 taken 54 times.
|
320 | for scal_var in Scalarize.scalarizeBackendVariable(var, slice.indices, resize = true) loop |
| 953 | 266 | crefs := scal_var.name :: crefs; | |
| 954 | 266 | osimvar := UnorderedMap.get(scal_var.name, simcode_map); | |
| 955 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 266 times.
✓ Branch 2 taken 211 times.
✓ Branch 3 taken 55 times.
|
266 | if isSome(osimvar) then |
| 956 | 211 | linVars := Util.getOption(osimvar) :: linVars; | |
| 957 | else | ||
| 958 | allLinVarsFound := false; | ||
| 959 | end if; | ||
| 960 | end for; | ||
| 961 | else | ||
| 962 | 588 | crefs := var.name :: crefs; | |
| 963 | 588 | osimvar := UnorderedMap.get(var.name, simcode_map); | |
| 964 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 588 times.
✓ Branch 2 taken 585 times.
✓ Branch 3 taken 3 times.
|
588 | if isSome(osimvar) then |
| 965 | 585 | linVars := Util.getOption(osimvar) :: linVars; | |
| 966 | else | ||
| 967 | allLinVarsFound := false; | ||
| 968 | end if; | ||
| 969 | end if; | ||
| 970 | end for; | ||
| 971 | |||
| 972 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 87 times.
✓ Branch 2 taken 85 times.
✓ Branch 3 taken 2 times.
|
87 | if isSome(strict.jac) then |
| 973 | 85 | (jacobian, simCodeIndices) := SimJacobian.create(Util.getOption(strict.jac), simCodeIndices, simcode_map); | |
| 974 | else | ||
| 975 | jacobian := NONE(); | ||
| 976 | end if; | ||
| 977 | |||
| 978 |
14/16✓ Branch 0 taken 31 times.
✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 31 times.
✓ Branch 4 taken 29 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 28 times.
✓ Branch 7 taken 1 time.
✓ Branch 8 taken 27 times.
✓ Branch 9 taken 1 time.
✓ Branch 11 taken 22 times.
✓ Branch 12 taken 5 times.
✓ Branch 15 taken 16 times.
✓ Branch 16 taken 6 times.
✓ Branch 17 taken 16 times.
✗ Branch 18 not taken.
|
87 | if comp.linear and isSome(jacobian) and not comp.homotopy and not comp.mixed |
| 979 | and not List.any(eqns, isForOrGenericResidual) | ||
| 980 | and not jacobianHasGenericLoopCalls(Util.getOption(jacobian)) | ||
| 981 | and allLinVarsFound then | ||
| 982 | // Linear torn systems with an analytic Jacobian get solved directly (A*x=b) | ||
| 983 | // instead of via Newton (#16458). Homotopy, for-loop/generic residuals, | ||
| 984 | // generic_loop_calls Jacobians, and mixed (discrete-coupled, e.g. ideal-diode | ||
| 985 | // switching networks) systems fall back below -- a one-shot direct solve has | ||
| 986 | // no damping across the discrete state, and coarser NBackend tearing than OB's | ||
| 987 | // for these networks makes that chatter across event iterations instead of | ||
| 988 | // settling (see newInst-newBackend library-testing regressions after #16463). | ||
| 989 |
4/4✓ Branch 1 taken 589 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 589 times.
✓ Branch 4 taken 16 times.
|
605 | linSystem := LINEAR_SYSTEM( |
| 990 | index = simCodeIndices.equationIndex, | ||
| 991 | mixed = comp.mixed, | ||
| 992 | torn = true, | ||
| 993 | vars = listReverse(linVars), | ||
| 994 | beqs = {}, | ||
| 995 | simJac = {}, | ||
| 996 | residual = listReverse(eqns), | ||
| 997 | jacobian = jacobian, | ||
| 998 | sources = list(blockSource(b) for b in listReverse(eqns)), | ||
| 999 | indexSystem = simCodeIndices.linearSystemIndex, | ||
| 1000 | size = listLength(crefs), | ||
| 1001 | partOfJac = false | ||
| 1002 | ); | ||
| 1003 | 16 | simCodeIndices.linearSystemIndex := simCodeIndices.linearSystemIndex + 1; | |
| 1004 | 16 | simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1; | |
| 1005 | 16 | tmp := LINEAR(linSystem, NONE()); | |
| 1006 | 16 | sysIndex := linSystem.index; | |
| 1007 | else | ||
| 1008 | 71 | system := NONLINEAR_SYSTEM( | |
| 1009 | index = simCodeIndices.equationIndex, | ||
| 1010 | blcks = listReverse(eqns), | ||
| 1011 | crefs = listReverse(crefs), | ||
| 1012 | indexSystem = simCodeIndices.nonlinearSystemIndex, | ||
| 1013 | size = listLength(crefs) + resizable_size, | ||
| 1014 | jacobian = Pointer.create(jacobian), | ||
| 1015 | homotopy = comp.homotopy, | ||
| 1016 | mixed = comp.mixed, | ||
| 1017 | torn = true | ||
| 1018 | ); | ||
| 1019 | 71 | simCodeIndices.nonlinearSystemIndex := simCodeIndices.nonlinearSystemIndex + 1; | |
| 1020 | 71 | simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1; | |
| 1021 | 71 | tmp := NONLINEAR(system, NONE()); | |
| 1022 | 71 | sysIndex := system.index; | |
| 1023 | end if; | ||
| 1024 | then (tmp, sysIndex); | ||
| 1025 | |||
| 1026 | case StrongComponent.ALIAS() algorithm | ||
| 1027 | 2689 | aliasOf := UnorderedMap.getOrDefault(comp.aliasInfo, simCodeIndices.alias_map, -1); | |
| 1028 |
4/4✓ Branch 1 taken 283 times.
✓ Branch 2 taken 2406 times.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 282 times.
|
2690 | tmp := ALIAS(simCodeIndices.equationIndex, comp.aliasInfo, aliasOf, |
| 1029 | StrongComponent.isDiscrete(comp) and not StrongComponent.isAlgebraicLoop(comp.original)); | ||
| 1030 | 2689 | simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1; | |
| 1031 | 2689 | then (tmp, getIndex(tmp)); | |
| 1032 | |||
| 1033 | case StrongComponent.ENTWINED_COMPONENT() algorithm | ||
| 1034 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because entwined equations have to be resolved beforehand in Solve.solve(). Failed for:\n" | |
| 1035 | + StrongComponent.toString(comp)}); | ||
| 1036 | ✗ | then fail(); | |
| 1037 | |||
| 1038 | else algorithm | ||
| 1039 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed with unknown reason for\n" + StrongComponent.toString(comp)}); | |
| 1040 | ✗ | then fail(); | |
| 1041 | end match; | ||
| 1042 | end fromStrongComponent; | ||
| 1043 | |||
| 1044 | function restrictedResizableIterator | ||
| 1045 | "the iterator of a slice of a for-equation with a scalar body over a | ||
| 1046 | resizable range, restricted to the iterations of the slice (whole if empty)" | ||
| 1047 | input Slice<EquationPointer> slice; | ||
| 1048 | output Option<Iterator> iter = NONE(); | ||
| 1049 | protected | ||
| 1050 | Equation eqn = Pointer.access(Slice.getT(slice)); | ||
| 1051 | Iterator it; | ||
| 1052 | algorithm | ||
| 1053 |
3/4✓ Branch 1 taken 48 times.
✓ Branch 2 taken 40 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 48 times.
|
88 | if not Flags.getConfigBool(Flags.RESIZABLE_ARRAYS) or not Equation.isForEquation(Slice.getT(slice)) then |
| 1054 | 40 | return; | |
| 1055 | end if; | ||
| 1056 | 48 | it := Equation.getForIterator(eqn); | |
| 1057 |
2/4✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 48 times.
|
48 | if Iterator.isResizable(it) and Equation.size(Slice.getT(slice), true) == Iterator.size(it, true) then |
| 1058 | // an empty slice is the whole loop | ||
| 1059 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
|
48 | iter := if listEmpty(slice.indices) then SOME(it) else Resizable.restrictIterator(it, slice.indices); |
| 1060 | end if; | ||
| 1061 | end restrictedResizableIterator; | ||
| 1062 | |||
| 1063 | function coversAllResizableIterations | ||
| 1064 | "true if the slice of a for-equation over a resizable range contains every | ||
| 1065 | iteration at the analysis sizes. The generated call decodes an index as the | ||
| 1066 | position of an iteration and computes the whole body of it." | ||
| 1067 | input Slice<EquationPointer> slice; | ||
| 1068 | output Boolean b = false; | ||
| 1069 | protected | ||
| 1070 | Equation eqn = Pointer.access(Slice.getT(slice)); | ||
| 1071 | Iterator iter; | ||
| 1072 | Integer n; | ||
| 1073 | array<Boolean> seen; | ||
| 1074 | algorithm | ||
| 1075 |
2/4✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 84 times.
|
84 | if not Equation.isForEquation(Slice.getT(slice)) or listEmpty(slice.indices) then |
| 1076 | ✗ | return; | |
| 1077 | end if; | ||
| 1078 | 84 | iter := Equation.getForIterator(eqn); | |
| 1079 |
2/2✓ Branch 1 taken 20 times.
✓ Branch 2 taken 64 times.
|
84 | if not Iterator.isResizable(iter) then |
| 1080 | 20 | return; | |
| 1081 | end if; | ||
| 1082 | 64 | n := Iterator.size(iter, true); | |
| 1083 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 64 times.
|
64 | if n <= 0 then |
| 1084 | ✗ | return; | |
| 1085 | end if; | ||
| 1086 | 64 | seen := arrayCreate(n, false); | |
| 1087 |
2/2✓ Branch 0 taken 224 times.
✓ Branch 1 taken 64 times.
|
288 | for i in slice.indices loop |
| 1088 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 224 times.
|
224 | arrayUpdate(seen, mod(i, n) + 1, true); |
| 1089 | end for; | ||
| 1090 | 64 | b := Array.all(seen, Util.id); | |
| 1091 | end coversAllResizableIterations; | ||
| 1092 | |||
| 1093 | function createResidual | ||
| 1094 | input Slice<EquationPointer> slice; | ||
| 1095 | output Block blck; | ||
| 1096 | input output SimCodeIndices simCodeIndices; | ||
| 1097 | input output Integer res_idx; | ||
| 1098 | input UnorderedMap<ComponentRef, Block> equation_map; | ||
| 1099 | protected | ||
| 1100 | Equation eqn = Pointer.access(Slice.getT(slice)); | ||
| 1101 | algorithm | ||
| 1102 | blck := match (eqn, slice.indices) | ||
| 1103 | local | ||
| 1104 | Block tmp; | ||
| 1105 | Integer i; | ||
| 1106 | list<Subscript> subs; | ||
| 1107 | Equation body_eqn; | ||
| 1108 | |||
| 1109 | // a scalar equation has size 1, so a slice {1} is the same as no slice | ||
| 1110 | case (BEquation.SCALAR_EQUATION(), _) algorithm | ||
| 1111 | 709 | tmp := RESIDUAL(simCodeIndices.equationIndex, res_idx, eqn.rhs, eqn.source, eqn.attr); | |
| 1112 | 709 | simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1; | |
| 1113 | 709 | res_idx := res_idx + 1; | |
| 1114 | then tmp; | ||
| 1115 | |||
| 1116 | case (BEquation.IF_EQUATION(), _) algorithm | ||
| 1117 | ✗ | (tmp, simCodeIndices, res_idx) := createResidual(Slice.SLICE(Pointer.create(IfEquationBody.inline(eqn.body, eqn)), slice.indices), simCodeIndices, res_idx, equation_map); | |
| 1118 | then tmp; | ||
| 1119 | |||
| 1120 | // unsliced array equation | ||
| 1121 | case (BEquation.ARRAY_EQUATION(), {}) algorithm | ||
| 1122 | 7 | tmp := ARRAY_RESIDUAL(simCodeIndices.equationIndex, res_idx, eqn.rhs, eqn.source, eqn.attr); | |
| 1123 | 7 | simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1; | |
| 1124 | 7 | res_idx := res_idx + Equation.size(Slice.getT(slice)); | |
| 1125 | then tmp; | ||
| 1126 | |||
| 1127 | // single slice array equation | ||
| 1128 | case (BEquation.ARRAY_EQUATION(), {i}) algorithm | ||
| 1129 | // get subscripts and apply them to rhs | ||
| 1130 | ✗ | subs := list(Subscript.fromExp(Expression.INTEGER(s)) for s in Slice.indexToLocation(i, Equation.sizes(Slice.getT(slice)))); | |
| 1131 | ✗ | tmp := ARRAY_RESIDUAL(simCodeIndices.equationIndex, res_idx, Expression.applySubscripts(subs, eqn.rhs), eqn.source, eqn.attr); | |
| 1132 | ✗ | simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1; | |
| 1133 | ✗ | res_idx := res_idx + listLength(slice.indices); | |
| 1134 | then tmp; | ||
| 1135 | |||
| 1136 | // handle large slice array equation as full slice | ||
| 1137 | // Note: could be improved -> scalarize? find good pattern? | ||
| 1138 | case (BEquation.ARRAY_EQUATION(), _) algorithm | ||
| 1139 | ✗ | tmp := ARRAY_RESIDUAL(simCodeIndices.equationIndex, res_idx, eqn.rhs, eqn.source, eqn.attr); | |
| 1140 | ✗ | simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1; | |
| 1141 | ✗ | res_idx := res_idx + Equation.size(Slice.getT(slice)); | |
| 1142 | then tmp; | ||
| 1143 | |||
| 1144 | // for equations have to be split up before. Since they are not causalized | ||
| 1145 | // they can be executed in any order | ||
| 1146 | case (BEquation.FOR_EQUATION(body = {_}), {}) algorithm | ||
| 1147 | 14 | tmp := FOR_RESIDUAL(simCodeIndices.equationIndex, res_idx, SimIterator.fromIterator(eqn.iter), Util.getOption(Equation.getRHS(eqn)), eqn.source, eqn.attr); | |
| 1148 | 14 | simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1; | |
| 1149 | 14 | res_idx := res_idx + Equation.size(Slice.getT(slice)); | |
| 1150 | then tmp; | ||
| 1151 | |||
| 1152 | // the generic residual writes one value per index, an array valued body would overflow the residual array | ||
| 1153 | case (BEquation.FOR_EQUATION(body = {body_eqn}), _) guard(Equation.size(Pointer.create(body_eqn)) > 1) algorithm | ||
| 1154 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " does not support a part of a for equation with an array valued body:\n" | |
| 1155 | + Slice.toString(slice, function Equation.pointerToString(str = ""))}); | ||
| 1156 | ✗ | then fail(); | |
| 1157 | |||
| 1158 | // generic residual, for loop could not be fully recovered | ||
| 1159 | case (BEquation.FOR_EQUATION(body = {_}), _) algorithm | ||
| 1160 | ✗ | tmp := GENERIC_RESIDUAL(simCodeIndices.equationIndex, res_idx, slice.indices, SimIterator.fromIterator(eqn.iter), Util.getOption(Equation.getRHS(eqn)), eqn.source, eqn.attr); | |
| 1161 | ✗ | simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1; | |
| 1162 | ✗ | res_idx := res_idx + listLength(slice.indices); | |
| 1163 | then tmp; | ||
| 1164 | |||
| 1165 | // WHEN equations can appear as residuals in event-iteration algebraic loops. | ||
| 1166 | // They are evaluated (not minimized) during the iteration — create a WHEN block. | ||
| 1167 | // res_idx is NOT incremented since this is not a numerical residual. | ||
| 1168 | case (BEquation.WHEN_EQUATION(), _) algorithm | ||
| 1169 | ✗ | (tmp, simCodeIndices) := createWhenBody(eqn.body, eqn.source, eqn.attr, simCodeIndices); | |
| 1170 | then tmp; | ||
| 1171 | |||
| 1172 | // ToDo: add all other cases! | ||
| 1173 | |||
| 1174 | else algorithm | ||
| 1175 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for\n" + Slice.toString(slice, function Equation.pointerToString(str = ""))}); | |
| 1176 | ✗ | then fail(); | |
| 1177 | |||
| 1178 | end match; | ||
| 1179 | 730 | UnorderedMap.add(Equation.getEqnName(Pointer.create(eqn)), blck, equation_map); | |
| 1180 | end createResidual; | ||
| 1181 | |||
| 1182 | function createEquation | ||
| 1183 | "Creates a single equation" | ||
| 1184 | input Variable var; | ||
| 1185 | input Equation eqn; | ||
| 1186 | input Solve.Status status; | ||
| 1187 | output Block blck; | ||
| 1188 | input output SimCodeIndices simCodeIndices; | ||
| 1189 | input Partition.Kind kind; | ||
| 1190 | input UnorderedMap<ComponentRef, SimVar> simcode_map; | ||
| 1191 | input UnorderedMap<ComponentRef, Block> equation_map; | ||
| 1192 | algorithm | ||
| 1193 | blck := match (eqn, status) | ||
| 1194 | local | ||
| 1195 | Operator operator; | ||
| 1196 | Expression lhs, rhs; | ||
| 1197 | Block tmp; | ||
| 1198 | list<tuple<Expression, list<Block>>> branches; | ||
| 1199 | |||
| 1200 | case (BEquation.SCALAR_EQUATION(), NBSolve.Status.EXPLICIT) algorithm | ||
| 1201 | 4823 | tmp := SIMPLE_ASSIGN(simCodeIndices.equationIndex, var.name, eqn.rhs, eqn.source, eqn.attr); | |
| 1202 | 4823 | simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1; | |
| 1203 | then tmp; | ||
| 1204 | |||
| 1205 | case (BEquation.ARRAY_EQUATION(), NBSolve.Status.EXPLICIT) algorithm | ||
| 1206 | // expand scalar rhs to array when lhs is array (implicit broadcast in Modelica) | ||
| 1207 |
1/2✓ Branch 2 taken 532 times.
✗ Branch 3 not taken.
|
532 | rhs := if Type.isArray(Expression.typeOf(eqn.rhs)) then eqn.rhs else Expression.fillType(eqn.ty, eqn.rhs); |
| 1208 | 532 | tmp := ARRAY_ASSIGN(simCodeIndices.equationIndex, eqn.lhs, rhs, eqn.source, eqn.attr); | |
| 1209 | 532 | simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1; | |
| 1210 | then tmp; | ||
| 1211 | |||
| 1212 | case (BEquation.RECORD_EQUATION(), NBSolve.Status.EXPLICIT) algorithm | ||
| 1213 | 66 | (tmp, simCodeIndices) := createAlgorithm(eqn, simCodeIndices, equation_map); | |
| 1214 | then tmp; | ||
| 1215 | |||
| 1216 | case (BEquation.FOR_EQUATION(), NBSolve.Status.EXPLICIT) algorithm | ||
| 1217 | 1 | (tmp, simCodeIndices) := createAlgorithm(eqn, simCodeIndices, equation_map); | |
| 1218 | then tmp; | ||
| 1219 | |||
| 1220 | case (BEquation.WHEN_EQUATION(), NBSolve.Status.EXPLICIT) algorithm | ||
| 1221 | 64 | (tmp, simCodeIndices) := createWhenBody(eqn.body, eqn.source, eqn.attr, simCodeIndices); | |
| 1222 | then tmp; | ||
| 1223 | |||
| 1224 | case (BEquation.IF_EQUATION(), NBSolve.Status.EXPLICIT) algorithm | ||
| 1225 | ✗ | (branches, simCodeIndices) := createIfBody(eqn.body, {}, simCodeIndices, kind, simcode_map, equation_map); | |
| 1226 | ✗ | tmp := IF(simCodeIndices.equationIndex, listReverse(branches), eqn.source, eqn.attr); | |
| 1227 | ✗ | simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1; | |
| 1228 | then tmp; | ||
| 1229 | |||
| 1230 | case (BEquation.ALGORITHM(), NBSolve.Status.EXPLICIT) algorithm | ||
| 1231 | 57 | tmp := ALGORITHM(simCodeIndices.equationIndex, eqn.alg.statements, eqn.attr); | |
| 1232 | 57 | simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1; | |
| 1233 | then tmp; | ||
| 1234 | |||
| 1235 | // ToDo: add all other cases! | ||
| 1236 | |||
| 1237 | // fallback implicit solving | ||
| 1238 | case (_, NBSolve.Status.IMPLICIT) algorithm | ||
| 1239 | ✗ | (tmp, simCodeIndices) := createImplicitEquation(var, eqn, simCodeIndices, kind, simcode_map, equation_map); | |
| 1240 | then tmp; | ||
| 1241 | |||
| 1242 | else algorithm | ||
| 1243 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed with status " + Solve.statusString(status) + " for\n" + Equation.toString(eqn)}); | |
| 1244 | ✗ | then fail(); | |
| 1245 | |||
| 1246 | end match; | ||
| 1247 | 5543 | UnorderedMap.add(Equation.getEqnName(Pointer.create(eqn)), blck, equation_map); | |
| 1248 | end createEquation; | ||
| 1249 | |||
| 1250 | function createImplicitEquation | ||
| 1251 | "Creates a single implicit equation" | ||
| 1252 | input BVariable.Variable var; | ||
| 1253 | input Equation eqn; | ||
| 1254 | output Block blck; | ||
| 1255 | input output SimCodeIndices simCodeIndices; | ||
| 1256 | input Partition.Kind kind; | ||
| 1257 | input UnorderedMap<ComponentRef, SimVar> simcode_map; | ||
| 1258 | input UnorderedMap<ComponentRef, Block> equation_map; | ||
| 1259 | protected | ||
| 1260 | StrongComponent comp; | ||
| 1261 | Integer index; | ||
| 1262 | algorithm | ||
| 1263 | ✗ | (comp, index) := Tearing.implicit( | |
| 1264 | comp = StrongComponent.SINGLE_COMPONENT(Pointer.create(var), Pointer.create(eqn), NBSolve.Status.IMPLICIT), | ||
| 1265 | funcMap = UnorderedMap.new<Function>(AbsynUtil.pathHash, AbsynUtil.pathEqual), | ||
| 1266 | index = simCodeIndices.implicitIndex, | ||
| 1267 | kind = kind | ||
| 1268 | ); | ||
| 1269 | ✗ | simCodeIndices.implicitIndex := index; | |
| 1270 | ✗ | (blck, simCodeIndices) := fromStrongComponent(comp, simCodeIndices, kind, simcode_map, equation_map); | |
| 1271 | end createImplicitEquation; | ||
| 1272 | |||
| 1273 | function createWhenBody | ||
| 1274 | input WhenEquationBody body; | ||
| 1275 | output Block blck; | ||
| 1276 | input DAE.ElementSource source; | ||
| 1277 | input EquationAttributes attr; | ||
| 1278 | input output SimCodeIndices simCodeIndices; | ||
| 1279 | protected | ||
| 1280 | list<ComponentRef> conditions; | ||
| 1281 | list<WhenStatement> when_stmts; | ||
| 1282 | Option<WhenEquationBody> else_when; | ||
| 1283 | Block tmp; | ||
| 1284 | Option<Block> else_when_block; | ||
| 1285 | Integer index = simCodeIndices.equationIndex; | ||
| 1286 | algorithm | ||
| 1287 | 105 | simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1; | |
| 1288 | 105 | (conditions, when_stmts, else_when) := WhenEquationBody.getBodyAttributes(body); | |
| 1289 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 105 times.
✓ Branch 2 taken 41 times.
✓ Branch 3 taken 64 times.
|
105 | if isSome(else_when) then |
| 1290 | 41 | (tmp, simCodeIndices) := createWhenBody(Util.getOption(else_when), source, attr, simCodeIndices); | |
| 1291 | else_when_block := SOME(tmp); | ||
| 1292 | else | ||
| 1293 | else_when_block := NONE(); | ||
| 1294 | end if; | ||
| 1295 | 105 | blck := WHEN(index, false, conditions, when_stmts, else_when_block, source, attr); | |
| 1296 | end createWhenBody; | ||
| 1297 | |||
| 1298 | function createIfBody | ||
| 1299 | input IfEquationBody body; | ||
| 1300 | input output list<tuple<Expression, list<Block>>> branches; | ||
| 1301 | input output SimCodeIndices simCodeIndices; | ||
| 1302 | input Partition.Kind kind; | ||
| 1303 | input UnorderedMap<ComponentRef, SimVar> simcode_map; | ||
| 1304 | input UnorderedMap<ComponentRef, Block> equation_map; | ||
| 1305 | protected | ||
| 1306 | list<StrongComponent> comps; | ||
| 1307 | Block blck; | ||
| 1308 | list<Block> blcks = {}; | ||
| 1309 | algorithm | ||
| 1310 | ✗ | comps := list(StrongComponent.fromSolvedEquationSlice(Slice.SLICE(eqn, {})) for eqn in body.then_eqns); | |
| 1311 | |||
| 1312 | ✗ | for comp in listReverse(comps) loop | |
| 1313 | ✗ | (blck, simCodeIndices, _) := Block.fromStrongComponent(comp, simCodeIndices, kind, simcode_map, equation_map); | |
| 1314 | blcks := blck :: blcks; | ||
| 1315 | end for; | ||
| 1316 | |||
| 1317 | ✗ | branches := (body.condition, blcks) :: branches; | |
| 1318 | ✗ | if isSome(body.else_if) then | |
| 1319 | ✗ | (branches, simCodeIndices) := createIfBody(Util.getOption(body.else_if), branches, simCodeIndices, kind, simcode_map, equation_map); | |
| 1320 | end if; | ||
| 1321 | end createIfBody; | ||
| 1322 | |||
| 1323 | function createAlgorithm | ||
| 1324 | input Equation eqn; | ||
| 1325 | output Block blck; | ||
| 1326 | input output SimCodeIndices indices; | ||
| 1327 | input UnorderedMap<ComponentRef, Block> equation_map; | ||
| 1328 | protected | ||
| 1329 | list<Statement> stmts; | ||
| 1330 | algorithm | ||
| 1331 | stmts := match eqn | ||
| 1332 | 254 | case Equation.ALGORITHM() then eqn.alg.statements; | |
| 1333 | 96 | else Equation.toStatement(eqn); | |
| 1334 | end match; | ||
| 1335 | |||
| 1336 | 350 | blck := ALGORITHM(indices.equationIndex, stmts, Equation.getAttributes(eqn)); | |
| 1337 | 350 | indices.equationIndex := indices.equationIndex + 1; | |
| 1338 | 350 | UnorderedMap.add(Equation.getEqnName(Pointer.create(eqn)), blck, equation_map); | |
| 1339 | end createAlgorithm; | ||
| 1340 | |||
| 1341 | function createAssignment | ||
| 1342 | "Creates an assignment equation." | ||
| 1343 | input Equation eqn; | ||
| 1344 | output Block blck; | ||
| 1345 | input output SimCodeIndices simCodeIndices; | ||
| 1346 | algorithm | ||
| 1347 | blck := match eqn | ||
| 1348 | local | ||
| 1349 | Equation qual; | ||
| 1350 | Operator operator; | ||
| 1351 | ComponentRef cref; | ||
| 1352 | Expression lhs, rhs; | ||
| 1353 | Block tmp; | ||
| 1354 | |||
| 1355 | case qual as BEquation.SCALAR_EQUATION(lhs = Expression.CREF(cref = cref)) | ||
| 1356 | algorithm | ||
| 1357 | ✗ | tmp := SIMPLE_ASSIGN(simCodeIndices.equationIndex, cref, qual.rhs, qual.source, qual.attr); | |
| 1358 | ✗ | simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1; | |
| 1359 | then tmp; | ||
| 1360 | |||
| 1361 | case qual as BEquation.ARRAY_EQUATION(lhs = Expression.CREF(cref = cref)) | ||
| 1362 | algorithm | ||
| 1363 | ✗ | tmp := SIMPLE_ASSIGN(simCodeIndices.equationIndex, cref, qual.rhs, qual.source, qual.attr); | |
| 1364 | ✗ | simCodeIndices.equationIndex := simCodeIndices.equationIndex + 1; | |
| 1365 | then tmp; | ||
| 1366 | |||
| 1367 | // ToDo: add all other cases! | ||
| 1368 | |||
| 1369 | else algorithm | ||
| 1370 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for\n" + Equation.toString(eqn)}); | |
| 1371 | ✗ | then fail(); | |
| 1372 | |||
| 1373 | end match; | ||
| 1374 | end createAssignment; | ||
| 1375 | |||
| 1376 | function collectAlgebraicLoops | ||
| 1377 | input list<list<Block>> blcks; | ||
| 1378 | input output list<Block> linearLoops; | ||
| 1379 | input output list<Block> nonlinearLoops; | ||
| 1380 | input output list<SimJacobian> jacobians; | ||
| 1381 | input output SimCodeIndices simCodeIndices; | ||
| 1382 | input UnorderedMap<ComponentRef, SimVar> simcode_map; | ||
| 1383 | algorithm | ||
| 1384 |
2/2✓ Branch 0 taken 710 times.
✓ Branch 1 taken 565 times.
|
1275 | for blck_lst in blcks loop |
| 1385 | 710 | (linearLoops, nonlinearLoops, jacobians, simCodeIndices) := collectAlgebraicLoopsSingle(blck_lst, linearLoops, nonlinearLoops, jacobians, simCodeIndices, simcode_map); | |
| 1386 | end for; | ||
| 1387 | end collectAlgebraicLoops; | ||
| 1388 | |||
| 1389 | function collectAlgebraicLoopsSingle | ||
| 1390 | input list<Block> blck_lst; | ||
| 1391 | input output list<Block> linearLoops; | ||
| 1392 | input output list<Block> nonlinearLoops; | ||
| 1393 | input output list<SimJacobian> jacobians; | ||
| 1394 | input output SimCodeIndices simCodeIndices; | ||
| 1395 | input UnorderedMap<ComponentRef, SimVar> simcode_map; | ||
| 1396 | algorithm | ||
| 1397 |
5/5✓ Branch 0 taken 16 times.
✓ Branch 1 taken 69 times.
✓ Branch 2 taken 6176 times.
✓ Branch 3 taken 6261 times.
✓ Branch 4 taken 710 times.
|
6971 | for blck in blck_lst loop |
| 1398 | (linearLoops, nonlinearLoops) := match blck | ||
| 1399 | local | ||
| 1400 | Option<SimJacobian> opt_jacobian; | ||
| 1401 | SimJacobian jacobian; | ||
| 1402 | |||
| 1403 | case LINEAR() algorithm | ||
| 1404 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
|
16 | if isSome(blck.system.jacobian) then |
| 1405 | 16 | jacobians := Util.getOption(blck.system.jacobian) :: jacobians; | |
| 1406 | end if; | ||
| 1407 | then (blck :: linearLoops, nonlinearLoops); | ||
| 1408 | case NONLINEAR() algorithm | ||
| 1409 | 69 | opt_jacobian := NonlinearSystem.getJacobian(blck.system); | |
| 1410 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 69 times.
✓ Branch 2 taken 69 times.
✗ Branch 3 not taken.
|
69 | if isSome(opt_jacobian) then |
| 1411 | 69 | jacobian := Util.getOption(opt_jacobian); | |
| 1412 | jacobians := jacobian :: jacobians; | ||
| 1413 | end if; | ||
| 1414 | 69 | blck.system := NonlinearSystem.setJacobian(blck.system, opt_jacobian); | |
| 1415 | then (linearLoops, blck :: nonlinearLoops); | ||
| 1416 | else (linearLoops, nonlinearLoops); | ||
| 1417 | end match; | ||
| 1418 | end for; | ||
| 1419 | end collectAlgebraicLoopsSingle; | ||
| 1420 | |||
| 1421 | function convert | ||
| 1422 | input Block blck; | ||
| 1423 | output OldSimCode.SimEqSystem oldBlck; | ||
| 1424 | algorithm | ||
| 1425 | oldBlck := match blck | ||
| 1426 | local | ||
| 1427 | Expression exp; | ||
| 1428 | list<Block> blcks; | ||
| 1429 | list<tuple<DAE.Exp, list<OldSimCode.SimEqSystem>>> oldBranches = {}; | ||
| 1430 | list<OldSimCode.SimEqSystem> else_branch = {}; | ||
| 1431 | |||
| 1432 | 1500 | case RESIDUAL() then OldSimCode.SES_RESIDUAL(blck.index, blck.res_index, Expression.toDAE(blck.exp), blck.source, EquationAttributes.convert(blck.attr)); | |
| 1433 | 20 | case ARRAY_RESIDUAL() then OldSimCode.SES_RESIDUAL(blck.index, blck.res_index, Expression.toDAE(blck.exp), blck.source, EquationAttributes.convert(blck.attr)); | |
| 1434 |
4/4✓ Branch 0 taken 45 times.
✓ Branch 1 taken 31 times.
✓ Branch 2 taken 45 times.
✓ Branch 3 taken 31 times.
|
76 | case FOR_RESIDUAL() then OldSimCode.SES_FOR_RESIDUAL(blck.index, blck.res_index, list(SimIterator.convert(it) for it in blck.iterators), Expression.toDAE(blck.exp), blck.source, EquationAttributes.convert(blck.attr)); |
| 1435 | ✗ | case GENERIC_RESIDUAL() then OldSimCode.SES_GENERIC_RESIDUAL(blck.index, blck.res_index, blck.scal_indices, list(SimIterator.convert(it) for it in blck.iterators), Expression.toDAE(blck.exp), blck.source, EquationAttributes.convert(blck.attr)); | |
| 1436 | 7840 | case SIMPLE_ASSIGN() then OldSimCode.SES_SIMPLE_ASSIGN(blck.index, ComponentRef.toDAE(blck.lhs), Expression.toDAE(blck.rhs), blck.source, EquationAttributes.convert(blck.attr)); | |
| 1437 | 652 | case ARRAY_ASSIGN() then OldSimCode.SES_ARRAY_CALL_ASSIGN(blck.index, Expression.toDAE(blck.lhs), Expression.toDAE(blck.rhs), blck.source, EquationAttributes.convert(blck.attr)); | |
| 1438 |
4/4✓ Branch 0 taken 696 times.
✓ Branch 1 taken 598 times.
✓ Branch 2 taken 696 times.
✓ Branch 3 taken 598 times.
|
1294 | case RESIZABLE_ASSIGN() then OldSimCode.SES_RESIZABLE_ASSIGN(blck.index, blck.call_index, list(SimIterator.convert(it) for it in blck.iters), blck.source, EquationAttributes.convert(blck.attr)); |
| 1439 | 59 | case GENERIC_ASSIGN() then OldSimCode.SES_GENERIC_ASSIGN(blck.index, blck.call_index, blck.scal_indices, blck.source, EquationAttributes.convert(blck.attr)); | |
| 1440 |
4/4✓ Branch 0 taken 9 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 3 times.
|
12 | case ENTWINED_ASSIGN() then OldSimCode.SES_ENTWINED_ASSIGN(blck.index, blck.call_order, list(convert(single_call) for single_call in blck.single_calls), blck.source, EquationAttributes.convert(blck.attr)); |
| 1441 | case IF() algorithm | ||
| 1442 | ✗ | for branch in blck.branches loop | |
| 1443 | ✗ | (exp, blcks) := branch; | |
| 1444 | ✗ | if Expression.isEnd(exp) then | |
| 1445 | ✗ | if listEmpty(else_branch) then | |
| 1446 | ✗ | else_branch := list(convert(blck_) for blck_ in blcks); | |
| 1447 | else | ||
| 1448 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because there is | |
| 1449 | at least two non-conditional branches in:\n" + Block.toString(blck)}); | ||
| 1450 | ✗ | fail(); | |
| 1451 | end if; | ||
| 1452 | elseif listEmpty(else_branch) then | ||
| 1453 | ✗ | oldBranches := (Expression.toDAE(exp), list(convert(blck_) for blck_ in blcks)) :: oldBranches; | |
| 1454 | else | ||
| 1455 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because there is a | |
| 1456 | conditional branch after a non-conditional branch in:\n" + Block.toString(blck)}); | ||
| 1457 | ✗ | fail(); | |
| 1458 | end if; | ||
| 1459 | end for; | ||
| 1460 | ✗ | if listEmpty(else_branch) then | |
| 1461 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because there " | |
| 1462 | + "is no non-conditional branch in:\n" + Block.toString(blck)}); | ||
| 1463 | ✗ | fail(); | |
| 1464 | end if; | ||
| 1465 | ✗ | then OldSimCode.SES_IFEQUATION( | |
| 1466 | index = blck.index, | ||
| 1467 | ifbranches = listReverse(oldBranches), | ||
| 1468 | elsebranch = else_branch, | ||
| 1469 | source = blck.source, | ||
| 1470 | eqAttr = EquationAttributes.convert(blck.attr) | ||
| 1471 | ); | ||
| 1472 | |||
| 1473 |
8/8✓ Branch 0 taken 132 times.
✓ Branch 1 taken 123 times.
✓ Branch 2 taken 132 times.
✓ Branch 3 taken 123 times.
✓ Branch 5 taken 123 times.
✓ Branch 6 taken 123 times.
✓ Branch 7 taken 123 times.
✓ Branch 8 taken 123 times.
|
378 | case WHEN() then OldSimCode.SES_WHEN( |
| 1474 | index = blck.index, | ||
| 1475 | conditions = list(ComponentRef.toDAE(cr) for cr in blck.conditions), | ||
| 1476 | initialCall = blck.initialCall, | ||
| 1477 | whenStmtLst = list(WhenStatement.convert(stmt) for stmt in blck.when_stmts), | ||
| 1478 | elseWhen = Util.applyOption(blck.else_when, convert), | ||
| 1479 | source = blck.source, | ||
| 1480 | eqAttr = EquationAttributes.convert(blck.attr) | ||
| 1481 | ); | ||
| 1482 | |||
| 1483 | 39 | case LINEAR() then OldSimCode.SES_LINEAR(LinearSystem.convert(blck.system), NONE(), EquationAttributes.convert(EquationAttributes.default(EquationKind.CONTINUOUS, false)) /* dangerous! */); | |
| 1484 | |||
| 1485 | 166 | case NONLINEAR() then OldSimCode.SES_NONLINEAR(NonlinearSystem.convert(blck.system), NONE(), EquationAttributes.convert(EquationAttributes.default(EquationKind.CONTINUOUS, false)) /* dangerous! */); | |
| 1486 | |||
| 1487 | 972 | case ALGORITHM() then OldSimCode.SES_ALGORITHM(blck.index, NSimGenericCall.setRelationAsubStatements(ConvertDAE.convertStatements(blck.stmts)), EquationAttributes.convert(blck.attr)); | |
| 1488 | |||
| 1489 | 5859 | case ALIAS() guard(blck.aliasOf > 0) then OldSimCode.SES_ALIAS(blck.index, blck.aliasOf); | |
| 1490 | |||
| 1491 | // ToDo: add all the other cases here! | ||
| 1492 | |||
| 1493 | |||
| 1494 | case ALIAS() guard(blck.aliasOf == -1) algorithm | ||
| 1495 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for following alias block because the index has not been updated:\n" + toString(blck)}); | |
| 1496 | ✗ | then fail(); | |
| 1497 | |||
| 1498 | else algorithm | ||
| 1499 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for\n" + toString(blck)}); | |
| 1500 | ✗ | then fail(); | |
| 1501 | end match; | ||
| 1502 | end convert; | ||
| 1503 | |||
| 1504 | function convertList | ||
| 1505 | input list<Block> blck_lst; | ||
| 1506 | output list<OldSimCode.SimEqSystem> oldBlck_lst = list(convert(blck) for blck in blck_lst); | ||
| 1507 | end convertList; | ||
| 1508 | |||
| 1509 | function convertListList | ||
| 1510 | input list<list<Block>> blck_lst_lst; | ||
| 1511 | output list<list<OldSimCode.SimEqSystem>> oldBlck_lst_lst = list(convertList(blck_lst) for blck_lst in blck_lst_lst); | ||
| 1512 | end convertListList; | ||
| 1513 | |||
| 1514 | function fixIndices | ||
| 1515 | input list<Block> blcks; | ||
| 1516 | input output list<Block> acc; | ||
| 1517 | input output SimCodeIndices indices; | ||
| 1518 | algorithm | ||
| 1519 | (acc, indices) := match blcks | ||
| 1520 | local | ||
| 1521 | Block blck; | ||
| 1522 | list<Block> rest; | ||
| 1523 | case blck :: rest algorithm | ||
| 1524 | ✗ | (blck, indices) := fixIndex(blck, indices); | |
| 1525 | ✗ | then fixIndices(rest, blck :: acc, indices); | |
| 1526 | else (acc, indices); | ||
| 1527 | end match; | ||
| 1528 | end fixIndices; | ||
| 1529 | |||
| 1530 | function fixIndex | ||
| 1531 | input output Block blck; | ||
| 1532 | input output SimCodeIndices indices; | ||
| 1533 | algorithm | ||
| 1534 | blck := match blck | ||
| 1535 | local | ||
| 1536 | Block tmp; | ||
| 1537 | list<Block> tmp_lst; | ||
| 1538 | |||
| 1539 | case RESIDUAL() algorithm | ||
| 1540 | ✗ | blck.index := indices.equationIndex; | |
| 1541 | ✗ | indices.equationIndex := indices.equationIndex + 1; | |
| 1542 | then blck; | ||
| 1543 | |||
| 1544 | case ARRAY_RESIDUAL() algorithm | ||
| 1545 | ✗ | blck.index := indices.equationIndex; | |
| 1546 | ✗ | indices.equationIndex := indices.equationIndex + 1; | |
| 1547 | then blck; | ||
| 1548 | |||
| 1549 | case SIMPLE_ASSIGN() algorithm | ||
| 1550 | ✗ | blck.index := indices.equationIndex; | |
| 1551 | ✗ | indices.equationIndex := indices.equationIndex + 1; | |
| 1552 | then blck; | ||
| 1553 | |||
| 1554 | case ARRAY_ASSIGN() algorithm | ||
| 1555 | ✗ | blck.index := indices.equationIndex; | |
| 1556 | ✗ | indices.equationIndex := indices.equationIndex + 1; | |
| 1557 | then blck; | ||
| 1558 | |||
| 1559 | case RESIZABLE_ASSIGN() algorithm | ||
| 1560 | ✗ | blck.index := indices.equationIndex; | |
| 1561 | ✗ | indices.equationIndex := indices.equationIndex + 1; | |
| 1562 | then blck; | ||
| 1563 | |||
| 1564 | case GENERIC_ASSIGN() algorithm | ||
| 1565 | ✗ | blck.index := indices.equationIndex; | |
| 1566 | ✗ | indices.equationIndex := indices.equationIndex + 1; | |
| 1567 | then blck; | ||
| 1568 | |||
| 1569 | case ALIAS() algorithm | ||
| 1570 | ✗ | blck.index := indices.equationIndex; | |
| 1571 | ✗ | indices.equationIndex := indices.equationIndex + 1; | |
| 1572 | then blck; | ||
| 1573 | |||
| 1574 | case ALGORITHM() algorithm | ||
| 1575 | ✗ | blck.index := indices.equationIndex; | |
| 1576 | ✗ | indices.equationIndex := indices.equationIndex + 1; | |
| 1577 | then blck; | ||
| 1578 | |||
| 1579 | case INVERSE_ALGORITHM() algorithm | ||
| 1580 | ✗ | blck.index := indices.equationIndex; | |
| 1581 | ✗ | indices.equationIndex := indices.equationIndex + 1; | |
| 1582 | then blck; | ||
| 1583 | |||
| 1584 | case IF() algorithm | ||
| 1585 | ✗ | blck.index := indices.equationIndex; | |
| 1586 | ✗ | indices.equationIndex := indices.equationIndex + 1; | |
| 1587 | then blck; | ||
| 1588 | |||
| 1589 | case WHEN() algorithm | ||
| 1590 | ✗ | blck.index := indices.equationIndex; | |
| 1591 | ✗ | indices.equationIndex := indices.equationIndex + 1; | |
| 1592 | ✗ | if isSome(blck.else_when) then | |
| 1593 | ✗ | (tmp, indices) := fixIndex(Util.getOption(blck.else_when), indices); | |
| 1594 | ✗ | blck.else_when := SOME(tmp); | |
| 1595 | end if; | ||
| 1596 | then blck; | ||
| 1597 | |||
| 1598 | case LINEAR() algorithm | ||
| 1599 | // TODO (these are not really necessary i suppose) | ||
| 1600 | then blck; | ||
| 1601 | |||
| 1602 | case NONLINEAR() algorithm | ||
| 1603 | // TODO (these are not really necessary i suppose) | ||
| 1604 | then blck; | ||
| 1605 | |||
| 1606 | case HYBRID() algorithm | ||
| 1607 | ✗ | (tmp, indices) := fixIndex(blck.continuous, indices); | |
| 1608 | ✗ | (tmp_lst, indices) := fixIndices(blck.discreteEqs, {}, indices); | |
| 1609 | ✗ | blck.continuous := tmp; | |
| 1610 | ✗ | blck.discreteEqs := tmp_lst; | |
| 1611 | then blck; | ||
| 1612 | |||
| 1613 | else algorithm | ||
| 1614 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for\n" + toString(blck)}); | |
| 1615 | ✗ | then fail(); | |
| 1616 | end match; | ||
| 1617 | end fixIndex; | ||
| 1618 | |||
| 1619 | function collectEntwinedEquations | ||
| 1620 | "collects entwined equations from initial blocks" | ||
| 1621 | input Block blck; | ||
| 1622 | output list<Block> lst; | ||
| 1623 | algorithm | ||
| 1624 | lst := match blck | ||
| 1625 | 1 | case ENTWINED_ASSIGN() then blck.single_calls; | |
| 1626 | else {}; | ||
| 1627 | end match; | ||
| 1628 | end collectEntwinedEquations; | ||
| 1629 | protected | ||
| 1630 | function whenString | ||
| 1631 | input list<ComponentRef> conditions; | ||
| 1632 | input list<WhenStatement> when_stmts; | ||
| 1633 | input Option<Block> else_when; | ||
| 1634 | input output String str = ""; | ||
| 1635 | protected | ||
| 1636 | String indent = str; | ||
| 1637 | algorithm | ||
| 1638 | ✗ | str := "when " + List.toString(conditions, ComponentRef.toString) + "\n" + | |
| 1639 | List.toString(when_stmts, function WhenStatement.toString(str = indent + "\t"), List.Style.NEWLINE) + "\n"; | ||
| 1640 | ✗ | if isSome(else_when) then | |
| 1641 | ✗ | str := str + indent + "else" + toString(Util.getOption(else_when)); | |
| 1642 | else | ||
| 1643 | ✗ | str := str + indent + "end when;\n"; | |
| 1644 | end if; | ||
| 1645 | end whenString; | ||
| 1646 | |||
| 1647 | function getGenericAssignIndex | ||
| 1648 | input Block blck; | ||
| 1649 | output Integer index; | ||
| 1650 | algorithm | ||
| 1651 | index := match blck | ||
| 1652 | ✗ | case RESIZABLE_ASSIGN() then blck.call_index; | |
| 1653 | ✗ | case GENERIC_ASSIGN() then blck.call_index; | |
| 1654 | else algorithm | ||
| 1655 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for\n" + toString(blck)}); | |
| 1656 | ✗ | then fail(); | |
| 1657 | end match; | ||
| 1658 | end getGenericAssignIndex; | ||
| 1659 | |||
| 1660 | function getGenericEquationName | ||
| 1661 | input StrongComponent comp; | ||
| 1662 | output ComponentRef name; | ||
| 1663 | algorithm | ||
| 1664 | name := match comp | ||
| 1665 | ✗ | case StrongComponent.GENERIC_COMPONENT() then Equation.getEqnName(Slice.getT(comp.eqn)); | |
| 1666 | else algorithm | ||
| 1667 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for\n" + StrongComponent.toString(comp)}); | |
| 1668 | ✗ | then fail(); | |
| 1669 | end match; | ||
| 1670 | end getGenericEquationName; | ||
| 1671 | |||
| 1672 | function getEntwinedEquationName | ||
| 1673 | "Returns the equation name for any slice type that can appear in an ENTWINED_COMPONENT." | ||
| 1674 | input StrongComponent comp; | ||
| 1675 | output ComponentRef name; | ||
| 1676 | algorithm | ||
| 1677 | name := match comp | ||
| 1678 | ✗ | case StrongComponent.SINGLE_COMPONENT() then Equation.getEqnName(comp.eqn); | |
| 1679 | ✗ | case StrongComponent.MULTI_COMPONENT() then Equation.getEqnName(Slice.getT(comp.eqn)); | |
| 1680 | ✗ | case StrongComponent.SLICED_COMPONENT() then Equation.getEqnName(Slice.getT(comp.eqn)); | |
| 1681 | 6 | case StrongComponent.GENERIC_COMPONENT() then Equation.getEqnName(Slice.getT(comp.eqn)); | |
| 1682 | ✗ | case StrongComponent.RESIZABLE_COMPONENT() then Equation.getEqnName(Slice.getT(comp.eqn)); | |
| 1683 | else algorithm | ||
| 1684 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for\n" + StrongComponent.toString(comp)}); | |
| 1685 | ✗ | then fail(); | |
| 1686 | end match; | ||
| 1687 | end getEntwinedEquationName; | ||
| 1688 | end Block; | ||
| 1689 | |||
| 1690 | uniontype LinearSystem | ||
| 1691 | record LINEAR_SYSTEM | ||
| 1692 | Integer index; | ||
| 1693 | Boolean mixed; | ||
| 1694 | Boolean torn; | ||
| 1695 | list<SimVar> vars; | ||
| 1696 | list<Expression> beqs; //ToDo what is this? binding expressions? | ||
| 1697 | list<tuple<Integer, Integer, Block>> simJac; // ToDo: is this the old jacobian structure? | ||
| 1698 | /* solver linear tearing system */ | ||
| 1699 | list<Block> residual; | ||
| 1700 | Option<SimJacobian> jacobian; | ||
| 1701 | list<DAE.ElementSource> sources; | ||
| 1702 | Integer indexSystem; | ||
| 1703 | Integer size "Number of variables that are solved in this system. Needed because 'crefs' only contains the iteration variables."; | ||
| 1704 | Boolean partOfJac "if TRUE then this system is part of a jacobian matrix"; | ||
| 1705 | end LINEAR_SYSTEM; | ||
| 1706 | |||
| 1707 | function toString | ||
| 1708 | input LinearSystem system; | ||
| 1709 | input output String str; | ||
| 1710 | algorithm | ||
| 1711 |
3/6✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 7 taken 2 times.
✗ Branch 8 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 2 times.
|
6 | str := "Linear System (size = " + intString(system.size) + ", jacobian = " + boolString(system.partOfJac) + ", mixed = " + boolString(system.mixed) + ", torn = " + boolString(system.torn) + ")\n" + Block.listToString(system.residual, str + "--"); |
| 1712 | end toString; | ||
| 1713 | |||
| 1714 | function convert | ||
| 1715 | input LinearSystem system; | ||
| 1716 | output OldSimCode.LinearSystem oldSystem; | ||
| 1717 | algorithm | ||
| 1718 | 39 | oldSystem := OldSimCode.LINEARSYSTEM( | |
| 1719 | index = system.index, | ||
| 1720 | partOfMixed = system.mixed, | ||
| 1721 | tornSystem = system.torn, | ||
| 1722 | vars = SimVar.convertList(system.vars), | ||
| 1723 | beqs = {}, | ||
| 1724 | simJac = {}, | ||
| 1725 | residual = Block.convertList(system.residual), | ||
| 1726 | jacobianMatrix = Util.applyOption(system.jacobian, SimJacobian.convert), | ||
| 1727 | sources = system.sources, | ||
| 1728 | indexLinearSystem = system.indexSystem, | ||
| 1729 | nUnknowns = system.size, | ||
| 1730 | partOfJac = system.partOfJac | ||
| 1731 | ); | ||
| 1732 | end convert; | ||
| 1733 | end LinearSystem; | ||
| 1734 | |||
| 1735 | uniontype NonlinearSystem | ||
| 1736 | record NONLINEAR_SYSTEM | ||
| 1737 | Integer index; | ||
| 1738 | list<Block> blcks "equations"; | ||
| 1739 | list<ComponentRef> crefs "iteration variables"; | ||
| 1740 | Integer indexSystem; | ||
| 1741 | Integer size "Number of variables that are solved in this system. Needed because 'crefs' only contains the iteration variables."; | ||
| 1742 | Pointer<Option<SimJacobian>> jacobian; | ||
| 1743 | Boolean homotopy; | ||
| 1744 | Boolean mixed; | ||
| 1745 | Boolean torn; | ||
| 1746 | end NONLINEAR_SYSTEM; | ||
| 1747 | |||
| 1748 | function getJacobian | ||
| 1749 | input NonlinearSystem syst; | ||
| 1750 | output Option<SimJacobian> jacobian = Pointer.access(syst.jacobian); | ||
| 1751 | end getJacobian; | ||
| 1752 | |||
| 1753 | function setJacobian | ||
| 1754 | input output NonlinearSystem syst; | ||
| 1755 | input Option<SimJacobian> jacobian; | ||
| 1756 | algorithm | ||
| 1757 | 69 | Pointer.update(syst.jacobian, jacobian); | |
| 1758 | end setJacobian; | ||
| 1759 | |||
| 1760 | function toString | ||
| 1761 | input NonlinearSystem system; | ||
| 1762 | input output String str; | ||
| 1763 | algorithm | ||
| 1764 |
4/6✓ Branch 3 taken 7 times.
✓ Branch 4 taken 4 times.
✓ Branch 7 taken 11 times.
✗ Branch 8 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 11 times.
|
29 | str := "Nonlinear System (size = " + intString(system.size) + ", homotopy = " + boolString(system.homotopy) |
| 1765 | + ", mixed = " + boolString(system.mixed) + ", torn = " + boolString(system.torn) + ")\n" | ||
| 1766 | + str + "--" + List.toStringCustom(system.crefs, ComponentRef.toString, "Iteration Vars:", "{", ", ", "}", true, 10) + "\n" | ||
| 1767 | + Block.listToString(system.blcks, str + "--"); | ||
| 1768 | end toString; | ||
| 1769 | |||
| 1770 | function convert | ||
| 1771 | input NonlinearSystem system; | ||
| 1772 | output OldSimCode.NonlinearSystem oldSystem; | ||
| 1773 | protected | ||
| 1774 | list<DAE.ComponentRef> crefs = {}; | ||
| 1775 | algorithm | ||
| 1776 |
2/2✓ Branch 0 taken 727 times.
✓ Branch 1 taken 166 times.
|
893 | for cref in system.crefs loop |
| 1777 | 727 | crefs := ComponentRef.toDAE(cref) :: crefs; | |
| 1778 | end for; | ||
| 1779 | 166 | oldSystem := OldSimCode.NONLINEARSYSTEM( | |
| 1780 | index = system.index, | ||
| 1781 | eqs = Block.convertList(system.blcks), | ||
| 1782 | crefs = listReverse(crefs), | ||
| 1783 | indexNonLinearSystem = system.indexSystem, | ||
| 1784 | nUnknowns = system.size, | ||
| 1785 | jacobianMatrix = Util.applyOption(Pointer.access(system.jacobian), SimJacobian.convert), // ToDo update this! | ||
| 1786 | homotopySupport = system.homotopy, | ||
| 1787 | mixedSystem = system.mixed, | ||
| 1788 | tornSystem = system.torn, | ||
| 1789 | clockIndex = NONE() // ToDo update this | ||
| 1790 | ); | ||
| 1791 | end convert; | ||
| 1792 | end NonlinearSystem; | ||
| 1793 | |||
| 1794 | annotation(__OpenModelica_Interface="nbackend"); | ||
| 1795 | end NSimStrongComponent; | ||
| 1796 |