5 minutes into TESPy#
General information#
TESPy is an open-source framework for the simulation of component based thermodynamic conversion processes. With the software you can use predefined components such as a pump, compressor, heat exchanger, turbine or valve (and many more) to build thermodynamic systems. The system is set up by connecting the components in a generic way and then specifying respective process and component parameters.
The software then performs a steady state simulation of your system by creating and solving a system of equations in the so-called equation oriented (EO) approach (see [6] for more information). The system represents the individual topology and component and process specifications provided by you. TESPy accomplishes this by solving for
mass flow,
pressure and
enthalpy
of every connection between two components[1]. After solving a model, missing component and process parameters - for example: efficiencies, temperatures, pressure losses - are determined based on this information. The EO approach lets the modeler choose, which parameters are inputs and which parameters are results: For instance, a compressor efficiency can be an input and the system variables are solved to meet that constraint, or it can be a result of other inputs.
Mini example#
TESPy consists of three main building blocks:
class
Network
as container of the simulationclass
Component
(children of them:Compressor
,Valve
, …), in which thermodynamic conversion processes take placeclass
Connection
, which define the topology of theNetwork
by connecting the individual components
In this example, we will create two simple networks to show the principle of TESPy. For further tutorials and examples we recommend looking into the online documentation.
Modeling a Compressor#
First, we are modeling a compressor, which compresses fully saturated steam to a higher pressure level. The Fig. 1 shows the abstract representation of the component. The table below summarizes the process parameters we are going to apply in our example.
parameter description |
model location |
model parameter |
value |
unit |
---|---|---|---|---|
saturated gas state |
in |
|
100 |
% |
temperature |
|
10 |
°C |
|
mass flow |
|
0.1 |
kg/s |
|
efficiency |
compressor |
|
80 |
% |
pressure ratio |
|
3 |
- |
from tespy.networks import Network
from tespy.components import Source, Sink, Compressor
from tespy.connections import Connection
nwk = Network(p_unit="bar", T_unit="C")
so = Source("source")
cp = Compressor("compressor")
si = Sink("sink")
c1 = Connection(so, "out1", cp, "in1", label="1")
c2 = Connection(cp, "out1", si, "in1", label="2")
nwk.add_conns(c1, c2)
To make a simulation it is now necessary to specify relevant component and process parameters. We start with the values as provided in Table 1.
c1.set_attr(fluid={"R290": 1}, T=10, x=1, m=0.1)
cp.set_attr(eta_s=0.8, pr=3)
nwk.solve("design")
iter | residual | progress | massflow | pressure | enthalpy | fluid | component
-------+------------+------------+------------+------------+------------+------------+------------
1 | 1.86e+06 | 0 % | 0.00e+00 | 1.81e+06 | 3.88e+05 | 0.00e+00 | 0.00e+00
2 | 5.91e+05 | 2 % | 0.00e+00 | 2.33e-10 | 7.39e+05 | 0.00e+00 | 0.00e+00
3 | 2.33e-10 | 100 % | 0.00e+00 | 2.33e-10 | 6.94e-12 | 0.00e+00 | 0.00e+00
4 | 2.33e-10 | 100 % | 0.00e+00 | 2.33e-10 | 6.94e-12 | 0.00e+00 | 0.00e+00
Total iterations: 4, Calculation time: 0.00 s, Iterations per second: 919.00
We can have a look at the results. An overview is provided by the print_results
method of the Network
.
nwk.print_results()
##### RESULTS (Compressor) #####
+------------+----------+----------+----------+--------+
| | P | eta_s | pr | igva |
|------------+----------+----------+----------+--------|
| compressor | 6.37e+03 | 8.00e-01 | 3.00e+00 | nan |
+------------+----------+----------+----------+--------+
##### RESULTS (Connection) #####
+----+-----------+-----------+-----------+-----------+
| | m | p | h | T |
|----+-----------+-----------+-----------+-----------|
| 1 | 1.000e-01 | 6.366e+00 | 5.857e+05 | 1.000e+01 |
| 2 | 1.000e-01 | 1.910e+01 | 6.494e+05 | 6.476e+01 |
+----+-----------+-----------+-----------+-----------+
Since TESPy is working with an equation oriented solver, we can now change things up. For example, instead of providing the efficiency of the compressor, we could provide an outlet temperature. Given that temperature, the efficiency of the compressor will be a result of the calculation.
Note
With the equation oriented structure the user is not constraint in the inputs. As long as the network is well determined, the solver be able to find a result. One downside of the equation oriented approach is that the a initial guess for all variables is required. Bad starting values often lead to the solver being unable to find a solution. For more information please have a look at the TESPy documentation. Here in detail information and best practices are provided for this topic.
cp.set_attr(eta_s=None) # unset the isentropic efficiency
c2.set_attr(T=70)
nwk.set_attr(iterinfo=False)
nwk.solve("design")
nwk.print_results()
##### RESULTS (Compressor) #####
+------------+----------+----------+----------+--------+
| | P | eta_s | pr | igva |
|------------+----------+----------+----------+--------|
| compressor | 7.64e+03 | 6.67e-01 | 3.00e+00 | nan |
+------------+----------+----------+----------+--------+
##### RESULTS (Connection) #####
+----+-----------+-----------+-----------+-----------+
| | m | p | h | T |
|----+-----------+-----------+-----------+-----------|
| 1 | 1.000e-01 | 6.366e+00 | 5.857e+05 | 1.000e+01 |
| 2 | 1.000e-01 | 1.910e+01 | 6.621e+05 | 7.000e+01 |
+----+-----------+-----------+-----------+-----------+
For example, we can make an invalid parameter specification by setting the mass flow at the inlet and at the outlet of the compressor. This overdetermines the system of equations and will result in an error when trying to solve.
c2.set_attr(T=None, m=0.1)
nwk.solve("design")
---------------------------------------------------------------------------
TESPyNetworkError Traceback (most recent call last)
Cell In[5], line 2
1 c2.set_attr(T=None, m=0.1)
----> 2 nwk.solve("design")
File /opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/tespy/networks/network.py:1962, in Network.solve(self, mode, init_path, design_path, max_iter, min_iter, init_only, init_previous, use_cuda, print_results, prepare_fast_lane)
1954 msg = (
1955 "Network information:\n"
1956 f" - Number of components: {len(self.comps)}\n"
1957 f" - Number of connections: {len(self.conns)}\n"
1958 f" - Number of busses: {len(self.busses)}"
1959 )
1960 logger.debug(msg)
-> 1962 self.initialise()
1964 if init_only:
1965 self._reset_topology_reduction_specifications()
File /opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/tespy/networks/network.py:877, in Network.initialise(self)
875 self.create_fluid_wrapper_branches()
876 self.propagate_fluid_wrappers()
--> 877 self.presolve_massflow_topology()
878 self.presolve_fluid_topology()
880 self.init_set_properties()
File /opt/hostedtoolcache/Python/3.10.14/x64/lib/python3.10/site-packages/tespy/networks/network.py:1015, in Network.presolve_massflow_topology(self)
1008 elif num_massflow_specs > 1:
1009 msg = (
1010 "You cannot specify two or more values for mass flow in "
1011 "the same linear branch (starting at "
1012 f"{branch['components'][0].label} and ending at "
1013 f"{branch['components'][-1].label})."
1014 )
-> 1015 raise hlp.TESPyNetworkError(msg)
1017 else:
1018 main_conn = branch["connections"][0]
TESPyNetworkError: You cannot specify two or more values for mass flow in the same linear branch (starting at source and ending at sink).
Modeling a Heat Exchanger#
In the second example we are going to model a heat exchanger as shown in Fig. 2, specifically an evaporator using heat from ambient air to evaporate the working fluid R290 (Propane). The parameter we want to provide are listed in the table below.
Similar to the compressor example we work with a Network
instance, this time two fluids are required, i.e. air and
R290. We create the HeatExchanger
component and connect and parametrize it according to the flowsheet and the data
listed in the table.
from tespy.networks import Network
from tespy.components import Source, Sink, HeatExchanger
from tespy.connections import Connection
from CoolProp.CoolProp import PropsSI as PSI
nwk = Network(p_unit="bar", T_unit="C", iterinfo=False)
so_wf = Source("working fluid source")
si_wf = Sink("working fluid sink")
so_air = Source("air source")
si_air = Sink("air sink")
eva = HeatExchanger("evaporator")
c1 = Connection(so_air, "out1", eva, "in1", label="1")
c2 = Connection(eva, "out1", si_air, "in1", label="2")
c3 = Connection(so_wf, "out1", eva, "in2", label="3")
c4 = Connection(eva, "out2", si_wf, "in1", label="4")
nwk.add_conns(c1, c2, c3, c4)
c1.set_attr(fluid={"Air": 1}, T=7, p=1, m=1)
c2.set_attr(T=4)
c3.set_attr(fluid={"R290": 1}, T=0, x=0.25)
# specification of a pressure guess value for convergence improvement
c4.set_attr(x=1, p0=5)
eva.set_attr(pr1=1, pr2=1)
nwk.solve("design")
nwk.print_results()
##### RESULTS (HeatExchanger) #####
+------------+-----------+----------+----------+----------+----------+----------+----------+----------+----------+
| | Q | kA | td_log | ttd_u | ttd_l | pr1 | pr2 | zeta1 | zeta2 |
|------------+-----------+----------+----------+----------+----------+----------+----------+----------+----------|
| evaporator | -3.02e+03 | 5.63e+02 | 5.36e+00 | 7.00e+00 | 4.00e+00 | 1.00e+00 | 1.00e+00 | 0.00e+00 | 0.00e+00 |
+------------+-----------+----------+----------+----------+----------+----------+----------+----------+----------+
##### RESULTS (Connection) #####
+----+-----------+-----------+-----------+-----------+
| | m | p | h | T |
|----+-----------+-----------+-----------+-----------|
| 1 | 1.000e+00 | 1.000e+00 | 4.063e+05 | 7.000e+00 |
| 2 | 1.000e+00 | 1.000e+00 | 4.033e+05 | 4.000e+00 |
| 3 | 1.073e-02 | 4.745e+00 | 2.937e+05 | 2.451e-10 |
| 4 | 1.073e-02 | 4.745e+00 | 5.749e+05 | 2.451e-10 |
+----+-----------+-----------+-----------+-----------+
After running the simulation we can see the heat transferred from the air to the working fluid, both mass flows, or the temperature differences between the hot side (air) and the cold side (R290). Instead of providing a fixed temperature value for the evaporation temperature level, we can provide a temperature difference to the air temperature level. When the air temperature changes, adjusts the evaporation pressure/temperature of the working fluid automatically.
eva.set_attr(ttd_l=5)
c3.set_attr(T=None)
nwk.solve("design")
c3.T.val
-0.9999999999998295
T_evaporation = []
for T_air in [-5, 0, 5, 10]:
c1.set_attr(T=T_air)
c2.set_attr(T=T_air - 3)
nwk.solve("design")
T_evaporation += [round(c3.T.val, 1)]
T_evaporation
[-13.0, -8.0, -3.0, 2.0]
Learn more#
TESPy relies on CoolProp to provide fluid property data for a large range of different fluids [7]. The online documentation of TESPy provides a large variety of examples and tutorials to learn to use the software as well as extensive background information and code documentation:
online documentation https://tespy.readthedocs.io
github repository oemof/tespy
user forum oemof/tespy#discussions