Heat integration¶
Pinch analysis and heat-integration targeting: composite and grand composite curves, energy and area targets, the optimal minimum-approach temperature, and automatic heat-exchanger-network synthesis.
See the heat integration & pinch analysis guide for worked examples.
integration
¶
Differentiable heat integration and pinch analysis for Fugacio.
Heat integration asks how to recover heat between a process's hot and cold streams so the least possible external utility is bought, and what network of exchangers achieves it. This subpackage supplies the whole pinch-technology workflow, kept end-to-end differentiable so the targets compose with the rest of the engine and can be optimised by gradients:
streams: theHeatStreammodel and extraction of hot/cold streams (and theirCP) from processStreamobjects via the real, two-phase-aware enthalpy;targeting: the problem table algorithm for the minimum hot/cold utilities and the pinch, plus the composite and grand composite curves;area: the Bath-formula area target, the minimum-units target, capital and total-annual-cost targets, and the capital-energy trade-off (optimal_dt_min, "supertargeting");network: heat-exchanger-network synthesis by the pinch design method, with rigorous feasibility/MER verification.
Modules:
| Name | Description |
|---|---|
area |
Area, unit-count, and capital targeting, and the capital-energy trade-off. |
network |
Heat-exchanger network synthesis by the pinch design method. |
streams |
Process streams for heat integration: the data the pinch targets act on. |
targeting |
Energy targeting: the problem table algorithm, composite curves, and the pinch. |
Classes:
| Name | Description |
|---|---|
OptimalDtMin |
Result of the capital-energy trade-off optimisation. |
SuperTargetResult |
Total-annual-cost target and its breakdown at a given |
UnitsTarget |
Minimum heat-exchange unit count target. |
Exchanger |
One heat-exchange unit in a synthesised network. |
HeatExchangerNetwork |
A synthesised heat-exchanger network and its verification. |
HeatStream |
A stream carrying a sensible-heat duty for heat integration. |
CompositeCurves |
Hot and cold composite curves positioned for the given |
GrandComposite |
The grand composite curve: net heat flow vs shifted temperature. |
HeatCascade |
The problem-table heat cascade and the targets read off it. |
PinchResult |
Headline energy targets for a heat-integration problem. |
Functions:
| Name | Description |
|---|---|
area_target |
Minimum heat-transfer area target (m^2) from the balanced composite curves. |
capital_cost_target |
Installed-capital target ($) from the area and unit targets. |
optimal_dt_min |
Find the |
supertarget |
Vectorised |
total_annual_cost_target |
Total annual cost (annualised capital + utilities) at a given |
units_target |
Minimum number of heat-exchange units (Euler's relation, pinch-respecting). |
synthesize_network |
Synthesise an MER heat-exchanger network by the pinch design method. |
verify_network |
Check a network's approaches, energy balances, and MER attainment. |
heat_stream |
Extract a |
make_stream |
Build a |
composite_curves |
Hot and cold composite curves (temperature-enthalpy), positioned by |
grand_composite_curve |
Grand composite curve (shifted temperature vs net heat flow). |
heat_cascade |
Run the problem table algorithm and return the full |
minimum_utilities |
Return just |
pinch_analysis |
Compute the minimum utilities, heat recovery, and pinch temperatures. |
OptimalDtMin
¶
Bases: NamedTuple
Result of the capital-energy trade-off optimisation.
Attributes:
| Name | Type | Description |
|---|---|---|
dt_min |
Array
|
Optimal minimum approach temperature (K). |
total_annual_cost |
Array
|
Total annual cost at the optimum ($/yr). |
target |
SuperTargetResult
|
The full |
converged |
Array
|
Whether the optimiser converged. |
SuperTargetResult
¶
Bases: NamedTuple
Total-annual-cost target and its breakdown at a given dt_min.
Attributes:
| Name | Type | Description |
|---|---|---|
dt_min |
Array
|
Minimum approach temperature (K). |
hot_utility |
Array
|
Minimum hot-utility duty (W). |
cold_utility |
Array
|
Minimum cold-utility duty (W). |
area |
Array
|
Area target (m^2). |
units |
Array
|
Unit-count target. |
capital |
Array
|
Installed-capital target ($). |
annualized_capital |
Array
|
Annualised capital charge ($/yr). |
utility_cost |
Array
|
Annual utility (operating) cost ($/yr). |
total_annual_cost |
Array
|
Annualised capital plus utilities ($/yr). |
UnitsTarget
¶
Bases: NamedTuple
Minimum heat-exchange unit count target.
Attributes:
| Name | Type | Description |
|---|---|---|
units |
Array
|
Minimum number of units (MER count when a pinch exists, else the
single-region |
above_pinch |
Array
|
Stream + utility count above the pinch. |
below_pinch |
Array
|
Stream + utility count below the pinch. |
Exchanger
dataclass
¶
Exchanger(
kind: str,
hot: str,
cold: str,
duty: float,
t_hot_in: float,
t_hot_out: float,
t_cold_in: float,
t_cold_out: float,
dt_a: float,
dt_b: float,
area: float,
)
One heat-exchange unit in a synthesised network.
Attributes:
| Name | Type | Description |
|---|---|---|
kind |
str
|
|
hot |
str
|
Label of the hot side (a stream name, or the hot-utility label). |
cold |
str
|
Label of the cold side (a stream name, or the cold-utility label). |
duty |
float
|
Exchanger duty (W). |
t_hot_in, |
t_hot_out
|
Hot-side inlet/outlet temperatures (K). |
t_cold_in, |
t_cold_out
|
Cold-side inlet/outlet temperatures (K). |
dt_a, |
dt_b
|
Terminal temperature approaches at the two ends (K). |
area |
float
|
Heat-transfer area from |
HeatExchangerNetwork
dataclass
¶
HeatExchangerNetwork(
exchangers: list[Exchanger],
hot_utility: float,
cold_utility: float,
dt_min: float,
n_units: int = 0,
total_area: float = 0.0,
min_approach: float = 0.0,
feasible: bool = False,
achieves_mer: bool = False,
_targets: tuple[float, float] = (0.0, 0.0),
)
A synthesised heat-exchanger network and its verification.
Attributes:
| Name | Type | Description |
|---|---|---|
exchangers |
list[Exchanger]
|
The units (process exchangers, heaters, coolers). |
hot_utility |
float
|
Total hot-utility duty used (W). |
cold_utility |
float
|
Total cold-utility duty used (W). |
dt_min |
float
|
Minimum approach temperature the design targeted (K). |
n_units |
int
|
Number of units. |
total_area |
float
|
Sum of exchanger areas (m^2). |
min_approach |
float
|
Smallest terminal approach over all exchangers (K). |
feasible |
bool
|
Whether every exchanger respects |
achieves_mer |
bool
|
Whether the utilities match the minimum (MER) targets. |
HeatStream
dataclass
¶
HeatStream(
t_supply: Array,
t_target: Array,
cp: Array,
h: Array,
name: str,
)
A stream carrying a sensible-heat duty for heat integration.
Attributes:
| Name | Type | Description |
|---|---|---|
t_supply |
Array
|
Supply (inlet) temperature (K). |
t_target |
Array
|
Target (outlet) temperature (K). |
cp |
Array
|
Heat-capacity flowrate |
h |
Array
|
Film heat-transfer coefficient (W/m^2/K) for area targeting. |
name |
str
|
Stream label (static metadata). |
A stream is hot (a heat source, to be cooled) when t_supply >
t_target and cold (a heat sink, to be heated) otherwise.
CompositeCurves
¶
Bases: NamedTuple
Hot and cold composite curves positioned for the given dt_min.
The cold composite is offset in enthalpy by the cold-utility target so the
curves overlap exactly over the recoverable heat and approach to dt_min
at the pinch.
Attributes:
| Name | Type | Description |
|---|---|---|
hot_t, |
hot_h
|
Hot composite temperature (K) and enthalpy (W) breakpoints. |
cold_t, |
cold_h
|
Cold composite temperature (K) and enthalpy (W). |
min_approach |
Array
|
Minimum vertical temperature gap between the curves (K);
equals |
GrandComposite
¶
Bases: NamedTuple
The grand composite curve: net heat flow vs shifted temperature.
Attributes:
| Name | Type | Description |
|---|---|---|
shifted_temperature |
Array
|
Interval-boundary shifted temperatures (K), shape
|
net_heat_flow |
Array
|
Feasible cascaded heat flow at each boundary (W); the curve touches zero at the pinch, equals the hot utility at the top and the cold utility at the bottom. |
HeatCascade
¶
Bases: NamedTuple
The problem-table heat cascade and the targets read off it.
Attributes:
| Name | Type | Description |
|---|---|---|
dt_min |
Array
|
Minimum approach temperature used (K). |
shifted_temperatures |
Array
|
Interval-boundary temperatures on the shifted
scale, descending (K), shape |
interval_cp |
Array
|
Net |
interval_dh |
Array
|
Net heat surplus of each interval (W), shape |
cascade |
Array
|
Feasible (non-negative) cascaded heat flow at each boundary (W),
shape |
hot_utility |
Array
|
Minimum hot-utility duty |
cold_utility |
Array
|
Minimum cold-utility duty |
pinch_shifted_temperature |
Array
|
Shifted temperature of the pinch (K). |
has_pinch |
Array
|
Whether a genuine pinch exists (both utilities non-zero). |
PinchResult
¶
Bases: NamedTuple
Headline energy targets for a heat-integration problem.
Attributes:
| Name | Type | Description |
|---|---|---|
dt_min |
Array
|
Minimum approach temperature (K). |
hot_utility |
Array
|
Minimum hot-utility duty |
cold_utility |
Array
|
Minimum cold-utility duty |
heat_recovery |
Array
|
Process-to-process heat recovered at the target (W). |
pinch_temperature |
Array
|
Mean (shifted) pinch temperature (K). |
hot_pinch_temperature |
Array
|
Pinch temperature on the hot-stream scale (K). |
cold_pinch_temperature |
Array
|
Pinch temperature on the cold-stream scale (K). |
has_pinch |
Array
|
Whether a genuine pinch exists ( |
area_target
¶
area_target(
streams: list[HeatStream],
dt_min: ArrayLike,
*,
hot_utility_t: ArrayLike | None = None,
cold_utility_t: ArrayLike | None = None,
hot_utility_h: ArrayLike = 5000.0,
cold_utility_h: ArrayLike = 5000.0,
) -> Array
Minimum heat-transfer area target (m^2) from the balanced composite curves.
Implements the Bath formula: the balanced composite curves (process streams plus the utility duties that close the enthalpy balance) are split into enthalpy intervals, and within each the area for vertical heat exchange is
``A_k = (dH_k / dT_lm,k) * sum_i (CP_i / h_i)``
summed over the hot and cold streams present, with dT_lm the log-mean of
the hot-cold temperature gaps at the interval ends. Summing over intervals
gives a target no real (vertically-matched) network can beat. Differentiable
in the stream data, film coefficients, and dt_min.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
streams
|
list[HeatStream]
|
Hot and cold process streams (each carrying a film coefficient
|
required |
dt_min
|
ArrayLike
|
Minimum approach temperature (K). |
required |
hot_utility_t
|
ArrayLike | None
|
Hot-utility temperature (K); defaults to just above the hottest process temperature. |
None
|
cold_utility_t
|
ArrayLike | None
|
Cold-utility temperature (K); defaults to just below the coldest process temperature. |
None
|
hot_utility_h
|
ArrayLike
|
Hot-utility film coefficient (W/m^2/K). |
5000.0
|
cold_utility_h
|
ArrayLike
|
Cold-utility film coefficient (W/m^2/K). |
5000.0
|
Returns:
| Type | Description |
|---|---|
Array
|
The area target (m^2). |
capital_cost_target
¶
capital_cost_target(
streams: list[HeatStream],
dt_min: ArrayLike,
*,
area_cost: tuple[
float, float, float
] = DEFAULT_AREA_COST,
area_kwargs: dict | None = None,
) -> Array
Installed-capital target ($) from the area and unit targets.
Distributes the area target equally over the unit target and costs each
exchanger by the smooth law a + b * (A / N)**c; differentiable in the
stream data and dt_min.
optimal_dt_min
¶
optimal_dt_min(
streams: list[HeatStream],
*,
bounds: tuple[float, float] = (1.0, 60.0),
grid: int = 121,
refine_iters: int = 40,
hot_utility: str = "hp_steam",
cold_utility: str = "cooling_water",
hours_per_year: ArrayLike = HOURS_PER_YEAR,
interest_rate: ArrayLike = 0.1,
years: ArrayLike = 10.0,
area_cost: tuple[
float, float, float
] = DEFAULT_AREA_COST,
area_kwargs: dict | None = None,
) -> OptimalDtMin
Find the dt_min that minimises total annual cost (supertargeting).
The capital-energy trade-off curve is broadly U-shaped (the area target
diverges as dt_min -> 0 while utilities rise with dt_min), but it is
only piecewise-smooth: the integer unit-count target steps at the
threshold/pinch transitions, so the curve has genuine kinks and small jumps.
A smooth gradient step would stall on those, so the optimum is found by a
vectorised grid scan (which locates the global basin despite the jumps)
followed by a golden-section polish inside the smooth neighbouring bracket.
The total-annual-cost target itself is fully differentiable between kinks (see
total_annual_cost_target).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
streams
|
list[HeatStream]
|
Hot and cold process streams. |
required |
bounds
|
tuple[float, float]
|
|
(1.0, 60.0)
|
grid
|
int
|
Number of grid points for the global scan. |
121
|
refine_iters
|
int
|
Golden-section iterations for the local polish. |
40
|
hot_utility
|
str
|
Hot-utility key, forwarded to |
'hp_steam'
|
cold_utility
|
str
|
Cold-utility key, forwarded to |
'cooling_water'
|
hours_per_year
|
ArrayLike
|
Operating hours per year, forwarded to |
HOURS_PER_YEAR
|
interest_rate
|
ArrayLike
|
Annual interest rate, forwarded to |
0.1
|
years
|
ArrayLike
|
Project life (years), forwarded to |
10.0
|
area_cost
|
tuple[float, float, float]
|
Exchanger cost-law coefficients, forwarded to |
DEFAULT_AREA_COST
|
area_kwargs
|
dict | None
|
Extra |
None
|
Returns:
| Type | Description |
|---|---|
OptimalDtMin
|
An |
OptimalDtMin
|
full target breakdown there. |
supertarget
¶
supertarget(
streams: list[HeatStream],
dt_min_grid: ArrayLike,
**kwargs: object,
) -> SuperTargetResult
Vectorised total_annual_cost_target over a grid of dt_min values.
Returns a SuperTargetResult whose fields are arrays aligned with
dt_min_grid, the data behind the supertargeting (cost-vs-dt_min)
plot.
total_annual_cost_target
¶
total_annual_cost_target(
streams: list[HeatStream],
dt_min: ArrayLike,
*,
hot_utility: str = "hp_steam",
cold_utility: str = "cooling_water",
hours_per_year: ArrayLike = HOURS_PER_YEAR,
interest_rate: ArrayLike = 0.1,
years: ArrayLike = 10.0,
area_cost: tuple[
float, float, float
] = DEFAULT_AREA_COST,
area_kwargs: dict | None = None,
) -> SuperTargetResult
Total annual cost (annualised capital + utilities) at a given dt_min.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
streams
|
list[HeatStream]
|
Hot and cold process streams. |
required |
dt_min
|
ArrayLike
|
Minimum approach temperature (K). |
required |
hot_utility
|
str
|
Hot-utility key priced via |
'hp_steam'
|
cold_utility
|
str
|
Cold-utility key priced via |
'cooling_water'
|
hours_per_year
|
ArrayLike
|
Operating hours per year. |
HOURS_PER_YEAR
|
interest_rate
|
ArrayLike
|
Annual interest rate for the capital-recovery factor. |
0.1
|
years
|
ArrayLike
|
Project life (years) for the capital-recovery factor. |
10.0
|
area_cost
|
tuple[float, float, float]
|
|
DEFAULT_AREA_COST
|
area_kwargs
|
dict | None
|
Extra keyword arguments forwarded to |
None
|
Returns:
| Type | Description |
|---|---|
SuperTargetResult
|
A |
units_target
¶
units_target(
streams: list[HeatStream], dt_min: ArrayLike
) -> UnitsTarget
Minimum number of heat-exchange units (Euler's relation, pinch-respecting).
For a network of S streams (including utilities) the minimum unit count
is S - 1; designing for minimum energy splits the problem at the pinch, so
the MER target sums (S - 1) over the above- and below-pinch regions.
synthesize_network
¶
synthesize_network(
streams: list[HeatStream],
dt_min: float,
*,
hot_utility_t: float | None = None,
cold_utility_t: float | None = None,
hot_utility_h: float = DEFAULT_FILM_COEFFICIENT,
cold_utility_h: float = DEFAULT_FILM_COEFFICIENT,
) -> HeatExchangerNetwork
Synthesise an MER heat-exchanger network by the pinch design method.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
streams
|
list[HeatStream]
|
Hot and cold process streams. |
required |
dt_min
|
float
|
Minimum approach temperature (K). |
required |
hot_utility_t
|
float | None
|
Hot-utility temperature (K); defaults to above the hottest process temperature. |
None
|
cold_utility_t
|
float | None
|
Cold-utility temperature (K); defaults to below the coldest process temperature. |
None
|
hot_utility_h
|
float
|
Hot-utility film coefficient (W/m^2/K). |
DEFAULT_FILM_COEFFICIENT
|
cold_utility_h
|
float
|
Cold-utility film coefficient (W/m^2/K). |
DEFAULT_FILM_COEFFICIENT
|
Returns:
| Type | Description |
|---|---|
HeatExchangerNetwork
|
A verified |
HeatExchangerNetwork
|
|
verify_network
¶
verify_network(
net: HeatExchangerNetwork, streams: list[HeatStream]
) -> HeatExchangerNetwork
Check a network's approaches, energy balances, and MER attainment.
Fills in n_units, total_area, min_approach, feasible and
achieves_mer and returns the same (mutated) network.
heat_stream
¶
heat_stream(
stream: Stream,
t_target: ArrayLike,
*,
h: ArrayLike = DEFAULT_FILM_COEFFICIENT,
name: str = "",
) -> HeatStream
Extract a HeatStream from a process Stream and a target T.
The duty is the actual enthalpy change of the stream between its temperature
and t_target (computed with the two-phase-aware
fugacio.sim.properties.enthalpy_flow), and the constant CP is that
duty divided by the temperature span, so the heat-integration stream carries
the flowsheet's real thermodynamics. Differentiable in the stream state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
stream
|
Stream
|
The process stream at its supply temperature. |
required |
t_target
|
ArrayLike
|
Target temperature to heat/cool the stream to (K). |
required |
h
|
ArrayLike
|
Film heat-transfer coefficient (W/m^2/K). |
DEFAULT_FILM_COEFFICIENT
|
name
|
str
|
Optional label. |
''
|
Returns:
| Type | Description |
|---|---|
HeatStream
|
A |
make_stream
¶
make_stream(
t_supply: ArrayLike,
t_target: ArrayLike,
cp: ArrayLike,
*,
h: ArrayLike = DEFAULT_FILM_COEFFICIENT,
name: str = "",
) -> HeatStream
Build a HeatStream from supply/target temperatures and CP.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
t_supply
|
ArrayLike
|
Supply temperature (K). |
required |
t_target
|
ArrayLike
|
Target temperature (K). |
required |
cp
|
ArrayLike
|
Heat-capacity flowrate |
required |
h
|
ArrayLike
|
Film heat-transfer coefficient (W/m^2/K). |
DEFAULT_FILM_COEFFICIENT
|
name
|
str
|
Optional label. |
''
|
Returns:
| Type | Description |
|---|---|
HeatStream
|
A |
composite_curves
¶
composite_curves(
streams: list[HeatStream], dt_min: ArrayLike
) -> CompositeCurves
Hot and cold composite curves (temperature-enthalpy), positioned by dt_min.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
streams
|
list[HeatStream]
|
Hot and cold process streams. |
required |
dt_min
|
ArrayLike
|
Minimum approach temperature (K). |
required |
Returns:
| Type | Description |
|---|---|
CompositeCurves
|
A |
CompositeCurves
|
approach (a consistency check: it equals |
CompositeCurves
|
problem). |
grand_composite_curve
¶
grand_composite_curve(
streams: list[HeatStream], dt_min: ArrayLike
) -> GrandComposite
Grand composite curve (shifted temperature vs net heat flow).
The GCC is the master diagram for utility selection: its shape shows where multiple utility levels can be placed and where heat pockets recover internally.
heat_cascade
¶
heat_cascade(
streams: list[HeatStream], dt_min: ArrayLike
) -> HeatCascade
Run the problem table algorithm and return the full HeatCascade.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
streams
|
list[HeatStream]
|
The hot and cold process streams (classified by their own supply/target temperatures). |
required |
dt_min
|
ArrayLike
|
Minimum approach temperature |
required |
Returns:
| Type | Description |
|---|---|
HeatCascade
|
A |
HeatCascade
|
interval data. |
minimum_utilities
¶
minimum_utilities(
streams: list[HeatStream], dt_min: ArrayLike
) -> tuple[Array, Array]
Return just (hot_utility, cold_utility) minimum duties (W), a convenience.
pinch_analysis
¶
pinch_analysis(
streams: list[HeatStream], dt_min: ArrayLike
) -> PinchResult
Compute the minimum utilities, heat recovery, and pinch temperatures.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
streams
|
list[HeatStream]
|
Hot and cold process streams. |
required |
dt_min
|
ArrayLike
|
Minimum approach temperature (K). |
required |
Returns:
| Type | Description |
|---|---|
PinchResult
|
A |