Snapshot WIP: solver HP epic progress, BPHX/HX physics, BMAD skill refresh.
Some checks failed
CI / check (push) Has been cancelled
Some checks failed
CI / check (push) Has been cancelled
Capture uncommitted solver robustness work (regularization, domain errors, linear solver lifecycle, tube DP/MSH), web workbench updates, and synced BMAD skills across IDE agent folders before starting BPHX pressure-drop. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
267
docs/architecture/dof_balance_and_real_machine_plan.md
Normal file
267
docs/architecture/dof_balance_and_real_machine_plan.md
Normal file
@@ -0,0 +1,267 @@
|
||||
# DoF Balance & Real-Machine Simulation Plan
|
||||
|
||||
**Date:** 2026-07-17
|
||||
**Status:** Active implementation plan
|
||||
**Audience:** architects + implementers
|
||||
**Related:** `docs/audits/heat_exchanger_architecture_audit.md`, ADR-0001, mission HX
|
||||
|
||||
---
|
||||
|
||||
## 0. Non-negotiable principles
|
||||
|
||||
1. **A thermodynamic system is a square algebraic problem:**
|
||||
\[
|
||||
n_{\text{equations}} = n_{\text{unknowns}}
|
||||
\]
|
||||
2. **Fixing a quantity consumes one degree of freedom.** Somewhere else an unknown
|
||||
must be freed (or an equation dropped). There is no free lunch.
|
||||
3. **Parameters are not states.** If a value is not in the Newton state vector, it is
|
||||
either (a) a true physical constant/input boundary, or (b) a **cheat** that must be
|
||||
labeled and forbidden in system mode.
|
||||
4. **No bricolage.** Silent clamping, fake residuals, scalar secondary streams that
|
||||
pretend to be a water loop, and design-point pressure pins are not “real machine”
|
||||
simulation.
|
||||
5. **Hard gate before solve.** Imbalance is an error, not a warning.
|
||||
|
||||
---
|
||||
|
||||
## 1. Diagnosis — what the codebase does today
|
||||
|
||||
### 1.1 State vector (unknowns)
|
||||
|
||||
Post CM1.4 layout (`System::finalize`):
|
||||
|
||||
```text
|
||||
[ ṁ_branch_0 … ṁ_branch_{B-1} | P_e0, h_e0, … P_e{|E|-1}, h_e{|E|-1}
|
||||
| inverse_controls | coupling_Q | saturated_(u,x) pairs | free_actuators ]
|
||||
```
|
||||
|
||||
- Series edges share one `ṁ` unknown per branch (`topology.rs`).
|
||||
- Full length: `full_state_vector_len()`.
|
||||
|
||||
### 1.2 Equations
|
||||
|
||||
```text
|
||||
n_eq = Σ component.n_equations()
|
||||
+ n_constraints
|
||||
+ n_thermal_couplings
|
||||
+ 2 × n_saturated_controllers
|
||||
```
|
||||
|
||||
Free actuators contribute **unknowns only**; the owning component supplies the
|
||||
closing residual inside `n_equations()`.
|
||||
|
||||
### 1.3 Existing Fix/Free mechanisms (good)
|
||||
|
||||
| Mechanism | Fix (equation) | Free (unknown) |
|
||||
|-----------|----------------|----------------|
|
||||
| `BrineSource` P,h,(ṁ) | Dirichlet on edge | — (boundary input) |
|
||||
| `BrineSink` P_back | Dirichlet on P | h free (emergent outlet) |
|
||||
| `Anchor` + constraint | +1 thermo spec | must free elsewhere |
|
||||
| `add_constraint` + `BoundedVariable` | +1 measure residual | +1 control |
|
||||
| `add_free_actuator` | component residual | +1 state slot |
|
||||
| `superheat_regulated` | **drops** SH residual | EXV opening closes it |
|
||||
| Emergent HX | outlet closure pins P via balance | design-point P removed from compressor/EXV |
|
||||
|
||||
### 1.4 Cheating patterns (forbidden for real-machine system solve)
|
||||
|
||||
| Cheat | Where | Why it is wrong |
|
||||
|-------|-------|-----------------|
|
||||
| Secondary as scalars `T_sec`, `C_sec` without edges | `FloodedEvaporator` coupled path | Water loop has no First-Law residual; h_sec,out never emerges |
|
||||
| `target_quality = 0.7` + quality residual | Flooded default | +1 equation without free actuator / level unknown |
|
||||
| Fake residual `-target_quality` when quality fails | Flooded | Hides config error |
|
||||
| `unwrap_or(inlet_p_idx)` for mass index | Cond/Evap/Flooded | Jacobian writes energy ∂/∂ṁ into **pressure column** |
|
||||
| Design-point P pins (non-emergent) | compressor/EXV legacy | Pressures not free to respond to secondary |
|
||||
| `p_in > 10_000` hard model switch | several HX | Discontinuous Jacobian near seed |
|
||||
| UI historically “hiding” secondary edges | obsolete HANDOFF claim | Must keep live edges in graph |
|
||||
| Rating `rate(p)` used as if system solve | qualification APIs | OK **only** when labeled rating mode |
|
||||
|
||||
### 1.5 Honest water-cooled chiller budget (reference)
|
||||
|
||||
```text
|
||||
Ref loop: Comp ⇄ Cond ⇄ EXV ⇄ Evap → 1 ṁ + 4×(P,h) = 9
|
||||
CW loop: BrineSrc → Cond.sec → Sink → 1 ṁ + 2×(P,h) = 5
|
||||
CHW loop: BrineSrc → Evap.sec → Sink → 1 ṁ + 2×(P,h) = 5
|
||||
Total unknowns = 19
|
||||
|
||||
Eqs (emergent, same-branch):
|
||||
Comp 2 + Cond (3 thermo + 1 sec energy) 4 + EXV 1
|
||||
+ Evap (3 + 1 sec) 4 + 2×(BrineSrc 3 + BrineSink 1) = 19
|
||||
```
|
||||
|
||||
**19 = 19.** This is the template. Flooded + dual circuit must keep the same discipline.
|
||||
|
||||
---
|
||||
|
||||
## 2. Fix / Free ledger (the core abstraction)
|
||||
|
||||
### 2.1 Rules
|
||||
|
||||
```text
|
||||
USER FIX (non-boundary) ⇒ must FREE something OR DROP a closing residual
|
||||
BOUNDARY FIX (source) ⇒ normal: physical input of the machine
|
||||
OUTLET CLOSURE (SH/SC/x) ⇒ either free actuator elsewhere OR mode drop of that residual
|
||||
```
|
||||
|
||||
Examples:
|
||||
|
||||
| User intent | Fix | Free / drop |
|
||||
|-------------|-----|-------------|
|
||||
| Fixed chilled-water supply T | load-side T_set or capacity constraint | free compressor speed or free EXV / free ṁ_ref |
|
||||
| Fixed superheat 5 K | SH residual OR anchor | free EXV opening (`superheat_regulated` + orifice) |
|
||||
| Fixed flooded level | level residual | free EXV / charge related |
|
||||
| Fixed circuit capacity | capacity constraint | free speed or free slide valve |
|
||||
| Quality target without actuator | **ILLEGAL** | refuse at validate |
|
||||
|
||||
### 2.2 Equation roles (semantic)
|
||||
|
||||
```rust
|
||||
pub enum EquationRole {
|
||||
MassConservation { stream: StreamId },
|
||||
MomentumOrPressureDrop { stream: StreamId },
|
||||
EnergyBalance { stream: StreamId },
|
||||
OutletClosure { kind: OutletClosureKind }, // SH | SC | Quality | Level
|
||||
BoundaryDirichlet { quantity: StateQuantity }, // P | H | M
|
||||
ActuatorClosure { name: String },
|
||||
CouplingDuty,
|
||||
ControlTracking { name: String },
|
||||
Unspecified, // legacy only; must disappear over time
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 Unknown kinds
|
||||
|
||||
```rust
|
||||
pub enum UnknownKind {
|
||||
BranchMassFlow { branch_id: usize },
|
||||
EdgePressure { edge: usize },
|
||||
EdgeEnthalpy { edge: usize },
|
||||
InverseControl { id: String },
|
||||
CouplingHeat { index: usize },
|
||||
SaturatedActuator { index: usize },
|
||||
SaturatedIntegrator { index: usize },
|
||||
FreeActuator { id: String },
|
||||
}
|
||||
```
|
||||
|
||||
### 2.4 System-level report
|
||||
|
||||
```text
|
||||
DofReport {
|
||||
n_unknowns, n_equations, balance: Balanced | Over(k) | Under(k),
|
||||
per_component: [(name, n_eq, roles)],
|
||||
free_actuators, constraints, couplings,
|
||||
diagnostics: ["FloodedEvaporator quality_control +1 eq without free actuator", ...]
|
||||
}
|
||||
```
|
||||
|
||||
Hard fail when `balance != Balanced` before Newton.
|
||||
|
||||
---
|
||||
|
||||
## 3. Implementation phases (ordered, each leaves workspace green)
|
||||
|
||||
### Phase D0 — Ledger + hard gate ✅ done (2026-07-17)
|
||||
|
||||
- [x] Study + this plan document
|
||||
- [x] `crates/solver/src/dof.rs` — `DofReport`, `SystemDofBalance`, errors
|
||||
- [x] `crates/components/src/dof.rs` — `EquationRole` + `Component::equation_roles()`
|
||||
- [x] `System::dof_report()` / `System::validate_system_dof()` / `total_equation_count()`
|
||||
- [x] Hard fail in `finalize()` on **over-constrained** (`enforce_dof_gate`, default on)
|
||||
- [x] Full square check via `validate_system_dof()` (production path)
|
||||
- [x] Roles on FloodedEvaporator, Condenser, BrineSource/Sink, Anchor
|
||||
- [x] Unit tests: `crates/solver/tests/dof_balance.rs` (balanced / over / under)
|
||||
|
||||
### Phase D1 — FloodedEvaporator honesty ✅ core done (2026-07-17)
|
||||
|
||||
- [x] 4-port live secondary via `set_port_context` (ports 2/3), `flow_paths=[(0,1),(2,3)]`
|
||||
- [x] Secondary energy residual `ṁ_sec(h_out−h_in) + Q = 0`
|
||||
- [x] `coupled_ready` requires live secondary edges in **system mode**
|
||||
- [x] Scalar `with_secondary_stream` documented as **rating-mode only**
|
||||
- [x] Remove mass→pressure index fallback; error if ṁ index missing
|
||||
- [x] Quality residual: return `Err` if quality uncomputable (no fake residual)
|
||||
- [x] `with_quality_control` documents DoF cost
|
||||
- [x] Equation roles complete for flooded
|
||||
- [ ] CLI example: flooded + BrineSrc/Sink secondary loop
|
||||
- [ ] Replace quality target with `FloodedEvaporatorControl` enum
|
||||
|
||||
### Phase D2 — Shared DoF diagnostics in CLI + UI ✅ done (2026-07-17)
|
||||
|
||||
- [x] CLI `run` hard-fails on non-square `validate_system_dof` after finalize
|
||||
- [x] `SimulationResult.dof` summary (n_eq, n_unk, balance, ledger text)
|
||||
- [x] CLI `validate` builds system and reports DoF
|
||||
- [x] Example `chiller_flooded_4port_watercooled.json`
|
||||
- [x] Web UI status bar: live eqs vs unk estimate
|
||||
- [x] Web UI Fix/Free badges on parameters + secondary wiring warnings
|
||||
- [x] `validateConfig` requires live secondary ports for 4-port HX
|
||||
|
||||
### Phase D3 — Zero-flow safe residuals (linked to HX mission §7)
|
||||
|
||||
- [ ] Reuse `entropyk_core::smoothing`
|
||||
- [ ] Activity blend with documented scales; Jacobian parity tests at m=0
|
||||
|
||||
### Phase D4 — Multi-circuit shared vessel (ADR-0001)
|
||||
|
||||
- [ ] Solver contract for multi-circuit ports on one component
|
||||
- [ ] `MultiCircuitFloodedEvaporator` with N independent ref balances + shared secondary energy
|
||||
- [ ] OFF circuit: zero duty, fixed eq count, no singularity
|
||||
|
||||
### Phase D5 — Geometry / correlations / product fixtures
|
||||
|
||||
- [ ] As HX mission Phases B–F, always under DoF ledger gate
|
||||
- [ ] No geometry mode ships without equation/unknown inventory table
|
||||
|
||||
---
|
||||
|
||||
## 4. Component checklist (every new residual)
|
||||
|
||||
Before adding a residual equation:
|
||||
|
||||
1. Name its `EquationRole`.
|
||||
2. State which unknown it closes (or which free it requires).
|
||||
3. Update `n_equations()` and Jacobian.
|
||||
4. Add a DoF unit test (balance before/after).
|
||||
5. Never add a residual “to make it converge”.
|
||||
|
||||
Before adding an unknown (actuator, coupling Q, …):
|
||||
|
||||
1. Name its `UnknownKind`.
|
||||
2. Provide the closing residual (component or system).
|
||||
3. Bounds if physical actuator.
|
||||
|
||||
---
|
||||
|
||||
## 5. Acceptance criteria (robust machine simulation)
|
||||
|
||||
A configuration is accepted as **real-machine system mode** only if:
|
||||
|
||||
- [ ] `validate_system_dof()` passes (hard)
|
||||
- [ ] Secondary fluids of every HX are live edges (or explicitly marked rating-only)
|
||||
- [ ] Pressures of interest are emergent (no design-point pin unless documented fixed-P study)
|
||||
- [ ] First Law closes at cycle level (`energy_transfers` sum ≈ 0 within tolerance)
|
||||
- [ ] No fake residual on missing properties
|
||||
- [ ] Jacobian analytic except documented property derivatives
|
||||
- [ ] Staging / zero flow keeps constant equation count
|
||||
|
||||
---
|
||||
|
||||
## 6. Relation to inverse control
|
||||
|
||||
Inverse (Eurovent / calibration) already has a partial DoF check. It is incomplete
|
||||
(misses free actuators, couplings, saturated controllers). The new
|
||||
`validate_system_dof` supersedes it as the **single** square-system gate; inverse
|
||||
mapping remains the Fix/Free pairing API for user constraints.
|
||||
|
||||
---
|
||||
|
||||
## 7. Immediate deliverables (this implementation slice)
|
||||
|
||||
1. This plan document.
|
||||
2. `solver::dof` module + public API.
|
||||
3. Hard DoF validation wired to `System`.
|
||||
4. Flooded evaporator path toward live secondary (D1 start).
|
||||
5. Tests proving overconstrained quality control is detected.
|
||||
|
||||
---
|
||||
|
||||
**Last updated:** 2026-07-17
|
||||
Reference in New Issue
Block a user