Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
fwitte committed Dec 29, 2024
2 parents 23beebe + 8d47499 commit c15e688
Show file tree
Hide file tree
Showing 7 changed files with 245 additions and 6 deletions.
1 change: 1 addition & 0 deletions docs/whats_new.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ What's New

Discover notable new features and improvements in each release

.. include:: whats_new/v0-7-8-002.rst
.. include:: whats_new/v0-7-8-001.rst
.. include:: whats_new/v0-7-8.rst
.. include:: whats_new/v0-7-7.rst
Expand Down
13 changes: 13 additions & 0 deletions docs/whats_new/v0-7-8-002.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
v0.7.8.post2 - Newton's Nature (December, 29, 2024)
+++++++++++++++++++++++++++++++++++++++++++++++++++

Bug Fixes
#########
- Fixed a bug in post processing of the :code:`ttd_min` parameter of
:code:`HeatExchangers`
(`PR #587 <https://github.com/oemof/tespy/pull/587>`__).

Contributors
############
- `@tlmerbecks <https://github.com/tlmerbecks>`__
- Francesco Witte (`@fwitte <https://github.com/fwitte>`__)
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ exclude = ["docs/_build"]

[project]
name = "tespy"
version = "0.7.8.post1"
version = "0.7.8.post2"
description = "Thermal Engineering Systems in Python (TESPy)"
readme = "README.rst"
authors = [
Expand Down
2 changes: 1 addition & 1 deletion src/tespy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import os

__datapath__ = os.path.join(importlib.resources.files("tespy"), "data")
__version__ = '0.7.8.post1 - Newton\'s Nature'
__version__ = '0.7.8.post2 - Newton\'s Nature'

# tespy data and connections import
from . import connections # noqa: F401
Expand Down
2 changes: 1 addition & 1 deletion src/tespy/components/heat_exchangers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1121,7 +1121,7 @@ def calc_parameters(self):
)
self.ttd_u.val = self.inl[0].T.val_SI - self.outl[1].T.val_SI
self.ttd_l.val = self.outl[0].T.val_SI - self.inl[1].T.val_SI
self.ttd_min.val = min(self.ttd_u.val, self.ttd_min.val)
self.ttd_min.val = min(self.ttd_u.val, self.ttd_l.val)

# pr and zeta
for i in range(2):
Expand Down
3 changes: 2 additions & 1 deletion src/tespy/components/heat_exchangers/condenser.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

from tespy.components.component import component_registry
from tespy.components.heat_exchangers.base import HeatExchanger
from tespy.tools import logger
from tespy.tools.data_containers import SimpleDataContainer as dc_simple
from tespy.tools.document_models import generate_latex_eq
from tespy.tools.fluid_properties import dh_mix_dpQ
Expand Down Expand Up @@ -474,7 +475,7 @@ def calc_parameters(self):
)
self.ttd_u.val = self.inl[0].calc_T_sat() - self.outl[1].T.val_SI
self.ttd_l.val = self.outl[0].T.val_SI - self.inl[1].T.val_SI
self.ttd_min.val = min(self.ttd_u.val, self.ttd_min.val)
self.ttd_min.val = min(self.ttd_u.val, self.ttd_l.val)

# pr and zeta
for i in range(2):
Expand Down
228 changes: 226 additions & 2 deletions tests/test_components/test_heat_exchangers.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@
import math

import numpy as np
from pytest import approx
from pytest import fixture
from pytest import mark

from tespy.components import Condenser
from tespy.components import Desuperheater
from tespy.components import HeatExchanger
from tespy.components import ParabolicTrough
from tespy.components import SimpleHeatExchanger
Expand All @@ -23,8 +27,228 @@
from tespy.connections import Bus
from tespy.connections import Connection
from tespy.networks import Network
from tespy.tools.fluid_properties import h_mix_pT


def _calc_Q(c1, c2):
return c1.m.val_SI * (c2.h.val_SI - c1.h.val_SI)


def _calc_zeta(c1, c2):
return (
(c1.p.val_SI - c2.p.val_SI) * math.pi ** 2
/ (4 * c1.m.val_SI ** 2 * (c1.vol.val_SI + c2.vol.val_SI))
)


def _calc_pr(c1, c2):
return c2.p.val_SI / c1.p.val_SI


def _calc_dp(c1, c2):
return c1.p.val_SI - c2.p.val_SI


def _calc_ttd_l(c2, c3):
return c2.T.val_SI - c3.T.val_SI


def _calc_ttd_u(c1, c4):
return c1.T.val_SI - c4.T.val_SI


def _calc_ttd_u_condenser(c1, c4):
return c1.calc_T_sat() - c4.T.val_SI


def _calc_td_log(ttd_u, ttd_l):
return (ttd_l - ttd_u) / math.log(ttd_l / ttd_u)


def _calc_kA(Q, td_log):
return - Q / td_log


def _calc_eff_hot(c1, c2, c3):
h_at_T_in_cold = h_mix_pT(
c2.p.val_SI, c3.T.val_SI, c2.fluid_data, c2.mixing_rule
)
return (c2.h.val_SI - c1.h.val_SI) / (h_at_T_in_cold - c1.h.val_SI)


def _calc_eff_cold(c3, c4, c1):
h_at_T_in_hot = h_mix_pT(
c4.p.val_SI, c1.T.val_SI, c4.fluid_data, c4.mixing_rule
)
return (c4.h.val_SI - c3.h.val_SI) / (h_at_T_in_hot - c3.h.val_SI)


@fixture
def heatexchanger_network(request):

nw = Network(T_unit='C', p_unit='bar', v_unit='m3 / s')

inl1 = Source('inlet 1')
outl1 = Sink('outlet 1')
inl2 = Source('inlet 2')
outl2 = Sink('outlet 2')
instance = request.param('heat exchanger')

c1 = Connection(inl1, 'out1', instance, 'in1', label='1')
c2 = Connection(instance, 'out1', outl1, 'in1', label='2')
c3 = Connection(inl2, 'out1', instance, 'in2', label='3')
c4 = Connection(instance, 'out2', outl2, 'in1', label='4')

nw.add_conns(c1, c2, c3, c4)

return nw


@fixture
def heatexchanger_converged_network(heatexchanger_network):
# rename for shorter variable name
nw = heatexchanger_network

c1, c2, c3, c4 = nw.get_conn(['1', '2', '3', '4'])
instance = nw.get_comp('heat exchanger')

c1.set_attr(T=120, p=1, fluid={'H2O': 1}, m=1)
c2.set_attr(p=0.95)
c3.set_attr(T=40, p=5, fluid={'Ar': 1})
c4.set_attr(T=90, p=4.9)

if type(instance) == HeatExchanger:
c2.set_attr(T=105)

nw.solve('design')
nw._convergence_check()

return nw


class TestHeatExchanger:

@mark.parametrize(
'heatexchanger_network',
[HeatExchanger, Condenser, Desuperheater],
indirect=True
)
def test_postprocessing(self, heatexchanger_converged_network):
# rename for shorter variable name
nw = heatexchanger_converged_network

c1, c2, c3, c4 = nw.get_conn(['1', '2', '3', '4'])
instance = nw.get_comp('heat exchanger')

assert approx(instance.Q.val) == _calc_Q(c1, c2)

assert approx(instance.pr1.val) == _calc_pr(c1, c2)
assert approx(instance.pr2.val) == _calc_pr(c3, c4)

# this already utilizes SI values, it should be changed!
assert approx(instance.dp1.val_SI) == _calc_dp(c1, c2)
assert approx(instance.dp2.val_SI) == _calc_dp(c3, c4)

assert approx(instance.zeta1.val) == _calc_zeta(c1, c2)
assert approx(instance.zeta2.val) == _calc_zeta(c3, c4)

assert approx(instance.ttd_l.val) == _calc_ttd_l(c2, c3)
# this is not really beautiful
if type(instance) == Condenser:
assert approx(instance.ttd_u.val) == _calc_ttd_u_condenser(c1, c4)
else:
assert approx(instance.ttd_u.val) == _calc_ttd_u(c1, c4)

assert instance.ttd_min.val == min(instance.ttd_l.val, instance.ttd_u.val)

assert approx(instance.td_log.val) == _calc_td_log(instance.ttd_u.val, instance.ttd_l.val)
assert approx(instance.kA.val) == _calc_kA(instance.Q.val, instance.td_log.val)

assert approx(instance.eff_hot.val) == _calc_eff_hot(c1, c2, c3)
assert approx(instance.eff_cold.val) == _calc_eff_cold(c3, c4, c1)

assert instance.eff_max.val == max(instance.eff_cold.val, instance.eff_hot.val)

@mark.parametrize(
'heatexchanger_network',
[HeatExchanger, Condenser, Desuperheater],
indirect=True
)
def test_pr1(self, heatexchanger_converged_network):
nw = heatexchanger_converged_network

c1, c2 = nw.get_conn(['1', '2'])
instance = nw.get_comp('heat exchanger')

pr = 0.95
c2.set_attr(p=None)
instance.set_attr(pr1=pr)

nw.solve('design')
nw._convergence_check()

assert approx(pr) == _calc_pr(c1, c2)

@mark.parametrize(
'heatexchanger_network',
[HeatExchanger, Condenser, Desuperheater],
indirect=True
)
def test_zeta1(self, heatexchanger_converged_network):
nw = heatexchanger_converged_network

c1, c2 = nw.get_conn(['1', '2'])
instance = nw.get_comp('heat exchanger')

zeta = 100
c2.set_attr(p=None)
instance.set_attr(zeta1=zeta)

nw.solve('design')
nw._convergence_check()

assert approx(zeta) == _calc_zeta(c1, c2)

@mark.parametrize(
'heatexchanger_network',
[HeatExchanger, Condenser, Desuperheater],
indirect=True
)
def test_pr2(self, heatexchanger_converged_network):
nw = heatexchanger_converged_network

c3, c4 = nw.get_conn(['3', '4'])
instance = nw.get_comp('heat exchanger')

pr = 0.95
c4.set_attr(p=None)
instance.set_attr(pr2=pr)

nw.solve('design')
nw._convergence_check()

assert approx(pr) == _calc_pr(c3, c4)

@mark.parametrize(
'heatexchanger_network',
[HeatExchanger, Condenser, Desuperheater],
indirect=True
)
def test_zeta2(self, heatexchanger_converged_network):
nw = heatexchanger_converged_network

c3, c4 = nw.get_conn(['3', '4'])
instance = nw.get_comp('heat exchanger')

zeta = 100
c4.set_attr(p=None)
instance.set_attr(zeta2=zeta)

nw.solve('design')
nw._convergence_check()

assert approx(zeta) == _calc_zeta(c3, c4)

class TestHeatExchangers:

def setup_method(self):
Expand Down Expand Up @@ -133,8 +357,8 @@ def test_SimpleHeatExchanger(self):
self.nw.solve('design')
self.nw._convergence_check()
kA_network = self.nw.results['SimpleHeatExchanger'].loc[
instance.label, 'kA']
print(kA_network)
instance.label, 'kA'
]
msg = 'kA value must not be included in network results.'
expr = not instance.kA.is_result and np.isnan(kA_network)
assert expr, msg
Expand Down

0 comments on commit c15e688

Please sign in to comment.