composite curves pinch analysis

Pinch Analysis and Waste Heat Recovery

In this post I will present a technique to model waste heat utilization using the pinch analysis. Therefore, I will explain the pinch technology among the problem table cascade. Furthermore, we will use Python to state our problem and do the pinch analysis.


First, waste heat recovery is a process where energy is removed from one system in order to utilize it for another process. Usually, this waste heat would be rejected without being used. For example, it can be used for process heating, space heating, service water heating or air reheating (air conditioning). Therefore, this is done to reduce the fuel consumption or the demand of electrical energy.

The stream which has a heat demand can be called heat sink. Furthermore, the stream where heat needs to be removed is called a heat source. Without external supply of energy, heat can only be transported from a hot to a cold stream. Therfore, the major limiting factor is the minimal driving temperature difference during the heat transfer. Therefore, the temperature range of heat source and sink need to be considered.

In order to predict the recoverable amount of waste heat, we need a modeling method. Hence, we can use the pinch analysis to identify potential energy savings in processes.

Pinch Analysis

The pinch analysis is a method to analyze heat flows to identify recoverable waste heat. You can find a very good overview regarding pinch analysis in [1]. Additionally, the pinch analysis can be used to analyze water streams, but I will not go into further details.

Hence, designs and system optimizations can be derived. At first, data like start T_s and target temperatures T_t and heat flows \dot Q, need to be extracted from heat balances. Furthermore, these data need to be processed.

Here, the heat capacity flow rate \dot C can be calculated from the heat flow \dot Q and the temperature difference \Delta T according to

(1)   \begin{equation*}  \dot C=\frac{\dot Q}{\Delta T}.  \end{equation*}

Furthermore, let us assume a global minimal temperature difference \Delta T_{min} of 10 K. Hence, the shifted temperatures (T_{s,s} and T_{t,s}) can be calculated as follows:

(2)   \begin{equation*}    T_{s,s} =    \begin{cases}      T_s - 0.5 \Delta T_{min} & \text{if hot stream} \\      T_s + 0.5 \Delta T_{min} & \text{if cold stream} \\    \end{cases} \end{equation*}

(3)   \begin{equation*}    T_{t,s} =    \begin{cases}      T_t - 0.5 \Delta T_{min} & \text{if hot stream} \\      T_t + 0.5 \Delta T_{min} & \text{if cold stream} \\    \end{cases} \end{equation*}

To explain the procedure sufficiently, let us consider the following system considering of 2 reactors and 4 heat exchangers.

flow sheet pinch analysis

And here are the 4 considered heat flows.

in °C
in °C
in kW
in kW/K
in °C
in °C

Principally, processes that have to be cooled form hot energy streams, while processes that have to be heated up form cold energy streams. By comparing these streams, we can determine heat recovery possibilities. The graphical allocation of the energy streams is shown in the following.

Energy stream population

Now, we can start to use the shifted temperatures to build six temperature intervals of the streams. Afterwards, the temperature difference for each temperature interval can be calculated.

For each temperature interval the heat capacity flow rate of the source is subtracted from the heat capacity flow rate of the heat sink. Hence, by multiplying the temperature difference and the heat capacity flowrate difference we can calculate the internal heat flow.

In case the sign of the heat flow is positive, there is a heat flow de cit in the corresponding interval. Therefore the cold streams are larger compared to the hot streams. This means the heat source cannot supply the heat sink entirely. In case the sign is negative, there is a heat flow surplus in the corresponding interval.

IntervalTemperature range
in °C
Delta T Interval
in K
Delta C Interval
in kW/K
Q Interval
in K
1155 - 13520240Deficit
2135 - 130500Balance
3130 - 85453135Deficit
485 - 7510-3-30Surplus
575 - 4530-6-180Surplus
645 - 3510-4-40Surplus

From these previous calculations we can build the so called problem table cascade. Above the hottest temperature level of 150 °C there is no heat flow. Therefore, the table starts with 0 kW on the left side (a).

Afterwards, the internal heat flow \dot Q_{interval} is successively subtracted from the previous values \dot Q_{balance}. Furthermore, a negative sign in the \dot Q_{balance}-column represents a heat de cit in the corresponding interval. Hence, heat flow surpluses from lower temperature levels cannot be used to cover heat flow de cits from upper temperature levels.

Therefore, the largest negative value of -175 kW represents the heat flow which cannot be provided using waste heat utilization measures. Through the identi cation of the largest negative heat flow the heat cascade can be altered into the figure on the right (b).

Hence, the initial heat flow is set to 175 kW. Furthermore, the \dot Q_{balance}-column stays the same. Again, the internal heat flow is subsequently subtracted from the previous values.

problem table cascade

Also, the top value of the problem table cascade is the remaining heat sink \dot Q_{snk,rem} of 175 kW. From that, we can calculate the recovered heat flow \dot Q_{rec} which is 230 kW:

(4)   \begin{equation*}    \dot Q_{rec} = \dot Q_{snk} - \dot Q_{snk,rem}. \end{equation*}

Furthermore, we can identify the remaining heat source \dot Q_{src,rem} of 250 kW which is the bottom value of the problem table cascade. Using this methodology, we can finally write the Python script.

Python Code Pinch Analysis

Now, let is have a look at the Python code. It consists of the following elements:

  • State input data
  • Identify hot and cold streams
  • Calculate shifted temperatures and heat capacity flow rates
  • Build hot and cold heat cascade
  • State problem table cascade and solve it
  • Calculate remaining and recovered heat flows
  • Prepare data and plot results.
#Author: johannes <>, 10.03.18
#License: MIT License (

import numpy as np
import matplotlib.pyplot as plt

#===Input: Q_dot, T_start, T_target, dT_min
IN = [[180, 140, 50, 10], [300, 90, 40, 10], [240, 30, 150, 10], [165, 70, 125, 10]]

#===Get hot and cold stream index
hotStreamIndex = []
coldStreamIndex = []

for i in range(len(IN)):
    if IN[i][1] > IN[i][2]:
    elif IN[i][1] < IN[i][2]:

#===Calc source and sink heat flow
Q_dot_source = 0

for i in range(len(hotStreamIndex)):
    Q_dot_source = Q_dot_source + IN[hotStreamIndex[i]][0]  

Q_dot_sink = 0

for i in range(len(coldStreamIndex)):
    Q_dot_sink = Q_dot_sink + IN[coldStreamIndex[i]][0]

#===Shifted temperature and heat capacity flow hot stream    
for i in range(len(hotStreamIndex)):
    deltaT = 0.5*IN[i][3]
    row = hotStreamIndex[i]
    IN[row].append(IN[row][1] - deltaT)
    IN[row].append(IN[row][2] - deltaT)
    IN[row].append(IN[row][0]/(IN[row][5]- IN[row][4]))

#===Shifted temperature and heat capacity flow cold stream
deltaT = 0

for i in range(len(coldStreamIndex)):
    deltaT = 0.5*IN[i][3]
    row = coldStreamIndex[i]
    IN[row].append(IN[row][1] + deltaT)
    IN[row].append(IN[row][2] + deltaT)
    IN[row].append(IN[row][0]/(IN[row][5]- IN[row][4]))

print IN

#===Get temperatures and intervals
temperatures = []
for i in range(len(IN)):

#===Get sorting index
tempInd = np.argsort(temperatures)
#===Get rid of duplicates
temperatures = set(temperatures)
temperatures = list(temperatures)
#===Sort temperatures

#===Set cascade temperatures
cascade = []
cascadeSink = []
cascadeSource = []

for i in range(len(temperatures)-1):

for i in range(len(cascade)):
    cascade[i].append(cascade[i][0] - cascade[i][1])
    cascadeSink[i].append(cascade[i][0] - cascade[i][1])
    cascadeSource[i].append(cascade[i][0] - cascade[i][1])
    C_source = 0
    C_sink = 0
    for j in range(len(IN)):
        if (cascade[i][0] <= IN[j][4]) and (cascade[i][1] >= IN[j][5]) and (IN[j][6] < 0):
            C_source = C_source + IN[j][6]
    for j in range(len(IN)):    
        if (cascade[i][0] > IN[j][4]) and (cascade[i][1] < IN[j][5]) and (IN[j][6] > 0):
            C_sink =C_sink + IN[j][6]
    cascade[i].append(C_source + C_sink)
    cascade[i].append(cascade[i][3] * cascade[i][2])  
    cascadeSink[i].append(cascadeSink[i][3] * cascadeSink[i][2])
    cascadeSource[i].append(cascadeSource[i][3] * cascadeSource[i][2])

heatFlow = 0
ptCascade = []

for i in range(len(cascade)):
    heatFlow = heatFlow - cascade[i][4]

#===Calc recovered and remaining heat flow
Q_dot_rem = min([n for n in ptCascade if n<0])
Q_dot_rec = Q_dot_sink - abs(Q_dot_rem)

heatFlow = abs(Q_dot_rem)
ptCascade = []

for i in range(len(cascade)):
    heatFlow = heatFlow - cascade[i][4]

#===Prepare plot for source
heatFlowSource = []
tempSource = []


for i in reversed(cascadeSource):
    if i[4] < 0:
        heatFlowSource.append(heatFlowSource[-1] + i[4]*-1.)
        tempSource.append(i[0] + deltaT)
        tempSource.append(i[1] + deltaT)

#===Get rid of duplicates
tempSource = set(tempSource)
tempSource = list(tempSource)
#===Sort temperatures

#===Prepare plot for sink
heatFlowSink = []
tempSink = []

heatFlowSink.append(ptCascade[-1]) #last element of cascade, start of sink

for i in reversed(cascadeSink):
    if i[4] > 0:
        heatFlowSink.append(heatFlowSink[-1] + i[4])
        tempSink.append(i[0] - deltaT)
        tempSink.append(i[1] - deltaT)
#===Get rid of duplicates
tempSink = set(tempSink)
tempSink = list(tempSink)
#===Sort temperatures

#===Prepare plots
fig1 = plt.figure()

#===Plot cycles sink
ax1.plot(heatFlowSink, tempSink, 'b', linewidth=3)
ax1.plot(heatFlowSource, tempSource, 'r', linewidth=3)

plt.xlabel('Heat flow in kW')
plt.ylabel('Temperature in C')

In case you need help to run the provided code snippets have a look at the Python HOWTO.

Composite curve

The results of our calculations are the hot and cold composite curves. They are separated by the minimal driving temperature difference of 10 K. Furthermore, in the area were they lie on top of each other heat can be recovered. Also, we can identify the remaining heat source and heat sink, after heat is recovered.

composite curves pinch analysis


In process engineering waste heat recovery measures can be used to reduce the fuel consumption or the demand of electrical energy.

A sophisticated method to identify the recoverable waste heat is the pinch analysis. Therefore, heat streams are analyzed and a so called heat cascade is build. Afterwards, a problem cascade algorithm is used to solve the emerging problem. As a result, we receive the so called hot and cold composite curve. Thus, the recovered heat, remaining heat source and heat sink can be identified.

In the future, this article will be extended by a method called grand composite curve and by heat exchanger networks.

In case you wanna read more about pinch analysis applied to refrigeration systems, you can download an article in the downloads.


[1] Linnhoff, Introduction to Pinch Technology, 1998, link

What do you think?

I’d like to hear what you think about this post.

Let me know by leaving a comment below and don’t forget to subscribe to this blog!