# Story 7.1: mass-balance-validation Status: done ## Story As a simulation engineer, I want automatic mass conservation verification, so that I trust physical correctness of the system simulation. ## Acceptance Criteria 1. **Given** converged solution **When** computing mass balance **Then** error Σ ṁ_in - Σ ṁ_out < 1e-9 kg/s 2. **Given** converged solution **When** computing mass balance **Then** violations trigger a validation error 3. **Given** converged solution **When** computing mass balance **Then** check performed after every solve ## Tasks / Subtasks - [x] Task 1: Add Mass Balance Method (AC: 1, 3) - [x] Add a `check_mass_balance` method to `System` (or similar orchestrator). - [x] Method should iterate through all nodes/components and verify that the sum of mass flows leaving equals the sum of mass flows entering. - [x] Establish `1e-9` kg/s as the threshold for mass balance violation. - [x] Task 2: Validation Error Definition (AC: 2) - [x] Ensure `ThermoError::Validation { mass_error: f64, energy_error: f64 }` exists in `crates/core/src/errors.rs` (ensure it handles isolated mass error check or create a specific mass validation error variant if suitable, though PRD says `Validation { mass_error, energy_error }`). - [x] Task 3: Hook into Solver (AC: 3) - [x] Update `solve` / `solve_with_fallback` in `crates/solver/src/lib.rs` (or relevant logic) to perform the mass balance check after convergence. - [x] Return the validation error if criteria are not met. - [x] Task 4: Unit Testing - [x] Implement tests in `tests/validation/energy_balance.rs` or `crates/solver/src/system.rs` for a system that converges successfully to verify validation passes. - [x] Add a mock case where mass balance fails to verify error is raised. ## Dev Notes ### Architecture Patterns & Constraints - **Zero-Panic Policy**: Return `ThermoError::Validation` if mass balance fails. Never panic. - **Scientific Testing Patterns**: Use `approx::assert_relative_eq!(..., epsilon = 1e-9)` for testing mass tolerance. - **Physical Types (NewType Pattern)**: Remember to handle `MassFlow(f64)` unwrapping properly when computing sums or errors. - **Error Handling Strategy**: Use existing `ThermoError` in `crates/core/src/errors.rs`. - Do not add dynamic allocations in the checks if they run in hot paths, although this runs strictly *after* convergence, so it's less critical but ideally iterate over existing graph structure without allocating new vectors. ### Source Tree Components to Touch - `crates/core/src/errors.rs` (if `ThermoError::Validation` needs tweaking) - `crates/solver/src/system.rs` (for `check_mass_balance` logic) - `crates/solver/src/strategies/mod.rs` or `fallback.rs` (to call validation logic post-solve) - `tests/validation/` (to add validation check tests) ### Testing Standards Summary - Use `approx` crate with explicit tolerance `1e-9` kg/s. - `cargo clippy -- -D warnings` must pass. - `cargo test --workspace` must pass. ### References - [Source: _bmad-output/planning-artifacts/epics.md#Epic-7] - Epic 7 Requirements and Story 7.1 - [Source: _bmad-output/planning-artifacts/architecture.md#Error-Handling-Strategy] - Error Handling - [Source: _bmad-output/planning-artifacts/architecture.md#Scientific-Testing-Patterns] - Testing Patterns definition ## Dev Agent Record ### Agent Model Used BMad Create Story Workflow ### Debug Log References ### Completion Notes List - Implemented `port_mass_flows` for all core components to standardize mass flow retrieval. - Integrated `check_mass_balance` into `System` and hooked it into the `SolverStrategy::solve` entry point. - Updated `thermo_error_to_pyerr` and C error mappings to handle the new `Validation` error type. - Fixed severe architectural issue in integration tests where `connect` methods were missing, by implementing them for `ExpansionValve`, `Compressor`, and `Pipe`. - Verified violation detection with passing unit test `test_mass_balance_violation`. ### File List - crates/entropyk/src/error.rs (Validation error variant) - crates/components/src/lib.rs (port_mass_flows trait method) - crates/components/src/compressor.rs (port_mass_flows implementation) - crates/components/src/expansion_valve.rs (port_mass_flows implementation) - crates/components/src/pipe.rs (port_mass_flows implementation) - crates/components/src/pump.rs (port_mass_flows implementation) - crates/components/src/fan.rs (port_mass_flows implementation) - crates/components/src/flow_boundary.rs (port_mass_flows for FlowSource, FlowSink) - crates/components/src/flow_junction.rs (port_mass_flows for FlowSplitter, FlowMerger) - crates/components/src/heat_exchanger/evaporator.rs (delegation to inner) - crates/components/src/heat_exchanger/evaporator_coil.rs (delegation to inner) - crates/components/src/heat_exchanger/condenser.rs (delegation to inner) - crates/components/src/heat_exchanger/condenser_coil.rs (delegation to inner) - crates/components/src/heat_exchanger/economizer.rs (delegation to inner) - crates/components/src/heat_exchanger/exchanger.rs (port_mass_flows base implementation) - crates/solver/src/solver.rs (post-solve validation hook) - crates/solver/src/system.rs (check_mass_balance method, tests, logging) - bindings/python/src/errors.rs (ValidationError mapping) ### Review Follow-ups (AI) - [x] [AI-Review][HIGH] Implement `port_mass_flows` for remaining components: FlowSource, FlowSink, Pump, Fan, Evaporator, Condenser, CondenserCoil, EvaporatorCoil, Economizer, FlowSplitter, FlowMerger - [x] [AI-Review][MEDIUM] Add integration test with full refrigeration cycle to verify mass balance validation end-to-end