Fix bugs from 5-2 code review

This commit is contained in:
Sepehr
2026-02-21 10:43:55 +01:00
parent 400f1c420e
commit 0d9a0e4231
27 changed files with 9838 additions and 114 deletions

View File

@@ -112,6 +112,14 @@ This document provides the complete epic and story breakdown for Entropyk, decom
**FR47:** Each refrigeration component natively exposes a complete thermodynamic state (Pressure, Temperature, T_sat, Quality, Superheat, Subcooling, Mass flow, Reynolds, Enthalpy, Entropy) easily accessible without complex recalculations.
**FR48:** Hierarchical Subsystems (MacroComponents) - encapsulate complete systems into reusable blocks
**FR49:** Flow Junctions (FlowSplitter 1→N, FlowMerger N→1) for compressible & incompressible fluids
**FR50:** Boundary Conditions (FlowSource, FlowSink) for compressible & incompressible fluids
**FR51:** Swappable Calibration Variables - swap calibration factors (f_m, f_ua, f_power, etc.) into solver unknowns and measured values (Tsat, capacity, power) into constraints for one-shot inverse calibration
### NonFunctional Requirements
**NFR1:** Steady State convergence time < **1 second** for standard cycle in Cold Start
@@ -252,6 +260,9 @@ This document provides the complete epic and story breakdown for Entropyk, decom
| FR46 | Epic 1 | Air Coils (EvaporatorCoil, CondenserCoil) |
| FR47 | Epic 2 | Rich Thermodynamic State Abstraction |
| FR48 | Epic 3 | Hierarchical Subsystems (MacroComponents) |
| FR49 | Epic 1 | Flow Junctions (FlowSplitter 1→N, FlowMerger N→1) for compressible & incompressible fluids |
| FR50 | Epic 1 | Boundary Conditions (FlowSource, FlowSink) for compressible & incompressible fluids |
| FR51 | Epic 5 | Swappable Calibration Variables (inverse calibration one-shot) |
## Epic List
@@ -260,7 +271,7 @@ This document provides the complete epic and story breakdown for Entropyk, decom
**Innovation:** Trait-based "Lego" architecture to add Compressors, Pumps, VFDs, Pipes, etc.
**FRs covered:** FR1, FR2, FR3, FR4, FR5, FR6, FR7, FR8, FR46
**FRs covered:** FR1, FR2, FR3, FR4, FR5, FR6, FR7, FR8, FR46, FR49, FR50
---
@@ -296,7 +307,7 @@ This document provides the complete epic and story breakdown for Entropyk, decom
**Innovation:** Native Inverse Control via Residual Embedding - "One-Shot".
**FRs covered:** FR22, FR23, FR24
**FRs covered:** FR22, FR23, FR24, FR51
---
@@ -453,7 +464,58 @@ This document provides the complete epic and story breakdown for Entropyk, decom
---
## Epic 2: Fluid Properties Backend
### Story 1.11: Flow Junctions — FlowSplitter & FlowMerger
**As a** system modeler,
**I want** `FlowSplitter` (1 inlet → N outlets) and `FlowMerger` (N inlets → 1 outlet) components,
**So that** I can build parallel branches in hydraulic and refrigerant circuits without manually writing junction equations.
**Status:** ✅ Done (2026-02-20)
**FRs covered:** FR49
**Acceptance Criteria:**
**Given** a refrigerant or water circuit with parallel branches
**When** I instantiate `FlowSplitter::compressible("R410A", inlet, vec![out_a, out_b])`
**Then** the splitter contributes `2N1` equations (isobaric + isenthalpic constraints)
**And** validation rejects incompatible fluid types (`::incompressible` rejects refrigerants)
**And** `FlowMerger` contributes `N+1` equations with weighted enthalpy mixing via `with_mass_flows`
**And** both implement `Box<dyn Component>` (object-safe)
**And** type aliases `Incompressible/CompressibleSplitter` and `Incompressible/CompressibleMerger` are available
**Implementation:**
- `crates/components/src/flow_junction.rs``FlowSplitter`, `FlowMerger`, `FluidKind`
- 16 unit tests passing
---
### Story 1.12: Boundary Conditions — FlowSource & FlowSink
**As a** simulation user,
**I want** `FlowSource` and `FlowSink` boundary condition components,
**So that** I can define the entry and exit points of a fluid circuit without manually managing pressure and enthalpy constraints.
**Status:** ✅ Done (2026-02-20)
**FRs covered:** FR50
**Acceptance Criteria:**
**Given** a fluid circuit with an entry point
**When** I instantiate `FlowSource::incompressible("Water", 3.0e5, 63_000.0, port)`
**Then** the source imposes `P_edge P_set = 0` and `h_edge h_set = 0` (2 equations)
**And** `FlowSink::incompressible("Water", 1.5e5, None, port)` imposes a back-pressure (1 equation)
**And** `FlowSink` with `Some(h_back)` adds a second enthalpy constraint (2 equations)
**And** `set_return_enthalpy` / `clear_return_enthalpy` toggle the second equation dynamically
**And** validation rejects incompatible fluid + constructor combinations
**And** type aliases `Incompressible/CompressibleSource` and `Incompressible/CompressibleSink` are available
**Implementation:**
- `crates/components/src/flow_boundary.rs``FlowSource`, `FlowSink`
- 17 unit tests passing
---
### Story 2.1: Fluid Backend Trait Abstraction
@@ -884,6 +946,69 @@ This document provides the complete epic and story breakdown for Entropyk, decom
---
### Story 5.5: Swappable Calibration Variables (Inverse Calibration One-Shot)
**As a** R&D engineer calibrating a machine model against test bench data,
**I want** to swap calibration coefficients (f_m, f_ua, f_power, etc.) into unknowns and measured values (Tsat, capacity, power) into constraints,
**So that** the solver directly computes the calibration coefficients in one shot without external optimizer.
**Context:** Each component has specific calibration factors. In normal simulation, f_ is fixed and outputs are computed. In calibration mode, measured values become constraints and f_ become unknowns.
**Component → Calibration Factor Mapping:**
| Component | f_ Factors | Measurable Values (can swap) |
|-----------|------------|------------------------------|
| Condenser | f_ua, f_dp | Tsat_cond, Q_cond (capacity), ΔP_cond |
| Evaporator | f_ua, f_dp | Tsat_evap, Q_evap (capacity), ΔP_evap |
| Compressor | f_m, f_power, f_etav | ṁ, Power, η_v |
| Expansion Valve | f_m | ṁ |
| Pipe | f_dp | ΔP |
**Acceptance Criteria:**
**Given** a Condenser with f_ua as calibration factor
**When** I enable calibration mode and fix Tsat_cond to measured value
**Then** f_ua becomes an unknown in solver state vector
**And** residual added: Tsat_cond_computed - Tsat_cond_measured = 0
**And** solver computes f_ua directly
**Given** an Evaporator with f_ua as calibration factor
**When** I enable calibration mode and fix Tsat_evap to measured value
**Then** same swap mechanism: f_ua → unknown, Tsat_evap → constraint
**Given** a Compressor with f_power as calibration factor
**When** I enable calibration mode and fix Power to measured value
**Then** f_power becomes unknown
**And** residual: Power_computed - Power_measured = 0
**Given** a Compressor with f_m as calibration factor
**When** I enable calibration mode and fix mass flow ṁ to measured value
**Then** f_m becomes unknown
**And** residual: ṁ_computed - ṁ_measured = 0
**Given** a machine in cooling mode calibration
**When** I impose evaporator cooling capacity Q_evap_measured
**Then** Q_evap becomes constraint (Q_evap_computed - Q_evap_measured = 0)
**And** corresponding f_ (typically f_ua on evaporator) becomes unknown
**Given** a machine in heating mode calibration
**When** I impose condenser heating capacity Q_cond_measured
**Then** Q_cond becomes constraint
**And** corresponding f_ (typically f_ua on condenser) becomes unknown
**Given** multiple calibration swaps on same system
**When** solver runs
**Then** all f_ unknowns solved simultaneously with cycle equations (One-Shot)
**And** Jacobian includes ∂constraint/∂f_ partial derivatives
**And** DoF validated: (equations + calibration_constraints) = (unknowns + swapped_f_factors)
**Given** a calibration swap configuration
**When** serializing system to JSON
**Then** swap state persisted (which f_ are unknowns, which values are fixed)
**And** deserialization restores exact calibration mode
---
## Epic 6: Multi-Platform APIs
### Story 6.1: Rust Native API