Entropyk/_bmad-output/implementation-artifacts/1-10-pipe-helpers-water-refrigerant.md
2026-02-21 19:15:34 +01:00

116 lines
5.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Story 1.10: Pipe Helpers for Water and Refrigerant
Status: done
<!-- Note: Validation is optional. Run validate-create-story for quality check before dev-story. -->
## Story
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.
**Architecture:** Fluid properties (ρ, μ) belong in the fluids crate (Story 2.7 IncompressibleBackend).
Pipe must NOT hardcode water/glycol properties—user obtains them from FluidBackend.
## Acceptance Criteria
1. **Pipe::for_incompressible** (AC: #1)
- [x] `Pipe::for_incompressible(geometry, port_inlet, port_outlet, density, viscosity)` — explicit ρ, μ from backend
- [x] Doc states: obtain ρ, μ from IncompressibleBackend (water, seawater, glycol)—do not hardcode
- [x] Doc examples show water and glycol circuit usage
2. **Pipe::for_refrigerant** (AC: #2)
- [x] `Pipe::for_refrigerant(geometry, port_inlet, port_outlet, density, viscosity)` — explicit ρ, μ at design point
- [x] Doc states ρ, μ vary with P,T — design-point values from CoolProp/tabular
- [x] Doc examples show refrigerant circuit usage
3. **Documentation** (AC: #3)
- [x] Module-level doc: Pipe serves refrigerant and incompressible (water, seawater, glycol)
- [x] "Fluid Support" section: refrigerant (ρ/μ from backend) vs incompressible (ρ/μ from IncompressibleBackend)
- [x] No hardcoded fluid properties in components crate
## Tasks / Subtasks
- [x] Add Pipe::for_incompressible (AC: #1)
- [x] Constructor accepting (geometry, ports, density, viscosity)
- [x] Doc: obtain from IncompressibleBackend, do not hardcode
- [x] Add Pipe::for_refrigerant (AC: #2)
- [x] Constructor accepting (geometry, ports, density, viscosity)
- [x] Doc: design-point values from CoolProp/tabular
- [x] Update documentation (AC: #3)
- [x] pipe.rs module doc: Fluid Support section
- [x] Pipe struct doc: dual refrigerant/incompressible usage
- [x] Doc tests for both constructors
- [x] Tests
- [x] test_pipe_for_incompressible_creation
- [x] test_pipe_for_incompressible_glycol
- [x] test_pipe_for_refrigerant_creation
- [x] test_pipe_inlet_outlet_same_fluid
## Dev Notes
### Previous Story Intelligence
**From Story 1.8 (Auxiliary & Transport):**
- Pipe uses Darcy-Weisbach, Haaland friction factor
- PipeGeometry: length_m, diameter_m, roughness_m
- Pipe::new(geometry, port_inlet, port_outlet, fluid_density, fluid_viscosity)
- Already validates inlet/outlet same FluidId
### Typical Values
| Fluid | ρ (kg/m³) | μ (Pa·s) |
|-------|-----------|----------|
| Water 20°C | 998 | 0.001 |
| Water 40°C | 992 | 0.00065 |
| R134a liquid 40°C | ~1140 | ~0.0002 |
| R410A liquid 40°C | ~1050 | ~0.00015 |
### References
- pipe.rs: Pipe::new, PipeGeometry
- port.rs: FluidId, Port
- Story 2.7: Incompressible fluids (water polynomial when done)
## Dev Agent Record
### Implementation Plan
- Added `Pipe::for_incompressible(geometry, port_inlet, port_outlet, density, viscosity)` — no hardcoding
- Added `Pipe::for_refrigerant(geometry, port_inlet, port_outlet, density, viscosity)`
- Module doc: Fluid Support section (refrigerant vs incompressible)
- Pipe struct doc: dual refrigerant/incompressible usage
- **Architecture**: Properties (ρ, μ) obtained from FluidBackend (IncompressibleBackend for water/glycol)
### Completion Notes
- for_incompressible and for_refrigerant: explicit ρ, μ from user (who gets from backend)
- No hardcoded water/glycol properties in components crate
- Unit tests: test_pipe_for_incompressible_creation, test_pipe_for_incompressible_glycol, test_pipe_for_refrigerant_creation
### Architecture Refactor (2026-02-15)
- **Removed** for_water, for_water_at_temp — hardcoded water-only properties (violated FR40, Story 2.7)
- **Replaced** with for_incompressible(density, viscosity) — user provides ρ, μ from IncompressibleBackend
- Water, seawater, glycol have different properties — must not hardcode in components
### Code Review Fixes (2026-02-21)
- Fixed solver bug where `jacobian_entries` unconditional numerical gradient calculation applied to `Off`/`Bypass` states.
- Fixed `compute_residuals` for `OperationalState::Bypass` to correctly output zero pressure drop (`p_in - p_out`).
- Fixed Haaland friction factor clipping the regularized Reynolds number improperly to `1.0`, breaking linear laminar pressure drop curve near 0 flow.
- Removed dead and unused code (`swamee_jain` and `simplified` friction factors).
- Refined numerical differentiation stepping `h` to avoid numerical instability for zero/tiny mass flows.
## File List
- crates/components/src/pipe.rs (modified)
## Change Log
- 2026-02-15: Implemented Pipe::for_water, Pipe::for_water_at_temp, Pipe::for_refrigerant
- 2026-02-15: Code review fixes
- 2026-02-15: **Architecture refactor** — Removed hardcoded water properties; replaced with Pipe::for_incompressible(density, viscosity). Properties from FluidBackend (Story 2.7).
- 2026-02-21: Fixed logic and numerical stability issues found during adversarial code review.