|
9 | 9 | ModelicaRealVariable, |
10 | 10 | ModelicaSimpleEquation, |
11 | 11 | } from "./dae.js"; |
| 12 | +import { isolateSymbolically } from "./symbolic.js"; |
12 | 13 |
|
13 | 14 | /** |
14 | 15 | * Visitor that collects all variable names referenced in an expression/equation. |
@@ -65,6 +66,21 @@ function isExplicitlySolvableFor(eq: ModelicaEquation, v: string): boolean { |
65 | 66 | return false; |
66 | 67 | } |
67 | 68 |
|
| 69 | +/** |
| 70 | + * Attempt to symbolically isolate `v` from a `ModelicaSimpleEquation`. |
| 71 | + * Returns a new explicit equation `v = expr` if successful, or null. |
| 72 | + */ |
| 73 | +function trySymbolicIsolation(eq: ModelicaEquation, v: string): ModelicaSimpleEquation | null { |
| 74 | + if (!(eq instanceof ModelicaSimpleEquation)) return null; |
| 75 | + if (!eq.expression1 || !eq.expression2) return null; |
| 76 | + |
| 77 | + const result = isolateSymbolically(eq.expression1, eq.expression2, v); |
| 78 | + if (!result) return null; |
| 79 | + |
| 80 | + const nameExpr = new ModelicaNameExpression(v); |
| 81 | + return new ModelicaSimpleEquation(nameExpr, result); |
| 82 | +} |
| 83 | + |
68 | 84 | /** |
69 | 85 | * Perform a full Block Lower Triangular (BLT) Transformation on the DAE equations. |
70 | 86 | */ |
@@ -241,11 +257,20 @@ export function performBltTransformation(dae: ModelicaDAE): { |
241 | 257 | const deps = eqDeps.get(eqIdx); |
242 | 258 | if (deps?.has(v)) { |
243 | 259 | // It's a single variable assigned to this equation. But is it a true loop? |
244 | | - // If it's a structural explicit assignment (v = ...), it's not an algebraic loop unless it's v = v + 1. |
| 260 | + // If it's a structural explicit assignment (v = ...), it's not an algebraic loop. |
245 | 261 | const matchingEq = equations[eqIdx]; |
246 | 262 | if (matchingEq && !isExplicitlySolvableFor(matchingEq, v)) { |
247 | | - // implicit single variable loop |
248 | | - algebraicLoops.push({ variables: scc, equations: sccEqs }); |
| 263 | + // Try symbolic isolation before giving up |
| 264 | + const isolated = trySymbolicIsolation(matchingEq, v); |
| 265 | + if (isolated) { |
| 266 | + // Replace the implicit equation with the explicit one |
| 267 | + const idx = sccEqs.indexOf(matchingEq); |
| 268 | + if (idx >= 0) sccEqs[idx] = isolated; |
| 269 | + equations[eqIdx] = isolated; |
| 270 | + } else { |
| 271 | + // implicit single variable loop — cannot isolate |
| 272 | + algebraicLoops.push({ variables: scc, equations: sccEqs }); |
| 273 | + } |
249 | 274 | } |
250 | 275 | } |
251 | 276 | } |
|
0 commit comments