1344 lines
46 KiB
Markdown
1344 lines
46 KiB
Markdown
---
|
||
stepsCompleted:
|
||
- step-01-validate-prerequisites
|
||
- step-02-design-epics
|
||
- step-03-create-stories
|
||
inputDocuments:
|
||
- /Users/sepehr/dev/Entropyk/_bmad-output/planning-artifacts/prd.md
|
||
- /Users/sepehr/dev/Entropyk/_bmad-output/planning-artifacts/architecture.md
|
||
---
|
||
|
||
# Entropyk - Epic Breakdown
|
||
|
||
## Overview
|
||
|
||
This document provides the complete epic and story breakdown for Entropyk, decomposing the requirements from the PRD and Architecture requirements into implementable stories.
|
||
|
||
## Requirements Inventory
|
||
|
||
### Functional Requirements
|
||
|
||
**FR1:** The system can model a Compressor according to AHRI 540 standard with manufacturer coefficients
|
||
|
||
**FR2:** The system can model a Condenser with heat transfer calculation
|
||
|
||
**FR3:** The system can model an Expansion Valve (isenthalpic expansion)
|
||
|
||
**FR4:** The system can model an Evaporator with phase change
|
||
|
||
**FR5:** The system can model an Economizer (internal heat exchanger) with Bypass mode
|
||
|
||
**FR6:** Each component can be in OperationalState (On, Off, Bypass)
|
||
|
||
**FR7:** In Off mode, an active component contributes zero mass flow to the system
|
||
|
||
**FR8:** In Bypass mode, a component behaves as an adiabatic pipe (P_in = P_out, h_in = h_out)
|
||
|
||
**FR9:** User can define a Machine containing N independent fluid circuits
|
||
|
||
**FR10:** User can connect components via Ports (inlet/outlet)
|
||
|
||
**FR11:** System supports connections between circuits (thermal coupling)
|
||
|
||
**FR12:** System can solve N circuits simultaneously or sequentially
|
||
|
||
**FR13:** System mathematically handles zero-flow branches without division by zero
|
||
|
||
**FR14:** System can solve equations using Newton-Raphson method
|
||
|
||
**FR15:** System can solve equations using Sequential Substitution (Picard) method
|
||
|
||
**FR16:** Solver automatically switches to Sequential Substitution if Newton-Raphson diverges
|
||
|
||
**FR17:** Solver respects configurable time budget (timeout)
|
||
|
||
**FR18:** On timeout, solver returns best known state with NonConverged status
|
||
|
||
**FR19:** Solver can freeze Jacobian calculation to accelerate (Jacobian Freezing)
|
||
|
||
**FR20:** Convergence criterion checks Delta Pressure < 1 Pa (1e-5 bar)
|
||
|
||
**FR21:** For multi-circuits, global convergence is achieved when ALL circuits converge
|
||
|
||
**FR22:** User can define output constraints (e.g., Superheat = 5K)
|
||
|
||
**FR23:** System calculates necessary inputs (e.g., valve opening) respecting Bounded Constraints (0.0 ≤ Valve ≤ 1.0). If solution is out of bounds, solver returns "Saturation" or "ControlLimitReached" error
|
||
|
||
**FR24:** Inverse Control is solved simultaneously with cycle equations (One-Shot)
|
||
|
||
**FR25:** System can load fluid properties via CoolProp
|
||
|
||
**FR26:** System supports Tabular Interpolation tables for 100x performance
|
||
|
||
**FR27:** System handles pure fluids and mixtures (R32/R125, R454B)
|
||
|
||
**FR28:** System handles Temperature Glide for zeotropic mixtures
|
||
|
||
**FR29:** System uses automatic damping near critical point (CO2 R744)
|
||
|
||
**FR30:** Native Rust API with types and ownership safety
|
||
|
||
**FR31:** Python bindings via PyO3 with tespy-compatible API
|
||
|
||
**FR32:** C FFI for integration with external systems (PLC, LabView)
|
||
|
||
**FR33:** WebAssembly compilation support for web interfaces
|
||
|
||
**FR34:** CLI for batch simulation execution
|
||
|
||
**FR35:** System automatically checks mass balance (Σ ṁ_in - Σ ṁ_out < 1e-9 kg/s)
|
||
|
||
**FR36:** System automatically checks energy balance (Σ Q̇ + Ẇ - Σ (ṁ · h) < 1e-6 kW)
|
||
|
||
**FR37:** Each result contains traceability metadata (solver version, fluid version, SHA-256 input hash)
|
||
|
||
**FR38:** Debug Verbose mode to display residuals and convergence history
|
||
|
||
**FR39:** Error handling via Result<T, ThermoError> (Zero-Panic Policy)
|
||
|
||
**FR40:** System handles Incompressible Fluids (Water, Glycol, Humid Air simplified) via lightweight models (constant Cp or polynomial) for heat sources and sinks
|
||
|
||
**FR41:** Complete graph (Topology + Parameters + Fluid State) is serializable/deserializable to JSON (or TOML)
|
||
|
||
**FR42:** System includes Automatic Initialization Heuristic (Smart Guesser) proposing coherent initial pressure values based on source/sink temperatures
|
||
|
||
**FR43:** Components support calibration parameters (Calib: f_m, f_dp, f_ua, f_power, f_etav) to match simulation to real machine test data
|
||
|
||
**FR44:** System can validate results against ASHRAE 140 / BESTEST test cases (post-MVP)
|
||
|
||
**FR45:** System supports inverse calibration (parameter estimation from test bench data)
|
||
|
||
**FR46:** Explicit Air Coil components (EvaporatorCoil, CondenserCoil) for finned air heat exchangers (post-MVP)
|
||
|
||
**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
|
||
|
||
**NFR2:** Simple cycle (Single-stage) solved in **< 100 ms**
|
||
|
||
**NFR3:** Complex cycle (Multi-circuits) solved in **< 1 second**
|
||
|
||
**NFR4:** No dynamic allocation in solver loop (pre-calculated allocation only)
|
||
|
||
**NFR5:** Guaranteed determinism: same inputs → same results within 1e-9 precision on all platforms (x86, ARM, WASM)
|
||
|
||
**NFR6:** HIL latency < **20 ms** for real-time integration with PLC
|
||
|
||
**NFR7:** Zero-Panic Policy: no crash even with invalid inputs or impossible states
|
||
|
||
**NFR8:** Memory Safety guaranteed by Rust ownership system (no memory leaks, no use-after-free)
|
||
|
||
**NFR9:** Capability to run **48h+** without interruption or degradation (HIL/Embedded)
|
||
|
||
**NFR10:** Graceful error handling: timeout, non-convergence, saturation return explicit Result<T, Error>
|
||
|
||
**NFR11:** CoolProp 6.4+ compatibility for fluid properties
|
||
|
||
**NFR12:** Stable C FFI: auto-generated .h headers via cbindgen, C99/C++ compatible
|
||
|
||
**NFR13:** Deterministic WebAssembly: same behavior as native, no non-determinism sources
|
||
|
||
**NFR14:** Python bindings PyO3: tespy-compatible API for facilitated migration
|
||
|
||
**NFR15:** 100% documentation of public APIs (rustdoc)
|
||
|
||
**NFR16:** Automated CI/CD: tests, benchmarks, memory checks (Valgrind + Miri)
|
||
|
||
**NFR17:** Zero tolerance warnings: `cargo clippy -- -D warnings`
|
||
|
||
### Additional Requirements
|
||
|
||
**Architecture Requirements:**
|
||
|
||
- Workspace-based multi-crate architecture with 4 crates (core, solver, components, fluids) and 3 bindings (python, c, wasm)
|
||
- Trait-based static polymorphism with enum dispatch for zero-cost abstraction
|
||
- NewType pattern for all physical quantities (Pressure, Temperature, Enthalpy, MassFlow) - never bare f64 in public APIs
|
||
- Type-State pattern for connection safety at compile-time
|
||
- Pre-allocated buffers only - no heap allocation in hot paths
|
||
- `#![deny(warnings)]` in lib.rs for all crates
|
||
- KaTeX configuration in `.cargo/config.toml` for mathematical documentation
|
||
- `tracing` for structured logging (never println!)
|
||
- `thiserror` for error handling with ThermoError enum
|
||
- `approx` crate for floating-point assertions with explicit tolerances
|
||
- Sys-crate pattern for CoolProp C++ integration
|
||
- cbindgen for C header generation
|
||
- Miri validation in CI for undefined behavior detection
|
||
- Mass balance tolerance: 1e-9 kg/s
|
||
- Energy balance tolerance: 1e-6 kW
|
||
- Convergence pressure tolerance: 1 Pa
|
||
|
||
**Standards Compliance:**
|
||
|
||
- AHRI 540 standard implementation for compressor modeling with manufacturer coefficients (Bitzer, Copeland, Danfoss)
|
||
- NIST REFPROP as gold standard for fluid properties
|
||
- CoolProp as open-source reference
|
||
- Tabular interpolation achieving < 0.01% deviation from NIST while being 100x faster than direct EOS calls
|
||
|
||
**Domain-Specific Requirements:**
|
||
|
||
- Critical Point handling (CO2 R744) with automatic damping to prevent NaN in partial derivatives
|
||
- Temperature Glide handling for zeotropic mixtures (R454B, R32/R125) integrating Bubble Point → Dew Point without approximation
|
||
- Traçability: Each SimulationResult contains solver_version, fluid_backend version, input_hash (SHA-256)
|
||
- Smart initialization heuristic for initial pressure guesses based on source/sink temperatures
|
||
|
||
**CI/CD Requirements:**
|
||
|
||
- `cargo test`: Unit tests
|
||
- `cargo bench`: Performance regression (failure if > 5% degradation)
|
||
- `valgrind`: Memory leaks (FFI)
|
||
- `cargo clippy -- -D warnings`: Zero tolerance style
|
||
- `miri test`: Undefined behavior detection
|
||
- 100% public documentation coverage
|
||
- Compiled and tested examples in CI
|
||
|
||
**Packaging & Distribution:**
|
||
|
||
- Rust: crates.io
|
||
- Python: pip install rust-thermo-cycle (Wheels PyPI, manylinux)
|
||
- C/C++: Headers + dynamic libraries
|
||
- Docker: Image rust-thermo-lab (JupyterLab + Rust kernel + CoolProp)
|
||
|
||
### FR Coverage Map
|
||
|
||
| FR | Epic | Description |
|
||
|----|------|-------------|
|
||
| FR1 | Epic 1 | Compressor AHRI 540 modeling |
|
||
| FR2 | Epic 1 | Condenser heat transfer |
|
||
| FR3 | Epic 1 | Expansion valve isenthalpic |
|
||
| FR4 | Epic 1 | Evaporator phase change |
|
||
| FR5 | Epic 1 | Economizer with bypass |
|
||
| FR6 | Epic 1 | Component states ON/OFF/BYPASS |
|
||
| FR7 | Epic 1 | Zero mass flow in OFF mode |
|
||
| FR8 | Epic 1 | Adiabatic pipe in BYPASS mode |
|
||
| FR9 | Epic 3 | Multi-circuit machine definition |
|
||
| FR10 | Epic 3 | Component connection via Ports |
|
||
| FR11 | Epic 3 | Thermal coupling between circuits |
|
||
| FR12 | Epic 3 | Simultaneous/sequential circuit solving |
|
||
| FR13 | Epic 3 | Zero-flow branch handling |
|
||
| FR14 | Epic 4 | Newton-Raphson solver |
|
||
| FR15 | Epic 4 | Sequential Substitution solver |
|
||
| FR16 | Epic 4 | Auto-fallback solver switching |
|
||
| FR17 | Epic 4 | Configurable timeout |
|
||
| FR18 | Epic 4 | Best state on timeout |
|
||
| FR19 | Epic 4 | Jacobian freezing |
|
||
| FR20 | Epic 4 | Delta Pressure < 1 Pa convergence |
|
||
| FR21 | Epic 4 | Global multi-circuit convergence |
|
||
| FR22 | Epic 5 | Output constraints definition |
|
||
| FR23 | Epic 5 | Bounded input calculation |
|
||
| FR24 | Epic 5 | One-shot inverse control |
|
||
| FR25 | Epic 2 | CoolProp integration |
|
||
| FR26 | Epic 2 | Tabular interpolation tables |
|
||
| FR27 | Epic 2 | Pure fluids and mixtures support |
|
||
| FR28 | Epic 2 | Temperature glide handling |
|
||
| FR29 | Epic 2 | Critical point damping |
|
||
| FR30 | Epic 6 | Native Rust API |
|
||
| FR31 | Epic 6 | Python PyO3 bindings |
|
||
| FR32 | Epic 6 | C FFI bindings |
|
||
| FR33 | Epic 6 | WebAssembly support |
|
||
| FR34 | Epic 6 | CLI for batch execution |
|
||
| FR35 | Epic 7 | Mass balance validation |
|
||
| FR36 | Epic 7 | Energy balance validation |
|
||
| FR37 | Epic 7 | Traceability metadata |
|
||
| FR38 | Epic 7 | Debug verbose mode |
|
||
| FR39 | Epic 7 | Zero-panic error handling |
|
||
| FR40 | Epic 2 | Incompressible fluids support |
|
||
| FR41 | Epic 7 | JSON serialization |
|
||
| FR42 | Epic 4 | Smart initialization heuristic |
|
||
| FR43 | Epic 7 | Component calibration parameters (Calib) |
|
||
| FR44 | Epic 7 | ASHRAE 140 / BESTEST validation |
|
||
| FR45 | Epic 7 | Inverse calibration (parameter estimation) |
|
||
| 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
|
||
|
||
### Epic 1: Extensible Component Framework
|
||
**Goal:** Create the foundation that allows adding any component (VFD, Battery, Pump, Pipe) by simply implementing a Rust Trait, without touching the calculation engine.
|
||
|
||
**Innovation:** Trait-based "Lego" architecture to add Compressors, Pumps, VFDs, Pipes, etc.
|
||
|
||
**FRs covered:** FR1, FR2, FR3, FR4, FR5, FR6, FR7, FR8, FR46, FR49, FR50
|
||
|
||
---
|
||
|
||
### Epic 2: Fluid Properties Backend
|
||
**Goal:** Provide precise thermodynamic properties via CoolProp, tabular tables, mixture handling, and critical point management.
|
||
|
||
**Innovation:** 100x performance with tabular tables, automatic CO2 damping.
|
||
|
||
**FRs covered:** FR25, FR26, FR27, FR28, FR29, FR40, FR47
|
||
|
||
---
|
||
|
||
### Epic 3: System Topology (Graph)
|
||
**Goal:** Enable component assembly via Ports and manage multi-circuits with thermal coupling, and support hierarchical subsystems.
|
||
|
||
**Innovation:** Multi-fluid directed graph in a single model, with natively supported hierarchical sub-blocks.
|
||
|
||
**FRs covered:** FR9, FR10, FR11, FR12, FR13, FR48
|
||
|
||
---
|
||
|
||
### Epic 4: Intelligent Solver Engine
|
||
**Goal:** Solve any system with < 1s guarantee, Newton-Raphson ↔ Sequential Substitution fallback.
|
||
|
||
**Innovation:** Solver-agnostic with intelligent fallback - guaranteed convergence.
|
||
|
||
**FRs covered:** FR14, FR15, FR16, FR17, FR18, FR19, FR20, FR21, FR42
|
||
|
||
---
|
||
|
||
### Epic 5: Inverse Control & Optimization
|
||
**Goal:** Transform component parameters (VFD speed, Valve position) into simultaneously solved unknowns.
|
||
|
||
**Innovation:** Native Inverse Control via Residual Embedding - "One-Shot".
|
||
|
||
**FRs covered:** FR22, FR23, FR24, FR51
|
||
|
||
---
|
||
|
||
### Epic 6: Multi-Platform APIs
|
||
**Goal:** Distribute the library via Python (PyO3), WebAssembly, C FFI, and CLI.
|
||
|
||
**Innovation:** Multi-target without code duplication (Rust → Python/WASM/C).
|
||
|
||
**FRs covered:** FR30, FR31, FR32, FR33, FR34
|
||
|
||
---
|
||
|
||
### Epic 7: Validation & Persistence
|
||
**Goal:** Guarantee trust via mass/energy balances, SHA-256 traceability, and JSON persistence.
|
||
|
||
**Innovation:** Complete traceability and scientific reproducibility.
|
||
|
||
**FRs covered:** FR35, FR36, FR37, FR38, FR39, FR41, FR43, FR44, FR45
|
||
|
||
---
|
||
|
||
### Epic 8: Component-Fluid Integration
|
||
**Goal:** Integrate real thermodynamic fluid properties directly into component Residual calculation models.
|
||
|
||
**Innovation:** True physical interaction between solver mathematics and state equations.
|
||
|
||
**FRs covered:** FR47
|
||
|
||
---
|
||
|
||
<!-- ALL EPICS AND STORIES -->
|
||
|
||
## Epic 1: Extensible Component Framework
|
||
|
||
### Story 1.1: Component Trait Definition
|
||
|
||
**As a** library developer,
|
||
**I want** to define a generic Component trait with methods for residuals, ports, and state management,
|
||
**So that** future components can be implemented by simply implementing this trait.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** a new component struct
|
||
**When** it implements the Component trait
|
||
**Then** it must provide compute_residuals(), get_ports(), and get_state() methods
|
||
**And** the trait must be object-safe for dynamic dispatch
|
||
|
||
---
|
||
|
||
### Story 1.2: Physical Types (NewType Pattern)
|
||
|
||
**As a** simulation user,
|
||
**I want** type-safe physical quantities (Pressure, Temperature, Enthalpy, MassFlow),
|
||
**So that** I cannot accidentally mix units.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** a function accepting Pressure and Temperature
|
||
**When** I try to pass Temperature where Pressure is expected
|
||
**Then** the code must not compile (compile-time safety)
|
||
**And** conversions must be explicit (e.g., pressure_bar.to_pascals())
|
||
|
||
---
|
||
|
||
### Story 1.3: Port and Connection System
|
||
|
||
**As a** system modeler,
|
||
**I want** to define inlet/outlet ports for components and connect them bidirectionally,
|
||
**So that** I can build fluid circuit topologies.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** two components with compatible ports
|
||
**When** I call connect(port_a, port_b)
|
||
**Then** the connection is established with state validation
|
||
**And** attempting to connect incompatible ports fails at compile-time
|
||
|
||
---
|
||
|
||
### Story 1.4: Compressor Component (AHRI 540)
|
||
|
||
**As a** thermodynamic engineer,
|
||
**I want** to model a compressor using AHRI 540 standard coefficients,
|
||
**So that** I can simulate real compressor behavior with manufacturer data.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** a compressor with 10 AHRI 540 coefficients
|
||
**When** I compute residuals for a given operating point
|
||
**Then** the power consumption and mass flow are calculated per AHRI 540 equations
|
||
**And** the result matches certified AHRI test data within 1%
|
||
|
||
---
|
||
|
||
### Story 1.5: Generic Heat Exchanger Framework
|
||
|
||
**As a** thermal systems engineer,
|
||
**I want** a pluggable heat exchanger framework supporting multiple calculation models (Pinch point, LMTD, ε-NTU),
|
||
**So that** I can add new exchanger types without modifying the solver.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** a heat exchanger component
|
||
**When** I plug in a calculation model (Pinch, LMTD, or ε-NTU)
|
||
**Then** the residuals are computed using the selected model
|
||
**And** new models can be added by implementing a HeatTransferModel trait
|
||
**And** Condenser, Evaporator, and Economizer are implemented as specific configurations
|
||
|
||
---
|
||
|
||
### Story 1.6: Expansion Valve Component
|
||
|
||
**As a** control engineer,
|
||
**I want** to model an expansion valve with isenthalpic expansion,
|
||
**So that** I can simulate pressure reduction in the refrigeration cycle.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** an expansion valve with inlet subcooled liquid at high pressure
|
||
**When** I compute residuals
|
||
**Then** the outlet is two-phase or saturated liquid at lower pressure
|
||
**And** enthalpy is conserved (h_in = h_out)
|
||
|
||
---
|
||
|
||
### Story 1.7: Component State Machine
|
||
|
||
**As a** simulation user,
|
||
**I want** components to support ON, OFF, and BYPASS states,
|
||
**So that** I can simulate system configurations and failures.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** a component in ON state
|
||
**When** I switch it to OFF
|
||
**Then** it contributes zero mass flow to the system
|
||
**And** when in BYPASS, it behaves as an adiabatic pipe (P_in = P_out, h_in = h_out)
|
||
|
||
---
|
||
|
||
### Story 1.8: Auxiliary & Transport Components
|
||
|
||
**As a** system integrator,
|
||
**I want** to model Pumps, VFDs, and Pipes,
|
||
**So that** I can simulate complete HVAC systems.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** a Pump with specified hydraulic efficiency
|
||
**When** I compute residuals
|
||
**Then** power consumption and pressure rise match the pump curve
|
||
**And** a VFD can modify Pump or Compressor speed via affinity laws
|
||
**And** a Pipe calculates pressure drop via Darcy-Weisbach
|
||
|
||
---
|
||
|
||
### 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 `2N−1` 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
|
||
|
||
**As a** library developer,
|
||
**I want** to define a FluidBackend trait,
|
||
**So that** the solver can switch between CoolProp, tabular, and mock backends.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** a fluid property query
|
||
**When** I call backend.property(fluid, property, state)
|
||
**Then** it returns correct values regardless of backend implementation
|
||
**And** CoolPropBackend, TabularBackend, and TestBackend all implement the trait
|
||
|
||
---
|
||
|
||
### Story 2.2: CoolProp Integration (sys-crate)
|
||
|
||
**As a** simulation user,
|
||
**I want** CoolProp as the primary backend,
|
||
**So that** I get NIST-quality thermodynamic data.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** a refrigerant and thermodynamic state
|
||
**When** I query via CoolPropBackend
|
||
**Then** results match CoolProp 6.4+ within machine precision
|
||
**And** C++ CoolProp is statically linked via sys-crate
|
||
|
||
---
|
||
|
||
### Story 2.3: Tabular Interpolation Backend
|
||
|
||
**As a** performance-critical user,
|
||
**I want** pre-computed NIST tables with fast interpolation,
|
||
**So that** queries are 100x faster than direct EOS.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** a tabular data file for a fluid
|
||
**When** I query via TabularBackend
|
||
**Then** results deviate < 0.01% from NIST REFPROP
|
||
**And** query time is < 1μs
|
||
|
||
---
|
||
|
||
### Story 2.4: LRU Cache for Fluid Properties
|
||
|
||
**As a** solver developer,
|
||
**I want** lock-free or thread-local caching,
|
||
**So that** redundant calculations are avoided without mutex contention.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** repeated property queries
|
||
**When** cache is enabled
|
||
**Then** Thread-Local or lock-free (dashmap) caching is used
|
||
**And** no mutex contention under high parallelism (Rayon)
|
||
**And** cache invalidates on state changes
|
||
|
||
---
|
||
|
||
### Story 2.5: Mixture and Temperature Glide Support
|
||
|
||
**As a** refrigeration engineer,
|
||
**I want** robust (P, h) and (P, x) inputs for zeotropic mixtures,
|
||
**So that** the solver handles temperature glide reliably.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** a zeotropic mixture at constant pressure
|
||
**When** calculating evaporation
|
||
**Then** temperature glide from bubble to dew point is correct
|
||
**And** backend supports (P, h) and (P, x) inputs robustly
|
||
**And** (P, h) is preferred over (P, T) for two-phase mixtures
|
||
|
||
---
|
||
|
||
### Story 2.6: Critical Point Damping (CO2 R744)
|
||
|
||
**As a** CO2 systems designer,
|
||
**I want** smooth, differentiable damping near critical point,
|
||
**So that** Newton-Raphson converges without discontinuities.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** CO2 near critical point (Tc=304.13K, Pc=7.3773 MPa)
|
||
**When** querying within 5% of critical point
|
||
**Then** damping is applied to partial derivatives
|
||
**And** no NaN values
|
||
**And** damping function is C1-continuous (sigmoid transition)
|
||
|
||
---
|
||
|
||
### Story 2.7: Incompressible Fluids Support
|
||
|
||
**As a** HVAC engineer,
|
||
**I want** water, glycol, and moist air as incompressible fluids,
|
||
**So that** heat sources/sinks are fast to compute.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** an incompressible fluid
|
||
**When** querying density, Cp, or enthalpy
|
||
**Then** lightweight polynomial models are used
|
||
**And** results match references within 0.1%
|
||
**And** computation is 1000x faster than compressible EOS
|
||
|
||
---
|
||
|
||
### Story 2.8: Rich Thermodynamic State Abstraction
|
||
|
||
**As a** system engineer,
|
||
**I want** components to expose a comprehensive `ThermoState` structure (P, T, T_sat, Quality, tsh, Reynolds, Enthalpy, Entropy, etc.),
|
||
**So that** I don't have to manually calculate these from raw state arrays after solver convergence.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** a converged component (e.g., Compressor or Condenser)
|
||
**When** I call `component.outlet_thermo_state()`
|
||
**Then** it returns a `ThermoState` object
|
||
**And** the object contains dynamically resolved saturated temperature, vapor quality, superheat, and phase
|
||
**And** `FluidBackend` natively supports resolving this full snapshot in one trait call `full_state(p, h)`
|
||
|
||
---
|
||
|
||
## Epic 3: System Topology (Graph)
|
||
|
||
### Story 3.1: System Graph Structure
|
||
|
||
**As a** system modeler,
|
||
**I want** edges to index the solver's state vector,
|
||
**So that** P and h unknowns assemble into the Jacobian.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** components with ports
|
||
**When** adding to System graph
|
||
**Then** edges serve as indices into solver's state vector
|
||
**And** each flow edge represents P and h unknowns
|
||
**And** solver traverses graph to assemble Jacobian
|
||
**And** cycles are detected and validated
|
||
|
||
---
|
||
|
||
### Story 3.2: Port Compatibility Validation
|
||
|
||
**As a** system designer,
|
||
**I want** port connection validation at build time,
|
||
**So that** incompatible connections are caught early.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** two ports with incompatible fluids
|
||
**When** attempting to connect
|
||
**Then** connection fails with clear error
|
||
**And** valid connections are accepted
|
||
**And** pressure/enthalpy continuity is enforced
|
||
|
||
---
|
||
|
||
### Story 3.3: Multi-Circuit Machine Definition
|
||
|
||
**As a** R&D engineer (Marie),
|
||
**I want** machines with N independent circuits,
|
||
**So that** I simulate complex heat pumps.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** a machine with 2+ circuits
|
||
**When** defining topology
|
||
**Then** each circuit is tracked independently
|
||
**And** circuits can be solved simultaneously or sequentially
|
||
**And** supports up to N=5 circuits
|
||
|
||
---
|
||
|
||
### Story 3.4: Thermal Coupling Between Circuits
|
||
|
||
**As a** systems engineer,
|
||
**I want** thermal coupling with circular dependency detection,
|
||
**So that** solver knows to solve simultaneously vs sequentially.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** two circuits with a heat exchanger
|
||
**When** defining thermal coupling
|
||
**Then** heat transfer equations link circuits
|
||
**And** energy is conserved (Q_hot = -Q_cold)
|
||
**And** circular dependencies force simultaneous solving
|
||
**And** coupling represented as additional residuals
|
||
|
||
---
|
||
|
||
### Story 3.5: Zero-Flow Branch Handling
|
||
|
||
**As a** simulation user,
|
||
**I want** zero-flow handling with regularization,
|
||
**So that** OFF components don't cause numerical instabilities.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** a branch with mass flow = 0
|
||
**When** computing residuals
|
||
**Then** no division-by-zero
|
||
**And** regularization applied (ε minimum in divisions)
|
||
**And** auto-switch to pressure continuity when OFF
|
||
**And** Jacobian remains well-conditioned
|
||
|
||
---
|
||
|
||
### Story 3.6: Hierarchical Subsystems (MacroComponents)
|
||
|
||
**As a** system designer,
|
||
**I want** to encapsulate a complete system (e.g., a Chiller with compressor, condenser, valve, evaporator) into a single reusable block,
|
||
**So that** I can compose larger models (like buildings or parallel chiller plants) using these blocks, just like in Modelica.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** a fully defined `System` with internal components and connections
|
||
**When** I wrap it in a `MacroComponent`
|
||
**Then** I can expose specific internal ports (e.g., Evaporator Water In/Out, Condenser Water In/Out) as the `MacroComponent`'s external ports
|
||
**And** this `MacroComponent` implements the `Component` trait
|
||
**And** I can add it to a higher-level `System` just like any regular component
|
||
**And** the global solver correctly flattens or delegates the residual and jacobian computations down to the nested components.
|
||
|
||
---
|
||
|
||
## Epic 4: Intelligent Solver Engine
|
||
|
||
### Story 4.1: Solver Trait Abstraction
|
||
|
||
**As a** numerical developer,
|
||
**I want** a generic Solver trait,
|
||
**So that** strategies are interchangeable.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** a system of equations
|
||
**When** instantiating solver strategies
|
||
**Then** all implement common Solver trait
|
||
**And** provides solve() and with_timeout() methods
|
||
**And** zero-cost abstraction via enum dispatch
|
||
|
||
---
|
||
|
||
### Story 4.2: Newton-Raphson Implementation
|
||
|
||
**As a** simulation engineer,
|
||
**I want** Newton-Raphson with analytical Jacobian support,
|
||
**So that** HIL performance is optimized.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** a system with residuals
|
||
**When** running Newton-Raphson
|
||
**Then** quadratic convergence near solution
|
||
**And** line search prevents overshooting
|
||
**And** supports both numerical and analytical Jacobian
|
||
**And** components provide analytical Jacobian entries
|
||
|
||
---
|
||
|
||
### Story 4.3: Sequential Substitution (Picard) Implementation
|
||
|
||
**As a** fallback solver user,
|
||
**I want** Sequential Substitution for robust convergence,
|
||
**So that** when Newton diverges, I have a stable alternative.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** a system where Newton diverges
|
||
**When** using Sequential Substitution
|
||
**Then** it converges reliably
|
||
**And** variables updated sequentially
|
||
**And** relaxation factors configurable
|
||
|
||
---
|
||
|
||
### Story 4.4: Intelligent Fallback Strategy
|
||
|
||
**As a** simulation user,
|
||
**I want** automatic fallback with smart return conditions,
|
||
**So that** convergence is guaranteed without solver oscillation.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** Newton-Raphson diverging
|
||
**When** divergence detected (> 3 increasing residuals)
|
||
**Then** auto-switch to Sequential Substitution
|
||
**And** return to Newton ONLY when convergence radius reached
|
||
**And** prevent oscillation by requiring stable Picard first
|
||
|
||
---
|
||
|
||
### Story 4.5: Time-Budgeted Solving
|
||
|
||
**As a** HIL engineer (Sarah),
|
||
**I want** strict timeout with graceful degradation,
|
||
**So that** real-time constraints are never violated.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** solver with timeout = 1000ms
|
||
**When** time budget exceeded
|
||
**Then** solver stops immediately
|
||
**And** returns best state with ComputationStatus::Timeout
|
||
**And** for HIL, returns previous state with ZOH
|
||
|
||
---
|
||
|
||
### Story 4.6: Smart Initialization Heuristic
|
||
|
||
**As a** R&D engineer (Marie),
|
||
**I want** automatic initial guesses from temperatures,
|
||
**So that** cold start convergence is fast.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** source and sink temperatures
|
||
**When** initializing system
|
||
**Then** pressures estimated via Antoine equation
|
||
**And** evaporator pressure < P_critical
|
||
**And** condenser pressure from T_sink + ΔT_approach
|
||
|
||
---
|
||
|
||
### Story 4.7: Convergence Criteria & Validation
|
||
|
||
**As a** simulation user,
|
||
**I want** strict criteria with sparse Jacobian for multi-circuit,
|
||
**So that** large systems remain tractable.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** system approaching solution
|
||
**When** checking convergence
|
||
**Then** max |ΔP| < 1 Pa
|
||
**And** mass error < 1e-9 kg/s, energy < 1e-6 kW
|
||
**And** ALL circuits converge for global convergence
|
||
**And** Jacobian uses sparse/block structure
|
||
**And** uncoupled circuits give block-diagonal
|
||
|
||
---
|
||
|
||
### Story 4.8: Jacobian-Freezing Optimization
|
||
|
||
**As a** performance-critical user,
|
||
**I want** to freeze Jacobian updates,
|
||
**So that** CPU time is reduced.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** nearly-converged system
|
||
**When** Jacobian freezing enabled
|
||
**Then** Jacobian computed once, reused
|
||
**And** speed increases ~80%
|
||
**And** auto-disabled if residuals increase
|
||
|
||
---
|
||
|
||
## Epic 5: Inverse Control & Optimization
|
||
|
||
### Story 5.1: Constraint Definition Framework
|
||
|
||
**As a** control engineer,
|
||
**I want** to define output constraints,
|
||
**So that** I specify target operating conditions.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** measurable outputs
|
||
**When** defining constraint (output - target = 0)
|
||
**Then** constraint added to residuals
|
||
**And** can reference any component output
|
||
**And** multiple constraints supported
|
||
|
||
---
|
||
|
||
### Story 5.2: Bounded Control Variables
|
||
|
||
**As a** control engineer,
|
||
**I want** Box Constraints or Step Clipping,
|
||
**So that** Newton steps stay physically possible.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** control variable with bounds [min, max]
|
||
**When** computing Newton step (Δx)
|
||
**Then** step scaled/clipped if exceeding bounds
|
||
**And** variable never outside bounds during iterations
|
||
**And** ControlSaturation error if converged solution exceeds bounds
|
||
|
||
---
|
||
|
||
### Story 5.3: Residual Embedding for Inverse Control
|
||
|
||
**As a** systems engineer,
|
||
**I want** constraints embedded with DoF validation,
|
||
**So that** system is well-posed.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** constraint and control variable
|
||
**When** solving system
|
||
**Then** residual added to residual vector
|
||
**And** control variable added to unknowns
|
||
**And** solved simultaneously (one-shot)
|
||
**And** Jacobian includes ∂constraint/∂control
|
||
**And** DoF validated (equations = unknowns)
|
||
**And** OverConstrainedSystem error if mismatch
|
||
|
||
---
|
||
|
||
### Story 5.4: Multi-Variable Control
|
||
|
||
**As a** control engineer,
|
||
**I want** to control multiple outputs simultaneously,
|
||
**So that** I optimize complete operation.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** multiple constraints
|
||
**When** defining control problem
|
||
**Then** each constraint maps to one control variable
|
||
**And** all solved simultaneously
|
||
**And** all constraints satisfied within tolerance
|
||
|
||
---
|
||
|
||
### 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
|
||
|
||
**As a** Rust developer,
|
||
**I want** clean, idiomatic Rust API,
|
||
**So that** I integrate into Rust applications.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** a Rust application
|
||
**When** using entropyk crate
|
||
**Then** builder pattern for systems
|
||
**And** all functions return Result<T, ThermoError>
|
||
**And** follows Rust conventions
|
||
**And** KaTeX documentation
|
||
|
||
---
|
||
|
||
### Story 6.2: Python Bindings (PyO3)
|
||
|
||
**As a** Python data scientist (Alice),
|
||
**I want** zero-copy NumPy support,
|
||
**So that** 100x speedup isn't wasted on conversion.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** Python script with rust_thermo_cycle
|
||
**When** creating components
|
||
**Then** API similar to tespy
|
||
**And** errors mapped to Python exceptions
|
||
**And** wheels on PyPI (manylinux)
|
||
**And** Buffer Protocol and NumPy arrays supported
|
||
**And** zero-copy for 10k+ element vectors
|
||
**And** 100x faster than tespy
|
||
|
||
---
|
||
|
||
### Story 6.3: C FFI Bindings (cbindgen)
|
||
|
||
**As a** HIL engineer (Sarah),
|
||
**I want** C headers with explicit memory management,
|
||
**So that** PLC integration has no memory leaks.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** C/C++ application
|
||
**When** including headers
|
||
**Then** extern "C" interface available
|
||
**And** headers auto-generated via cbindgen
|
||
**And** error codes as enum values
|
||
**And** opaque pointers for complex types
|
||
**And** every allocation has free function (e.g., entropyk_free_system)
|
||
**And** latency < 20ms
|
||
|
||
---
|
||
|
||
### Story 6.4: WebAssembly Compilation
|
||
|
||
**As a** web developer (Charlie),
|
||
**I want** WASM with TabularBackend default,
|
||
**So that** it works without CoolProp in browser.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** web application
|
||
**When** importing WASM module
|
||
**Then** can create and solve in browser
|
||
**And** results JSON-serializable
|
||
**And** deterministic performance
|
||
**And** package on npm
|
||
**And** defaults to TabularBackend (CoolProp unavailable in WASM)
|
||
**And** works out-of-box in Chrome/Edge
|
||
**And** cycle time < 100ms
|
||
|
||
---
|
||
|
||
### Story 6.5: CLI for Batch Execution
|
||
|
||
**As a** data engineer (David),
|
||
**I want** CLI for batch simulations,
|
||
**So that** I process millions of scenarios.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** JSON config file
|
||
**When** running entropyk-cli run config.json
|
||
**Then** simulation executes
|
||
**And** outputs results to JSON
|
||
**And** batch mode supports parallel execution
|
||
**And** progress reported
|
||
**And** exit codes indicate success/failure
|
||
|
||
---
|
||
|
||
## Epic 7: Validation & Persistence
|
||
|
||
### Story 7.1: Mass Balance Validation
|
||
|
||
**As a** simulation engineer,
|
||
**I want** automatic mass conservation verification,
|
||
**So that** I trust physical correctness.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** converged solution
|
||
**When** computing mass balance
|
||
**Then** error Σ ṁ_in - Σ ṁ_out < 1e-9 kg/s
|
||
**And** violations trigger validation error
|
||
**And** check performed after every solve
|
||
|
||
---
|
||
|
||
### Story 7.2: Energy Balance Validation
|
||
|
||
**As a** simulation engineer,
|
||
**I want** First AND Second Law verification,
|
||
**So that** thermodynamic consistency is guaranteed.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** converged solution
|
||
**When** computing balances
|
||
**Then** energy error < 1e-6 kW
|
||
**And** violations trigger error with breakdown
|
||
**And** Second Law check: entropy generation ≥ 0
|
||
**And** warning if negative entropy destruction
|
||
**And** violations flagged
|
||
|
||
---
|
||
|
||
### Story 7.3: Traceability Metadata
|
||
|
||
**As a** researcher (Robert),
|
||
**I want** complete traceability metadata,
|
||
**So that** simulations are reproducible.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** simulation result
|
||
**When** accessing metadata
|
||
**Then** includes solver_version, fluid_backend_version, input_hash (SHA-256)
|
||
**And** SHA-256 uniquely identifies input
|
||
**And** metadata in structured JSON
|
||
|
||
---
|
||
|
||
### Story 7.4: Debug Verbose Mode
|
||
|
||
**As a** researcher (Robert),
|
||
**I want** detailed convergence diagnostics,
|
||
**So that** I debug non-converging systems.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** non-converging system
|
||
**When** verbose mode enabled
|
||
**Then** residuals logged each iteration
|
||
**And** Jacobian condition number reported
|
||
**And** solver switches logged
|
||
**And** final state dumped
|
||
|
||
---
|
||
|
||
### Story 7.5: JSON Serialization & Deserialization
|
||
|
||
**As a** system designer,
|
||
**I want** complete system serialization with backend definition,
|
||
**So that** models are reproducible across machines.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** system with components, connections, parameters
|
||
**When** serializing to JSON
|
||
**Then** complete state saved (Topology + Parameters + Fluid State)
|
||
**And** fluid backend fully included (version, hash)
|
||
**And** deserialization reconstructs identical system
|
||
**And** round-trip produces identical results
|
||
**And** human-readable, versioned format
|
||
**And** explicit error if backend missing on load
|
||
**And** error specifies required backend version
|
||
|
||
---
|
||
|
||
### Story 7.6: Component Calibration Parameters (Calib)
|
||
|
||
**As a** R&D engineer matching simulation to real machine test data,
|
||
**I want** calibration factors (Calib: f_m, f_dp, f_ua, f_power, f_etav) on components,
|
||
**So that** simulation results align with manufacturer test data and field measurements.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** a component with nominal model parameters
|
||
**When** Calib (calibration factors) are set (default 1.0 = no correction)
|
||
**Then** f_m scales mass flow: ṁ_eff = f_m × ṁ_nominal (Compressor, Expansion Valve)
|
||
**And** f_dp scales pressure drop: ΔP_eff = f_dp × ΔP_nominal (Pipe, Heat Exchanger)
|
||
**And** f_ua scales thermal conductance: UA_eff = f_ua × UA_nominal (Evaporator, Condenser)
|
||
**And** f_power scales compressor power: Ẇ_eff = f_power × Ẇ_nominal (Compressor)
|
||
**And** f_etav scales volumetric efficiency: η_v,eff = f_etav × η_v,nominal (Compressor, displacement models)
|
||
|
||
**Given** calibration factors from test data optimization
|
||
**When** running simulation with calibrated components
|
||
**Then** results match test data within configurable tolerance (e.g., capacity ±2%, power ±3%)
|
||
**And** Calib values are serializable in JSON (persisted with system definition)
|
||
**And** calibration workflow order documented: f_m → f_dp → f_ua, then f_power (prevents parameter fighting)
|
||
|
||
**Given** a calibrated system
|
||
**When** loading from JSON
|
||
**Then** Calib parameters are restored
|
||
**And** traceability metadata includes calibration source (test data hash or identifier)
|
||
|
||
---
|
||
|
||
### Story 7.7: ASHRAE 140 / BESTEST Validation (post-MVP)
|
||
|
||
**As a** simulation engineer seeking industrial credibility,
|
||
**I want** to validate Entropyk against ASHRAE Standard 140 and BESTEST test cases,
|
||
**So that** results are comparable to EnergyPlus, TRNSYS, and Modelica.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** ASHRAE 140 / Airside HVAC BESTEST (AE101–AE445) test case definitions
|
||
**When** running Entropyk on equivalent cycle configurations
|
||
**Then** results fall within documented tolerance bands vs reference
|
||
**And** discrepancies are documented (algorithmic, modeling assumptions)
|
||
**And** CI includes regression tests for selected cases
|
||
|
||
**Given** a new Entropyk release
|
||
**When** running validation suite
|
||
**Then** no regression beyond tolerance
|
||
**And** validation report generated (JSON or markdown)
|
||
|
||
---
|
||
|
||
### Story 7.8: Inverse Calibration (Parameter Estimation)
|
||
|
||
**As a** R&D engineer with test bench data,
|
||
**I want** to estimate Calib (or component) parameters from measured data,
|
||
**So that** the model matches my machine without manual tuning.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** test data (P, T, ṁ, Ẇ, Q at multiple operating points)
|
||
**When** running inverse calibration
|
||
**Then** optimizer minimizes error (e.g., MAPE) between model and data
|
||
**And** estimated Calib (or coefficients) are returned
|
||
**And** supports constraints (e.g., 0.8 ≤ f_ua ≤ 1.2)
|
||
**And** calibration order respected (f_m → f_dp → f_ua → f_power)
|
||
|
||
**Given** calibrated parameters
|
||
**When** saving system
|
||
**Then** Calib values and calibration_source (data hash) persisted in JSON
|
||
|
||
---
|
||
|
||
## Epic 8: Component-Fluid Integration
|
||
|
||
### Story 8.1: Fluid Backend Component Integration
|
||
|
||
**As a** systems engineer,
|
||
**I want** the thermodynamic components (Compressor, Condenser, etc.) to use the real `FluidBackend`,
|
||
**So that** the residuals sent to the solver reflect accurate physical states.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** a component needing physical properties
|
||
**When** the solver computes its residuals
|
||
**Then** it natively references the configured `FluidBackend`
|
||
**And** returns real values vs placeholders
|
||
**And** handles missing backends gracefully with fallbacks
|
||
|
||
---
|
||
|
||
### Story 1.9: Air Coils (EvaporatorCoil, CondenserCoil) (post-MVP)
|
||
|
||
**As a** HVAC engineer modeling split systems or air-source heat pumps,
|
||
**I want** explicit EvaporatorCoil and CondenserCoil components,
|
||
**So that** air-side heat exchangers (finned) are clearly distinguished from water-cooled.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** an EvaporatorCoil (refrigerant + air)
|
||
**When** defining the component
|
||
**Then** 4 ports: refrigerant in/out, air in/out
|
||
**And** UA or geometry (fins, tubes) configurable
|
||
**And** integrates with Fan for air flow
|
||
**And** Calib (f_ua, f_dp) applicable
|
||
|
||
**Given** a CondenserCoil
|
||
**Then** same structure as EvaporatorCoil
|
||
**And** refrigerant condenses on hot side, air on cold side
|
||
|
||
---
|
||
|
||
### Story 1.10: Pipe Helpers for Water and Refrigerant
|
||
|
||
**As a** HVAC engineer modeling refrigerant and incompressible fluid circuits (water, seawater, glycol),
|
||
**I want** convenient constructors `Pipe::for_incompressible()` and `Pipe::for_refrigerant()` with explicit ρ/μ from a fluid backend,
|
||
**So that** I can create pipes without hardcoding fluid properties in the component.
|
||
|
||
**Acceptance Criteria:**
|
||
|
||
**Given** an incompressible fluid circuit (water, seawater, glycol)
|
||
**When** calling `Pipe::for_incompressible(geometry, port_inlet, port_outlet, density, viscosity)`
|
||
**Then** accepts explicit ρ, μ obtained from IncompressibleBackend (Story 2.7)
|
||
**And** no hardcoded fluid properties in components crate
|
||
**And** doc examples show water and glycol usage
|
||
|
||
**Given** a refrigerant circuit (R134a, R410A, CO2, etc.)
|
||
**When** calling `Pipe::for_refrigerant(geometry, port_inlet, port_outlet, density, viscosity)`
|
||
**Then** accepts explicit ρ, μ (from CoolProp/tabular at design point)
|
||
**And** doc examples show refrigerant circuit usage
|
||
**And** doc states that ρ, μ vary with P,T — design-point values are typical
|
||
|
||
**Given** the Pipe module documentation
|
||
**When** reading the crate-level and `Pipe` docs
|
||
**Then** explicitly states that Pipe serves for both refrigerant and incompressible fluids
|
||
**And** includes a "Fluid Support" section: refrigerant (ρ/μ from backend) vs incompressible (ρ/μ from IncompressibleBackend)
|
||
|
||
---
|
||
|
||
## Future Epics (Vision – littérature HVAC)
|
||
|
||
*Non planifiés – alignement avec EnergyPlus, Modelica, TRNSYS :*
|
||
|
||
| Epic | Thème | Référence littérature |
|
||
|------|-------|------------------------|
|
||
| **Transient** | Simulation dynamique, start-up/shutdown, ODEs | Reddy, Purdue IIAR |
|
||
| **Part-load** | Courbes PLF, pertes de cyclage | EnergyPlus PLF |
|
||
| **Frost/Defrost** | Givre, dégivrage, enthalpy method | arXiv 2412.00017 |
|
||
| **Moving Boundary** | Échangeurs discretisés, zones phase | Modelica Buildings, TIL Suite |
|
||
| **Export ML** | Données synthétiques pour surrogates | arXiv 2505.15041 |
|