1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
//! # VLE Engine — Vapor-Liquid Equilibrium Thermodynamic Calculator
//!
//! This crate is the computational core of the VLE project, a modernization of two
//! legacy thermodynamic codebases (VB6 ~15,000 lines + Pascal ~2,500 lines) into a
//! high-performance Rust library with Python bindings via PyO3.
//!
//! ## What this library does
//!
//! VLE (Vapor-Liquid Equilibrium) calculations predict how chemical mixtures split
//! between liquid and vapor phases at given temperature and pressure conditions.
//! This is fundamental to chemical engineering — every distillation column, flash
//! drum, and separation process relies on VLE predictions.
//!
//! The library supports:
//! - **22+ cubic equations of state** (EOS) for modeling PVT behavior of gases and liquids
//! - **5 activity coefficient models** for liquid-phase non-ideality (van Laar, Wilson, etc.)
//! - **11 mixing rules** for combining pure-component parameters into mixture parameters
//! - **6 saturation pressure correlations** for estimating boiling points
//! - **6 flash calculation types**: bubble point (T/P), dew point (T/P), isothermal flash,
//! adiabatic flash
//! - **Parameter regression**: kij (binary interaction) and Aij (activity model) fitting
//!
//! ## Why these modules exist
//!
//! The module structure mirrors the mathematical layers of a VLE calculation:
//!
//! 1. **`eos`** — Equation of state definitions. An EOS is a mathematical model
//! (e.g., Peng-Robinson, Soave-Redlich-Kwong) that relates pressure, volume, and
//! temperature for a substance. Each variant uses a different α(T) function to
//! capture how molecular attractions change with temperature. The 22+ variants come
//! from merging 19 VB6 models with 3 additional Pascal models (Schmidt-Wenzel,
//! Patel-Teja) that handle polar and asymmetric molecules better via a third
//! parameter.
//!
//! 2. **`activity`** — Activity coefficient models. These capture liquid-phase
//! non-ideality (deviations from Raoult's law) using empirical correlations fit
//! to experimental data. Essential for polar/associating mixtures (e.g., water +
//! alcohol) where cubic EOS alone gives poor liquid-phase predictions.
//!
//! 3. **`mixing`** — Mixing rules. When applying a pure-component EOS to a mixture,
//! you need rules for combining the individual a, b (and sometimes c) parameters
//! into mixture-average values. Classical rules (quadratic in composition) work
//! for simple mixtures; advanced rules like Wong-Sandler incorporate activity
//! coefficient information for better accuracy with non-ideal systems.
//!
//! 4. **`saturation`** — Saturation pressure models. These correlations (Antoine,
//! Riedel, etc.) estimate pure-component boiling pressure at a given temperature.
//! Flash calculations use these for initial K-value estimates to seed iterative
//! convergence.
//!
//! 5. **`types`** — Core data structures shared across all modules. `Component`
//! holds pure-component properties (critical T/P, acentric factor, etc.),
//! `Mixture` groups components with their compositions, `Flow` represents a
//! process stream with phase-specific data, `Tolerances` controls convergence
//! criteria, and `ReferenceState` defines the thermodynamic reference for
//! enthalpy/entropy calculations.
//!
//! ## Origin and academic references
//!
//! Based on the thesis: *"Desarrollo de un Programa Computacional para el Cálculo
//! del Equilibrio Líquido Vapor de Mezclas Multicomponentes bajo el Ambiente Windows"*
//! (Jackson & Mendible, USB, 1999). Additional models from Reference (4): Da Silva &
//! Báez (1989) — Mac Pascal program contributing Schmidt-Wenzel, Patel-Teja, and
//! Chao-Seader models. All code derived from (4) is annotated with citation comments.
//!
//! ## Internal units
//!
//! All calculations use these canonical units (matching the legacy codebases):
//! - Temperature: **K** (Kelvin, absolute)
//! - Pressure: **kPa** (absolute — never gauge)
//! - Molar energy: **kJ/kmol**
//! - Molar entropy: **kJ/(kmol·K)**
//! - Molar volume: **cm³/mol**
//! - Amount: **kmol**
//! - Gas constant R: **8.31451 kJ/(kmol·K)**
// `pub mod eos` does two things:
// 1. `mod eos` tells Rust to look for a file named `eos.rs` (or `eos/mod.rs`)
// and include it as a sub-module of this library.
// 2. `pub` makes the module public, so code outside this crate (e.g., the
// Python bindings or other Rust crates) can access it. Without `pub`,
// the module would only be usable within this crate.
// Bundled Rust-side component database (M12.2, gap G3). Feature-gated behind
// `component-db` so the default crate pulls no serde: `cargo add vle-thermo`
// stays dependency-lean, and a consumer opts in with `--features component-db`
// to get `vle_thermo::db::component(name)` / `available()`. The `python`
// feature turns it on transitively (see Cargo.toml) so the wheel can expose it.
// Petroleum characterization: assay -> pseudocomponents (M19, Phase 26).
// See docs/plans/engine/PETROLEUM_PSEUDOCOMPONENT_PLAN.md §2 (U1, U2).
// Refinery thermodynamics: Grayson-Streed / BK10 (via flash::system), Lee-Kesler
// departure, Peneloux translation, free-water flash (M20, Phase 27).
// Python bindings live in their own module, gated behind the `python` feature.
// Maturin enables this feature when building the wheel; `cargo add vle-thermo`
// (pure-Rust consumer) does not, so PyO3 stays out of the dependency closure.
// The module's `#[pymodule] fn _engine` is the entry point CPython dlopen's;
// see engine/src/py_bindings.rs for the binding surface and the rule that
// every milestone from M5 forward must wire up its new functions here.
// The persistent `System` pyclass + batch numpy API (Milestone 10, Track D
// of PERFORMANCE_PROPOSAL.md). Separate module so the M5–M9 free-function
// binding surface and the M10 stateful/batch surface stay independently
// readable; registered into the same `_engine` module by py_bindings.rs.
// IAPWS-IF97 steam tables (Milestone 13). The sibling `vle-steam` crate is
// re-exported here behind the `steam` feature so downstream Rust consumers can
// reach it as `vle_thermo::steam::SteamState` without a second `cargo add`. The
// `python` feature turns on `steam` (see Cargo.toml), so the wheel always ships
// the `vle.steam` bindings from `py_steam.rs`.
pub use vle_steam as steam;
// PyO3 bindings for the steam tables — the `SteamState`/`SatState` pyclasses,
// module functions, and batch numpy kernels surfaced as `vle.steam`. Gated on
// `python` (which implies `steam`); registered into `_engine` by py_bindings.rs.
// PyO3 bindings for petroleum characterization (M19) — the `Assay` pyclass and
// the `petro_*` correlation functions, surfaced as part of `vle._engine`.
// Registered into the same module by py_bindings.rs.
// PyO3 bindings for refinery thermodynamics (M20) — reduced Lee-Kesler,
// regular-solution ν, Peneloux shift as free functions; the mixture-level
// methods live on `System` in py_system.rs. Registered by py_bindings.rs.
// `pub use` re-exports an item from a sub-module, making it available
// directly at this crate's top level. Without these lines, users would
// have to write the full path: `vle_thermo::eos::CubicEos`. With them,
// they can write the shorter `vle_thermo::CubicEos` instead. It's purely
// a convenience — the types still live in their original modules, but
// `pub use` creates a public shortcut at the crate root.
pub use ActivityModel;
pub use CubicEos;
pub use MixingRule;
pub use SatPressureModel;
// Re-export all core data structures from types module.
pub use *;