OMCompiler/Compiler/NBackEnd/Classes/NBStrongComponent.mo
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * This file is part of OpenModelica. | ||
| 3 | * | ||
| 4 | * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC), | ||
| 5 | * c/o Linköpings universitet, Department of Computer and Information Science, | ||
| 6 | * SE-58183 Linköping, Sweden. | ||
| 7 | * | ||
| 8 | * All rights reserved. | ||
| 9 | * | ||
| 10 | * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR | ||
| 11 | * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8. | ||
| 12 | * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES | ||
| 13 | * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL | ||
| 14 | * VERSION 3, ACCORDING TO RECIPIENTS CHOICE. | ||
| 15 | * | ||
| 16 | * The OpenModelica software and the OSMC (Open Source Modelica Consortium) | ||
| 17 | * Public License (OSMC-PL) are obtained from OSMC, either from the above | ||
| 18 | * address, from the URLs: | ||
| 19 | * http://www.openmodelica.org or | ||
| 20 | * https://github.com/OpenModelica/ or | ||
| 21 | * http://www.ida.liu.se/projects/OpenModelica, | ||
| 22 | * and in the OpenModelica distribution. | ||
| 23 | * | ||
| 24 | * GNU AGPL version 3 is obtained from: | ||
| 25 | * https://www.gnu.org/licenses/licenses.html#GPL | ||
| 26 | * | ||
| 27 | * This program is distributed WITHOUT ANY WARRANTY; without | ||
| 28 | * even the implied warranty of MERCHANTABILITY or FITNESS | ||
| 29 | * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH | ||
| 30 | * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL. | ||
| 31 | * | ||
| 32 | * See the full OSMC Public License conditions for more details. | ||
| 33 | * | ||
| 34 | */ | ||
| 35 | |||
| 36 | encapsulated uniontype NBStrongComponent | ||
| 37 | "file: NBStrongComponent.mo | ||
| 38 | package: NBStrongComponent | ||
| 39 | description: This file contains the data-types used save the strong Component | ||
| 40 | data after causalization. | ||
| 41 | " | ||
| 42 | public | ||
| 43 | import NBResizable.EvalOrder; | ||
| 44 | |||
| 45 | protected | ||
| 46 | // selfimport | ||
| 47 | import StrongComponent = NBStrongComponent; | ||
| 48 | |||
| 49 | // NF imports | ||
| 50 | import ComponentRef = NFComponentRef; | ||
| 51 | import Dimension = NFDimension; | ||
| 52 | import Expression = NFExpression; | ||
| 53 | import Subscript = NFSubscript; | ||
| 54 | import Type = NFType; | ||
| 55 | import Variable = NFVariable; | ||
| 56 | |||
| 57 | // Backend imports | ||
| 58 | import Adjacency = NBAdjacency; | ||
| 59 | import NBAdjacency.Mapping; | ||
| 60 | import BackendDAE = NBackendDAE; | ||
| 61 | import Causalize = NBCausalize; | ||
| 62 | import BVariable = NBVariable; | ||
| 63 | import NBEquation.{Equation, EquationPointer, EquationPointers, EquationAttributes, Iterator, IfEquationBody}; | ||
| 64 | import Initialization = NBInitialization; | ||
| 65 | import Inline = NBInline; | ||
| 66 | import NBJacobian.JacobianType; | ||
| 67 | import Matching = NBMatching; | ||
| 68 | import Resizable = NBResizable; | ||
| 69 | import Solve = NBSolve; | ||
| 70 | import Sorting = NBSorting; | ||
| 71 | import NBSorting.SuperNode; | ||
| 72 | import BPartition = NBPartition; | ||
| 73 | import NBPartition.{Partition}; | ||
| 74 | import Tearing = NBTearing; | ||
| 75 | import NBVariable.{VariablePointer, VariablePointers}; | ||
| 76 | |||
| 77 | // Util imports | ||
| 78 | import Pointer; | ||
| 79 | import Slice = NBSlice; | ||
| 80 | import StringUtil; | ||
| 81 | import UnorderedMap; | ||
| 82 | import UnorderedSet; | ||
| 83 | |||
| 84 | public | ||
| 85 | uniontype AliasInfo | ||
| 86 | record ALIAS_INFO | ||
| 87 | BPartition.Kind kind "The partition kind"; | ||
| 88 | Integer partitionIndex "the partition index"; | ||
| 89 | Integer componentIndex "The index in that strong component array"; | ||
| 90 | end ALIAS_INFO; | ||
| 91 | |||
| 92 | function toString | ||
| 93 | input AliasInfo info; | ||
| 94 | output String str = Partition.kindToString(info.kind) + "[" + intString(info.partitionIndex) + " | " + intString(info.componentIndex) + "]"; | ||
| 95 | end toString; | ||
| 96 | |||
| 97 | function hash | ||
| 98 | input AliasInfo info; | ||
| 99 | output Integer i = stringHashDjb2(toString(info)); | ||
| 100 | end hash; | ||
| 101 | |||
| 102 | function isEqual | ||
| 103 | input AliasInfo info1; | ||
| 104 | input AliasInfo info2; | ||
| 105 | output Boolean b = (info1.componentIndex == info2.componentIndex) and (info1.partitionIndex == info2.partitionIndex) and (info1.kind == info2.kind); | ||
| 106 | end isEqual; | ||
| 107 | end AliasInfo; | ||
| 108 | |||
| 109 | record SINGLE_COMPONENT | ||
| 110 | "component for all equations that solve for a single (possibly multidimensional) variable | ||
| 111 | SCALAR_EQUATION, ARRAY_EQUATION, RECORD_EQUATION." | ||
| 112 | Pointer<Variable> var; | ||
| 113 | Pointer<Equation> eqn; | ||
| 114 | Solve.Status status; | ||
| 115 | end SINGLE_COMPONENT; | ||
| 116 | |||
| 117 | record MULTI_COMPONENT | ||
| 118 | "component for all equations that can solve for more than one variable instance | ||
| 119 | ALGORITHM, WHEN_EQUATION, IF_EQUATION" | ||
| 120 | list<Slice<VariablePointer>> vars; | ||
| 121 | Slice<EquationPointer> eqn; | ||
| 122 | Solve.Status status; | ||
| 123 | end MULTI_COMPONENT; | ||
| 124 | |||
| 125 | record SLICED_COMPONENT | ||
| 126 | "component for all equations AND/OR variables that need to be sliced (zero based indices)" | ||
| 127 | ComponentRef var_cref "cref to solve for"; | ||
| 128 | Slice<VariablePointer> var "sliced variable"; | ||
| 129 | Slice<EquationPointer> eqn "sliced equation"; | ||
| 130 | Solve.Status status; | ||
| 131 | end SLICED_COMPONENT; | ||
| 132 | |||
| 133 | record RESIZABLE_COMPONENT | ||
| 134 | "component for for-equations with trivial evaluation order" | ||
| 135 | ComponentRef var_cref "cref to solve for"; | ||
| 136 | Slice<VariablePointer> var "sliced variable"; | ||
| 137 | Slice<EquationPointer> eqn "sliced equation"; | ||
| 138 | UnorderedMap<ComponentRef, EvalOrder> order "independent, forward, backward"; | ||
| 139 | Solve.Status status; | ||
| 140 | end RESIZABLE_COMPONENT; | ||
| 141 | |||
| 142 | record GENERIC_COMPONENT | ||
| 143 | "component for all equations that need to be sliced but where no for-loop could be recovered | ||
| 144 | has no status since this is generated by the Solve module and is always status=EXPLICIT." | ||
| 145 | ComponentRef var_cref "cref to solve for"; | ||
| 146 | Slice<VariablePointer> var "sliced variable"; | ||
| 147 | Slice<EquationPointer> eqn "sliced equation"; | ||
| 148 | end GENERIC_COMPONENT; | ||
| 149 | |||
| 150 | record ENTWINED_COMPONENT | ||
| 151 | "component for entwined equations that have to be called in a specific interleaved order | ||
| 152 | but do not form an algebraic loop. Slices can be SLICED_COMPONENT, GENERIC_COMPONENT, | ||
| 153 | RESIZABLE_COMPONENT, SINGLE_COMPONENT or MULTI_COMPONENT." | ||
| 154 | list<StrongComponent> entwined_slices "one entry per distinct equation (for-loop or scalar)"; | ||
| 155 | list<tuple<Pointer<Equation>, Integer>> entwined_tpl_lst "equation with scalar idx (0 based) - fallback scalarization"; | ||
| 156 | end ENTWINED_COMPONENT; | ||
| 157 | |||
| 158 | record ALGEBRAIC_LOOP | ||
| 159 | "component for equations that have to be solved as a system." | ||
| 160 | Integer idx; | ||
| 161 | Tearing strict; | ||
| 162 | Option<Tearing> casual; | ||
| 163 | Boolean linear "true if the loop is linear"; | ||
| 164 | Boolean mixed "true for systems that have discrete variables"; | ||
| 165 | Boolean homotopy "true if contains homotopy()"; | ||
| 166 | Solve.Status status; | ||
| 167 | Boolean implicitlyCreated "true if this component was promoted straight from a | ||
| 168 | single/multi/resizable component by NBSolve.mo's | ||
| 169 | Tearing.implicit() rather than found and torn by | ||
| 170 | NBTearing.mo's own tearing pass. The two are numbered | ||
| 171 | (idx) via separate counters that can coincide, so this | ||
| 172 | flag lets the generated Jacobian's name stay unique."; | ||
| 173 | end ALGEBRAIC_LOOP; | ||
| 174 | |||
| 175 | record ALIAS | ||
| 176 | "Component representing equal strong components in ODE<->INIT<->DAE | ||
| 177 | has no status since this is generated by the Solve module and is always status=EXPLICIT." | ||
| 178 | AliasInfo aliasInfo "The strong component array and index it refers to"; | ||
| 179 | StrongComponent original "The original strong component for analysis"; | ||
| 180 | end ALIAS; | ||
| 181 | |||
| 182 | function toString | ||
| 183 | input StrongComponent comp; | ||
| 184 | input Integer index = -1 "negative indices will not be printed"; | ||
| 185 | output String str; | ||
| 186 | protected | ||
| 187 | Integer s = StrongComponent.size(comp, true); | ||
| 188 | String indexStr = if index > 0 then " " + intString(index) else ""; | ||
| 189 | algorithm | ||
| 190 | str := match comp | ||
| 191 | |||
| 192 | case SINGLE_COMPONENT() algorithm | ||
| 193 | 18 | str := StringUtil.headline_3("BLOCK" + indexStr + ": Single Strong Component (status = " + Solve.statusString(comp.status) + ", size = " + intString(s) + ")"); | |
| 194 | 18 | str := str + "### Variable:\n" + Variable.toString(Pointer.access(comp.var), "\t") + "\n"; | |
| 195 | 18 | str := str + "### Equation:\n" + Equation.toString(Pointer.access(comp.eqn), "\t") + "\n"; | |
| 196 | then str; | ||
| 197 | |||
| 198 | case MULTI_COMPONENT() algorithm | ||
| 199 | 6 | str := StringUtil.headline_3("BLOCK" + indexStr + ": Multi Strong Component (status = " + Solve.statusString(comp.status) + ", size = " + intString(s) + ")"); | |
| 200 | 6 | str := str + "### Variables:\n"; | |
| 201 | 6 | str := str + List.toString(comp.vars, function Slice.toString(func = BVariable.pointerToString, maxLength = 10), List.Style.NEWLINE_TAB); | |
| 202 | 6 | str := str + "\n### Equation:\n" + Slice.toString(comp.eqn, function Equation.pointerToString(str = "\t")) + "\n"; | |
| 203 | then str; | ||
| 204 | |||
| 205 | case SLICED_COMPONENT() algorithm | ||
| 206 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | str := if index == -2 then "" else StringUtil.headline_3("BLOCK" + indexStr + ": Sliced Component (status = " + Solve.statusString(comp.status) + ", size = " + intString(s) + ")"); |
| 207 | 11 | str := str + "### Variable:\n\t" + ComponentRef.toString(comp.var_cref) + "\n"; | |
| 208 | 11 | str := str + "### Equation:\n" + Slice.toString(comp.eqn, function Equation.pointerToString(str = "\t")) + "\n"; | |
| 209 | then str; | ||
| 210 | |||
| 211 | case RESIZABLE_COMPONENT() algorithm | ||
| 212 | 26 | str := StringUtil.headline_3("BLOCK" + indexStr + ": Resizable Component (status = " + Solve.statusString(comp.status) + ", size = " + intString(s) + ")"); | |
| 213 | 26 | str := str + "### Variable:\n\t" + ComponentRef.toString(comp.var_cref) + "\n"; | |
| 214 | 26 | str := str + "### Equation:\n" + Equation.pointerToString(Slice.getT(comp.eqn), "\t") + "\n"; | |
| 215 | then str; | ||
| 216 | |||
| 217 | case ENTWINED_COMPONENT() algorithm | ||
| 218 | ✗ | str := StringUtil.headline_3("BLOCK" + indexStr + ": Entwined Component (status = Solve.EXPLICIT, size = " + intString(s) + ")"); | |
| 219 | ✗ | str := str + "call order: " + List.toString(list(Equation.getEqnName(Util.tuple21(e)) for e in comp.entwined_tpl_lst), ComponentRef.toString, List.Style.FLAT_CURLY_SHORT) + "\n"; | |
| 220 | ✗ | str := str + List.toString(comp.entwined_slices, function toString(index = -2), List.Style.NONE); | |
| 221 | then str; | ||
| 222 | |||
| 223 | case GENERIC_COMPONENT() algorithm | ||
| 224 | ✗ | str := StringUtil.headline_3("BLOCK" + indexStr + ": Generic Component (status = Solve.EXPLICIT, size = " + intString(s) + ")"); | |
| 225 | ✗ | str := str + "### Variable:\n\t" + ComponentRef.toString(comp.var_cref) + "\n"; | |
| 226 | ✗ | str := str + "### Equation:\n" + Slice.toString(comp.eqn, function Equation.pointerToString(str = "\t")) + "\n"; | |
| 227 | then str; | ||
| 228 | |||
| 229 | case ALGEBRAIC_LOOP() algorithm | ||
| 230 |
3/6✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 10 taken 4 times.
✗ Branch 11 not taken.
|
12 | str := StringUtil.headline_3("BLOCK" + indexStr + ": Algebraic Loop (Linear = " + boolString(comp.linear) + ", Mixed = " + boolString(comp.mixed) + ", Homotopy = " + boolString(comp.homotopy) + ", size = " + intString(s) + ")"); |
| 231 | 4 | str := str + Tearing.toString(comp.strict, "Strict Tearing Set"); | |
| 232 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
|
4 | if isSome(comp.casual) then |
| 233 | ✗ | str := str + Tearing.toString(Util.getOption(comp.casual), "Casual Tearing Set"); | |
| 234 | end if; | ||
| 235 | then str; | ||
| 236 | |||
| 237 | case ALIAS() algorithm | ||
| 238 | 16 | str := "--- Alias of " + AliasInfo.toString(comp.aliasInfo) + " ---\n" + toString(comp.original, index); | |
| 239 | then str; | ||
| 240 | |||
| 241 | else algorithm | ||
| 242 | ✗ | Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed."}); | |
| 243 | ✗ | then fail(); | |
| 244 | end match; | ||
| 245 | end toString; | ||
| 246 | |||
| 247 | uniontype CountCollector | ||
| 248 | record COUNT_COLLECTOR | ||
| 249 | Integer single_scalar; | ||
| 250 | Integer single_array; | ||
| 251 | Integer single_record; | ||
| 252 | Integer multi_algorithm; | ||
| 253 | Integer multi_when; | ||
| 254 | Integer multi_if; | ||
| 255 | Integer multi_tpl; | ||
| 256 | Integer resizable_for; | ||
| 257 | Integer generic_for; | ||
| 258 | Integer entwined_for; | ||
| 259 | Integer loop_lin; | ||
| 260 | Integer loop_nlin; | ||
| 261 | end COUNT_COLLECTOR; | ||
| 262 | end CountCollector; | ||
| 263 | |||
| 264 | function strongComponentInfo | ||
| 265 | input output StrongComponent comp; | ||
| 266 | input Pointer<CountCollector> collector_ptr; | ||
| 267 | protected | ||
| 268 | CountCollector collector = Pointer.access(collector_ptr); | ||
| 269 | algorithm | ||
| 270 | () := match comp | ||
| 271 | case SINGLE_COMPONENT() algorithm | ||
| 272 | () := match Pointer.access(comp.eqn) | ||
| 273 | ✗ | case Equation.SCALAR_EQUATION() algorithm collector.single_scalar := collector.single_scalar + 1; Pointer.update(collector_ptr, collector); then (); | |
| 274 | ✗ | case Equation.ARRAY_EQUATION() algorithm collector.single_array := collector.single_array + 1; Pointer.update(collector_ptr, collector); then (); | |
| 275 | ✗ | case Equation.RECORD_EQUATION() algorithm collector.single_record := collector.single_record + 1; Pointer.update(collector_ptr, collector); then (); | |
| 276 | ✗ | else algorithm Error.addCompilerWarning("Cannot classify strong component:\n" + toString(comp) + "\n"); then (); | |
| 277 | end match; | ||
| 278 | then (); | ||
| 279 | |||
| 280 | case MULTI_COMPONENT() algorithm | ||
| 281 | () := match Pointer.access(Slice.getT(comp.eqn)) | ||
| 282 | ✗ | case Equation.ALGORITHM() algorithm collector.multi_algorithm := collector.multi_algorithm + 1; Pointer.update(collector_ptr, collector); then (); | |
| 283 | ✗ | case Equation.WHEN_EQUATION() algorithm collector.multi_when := collector.multi_when + 1; Pointer.update(collector_ptr, collector); then (); | |
| 284 | ✗ | case Equation.IF_EQUATION() algorithm collector.multi_if := collector.multi_if + 1; Pointer.update(collector_ptr, collector); then (); | |
| 285 | ✗ | case Equation.RECORD_EQUATION() algorithm collector.multi_tpl := collector.multi_tpl + 1; Pointer.update(collector_ptr, collector); then (); | |
| 286 | ✗ | else algorithm Error.addCompilerWarning("Cannot classify strong component:\n" + toString(comp) + "\n"); then (); | |
| 287 | end match; | ||
| 288 | then (); | ||
| 289 | |||
| 290 | case SLICED_COMPONENT() algorithm | ||
| 291 | () := match Pointer.access(Slice.getT(comp.eqn)) | ||
| 292 | ✗ | case Equation.SCALAR_EQUATION() algorithm collector.single_scalar := collector.single_scalar + 1; Pointer.update(collector_ptr, collector); then (); | |
| 293 | ✗ | case Equation.ARRAY_EQUATION() algorithm collector.single_array := collector.single_array + 1; Pointer.update(collector_ptr, collector); then (); | |
| 294 | ✗ | case Equation.RECORD_EQUATION() algorithm collector.single_record := collector.single_record + 1; Pointer.update(collector_ptr, collector); then (); | |
| 295 | ✗ | else algorithm Error.addCompilerWarning("Cannot classify strong component:\n" + toString(comp) + "\n"); then (); | |
| 296 | end match; | ||
| 297 | then (); | ||
| 298 | |||
| 299 | ✗ | case RESIZABLE_COMPONENT() algorithm collector.resizable_for := collector.resizable_for +1; Pointer.update(collector_ptr, collector); then (); | |
| 300 | ✗ | case GENERIC_COMPONENT() algorithm collector.generic_for := collector.generic_for + 1; Pointer.update(collector_ptr, collector); then (); | |
| 301 | ✗ | case ENTWINED_COMPONENT() algorithm collector.entwined_for := collector.entwined_for + 1; Pointer.update(collector_ptr, collector); then (); | |
| 302 | ✗ | case ALGEBRAIC_LOOP() guard(comp.linear) algorithm collector.loop_lin := collector.loop_lin + 1; Pointer.update(collector_ptr, collector); then (); | |
| 303 | ✗ | case ALGEBRAIC_LOOP() algorithm collector.loop_nlin := collector.loop_nlin + 1; Pointer.update(collector_ptr, collector); then (); | |
| 304 | ✗ | case ALIAS() algorithm strongComponentInfo(comp.original, collector_ptr); then (); | |
| 305 | ✗ | else algorithm Error.addCompilerWarning("Cannot classify strong component:\n" + toString(comp) + "\n"); then (); | |
| 306 | end match; | ||
| 307 | end strongComponentInfo; | ||
| 308 | |||
| 309 | function hash | ||
| 310 | "only hashes basic types, isEqual is used to differ between sliced/entwined loops" | ||
| 311 | input StrongComponent comp; | ||
| 312 | output Integer i; | ||
| 313 | algorithm | ||
| 314 | i := match comp | ||
| 315 | 5005 | case SINGLE_COMPONENT() then BVariable.hash(comp.var) + Equation.hash(comp.eqn); | |
| 316 | 299 | case MULTI_COMPONENT() then Equation.hash(Slice.getT(comp.eqn)); | |
| 317 | 3096 | case SLICED_COMPONENT() then ComponentRef.hash(comp.var_cref) + Equation.hash(Slice.getT(comp.eqn)); | |
| 318 | 777 | case RESIZABLE_COMPONENT()then ComponentRef.hash(comp.var_cref) + Equation.hash(Slice.getT(comp.eqn)); | |
| 319 | ✗ | case GENERIC_COMPONENT() then Equation.hash(Slice.getT(comp.eqn)); | |
| 320 |
4/4✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 4 times.
|
16 | case ENTWINED_COMPONENT() then sum(hash(sub_comp) for sub_comp in comp.entwined_slices); |
| 321 | 171 | case ALGEBRAIC_LOOP() then Tearing.hash(comp.strict); | |
| 322 | ✗ | case ALIAS() then AliasInfo.hash(comp.aliasInfo); | |
| 323 | else algorithm | ||
| 324 | ✗ | Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed."}); | |
| 325 | ✗ | then fail(); | |
| 326 | end match; | ||
| 327 | end hash; | ||
| 328 | |||
| 329 | function isEqual | ||
| 330 | input StrongComponent comp1; | ||
| 331 | input StrongComponent comp2; | ||
| 332 | output Boolean b; | ||
| 333 | algorithm | ||
| 334 | b := match(comp1, comp2) | ||
| 335 |
4/4✓ Branch 1 taken 1631 times.
✓ Branch 2 taken 430 times.
✓ Branch 4 taken 52 times.
✓ Branch 5 taken 1579 times.
|
2061 | case (SINGLE_COMPONENT(), SINGLE_COMPONENT()) then BVariable.equalName(comp1.var, comp2.var) and Equation.isEqualPtr(comp1.eqn, comp2.eqn); |
| 336 | 57 | case (MULTI_COMPONENT(), MULTI_COMPONENT()) then Equation.isEqualPtr(Slice.getT(comp1.eqn), Slice.getT(comp2.eqn)); | |
| 337 |
3/4✓ Branch 1 taken 909 times.
✓ Branch 2 taken 36 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 909 times.
|
945 | case (SLICED_COMPONENT(), SLICED_COMPONENT()) then ComponentRef.isEqual(comp1.var_cref, comp2.var_cref) and Slice.isEqual(comp1.eqn, comp2.eqn, Equation.isEqualPtr); |
| 338 |
3/4✓ Branch 1 taken 235 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 233 times.
|
235 | case (RESIZABLE_COMPONENT(), RESIZABLE_COMPONENT()) then ComponentRef.isEqual(comp1.var_cref, comp2.var_cref) and Slice.isEqual(comp1.eqn, comp2.eqn, Equation.isEqualPtr); |
| 339 | ✗ | case (GENERIC_COMPONENT(), GENERIC_COMPONENT()) then Slice.isEqual(comp1.eqn, comp2.eqn, Equation.isEqualPtr); | |
| 340 | 2 | case (ENTWINED_COMPONENT(), ENTWINED_COMPONENT()) then List.isEqualOnTrue(comp1.entwined_slices, comp2.entwined_slices, isEqual); | |
| 341 | 49 | case (ALGEBRAIC_LOOP(), ALGEBRAIC_LOOP()) then Tearing.isEqual(comp1.strict, comp2.strict); | |
| 342 | ✗ | case (ALIAS(), ALIAS()) then AliasInfo.isEqual(comp1.aliasInfo, comp2.aliasInfo); | |
| 343 | else false; | ||
| 344 | end match; | ||
| 345 | end isEqual; | ||
| 346 | |||
| 347 | function size | ||
| 348 | input StrongComponent comp; | ||
| 349 | input Boolean resize; | ||
| 350 | output Integer s; | ||
| 351 | algorithm | ||
| 352 | s := match comp | ||
| 353 | 27 | case SINGLE_COMPONENT() then Equation.size(comp.eqn, resize); | |
| 354 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | case MULTI_COMPONENT() then Slice.size(comp.eqn, function Equation.size(resize = resize)); |
| 355 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | case SLICED_COMPONENT() then Slice.size(comp.eqn, function Equation.size(resize = resize)); |
| 356 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
|
32 | case RESIZABLE_COMPONENT() then Slice.size(comp.eqn, function Equation.size(resize = resize)); |
| 357 | ✗ | case GENERIC_COMPONENT() then Slice.size(comp.eqn, function Equation.size(resize = resize)); | |
| 358 | ✗ | case ENTWINED_COMPONENT() then sum(StrongComponent.size(c, resize) for c in comp.entwined_slices); | |
| 359 | 4 | case ALGEBRAIC_LOOP() then Tearing.size(comp.strict, resize); | |
| 360 | 16 | case ALIAS() then StrongComponent.size(comp.original, resize); | |
| 361 | else algorithm | ||
| 362 | ✗ | Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed. Cannot determine size of strong component:\n" + toString(comp) + "\n"}); | |
| 363 | ✗ | then fail(); | |
| 364 | end match; | ||
| 365 | end size; | ||
| 366 | |||
| 367 | function removeAlias | ||
| 368 | input output StrongComponent comp; | ||
| 369 | algorithm | ||
| 370 | comp := match comp | ||
| 371 | 74 | case ALIAS() then comp.original; | |
| 372 | else comp; | ||
| 373 | end match; | ||
| 374 | end removeAlias; | ||
| 375 | |||
| 376 | function solvesInsideReduction | ||
| 377 | "true if a scalar for-equation is solved for a cref with a whole dimension, e.g. x[i, :] for | ||
| 378 | y[i] = sum(x[i, j] for j in 1:n) matched to x[i, 1]. The cref does not determine the solved | ||
| 379 | elements, they have to be solved one by one. A whole dimension of an array equation inside | ||
| 380 | the for-equation, e.g. a[i, :] = b * i, determines them." | ||
| 381 | input Pointer<Equation> eqn_ptr; | ||
| 382 | input ComponentRef cref; | ||
| 383 | output Boolean b; | ||
| 384 | algorithm | ||
| 385 | b := match Pointer.access(eqn_ptr) | ||
| 386 | local | ||
| 387 | Equation body; | ||
| 388 | // a size one array equation, e.g. a[i, :] = b[1:1, i], determines the elements as well | ||
| 389 |
5/6✓ Branch 2 taken 565 times.
✓ Branch 3 taken 47 times.
✓ Branch 6 taken 556 times.
✓ Branch 7 taken 9 times.
✓ Branch 10 taken 556 times.
✗ Branch 11 not taken.
|
612 | case Equation.FOR_EQUATION(body = {body}) then Equation.size(Pointer.create(body)) == 1 |
| 390 | and not Type.isArray(Equation.getType(body)) | ||
| 391 | and List.any(ComponentRef.subscriptsAllFlat(cref), Subscript.isWhole); | ||
| 392 | else false; | ||
| 393 | end match; | ||
| 394 | end solvesInsideReduction; | ||
| 395 | |||
| 396 | function createPseudoSlice | ||
| 397 | input Integer var_arr_idx; | ||
| 398 | input Integer eqn_arr_idx; | ||
| 399 | input ComponentRef cref_to_solve; | ||
| 400 | input list<Integer> eqn_scal_indices; | ||
| 401 | input array<Integer> eqn_to_var; | ||
| 402 | input EquationPointers eqns; | ||
| 403 | input Adjacency.Mapping mapping; | ||
| 404 | input Boolean independent = false "true if scalar equations can be solved in any order"; | ||
| 405 | output StrongComponent comp; | ||
| 406 | protected | ||
| 407 | Pointer<Variable> var_ptr; | ||
| 408 | Pointer<Equation> eqn_ptr; | ||
| 409 | Integer first_var, var_size, first_eqn, eqn_size; | ||
| 410 | Slice<VariablePointer>var_slice; | ||
| 411 | Slice<EquationPointer>eqn_slice; | ||
| 412 | list<Integer> var_scal_indices; | ||
| 413 | UnorderedMap<ComponentRef, EvalOrder> order; | ||
| 414 | algorithm | ||
| 415 | // get and save sliced variable and equation | ||
| 416 | 1129 | var_ptr := BVariable.getVarPointer(cref_to_solve, sourceInfo()); | |
| 417 | 1129 | eqn_ptr := EquationPointers.getEqnAt(eqns, eqn_arr_idx); | |
| 418 | 1129 | (first_var, var_size) := mapping.var_AtS[var_arr_idx]; | |
| 419 | 1129 | (first_eqn, eqn_size) := mapping.eqn_AtS[eqn_arr_idx]; | |
| 420 |
4/4✓ Branch 0 taken 9034 times.
✓ Branch 1 taken 1129 times.
✓ Branch 2 taken 9034 times.
✓ Branch 3 taken 1129 times.
|
10163 | var_scal_indices := list(eqn_to_var[e] for e in eqn_scal_indices); |
| 421 | |||
| 422 | // check if the full variable occurs and its independent | ||
| 423 |
7/8✓ Branch 0 taken 1027 times.
✓ Branch 1 taken 102 times.
✓ Branch 3 taken 533 times.
✓ Branch 4 taken 494 times.
✓ Branch 6 taken 533 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 488 times.
✓ Branch 10 taken 45 times.
|
1129 | if independent and Equation.isArrayEquation(eqn_ptr) and listLength(eqn_scal_indices) == eqn_size and listLength(var_scal_indices) == var_size then |
| 424 | 488 | var_slice := Slice.SLICE(var_ptr, {}); | |
| 425 | 488 | eqn_slice := Slice.SLICE(eqn_ptr, {}); | |
| 426 | else | ||
| 427 |
4/4✓ Branch 0 taken 6583 times.
✓ Branch 1 taken 641 times.
✓ Branch 2 taken 6583 times.
✓ Branch 3 taken 641 times.
|
7224 | var_slice := Slice.SLICE(var_ptr, list(idx - first_var for idx in var_scal_indices)); |
| 428 |
4/4✓ Branch 0 taken 6583 times.
✓ Branch 1 taken 641 times.
✓ Branch 2 taken 6583 times.
✓ Branch 3 taken 641 times.
|
7224 | eqn_slice := Slice.SLICE(eqn_ptr, list(idx - first_eqn for idx in eqn_scal_indices)); |
| 429 | end if; | ||
| 430 | |||
| 431 | // check if it is a resizable component. a variable inside a reduction can only be solved as a slice | ||
| 432 | 1129 | order := Resizable.detect(Pointer.access(eqn_ptr), cref_to_solve); | |
| 433 |
5/6✓ Branch 2 taken 589 times.
✓ Branch 3 taken 540 times.
✓ Branch 5 taken 533 times.
✓ Branch 6 taken 56 times.
✓ Branch 8 taken 533 times.
✗ Branch 9 not taken.
|
1129 | if not List.any(UnorderedMap.valueList(order), Resizable.orderFailed) and listLength(eqn_scal_indices) == eqn_size |
| 434 | and not solvesInsideReduction(eqn_ptr, cref_to_solve) then | ||
| 435 | 533 | comp := RESIZABLE_COMPONENT( | |
| 436 | var_cref = cref_to_solve, | ||
| 437 | var = var_slice, | ||
| 438 | eqn = eqn_slice, | ||
| 439 | order = order, | ||
| 440 | status = NBSolve.Status.UNPROCESSED); | ||
| 441 | else | ||
| 442 | 596 | comp := createSliceOrSingle(cref_to_solve, var_slice, eqn_slice); | |
| 443 | end if; | ||
| 444 | end createPseudoSlice; | ||
| 445 | |||
| 446 | function createPseudoEntwined | ||
| 447 | input list<Integer> eqn_indices; | ||
| 448 | input array<Integer> eqn_to_var; | ||
| 449 | input Mapping mapping; | ||
| 450 | input VariablePointers vars; | ||
| 451 | input EquationPointers eqns; | ||
| 452 | input list<SuperNode> nodes; | ||
| 453 | output StrongComponent entwined; | ||
| 454 | protected | ||
| 455 | UnorderedMap<Integer, Slice.IntLst> elem_map = UnorderedMap.new<Slice.IntLst>(Util.id, intEq); | ||
| 456 | UnorderedMap<Integer, ComponentRef> cref_map = UnorderedMap.new<ComponentRef>(Util.id, intEq); | ||
| 457 | Integer eqn_arr_idx, var_arr_idx; | ||
| 458 | Slice.IntLst scal_indices; | ||
| 459 | list<StrongComponent> entwined_slices = {}; | ||
| 460 | list<tuple<Pointer<Equation>, Integer>> entwined_tpl_lst; | ||
| 461 | algorithm | ||
| 462 | // collect individual buckets again | ||
| 463 |
2/2✓ Branch 0 taken 36 times.
✓ Branch 1 taken 2 times.
|
38 | for idx in eqn_indices loop |
| 464 | 72 | UnorderedMap.add(mapping.eqn_StA[idx], idx :: UnorderedMap.getOrDefault(mapping.eqn_StA[idx], elem_map, {}), elem_map); | |
| 465 | end for; | ||
| 466 | // collect crefs to solve for | ||
| 467 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
|
8 | for node in nodes loop |
| 468 | () := match node | ||
| 469 | case SuperNode.ARRAY_BUCKET() algorithm | ||
| 470 | 6 | UnorderedMap.add(node.arr_idx, node.cref_to_solve, cref_map); | |
| 471 | then (); | ||
| 472 | else (); | ||
| 473 | end match; | ||
| 474 | end for; | ||
| 475 | |||
| 476 | // create individual slices (array bucket → slice component, scalar → scalar component) | ||
| 477 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 2 taken 2 times.
|
8 | for tpl in UnorderedMap.toList(elem_map) loop |
| 478 | 6 | (eqn_arr_idx, scal_indices) := tpl; | |
| 479 | // the calls of the slice consume its indices in order, see the call order below | ||
| 480 | 6 | scal_indices := listReverse(scal_indices); | |
| 481 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | if UnorderedMap.contains(eqn_arr_idx, cref_map) then |
| 482 | 6 | var_arr_idx := mapping.var_StA[eqn_to_var[Util.tuple21(mapping.eqn_AtS[eqn_arr_idx])]]; | |
| 483 | 6 | entwined_slices := createPseudoSlice(var_arr_idx, eqn_arr_idx, UnorderedMap.getSafe(eqn_arr_idx, cref_map, sourceInfo()), scal_indices, eqn_to_var, eqns, mapping) :: entwined_slices; | |
| 484 | else | ||
| 485 | ✗ | entwined_slices := createPseudoScalar(scal_indices, eqn_to_var, mapping, vars, eqns) :: entwined_slices; | |
| 486 | end if; | ||
| 487 | end for; | ||
| 488 | |||
| 489 | // create scalar list for fallback | ||
| 490 |
4/4✓ Branch 0 taken 36 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 36 times.
✓ Branch 3 taken 2 times.
|
38 | entwined_tpl_lst := list((EquationPointers.getEqnAt(eqns, mapping.eqn_StA[idx]), idx) for idx in eqn_indices); |
| 491 | |||
| 492 | 2 | entwined := ENTWINED_COMPONENT(entwined_slices, entwined_tpl_lst); | |
| 493 | end createPseudoEntwined; | ||
| 494 | |||
| 495 | function createAlias | ||
| 496 | input BPartition.Kind kind; | ||
| 497 | input Integer partitionIndex; | ||
| 498 | input Pointer<Integer> index_ptr; | ||
| 499 | input StrongComponent orig_comp; | ||
| 500 | output StrongComponent alias_comp; | ||
| 501 | algorithm | ||
| 502 | 3325 | alias_comp := ALIAS(ALIAS_INFO(kind, partitionIndex, Pointer.access(index_ptr)), orig_comp); | |
| 503 | 3325 | Pointer.update(index_ptr, Pointer.access(index_ptr) + 1); | |
| 504 | end createAlias; | ||
| 505 | |||
| 506 | function createPseudoEntwinedIndices | ||
| 507 | input array<list<Integer>> entwined_indices; | ||
| 508 | input EquationPointers eqns; | ||
| 509 | input Adjacency.Mapping mapping; | ||
| 510 | output list<tuple<Pointer<Equation>, Integer>> flat_tpl_indices = {}; | ||
| 511 | protected | ||
| 512 | Integer arr_idx, first_idx; | ||
| 513 | array<Integer> eqn_StA "safe access with iterated integer (void pointer)"; | ||
| 514 | algorithm | ||
| 515 | ✗ | for tmp in entwined_indices loop | |
| 516 | ✗ | for scal_idx in tmp loop | |
| 517 | ✗ | eqn_StA := mapping.eqn_StA; | |
| 518 | ✗ | arr_idx := eqn_StA[scal_idx]; | |
| 519 | ✗ | (first_idx, _) := mapping.eqn_AtS[arr_idx]; | |
| 520 | ✗ | flat_tpl_indices := (EquationPointers.getEqnAt(eqns, arr_idx), scal_idx-first_idx) :: flat_tpl_indices; | |
| 521 | end for; | ||
| 522 | end for; | ||
| 523 | ✗ | flat_tpl_indices := listReverse(flat_tpl_indices); | |
| 524 | end createPseudoEntwinedIndices; | ||
| 525 | |||
| 526 | type DAEType = enumeration(UNPROCESSED, REMOVED, INNER, RESIDUAL); | ||
| 527 | |||
| 528 | function sortDAEModeComponents | ||
| 529 | input output Option<array<StrongComponent>> comps; | ||
| 530 | input VariablePointers variables; | ||
| 531 | input Pointer<Integer> uniqueIndex; | ||
| 532 | protected | ||
| 533 | list<StrongComponent> residuals = {}, inners = {}; | ||
| 534 | // used to determine if a sliced equation will be handled as residual or as inner | ||
| 535 | UnorderedSet<ComponentRef> slice_set = UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual); | ||
| 536 | algorithm | ||
| 537 | comps := match comps | ||
| 538 | local | ||
| 539 | array<StrongComponent> original; | ||
| 540 | |||
| 541 | case SOME(original) algorithm | ||
| 542 |
2/2✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
|
2 | for comp in original loop |
| 543 | 1 | (residuals, inners) := sortDAEModeComponent(comp, residuals, inners, variables, uniqueIndex, slice_set); | |
| 544 | end for; | ||
| 545 | |||
| 546 | /* order of inners matters */ | ||
| 547 | 1 | comps := SOME(listArray(listAppend(listReverse(inners), residuals))); | |
| 548 | then comps; | ||
| 549 | |||
| 550 | else comps; | ||
| 551 | end match; | ||
| 552 | end sortDAEModeComponents; | ||
| 553 | |||
| 554 | function sortDAEModeComponent | ||
| 555 | input StrongComponent comp; | ||
| 556 | input output list<StrongComponent> residuals; | ||
| 557 | input output list<StrongComponent> inners; | ||
| 558 | input VariablePointers variables; | ||
| 559 | input Pointer<Integer> uniqueIndex; | ||
| 560 | input UnorderedSet<ComponentRef> slice_set; | ||
| 561 | protected | ||
| 562 | list<StrongComponent> new_residuals; | ||
| 563 | DAEType dae_type; | ||
| 564 | algorithm | ||
| 565 | (new_residuals, dae_type) := match comp | ||
| 566 | // single equation fully solved for single variable (not neccessarily scalar) | ||
| 567 | case SINGLE_COMPONENT() algorithm | ||
| 568 | 1 | (new_residuals, dae_type) := singleDAEModeComponent(comp.eqn, variables, uniqueIndex); | |
| 569 | then (new_residuals, dae_type); | ||
| 570 | |||
| 571 | case MULTI_COMPONENT() algorithm | ||
| 572 | ✗ | (new_residuals, dae_type) := slicedDAEModeComponent(comp.vars, {comp.eqn}, variables, uniqueIndex, slice_set); | |
| 573 | then (new_residuals, dae_type); | ||
| 574 | |||
| 575 | case SLICED_COMPONENT() algorithm | ||
| 576 | // this will always result in inner equation for now as either eqn or var are sliced | ||
| 577 | // -> in the future improve this | ||
| 578 | ✗ | (new_residuals, dae_type) := slicedDAEModeComponent({comp.var}, {comp.eqn}, variables, uniqueIndex, slice_set); | |
| 579 | then (new_residuals, dae_type); | ||
| 580 | |||
| 581 | case RESIZABLE_COMPONENT() algorithm | ||
| 582 | ✗ | (new_residuals, dae_type) := slicedDAEModeComponent({comp.var}, {comp.eqn}, variables, uniqueIndex, slice_set); | |
| 583 | then (new_residuals, dae_type); | ||
| 584 | |||
| 585 | case GENERIC_COMPONENT() algorithm | ||
| 586 | ✗ | (new_residuals, dae_type) := slicedDAEModeComponent({comp.var}, {comp.eqn}, variables, uniqueIndex, slice_set); | |
| 587 | then (new_residuals, dae_type); | ||
| 588 | |||
| 589 | case ALGEBRAIC_LOOP() algorithm | ||
| 590 | ✗ | (new_residuals, dae_type) := slicedDAEModeComponent(comp.strict.iteration_vars, comp.strict.residual_eqns, variables, uniqueIndex, slice_set); | |
| 591 | then (new_residuals, dae_type); | ||
| 592 | |||
| 593 | ✗ | else ({}, if isDiscrete(comp) then DAEType.REMOVED else DAEType.INNER); | |
| 594 | end match; | ||
| 595 | |||
| 596 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | if dae_type == DAEType.RESIDUAL then |
| 597 | // add residuals | ||
| 598 | 1 | residuals := listAppend(new_residuals, residuals); | |
| 599 | elseif dae_type == DAEType.INNER then | ||
| 600 | // add original to inners | ||
| 601 | inners := comp :: inners; | ||
| 602 | end if; | ||
| 603 | end sortDAEModeComponent; | ||
| 604 | |||
| 605 | function slicedDAEModeComponent | ||
| 606 | input list<Slice<Pointer<Variable>>> var_slices; | ||
| 607 | input list<Slice<Pointer<Equation>>> eqn_slices; | ||
| 608 | input VariablePointers variables; | ||
| 609 | input Pointer<Integer> uniqueIndex; | ||
| 610 | input UnorderedSet<ComponentRef> slice_set; | ||
| 611 | output list<StrongComponent> new_residuals; | ||
| 612 | output DAEType dae_type = DAEType.RESIDUAL; | ||
| 613 | protected | ||
| 614 | Pointer<Equation> eqn; | ||
| 615 | ComponentRef eqn_name; | ||
| 616 | list<list<StrongComponent>> acc_new_residuals = {}; | ||
| 617 | algorithm | ||
| 618 | ✗ | if List.all(list(v.indices for v in var_slices), listEmpty) then | |
| 619 | ✗ | for eqn_slice in eqn_slices loop | |
| 620 | ✗ | eqn := Slice.getT(eqn_slice); | |
| 621 | ✗ | eqn_name := Equation.getEqnName(eqn); | |
| 622 | ✗ | if listEmpty(eqn_slice.indices) and not UnorderedSet.contains(eqn_name, slice_set) then | |
| 623 | // unsliced equation in multi component / equation not found in map | ||
| 624 | ✗ | (new_residuals, dae_type) := singleDAEModeComponent(eqn, variables, uniqueIndex); | |
| 625 | ✗ | if dae_type == DAEType.RESIDUAL then | |
| 626 | acc_new_residuals := new_residuals :: acc_new_residuals; | ||
| 627 | elseif dae_type == DAEType.INNER then | ||
| 628 | break; | ||
| 629 | end if; | ||
| 630 | else | ||
| 631 | // this sliced equation cannot be made residual, add it to the map | ||
| 632 | ✗ | dae_type := DAEType.INNER; | |
| 633 | ✗ | break; | |
| 634 | end if; | ||
| 635 | end for; | ||
| 636 | else | ||
| 637 | ✗ | dae_type := DAEType.INNER; | |
| 638 | end if; | ||
| 639 | |||
| 640 | ✗ | if dae_type == DAEType.INNER then | |
| 641 | ✗ | for eqn_slice in eqn_slices loop | |
| 642 | ✗ | eqn := Slice.getT(eqn_slice); | |
| 643 | ✗ | eqn_name := Equation.getEqnName(eqn); | |
| 644 | ✗ | UnorderedSet.add(eqn_name, slice_set); | |
| 645 | end for; | ||
| 646 | new_residuals := {}; | ||
| 647 | else | ||
| 648 | ✗ | new_residuals := List.flatten(acc_new_residuals); | |
| 649 | end if; | ||
| 650 | end slicedDAEModeComponent; | ||
| 651 | |||
| 652 | function singleDAEModeComponent | ||
| 653 | input Pointer<Equation> eqn_ptr; | ||
| 654 | input VariablePointers variables; | ||
| 655 | input Pointer<Integer> uniqueIndex; | ||
| 656 | output list<StrongComponent> new_residuals; | ||
| 657 | output DAEType dae_type = DAEType.RESIDUAL; | ||
| 658 | protected | ||
| 659 | Pointer<list<Pointer<Equation>>> new_eqns; | ||
| 660 | UnorderedSet<VariablePointer> dummy_set; | ||
| 661 | Equation eqn; | ||
| 662 | list<Pointer<Equation>> eqns; | ||
| 663 | algorithm | ||
| 664 | 1 | new_eqns := Pointer.create({}); | |
| 665 | 1 | dummy_set := UnorderedSet.new(BVariable.hash, BVariable.equalName); | |
| 666 | 1 | eqn := Inline.inlineRecordTupleArrayEquation(Pointer.access(eqn_ptr), Iterator.EMPTY(), variables, new_eqns, dummy_set, uniqueIndex, true); | |
| 667 | 1 | eqns := Pointer.access(new_eqns); | |
| 668 | // create equation, deliberately use new pointer. allow creating residual to fail and add original strong component to inners | ||
| 669 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | eqns := if listEmpty(eqns) then {Pointer.create(eqn)} else eqns; |
| 670 | 1 | (new_residuals, dae_type) := inlinedDAEModeComponent(eqns); | |
| 671 | end singleDAEModeComponent; | ||
| 672 | |||
| 673 | function inlinedDAEModeComponent | ||
| 674 | input list<Pointer<Equation>> eqns; | ||
| 675 | output list<StrongComponent> comps = {}; | ||
| 676 | output DAEType dae_type = DAEType.UNPROCESSED; | ||
| 677 | protected | ||
| 678 | Pointer<Equation> new_eqn; | ||
| 679 | StrongComponent new_comp; | ||
| 680 | algorithm | ||
| 681 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
|
2 | for eqn in eqns loop |
| 682 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
|
1 | if Equation.isDiscrete(eqn) then |
| 683 | // all sub equations are discrete, remove whole equation | ||
| 684 | if dae_type < DAEType.INNER then | ||
| 685 | dae_type := DAEType.REMOVED; | ||
| 686 | end if; | ||
| 687 | else | ||
| 688 | 1 | new_eqn := Equation.createResidual(eqn, NONE(), false, true); | |
| 689 |
1/2✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
|
1 | if Equation.isResidual(new_eqn) then |
| 690 | // add to residuals | ||
| 691 | 1 | new_comp := SINGLE_COMPONENT(Equation.getResidualVar(new_eqn), new_eqn, NBSolve.Status.UNPROCESSED); | |
| 692 | comps := new_comp :: comps; | ||
| 693 | dae_type := DAEType.RESIDUAL; | ||
| 694 | else | ||
| 695 | // cannot make residuals for all, make whole equation inner for now | ||
| 696 | // might not be neccessary --> needs further solving to get proper sub strong component | ||
| 697 | dae_type := DAEType.INNER; break; | ||
| 698 | end if; | ||
| 699 | end if; | ||
| 700 | end for; | ||
| 701 | end inlinedDAEModeComponent; | ||
| 702 | |||
| 703 | function fromSolvedEquationSlice | ||
| 704 | "creates a strong component assuming the equation is already solved | ||
| 705 | todo: if and when equations" | ||
| 706 | input Slice<EquationPointer> eqn_slice; | ||
| 707 | output StrongComponent comp; | ||
| 708 | protected | ||
| 709 | Pointer<Equation> eqn_ptr = Slice.getT(eqn_slice); | ||
| 710 | Equation eqn = Pointer.access(eqn_ptr); | ||
| 711 | IfEquationBody body; | ||
| 712 | list<Subscript> subs; | ||
| 713 | ComponentRef lhs_cref; | ||
| 714 | function simpleSolvedEquation | ||
| 715 | input Equation eqn; | ||
| 716 | input Pointer<Equation> eqn_ptr; | ||
| 717 | output StrongComponent comp; | ||
| 718 | algorithm | ||
| 719 | comp := match Equation.getLHS(eqn) | ||
| 720 | local | ||
| 721 | Expression lhs; | ||
| 722 | Pointer<Variable> var_ptr; | ||
| 723 | case SOME(lhs as Expression.CREF()) algorithm | ||
| 724 | 1810 | var_ptr := BVariable.getVarPointer(lhs.cref, sourceInfo()); | |
| 725 | // an element of an array variable keeps its subscripts, e.g. p[2] in an if-equation branch | ||
| 726 |
3/4✓ Branch 1 taken 76 times.
✓ Branch 2 taken 1734 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 76 times.
|
1810 | comp := if BVariable.isArray(var_ptr) and not Type.isArray(Expression.typeOf(lhs)) |
| 727 | then SLICED_COMPONENT(lhs.cref, Slice.SLICE(var_ptr, {}), Slice.SLICE(eqn_ptr, {}), NBSolve.Status.EXPLICIT) | ||
| 728 | else SINGLE_COMPONENT(var_ptr, eqn_ptr, NBSolve.Status.EXPLICIT); | ||
| 729 | then comp; | ||
| 730 | ✗ | else MULTI_COMPONENT(Equation.getLHSVars(eqn), Slice.SLICE(eqn_ptr, {}), NBSolve.Status.EXPLICIT); | |
| 731 | end match; | ||
| 732 | end simpleSolvedEquation; | ||
| 733 | algorithm | ||
| 734 | // a genuine partial slice of an array equation (e.g. one row of a torn | ||
| 735 | // matrix-shaped subsystem, see NBTearing.scalarSlices) needs a | ||
| 736 | // SLICED_COMPONENT, not a SINGLE_COMPONENT -- the latter's .eqn field is a | ||
| 737 | // whole Pointer<Equation> with no room for which row this is, so every | ||
| 738 | // slice of the same array equation previously collapsed to an identical | ||
| 739 | // whole-array component, undercounting rows for the caller's adjacency/ | ||
| 740 | // sparsity build (e.g. NBJacobian.compJacobian, empty Jacobian columns). | ||
| 741 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 1839 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
1839 | if not listEmpty(eqn_slice.indices) and Equation.isArrayEquation(eqn_ptr) and List.hasOneElement(eqn_slice.indices) then |
| 742 | ✗ | subs := list(Subscript.INDEX(Expression.INTEGER(l + 1)) for l in Slice.indexToLocation(listHead(eqn_slice.indices), Equation.sizes(eqn_ptr))); | |
| 743 | ✗ | lhs_cref := ComponentRef.setSubscripts(subs, Expression.toCref(Util.getOption(Equation.getLHS(eqn)))); | |
| 744 | ✗ | comp := SLICED_COMPONENT(lhs_cref, Slice.SLICE(BVariable.getVarPointer(lhs_cref, sourceInfo()), {}), eqn_slice, NBSolve.Status.EXPLICIT); | |
| 745 | else | ||
| 746 | comp := match eqn | ||
| 747 | 1723 | case Equation.SCALAR_EQUATION() then simpleSolvedEquation(eqn, eqn_ptr); | |
| 748 | 76 | case Equation.ARRAY_EQUATION() then simpleSolvedEquation(eqn, eqn_ptr); | |
| 749 | 11 | case Equation.RECORD_EQUATION() then simpleSolvedEquation(eqn, eqn_ptr); | |
| 750 | case Equation.IF_EQUATION(body = body) algorithm | ||
| 751 | ✗ | if IfEquationBody.isSplit(body) then | |
| 752 | ✗ | comp := SINGLE_COMPONENT(BVariable.getVarPointer(Expression.toCref(Util.getOption(Equation.getLHS(eqn))), sourceInfo()), eqn_ptr, NBSolve.Status.EXPLICIT); | |
| 753 | else | ||
| 754 | ✗ | comp := MULTI_COMPONENT(Equation.getLHSVars(eqn), Slice.SLICE(eqn_ptr, {}), NBSolve.Status.EXPLICIT); | |
| 755 | end if; | ||
| 756 | then comp; | ||
| 757 | 29 | case Equation.FOR_EQUATION() then SLICED_COMPONENT(ComponentRef.EMPTY(), Slice.SLICE(Pointer.create(NBVariable.DUMMY_VARIABLE), {}), eqn_slice, NBSolve.Status.EXPLICIT); | |
| 758 | // ToDo: the other types | ||
| 759 | else algorithm | ||
| 760 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed for:\n" + Slice.toString(eqn_slice, function Equation.pointerToString(str = ""))}); | |
| 761 | ✗ | then fail(); | |
| 762 | end match; | ||
| 763 | end if; | ||
| 764 | end fromSolvedEquationSlice; | ||
| 765 | |||
| 766 | function toSolvedEquation | ||
| 767 | "creates a solved equation for an explicitly solved strong component. | ||
| 768 | fails if it is not solved explicitly." | ||
| 769 | input StrongComponent comp; | ||
| 770 | output Pointer<Equation> eqn; | ||
| 771 | algorithm | ||
| 772 | eqn := match comp | ||
| 773 | ✗ | case SINGLE_COMPONENT(status = NBSolve.Status.EXPLICIT) then comp.eqn; | |
| 774 | ✗ | case MULTI_COMPONENT(status = NBSolve.Status.EXPLICIT) then Slice.getT(comp.eqn); | |
| 775 | 6 | case SLICED_COMPONENT(status = NBSolve.Status.EXPLICIT) then Slice.getT(comp.eqn); | |
| 776 | ✗ | case GENERIC_COMPONENT() then Slice.getT(comp.eqn); | |
| 777 | else algorithm | ||
| 778 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because strong component could not be | |
| 779 | solved explicitly:\n" + toString(comp)}); | ||
| 780 | ✗ | then fail(); | |
| 781 | end match; | ||
| 782 | end toSolvedEquation; | ||
| 783 | |||
| 784 | function collectCrefs | ||
| 785 | "Collects dependent crefs in current comp and saves them in the | ||
| 786 | unordered map. Saves both directions." | ||
| 787 | input StrongComponent comp "strong component to be analyzed"; | ||
| 788 | input VariablePointers var_rep "scalarized variable representatives"; | ||
| 789 | input VariablePointers eqn_rep "scalarized equation representatives"; | ||
| 790 | input Mapping var_rep_mapping "index mapping for variable representatives"; | ||
| 791 | input Mapping eqn_rep_mapping "index mapping for equation representatives"; | ||
| 792 | input UnorderedMap<ComponentRef, list<ComponentRef>> map "unordered map to save the dependencies"; | ||
| 793 | input UnorderedSet<ComponentRef> set "unordered set of array crefs to check for relevance (index lookup)"; | ||
| 794 | input JacobianType jacType "sets the context"; | ||
| 795 | algorithm | ||
| 796 | () := match comp | ||
| 797 | local | ||
| 798 | Pointer<Equation> eqn_ptr; | ||
| 799 | ComponentRef cref; | ||
| 800 | list<ComponentRef> dependencies, loop_vars, tmp; | ||
| 801 | list<tuple<ComponentRef, list<ComponentRef>>> scalarized_dependencies; | ||
| 802 | Tearing strict; | ||
| 803 | Equation eqn, body; | ||
| 804 | Iterator iter; | ||
| 805 | UnorderedSet<ComponentRef> deps_set; | ||
| 806 | |||
| 807 | // sliced array equations - create all the single entries | ||
| 808 | case SINGLE_COMPONENT() guard(Equation.isArrayEquation(comp.eqn)) algorithm | ||
| 809 | ✗ | dependencies := Equation.collectCrefs(Pointer.access(comp.eqn), function Slice.getDependentCrefCausalized(set = set), Expression.fakeMap); | |
| 810 | ✗ | scalarized_dependencies := Slice.getDependentCrefsPseudoArrayCausalized(BVariable.getVarName(comp.var), dependencies); | |
| 811 | ✗ | addScalarizedDependencies(scalarized_dependencies, map, jacType); | |
| 812 | then (); | ||
| 813 | |||
| 814 | case SINGLE_COMPONENT() algorithm | ||
| 815 | ✗ | dependencies := Equation.collectCrefs(Pointer.access(comp.eqn), function Slice.getDependentCrefCausalized(set = set), Expression.fakeMap); | |
| 816 | ✗ | dependencies := List.flatten(list(ComponentRef.scalarizeAll(dep, true) for dep in dependencies)); | |
| 817 | ✗ | deps_set := prepareDependencies(UnorderedSet.fromList(dependencies, ComponentRef.hash, ComponentRef.isEqual), map, jacType); | |
| 818 | ✗ | updateDependencyMap(BVariable.getVarName(comp.var), deps_set, map); | |
| 819 | then (); | ||
| 820 | |||
| 821 | case MULTI_COMPONENT() algorithm | ||
| 822 | ✗ | dependencies := Equation.collectCrefs(Pointer.access(Slice.getT(comp.eqn)), function Slice.getDependentCrefCausalized(set = set), Expression.fakeMap); | |
| 823 | ✗ | dependencies := list(ComponentRef.stripIteratorSubscripts(dep) for dep in dependencies); | |
| 824 | ✗ | dependencies := List.flatten(list(ComponentRef.scalarizeAll(dep, true) for dep in dependencies)); | |
| 825 | ✗ | deps_set := prepareDependencies(UnorderedSet.fromList(dependencies, ComponentRef.hash, ComponentRef.isEqual), map, jacType); | |
| 826 | ✗ | for var in comp.vars loop | |
| 827 | ✗ | for cref in ComponentRef.scalarizeAll(BVariable.getVarName(Slice.getT(var)), true) loop | |
| 828 | ✗ | updateDependencyMap(cref, deps_set, map); | |
| 829 | end for; | ||
| 830 | end for; | ||
| 831 | then (); | ||
| 832 | |||
| 833 | // resizable for equations - create all the single entries | ||
| 834 | case RESIZABLE_COMPONENT() guard(Equation.isForEquation(Slice.getT(comp.eqn))) algorithm | ||
| 835 | ✗ | addForLoopDependencies(Pointer.access(Slice.getT(comp.eqn)), comp.eqn.indices, comp.var_cref, var_rep, eqn_rep, var_rep_mapping, eqn_rep_mapping, map, set, jacType); | |
| 836 | then (); | ||
| 837 | |||
| 838 | // sliced for equations - create all the single entries | ||
| 839 | case SLICED_COMPONENT() guard(Equation.isForEquation(Slice.getT(comp.eqn))) algorithm | ||
| 840 | ✗ | addForLoopDependencies(Pointer.access(Slice.getT(comp.eqn)), comp.eqn.indices, comp.var_cref, var_rep, eqn_rep, var_rep_mapping, eqn_rep_mapping, map, set, jacType); | |
| 841 | then (); | ||
| 842 | |||
| 843 | // sliced array equations - create all the single entries | ||
| 844 | case SLICED_COMPONENT() guard(Equation.isArrayEquation(Slice.getT(comp.eqn))) algorithm | ||
| 845 | ✗ | eqn := Pointer.access(Slice.getT(comp.eqn)); | |
| 846 | ✗ | dependencies := Equation.collectCrefs(eqn, function Slice.getDependentCrefCausalized(set = set), Expression.fakeMap); | |
| 847 | ✗ | scalarized_dependencies := Slice.getDependentCrefsPseudoArrayCausalized(comp.var_cref, dependencies, comp.eqn.indices); | |
| 848 | ✗ | addScalarizedDependencies(scalarized_dependencies, map, jacType); | |
| 849 | then (); | ||
| 850 | |||
| 851 | // sliced regular equation. | ||
| 852 | case SLICED_COMPONENT() algorithm | ||
| 853 | ✗ | eqn := Pointer.access(Slice.getT(comp.eqn)); | |
| 854 | ✗ | dependencies := Equation.collectCrefs(eqn, function Slice.getDependentCrefCausalized(set = set), Expression.fakeMap); | |
| 855 | ✗ | dependencies := List.flatten(list(ComponentRef.scalarizeAll(dep, true) for dep in dependencies)); | |
| 856 | ✗ | deps_set := prepareDependencies(UnorderedSet.fromList(dependencies, ComponentRef.hash, ComponentRef.isEqual), map, jacType); | |
| 857 | ✗ | updateDependencyMap(comp.var_cref, deps_set, map); | |
| 858 | then (); | ||
| 859 | |||
| 860 | // sliced for equations - create all the single entries | ||
| 861 | case GENERIC_COMPONENT() guard(Equation.isForEquation(Slice.getT(comp.eqn))) algorithm | ||
| 862 | ✗ | addForLoopDependencies(Pointer.access(Slice.getT(comp.eqn)), comp.eqn.indices, comp.var_cref, var_rep, eqn_rep, var_rep_mapping, eqn_rep_mapping, map, set, jacType); | |
| 863 | then (); | ||
| 864 | |||
| 865 | case ALGEBRAIC_LOOP(strict = strict) algorithm | ||
| 866 | // traverse residual equations and collect dependencies | ||
| 867 | ✗ | deps_set := UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual); | |
| 868 | ✗ | for slice in strict.residual_eqns loop | |
| 869 | // ToDo: does this work properly for arrays? | ||
| 870 | ✗ | tmp := Equation.collectCrefs(Pointer.access(Slice.getT(slice)), function Slice.getDependentCrefCausalized(set = set), Expression.fakeMap); | |
| 871 | ✗ | eqn_ptr := Slice.getT(slice); | |
| 872 | ✗ | if Equation.isForEquation(eqn_ptr) then | |
| 873 | // if its a for equation get all dependencies corresponding to their residual. | ||
| 874 | // we do not really care for order and assume full dependency anyway | ||
| 875 | ✗ | Equation.FOR_EQUATION(iter = iter, body = {body}) := Pointer.access(eqn_ptr); | |
| 876 | ✗ | cref := Equation.getEqnName(eqn_ptr); | |
| 877 | ✗ | scalarized_dependencies := Slice.getDependentCrefsPseudoForCausalized( | |
| 878 | cref, tmp, var_rep, eqn_rep, var_rep_mapping, eqn_rep_mapping, | ||
| 879 | iter, Equation.size(eqn_ptr), slice.indices, true); | ||
| 880 | ✗ | tmp := List.flatten(list(Util.tuple22(tpl) for tpl in scalarized_dependencies)); | |
| 881 | end if; | ||
| 882 | ✗ | for dep in tmp loop | |
| 883 | ✗ | for scal in ComponentRef.scalarizeAll(dep, true) loop | |
| 884 | ✗ | UnorderedSet.add(scal, deps_set); | |
| 885 | end for; | ||
| 886 | end for; | ||
| 887 | end for; | ||
| 888 | ✗ | deps_set := prepareDependencies(deps_set, map, jacType); | |
| 889 | |||
| 890 | // collect iteration loop vars | ||
| 891 | ✗ | loop_vars := list(BVariable.getVarName(Slice.getT(var)) for var in strict.iteration_vars); | |
| 892 | |||
| 893 | // traverse inner equations and collect loop vars and dependencies | ||
| 894 | ✗ | for i in 1:arrayLength(strict.innerEquations) loop | |
| 895 | // collect inner equation dependencies | ||
| 896 | ✗ | collectCrefs(strict.innerEquations[i], var_rep, eqn_rep, var_rep_mapping, eqn_rep_mapping, map, set, jacType); | |
| 897 | |||
| 898 | // collect inner loop variables | ||
| 899 | ✗ | loop_vars := listAppend(list(BVariable.getVarName(var) for var in getVariables(strict.innerEquations[i])), loop_vars); | |
| 900 | end for; | ||
| 901 | |||
| 902 | // add all dependencies | ||
| 903 | ✗ | for cref in loop_vars loop | |
| 904 | ✗ | updateDependencyMap(cref, deps_set, map); | |
| 905 | end for; | ||
| 906 | |||
| 907 | then (); | ||
| 908 | |||
| 909 | case ALIAS() algorithm | ||
| 910 | ✗ | collectCrefs(comp.original, var_rep, eqn_rep, var_rep_mapping, eqn_rep_mapping, map, set, jacType); | |
| 911 | then (); | ||
| 912 | |||
| 913 | /* ToDo add the others and let else case fail! */ | ||
| 914 | |||
| 915 | else (); | ||
| 916 | end match; | ||
| 917 | end collectCrefs; | ||
| 918 | |||
| 919 | function addScalarizedDependencies | ||
| 920 | input list<tuple<ComponentRef, list<ComponentRef>>> scalarized_dependencies; | ||
| 921 | input UnorderedMap<ComponentRef, list<ComponentRef>> map "unordered map to save the dependencies"; | ||
| 922 | input JacobianType jacType "sets the context"; | ||
| 923 | protected | ||
| 924 | ComponentRef cref; | ||
| 925 | list<ComponentRef> dependencies; | ||
| 926 | UnorderedSet<ComponentRef> deps_set; | ||
| 927 | algorithm | ||
| 928 | ✗ | for tpl in listReverse(scalarized_dependencies) loop | |
| 929 | ✗ | (cref, dependencies) := tpl; | |
| 930 | ✗ | deps_set := prepareDependencies(UnorderedSet.fromList(dependencies, ComponentRef.hash, ComponentRef.isEqual), map, jacType); | |
| 931 | ✗ | updateDependencyMap(cref, deps_set, map); | |
| 932 | end for; | ||
| 933 | end addScalarizedDependencies; | ||
| 934 | |||
| 935 | function addForLoopDependencies | ||
| 936 | input Equation eqn; | ||
| 937 | input list<Integer> indices; | ||
| 938 | input ComponentRef var_cref; | ||
| 939 | input VariablePointers var_rep "scalarized variable representatives"; | ||
| 940 | input VariablePointers eqn_rep "scalarized equation representatives"; | ||
| 941 | input Mapping var_rep_mapping "index mapping for variable representatives"; | ||
| 942 | input Mapping eqn_rep_mapping "index mapping for equation representatives"; | ||
| 943 | input UnorderedMap<ComponentRef, list<ComponentRef>> map "unordered map to save the dependencies"; | ||
| 944 | input UnorderedSet<ComponentRef> set "unordered set of array crefs to check for relevance (index lookup)"; | ||
| 945 | input JacobianType jacType "sets the context"; | ||
| 946 | protected | ||
| 947 | Iterator iter; | ||
| 948 | Equation body; | ||
| 949 | list<ComponentRef> dependencies; | ||
| 950 | ComponentRef cref; | ||
| 951 | list<tuple<ComponentRef, list<ComponentRef>>> scalarized_dependencies; | ||
| 952 | algorithm | ||
| 953 | try | ||
| 954 | ✗ | Equation.FOR_EQUATION(iter = iter, body = {body}) := eqn; | |
| 955 | else | ||
| 956 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because the for-loop had more than one body equation:\n" + Equation.toString(eqn)}); | |
| 957 | ✗ | fail(); | |
| 958 | end try; | ||
| 959 | |||
| 960 | ✗ | dependencies := Equation.collectCrefs(eqn, function Slice.getDependentCrefCausalized(set = set), Expression.fakeMap); | |
| 961 | ✗ | if ComponentRef.isEmpty(var_cref) then | |
| 962 | ✗ | SOME(Expression.CREF(cref = cref)) := Equation.getLHS(body); | |
| 963 | else | ||
| 964 | cref := var_cref; | ||
| 965 | end if; | ||
| 966 | ✗ | scalarized_dependencies := Slice.getDependentCrefsPseudoForCausalized( | |
| 967 | cref, dependencies, var_rep, eqn_rep, var_rep_mapping, eqn_rep_mapping, | ||
| 968 | iter, Equation.size(Pointer.create(eqn)), indices, false); | ||
| 969 | ✗ | addScalarizedDependencies(scalarized_dependencies, map, jacType); | |
| 970 | end addForLoopDependencies; | ||
| 971 | |||
| 972 | function addLoopJacobian | ||
| 973 | input output StrongComponent comp; | ||
| 974 | input Option<BackendDAE> jac; | ||
| 975 | algorithm | ||
| 976 | comp := match comp | ||
| 977 | local | ||
| 978 | Tearing strict; | ||
| 979 | |||
| 980 | case ALGEBRAIC_LOOP(strict = strict) algorithm | ||
| 981 | // ToDo: update linearity here | ||
| 982 | ✗ | strict.jac := jac; | |
| 983 | ✗ | comp.strict := strict; | |
| 984 | then comp; | ||
| 985 | |||
| 986 | else algorithm | ||
| 987 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of wrong component: " + toString(comp)}); | |
| 988 | ✗ | then fail(); | |
| 989 | end match; | ||
| 990 | end addLoopJacobian; | ||
| 991 | |||
| 992 | function getLoopResiduals | ||
| 993 | input StrongComponent comp; | ||
| 994 | output list<Pointer<Variable>> residuals; | ||
| 995 | algorithm | ||
| 996 | residuals := match comp | ||
| 997 | 80 | case ALGEBRAIC_LOOP() then Tearing.getResidualVars(comp.strict); | |
| 998 | else {}; | ||
| 999 | end match; | ||
| 1000 | end getLoopResiduals; | ||
| 1001 | |||
| 1002 | function getVariables | ||
| 1003 | input StrongComponent comp; | ||
| 1004 | output list<Pointer<Variable>> vars; | ||
| 1005 | algorithm | ||
| 1006 | vars := match comp | ||
| 1007 | 1278 | case SINGLE_COMPONENT() then {comp.var}; | |
| 1008 |
4/4✓ Branch 0 taken 18 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 9 times.
|
27 | case MULTI_COMPONENT() then list(Slice.getT(v) for v in comp.vars); |
| 1009 | 217 | case SLICED_COMPONENT() then {Slice.getT(comp.var)}; | |
| 1010 | 31 | case RESIZABLE_COMPONENT() then {Slice.getT(comp.var)}; | |
| 1011 | 40 | case GENERIC_COMPONENT() then {Slice.getT(comp.var)}; | |
| 1012 | ✗ | case ENTWINED_COMPONENT() then List.flatten(list(getVariables(slice) for slice in comp.entwined_slices)); | |
| 1013 | ✗ | case ALGEBRAIC_LOOP() then Tearing.getVariables(comp.strict); | |
| 1014 | ✗ | case ALIAS() then getVariables(comp.original); | |
| 1015 | else algorithm | ||
| 1016 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of wrong component: " + toString(comp)}); | |
| 1017 | ✗ | then fail(); | |
| 1018 | end match; | ||
| 1019 | end getVariables; | ||
| 1020 | |||
| 1021 | function getVariableCrefs | ||
| 1022 | input StrongComponent comp; | ||
| 1023 | output list<ComponentRef> var_crefs; | ||
| 1024 | algorithm | ||
| 1025 | var_crefs := match comp | ||
| 1026 | 1168 | case SINGLE_COMPONENT() then {BVariable.getVarName(comp.var)}; | |
| 1027 |
4/4✓ Branch 0 taken 22 times.
✓ Branch 1 taken 11 times.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 11 times.
|
33 | case MULTI_COMPONENT() then list(BVariable.getVarName(Slice.getT(v)) for v in comp.vars); |
| 1028 | case SLICED_COMPONENT() algorithm | ||
| 1029 | // EMPTY var_cref (NLS FOR residuals): use residual var for pder classification in fullToSparsity | ||
| 1030 |
2/2✓ Branch 1 taken 14 times.
✓ Branch 2 taken 307 times.
|
321 | if ComponentRef.isEmpty(comp.var_cref) then |
| 1031 | try | ||
| 1032 | 14 | var_crefs := {BVariable.getVarName(Equation.getResidualVar(Slice.getT(comp.eqn)))}; | |
| 1033 | else | ||
| 1034 | ✗ | var_crefs := {comp.var_cref}; | |
| 1035 | end try; | ||
| 1036 | else | ||
| 1037 | 307 | var_crefs := {comp.var_cref}; | |
| 1038 | end if; | ||
| 1039 | then var_crefs; | ||
| 1040 | 139 | case RESIZABLE_COMPONENT() then {comp.var_cref}; | |
| 1041 | 46 | case GENERIC_COMPONENT() then {comp.var_cref}; | |
| 1042 | ✗ | case ENTWINED_COMPONENT() then List.flatten(list(list(BVariable.getVarName(var) for var in getVariables(slice)) for slice in comp.entwined_slices)); | |
| 1043 |
4/4✓ Branch 1 taken 58 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 58 times.
✓ Branch 4 taken 16 times.
|
74 | case ALGEBRAIC_LOOP() then list(BVariable.getVarName(var) for var in Tearing.getVariables(comp.strict)); |
| 1044 | 521 | case ALIAS() then getVariableCrefs(comp.original); | |
| 1045 | else algorithm | ||
| 1046 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of wrong component: " + toString(comp)}); | |
| 1047 | ✗ | then fail(); | |
| 1048 | end match; | ||
| 1049 | end getVariableCrefs; | ||
| 1050 | |||
| 1051 | function getVarCref | ||
| 1052 | input StrongComponent comp; | ||
| 1053 | output ComponentRef var_cref; | ||
| 1054 | algorithm | ||
| 1055 | var_cref := match comp | ||
| 1056 | ✗ | case SLICED_COMPONENT() then comp.var_cref; | |
| 1057 | ✗ | case RESIZABLE_COMPONENT() then comp.var_cref; | |
| 1058 | ✗ | case GENERIC_COMPONENT() then comp.var_cref; | |
| 1059 | ✗ | case ALIAS() then getVarCref(comp.original); | |
| 1060 | else algorithm | ||
| 1061 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of wrong component: " + toString(comp)}); | |
| 1062 | ✗ | then fail(); | |
| 1063 | end match; | ||
| 1064 | end getVarCref; | ||
| 1065 | |||
| 1066 | function getEquations | ||
| 1067 | input StrongComponent comp; | ||
| 1068 | output list<Pointer<Equation>> eqns; | ||
| 1069 | algorithm | ||
| 1070 | eqns := match comp | ||
| 1071 | 2397 | case SINGLE_COMPONENT() then {comp.eqn}; | |
| 1072 | 28 | case MULTI_COMPONENT() then {Slice.getT(comp.eqn)}; | |
| 1073 | 644 | case SLICED_COMPONENT() then {Slice.getT(comp.eqn)}; | |
| 1074 | 281 | case RESIZABLE_COMPONENT() then {Slice.getT(comp.eqn)}; | |
| 1075 | 92 | case GENERIC_COMPONENT() then {Slice.getT(comp.eqn)}; | |
| 1076 | ✗ | case ENTWINED_COMPONENT() then List.flatten(list(getEquations(slice) for slice in comp.entwined_slices)); | |
| 1077 | 32 | case ALGEBRAIC_LOOP() then Tearing.getResidualEqns(comp.strict); // + inner? | |
| 1078 | 1042 | case ALIAS() then getEquations(comp.original); | |
| 1079 | else algorithm | ||
| 1080 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of wrong component: " + toString(comp)}); | |
| 1081 | ✗ | then fail(); | |
| 1082 | end match; | ||
| 1083 | end getEquations; | ||
| 1084 | |||
| 1085 | function getSolveStatus | ||
| 1086 | input StrongComponent comp; | ||
| 1087 | output Solve.Status status; | ||
| 1088 | algorithm | ||
| 1089 | status := match comp | ||
| 1090 | 138 | case SINGLE_COMPONENT() then comp.status; | |
| 1091 | 3 | case MULTI_COMPONENT() then comp.status; | |
| 1092 | 206 | case SLICED_COMPONENT() then comp.status; | |
| 1093 | 25 | case RESIZABLE_COMPONENT() then comp.status; | |
| 1094 | case GENERIC_COMPONENT() then NBSolve.Status.EXPLICIT; | ||
| 1095 | case ENTWINED_COMPONENT() then NBSolve.Status.EXPLICIT; | ||
| 1096 | ✗ | case ALGEBRAIC_LOOP() then comp.status; | |
| 1097 | ✗ | case ALIAS() then getSolveStatus(comp.original); | |
| 1098 | else algorithm | ||
| 1099 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of wrong component: " + toString(comp)}); | |
| 1100 | ✗ | then fail(); | |
| 1101 | end match; | ||
| 1102 | end getSolveStatus; | ||
| 1103 | |||
| 1104 | function isDiscrete | ||
| 1105 | "checks if all equations are discrete" | ||
| 1106 | input StrongComponent comp; | ||
| 1107 | output Boolean b; | ||
| 1108 | algorithm | ||
| 1109 | b := match comp | ||
| 1110 | 2413 | case SINGLE_COMPONENT() then Equation.isDiscrete(comp.eqn); | |
| 1111 | // mixed algorithms assign both discrete (e.g. $SEV_0) and continuous vars; | ||
| 1112 | // treat as discrete so Jacobian computation does not try to differentiate boolean assignments | ||
| 1113 |
8/8✓ Branch 0 taken 58 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 58 times.
✓ Branch 3 taken 24 times.
✓ Branch 7 taken 22 times.
✓ Branch 8 taken 2 times.
✓ Branch 10 taken 7 times.
✓ Branch 11 taken 15 times.
|
82 | case MULTI_COMPONENT() then Equation.isDiscrete(Slice.getT(comp.eqn)) or |
| 1114 | List.any(list(Slice.getT(v) for v in comp.vars), BVariable.isDiscrete); | ||
| 1115 | 1087 | case SLICED_COMPONENT() then Equation.isDiscrete(Slice.getT(comp.eqn)); | |
| 1116 | 247 | case RESIZABLE_COMPONENT() then Equation.isDiscrete(Slice.getT(comp.eqn)); | |
| 1117 | ✗ | case ENTWINED_COMPONENT() then List.all(comp.entwined_slices, isDiscrete); | |
| 1118 | 47 | case GENERIC_COMPONENT() then Equation.isDiscrete(Slice.getT(comp.eqn)); | |
| 1119 | 29 | case ALGEBRAIC_LOOP() then comp.mixed; | |
| 1120 | 2719 | case ALIAS() then isDiscrete(comp.original); | |
| 1121 | else algorithm | ||
| 1122 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because of wrong component: " + toString(comp)}); | |
| 1123 | ✗ | then fail(); | |
| 1124 | end match; | ||
| 1125 | end isDiscrete; | ||
| 1126 | |||
| 1127 | function isDummy | ||
| 1128 | input StrongComponent comp; | ||
| 1129 | output Boolean b; | ||
| 1130 | algorithm | ||
| 1131 | b := match comp | ||
| 1132 | 2740 | case SINGLE_COMPONENT() then Equation.isDummy(Pointer.access(comp.eqn)); | |
| 1133 | 140 | case MULTI_COMPONENT() then Equation.isDummy(Pointer.access(Slice.getT(comp.eqn))); | |
| 1134 | else false; | ||
| 1135 | end match; | ||
| 1136 | end isDummy; | ||
| 1137 | |||
| 1138 | function isAlias | ||
| 1139 | input StrongComponent comp; | ||
| 1140 | output Boolean b; | ||
| 1141 | algorithm | ||
| 1142 | b := match comp | ||
| 1143 | case ALIAS() then true; | ||
| 1144 | else false; | ||
| 1145 | end match; | ||
| 1146 | end isAlias; | ||
| 1147 | |||
| 1148 | function isSingleComponent | ||
| 1149 | input StrongComponent comp; | ||
| 1150 | output Boolean b; | ||
| 1151 | algorithm | ||
| 1152 | b := match removeAlias(comp) | ||
| 1153 | case SINGLE_COMPONENT() then true; | ||
| 1154 | else false; | ||
| 1155 | end match; | ||
| 1156 | end isSingleComponent; | ||
| 1157 | |||
| 1158 | function isAlgebraicLoop | ||
| 1159 | input StrongComponent comp; | ||
| 1160 | output Boolean b; | ||
| 1161 | algorithm | ||
| 1162 | b := match removeAlias(comp) | ||
| 1163 | case ALGEBRAIC_LOOP() then true; | ||
| 1164 | else false; | ||
| 1165 | end match; | ||
| 1166 | end isAlgebraicLoop; | ||
| 1167 | |||
| 1168 | function setHomotopy | ||
| 1169 | input output StrongComponent comp; | ||
| 1170 | input Boolean homotopy; | ||
| 1171 | algorithm | ||
| 1172 | comp := match comp | ||
| 1173 | case ALGEBRAIC_LOOP() algorithm | ||
| 1174 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
|
6 | comp.homotopy := homotopy; |
| 1175 | then comp; | ||
| 1176 | else comp; | ||
| 1177 | end match; | ||
| 1178 | end setHomotopy; | ||
| 1179 | |||
| 1180 | function createPseudoScalar | ||
| 1181 | input list<Integer> comp_indices; | ||
| 1182 | input array<Integer> eqn_to_var; | ||
| 1183 | input Adjacency.Mapping mapping; | ||
| 1184 | input VariablePointers vars; | ||
| 1185 | input EquationPointers eqns; | ||
| 1186 | output StrongComponent comp; | ||
| 1187 | algorithm | ||
| 1188 | comp := match comp_indices | ||
| 1189 | local | ||
| 1190 | Integer i, var_scal_idx, var_arr_idx; | ||
| 1191 | Pointer<Variable> var; | ||
| 1192 | Pointer<Equation> eqn; | ||
| 1193 | list<Slice<VariablePointer>> comp_vars; | ||
| 1194 | list<Slice<EquationPointer>> comp_eqns; | ||
| 1195 | Tearing tearingSet; | ||
| 1196 | Slice<VariablePointer> var_slice; | ||
| 1197 | Slice<EquationPointer> eqn_slice; | ||
| 1198 | Pointer<Boolean> homotopy = Pointer.create(false); | ||
| 1199 | ComponentRef resolved_cref; | ||
| 1200 | |||
| 1201 | // Size 1 strong component | ||
| 1202 | // - case 1: sliced equation because of for-equation | ||
| 1203 | // - case 2: multi components for when/if and algorithm although its size 1 | ||
| 1204 | // - case 3: single or sliced strong component | ||
| 1205 | case {i} algorithm | ||
| 1206 | 7044 | var_scal_idx := eqn_to_var[i]; | |
| 1207 | 7044 | var_arr_idx := mapping.var_StA[var_scal_idx]; | |
| 1208 | 7044 | var := VariablePointers.getVarAt(vars, var_arr_idx); | |
| 1209 | 7044 | eqn := EquationPointers.getEqnAt(eqns, mapping.eqn_StA[i]); | |
| 1210 | |||
| 1211 |
2/2✓ Branch 1 taken 58 times.
✓ Branch 2 taken 6986 times.
|
7044 | if Equation.isForEquation(eqn) then |
| 1212 | // - case 1: sliced equation because of for-equation | ||
| 1213 | try | ||
| 1214 |
4/8✗ Branch 1 not taken.
✓ Branch 2 taken 58 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 58 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 58 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 58 times.
|
58 | ({var_slice}, {eqn_slice}) := getLoopVarsAndEqns(comp_indices, eqn_to_var, mapping, vars, eqns); |
| 1215 | else | ||
| 1216 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because single indices did not turn out to be single components."}); | |
| 1217 | ✗ | fail(); | |
| 1218 | end try; | ||
| 1219 | 58 | comp := SLICED_COMPONENT(VariablePointers.varSlice(vars, var_scal_idx, mapping.var_StA[var_scal_idx], mapping, true), var_slice, eqn_slice, NBSolve.Status.UNPROCESSED); | |
| 1220 | elseif Equation.isCompound(eqn) then | ||
| 1221 | // - case 2: multi components for when/if and algorithm although its size 1 | ||
| 1222 | 138 | comp := MULTI_COMPONENT({Slice.SLICE(var, {})}, Slice.SLICE(eqn, {}), NBSolve.Status.UNPROCESSED); | |
| 1223 | else | ||
| 1224 | // - case 3: single or sliced strong component | ||
| 1225 | try | ||
| 1226 |
4/8✗ Branch 1 not taken.
✓ Branch 2 taken 6917 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6917 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 6917 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 6917 times.
|
6917 | ({var_slice}, {eqn_slice}) := getLoopVarsAndEqns(comp_indices, eqn_to_var, mapping, vars, eqns); |
| 1227 | else | ||
| 1228 | ✗ | Error.addMessage(Error.INTERNAL_ERROR,{getInstanceName() + " failed because single indices did not turn out to be single components."}); | |
| 1229 | ✗ | fail(); | |
| 1230 | end try; | ||
| 1231 | 6917 | comp := createSliceOrSingle(VariablePointers.varSlice(vars, var_scal_idx, mapping.var_StA[var_scal_idx], mapping, true), var_slice, eqn_slice); | |
| 1232 | end if; | ||
| 1233 | then comp; | ||
| 1234 | |||
| 1235 | // Size > 1 strong component | ||
| 1236 | case _ algorithm | ||
| 1237 | 234 | (comp_vars, comp_eqns) := getLoopVarsAndEqns(comp_indices, eqn_to_var, mapping, vars, eqns); | |
| 1238 | comp := match (comp_vars, comp_eqns) | ||
| 1239 | case ({var_slice}, {eqn_slice}) guard(not (Equation.isForEquation(Slice.getT(eqn_slice)) or Equation.isAlgorithm(Slice.getT(eqn_slice)))) | ||
| 1240 | algorithm | ||
| 1241 | // var_slice can be a genuine partial slice (e.g. i_s[{1, 2}]); the bare | ||
| 1242 | // declared name loses that, so resolve the cref that actually occurs in the | ||
| 1243 | // equation with the matching size instead (SLICED_COMPONENT.var_cref is | ||
| 1244 | // documented to carry subscripts, see NBSolve.solveStrongComponent). | ||
| 1245 |
1/2✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
|
46 | resolved_cref := if Slice.isFull(var_slice) then BVariable.getVarName(Slice.getT(var_slice)) |
| 1246 | else Slice.resolveSlicedCref(BVariable.getVarName(Slice.getT(var_slice)), Pointer.access(Slice.getT(eqn_slice)), Slice.size(var_slice, function BVariable.size(resize = false))); | ||
| 1247 | 46 | then createSliceOrSingle(resolved_cref, var_slice, eqn_slice); | |
| 1248 | |||
| 1249 | // for equations that are not algebraic loops are caught earlier! Any for equation | ||
| 1250 | // getting to this point is an actual algebraic loop, unless it is a tuple that | ||
| 1251 | // assigns a variable to each of its outputs in every iteration | ||
| 1252 | case (_, {eqn_slice}) guard(not Equation.isForEquation(Slice.getT(eqn_slice)) or Equation.isRecordOrTupleEquation(Slice.getT(eqn_slice))) | ||
| 1253 | 92 | then MULTI_COMPONENT( | |
| 1254 | vars = comp_vars, | ||
| 1255 | eqn = eqn_slice, | ||
| 1256 | status = NBSolve.Status.UNPROCESSED | ||
| 1257 | ); | ||
| 1258 | |||
| 1259 | else algorithm | ||
| 1260 | 96 | tearingSet := Tearing.TEARING_SET( | |
| 1261 | iteration_vars = comp_vars, | ||
| 1262 | residual_eqns = comp_eqns, | ||
| 1263 | innerEquations = listArray({}), | ||
| 1264 | jac = NONE()); | ||
| 1265 |
2/2✓ Branch 0 taken 1659 times.
✓ Branch 1 taken 96 times.
|
1755 | for eqn in comp_eqns loop |
| 1266 | 1659 | Equation.map(Pointer.access(Slice.getT(eqn)), function Initialization.containsHomotopyCall(b = homotopy)); | |
| 1267 | end for; | ||
| 1268 | 96 | then ALGEBRAIC_LOOP( | |
| 1269 | idx = -1, | ||
| 1270 | strict = tearingSet, | ||
| 1271 | casual = NONE(), | ||
| 1272 | linear = false, | ||
| 1273 | mixed = false, | ||
| 1274 | homotopy = Pointer.access(homotopy), | ||
| 1275 | status = NBSolve.Status.IMPLICIT, | ||
| 1276 | implicitlyCreated = false); | ||
| 1277 | end match; | ||
| 1278 | then comp; | ||
| 1279 | |||
| 1280 | else algorithm | ||
| 1281 | ✗ | Error.addMessage(Error.INTERNAL_ERROR, {getInstanceName() + " failed."}); | |
| 1282 | ✗ | then fail(); | |
| 1283 | end match; | ||
| 1284 | end createPseudoScalar; | ||
| 1285 | |||
| 1286 | function createSliceOrSingle | ||
| 1287 | input ComponentRef cref; | ||
| 1288 | input Slice<VariablePointer> var_slice; | ||
| 1289 | input Slice<EquationPointer> eqn_slice; | ||
| 1290 | output StrongComponent comp; | ||
| 1291 | algorithm | ||
| 1292 |
5/6✓ Branch 1 taken 5704 times.
✓ Branch 2 taken 1855 times.
✓ Branch 4 taken 5704 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5364 times.
✓ Branch 8 taken 340 times.
|
7559 | if Slice.isFull(var_slice) and Slice.isFull(eqn_slice) and not ComponentRef.hasSubscripts(cref) then |
| 1293 | 5364 | comp := SINGLE_COMPONENT( | |
| 1294 | var = Slice.getT(var_slice), | ||
| 1295 | eqn = Slice.getT(eqn_slice), | ||
| 1296 | status = NBSolve.Status.UNPROCESSED); | ||
| 1297 | else | ||
| 1298 | 2195 | comp := SLICED_COMPONENT( | |
| 1299 | var_cref = cref, | ||
| 1300 | var = var_slice, | ||
| 1301 | eqn = eqn_slice, | ||
| 1302 | status = NBSolve.Status.UNPROCESSED); | ||
| 1303 | end if; | ||
| 1304 | end createSliceOrSingle; | ||
| 1305 | |||
| 1306 | // ############################################################ | ||
| 1307 | // Protected Functions and Types | ||
| 1308 | // ############################################################ | ||
| 1309 | |||
| 1310 | protected | ||
| 1311 | function getLoopVarsAndEqns | ||
| 1312 | "adds the equation and matched variable to accumulated lists. | ||
| 1313 | used to collect algebraic loops. | ||
| 1314 | ToDo: currently assumes full dependency - update with Slice structures!" | ||
| 1315 | input list<Integer> comp_indices; | ||
| 1316 | input array<Integer> eqn_to_var; | ||
| 1317 | input Adjacency.Mapping mapping; | ||
| 1318 | input VariablePointers vars; | ||
| 1319 | input EquationPointers eqns; | ||
| 1320 | output list<Slice<VariablePointer>> acc_vars = {}; | ||
| 1321 | output list<Slice<EquationPointer>> acc_eqns = {}; | ||
| 1322 | protected | ||
| 1323 | Integer var_idx, var_arr_idx, var_scal_idx, eqn_arr_idx, eqn_scal_idx; | ||
| 1324 | list<Integer> idx_lst; | ||
| 1325 | Pointer<Variable> var; | ||
| 1326 | Pointer<Equation> eqn; | ||
| 1327 | Integer len_comps = listLength(comp_indices); | ||
| 1328 | UnorderedMap<Integer, Slice.IntLst> var_map = UnorderedMap.new<Slice.IntLst>(Util.id, intEq, len_comps); | ||
| 1329 | UnorderedMap<Integer, Slice.IntLst> eqn_map = UnorderedMap.new<Slice.IntLst>(Util.id, intEq, len_comps); | ||
| 1330 | algorithm | ||
| 1331 | // store all component var and eqn indices in maps | ||
| 1332 |
2/2✓ Branch 0 taken 9953 times.
✓ Branch 1 taken 7209 times.
|
17162 | for eqn_idx in comp_indices loop |
| 1333 | 9953 | var_idx := eqn_to_var[eqn_idx]; | |
| 1334 | 9953 | var_arr_idx := mapping.var_StA[var_idx]; | |
| 1335 | 9953 | eqn_arr_idx := mapping.eqn_StA[eqn_idx]; | |
| 1336 | |||
| 1337 | // collect variable and equation slices | ||
| 1338 | 9953 | idx_lst := UnorderedMap.getOrDefault(var_arr_idx, var_map, {}); | |
| 1339 | 9953 | UnorderedMap.add(var_arr_idx, var_idx :: idx_lst, var_map); | |
| 1340 | 9953 | idx_lst := UnorderedMap.getOrDefault(eqn_arr_idx, eqn_map, {}); | |
| 1341 | 9953 | UnorderedMap.add(eqn_arr_idx, eqn_idx :: idx_lst, eqn_map); | |
| 1342 | end for; | ||
| 1343 | |||
| 1344 | // extract variables and equations from maps | ||
| 1345 | // check if slices are full and reduce them to base 0 indexing | ||
| 1346 | // sort the index lists so we can compare two equal loops, order doesn't matter for evaluating inside alg. loops | ||
| 1347 |
2/2✓ Branch 1 taken 8783 times.
✓ Branch 2 taken 7209 times.
|
15992 | for tpl in UnorderedMap.toList(var_map) loop |
| 1348 | 8783 | (var_arr_idx, idx_lst) := tpl; | |
| 1349 | 8783 | (var_scal_idx, _) := mapping.var_AtS[var_arr_idx]; | |
| 1350 | 8783 | var := VariablePointers.getVarAt(vars, var_arr_idx); | |
| 1351 |
6/6✓ Branch 2 taken 1989 times.
✓ Branch 3 taken 6794 times.
✓ Branch 4 taken 2378 times.
✓ Branch 5 taken 1989 times.
✓ Branch 6 taken 2378 times.
✓ Branch 7 taken 1989 times.
|
11161 | idx_lst := if listLength(idx_lst) == BVariable.size(var) then {} else list(i - var_scal_idx for i in idx_lst); |
| 1352 | 8783 | acc_vars := Slice.SLICE(var, sortAscending(idx_lst)) :: acc_vars; | |
| 1353 | end for; | ||
| 1354 |
2/2✓ Branch 1 taken 8772 times.
✓ Branch 2 taken 7209 times.
|
15981 | for tpl in UnorderedMap.toList(eqn_map) loop |
| 1355 | 8772 | (eqn_arr_idx, idx_lst) := tpl; | |
| 1356 | 8772 | (eqn_scal_idx, _) := mapping.eqn_AtS[eqn_arr_idx]; | |
| 1357 | 8772 | eqn := EquationPointers.getEqnAt(eqns, eqn_arr_idx); | |
| 1358 |
6/6✓ Branch 2 taken 200 times.
✓ Branch 3 taken 8572 times.
✓ Branch 4 taken 392 times.
✓ Branch 5 taken 200 times.
✓ Branch 6 taken 392 times.
✓ Branch 7 taken 200 times.
|
9164 | idx_lst := if listLength(idx_lst) == Equation.size(eqn) then {} else list(i - eqn_scal_idx for i in idx_lst); |
| 1359 | 8772 | acc_eqns := Slice.SLICE(eqn, sortAscending(idx_lst)) :: acc_eqns; | |
| 1360 | end for; | ||
| 1361 | end getLoopVarsAndEqns; | ||
| 1362 | |||
| 1363 | function sortAscending | ||
| 1364 | "List.sort(lst, intGt) without the merge sort's allocations" | ||
| 1365 | input list<Integer> lst; | ||
| 1366 | output list<Integer> sorted; | ||
| 1367 | algorithm | ||
| 1368 |
4/4✓ Branch 0 taken 2189 times.
✓ Branch 1 taken 15366 times.
✓ Branch 3 taken 153 times.
✓ Branch 4 taken 2036 times.
|
17555 | if listEmpty(lst) or listEmpty(listRest(lst)) then |
| 1369 | sorted := lst; | ||
| 1370 | else | ||
| 1371 | 153 | sorted := arrayList(Array.heapSort(listArray(lst))); | |
| 1372 | end if; | ||
| 1373 | end sortAscending; | ||
| 1374 | |||
| 1375 | function updateDependencyMap | ||
| 1376 | input ComponentRef cref "cref representing current equation"; | ||
| 1377 | input UnorderedSet<ComponentRef> dependencies "the dependency crefs"; | ||
| 1378 | input UnorderedMap<ComponentRef, list<ComponentRef>> map "unordered map to save the dependencies"; | ||
| 1379 | protected | ||
| 1380 | Boolean removed; | ||
| 1381 | algorithm | ||
| 1382 | ✗ | removed := UnorderedSet.remove(cref, dependencies) "remove self dependency"; | |
| 1383 | ✗ | UnorderedMap.add(cref, UnorderedSet.toList(dependencies), map) "update the current value (res/tmp) --> {independent vars}"; | |
| 1384 | ✗ | if removed then UnorderedSet.addNew(cref, dependencies); end if "restore dependencies"; | |
| 1385 | end updateDependencyMap; | ||
| 1386 | |||
| 1387 | function prepareDependencies | ||
| 1388 | input output UnorderedSet<ComponentRef> dependencies; | ||
| 1389 | input UnorderedMap<ComponentRef, list<ComponentRef>> map; | ||
| 1390 | input JacobianType jacType; | ||
| 1391 | protected | ||
| 1392 | function addSubDependencies | ||
| 1393 | input ComponentRef dep; | ||
| 1394 | input UnorderedMap<ComponentRef, list<ComponentRef>> map; | ||
| 1395 | input BVariable.checkVar checkFn; | ||
| 1396 | input output UnorderedSet<ComponentRef> set; | ||
| 1397 | algorithm | ||
| 1398 | // if the dependency is a state add itself, otherwise add the dependencies already saved | ||
| 1399 | // (those are known to be states). ToDo: avoid this check by adding state self dependency beforehand? | ||
| 1400 | ✗ | if BVariable.checkCref(dep, checkFn, sourceInfo()) then | |
| 1401 | ✗ | UnorderedSet.add(dep, set); | |
| 1402 | else | ||
| 1403 | ✗ | for tmp in UnorderedMap.getSafe(dep, map, sourceInfo()) loop | |
| 1404 | ✗ | UnorderedSet.add(tmp, set); | |
| 1405 | end for; | ||
| 1406 | end if; | ||
| 1407 | end addSubDependencies; | ||
| 1408 | algorithm | ||
| 1409 | ✗ | dependencies := UnorderedSet.selfMap(dependencies, function ComponentRef.mapExp(func = Expression.replaceResizableParameter)); | |
| 1410 | ✗ | dependencies := UnorderedSet.selfMap(dependencies, function ComponentRef.simplifySubscripts(trim = false)); | |
| 1411 | // replace non derivative dependencies with their previous dependencies | ||
| 1412 | // (be careful with algebraic loops. this here assumes that cyclic dependencies have already been resolved) | ||
| 1413 | dependencies := match jacType | ||
| 1414 | case NBJacobian.JacobianType.ODE | ||
| 1415 | ✗ | then UnorderedSet.fold(dependencies, function addSubDependencies(map = map, checkFn = BVariable.isState), UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual)); | |
| 1416 | // TODO: for optimization these checks / checkFn are not valid yet, add free time | ||
| 1417 | case NBJacobian.JacobianType.OPT_LFG | ||
| 1418 | ✗ | then UnorderedSet.fold(dependencies, function addSubDependencies(map = map, checkFn = BVariable.isStateOrOptimizable), UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual)); | |
| 1419 | case NBJacobian.JacobianType.OPT_MRF | ||
| 1420 | ✗ | then UnorderedSet.fold(dependencies, function addSubDependencies(map = map, checkFn = BVariable.isStateOrOptimizable), UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual)); | |
| 1421 | case NBJacobian.JacobianType.OPT_R0 | ||
| 1422 | ✗ | then UnorderedSet.fold(dependencies, function addSubDependencies(map = map, checkFn = BVariable.isStateOrOptimizable), UnorderedSet.new(ComponentRef.hash, ComponentRef.isEqual)); | |
| 1423 | else dependencies; | ||
| 1424 | end match; | ||
| 1425 | end prepareDependencies; | ||
| 1426 | |||
| 1427 | annotation(__OpenModelica_Interface="nbackend"); | ||
| 1428 | end NBStrongComponent; | ||
| 1429 |