Skip to content

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: the HeatStream model and extraction of hot/cold streams (and their CP) from process Stream objects 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 dt_min.

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 dt_min.

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 dt_min that minimises total annual cost (supertargeting).

supertarget

Vectorised total_annual_cost_target over a grid of dt_min values.

total_annual_cost_target

Total annual cost (annualised capital + utilities) at a given dt_min.

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 HeatStream from a process Stream and a target T.

make_stream

Build a HeatStream from supply/target temperatures and CP.

composite_curves

Hot and cold composite curves (temperature-enthalpy), positioned by dt_min.

grand_composite_curve

Grand composite curve (shifted temperature vs net heat flow).

heat_cascade

Run the problem table algorithm and return the full HeatCascade.

minimum_utilities

Return just (hot_utility, cold_utility) minimum duties (W), a convenience.

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 SuperTargetResult at the optimum.

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 N - 1).

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

"process" (stream-stream), "heater" (hot utility), or "cooler" (cold utility).

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 Q / (U * LMTD) with series film resistances (m^2).

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 dt_min and every stream's energy balance closes.

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 CP = m * cp (W/K), assumed constant between supply and target. Always positive.

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.

is_hot property

is_hot: Array

Whether this is a hot stream (supply hotter than target).

duty property

duty: Array

Magnitude of the stream duty CP * |Ts - Tt| (W).

t_hot property

t_hot: Array

The higher of the supply and target temperatures (K).

t_cold property

t_cold: Array

The lower of the supply and target temperatures (K).

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 dt_min at a pinched problem.

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 (m,), descending.

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 (m,).

interval_cp Array

Net sum(CP_hot) - sum(CP_cold) in each interval (W/K), shape (m - 1,).

interval_dh Array

Net heat surplus of each interval (W), shape (m - 1,).

cascade Array

Feasible (non-negative) cascaded heat flow at each boundary (W), shape (m,); cascade[0] is the hot utility, cascade[-1] the cold utility, and it touches zero at the pinch.

hot_utility Array

Minimum hot-utility duty Q_h,min (W).

cold_utility Array

Minimum cold-utility duty Q_c,min (W).

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 Q_h,min (W).

cold_utility Array

Minimum cold-utility duty Q_c,min (W).

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 (False for a threshold problem needing only one utility).

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 h).

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]

(lower, upper) search interval for dt_min (K).

(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 total_annual_cost_target.

'hp_steam'
cold_utility str

Cold-utility key, forwarded to total_annual_cost_target.

'cooling_water'
hours_per_year ArrayLike

Operating hours per year, forwarded to total_annual_cost_target.

HOURS_PER_YEAR
interest_rate ArrayLike

Annual interest rate, forwarded to total_annual_cost_target.

0.1
years ArrayLike

Project life (years), forwarded to total_annual_cost_target.

10.0
area_cost tuple[float, float, float]

Exchanger cost-law coefficients, forwarded to total_annual_cost_target.

DEFAULT_AREA_COST
area_kwargs dict | None

Extra area_target keyword arguments, forwarded to the target.

None

Returns:

Type Description
OptimalDtMin

An OptimalDtMin with the optimal approach temperature and the

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 fugacio.sim.economics.UTILITIES.

'hp_steam'
cold_utility str

Cold-utility key priced via fugacio.sim.economics.UTILITIES.

'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]

(a, b, c) exchanger cost-law coefficients.

DEFAULT_AREA_COST
area_kwargs dict | None

Extra keyword arguments forwarded to area_target.

None

Returns:

Type Description
SuperTargetResult

A SuperTargetResult.

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. Inspect feasible and

HeatExchangerNetwork

achieves_mer to confirm the design.

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 HeatStream; hot if stream.t > t_target, cold otherwise.

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 CP (W/K), positive.

required
h ArrayLike

Film heat-transfer coefficient (W/m^2/K).

DEFAULT_FILM_COEFFICIENT
name str

Optional label.

''

Returns:

Type Description
HeatStream

A HeatStream with array-valued leaves.

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 with the two curves and the achieved minimum

CompositeCurves

approach (a consistency check: it equals dt_min for a pinched

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 dt_min (K).

required

Returns:

Type Description
HeatCascade

A HeatCascade carrying the minimum utilities, the pinch, and the

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 PinchResult.