A heat exchanger exampleΒΆ

within carbatpy

import numpy as np
import matplotlib.pyplot as plt
import carbatpy as cb
Trend not found! Check the environmentvariable TREND_DLL, TREND_PATH
Refprop is not installed!

Select two fluid (mixtures) and further conditions. H_DOT is the wanted heatflow rate ($\dot Q = $1 kW) here.

FLUID = "Propane * Pentane"  # working fluid
FLS = "Methanol"  # "Water"  # secondary fluid
comp = [.50, 0.5]
flm = cb.fprop.FluidModel(FLUID)
myFluid = cb.fprop.Fluid(flm, comp)

secFlm = cb.fprop.FluidModel(FLS)
secFluid = cb.fprop.Fluid(secFlm, [1.])
D_TEMP_MIN = 5.0

# Condenser, working fluid fixes all, secondary output enthalpy can be varied:
SEC_TEMP_IN = 300.0  # K
SEC_TEMP_OUT_MAX = 370.0
SEC_PRES_IN = 5e5  # Pa
H_DOT = 1e3  # W
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[2], line 4
      2 FLS = "Methanol"  # "Water"  # secondary fluid
      3 comp = [.50, 0.5]
----> 4 flm = cb.fprop.FluidModel(FLUID)
      5 myFluid = cb.fprop.Fluid(flm, comp)
      7 secFlm = cb.fprop.FluidModel(FLS)

File ~/checkouts/readthedocs.org/user_builds/carbatpy-010/checkouts/stable/src/carbatpy/models/fluids/fluid_props.py:111, in FluidModel.__init__(self, fluid, units, props, rp_inst, args)
    109 if props == "REFPROP":
    110     self.rp_instance = rp_inst
--> 111     self.set_rp_fluid()
    112 elif props == "TREND":
    113     self.set_tr_fluid()

File ~/checkouts/readthedocs.org/user_builds/carbatpy-010/checkouts/stable/src/carbatpy/models/fluids/fluid_props.py:132, in FluidModel.set_rp_fluid(self, modwf, name)
    115 def set_rp_fluid(self, modwf=REFPROPFunctionLibrary, name='RPPREFIX'):
    116     """
    117     A new instance of Refpropdll for the given fluid. It can then be called
    118     using fluid =""
   (...)
    129 
    130     """
--> 132     self.rp_instance = modwf(os.environ[name])
    133     self.rp_instance.SETPATHdll(os.environ[name])
    134     ierr = self.rp_instance.SETFLUIDSdll(self.fluid)

File ~/checkouts/readthedocs.org/user_builds/carbatpy-010/envs/stable/lib/python3.10/site-packages/ctREFPROP/ctREFPROP.py:161, in REFPROPFunctionLibrary(name, shared_extension)
    159             raise ValueError('Too many loadable shared libraries were found in the folder "{name:s}"; obtained libraries were: {libs:s}.  You must provide an absolute path to the shared library you would like to load'.format(name=name, libs=str(list(good_so))))
    160 else:
--> 161     raise ValueError('"{name:s}" is neither a directory nor a file'.format(name=name))
    163 # Now load the library
    164 dll = loader_fcn(full_path)

ValueError: "C:/Program Files (x86)/REFPROP" is neither a directory nor a file

Now set the wanted states, determine the enthalpies (alwas the value state[2] below), needed as input

state_sec_out = secFluid.set_state([SEC_TEMP_OUT_MAX, SEC_PRES_IN], "TP")

state_sec_in = secFluid.set_state(
    [SEC_TEMP_IN, SEC_PRES_IN], "TP")  # this is the entering state

# working fluid

TEMP_SAT_VAP = SEC_TEMP_OUT_MAX + D_TEMP_MIN
state_in = myFluid.set_state(
    [TEMP_SAT_VAP, 1.], "TQ")  # find minimum pressure

WF_TEMP_IN = TEMP_SAT_VAP + D_TEMP_MIN
WF_TEMP_OUT = SEC_TEMP_IN + D_TEMP_MIN
state_out = myFluid.set_state([WF_TEMP_OUT, state_in[1]], "TP")

state_in = myFluid.set_state([myFluid.properties.pressure,
                              WF_TEMP_IN],
                             "PT")

Now we create an instance of the heat exchanger here: hex0. The input are the two Fluid-instances with the correct input states. The enthalpies of the wanted output states (one will be varied later to meet the minimum approach temperature). The pressures will be deduced from the actual values.

hex0 = cb.hex_th.StaticHeatExchanger([myFluid, secFluid], H_DOT, state_out[2],
                           state_sec_out[2],
                           d_temp_separation_min=D_TEMP_MIN)

It is called find_pinch, but it actually just varies the fluid mass flow rate ratio, until the minimum approach temperature(d_temp_separation_min) is reached, if it is possible for the given inlet, wanted outlet values. If not a warning is given.

hex0.find_pinch()
if hex0.warning > 0:
    print(hex0.warning_message)

# now plotting can directly be done in pinch_calc 2024-05-24
fig_act, ax_act = plt.subplots(1)
PLOT_INFO = {"fig": fig_act, "ax": ax_act, "what": [2, 0], "col": ["r:", "ko"],
             "label": ["work,c", "sec,c"], "x-shift": [0, 0]}
hex0.plot_info=PLOT_INFO
hex0.pinch_calc(verbose=True)
ax_act.legend()
Min T-distance 4.999, Mean T-distance 13.816
Min T-distance 4.9990002898326225, Mean T-distance 13.816388378792048
cond 4.999999996768054 7.880529723560983 4.9990002898326225 22.9172499170362
<matplotlib.legend.Legend at 0x1e7a76ec550>
_images/7305882cb18de0fef6c34170c06f03b6f573aa912d0401e27a2a8f45e65cfc33.png
print(hex0.warning, hex0.warning_message)
0 All o.k.

You can plot a second heat exchanger into the same plot by passing the figure information. But first we need a new instance of an heat exchanger, now an evaporator called hex1:

#  Evaporator: ----------------------------

SEC_TEMP_IN = 300.0 # K
SEC_TEMP_OUT = 285
SEC_PRES_IN = 15e5
H_DOT = 1e3  # heat flow rate
extra = 2  # some additional temperature difference between both fluids at the entrance of the working fluid
# D_TEMP_SUPER = 5.
D_TEMP_MIN = 6.0  # Minimum approach temperature, allowed

state_sec_out = secFluid.set_state([SEC_TEMP_OUT, SEC_PRES_IN], "TP")
state_out = myFluid.set_state([SEC_TEMP_IN-D_TEMP_MIN - extra, 1.0], "TQ")

# the inlet states must be the last set_state before the hex is constructed, because it is further used by the heat exchanger:
state_sec_in = secFluid.set_state([SEC_TEMP_IN, SEC_PRES_IN], "TP")
state_in = myFluid.set_state(
    [SEC_TEMP_OUT-D_TEMP_MIN - extra, state_out[1]], "TP")

print("state in (T,p,h,v,s,q,u):", state_in)
state in (T,p,h,v,s,q,u): [2.77000000e+02 1.04510486e+05 2.37193722e+05 2.21710771e-01
 1.11102909e+03 5.28596305e-01 2.14022622e+05]

The new states are set, now we can do the calculations again.

hex1 = cb.hex_th.StaticHeatExchanger([myFluid, secFluid], H_DOT, state_out[2],
                           state_sec_out[2],
                           d_temp_separation_min=D_TEMP_MIN)
# ms1, d_tempall1, w1, s1 = hex1.pinch_calc()

factor_out = hex1.find_pinch()
if hex1.warning > 2:
    print("Second heat exchanger:", hex1.warning_message, hex1.dt_min)
else:

    # plotting in the same figure
    PLOT_INFO = {"fig": fig_act, "ax": ax_act, "what": [2, 0], "col": ["k:", "bo"],
                 "label": ["work,e", "sec,e"], "x-shift": [0, 0]}
    hex1.plot_info=PLOT_INFO
    hex1.pinch_calc(verbose=True)
    ax_act.legend()
Min T-distance 5.999, Mean T-distance -6.650
Min T-distance 5.9990002875455275, Mean T-distance -6.65042055546035
evap -8.000000001512547 -7.619450263333988 -5.9990002875455275 -8.000000001512547

By the way, the mean temperature difference between both curves is evaluated. If you have an idea of the mean heat transfer coefficient U, you can calculate the needed heat exchanger area:

u_heat_transfer = 500 # W/ (m2 K)
area_needed = H_DOT/ np.abs(hex1.dt_mean) /u_heat_transfer
print(f"Estimated HEX area: {area_needed:.3f} m^2")
Estimated HEX area: 0.301 m^2
fig_act
_images/755c123221650ea1cbb81c1829b191aa09ea8a4b0327491f5e2c057379d23e8f.png