# Story 2.2: CoolProp Integration (sys-crate)

Status: done

<!-- Note: Validation is optional. Run validate-create-story for quality check before dev-story. -->

## Story

As a simulation user,
I want CoolProp as the primary backend,
so that I get NIST-quality thermodynamic data.

## Acceptance Criteria

1. **CoolProp Backend Implementation** (AC: #1)
   - [x] Implement `CoolPropBackend` struct wrapping CoolProp C++ library
   - [x] All `FluidBackend` trait methods must work correctly
   - [x] Results must match CoolProp 6.4+ within machine precision

2. **Static Linking via sys-crate** (AC: #2)
   - [x] Set up `crates/fluids/coolprop-sys/` sys-crate
   - [x] Configure `build.rs` for static compilation of CoolProp C++
   - [x] Ensure distribution without runtime C++ dependencies

3. **Safe Rust FFI Wrappers** (AC: #3)
   - [x] Create safe Rust wrappers around raw CoolProp FFI
   - [x] Handle error translation between C++ and Rust
   - [x] No unsafe code exposed in public API

4. **Thermodynamic Properties** (AC: #4)
   - [x] Support property queries: density, enthalpy, entropy, specific heat
   - [x] Support (P, T), (P, h), (P, x) state inputs
   - [x] Handle pure fluids and mixtures

## Tasks / Subtasks

- [x] Complete coolprop-sys sys-crate setup (continues from 2-1)
  - [x] Finalize `coolprop-sys/Cargo.toml` with correct features
  - [x] Configure static linking in `build.rs`
  - [x] Generate safe FFI bindings
- [x] Implement CoolPropBackend struct (AC: #1)
  - [x] Wrap CoolProp C++ calls in safe Rust
  - [x] Implement all FluidBackend trait methods
  - [x] Handle fluid name translation (CoolProp internal names)
- [x] Add error handling (AC: #3)
  - [x] Translate CoolProp error codes to FluidError
  - [x] Handle missing fluids gracefully
  - [x] Handle invalid states
- [x] Test CoolProp backend (AC: #4)
  - [x] Test against known values from CoolProp documentation
  - [x] Verify precision matches within machine epsilon
  - [x] Test all supported property types

## Dev Notes

### Previous Story Intelligence

**From Story 2-1 (Fluid Backend Trait Abstraction):**
- The `FluidBackend` trait is already defined in `crates/fluids/src/backend.rs`
- Trait includes `property()` and `critical_point()` methods
- Three backends planned: CoolPropBackend, TabularBackend, TestBackend
- Error handling pattern established with `FluidError` enum
- Workspace structure created: `crates/fluids/coolprop-sys/` directory exists
- Build.rs started for CoolProp C++ compilation
- **Key learning:** Sys-crate setup is complex - ensure static linking works before implementing backend

### Architecture Context

**C++ Integration Requirements (from Architecture):**
```rust
// Sys-crate pattern location: crates/fluids/coolprop-sys/
// build.rs manages static compilation of CoolProp C++
```

**CoolPropBackend Structure:**
```rust
pub struct CoolPropBackend {
    // Wraps coolprop-sys FFI calls
    // Uses interior mutability for thread-safety if needed
}

impl FluidBackend for CoolPropBackend {
    fn property(&self, fluid: FluidId, property: Property, state: ThermoState) 
        -> Result<f64, FluidError> {
        // Translate to CoolProp internal fluid names
        // Call CoolProp C++ via sys-crate
        // Translate result/error back to Rust
    }
}
```

**Fluid Name Translation:**
- CoolProp uses internal names (e.g., "R134a" → "R1344A")
- Need mapping table or lookup
- Handle case sensitivity

### Workspace Structure

**Location:** `crates/fluids/`
```
crates/fluids/
├── Cargo.toml
├── build.rs                    # Compilation CoolProp C++
├── coolprop-sys/               # Sys-crate C++ (CONTINUE FROM 2-1)
│   ├── Cargo.toml
│   ├── build.rs               # Configure static linking
│   └── src/
│       └── lib.rs             # FFI bindings
└── src/
    ├── lib.rs
    ├── backend.rs             # FluidBackend trait (DONE in 2-1)
    ├── coolprop.rs            # FR25: CoolProp integration (THIS STORY)
    ├── tabular.rs            # FR26: Tables NIST (Story 2.3)
    ├── cache.rs              # LRU cache (Story 2.4)
    └── damping.rs            # FR29: Critical point (Story 2.6)
```

### Technical Requirements

**Sys-crate Configuration (CRITICAL):**
- Static linking required for distribution
- `build.rs` must compile CoolProp C++ library
- Use `cc` crate for C++ compilation
- Configure appropriate compiler flags for static libs

**FFI Safety:**
- All FFI calls must be in `unsafe` blocks
- Wrap in safe public methods
- No `unsafe` exposed to users of the crate

**Supported Properties:**
- Density (rho)
- Enthalpy (h)
- Entropy (s)
- Specific heat (cp, cv)
- Temperature (T)
- Pressure (P)
- Quality (x)
- Viscosity (optional)
- Thermal conductivity (optional)

**Supported State Inputs:**
- (P, T) - pressure & temperature
- (P, h) - pressure & enthalpy (preferred for two-phase)
- (P, x) - pressure & quality
- (T, x) - temperature & quality
- (P, s) - pressure & entropy

### Error Handling Pattern

```rust
#[derive(Error, Debug)]
pub enum FluidError {
    #[error("Fluid {fluid} not found")]
    UnknownFluid { fluid: String },
    
    #[error("Invalid state for property calculation: {reason}")]
    InvalidState { reason: String },
    
    #[error("CoolProp error: {0}")]
    CoolPropError(String),
    
    #[error("Critical point not available for {fluid}")]
    NoCriticalPoint { fluid: String },
}

// From 2-1 - already defined, reuse
```

### Testing Requirements

**Required Tests:**
- Verify CoolProp backend returns expected values for R134a, R410A, CO2
- Test all property types
- Test all state input types
- Compare against CoolProp documentation values
- Test error handling for invalid fluids
- Test mixture handling (if supported)

**Validation Values (Examples from CoolProp):**
```rust
// R134a at 0°C (273.15K), saturated liquid
// Expected: density ≈ 1205.97 kg/m³, h ≈ 200 kJ/kg
```

### Project Structure Notes

**Alignment with Unified Structure:**
- Follows workspace-based multi-crate architecture
- Uses trait-based design from Story 2-1
- Located in `crates/fluids/` per project structure
- Sys-crate pattern for CoolProp C++ integration

**Dependencies:**
- Depends on `crates/core` for types (Pressure, Temperature, etc.)
- Depends on Story 2-1 `FluidBackend` trait
- coolprop-sys provides C++ FFI layer

### References

- **Epic 2 Story 2.2:** [Source: planning-artifacts/epics.md#Story 2.2]
- **Architecture C++ Integration:** [Source: planning-artifacts/architecture.md#C++ Integration]
- **Architecture Fluid Backend:** [Source: planning-artifacts/architecture.md#Fluid Properties Backend]
- **Story 2-1 (Previous):** [Source: implementation-artifacts/2-1-fluid-backend-trait-abstraction.md]
- **NFR11:** CoolProp 6.4+ compatibility [Source: planning-artifacts/epics.md#NonFunctional Requirements]
- **FR25:** Load fluid properties via CoolProp [Source: planning-artifacts/epics.md#Requirements Inventory]

---

## Dev Agent Record

### Agent Model Used

opencode/minimax-m2.5-free

### Debug Log References

N/A - Story just created

### Completion Notes List

- Story file created with comprehensive context from epics, architecture, and previous story
- All acceptance criteria defined with checkboxes
- Dev notes include architecture patterns, code examples, testing requirements
- References to source documents provided
- Previous story learnings incorporated (2-1)
- Status set to ready-for-dev
- Code review fixes applied:
  - Added #![allow(dead_code)] to coolprop-sys to suppress unused FFI warnings
  - Added lints.rust configuration to Cargo.toml for unsafe_code
  - Fixed test imports to only include what's needed

### File List

1. `crates/fluids/coolprop-sys/Cargo.toml` - Sys-crate configuration
2. `crates/fluids/coolprop-sys/build.rs` - Build script for static linking
3. `crates/fluids/coolprop-sys/src/lib.rs` - FFI bindings to CoolProp C++
4. `crates/fluids/src/coolprop.rs` - CoolPropBackend implementation
5. `crates/fluids/src/lib.rs` - Updated exports
6. `crates/fluids/Cargo.toml` - Added coolprop-sys dependency

### Change Log

- Date: 2026-02-15 - Initial implementation of CoolPropBackend with sys-crate FFI
- Date: 2026-02-15 - Code review fixes: Added #![allow(dead_code)] and lints.rust config

---

**Ultimate context engine analysis completed - comprehensive developer guide created**
