OMCompiler/Compiler/BackEnd/Tearing.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 Tearing | ||
| 37 | " file: Tearing.mo | ||
| 38 | package: Tearing | ||
| 39 | description: Tearing contains functions used for tear strong connected components. | ||
| 40 | Implemented Methods are: | ||
| 41 | - omc tearing developed by TU Dresden: Frenkel,Schubert | ||
| 42 | - Cellier Tearing" | ||
| 43 | |||
| 44 | |||
| 45 | import BackendDAE; | ||
| 46 | import DAE; | ||
| 47 | |||
| 48 | protected | ||
| 49 | import AdjacencyMatrix; | ||
| 50 | import Array; | ||
| 51 | import BackendDAEEXT; | ||
| 52 | import BackendDAEOptimize; | ||
| 53 | import BackendDAEUtil; | ||
| 54 | import BackendDump; | ||
| 55 | import BackendEquation; | ||
| 56 | import BackendVariable; | ||
| 57 | import ComponentReference; | ||
| 58 | import ComponentReferenceBasics; | ||
| 59 | import Config; | ||
| 60 | import DoubleEnded; | ||
| 61 | import DumpGraphML; | ||
| 62 | import Error; | ||
| 63 | import ExecStat.execStat; | ||
| 64 | import Expression; | ||
| 65 | import ExpressionBasics; | ||
| 66 | import ExpressionSimplify; | ||
| 67 | import ExpressionSolve; | ||
| 68 | import Flags; | ||
| 69 | import GCExt; | ||
| 70 | import Global; | ||
| 71 | import List; | ||
| 72 | import Matching; | ||
| 73 | import MetaModelica.Dangerous; | ||
| 74 | import Mutable; | ||
| 75 | import UnorderedSet; | ||
| 76 | import Util; | ||
| 77 | import Sorting; | ||
| 78 | import System; | ||
| 79 | import ElementSource; | ||
| 80 | import SimCodeCodegenUtil; | ||
| 81 | |||
| 82 | // ============================================================================= | ||
| 83 | // section for type definitions | ||
| 84 | // | ||
| 85 | // | ||
| 86 | // ============================================================================= | ||
| 87 | |||
| 88 | protected constant String BORDER = "****************************************"; | ||
| 89 | protected constant String UNDERLINE = "========================================"; | ||
| 90 | protected constant list<String> withLSS = {"C", "wasm-jit", "wasm"} "targets that provide a linear sparse solver"; | ||
| 91 | protected constant list<String> withNSS = {"C", "wasm-jit", "wasm"} "targets that provide a nonlinear sparse solver"; | ||
| 92 | |||
| 93 | uniontype TearingMethod | ||
| 94 | record MINIMAL_TEARING "Only tear discrete variables from loops" | ||
| 95 | end MINIMAL_TEARING; | ||
| 96 | record OMC_TEARING end OMC_TEARING; | ||
| 97 | record CELLIER_TEARING end CELLIER_TEARING; | ||
| 98 | record TOTAL_TEARING end TOTAL_TEARING; | ||
| 99 | record USER_DEFINED_TEARING end USER_DEFINED_TEARING; | ||
| 100 | end TearingMethod; | ||
| 101 | |||
| 102 | // ============================================================================= | ||
| 103 | // section for all public functions | ||
| 104 | // | ||
| 105 | // main function to divide to the selected tearing method | ||
| 106 | // ============================================================================= | ||
| 107 | |||
| 108 | public function tearingSystem "author: Frenkel TUD 2012-05" | ||
| 109 | input BackendDAE.BackendDAE inDAE; | ||
| 110 | output BackendDAE.BackendDAE outDAE; | ||
| 111 | protected | ||
| 112 | String methodString = Config.getTearingMethod(); | ||
| 113 | TearingMethod method; | ||
| 114 | BackendDAE.BackendDAEType DAEtype; | ||
| 115 | Integer strongComponentIndex = System.tmpTickIndex(Global.strongComponent_index); | ||
| 116 | algorithm | ||
| 117 | // Check if maxSizeLinearTearing maxSizeNonlinearTearing flag is illegal | ||
| 118 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3938 times.
|
3938 | if (Flags.getConfigInt(Flags.MAX_SIZE_LINEAR_TEARING) < 0) then |
| 119 | ✗ | Error.addMessage(Error.INVALID_FLAG_TYPE, {"maxSizeLinearTearing", "non-negative integer", intString(Flags.getConfigInt(Flags.MAX_SIZE_LINEAR_TEARING))}); | |
| 120 | ✗ | fail(); | |
| 121 | elseif (Flags.getConfigInt(Flags.MAX_SIZE_NONLINEAR_TEARING) < 0) then | ||
| 122 | ✗ | Error.addMessage(Error.INVALID_FLAG_TYPE, {"maxSizeNonlinearTearing", "non-negative integer", intString(Flags.getConfigInt(Flags.MAX_SIZE_NONLINEAR_TEARING))}); | |
| 123 | ✗ | fail(); | |
| 124 | end if; | ||
| 125 | |||
| 126 | // get method function and traverse systems | ||
| 127 | try | ||
| 128 | 3938 | method := getTearingMethod(methodString); | |
| 129 |
3/4✓ Branch 1 taken 3936 times.
✓ Branch 2 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 3936 times.
|
3938 | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 130 | 2 | BackendDAE.SHARED(backendDAEType=DAEtype) := inDAE.shared; | |
| 131 | 2 | print("\n\n\n\n" + UNDERLINE + UNDERLINE + "\nCalling Tearing for " + | |
| 132 | BackendDump.printBackendDAEType2String(DAEtype) + | ||
| 133 | "!\n" + UNDERLINE + UNDERLINE + "\n"); | ||
| 134 | end if; | ||
| 135 | 3938 | (outDAE, strongComponentIndex) := BackendDAEUtil.mapEqSystemAndFold(inDAE, function tearingSystemWork(tearingMethod = method), strongComponentIndex); | |
| 136 | 3938 | System.tmpTickSetIndex(strongComponentIndex, Global.strongComponent_index); | |
| 137 | else | ||
| 138 | ✗ | Error.addInternalError(getInstanceName() + " failed", sourceInfo()); | |
| 139 | ✗ | fail(); | |
| 140 | end try; | ||
| 141 | end tearingSystem; | ||
| 142 | |||
| 143 | // ============================================================================= | ||
| 144 | // protected | ||
| 145 | // | ||
| 146 | // | ||
| 147 | // ============================================================================= | ||
| 148 | |||
| 149 | protected function getTearingMethod | ||
| 150 | input String inTearingMethod; | ||
| 151 | output TearingMethod outTearingMethod; | ||
| 152 | algorithm | ||
| 153 | outTearingMethod := match inTearingMethod | ||
| 154 | case "minimalTearing" then MINIMAL_TEARING(); | ||
| 155 | case "omcTearing" then OMC_TEARING(); | ||
| 156 | case "cellier" then CELLIER_TEARING(); | ||
| 157 | |||
| 158 | else algorithm | ||
| 159 | ✗ | Error.addInternalError(getInstanceName() + " got invalid name \"" + inTearingMethod + "\".", sourceInfo()); | |
| 160 | ✗ | then fail(); | |
| 161 | end match; | ||
| 162 | end getTearingMethod; | ||
| 163 | |||
| 164 | protected function callTearingMethod | ||
| 165 | input TearingMethod inTearingMethod; | ||
| 166 | input BackendDAE.EqSystem isyst; | ||
| 167 | input BackendDAE.Shared ishared; | ||
| 168 | input list<Integer> eindex; | ||
| 169 | input list<Integer> vindx; | ||
| 170 | input BackendDAE.FullJacobian ojac; | ||
| 171 | input BackendDAE.JacobianType jacType; | ||
| 172 | input Boolean mixedSystem; | ||
| 173 | input Integer strongComponentIndex; | ||
| 174 | output BackendDAE.StrongComponent ocomp; | ||
| 175 | output Boolean outRunMatching; | ||
| 176 | protected | ||
| 177 | constant Boolean debug = false; | ||
| 178 | list<Integer> userTVars = {}, userResiduals = {}; | ||
| 179 | TearingMethod tearingMethod = inTearingMethod; | ||
| 180 | algorithm | ||
| 181 | |||
| 182 | // Check for total tearing for this component | ||
| 183 |
2/2✓ Branch 2 taken 2025 times.
✓ Branch 3 taken 1 time.
|
2026 | if listMember(strongComponentIndex, Flags.getConfigIntList(Flags.TOTAL_TEARING)) then |
| 184 | tearingMethod := TOTAL_TEARING(); | ||
| 185 | else | ||
| 186 | // Get users tearing sets if existing | ||
| 187 | 2025 | userTVars := Flags.getConfigIntList(Flags.SET_TEARING_VARS); | |
| 188 | 2025 | userResiduals := Flags.getConfigIntList(Flags.SET_RESIDUAL_EQNS); | |
| 189 | 2025 | (userTVars, userResiduals) := getUserTearingSet(userTVars, userResiduals, strongComponentIndex); | |
| 190 | |||
| 191 | // Check for user defined tearing for this component | ||
| 192 |
3/4✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2024 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
|
2025 | if not listEmpty(userTVars) and not listEmpty(userResiduals) then |
| 193 | tearingMethod := USER_DEFINED_TEARING(); | ||
| 194 | end if; | ||
| 195 | end if; | ||
| 196 | |||
| 197 | // Call the appropriate tearing method | ||
| 198 | (ocomp, outRunMatching) := match tearingMethod | ||
| 199 | case OMC_TEARING() | ||
| 200 | algorithm | ||
| 201 |
2/4✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 35 times.
|
35 | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 202 | ✗ | print("\nTearing type: heuristic\n"); | |
| 203 | ✗ | print("Tearing strictness: " + Flags.getConfigString(Flags.TEARING_STRICTNESS) + "\n"); | |
| 204 | end if; | ||
| 205 | 35 | (ocomp,outRunMatching) := omcTearing(isyst, ishared, eindex, vindx, ojac, jacType, mixedSystem); | |
| 206 | if debug then execStat("Tearing.omcTearing"); end if; | ||
| 207 | then (ocomp,outRunMatching); | ||
| 208 | |||
| 209 | case CELLIER_TEARING() | ||
| 210 | algorithm | ||
| 211 |
3/4✓ Branch 1 taken 1954 times.
✓ Branch 2 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1954 times.
|
1956 | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 212 | 2 | print("\nTearing type: heuristic\n"); | |
| 213 | 2 | print("Tearing strictness: " + Flags.getConfigString(Flags.TEARING_STRICTNESS) + "\n"); | |
| 214 | end if; | ||
| 215 | 1956 | (ocomp,outRunMatching) := CellierTearing(isyst, ishared, eindex, vindx, userTVars, ojac, jacType, mixedSystem, strongComponentIndex); | |
| 216 | if debug then execStat("Tearing.CellierTearing"); end if; | ||
| 217 | then (ocomp,outRunMatching); | ||
| 218 | |||
| 219 | case TOTAL_TEARING() | ||
| 220 | algorithm | ||
| 221 |
2/4✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 time.
|
1 | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 222 | ✗ | print("\nTearing type: total\n"); | |
| 223 | ✗ | print("Tearing strictness: " + Flags.getConfigString(Flags.TEARING_STRICTNESS) + "\n"); | |
| 224 | end if; | ||
| 225 | 1 | (ocomp,outRunMatching) := totalTearing(isyst, ishared, eindex, vindx, ojac, jacType, mixedSystem); | |
| 226 | if debug then execStat("Tearing.totalTearing"); end if; | ||
| 227 | then (ocomp,outRunMatching); | ||
| 228 | |||
| 229 | case MINIMAL_TEARING() | ||
| 230 | algorithm | ||
| 231 |
2/4✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 34 times.
|
34 | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 232 | ✗ | print("\nTearing type: minimal\n"); | |
| 233 | end if; | ||
| 234 | 34 | ocomp := minimalTearing(isyst, ishared, eindex, vindx, jacType, mixedSystem); | |
| 235 | if debug then execStat("Tearing.minimalTearing"); end if; | ||
| 236 | 34 | then (ocomp, true); | |
| 237 | |||
| 238 | case USER_DEFINED_TEARING() | ||
| 239 | algorithm | ||
| 240 | ✗ | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 241 | ✗ | print("\nTearing type: user defined\n"); | |
| 242 | ✗ | print("Tearing strictness: " + Flags.getConfigString(Flags.TEARING_STRICTNESS) + "\n"); | |
| 243 | end if; | ||
| 244 | ✗ | (ocomp,outRunMatching) := userDefinedTearing(isyst, ishared, eindex, vindx, ojac, jacType, mixedSystem, userTVars, userResiduals); | |
| 245 | if debug then execStat("Tearing.userDefinedTearing"); end if; | ||
| 246 | then (ocomp,outRunMatching); | ||
| 247 | end match; | ||
| 248 | end callTearingMethod; | ||
| 249 | |||
| 250 | protected function tearingSystemWork "author: Frenkel TUD 2012-05" | ||
| 251 | input TearingMethod tearingMethod; | ||
| 252 | input BackendDAE.EqSystem isyst; | ||
| 253 | input BackendDAE.Shared inShared; | ||
| 254 | input Integer inStrongComponentIndex; | ||
| 255 | output BackendDAE.EqSystem osyst; | ||
| 256 | output BackendDAE.Shared outShared = inShared "unused"; | ||
| 257 | output Integer outStrongComponentIndex; | ||
| 258 | protected | ||
| 259 | BackendDAE.StrongComponents comps; | ||
| 260 | Boolean runMatching; | ||
| 261 | array<Integer> ass1, ass2; | ||
| 262 | algorithm | ||
| 263 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 53245 times.
|
53245 | BackendDAE.EQSYSTEM(matching=BackendDAE.MATCHING(ass1=ass1, ass2=ass2, comps=comps)) := isyst; |
| 264 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 53245 times.
|
53245 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 265 | ✗ | print("\n" + BORDER + "\nBEGINNING of traverseComponents\n\n"); | |
| 266 | end if; | ||
| 267 | |||
| 268 | 53245 | (comps, runMatching, outStrongComponentIndex) := traverseComponents(comps, isyst, inShared, tearingMethod, inStrongComponentIndex); | |
| 269 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 53245 times.
|
53245 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 270 | ✗ | print("\nEND of traverseComponents\n" + BORDER + "\n\n"); | |
| 271 | end if; | ||
| 272 |
2/2✓ Branch 0 taken 716 times.
✓ Branch 1 taken 52529 times.
|
53245 | osyst := if runMatching then BackendDAEUtil.setEqSystMatching(isyst, BackendDAE.MATCHING(ass1, ass2, comps)) else isyst; |
| 273 | end tearingSystemWork; | ||
| 274 | |||
| 275 | protected function traverseComponents "author: Frenkel TUD 2012-05" | ||
| 276 | input BackendDAE.StrongComponents inComps; | ||
| 277 | input BackendDAE.EqSystem isyst; | ||
| 278 | input BackendDAE.Shared ishared; | ||
| 279 | input TearingMethod inMethod; | ||
| 280 | input Integer strongComponentIndexIn; | ||
| 281 | output BackendDAE.StrongComponents oComps; | ||
| 282 | output Boolean outRunMatching = false; | ||
| 283 | output Integer strongComponentIndexOut = strongComponentIndexIn; | ||
| 284 | algorithm | ||
| 285 |
4/4✓ Branch 0 taken 160352 times.
✓ Branch 1 taken 53245 times.
✓ Branch 2 taken 160352 times.
✓ Branch 3 taken 53245 times.
|
213597 | oComps := list(match co |
| 286 | local | ||
| 287 | BackendDAE.StrongComponent comp; | ||
| 288 | Boolean b; | ||
| 289 | case comp | ||
| 290 | algorithm | ||
| 291 | 160352 | (comp, b, strongComponentIndexOut) := traverseComponent(comp, isyst, ishared, inMethod, strongComponentIndexOut); | |
| 292 |
4/4✓ Branch 0 taken 125499 times.
✓ Branch 1 taken 34853 times.
✓ Branch 2 taken 124783 times.
✓ Branch 3 taken 716 times.
|
160352 | outRunMatching := outRunMatching or b; |
| 293 | then comp; | ||
| 294 | end match for co in inComps); | ||
| 295 | end traverseComponents; | ||
| 296 | |||
| 297 | protected function traverseComponent "author: Frenkel TUD 2012-05" | ||
| 298 | input BackendDAE.StrongComponent inComp; | ||
| 299 | input BackendDAE.EqSystem isyst; | ||
| 300 | input BackendDAE.Shared ishared; | ||
| 301 | input TearingMethod inMethod; | ||
| 302 | input Integer strongComponentIndexIn; | ||
| 303 | output BackendDAE.StrongComponent oComp; | ||
| 304 | output Boolean outRunMatching; | ||
| 305 | output Integer strongComponentIndexOut = strongComponentIndexIn; | ||
| 306 | protected | ||
| 307 | constant Boolean debug = false; | ||
| 308 | Boolean debugFlag = Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE); | ||
| 309 | algorithm | ||
| 310 | strongComponentIndexOut := match inComp | ||
| 311 | case BackendDAE.EQUATIONSYSTEM(jac=BackendDAE.FULL_JACOBIAN()) algorithm | ||
| 312 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2038 times.
|
2040 | if debugFlag then |
| 313 | 2 | print("Handle strong component with index: " + intString(strongComponentIndexOut+1) + "\n"); | |
| 314 |
1/2✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
2 | if not listMember(strongComponentIndexOut+1, Flags.getConfigIntList(Flags.NO_TEARING_FOR_COMPONENT)) then |
| 315 | 2 | print("To disable tearing of this component use '--noTearingForComponent=" + intString(strongComponentIndexOut+1) + "'.\n"); | |
| 316 | end if; | ||
| 317 | end if; | ||
| 318 | 2040 | then (strongComponentIndexOut + 1); | |
| 319 | else strongComponentIndexOut; | ||
| 320 | end match; | ||
| 321 | |||
| 322 | (oComp, outRunMatching) := match inComp | ||
| 323 | local | ||
| 324 | list<Integer> eindex, vindx; | ||
| 325 | Option<list<tuple<Integer, Integer, BackendDAE.Equation>>> ojac; | ||
| 326 | BackendDAE.JacobianType jacType; | ||
| 327 | Boolean mixedSystem; | ||
| 328 | Boolean isLinear, useTearing; | ||
| 329 | |||
| 330 | // Tearing | ||
| 331 | case BackendDAE.EQUATIONSYSTEM(eqns=eindex, vars=vindx, jac=BackendDAE.FULL_JACOBIAN(ojac), jacType=jacType, mixedSystem=mixedSystem) algorithm | ||
| 332 | 2040 | isLinear := BackendDAEUtil.getLinearfromJacType(jacType); | |
| 333 | 2040 | useTearing := checkTearingSettings(isLinear, strongComponentIndexOut, listLength(vindx)); | |
| 334 |
2/2✓ Branch 0 taken 2026 times.
✓ Branch 1 taken 14 times.
|
2040 | if useTearing then |
| 335 | // do some printing | ||
| 336 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2024 times.
|
2026 | if debugFlag then |
| 337 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
4 | print("\nTearing of " + (if isLinear then "LINEAR" else "NONLINEAR") + " component\n"); |
| 338 | () := match (Flags.isSet(Flags.TEARING_DUMPVERBOSE), Flags.isSet(Flags.ITERATION_VARS)) | ||
| 339 | case (false, false) algorithm | ||
| 340 | 2 | print("Use Flag '-d=tearingdumpV' and '-d=iterationVars' for more details\n\n"); | |
| 341 | then (); | ||
| 342 | case (false, true) algorithm | ||
| 343 | ✗ | print("Use Flag '-d=tearingdumpV' for more details\n\n"); | |
| 344 | then (); | ||
| 345 | case (true, false) algorithm | ||
| 346 | ✗ | print("Use Flag '-d=iterationVars' for more details\n\n"); | |
| 347 | then (); | ||
| 348 | case (true, true) algorithm | ||
| 349 | ✗ | print("\n"); | |
| 350 | then (); | ||
| 351 | end match; | ||
| 352 | end if; | ||
| 353 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2026 times.
|
2026 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 354 | ✗ | print("Jacobian:\n" + BackendDump.dumpJacobianStr(ojac) + "\n\n"); | |
| 355 | end if; | ||
| 356 | if debug then | ||
| 357 | execStat("Tearing.traverseComponent " + (if isLinear then "LS" else "NLS") + " start"); | ||
| 358 | end if; | ||
| 359 | |||
| 360 | // try the actual tearing | ||
| 361 | try | ||
| 362 | 2026 | oComp := callTearingMethod(inMethod, isyst, ishared, eindex, vindx, ojac, jacType, mixedSystem, strongComponentIndexOut); | |
| 363 | outRunMatching := true; | ||
| 364 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 1836 times.
|
1844 | if not tearingPaysOff(oComp, ishared, eindex, vindx, ojac, jacType, strongComponentIndexOut, isLinear) then |
| 365 | oComp := inComp; | ||
| 366 | outRunMatching := false; | ||
| 367 | end if; | ||
| 368 | else | ||
| 369 | oComp := inComp; | ||
| 370 | outRunMatching := false; | ||
| 371 | end try; | ||
| 372 | else | ||
| 373 | oComp := inComp; | ||
| 374 | outRunMatching := false; | ||
| 375 | end if; | ||
| 376 | then (oComp, outRunMatching); | ||
| 377 | |||
| 378 | // no component for tearing | ||
| 379 | else (inComp, false); | ||
| 380 | end match; | ||
| 381 | end traverseComponent; | ||
| 382 | |||
| 383 | |||
| 384 | protected function checkTearingSettings | ||
| 385 | "Checks if we want to do tearing for the current component. | ||
| 386 | It will also issue optional maesages if not." | ||
| 387 | input Boolean isLinear; | ||
| 388 | input Integer strongComponentIndex; | ||
| 389 | input Integer numVars; | ||
| 390 | output Boolean activateTearing = false; | ||
| 391 | protected | ||
| 392 | Boolean debugFlag = Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE); | ||
| 393 | Integer maxSize; | ||
| 394 | Boolean isDense; | ||
| 395 | Boolean hasSparseSolver; | ||
| 396 | Boolean forcedTearing; | ||
| 397 | algorithm | ||
| 398 |
2/2✓ Branch 0 taken 916 times.
✓ Branch 1 taken 1124 times.
|
2956 | maxSize := Flags.getConfigInt(if isLinear then Flags.MAX_SIZE_LINEAR_TEARING else Flags.MAX_SIZE_NONLINEAR_TEARING); |
| 399 | // Check if tearing is disabled (maxSize=0) | ||
| 400 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 2026 times.
|
2040 | if maxSize == 0 then |
| 401 | 14 | return; | |
| 402 | end if; | ||
| 403 | |||
| 404 | // Check if (component is too big) or (matrix is dense and target has no sparse solver) | ||
| 405 |
2/4✓ Branch 1 taken 2026 times.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 2026 times.
|
2026 | isDense := Flags.getConfigString(Flags.MATRIX_FORMAT) == "dense"; |
| 406 | 2026 | hasSparseSolver := targetHasSparseSolver(isLinear); | |
| 407 | 2026 | forcedTearing := isDense and not hasSparseSolver; | |
| 408 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2026 times.
|
2026 | if numVars > maxSize and not forcedTearing then |
| 409 | ✗ | Error.addMessage(Error.MAX_TEARING_SIZE, {intString(strongComponentIndex), intString(numVars), | |
| 410 | (if isLinear then "linear" else "nonlinear"), intString(maxSize), | ||
| 411 | (if isLinear then "maxSizeLinearTearing" else "maxSizeNonlinearTearing")}); | ||
| 412 | ✗ | return; | |
| 413 | end if; | ||
| 414 | |||
| 415 | // Check if tearing is disabled for this component | ||
| 416 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 2026 times.
|
2026 | if listMember(strongComponentIndex, Flags.getConfigIntList(Flags.NO_TEARING_FOR_COMPONENT)) then |
| 417 | ✗ | if debugFlag then | |
| 418 | ✗ | print("\nTearing deactivated by user.\n"); | |
| 419 | end if; | ||
| 420 | ✗ | Error.addMessage(Error.NO_TEARING_FOR_COMPONENT, {intString(strongComponentIndex)}); | |
| 421 | ✗ | return; | |
| 422 | end if; | ||
| 423 | |||
| 424 | activateTearing := true; | ||
| 425 | end checkTearingSettings; | ||
| 426 | |||
| 427 | protected function targetHasSparseSolver | ||
| 428 | input Boolean isLinear; | ||
| 429 | output Boolean hasSparseSolver = listMember(Config.simCodeTarget(), if isLinear then withLSS else withNSS); | ||
| 430 | end targetHasSparseSolver; | ||
| 431 | |||
| 432 | protected function tearingPaysOff | ||
| 433 | "Keeps the torn system unless solving it untorn is clearly cheaper, or unless | ||
| 434 | substituting through the inner equations amplifies an error past what a double | ||
| 435 | carries. The torn matrix does not exist yet, so both its structure and that | ||
| 436 | amplification come from walking the substitution. Costs are in flops." | ||
| 437 | input BackendDAE.StrongComponent tornComp; | ||
| 438 | input BackendDAE.Shared shared; | ||
| 439 | input list<Integer> eindex; | ||
| 440 | input list<Integer> vindx; | ||
| 441 | input Option<list<tuple<Integer, Integer, BackendDAE.Equation>>> ojac; | ||
| 442 | input BackendDAE.JacobianType jacType; | ||
| 443 | input Integer strongComponentIndex; | ||
| 444 | input Boolean isLinear; | ||
| 445 | output Boolean keep = true; | ||
| 446 | protected | ||
| 447 | constant Real entryCost = 4.0 "flops one Jacobian entry evaluation is worth"; | ||
| 448 | constant Real fillFactor = 14.0 "fill-in a sparse factorization sees, measured"; | ||
| 449 | constant Real precisionDigits = 16.0 "digits a double carries"; | ||
| 450 | constant Real trustedCoeffs = 0.9 "known coefficients the growth estimate needs"; | ||
| 451 | list<tuple<Integer, Integer, BackendDAE.Equation>> jac; | ||
| 452 | list<Integer> tvars, residuals, innerVars; | ||
| 453 | list<tuple<Integer, Real>> stack; | ||
| 454 | tuple<Integer, Real> dep; | ||
| 455 | BackendDAE.Equation dEqn; | ||
| 456 | BackendDAE.InnerEquations innerEquations; | ||
| 457 | BackendDAE.Variables globalKnownVars; | ||
| 458 | array<list<tuple<Integer, Real>>> eqDeps "local equation index -> the local variables it depends on and their coefficients"; | ||
| 459 | array<Integer> tvarId, solvedBy, stamp, depth; | ||
| 460 | array<Real> growth "error amplification of the forward substitution, iteration variables being 1"; | ||
| 461 | Integer n, nnz, t, m, row, col, v, w, eq, cnt, nnzA, maxRowA, maxDepth, d, valued = 0; | ||
| 462 | Real density, densityA, buildTorn, costDense, costSparse, costTornDense, costTornSparse; | ||
| 463 | Real costTorn, costUntorn, rn, rt, g, coeff, pivot, maxGrowth, digitsLost; | ||
| 464 | Boolean known, isValued; | ||
| 465 | algorithm | ||
| 466 | (jac, tvars, residuals, innerEquations, known) := match (ojac, tornComp) | ||
| 467 | case (SOME(jac), BackendDAE.TORNSYSTEM(strictTearingSet = BackendDAE.TEARINGSET( | ||
| 468 | tearingvars = tvars, residualequations = residuals, innerEquations = innerEquations))) | ||
| 469 | then (jac, tvars, residuals, innerEquations, true); | ||
| 470 | else ({}, {}, {}, {}, false); | ||
| 471 | end match; | ||
| 472 |
2/2✓ Branch 0 taken 663 times.
✓ Branch 1 taken 1181 times.
|
1844 | if not known then |
| 473 | 663 | return; | |
| 474 | end if; | ||
| 475 | |||
| 476 | 1181 | n := listLength(vindx); | |
| 477 | 1181 | nnz := listLength(jac); | |
| 478 | 1181 | t := listLength(tvars); | |
| 479 | 1181 | m := listLength(innerEquations); | |
| 480 | |||
| 481 | 1181 | globalKnownVars := BackendDAEUtil.getGlobalKnownVarsFromShared(shared); | |
| 482 | 1181 | eqDeps := arrayCreate(n, {}); | |
| 483 |
2/2✓ Branch 0 taken 50793 times.
✓ Branch 1 taken 1181 times.
|
51974 | for entry in jac loop |
| 484 | 50793 | (row, col, dEqn) := entry; | |
| 485 | 50793 | (coeff, isValued) := jacEntryMagnitude(dEqn, globalKnownVars); | |
| 486 |
2/2✓ Branch 0 taken 14970 times.
✓ Branch 1 taken 35823 times.
|
50793 | valued := valued + (if isValued then 1 else 0); |
| 487 | 101586 | arrayUpdate(eqDeps, row, (col, coeff) :: eqDeps[row]); | |
| 488 | end for; | ||
| 489 | |||
| 490 | // inner equations come in solve order, so one pass gives every depth and growth | ||
| 491 | 1181 | tvarId := arrayCreate(n, 0); | |
| 492 | 1181 | growth := arrayCreate(n, 0.0); | |
| 493 | cnt := 0; | ||
| 494 |
2/2✓ Branch 0 taken 4888 times.
✓ Branch 1 taken 1181 times.
|
6069 | for gv in tvars loop |
| 495 | 4888 | cnt := cnt + 1; | |
| 496 | 4888 | v := List.position(gv, vindx); | |
| 497 | 4888 | arrayUpdate(tvarId, v, cnt); | |
| 498 | 4888 | arrayUpdate(growth, v, 1.0); | |
| 499 | end for; | ||
| 500 | |||
| 501 | 1181 | solvedBy := arrayCreate(n, 0); | |
| 502 | 1181 | depth := arrayCreate(n, 0); | |
| 503 | maxDepth := 0; | ||
| 504 |
2/2✓ Branch 0 taken 12553 times.
✓ Branch 1 taken 1181 times.
|
13734 | for ie in innerEquations loop |
| 505 | (eq, innerVars) := match ie | ||
| 506 | case BackendDAE.INNEREQUATION() | ||
| 507 |
4/4✓ Branch 0 taken 12553 times.
✓ Branch 1 taken 12553 times.
✓ Branch 2 taken 12553 times.
✓ Branch 3 taken 12553 times.
|
25106 | then (List.position(ie.eqn, eindex), list(List.position(gv, vindx) for gv in ie.vars)); |
| 508 | case BackendDAE.INNEREQUATIONCONSTRAINTS() | ||
| 509 | ✗ | then (List.position(ie.eqn, eindex), list(List.position(gv, vindx) for gv in ie.vars)); | |
| 510 | end match; | ||
| 511 | d := 0; | ||
| 512 | g := 0.0; | ||
| 513 | pivot := 0.0; | ||
| 514 |
2/2✓ Branch 1 taken 35162 times.
✓ Branch 2 taken 12553 times.
|
47715 | for dep in eqDeps[eq] loop |
| 515 | 35162 | w := Util.tuple21(dep); | |
| 516 | 35162 | coeff := Util.tuple22(dep); | |
| 517 |
2/2✓ Branch 1 taken 12553 times.
✓ Branch 2 taken 22609 times.
|
35162 | if listMember(w, innerVars) then |
| 518 | 12553 | pivot := realMax(pivot, coeff); | |
| 519 | else | ||
| 520 | 22609 | d := intMax(d, depth[w]); | |
| 521 | 22609 | g := g + coeff * growth[w]; | |
| 522 | end if; | ||
| 523 | end for; | ||
| 524 |
2/4✓ Branch 0 taken 12553 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12553 times.
|
12553 | g := if pivot > 0.0 then g / pivot else g; |
| 525 |
2/2✓ Branch 1 taken 12553 times.
✓ Branch 2 taken 12553 times.
|
25106 | for v in innerVars loop |
| 526 | 12553 | arrayUpdate(solvedBy, v, eq); | |
| 527 | 12553 | arrayUpdate(depth, v, d + 1); | |
| 528 |
1/2✓ Branch 0 taken 12553 times.
✗ Branch 1 not taken.
|
25106 | arrayUpdate(growth, v, if g > 1e300 then 1e300 else g); |
| 529 | end for; | ||
| 530 | 12553 | maxDepth := intMax(maxDepth, d + 1); | |
| 531 | end for; | ||
| 532 | |||
| 533 | 1181 | stamp := arrayCreate(n, 0); | |
| 534 | nnzA := 0; | ||
| 535 | maxRowA := 0; | ||
| 536 | maxGrowth := 0.0; | ||
| 537 | row := 0; | ||
| 538 |
2/2✓ Branch 0 taken 4888 times.
✓ Branch 1 taken 1181 times.
|
6069 | for ge in residuals loop |
| 539 | 4888 | row := row + 1; | |
| 540 | cnt := 0; | ||
| 541 | 4888 | eq := List.position(ge, eindex); | |
| 542 | g := 0.0; | ||
| 543 | pivot := 0.0; | ||
| 544 |
2/2✓ Branch 1 taken 15631 times.
✓ Branch 2 taken 4888 times.
|
20519 | for dep in eqDeps[eq] loop |
| 545 | 15631 | w := Util.tuple21(dep); | |
| 546 | 15631 | coeff := Util.tuple22(dep); | |
| 547 | 15631 | g := g + coeff * growth[w]; | |
| 548 | 15631 | pivot := realMax(pivot, coeff); | |
| 549 | end for; | ||
| 550 |
2/4✓ Branch 0 taken 4888 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4888 times.
|
4888 | maxGrowth := realMax(maxGrowth, if pivot > 0.0 then g / pivot else g); |
| 551 | 4888 | stack := eqDeps[eq]; | |
| 552 |
2/2✓ Branch 0 taken 209828 times.
✓ Branch 1 taken 4888 times.
|
214716 | while not listEmpty(stack) loop |
| 553 | 209828 | v := Util.tuple21(listHead(stack)); | |
| 554 | 209828 | stack := listRest(stack); | |
| 555 |
2/2✓ Branch 1 taken 129321 times.
✓ Branch 2 taken 80507 times.
|
209828 | if stamp[v] <> row then |
| 556 | 80507 | arrayUpdate(stamp, v, row); | |
| 557 |
2/2✓ Branch 1 taken 21394 times.
✓ Branch 2 taken 59113 times.
|
80507 | if tvarId[v] > 0 then |
| 558 | 21394 | cnt := cnt + 1; | |
| 559 | elseif solvedBy[v] > 0 then | ||
| 560 | 59113 | stack := listAppend(eqDeps[solvedBy[v]], stack); | |
| 561 | end if; | ||
| 562 | end if; | ||
| 563 | end while; | ||
| 564 | 4888 | nnzA := nnzA + cnt; | |
| 565 | maxRowA := intMax(maxRowA, cnt); | ||
| 566 | end for; | ||
| 567 | |||
| 568 | 1181 | rn := intReal(n); | |
| 569 | 1181 | rt := intReal(t); | |
| 570 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1181 times.
|
1181 | density := intReal(nnz) / (rn * rn); |
| 571 |
2/4✓ Branch 0 taken 1181 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1181 times.
|
1181 | densityA := if t > 0 then intReal(nnzA) / (rt * rt) else 1.0; |
| 572 |
3/4✓ Branch 0 taken 1087 times.
✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1087 times.
|
1181 | digitsLost := if maxGrowth > 1.0 then log10(maxGrowth) else 0.0; |
| 573 | |||
| 574 | 1181 | buildTorn := entryCost * intReal(maxRowA * nnz); | |
| 575 | 1181 | costDense := entryCost * intReal(nnz) + solveCost(rn, intReal(nnz), false); | |
| 576 | 1181 | costSparse := entryCost * intReal(nnz) + solveCost(rn, intReal(nnz), true, fillFactor); | |
| 577 | 1181 | costTornDense := buildTorn + solveCost(rt, intReal(nnzA), false); | |
| 578 | 1181 | costTornSparse := buildTorn + solveCost(rt, intReal(nnzA), true); | |
| 579 | |||
| 580 | // costed at the format the backend will emit for each | ||
| 581 |
2/2✓ Branch 1 taken 916 times.
✓ Branch 2 taken 265 times.
|
1181 | costUntorn := if SimCodeCodegenUtil.useSparseSolver(n, nnz, isLinear) then costSparse else costDense; |
| 582 |
2/2✓ Branch 1 taken 1165 times.
✓ Branch 2 taken 16 times.
|
1181 | costTorn := if SimCodeCodegenUtil.useSparseSolver(t, nnzA, isLinear) then costTornSparse else costTornDense; |
| 583 | |||
| 584 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1181 times.
|
1181 | if Flags.isSet(Flags.TEARING_COST) then |
| 585 | ✗ | print("[tearingCost] component " + intString(strongComponentIndex) + " " + (if isLinear then "LS" else "NLS") | |
| 586 | + " [" + BackendDump.jacobianTypeStr(jacType) + "]" | ||
| 587 | + " n=" + intString(n) + " nnz=" + intString(nnz) + " density=" + realString(density) | ||
| 588 | + " t=" + intString(t) + " inner=" + intString(m) + " nnzA=" + intString(nnzA) | ||
| 589 | + " densityA=" + realString(densityA) + " colors=" + intString(maxRowA) + " chain=" + intString(maxDepth) | ||
| 590 | + " digitsLost=" + realString(digitsLost) + " valuedCoeffs=" + intString(valued) + "/" + intString(nnz) | ||
| 591 | + " cost dense=" + realString(costDense) + " sparse=" + realString(costSparse) | ||
| 592 | + " tornDense=" + realString(costTornDense) + " tornSparse=" + realString(costTornSparse) | ||
| 593 | + " format=" + (if SimCodeCodegenUtil.useSparseSolver(n, nnz, isLinear) then "sparse" else "dense") | ||
| 594 | + " tornFormat=" + (if SimCodeCodegenUtil.useSparseSolver(t, nnzA, isLinear) then "sparse" else "dense") + "\n"); | ||
| 595 | end if; | ||
| 596 | |||
| 597 | // a nonlinear system's cost is its Newton iterations, which this does not model | ||
| 598 |
2/2✓ Branch 0 taken 194 times.
✓ Branch 1 taken 987 times.
|
1181 | if not isLinear then |
| 599 | 194 | return; | |
| 600 | end if; | ||
| 601 | |||
| 602 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 985 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
987 | if digitsLost >= precisionDigits and intReal(valued) >= trustedCoeffs * intReal(nnz) then |
| 603 | ✗ | Error.addMessage(Error.TEARING_AMPLIFIES_ERROR, {intString(strongComponentIndex), intString(m), | |
| 604 | intString(realInt(digitsLost))}); | ||
| 605 | ✗ | keep := false; | |
| 606 | elseif costUntorn * Flags.getConfigReal(Flags.TEARING_COST_MARGIN) < costTorn then | ||
| 607 | 48 | Error.addMessage(Error.TEARING_NOT_WORTH_IT, {intString(strongComponentIndex), intString(t), | |
| 608 | intString(realInt(costTorn)), intString(realInt(costUntorn)), | ||
| 609 | intString(n)}); | ||
| 610 | keep := false; | ||
| 611 | end if; | ||
| 612 | end tearingPaysOff; | ||
| 613 | |||
| 614 | protected function jacEntryMagnitude | ||
| 615 | "Magnitude of one Jacobian entry, parameters taken at their bound value. Entries | ||
| 616 | that are not a number at compile time count as 1." | ||
| 617 | input BackendDAE.Equation dEqn; | ||
| 618 | input BackendDAE.Variables globalKnownVars; | ||
| 619 | output Real magnitude; | ||
| 620 | output Boolean known; | ||
| 621 | protected | ||
| 622 | DAE.Exp exp; | ||
| 623 | algorithm | ||
| 624 | (magnitude, known) := matchcontinue dEqn | ||
| 625 | case BackendDAE.RESIDUAL_EQUATION() algorithm | ||
| 626 | 50793 | exp := dEqn.exp; | |
| 627 | 51061 | for i in 1:3 loop | |
| 628 |
2/2✓ Branch 0 taken 51061 times.
✓ Branch 1 taken 35240 times.
|
86301 | if Expression.isScalarConst(exp) then |
| 629 | break; | ||
| 630 | end if; | ||
| 631 | 51061 | (exp, _) := Expression.traverseExpBottomUp(exp, substituteKnownVar, globalKnownVars); | |
| 632 | 51061 | (exp, _) := ExpressionSimplify.simplify(exp); | |
| 633 | end for; | ||
| 634 | 50793 | then (abs(Expression.toReal(exp)), true); | |
| 635 | else (1.0, false); | ||
| 636 | end matchcontinue; | ||
| 637 | end jacEntryMagnitude; | ||
| 638 | |||
| 639 | protected function substituteKnownVar | ||
| 640 | input output DAE.Exp exp; | ||
| 641 | input output BackendDAE.Variables globalKnownVars; | ||
| 642 | algorithm | ||
| 643 | exp := matchcontinue exp | ||
| 644 | local | ||
| 645 | BackendDAE.Var var; | ||
| 646 | case DAE.CREF() algorithm | ||
| 647 | 90582 | (var, _) := BackendVariable.getVarSingle(exp.componentRef, globalKnownVars); | |
| 648 | 31085 | then BackendVariable.varBindExp(var); | |
| 649 | 295958 | else exp; | |
| 650 | end matchcontinue; | ||
| 651 | end substituteKnownVar; | ||
| 652 | |||
| 653 | protected function solveCost | ||
| 654 | "One factorization and back-solve, sparse LU modelled as nnz/size per column." | ||
| 655 | input Real size; | ||
| 656 | input Real nnz; | ||
| 657 | input Boolean sparse; | ||
| 658 | input Real fill = 1.0 "fill-in the factorization sees, 1 for an already dense matrix"; | ||
| 659 | output Real cost; | ||
| 660 | algorithm | ||
| 661 |
4/6✓ Branch 0 taken 4724 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2362 times.
✓ Branch 3 taken 2362 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2362 times.
|
4724 | cost := if size <= 0.0 then 0.0 |
| 662 | elseif sparse then fill * nnz * nnz / size + 2.0 * nnz | ||
| 663 | else 2.0 / 3.0 * size * size * size + 2.0 * size * size; | ||
| 664 | end solveCost; | ||
| 665 | |||
| 666 | protected function getUserTearingSet | ||
| 667 | input list<Integer> userTVars; | ||
| 668 | input list<Integer> userResiduals; | ||
| 669 | input Integer strongComponentIndex; | ||
| 670 | output list<Integer> userTvarsThisComponent = {}; | ||
| 671 | output list<Integer> userResidualsThisComponent = {}; | ||
| 672 | protected | ||
| 673 | Integer i, len, start, end_; | ||
| 674 | array<Integer> arr_TVars, arr_residuals; | ||
| 675 | algorithm | ||
| 676 | // work with arrays so the accesses are faster | ||
| 677 | 2025 | arr_TVars := listArray(userTVars); | |
| 678 | 2025 | arr_residuals := listArray(userResiduals); | |
| 679 | |||
| 680 | // find tearing variables | ||
| 681 | i := 1; | ||
| 682 | 2025 | len := listLength(userTVars); | |
| 683 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2024 times.
|
2026 | while i < len loop |
| 684 |
2/2✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
|
2 | if arr_TVars[i] == strongComponentIndex then |
| 685 | start := i + 2; | ||
| 686 | 1 | end_ := i + 1 + arr_TVars[i+1]; | |
| 687 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
|
2 | userTvarsThisComponent := List.unique(list(arr_TVars[j] for j in start:end_)); |
| 688 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
|
1 | if listLength(userTvarsThisComponent) <> arr_TVars[i+1] then |
| 689 | ✗ | Error.addMessage(Error.USER_DEFINED_TEARING_ERROR, {"The selected tearing variables must have unique indexes."}); | |
| 690 | ✗ | fail(); | |
| 691 | end if; | ||
| 692 | break; | ||
| 693 | else | ||
| 694 | 1 | i := i + 2 + arr_TVars[i+1]; | |
| 695 | end if; | ||
| 696 | end while; | ||
| 697 | |||
| 698 | // find residual equations | ||
| 699 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 2024 times.
|
2025 | if not listEmpty(userTvarsThisComponent) then |
| 700 | i := 1; | ||
| 701 | 1 | len := listLength(userResiduals); | |
| 702 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | while i < len loop |
| 703 | ✗ | if arr_residuals[i] == strongComponentIndex then | |
| 704 | start := i + 2; | ||
| 705 | ✗ | end_ := i + 1 + arr_residuals[i+1]; | |
| 706 | ✗ | userResidualsThisComponent := List.unique(list(arr_residuals[j] for j in start:end_)); | |
| 707 | ✗ | if listLength(userResidualsThisComponent) <> arr_residuals[i+1] then | |
| 708 | ✗ | Error.addMessage(Error.USER_DEFINED_TEARING_ERROR, {"The selected residual equations must have unique indexes."}); | |
| 709 | ✗ | fail(); | |
| 710 | end if; | ||
| 711 | break; | ||
| 712 | else | ||
| 713 | ✗ | i := i + 2 + arr_residuals[i+1]; | |
| 714 | end if; | ||
| 715 | end while; | ||
| 716 | end if; | ||
| 717 | end getUserTearingSet; | ||
| 718 | |||
| 719 | |||
| 720 | // ============================================================================= | ||
| 721 | // | ||
| 722 | // method: omc tearing | ||
| 723 | // | ||
| 724 | // ============================================================================= | ||
| 725 | |||
| 726 | protected function omcTearing " author: Frenkel TUD 2012-05" | ||
| 727 | input BackendDAE.EqSystem isyst; | ||
| 728 | input BackendDAE.Shared ishared; | ||
| 729 | input list<Integer> eindex; | ||
| 730 | input list<Integer> vindx; | ||
| 731 | input Option<list<tuple<Integer, Integer, BackendDAE.Equation>>> ojac; | ||
| 732 | input BackendDAE.JacobianType jacType; | ||
| 733 | input Boolean mixedSystem; | ||
| 734 | output BackendDAE.StrongComponent ocomp; | ||
| 735 | output Boolean outRunMatching; | ||
| 736 | protected | ||
| 737 | list<Integer> tvars,residual,unsolvables; | ||
| 738 | list<list<Integer>> othercomps; | ||
| 739 | BackendDAE.EqSystem subsyst; | ||
| 740 | array<Integer> ass1,ass2,columark; | ||
| 741 | Integer size,tornsize,mark; | ||
| 742 | list<BackendDAE.Equation> eqn_lst; | ||
| 743 | list<BackendDAE.Var> var_lst; | ||
| 744 | BackendDAE.Variables vars; | ||
| 745 | BackendDAE.EquationArray eqns; | ||
| 746 | BackendDAE.AdjacencyMatrix m,m1; | ||
| 747 | BackendDAE.AdjacencyMatrix mt,mt1; | ||
| 748 | BackendDAE.AdjacencyMatrixEnhanced me; | ||
| 749 | BackendDAE.AdjacencyMatrixTEnhanced meT; | ||
| 750 | array<list<Integer>> mapEqnIncRow; | ||
| 751 | array<Integer> mapIncRowEqn; | ||
| 752 | AvlTreePathFunction.Tree funcs; | ||
| 753 | list<Integer> tSel_always, tSel_prefer, tSel_avoid, tSel_never; | ||
| 754 | String DAEtypeStr; | ||
| 755 | algorithm | ||
| 756 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 35 times.
|
35 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 757 | ✗ | print("\n" + BORDER + "\nBEGINNING of omcTearing\n\n"); | |
| 758 | end if; | ||
| 759 | 35 | DAEtypeStr := BackendDump.printBackendDAEType2String(ishared.backendDAEType); | |
| 760 | // generate Subsystem to get the adjacency matrix | ||
| 761 | 35 | size := listLength(vindx); | |
| 762 | 35 | eqn_lst := BackendEquation.getList(eindex,BackendEquation.getEqnsFromEqSystem(isyst)); | |
| 763 | 35 | eqns := BackendEquation.listEquation(eqn_lst); | |
| 764 | 35 | var_lst := List.map1r(vindx, BackendVariable.getVarAt, BackendVariable.daeVars(isyst)); | |
| 765 | 35 | vars := BackendVariable.listVar1(var_lst); | |
| 766 | 35 | subsyst := BackendDAEUtil.createEqSystem(vars, eqns); | |
| 767 | 35 | funcs := BackendDAEUtil.getFunctions(ishared); | |
| 768 | 70 | (subsyst,m,mt,_,_) := BackendDAEUtil.getAdjacencyMatrixScalar(subsyst, BackendDAE.NORMAL(), SOME(funcs), BackendDAEUtil.isInitializationDAE(ishared)); | |
| 769 | // DumpGraphML.dumpSystem(subsyst,ishared,NONE(),"System" + intString(size) + ".graphml"); | ||
| 770 |
2/4✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 35 times.
|
35 | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 771 | ✗ | print("\n\n###BEGIN print Strong Component#####################\n(Function:omcTearing)\n"); | |
| 772 | ✗ | BackendDump.printEqSystem(subsyst); | |
| 773 | ✗ | print("\n###END print Strong Component#######################\n(Function:omcTearing)\n\n\n"); | |
| 774 | end if; | ||
| 775 | 35 | (me,meT,mapEqnIncRow,mapIncRowEqn) := BackendDAEUtil.getAdjacencyMatrixEnhancedScalar(subsyst,ishared,false); | |
| 776 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 35 times.
|
35 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 777 | ✗ | print("\n\nAdjacencyMatrixEnhanced:\n"); | |
| 778 | ✗ | BackendDump.dumpAdjacencyMatrixEnhanced(me); | |
| 779 | ✗ | print("\nAdjacencyMatrixTransposedEnhanced:\n"); | |
| 780 | ✗ | BackendDump.dumpAdjacencyMatrixTEnhanced(meT); | |
| 781 | ✗ | print("\nmapEqnIncRow:"); //+ stringDelimitList(List.map(List.flatten(arrayList(mapEqnIncRow)),intString),",") + "\n\n"); | |
| 782 | ✗ | BackendDump.dumpAdjacencyMatrix(mapEqnIncRow); | |
| 783 | ✗ | print("\nmapIncRowEqn:\n" + stringDelimitList(List.mapArray(mapIncRowEqn,intString),",") + "\n\n"); | |
| 784 | end if; | ||
| 785 | |||
| 786 | 35 | ass1 := arrayCreate(size,-1); | |
| 787 | 35 | ass2 := arrayCreate(size,-1); | |
| 788 | // get all unsolvable variables | ||
| 789 | 35 | unsolvables := getUnsolvableVars(size,meT); | |
| 790 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 35 times.
|
35 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 791 | ✗ | print("\n\nUnsolvable Vars:\n"); | |
| 792 | ✗ | BackendDump.debuglst(unsolvables,intString,", ","\n"); | |
| 793 | end if; | ||
| 794 | 35 | columark := arrayCreate(size,-1); | |
| 795 | |||
| 796 | // Collect variables with annotation attribute '__OpenModelica_tearingSelect in [always, prefer, avoid, never]' | ||
| 797 | 35 | (tSel_always,tSel_prefer,tSel_avoid,tSel_never,_) := tearingSelect(var_lst, {}, DAEtypeStr); | |
| 798 | |||
| 799 | // determine tvars and do cheap matching until a maximum matching is there | ||
| 800 | // if cheap matching stucks select additional tearing variable and continue | ||
| 801 | // (mark+1 for every call of omcTearing3) | ||
| 802 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 35 times.
|
35 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 803 | ✗ | print("\n" + BORDER + "\nBEGINNING of omcTearing2\n\n"); | |
| 804 | end if; | ||
| 805 | 35 | (tvars,mark) := omcTearing2(unsolvables,tSel_always,tSel_prefer,tSel_avoid,tSel_never,me,meT,mapEqnIncRow,mapIncRowEqn,size,vars,ishared,ass1,ass2,columark,1,{}); | |
| 806 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 35 times.
|
35 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 807 | ✗ | print("\nEND of omcTearing2\n" + BORDER + "\n\n"); | |
| 808 | end if; | ||
| 809 | |||
| 810 | // unassign tvars | ||
| 811 | 35 | ass1 := List.fold(tvars,unassignTVars,ass1); | |
| 812 |
2/4✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 35 times.
|
35 | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 813 | ✗ | print("\n" + BORDER + "\n* BFS RESULTS:\n* ass1: "+ stringDelimitList(List.mapArray(ass1, intString),",") +"\n"); | |
| 814 | ✗ | print("* ass2: "+ stringDelimitList(List.mapArray(ass2,intString),",") + "\n" + BORDER +"\n\n"); | |
| 815 | end if; | ||
| 816 | |||
| 817 | // unmatched equations are residual equations | ||
| 818 | 35 | residual := Matching.getUnassigned(size,ass2,{}); | |
| 819 | // subsyst := BackendDAEUtil.setEqSystMatching(subsyst,BackendDAE.MATCHING(ass1,ass2,{})); | ||
| 820 | // DumpGraphML.dumpSystem(subsyst,ishared,NONE(),"TornSystem" + intString(size) + ".graphml"); | ||
| 821 | |||
| 822 | // check if tearing makes sense | ||
| 823 | 35 | tornsize := listLength(tvars); | |
| 824 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 30 times.
|
35 | true := intLt(tornsize, size); |
| 825 | |||
| 826 | // create adjacency matrices w/o tvar and residual | ||
| 827 | 30 | m1 := arrayCreate(size,{}); | |
| 828 | 30 | mt1 := arrayCreate(size,{}); | |
| 829 | 30 | m1 := AdjacencyMatrix.getOtherEqSysAdjacencyMatrix(m,size,1,ass2,ass1,m1); | |
| 830 | 30 | mt1 := AdjacencyMatrix.getOtherEqSysAdjacencyMatrix(mt,size,1,ass1,ass2,mt1); | |
| 831 | |||
| 832 | // run tarjan to get order of other equations | ||
| 833 | 30 | othercomps := Sorting.TarjanTransposed(mt1, ass2); | |
| 834 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
|
30 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 835 | ✗ | print("\nOtherEquationsOrder:\n"); | |
| 836 | ✗ | BackendDump.dumpComponentsOLD(othercomps); | |
| 837 | ✗ | print("\n"); | |
| 838 | end if; | ||
| 839 | |||
| 840 | // calculate influence of tearing vars in residual equations | ||
| 841 | // mt1: row=variable, columns: tvars, that influence the result of the variable | ||
| 842 | 30 | mt1 := arrayCreate(size, {}); | |
| 843 | 30 | mark := getDependenciesOfVars(othercomps, ass1, ass2, m, mt1, columark, mark); | |
| 844 | |||
| 845 | 30 | (residual, mark) := sortResidualDepentOnTVars(residual, tvars, ass1, m, mt1, columark, mark); | |
| 846 | 30 | (ocomp,outRunMatching) := omcTearing4(jacType,isyst,ishared,subsyst,tvars,residual,ass1,ass2,othercomps,eindex,vindx,mapEqnIncRow,mapIncRowEqn,columark,mark,mixedSystem); | |
| 847 | |||
| 848 |
2/4✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 30 times.
|
30 | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 849 | ✗ | print(if outRunMatching then "\nStatus:\nOk system torn\n\n" else "\nStatus:\nSystem not torn\n\n"); | |
| 850 | ✗ | print("\n" + BORDER + "\n* TEARING RESULTS:\n*\n* No of equations in strong component: "+intString(size)+"\n"); | |
| 851 | ✗ | print("* No of tVars: "+intString(tornsize)+"\n"); | |
| 852 | ✗ | print("*\n* tVars: "+ stringDelimitList(List.map(tvars,intString),",") + "\n"); | |
| 853 | ✗ | print("*\n* resEq: "+ stringDelimitList(List.map(residual,intString),",") + "\n*\n*"); | |
| 854 | ✗ | BackendDAE.TORNSYSTEM(BackendDAE.TEARINGSET(tearingvars=tvars,residualequations=residual)) := ocomp; | |
| 855 | ✗ | print("\n* Related to entire Equationsystem:\n* =====\n* tVars: "+ stringDelimitList(List.map(tvars,intString),",") + "\n* =====\n"); | |
| 856 | ✗ | print("*\n* =====\n* resEq: "+ stringDelimitList(List.map(residual,intString),",") + "\n* =====\n" + BORDER + "\n"); | |
| 857 | end if; | ||
| 858 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 859 | ✗ | print("\n\nStrongComponents:\n"); | |
| 860 | ✗ | BackendDump.dumpComponent(ocomp); | |
| 861 | ✗ | print("\n\nEND of omcTearing\n" + BORDER + "\n\n"); | |
| 862 | end if; | ||
| 863 | end omcTearing; | ||
| 864 | |||
| 865 | |||
| 866 | protected function getUnsolvableVars | ||
| 867 | " author: Frenkel TUD 2012-08" | ||
| 868 | input Integer size; | ||
| 869 | input BackendDAE.AdjacencyMatrixTEnhanced meT; | ||
| 870 | output list<Integer> unsolvables = {}; | ||
| 871 | protected | ||
| 872 | Boolean isUnsolvable; | ||
| 873 | algorithm | ||
| 874 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1995 times.
|
38921 | for index in 1:size loop |
| 875 | 36926 | isUnsolvable := unsolvable(meT[index]); | |
| 876 |
2/2✓ Branch 0 taken 2025 times.
✓ Branch 1 taken 34901 times.
|
36926 | if isUnsolvable then |
| 877 | unsolvables := index::unsolvables; | ||
| 878 | end if; | ||
| 879 | end for; | ||
| 880 | end getUnsolvableVars; | ||
| 881 | |||
| 882 | |||
| 883 | public function unsolvable | ||
| 884 | " author: Frenkel TUD 2012-08" | ||
| 885 | input BackendDAE.AdjacencyMatrixElementEnhanced elem; | ||
| 886 | output Boolean isUnsolvable = true; | ||
| 887 | protected | ||
| 888 | Integer e; | ||
| 889 | BackendDAE.Solvability s; | ||
| 890 | algorithm | ||
| 891 |
2/2✓ Branch 0 taken 860496 times.
✓ Branch 1 taken 2025 times.
|
862521 | for el in elem loop |
| 892 | 860496 | (e,s,_) := el; | |
| 893 |
2/2✓ Branch 1 taken 456484 times.
✓ Branch 2 taken 404012 times.
|
860496 | if solvable(s) then |
| 894 |
2/2✓ Branch 0 taken 456480 times.
✓ Branch 1 taken 4 times.
|
456484 | if e > 0 then |
| 895 | isUnsolvable := false; | ||
| 896 | 456480 | return; | |
| 897 | end if; | ||
| 898 | end if; | ||
| 899 | end for; | ||
| 900 | end unsolvable; | ||
| 901 | |||
| 902 | |||
| 903 | protected function unassignTVars " author: Frenkel TUD 2012-05" | ||
| 904 | input Integer v; | ||
| 905 | input array<Integer> inAss; | ||
| 906 | output array<Integer> outAss; | ||
| 907 | algorithm | ||
| 908 | 74 | outAss := arrayUpdate(inAss,v,-1); | |
| 909 | end unassignTVars; | ||
| 910 | |||
| 911 | |||
| 912 | |||
| 913 | |||
| 914 | protected function getDependenciesOfVars " function to determine which variables are influenced by the tvars" | ||
| 915 | input list<list<Integer>> iComps; | ||
| 916 | input array<Integer> ass1; | ||
| 917 | input array<Integer> ass2; | ||
| 918 | input BackendDAE.AdjacencyMatrix m; | ||
| 919 | input array<list<Integer>> mT; | ||
| 920 | input array<Integer> visited; | ||
| 921 | input Integer iMark; | ||
| 922 | output Integer oMark; | ||
| 923 | algorithm | ||
| 924 | oMark := match iComps | ||
| 925 | local | ||
| 926 | Integer c, v; | ||
| 927 | list<Integer> comp, tvars, vars; | ||
| 928 | list<list<Integer>> comps; | ||
| 929 | |||
| 930 | case {} | ||
| 931 | then iMark; | ||
| 932 | |||
| 933 | case {c}::comps algorithm | ||
| 934 | // get var of eqn | ||
| 935 | 201 | v := ass2[c]; | |
| 936 | // get TVars of Eqn | ||
| 937 | 201 | vars := List.select(m[c], Util.intPositive); | |
| 938 | 201 | tvars := tVarsofEqn(vars, ass1, mT, visited, iMark, {}); | |
| 939 | // update map | ||
| 940 | 201 | arrayUpdate(mT, v, tvars); | |
| 941 | 201 | then getDependenciesOfVars(comps, ass1, ass2, m, mT, visited, iMark+1); | |
| 942 | |||
| 943 | case comp::comps algorithm | ||
| 944 | // get var of eqns | ||
| 945 | 2 | vars := List.map1r(comp,arrayGet,ass2); | |
| 946 | // get TVars of Eqns | ||
| 947 | 2 | tvars := tVarsofEqns(comp, m, ass1, mT, visited, iMark); | |
| 948 | // update map | ||
| 949 | 2 | List.fold1r(vars, arrayUpdate, tvars, mT); | |
| 950 | 2 | then getDependenciesOfVars(comps, ass1, ass2, m, mT, visited, iMark+1); | |
| 951 | end match; | ||
| 952 | end getDependenciesOfVars; | ||
| 953 | |||
| 954 | |||
| 955 | protected function tVarsofEqns "determines tvars that influence this equations" | ||
| 956 | input list<Integer> iEqns; | ||
| 957 | input BackendDAE.AdjacencyMatrix m; | ||
| 958 | input array<Integer> ass1; | ||
| 959 | input array<list<Integer>> mT; | ||
| 960 | input array<Integer> visited; | ||
| 961 | input Integer iMark; | ||
| 962 | output list<Integer> oAcc = {}; | ||
| 963 | protected | ||
| 964 | list<Integer> vars; | ||
| 965 | algorithm | ||
| 966 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
|
8 | for e in iEqns loop |
| 967 | 6 | vars := List.select(m[e], Util.intPositive); | |
| 968 | 6 | oAcc := tVarsofEqn(vars, ass1, mT, visited, iMark, oAcc); | |
| 969 | end for; | ||
| 970 | end tVarsofEqns; | ||
| 971 | |||
| 972 | |||
| 973 | protected function tVarsofEqn "determines tvars that influence this equation" | ||
| 974 | input list<Integer> iVars; | ||
| 975 | input array<Integer> ass1; | ||
| 976 | input array<list<Integer>> mT; | ||
| 977 | input array<Integer> visited; | ||
| 978 | input Integer iMark; | ||
| 979 | input list<Integer> iAcc; | ||
| 980 | output list<Integer> oAcc = iAcc; | ||
| 981 | algorithm | ||
| 982 |
2/2✓ Branch 0 taken 686 times.
✓ Branch 1 taken 271 times.
|
957 | for v in iVars loop |
| 983 |
2/2✓ Branch 1 taken 187 times.
✓ Branch 2 taken 499 times.
|
686 | if intLt(ass1[v],0) then |
| 984 | 187 | oAcc := uniqueIntLst(v,iMark,visited,oAcc); | |
| 985 | else | ||
| 986 | 499 | oAcc := List.fold2(mT[v],uniqueIntLst,iMark,visited,oAcc); | |
| 987 | end if; | ||
| 988 | end for; | ||
| 989 | end tVarsofEqn; | ||
| 990 | |||
| 991 | |||
| 992 | protected function uniqueIntLst | ||
| 993 | input Integer c; | ||
| 994 | input Integer mark; | ||
| 995 | input array<Integer> markarray; | ||
| 996 | input list<Integer> iAcc; | ||
| 997 | output list<Integer> oAcc = iAcc; | ||
| 998 | algorithm | ||
| 999 |
2/2✓ Branch 1 taken 156 times.
✓ Branch 2 taken 536 times.
|
692 | if not intEq(mark,markarray[c]) then |
| 1000 | 536 | arrayUpdate(markarray,c,mark); | |
| 1001 | oAcc := c::oAcc; | ||
| 1002 | end if; | ||
| 1003 | end uniqueIntLst; | ||
| 1004 | |||
| 1005 | |||
| 1006 | protected function sortResidualDepentOnTVars | ||
| 1007 | input list<Integer> iResiduals; | ||
| 1008 | input list<Integer> iTVars; | ||
| 1009 | input array<Integer> ass1; | ||
| 1010 | input BackendDAE.AdjacencyMatrix m; | ||
| 1011 | input array<list<Integer>> mT; | ||
| 1012 | input array<Integer> visited; | ||
| 1013 | input Integer iMark; | ||
| 1014 | output list<Integer> oResiduals; | ||
| 1015 | output Integer oMark; | ||
| 1016 | protected | ||
| 1017 | Integer size; | ||
| 1018 | list<list<Integer>> maplst; | ||
| 1019 | array<list<Integer>> map; | ||
| 1020 | array<Integer> eqnLocalGlobal,varGlobalLocal,v1,v2; | ||
| 1021 | algorithm | ||
| 1022 | // eqn - local - Global indices | ||
| 1023 | 30 | eqnLocalGlobal := listArray(iResiduals); | |
| 1024 | // var - global local indices | ||
| 1025 | 30 | varGlobalLocal := arrayCreate(arrayLength(m),-1); | |
| 1026 | 30 | varGlobalLocal := getGlobalLocal(iTVars,1,varGlobalLocal); | |
| 1027 | // generate list of map[residual]=tvars | ||
| 1028 | // change indices in map to local | ||
| 1029 | 30 | (oMark,maplst) := tVarsofResidualEqns(iResiduals,m,ass1,mT,varGlobalLocal,visited,iMark); | |
| 1030 | 30 | map := listArray(maplst); | |
| 1031 | // get for each residual a tvar | ||
| 1032 | size := arrayLength(map); | ||
| 1033 | 30 | Matching.matchingExternalsetAdjacencyMatrix(size,size,map); | |
| 1034 | 30 | BackendDAEEXT.matching(size,size,5,-1,1.0,1); | |
| 1035 | 30 | v1 := arrayCreate(size,-1); | |
| 1036 | 30 | v2 := arrayCreate(size,-1); | |
| 1037 | 30 | BackendDAEEXT.getAssignment(v2,v1); | |
| 1038 | // BackendDump.dumpAdjacencyMatrix(map); | ||
| 1039 | // BackendDump.dumpMatching(v1); | ||
| 1040 | // BackendDump.dumpMatching(v2); | ||
| 1041 | // sort residuals depent on matching to tvars | ||
| 1042 | 30 | oResiduals := getTVarResiduals(size,v1,eqnLocalGlobal,{}); | |
| 1043 | //print("iResiduals " + stringDelimitList(List.map(iResiduals,intString),",") + "\n"); | ||
| 1044 | //print("oResiduals " + stringDelimitList(List.map(oResiduals,intString),",") + "\n"); | ||
| 1045 | end sortResidualDepentOnTVars; | ||
| 1046 | |||
| 1047 | |||
| 1048 | protected function getGlobalLocal | ||
| 1049 | input list<Integer> iTVars; | ||
| 1050 | input Integer index; | ||
| 1051 | input array<Integer> iVarGlobalLocal; | ||
| 1052 | output array<Integer> oVarGlobalLocal = iVarGlobalLocal; | ||
| 1053 | protected | ||
| 1054 | Integer idx = index; | ||
| 1055 | algorithm | ||
| 1056 |
2/2✓ Branch 1 taken 64 times.
✓ Branch 2 taken 30 times.
|
94 | for i in iTVars loop |
| 1057 | 64 | arrayUpdate(oVarGlobalLocal,i,idx); | |
| 1058 | 64 | idx := idx + 1; | |
| 1059 | end for; | ||
| 1060 | end getGlobalLocal; | ||
| 1061 | |||
| 1062 | |||
| 1063 | protected function tVarsofResidualEqns | ||
| 1064 | input list<Integer> iEqns; | ||
| 1065 | input BackendDAE.AdjacencyMatrix m; | ||
| 1066 | input array<Integer> ass1; | ||
| 1067 | input array<list<Integer>> mT; | ||
| 1068 | input array<Integer> varGlobalLocal; | ||
| 1069 | input array<Integer> visited; | ||
| 1070 | input Integer iMark; | ||
| 1071 | output Integer oMark = iMark; | ||
| 1072 | output list<list<Integer>> oAcc; | ||
| 1073 | algorithm | ||
| 1074 |
4/4✓ Branch 0 taken 64 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 64 times.
✓ Branch 3 taken 30 times.
|
94 | oAcc := list( |
| 1075 | match eq | ||
| 1076 | local | ||
| 1077 | Integer e; | ||
| 1078 | list<Integer> vars,tvars; | ||
| 1079 | case e | ||
| 1080 | algorithm | ||
| 1081 | 64 | vars := List.select(m[e], Util.intPositive); | |
| 1082 | 64 | tvars := tVarsofEqn(vars,ass1,mT,visited,oMark,{}); | |
| 1083 | // change indices to local | ||
| 1084 | 64 | tvars := List.map1r(tvars,arrayGet,varGlobalLocal); | |
| 1085 | 64 | oMark := oMark + 1; | |
| 1086 | then tvars; | ||
| 1087 | end match for eq in iEqns); | ||
| 1088 | end tVarsofResidualEqns; | ||
| 1089 | |||
| 1090 | |||
| 1091 | protected function getTVarResiduals | ||
| 1092 | input Integer index; | ||
| 1093 | input array<Integer> v1; | ||
| 1094 | input array<Integer> eqnLocalGlobal; | ||
| 1095 | input list<Integer> iAcc; | ||
| 1096 | output list<Integer> oAcc; | ||
| 1097 | algorithm | ||
| 1098 | oAcc := match index | ||
| 1099 | local | ||
| 1100 | Integer e; | ||
| 1101 | case 0 then iAcc; | ||
| 1102 | case _ | ||
| 1103 | algorithm | ||
| 1104 | 64 | e := v1[index]; | |
| 1105 | 64 | e := eqnLocalGlobal[e]; | |
| 1106 | 64 | then | |
| 1107 | getTVarResiduals(index-1,v1,eqnLocalGlobal,e::iAcc); | ||
| 1108 | end match; | ||
| 1109 | end getTVarResiduals; | ||
| 1110 | |||
| 1111 | |||
| 1112 | protected function omcTearing2 " function to determine tvars and do cheap matching | ||
| 1113 | author: Frenkel TUD 2012-05" | ||
| 1114 | input list<Integer> unsolvables; | ||
| 1115 | input list<Integer> tSel_always; | ||
| 1116 | input list<Integer> tSel_prefer; | ||
| 1117 | input list<Integer> tSel_avoid; | ||
| 1118 | input list<Integer> tSel_never; | ||
| 1119 | input BackendDAE.AdjacencyMatrixEnhanced m; | ||
| 1120 | input BackendDAE.AdjacencyMatrixTEnhanced mt; | ||
| 1121 | input array<list<Integer>> mapEqnIncRow; | ||
| 1122 | input array<Integer> mapIncRowEqn; | ||
| 1123 | input Integer size; | ||
| 1124 | input BackendDAE.Variables vars; | ||
| 1125 | input BackendDAE.Shared ishared; | ||
| 1126 | input array<Integer> ass1; | ||
| 1127 | input array<Integer> ass2; | ||
| 1128 | input array<Integer> columark; | ||
| 1129 | input Integer mark; | ||
| 1130 | input list<Integer> inTVars; | ||
| 1131 | output list<Integer> outTVars; | ||
| 1132 | output Integer oMark; | ||
| 1133 | algorithm | ||
| 1134 | (outTVars,oMark) := matchcontinue(unsolvables,tSel_always) | ||
| 1135 | local | ||
| 1136 | Integer tvar; | ||
| 1137 | list<Integer> unassigned,rest,unsolv; | ||
| 1138 | BackendDAE.AdjacencyMatrixElementEnhanced vareqns; | ||
| 1139 | // if there are no unsolvables choose tvar by heuristic | ||
| 1140 | case ({},{}) | ||
| 1141 | algorithm | ||
| 1142 | // select tearing var | ||
| 1143 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
|
44 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 1144 | ✗ | print("\n" + BORDER + "\nBEGINNING of omcTearingSelectTearingVar\n\n\n"); | |
| 1145 | end if; | ||
| 1146 | 44 | tvar := omcTearingSelectTearingVar(vars,ass1,ass2,m,mt,tSel_prefer,tSel_avoid,tSel_never); | |
| 1147 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
|
44 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 1148 | ✗ | print("\nEND of omcTearingSelectTearingVar\n" + BORDER + "\n\n"); | |
| 1149 | end if; | ||
| 1150 | // mark tearing var | ||
| 1151 | 44 | arrayUpdate(ass1,tvar,size*2); | |
| 1152 | // equations not yet assigned containing the tvar | ||
| 1153 | 44 | vareqns := List.removeOnTrue(ass2, isAssignedSaveEnhanced, mt[tvar]); | |
| 1154 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
|
44 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 1155 | ✗ | print("Assignable equations containing new tvar:\n"); | |
| 1156 | ✗ | BackendDump.dumpAdjacencyRowEnhanced(vareqns); | |
| 1157 | ✗ | print("\n"); | |
| 1158 | end if; | ||
| 1159 | // cheap matching | ||
| 1160 | 44 | tearingBFS(vareqns,m,mt,mapEqnIncRow,mapIncRowEqn,size,ass1,ass2,{}); | |
| 1161 | // check for unassigned vars, if there some rerun | ||
| 1162 | 44 | unassigned := Matching.getUnassigned(size,ass1,{}); | |
| 1163 | 44 | (outTVars,oMark) := omcTearing3(unassigned,{},tSel_always,tSel_prefer,tSel_avoid,tSel_never,m,mt,mapEqnIncRow,mapIncRowEqn,size,vars,ishared,ass1,ass2,columark,mark+1,tvar::inTVars); | |
| 1164 | then | ||
| 1165 | (outTVars,oMark); | ||
| 1166 | // if there are unsolvables choose unsolvables as tvars | ||
| 1167 | case (tvar::rest,{}) | ||
| 1168 | algorithm | ||
| 1169 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
|
30 | if listMember(tvar,tSel_never) then |
| 1170 | ✗ | Error.addCompilerWarning("There are tearing variables with annotation attribute '__OpenModelica_tearingSelect = TearingSelect.never'. Use -d=tearingdump and -d=tearingdumpV for more information."); | |
| 1171 | end if; | ||
| 1172 |
2/4✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 30 times.
|
30 | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 1173 | ✗ | print("\nForced selection of Tearing Variable:\n" + UNDERLINE + "\n"); | |
| 1174 | ✗ | print("tVar: " + intString(tvar) + " (unsolvable in omcTearing2)\n\n\n"); | |
| 1175 | end if; | ||
| 1176 | // mark tearing var | ||
| 1177 | 30 | arrayUpdate(ass1,tvar,size*2); | |
| 1178 | // equations not yet assigned containing the tvar | ||
| 1179 | 30 | vareqns := List.removeOnTrue(ass2, isAssignedSaveEnhanced, mt[tvar]); | |
| 1180 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
|
30 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 1181 | ✗ | print("Assignable equations containing new tvar:\n"); | |
| 1182 | ✗ | BackendDump.dumpAdjacencyRowEnhanced(vareqns); | |
| 1183 | ✗ | print("\n"); | |
| 1184 | end if; | ||
| 1185 | // cheap matching | ||
| 1186 | 30 | tearingBFS(vareqns,m,mt,mapEqnIncRow,mapIncRowEqn,size,ass1,ass2,{}); | |
| 1187 | // check for unassigned vars, if there some rerun | ||
| 1188 | 30 | unassigned := Matching.getUnassigned(size,ass1,{}); | |
| 1189 | 30 | (outTVars,oMark) := omcTearing3(unassigned,rest,tSel_always,tSel_prefer,tSel_avoid,tSel_never,m,mt,mapEqnIncRow,mapIncRowEqn,size,vars,ishared,ass1,ass2,columark,mark+1,tvar::inTVars); | |
| 1190 | then | ||
| 1191 | (outTVars,oMark); | ||
| 1192 | case (_,_) | ||
| 1193 | algorithm | ||
| 1194 | ✗ | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 1195 | ✗ | print("\nForced selection of Tearing Variables:\n" + UNDERLINE + "\n"); | |
| 1196 | ✗ | print("Variables with annotation attribute 'always' as tVars: " + stringDelimitList(List.map(tSel_always,intString),",")+"\n"); | |
| 1197 | end if; | ||
| 1198 | // mark tearing var | ||
| 1199 | ✗ | markTVarsOrResiduals(tSel_always, ass1); | |
| 1200 | ✗ | (_,unsolv,_) := List.intersection1OnTrue(unsolvables,tSel_always,intEq); | |
| 1201 | // equations not yet assigned containing the tvars | ||
| 1202 | ✗ | vareqns := findVareqns(ass2,isAssignedSaveEnhanced,mt,tSel_always); | |
| 1203 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 1204 | ✗ | print("Assignable equations containing new tvars:\n"); | |
| 1205 | ✗ | BackendDump.dumpAdjacencyRowEnhanced(vareqns); | |
| 1206 | ✗ | print("\n"); | |
| 1207 | end if; | ||
| 1208 | // cheap matching | ||
| 1209 | ✗ | tearingBFS(vareqns,m,mt,mapEqnIncRow,mapIncRowEqn,size,ass1,ass2,{}); | |
| 1210 | // check for unassigned vars, if there some rerun | ||
| 1211 | ✗ | unassigned := Matching.getUnassigned(size,ass1,{}); | |
| 1212 | ✗ | (outTVars,oMark) := omcTearing3(unassigned,unsolv,{},tSel_prefer,tSel_avoid,tSel_never,m,mt,mapEqnIncRow,mapIncRowEqn,size,vars,ishared,ass1,ass2,columark,mark+1,listAppend(tSel_always,inTVars)); | |
| 1213 | then | ||
| 1214 | (outTVars,oMark); | ||
| 1215 | else | ||
| 1216 | algorithm | ||
| 1217 | ✗ | print("Tearing.omcTearing2 failed!"); | |
| 1218 | ✗ | then | |
| 1219 | fail(); | ||
| 1220 | end matchcontinue; | ||
| 1221 | end omcTearing2; | ||
| 1222 | |||
| 1223 | |||
| 1224 | protected function findVareqns | ||
| 1225 | "Function returns equations not yet assigned containing the currently handled tvars. | ||
| 1226 | author: ptaeuber FHB 2014-05" | ||
| 1227 | input array<Integer> ass2In; | ||
| 1228 | input CompFunc inCompFunc; | ||
| 1229 | input BackendDAE.AdjacencyMatrixTEnhanced mt; | ||
| 1230 | input list<Integer> tSel_alwaysIn; | ||
| 1231 | output list<tuple<Integer,BackendDAE.Solvability,BackendDAE.Constraints>> vareqnsOut = {}; | ||
| 1232 | partial function CompFunc | ||
| 1233 | input array<Integer> inValue; | ||
| 1234 | input tuple<Integer,BackendDAE.Solvability,BackendDAE.Constraints> inElement; | ||
| 1235 | output Boolean outIsEqual; | ||
| 1236 | end CompFunc; | ||
| 1237 | algorithm | ||
| 1238 | ✗ | for tvar in tSel_alwaysIn loop | |
| 1239 | ✗ | vareqnsOut := List.append_reverse(List.removeOnTrue(ass2In,inCompFunc,mt[tvar]), vareqnsOut); | |
| 1240 | end for; | ||
| 1241 | ✗ | vareqnsOut := List.unique(vareqnsOut); | |
| 1242 | end findVareqns; | ||
| 1243 | |||
| 1244 | |||
| 1245 | protected function omcTearingSelectTearingVar " author: Frenkel TUD 2012-05" | ||
| 1246 | input BackendDAE.Variables vars; | ||
| 1247 | input array<Integer> ass1; | ||
| 1248 | input array<Integer> ass2; | ||
| 1249 | input BackendDAE.AdjacencyMatrixEnhanced m; | ||
| 1250 | input BackendDAE.AdjacencyMatrixTEnhanced mt; | ||
| 1251 | input list<Integer> tSel_prefer; | ||
| 1252 | input list<Integer> tSel_avoid; | ||
| 1253 | input list<Integer> tSel_never; | ||
| 1254 | output Integer tearingVar; | ||
| 1255 | algorithm | ||
| 1256 | tearingVar := matchcontinue tSel_never | ||
| 1257 | local | ||
| 1258 | list<Integer> freeVars,eqns,unsolvables,pointsLst; | ||
| 1259 | Integer tvar; | ||
| 1260 | Integer varsize; | ||
| 1261 | array<Integer> points; | ||
| 1262 | |||
| 1263 | // if there is a variable unsolvable select it | ||
| 1264 | case _ | ||
| 1265 | algorithm | ||
| 1266 | 44 | unsolvables := getUnsolvableVarsConsiderMatching(BackendVariable.varsSize(vars),mt,ass1,ass2); | |
| 1267 |
1/2✓ Branch 0 taken 44 times.
✗ Branch 1 not taken.
|
44 | false := listEmpty(unsolvables); |
| 1268 | ✗ | tvar := listHead(unsolvables); | |
| 1269 | ✗ | if listMember(tvar,tSel_never) then | |
| 1270 | ✗ | Error.addCompilerWarning("There are tearing variables with annotation attribute '__OpenModelica_tearingSelect = TearingSelect.never'. Use -d=tearingdump and -d=tearingdumpV for more information."); | |
| 1271 | end if; | ||
| 1272 | ✗ | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 1273 | ✗ | print("\nForced selection of Tearing Variable:\n" + UNDERLINE + "\n"); | |
| 1274 | end if; | ||
| 1275 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 1276 | ✗ | print("tVar: " + intString(tvar) + " (unsolvable in omcTearingSelectTearingVar)\n\n"); | |
| 1277 | end if; | ||
| 1278 | then | ||
| 1279 | tvar; | ||
| 1280 | |||
| 1281 | case _ | ||
| 1282 | algorithm | ||
| 1283 | 44 | varsize := BackendVariable.varsSize(vars); | |
| 1284 | // variables not assigned yet: | ||
| 1285 | 44 | freeVars := Matching.getUnassigned(varsize,ass1,{}); | |
| 1286 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
|
44 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 1287 | ✗ | print("omcTearingSelectTearingVar Candidates(unassigned vars):\n"); | |
| 1288 | ✗ | BackendDump.debuglst(freeVars,intString,", ","\n"); | |
| 1289 | end if; | ||
| 1290 | 44 | (_,freeVars,_) := List.intersection1OnTrue(freeVars,tSel_never,intEq); | |
| 1291 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
|
44 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 1292 | ✗ | print("Candidates without variables with annotation attribute 'never':\n"); | |
| 1293 | ✗ | BackendDump.debuglst(freeVars,intString,", ","\n"); | |
| 1294 | end if; | ||
| 1295 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
|
44 | false := listEmpty(freeVars); |
| 1296 | |||
| 1297 | // CALCULATE TEARING-VARIABLE WEIGHTS | ||
| 1298 | 44 | points := arrayCreate(varsize,0); | |
| 1299 | // 1st: Points for solvability (see function solvabilityWeights) | ||
| 1300 | 44 | points := List.fold2(freeVars, calcVarWeights,mt,ass2,points); | |
| 1301 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
|
44 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 1302 | ✗ | print("\nPoints after 'calcVarWeights':\n" + stringDelimitList(List.mapArray(points, intString),",") + "\n\n"); | |
| 1303 | end if; | ||
| 1304 | 44 | eqns := Matching.getUnassigned(arrayLength(m),ass2,{}); | |
| 1305 | // 2nd: 5 points for each equation this variable would causalize | ||
| 1306 | 44 | points := List.fold2(eqns,addEqnWeights,m,ass1,points); | |
| 1307 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
|
44 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 1308 | ✗ | print("Points after 'addEqnWeights':\n" + stringDelimitList(List.mapArray(points, intString),",") + "\n\n"); | |
| 1309 | end if; | ||
| 1310 | // 3rd: only one-tenth of points for each discrete variable | ||
| 1311 | 44 | points := List.fold1(freeVars,discriminateDiscrete,vars,points); | |
| 1312 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
|
44 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 1313 | ✗ | print("Points after 'discriminateDiscrete':\n" + stringDelimitList(List.mapArray(points, intString),",") + "\n\n"); | |
| 1314 | end if; | ||
| 1315 | // 4th: Prefer variables with annotation attribute '__OpenModelica_tearingSelect = TearingSelect.prefer' | ||
| 1316 | 44 | pointsLst := preferAvoidVariables(freeVars, arrayList(points), tSel_prefer, 3.0); | |
| 1317 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
|
44 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 1318 | ✗ | print("Points after preferring variables with attribute 'prefer':\n" + stringDelimitList(List.map(pointsLst,intString),",") + "\n\n"); | |
| 1319 | end if; | ||
| 1320 | // 5th: Avoid variables with annotation attribute '__OpenModelica_tearingSelect = TearingSelect.avoid' | ||
| 1321 | 44 | pointsLst := preferAvoidVariables(freeVars, pointsLst, tSel_avoid, 0.334); | |
| 1322 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
|
44 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 1323 | ✗ | print("Points after discrimination against variables with attribute 'avoid':\n" + stringDelimitList(List.map(pointsLst,intString),",") + "\n\n"); | |
| 1324 | end if; | ||
| 1325 | 44 | tvar := selectVarWithMostPoints(freeVars,pointsLst); | |
| 1326 | // fcall(Flags.TEARING_DUMPVERBOSE,print,"VarsWithMostEqns:\n"); | ||
| 1327 | // fcall(Flags.TEARING_DUMPVERBOSE,BackendDump.debuglst,(freeVars,intString,", ","\n")); | ||
| 1328 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
|
44 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 1329 | ✗ | print("tVar: " + intString(tvar) + " (" + intString(listGet(pointsLst,tvar)) + " points)\n\n"); | |
| 1330 | elseif listMember(tvar,tSel_avoid) then | ||
| 1331 | 2 | Error.addCompilerWarning("The Tearing heuristic has chosen variables with annotation attribute '__OpenModelica_tearingSelect = TearingSelect.avoid'. Use -d=tearingdump and -d=tearingdumpV for more information."); | |
| 1332 | end if; | ||
| 1333 | then | ||
| 1334 | tvar; | ||
| 1335 | else | ||
| 1336 | algorithm | ||
| 1337 | ✗ | print("omcTearingSelectTearingVar failed because no unmatched var!\n"); | |
| 1338 | ✗ | then | |
| 1339 | fail(); | ||
| 1340 | end matchcontinue; | ||
| 1341 | end omcTearingSelectTearingVar; | ||
| 1342 | |||
| 1343 | |||
| 1344 | protected function getUnsolvableVarsConsiderMatching | ||
| 1345 | " returns one unsolvable var with respect to the current matching | ||
| 1346 | author: Frenkel TUD 2012-08" | ||
| 1347 | input Integer size; | ||
| 1348 | input BackendDAE.AdjacencyMatrixTEnhanced meT; | ||
| 1349 | input array<Integer> ass1; | ||
| 1350 | input array<Integer> ass2; | ||
| 1351 | output list<Integer> unsolvables = {}; | ||
| 1352 | protected | ||
| 1353 | BackendDAE.AdjacencyMatrixElementEnhanced elem; | ||
| 1354 | Boolean isUnsolvable; | ||
| 1355 | algorithm | ||
| 1356 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4147 times.
|
751855 | for index in 1:size loop |
| 1357 | /* unmatched var */ | ||
| 1358 |
2/2✓ Branch 1 taken 421575 times.
✓ Branch 2 taken 326133 times.
|
747708 | if intLt(ass1[index],0) then |
| 1359 | 421575 | elem := meT[index]; | |
| 1360 | /* consider only unmatched eqns */ | ||
| 1361 | 421575 | elem := removeMatched(elem,ass2); | |
| 1362 | 421575 | isUnsolvable := unsolvable(elem); | |
| 1363 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 421575 times.
|
421575 | if isUnsolvable then |
| 1364 | unsolvables := index::unsolvables; | ||
| 1365 | end if; | ||
| 1366 | end if; | ||
| 1367 | end for; | ||
| 1368 | end getUnsolvableVarsConsiderMatching; | ||
| 1369 | |||
| 1370 | |||
| 1371 | protected function removeMatched | ||
| 1372 | " helper function for getUnsolvableVarsConsiderMatching, | ||
| 1373 | returns only unmatched equations | ||
| 1374 | author: Frenkel TUD 2012-08" | ||
| 1375 | input BackendDAE.AdjacencyMatrixElementEnhanced elem; | ||
| 1376 | input array<Integer> ass2; | ||
| 1377 | output BackendDAE.AdjacencyMatrixElementEnhanced oAcc = {}; | ||
| 1378 | protected | ||
| 1379 | Integer e; | ||
| 1380 | algorithm | ||
| 1381 |
2/2✓ Branch 0 taken 1490344 times.
✓ Branch 1 taken 421575 times.
|
1911919 | for el in elem loop |
| 1382 | 1490344 | (e,_,_) := el; | |
| 1383 |
3/4✓ Branch 0 taken 1489796 times.
✓ Branch 1 taken 548 times.
✓ Branch 3 taken 1489796 times.
✗ Branch 4 not taken.
|
1490344 | if intGt(e,0) and intLt(ass2[e],0) then |
| 1384 | oAcc := el::oAcc; | ||
| 1385 | end if; | ||
| 1386 | end for; | ||
| 1387 | end removeMatched; | ||
| 1388 | |||
| 1389 | |||
| 1390 | protected function calcVarWeights "function giving points for solvability" | ||
| 1391 | input Integer v; | ||
| 1392 | input BackendDAE.AdjacencyMatrixTEnhanced mt; | ||
| 1393 | input array<Integer> ass2; | ||
| 1394 | input array<Integer> iPoints; | ||
| 1395 | output array<Integer> oPoints; | ||
| 1396 | protected | ||
| 1397 | Integer p; | ||
| 1398 | algorithm | ||
| 1399 | 341 | p := calcSolvabilityWeight(mt[v],ass2); | |
| 1400 | 341 | oPoints := arrayUpdate(iPoints,v,p); | |
| 1401 | end calcVarWeights; | ||
| 1402 | |||
| 1403 | |||
| 1404 | protected function calcSolvabilityWeight | ||
| 1405 | "helper function for calcVarWeights, giving points for solvability" | ||
| 1406 | input BackendDAE.AdjacencyMatrixElementEnhanced inRow; | ||
| 1407 | input array<Integer> ass2; | ||
| 1408 | output Integer w; | ||
| 1409 | algorithm | ||
| 1410 | 341 | w := List.fold1(inRow,solvabilityWeightsnoStates,ass2,0); | |
| 1411 | end calcSolvabilityWeight; | ||
| 1412 | |||
| 1413 | |||
| 1414 | protected function solvabilityWeightsnoStates | ||
| 1415 | "helper function for calcSolvabilityWeight, giving points for solvability | ||
| 1416 | author: Frenkel TUD 2012-05" | ||
| 1417 | input tuple<Integer,BackendDAE.Solvability,BackendDAE.Constraints> inTpl; | ||
| 1418 | input array<Integer> ass; | ||
| 1419 | input Integer iW; | ||
| 1420 | output Integer oW; | ||
| 1421 | algorithm | ||
| 1422 | oW := match inTpl | ||
| 1423 | local | ||
| 1424 | BackendDAE.Solvability s; | ||
| 1425 | Integer eq,w; | ||
| 1426 | case (eq,s,_) | ||
| 1427 | guard | ||
| 1428 | intGt(eq,0) and | ||
| 1429 | not intGt(ass[eq], 0) | ||
| 1430 | algorithm | ||
| 1431 | 912 | w := solvabilityWeights(s); | |
| 1432 | 912 | then | |
| 1433 | intAdd(w,iW); | ||
| 1434 | else iW; | ||
| 1435 | end match; | ||
| 1436 | end solvabilityWeightsnoStates; | ||
| 1437 | |||
| 1438 | |||
| 1439 | protected function solvabilityWeights | ||
| 1440 | " helper function for solvabilityWeightsnoStates | ||
| 1441 | author: Frenkel TUD 2012-05, | ||
| 1442 | return a integer for the solvability, this function is used | ||
| 1443 | to calculade weights for variables to select the tearing variable." | ||
| 1444 | input BackendDAE.Solvability solva; | ||
| 1445 | output Integer i; | ||
| 1446 | algorithm | ||
| 1447 | i := match solva | ||
| 1448 | case BackendDAE.SOLVABILITY_SOLVED() then 0; | ||
| 1449 | case BackendDAE.SOLVABILITY_CONSTONE() then 2; | ||
| 1450 | case BackendDAE.SOLVABILITY_CONST() then 5; | ||
| 1451 | case BackendDAE.SOLVABILITY_PARAMETER(b=false) then 0; | ||
| 1452 | case BackendDAE.SOLVABILITY_PARAMETER(b=true) then 50; | ||
| 1453 | case BackendDAE.SOLVABILITY_LINEAR(b=false) then 0; | ||
| 1454 | case BackendDAE.SOLVABILITY_LINEAR(b=true) then 100; | ||
| 1455 | case BackendDAE.SOLVABILITY_NONLINEAR() then 200; | ||
| 1456 | case BackendDAE.SOLVABILITY_UNSOLVABLE() then 300; | ||
| 1457 | else 0; | ||
| 1458 | end match; | ||
| 1459 | end solvabilityWeights; | ||
| 1460 | |||
| 1461 | |||
| 1462 | protected function addEqnWeights | ||
| 1463 | "function adds five points to variables for each equation it would causalize as tvar" | ||
| 1464 | input Integer e; | ||
| 1465 | input BackendDAE.AdjacencyMatrixEnhanced m; | ||
| 1466 | input array<Integer> ass1; | ||
| 1467 | input array<Integer> iPoints; | ||
| 1468 | output array<Integer> oPoints; | ||
| 1469 | algorithm | ||
| 1470 | oPoints := matchcontinue iPoints | ||
| 1471 | local | ||
| 1472 | Integer v1,v2; | ||
| 1473 | array<Integer> points; | ||
| 1474 | case _ | ||
| 1475 | algorithm | ||
| 1476 | // finds equations with exact two variables (v1,v2) | ||
| 1477 |
6/6✓ Branch 2 taken 4 times.
✓ Branch 3 taken 369 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 357 times.
✓ Branch 6 taken 132 times.
✓ Branch 7 taken 225 times.
|
373 | (v1,_,_)::(v2,_,_)::{} := List.removeOnTrue(ass1, isAssignedSaveEnhanced, m[e]); |
| 1478 | 225 | points := arrayUpdate(iPoints,v1,iPoints[v1]+5); | |
| 1479 | 225 | points := arrayUpdate(iPoints,v2,points[v2]+5); | |
| 1480 | then | ||
| 1481 | points; | ||
| 1482 | else | ||
| 1483 | iPoints; | ||
| 1484 | end matchcontinue; | ||
| 1485 | end addEqnWeights; | ||
| 1486 | |||
| 1487 | |||
| 1488 | protected function isAssignedSaveEnhanced " returns true if var/eqn is already assigned | ||
| 1489 | author: Frenkel TUD 2012-05" | ||
| 1490 | input array<Integer> ass; | ||
| 1491 | input tuple<Integer,BackendDAE.Solvability,BackendDAE.Constraints> inTpl; | ||
| 1492 | output Boolean outB; | ||
| 1493 | algorithm | ||
| 1494 | outB := match inTpl | ||
| 1495 | local | ||
| 1496 | Integer i; | ||
| 1497 | case (i,_,_) guard intGt(i,0) | ||
| 1498 | 1533553 | then | |
| 1499 | intGt(ass[i],0); | ||
| 1500 | else | ||
| 1501 | true; | ||
| 1502 | end match; | ||
| 1503 | end isAssignedSaveEnhanced; | ||
| 1504 | |||
| 1505 | |||
| 1506 | protected function discriminateDiscrete " leaves only one-tenth of points for each discrete variable | ||
| 1507 | author: Frenkel TUD 2012-08" | ||
| 1508 | input Integer v; | ||
| 1509 | input BackendDAE.Variables vars; | ||
| 1510 | input array<Integer> iPoints; | ||
| 1511 | output array<Integer> oPoints; | ||
| 1512 | protected | ||
| 1513 | Integer p; | ||
| 1514 | Boolean b; | ||
| 1515 | BackendDAE.Var var; | ||
| 1516 | algorithm | ||
| 1517 | 341 | var := BackendVariable.getVarAt(vars, v); | |
| 1518 | 341 | b := BackendVariable.isVarDiscrete(var); | |
| 1519 | 341 | p := iPoints[v]; | |
| 1520 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 337 times.
|
341 | p := if b then intDiv(p,10) else p; |
| 1521 | 341 | oPoints := arrayUpdate(iPoints,v,p); | |
| 1522 | end discriminateDiscrete; | ||
| 1523 | |||
| 1524 | |||
| 1525 | protected function selectVarWithMostPoints " returns one var with most points | ||
| 1526 | author: Frenkel TUD 2012-05" | ||
| 1527 | input list<Integer> vars; | ||
| 1528 | input list<Integer> points; | ||
| 1529 | output Integer oVar = -1; | ||
| 1530 | protected | ||
| 1531 | Integer defp = -1; | ||
| 1532 | Integer p; | ||
| 1533 | algorithm | ||
| 1534 |
2/2✓ Branch 0 taken 341 times.
✓ Branch 1 taken 44 times.
|
385 | for v in vars loop |
| 1535 | 341 | p := listGet(points,v); | |
| 1536 |
2/2✓ Branch 0 taken 100 times.
✓ Branch 1 taken 241 times.
|
341 | if p > defp then |
| 1537 | defp := p; | ||
| 1538 | oVar := v; | ||
| 1539 | end if; | ||
| 1540 | end for; | ||
| 1541 | end selectVarWithMostPoints; | ||
| 1542 | |||
| 1543 | |||
| 1544 | protected function tearingBFS " function to find maximum matching | ||
| 1545 | author: Frenkel TUD 2012-05" | ||
| 1546 | input BackendDAE.AdjacencyMatrixElementEnhanced queue; | ||
| 1547 | input BackendDAE.AdjacencyMatrixEnhanced m; | ||
| 1548 | input BackendDAE.AdjacencyMatrixTEnhanced mt; | ||
| 1549 | input array<list<Integer>> mapEqnIncRow; | ||
| 1550 | input array<Integer> mapIncRowEqn; | ||
| 1551 | input Integer size; | ||
| 1552 | input array<Integer> ass1; | ||
| 1553 | input array<Integer> ass2; | ||
| 1554 | //input array<Integer> columark; | ||
| 1555 | //input Integer mark; | ||
| 1556 | input BackendDAE.AdjacencyMatrixElementEnhanced nextQueue; | ||
| 1557 | algorithm | ||
| 1558 | () := match(queue, nextQueue) | ||
| 1559 | local | ||
| 1560 | Integer c,eqnsize,cnonscalar; | ||
| 1561 | BackendDAE.AdjacencyMatrixElementEnhanced rest,newqueue,rows; | ||
| 1562 | // if there are no more equations in queue maximum matching is found | ||
| 1563 | case ({}, {}) then (); | ||
| 1564 | |||
| 1565 | // if queue is empty, use next queue | ||
| 1566 | case ({}, _) | ||
| 1567 | algorithm | ||
| 1568 | // use only equations from next queue which are not assigned yet | ||
| 1569 | 145 | newqueue := List.removeOnTrue(ass2, isAssignedSaveEnhanced, nextQueue); | |
| 1570 | // use linear equations first | ||
| 1571 | 145 | newqueue := sortEqnsSolvable(newqueue,m); | |
| 1572 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 145 times.
|
145 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 1573 | ✗ | print("Use next Queue!\n"); | |
| 1574 | end if; | ||
| 1575 | 145 | tearingBFS(newqueue,m,mt,mapEqnIncRow,mapIncRowEqn,size,ass1,ass2,{}); | |
| 1576 | then | ||
| 1577 | (); | ||
| 1578 | case((c,_,_)::rest, _) | ||
| 1579 | algorithm | ||
| 1580 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 470 times.
|
470 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 1581 | ✗ | print("Queue:\n"); | |
| 1582 | ✗ | BackendDump.dumpAdjacencyRowEnhanced(queue); | |
| 1583 | ✗ | print("Process Eqn: " + intString(c) + "\n"); | |
| 1584 | end if; | ||
| 1585 | // not assigned variables in equation c: | ||
| 1586 | 470 | rows := List.removeOnTrue(ass1, isAssignedSaveEnhanced, m[c]); | |
| 1587 | //arrayUpdate(columark,c,mark); | ||
| 1588 | // For Equationarrays | ||
| 1589 | 470 | cnonscalar := mapIncRowEqn[c]; | |
| 1590 | 470 | eqnsize := listLength(mapEqnIncRow[cnonscalar]); | |
| 1591 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 470 times.
|
470 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 1592 | ✗ | print("Eqn Size: " + intString(eqnsize) + "\n"); | |
| 1593 | // fcall(Flags.TEARING_DUMPVERBOSE, print,"Rows(not assigned variables in eqn " + intString(c) + ":\n" + stringDelimitList(List.mapMap(rows,Util.tuple21,intString),", ") + "\n"); | ||
| 1594 | ✗ | print("Rows (not assigned variables in eqn " + intString(c) + "):\n"); | |
| 1595 | ✗ | BackendDump.dumpAdjacencyRowEnhanced(rows); | |
| 1596 | ✗ | print("\n"); | |
| 1597 | end if; | ||
| 1598 | // make assignment and find next equations to get causalized | ||
| 1599 | 470 | newqueue := tearingBFS1(rows,eqnsize,mapEqnIncRow[cnonscalar],mt,ass1,ass2,nextQueue); | |
| 1600 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 470 times.
|
470 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 1601 | ✗ | print("Next Queue:\n"); | |
| 1602 | ✗ | BackendDump.dumpAdjacencyRowEnhanced(newqueue); | |
| 1603 | ✗ | print("\n\n"); | |
| 1604 | end if; | ||
| 1605 | 470 | tearingBFS(rest,m,mt,mapEqnIncRow,mapIncRowEqn,size,ass1,ass2,newqueue); | |
| 1606 | then | ||
| 1607 | (); | ||
| 1608 | end match; | ||
| 1609 | end tearingBFS; | ||
| 1610 | |||
| 1611 | |||
| 1612 | protected function sortEqnsSolvable | ||
| 1613 | " author: Frenkel TUD 2012-10 | ||
| 1614 | moves equations with nonlinear or unsolvable parts to the end" | ||
| 1615 | input BackendDAE.AdjacencyMatrixElementEnhanced queue; | ||
| 1616 | input BackendDAE.AdjacencyMatrixEnhanced m; | ||
| 1617 | output BackendDAE.AdjacencyMatrixElementEnhanced nextQueue; | ||
| 1618 | protected | ||
| 1619 | BackendDAE.AdjacencyMatrixElementEnhanced qnon,qsolv; | ||
| 1620 | algorithm | ||
| 1621 | 145 | (qnon,qsolv) := List.split1OnTrue(queue,hasnonlinearVars,m); | |
| 1622 | 145 | nextQueue := listAppend(qsolv,qnon); | |
| 1623 | end sortEqnsSolvable; | ||
| 1624 | |||
| 1625 | |||
| 1626 | protected function hasnonlinearVars | ||
| 1627 | input BackendDAE.AdjacencyMatrixElementEnhancedEntry entry; | ||
| 1628 | input BackendDAE.AdjacencyMatrixEnhanced m; | ||
| 1629 | output Boolean hasnonlinear; | ||
| 1630 | protected | ||
| 1631 | Integer r; | ||
| 1632 | BackendDAE.AdjacencyMatrixElementEnhanced row; | ||
| 1633 | algorithm | ||
| 1634 | 263 | (r,_,_) := entry; | |
| 1635 | 263 | row := m[r]; | |
| 1636 | 263 | hasnonlinear := hasnonlinearVars1(row); | |
| 1637 | end hasnonlinearVars; | ||
| 1638 | |||
| 1639 | |||
| 1640 | protected function hasnonlinearVars1 | ||
| 1641 | input BackendDAE.AdjacencyMatrixElementEnhanced row; | ||
| 1642 | output Boolean hasnonlinear; | ||
| 1643 | algorithm | ||
| 1644 | hasnonlinear := match row | ||
| 1645 | local | ||
| 1646 | BackendDAE.AdjacencyMatrixElementEnhanced rest; | ||
| 1647 | case {} then false; | ||
| 1648 | case (_,BackendDAE.SOLVABILITY_NONLINEAR(),_)::_ | ||
| 1649 | then | ||
| 1650 | true; | ||
| 1651 | case _::rest | ||
| 1652 | 731 | then | |
| 1653 | hasnonlinearVars1(rest); | ||
| 1654 | end match; | ||
| 1655 | end hasnonlinearVars1; | ||
| 1656 | |||
| 1657 | |||
| 1658 | protected function tearingBFS1 " function checks for possible assignments and calls tearingBFS2 | ||
| 1659 | author: Frenkel TUD 2012-05" | ||
| 1660 | input BackendDAE.AdjacencyMatrixElementEnhanced rows; | ||
| 1661 | input Integer size; | ||
| 1662 | input list<Integer> c; | ||
| 1663 | input BackendDAE.AdjacencyMatrixTEnhanced mt; | ||
| 1664 | input array<Integer> ass1; | ||
| 1665 | input array<Integer> ass2; | ||
| 1666 | //input array<Integer> columark; | ||
| 1667 | //input Integer mark; | ||
| 1668 | input BackendDAE.AdjacencyMatrixElementEnhanced inNextQueue; | ||
| 1669 | output BackendDAE.AdjacencyMatrixElementEnhanced outNextQueue; | ||
| 1670 | algorithm | ||
| 1671 | outNextQueue := match inNextQueue | ||
| 1672 | local | ||
| 1673 | // there is only one variable assignable from this equation and the equation is solvable for this variable | ||
| 1674 | case _ | ||
| 1675 | guard | ||
| 1676 | intEq(listLength(rows),size) and | ||
| 1677 | solvableLst(rows) | ||
| 1678 | algorithm | ||
| 1679 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 203 times.
|
203 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 1680 | ✗ | print("Assign Eqns: " + stringDelimitList(List.map(c,intString),", ") + "\n"); | |
| 1681 | end if; | ||
| 1682 | 203 | then | |
| 1683 | // make assignment and get next equations | ||
| 1684 | tearingBFS2(rows,c,mt,ass1,ass2,inNextQueue); | ||
| 1685 | /* case (_,_,_,_,_,_,_) | ||
| 1686 | guard | ||
| 1687 | intEq(listLength(rows),size) and | ||
| 1688 | not solvableLst(rows); | ||
| 1689 | algorithm | ||
| 1690 | //fcall(Flags.TEARING_DUMPVERBOSE, print,"cannot Assign Var" + intString(r) + " with Eqn " + intString(c) + "\n"); | ||
| 1691 | then | ||
| 1692 | inNextQueue; | ||
| 1693 | */ | ||
| 1694 | else inNextQueue; | ||
| 1695 | end match; | ||
| 1696 | end tearingBFS1; | ||
| 1697 | |||
| 1698 | |||
| 1699 | protected function solvableLst | ||
| 1700 | " returns true if all variables are solvable" | ||
| 1701 | input BackendDAE.AdjacencyMatrixElementEnhanced rows; | ||
| 1702 | output Boolean solvable = true; | ||
| 1703 | protected | ||
| 1704 | BackendDAE.Solvability s; | ||
| 1705 | algorithm | ||
| 1706 |
2/2✓ Branch 0 taken 511965 times.
✓ Branch 1 taken 212600 times.
|
724565 | for r in rows loop |
| 1707 | 511965 | (_,s,_) := r; | |
| 1708 |
2/2✓ Branch 1 taken 59932 times.
✓ Branch 2 taken 452033 times.
|
511965 | if not solvable(s) then |
| 1709 | solvable := false; | ||
| 1710 | 59932 | return; | |
| 1711 | end if; | ||
| 1712 | end for; | ||
| 1713 | end solvableLst; | ||
| 1714 | |||
| 1715 | |||
| 1716 | protected function solvable | ||
| 1717 | input BackendDAE.Solvability s; | ||
| 1718 | output Boolean b; | ||
| 1719 | algorithm | ||
| 1720 | b := match s | ||
| 1721 | case BackendDAE.SOLVABILITY_SOLVED() then true; | ||
| 1722 | case BackendDAE.SOLVABILITY_CONSTONE() then true; | ||
| 1723 | case BackendDAE.SOLVABILITY_CONST(b=b) then b; | ||
| 1724 |
5/6✓ Branch 0 taken 129933 times.
✓ Branch 1 taken 17949 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 129925 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 8 times.
|
147882 | case BackendDAE.SOLVABILITY_PARAMETER(b=b) then (b and not stringEqual(Flags.getConfigString(Flags.TEARING_STRICTNESS), "veryStrict")); |
| 1725 | case BackendDAE.SOLVABILITY_LINEAR() then false; | ||
| 1726 | case BackendDAE.SOLVABILITY_NONLINEAR() then false; | ||
| 1727 | case BackendDAE.SOLVABILITY_UNSOLVABLE() then false; | ||
| 1728 | case BackendDAE.SOLVABILITY_SOLVABLE() then true; | ||
| 1729 | else false; | ||
| 1730 | end match; | ||
| 1731 | end solvable; | ||
| 1732 | |||
| 1733 | protected function isEntrySolved | ||
| 1734 | input BackendDAE.AdjacencyMatrixElementEnhancedEntry entry; | ||
| 1735 | output Boolean b; | ||
| 1736 | algorithm | ||
| 1737 | b := match entry | ||
| 1738 | case (_, BackendDAE.SOLVABILITY_SOLVED(), _) then true; | ||
| 1739 | case (_, BackendDAE.SOLVABILITY_PARAMETER(b=b), _) algorithm | ||
| 1740 | ✗ | Error.addInternalError("SOLVABILITY_PARAMETER is not handled yet. Requires revision.", sourceInfo()); | |
| 1741 | ✗ | then (b and not stringEqual(Flags.getConfigString(Flags.TEARING_STRICTNESS), "veryStrict")); | |
| 1742 | else false; | ||
| 1743 | end match; | ||
| 1744 | end isEntrySolved; | ||
| 1745 | |||
| 1746 | protected function isEntrySolvable | ||
| 1747 | input BackendDAE.AdjacencyMatrixElementEnhancedEntry entry; | ||
| 1748 | output Boolean b; | ||
| 1749 | algorithm | ||
| 1750 | 10 | b := solvable(Util.tuple32(entry)); | |
| 1751 | end isEntrySolvable; | ||
| 1752 | |||
| 1753 | |||
| 1754 | protected function tearingBFS2 " function to make an assignment and determine the next equations for queue | ||
| 1755 | author: Frenkel TUD 2012-05" | ||
| 1756 | input BackendDAE.AdjacencyMatrixElementEnhanced rows; | ||
| 1757 | input list<Integer> clst; | ||
| 1758 | input BackendDAE.AdjacencyMatrixTEnhanced mt; | ||
| 1759 | input array<Integer> ass1; | ||
| 1760 | input array<Integer> ass2; | ||
| 1761 | //input array<Integer> columark; | ||
| 1762 | //input Integer mark; | ||
| 1763 | input BackendDAE.AdjacencyMatrixElementEnhanced inNextQueue; | ||
| 1764 | output BackendDAE.AdjacencyMatrixElementEnhanced outNextQueue; | ||
| 1765 | algorithm | ||
| 1766 | outNextQueue := match(rows, clst) | ||
| 1767 | local | ||
| 1768 | Integer r,c; | ||
| 1769 | list<Integer> ilst; | ||
| 1770 | BackendDAE.AdjacencyMatrixElementEnhanced rest,vareqns,newqueue; | ||
| 1771 | case ({}, _) then inNextQueue; | ||
| 1772 | case ((r,_,_)::rest, c::ilst) | ||
| 1773 | algorithm | ||
| 1774 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 207 times.
|
207 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 1775 | ✗ | print("Assignment: Eq " + intString(c) + " - Var " + intString(r) + "\n"); | |
| 1776 | end if; | ||
| 1777 | // assign | ||
| 1778 | 207 | arrayUpdate(ass1,r,c); | |
| 1779 | 207 | arrayUpdate(ass2,c,r); | |
| 1780 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 207 times.
|
207 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 1781 | ✗ | print("ass1: " + stringDelimitList(List.mapArray(ass1, intString),",")+"\n"); | |
| 1782 | ✗ | print("ass2: " + stringDelimitList(List.mapArray(ass2, intString),",")+"\n"); | |
| 1783 | end if; | ||
| 1784 | // not yet assigned equations containing var r | ||
| 1785 | 207 | vareqns := List.removeOnTrue(ass2, isAssignedSaveEnhanced, mt[r]); | |
| 1786 | 207 | newqueue := listAppend(inNextQueue,vareqns); | |
| 1787 | 207 | then | |
| 1788 | tearingBFS2(rest,ilst,mt,ass1,ass2,newqueue); | ||
| 1789 | end match; | ||
| 1790 | end tearingBFS2; | ||
| 1791 | |||
| 1792 | |||
| 1793 | protected function omcTearing3 " function to rerun omcTearing2 if there are still unassigned vars | ||
| 1794 | author: Frenkel TUD 2012-05" | ||
| 1795 | input list<Integer> unassigned; | ||
| 1796 | input list<Integer> unsolvables; | ||
| 1797 | input list<Integer> tSel_always; | ||
| 1798 | input list<Integer> tSel_prefer; | ||
| 1799 | input list<Integer> tSel_avoid; | ||
| 1800 | input list<Integer> tSel_never; | ||
| 1801 | input BackendDAE.AdjacencyMatrixEnhanced m; | ||
| 1802 | input BackendDAE.AdjacencyMatrixTEnhanced mt; | ||
| 1803 | input array<list<Integer>> mapEqnIncRow; | ||
| 1804 | input array<Integer> mapIncRowEqn; | ||
| 1805 | input Integer size; | ||
| 1806 | input BackendDAE.Variables vars; | ||
| 1807 | input BackendDAE.Shared ishared; | ||
| 1808 | input array<Integer> ass1; | ||
| 1809 | input array<Integer> ass2; | ||
| 1810 | input array<Integer> columark; | ||
| 1811 | input Integer mark; | ||
| 1812 | input list<Integer> inTVars; | ||
| 1813 | output list<Integer> outTVars; | ||
| 1814 | output Integer oMark; | ||
| 1815 | algorithm | ||
| 1816 | (outTVars,oMark) := match unassigned | ||
| 1817 | local | ||
| 1818 | 35 | case {} then (inTVars,mark); | |
| 1819 | else | ||
| 1820 | algorithm | ||
| 1821 | 39 | (outTVars,oMark) := omcTearing2(unsolvables,tSel_always,tSel_prefer,tSel_avoid,tSel_never,m,mt,mapEqnIncRow,mapIncRowEqn,size,vars,ishared,ass1,ass2,columark,mark,inTVars); | |
| 1822 | then | ||
| 1823 | (outTVars,oMark); | ||
| 1824 | end match; | ||
| 1825 | end omcTearing3; | ||
| 1826 | |||
| 1827 | |||
| 1828 | protected function omcTearing4 | ||
| 1829 | " maps indexes back to entire system and creates strong component from tearing information | ||
| 1830 | author: Frenkel TUD 2012-09" | ||
| 1831 | input BackendDAE.JacobianType jacType; | ||
| 1832 | input BackendDAE.EqSystem isyst; | ||
| 1833 | input BackendDAE.Shared ishared; | ||
| 1834 | input BackendDAE.EqSystem subsyst; | ||
| 1835 | input list<Integer> tvars; | ||
| 1836 | input list<Integer> residual; | ||
| 1837 | input array<Integer> ass1; | ||
| 1838 | input array<Integer> ass2; | ||
| 1839 | input list<list<Integer>> othercomps; | ||
| 1840 | input list<Integer> eindex; | ||
| 1841 | input list<Integer> vindx; | ||
| 1842 | input array<list<Integer>> mapEqnIncRow; | ||
| 1843 | input array<Integer> mapIncRowEqn; | ||
| 1844 | input array<Integer> columark; | ||
| 1845 | input Integer mark; | ||
| 1846 | input Boolean mixedSystem; | ||
| 1847 | output BackendDAE.StrongComponent ocomp; | ||
| 1848 | output Boolean outRunMatching; | ||
| 1849 | algorithm | ||
| 1850 | (ocomp,outRunMatching):= | ||
| 1851 | matchcontinue mixedSystem | ||
| 1852 | local | ||
| 1853 | list<Integer> ores,residual1,ovars; | ||
| 1854 | BackendDAE.InnerEquations innerEquations; | ||
| 1855 | array<Integer> eindxarr,varindxarr; | ||
| 1856 | Boolean linear; | ||
| 1857 | case _ | ||
| 1858 | algorithm | ||
| 1859 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 30 times.
|
30 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 1860 | ✗ | print("handle torn System\n"); | |
| 1861 | end if; | ||
| 1862 | 30 | residual1 := List.map1r(residual,arrayGet,mapIncRowEqn); | |
| 1863 | 30 | residual1 := List.fold2(residual1,uniqueIntLst,mark,columark,{}); | |
| 1864 | // map indexes back | ||
| 1865 | 30 | eindxarr := listArray(eindex); | |
| 1866 | 30 | ores := List.map1r(residual1,arrayGet,eindxarr); | |
| 1867 | 30 | varindxarr := listArray(vindx); | |
| 1868 | 30 | ovars := List.map1r(tvars,arrayGet,varindxarr); | |
| 1869 | 30 | innerEquations := omcTearing4_1(othercomps,ass2,mapIncRowEqn,eindxarr,varindxarr,columark,mark); | |
| 1870 | 30 | linear := BackendDAEUtil.getLinearfromJacType(jacType); | |
| 1871 |
4/4✓ Branch 1 taken 28 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 22 times.
|
66 | then |
| 1872 | (BackendDAE.TORNSYSTEM(BackendDAE.TEARINGSET(ovars, ores, innerEquations, BackendDAE.EMPTY_JACOBIAN()), NONE(), linear,mixedSystem),true); | ||
| 1873 | case _ | ||
| 1874 | ✗ | then | |
| 1875 | (BackendDAE.TORNSYSTEM(BackendDAE.TEARINGSET({}, {}, {}, BackendDAE.EMPTY_JACOBIAN()), NONE(), false,mixedSystem),false); | ||
| 1876 | end matchcontinue; | ||
| 1877 | end omcTearing4; | ||
| 1878 | |||
| 1879 | |||
| 1880 | protected function omcTearing4_1 | ||
| 1881 | " creates innerEquations for TearingSet | ||
| 1882 | author: Frenkel TUD 2012-09" | ||
| 1883 | input list<list<Integer>> othercomps; | ||
| 1884 | input array<Integer> ass2; | ||
| 1885 | input array<Integer> mapIncRowEqn; | ||
| 1886 | input array<Integer> eindxarr; | ||
| 1887 | input array<Integer> varindxarr; | ||
| 1888 | input array<Integer> columark; | ||
| 1889 | input Integer mark; | ||
| 1890 | output BackendDAE.InnerEquations outInnerEquations; | ||
| 1891 | algorithm | ||
| 1892 |
4/4✓ Branch 0 taken 203 times.
✓ Branch 1 taken 30 times.
✓ Branch 2 taken 203 times.
✓ Branch 3 taken 30 times.
|
233 | outInnerEquations := list( |
| 1893 | match x | ||
| 1894 | local | ||
| 1895 | list<Integer> vlst,clst,elst; | ||
| 1896 | Integer e,v,c; | ||
| 1897 | |||
| 1898 | case {c} | ||
| 1899 | algorithm | ||
| 1900 | 201 | e := mapIncRowEqn[c]; | |
| 1901 | 201 | e := eindxarr[e]; | |
| 1902 | 201 | v := ass2[c]; | |
| 1903 | 201 | v := varindxarr[v]; | |
| 1904 | 201 | then | |
| 1905 | BackendDAE.INNEREQUATION(eqn=e,vars={v}); | ||
| 1906 | |||
| 1907 | case clst | ||
| 1908 | algorithm | ||
| 1909 | 2 | elst := List.map1r(clst,arrayGet,mapIncRowEqn); | |
| 1910 | 2 | elst := List.fold2(elst,uniqueIntLst,mark,columark,{}); | |
| 1911 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | {e} := elst; |
| 1912 | 2 | e := eindxarr[e]; | |
| 1913 | 2 | vlst := List.map1r(clst,arrayGet,ass2); | |
| 1914 | 2 | vlst := List.map1r(vlst,arrayGet,varindxarr); | |
| 1915 | 2 | then | |
| 1916 | BackendDAE.INNEREQUATION(eqn=e,vars=vlst); | ||
| 1917 | end match | ||
| 1918 | for x in othercomps); | ||
| 1919 | end omcTearing4_1; | ||
| 1920 | |||
| 1921 | |||
| 1922 | // ============================================================================ | ||
| 1923 | // Section for minimal tearing | ||
| 1924 | // Tear only the minimal amount of variables from strong components which are | ||
| 1925 | // all discrete variables and CSE variables. | ||
| 1926 | // ============================================================================ | ||
| 1927 | protected function minimalTearing | ||
| 1928 | "Tears discrete variables from Loops. | ||
| 1929 | Returns torn system with discrete variables as tearing variables." | ||
| 1930 | input BackendDAE.EqSystem isyst; | ||
| 1931 | input BackendDAE.Shared ishared; | ||
| 1932 | input list<Integer> eindex; | ||
| 1933 | input list<Integer> vindx; | ||
| 1934 | input BackendDAE.JacobianType jacType; | ||
| 1935 | input Boolean mixedSystem; | ||
| 1936 | output BackendDAE.StrongComponent ocomp; | ||
| 1937 | protected | ||
| 1938 | Integer size, qidx, vidx; | ||
| 1939 | array<Integer> nE, nV; | ||
| 1940 | array<Boolean> varArray, eqArray; | ||
| 1941 | list<Integer> unsolvedDiscreteVars, unsolvedCSEVars, unsolvedCombined, algSolvedVars; | ||
| 1942 | list<Integer> iterationVars = {}, residualequations = {}; | ||
| 1943 | list<BackendDAE.Var> var_lst; | ||
| 1944 | list<BackendDAE.Equation> eqn_lst; | ||
| 1945 | BackendDAE.InnerEquations innerEquationsLocalIndex = {}, innerEquations; | ||
| 1946 | BackendDAE.AdjacencyMatrixEnhanced adjEnh, adjEnhT; | ||
| 1947 | Boolean linear; | ||
| 1948 | BackendDAE.EquationArray eqns; | ||
| 1949 | BackendDAE.EqSystem subsyst; | ||
| 1950 | BackendDAE.Variables vars; | ||
| 1951 | algorithm | ||
| 1952 | 34 | linear := BackendDAEUtil.getLinearfromJacType(jacType); | |
| 1953 | |||
| 1954 | try | ||
| 1955 | |||
| 1956 | // Create a local subsystem to simplify processing. This is not neccessary per-se but is helpful. | ||
| 1957 | // A little bit of cost is something we can live with for getting a clear view of the system. | ||
| 1958 | 34 | eqn_lst := BackendEquation.getList(eindex,BackendEquation.getEqnsFromEqSystem(isyst)); | |
| 1959 | 34 | eqns := BackendEquation.listEquation(eqn_lst); | |
| 1960 | 34 | var_lst := List.map1r(vindx, BackendVariable.getVarAt, BackendVariable.daeVars(isyst)); | |
| 1961 | 34 | vars := BackendVariable.listVar1(var_lst); | |
| 1962 | 34 | subsyst := BackendDAEUtil.createEqSystem(vars, eqns); | |
| 1963 | |||
| 1964 | 34 | (adjEnh,adjEnhT) := BackendDAEUtil.getAdjacencyMatrixEnhanced(subsyst, ishared, BackendDAEUtil.isInitializationDAE(ishared)); | |
| 1965 | |||
| 1966 | // print("Minimal Tearing subsystem: \n"); | ||
| 1967 | // BackendDump.printEqSystem(subsyst); | ||
| 1968 | |||
| 1969 | 34 | size := listLength(vindx); | |
| 1970 | 34 | varArray := arrayCreate(size,true); | |
| 1971 | 34 | eqArray := arrayCreate(size,true); | |
| 1972 | 34 | nE := arrayCreate(size,-1); | |
| 1973 | 34 | nV := arrayCreate(size,-1); | |
| 1974 | |||
| 1975 | // find discrete vars. Warn on tearing select always and prefer on discrete vars. | ||
| 1976 | 34 | unsolvedDiscreteVars := findDiscreteWarnTearingSelect(var_lst); | |
| 1977 | // print("All discrete Vars: " + stringDelimitList(List.map(unsolvedDiscreteVars,intString),",") + "\n"); | ||
| 1978 | |||
| 1979 | // also find $cse vars and try to make them inner vars since they have implicit '__OpenModelica_tearingSelect = TearingSelect.never' | ||
| 1980 | 34 | unsolvedCSEVars := findCSE(var_lst); | |
| 1981 | // print("All CSE Vars: " + stringDelimitList(List.map(unsolvedCSEVars,intString),",") + "\n"); | ||
| 1982 | |||
| 1983 | 34 | unsolvedCombined := listReverse(List.uniqueIntN(listAppend(unsolvedDiscreteVars, unsolvedCSEVars),listLength(var_lst))); | |
| 1984 | // print("All discrete+CSE Vars: " + stringDelimitList(List.map(unsolvedCombined,intString),",") + "\n"); | ||
| 1985 | |||
| 1986 | // Look for algorithm equations. If there is an algorithm equation | ||
| 1987 | // remove all discrete variables solved in it. The algorithm is added as | ||
| 1988 | // inner equation. | ||
| 1989 | qidx := 1; | ||
| 1990 |
2/2✓ Branch 0 taken 2226 times.
✓ Branch 1 taken 34 times.
|
2260 | for eqn in eqn_lst loop |
| 1991 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2226 times.
|
2226 | if BackendEquation.isAlgorithm(eqn) then |
| 1992 | // mark the alg eqn to be ignored for later | ||
| 1993 | // matching. | ||
| 1994 | ✗ | eqArray[qidx] := false; | |
| 1995 | |||
| 1996 | algSolvedVars := {}; | ||
| 1997 | ✗ | for entr in adjEnh[qidx] loop | |
| 1998 | // var is solved in this algorithm. | ||
| 1999 | ✗ | if isEntrySolved(entr) then | |
| 2000 | ✗ | (vidx,_,_) := entr; | |
| 2001 | algSolvedVars := vidx::algSolvedVars; | ||
| 2002 | ✗ | unsolvedCombined := List.deleteMemberOnTrue(vidx, unsolvedCombined, intEq); | |
| 2003 | |||
| 2004 | // mark the var to be ignored for later | ||
| 2005 | // matching. | ||
| 2006 | ✗ | varArray[vidx] := false; | |
| 2007 | end if; | ||
| 2008 | end for; | ||
| 2009 | |||
| 2010 | // create an inner equation for the algorithm. | ||
| 2011 | ✗ | innerEquationsLocalIndex := BackendDAE.INNEREQUATION(qidx, algSolvedVars)::innerEquationsLocalIndex; | |
| 2012 | end if; | ||
| 2013 | 2226 | qidx := qidx + 1; | |
| 2014 | end for; | ||
| 2015 | // print("Non-algorithm-output Vars: " + stringDelimitList(List.map(unsolvedCombined,intString),",") + "\n"); | ||
| 2016 | |||
| 2017 | // Match the remaining discrete variables | ||
| 2018 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 29 times.
|
34 | if not listEmpty(unsolvedCombined) then |
| 2019 | 5 | matchDiscreteVars(unsolvedCombined, adjEnhT, varArray, eqArray, nE, nV); | |
| 2020 | // make inner equations for the matched non-algorithm-output discrete vars. | ||
| 2021 | 5 | (varArray, eqArray, innerEquations) := getTearingSetfromAssign(unsolvedCombined, nE, varArray, eqArray); | |
| 2022 | |||
| 2023 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 2 taken 5 times.
|
11 | for iq in innerEquations loop |
| 2024 | innerEquationsLocalIndex := iq::innerEquationsLocalIndex; | ||
| 2025 | end for; | ||
| 2026 | |||
| 2027 | end if; | ||
| 2028 | |||
| 2029 | // Mark all other equations as residual and all other vars | ||
| 2030 | // as tearing vars. | ||
| 2031 | // This can be improved a bit to be clearer. | ||
| 2032 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
2260 | for i in 1:listLength(eindex) loop |
| 2033 |
2/2✓ Branch 1 taken 2220 times.
✓ Branch 2 taken 6 times.
|
2226 | if eqArray[i] then |
| 2034 | residualequations := i::residualequations; | ||
| 2035 | end if; | ||
| 2036 | |||
| 2037 | // This ordering of iteration vars based on the ordering | ||
| 2038 | // in the normal adjacency matrix seems to cause differences | ||
| 2039 | // in sumulation time. | ||
| 2040 | // What is odd is that the order in adj matrix is not really guided | ||
| 2041 | // by anything. Somehow this seems to be faster for some models. | ||
| 2042 | // However, we now use the enahnced matrix which can sometimes have | ||
| 2043 | // the var entries for an equation slightly different order than the normal | ||
| 2044 | // adj matix. | ||
| 2045 | // Simulation should not be affected by what order we have here but it is. | ||
| 2046 | // There is something in later phases that operates according to this order | ||
| 2047 | // But it should not. This is just random order. | ||
| 2048 | /* | ||
| 2049 | for elem in aMatrix[i] loop | ||
| 2050 | if elem > 0 then | ||
| 2051 | if varArray[elem] then | ||
| 2052 | arrayUpdate(varArray,elem,false); | ||
| 2053 | iterationVars := elem::iterationVars; | ||
| 2054 | end if; | ||
| 2055 | end if; | ||
| 2056 | end for; | ||
| 2057 | */ | ||
| 2058 | |||
| 2059 | // This performs a bit worse but still better than below. | ||
| 2060 | /* | ||
| 2061 | for entry in adjEnh[i] loop | ||
| 2062 | (vidx,_,_) := entry; | ||
| 2063 | if vidx > 0 then | ||
| 2064 | if varArray[vidx] then | ||
| 2065 | varArray[vidx] := false; | ||
| 2066 | iterationVars := vidx::iterationVars; | ||
| 2067 | end if; | ||
| 2068 | end if; | ||
| 2069 | end for; | ||
| 2070 | */ | ||
| 2071 | |||
| 2072 | end for; | ||
| 2073 | |||
| 2074 | // Mark all other vars as iteration vars. | ||
| 2075 | // This should be all we need here. The ordering issue needs to be investigated later. | ||
| 2076 |
1/2✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
|
2260 | for i in 1:listLength(vindx) loop |
| 2077 |
2/2✓ Branch 1 taken 2220 times.
✓ Branch 2 taken 6 times.
|
2226 | if varArray[i] then |
| 2078 | iterationVars := i::iterationVars; | ||
| 2079 | end if; | ||
| 2080 | end for; | ||
| 2081 | |||
| 2082 | // dumpTearingSetGlobalIndexes(BackendDAE.TEARINGSET(iterationVars, residualequations, listReverse(innerEquationsLocalIndex), BackendDAE.EMPTY_JACOBIAN()),size," - STRICT SET"); | ||
| 2083 | |||
| 2084 | // Start converting local indeces of variables and equations to their global | ||
| 2085 | // counterparts (We used a smaller local subsystem for processing the system above.) | ||
| 2086 |
4/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 34 times.
|
40 | innerEquations := list( |
| 2087 | match ieqn | ||
| 2088 | case BackendDAE.INNEREQUATION() algorithm | ||
| 2089 | 6 | ieqn.vars := selectFromList_rev(vindx, ieqn.vars); | |
| 2090 | 6 | ieqn.eqn := listGet(eindex,ieqn.eqn); | |
| 2091 | then ieqn; | ||
| 2092 | else fail(); | ||
| 2093 | end match for ieqn in innerEquationsLocalIndex); | ||
| 2094 | |||
| 2095 | 34 | iterationVars := selectFromList_rev(vindx, iterationVars); | |
| 2096 | 34 | residualequations := selectFromList_rev(eindex, residualequations); | |
| 2097 | |||
| 2098 | // dumpTearingSetGlobalIndexes(BackendDAE.TEARINGSET(iterationVars, residualequations, listReverse(innerEquations), BackendDAE.EMPTY_JACOBIAN()),size," - STRICT SET"); | ||
| 2099 | |||
| 2100 | // Return torn system | ||
| 2101 |
3/4✓ Branch 4 taken 34 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 20 times.
✓ Branch 7 taken 14 times.
|
88 | ocomp := BackendDAE.TORNSYSTEM(BackendDAE.TEARINGSET(listReverse(iterationVars), listReverse(residualequations), listReverse(innerEquations), BackendDAE.EMPTY_JACOBIAN()), NONE(), linear, mixedSystem); |
| 2102 | else | ||
| 2103 | ✗ | Error.addInternalError("function minimalTearing failed", sourceInfo()); | |
| 2104 | ✗ | fail(); | |
| 2105 | end try; | ||
| 2106 | end minimalTearing; | ||
| 2107 | |||
| 2108 | |||
| 2109 | protected function matchDiscreteVars | ||
| 2110 | "Matches all discrete vars given by inDiscreteVars." | ||
| 2111 | input list<Integer> inDiscreteVars; | ||
| 2112 | input BackendDAE.AdjacencyMatrixEnhanced adjEnhT; | ||
| 2113 | input array<Boolean> varArray; | ||
| 2114 | input array<Boolean> eqArray; | ||
| 2115 | input output array<Integer> nE "Equations"; | ||
| 2116 | input output array<Integer> nV "Variables"; | ||
| 2117 | protected | ||
| 2118 | array<Boolean> eqMarker; | ||
| 2119 | algorithm | ||
| 2120 | try | ||
| 2121 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 5 times.
|
11 | for varIdx in inDiscreteVars loop |
| 2122 | 6 | eqMarker := arrayCopy(eqArray); | |
| 2123 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
|
6 | (eqMarker, nE, nV, true) := pathFound(varIdx, adjEnhT, varArray, eqArray, eqMarker, nE, nV); |
| 2124 | end for; | ||
| 2125 | else | ||
| 2126 | ✗ | Error.addInternalError("function matchDiscreteVars failed", sourceInfo()); | |
| 2127 | ✗ | fail(); | |
| 2128 | end try; | ||
| 2129 | end matchDiscreteVars; | ||
| 2130 | |||
| 2131 | protected function pathFound | ||
| 2132 | "Tries to find a path in the bipartit graph with respect to solvability for | ||
| 2133 | matching of discrete variables." | ||
| 2134 | input Integer varIdx; | ||
| 2135 | input BackendDAE.AdjacencyMatrixEnhanced adjEnhT; | ||
| 2136 | input array<Boolean> varArray; | ||
| 2137 | input array<Boolean> eqArray; | ||
| 2138 | input output array<Boolean> eqMarker; | ||
| 2139 | input output array<Integer> nE "Equations"; | ||
| 2140 | input output array<Integer> nV "Variables"; | ||
| 2141 | output Boolean success = false; | ||
| 2142 | protected | ||
| 2143 | Integer eqIdx; | ||
| 2144 | algorithm | ||
| 2145 | try | ||
| 2146 | // Try to find a path in given equation from adjacency matrix | ||
| 2147 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | for entry in adjEnhT[varIdx] loop |
| 2148 | 10 | (eqIdx,_,_) := entry; | |
| 2149 |
3/4✓ Branch 1 taken 6 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 6 times.
✗ Branch 4 not taken.
|
10 | if isEntrySolvable(entry) and eqIdx > 0 then |
| 2150 | |||
| 2151 |
2/4✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
|
6 | if eqArray[eqIdx] and nV[eqIdx] == -1 then |
| 2152 | // Path found | ||
| 2153 | 6 | nV[eqIdx] := varIdx; | |
| 2154 | 6 | nE[varIdx] := eqIdx; | |
| 2155 | 6 | success := true; | |
| 2156 | 6 | return; | |
| 2157 | end if; | ||
| 2158 | |||
| 2159 | end if; | ||
| 2160 | end for; | ||
| 2161 | |||
| 2162 | // If no path was found mark equation as false and call pathFound | ||
| 2163 | ✗ | for entry in adjEnhT[varIdx] loop | |
| 2164 | ✗ | (eqIdx,_,_) := entry; | |
| 2165 | |||
| 2166 | ✗ | if isEntrySolvable(entry) and eqIdx > 0 then | |
| 2167 | ✗ | if eqMarker[eqIdx] then | |
| 2168 | ✗ | eqMarker[eqIdx] := false; | |
| 2169 | ✗ | (eqMarker, nE, nV , success) := pathFound(nV[eqIdx], adjEnhT, varArray, eqArray, eqMarker, nE, nV); | |
| 2170 | end if; | ||
| 2171 | end if; | ||
| 2172 | ✗ | if success then | |
| 2173 | ✗ | nV[eqIdx] := varIdx; | |
| 2174 | ✗ | nE[varIdx] := eqIdx; | |
| 2175 | ✗ | return; | |
| 2176 | end if; | ||
| 2177 | end for; | ||
| 2178 | |||
| 2179 | else | ||
| 2180 | ✗ | Error.addInternalError("function pathFound failed", sourceInfo()); | |
| 2181 | ✗ | fail(); | |
| 2182 | end try; | ||
| 2183 | end pathFound; | ||
| 2184 | |||
| 2185 | |||
| 2186 | protected function getTearingSetfromAssign | ||
| 2187 | "Set equations matched with the discrete vars as inner equations" | ||
| 2188 | input list<Integer> inDiscreteVars; | ||
| 2189 | input array<Integer> assign1; | ||
| 2190 | input output array<Boolean> varArray; | ||
| 2191 | input output array<Boolean> equationArray; | ||
| 2192 | output BackendDAE.InnerEquations innerEquations = {}; | ||
| 2193 | protected | ||
| 2194 | Integer eqIdx; | ||
| 2195 | algorithm | ||
| 2196 | try | ||
| 2197 | // Add matched discrete equation to inner equations | ||
| 2198 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 5 times.
|
11 | for varIdx in inDiscreteVars loop |
| 2199 | 6 | arrayUpdate(varArray,varIdx,false); | |
| 2200 | 6 | eqIdx := assign1[varIdx]; | |
| 2201 | 6 | arrayUpdate(equationArray,eqIdx,false); | |
| 2202 | 6 | innerEquations := BackendDAE.INNEREQUATION(eqIdx, {varIdx})::innerEquations; | |
| 2203 | end for; | ||
| 2204 | |||
| 2205 | else | ||
| 2206 | ✗ | Error.addInternalError("function getTearingSetfromAssign failed", sourceInfo()); | |
| 2207 | ✗ | fail(); | |
| 2208 | end try; | ||
| 2209 | end getTearingSetfromAssign; | ||
| 2210 | |||
| 2211 | |||
| 2212 | // ============================================================================= | ||
| 2213 | // | ||
| 2214 | // Tearing from Book of Cellier | ||
| 2215 | // | ||
| 2216 | // ============================================================================= | ||
| 2217 | |||
| 2218 | protected function CellierTearing " tearing method based on the method from book of Cellier | ||
| 2219 | author: ptaeuber FHB 2013-2016" | ||
| 2220 | input BackendDAE.EqSystem isyst; | ||
| 2221 | input BackendDAE.Shared ishared; | ||
| 2222 | input list<Integer> eindex; | ||
| 2223 | input list<Integer> vindx; | ||
| 2224 | input list<Integer> tearingSelect_always; | ||
| 2225 | input Option<list<tuple<Integer, Integer, BackendDAE.Equation>>> ojac; | ||
| 2226 | input BackendDAE.JacobianType jacType; | ||
| 2227 | input Boolean mixedSystem; | ||
| 2228 | input Integer strongComponentIndex; | ||
| 2229 | output BackendDAE.StrongComponent ocomp; | ||
| 2230 | output Boolean outRunMatching; | ||
| 2231 | protected | ||
| 2232 | Integer size, tornsize; | ||
| 2233 | array<Integer> ass1, ass2, mapIncRowEqn, eqnNonlinPoints; | ||
| 2234 | array<list<Integer>> mapEqnIncRow; | ||
| 2235 | list<Integer> OutTVars, residual, residual_coll, order, unsolvables, discreteVars, tSel_always, tSel_alwaysByUser, tSel_prefer, tSel_avoid, tSel_never; | ||
| 2236 | BackendDAE.InnerEquations innerEquations; | ||
| 2237 | BackendDAE.EqSystem subsyst; | ||
| 2238 | BackendDAE.Variables vars; | ||
| 2239 | BackendDAE.EquationArray eqns; | ||
| 2240 | BackendDAE.AdjacencyMatrix m; | ||
| 2241 | BackendDAE.AdjacencyMatrix mt; | ||
| 2242 | BackendDAE.AdjacencyMatrixEnhanced me; | ||
| 2243 | BackendDAE.AdjacencyMatrixTEnhanced meT; | ||
| 2244 | BackendDAE.BackendDAEType DAEtype; | ||
| 2245 | String DAEtypeStr; | ||
| 2246 | BackendDAE.TearingSet strictTearingSet; | ||
| 2247 | BackendDAE.StateSets stateSets; | ||
| 2248 | Option<BackendDAE.TearingSet> casualTearingSet; | ||
| 2249 | list<BackendDAE.Equation> eqn_lst; | ||
| 2250 | list<BackendDAE.Var> var_lst; | ||
| 2251 | Boolean linear,b,noDynamicStateSelection,dynamicTearing,dtTarget,forceDegree1,hasStartCycle; | ||
| 2252 | DAE.ComponentRef cref; | ||
| 2253 | list<DAE.ComponentRef> startBaseCrefs, valueCrefs, cyclicBaseCrefs; | ||
| 2254 | BackendDAE.AdjacencyMatrixTEnhanced meTFull; | ||
| 2255 | String s,modelName; | ||
| 2256 | constant Boolean debug = false; | ||
| 2257 | algorithm | ||
| 2258 | 1956 | linear := BackendDAEUtil.getLinearfromJacType(jacType); | |
| 2259 | 1956 | BackendDAE.EQSYSTEM(stateSets = stateSets) := isyst; | |
| 2260 | 1956 | noDynamicStateSelection := listEmpty(stateSets); | |
| 2261 | 1956 | BackendDAE.SHARED(backendDAEType=DAEtype, info=BackendDAE.EXTRA_INFO(fileNamePrefix=modelName)) := ishared; | |
| 2262 | 1956 | DAEtypeStr := BackendDump.printBackendDAEType2String(DAEtype); | |
| 2263 | |||
| 2264 | // ticket #15433: the variable-driven degree-1 forced assignment (getNextDegree1Var) is only | ||
| 2265 | // needed - and only safe - for the initialization system, where a $START.x variable is | ||
| 2266 | // structurally linked to the state's equations but solvable in exactly one of them. Enabling it | ||
| 2267 | // for the simulation system reorders the Tarjan causalization for components that already | ||
| 2268 | // causalize correctly, changing tearing results. Restrict it to the initialization DAE; the | ||
| 2269 | // forcing is then further restricted, below, to the components that actually exhibit the defect | ||
| 2270 | // (a $START.x->x cycle). | ||
| 2271 | 1956 | forceDegree1 := BackendDAEUtil.isInitializationDAE(ishared); | |
| 2272 | |||
| 2273 | // check if dynamic tearing is enabled for linear/nonlinear system. | ||
| 2274 | // Only the targets whose runtime can switch tearing sets ("wasm" is the same | ||
| 2275 | // code generator as "wasm-jit", emitting a standalone module). | ||
| 2276 | 1956 | dtTarget := listMember(Config.simCodeTarget(), {"C", "wasm-jit", "wasm"}); | |
| 2277 | dynamicTearing := match (Config.dynamicTearing(),linear,noDynamicStateSelection,DAEtypeStr,Flags.getConfigBool(Flags.DYNAMIC_TEARING_FOR_INITIALIZATION),dtTarget) | ||
| 2278 | case ("true",_,true,"simulation",_,true) then true; | ||
| 2279 | case ("true",_,true,"initialization",true,true) then true; | ||
| 2280 | case ("linear",true,true,"simulation",_,true) then true; | ||
| 2281 | case ("linear",true,true,"initialization",true,true) then true; | ||
| 2282 | case ("nonlinear",false,true,"simulation",_,true) then true; | ||
| 2283 | case ("nonlinear",false,true,"initialization",true,true) then true; | ||
| 2284 | else false; | ||
| 2285 | end match; | ||
| 2286 | |||
| 2287 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1956 times.
|
1956 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2288 | ✗ | print("\n" + BORDER + "\nBEGINNING of CellierTearing\n\n"); | |
| 2289 | end if; | ||
| 2290 | |||
| 2291 | // Generate Subsystem to get the adjacency matrix | ||
| 2292 | 1956 | size := listLength(vindx); | |
| 2293 | 1956 | eqn_lst := BackendEquation.getList(eindex,BackendEquation.getEqnsFromEqSystem(isyst)); | |
| 2294 | 1956 | eqns := BackendEquation.listEquation(eqn_lst); | |
| 2295 | 1956 | var_lst := List.map1r(vindx, BackendVariable.getVarAt, BackendVariable.daeVars(isyst)); | |
| 2296 | 1956 | vars := BackendVariable.listVar1(var_lst); | |
| 2297 | 1956 | subsyst := BackendDAEUtil.createEqSystem(vars, eqns); | |
| 2298 | 1956 | (subsyst,m,mt,_,_) := BackendDAEUtil.getAdjacencyMatrixScalar(subsyst, BackendDAE.NORMAL(),NONE(), BackendDAEUtil.isInitializationDAE(ishared)); | |
| 2299 | if debug then execStat("Tearing.CellierTearing -> 1"); end if; | ||
| 2300 | |||
| 2301 | // Delete negative entries from adjacency matrix | ||
| 2302 | 1956 | m := Array.map(m,deleteNegativeEntries); | |
| 2303 | 1956 | mt := Array.map(mt,deleteNegativeEntries); | |
| 2304 | |||
| 2305 |
3/4✓ Branch 1 taken 1954 times.
✓ Branch 2 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1954 times.
|
1956 | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2306 | 2 | print("\n\n###BEGIN print Strong Component#####################\n(Function:CellierTearing)\n"); | |
| 2307 | 2 | BackendDump.printEqSystem(subsyst); | |
| 2308 | 2 | print("\n###END print Strong Component#######################\n(Function:CellierTearing)\n\n\n"); | |
| 2309 | end if; | ||
| 2310 | |||
| 2311 | |||
| 2312 | // Determine strict tearing set | ||
| 2313 | // ****************************************** | ||
| 2314 | |||
| 2315 |
3/4✓ Branch 1 taken 1954 times.
✓ Branch 2 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1954 times.
|
1956 | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2316 | 2 | print("\n\nDetermine STRICT TEARING SET\n" + BORDER + BORDER + "\n\n"); | |
| 2317 | end if; | ||
| 2318 | |||
| 2319 | // Get advanced adjacency matrix (determine how the variables occur in the equations) | ||
| 2320 | 1956 | (me,meT,mapEqnIncRow,mapIncRowEqn) := BackendDAEUtil.getAdjacencyMatrixEnhancedScalar(subsyst,ishared,false); | |
| 2321 | if debug then execStat("Tearing.CellierTearing -> 1.5"); end if; | ||
| 2322 | |||
| 2323 | // Determine unsolvable vars to consider solvability | ||
| 2324 | 1956 | unsolvables := getUnsolvableVars(size,meT); | |
| 2325 | |||
| 2326 | // ticket #15433: detect the degenerate "$START.x depends on x" cycle inside this strong | ||
| 2327 | // component and only then keep the degree-1 forced assignment enabled. The component is cyclic | ||
| 2328 | // when it contains BOTH a $START.x variable and its base value variable x: since a strong | ||
| 2329 | // component is an algebraic loop, the two are mutually reachable, i.e. x's start attribute | ||
| 2330 | // transitively depends on x itself (e.g. a fixed=false state whose start binds to a parameter | ||
| 2331 | // computed from the state - the cable models in #15433). Exactly this cycle produces the matching | ||
| 2332 | // defect that orphans $START.x and yields a structurally singular torn init system; the degree-1 | ||
| 2333 | // forcing repairs it. For every OTHER component (no such cycle) the forcing is switched OFF so the | ||
| 2334 | // plain Cellier result - which is already correct there - is preserved (this is what keeps models | ||
| 2335 | // like Tearing16/Algorithm2 unchanged). A modeler warning is emitted, naming the self-dependent | ||
| 2336 | // variable (with subscripts), because a start value that depends on its own variable is an | ||
| 2337 | // ill-posed initialization; the transformational debugger can be used to inspect the full chain. | ||
| 2338 | hasStartCycle := false; | ||
| 2339 | cyclicBaseCrefs := {}; | ||
| 2340 |
2/2✓ Branch 0 taken 930 times.
✓ Branch 1 taken 1026 times.
|
1956 | if forceDegree1 then |
| 2341 | startBaseCrefs := {}; | ||
| 2342 | valueCrefs := {}; | ||
| 2343 |
1/2✓ Branch 0 taken 930 times.
✗ Branch 1 not taken.
|
24958 | for i in 1:size loop |
| 2344 | 24028 | cref := BackendVariable.varCref(BackendVariable.getVarAt(vars, i)); | |
| 2345 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 24028 times.
|
24028 | if ComponentReference.isStartCref(cref) then |
| 2346 | ✗ | startBaseCrefs := ComponentReference.popCref(cref) :: startBaseCrefs; | |
| 2347 | else | ||
| 2348 | valueCrefs := cref :: valueCrefs; | ||
| 2349 | end if; | ||
| 2350 | end for; | ||
| 2351 | // a $START.x whose base value variable x is also in this component closes the cycle | ||
| 2352 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 930 times.
|
930 | for baseCref in startBaseCrefs loop |
| 2353 | ✗ | if List.isMemberOnTrue(baseCref, valueCrefs, ComponentReferenceBasics.crefEqual) then | |
| 2354 | hasStartCycle := true; | ||
| 2355 | cyclicBaseCrefs := baseCref :: cyclicBaseCrefs; | ||
| 2356 | end if; | ||
| 2357 | end for; | ||
| 2358 | end if; | ||
| 2359 | // ticket #15433: a $START.x->x cycle is always an ill-posed start value (MLS 4.9.6 - the start | ||
| 2360 | // attribute of x cannot be computed from x). Always warn, regardless of whether the degree-1 | ||
| 2361 | // forcing below is needed to keep initialization solvable, and let the modeler decide whether the | ||
| 2362 | // dependency is intended: even when initialization still succeeds, the start value (a guess) is | ||
| 2363 | // never actually used to initialize the variable. | ||
| 2364 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1956 times.
|
1956 | for baseCref in cyclicBaseCrefs loop |
| 2365 | ✗ | Error.addCompilerWarning("Initialization start-value cycle: the start attribute of '" + | |
| 2366 | ComponentReferenceBasics.printComponentRefStr(baseCref) + | ||
| 2367 | "' depends, directly or transitively, on the variable itself. The start attribute defines the " + | ||
| 2368 | "initial value of '" + ComponentReferenceBasics.printComponentRefStr(baseCref) + "' and therefore " + | ||
| 2369 | "cannot be computed from it, so this start value cannot be used to initialize the variable (see " + | ||
| 2370 | "Modelica Specification section 4.9.6). This is possibly a modeling error; if unintended, give '" + | ||
| 2371 | ComponentReferenceBasics.printComponentRefStr(baseCref) + "' a start value that does not depend on " + | ||
| 2372 | "itself. Use the transformational debugger to inspect the dependency chain."); | ||
| 2373 | end for; | ||
| 2374 | // ticket #15433: a $START.x->x cycle is NECESSARY but NOT SUFFICIENT to need the degree-1 | ||
| 2375 | // forcing. Such a cycle is always an ill-posed start value (the start attribute of x cannot be | ||
| 2376 | // computed from x), but many initialization components with one (e.g. the lag/limiter blocks in | ||
| 2377 | // the OpenIPSL PSSE controllers) still tear and initialize correctly, because $START.x keeps its | ||
| 2378 | // own defining equation; forcing them only reorders a healthy system and breaks it. So we do NOT | ||
| 2379 | // decide here. We first run the plain Cellier pass below and only re-run it with forcing if that | ||
| 2380 | // plain pass actually orphans a $START.x variable, leaving a structurally singular torn set - the | ||
| 2381 | // cable defect. 'forceDegree1' stays the init-DAE eligibility flag, passed as 'false' to pass one. | ||
| 2382 | |||
| 2383 | // Determine a weight for the nonlinearity of each equation | ||
| 2384 | 1956 | eqnNonlinPoints := arrayCreate(size, -1); | |
| 2385 | 1956 | getEquationNonlinearityPoints(eqnNonlinPoints, me, size); | |
| 2386 | if debug then execStat("Tearing.CellierTearing -> 2"); end if; | ||
| 2387 | |||
| 2388 |
3/4✓ Branch 1 taken 1954 times.
✓ Branch 2 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1954 times.
|
1956 | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2389 | 2 | print("\nAdjacencyMatrixEnhanced:\n"); | |
| 2390 | 2 | BackendDump.dumpAdjacencyMatrixEnhanced(me); | |
| 2391 | 2 | print("\nAdjacencyMatrixTransposedEnhanced:\n"); | |
| 2392 | 2 | BackendDump.dumpAdjacencyMatrixTEnhanced(meT); | |
| 2393 | 2 | print("\neqLinPoints:\n" + stringDelimitList(List.mapArray(eqnNonlinPoints, intString),",") + "\n\n"); | |
| 2394 | end if; | ||
| 2395 | |||
| 2396 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1956 times.
|
1956 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2397 | ✗ | print("mapEqnIncRow:"); //+ stringDelimitList(List.map(List.flatten(arrayList(mapEqnIncRow)),intString),",") + "\n\n"); | |
| 2398 | ✗ | BackendDump.dumpAdjacencyMatrix(mapEqnIncRow); | |
| 2399 | ✗ | print("\nmapIncRowEqn:\n" + stringDelimitList(List.mapArray(mapIncRowEqn, intString),",") + "\n\n"); | |
| 2400 | ✗ | print("\n\nUNSOLVABLES:\n" + stringDelimitList(List.map(unsolvables,intString),",") + "\n\n"); | |
| 2401 | end if; | ||
| 2402 | |||
| 2403 | // Determine discrete vars | ||
| 2404 | 1956 | discreteVars := findDiscrete(var_lst); | |
| 2405 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1956 times.
|
1956 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2406 | ✗ | print("\nDiscrete Vars:\n" + stringDelimitList(List.map(discreteVars,intString),",") + "\n\n"); | |
| 2407 | end if; | ||
| 2408 | |||
| 2409 | // Collect variables with annotation attribute '__OpenModelica_tearingSelect in [always, prefer, avoid, never]' | ||
| 2410 | 1956 | (tSel_always, tSel_prefer, tSel_avoid, tSel_never, tSel_alwaysByUser) := tearingSelect(var_lst, tearingSelect_always, DAEtypeStr); | |
| 2411 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1953 times.
|
1956 | if not listEmpty(tSel_alwaysByUser) then |
| 2412 | 12 | Error.addMessage(Error.USER_TEARING_VARS, {intString(strongComponentIndex), BackendDump.printBackendDAEType2String(DAEtype), BackendDump.dumpMarkedVarList(var_lst, tSel_alwaysByUser)}); | |
| 2413 | end if; | ||
| 2414 | if debug then execStat("Tearing.CellierTearing -> 3"); end if; | ||
| 2415 | |||
| 2416 | // Initialize matching | ||
| 2417 | 1956 | ass1 := arrayCreate(size,-1); | |
| 2418 | 1956 | ass2 := arrayCreate(size,-1); | |
| 2419 | 1956 | order := {}; | |
| 2420 | if debug then execStat("Tearing.CellierTearing -> 3.1"); end if; | ||
| 2421 | |||
| 2422 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1956 times.
|
1956 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2423 | ✗ | print("\n" + BORDER + "\nBEGINNING of CellierTearing2\n\n"); | |
| 2424 | end if; | ||
| 2425 | // ticket #15433: keep an unmutated copy of the enhanced transposed adjacency (variable -> | ||
| 2426 | // (equation, solvability)); CellierTearing2 consumes the adjacency matrices while matching, but | ||
| 2427 | // the structural-singularity test below needs the original incidence/solvability of every | ||
| 2428 | // variable. Only the initialization DAE can take the forcing path, so for the simulation DAE skip | ||
| 2429 | // the copy entirely (meTFull is then never read). | ||
| 2430 |
2/2✓ Branch 0 taken 930 times.
✓ Branch 1 taken 1026 times.
|
1956 | meTFull := if forceDegree1 then arrayCopy(meT) else meT; |
| 2431 | // First pass: plain Cellier tearing, never forced. | ||
| 2432 | 1956 | (OutTVars, order) := CellierTearing2(false,m,mt,me,meT,ass1,ass2,unsolvables,{},discreteVars,tSel_always,tSel_prefer,tSel_avoid,tSel_never,order,mapEqnIncRow,mapIncRowEqn,eqnNonlinPoints,false); | |
| 2433 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1954 times.
|
1954 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2434 | ✗ | print("\nEND of CellierTearing2\n" + BORDER + "\n\n"); | |
| 2435 | end if; | ||
| 2436 | |||
| 2437 | // ticket #15433: only the cable's defect needs the degree-1 forcing. The equation-driven Cellier | ||
| 2438 | // pass matches on plain structural incidence, so a variable that is structurally incident to | ||
| 2439 | // several equations but solvable in only one (the cable's $START.x, solvable only in its defining | ||
| 2440 | // equation $START.x = sp) can be matched to an equation where it cannot be solved - a structurally | ||
| 2441 | // singular assignment that makes initialization fail. If this initialization component has a | ||
| 2442 | // $START.x->x cycle AND the plain matching contains such an unsolvable assignment, redo the | ||
| 2443 | // tearing with the variable-driven degree-1 forcing, which matches $START.x to its defining | ||
| 2444 | // equation and removes the singularity. A component whose plain matching is fully solvable - i.e. | ||
| 2445 | // one that already initializes correctly, like the OpenIPSL PSSE controllers - is left untouched. | ||
| 2446 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1954 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
1954 | if forceDegree1 and hasStartCycle and tornMatchingIsStructurallySingular(ass2, meTFull, size, vars) then |
| 2447 | // CellierTearing2 consumed the adjacency matrices, so rebuild them before the forced re-run. | ||
| 2448 | ✗ | subsyst := BackendDAEUtil.createEqSystem(vars, eqns); | |
| 2449 | ✗ | (subsyst,m,mt,_,_) := BackendDAEUtil.getAdjacencyMatrixScalar(subsyst, BackendDAE.NORMAL(),NONE(), BackendDAEUtil.isInitializationDAE(ishared)); | |
| 2450 | ✗ | m := Array.map(m,deleteNegativeEntries); | |
| 2451 | ✗ | mt := Array.map(mt,deleteNegativeEntries); | |
| 2452 | ✗ | (me,meT,mapEqnIncRow,mapIncRowEqn) := BackendDAEUtil.getAdjacencyMatrixEnhancedScalar(subsyst,ishared,false); | |
| 2453 | ✗ | unsolvables := getUnsolvableVars(size,meT); | |
| 2454 | ✗ | eqnNonlinPoints := arrayCreate(size, -1); | |
| 2455 | ✗ | getEquationNonlinearityPoints(eqnNonlinPoints, me, size); | |
| 2456 | ✗ | ass1 := arrayCreate(size,-1); | |
| 2457 | ✗ | ass2 := arrayCreate(size,-1); | |
| 2458 | ✗ | order := {}; | |
| 2459 | ✗ | (OutTVars, order) := CellierTearing2(false,m,mt,me,meT,ass1,ass2,unsolvables,{},discreteVars,tSel_always,tSel_prefer,tSel_avoid,tSel_never,order,mapEqnIncRow,mapIncRowEqn,eqnNonlinPoints,true); | |
| 2460 | end if; | ||
| 2461 | |||
| 2462 | // check if tearing makes sense | ||
| 2463 | 1954 | tornsize := listLength(OutTVars); | |
| 2464 | b := intLt(tornsize, size); | ||
| 2465 | |||
| 2466 | if debug then execStat("Tearing.CellierTearing -> 3.2"); end if; | ||
| 2467 | // Unassigned equations are residual equations | ||
| 2468 | 1954 | residual := getUnassigned(ass2); | |
| 2469 | if debug then execStat("Tearing.CellierTearing -> 3.3"); end if; | ||
| 2470 | 1954 | residual_coll := List.map1r(residual,arrayGet,mapIncRowEqn); | |
| 2471 | if debug then execStat("Tearing.CellierTearing -> 3.4"); end if; | ||
| 2472 | 1954 | residual_coll := List.unique(residual_coll); | |
| 2473 | if debug then execStat("Tearing.CellierTearing -> 3.5"); end if; | ||
| 2474 | // dump results with local indexes | ||
| 2475 |
3/4✓ Branch 1 taken 1952 times.
✓ Branch 2 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1952 times.
|
1954 | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2476 | 2 | dumpTearingSetLocalIndexes(OutTVars,residual_coll,order,ass2,size,mapEqnIncRow,vars,eqns," - STRICT SET"); | |
| 2477 | end if; | ||
| 2478 | |||
| 2479 | if debug then execStat("Tearing.CellierTearing -> 4"); end if; | ||
| 2480 | |||
| 2481 | // Convert indexes | ||
| 2482 | 1954 | OutTVars := selectFromList_rev(vindx, OutTVars); | |
| 2483 | 1954 | residual := selectFromList_rev(eindex, residual_coll); | |
| 2484 | |||
| 2485 | // assign innerEquations: | ||
| 2486 | 1954 | innerEquations := assignInnerEquations(order,eindex,vindx,ass2,mapEqnIncRow,NONE()); | |
| 2487 | if debug then execStat("Tearing.CellierTearing -> 5"); end if; | ||
| 2488 | |||
| 2489 | // Create BackendDAE.TearingSet for strict set | ||
| 2490 | 1954 | strictTearingSet := BackendDAE.TEARINGSET(OutTVars,residual,innerEquations,BackendDAE.EMPTY_JACOBIAN()); | |
| 2491 | |||
| 2492 | // dump results with global indexes | ||
| 2493 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1954 times.
|
1954 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2494 | ✗ | dumpTearingSetGlobalIndexes(strictTearingSet,size," - STRICT SET"); | |
| 2495 | end if; | ||
| 2496 | |||
| 2497 | |||
| 2498 | // Determine casual tearing set if dynamic tearing is enabled | ||
| 2499 | // ***************************************************************** | ||
| 2500 | |||
| 2501 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1951 times.
|
1954 | if dynamicTearing then |
| 2502 | |||
| 2503 |
3/4✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 time.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
|
3 | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2504 | 1 | print("\n\nDetermine CASUAL TEARING SET\n" + BORDER + BORDER + "\n\n"); | |
| 2505 | end if; | ||
| 2506 | |||
| 2507 | // Get adjacency matrix again | ||
| 2508 | 3 | (_,m,mt,_,_) := BackendDAEUtil.getAdjacencyMatrixScalar(subsyst, BackendDAE.NORMAL(),NONE(), BackendDAEUtil.isInitializationDAE(ishared)); | |
| 2509 | |||
| 2510 | // Delete negative entries from adjacency matrix | ||
| 2511 | 3 | m := Array.map(m,deleteNegativeEntries); | |
| 2512 | 3 | mt := Array.map(mt,deleteNegativeEntries); | |
| 2513 | |||
| 2514 | // Get advanced adjacency matrix (determine if the equations are solvable for the variables) | ||
| 2515 | 3 | (me,meT,mapEqnIncRow,mapIncRowEqn) := BackendDAEUtil.getAdjacencyMatrixEnhancedScalar(subsyst,ishared,true); | |
| 2516 | |||
| 2517 | // Determine unsolvable vars to consider solvability | ||
| 2518 | 3 | unsolvables := getUnsolvableVars(size,meT); | |
| 2519 | |||
| 2520 |
3/4✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 time.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
|
3 | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2521 | 1 | print("\nAdjacencyMatrixEnhanced:\n"); | |
| 2522 | 1 | BackendDump.dumpAdjacencyMatrixEnhanced(me); | |
| 2523 | 1 | print("\nAdjacencyMatrixTransposedEnhanced:\n"); | |
| 2524 | 1 | BackendDump.dumpAdjacencyMatrixTEnhanced(meT); | |
| 2525 | 1 | print("\neqLinPoints:\n" + stringDelimitList(List.mapArray(eqnNonlinPoints, intString),",") + "\n\n"); | |
| 2526 | end if; | ||
| 2527 | |||
| 2528 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2529 | ✗ | print("mapEqnIncRow:"); //+ stringDelimitList(List.map(List.flatten(arrayList(mapEqnIncRow)),intString),",") + "\n\n"); | |
| 2530 | ✗ | BackendDump.dumpAdjacencyMatrix(mapEqnIncRow); | |
| 2531 | ✗ | print("\nmapIncRowEqn:\n" + stringDelimitList(List.mapArray(mapIncRowEqn, intString),",") + "\n\n"); | |
| 2532 | ✗ | print("\n\nUNSOLVABLES:\n" + stringDelimitList(List.map(unsolvables,intString),",") + "\n\n"); | |
| 2533 | ✗ | print("\nDiscrete Vars:\n" + stringDelimitList(List.map(discreteVars,intString),",") + "\n\n"); | |
| 2534 | end if; | ||
| 2535 | |||
| 2536 | // Initialize matching | ||
| 2537 | 3 | ass1 := arrayCreate(size,-1); | |
| 2538 | 3 | ass2 := arrayCreate(size,-1); | |
| 2539 | 3 | order := {}; | |
| 2540 | |||
| 2541 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2542 | ✗ | print("\n" + BORDER + "\nBEGINNING of CellierTearing2\n\n"); | |
| 2543 | end if; | ||
| 2544 | // ticket #15433: the degree-1 forcing is only applied to the strict set (above) when its plain | ||
| 2545 | // pass is singular; never force the casual/dynamic set. | ||
| 2546 | 3 | (OutTVars, order) := CellierTearing2(false,m,mt,me,meT,ass1,ass2,unsolvables,{},discreteVars,tSel_always,tSel_prefer,tSel_avoid,tSel_never,order,mapEqnIncRow,mapIncRowEqn,eqnNonlinPoints,false); | |
| 2547 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2548 | ✗ | print("\nEND of CellierTearing2\n" + BORDER + "\n\n"); | |
| 2549 | end if; | ||
| 2550 | |||
| 2551 | // only continue if dynamic tearing makes sense (casual set < strict set) | ||
| 2552 |
1/2✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
|
3 | if intLt(listLength(OutTVars), tornsize) then |
| 2553 | |||
| 2554 | // Unassigned equations are residual equations | ||
| 2555 | 3 | residual := getUnassigned(ass2); | |
| 2556 | 3 | residual_coll := List.map1r(residual,arrayGet,mapIncRowEqn); | |
| 2557 | 3 | residual_coll := List.unique(residual_coll); | |
| 2558 | |||
| 2559 | // dump results with local indexes | ||
| 2560 |
3/4✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 time.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
|
3 | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2561 | 1 | dumpTearingSetLocalIndexes(OutTVars,residual_coll,order,ass2,size,mapEqnIncRow,vars,eqns," - CASUAL SET"); | |
| 2562 | end if; | ||
| 2563 | |||
| 2564 | // Convert indexes | ||
| 2565 | 3 | OutTVars := selectFromList_rev(vindx, OutTVars); | |
| 2566 | 3 | residual := selectFromList_rev(eindex, residual_coll); | |
| 2567 | |||
| 2568 | // assign innerEquations: | ||
| 2569 | 3 | innerEquations := assignInnerEquations(order,eindex,vindx,ass2,mapEqnIncRow,SOME(me)); | |
| 2570 | |||
| 2571 | // Create BackendDAE.TearingSet for casual set | ||
| 2572 | 3 | casualTearingSet := SOME(BackendDAE.TEARINGSET(OutTVars,residual,innerEquations,BackendDAE.EMPTY_JACOBIAN())); | |
| 2573 | |||
| 2574 | // dump results with global indexes | ||
| 2575 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2576 | ✗ | dumpTearingSetGlobalIndexes(BackendDAE.TEARINGSET(OutTVars,residual,innerEquations,BackendDAE.EMPTY_JACOBIAN()),size," - CASUAL SET"); | |
| 2577 | end if; | ||
| 2578 | |||
| 2579 |
3/4✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 time.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
|
3 | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2580 |
1/2✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
|
1 | if linear then s:="Linear"; else s:="Nonlinear"; end if; |
| 2581 | 1 | print("\nNote:\n=====\n" + s + " dynamic tearing for this strong component in model:\n" + modelName + "\n\n"); | |
| 2582 | end if; | ||
| 2583 | |||
| 2584 | else | ||
| 2585 | ✗ | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 2586 | ✗ | print("\n" + BORDER + "\n* TEARING RESULTS (CASUAL SET):\n*\n* No of equations in strong component: "+intString(size)+"\n"); | |
| 2587 | ✗ | print("* No of tVars: "+intString(listLength(OutTVars))+"\n"); | |
| 2588 | ✗ | print("*\n* tVars: "+ stringDelimitList(List.map(listReverse(OutTVars),intString),",") + "\n"); | |
| 2589 | ✗ | print("*\n* The casual tearing set is not smaller\n* than the strict tearing set and there-\n* fore it is discarded.\n*" + BORDER + "\n"); | |
| 2590 | end if; | ||
| 2591 | |||
| 2592 | ✗ | if not b and not Flags.getConfigBool(Flags.FORCE_TEARING) then | |
| 2593 | ✗ | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 2594 | ✗ | print("\nNote:\n=====\nTearing set is discarded because it is not smaller than the original set. Use +forceTearing to prevent this.\n\n"); | |
| 2595 | end if; | ||
| 2596 | ✗ | fail(); | |
| 2597 | end if; | ||
| 2598 | casualTearingSet := NONE(); | ||
| 2599 | end if; | ||
| 2600 | if debug then execStat("Tearing.CellierTearing -> 6"); end if; | ||
| 2601 | |||
| 2602 | else | ||
| 2603 |
3/4✓ Branch 1 taken 1950 times.
✓ Branch 2 taken 1 time.
✗ Branch 4 not taken.
✓ Branch 5 taken 1950 times.
|
1951 | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2604 | 1 | print("Note:\n=====\nNo dynamic Tearing for this strong component. Check if\n- flag 'dynamicTearing' is set proper\n- strong component does not contain statesets\n- system belongs to simulation\n- SimCode target is 'C'\n\n"); | |
| 2605 | end if; | ||
| 2606 |
4/4✓ Branch 0 taken 177 times.
✓ Branch 1 taken 1774 times.
✓ Branch 3 taken 175 times.
✓ Branch 4 taken 2 times.
|
1951 | if not b and not Flags.getConfigBool(Flags.FORCE_TEARING) then |
| 2607 |
2/4✓ Branch 1 taken 175 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 175 times.
|
175 | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2608 | ✗ | print("\nNote:\n=====\nTearing set is discarded because it is not smaller than the original set. Use +forceTearing to prevent this.\n\n"); | |
| 2609 | end if; | ||
| 2610 | 175 | fail(); | |
| 2611 | end if; | ||
| 2612 | casualTearingSet := NONE(); | ||
| 2613 | if debug then execStat("Tearing.CellierTearing -> 7"); end if; | ||
| 2614 | end if; | ||
| 2615 | |||
| 2616 | // Determine the rest of the information needed for BackendDAE.TORNSYSTEM | ||
| 2617 | // *************************************************************************** | ||
| 2618 | |||
| 2619 |
4/4✓ Branch 0 taken 1568 times.
✓ Branch 1 taken 211 times.
✓ Branch 2 taken 828 times.
✓ Branch 3 taken 951 times.
|
4175 | ocomp := BackendDAE.TORNSYSTEM(strictTearingSet,casualTearingSet,linear,mixedSystem); |
| 2620 | outRunMatching := true; | ||
| 2621 |
1/2✓ Branch 1 taken 1779 times.
✗ Branch 2 not taken.
|
1779 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2622 | ✗ | print("\nEND of CellierTearing\n" + BORDER + "\n\n"); | |
| 2623 | end if; | ||
| 2624 | end CellierTearing; | ||
| 2625 | |||
| 2626 | |||
| 2627 | protected function tearingSelect | ||
| 2628 | "collects variables with annotation attribute '__OpenModelica_tearingSelect in [always, prefer, avoid, never]' | ||
| 2629 | author: ptaeuber FHB 2014-05" | ||
| 2630 | input list<BackendDAE.Var> var_lstIn; | ||
| 2631 | input output list<Integer> always; | ||
| 2632 | input String DAEtypeStr; | ||
| 2633 | output list<Integer> prefer = {}; | ||
| 2634 | output list<Integer> avoid = {}; | ||
| 2635 | output list<Integer> never = {}; | ||
| 2636 | output list<Integer> alwaysByUser = always "distinguish between user choice and compiler choice"; | ||
| 2637 | protected | ||
| 2638 | BackendDAE.Var var; | ||
| 2639 | Integer index = 1; | ||
| 2640 | Option<BackendDAE.TearingSelect> ts; | ||
| 2641 | Boolean preferTVarsWithStartValue; | ||
| 2642 | Boolean inSimulation = DAEtypeStr == "simulation"; | ||
| 2643 | Boolean decided; | ||
| 2644 | algorithm | ||
| 2645 |
4/6✓ Branch 1 taken 1991 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 946 times.
✓ Branch 4 taken 1045 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 946 times.
|
1991 | preferTVarsWithStartValue := Flags.getConfigBool(Flags.PREFER_TVARS_WITH_START_VALUE) and (DAEtypeStr == "initialization"); |
| 2646 |
2/2✓ Branch 0 taken 36914 times.
✓ Branch 1 taken 1991 times.
|
38905 | for var in var_lstIn loop |
| 2647 | // Get the value of the variable's __OpenModelica_tearingSelect attribute. | ||
| 2648 | 36914 | BackendDAE.VAR(tearingSelectOption = ts) := var; | |
| 2649 | |||
| 2650 | // Add the variable's index to the appropriate list. | ||
| 2651 | decided := match ts | ||
| 2652 | case NONE() then false; | ||
| 2653 | case SOME(BackendDAE.ALWAYS()) algorithm | ||
| 2654 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | if not listMember(index, always) then |
| 2655 | always := index :: always; | ||
| 2656 | alwaysByUser := index :: alwaysByUser; | ||
| 2657 | end if; | ||
| 2658 | then true; | ||
| 2659 | case SOME(BackendDAE.PREFER()) algorithm prefer := index :: prefer; then true; | ||
| 2660 | case SOME(BackendDAE.DEFAULT()) then true; | ||
| 2661 | case SOME(BackendDAE.AVOID()) algorithm avoid := index :: avoid; then true; | ||
| 2662 | case SOME(BackendDAE.NEVER()) algorithm never := index :: never; then true; | ||
| 2663 | end match; | ||
| 2664 | |||
| 2665 |
2/2✓ Branch 0 taken 35779 times.
✓ Branch 1 taken 1135 times.
|
36914 | if not decided then |
| 2666 | // During simulation, always select states | ||
| 2667 | // see https://github.com/OpenModelica/OpenModelica/issues/7704 | ||
| 2668 |
1/8✗ Branch 1 not taken.
✓ Branch 2 taken 35779 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
|
35779 | if Flags.getConfigBool(Flags.TEARING_ALWAYS_DERIVATIVES) and |
| 2669 | inSimulation and BackendVariable.isStateVar(var) and not listMember(index, always) then | ||
| 2670 | ✗ | always := index :: always; | |
| 2671 | |||
| 2672 | // Also prefer variables with start value that is not just the default of their type | ||
| 2673 | elseif preferTVarsWithStartValue and BackendVariable.varHasStartValue(var) and not BackendVariable.varStartFromType(var) then | ||
| 2674 | prefer := index :: prefer; | ||
| 2675 | end if; | ||
| 2676 | end if; | ||
| 2677 | 36914 | index := index + 1; | |
| 2678 | end for; | ||
| 2679 | |||
| 2680 |
1/2✓ Branch 1 taken 1991 times.
✗ Branch 2 not taken.
|
1991 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2681 | ✗ | print("\nExternal influence on selection of iteration variables by variable annotations (__OpenModelica_tearingSelect)" + (if preferTVarsWithStartValue then " and preference of variables with start attribute" else "") + ":\n"); | |
| 2682 | ✗ | print("Always: " + stringDelimitList(List.map(always, intString), ",") + "\n"); | |
| 2683 | ✗ | print("Prefer: " + stringDelimitList(List.map(prefer, intString), ",")+ "\n"); | |
| 2684 | ✗ | print("Avoid: " + stringDelimitList(List.map(avoid, intString), ",")+ "\n"); | |
| 2685 | ✗ | print("Never: " + stringDelimitList(List.map(never, intString), ",") + "\n\n"); | |
| 2686 | end if; | ||
| 2687 | end tearingSelect; | ||
| 2688 | |||
| 2689 | |||
| 2690 | public function deleteNegativeEntries | ||
| 2691 | "deletes all negative entries from adjacency matrix, works with Array.map1, needed for proper Cellier-Tearing | ||
| 2692 | author: ptaeuber FHB 2014-01" | ||
| 2693 | input list<Integer> rowIn; | ||
| 2694 | output list<Integer> rowOut; | ||
| 2695 | algorithm | ||
| 2696 |
6/6✓ Branch 0 taken 2378 times.
✓ Branch 1 taken 284969 times.
✓ Branch 2 taken 287347 times.
✓ Branch 3 taken 73295 times.
✓ Branch 4 taken 284969 times.
✓ Branch 5 taken 73295 times.
|
360642 | rowOut := list(r for r guard r > 0 in rowIn); |
| 2697 | end deleteNegativeEntries; | ||
| 2698 | |||
| 2699 | |||
| 2700 | protected function findDiscrete "takes a list of BackendDAE.Var and returns the indexes of the discrete Variables | ||
| 2701 | author: ptaeuber FHB 2014-01" | ||
| 2702 | input list<BackendDAE.Var> inVars; | ||
| 2703 | output list<Integer> discreteVarsOut = {}; | ||
| 2704 | protected | ||
| 2705 | Integer index = 1; | ||
| 2706 | algorithm | ||
| 2707 |
2/2✓ Branch 0 taken 36637 times.
✓ Branch 1 taken 1957 times.
|
38594 | for var in inVars loop |
| 2708 |
2/2✓ Branch 1 taken 360 times.
✓ Branch 2 taken 36277 times.
|
36637 | if BackendVariable.isVarDiscrete(var) then |
| 2709 | discreteVarsOut := index::discreteVarsOut; | ||
| 2710 | end if; | ||
| 2711 | 36637 | index := index + 1; | |
| 2712 | end for; | ||
| 2713 | end findDiscrete; | ||
| 2714 | |||
| 2715 | protected function findDiscreteWarnTearingSelect | ||
| 2716 | "mahge: Finds discrete variables in a variable list. This will also warn if the | ||
| 2717 | discrete variable has tearing select annotations. Right now this is used in manadatory | ||
| 2718 | tearing. It should probably used everywhere else as long as we don't have mixed solvers | ||
| 2719 | since we can not chose a discrete variable as a tearing(iteration) variable anyway. | ||
| 2720 | Note: This function returns indices based on the order of the variables in the list." | ||
| 2721 | input list<BackendDAE.Var> inVars; | ||
| 2722 | output list<Integer> discreteVarsOut = {}; | ||
| 2723 | protected | ||
| 2724 | Integer index = 1; | ||
| 2725 | algorithm | ||
| 2726 |
2/2✓ Branch 0 taken 2226 times.
✓ Branch 1 taken 34 times.
|
2260 | for var in inVars loop |
| 2727 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2226 times.
|
2226 | if BackendVariable.isVarDiscrete(var) then |
| 2728 | discreteVarsOut := index::discreteVarsOut; | ||
| 2729 | |||
| 2730 | () := match var.tearingSelectOption | ||
| 2731 | case SOME(BackendDAE.ALWAYS()) algorithm | ||
| 2732 | ✗ | Error.addSourceMessage(Error.COMPILER_WARNING,{"Minimal Tearing is ignoring '__OpenModelica_tearingSelect = TearingSelect.always' annotation for discrete variable: " | |
| 2733 | + BackendDump.varString(var)},ElementSource.getInfo(var.source)); | ||
| 2734 | then (); | ||
| 2735 | case SOME(BackendDAE.PREFER()) algorithm | ||
| 2736 | ✗ | Error.addSourceMessage(Error.COMPILER_WARNING,{"Minimal Tearing is ignoring '__OpenModelica_tearingSelect = TearingSelect.prefer' annotation for discrete variable: " | |
| 2737 | + BackendDump.varString(var)},ElementSource.getInfo(var.source)); | ||
| 2738 | then (); | ||
| 2739 | else (); | ||
| 2740 | end match; | ||
| 2741 | |||
| 2742 | end if; | ||
| 2743 | 2226 | index := index + 1; | |
| 2744 | end for; | ||
| 2745 | end findDiscreteWarnTearingSelect; | ||
| 2746 | |||
| 2747 | protected function findCSE | ||
| 2748 | input list<BackendDAE.Var> inVars; | ||
| 2749 | output list<Integer> cseVarsOut = {}; | ||
| 2750 | protected | ||
| 2751 | Integer index = 1; | ||
| 2752 | algorithm | ||
| 2753 |
2/2✓ Branch 0 taken 2226 times.
✓ Branch 1 taken 34 times.
|
2260 | for var in inVars loop |
| 2754 |
2/2✓ Branch 1 taken 6 times.
✓ Branch 2 taken 2220 times.
|
2226 | if BackendVariable.isCSEVar(var) then |
| 2755 | cseVarsOut := index::cseVarsOut; | ||
| 2756 | end if; | ||
| 2757 | 2226 | index := index + 1; | |
| 2758 | end for; | ||
| 2759 | end findCSE; | ||
| 2760 | |||
| 2761 | |||
| 2762 | protected function getEquationNonlinearityPoints | ||
| 2763 | "Function returns an array with an integer assessment of the nonlinearity | ||
| 2764 | author: ptaeuber" | ||
| 2765 | input output array<Integer> eqnNonlinPoints; | ||
| 2766 | input BackendDAE.AdjacencyMatrixEnhanced me; | ||
| 2767 | input Integer size; | ||
| 2768 | protected | ||
| 2769 | BackendDAE.AdjacencyMatrixElementEnhanced row; | ||
| 2770 | Integer sum; | ||
| 2771 | algorithm | ||
| 2772 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1956 times.
|
38589 | for i in 1:size loop |
| 2773 | 36633 | row := me[i]; | |
| 2774 | sum := 0; | ||
| 2775 |
2/2✓ Branch 0 taken 143641 times.
✓ Branch 1 taken 36633 times.
|
180274 | for entry in row loop |
| 2776 | 143641 | sum := sum + nonlinearityWeight(entry); | |
| 2777 | end for; | ||
| 2778 | 36633 | eqnNonlinPoints[i] := sum; | |
| 2779 | end for; | ||
| 2780 | end getEquationNonlinearityPoints; | ||
| 2781 | |||
| 2782 | |||
| 2783 | protected function nonlinearityWeight | ||
| 2784 | "Function returns a weight for specific solvability | ||
| 2785 | author: ptaeuber" | ||
| 2786 | input BackendDAE.AdjacencyMatrixElementEnhancedEntry entry; | ||
| 2787 | output Integer weight; | ||
| 2788 | algorithm | ||
| 2789 | weight := match entry | ||
| 2790 | case(_, BackendDAE.SOLVABILITY_SOLVED(), _) then 0; | ||
| 2791 | case(_, BackendDAE.SOLVABILITY_CONSTONE(), _) then 2; | ||
| 2792 | case(_, BackendDAE.SOLVABILITY_CONST(), _) then 5; | ||
| 2793 | case(_, BackendDAE.SOLVABILITY_PARAMETER(b=true), _) then 10; | ||
| 2794 | case(_, BackendDAE.SOLVABILITY_PARAMETER(b=false), _) then 20; | ||
| 2795 | case(_, BackendDAE.SOLVABILITY_LINEAR(b=true), _) then 20; | ||
| 2796 | case(_, BackendDAE.SOLVABILITY_LINEAR(b=false), _) then 50; | ||
| 2797 | case(_, BackendDAE.SOLVABILITY_NONLINEAR(), _) then 50; | ||
| 2798 | case(_, BackendDAE.SOLVABILITY_UNSOLVABLE(), _) then 100; | ||
| 2799 | else 0; | ||
| 2800 | end match; | ||
| 2801 | end nonlinearityWeight; | ||
| 2802 | |||
| 2803 | |||
| 2804 | protected function CellierTearing2 " function to call tearing heuristic and matching algorithm | ||
| 2805 | author: ptaeuber FHB 2013-2015" | ||
| 2806 | input Boolean inCausal; | ||
| 2807 | input BackendDAE.AdjacencyMatrix mIn; | ||
| 2808 | input BackendDAE.AdjacencyMatrixT mtIn; | ||
| 2809 | input BackendDAE.AdjacencyMatrixEnhanced meIn; | ||
| 2810 | input BackendDAE.AdjacencyMatrixTEnhanced meTIn; | ||
| 2811 | input array<Integer> ass1In,ass2In; | ||
| 2812 | input list<Integer> Unsolvables,tvarsIn,discreteVars,tSel_always,tSel_prefer,tSel_avoid,tSel_never,orderIn; | ||
| 2813 | input array<list<Integer>> mapEqnIncRow; | ||
| 2814 | input array<Integer> mapIncRowEqn; | ||
| 2815 | input array<Integer> eqnNonlinPoints; | ||
| 2816 | input Boolean forceDegree1 "ticket #15433: enable variable-driven degree-1 forced assignment (set by CellierTearing only for initialization components that have a $START.x->x cycle)"; | ||
| 2817 | output list<Integer> OutTVars; | ||
| 2818 | output list<Integer> orderOut; | ||
| 2819 | protected | ||
| 2820 | constant Boolean debug = false; | ||
| 2821 | algorithm | ||
| 2822 |
2/2✓ Branch 0 taken 1957 times.
✓ Branch 1 taken 4105 times.
|
6062 | if inCausal then |
| 2823 | OutTVars := tvarsIn; | ||
| 2824 | orderOut := orderIn; | ||
| 2825 | if debug then execStat("Tearing.CellierTearing2 - done"); end if; | ||
| 2826 |
1/2✓ Branch 0 taken 1957 times.
✗ Branch 1 not taken.
|
1957 | return; |
| 2827 | end if; | ||
| 2828 | (OutTVars, orderOut) := match (Unsolvables,tSel_always) | ||
| 2829 | local | ||
| 2830 | Integer tvar; | ||
| 2831 | list<Integer> tvars,unsolvables,tVar_never,tVar_discrete,order; | ||
| 2832 | Boolean causal; | ||
| 2833 | |||
| 2834 | // case: There are no unsolvables and no variables with annotation '__OpenModelica_tearingSelect = TearingSelect.always' | ||
| 2835 | case ({},{}) | ||
| 2836 | algorithm | ||
| 2837 | // select tearing Var | ||
| 2838 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3314 times.
|
3314 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2839 | ✗ | print("\n" + BORDER + "\nBEGINNING of selectTearingVar\n\n"); | |
| 2840 | end if; | ||
| 2841 | 3314 | tvar := selectTearingVar(meIn,meTIn,mIn,mtIn,ass1In,ass2In,discreteVars,tSel_prefer,tSel_avoid,tSel_never,mapEqnIncRow,mapIncRowEqn); | |
| 2842 | if debug then execStat("Tearing.CellierTearing2 - 1.0"); end if; | ||
| 2843 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3312 times.
|
3312 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2844 | ✗ | print("\nEND of selectTearingVar\n" + BORDER + "\n\n"); | |
| 2845 | end if; | ||
| 2846 | |||
| 2847 | // mark tvar in ass1In | ||
| 2848 | 3312 | arrayUpdate(ass1In,tvar,arrayLength(ass1In)*2); | |
| 2849 | |||
| 2850 | // remove tearing var from adjacency matrix and transposed inc matrix | ||
| 2851 | 3312 | deleteEntriesFromAdjacencyMatrix(mIn,mtIn,{tvar}); | |
| 2852 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3312 times.
|
3312 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2853 | ✗ | print("\n\n###BEGIN print Adjacency Matrix w/o tvar############\n(Function: CellierTearing2)\n"); | |
| 2854 | ✗ | BackendDump.dumpAdjacencyMatrix(mIn); | |
| 2855 | end if; | ||
| 2856 | 3312 | Array.replaceAtWithFill(tvar,{},{},mtIn); | |
| 2857 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3312 times.
|
3312 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2858 | ✗ | BackendDump.dumpAdjacencyMatrixT(mtIn); | |
| 2859 | ✗ | print("\n###END print Adjacency Matrix w/o tvar##############\n(Function: CellierTearing2)\n\n\n"); | |
| 2860 | end if; | ||
| 2861 | |||
| 2862 | if debug then execStat("Tearing.CellierTearing2 - 1.1"); end if; | ||
| 2863 | tvars := tvar::tvarsIn; | ||
| 2864 | |||
| 2865 | // assign vars to eqs until complete or partially causalisation(and restart algorithm) | ||
| 2866 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3312 times.
|
3312 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2867 | ✗ | print("\n" + BORDER + "\nBEGINNING of TarjanMatching\n\n"); | |
| 2868 | end if; | ||
| 2869 | 3312 | (order,causal) := TarjanMatching(mIn,mtIn,meIn,meTIn,ass1In,ass2In,orderIn,mapEqnIncRow,mapIncRowEqn,eqnNonlinPoints,forceDegree1); | |
| 2870 | if debug then execStat("Tearing.CellierTearing2 - 1.2"); end if; | ||
| 2871 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3312 times.
|
3312 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2872 | ✗ | print("\nEND of TarjanMatching\n" + BORDER + "\n\n"); | |
| 2873 | ✗ | print("\n" + BORDER + "\n* TARJAN RESULTS:\n* ass1: " + stringDelimitList(List.mapArray(ass1In, intString),",")+"\n"); | |
| 2874 | ✗ | print("* ass2: "+stringDelimitList(List.mapArray(ass2In, intString),",")+"\n"); | |
| 2875 | ✗ | print("* order: "+stringDelimitList(List.map(order,intString),",")+"\n" + BORDER + "\n\n"); | |
| 2876 | end if; | ||
| 2877 |
5/6✓ Branch 0 taken 1336 times.
✓ Branch 1 taken 1976 times.
✓ Branch 3 taken 1333 times.
✓ Branch 4 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1333 times.
|
3312 | if causal and (Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE)) then |
| 2878 | 3 | print("\n"); | |
| 2879 | 3 | BackendDump.dumpMatching(ass1In); | |
| 2880 | 3 | print("\norder: "+stringDelimitList(List.map(order,intString),",")+"\n" + UNDERLINE + "\n\n"); | |
| 2881 | end if; | ||
| 2882 | |||
| 2883 | // ascertain if there are new unsolvables now | ||
| 2884 | 3312 | unsolvables := getUnsolvableVarsConsiderMatching(arrayLength(meTIn),meTIn,ass1In,ass2In); | |
| 2885 | if debug then execStat("Tearing.CellierTearing2 - 1.3"); end if; | ||
| 2886 | 3312 | (_,unsolvables,_) := List.intersection1OnTrue(unsolvables,tvars,intEq); | |
| 2887 | |||
| 2888 | if debug then execStat("Tearing.CellierTearing2 - 1 done"); end if; | ||
| 2889 | |||
| 2890 | // repeat until system is causal | ||
| 2891 | 4103 | (tvars, order) := CellierTearing2(causal,mIn,mtIn,meIn,meTIn,ass1In,ass2In,unsolvables,tvars,discreteVars,tSel_always,tSel_prefer,tSel_avoid,tSel_never,order,mapEqnIncRow,mapIncRowEqn,eqnNonlinPoints,forceDegree1); | |
| 2892 | |||
| 2893 | then | ||
| 2894 | (tvars,order); | ||
| 2895 | |||
| 2896 | // case: There are unsolvables and/or variables with annotation '__OpenModelica_tearingSelect = TearingSelect.always' | ||
| 2897 | else | ||
| 2898 | algorithm | ||
| 2899 | // First choose unsolvables and 'always'-vars as tVars | ||
| 2900 | 791 | tvars := List.unique(listAppend(Unsolvables,tSel_always)); | |
| 2901 | 791 | tVar_never := List.intersectionOnTrue(tSel_never,tvars,intEq); | |
| 2902 | 791 | tVar_discrete := List.intersectionOnTrue(discreteVars,tvars,intEq); | |
| 2903 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 789 times.
|
791 | if not listEmpty(tVar_never) then |
| 2904 | 2 | Error.addCompilerWarning("There are tearing variables with annotation attribute '__OpenModelica_tearingSelect = TearingSelect.never'. Use -d=tearingdump and -d=tearingdumpV for more information."); | |
| 2905 | end if; | ||
| 2906 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 791 times.
|
791 | if not listEmpty(tVar_discrete) then |
| 2907 | ✗ | Error.addCompilerWarning("There are discrete tearing variables because otherwise the system could not have been torn (unsolvables). This may lead to problems during simulation."); | |
| 2908 | end if; | ||
| 2909 |
3/4✓ Branch 1 taken 789 times.
✓ Branch 2 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 789 times.
|
791 | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2910 | 2 | print("\nForced selection of Tearing Variables:\n" + UNDERLINE + "\nUnsolvables as tVars: "+ stringDelimitList(List.map(Unsolvables,intString),",")+"\n"); | |
| 2911 | 2 | print("Variables with annotation attribute 'always' as tVars: "+ stringDelimitList(List.map(tSel_always,intString),",")+"\n"); | |
| 2912 | end if; | ||
| 2913 | |||
| 2914 | // mark tvars in ass1In | ||
| 2915 | 791 | markTVarsOrResiduals(tvars, ass1In); | |
| 2916 | |||
| 2917 | // remove tearing var from adjacency matrix and transposed adjacency matrix | ||
| 2918 | 791 | deleteEntriesFromAdjacencyMatrix(mIn, mtIn, tvars); | |
| 2919 | 791 | deleteRowsFromAdjacencyMatrix(mtIn, tvars); | |
| 2920 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 791 times.
|
791 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2921 | ✗ | print("\n\n###BEGIN print Adjacency Matrix w/o tvars###########\n(Function: CellierTearing2)\n"); | |
| 2922 | ✗ | BackendDump.dumpAdjacencyMatrix(mIn); | |
| 2923 | ✗ | BackendDump.dumpAdjacencyMatrixT(mtIn); | |
| 2924 | ✗ | print("\n###END print Adjacency Matrix w/o tvars#############\n(Function: CellierTearing2)\n\n\n"); | |
| 2925 | ✗ | print("\n" + BORDER + "\nBEGINNING of TarjanMatching\n\n"); | |
| 2926 | end if; | ||
| 2927 | |||
| 2928 | 791 | tvars := listAppend(tvars,tvarsIn) annotation(__OpenModelica_DisableListAppendWarning=true); | |
| 2929 | |||
| 2930 | // assign vars to eqs until complete or partially causalisation(and restart algorithm) | ||
| 2931 | 791 | (order,causal) := TarjanMatching(mIn,mtIn,meIn,meTIn,ass1In,ass2In,orderIn,mapEqnIncRow,mapIncRowEqn,eqnNonlinPoints,forceDegree1); | |
| 2932 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 791 times.
|
791 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2933 | ✗ | print("\nEND of TarjanMatching\n" + BORDER + "\n\n"); | |
| 2934 | ✗ | print("\n" + BORDER + "\n* TARJAN RESULTS:\n* ass1: " + stringDelimitList(List.mapArray(ass1In, intString),",")+"\n"); | |
| 2935 | ✗ | print("* ass2: "+stringDelimitList(List.mapArray(ass2In,intString),",")+"\n"); | |
| 2936 | ✗ | print("* order: "+stringDelimitList(List.map(order,intString),",")+"\n" + BORDER + "\n\n"); | |
| 2937 | end if; | ||
| 2938 |
4/6✓ Branch 0 taken 621 times.
✓ Branch 1 taken 170 times.
✓ Branch 3 taken 621 times.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 621 times.
|
791 | if causal and (Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE)) then |
| 2939 | ✗ | print("\n"); | |
| 2940 | ✗ | BackendDump.dumpMatching(ass1In); | |
| 2941 | ✗ | print("\norder: "+stringDelimitList(List.map(order,intString),",")+"\n" + UNDERLINE + "\n\n"); | |
| 2942 | end if; | ||
| 2943 | |||
| 2944 | // ascertain if there are new unsolvables now | ||
| 2945 | 791 | unsolvables := getUnsolvableVarsConsiderMatching(arrayLength(meTIn),meTIn,ass1In,ass2In); | |
| 2946 | 791 | (_,unsolvables,_) := List.intersection1OnTrue(unsolvables,tvars,intEq); | |
| 2947 | if debug then execStat("Tearing.CellierTearing2 - 2"); end if; | ||
| 2948 | |||
| 2949 | // repeat until system is causal | ||
| 2950 | 791 | (tvars, order) := CellierTearing2(causal,mIn,mtIn,meIn,meTIn,ass1In,ass2In,unsolvables,tvars,discreteVars,{},tSel_prefer,tSel_avoid,tSel_never,order,mapEqnIncRow,mapIncRowEqn,eqnNonlinPoints,forceDegree1); | |
| 2951 | |||
| 2952 | then | ||
| 2953 | (tvars, order); | ||
| 2954 | end match; | ||
| 2955 | end CellierTearing2; | ||
| 2956 | |||
| 2957 | |||
| 2958 | protected function selectTearingVar | ||
| 2959 | "Selects the next tearing variable referred to one of the following heuristics. | ||
| 2960 | author: ptaeuber FHB 2013-2015" | ||
| 2961 | input BackendDAE.AdjacencyMatrixEnhanced me; | ||
| 2962 | input BackendDAE.AdjacencyMatrixTEnhanced meT; | ||
| 2963 | input BackendDAE.AdjacencyMatrix m; | ||
| 2964 | input BackendDAE.AdjacencyMatrixT mt; | ||
| 2965 | input array<Integer> ass1In,ass2In; | ||
| 2966 | input list<Integer> discreteVars,tSel_prefer,tSel_avoid,tSel_never; | ||
| 2967 | input array<list<Integer>> mapEqnIncRow; | ||
| 2968 | input array<Integer> mapIncRowEqn; | ||
| 2969 | output Integer OutTVar; | ||
| 2970 | protected | ||
| 2971 | list<Integer> potentials; | ||
| 2972 | String heuristic; | ||
| 2973 | TearingHeuristic tearingHeuristic; | ||
| 2974 | algorithm | ||
| 2975 | // get the function for the requested tearing heuristic | ||
| 2976 | 3314 | heuristic := Config.getTearingHeuristic(); | |
| 2977 | tearingHeuristic := match heuristic | ||
| 2978 | case "MC1" then ModifiedCellierHeuristic_1; | ||
| 2979 | case "MC2" then ModifiedCellierHeuristic_2; | ||
| 2980 | case "MC11" then ModifiedCellierHeuristic_1_1; | ||
| 2981 | case "MC21" then ModifiedCellierHeuristic_2_1; | ||
| 2982 | case "MC12" then ModifiedCellierHeuristic_1_2; | ||
| 2983 | case "MC22" then ModifiedCellierHeuristic_2_2; | ||
| 2984 | case "MC13" then ModifiedCellierHeuristic_1_3; | ||
| 2985 | case "MC23" then ModifiedCellierHeuristic_2_3; | ||
| 2986 | case "MC231" then ModifiedCellierHeuristic_2_3_1; | ||
| 2987 | case "MC3" then ModifiedCellierHeuristic_3; | ||
| 2988 | case "MC4" then ModifiedCellierHeuristic_4; | ||
| 2989 | else | ||
| 2990 | algorithm | ||
| 2991 | ✗ | Error.addInternalError("Unknown tearing heuristic: " + heuristic, sourceInfo()); | |
| 2992 | ✗ | then fail(); | |
| 2993 | end match; | ||
| 2994 | |||
| 2995 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3314 times.
|
3314 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 2996 | ✗ | print("\n" + BORDER + "\nBEGINNING of TearingHeuristic\n\n"); | |
| 2997 | ✗ | print("Chosen Heuristic: " + heuristic + "\n\n\n"); | |
| 2998 | end if; | ||
| 2999 | |||
| 3000 | // get potential tearing variables | ||
| 3001 | try | ||
| 3002 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3314 times.
|
3314 | potentials := tearingHeuristic(m,mt,me,meT,ass1In,ass2In,discreteVars,tSel_prefer,tSel_avoid,tSel_never,mapEqnIncRow,mapIncRowEqn); |
| 3003 |
3/4✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3312 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3312 times.
|
3314 | {OutTVar} := potentials; |
| 3004 | else | ||
| 3005 | 2 | print("\nThe selection of a new tearing variable failed.\n"); | |
| 3006 | 2 | Error.addCompilerWarning("Function Tearing.selectTearingVar failed at least once. Use -d=tearingdump or -d=tearingdumpV for more information."); | |
| 3007 | 2 | fail(); | |
| 3008 | end try; | ||
| 3009 | |||
| 3010 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3312 times.
|
3312 | if listMember(OutTVar,tSel_avoid) then |
| 3011 | ✗ | Error.addCompilerWarning("The Tearing heuristic has chosen variables with annotation attribute '__OpenModelica_tearingSelect = TearingSelect.avoid'. Use -d=tearingdump and -d=tearingdumpV for more information."); | |
| 3012 | end if; | ||
| 3013 |
1/2✓ Branch 1 taken 3312 times.
✗ Branch 2 not taken.
|
3312 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3014 | ✗ | print("\nEND of TearingHeuristic\n" + BORDER + "\n\n"); | |
| 3015 | end if; | ||
| 3016 | end selectTearingVar; | ||
| 3017 | |||
| 3018 | |||
| 3019 | protected partial function TearingHeuristic "Heuristic to find a preferably good tearing variable; interface function" | ||
| 3020 | input BackendDAE.AdjacencyMatrix mIn,mtIn; | ||
| 3021 | input BackendDAE.AdjacencyMatrixEnhanced meIn; | ||
| 3022 | input BackendDAE.AdjacencyMatrixTEnhanced metIn; | ||
| 3023 | input array<Integer> ass1In; | ||
| 3024 | input array<Integer> ass2In; | ||
| 3025 | input list<Integer> discreteVars; | ||
| 3026 | input list<Integer> tSel_prefer; | ||
| 3027 | input list<Integer> tSel_avoid; | ||
| 3028 | input list<Integer> tSel_never; | ||
| 3029 | input array<list<Integer>> mapEqnIncRow; | ||
| 3030 | input array<Integer> mapIncRowEqn; | ||
| 3031 | output list<Integer> potentials={}; | ||
| 3032 | end TearingHeuristic; | ||
| 3033 | |||
| 3034 | |||
| 3035 | protected function ModifiedCellierHeuristic_1 " Heuristic to find a preferably good tearing variable [MC1]. | ||
| 3036 | author: ptaeuber FHB 2013-2015" | ||
| 3037 | extends TearingHeuristic; | ||
| 3038 | protected | ||
| 3039 | Integer edges; | ||
| 3040 | list<Integer> selectedcols1,selectedrows; | ||
| 3041 | algorithm | ||
| 3042 | // Cellier heuristic [MC1] | ||
| 3043 | |||
| 3044 | // 0. get all unassigned variables | ||
| 3045 | 146 | selectedcols1 := getUnassigned(ass1In); | |
| 3046 | |||
| 3047 | // 1. choose rows(eqs) with most nonzero entries and write the column indexes(vars) for nonzeros in a list | ||
| 3048 | 146 | selectedcols1 := getVarsOfEqnsWithMostVars(selectedcols1, mIn, mtIn); | |
| 3049 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 146 times.
|
146 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3050 | ✗ | print("1st: " + stringDelimitList(List.map(selectedcols1,intString),",") + "\n"); | |
| 3051 | end if; | ||
| 3052 | // Without discrete: | ||
| 3053 | 146 | (_,selectedcols1,_) := List.intersection1OnTrue(selectedcols1,discreteVars,intEq); | |
| 3054 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 146 times.
|
146 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3055 | ✗ | print("Without Discrete: " + stringDelimitList(List.map(selectedcols1,intString),",") + "\n(Variables in the equation(s) with most Variables)\n\n"); | |
| 3056 | end if; | ||
| 3057 | |||
| 3058 | // 2. choose rows (vars) with most nonzero entries and write the indexes in a list | ||
| 3059 | 146 | (edges,selectedcols1) := getVarsOccurringInMostEquations(mtIn, selectedcols1); | |
| 3060 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 146 times.
|
146 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3061 | ✗ | print("2nd: "+ stringDelimitList(List.map(selectedcols1,intString),",")+"\n(Variables from (1st) with most occurrence in equations (" + intString(edges) +" times))\n\n"); | |
| 3062 | end if; | ||
| 3063 | |||
| 3064 | // 3. select the rows(eqs) from mIn which could be causalized by knowing one more Var | ||
| 3065 | 146 | selectedrows := traverseSingleEqnsforAssignable(ass2In,mIn,mapEqnIncRow,mapIncRowEqn); | |
| 3066 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 146 times.
|
146 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3067 | ✗ | print(stringDelimitList(List.map(selectedrows,intString),",")+"\n(Equations which could be causalized by knowing one more Var)\n\n"); | |
| 3068 | end if; | ||
| 3069 | |||
| 3070 | // 4. determine which possible Vars causalize most equations considering impossible assignments and write them into potentials | ||
| 3071 | 146 | (potentials,edges) := selectOneMostCausalizingVar(mtIn,selectedcols1, me=meIn,ass1In=ass1In,selEqsSetArray=selectCausalVarsPrepareSelectionSet(selectedrows, arrayLength(ass1In))); | |
| 3072 |
1/2✓ Branch 1 taken 146 times.
✗ Branch 2 not taken.
|
146 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3073 | ✗ | print("\n3rd: "+ stringDelimitList(List.map(potentials,intString),",")+"\n(Chosen tearing variable. One from (2nd) causalizing most equations [" + intString(edges) + "])\n\n"); | |
| 3074 | end if; | ||
| 3075 | end ModifiedCellierHeuristic_1; | ||
| 3076 | |||
| 3077 | |||
| 3078 | protected function ModifiedCellierHeuristic_2 " Heuristic to find a preferably good tearing variable [MC2]. | ||
| 3079 | author: ptaeuber FHB 2013-2015" | ||
| 3080 | extends TearingHeuristic; | ||
| 3081 | protected | ||
| 3082 | Integer edges; | ||
| 3083 | list<Integer> varlst,selectedcols1,selectedrows; | ||
| 3084 | algorithm | ||
| 3085 | // modified Cellier heuristic [MC2] | ||
| 3086 | |||
| 3087 | // 0. Consider only non-discrete Vars | ||
| 3088 | ✗ | varlst := getUnassigned(ass1In); | |
| 3089 | ✗ | (_,selectedcols1,_) := List.intersection1OnTrue(varlst,discreteVars,intEq); | |
| 3090 | |||
| 3091 | // 1. choose rows (vars) with most nonzero entries and write the indexes in a list | ||
| 3092 | ✗ | (edges,selectedcols1) := getVarsOccurringInMostEquations(mtIn, selectedcols1); | |
| 3093 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3094 | ✗ | print("1st: "+ stringDelimitList(List.map(selectedcols1,intString),",")+"\n(Non-discrete variables with most occurrence in equations (" + intString(edges) +" times))\n\n"); | |
| 3095 | end if; | ||
| 3096 | |||
| 3097 | // 2. select the rows(eqs) from mIn which could be causalized by knowing one more Var | ||
| 3098 | ✗ | selectedrows := traverseSingleEqnsforAssignable(ass2In,mIn,mapEqnIncRow,mapIncRowEqn); | |
| 3099 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3100 | ✗ | print(stringDelimitList(List.map(selectedrows,intString),",")+"\n(Equations which could be causalized by knowing one more Var)\n\n"); | |
| 3101 | end if; | ||
| 3102 | |||
| 3103 | // 3. determine which possible Vars causalize most equations considering impossible assignments and write them into potentials | ||
| 3104 | ✗ | (potentials,edges) := selectOneMostCausalizingVar(mtIn,selectedcols1, me=meIn,ass1In=ass1In,selEqsSetArray=selectCausalVarsPrepareSelectionSet(selectedrows, arrayLength(ass1In))); | |
| 3105 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3106 | ✗ | print("\n2nd: "+ stringDelimitList(List.map(potentials,intString),",")+"\n(Chosen tearing variable. One from (1st) causalizing most equations [" + intString(edges) + "])\n\n"); | |
| 3107 | end if; | ||
| 3108 | end ModifiedCellierHeuristic_2; | ||
| 3109 | |||
| 3110 | |||
| 3111 | protected function ModifiedCellierHeuristic_1_1 " Heuristic to find a preferably good tearing variable [MC11]. | ||
| 3112 | author: ptaeuber FHB 2013-2015" | ||
| 3113 | extends TearingHeuristic; | ||
| 3114 | protected | ||
| 3115 | Integer edges; | ||
| 3116 | list<Integer> selectedcols1,selectedrows; | ||
| 3117 | algorithm | ||
| 3118 | // modified Cellier heuristic [MC11] | ||
| 3119 | |||
| 3120 | // 0. get all unassigned variables | ||
| 3121 | ✗ | selectedcols1 := getUnassigned(ass1In); | |
| 3122 | |||
| 3123 | // 1. choose rows(eqs) with most nonzero entries and write the column indexes(vars) for nonzeros in a list | ||
| 3124 | ✗ | selectedcols1 := getVarsOfEqnsWithMostVars(selectedcols1, mIn, mtIn); | |
| 3125 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3126 | ✗ | print("1st: " + stringDelimitList(List.map(selectedcols1,intString),",") + "\n"); | |
| 3127 | end if; | ||
| 3128 | |||
| 3129 | // Without discrete: | ||
| 3130 | ✗ | (_,selectedcols1,_) := List.intersection1OnTrue(selectedcols1,discreteVars,intEq); | |
| 3131 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3132 | ✗ | print("Without Discrete: " + stringDelimitList(List.map(selectedcols1,intString),",") + "\n(Variables in the equation(s) with most Variables)\n\n"); | |
| 3133 | end if; | ||
| 3134 | |||
| 3135 | // 2. choose rows (vars) with most nonzero entries and write the indexes in a list | ||
| 3136 | ✗ | (edges,selectedcols1) := getVarsOccurringInMostEquations(mtIn, selectedcols1); | |
| 3137 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3138 | ✗ | print("2nd: "+ stringDelimitList(List.map(selectedcols1,intString),",")+"\n(Variables from (1st) with most occurrence in equations (" + intString(edges) +" times))\n\n"); | |
| 3139 | end if; | ||
| 3140 | |||
| 3141 | // 3. select the rows(eqs) from mIn which could be causalized by knowing one more Var | ||
| 3142 | ✗ | selectedrows := traverseSingleEqnsforAssignable(ass2In,mIn,mapEqnIncRow,mapIncRowEqn); | |
| 3143 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3144 | ✗ | print(stringDelimitList(List.map(selectedrows,intString),",")+"\n(Equations which could be causalized by knowing one more Var)\n\n"); | |
| 3145 | end if; | ||
| 3146 | |||
| 3147 | // 4. determine which possible Vars causalize most equations considering impossible assignments and write them into potentials | ||
| 3148 | ✗ | (potentials,_) := selectMostCausalizingVars(mtIn,selectedcols1, me=meIn,ass1In=ass1In,selEqsSetArray=selectCausalVarsPrepareSelectionSet(selectedrows, arrayLength(ass1In))); | |
| 3149 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3150 | ✗ | print("\n3rd: "+ stringDelimitList(List.map(potentials,intString),",")+"\n(Variables from (2nd) causalizing most equations)\n\n"); | |
| 3151 | end if; | ||
| 3152 | |||
| 3153 | // 5. choose vars with the most impossible assignments | ||
| 3154 | ✗ | (potentials,edges) := getOneVarWithMostImpAss(potentials,ass2In,metIn); | |
| 3155 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3156 | ✗ | print("\n4th: "+ stringDelimitList(List.map(potentials,intString),",")+"\n(Chosen tearing variable. One from from (3rd) with most incident impossible assignments [" + intString(edges) + "])\n\n"); | |
| 3157 | end if; | ||
| 3158 | end ModifiedCellierHeuristic_1_1; | ||
| 3159 | |||
| 3160 | |||
| 3161 | protected function ModifiedCellierHeuristic_2_1 " Heuristic to find a preferably good tearing variable [MC21]. | ||
| 3162 | author: ptaeuber FHB 2013-2015" | ||
| 3163 | extends TearingHeuristic; | ||
| 3164 | protected | ||
| 3165 | Integer edges; | ||
| 3166 | list<Integer> varlst,selectedcols1,selectedrows; | ||
| 3167 | algorithm | ||
| 3168 | // modified Cellier heuristic [MC21] | ||
| 3169 | |||
| 3170 | // 0. Consider only non-discrete Vars | ||
| 3171 | 2 | varlst := getUnassigned(ass1In); | |
| 3172 | 2 | (_,selectedcols1,_) := List.intersection1OnTrue(varlst,discreteVars,intEq); | |
| 3173 | |||
| 3174 | // 1. choose rows (vars) with most nonzero entries and write the indexes in a list | ||
| 3175 | 2 | (edges,selectedcols1) := getVarsOccurringInMostEquations(mtIn, selectedcols1); | |
| 3176 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3177 | ✗ | print("1st: "+ stringDelimitList(List.map(selectedcols1,intString),",")+"\n(Non-discrete variables with most occurrence in equations (" + intString(edges) +" times))\n\n"); | |
| 3178 | end if; | ||
| 3179 | |||
| 3180 | // 2. select the rows(eqs) from mIn which could be causalized by knowing one more Var | ||
| 3181 | 2 | selectedrows := traverseSingleEqnsforAssignable(ass2In,mIn,mapEqnIncRow,mapIncRowEqn); | |
| 3182 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3183 | ✗ | print(stringDelimitList(List.map(selectedrows,intString),",")+"\n(Equations which could be causalized by knowing one more Var)\n\n"); | |
| 3184 | end if; | ||
| 3185 | |||
| 3186 | // 3. determine which possible Vars causalize most equations considering impossible assignments and write them into potentials | ||
| 3187 | 2 | (potentials,_) := selectMostCausalizingVars(mtIn,selectedcols1, me=meIn,ass1In=ass1In,selEqsSetArray=selectCausalVarsPrepareSelectionSet(selectedrows, arrayLength(ass1In))); | |
| 3188 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3189 | ✗ | print("\n2nd: "+ stringDelimitList(List.map(potentials,intString),",")+"\n(Variables from (1st) causalizing most equations)\n\n"); | |
| 3190 | end if; | ||
| 3191 | |||
| 3192 | // 4. choose vars with the most impossible assignments | ||
| 3193 | 2 | (potentials,edges) := getOneVarWithMostImpAss(potentials,ass2In,metIn); | |
| 3194 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3195 | ✗ | print("\n3rd: "+ stringDelimitList(List.map(potentials,intString),",")+"\n(Chosen tearing variable. One from (2nd) with most incident impossible assignments [" + intString(edges) + "])\n\n"); | |
| 3196 | end if; | ||
| 3197 | end ModifiedCellierHeuristic_2_1; | ||
| 3198 | |||
| 3199 | |||
| 3200 | protected function ModifiedCellierHeuristic_1_2 " Heuristic to find a preferably good tearing variable [MC12]. | ||
| 3201 | author: ptaeuber FHB 2013-2015" | ||
| 3202 | extends TearingHeuristic; | ||
| 3203 | protected | ||
| 3204 | Integer edges; | ||
| 3205 | list<Integer> selectedcols1,selectedrows; | ||
| 3206 | algorithm | ||
| 3207 | // modified Cellier heuristic [MC12] | ||
| 3208 | |||
| 3209 | // 0. get all unassigned variables | ||
| 3210 | 2 | selectedcols1 := getUnassigned(ass1In); | |
| 3211 | |||
| 3212 | // 1. choose rows(eqs) with most nonzero entries and write the column indexes(vars) for nonzeros in a list | ||
| 3213 | 2 | selectedcols1 := getVarsOfEqnsWithMostVars(selectedcols1, mIn, mtIn); | |
| 3214 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3215 | ✗ | print("1st: " + stringDelimitList(List.map(selectedcols1,intString),",") + "\n"); | |
| 3216 | end if; | ||
| 3217 | |||
| 3218 | // Without discrete: | ||
| 3219 | 2 | (_,selectedcols1,_) := List.intersection1OnTrue(selectedcols1,discreteVars,intEq); | |
| 3220 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3221 | ✗ | print("Without Discrete: " + stringDelimitList(List.map(selectedcols1,intString),",") + "\n(Variables in the equation(s) with most Variables)\n\n"); | |
| 3222 | end if; | ||
| 3223 | |||
| 3224 | // 2. choose rows (vars) with most nonzero entries and write the indexes in a list | ||
| 3225 | 2 | (edges,selectedcols1) := getVarsOccurringInMostEquations(mtIn, selectedcols1); | |
| 3226 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3227 | ✗ | print("2nd: "+ stringDelimitList(List.map(selectedcols1,intString),",")+"\n(Variables from (1st) with most occurrence in equations (" + intString(edges) +" times))\n\n"); | |
| 3228 | end if; | ||
| 3229 | |||
| 3230 | // 3. choose vars with the most impossible assignments | ||
| 3231 | 2 | (selectedcols1,_,_) := getAllVarsWithMostImpAss(selectedcols1,ass2In,metIn); | |
| 3232 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3233 | ✗ | print("\n3rd: "+ stringDelimitList(List.map(selectedcols1,intString),",")+"\n(Variables from (2nd) with most incident impossible assignments)\n\n"); | |
| 3234 | end if; | ||
| 3235 | |||
| 3236 | // 4. select the rows(eqs) from mIn which could be causalized by knowing one more Var | ||
| 3237 | 2 | selectedrows := traverseSingleEqnsforAssignable(ass2In,mIn,mapEqnIncRow,mapIncRowEqn); | |
| 3238 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3239 | ✗ | print(stringDelimitList(List.map(selectedrows,intString),",")+"\n(Equations which could be causalized by knowing one more Var)\n\n"); | |
| 3240 | end if; | ||
| 3241 | |||
| 3242 | // 5. determine which possible Vars causalize most equations considering impossible assignments and write them into potentials | ||
| 3243 | 2 | (potentials,edges) := selectOneMostCausalizingVar(mtIn,selectedcols1, me=meIn,ass1In=ass1In,selEqsSetArray=selectCausalVarsPrepareSelectionSet(selectedrows, arrayLength(ass1In))); | |
| 3244 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3245 | ✗ | print("\n4th: "+ stringDelimitList(List.map(potentials,intString),",")+"\n(Chosen tearing variable.One from (3rd) causalizing most equations [" + intString(edges) + "])\n\n"); | |
| 3246 | end if; | ||
| 3247 | end ModifiedCellierHeuristic_1_2; | ||
| 3248 | |||
| 3249 | |||
| 3250 | protected function ModifiedCellierHeuristic_2_2 " Heuristic to find a preferably good tearing variable [MC22]. | ||
| 3251 | author: ptaeuber FHB 2013-2015" | ||
| 3252 | extends TearingHeuristic; | ||
| 3253 | protected | ||
| 3254 | Integer edges; | ||
| 3255 | list<Integer> varlst,selectedcols1,selectedrows; | ||
| 3256 | algorithm | ||
| 3257 | // modified Cellier heuristic [MC22] | ||
| 3258 | |||
| 3259 | // 0. Consider only non-discrete Vars | ||
| 3260 | ✗ | varlst := getUnassigned(ass1In); | |
| 3261 | ✗ | (_,selectedcols1,_) := List.intersection1OnTrue(varlst,discreteVars,intEq); | |
| 3262 | |||
| 3263 | // 1. choose rows (vars) with most nonzero entries and write the indexes in a list | ||
| 3264 | ✗ | (edges,selectedcols1) := getVarsOccurringInMostEquations(mtIn, selectedcols1); | |
| 3265 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3266 | ✗ | print("1st: "+ stringDelimitList(List.map(selectedcols1,intString),",")+"\n(Non-discrete variables with most occurrence in equations (" + intString(edges) +" times))\n\n"); | |
| 3267 | end if; | ||
| 3268 | |||
| 3269 | // 2. choose vars with the most impossible assignments | ||
| 3270 | ✗ | (selectedcols1,_,_) := getAllVarsWithMostImpAss(selectedcols1,ass2In,metIn); | |
| 3271 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3272 | ✗ | print("\n2nd: "+ stringDelimitList(List.map(selectedcols1,intString),",")+"\n(Variables from (1st) with most incident impossible assignments)\n\n"); | |
| 3273 | end if; | ||
| 3274 | |||
| 3275 | // 3. select the rows(eqs) from mIn which could be causalized by knowing one more Var | ||
| 3276 | ✗ | selectedrows := traverseSingleEqnsforAssignable(ass2In,mIn,mapEqnIncRow,mapIncRowEqn); | |
| 3277 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3278 | ✗ | print(stringDelimitList(List.map(selectedrows,intString),",")+"\n(Equations which could be causalized by knowing one more Var)\n\n"); | |
| 3279 | end if; | ||
| 3280 | |||
| 3281 | // 4. determine which possible Vars causalize most equations considering impossible assignments and write them into potentials | ||
| 3282 | ✗ | (potentials,edges) := selectOneMostCausalizingVar(mtIn,selectedcols1, me=meIn,ass1In=ass1In,selEqsSetArray=selectCausalVarsPrepareSelectionSet(selectedrows, arrayLength(ass1In))); | |
| 3283 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3284 | ✗ | print("\n3rd: "+ stringDelimitList(List.map(potentials,intString),",")+"\n(Chosen tearing variable. One from (2nd) causalizing most equations [" + intString(edges) + "])\n\n"); | |
| 3285 | end if; | ||
| 3286 | end ModifiedCellierHeuristic_2_2; | ||
| 3287 | |||
| 3288 | |||
| 3289 | protected function ModifiedCellierHeuristic_1_3 " Heuristic to find a preferably good tearing variable [MC13]. | ||
| 3290 | author: ptaeuber FHB 2013-2015" | ||
| 3291 | extends TearingHeuristic; | ||
| 3292 | protected | ||
| 3293 | Integer edges,maxPoints; | ||
| 3294 | list<Integer> selectedcols1,selectedrows,points,counts1,counts2; | ||
| 3295 | algorithm | ||
| 3296 | // Cellier heuristic [MC13] | ||
| 3297 | |||
| 3298 | // 0. get all unassigned variables | ||
| 3299 | ✗ | selectedcols1 := getUnassigned(ass1In); | |
| 3300 | |||
| 3301 | // 1. choose rows(eqs) with most nonzero entries and write the column indexes(vars) for nonzeros in a list | ||
| 3302 | ✗ | selectedcols1 := getVarsOfEqnsWithMostVars(selectedcols1, mIn, mtIn); | |
| 3303 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3304 | ✗ | print("1st: " + stringDelimitList(List.map(selectedcols1,intString),",") + "\n"); | |
| 3305 | end if; | ||
| 3306 | |||
| 3307 | // Without discrete: | ||
| 3308 | ✗ | (_,selectedcols1,_) := List.intersection1OnTrue(selectedcols1,discreteVars,intEq); | |
| 3309 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3310 | ✗ | print("Without Discrete: " + stringDelimitList(List.map(selectedcols1,intString),",") + "\n(Variables in the equation(s) with most Variables)\n\n"); | |
| 3311 | end if; | ||
| 3312 | |||
| 3313 | // 2. choose rows (vars) with most nonzero entries and write the indexes in a list | ||
| 3314 | ✗ | (edges,selectedcols1) := getVarsOccurringInMostEquations(mtIn, selectedcols1); | |
| 3315 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3316 | ✗ | print("2nd: "+ stringDelimitList(List.map(selectedcols1,intString),",")+"\n(Variables from (1st) with most occurrence in equations (" + intString(edges) +" times))\n\n"); | |
| 3317 | end if; | ||
| 3318 | |||
| 3319 | // 3. select the rows(eqs) from mIn which could be causalized by knowing one more Var | ||
| 3320 | ✗ | selectedrows := traverseSingleEqnsforAssignable(ass2In,mIn,mapEqnIncRow,mapIncRowEqn); | |
| 3321 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3322 | ✗ | print(stringDelimitList(List.map(selectedrows,intString),",")+"\n(Equations which could be causalized by knowing one more Var)\n\n"); | |
| 3323 | end if; | ||
| 3324 | |||
| 3325 | // 4. determine for each variable the number of equations it could causalize considering impossible assignments and save them in counts1 | ||
| 3326 | ✗ | (_,counts1) := selectMostCausalizingVars(mtIn,selectedcols1, me=meIn,ass1In=ass1In,selEqsSetArray=selectCausalVarsPrepareSelectionSet(selectedrows, arrayLength(ass1In))); | |
| 3327 | ✗ | counts1 := listReverse(counts1); | |
| 3328 | |||
| 3329 | // 5. determine for each variable the number of impossible assignments and save them in counts2 | ||
| 3330 | ✗ | (_,counts2,_) := getAllVarsWithMostImpAss(selectedcols1,ass2In,metIn); | |
| 3331 | |||
| 3332 | // 6. Calculate the sum of number of impossible assignments and causalizable equations for each variable and save them in points | ||
| 3333 | ✗ | points := List.threadMap(counts1,counts2,intAdd); | |
| 3334 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3335 | ✗ | print("\nPoints: "+ stringDelimitList(List.map(points,intString),",")+"\n(Sum of impossible assignments and causalizable equations)\n"); | |
| 3336 | end if; | ||
| 3337 | |||
| 3338 | // 7. Choose vars with most points as potentials (tearing variable) | ||
| 3339 | ✗ | (potentials, maxPoints) := getOneVarWithMostPoints(selectedcols1, points); | |
| 3340 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3341 | ✗ | print("\n3rd: "+ stringDelimitList(List.map(potentials,intString),",")+"\n(Chosen tearing variable. One from (2nd) with most points [" + intString(maxPoints) + "])\n\n"); | |
| 3342 | end if; | ||
| 3343 | end ModifiedCellierHeuristic_1_3; | ||
| 3344 | |||
| 3345 | |||
| 3346 | protected function ModifiedCellierHeuristic_2_3 " Heuristic to find a preferably good tearing variable [MC23]. | ||
| 3347 | author: ptaeuber FHB 2013-2015" | ||
| 3348 | extends TearingHeuristic; | ||
| 3349 | protected | ||
| 3350 | Integer edges,maxPoints; | ||
| 3351 | list<Integer> varlst,selectedcols1,selectedrows,points,counts1,counts2; | ||
| 3352 | algorithm | ||
| 3353 | // Cellier heuristic [MC23] | ||
| 3354 | |||
| 3355 | // 0. Consider only non-discrete Vars | ||
| 3356 | 2 | varlst := getUnassigned(ass1In); | |
| 3357 | 2 | (_,selectedcols1,_) := List.intersection1OnTrue(varlst,discreteVars,intEq); | |
| 3358 | |||
| 3359 | // 1. choose rows (vars) with most nonzero entries and write the indexes in a list | ||
| 3360 | 2 | (edges,selectedcols1) := getVarsOccurringInMostEquations(mtIn, selectedcols1); | |
| 3361 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3362 | ✗ | print("1st: "+ stringDelimitList(List.map(selectedcols1,intString),",")+"\n(Non-discrete variables with most occurrence in equations (" + intString(edges) +" times))\n\n"); | |
| 3363 | end if; | ||
| 3364 | |||
| 3365 | // 2. select the rows(eqs) from mIn which could be causalized by knowing one more Var | ||
| 3366 | 2 | selectedrows := traverseSingleEqnsforAssignable(ass2In,mIn,mapEqnIncRow,mapIncRowEqn); | |
| 3367 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3368 | ✗ | print(stringDelimitList(List.map(selectedrows,intString),",")+"\n(Equations which could be causalized by knowing one more Var)\n\n"); | |
| 3369 | end if; | ||
| 3370 | |||
| 3371 | // 3. determine for each variable the number of equations it could causalize considering impossible assignments and save them in counts1 | ||
| 3372 | 2 | (_,counts1) := selectMostCausalizingVars(mtIn,selectedcols1, me=meIn,ass1In=ass1In,selEqsSetArray=selectCausalVarsPrepareSelectionSet(selectedrows, arrayLength(ass1In))); | |
| 3373 | 2 | counts1 := listReverse(counts1); | |
| 3374 | |||
| 3375 | // 4. determine for each variable the number of impossible assignments and save them in counts2 | ||
| 3376 | 2 | (_,counts2,_) := getAllVarsWithMostImpAss(selectedcols1,ass2In,metIn); | |
| 3377 | |||
| 3378 | // 5. Calculate the sum of number of impossible assignments and causalizable equations for each variable and save them in points | ||
| 3379 | 2 | points := List.threadMap(counts1,counts2,intAdd); | |
| 3380 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3381 | ✗ | print("\nPoints: "+ stringDelimitList(List.map(points,intString),",")+"\n(Sum of impossible assignments and causalizable equations)\n"); | |
| 3382 | end if; | ||
| 3383 | |||
| 3384 | // 6. Choose vars with most points as potentials (tearing variable) | ||
| 3385 | 2 | (potentials, maxPoints) := getOneVarWithMostPoints(selectedcols1, points); | |
| 3386 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3387 | ✗ | print("\n2nd: "+ stringDelimitList(List.map(potentials,intString),",")+"\n(Chosen tearing variable. One from (1st) with most points [" + intString(maxPoints) + "])\n\n"); | |
| 3388 | end if; | ||
| 3389 | end ModifiedCellierHeuristic_2_3; | ||
| 3390 | |||
| 3391 | |||
| 3392 | protected function ModifiedCellierHeuristic_2_3_1 " Heuristic to find a preferably good tearing variable [MC231]. | ||
| 3393 | author: ptaeuber FHB 2013-2015" | ||
| 3394 | extends TearingHeuristic; | ||
| 3395 | protected | ||
| 3396 | Integer edges,potpoints1,potpoints2; | ||
| 3397 | list<Integer> varlst,selectedcols0,selectedcols1,selectedrows,potentials1,potentials2,counts1,counts2,points1,points2; | ||
| 3398 | algorithm | ||
| 3399 | // modified Cellier heuristic [MC231] | ||
| 3400 | |||
| 3401 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3402 | ✗ | print("Start round 1:\n==============\n\n"); | |
| 3403 | end if; | ||
| 3404 | |||
| 3405 | // 0. Consider only non-discrete Vars | ||
| 3406 | ✗ | varlst := getUnassigned(ass1In); | |
| 3407 | ✗ | (_,selectedcols0,_) := List.intersection1OnTrue(varlst,discreteVars,intEq); | |
| 3408 | |||
| 3409 | // 1. choose rows (vars) with most nonzero entries and write the indexes in a list | ||
| 3410 | ✗ | (edges,selectedcols1) := getVarsOccurringInMostEquations(mtIn, selectedcols0); | |
| 3411 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3412 | ✗ | print("1st: "+ stringDelimitList(List.map(selectedcols1,intString),",")+"\n(Non-discrete variables with most occurrence in equations (" + intString(edges) +" times))\n\n"); | |
| 3413 | end if; | ||
| 3414 | |||
| 3415 | // 2. select the rows(eqs) from mIn which could be causalized by knowing one more Var | ||
| 3416 | ✗ | selectedrows := traverseSingleEqnsforAssignable(ass2In,mIn,mapEqnIncRow,mapIncRowEqn); | |
| 3417 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3418 | ✗ | print(stringDelimitList(List.map(selectedrows,intString),",")+"\n(Equations which could be causalized by knowing one more Var)\n\n"); | |
| 3419 | end if; | ||
| 3420 | |||
| 3421 | // 3. determine for each variable the number of equations it could causalize considering impossible assignments and save them in counts1 | ||
| 3422 | ✗ | (_,counts1) := selectMostCausalizingVars(mtIn,selectedcols1, me=meIn,ass1In=ass1In,selEqsSetArray=selectCausalVarsPrepareSelectionSet(selectedrows, arrayLength(ass1In))); | |
| 3423 | ✗ | counts1 := listReverse(counts1); | |
| 3424 | |||
| 3425 | // 4. determine for each variable the number of impossible assignments and save them in counts2 | ||
| 3426 | ✗ | (_,counts2,_) := getAllVarsWithMostImpAss(selectedcols1,ass2In,metIn); | |
| 3427 | |||
| 3428 | // 5. Calculate the sum of number of impossible assignments and causalizable equations for each variable and save them in points1 | ||
| 3429 | ✗ | points1 := List.threadMap(counts1,counts2,intAdd); | |
| 3430 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3431 | ✗ | print("\nPoints: "+ stringDelimitList(List.map(points1,intString),",")+"\n(Sum of impossible assignments and causalizable equations)\n"); | |
| 3432 | end if; | ||
| 3433 | |||
| 3434 | // 6. Choose vars with most points as potentials (tearing variable) | ||
| 3435 | ✗ | (potentials1, potpoints1) := getOneVarWithMostPoints(selectedcols1, points1); | |
| 3436 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3437 | ✗ | print("\n2nd: "+ stringDelimitList(List.map(potentials1,intString),",")+"\n(Chosen tearing variable. One from (1st) with most points (" + intString(potpoints1) + " points))\n\n"); | |
| 3438 | end if; | ||
| 3439 | |||
| 3440 | // 7. choose non-discrete vars with edges-1 edges and write the indexes in a list | ||
| 3441 | ✗ | selectedcols1 := findNEntries(mtIn,selectedcols0, edges-1); | |
| 3442 | |||
| 3443 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3444 | ✗ | print("\nStart round 2:\n==============\n\n1st: "+ stringDelimitList(List.map(selectedcols1,intString),",")+"\n(Variables with occurrence in " + intString(edges-1) + " equations)\n\n" + stringDelimitList(List.map(selectedrows,intString),",")+"\n(Equations which could be causalized by knowing one more Var)\n\n"); | |
| 3445 | end if; | ||
| 3446 | ✗ | if listEmpty(selectedcols1) then | |
| 3447 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3448 | ✗ | print("Second set is empty."); | |
| 3449 | end if; | ||
| 3450 | potentials := potentials1; | ||
| 3451 | ✗ | potpoints2 := 0; | |
| 3452 | else | ||
| 3453 | // 9. determine for each variable the number of equations it could causalize considering impossible assignments and save them in counts1 | ||
| 3454 | ✗ | (_,counts1) := selectMostCausalizingVars(mtIn,selectedcols1, me=meIn,ass1In=ass1In,selEqsSetArray=selectCausalVarsPrepareSelectionSet(selectedrows, arrayLength(ass1In))); | |
| 3455 | ✗ | counts1 := listReverse(counts1); | |
| 3456 | |||
| 3457 | // 10. determine for each variable the number of impossible assignments and save them in counts2 | ||
| 3458 | ✗ | (_,counts2,_) := getAllVarsWithMostImpAss(selectedcols1,ass2In,metIn); | |
| 3459 | |||
| 3460 | // 11. Calculate the sum of number of impossible assignments and causalizable equations for each variable and save them in points2 | ||
| 3461 | ✗ | points2 := List.threadMap(counts1,counts2,intAdd); | |
| 3462 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3463 | ✗ | print("\nPoints: "+ stringDelimitList(List.map(points2,intString),",")+"\n(Sum of impossible assignments and causalizable equations)\n"); | |
| 3464 | end if; | ||
| 3465 | |||
| 3466 | // 12. Choose vars with most points as potentials (tearing variable) | ||
| 3467 | ✗ | (potentials2, potpoints2) := getOneVarWithMostPoints(selectedcols1, points2); | |
| 3468 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3469 | ✗ | print("\n2nd: "+ stringDelimitList(List.map(potentials2,intString),",")+"\n(Chosen tearing variable. One from (1st) with most points (" + intString(potpoints2) + " points))\n\n"); | |
| 3470 | end if; | ||
| 3471 | |||
| 3472 | // 13. choose potentials-set with most points | ||
| 3473 | ✗ | potentials := if intGe(potpoints1,potpoints2) then potentials1 else potentials2; | |
| 3474 | end if; | ||
| 3475 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3476 | ✗ | print("\n=====================\nChosen tearing variable: " + stringDelimitList(List.map(potentials,intString),",") + "\n=====================\n(from round 1: " + boolString(intGe(potpoints1,potpoints2)) + ")\n\n"); | |
| 3477 | end if; | ||
| 3478 | end ModifiedCellierHeuristic_2_3_1; | ||
| 3479 | |||
| 3480 | |||
| 3481 | protected function ModifiedCellierHeuristic_3 " Heuristic to find a preferably good tearing variable [MC3]. | ||
| 3482 | author: ptaeuber FHB 2013-2015" | ||
| 3483 | extends TearingHeuristic; | ||
| 3484 | protected | ||
| 3485 | Integer edges,maxPoints; | ||
| 3486 | list<Integer> potentialTVars,potentialTVars2,bestPotentialTVars,causEq,points,counts1,counts2; | ||
| 3487 | constant Boolean debug = false; | ||
| 3488 | algorithm | ||
| 3489 | // Cellier heuristic [MC3] | ||
| 3490 | if debug then execStat("TEARINGHEURISTIC0"); end if; | ||
| 3491 | |||
| 3492 | // 1. Determine the equations with size(equation)+1 variables and save them in causEq | ||
| 3493 | // ********************************************************************************** | ||
| 3494 | 3162 | causEq := traverseSingleEqnsforAssignable(ass2In,mIn,mapEqnIncRow,mapIncRowEqn); | |
| 3495 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3162 times.
|
3162 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3496 | ✗ | print("1st: "+ stringDelimitList(List.map(causEq,intString),",")+"\n(Equations which could be causalized by knowing one more variable)\n\n"); | |
| 3497 | end if; | ||
| 3498 | if debug then execStat("TEARINGHEURISTIC1"); end if; | ||
| 3499 | |||
| 3500 | // 2. Get all unassigned variables as a first selection of potential tearing variables | ||
| 3501 | // *********************************************************************************** | ||
| 3502 | 3162 | potentialTVars := getUnassigned(ass1In); | |
| 3503 | |||
| 3504 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3162 times.
|
3162 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3505 | ✗ | print("2nd: "+ stringDelimitList(List.map(potentialTVars,intString),",")+"\n(All unassigned variables)\n\n"); | |
| 3506 | end if; | ||
| 3507 | if debug then execStat("TEARINGHEURISTIC2"); end if; | ||
| 3508 | |||
| 3509 | // 3. Remove variables we don't want as tearing variables | ||
| 3510 | // ****************************************************** | ||
| 3511 | // Remove variables with attribute '__OpenModelica_tearingSelect = TearingSelect.never' | ||
| 3512 | 3162 | (_,potentialTVars,_) := List.intersection1OnTrue(potentialTVars,tSel_never,intEq); | |
| 3513 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3160 times.
|
3162 | if listEmpty(potentialTVars) then |
| 3514 | 2 | Error.addCompilerError("It is not possible to select a new tearing variable, because all remaining variables have the attribute '__OpenModelica_tearingSelect = TearingSelect.never'."); | |
| 3515 | 2 | return; | |
| 3516 | end if; | ||
| 3517 | |||
| 3518 | // Remove discrete variables | ||
| 3519 | 3160 | (_,potentialTVars2,_) := List.intersection1OnTrue(potentialTVars,discreteVars,intEq); | |
| 3520 | |||
| 3521 | // Only discrete potentials, then allow discrete tearing variables | ||
| 3522 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3158 times.
|
3160 | if listEmpty(potentialTVars2) then |
| 3523 | 2 | potentialTVars2 := potentialTVars; | |
| 3524 | 2 | Error.addCompilerWarning("The tearing heuristic was not able to avoid discrete iteration variables because otherwise the system could not have been torn. This may lead to problems during simulation."); | |
| 3525 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3526 | ✗ | print("3rd: "+ stringDelimitList(List.map(potentialTVars2,intString),",")+"\n(All unassigned variables without attribute 'never' (only discrete variables left))\n\n"); | |
| 3527 | end if; | ||
| 3528 | else | ||
| 3529 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3158 times.
|
3158 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3530 | ✗ | print("3rd: "+ stringDelimitList(List.map(potentialTVars2,intString),",")+"\n(All non-discrete variables from (2nd) without attribute 'never')\n\n"); | |
| 3531 | end if; | ||
| 3532 | end if; | ||
| 3533 | if debug then execStat("TEARINGHEURISTIC3"); end if; | ||
| 3534 | |||
| 3535 | // 4. Assess the potential tearing variables | ||
| 3536 | // ***************************************** | ||
| 3537 | // 4.1 Determine for each variable the number of equations it could causalize considering impossible assignments and save them in counts1 | ||
| 3538 | 3160 | (potentialTVars,counts1) := selectCausalizingVars(mtIn,potentialTVars2, me=meIn,ass1In=ass1In,selEqsSetArray=selectCausalVarsPrepareSelectionSet(causEq, arrayLength(ass1In))); | |
| 3539 | |||
| 3540 | // If none of the variables is able to causalize an equation in the next step, use the previous selection | ||
| 3541 |
2/2✓ Branch 0 taken 178 times.
✓ Branch 1 taken 2982 times.
|
3160 | if listEmpty(potentialTVars) then |
| 3542 | 178 | potentialTVars := potentialTVars2; | |
| 3543 | 178 | counts1 := List.fill(0, listLength(potentialTVars2)); | |
| 3544 | end if; | ||
| 3545 | if debug then execStat("TEARINGHEURISTIC4_1"); end if; | ||
| 3546 | |||
| 3547 | // 4.2 Determine for each variable the number of impossible assignments and save them in counts2 | ||
| 3548 | 3160 | (_,counts2,_) := getAllVarsWithMostImpAss(potentialTVars,ass2In,metIn); | |
| 3549 | if debug then execStat("TEARINGHEURISTIC4_2"); end if; | ||
| 3550 | |||
| 3551 | // 4.3 Calculate the sum of number of impossible assignments and causalizable equations for each variable and save them in points | ||
| 3552 | 3160 | points := List.threadMap(counts1,counts2,intAdd); | |
| 3553 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3160 times.
|
3160 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3554 | ✗ | print("\n4th (Points): "+ stringDelimitList(List.map(listReverse(points),intString),",")+"\n(Sum of impossible assignments and causalizable equations)\n"); | |
| 3555 | end if; | ||
| 3556 | if debug then execStat("TEARINGHEURISTIC4_3"); end if; | ||
| 3557 | |||
| 3558 | // 4.4 Prefer variables with annotation attribute '__OpenModelica_tearingSelect = TearingSelect.prefer' | ||
| 3559 |
2/2✓ Branch 0 taken 1522 times.
✓ Branch 1 taken 1638 times.
|
3160 | if not listEmpty(tSel_prefer) then |
| 3560 | 1522 | points := preferAvoidVariables(potentialTVars, points, tSel_prefer, 3.0); | |
| 3561 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1522 times.
|
1522 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3562 | ✗ | print(" (Points): "+ stringDelimitList(List.map(points,intString),",")+"\n(Points after preferring variables with attribute 'prefer')\n"); | |
| 3563 | end if; | ||
| 3564 | end if; | ||
| 3565 | if debug then execStat("TEARINGHEURISTIC4_4"); end if; | ||
| 3566 | |||
| 3567 | // 4.5 Avoid variables with annotation attribute '__OpenModelica_tearingSelect = TearingSelect.avoid' | ||
| 3568 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 3155 times.
|
3160 | if not listEmpty(tSel_avoid) then |
| 3569 | 5 | points := preferAvoidVariables(potentialTVars, points, tSel_avoid, 0.334); | |
| 3570 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
|
5 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3571 | ✗ | print(" (Points): "+ stringDelimitList(List.map(points,intString),",")+"\n(Points after discrimination against variables with attribute 'avoid')\n"); | |
| 3572 | end if; | ||
| 3573 | end if; | ||
| 3574 | if debug then execStat("TEARINGHEURISTIC4_5"); end if; | ||
| 3575 | |||
| 3576 | // 5. Choose vars with most points and save them in bestPotentialTVars | ||
| 3577 | // ******************************************************************* | ||
| 3578 | 3160 | (bestPotentialTVars, maxPoints) := getAllVarsWithMostPoints(potentialTVars, points); | |
| 3579 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3160 times.
|
3160 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3580 | ✗ | print("\n5th: "+ stringDelimitList(List.map(bestPotentialTVars,intString),",")+"\n(Variables from (3rd) with most points [" + intString(maxPoints) + "])\n\n"); | |
| 3581 | end if; | ||
| 3582 | if debug then execStat("TEARINGHEURISTIC5"); end if; | ||
| 3583 | |||
| 3584 | // 6. Choose one var with most occurrence in equations as potentials (tearing variable) | ||
| 3585 | // ************************************************************************************ | ||
| 3586 | 3160 | (edges,potentials) := getVarOccurringInMostEquations(mtIn,bestPotentialTVars); | |
| 3587 |
1/2✓ Branch 1 taken 3160 times.
✗ Branch 2 not taken.
|
3160 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3588 | ✗ | print("6th: "+ stringDelimitList(List.map(potentials,intString),",")+"\n(Chosen tearing variable. One from (5th) with most occurrence in equations (" + intString(edges) +" times))\n\n"); | |
| 3589 | end if; | ||
| 3590 | if debug then execStat("TEARINGHEURISTIC6"); end if; | ||
| 3591 | end ModifiedCellierHeuristic_3; | ||
| 3592 | |||
| 3593 | |||
| 3594 | protected function ModifiedCellierHeuristic_4 " Heuristic to find a preferably good tearing variable [MC4]. | ||
| 3595 | author: ptaeuber FHB 2013-2015" | ||
| 3596 | extends TearingHeuristic; | ||
| 3597 | protected | ||
| 3598 | Integer edges; | ||
| 3599 | list<Integer> potentials1,potentials2,potentials3,potentials4,potentials5,potentials6,potentials7,potentials8,potentials9,potentials10,selectedvars,count; | ||
| 3600 | algorithm | ||
| 3601 | // Cellier heuristic [MC4] | ||
| 3602 | |||
| 3603 | // 1. Use heuristics MC1, MC2, MC11, MC21, MC12, MC22, MC13, MC23, MC231, MC3 to determine their potential sets | ||
| 3604 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3605 | ✗ | print("Heuristic uses all modified Cellier-Heuristics\n\nHeuristic [MC1]\n"+ BORDER +"\n"); | |
| 3606 | end if; | ||
| 3607 | ✗ | potentials1 := ModifiedCellierHeuristic_1(mIn,mtIn,meIn,metIn,ass1In,ass2In,discreteVars,tSel_prefer,tSel_avoid,tSel_never,mapEqnIncRow,mapIncRowEqn); | |
| 3608 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3609 | ✗ | print("\n\nHeuristic [MC2]\n"+ BORDER +"\n"); | |
| 3610 | end if; | ||
| 3611 | ✗ | potentials2 := ModifiedCellierHeuristic_2(mIn,mtIn,meIn,metIn,ass1In,ass2In,discreteVars,tSel_prefer,tSel_avoid,tSel_never,mapEqnIncRow,mapIncRowEqn); | |
| 3612 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3613 | ✗ | print("\n\nHeuristic [MC11]\n"+ BORDER +"\n"); | |
| 3614 | end if; | ||
| 3615 | ✗ | potentials3 := ModifiedCellierHeuristic_1_1(mIn,mtIn,meIn,metIn,ass1In,ass2In,discreteVars,tSel_prefer,tSel_avoid,tSel_never,mapEqnIncRow,mapIncRowEqn); | |
| 3616 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3617 | ✗ | print("\n\nHeuristic [MC21]\n"+ BORDER +"\n"); | |
| 3618 | end if; | ||
| 3619 | ✗ | potentials4 := ModifiedCellierHeuristic_2_1(mIn,mtIn,meIn,metIn,ass1In,ass2In,discreteVars,tSel_prefer,tSel_avoid,tSel_never,mapEqnIncRow,mapIncRowEqn); | |
| 3620 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3621 | ✗ | print("\n\nHeuristic [MC12]\n"+ BORDER +"\n"); | |
| 3622 | end if; | ||
| 3623 | ✗ | potentials5 := ModifiedCellierHeuristic_1_2(mIn,mtIn,meIn,metIn,ass1In,ass2In,discreteVars,tSel_prefer,tSel_avoid,tSel_never,mapEqnIncRow,mapIncRowEqn); | |
| 3624 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3625 | ✗ | print("\n\nHeuristic [MC22]\n"+ BORDER +"\n"); | |
| 3626 | end if; | ||
| 3627 | ✗ | potentials6 := ModifiedCellierHeuristic_2_2(mIn,mtIn,meIn,metIn,ass1In,ass2In,discreteVars,tSel_prefer,tSel_avoid,tSel_never,mapEqnIncRow,mapIncRowEqn); | |
| 3628 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3629 | ✗ | print("\n\nHeuristic [MC13]\n"+ BORDER +"\n"); | |
| 3630 | end if; | ||
| 3631 | ✗ | potentials7 := ModifiedCellierHeuristic_1_3(mIn,mtIn,meIn,metIn,ass1In,ass2In,discreteVars,tSel_prefer,tSel_avoid,tSel_never,mapEqnIncRow,mapIncRowEqn); | |
| 3632 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3633 | ✗ | print("\n\nHeuristic [MC23]\n"+ BORDER +"\n"); | |
| 3634 | end if; | ||
| 3635 | ✗ | potentials8 := ModifiedCellierHeuristic_2_3(mIn,mtIn,meIn,metIn,ass1In,ass2In,discreteVars,tSel_prefer,tSel_avoid,tSel_never,mapEqnIncRow,mapIncRowEqn); | |
| 3636 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3637 | ✗ | print("\n\nHeuristic [MC231]\n"+ BORDER +"\n"); | |
| 3638 | end if; | ||
| 3639 | ✗ | potentials9 := ModifiedCellierHeuristic_2_3_1(mIn,mtIn,meIn,metIn,ass1In,ass2In,discreteVars,tSel_prefer,tSel_avoid,tSel_never,mapEqnIncRow,mapIncRowEqn); | |
| 3640 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3641 | ✗ | print("\n\nHeuristic [MC3]\n"+ BORDER +"\n"); | |
| 3642 | end if; | ||
| 3643 | ✗ | potentials10 := ModifiedCellierHeuristic_3(mIn,mtIn,meIn,metIn,ass1In,ass2In,discreteVars,tSel_prefer,tSel_avoid,tSel_never,mapEqnIncRow,mapIncRowEqn); | |
| 3644 | ✗ | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3645 | ✗ | print(BORDER + "\n\nSynopsis:\n=========\n[MC1]: " + stringDelimitList(List.map(potentials1,intString),",")+"\n"); | |
| 3646 | ✗ | print("[MC2]: " + stringDelimitList(List.map(potentials2,intString),",")+"\n"); | |
| 3647 | ✗ | print("[MC11]: " + stringDelimitList(List.map(potentials3,intString),",")+"\n"); | |
| 3648 | ✗ | print("[MC21]: " + stringDelimitList(List.map(potentials4,intString),",")+"\n"); | |
| 3649 | ✗ | print("[MC12]: " + stringDelimitList(List.map(potentials5,intString),",")+"\n"); | |
| 3650 | ✗ | print("[MC22]: " + stringDelimitList(List.map(potentials6,intString),",")+"\n"); | |
| 3651 | ✗ | print("[MC13]: " + stringDelimitList(List.map(potentials7,intString),",")+"\n"); | |
| 3652 | ✗ | print("[MC23]: " + stringDelimitList(List.map(potentials8,intString),",")+"\n"); | |
| 3653 | ✗ | print("[MC231]: " + stringDelimitList(List.map(potentials9,intString),",")+"\n"); | |
| 3654 | ✗ | print("[MC3]: " + stringDelimitList(List.map(potentials10,intString),",")+"\n\n"); | |
| 3655 | end if; | ||
| 3656 | |||
| 3657 | // 2. Collect all variables from different potential-sets in one list | ||
| 3658 | ✗ | selectedvars := listAppend(potentials1,listAppend(potentials2,listAppend(potentials3,listAppend(potentials4,listAppend(potentials5,listAppend(potentials6,listAppend(potentials7,listAppend(potentials8,listAppend(potentials9,potentials10))))))))); | |
| 3659 | ✗ | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3660 | ✗ | print("1st: "+ stringDelimitList(List.map(selectedvars,intString),",")+"\n(All potentials)\n\n"); | |
| 3661 | end if; | ||
| 3662 | |||
| 3663 | // 3. determine potentials with most occurrence in potential sets | ||
| 3664 | ✗ | (count,selectedvars,_) := countMultiples(arrayCreate(1,selectedvars)); | |
| 3665 | ✗ | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3666 | ✗ | print("2nd: "+ stringDelimitList(List.map(selectedvars,intString),",")+"\n(Variables from (1st) occurring in most potential-sets (" + stringDelimitList(List.map(count,intString),",") + " sets))\n\n"); | |
| 3667 | end if; | ||
| 3668 | |||
| 3669 | // 4. Choose vars with most occurrence in equations as potentials | ||
| 3670 | ✗ | (edges,potentials) := getVarOccurringInMostEquations(mtIn, selectedvars); | |
| 3671 | |||
| 3672 | ✗ | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 3673 | ✗ | print("3rd: "+ stringDelimitList(List.map(potentials,intString),",")+"\n(Chosen tearing variable. One from from (2nd) with most occurrence in equations (" + intString(edges) +" times))\n\n\n"); | |
| 3674 | end if; | ||
| 3675 | end ModifiedCellierHeuristic_4; | ||
| 3676 | |||
| 3677 | |||
| 3678 | protected function preferAvoidVariables | ||
| 3679 | "multiplies points of variables with annotation attribute '__OpenModelica_tearingSelect in [prefer, avoid]' with factor | ||
| 3680 | author: ptaeuber FHB 2014-05" | ||
| 3681 | input list<Integer> varsIn; | ||
| 3682 | input output list<Integer> points; | ||
| 3683 | input list<Integer> preferAvoidIn; | ||
| 3684 | input Real factor; | ||
| 3685 | protected | ||
| 3686 | array<Integer> pointsArr, firstPos "1-based position of each variable in varsIn"; | ||
| 3687 | Integer pos, maxVar; | ||
| 3688 | algorithm | ||
| 3689 |
2/2✓ Branch 0 taken 78 times.
✓ Branch 1 taken 1537 times.
|
1615 | if listEmpty(preferAvoidIn) then |
| 3690 | 78 | return; | |
| 3691 | end if; | ||
| 3692 | 1537 | maxVar := List.fold(varsIn, intMax, 0); | |
| 3693 | 1537 | firstPos := arrayCreate(maxVar, 0); | |
| 3694 | pos := 1; | ||
| 3695 |
2/2✓ Branch 0 taken 126502 times.
✓ Branch 1 taken 1537 times.
|
128039 | for v in varsIn loop |
| 3696 |
2/4✓ Branch 0 taken 126502 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 126502 times.
✗ Branch 4 not taken.
|
126502 | if v > 0 and firstPos[v] == 0 then |
| 3697 | 126502 | firstPos[v] := pos; | |
| 3698 | end if; | ||
| 3699 | 126502 | pos := pos + 1; | |
| 3700 | end for; | ||
| 3701 | 1537 | pointsArr := listArray(points); | |
| 3702 |
2/2✓ Branch 0 taken 128852 times.
✓ Branch 1 taken 1537 times.
|
130389 | for preferAvoidVar in preferAvoidIn loop |
| 3703 |
3/4✓ Branch 0 taken 128852 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 121586 times.
✓ Branch 3 taken 7266 times.
|
128852 | if preferAvoidVar > 0 and preferAvoidVar <= maxVar then |
| 3704 | 121586 | pos := firstPos[preferAvoidVar]; | |
| 3705 | else | ||
| 3706 | try | ||
| 3707 | 7266 | pos := List.position(preferAvoidVar, varsIn); | |
| 3708 | else | ||
| 3709 | pos := 0; | ||
| 3710 | end try; | ||
| 3711 | end if; | ||
| 3712 |
3/4✓ Branch 0 taken 41347 times.
✓ Branch 1 taken 87505 times.
✓ Branch 2 taken 41347 times.
✗ Branch 3 not taken.
|
170199 | if pos > 0 and pos <= arrayLength(pointsArr) then |
| 3713 | 41347 | pointsArr[pos] := realInt(realMul(factor, intReal(pointsArr[pos]))); | |
| 3714 | end if; | ||
| 3715 | end for; | ||
| 3716 | 1537 | points := arrayList(pointsArr); | |
| 3717 | end preferAvoidVariables; | ||
| 3718 | |||
| 3719 | |||
| 3720 | protected function selectCausalVarsPrepareSelectionSet | ||
| 3721 | "selectMostCausalizingVars takes as input an array ass1In. selEqs and each row | ||
| 3722 | has indexes into ass1In and we need to intersect selEqs with each row. | ||
| 3723 | This prepares a set by making an array of all possible indexes and | ||
| 3724 | marking the ones that exist in selEqs." | ||
| 3725 | input list<Integer> selEqs; | ||
| 3726 | input Integer ass1In_size; | ||
| 3727 | output array<Boolean> selEqsSetArray; | ||
| 3728 | algorithm | ||
| 3729 | 3312 | selEqsSetArray := arrayCreate(ass1In_size, false); | |
| 3730 |
2/2✓ Branch 1 taken 136302 times.
✓ Branch 2 taken 3312 times.
|
139614 | for e in selEqs loop |
| 3731 | 136302 | arrayUpdate(selEqsSetArray, e, true); | |
| 3732 | end for; | ||
| 3733 | end selectCausalVarsPrepareSelectionSet; | ||
| 3734 | |||
| 3735 | |||
| 3736 | protected function selectMostCausalizingVars | ||
| 3737 | " determines the variables causalizing the most equations in the next step. | ||
| 3738 | author: ptaeuber FHB 2013-2015" | ||
| 3739 | input BackendDAE.AdjacencyMatrix inMt; | ||
| 3740 | input list<Integer> selVars; | ||
| 3741 | input BackendDAE.AdjacencyMatrixEnhanced me; | ||
| 3742 | input array<Integer> ass1In; | ||
| 3743 | input array<Boolean> selEqsSetArray; | ||
| 3744 | output list<Integer> cVars = {}; | ||
| 3745 | output list<Integer> counts = {}; | ||
| 3746 | protected | ||
| 3747 | list<Integer> row; | ||
| 3748 | Integer size,num = 0; | ||
| 3749 | algorithm | ||
| 3750 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 4 times.
|
24 | for var in selVars loop |
| 3751 | 20 | row := arrayGet(inMt, var); | |
| 3752 | 20 | arrayUpdate(ass1In,var,1); | |
| 3753 | size := 0; | ||
| 3754 |
2/2✓ Branch 0 taken 60 times.
✓ Branch 1 taken 20 times.
|
80 | for i in row loop |
| 3755 |
2/2✓ Branch 1 taken 28 times.
✓ Branch 2 taken 32 times.
|
60 | if arrayGet(selEqsSetArray,i) then |
| 3756 | 28 | size := sizeOfAssignable(i,me,ass1In,size); | |
| 3757 | end if; | ||
| 3758 | end for; | ||
| 3759 | 20 | arrayUpdate(ass1In,var,-1); | |
| 3760 | |||
| 3761 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 12 times.
|
20 | if size < num then |
| 3762 | counts := size::counts; | ||
| 3763 | elseif size == num then | ||
| 3764 | cVars := var::cVars; | ||
| 3765 | counts := size::counts; | ||
| 3766 | else | ||
| 3767 | cVars := {var}; | ||
| 3768 | num := size; | ||
| 3769 | counts := size::counts; | ||
| 3770 | end if; | ||
| 3771 | |||
| 3772 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
|
20 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3773 | ✗ | print("Var " + intString(var) + " would causalize " + intString(size) + " Eqns\n"); | |
| 3774 | end if; | ||
| 3775 | end for; | ||
| 3776 | end selectMostCausalizingVars; | ||
| 3777 | |||
| 3778 | |||
| 3779 | protected function selectCausalizingVars | ||
| 3780 | " returns the variables causalizing at least one equation in the next step and the counts in a second list. | ||
| 3781 | author: ptaeuber" | ||
| 3782 | input BackendDAE.AdjacencyMatrix inMt; | ||
| 3783 | input list<Integer> selVars; | ||
| 3784 | input BackendDAE.AdjacencyMatrixEnhanced me; | ||
| 3785 | input array<Integer> ass1In; | ||
| 3786 | input array<Boolean> selEqsSetArray; | ||
| 3787 | output list<Integer> cVars = {}; | ||
| 3788 | output list<Integer> counts = {}; | ||
| 3789 | protected | ||
| 3790 | list<Integer> row; | ||
| 3791 | Integer size; | ||
| 3792 | algorithm | ||
| 3793 |
2/2✓ Branch 0 taken 335383 times.
✓ Branch 1 taken 3160 times.
|
338543 | for var in selVars loop |
| 3794 | 335383 | row := arrayGet(inMt, var); | |
| 3795 | 335383 | arrayUpdate(ass1In,var,1); | |
| 3796 | size := 0; | ||
| 3797 |
2/2✓ Branch 0 taken 1194532 times.
✓ Branch 1 taken 335383 times.
|
1529915 | for i in row loop |
| 3798 |
2/2✓ Branch 1 taken 240603 times.
✓ Branch 2 taken 953929 times.
|
1194532 | if arrayGet(selEqsSetArray,i) then |
| 3799 | 240603 | size := sizeOfAssignable(i,me,ass1In,size); | |
| 3800 | end if; | ||
| 3801 | end for; | ||
| 3802 | 335383 | arrayUpdate(ass1In,var,-1); | |
| 3803 | |||
| 3804 |
2/2✓ Branch 0 taken 142222 times.
✓ Branch 1 taken 193161 times.
|
335383 | if not size == 0 then |
| 3805 | cVars := var::cVars; | ||
| 3806 | counts := size::counts; | ||
| 3807 | end if; | ||
| 3808 | |||
| 3809 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 335383 times.
|
335383 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3810 | ✗ | print("Var " + intString(var) + " would causalize " + intString(size) + " Eqns\n"); | |
| 3811 | end if; | ||
| 3812 | end for; | ||
| 3813 | end selectCausalizingVars; | ||
| 3814 | |||
| 3815 | |||
| 3816 | protected function selectOneMostCausalizingVar | ||
| 3817 | " determines one variable causalizing the most equations in the next step. | ||
| 3818 | author: ptaeuber" | ||
| 3819 | input BackendDAE.AdjacencyMatrix inMt; | ||
| 3820 | input list<Integer> selVars; | ||
| 3821 | input BackendDAE.AdjacencyMatrixEnhanced me; | ||
| 3822 | input array<Integer> ass1In; | ||
| 3823 | input array<Boolean> selEqsSetArray; | ||
| 3824 | output list<Integer> cVars = {}; | ||
| 3825 | output Integer outMax = 0; | ||
| 3826 | protected | ||
| 3827 | list<Integer> row; | ||
| 3828 | Integer size; | ||
| 3829 | algorithm | ||
| 3830 |
2/2✓ Branch 0 taken 3351 times.
✓ Branch 1 taken 148 times.
|
3499 | for var in selVars loop |
| 3831 | 3351 | row := arrayGet(inMt, var); | |
| 3832 | 3351 | arrayUpdate(ass1In,var,1); | |
| 3833 | size := 0; | ||
| 3834 |
2/2✓ Branch 0 taken 29643 times.
✓ Branch 1 taken 3351 times.
|
32994 | for i in row loop |
| 3835 |
2/2✓ Branch 1 taken 162 times.
✓ Branch 2 taken 29481 times.
|
29643 | if arrayGet(selEqsSetArray,i) then |
| 3836 | 162 | size := sizeOfAssignable(i,me,ass1In,size); | |
| 3837 | end if; | ||
| 3838 | end for; | ||
| 3839 | 3351 | arrayUpdate(ass1In,var,-1); | |
| 3840 | |||
| 3841 |
2/2✓ Branch 0 taken 3029 times.
✓ Branch 1 taken 322 times.
|
3351 | if intGe(size,outMax) then |
| 3842 | cVars := {var}; | ||
| 3843 | outMax := size; | ||
| 3844 | end if; | ||
| 3845 | |||
| 3846 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3351 times.
|
3351 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3847 | ✗ | print("Var " + intString(var) + " would causalize " + intString(size) + " Eqns\n"); | |
| 3848 | end if; | ||
| 3849 | end for; | ||
| 3850 | end selectOneMostCausalizingVar; | ||
| 3851 | |||
| 3852 | |||
| 3853 | protected function getOneVarWithMostPoints | ||
| 3854 | "function to find a variable from inVarList with most points in corresponding inPointsLst. | ||
| 3855 | author: ptaeuber" | ||
| 3856 | input list<Integer> inVarList; | ||
| 3857 | input list<Integer> inPointsLst; | ||
| 3858 | output list<Integer> outVarList={}; | ||
| 3859 | output Integer outMax; | ||
| 3860 | protected | ||
| 3861 | Integer index=1; | ||
| 3862 | algorithm | ||
| 3863 |
4/4✓ Branch 0 taken 10 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 10 times.
✓ Branch 3 taken 2 times.
|
12 | outMax := max(i for i in inPointsLst); |
| 3864 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | for i in inPointsLst loop |
| 3865 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | if i==outMax then |
| 3866 | 2 | outVarList := {listGet(inVarList,index)}; | |
| 3867 | 2 | return; | |
| 3868 | end if; | ||
| 3869 | 2 | index := index+1; | |
| 3870 | end for; | ||
| 3871 | end getOneVarWithMostPoints; | ||
| 3872 | |||
| 3873 | |||
| 3874 | protected function getAllVarsWithMostPoints | ||
| 3875 | "function to find all variables from inVarList with most points in corresponding inPointsLst. | ||
| 3876 | author: ptaeuber" | ||
| 3877 | input list<Integer> inVarList; | ||
| 3878 | input list<Integer> inPointsLst; | ||
| 3879 | input output list<Integer> outVarList={}; | ||
| 3880 | input output Integer outMax=-1; | ||
| 3881 | algorithm | ||
| 3882 | () := match(inVarList, inPointsLst) | ||
| 3883 | local | ||
| 3884 | Integer p,v; | ||
| 3885 | list<Integer> prest,vrest; | ||
| 3886 | case(v::{}, p::{}) | ||
| 3887 | algorithm | ||
| 3888 |
2/2✓ Branch 0 taken 345 times.
✓ Branch 1 taken 2815 times.
|
3160 | if intGt(p, outMax) then |
| 3889 | 345 | outMax := p; | |
| 3890 | outVarList := {v}; | ||
| 3891 | elseif intEq(p, outMax) then | ||
| 3892 | outVarList := v::outVarList; | ||
| 3893 | end if; | ||
| 3894 | then (); | ||
| 3895 | case(v::vrest, p::prest) | ||
| 3896 | algorithm | ||
| 3897 |
2/2✓ Branch 0 taken 6588 times.
✓ Branch 1 taken 133821 times.
|
140409 | if intGt(p, outMax) then |
| 3898 | 6588 | outMax := p; | |
| 3899 | outVarList := {v}; | ||
| 3900 | elseif intEq(p, outMax) then | ||
| 3901 | outVarList := v::outVarList; | ||
| 3902 | end if; | ||
| 3903 | 140409 | (outVarList, outMax) := getAllVarsWithMostPoints(vrest, prest, outVarList, outMax); | |
| 3904 | then (); | ||
| 3905 | else | ||
| 3906 | algorithm | ||
| 3907 | ✗ | Error.addCompilerError("Tearing.getAllVarsWithMostPoints: Finding variables with most points failed."); | |
| 3908 | ✗ | fail(); | |
| 3909 | then (); | ||
| 3910 | end match; | ||
| 3911 | end getAllVarsWithMostPoints; | ||
| 3912 | |||
| 3913 | |||
| 3914 | protected function sizeOfAssignable | ||
| 3915 | " calculates the number of equations a potential tvar would | ||
| 3916 | causalize considering the impossible assignments | ||
| 3917 | author: ptaeuber FHB 2013-10" | ||
| 3918 | input Integer Eqn; | ||
| 3919 | input BackendDAE.AdjacencyMatrixEnhanced me; | ||
| 3920 | input array<Integer> ass1; | ||
| 3921 | input Integer inSize; | ||
| 3922 | output Integer outSize; | ||
| 3923 | protected | ||
| 3924 | BackendDAE.AdjacencyMatrixElementEnhanced vars; | ||
| 3925 | Boolean b; | ||
| 3926 | algorithm | ||
| 3927 | 240793 | vars := List.removeOnTrue(ass1,isAssignedSaveEnhanced,me[Eqn]); | |
| 3928 | 240793 | b := solvableLst(vars); | |
| 3929 |
2/2✓ Branch 0 taken 183722 times.
✓ Branch 1 taken 57071 times.
|
240793 | outSize := if b then inSize+1 else inSize; |
| 3930 | end sizeOfAssignable; | ||
| 3931 | |||
| 3932 | |||
| 3933 | protected function getAllVarsWithMostImpAss | ||
| 3934 | " function to return the variables with the highest number of impossible assignments | ||
| 3935 | considering the current matching | ||
| 3936 | author: ptaeuber FHB 2013-10" | ||
| 3937 | input list<Integer> inPotentials; | ||
| 3938 | input array<Integer> ass2; | ||
| 3939 | input BackendDAE.AdjacencyMatrixEnhanced meT; | ||
| 3940 | output list<Integer> outPotentials={}; | ||
| 3941 | output list<Integer> outCounts={}; | ||
| 3942 | output Integer outMax=0; | ||
| 3943 | protected | ||
| 3944 | Integer count; | ||
| 3945 | BackendDAE.AdjacencyMatrixElementEnhanced elem; | ||
| 3946 | algorithm | ||
| 3947 |
2/2✓ Branch 0 taken 143589 times.
✓ Branch 1 taken 3164 times.
|
146753 | for v in inPotentials loop |
| 3948 | 143589 | elem := List.removeOnTrue(ass2,isAssignedSaveEnhanced,meT[v]); | |
| 3949 | 143589 | count := countImpossibleAss(elem); | |
| 3950 | |||
| 3951 |
2/2✓ Branch 0 taken 4572 times.
✓ Branch 1 taken 139017 times.
|
143589 | if count > outMax then |
| 3952 | outPotentials := {v}; | ||
| 3953 | outMax := count; | ||
| 3954 | elseif count == outMax then | ||
| 3955 | outPotentials := v::outPotentials; | ||
| 3956 | end if; | ||
| 3957 | outCounts := count::outCounts; | ||
| 3958 | |||
| 3959 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 143589 times.
|
143589 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3960 | ✗ | print("Var " + intString(v) + " has " + intString(count) + " incident impossible assignments\n"); | |
| 3961 | end if; | ||
| 3962 | end for; | ||
| 3963 | 3164 | outCounts := listReverse(outCounts); | |
| 3964 | end getAllVarsWithMostImpAss; | ||
| 3965 | |||
| 3966 | |||
| 3967 | protected function getOneVarWithMostImpAss | ||
| 3968 | " function to return one variable with the highest number of impossible assignments | ||
| 3969 | considering the current matching | ||
| 3970 | author: ptaeuber" | ||
| 3971 | input list<Integer> inPotentials; | ||
| 3972 | input array<Integer> ass2; | ||
| 3973 | input BackendDAE.AdjacencyMatrixEnhanced meT; | ||
| 3974 | output list<Integer> outPotentials={}; | ||
| 3975 | output Integer outMax=-1; | ||
| 3976 | protected | ||
| 3977 | Integer count; | ||
| 3978 | BackendDAE.AdjacencyMatrixElementEnhanced elem; | ||
| 3979 | algorithm | ||
| 3980 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
|
6 | for v in inPotentials loop |
| 3981 | 4 | elem := List.removeOnTrue(ass2,isAssignedSaveEnhanced,meT[v]); | |
| 3982 | 4 | count := countImpossibleAss(elem); | |
| 3983 | |||
| 3984 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | if count > outMax then |
| 3985 | outPotentials := {v}; | ||
| 3986 | outMax := count; | ||
| 3987 | end if; | ||
| 3988 | |||
| 3989 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
|
4 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 3990 | ✗ | print("Var " + intString(v) + " has " + intString(count) + " incident impossible assignments\n"); | |
| 3991 | end if; | ||
| 3992 | end for; | ||
| 3993 | end getOneVarWithMostImpAss; | ||
| 3994 | |||
| 3995 | |||
| 3996 | protected function countImpossibleAss | ||
| 3997 | " helper function for getAllVarsWithMostImpAss, | ||
| 3998 | traverses AdjacencyMatrixElementEnhanced and counts the number of impossible assignments of one var | ||
| 3999 | author: ptaeuber FHB 2013-10" | ||
| 4000 | input BackendDAE.AdjacencyMatrixElementEnhanced elem; | ||
| 4001 | output Integer outCount = 0; | ||
| 4002 | protected | ||
| 4003 | BackendDAE.Solvability s; | ||
| 4004 | algorithm | ||
| 4005 |
2/2✓ Branch 0 taken 554478 times.
✓ Branch 1 taken 143593 times.
|
698071 | for e in elem loop |
| 4006 | 554478 | (_,s,_) := e; | |
| 4007 |
2/2✓ Branch 1 taken 276742 times.
✓ Branch 2 taken 277736 times.
|
554478 | if not solvable(s) then |
| 4008 | 276742 | outCount := outCount + 1; | |
| 4009 | end if; | ||
| 4010 | end for; | ||
| 4011 | end countImpossibleAss; | ||
| 4012 | |||
| 4013 | |||
| 4014 | protected function TarjanMatching "Modified matching algorithm according to Tarjan as it is used by Cellier. | ||
| 4015 | author: ptaeuber 2013-2015" | ||
| 4016 | input BackendDAE.AdjacencyMatrix mIn; | ||
| 4017 | input BackendDAE.AdjacencyMatrixT mtIn; | ||
| 4018 | input BackendDAE.AdjacencyMatrixEnhanced meIn; | ||
| 4019 | input BackendDAE.AdjacencyMatrixTEnhanced meTIn; | ||
| 4020 | input array<Integer> ass1In,ass2In; | ||
| 4021 | input list<Integer> orderIn; | ||
| 4022 | input array<list<Integer>> mapEqnIncRow; | ||
| 4023 | input array<Integer> mapIncRowEqn; | ||
| 4024 | input array<Integer> eqnNonlinPoints; | ||
| 4025 | input Boolean forceDegree1 "ticket #15433: enable variable-driven degree-1 forced assignment (set by CellierTearing only for initialization components that have a $START.x->x cycle)"; | ||
| 4026 | output list<Integer> orderOut; | ||
| 4027 | output Boolean causal; | ||
| 4028 | protected | ||
| 4029 | list<Integer> unassigned; | ||
| 4030 | list<Integer> order=orderIn; | ||
| 4031 | Boolean assignable = true; | ||
| 4032 | constant Boolean debug = false; | ||
| 4033 | algorithm | ||
| 4034 |
2/2✓ Branch 0 taken 32723 times.
✓ Branch 1 taken 4103 times.
|
36826 | while assignable loop |
| 4035 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 32723 times.
|
32723 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 4036 | ✗ | print("\nTarjanAssignment:\n"); | |
| 4037 | end if; | ||
| 4038 | 32723 | (order,assignable) := TarjanAssignment(mIn,mtIn,meIn,meTIn,ass1In,ass2In,order,mapEqnIncRow,mapIncRowEqn,eqnNonlinPoints,forceDegree1); | |
| 4039 | end while; | ||
| 4040 | if debug then execStat("Tearing.TarjanMatching iters done"); end if; | ||
| 4041 | |||
| 4042 | 4103 | unassigned := getUnassigned(ass1In); | |
| 4043 |
2/2✓ Branch 0 taken 1957 times.
✓ Branch 1 taken 2146 times.
|
4103 | if listEmpty(unassigned) then |
| 4044 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1957 times.
|
1957 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 4045 | ✗ | print("\ncausal\n"); | |
| 4046 | end if; | ||
| 4047 | 1957 | orderOut := listReverse(order); | |
| 4048 | causal := true; | ||
| 4049 | else | ||
| 4050 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2146 times.
|
2146 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 4051 | ✗ | print("\nnoncausal\n"); | |
| 4052 | end if; | ||
| 4053 | orderOut := order; | ||
| 4054 | causal := false; | ||
| 4055 | end if; | ||
| 4056 | if debug then execStat("Tearing.TarjanMatching done"); end if; | ||
| 4057 | end TarjanMatching; | ||
| 4058 | |||
| 4059 | |||
| 4060 | protected function TarjanAssignment " finds assignable equations and variables and assigns | ||
| 4061 | author: ptaeuber FHB 2013-2015" | ||
| 4062 | input BackendDAE.AdjacencyMatrix mIn; | ||
| 4063 | input BackendDAE.AdjacencyMatrixT mtIn; | ||
| 4064 | input BackendDAE.AdjacencyMatrixEnhanced meIn; | ||
| 4065 | input BackendDAE.AdjacencyMatrixTEnhanced meTIn; | ||
| 4066 | input array<Integer> ass1In,ass2In; | ||
| 4067 | input list<Integer> orderIn; | ||
| 4068 | input array<list<Integer>> mapEqnIncRow; | ||
| 4069 | input array<Integer> mapIncRowEqn; | ||
| 4070 | input array<Integer> eqnNonlinPoints; | ||
| 4071 | input Boolean forceDegree1 "ticket #15433: enable variable-driven degree-1 forced assignment (set by CellierTearing only for initialization components that have a $START.x->x cycle)"; | ||
| 4072 | output list<Integer> orderOut = orderIn; | ||
| 4073 | output Boolean assignable = false; | ||
| 4074 | protected | ||
| 4075 | Integer eq_coll; | ||
| 4076 | list<Integer> assEq_coll, eqns = {}, vars = {}; | ||
| 4077 | algorithm | ||
| 4078 | // ticket #15433: variable-driven forced assignment of degree-1 variables. The defect this repairs | ||
| 4079 | // is a $START.x variable solvable in exactly one still-unassigned equation (its defining initial | ||
| 4080 | // equation) but structurally incident to more than one (it is linked to the state's equations); it | ||
| 4081 | // must be matched to its defining equation, otherwise the equation-driven pass below (which matches | ||
| 4082 | // on structural incidence) lets a higher-degree variable steal that equation, orphaning the | ||
| 4083 | // $START.x variable and producing a structurally singular torn system. forceDegree1 already gates | ||
| 4084 | // this to exactly the initialization components that exhibit the $START.x->x cycle (see | ||
| 4085 | // CellierTearing), so it runs only where the defect can occur. | ||
| 4086 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 32723 times.
|
32723 | if forceDegree1 then |
| 4087 | try | ||
| 4088 | ✗ | (eq_coll,eqns,vars) := getNextDegree1Var(mtIn,meTIn,ass1In,ass2In,mapEqnIncRow,mapIncRowEqn); | |
| 4089 | orderOut := eq_coll::orderOut; | ||
| 4090 | assignable := true; | ||
| 4091 | else | ||
| 4092 | end try; | ||
| 4093 | end if; | ||
| 4094 | |||
| 4095 |
1/2✓ Branch 0 taken 32723 times.
✗ Branch 1 not taken.
|
32723 | if not assignable then |
| 4096 | // find equations with one variable | ||
| 4097 | 32723 | assEq_coll := traverseCollectiveEqnsforAssignable(ass2In,mIn,mapEqnIncRow); | |
| 4098 | |||
| 4099 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 32723 times.
|
32723 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 4100 | ✗ | print("New assEq_coll: "+stringDelimitList(List.map(assEq_coll,intString),",")+"\n"); | |
| 4101 | end if; | ||
| 4102 | |||
| 4103 | // NOTE: For tearing of strong components with the same number of equations and variables and with a late choice of the | ||
| 4104 | // residual equation it is not possible to match starting from the variables, so this case is not considered. | ||
| 4105 | // For other tearing structures this case has to be added. | ||
| 4106 | |||
| 4107 | // Get the next solvable equation from the equation queue | ||
| 4108 | try | ||
| 4109 | 32723 | (eq_coll,eqns,vars) := getNextSolvableEqn(assEq_coll,mIn,meIn,ass1In,ass2In,mapEqnIncRow,mapIncRowEqn,eqnNonlinPoints); | |
| 4110 | orderOut := eq_coll::orderOut; | ||
| 4111 | assignable := true; | ||
| 4112 | else | ||
| 4113 | end try; | ||
| 4114 | end if; | ||
| 4115 | |||
| 4116 | // Make the assignment if possible | ||
| 4117 |
2/2✓ Branch 0 taken 28620 times.
✓ Branch 1 taken 4103 times.
|
32723 | if assignable then |
| 4118 | 28620 | makeAssignment(eqns,vars,ass1In,ass2In,mIn,mtIn); | |
| 4119 | end if; | ||
| 4120 | |||
| 4121 |
1/2✓ Branch 1 taken 32723 times.
✗ Branch 2 not taken.
|
32723 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 4122 | ✗ | print("order: "+stringDelimitList(List.map(listReverse(orderOut),intString),",")+"\n\n"); | |
| 4123 | end if; | ||
| 4124 | end TarjanAssignment; | ||
| 4125 | |||
| 4126 | |||
| 4127 | protected function getNextDegree1Var | ||
| 4128 | "ticket #15433: finds an unassigned variable that is SOLVABLE in exactly one still-unassigned | ||
| 4129 | scalar equation while being STRUCTURALLY incident to more than one, and returns the assignment | ||
| 4130 | for it. This is exactly the case the equation-driven pass mishandles: it matches on the plain | ||
| 4131 | structural adjacency mtIn, where such a variable looks high-degree (during initialization a | ||
| 4132 | $START.x variable is structurally linked to the state's equations), so a higher-degree variable | ||
| 4133 | can steal its only solvable equation and orphan it, producing a structurally singular torn | ||
| 4134 | system. The solvability is read from the enhanced transposed adjacency meTIn (entries | ||
| 4135 | (eqn, solvability, _); unsolvable entries are ignored via BackendDAEUtil.isSolvable). The caller | ||
| 4136 | (TarjanAssignment) only invokes this when forceDegree1 is set, which CellierTearing restricts to | ||
| 4137 | initialization components that have a $START.x->x cycle (a variable whose start attribute | ||
| 4138 | transitively depends on the variable itself) - the only place this matching defect occurs. The | ||
| 4139 | search is restricted to variables whose structural degree exceeds their solvable degree, so an | ||
| 4140 | ordinary degree-1 variable handled correctly by the equation-driven pass is never reordered here. | ||
| 4141 | Only scalar equations are forced, to stay on the safe side of array/collective equations. Fails if | ||
| 4142 | there is no such variable." | ||
| 4143 | input BackendDAE.AdjacencyMatrixT mtIn; | ||
| 4144 | input BackendDAE.AdjacencyMatrixTEnhanced meTIn; | ||
| 4145 | input array<Integer> ass1; | ||
| 4146 | input array<Integer> ass2; | ||
| 4147 | input array<list<Integer>> mapEqnIncRow; | ||
| 4148 | input array<Integer> mapIncRowEqn; | ||
| 4149 | output Integer eqCollOut; | ||
| 4150 | output list<Integer> eqnsOut; | ||
| 4151 | output list<Integer> varsOut; | ||
| 4152 | protected | ||
| 4153 | Integer e, eqColl, cnt, theEqn; | ||
| 4154 | BackendDAE.Solvability s; | ||
| 4155 | algorithm | ||
| 4156 | ✗ | for v in 1:arrayLength(meTIn) loop | |
| 4157 | // only consider unassigned variables that the structural pass sees as high-degree (degree > 1); | ||
| 4158 | // a variable structurally incident to a single remaining equation is matched there correctly by | ||
| 4159 | // the equation-driven pass and must not be reordered here. ticket #15433: only a structurally- | ||
| 4160 | // divergent var (struct degree > 1 but solvable degree == 1 below) - the matching defect the | ||
| 4161 | // equation-driven pass mishandles - is forced. | ||
| 4162 | ✗ | if arrayGet(ass1, v) == -1 and listLength(arrayGet(mtIn, v)) > 1 then | |
| 4163 | // count the still-unassigned equations this variable can actually be solved in | ||
| 4164 | cnt := 0; | ||
| 4165 | theEqn := -1; | ||
| 4166 | ✗ | for entry in meTIn[v] loop | |
| 4167 | ✗ | (e, s, _) := entry; | |
| 4168 | ✗ | if arrayGet(ass2, e) == -1 and BackendDAEUtil.isSolvable(s) then | |
| 4169 | ✗ | cnt := cnt + 1; | |
| 4170 | theEqn := e; | ||
| 4171 | ✗ | if cnt > 1 then break; end if; | |
| 4172 | end if; | ||
| 4173 | end for; | ||
| 4174 | ✗ | if cnt == 1 then | |
| 4175 | ✗ | eqColl := mapIncRowEqn[theEqn]; | |
| 4176 | // only force scalar equations; the degree-1 variable v must claim theEqn before a | ||
| 4177 | // higher-degree variable does. | ||
| 4178 | ✗ | if listLength(mapEqnIncRow[eqColl]) == 1 then | |
| 4179 | eqCollOut := eqColl; | ||
| 4180 | eqnsOut := {theEqn}; | ||
| 4181 | varsOut := {v}; | ||
| 4182 | ✗ | return; | |
| 4183 | end if; | ||
| 4184 | end if; | ||
| 4185 | end if; | ||
| 4186 | end for; | ||
| 4187 | ✗ | fail(); | |
| 4188 | end getNextDegree1Var; | ||
| 4189 | |||
| 4190 | protected function tornMatchingIsStructurallySingular | ||
| 4191 | "ticket #15433: returns true when the plain Cellier matching left a variable that is solvable in | ||
| 4192 | EXACTLY ONE equation (per the enhanced solvability adjacency) matched to some OTHER variable, so | ||
| 4193 | that degree-1 variable is orphaned and can be solved nowhere - a structural singularity. This is | ||
| 4194 | the cable's $START.x defect: its single defining equation $START.x = sp is stolen by the high- | ||
| 4195 | degree r_start, leaving $START.x to be paired with a pin equation it does not occur in. The | ||
| 4196 | degree-1 forcing repairs exactly this (it gives every degree-1-solvable variable its unique | ||
| 4197 | equation), so this test is symmetric with the forcing: it fires precisely when forcing would | ||
| 4198 | change the matching. A healthy matching - e.g. the OpenIPSL PSSE controllers, which initialize | ||
| 4199 | correctly without forcing - gives every degree-1-solvable variable its unique solvable equation | ||
| 4200 | and returns false, so those components are left on the plain (master) result. | ||
| 4201 | ass2[e] is the variable matched to scalar equation e - the SAME index space as the enhanced | ||
| 4202 | matrix equation indices and as getNextDegree1Var's ass2 use. The value of ass2[e] discriminates | ||
| 4203 | the two start-cycle classes: a POSITIVE variable index means equation e is solved for THAT other | ||
| 4204 | variable, so a degree-1 variable whose only solvable equation is taken this way is genuinely | ||
| 4205 | orphaned (the cable's $START.x defect -> singular); a value of -2 means e became a RESIDUAL | ||
| 4206 | (getNextSolvableEqn marks unsolvable/residual rows with -2), in which case the degree-1 variable is | ||
| 4207 | simply the iteration variable of a residual it actually occurs in - the normal, non-singular | ||
| 4208 | nonlinear tearing of the OpenIPSL PSSE controllers, which initialize correctly without forcing. | ||
| 4209 | meTFull is the UNMUTATED enhanced transposed adjacency (variable -> list of (equation, solvability, | ||
| 4210 | _))." | ||
| 4211 | input array<Integer> ass2; | ||
| 4212 | input BackendDAE.AdjacencyMatrixTEnhanced meTFull; | ||
| 4213 | input Integer size; | ||
| 4214 | input BackendDAE.Variables vars; | ||
| 4215 | output Boolean singular = false; | ||
| 4216 | protected | ||
| 4217 | Integer ev, cnt, theEqn, owner; | ||
| 4218 | BackendDAE.Solvability s; | ||
| 4219 | DAE.ComponentRef cref; | ||
| 4220 | algorithm | ||
| 4221 | ✗ | for v in 1:size loop | |
| 4222 | ✗ | cref := BackendVariable.varCref(BackendVariable.getVarAt(vars, v)); | |
| 4223 | // restrict to the start-value-cycle singularity: only a $START.x variable orphaned this way is | ||
| 4224 | // the cable defect. A non-$START value variable whose unique solvable equation is taken by | ||
| 4225 | // another variable (e.g. AC8B's rotatingExciterWithDemagnetizationVarLim.feedback.y) instead | ||
| 4226 | // becomes the iteration variable of a residual it DOES occur in - non-singular, and forcing it | ||
| 4227 | // only reorders a healthy system and breaks initialization. | ||
| 4228 | ✗ | if ComponentReference.isStartCref(cref) then | |
| 4229 | // count the equations $START.x can actually be solved in (enhanced solvability), recording the | ||
| 4230 | // unique one when there is exactly one | ||
| 4231 | cnt := 0; | ||
| 4232 | theEqn := -1; | ||
| 4233 | ✗ | for entry in arrayGet(meTFull, v) loop | |
| 4234 | ✗ | (ev, s, _) := entry; | |
| 4235 | ✗ | if BackendDAEUtil.isSolvable(s) then | |
| 4236 | ✗ | cnt := cnt + 1; | |
| 4237 | theEqn := ev; | ||
| 4238 | ✗ | if cnt > 1 then break; end if; | |
| 4239 | end if; | ||
| 4240 | end for; | ||
| 4241 | // $START.x is solvable in exactly ONE equation (its defining equation $START.x = sp). The | ||
| 4242 | // variable that equation got matched to (ass2[theEqn]) decides whether the matching is sound: | ||
| 4243 | // owner == v -> $START.x kept its own defining equation: correctly matched, healthy | ||
| 4244 | // (the OpenIPSL PSSE controllers - they initialize without forcing). | ||
| 4245 | // owner == -2 -> that equation became a residual and $START.x iterates it (it occurs there | ||
| 4246 | // solvably): non-singular, healthy. | ||
| 4247 | // owner > 0, <> v -> a DIFFERENT real variable (e.g. the cable's high-degree r_start) stole | ||
| 4248 | // the only equation $START.x could be solved in: $START.x is orphaned. | ||
| 4249 | // owner == -1 -> the equation is left unmatched and $START.x is orphaned (the inlined- | ||
| 4250 | // parameter case of the minimal reproducer InitStartTearingDegree1). | ||
| 4251 | // In the two orphaned cases $START.x can be solved nowhere and ends up paired with a residual it | ||
| 4252 | // does not occur in -> zero Jacobian column -> structurally singular. The degree-1 forcing | ||
| 4253 | // repairs exactly this by giving $START.x its defining equation back. | ||
| 4254 | ✗ | if cnt == 1 then | |
| 4255 | ✗ | owner := arrayGet(ass2, theEqn); | |
| 4256 | ✗ | if owner <> v and owner <> -2 then | |
| 4257 | // $START.x is orphaned -> the matching is structurally singular; one such variable is | ||
| 4258 | // enough to require the degree-1 forcing for this component | ||
| 4259 | singular := true; | ||
| 4260 | ✗ | return; | |
| 4261 | end if; | ||
| 4262 | end if; | ||
| 4263 | end if; | ||
| 4264 | end for; | ||
| 4265 | end tornMatchingIsStructurallySingular; | ||
| 4266 | |||
| 4267 | |||
| 4268 | protected function traverseSingleEqnsforAssignable | ||
| 4269 | " selects next equations that can be causalized without consideration of solvability | ||
| 4270 | author: ptaeuber FHB 2013-10" | ||
| 4271 | input array<Integer> inAss; | ||
| 4272 | input BackendDAE.AdjacencyMatrix m; | ||
| 4273 | input array<list<Integer>> mapEqnIncRow; | ||
| 4274 | input array<Integer> mapIncRowEqn; | ||
| 4275 | output list<Integer> selectedrows; | ||
| 4276 | protected | ||
| 4277 | Integer eqnColl,eqnSize; | ||
| 4278 | DoubleEnded.MutableList<Integer> delst; | ||
| 4279 | algorithm | ||
| 4280 | 3314 | delst := DoubleEnded.empty(0); | |
| 4281 |
1/2✓ Branch 0 taken 3314 times.
✗ Branch 1 not taken.
|
731486 | for e in 1:arrayLength(inAss) loop |
| 4282 |
2/2✓ Branch 1 taken 270597 times.
✓ Branch 2 taken 457575 times.
|
728172 | if arrayGet(inAss,e)<>-1 then |
| 4283 | 270597 | continue; | |
| 4284 | end if; | ||
| 4285 | 457575 | eqnColl := mapIncRowEqn[e]; | |
| 4286 | 457575 | eqnSize := listLength(mapEqnIncRow[eqnColl]); | |
| 4287 |
2/2✓ Branch 2 taken 136302 times.
✓ Branch 3 taken 321273 times.
|
457575 | if listLength(m[e]) == eqnSize + 1 then |
| 4288 |
2/2✓ Branch 0 taken 132923 times.
✓ Branch 1 taken 3379 times.
|
136302 | if eqnSize == 1 then |
| 4289 | 132923 | DoubleEnded.push_back(delst, e); | |
| 4290 | else | ||
| 4291 | 3379 | DoubleEnded.push_front(delst, e); | |
| 4292 | end if; | ||
| 4293 | end if; | ||
| 4294 | end for; | ||
| 4295 | 3314 | selectedrows := DoubleEnded.toListAndClear(delst); | |
| 4296 | end traverseSingleEqnsforAssignable; | ||
| 4297 | |||
| 4298 | |||
| 4299 | protected function traverseCollectiveEqnsforAssignable | ||
| 4300 | " selects next collective equations that can be causalized without consideration of solvability | ||
| 4301 | author: ptaeuber" | ||
| 4302 | input array<Integer> inAss; | ||
| 4303 | input BackendDAE.AdjacencyMatrix m; | ||
| 4304 | input array<list<Integer>> mapEqnIncRow; | ||
| 4305 | output list<Integer> selectedrows; | ||
| 4306 | protected | ||
| 4307 | Integer eqnSize,e,eqnColl=0; | ||
| 4308 | DoubleEnded.MutableList<Integer> delst; | ||
| 4309 | algorithm | ||
| 4310 | 32784 | delst := DoubleEnded.empty(0); | |
| 4311 |
2/2✓ Branch 1 taken 12015884 times.
✓ Branch 2 taken 32784 times.
|
12048668 | for eqnLst in mapEqnIncRow loop |
| 4312 | 12015884 | eqnColl := eqnColl + 1; | |
| 4313 | 12015884 | e := listHead(eqnLst); | |
| 4314 |
2/2✓ Branch 1 taken 5745288 times.
✓ Branch 2 taken 6270596 times.
|
12015884 | if arrayGet(inAss,e)<>-1 then |
| 4315 | 5745288 | continue; | |
| 4316 | end if; | ||
| 4317 | 6270596 | eqnSize := listLength(eqnLst); | |
| 4318 |
2/2✓ Branch 2 taken 153288 times.
✓ Branch 3 taken 6117308 times.
|
6270596 | if listLength(m[e]) == eqnSize then |
| 4319 |
2/2✓ Branch 0 taken 152417 times.
✓ Branch 1 taken 871 times.
|
153288 | if eqnSize == 1 then |
| 4320 | 152417 | DoubleEnded.push_back(delst, eqnColl); | |
| 4321 | else | ||
| 4322 | 871 | DoubleEnded.push_front(delst, eqnColl); | |
| 4323 | end if; | ||
| 4324 | end if; | ||
| 4325 | end for; | ||
| 4326 | 32784 | selectedrows := DoubleEnded.toListAndClear(delst); | |
| 4327 | end traverseCollectiveEqnsforAssignable; | ||
| 4328 | |||
| 4329 | |||
| 4330 | protected function makeAssignment | ||
| 4331 | " function to assign equations with variables | ||
| 4332 | author: ptaeuber FHB 2013-10" | ||
| 4333 | input list<Integer> eqns,vars; | ||
| 4334 | input array<Integer> ass1In,ass2In; | ||
| 4335 | input BackendDAE.AdjacencyMatrix mIn; | ||
| 4336 | input BackendDAE.AdjacencyMatrixT mtIn; | ||
| 4337 | protected | ||
| 4338 | Integer eq, var; | ||
| 4339 | algorithm | ||
| 4340 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 28675 times.
|
60041 | for index in 1:listLength(eqns) loop |
| 4341 | 31366 | eq := listGet(eqns, index); | |
| 4342 | 31366 | var := listGet(vars, index); | |
| 4343 | 31366 | arrayUpdate(ass1In,var,eq); | |
| 4344 | 31366 | arrayUpdate(ass2In,eq,var); | |
| 4345 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 31366 times.
|
31366 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 4346 | ✗ | print("assignment: Eq " + intString(eq) + " - Var " + intString(var) + "\n"); | |
| 4347 | end if; | ||
| 4348 | 31366 | Array.replaceAtWithFill(eq,{},{},mIn); | |
| 4349 | 31366 | deleteEntriesFromAdjacencyMatrix(mIn,mtIn,{var}); | |
| 4350 | 31366 | Array.replaceAtWithFill(var,{},{},mtIn); | |
| 4351 | 31366 | deleteEntriesFromAdjacencyMatrix(mtIn,mIn,{eq}); | |
| 4352 | end for; | ||
| 4353 | end makeAssignment; | ||
| 4354 | |||
| 4355 | |||
| 4356 | protected function getNextSolvableEqn " finds equation that can be matched with respect to solvability | ||
| 4357 | author: ptaeuber FHB 2013-08" | ||
| 4358 | input list<Integer> assEq_coll; | ||
| 4359 | input BackendDAE.AdjacencyMatrix m; | ||
| 4360 | input BackendDAE.AdjacencyMatrixEnhanced me; | ||
| 4361 | input array<Integer> ass1; | ||
| 4362 | input array<Integer> ass2; | ||
| 4363 | input array<list<Integer>> mapEqnIncRow; | ||
| 4364 | input array<Integer> mapIncRowEqn; | ||
| 4365 | input array<Integer> eqnNonlinPoints; | ||
| 4366 | output Integer eqOut = 0; | ||
| 4367 | output list<Integer> eqnsOut = {}; | ||
| 4368 | output list<Integer> varsOut = {}; | ||
| 4369 | protected | ||
| 4370 | Boolean solvable = false; | ||
| 4371 | list<Integer> eqns = assEq_coll; | ||
| 4372 | algorithm | ||
| 4373 |
2/2✓ Branch 0 taken 31419 times.
✓ Branch 1 taken 4103 times.
|
35522 | while not listEmpty(eqns) loop |
| 4374 | 31419 | eqOut := getMostNonlinearEquation(eqnNonlinPoints, eqns, mapEqnIncRow, mapIncRowEqn); | |
| 4375 | 31419 | (solvable, eqnsOut, varsOut) := eqnSolvableCheck(eqOut, mapEqnIncRow, ass1, m, me); | |
| 4376 | 31419 | eqns := List.deleteMemberOnTrue(eqOut, eqns, intEq); | |
| 4377 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 31419 times.
|
31419 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 4378 | ✗ | print("Most nonlinear equation: " + intString(eqOut) + " - solvable?: " + boolString(solvable) + "\n"); | |
| 4379 | end if; | ||
| 4380 |
2/2✓ Branch 0 taken 2799 times.
✓ Branch 1 taken 28620 times.
|
31419 | if solvable then |
| 4381 | break; | ||
| 4382 | else | ||
| 4383 |
2/2✓ Branch 2 taken 2799 times.
✓ Branch 3 taken 2843 times.
|
5642 | for eq in mapEqnIncRow[eqOut] loop |
| 4384 | 2843 | arrayUpdate(ass2,eq,-2); | |
| 4385 | end for; | ||
| 4386 | end if; | ||
| 4387 | end while; | ||
| 4388 |
2/2✓ Branch 0 taken 4103 times.
✓ Branch 1 taken 28620 times.
|
32723 | if not solvable then fail(); end if; |
| 4389 | end getNextSolvableEqn; | ||
| 4390 | |||
| 4391 | |||
| 4392 | protected function eqnSolvableCheck " | ||
| 4393 | returns the expanded equation(s), variables and | ||
| 4394 | a boolean whether the equation is solvable or not | ||
| 4395 | author: ptaeuber FHB 2016" | ||
| 4396 | input Integer eqn_coll; | ||
| 4397 | input array<list<Integer>> mapEqnIncRow; | ||
| 4398 | input array<Integer> ass1; | ||
| 4399 | input BackendDAE.AdjacencyMatrix m; | ||
| 4400 | input BackendDAE.AdjacencyMatrixEnhanced me; | ||
| 4401 | output Boolean solvable; | ||
| 4402 | output list<Integer> eqns; | ||
| 4403 | output list<Integer> vars; | ||
| 4404 | protected | ||
| 4405 | Integer eqn; | ||
| 4406 | BackendDAE.AdjacencyMatrixElementEnhanced vars_enh; | ||
| 4407 | algorithm | ||
| 4408 | 31493 | eqns := mapEqnIncRow[eqn_coll]; | |
| 4409 | 31493 | eqn := listHead(eqns); | |
| 4410 | 31493 | vars := arrayGet(m,eqn); | |
| 4411 | 31493 | vars_enh := List.removeOnTrue(ass1, isAssignedSaveEnhanced,me[eqn]); | |
| 4412 | 31493 | solvable := solvableLst(vars_enh); | |
| 4413 | end eqnSolvableCheck; | ||
| 4414 | |||
| 4415 | |||
| 4416 | protected function assignInnerEquations " assigns innerEquations for TearingSet | ||
| 4417 | author: ptaeuber FHB 2013-08" | ||
| 4418 | input list<Integer> inEqns "order of equations with local numbering"; | ||
| 4419 | input list<Integer> eindex "equation indexes with global numbering"; | ||
| 4420 | input list<Integer> vindex "variable indexes with global numbering"; | ||
| 4421 | input array<Integer> ass2; | ||
| 4422 | input array<list<Integer>> mapEqnIncRow; | ||
| 4423 | input Option<BackendDAE.AdjacencyMatrixEnhanced> meOpt; | ||
| 4424 | output BackendDAE.InnerEquations outInnerEquations; | ||
| 4425 | algorithm | ||
| 4426 |
4/4✓ Branch 0 taken 28655 times.
✓ Branch 1 taken 1981 times.
✓ Branch 2 taken 28655 times.
✓ Branch 3 taken 1981 times.
|
30636 | outInnerEquations := list( |
| 4427 | match (eqn,meOpt) | ||
| 4428 | local | ||
| 4429 | Integer eq,otherEqn; | ||
| 4430 | list<Integer> eqns,vars,otherVars; | ||
| 4431 | BackendDAE.InnerEquation innerEquation; | ||
| 4432 | BackendDAE.Constraints constraints; | ||
| 4433 | BackendDAE.AdjacencyMatrixEnhanced me; | ||
| 4434 | case (eq,NONE()) | ||
| 4435 | algorithm | ||
| 4436 | 28650 | vars := List.map1r(mapEqnIncRow[eq],arrayGet,ass2); | |
| 4437 | 28650 | otherEqn := listGet(eindex,eq); | |
| 4438 | 28650 | otherVars := selectFromList_rev(vindex,vars); | |
| 4439 | 28650 | then BackendDAE.INNEREQUATION(eqn=otherEqn, vars=otherVars); | |
| 4440 | case (eq,SOME(me)) | ||
| 4441 | algorithm | ||
| 4442 | 5 | eqns := mapEqnIncRow[eq]; | |
| 4443 | 5 | vars := List.map1r(eqns,arrayGet,ass2); | |
| 4444 | 5 | otherEqn := listGet(eindex,eq); | |
| 4445 | 5 | otherVars := selectFromList_rev(vindex,vars); | |
| 4446 | 5 | constraints := findConstraintForInnerEquation(me[listHead(eqns)],listHead(vars)); | |
| 4447 |
2/2✓ Branch 0 taken 1 time.
✓ Branch 1 taken 4 times.
|
5 | if listEmpty(constraints) then |
| 4448 | 1 | innerEquation := BackendDAE.INNEREQUATION(eqn=otherEqn, vars=otherVars); | |
| 4449 | else | ||
| 4450 | 4 | innerEquation := BackendDAE.INNEREQUATIONCONSTRAINTS(eqn=otherEqn, vars=otherVars, cons=constraints); | |
| 4451 | end if; | ||
| 4452 | then (innerEquation); | ||
| 4453 | end match for eqn in inEqns); | ||
| 4454 | end assignInnerEquations; | ||
| 4455 | |||
| 4456 | |||
| 4457 | protected function findConstraintForInnerEquation | ||
| 4458 | input BackendDAE.AdjacencyMatrixElementEnhanced meRow; | ||
| 4459 | input Integer searchIndex; | ||
| 4460 | output BackendDAE.Constraints constraints={}; | ||
| 4461 | protected | ||
| 4462 | Integer index; | ||
| 4463 | BackendDAE.AdjacencyMatrixElementEnhancedEntry meElem; | ||
| 4464 | BackendDAE.Constraints cons; | ||
| 4465 | algorithm | ||
| 4466 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | for meElem in meRow loop |
| 4467 | 10 | (index,_,cons) := meElem; | |
| 4468 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
|
10 | if intEq(index,searchIndex) then |
| 4469 | constraints := cons; | ||
| 4470 | break; | ||
| 4471 | end if; | ||
| 4472 | end for; | ||
| 4473 | end findConstraintForInnerEquation; | ||
| 4474 | |||
| 4475 | |||
| 4476 | protected function markTVarsOrResiduals | ||
| 4477 | " marks several tVars in ass1 or residuals in ass2 | ||
| 4478 | author: ptaeuber FHB 2013-10" | ||
| 4479 | input list<Integer> markList; | ||
| 4480 | input array<Integer> assIn; | ||
| 4481 | output array<Integer> assOut = assIn; | ||
| 4482 | protected | ||
| 4483 | Integer len; | ||
| 4484 | algorithm | ||
| 4485 | len := arrayLength(assIn); | ||
| 4486 |
2/2✓ Branch 0 taken 2032 times.
✓ Branch 1 taken 806 times.
|
2838 | for i in markList loop |
| 4487 | 2032 | arrayUpdate(assOut, i, len * 2); | |
| 4488 | end for; | ||
| 4489 | end markTVarsOrResiduals; | ||
| 4490 | |||
| 4491 | protected function countMultiples "counts multiple entries in array<list<Integer row(list)-wise. | ||
| 4492 | counter gives the maximum amount of same entries and value gives the corresponding entry. | ||
| 4493 | if only 0s appear in the row, then (0,0). | ||
| 4494 | author: Waurich TUD 2013-01" | ||
| 4495 | input array<list<Integer>> inArr; | ||
| 4496 | output list<Integer> counter,numbers,values; | ||
| 4497 | algorithm | ||
| 4498 | ✗ | (counter,numbers,values,_) := Array.fold(inArr,countMultiples2,({},{},{},1)); | |
| 4499 | end countMultiples; | ||
| 4500 | |||
| 4501 | |||
| 4502 | protected function countMultiples2 " FoldFunc for countMultiples.if entries appear equaly often, | ||
| 4503 | just one is taken. | ||
| 4504 | author: Waurich TUD 2013-01" | ||
| 4505 | input list<Integer> rowIn; | ||
| 4506 | input tuple<list<Integer>,list<Integer>,list<Integer>,Integer> valIn; | ||
| 4507 | output tuple<list<Integer>,list<Integer>,list<Integer>,Integer> valOut; | ||
| 4508 | protected | ||
| 4509 | list<Integer> counter,values,row,set,num,val,positions,numbers; | ||
| 4510 | Integer indx,value,number,position; | ||
| 4511 | algorithm | ||
| 4512 | ✗ | (counter,_,values,indx) := valIn; | |
| 4513 | ✗ | row := List.removeOnTrue(0,intEq,rowIn); | |
| 4514 | ✗ | set := List.unique(row); | |
| 4515 | ✗ | if listEmpty(set) then | |
| 4516 | val := {0}; | ||
| 4517 | ✗ | num := {0}; | |
| 4518 | else | ||
| 4519 | ✗ | (val,num) := countMultiples3(row,set,{},{}); | |
| 4520 | end if; | ||
| 4521 | ✗ | positions := maxListInt(num); | |
| 4522 | ✗ | position := listHead(positions); | |
| 4523 | ✗ | number := listGet(num,position); | |
| 4524 | ✗ | numbers := selectFromList(val,positions); | |
| 4525 | ✗ | value := listGet(val,position); | |
| 4526 | ✗ | counter := List.set(counter,indx,number); | |
| 4527 | ✗ | values := List.set(values,indx,value); | |
| 4528 | ✗ | valOut := (counter,numbers,values,indx+1); | |
| 4529 | end countMultiples2; | ||
| 4530 | |||
| 4531 | |||
| 4532 | protected function countMultiples3 " helper function for countMultiples2. | ||
| 4533 | author:Waurich TUD 2013-01" | ||
| 4534 | input list<Integer> lstIn; | ||
| 4535 | input list<Integer> set; | ||
| 4536 | input list<Integer> valIn; | ||
| 4537 | input list<Integer> numIn; | ||
| 4538 | output list<Integer> valOut; | ||
| 4539 | output list<Integer> numOut; | ||
| 4540 | algorithm | ||
| 4541 | (valOut,numOut) := match set | ||
| 4542 | local | ||
| 4543 | Integer value,number; | ||
| 4544 | list<Integer> val,num,rest; | ||
| 4545 | case value::rest | ||
| 4546 | algorithm | ||
| 4547 | ✗ | number := listLength(lstIn)-listLength(List.removeOnTrue(value,intEq,lstIn)); | |
| 4548 | ✗ | (val,num) := countMultiples3(lstIn,rest,value::valIn,number::numIn); | |
| 4549 | then | ||
| 4550 | (val,num); | ||
| 4551 | else (valIn,numIn); | ||
| 4552 | end match; | ||
| 4553 | end countMultiples3; | ||
| 4554 | |||
| 4555 | |||
| 4556 | protected function maxListInt | ||
| 4557 | "function to find maximum Integers in inList and output a list with the indexes. | ||
| 4558 | author: Waurich TUD 2012-11" | ||
| 4559 | input list<Integer> inList; | ||
| 4560 | output list<Integer> outList={}; | ||
| 4561 | protected | ||
| 4562 | Integer maxi, index=1; | ||
| 4563 | algorithm | ||
| 4564 | ✗ | maxi := max(i for i in inList); | |
| 4565 | ✗ | for i in inList loop | |
| 4566 | ✗ | if i==maxi then | |
| 4567 | outList := index::outList; | ||
| 4568 | end if; | ||
| 4569 | ✗ | index := index+1; | |
| 4570 | end for; | ||
| 4571 | end maxListInt; | ||
| 4572 | |||
| 4573 | |||
| 4574 | protected function getMostNonlinearEquation | ||
| 4575 | "Function to find maximum Integers in a selection of inArray and outputs the first index. | ||
| 4576 | author: ptaeuber" | ||
| 4577 | input array<Integer> inArray; | ||
| 4578 | input list<Integer> inList; | ||
| 4579 | input array<list<Integer>> mapEqnIncRow; | ||
| 4580 | input array<Integer> mapIncRowEqn; | ||
| 4581 | output Integer index=1; | ||
| 4582 | protected | ||
| 4583 | Integer maxi; | ||
| 4584 | algorithm | ||
| 4585 |
4/4✓ Branch 0 taken 161979 times.
✓ Branch 1 taken 31419 times.
✓ Branch 2 taken 161979 times.
✓ Branch 3 taken 31419 times.
|
193398 | maxi := max(inArray[listHead(mapEqnIncRow[i])] for i in inList); |
| 4586 | |||
| 4587 |
1/2✓ Branch 0 taken 71039 times.
✗ Branch 1 not taken.
|
71039 | for i in inList loop |
| 4588 | 71039 | index := listHead(mapEqnIncRow[i]); | |
| 4589 |
2/2✓ Branch 1 taken 31419 times.
✓ Branch 2 taken 39620 times.
|
71039 | if inArray[index] == maxi then |
| 4590 | 31419 | index := mapIncRowEqn[index]; | |
| 4591 | 31419 | return; | |
| 4592 | end if; | ||
| 4593 | end for; | ||
| 4594 | end getMostNonlinearEquation; | ||
| 4595 | |||
| 4596 | |||
| 4597 | protected function selectFromList_rev" selects Ints from inList by indexes given in selList | ||
| 4598 | author: Waurich TUD 2012-11" | ||
| 4599 | input List<Integer> inList,selList; | ||
| 4600 | output List<Integer> outList; | ||
| 4601 | protected | ||
| 4602 | Integer len; | ||
| 4603 | algorithm | ||
| 4604 | 32691 | len := listLength(inList); | |
| 4605 |
6/8✓ Branch 0 taken 46447 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 46447 times.
✓ Branch 4 taken 46447 times.
✓ Branch 5 taken 32691 times.
✓ Branch 6 taken 46447 times.
✓ Branch 7 taken 32691 times.
|
79138 | outList := list(listGet(inList,num) for num guard num > 0 and num <= len in selList); |
| 4606 | end selectFromList_rev; | ||
| 4607 | |||
| 4608 | |||
| 4609 | protected function selectFromList " selects Ints from inList by indexes given in selList in reverse order. | ||
| 4610 | auhtor: Waurich TUD 2012-11" | ||
| 4611 | input List<Integer> inList,selList; | ||
| 4612 | output List<Integer> outList = {}; | ||
| 4613 | protected | ||
| 4614 | Integer num,actual,len; | ||
| 4615 | algorithm | ||
| 4616 | ✗ | len := listLength(inList); | |
| 4617 | ✗ | for num in selList loop | |
| 4618 | ✗ | if num > 0 and num <= len then | |
| 4619 | ✗ | actual := listGet(inList,num); | |
| 4620 | outList := actual::outList; | ||
| 4621 | end if; | ||
| 4622 | end for; | ||
| 4623 | end selectFromList; | ||
| 4624 | |||
| 4625 | |||
| 4626 | protected function deleteEntriesFromAdjacencyMatrix "Deletes given entries from matrix. Applicable on Adjacency and on transposed Adjacency. | ||
| 4627 | author: ptaeuber 2015-02" | ||
| 4628 | input BackendDAE.AdjacencyMatrix mUpdate; | ||
| 4629 | input BackendDAE.AdjacencyMatrix mHelp; | ||
| 4630 | input list<Integer> entries; | ||
| 4631 | protected | ||
| 4632 | Integer rowIndx; | ||
| 4633 | list<Integer> rowsIndx, row; | ||
| 4634 | algorithm | ||
| 4635 |
2/2✓ Branch 0 taken 68076 times.
✓ Branch 1 taken 66850 times.
|
134926 | for entry in entries loop |
| 4636 | 68076 | rowsIndx := arrayGet(mHelp,entry); | |
| 4637 |
2/2✓ Branch 0 taken 142486 times.
✓ Branch 1 taken 68076 times.
|
210562 | for rowIndx in rowsIndx loop |
| 4638 | 142486 | row := arrayGet(mUpdate,rowIndx); | |
| 4639 | 142486 | row := List.deleteMemberOnTrue(entry, row, intEq); | |
| 4640 | 142486 | Array.replaceAtWithFill(rowIndx,row,row,mUpdate); | |
| 4641 | end for; | ||
| 4642 | end for; | ||
| 4643 | end deleteEntriesFromAdjacencyMatrix; | ||
| 4644 | |||
| 4645 | |||
| 4646 | protected function deleteRowsFromAdjacencyMatrix "Deletes given rows from matrix. Applicable on Adjacency and on transposed Adjacency. | ||
| 4647 | author: ptaeuber 2015-02" | ||
| 4648 | input BackendDAE.AdjacencyMatrix mUpdate; | ||
| 4649 | input list<Integer> rows; | ||
| 4650 | algorithm | ||
| 4651 |
2/2✓ Branch 0 taken 2032 times.
✓ Branch 1 taken 806 times.
|
2838 | for row in rows loop |
| 4652 | 2032 | Array.replaceAtWithFill(row,{},{},mUpdate); | |
| 4653 | end for; | ||
| 4654 | end deleteRowsFromAdjacencyMatrix; | ||
| 4655 | |||
| 4656 | |||
| 4657 | protected function getVarsOfEqnsWithMostVars "find vars occurring in the equations with the | ||
| 4658 | most variables considering the current matching. | ||
| 4659 | author: ptaeuber" | ||
| 4660 | input list<Integer> inVars; | ||
| 4661 | input BackendDAE.AdjacencyMatrix mIn; | ||
| 4662 | input BackendDAE.AdjacencyMatrixT mtIn; | ||
| 4663 | output list<Integer> outVars = {}; | ||
| 4664 | protected | ||
| 4665 | Integer size, maxSize = 0; | ||
| 4666 | list<Integer> eqns; | ||
| 4667 | array<Integer> eqn_size_arr; | ||
| 4668 | algorithm | ||
| 4669 | 148 | eqn_size_arr := arrayCreate(arrayLength(mIn),-1); | |
| 4670 |
1/2✓ Branch 0 taken 148 times.
✗ Branch 1 not taken.
|
108199 | for i in 1:arrayLength(mIn) loop |
| 4671 | 108051 | size := listLength(mIn[i]); | |
| 4672 | 108051 | eqn_size_arr[i] := size; | |
| 4673 | if size > maxSize then | ||
| 4674 | maxSize := size; | ||
| 4675 | end if; | ||
| 4676 | end for; | ||
| 4677 | |||
| 4678 |
2/2✓ Branch 0 taken 100068 times.
✓ Branch 1 taken 148 times.
|
100216 | for var in inVars loop |
| 4679 | 100068 | eqns := mtIn[var]; | |
| 4680 |
2/2✓ Branch 0 taken 288277 times.
✓ Branch 1 taken 80442 times.
|
368719 | for e in eqns loop |
| 4681 |
2/2✓ Branch 1 taken 19626 times.
✓ Branch 2 taken 268651 times.
|
288277 | if eqn_size_arr[e] == maxSize then |
| 4682 | outVars := var :: outVars; | ||
| 4683 | 19626 | break; | |
| 4684 | end if; | ||
| 4685 | end for; | ||
| 4686 | end for; | ||
| 4687 | 148 | GCExt.free(eqn_size_arr); | |
| 4688 | end getVarsOfEqnsWithMostVars; | ||
| 4689 | |||
| 4690 | |||
| 4691 | protected function getVarsOccurringInMostEquations | ||
| 4692 | "find rows in transposed adjacency matrix enhanced with most nonzero | ||
| 4693 | elements and put the indexes of these rows in a list. | ||
| 4694 | author: ptaeuber" | ||
| 4695 | input BackendDAE.AdjacencyMatrixT mtIn; | ||
| 4696 | input list<Integer> inSelect; | ||
| 4697 | output Integer length = 0; | ||
| 4698 | output list<Integer> outLst = {}; | ||
| 4699 | protected | ||
| 4700 | Integer length1; | ||
| 4701 | list<Integer> row; | ||
| 4702 | algorithm | ||
| 4703 |
2/2✓ Branch 0 taken 19670 times.
✓ Branch 1 taken 152 times.
|
19822 | for sel in inSelect loop |
| 4704 | 19670 | row := arrayGet(mtIn, sel); | |
| 4705 | 19670 | length1 := listLength(row); | |
| 4706 |
2/2✓ Branch 0 taken 393 times.
✓ Branch 1 taken 19277 times.
|
19670 | if intGt(length1,length) then |
| 4707 | length := length1; | ||
| 4708 | outLst := {sel}; | ||
| 4709 | elseif intEq(length1,length) then | ||
| 4710 | outLst := sel::outLst; | ||
| 4711 | end if; | ||
| 4712 | end for; | ||
| 4713 | end getVarsOccurringInMostEquations; | ||
| 4714 | |||
| 4715 | |||
| 4716 | protected function getVarOccurringInMostEquations "find rows in transposed adjacency matrix enhanced with most nonzero | ||
| 4717 | elements. Return the first found row index with most entries. | ||
| 4718 | author: ptaeuber" | ||
| 4719 | input BackendDAE.AdjacencyMatrixT mtIn; | ||
| 4720 | input list<Integer> inSelect; | ||
| 4721 | output Integer length = 0; | ||
| 4722 | output list<Integer> outLst = {}; | ||
| 4723 | protected | ||
| 4724 | Integer length1; | ||
| 4725 | list<Integer> row; | ||
| 4726 | algorithm | ||
| 4727 |
2/2✓ Branch 0 taken 10025 times.
✓ Branch 1 taken 3160 times.
|
13185 | for sel in inSelect loop |
| 4728 | 10025 | row := arrayGet(mtIn, sel); | |
| 4729 | 10025 | length1 := listLength(row); | |
| 4730 |
2/2✓ Branch 0 taken 3421 times.
✓ Branch 1 taken 6604 times.
|
10025 | if intGt(length1,length) then |
| 4731 | length := length1; | ||
| 4732 | outLst := {sel}; | ||
| 4733 | end if; | ||
| 4734 | end for; | ||
| 4735 | end getVarOccurringInMostEquations; | ||
| 4736 | |||
| 4737 | |||
| 4738 | protected function findNEntries " find rows with n nonzero elements and | ||
| 4739 | put the indexes of these rows in a list. | ||
| 4740 | author: Waurich TUD 2012-10" | ||
| 4741 | input BackendDAE.AdjacencyMatrix mtIn; | ||
| 4742 | input list<Integer> inSelect; | ||
| 4743 | input Integer num; | ||
| 4744 | output list<Integer> outList = {}; | ||
| 4745 | protected | ||
| 4746 | Integer length; | ||
| 4747 | list<Integer> row; | ||
| 4748 | algorithm | ||
| 4749 | ✗ | for sel in inSelect loop | |
| 4750 | ✗ | row := arrayGet(mtIn, sel); | |
| 4751 | ✗ | length := listLength(row); | |
| 4752 | ✗ | if intEq(num,length) then | |
| 4753 | outList := sel::outList; | ||
| 4754 | end if; | ||
| 4755 | end for; | ||
| 4756 | end findNEntries; | ||
| 4757 | |||
| 4758 | // ============================================================================= | ||
| 4759 | // section for preOptModule >>recursiveTearing<< | ||
| 4760 | // | ||
| 4761 | // inline and repeat tearing | ||
| 4762 | // author: Vitalij Ruge | ||
| 4763 | // ============================================================================= | ||
| 4764 | |||
| 4765 | public function recursiveTearing | ||
| 4766 | input BackendDAE.BackendDAE inDAE; | ||
| 4767 | output BackendDAE.BackendDAE outDAE; | ||
| 4768 | protected | ||
| 4769 | Boolean con; | ||
| 4770 | algorithm | ||
| 4771 |
1/2✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
|
17 | if Flags.getConfigInt(Flags.RTEARING) > 0 then |
| 4772 | 17 | (outDAE, con) := recursiveTearingMain(inDAE); | |
| 4773 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 17 times.
|
20 | while con loop |
| 4774 | 3 | outDAE := tearingSystem(outDAE); | |
| 4775 | 3 | (outDAE, con) := recursiveTearingMain(outDAE); | |
| 4776 | end while; | ||
| 4777 | else | ||
| 4778 | outDAE := inDAE; | ||
| 4779 | end if; | ||
| 4780 | end recursiveTearing; | ||
| 4781 | |||
| 4782 | protected function recursiveTearingMain | ||
| 4783 | input BackendDAE.BackendDAE inDAE; | ||
| 4784 | output BackendDAE.BackendDAE outDAE; | ||
| 4785 | output Boolean update = false; | ||
| 4786 | protected | ||
| 4787 | list<BackendDAE.EqSystem> systlst_new = {}; | ||
| 4788 | BackendDAE.Shared shared; | ||
| 4789 | AvlTreePathFunction.Tree funcs; | ||
| 4790 | BackendDAE.Variables vars, globalKnownVars; | ||
| 4791 | BackendDAE.StrongComponents comps; | ||
| 4792 | BackendDAE.EquationArray eqns; | ||
| 4793 | BackendDAE.StateSets stateSets; | ||
| 4794 | BackendDAE.BaseClockPartitionKind partitionKind; | ||
| 4795 | |||
| 4796 | BackendDAE.InnerEquations innerEquations; | ||
| 4797 | BackendDAE.InnerEquation innerEquation; | ||
| 4798 | Integer eqindex, vindex; | ||
| 4799 | list<Integer> residualequations; | ||
| 4800 | list<Integer> tearingvars; | ||
| 4801 | list<BackendDAE.Var> var_lst; | ||
| 4802 | BackendDAE.Var var; | ||
| 4803 | array<DAE.ComponentRef> tear_cr; | ||
| 4804 | list<DAE.ComponentRef> tear_cr_lst, all_vars = {}; | ||
| 4805 | array<DAE.Exp> tear_exp; | ||
| 4806 | DAE.ComponentRef cr; | ||
| 4807 | BackendDAE.Equation eqn, eqn1; | ||
| 4808 | DAE.Exp rhs, lhs, rhs1, sumRhs, sumLhs, e, res; | ||
| 4809 | Integer n, i, j, m, index = 1; | ||
| 4810 | array<Option<BackendDAE.Equation>> optarr, optarr_res; | ||
| 4811 | array<Integer> indx_res, indx_eq, indx_var; | ||
| 4812 | Boolean tmp_update, isDer; | ||
| 4813 | BackendDAE.AdjacencyMatrix mm; | ||
| 4814 | Boolean maxSizeOne = Flags.getConfigInt(Flags.RTEARING) == 1; | ||
| 4815 | list<DAE.Exp> loopT, noLoopT; | ||
| 4816 | algorithm | ||
| 4817 | 20 | shared := inDAE.shared; | |
| 4818 | 20 | BackendDAE.SHARED(functionTree=funcs, globalKnownVars=globalKnownVars) := shared; | |
| 4819 | //BackendDump.bltdump("IN:", inDAE); | ||
| 4820 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
|
40 | for syst in inDAE.eqs loop |
| 4821 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
20 | BackendDAE.EQSYSTEM(orderedVars=vars,orderedEqs=eqns,matching=BackendDAE.MATCHING(comps=comps),stateSets=stateSets,partitionKind=partitionKind) := syst; |
| 4822 | 40 | (_, mm, _) := BackendDAEUtil.getAdjacencyMatrix(syst, BackendDAE.SPARSE(), SOME(funcs), BackendDAEUtil.isInitializationDAE(shared)); | |
| 4823 | tmp_update := false; | ||
| 4824 |
2/2✓ Branch 0 taken 66 times.
✓ Branch 1 taken 20 times.
|
86 | for comp in comps loop |
| 4825 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 63 times.
|
66 | if isTornsystem(comp, true, false) then |
| 4826 | // ----- | ||
| 4827 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | BackendDAE.TORNSYSTEM(BackendDAE.TEARINGSET(innerEquations = innerEquations, residualequations= residualequations, tearingvars=tearingvars)) := comp; |
| 4828 | 3 | n := listLength(innerEquations); | |
| 4829 | 3 | m := listLength(residualequations); | |
| 4830 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if maxSizeOne and m > 1 then |
| 4831 | ✗ | continue; | |
| 4832 | end if; | ||
| 4833 | 3 | indx_res := arrayCreate(m,0); | |
| 4834 | 3 | indx_var := arrayCreate(n,0); | |
| 4835 | 3 | indx_eq := arrayCreate(n,0); | |
| 4836 | i := 1; | ||
| 4837 | 3 | optarr := arrayCreate(n, NONE()); | |
| 4838 | 3 | update := true; | |
| 4839 | tmp_update := true; | ||
| 4840 | // ----- | ||
| 4841 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 3 times.
|
12 | for innerEquation in innerEquations loop |
| 4842 |
2/4✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 9 times.
|
9 | (eqindex, {vindex}, _) := BackendDAEUtil.getEqnAndVarsFromInnerEquation(innerEquation); |
| 4843 | 9 | var as BackendDAE.VAR(varName = cr) := BackendVariable.getVarAt(vars, vindex); | |
| 4844 | all_vars := cr :: all_vars; | ||
| 4845 | 9 | arrayUpdate(indx_var,i,vindex); | |
| 4846 | 9 | eqn := BackendEquation.get(eqns, eqindex); | |
| 4847 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
|
9 | if BackendVariable.isStateVar(var) then |
| 4848 | ✗ | eqn := BackendEquation.solveEquation(eqn, Expression.expDer(Expression.crefExp(cr)), SOME(funcs)); | |
| 4849 | else | ||
| 4850 | 9 | eqn := BackendEquation.solveEquation(eqn, Expression.crefExp(cr), SOME(funcs)); | |
| 4851 | end if; | ||
| 4852 | 9 | arrayUpdate(optarr, i, SOME(eqn)); | |
| 4853 | 9 | eqns := BackendEquation.setAtIndex(eqns, eqindex, eqn); | |
| 4854 | 9 | arrayUpdate(indx_eq, i , eqindex); | |
| 4855 | 9 | i := i + 1; | |
| 4856 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 1 time.
|
9 | if Flags.isSet(Flags.DUMP_RTEARING) then |
| 4857 | 8 | print("INeqn => " + BackendDump.equationString(eqn) + "[" + intString(i-1) + "]\n"); | |
| 4858 | end if; | ||
| 4859 | end for; //innerEquations | ||
| 4860 | |||
| 4861 | // ----- | ||
| 4862 |
4/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
|
6 | var_lst := list(BackendVariable.getVarAt(vars, i) for i in tearingvars); |
| 4863 |
4/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 3 times.
|
6 | tear_cr_lst := list(BackendVariable.varCref(vv) for vv in var_lst); |
| 4864 | 3 | tear_cr := listArray(tear_cr_lst); | |
| 4865 | 3 | all_vars := listAppend(tear_cr_lst, all_vars); | |
| 4866 | 3 | tear_exp := arrayCreate(m, DAE.RCONST(0.0)); | |
| 4867 | i := 1; | ||
| 4868 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 3 times.
|
6 | for tcr in tear_cr loop |
| 4869 | 3 | arrayUpdate(tear_exp, i, Expression.crefExp(tcr)); | |
| 4870 | 3 | i := i +1; | |
| 4871 | end for; //cr | ||
| 4872 | // ----- | ||
| 4873 | 3 | optarr_res := arrayCreate(m, NONE()); | |
| 4874 | |||
| 4875 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
6 | for i in 1:m loop |
| 4876 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | eqindex :: residualequations := residualequations; |
| 4877 | 3 | arrayUpdate(indx_res, i , eqindex); | |
| 4878 | 3 | eqn := BackendEquation.get(eqns, eqindex); | |
| 4879 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 time.
|
3 | if Flags.isSet(Flags.DUMP_RTEARING) then |
| 4880 | 2 | print("INres => " + BackendDump.equationString(eqn) + "[" + intString(i) + "]\n"); | |
| 4881 | end if; | ||
| 4882 | 3 | arrayUpdate(optarr_res, i, SOME(eqn)); | |
| 4883 | end for; | ||
| 4884 | |||
| 4885 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | for i in 1:n loop |
| 4886 |
2/4✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
|
9 | SOME(eqn) := arrayGet(optarr, i); |
| 4887 | 9 | rhs := BackendEquation.getEquationRHS(eqn); | |
| 4888 | 9 | lhs := BackendEquation.getEquationLHS(eqn); | |
| 4889 | 9 | (cr,isDer) := Expression.expOrDerCref(lhs); | |
| 4890 | |||
| 4891 | //print("*****" + ExpressionBasics.printExpStr(lhs) + "= " + ExpressionBasics.printExpStr(rhs) + "*******\n"); | ||
| 4892 |
2/2✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
|
21 | for j in (i+1):n loop |
| 4893 |
2/2✓ Branch 4 taken 6 times.
✓ Branch 5 taken 6 times.
|
12 | if listMember(arrayGet(indx_var,i) , arrayGet(mm, arrayGet(indx_eq,j))) then |
| 4894 |
2/4✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6 times.
|
6 | SOME(eqn1) := arrayGet(optarr, j); |
| 4895 | //print("\n (" + intString(i) + "," + intString(j) + ") => \n" + BackendDump.equationString(eqn1)); | ||
| 4896 | 6 | rhs1 := BackendEquation.getEquationRHS(eqn1); | |
| 4897 | 6 | rhs1 := recursiveTearingReplace(rhs1, cr, rhs, isDer); | |
| 4898 | 6 | rhs1 := recursiveTearingCollect(tear_exp, rhs1); | |
| 4899 | 6 | (index, vars, eqns, shared, _, e, _, _, _) := BackendDAEOptimize.simplifyLoopExp(index, vars, eqns, shared, all_vars, rhs1, {}, {}, true, true,-1,{}, "RTEARING"); | |
| 4900 | 6 | eqn1 := BackendEquation.setEquationRHS(eqn1, e); | |
| 4901 | //print( "=>" + BackendDump.equationString(eqn1) + "\n"); | ||
| 4902 | 6 | arrayUpdate(optarr,j,SOME(eqn1)); | |
| 4903 | end if; | ||
| 4904 | end for; // j | ||
| 4905 | |||
| 4906 | //res eqn | ||
| 4907 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
18 | for j in 1:m loop |
| 4908 |
2/2✓ Branch 4 taken 3 times.
✓ Branch 5 taken 6 times.
|
9 | if listMember(arrayGet(indx_var,i) , arrayGet(mm, arrayGet(indx_res,j))) then |
| 4909 |
2/4✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
|
3 | SOME(eqn1) := arrayGet(optarr_res, j); |
| 4910 | |||
| 4911 | 3 | res := BackendDAEOptimize.makeEquationToResidualExp(eqn1); | |
| 4912 | 3 | res := recursiveTearingCollect(tear_exp, res); | |
| 4913 | 3 | (loopT, noLoopT) := BackendDAEOptimize.simplifyLoops_SplitTerms(all_vars, res); | |
| 4914 | |||
| 4915 | 3 | sumRhs := Expression.makeSum1(noLoopT,true); | |
| 4916 | 3 | sumLhs := Expression.makeSum1(loopT,true); | |
| 4917 | |||
| 4918 | 3 | sumRhs := recursiveTearingReplace(sumRhs, cr, rhs, isDer); | |
| 4919 | 3 | sumLhs := recursiveTearingReplace(sumLhs, cr, rhs, isDer); | |
| 4920 | |||
| 4921 | 3 | sumRhs := recursiveTearingCollect(tear_exp,sumRhs); | |
| 4922 | 3 | sumLhs := recursiveTearingCollect(tear_exp,sumLhs); | |
| 4923 | |||
| 4924 | // RHS | ||
| 4925 | 3 | (sumRhs,_) := ExpressionSimplify.simplify(sumRhs); | |
| 4926 | 3 | (index, vars, eqns, shared, _, sumRhs, _, _, _) := BackendDAEOptimize.simplifyLoopExp(index, vars, eqns, shared, all_vars, sumRhs, {}, {}, true, true,-1,{}, "RTEARING"); | |
| 4927 | 3 | eqn1 := BackendEquation.setEquationRHS(eqn1, Expression.negate(sumRhs)); | |
| 4928 | |||
| 4929 | //LHS | ||
| 4930 | 3 | (sumLhs,_) := ExpressionSimplify.simplify(sumLhs); | |
| 4931 | 3 | (index, vars, eqns, shared, _, sumLhs, _, _, _) := BackendDAEOptimize.simplifyLoopExp(index, vars, eqns, shared, all_vars, sumLhs, {}, {}, true, true,-1,{}, "RTEARING"); | |
| 4932 | 3 | eqn1 := BackendEquation.setEquationLHS(eqn1, sumLhs); | |
| 4933 | 3 | arrayUpdate(optarr_res,j,SOME(eqn1)); | |
| 4934 | end if; // listMember | ||
| 4935 | end for;//j | ||
| 4936 | end for; // i | ||
| 4937 | |||
| 4938 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
12 | for i in 1:n loop |
| 4939 | 9 | eqindex := arrayGet(indx_eq,i); | |
| 4940 |
2/4✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9 times.
|
9 | SOME(eqn) := arrayGet(optarr, i); |
| 4941 | 9 | eqns := BackendEquation.setAtIndex(eqns, eqindex, eqn); | |
| 4942 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 1 time.
|
9 | if Flags.isSet(Flags.DUMP_RTEARING) then |
| 4943 | 8 | print("OUTeqn => " + BackendDump.equationString(eqn) + "[" + intString(i-1) + "]\n"); | |
| 4944 | end if; | ||
| 4945 | end for; // i | ||
| 4946 | |||
| 4947 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
6 | for i in 1:m loop |
| 4948 | 3 | eqindex := arrayGet(indx_res,i); | |
| 4949 |
2/4✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
|
3 | SOME(eqn) := arrayGet(optarr_res, i); |
| 4950 | 3 | eqns := BackendEquation.setAtIndex(eqns, eqindex, eqn); | |
| 4951 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 time.
|
3 | if Flags.isSet(Flags.DUMP_RTEARING) then |
| 4952 | 2 | print("OUTres => " + BackendDump.equationString(eqn) + "[" + intString(i-1) + "]\n"); | |
| 4953 | end if; | ||
| 4954 | end for; // i | ||
| 4955 | |||
| 4956 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 time.
|
3 | if Flags.isSet(Flags.DUMP_RTEARING) then |
| 4957 | 2 | print("****************\n"); | |
| 4958 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
4 | for i in 1:m loop |
| 4959 | 2 | print("TearVar: " + ExpressionBasics.printExpStr(arrayGet(tear_exp, i)) + "[" + intString(i-1) + "]\n"); | |
| 4960 | end for; | ||
| 4961 | 2 | print("****************\n"); | |
| 4962 | end if; | ||
| 4963 | |||
| 4964 | end if; // isTornsystem | ||
| 4965 | end for; // comp | ||
| 4966 | |||
| 4967 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 17 times.
|
20 | if tmp_update then |
| 4968 | 3 | systlst_new := BackendDAEUtil.createEqSystem(vars, eqns, stateSets, partitionKind) :: systlst_new; | |
| 4969 | else | ||
| 4970 | systlst_new := syst :: systlst_new; | ||
| 4971 | end if; | ||
| 4972 | |||
| 4973 | end for; // syst | ||
| 4974 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 17 times.
|
20 | if update then |
| 4975 | 3 | outDAE := BackendDAE.DAE(systlst_new, shared); | |
| 4976 | try | ||
| 4977 | 3 | outDAE := BackendDAEUtil.transformBackendDAE(outDAE,SOME((BackendDAE.NO_INDEX_REDUCTION(),BackendDAE.EXACT())),NONE(),NONE()); | |
| 4978 | else | ||
| 4979 | update := false; | ||
| 4980 | end try; | ||
| 4981 | else | ||
| 4982 | outDAE := inDAE; | ||
| 4983 | end if; | ||
| 4984 | //BackendDAE.DAE(systlst_new) := outDAE; | ||
| 4985 | //outDAE := BackendDAE.DAE(systlst_new, shared); | ||
| 4986 | //BackendDump.bltdump("OUT:", outDAE); | ||
| 4987 | end recursiveTearingMain; | ||
| 4988 | |||
| 4989 | protected function recursiveTearingCollect | ||
| 4990 | input array<DAE.Exp> tear_exp; | ||
| 4991 | input DAE.Exp inExp; | ||
| 4992 | output DAE.Exp outExp; | ||
| 4993 | protected | ||
| 4994 | Integer k; | ||
| 4995 | DAE.Exp lhs, e1, e2; | ||
| 4996 | algorithm | ||
| 4997 | |||
| 4998 | 15 | (e1, e2) := ExpressionSolve.collectX(inExp, arrayGet(tear_exp, 1)); | |
| 4999 | |||
| 5000 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 15 times.
|
15 | for k in 2:arrayLength(tear_exp) loop |
| 5001 | ✗ | (lhs, e2) := ExpressionSolve.collectX(e2, arrayGet(tear_exp, k)); | |
| 5002 | ✗ | e1 := Expression.expAdd(e1, lhs); | |
| 5003 | end for; | ||
| 5004 | 15 | outExp := Expression.expAdd(e2, e1); | |
| 5005 | end recursiveTearingCollect; | ||
| 5006 | |||
| 5007 | protected function isTornsystem | ||
| 5008 | input BackendDAE.StrongComponent comp; | ||
| 5009 | input Boolean getLin = true; | ||
| 5010 | input Boolean getNoLin = false; | ||
| 5011 | output Boolean res; | ||
| 5012 | |||
| 5013 | algorithm | ||
| 5014 | res := match comp | ||
| 5015 | local Boolean linear; | ||
| 5016 | |||
| 5017 | case BackendDAE.TORNSYSTEM(linear=linear) | ||
| 5018 | guard linear == getLin or getNoLin == (not linear) | ||
| 5019 | then true; | ||
| 5020 | else false; | ||
| 5021 | end match; | ||
| 5022 | end isTornsystem; | ||
| 5023 | |||
| 5024 | protected function recursiveTearingHelper | ||
| 5025 | " | ||
| 5026 | collect expression | ||
| 5027 | " | ||
| 5028 | input DAE.Exp rhs1; | ||
| 5029 | input array<DAE.Exp> tear_exp; | ||
| 5030 | input Integer m; | ||
| 5031 | output DAE.Exp sumRhs = Expression.makeConstZeroE(rhs1); | ||
| 5032 | protected | ||
| 5033 | Integer k; | ||
| 5034 | DAE.Exp e, rhs = rhs1; | ||
| 5035 | algorithm | ||
| 5036 | ✗ | for k in 1:m loop | |
| 5037 | ✗ | (e, rhs) := ExpressionSolve.collectX(rhs, arrayGet(tear_exp, k)); | |
| 5038 | ✗ | sumRhs := Expression.expAdd(e, sumRhs); | |
| 5039 | end for; | ||
| 5040 | ✗ | sumRhs := Expression.expAdd(rhs, sumRhs); | |
| 5041 | ✗ | (sumRhs,_) := ExpressionSimplify.simplify(sumRhs); | |
| 5042 | end recursiveTearingHelper; | ||
| 5043 | |||
| 5044 | protected function recursiveTearingReplace | ||
| 5045 | input DAE.Exp inExp; | ||
| 5046 | input DAE.ComponentRef inSourceExp; | ||
| 5047 | input DAE.Exp inTargetExp; | ||
| 5048 | input Boolean isDer; | ||
| 5049 | output DAE.Exp res; | ||
| 5050 | algorithm | ||
| 5051 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if isDer then |
| 5052 | ✗ | res := Expression.crefExp(inSourceExp); | |
| 5053 | ✗ | res := Expression.expDer(res); | |
| 5054 | ✗ | (res,_) := Expression.replaceExp(inExp, res, inTargetExp); | |
| 5055 | else | ||
| 5056 | 12 | res := Expression.replaceCrefBottomUp(inExp, inSourceExp, inTargetExp); | |
| 5057 | end if; | ||
| 5058 | |||
| 5059 | end recursiveTearingReplace; | ||
| 5060 | |||
| 5061 | |||
| 5062 | protected function getUnassigned | ||
| 5063 | input array<Integer> ass; | ||
| 5064 | output list<Integer> unassigned={}; | ||
| 5065 | algorithm | ||
| 5066 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9422 times.
|
1521640 | for i in 1:arrayLength(ass) loop |
| 5067 |
2/2✓ Branch 0 taken 865292 times.
✓ Branch 1 taken 646926 times.
|
1512218 | if Dangerous.arrayGetNoBoundsChecking(ass, i) < 0 then |
| 5068 | unassigned := i::unassigned; | ||
| 5069 | end if; | ||
| 5070 | end for; | ||
| 5071 | end getUnassigned; | ||
| 5072 | |||
| 5073 | |||
| 5074 | protected function dumpTearingSetLocalIndexes | ||
| 5075 | input list<Integer> tVars,residuals,order; | ||
| 5076 | input array<Integer> ass2; | ||
| 5077 | input Integer size; | ||
| 5078 | input array<list<Integer>> mapEqnIncRow; | ||
| 5079 | input BackendDAE.Variables vars; | ||
| 5080 | input BackendDAE.EquationArray eqns; | ||
| 5081 | input String setString; | ||
| 5082 | protected | ||
| 5083 | list<String> s; | ||
| 5084 | algorithm | ||
| 5085 | 3 | print("\n" + BORDER + "\n* TEARING RESULTS" + setString + ":\n* (Local Indexes)\n*\n* No of equations in strong component: "+intString(size)+"\n"); | |
| 5086 | 3 | print("* No of tVars: "+intString(listLength(tVars))+"\n"); | |
| 5087 | 3 | print("*\n* tVars: "+ stringDelimitList(List.map(listReverse(tVars),intString),",") + "\n"); | |
| 5088 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
|
3 | if Flags.isSet(Flags.ITERATION_VARS) then |
| 5089 | ✗ | s := list("* " + intString(tVar) + ": " + BackendDump.varString(BackendVariable.getVarAt(vars,tVar)) for tVar in tVars); | |
| 5090 | ✗ | print(stringDelimitList(s, "\n") + "\n"); | |
| 5091 | end if; | ||
| 5092 | 3 | print("*\n* resEq: "+ stringDelimitList(List.map(residuals,intString),",") + "\n"); | |
| 5093 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
3 | if Flags.isSet(Flags.ITERATION_VARS) and Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 5094 | ✗ | s := list("* " + intString(eqn) + ": " + BackendDump.equationString(BackendEquation.get(eqns,eqn)) for eqn in residuals); | |
| 5095 | ✗ | print(stringDelimitList(s, "\n") + "\n"); | |
| 5096 | end if; | ||
| 5097 |
4/4✓ Branch 0 taken 7 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 3 times.
|
10 | s := list("{" + intString(e) + ":" + stringDelimitList(List.map(List.map1r(mapEqnIncRow[e],arrayGet,ass2),intString),",") + "}" for e in order); |
| 5098 | 3 | print("*\n* innerEquations ({eqn,vars}):\n* " + stringDelimitList(s,", ") + "\n*\n" + BORDER + "\n\n"); | |
| 5099 | end dumpTearingSetLocalIndexes; | ||
| 5100 | |||
| 5101 | |||
| 5102 | protected function dumpTearingSetGlobalIndexes | ||
| 5103 | input BackendDAE.TearingSet tearingSet; | ||
| 5104 | input Integer size; | ||
| 5105 | input String setString; | ||
| 5106 | protected | ||
| 5107 | list<Integer> tVars,residuals; | ||
| 5108 | BackendDAE.InnerEquations innerEquations; | ||
| 5109 | algorithm | ||
| 5110 | 24 | BackendDAE.TEARINGSET(tearingvars=tVars,residualequations=residuals,innerEquations=innerEquations) := tearingSet; | |
| 5111 | 24 | print("\n" + BORDER + "\n* TEARING RESULTS" + setString + ":\n* (Global Indexes)\n*\n* No of equations in strong component: "+intString(size)+"\n"); | |
| 5112 | 24 | print("* No of tVars: "+intString(listLength(tVars))+"\n"); | |
| 5113 | 24 | print("*\n* tVars: "+ stringDelimitList(List.map(listReverse(tVars),intString),",") + "\n"); | |
| 5114 | 24 | print("*\n* resEq: "+ stringDelimitList(List.map(residuals,intString),",") + "\n"); | |
| 5115 | 24 | print("*\n* innerEquations ({eqn,vars}):\n* " + stringDelimitList(List.map(innerEquations, BackendDump.innerEquationString),", ") + "\n*\n*" + BORDER + "\n\n"); | |
| 5116 | end dumpTearingSetGlobalIndexes; | ||
| 5117 | |||
| 5118 | |||
| 5119 | protected function dumpTearingSetsGlobalIndexes | ||
| 5120 | input list<BackendDAE.TearingSet> tearingSets; | ||
| 5121 | input Integer size; | ||
| 5122 | algorithm | ||
| 5123 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 1 time.
|
25 | for tearingSet in tearingSets loop |
| 5124 | 24 | dumpTearingSetGlobalIndexes(tearingSet,size,""); | |
| 5125 | end for; | ||
| 5126 | end dumpTearingSetsGlobalIndexes; | ||
| 5127 | |||
| 5128 | |||
| 5129 | // ============================================================================= | ||
| 5130 | // | ||
| 5131 | // Total Tearing - Determination of All Possible Tearing Sets | ||
| 5132 | // author: ptaeuber FHB 2016 | ||
| 5133 | // | ||
| 5134 | // ============================================================================= | ||
| 5135 | |||
| 5136 | protected function totalTearing " determination of all possible tearing sets | ||
| 5137 | author: ptaeuber FHB 2016" | ||
| 5138 | input BackendDAE.EqSystem isyst; | ||
| 5139 | input BackendDAE.Shared ishared; | ||
| 5140 | input list<Integer> eindex; | ||
| 5141 | input list<Integer> vindx; | ||
| 5142 | input Option<list<tuple<Integer, Integer, BackendDAE.Equation>>> ojac; | ||
| 5143 | input BackendDAE.JacobianType jacType; | ||
| 5144 | input Boolean mixedSystem; | ||
| 5145 | output BackendDAE.StrongComponent ocomp; | ||
| 5146 | output Boolean outRunMatching; | ||
| 5147 | protected | ||
| 5148 | Integer size; | ||
| 5149 | array<Integer> ass1,ass2,mapIncRowEqn; | ||
| 5150 | array<list<Integer>> mapEqnIncRow; | ||
| 5151 | list<Integer> tVars,order,causEq,unsolvables,discreteVars; | ||
| 5152 | BackendDAE.EqSystem subsyst; | ||
| 5153 | BackendDAE.Variables vars; | ||
| 5154 | BackendDAE.EquationArray eqns; | ||
| 5155 | BackendDAE.AdjacencyMatrix m,mLoop; | ||
| 5156 | BackendDAE.AdjacencyMatrix mt,mtLoop; | ||
| 5157 | BackendDAE.AdjacencyMatrixEnhanced me; | ||
| 5158 | BackendDAE.AdjacencyMatrixTEnhanced meT; | ||
| 5159 | BackendDAE.BackendDAEType DAEtype; | ||
| 5160 | list<BackendDAE.TearingSet> tearingSets; | ||
| 5161 | list<BackendDAE.Equation> eqn_lst; | ||
| 5162 | list<BackendDAE.Var> var_lst; | ||
| 5163 | Boolean linear; | ||
| 5164 | String modelName; | ||
| 5165 | list<list<Integer>> powerSet={}; | ||
| 5166 | list<tuple<array<Integer>,array<Integer>,list<Integer>>> matchingList; | ||
| 5167 | UnorderedSet<array<Integer>> visited; | ||
| 5168 | algorithm | ||
| 5169 | 1 | linear := BackendDAEUtil.getLinearfromJacType(jacType); | |
| 5170 | BackendDAE.SHARED(backendDAEType=DAEtype, info=BackendDAE.EXTRA_INFO(fileNamePrefix=modelName)) := ishared; | ||
| 5171 | |||
| 5172 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
|
1 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 5173 | ✗ | print("\n" + BORDER + "\nBEGINNING of totalTearing\n\n"); | |
| 5174 | end if; | ||
| 5175 | |||
| 5176 | // Generate Subsystem to get the adjacency matrix | ||
| 5177 | 1 | size := listLength(vindx); | |
| 5178 | 1 | eqn_lst := BackendEquation.getList(eindex,BackendEquation.getEqnsFromEqSystem(isyst)); | |
| 5179 | 1 | eqns := BackendEquation.listEquation(eqn_lst); | |
| 5180 | 1 | var_lst := List.map1r(vindx, BackendVariable.getVarAt, BackendVariable.daeVars(isyst)); | |
| 5181 | 1 | vars := BackendVariable.listVar1(var_lst); | |
| 5182 | 1 | subsyst := BackendDAEUtil.createEqSystem(vars, eqns); | |
| 5183 | 1 | (subsyst,m,mt,_,_) := BackendDAEUtil.getAdjacencyMatrixScalar(subsyst, BackendDAE.NORMAL(),NONE(), BackendDAEUtil.isInitializationDAE(ishared)); | |
| 5184 | |||
| 5185 | |||
| 5186 | // Delete negative entries from adjacency matrix | ||
| 5187 | 1 | m := Array.map(m,deleteNegativeEntries); | |
| 5188 | 1 | mt := Array.map(mt,deleteNegativeEntries); | |
| 5189 | |||
| 5190 |
2/4✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 time.
|
1 | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 5191 | ✗ | print("\n\n###BEGIN print Strong Component#####################\n(Function:totalTearing)\n"); | |
| 5192 | ✗ | BackendDump.printEqSystem(subsyst); | |
| 5193 | ✗ | print("\n###END print Strong Component#######################\n(Function:totalTearing)\n\n\n"); | |
| 5194 | end if; | ||
| 5195 | |||
| 5196 | // Get advanced adjacency matrix (determine how the variables occur in the equations) | ||
| 5197 | 1 | (me,meT,mapEqnIncRow,mapIncRowEqn) := BackendDAEUtil.getAdjacencyMatrixEnhancedScalar(subsyst,ishared,false); | |
| 5198 | |||
| 5199 | // Determine unsolvable vars to consider solvability | ||
| 5200 | 1 | unsolvables := getUnsolvableVars(size,meT); | |
| 5201 | |||
| 5202 |
2/4✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 time.
|
1 | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 5203 | ✗ | print("\nAdjacencyMatrixEnhanced:\n"); | |
| 5204 | ✗ | BackendDump.dumpAdjacencyMatrixEnhanced(me); | |
| 5205 | ✗ | print("\nAdjacencyMatrixTransposedEnhanced:\n"); | |
| 5206 | ✗ | BackendDump.dumpAdjacencyMatrixTEnhanced(meT); | |
| 5207 | end if; | ||
| 5208 | |||
| 5209 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
|
1 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 5210 | ✗ | print("\n\nmapEqnIncRow:"); //+ stringDelimitList(List.map(List.flatten(arrayList(mapEqnIncRow)),intString),",") + "\n\n"); | |
| 5211 | ✗ | BackendDump.dumpAdjacencyMatrix(mapEqnIncRow); | |
| 5212 | ✗ | print("\nmapIncRowEqn:\n" + stringDelimitList(List.mapArray(mapIncRowEqn, intString),",") + "\n\n"); | |
| 5213 | ✗ | print("\n\nUNSOLVABLES:\n" + stringDelimitList(List.map(unsolvables,intString),",") + "\n\n"); | |
| 5214 | end if; | ||
| 5215 | |||
| 5216 | // Determine discrete vars | ||
| 5217 | 1 | discreteVars := findDiscrete(var_lst); | |
| 5218 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
|
1 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 5219 | ✗ | print("\nDiscrete Vars:\n" + stringDelimitList(List.map(discreteVars,intString),",") + "\n\n"); | |
| 5220 | end if; | ||
| 5221 | |||
| 5222 | |||
| 5223 | // Determine all possible sets of tearing variables and save them in powerSet | ||
| 5224 | // ****************************************** | ||
| 5225 | |||
| 5226 |
1/2✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
|
16 | for i in (Util.intPow(2,size)-1):-1:1 loop |
| 5227 | 15 | powerSet := getPowerSetElement(i)::powerSet; | |
| 5228 | end for; | ||
| 5229 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
1 | if Flags.isSet(Flags.TOTAL_TEARING_DUMP) or Flags.isSet(Flags.TOTAL_TEARING_DUMPVERBOSE) then |
| 5230 | 1 | BackendDump.dumpListList(powerSet,"Power Set"); | |
| 5231 | end if; | ||
| 5232 | |||
| 5233 | |||
| 5234 | |||
| 5235 | // BEGIN TO LOOP | ||
| 5236 | // ****************************************** | ||
| 5237 | tearingSets := {}; | ||
| 5238 | |||
| 5239 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
1 | if Flags.isSet(Flags.TOTAL_TEARING_DUMP) or Flags.isSet(Flags.TOTAL_TEARING_DUMPVERBOSE) then |
| 5240 | 1 | print("\n\n###BEGIN TO LOOP#####################\n" + BORDER + "\n\n\n"); | |
| 5241 | end if; | ||
| 5242 | |||
| 5243 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 1 time.
|
16 | for tVars in powerSet loop |
| 5244 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
|
15 | if Flags.isSet(Flags.TOTAL_TEARING_DUMPVERBOSE) then |
| 5245 | ✗ | print("\ntVars:\n" + stringDelimitList(List.map(tVars,intString),",") + "\n\n"); | |
| 5246 | end if; | ||
| 5247 | |||
| 5248 | |||
| 5249 | // Initialize matching | ||
| 5250 | 15 | ass1 := arrayCreate(size,-1); | |
| 5251 | 15 | ass2 := arrayCreate(size,-1); | |
| 5252 | order := {}; | ||
| 5253 | |||
| 5254 | 15 | mLoop := arrayCopy(m); | |
| 5255 | 15 | mtLoop := arrayCopy(mt); | |
| 5256 | |||
| 5257 | // mark tVars in ass1 | ||
| 5258 | 15 | markTVarsOrResiduals(tVars, ass1); | |
| 5259 | |||
| 5260 | // remove tearing vars from adjacency matrix and transposed adjacency matrix | ||
| 5261 | 15 | deleteEntriesFromAdjacencyMatrix(mLoop, mtLoop, tVars); | |
| 5262 | 15 | deleteRowsFromAdjacencyMatrix(mtLoop, tVars); | |
| 5263 | |||
| 5264 | // initially find equations which can be causalized in the next step and save in causEq | ||
| 5265 | 15 | causEq := traverseCollectiveEqnsforAssignable(ass2,mLoop,mapEqnIncRow); | |
| 5266 | |||
| 5267 | // if Flags.isSet(Flags.TOTAL_TEARING_DUMPVERBOSE) then | ||
| 5268 | // print("\nInitial ass1: " + stringDelimitList(List.mapArray(ass1, intString),",")+"\n"); | ||
| 5269 | // print("Initial ass2: " + stringDelimitList(List.mapArray(ass2, intString),",") + "\n"); | ||
| 5270 | // print("\nInitial m:");BackendDump.dumpAdjacencyMatrix(mLoop); | ||
| 5271 | // print("\nInitial mt:");BackendDump.dumpAdjacencyMatrix(mtLoop); | ||
| 5272 | // print("\nInitial causEq: " + stringDelimitList(List.map(causEq,intString),",") + "\n"); | ||
| 5273 | // print("Initial order: " + stringDelimitList(List.map(order,intString),",") + "\n\n\n\n"); | ||
| 5274 | // end if; | ||
| 5275 | |||
| 5276 | |||
| 5277 | // Find all possible matchings for this set of tearing variables. | ||
| 5278 | // The visited set memoizes already explored assignment states so that | ||
| 5279 | // states reachable via several causalization orders are only expanded once. | ||
| 5280 | 15 | visited := UnorderedSet.new(Array.hashIntArray, Array.isEqual); | |
| 5281 | 15 | matchingList := totalMatching(ass1,ass2,order,causEq,mLoop,mtLoop,me,mapEqnIncRow,mapIncRowEqn,visited,{}); | |
| 5282 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 15 times.
|
15 | if Flags.isSet(Flags.TOTAL_TEARING_DUMPVERBOSE) then |
| 5283 | ✗ | dumpMatchingList(matchingList); | |
| 5284 | end if; | ||
| 5285 | |||
| 5286 | // save tearing sets in list | ||
| 5287 | 15 | tearingSets := createTearingSets(tVars,matchingList,vindx,eindex,mapEqnIncRow,mapIncRowEqn,tearingSets); | |
| 5288 | |||
| 5289 | end for; | ||
| 5290 | |||
| 5291 | // dump all different tearing sets | ||
| 5292 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
1 | if Flags.isSet(Flags.TOTAL_TEARING_DUMP) or Flags.isSet(Flags.TOTAL_TEARING_DUMPVERBOSE) then |
| 5293 | 1 | dumpTearingSetsGlobalIndexes(tearingSets,size); | |
| 5294 | end if; | ||
| 5295 | |||
| 5296 | // Determine the rest of the information needed for BackendDAE.TORNSYSTEM | ||
| 5297 | // *************************************************************************** | ||
| 5298 |
2/4✓ Branch 0 taken 1 time.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 3 not taken.
|
3 | ocomp := BackendDAE.TORNSYSTEM(listHead(tearingSets),NONE(),linear,mixedSystem); |
| 5299 | outRunMatching := true; | ||
| 5300 | |||
| 5301 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
1 | if Flags.isSet(Flags.TOTAL_TEARING_DUMP) or Flags.isSet(Flags.TOTAL_TEARING_DUMPVERBOSE) then |
| 5302 | 1 | print("\n\nTotal number of different tearing sets: " + intString(listLength(tearingSets)) + "\n\n"); | |
| 5303 | end if; | ||
| 5304 | |||
| 5305 |
1/2✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
|
1 | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 5306 | ✗ | print("\nEND of totalTearing\n" + BORDER + "\n\n"); | |
| 5307 | end if; | ||
| 5308 | end totalTearing; | ||
| 5309 | |||
| 5310 | |||
| 5311 | protected function getPowerSetElement | ||
| 5312 | input Integer i; | ||
| 5313 | output list<Integer> powerSetElement={}; | ||
| 5314 | protected | ||
| 5315 | Integer c=0,e=i,r; | ||
| 5316 | algorithm | ||
| 5317 |
2/2✓ Branch 0 taken 49 times.
✓ Branch 1 taken 15 times.
|
64 | while not intEq(e,0) loop |
| 5318 |
1/2✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
|
49 | c := c+1; |
| 5319 | r := intMod(e,2); | ||
| 5320 | 49 | e := intDiv(e,2); | |
| 5321 |
2/2✓ Branch 0 taken 17 times.
✓ Branch 1 taken 32 times.
|
49 | if intEq(r,1) then |
| 5322 | powerSetElement := c :: powerSetElement; | ||
| 5323 | end if; | ||
| 5324 | end while; | ||
| 5325 | end getPowerSetElement; | ||
| 5326 | |||
| 5327 | |||
| 5328 | protected function totalMatching "function to find all possible matchings for one given set of tearing variables (DFS) | ||
| 5329 | author: ptaeuber FHB 2016" | ||
| 5330 | input array<Integer> ass1,ass2; | ||
| 5331 | input list<Integer> orderIn; | ||
| 5332 | input list<Integer> causEqIn; | ||
| 5333 | input BackendDAE.AdjacencyMatrix m; | ||
| 5334 | input BackendDAE.AdjacencyMatrixT mt; | ||
| 5335 | input BackendDAE.AdjacencyMatrixEnhanced me; | ||
| 5336 | input array<list<Integer>> mapEqnIncRow; | ||
| 5337 | input array<Integer> mapIncRowEqn; | ||
| 5338 | input UnorderedSet<array<Integer>> visited "already explored assignment states (ass1)"; | ||
| 5339 | input list<tuple<array<Integer>,array<Integer>,list<Integer>>> matchingListIn; | ||
| 5340 | output list<tuple<array<Integer>,array<Integer>,list<Integer>>> matchingListOut=matchingListIn; | ||
| 5341 | protected | ||
| 5342 | list<Integer> order, causEq, e_exp, vars, unassigned; | ||
| 5343 | array<Integer> ass1Copy,ass2Copy; | ||
| 5344 | BackendDAE.AdjacencyMatrix mCopy; | ||
| 5345 | BackendDAE.AdjacencyMatrixT mtCopy; | ||
| 5346 | Boolean solvable; | ||
| 5347 | algorithm | ||
| 5348 |
2/2✓ Branch 0 taken 74 times.
✓ Branch 1 taken 37 times.
|
111 | for e in causEqIn loop |
| 5349 | // 1. Check solvability (read-only, no copies needed yet) | ||
| 5350 | 74 | (solvable, e_exp, vars) := eqnSolvableCheck(e, mapEqnIncRow, ass1, m, me); | |
| 5351 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 55 times.
|
74 | if not solvable then |
| 5352 | 19 | continue; | |
| 5353 | else | ||
| 5354 | // 2. Deep copies to avoid side effects: makeAssignment mutates the arrays | ||
| 5355 | // in place, but each sibling branch of the DFS needs the unmodified state | ||
| 5356 | 55 | ass1Copy := arrayCopy(ass1); | |
| 5357 | 55 | ass2Copy := arrayCopy(ass2); | |
| 5358 | 55 | mCopy := arrayCopy(m); | |
| 5359 | 55 | mtCopy := arrayCopy(mt); | |
| 5360 | |||
| 5361 | // 3. Match e_exp with corresponding variable(s), i.e.: update ass1, ass2, m, order | ||
| 5362 | 55 | makeAssignment(e_exp,vars,ass1Copy,ass2Copy,mCopy,mtCopy); | |
| 5363 | order := e::orderIn; | ||
| 5364 | |||
| 5365 | // The new state (and thereby its whole subtree) is fully determined by the | ||
| 5366 | // assignments in ass1: skip it if it was already reached via a different | ||
| 5367 | // causalization order | ||
| 5368 |
2/2✓ Branch 1 taken 9 times.
✓ Branch 2 taken 46 times.
|
55 | if UnorderedSet.contains(ass1Copy, visited) then |
| 5369 | 9 | continue; | |
| 5370 | end if; | ||
| 5371 | 46 | UnorderedSet.addNew(ass1Copy, visited); | |
| 5372 | |||
| 5373 | // 4. Determine new possible causEq | ||
| 5374 | 46 | causEq := traverseCollectiveEqnsforAssignable(ass2Copy,mCopy,mapEqnIncRow); | |
| 5375 | |||
| 5376 | // 5. Dump | ||
| 5377 | // if Flags.isSet(Flags.TOTAL_TEARING_DUMPVERBOSE) then | ||
| 5378 | // print("\nNew ass1: " + stringDelimitList(List.mapArray(ass1Copy, intString),",")+"\n"); | ||
| 5379 | // print("New ass2: " + stringDelimitList(List.mapArray(ass2Copy, intString),",") + "\n"); | ||
| 5380 | // print("\nNew m:");BackendDump.dumpAdjacencyMatrix(mCopy); | ||
| 5381 | // print("\nNew mt:");BackendDump.dumpAdjacencyMatrix(mtCopy); | ||
| 5382 | // print("\nNew causEq: " + stringDelimitList(List.map(causEq,intString),",") + "\n"); | ||
| 5383 | // print("New order: " + stringDelimitList(List.map(order,intString),",") + "\n\n\n\n"); | ||
| 5384 | // end if; | ||
| 5385 | |||
| 5386 | // 6. Decide what to do | ||
| 5387 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 22 times.
|
46 | if listEmpty(causEq) then |
| 5388 | // full matching found? | ||
| 5389 | 24 | unassigned := getUnassigned(ass1Copy); | |
| 5390 |
1/2✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
|
24 | if listEmpty(unassigned) then |
| 5391 | // save current full matching (it is new since the state was not visited before) | ||
| 5392 | 24 | matchingListOut := (ass1Copy,ass2Copy,listReverse(order)) :: matchingListOut; | |
| 5393 | end if; | ||
| 5394 | else | ||
| 5395 | // Continue with matching | ||
| 5396 | 22 | matchingListOut := totalMatching(ass1Copy,ass2Copy,order,causEq,mCopy,mtCopy,me,mapEqnIncRow,mapIncRowEqn,visited,matchingListOut); | |
| 5397 | end if; | ||
| 5398 | end if; | ||
| 5399 | end for; | ||
| 5400 | end totalMatching; | ||
| 5401 | |||
| 5402 | |||
| 5403 | protected function createTearingSets | ||
| 5404 | input list<Integer> tVarsIn; | ||
| 5405 | input list<tuple<array<Integer>,array<Integer>,list<Integer>>> matchingList; | ||
| 5406 | input list<Integer> vindx; | ||
| 5407 | input list<Integer> eindex; | ||
| 5408 | input array<list<Integer>> mapEqnIncRow; | ||
| 5409 | input array<Integer> mapIncRowEqn; | ||
| 5410 | input list<BackendDAE.TearingSet> tearingSetsIn; | ||
| 5411 | output list<BackendDAE.TearingSet> tearingSetsOut=tearingSetsIn; | ||
| 5412 | protected | ||
| 5413 | array<Integer> ass1,ass2; | ||
| 5414 | list<Integer> tVars,residual,residual_coll,order; | ||
| 5415 | BackendDAE.InnerEquations innerEquations; | ||
| 5416 | algorithm | ||
| 5417 |
2/2✓ Branch 0 taken 24 times.
✓ Branch 1 taken 15 times.
|
39 | for matching in matchingList loop |
| 5418 | 24 | (ass1,ass2,order) := matching; | |
| 5419 | |||
| 5420 | // Unassigned equations are residual equations | ||
| 5421 | 24 | residual := getUnassigned(ass2); | |
| 5422 | 24 | residual_coll := List.map1r(residual,arrayGet,mapIncRowEqn); | |
| 5423 | 24 | residual_coll := List.unique(residual_coll); | |
| 5424 | |||
| 5425 | // Convert indexes | ||
| 5426 | 24 | tVars := selectFromList_rev(vindx, tVarsIn); | |
| 5427 | 24 | residual := selectFromList_rev(eindex, residual_coll); | |
| 5428 | |||
| 5429 | // assign innerEquations: | ||
| 5430 | 24 | innerEquations := assignInnerEquations(order,eindex,vindx,ass2,mapEqnIncRow,NONE()); | |
| 5431 | |||
| 5432 | // Create BackendDAE.TearingSet for strict set | ||
| 5433 | 24 | tearingSetsOut := BackendDAE.TEARINGSET(tVars,residual,innerEquations,BackendDAE.EMPTY_JACOBIAN()) :: tearingSetsOut; | |
| 5434 | |||
| 5435 |
2/4✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 24 times.
|
24 | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then |
| 5436 | ✗ | print("\nTearing Variables:\n" + stringDelimitList(List.map(tVarsIn,intString),",") +"\n"); | |
| 5437 | ✗ | print("Residual Equations:\n" + stringDelimitList(List.map(residual_coll,intString),",") +"\n\n"); | |
| 5438 | end if; | ||
| 5439 | end for; | ||
| 5440 | end createTearingSets; | ||
| 5441 | |||
| 5442 | |||
| 5443 | protected function dumpMatchingList | ||
| 5444 | input list<tuple<array<Integer>,array<Integer>,list<Integer>>> matchingList; | ||
| 5445 | protected | ||
| 5446 | Integer c=0; | ||
| 5447 | list<Integer> order; | ||
| 5448 | array<Integer> ass1, ass2; | ||
| 5449 | algorithm | ||
| 5450 | ✗ | print("\n"); | |
| 5451 | ✗ | for matching in matchingList loop | |
| 5452 | ✗ | c := c+1; | |
| 5453 | ✗ | (ass1,ass2,order) := matching; | |
| 5454 | ✗ | print("Matching " + intString(c) + ":\n"); | |
| 5455 | ✗ | print("ass1: " + stringDelimitList(List.mapArray(ass1, intString),",") + "\n"); | |
| 5456 | ✗ | print("ass2: " + stringDelimitList(List.mapArray(ass2, intString),",") + "\n"); | |
| 5457 | ✗ | print("order: " + stringDelimitList(List.map(order,intString),",") + "\n\n"); | |
| 5458 | end for; | ||
| 5459 | end dumpMatchingList; | ||
| 5460 | |||
| 5461 | |||
| 5462 | |||
| 5463 | // ============================================================================= | ||
| 5464 | // | ||
| 5465 | // User-Defined Tearing - Determine the tearing set defined by the user | ||
| 5466 | // author: ptaeuber FHB 2016 | ||
| 5467 | // | ||
| 5468 | // ============================================================================= | ||
| 5469 | |||
| 5470 | protected function userDefinedTearing " determine the tearing set defined by the user | ||
| 5471 | author: ptaeuber FHB 2016" | ||
| 5472 | input BackendDAE.EqSystem isyst; | ||
| 5473 | input BackendDAE.Shared ishared; | ||
| 5474 | input list<Integer> eindex; | ||
| 5475 | input list<Integer> vindx; | ||
| 5476 | input Option<list<tuple<Integer, Integer, BackendDAE.Equation>>> ojac; | ||
| 5477 | input BackendDAE.JacobianType jacType; | ||
| 5478 | input Boolean mixedSystem; | ||
| 5479 | input list<Integer> userTVars; | ||
| 5480 | input list<Integer> userResiduals; | ||
| 5481 | output BackendDAE.StrongComponent ocomp; | ||
| 5482 | output Boolean outRunMatching; | ||
| 5483 | protected | ||
| 5484 | Integer size; | ||
| 5485 | array<Integer> ass1,ass2,mapIncRowEqn; | ||
| 5486 | array<list<Integer>> mapEqnIncRow; | ||
| 5487 | list<Integer> tVars,residuals,order,causEq,unsolvables,discreteVars,userResiduals_exp; | ||
| 5488 | BackendDAE.EqSystem subsyst; | ||
| 5489 | BackendDAE.Variables vars; | ||
| 5490 | BackendDAE.EquationArray eqns; | ||
| 5491 | BackendDAE.AdjacencyMatrix m; | ||
| 5492 | BackendDAE.AdjacencyMatrix mt; | ||
| 5493 | BackendDAE.AdjacencyMatrixEnhanced me; | ||
| 5494 | BackendDAE.AdjacencyMatrixTEnhanced meT; | ||
| 5495 | BackendDAE.BackendDAEType DAEtype; | ||
| 5496 | BackendDAE.InnerEquations innerEquations; | ||
| 5497 | BackendDAE.TearingSet tearingSet; | ||
| 5498 | list<BackendDAE.Equation> eqn_lst; | ||
| 5499 | list<BackendDAE.Var> var_lst; | ||
| 5500 | Boolean linear; | ||
| 5501 | String modelName; | ||
| 5502 | algorithm | ||
| 5503 | |||
| 5504 | ✗ | linear := BackendDAEUtil.getLinearfromJacType(jacType); | |
| 5505 | BackendDAE.SHARED(backendDAEType=DAEtype, info=BackendDAE.EXTRA_INFO(fileNamePrefix=modelName)) := ishared; | ||
| 5506 | |||
| 5507 | // Generate Subsystem to get the adjacency matrix | ||
| 5508 | ✗ | size := listLength(vindx); | |
| 5509 | ✗ | eqn_lst := BackendEquation.getList(eindex,BackendEquation.getEqnsFromEqSystem(isyst)); | |
| 5510 | ✗ | eqns := BackendEquation.listEquation(eqn_lst); | |
| 5511 | ✗ | var_lst := List.map1r(vindx, BackendVariable.getVarAt, BackendVariable.daeVars(isyst)); | |
| 5512 | ✗ | vars := BackendVariable.listVar1(var_lst); | |
| 5513 | ✗ | subsyst := BackendDAEUtil.createEqSystem(vars, eqns); | |
| 5514 | ✗ | (subsyst,m,mt,_,_) := BackendDAEUtil.getAdjacencyMatrixScalar(subsyst, BackendDAE.NORMAL(),NONE(), BackendDAEUtil.isInitializationDAE(ishared)); | |
| 5515 | |||
| 5516 | // Delete negative entries from adjacency matrix | ||
| 5517 | ✗ | m := Array.map(m,deleteNegativeEntries); | |
| 5518 | ✗ | mt := Array.map(mt,deleteNegativeEntries); | |
| 5519 | |||
| 5520 | // Get advanced adjacency matrix (determine how the variables occur in the equations) | ||
| 5521 | ✗ | (me,meT,mapEqnIncRow,mapIncRowEqn) := BackendDAEUtil.getAdjacencyMatrixEnhancedScalar(subsyst,ishared,false); | |
| 5522 | |||
| 5523 | // Expand algorithm or equation array residual equations | ||
| 5524 | try | ||
| 5525 | ✗ | userResiduals_exp := List.flatten(list(arrayGet(mapEqnIncRow, i) for i in userResiduals)); | |
| 5526 | else | ||
| 5527 | ✗ | Error.addMessage(Error.USER_DEFINED_TEARING_ERROR, {"Index out of bounds."}); | |
| 5528 | ✗ | fail(); | |
| 5529 | end try; | ||
| 5530 | |||
| 5531 | |||
| 5532 | // Dumps | ||
| 5533 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 5534 | ✗ | print("\n" + BORDER + "\nBEGINNING of userDefinedTearing\n\n"); | |
| 5535 | end if; | ||
| 5536 | |||
| 5537 | ✗ | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 5538 | ✗ | print("\nUsers tearing vars: " + stringDelimitList(List.map(userTVars,intString),",") + "\n"); | |
| 5539 | ✗ | print("\nUsers residual equations: " + stringDelimitList(List.map(userResiduals,intString),",") + "\n"); | |
| 5540 | ✗ | print("\nUsers residual equations expanded: " + stringDelimitList(List.map(userResiduals_exp,intString),",") + "\n"); | |
| 5541 | ✗ | print("\n\n###BEGIN print Strong Component#####################\n(Function:userDefinedTearing)\n"); | |
| 5542 | ✗ | BackendDump.printEqSystem(subsyst); | |
| 5543 | ✗ | print("\n###END print Strong Component#######################\n(Function:userDefinedTearing)\n\n\n"); | |
| 5544 | end if; | ||
| 5545 | |||
| 5546 | ✗ | if not intEq(listLength(userTVars),listLength(userResiduals_exp)) then | |
| 5547 | ✗ | Error.addMessage(Error.USER_DEFINED_TEARING_ERROR, {"The number of tearing variables and residual equations is not identical."}); | |
| 5548 | ✗ | fail(); | |
| 5549 | end if; | ||
| 5550 | |||
| 5551 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 5552 | ✗ | print("\nAdjacencyMatrixEnhanced:\n"); | |
| 5553 | ✗ | BackendDump.dumpAdjacencyMatrixEnhanced(me); | |
| 5554 | ✗ | print("\nAdjacencyMatrixTransposedEnhanced:\n"); | |
| 5555 | ✗ | BackendDump.dumpAdjacencyMatrixTEnhanced(meT); | |
| 5556 | end if; | ||
| 5557 | |||
| 5558 | // Determine unsolvable vars to consider solvability | ||
| 5559 | ✗ | unsolvables := getUnsolvableVars(size,meT); | |
| 5560 | |||
| 5561 | // Determine discrete vars | ||
| 5562 | ✗ | discreteVars := findDiscrete(var_lst); | |
| 5563 | |||
| 5564 | // Dumps | ||
| 5565 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 5566 | ✗ | print("\n\nmapEqnIncRow:"); //+ stringDelimitList(List.map(List.flatten(arrayList(mapEqnIncRow)),intString),",") + "\n\n"); | |
| 5567 | ✗ | BackendDump.dumpAdjacencyMatrix(mapEqnIncRow); | |
| 5568 | ✗ | print("\nmapIncRowEqn:\n" + stringDelimitList(List.mapArray(mapIncRowEqn, intString),",") + "\n\n"); | |
| 5569 | ✗ | print("\n\nUNSOLVABLES:\n" + stringDelimitList(List.map(unsolvables,intString),",") + "\n\n"); | |
| 5570 | ✗ | print("\nDiscrete Vars:\n" + stringDelimitList(List.map(discreteVars,intString),",") + "\n\n"); | |
| 5571 | end if; | ||
| 5572 | |||
| 5573 | // Initialize matching | ||
| 5574 | ✗ | ass1 := arrayCreate(size,-1); | |
| 5575 | ✗ | ass2 := arrayCreate(size,-1); | |
| 5576 | order := {}; | ||
| 5577 | |||
| 5578 | // mark userTVars in ass1 | ||
| 5579 | ✗ | markTVarsOrResiduals(userTVars, ass1); | |
| 5580 | // mark userResiduals in ass2 | ||
| 5581 | ✗ | markTVarsOrResiduals(userResiduals_exp, ass2); | |
| 5582 | |||
| 5583 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 5584 | ✗ | print("\nass1: " + stringDelimitList(List.mapArray(ass1, intString),",") + "\n"); | |
| 5585 | ✗ | print("ass2: " + stringDelimitList(List.mapArray(ass2, intString),",") + "\n"); | |
| 5586 | end if; | ||
| 5587 | |||
| 5588 | // remove tearing vars from adjacency matrix and transposed adjacency matrix | ||
| 5589 | ✗ | deleteEntriesFromAdjacencyMatrix(m, mt, userTVars); | |
| 5590 | ✗ | deleteRowsFromAdjacencyMatrix(mt, userTVars); | |
| 5591 | // remove residual equations from adjacency matrix and transposed adjacency matrix | ||
| 5592 | ✗ | deleteEntriesFromAdjacencyMatrix(mt, m, userResiduals_exp); | |
| 5593 | ✗ | deleteRowsFromAdjacencyMatrix(m, userResiduals_exp); | |
| 5594 | |||
| 5595 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 5596 | ✗ | print("\nAdjacency Matrix without tvars and residuals:\n"); | |
| 5597 | ✗ | BackendDump.dumpAdjacencyMatrix(m); | |
| 5598 | ✗ | BackendDump.dumpAdjacencyMatrix(mt); | |
| 5599 | end if; | ||
| 5600 | |||
| 5601 | ✗ | if intEq(listLength(userTVars), countEmptyRows(m)) and intEq(listLength(userResiduals_exp), countEmptyRows(mt)) then | |
| 5602 | // Find initial causalizable equations | ||
| 5603 | ✗ | causEq := traverseCollectiveEqnsforAssignable(ass2,m,mapEqnIncRow); | |
| 5604 | |||
| 5605 | // Call the matching algorithm | ||
| 5606 | ✗ | order := simpleMatching(ass1,ass2,order,causEq,m,mt,me,mapEqnIncRow,mapIncRowEqn); | |
| 5607 | |||
| 5608 | // Convert indexes | ||
| 5609 | ✗ | tVars := selectFromList_rev(vindx, userTVars); | |
| 5610 | ✗ | residuals := selectFromList_rev(eindex, userResiduals); | |
| 5611 | |||
| 5612 | // assign innerEquation: | ||
| 5613 | ✗ | innerEquations := assignInnerEquations(order,eindex,vindx,ass2,mapEqnIncRow,NONE()); | |
| 5614 | |||
| 5615 | ✗ | tearingSet := BackendDAE.TEARINGSET(tVars,residuals,innerEquations,BackendDAE.EMPTY_JACOBIAN()); | |
| 5616 | |||
| 5617 | // Create BackendDAE.TornSystem | ||
| 5618 | ✗ | ocomp := BackendDAE.TORNSYSTEM(tearingSet,NONE(),linear,mixedSystem); | |
| 5619 | outRunMatching := true; | ||
| 5620 | |||
| 5621 | // dump results with local indexes | ||
| 5622 | ✗ | if Flags.isSet(Flags.TEARING_DUMP) or Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 5623 | ✗ | dumpTearingSetLocalIndexes(userTVars,userResiduals,order,ass2,size,mapEqnIncRow,vars,eqns,""); | |
| 5624 | end if; | ||
| 5625 | |||
| 5626 | // dump results with global indexes | ||
| 5627 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 5628 | ✗ | dumpTearingSetGlobalIndexes(tearingSet,size,""); | |
| 5629 | end if; | ||
| 5630 | |||
| 5631 | else | ||
| 5632 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 5633 | ✗ | print("\nMatching failed, choose different tearing set!\n\n\n"); | |
| 5634 | end if; | ||
| 5635 | ✗ | Error.addCompilerError("There is no possible matching for a user-defined tearing set."); | |
| 5636 | ✗ | fail(); | |
| 5637 | |||
| 5638 | end if; | ||
| 5639 | |||
| 5640 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 5641 | ✗ | print("\nEND of userDefinedTearing\n" + BORDER + "\n\n"); | |
| 5642 | end if; | ||
| 5643 | end userDefinedTearing; | ||
| 5644 | |||
| 5645 | |||
| 5646 | protected function countEmptyRows | ||
| 5647 | "function to count empty rows in adjacency matrices" | ||
| 5648 | input BackendDAE.AdjacencyMatrix m; | ||
| 5649 | output Integer count=0; | ||
| 5650 | algorithm | ||
| 5651 | ✗ | for row in m loop | |
| 5652 | ✗ | if listEmpty(row) then | |
| 5653 | ✗ | count := count + 1; | |
| 5654 | end if; | ||
| 5655 | end for; | ||
| 5656 | end countEmptyRows; | ||
| 5657 | |||
| 5658 | |||
| 5659 | protected function simpleMatching "function tries to find a matching based on a given set of tearing variables and residual equations | ||
| 5660 | author: ptaeuber FHB 2016" | ||
| 5661 | input array<Integer> ass1,ass2; | ||
| 5662 | input list<Integer> orderIn; | ||
| 5663 | input list<Integer> causEqIn; | ||
| 5664 | input BackendDAE.AdjacencyMatrix m; | ||
| 5665 | input BackendDAE.AdjacencyMatrixT mt; | ||
| 5666 | input BackendDAE.AdjacencyMatrixEnhanced me; | ||
| 5667 | input array<list<Integer>> mapEqnIncRow; | ||
| 5668 | input array<Integer> mapIncRowEqn; | ||
| 5669 | output list<Integer> orderOut=orderIn; | ||
| 5670 | protected | ||
| 5671 | Integer e; | ||
| 5672 | list<Integer> causEq=causEqIn, e_exp, vars; | ||
| 5673 | algorithm | ||
| 5674 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 5675 | ✗ | print("\nStart Matching:\n"+ UNDERLINE + "\n"); | |
| 5676 | end if; | ||
| 5677 | ✗ | while not listEmpty(causEq) loop | |
| 5678 | try | ||
| 5679 | ✗ | (e,e_exp,vars) := getNextSolvableEqn(causEq,m,me,ass1,ass2,mapEqnIncRow,mapIncRowEqn,ass1); | |
| 5680 | else | ||
| 5681 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 5682 | ✗ | print("\nMatching failed, choose different tearing set!\n\n\n"); | |
| 5683 | end if; | ||
| 5684 | ✗ | Error.addCompilerError("There is no possible matching for a user-defined tearing set."); | |
| 5685 | ✗ | fail(); | |
| 5686 | end try; | ||
| 5687 | |||
| 5688 | // Dump | ||
| 5689 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 5690 | ✗ | print("causEq: " + stringDelimitList(List.map(causEq,intString),",") + "\nProcess " + intString(e) + ":\ne_exp: " + stringDelimitList(List.map(e_exp,intString),",") + "\n"); | |
| 5691 | end if; | ||
| 5692 | |||
| 5693 | // Match e_exp with corresponding variable(s), i.e.: update ass1, ass2, m, order | ||
| 5694 | ✗ | makeAssignment(e_exp,vars,ass1,ass2,m,mt); | |
| 5695 | ✗ | orderOut := e::orderOut; | |
| 5696 | |||
| 5697 | // Determine new possible causEq | ||
| 5698 | ✗ | causEq := traverseCollectiveEqnsforAssignable(ass2,m,mapEqnIncRow); | |
| 5699 | end while; | ||
| 5700 | ✗ | if listEmpty(getUnassigned(ass1)) then | |
| 5701 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 5702 | ✗ | print("\nMatching succeeded!\n"); | |
| 5703 | end if; | ||
| 5704 | ✗ | orderOut := listReverse(orderOut); | |
| 5705 | else | ||
| 5706 | ✗ | if Flags.isSet(Flags.TEARING_DUMPVERBOSE) then | |
| 5707 | ✗ | print("\nMatching failed, choose different tearing set!\n\n\n"); | |
| 5708 | end if; | ||
| 5709 | ✗ | Error.addCompilerError("There is no possible matching for a user-defined tearing set."); | |
| 5710 | ✗ | fail(); | |
| 5711 | end if; | ||
| 5712 | end simpleMatching; | ||
| 5713 | |||
| 5714 | |||
| 5715 | annotation(__OpenModelica_Interface="backend"); | ||
| 5716 | end Tearing; | ||
| 5717 |