Distillation & diagrams¶
Shortcut (Fenske-Underwood-Gilliland) and rigorous equilibrium-stage distillation columns, plus binary diagrams, azeotropes, and residue-curve maps.
Distillation columns¶
column
¶
Distillation columns: shortcut (Fenske-Underwood-Gilliland) and rigorous stages.
Two complementary, fully differentiable column models:
- Shortcut: the Fenske-Underwood-Gilliland (FUG) method, giving minimum stages
at total reflux (
fenske_min_stages), minimum reflux (underwood_min_reflux), the actual stage count at a working reflux (gilliland_stages), and the feed-stage location (kirkbride_feed_stage), tied together byshortcut_column. Cheap, robust, and ideal for screening or as an initial guess for the rigorous model. - Rigorous: a multistage equilibrium-stage column solved by the Wang-Henke
bubble-point method under constant molar overflow, with EOS K-values on every
stage (
solve_column). The converged profile is differentiable through the fixed-point iteration by implicit differentiation.
Both expose exact gradients of their outputs (stage count, reflux, product purities) with respect to the design variables, so a column can be embedded in a gradient-based optimisation alongside the rest of a flowsheet.
Component ordering convention: relative volatilities alpha are given relative
to a common reference (any component); the light key lk is more volatile
than the heavy key hk (alpha[lk] > alpha[hk]).
Classes:
| Name | Description |
|---|---|
ShortcutResult |
Summary of a Fenske-Underwood-Gilliland shortcut design. |
ColumnResult |
Converged profile and products of a rigorous equilibrium-stage column. |
Functions:
| Name | Description |
|---|---|
relative_volatility |
Relative volatilities |
fenske_min_stages |
Fenske minimum number of equilibrium stages at total reflux. |
underwood_min_reflux |
Underwood minimum reflux ratio |
gilliland_stages |
Actual equilibrium-stage count from the Gilliland (Eduljee) correlation. |
kirkbride_feed_stage |
Kirkbride correlation for the number of stages above the feed. |
shortcut_column |
Full FUG shortcut design from a feed and a specified product split. |
solve_column |
Rigorous multistage column by the Wang-Henke bubble-point method (CMO). |
ShortcutResult
¶
Bases: NamedTuple
Summary of a Fenske-Underwood-Gilliland shortcut design.
Attributes:
| Name | Type | Description |
|---|---|---|
n_min |
Array
|
Minimum equilibrium stages at total reflux (Fenske). |
r_min |
Array
|
Minimum reflux ratio (Underwood). |
theta |
Array
|
Underwood common root. |
r |
Array
|
Working reflux ratio used for the Gilliland step. |
n_stages |
Array
|
Actual equilibrium stages (Gilliland). |
feed_stage |
Array
|
Number of stages above the feed (Kirkbride). |
ColumnResult
¶
Bases: NamedTuple
Converged profile and products of a rigorous equilibrium-stage column.
Attributes:
| Name | Type | Description |
|---|---|---|
t |
Array
|
Stage temperatures (K), top stage first. |
x |
Array
|
Liquid mole fractions, shape |
y |
Array
|
Vapour mole fractions, shape |
distillate |
Stream
|
Distillate product |
bottoms |
Stream
|
Bottoms product |
reflux |
Array
|
Reflux ratio used. |
condenser_duty |
Array
|
Condenser heat removed (W, positive). |
reboiler_duty |
Array
|
Reboiler heat added (W, positive). |
relative_volatility
¶
relative_volatility(
eos: CubicEOS,
t: ArrayLike,
p: ArrayLike,
z: Array,
tc: Array,
pc: Array,
omega: Array,
*,
ref: int,
kij: Array | None = None,
) -> Array
Relative volatilities alpha_i = K_i / K_ref at (T, P, z) from the EOS.
K-values are evaluated as phi_i^L(z) / phi_i^V(z) at the given composition,
a standard shortcut estimate that is well defined whether or not the feed is
two-phase. Differentiable in (T, P, z).
fenske_min_stages
¶
Fenske minimum number of equilibrium stages at total reflux.
N_min = ln[(d_LK/d_HK)(b_HK/b_LK)] / ln(alpha_LK/alpha_HK) where d and
b are the distillate and bottoms component molar flows. Includes the
reboiler as a stage (the classic Fenske count).
underwood_min_reflux
¶
underwood_min_reflux(
z: Array,
x_d: Array,
alpha: Array,
q: ArrayLike,
lk: int,
hk: int,
*,
tol: float = 1e-12,
max_iter: int = 200,
) -> tuple[Array, Array]
Underwood minimum reflux ratio R_min (constant relative volatility).
Solves the first Underwood equation sum_i alpha_i z_i / (alpha_i - theta) =
1 - q for the common root theta between alpha_HK and alpha_LK,
then evaluates R_min + 1 = sum_i alpha_i x_{i,D} / (alpha_i - theta).
Returns (R_min, theta); both are differentiable in (z, x_d, alpha, q).
gilliland_stages
¶
Actual equilibrium-stage count from the Gilliland (Eduljee) correlation.
With X = (R - R_min)/(R + 1) and Y = 0.75 (1 - X^0.5668), the stage
count follows from (N - N_min)/(N + 1) = Y, i.e. N = (N_min + Y)/(1 - Y).
kirkbride_feed_stage
¶
kirkbride_feed_stage(
n: ArrayLike,
z: Array,
x_d: Array,
x_b: Array,
d_total: ArrayLike,
b_total: ArrayLike,
lk: int,
hk: int,
) -> Array
Kirkbride correlation for the number of stages above the feed.
log10(N_R/N_S) = 0.206 log10[(z_HK/z_LK)(x_{LK,B}/x_{HK,D})^2 (B/D)];
returns N_R given the total stage count N = N_R + N_S.
shortcut_column
¶
shortcut_column(
z: Array,
d: Array,
b: Array,
alpha: Array,
q: ArrayLike,
lk: int,
hk: int,
*,
reflux: ArrayLike | None = None,
reflux_factor: ArrayLike = 1.3,
) -> ShortcutResult
Full FUG shortcut design from a feed and a specified product split.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
z
|
Array
|
Feed mole fractions. |
required |
d
|
Array
|
Distillate component molar flows (the chosen split of the feed). |
required |
b
|
Array
|
Bottoms component molar flows ( |
required |
alpha
|
Array
|
Relative volatilities (to any common reference). |
required |
q
|
ArrayLike
|
Feed thermal quality (1 = saturated liquid, 0 = saturated vapour). |
required |
lk
|
int
|
Light-key component index. |
required |
hk
|
int
|
Heavy-key component index. |
required |
reflux
|
ArrayLike | None
|
Working reflux ratio. If |
None
|
reflux_factor
|
ArrayLike
|
Multiplier on |
1.3
|
Returns:
| Type | Description |
|---|---|
ShortcutResult
|
A |
solve_column
¶
solve_column(
feed: Stream,
n_stages: int,
feed_stage: int,
reflux: ArrayLike,
distillate_rate: ArrayLike,
*,
eos: CubicEOS = PR,
q: ArrayLike = 1.0,
kij: Array | None = None,
t_top: ArrayLike | None = None,
t_bottom: ArrayLike | None = None,
t_min: float = 100.0,
t_max: float = 800.0,
tol: float = 1e-09,
max_iter: int = 400,
) -> ColumnResult
Rigorous multistage column by the Wang-Henke bubble-point method (CMO).
A total condenser sits above stage 1 (distillate and reflux share the stage-1
vapour composition) and a partial reboiler is stage n_stages; a single feed
of quality q enters at feed_stage (1-indexed from the top). Under
constant molar overflow the section flows are fixed by reflux and
distillate_rate, and each outer sweep (i) solves the tridiagonal component
balances for the liquid profile with the current EOS K-values, (ii) takes a
bubble-point Newton step on every stage temperature, and (iii) refreshes the
vapour compositions. The sweep is iterated to a fixed point by
tear_solve, so the converged profile, products,
and duties are all differentiable (implicit differentiation) with respect to
reflux, distillate_rate, the feed, and model parameters.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
feed
|
Stream
|
Feed |
required |
n_stages
|
int
|
Number of equilibrium stages including the reboiler. |
required |
feed_stage
|
int
|
1-indexed feed stage ( |
required |
reflux
|
ArrayLike
|
Reflux ratio |
required |
distillate_rate
|
ArrayLike
|
Distillate molar flow (mol/s); bottoms is the remainder. |
required |
eos
|
CubicEOS
|
Cubic equation of state (default Peng-Robinson). |
PR
|
q
|
ArrayLike
|
Feed thermal quality (1 = saturated liquid). |
1.0
|
kij
|
Array | None
|
Optional binary interaction matrix. |
None
|
t_top
|
ArrayLike | None
|
Optional initial top-stage temperature for the linear starting
profile (default |
None
|
t_bottom
|
ArrayLike | None
|
Optional initial bottom-stage temperature for the linear starting
profile (default |
None
|
t_min
|
float
|
Lower bracket clamp for the per-stage temperature updates. |
100.0
|
t_max
|
float
|
Upper bracket clamp for the per-stage temperature updates. |
800.0
|
tol
|
float
|
Convergence tolerance for the outer fixed point. |
1e-09
|
max_iter
|
int
|
Maximum number of outer sweeps. |
400
|
Returns:
| Type | Description |
|---|---|
ColumnResult
|
A |
Binary diagrams & residue curves¶
diagrams
¶
Binary phase-diagram data and azeotrope finding for an equilibrium model.
Conceptual design and column screening lean on the binary picture: the P-x-y and
T-x-y envelopes and, above all, where the azeotrope is (it bounds what ordinary
distillation can reach). These helpers turn any binary
EquilibriumModel into:
pxy_diagram/txy_diagram: the bubble (liquid) and the equilibrium-vapour curves on a composition grid, from one bubble sweep each; andazeotrope_pressure/azeotrope_temperature: the azeotropic composition (wherey_1 = x_1) at fixedTorP, returned with anexistsflag so a non-azeotropic system is reported, not faked.
All outputs are differentiable: the diagram arrays through the bubble solves, and
the azeotrope locus through the bracketed root's implicit derivative, so an
azeotrope's pressure sensitivity to a model parameter is a single
jax.grad away.
Classes:
| Name | Description |
|---|---|
PxyDiagram |
Isothermal P-x-y data for a binary. |
TxyDiagram |
Isobaric T-x-y data for a binary. |
AzeotropeResult |
A binary azeotrope locus (or the best bracketed point if none exists). |
ResidueCurve |
A simple-distillation residue curve: the still-liquid composition path. |
Functions:
| Name | Description |
|---|---|
pxy_diagram |
Isothermal P-x-y curves for a binary on an |
txy_diagram |
Isobaric T-x-y curves for a binary on an |
azeotrope_pressure |
Find the binary azeotrope at fixed temperature |
azeotrope_temperature |
Find the binary azeotrope at fixed pressure |
residue_curve |
Integrate one residue curve of open (Rayleigh) distillation at fixed |
residue_curve_map |
Trace a residue-curve map: one full curve through each starting composition. |
PxyDiagram
¶
Bases: NamedTuple
Isothermal P-x-y data for a binary.
Attributes:
| Name | Type | Description |
|---|---|---|
x1 |
Array
|
Liquid mole fraction of component 1 (the grid). |
y1 |
Array
|
Equilibrium vapour mole fraction of component 1 (the bubble vapour). |
p |
Array
|
Bubble pressure at each |
t |
Array
|
The (fixed) temperature (K). |
TxyDiagram
¶
Bases: NamedTuple
Isobaric T-x-y data for a binary.
Attributes:
| Name | Type | Description |
|---|---|---|
x1 |
Array
|
Liquid mole fraction of component 1 (the grid). |
y1 |
Array
|
Equilibrium vapour mole fraction of component 1. |
t |
Array
|
Bubble temperature at each |
p |
Array
|
The (fixed) pressure (Pa). |
AzeotropeResult
¶
Bases: NamedTuple
A binary azeotrope locus (or the best bracketed point if none exists).
Attributes:
| Name | Type | Description |
|---|---|---|
exists |
Array
|
|
x1 |
Array
|
Azeotropic composition ( |
t |
Array
|
Temperature (K). |
p |
Array
|
Pressure (Pa). |
ResidueCurve
¶
Bases: NamedTuple
A simple-distillation residue curve: the still-liquid composition path.
Attributes:
| Name | Type | Description |
|---|---|---|
x |
Array
|
Liquid composition along the curve, shape |
t |
Array
|
Bubble (boiling) temperature at each point (K), shape |
p |
Array
|
The (fixed) pressure of the map (Pa). |
pxy_diagram
¶
pxy_diagram(
model: _BinaryModel,
t: ArrayLike,
*,
n: int = 51,
eps: float = 0.001,
) -> PxyDiagram
Isothermal P-x-y curves for a binary on an n-point composition grid.
The grid is clipped to [eps, 1 - eps] to avoid the pure-component limits.
Both curves come from a single bubble-pressure sweep: plot (x1, p) for the
liquid line and (y1, p) for the vapour line.
txy_diagram
¶
txy_diagram(
model: _BinaryModel,
p: ArrayLike,
*,
n: int = 51,
eps: float = 0.001,
t_min: float = 200.0,
t_max: float = 600.0,
) -> TxyDiagram
Isobaric T-x-y curves for a binary on an n-point composition grid.
Each grid point solves a bubble temperature (bracketed in [t_min, t_max])
and returns the equilibrium vapour, giving both the liquid line (x1, t) and
the vapour line (y1, t) from one sweep. Widen the bracket for very light or
very heavy pairs.
azeotrope_pressure
¶
azeotrope_pressure(
model: _BinaryModel,
t: ArrayLike,
*,
x_lo: float = 0.001,
x_hi: float = 1.0 - 0.001,
tol: float = 1e-10,
max_iter: int = 200,
) -> AzeotropeResult
Find the binary azeotrope at fixed temperature t (where y_1 = x_1).
Brackets the root of y_1(x_1) - x_1 from the bubble-pressure relation. The
returned x1 and p are differentiable with respect to the model
parameters; check exists before trusting them.
azeotrope_temperature
¶
azeotrope_temperature(
model: _BinaryModel,
p: ArrayLike,
*,
x_lo: float = 0.001,
x_hi: float = 1.0 - 0.001,
t_min: float = 200.0,
t_max: float = 600.0,
tol: float = 1e-10,
max_iter: int = 200,
) -> AzeotropeResult
Find the binary azeotrope at fixed pressure p (where y_1 = x_1).
As azeotrope_pressure but at constant pressure: each residual
evaluation solves a bubble temperature (bracketed in [t_min, t_max]).
residue_curve
¶
residue_curve(
model: _BubbleTemperatureModel,
x0: Array,
p: ArrayLike,
*,
steps: int = 200,
ds: float = 0.05,
direction: float = 1.0,
t_min: float = 150.0,
t_max: float = 700.0,
) -> ResidueCurve
Integrate one residue curve of open (Rayleigh) distillation at fixed P.
Solves the residue-curve ODE dx_i/dtau = x_i - y_i(x), where y(x) is the
bubble-point vapour in equilibrium with the still liquid x. With
direction = +1 the curve advances toward the high-boiling stable node
(the still-pot residue enriches in heavy components); direction = -1 traces
it back toward the low-boiling node.
Integration is an explicit Euler march with the composition re-projected onto
the simplex each step, so the path stays a valid composition. The expensive part,
the bubble-point (T, y) at each point, is one compiled, differentiable
solve (_bubble_ty) reused across every step and every curve.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
_BubbleTemperatureModel
|
Any object with a |
required |
x0
|
Array
|
Starting liquid composition, shape |
required |
p
|
ArrayLike
|
Pressure (Pa). |
required |
steps
|
int
|
Number of integration steps. |
200
|
ds
|
float
|
Pseudo-time step size. |
0.05
|
direction
|
float
|
|
1.0
|
t_min
|
float
|
Lower bound of the bubble-temperature search bracket (K). |
150.0
|
t_max
|
float
|
Upper bound of the bubble-temperature search bracket (K). |
700.0
|
Returns:
| Type | Description |
|---|---|
ResidueCurve
|
A |
ResidueCurve
|
( |
residue_curve_map
¶
residue_curve_map(
model: _BubbleTemperatureModel,
starts: Array,
p: ArrayLike,
*,
steps: int = 150,
ds: float = 0.05,
t_min: float = 150.0,
t_max: float = 700.0,
) -> list[ResidueCurve]
Trace a residue-curve map: one full curve through each starting composition.
Each start is integrated both directions (toward the light and the heavy node) and the two halves are stitched into a single curve passing through the start. This is the ternary distillation designer's master diagram: distillation boundaries and reachable products fall out of the family of curves.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
model
|
_BubbleTemperatureModel
|
Object exposing |
required |
starts
|
Array
|
Starting compositions, shape |
required |
p
|
ArrayLike
|
Pressure (Pa). |
required |
steps
|
int
|
Steps taken in each direction (the curve has |
150
|
ds
|
float
|
Pseudo-time step size. |
0.05
|
t_min
|
float
|
Lower bound of the bubble-temperature search bracket (K). |
150.0
|
t_max
|
float
|
Upper bound of the bubble-temperature search bracket (K). |
700.0
|
Returns:
| Type | Description |
|---|---|
list[ResidueCurve]
|
A list of |