# refprop-rs
Safe Rust bindings for [NIST REFPROP](https://www.nist.gov/srd/refprop) -- thermodynamic and transport properties of refrigerants, pure fluids, and mixtures.
## Features
- **Pure fluids** -- `Fluid::new("R134A")`, `Fluid::new("CO2")`, ...
- **Predefined mixtures** -- `Fluid::new("R410A")` (auto-loaded from `.MIX` files)
- **Custom mixtures** -- `Fluid::mixture(&[("R32", 0.5), ("R125", 0.5)])`
- **CoolProp-style `get()`** -- `fluid.get("D", "T", 0.0, "Q", 1.0)`
- **Configurable units** -- work in **°C + bar + kg/m³ + kJ/kg**, or K + kPa, or any mix
- **Flash calculations** -- TP, TD, TH, TS, TQ, PD, PH, PS, PQ, DH, DS, HS
- **Saturation, transport, critical point, fluid info**
- **Thread-safe** -- global mutex with automatic fluid re-setup
- **Dynamic loading** -- no compile-time linking, just point to your REFPROP installation
## Prerequisites
A licensed [REFPROP](https://www.nist.gov/srd/refprop) installation (v9.1 or v10).
## Installation
Add to your `Cargo.toml`:
```toml
[dependencies]
refprop-rs = { git = "https://github.com/math-dev-24/refprop-rs" }
```
The library name is `refprop`, so you import it as:
```rust
use refprop::{Fluid, UnitSystem};
```
## Configuration
Tell the library where REFPROP is installed. Create a `.env` file at
the project root (or set the environment variable directly):
```
REFPROP_PATH='C:\Program Files (x86)\REFPROP'
```
The library also checks standard install locations automatically.
## Quick start
### Engineering units (°C, bar, kg/m³, kJ/kg)
```rust
use refprop::{Fluid, UnitSystem};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let co2 = Fluid::with_units("CO2", UnitSystem::engineering())?;
// Everything is in °C, bar, kg/m³, kJ/kg -- no manual conversion!
let p = co2.get("P", "T", -5.0, "Q", 1.0)?;
println!("Psat(-5 °C) = {p:.2} bar");
let d = co2.get("D", "T", -5.0, "Q", 1.0)?;
println!("D_vap(-5 °C) = {d:.2} kg/m³");
let h = co2.get("H", "T", -5.0, "Q", 1.0)?;
println!("H_vap(-5 °C) = {h:.2} kJ/kg");
Ok(())
}
```
### REFPROP native units (K, kPa, mol/L, J/mol)
```rust
use refprop::Fluid;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let r134a = Fluid::new("R134A")?;
let d = r134a.get("D", "T", 273.15, "Q", 1.0)?;
println!("density = {d:.6} mol/L");
let props = r134a.props_tp(300.0, 500.0)?;
println!("{props}");
Ok(())
}
```
## Unit system
Choose your preferred units at construction time. All inputs and
outputs are automatically converted.
### Presets
| `UnitSystem::refprop()` | K | kPa | mol/L | J/mol | J/(mol·K) | µPa·s | W/(m·K) |
| `UnitSystem::engineering()` | °C | bar | kg/m³ | kJ/kg | kJ/(kg·K) | µPa·s | W/(m·K) |
| `UnitSystem::si()` | K | Pa | kg/m³ | J/kg | J/(kg·K) | Pa·s | W/(m·K) |
### Custom builder
Pick only the units you care about; the rest stay at REFPROP defaults:
```rust
use refprop::{Fluid, UnitSystem, TempUnit, PressUnit};
let units = UnitSystem::new()
.temperature(TempUnit::Celsius)
.pressure(PressUnit::Bar);
// density stays mol/L, energy stays J/mol, etc.
let fluid = Fluid::with_units("R134A", units)?;
let sat = fluid.saturation_t(0.0)?; // 0 °C directly
println!("Psat = {:.2} bar", sat.pressure);
```
### Available unit choices
| Temperature | `Kelvin`, `Celsius`, `Fahrenheit` |
| Pressure | `KPa`, `Bar`, `MPa`, `Pa`, `Atm`, `Psi` |
| Density | `MolPerL`, `KgPerM3` |
| Energy/Enthalpy | `JPerMol`, `KJPerKg`, `JPerKg` |
| Entropy/Cv/Cp | `JPerMolK`, `KJPerKgK`, `JPerKgK` |
| Viscosity | `MicroPaS`, `MilliPaS`, `PaS` |
| Conductivity | `WPerMK`, `MilliWPerMK` |
## Mixtures
```rust
use refprop::{Fluid, UnitSystem};
// Predefined mixture (from .MIX file)
let r410a = Fluid::with_units("R410A", UnitSystem::engineering())?;
// Custom composition
let r454c = Fluid::mixture_with_units(
&[("R32", 0.215), ("R1234YF", 0.785)],
UnitSystem::engineering(),
)?;
let p = r454c.get("P", "T", 0.0, "Q", 0.0)?;
println!("R454C Psat(0 °C) = {p:.2} bar");
```
## `get()` -- generic property lookup
```rust
// get(output, key1, val1, key2, val2) -> f64
let density = fluid.get("D", "T", 25.0, "P", 10.0)?;
```
### Input pairs (order-independent)
| `T`, `P` | Temperature + Pressure |
| `P`, `H` | Pressure + Enthalpy |
| `P`, `S` | Pressure + Entropy |
| `T`, `Q` | Temperature + Quality |
| `P`, `Q` | Pressure + Quality |
| `T`, `D` | Temperature + Density |
| `T`, `H` | Temperature + Enthalpy |
| `T`, `S` | Temperature + Entropy |
| `P`, `D` | Pressure + Density |
| `D`, `H` | Density + Enthalpy |
| `D`, `S` | Density + Entropy |
| `H`, `S` | Enthalpy + Entropy |
### Output keys
| `T` | Temperature |
| `P` | Pressure |
| `D` | Density |
| `H` | Enthalpy |
| `S` | Entropy |
| `Q` | Quality (vapor frac.) |
| `Cv` | Heat capacity (v) |
| `Cp` | Heat capacity (p) |
| `W` | Speed of sound |
| `E` | Internal energy |
| `ETA` | Dynamic viscosity |
| `TCX` | Thermal conductivity |
Units depend on the `UnitSystem` you chose at construction time.
## Flash & saturation methods
All methods respect the configured unit system.
```rust
let props = fluid.props_tp(25.0, 10.0)?; // TP flash
let props = fluid.props_ph(10.0, 250.0)?; // PH flash
let props = fluid.props_ps(10.0, 1.2)?; // PS flash
let props = fluid.props_tq(0.0, 1.0)?; // TQ flash (saturation)
let props = fluid.props_pq(5.0, 0.0)?; // PQ flash (saturation)
let props = fluid.props_td(50.0, 30.0)?; // TD flash
let props = fluid.props_th(50.0, 280.0)?; // TH flash
let props = fluid.props_ts(50.0, 1.1)?; // TS flash
let props = fluid.props_pd(5.0, 30.0)?; // PD flash
let props = fluid.props_dh(30.0, 280.0)?; // DH flash
let props = fluid.props_ds(30.0, 1.1)?; // DS flash
let props = fluid.props_hs(280.0, 1.1)?; // HS flash
let sat = fluid.saturation_t(0.0)?; // saturation at T
let sat = fluid.saturation_p(5.0)?; // saturation at P
let crit = fluid.critical_point()?; // Tc, Pc, Dc
let trn = fluid.transport(25.0, d)?; // viscosity, conductivity
let info = fluid.info()?; // molar mass, Ttrp, Tnbp, ...
```
## Project structure
```
refprop-rs/
├── Cargo.toml single crate: refprop-rs
├── src/
│ ├── lib.rs public API & re-exports
│ ├── fluid.rs Fluid struct (high-level API)
│ ├── converter.rs UnitSystem + Converter
│ ├── sys.rs low-level FFI (libloading)
│ ├── error.rs error types
│ ├── properties.rs result structs
│ └── backend/
│ └── refprop.rs REFPROP backend (flash, sat, etc.)
└── examples/
├── demo.rs engineering units showcase
├── simple.rs pure fluid, native units
└── mixture.rs predefined & custom mixtures
```
| `sys` | Dynamic DLL loading + raw FFI function wrappers |
| `converter` | `UnitSystem` + `Converter` (unit conversion) |
| `fluid` | High-level API: `Fluid`, `get()`, flash, units |
| `backend::refprop` | Core REFPROP calls, global state management |
## License
MIT