$d$ means a derivative ALONG the saturation line,
$\partial$ means a partial derivative AT the saturation line (or anywhere in the single phase region).
Krafcik and Velasco, DOI 10.1119/1.4858403
Thorade and Saadat, DOI 10.1007/s12665-013-2394-z
https://en.wikipedia.org/wiki/Product_rule
https://en.wikipedia.org/wiki/Quotient_rule
https://en.wikipedia.org/wiki/Triple_product_rule
Clausius-Clapeyron p/T
\begin{equation} \frac{dp}{dT} = \frac{s''-s'}{v''-v'} \end{equation}derivative of Clausius-Clapeyron \begin{equation} \begin{split} \frac{d^2 p}{d T^2} &= \frac{\left(\frac{ds''}{dT}-\frac{ds'}{dT}\right) (v''-v')}{(v''-v')^2}
Clausius-Clapeyron T/p \begin{equation} \frac{dT}{dp} = \frac{v''-v'}{s''-s'} \end{equation}
derivative of Clausius-Clapeyron \begin{equation} \begin{split} \frac{d^2 T}{d p^2} &= \frac{\left(\frac{dv''}{dp}-\frac{dv'}{dp}\right) (s''-s')}{(s''-s')^2}
where \begin{equation} \begin{split} \frac{ds}{dT} &= \left(\frac{\partial s}{\partial T}\right)_p + \left(\frac{\partial s}{\partial p}\right)_T \frac{dp}{dT}\\ \frac{dv}{dT} &= \left(\frac{\partial v}{\partial T}\right)_p + \left(\frac{\partial v}{\partial p}\right)_T \frac{dp}{dT}\\ \frac{dv}{dp} &= \left(\frac{\partial v}{\partial p}\right)_T + \left(\frac{\partial v}{\partial T}\right)_p \frac{dT}{dp}\\ \frac{ds}{dp} &= \left(\frac{\partial s}{\partial p}\right)_T + \left(\frac{\partial s}{\partial T}\right)_p \frac{dT}{dp} \end{split} \end{equation}
Introduce temporary names for some of the partial derivatives wrt $p$ and $T$: \begin{equation} \begin{split} A &= \left(\frac{\partial \rho}{\partial T}\right)_p \\ B &= \left(\frac{\partial \rho}{\partial p}\right)_T \\ C &= \left(\frac{\partial s}{\partial T}\right)_p \\ E &= \left(\frac{\partial s}{\partial p}\right)_T \\ G &= \left(\frac{\partial h}{\partial T}\right)_p \\ K &= \left(\frac{\partial h}{\partial p}\right)_T \end{split} \end{equation}
Introduce temporary names for some of the partial derivatives wrt $\rho$ and $T$: \begin{equation} \begin{split} W &= \left(\frac{\partial p}{\partial T}\right)_{\rho} \\ X &= \left(\frac{\partial p}{\partial \rho}\right)_T \\ Y &= \left(\frac{\partial s}{\partial T}\right)_{\rho} \\ Z &= \left(\frac{\partial s}{\partial \rho}\right)_T \end{split} \end{equation}
Introduce temporary names for some of the derivatives along the saturation line: \begin{equation} \begin{split} M &= \frac{d \rho}{d h} = \frac{{d \rho}/{dT}}{{dh}/{dT}} \\ N &= \frac{d s}{d h} = \frac{{ds}/{dT}}{{dh}/{dT}} \end{split} \end{equation}
Now the rest is not too hard, but with intermediate steps it is quite long.
The corresponding first derivative can be written in two ways:
\begin{equation}
\begin{split}
\frac{d \rho}{dT}
&= \left(\frac{\partial \rho}{\partial T}\right)_p + \left(\frac{\partial \rho}{\partial p}\right)_T \frac{d p}{dT}
= A + B \frac{dp}{dT}\\
&= {\frac{dp}{dT} \left(\frac{\partial p}{\partial T}\right)_{\rho}} / {\left(\frac{\partial p}{\partial \rho}\right)_T}
= {\frac{dp}{dT} W}/X
\end{split}
\end{equation}
Both ways can be used as a starting point for the second derivative:
\begin{equation}
\begin{split}
\frac{d^2 \rho}{dT^2}
&= \frac{dA}{dT} + \frac{dB}{dT}\frac{dp}{dT} + B\frac{d^2p}{dT^2}\\
&= \frac{\left(\frac{d^2p}{dT^2} - \frac{dW}{dT}\right)X - \left(\frac{dp}{dT}-W\right)\frac{dX}{dT}}{X^2}
\end{split}
\end{equation}
The first variant seems to be nicer, because the first deriv did not have a fraction in it.
The derivatives along the saturation line that appeared can be written as (again, using two different approaches):
\begin{equation}
\begin{split}
\frac{dA}{dT} &= \left(\frac{\partial A}{\partial T}\right)_p + \left(\frac{\partial A}{\partial p}\right)_T \frac{d p}{dT}\\
\frac{dB}{dT} &= \left(\frac{\partial B}{\partial T}\right)_p + \left(\frac{\partial B}{\partial p}\right)_T \frac{d p}{dT}\\
\frac{dW}{dT} &= \left(\frac{\partial W}{\partial T}\right)_{\rho} + \left(\frac{\partial W}{\partial \rho}\right)_T \frac{d\rho}{dT}\\
\frac{dX}{dT} &= \left(\frac{\partial X}{\partial T}\right)_{\rho} + \left(\frac{\partial X}{\partial \rho}\right)_T \frac{d\rho}{dT}\\
\end{split}
\end{equation}
and then the partial derivatives of A, B, W and X wrt p and T can be written as:
\begin{equation}
\begin{split}
\left(\frac{\partial A}{\partial T}\right)_p &= \left(\frac{\partial^2 \rho}{\partial T^2}\right)_p \\
\left(\frac{\partial A}{\partial p}\right)_T &= \left(\frac{\partial^2 \rho}{\partial p \partial T}\right) \\
\left(\frac{\partial B}{\partial T}\right)_p &= \left(\frac{\partial^2 \rho}{\partial T \partial p}\right) = \left(\frac{\partial A}{\partial p}\right)_T \\
\left(\frac{\partial B}{\partial p}\right)_T &= \left(\frac{\partial^2 \rho}{\partial p^2}\right)_T \\
\left(\frac{\partial W}{\partial T}\right)_{\rho} &= \left(\frac{\partial^2 p}{\partial T^2}\right)_{\rho} \\
\left(\frac{\partial W}{\partial \rho}\right)_T &= \left(\frac{\partial^2 p}{\partial \rho \partial T}\right) \\
\left(\frac{\partial X}{\partial T}\right)_{\rho} &= \left(\frac{\partial^2 p}{\partial T \partial \rho}\right) = \left(\frac{\partial W}{\partial \rho}\right)_T \\
\left(\frac{\partial X}{\partial \rho}\right)_T &= \left(\frac{\partial^2 p}{\partial {\rho}^2}\right)_T
\end{split}
\end{equation}
So this time, the second way looks maybe nicer, because it uses partial derivatives wrt to density and temperature. On the other hand, all second partial derivatives are already implemented in Coolprop and the pT derivatives are internally rewritten as dT derivatives.
The corresponding first derivative can be written in two ways: \begin{equation} \begin{split} \frac{ds}{dT} &= \left(\frac{\partial s}{\partial T}\right)_p + \left(\frac{\partial s}{\partial p}\right)_T \frac{dp}{dT} = C + E\frac{dp}{dT}\\ &= \left(\frac{\partial s}{\partial T}\right)_{\rho} + \left(\frac{\partial s}{\partial \rho}\right)_T \frac{d \rho}{dT} = Y + Z\frac{d \rho}{dT} \end{split} \end{equation} Both can be used as starting point for the second derivatives. \begin{split} \frac{d^2 s}{dT^2} &= \frac{dC}{dT} + \frac{dE}{dT}\frac{dp}{dT} + E\frac{d^2p}{dT^2}\\ &= \frac{dY}{dT} + \frac{dZ}{dT}\frac{dp}{dT} + Z\frac{d^2 \rho}{dT^2} \end{split} Now, which one is nicer to work with? Not sure. Just as shown above, the derivatives along the saturation line that appeared can be written as (again, using two different approaches): \begin{equation} \begin{split} \frac{dC}{dT} &= \left(\frac{\partial C}{\partial T}\right)_p + \left(\frac{\partial C}{\partial p}\right)_T \frac{d p}{dT}\\ \frac{E}{dT} &= \left(\frac{\partial E}{\partial T}\right)_p + \left(\frac{\partial E}{\partial p}\right)_T \frac{d p}{dT}\\ \frac{dY}{dT} &= \left(\frac{\partial Y}{\partial T}\right)_{\rho} + \left(\frac{\partial Y}{\partial \rho}\right)_T \frac{d\rho}{dT}\\ \frac{dZ}{dT} &= \left(\frac{\partial Z}{\partial T}\right)_{\rho} + \left(\frac{\partial Z}{\partial \rho}\right)_T \frac{d\rho}{dT}\\ \end{split} \end{equation} Rewriting the the partial derivatives works just like shown above.
The corresponding first derivative can be written in many ways, here is one: \begin{equation} \frac{d \rho}{dp} = \left(\frac{\partial \rho}{\partial p}\right)_T + \left(\frac{\partial \rho}{\partial T}\right)_p \frac{dT}{dp} = B + A\frac{dT}{dp} \end{equation}
The second derivative is then: \begin{equation} \frac{d^2 \rho}{dp^2} = \frac{dB}{dp} + \frac{dA}{dp}\frac{dT}{dp} + A\frac{d^2T}{dp^2} \end{equation} The derivatives wrt p along the saturation line can be written as: \begin{equation} \begin{split} \frac{dB}{dp} &= \left(\frac{\partial B}{\partial p}\right)_T + \left(\frac{\partial B}{\partial T}\right)_p \frac{d T}{dp}\\ \frac{dA}{dp} &= \left(\frac{\partial A}{\partial p}\right)_T + \left(\frac{\partial A}{\partial T}\right)_p \frac{d T}{dp} \end{split} \end{equation} Rewriting the partial derivatives works just like shown above.
The corresponding first derivative can be written in many ways, here is one: \begin{equation} \frac{ds}{dp} = \left(\frac{\partial s}{\partial p}\right)_T + \left(\frac{\partial s}{\partial T}\right)_p \frac{dT}{dp} = E + C\frac{dT}{dp} \end{equation}
The second derivative is then: \begin{equation} \frac{d^2 s}{dp^2} = \frac{dE}{dp} + \frac{dC}{dp}\frac{dT}{dp} + C\frac{d^2T}{dp^2} \end{equation} Rewriting the derivatives along the sat line and the partial derivatives works just like shown above.
First: \begin{equation} \frac{dh}{dT} = \left(\frac{\partial h}{\partial T}\right)_p + \left(\frac{\partial h}{\partial p}\right)_T \frac{dp}{dT} = G + K\frac{dp}{dT} \end{equation}
Second: \begin{equation} \frac{d^2 h}{dT^2} = \frac{dG}{dT} + \frac{dK}{dT}\frac{dp}{dT} + K\frac{d^2p}{dT^2} \end{equation}
This is a bit different, but also not difficult.
First:
\begin{equation}
M = \frac{d\rho}{dh} = \frac{{d\rho}/{dT}}{{dh}/{dT}}
\end{equation}
Intermediate: \begin{equation} \frac{dM}{dT} = \frac{\frac{d^2 \rho}{dT^2}\frac{dh}{dT}-\frac{d \rho}{dT}\frac{d^2h}{dT^2}}{\left(\frac{dh}{dT}\right)^2} \end{equation}
Second: \begin{equation} \frac{d^2 \rho}{dh^2} = \frac{dM}{dh} = \frac{{dM}/{dT}}{{dh}/{dT}} = \frac{\frac{d^2 \rho}{dT^2}\frac{dh}{dT}-\frac{d \rho}{dT}\frac{d^2h}{dT^2}}{\left(\frac{dh}{dT}\right)^3} \end{equation}
First: \begin{equation} N = \frac{ds}{dh} = \frac{{ds}/{dT}}{{dh}/{dT}} \end{equation}
Intermediate: \begin{equation} \frac{dN}{dT} = \frac{\frac{d^2s}{dT^2}\frac{dh}{dT}-\frac{ds}{dT}\frac{d^2h}{dT^2}}{\left(\frac{dh}{dT}\right)^2} \end{equation}
Second: \begin{equation} \frac{d^2s}{dh^2} = \frac{dN}{dh} = \frac{{dN}/{dT}}{{dh}/{dT}} = \frac{\frac{d^2s}{dT^2}\frac{dh}{dT}-\frac{ds}{dT}\frac{d^2h}{dT^2}}{\left(\frac{dh}{dT}\right)^3} \end{equation}
First: \begin{equation} N = \frac{ds}{dh} = \frac{{ds}/{dT}}{{dh}/{dT}} \end{equation}
Intermediate: \begin{equation} \frac{dN}{dT} = \frac{\frac{d^2s}{dT^2}\frac{dh}{dT}-\frac{ds}{dT}\frac{d^2h}{dT^2}}{\left(\frac{dh}{dT}\right)^2} \end{equation}
Second: \begin{equation} \frac{d^2s}{dh dp} = \frac{dN}{dp} = \frac{{dN}/{dT}}{{dp}/{dT}} = \frac{\frac{d^2s}{dT^2}\frac{dh}{dT}-\frac{ds}{dT}\frac{d^2h}{dT^2}}{\left(\frac{dh}{dT}\right)^2 \left(\frac{dp}{dT}\right)} \end{equation}
In [6]:
# load some bits and pieces
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import CoolProp as CP
from CoolProp.CoolProp import PropsSI
# Check: CoolProp version
print(CP.__version__)
print(CP.__gitrevision__)
# Constants
eps = 1e-9
kilo = 1e3
Mega = 1e6
golden = (1 + 5 ** 0.5) / 2
nPoints = 1000
width = 12.5
# helper function: get slope from two sorted arrays
def numSlopeAr(xAr, yAr):
deltaX = np.ones(len(xAr))
deltaY = np.ones(len(yAr))
slopeAr = np.ones(len(yAr))
for index in range(1,len(xAr)-1):
deltaX[index] = xAr[index-1] - xAr[index+1]
deltaY[index] = yAr[index-1] - yAr[index+1]
slopeAr[index] = deltaY[index]/deltaX[index]
# inaccurate, but who cares?
slopeAr[0]=slopeAr[1]
slopeAr[-1]=slopeAr[-2]
return slopeAr
# helper function: draw tangent from array
def drawTangent(xAr, yAr, slopeAr, index: int):
xVal = xAr[index]
yVal = yAr[index]
slopeVal = slopeAr[index]
# line length as percentage of length of x axis
xRange = 0.15*abs(max(xAr)-min(xAr))
xRangeAr = np.arange(xVal-xRange, xVal+xRange)
tang = yVal + slopeVal*(xRangeAr-xVal)
plt.plot(xVal,yVal,'om',xRangeAr,tang,'-k')
In [7]:
# All calculations happen in this cell
# All following cells are used for plotting only
# Run this cell twice to get rid of error message
# Set FluidName
FluidName = 'Propane'
# Triple and critical data
T_crt = PropsSI('TCRIT',FluidName)
T_trp = PropsSI('TTRIPLE',FluidName)
p_crt = PropsSI('PCRIT',FluidName)
p_trp = PropsSI('PTRIPLE',FluidName)
d_crt = PropsSI('RHOCRIT',FluidName)
d_trp_liq = PropsSI('D','T',T_trp,'Q',0,FluidName)
d_trp_vap = PropsSI('D','T',T_trp,'Q',1,FluidName)
print("T_crt = " + str(T_crt))
print("T_trp = " + str(T_trp))
# Properties at saturation, liq and vap
# All the way to the crt point or keep some distance?
T_sat = np.linspace(T_trp, T_crt, num=nPoints)
p_sat = CP.CoolProp.PropsSI('P','T',T_sat,'Q',0,FluidName)
d_sat_liq = CP.CoolProp.PropsSI('D','T',T_sat,'Q',0,FluidName)
d_sat_vap = CP.CoolProp.PropsSI('D','T',T_sat,'Q',1,FluidName)
v_sat_liq = 1/d_sat_liq
v_sat_vap = 1/d_sat_vap
s_sat_liq = CP.CoolProp.PropsSI('S','T',T_sat,'Q',0,FluidName)
s_sat_vap = CP.CoolProp.PropsSI('S','T',T_sat,'Q',1,FluidName)
h_sat_liq = CP.CoolProp.PropsSI('H','T',T_sat,'Q',0,FluidName)
h_sat_vap = CP.CoolProp.PropsSI('H','T',T_sat,'Q',1,FluidName)
u_sat_liq = CP.CoolProp.PropsSI('U','T',T_sat,'Q',0,FluidName)
u_sat_vap = CP.CoolProp.PropsSI('U','T',T_sat,'Q',1,FluidName)
# Clausius-Clapeyron
# at crt point, vap=liq, so D becomes zero
Ds_vl = (s_sat_vap-s_sat_liq)
Dv_vl = (v_sat_vap-v_sat_liq)
dp_dT_q = Ds_vl/Dv_vl
dT_dp_q = Dv_vl/Ds_vl # = 1/dp_dT_q
dp_dT_qn = numSlopeAr(T_sat,p_sat)
dT_dp_qn = numSlopeAr(p_sat,T_sat)
# derivs wrt pT, single-phase AT the sat liq line
dd_dp_Tl = CP.CoolProp.PropsSI('d(Dmass)/d(P)|T','D',d_sat_liq,'T',T_sat,FluidName)
dd_dT_pl = CP.CoolProp.PropsSI('d(Dmass)/d(T)|P','D',d_sat_liq,'T',T_sat,FluidName)
ds_dp_Tl = CP.CoolProp.PropsSI('d(Smass)/d(P)|T','D',d_sat_liq,'T',T_sat,FluidName)
ds_dT_pl = CP.CoolProp.PropsSI('d(Smass)/d(T)|P','D',d_sat_liq,'T',T_sat,FluidName)
dh_dp_Tl = CP.CoolProp.PropsSI('d(Hmass)/d(P)|T','D',d_sat_liq,'T',T_sat,FluidName)
dh_dT_pl = CP.CoolProp.PropsSI('d(Hmass)/d(T)|P','D',d_sat_liq,'T',T_sat,FluidName)
dv_dp_Tl = -dd_dp_Tl/d_sat_liq**2
dv_dT_pl = -dd_dT_pl/d_sat_liq**2
# derivs wrt pT, single-phase AT the sat vap line
dd_dp_Tv = CP.CoolProp.PropsSI('d(Dmass)/d(P)|T','D',d_sat_vap,'T',T_sat,FluidName)
dd_dT_pv = CP.CoolProp.PropsSI('d(Dmass)/d(T)|P','D',d_sat_vap,'T',T_sat,FluidName)
ds_dp_Tv = CP.CoolProp.PropsSI('d(Smass)/d(P)|T','D',d_sat_vap,'T',T_sat,FluidName)
ds_dT_pv = CP.CoolProp.PropsSI('d(Smass)/d(T)|P','D',d_sat_vap,'T',T_sat,FluidName)
dh_dp_Tv = CP.CoolProp.PropsSI('d(Hmass)/d(P)|T','D',d_sat_vap,'T',T_sat,FluidName)
dh_dT_pv = CP.CoolProp.PropsSI('d(Hmass)/d(T)|P','D',d_sat_vap,'T',T_sat,FluidName)
dv_dp_Tv = -dd_dp_Tv/d_sat_vap**2
dv_dT_pv = -dd_dT_pv/d_sat_vap**2
# derivs wrt dT, single-phase AT the sat liq line
dp_dd_Tl = CP.CoolProp.PropsSI('d(P)/d(Dmass)|T','D',d_sat_liq,'T',T_sat,FluidName)
dp_dT_dl = CP.CoolProp.PropsSI('d(P)/d(T)|Dmass','D',d_sat_liq,'T',T_sat,FluidName)
ds_dd_Tl = CP.CoolProp.PropsSI('d(Smass)/d(D)|T','D',d_sat_liq,'T',T_sat,FluidName)
ds_dT_dl = CP.CoolProp.PropsSI('d(Smass)/d(T)|D','D',d_sat_liq,'T',T_sat,FluidName)
dh_dd_Tl = CP.CoolProp.PropsSI('d(Hmass)/d(D)|T','D',d_sat_liq,'T',T_sat,FluidName)
dh_dT_dl = CP.CoolProp.PropsSI('d(Hmass)/d(T)|D','D',d_sat_liq,'T',T_sat,FluidName)
dp_dv_Tl = -d_sat_liq**2 * dp_dd_Tl
dp_dT_vl = dp_dT_dl
# derivs wrt dT, single-phase AT the sat vap line
dp_dd_Tv = CP.CoolProp.PropsSI('d(P)/d(Dmass)|T','D',d_sat_vap,'T',T_sat,FluidName)
dp_dT_dv = CP.CoolProp.PropsSI('d(P)/d(T)|Dmass','D',d_sat_vap,'T',T_sat,FluidName)
ds_dd_Tv = CP.CoolProp.PropsSI('d(Smass)/d(D)|T','D',d_sat_vap,'T',T_sat,FluidName)
ds_dT_dv = CP.CoolProp.PropsSI('d(Smass)/d(T)|D','D',d_sat_vap,'T',T_sat,FluidName)
dh_dd_Tv = CP.CoolProp.PropsSI('d(Hmass)/d(D)|T','D',d_sat_vap,'T',T_sat,FluidName)
dh_dT_dv = CP.CoolProp.PropsSI('d(Hmass)/d(T)|D','D',d_sat_vap,'T',T_sat,FluidName)
dp_dv_Tv = -d_sat_vap**2 * dp_dd_Tv
dp_dT_vv = dp_dT_dv
# two ways for derivs along the sat line: using derivs wrt dT or pT
# derivs wrt T ALONG the sat liq line (that is, at q=const=0)
dd_dT_ql = (dp_dT_q - dp_dT_dl)/dp_dd_Tl
dv_dT_ql = dv_dT_pl + dv_dp_Tl*dp_dT_q
ds_dT_ql = ds_dT_dl + ds_dd_Tl*dd_dT_ql
#ds_dT_ql = ds_dT_pl + ds_dp_Tl*dp_dT_q
dh_dT_ql = dh_dT_pl + dh_dp_Tl*dp_dT_q
# derivs wrt T ALONG the sat vap line (that is, at q=const=1)
dd_dT_qv = (dp_dT_q - dp_dT_dv)/dp_dd_Tv
dv_dT_qv = (dp_dT_q - dp_dT_dv)/dp_dd_Tv
dv_dT_qv = dv_dT_pv + dv_dp_Tv*dp_dT_q
ds_dT_qv = ds_dT_dv + ds_dd_Tv*dd_dT_qv
dh_dT_qv = dh_dT_pv + dh_dp_Tv*dp_dT_q
# derivs wrt p ALONG the sat liq line (that is, at q=const=0)
dd_dp_ql = dd_dp_Tl + dd_dT_pl*dT_dp_q
ds_dp_ql = ds_dp_Tl + ds_dT_pl*dT_dp_q
dv_dp_ql = dv_dp_Tl + dv_dT_pl*dT_dp_q
# derivs wrt p ALONG the sat vap line (that is, at q=const=1)
dd_dp_qv = dd_dp_Tv + dd_dT_pv*dT_dp_q
ds_dp_qv = ds_dp_Tv + ds_dT_pv*dT_dp_q
dv_dp_qv = dv_dp_Tv + dv_dT_pv*dT_dp_q
# derivs wrt h ALONG the sat line
dd_dh_ql = dd_dT_ql/dh_dT_ql
dd_dh_qv = dd_dT_qv/dh_dT_qv
ds_dh_ql = ds_dT_ql/dh_dT_ql
ds_dh_qv = ds_dT_qv/dh_dT_qv
# derivs of Clausius-Clapeyron
# d2p_dT2_q = ((ds_dT_qv-ds_dT_ql)*Dv_vl - Ds_vl*(dv_dT_qv-dv_dT_ql)) / Dv_vl**2
d2p_dT2_q = (ds_dT_qv-ds_dT_ql)/Dv_vl - dp_dT_q*(dv_dT_qv-dv_dT_ql)/Dv_vl
d2T_dp2_q = (dv_dp_qv-dv_dp_ql)/Ds_vl - dT_dp_q*(ds_dp_qv-ds_dp_ql)/Ds_vl
d2p_dT2_qn = numSlopeAr(T_sat,dp_dT_q)
d2T_dp2_qn = numSlopeAr(p_sat,dT_dp_q)
# second derivs AT the sat line
# AT the liq line
# wrt pT
d2d_dT2_pl = np.empty(nPoints)
d2d_dp2_Tl = np.empty(len(T_sat))
d2d_dpTl = np.empty(len(T_sat))
d2s_dT2_pl = np.empty(len(T_sat))
d2s_dp2_Tl = np.empty(len(T_sat))
d2s_dpTl = np.empty(len(T_sat))
d2h_dT2_pl = np.empty(len(T_sat))
d2h_dp2_Tl = np.empty(len(T_sat))
d2h_dpTl = np.empty(len(T_sat))
# wrt dT
d2s_dT2_dl = np.empty(len(T_sat))
d2s_dd2_Tl = np.empty(len(T_sat))
d2s_ddTl = np.empty(len(T_sat))
# AT the vap line
# wrt pT
d2d_dT2_pv = np.empty(len(T_sat))
d2d_dp2_Tv = np.empty(len(T_sat))
d2d_dpTv = np.empty(len(T_sat))
d2s_dT2_pv = np.empty(len(T_sat))
d2s_dp2_Tv = np.empty(len(T_sat))
d2s_dpTv = np.empty(len(T_sat))
d2h_dT2_pv = np.empty(len(T_sat))
d2h_dp2_Tv = np.empty(len(T_sat))
d2h_dpTv = np.empty(len(T_sat))
# wrt dT
d2s_dT2_dv = np.empty(len(T_sat))
d2s_dd2_Tv = np.empty(len(T_sat))
d2s_ddTv = np.empty(len(T_sat))
HEOS = CP.AbstractState("HEOS", FluidName)
for idx in range(0,len(T_sat)):
# AT the liq line
HEOS.update(CP.QT_INPUTS, 0, T_sat[idx])
# wrt pT
d2d_dT2_pl[idx] = HEOS.second_partial_deriv(CP.iDmass, CP.iT, CP.iP, CP.iT, CP.iP)
d2d_dp2_Tl[idx] = HEOS.second_partial_deriv(CP.iDmass, CP.iP, CP.iT, CP.iP, CP.iT)
d2d_dpTl[idx] = HEOS.second_partial_deriv(CP.iDmass, CP.iP, CP.iT, CP.iT, CP.iP)
d2s_dT2_pl[idx] = HEOS.second_partial_deriv(CP.iSmass, CP.iT, CP.iP, CP.iT, CP.iP)
d2s_dp2_Tl[idx] = HEOS.second_partial_deriv(CP.iSmass, CP.iP, CP.iT, CP.iP, CP.iT)
d2s_dpTl[idx] = HEOS.second_partial_deriv(CP.iSmass, CP.iP, CP.iT, CP.iT, CP.iP)
d2h_dT2_pl[idx] = HEOS.second_partial_deriv(CP.iHmass, CP.iT, CP.iP, CP.iT, CP.iP)
d2h_dp2_Tl[idx] = HEOS.second_partial_deriv(CP.iHmass, CP.iP, CP.iT, CP.iP, CP.iT)
d2h_dpTl[idx] = HEOS.second_partial_deriv(CP.iHmass, CP.iP, CP.iT, CP.iT, CP.iP)
# wrt dT
d2s_dT2_dl[idx] = HEOS.second_partial_deriv(CP.iSmass, CP.iT, CP.iDmass, CP.iT, CP.iDmass)
d2s_dd2_Tl[idx] = HEOS.second_partial_deriv(CP.iSmass, CP.iDmass, CP.iT, CP.iDmass, CP.iT)
d2s_ddTl[idx] = HEOS.second_partial_deriv(CP.iSmass, CP.iDmass, CP.iT, CP.iT, CP.iDmass)
# AT the vap line
HEOS.update(CP.QT_INPUTS, 1, T_sat[idx])
# wrt pT
d2d_dT2_pv[idx] = HEOS.second_partial_deriv(CP.iDmass, CP.iT, CP.iP, CP.iT, CP.iP)
d2d_dp2_Tv[idx] = HEOS.second_partial_deriv(CP.iDmass, CP.iP, CP.iT, CP.iP, CP.iT)
d2d_dpTv[idx] = HEOS.second_partial_deriv(CP.iDmass, CP.iP, CP.iT, CP.iT, CP.iP)
d2s_dT2_pv[idx] = HEOS.second_partial_deriv(CP.iSmass, CP.iT, CP.iP, CP.iT, CP.iP)
d2s_dp2_Tv[idx] = HEOS.second_partial_deriv(CP.iSmass, CP.iP, CP.iT, CP.iP, CP.iT)
d2s_dpTv[idx] = HEOS.second_partial_deriv(CP.iSmass, CP.iP, CP.iT, CP.iT, CP.iP)
d2h_dT2_pv[idx] = HEOS.second_partial_deriv(CP.iHmass, CP.iT, CP.iP, CP.iT, CP.iP)
d2h_dp2_Tv[idx] = HEOS.second_partial_deriv(CP.iHmass, CP.iP, CP.iT, CP.iP, CP.iT)
d2h_dpTv[idx] = HEOS.second_partial_deriv(CP.iHmass, CP.iP, CP.iT, CP.iT, CP.iP)
# wrt dT
d2s_dT2_dv[idx] = HEOS.second_partial_deriv(CP.iSmass, CP.iT, CP.iDmass, CP.iT, CP.iDmass)
d2s_dd2_Tv[idx] = HEOS.second_partial_deriv(CP.iSmass, CP.iDmass, CP.iT, CP.iDmass, CP.iT)
d2s_ddTv[idx] = HEOS.second_partial_deriv(CP.iSmass, CP.iDmass, CP.iT, CP.iT, CP.iDmass)
# calculate 2nd derivs ALONG the sat line (analytically and numerically)
# A=dd_dT_p and B=dd_dp_T
# liq side
dA_dT_ql = d2d_dT2_pl + d2d_dpTl*dp_dT_q
dB_dT_ql = d2d_dpTl + d2d_dp2_Tl*dp_dT_q
d2d_dT2_qla = dA_dT_ql + dB_dT_ql*dp_dT_q + dd_dp_Tl*d2p_dT2_q
d2d_dT2_qln = numSlopeAr(T_sat, dd_dT_ql)
# vap side
dA_dT_qv = d2d_dT2_pv + d2d_dpTv*dp_dT_q
dB_dT_qv = d2d_dpTv + d2d_dp2_Tv*dp_dT_q
d2d_dT2_qva = dA_dT_qv + dB_dT_qv*dp_dT_q + dd_dp_Tv*d2p_dT2_q
d2d_dT2_qvn = numSlopeAr(T_sat, dd_dT_qv)
#print(d2d_dT2_qla - d2d_dT2_qln)
#print(d2d_dT2_qva - d2d_dT2_qln)
# C=ds_dT_p and E=ds_dp_T
# liq side
dC_dT_ql = d2s_dT2_dl + d2s_ddTl*dd_dT_ql
dE_dT_ql = d2s_ddTl + d2s_dd2_Tl*dd_dT_ql
d2s_dT2_qla = dC_dT_ql + dE_dT_ql*dd_dT_ql + ds_dd_Tl*d2d_dT2_qla
d2s_dT2_qln = numSlopeAr(T_sat, ds_dT_ql)
# vap side
dC_dT_qv = d2s_dT2_dv + d2s_ddTv*dd_dT_qv
dE_dT_qv = d2s_ddTv + d2s_dd2_Tv*dd_dT_qv
d2s_dT2_qva = dC_dT_qv + dE_dT_qv*dd_dT_qv + ds_dd_Tv*d2d_dT2_qva
d2s_dT2_qvn = numSlopeAr(T_sat, ds_dT_qv)
#print(d2s_dT2_qla - d2s_dT2_qln)
#print(d2s_dT2_qva - d2s_dT2_qvn)
# B=dd_dp_T and A=dd_dT_p
# liq side
dB_dp_ql = d2d_dp2_Tl + d2d_dpTl*dT_dp_q
dA_dp_ql = d2d_dpTl + d2d_dT2_pl*dT_dp_q
d2d_dp2_qla = dB_dp_ql + dA_dp_ql*dT_dp_q + dd_dT_pl*d2T_dp2_q
d2d_dp2_qln = numSlopeAr(T_sat, ds_dp_ql)
# vap side
dB_dp_qv = d2d_dp2_Tv + d2d_dpTv*dT_dp_q
dA_dp_qv = d2d_dpTv + d2d_dT2_pv*dT_dp_q
d2d_dp2_qva = dB_dp_qv + dA_dp_qv*dT_dp_q + dd_dT_pv*d2T_dp2_q
d2d_dp2_qvn = numSlopeAr(T_sat, ds_dp_qv)
#print(d2d_dp2_qla - d2d_dp2_qln)
#print(d2d_dp2_qva - d2d_dp2_qvn)
# E=ds_dp_T and C=ds_dT_p
# liq side
dE_dp_ql = d2s_dp2_Tl + d2s_dpTl*dT_dp_q
dC_dp_ql = d2s_dpTl + d2s_dT2_pl*dT_dp_q
d2s_dp2_qla = dE_dp_ql + dC_dp_ql*dT_dp_q + ds_dT_pl*d2T_dp2_q
d2s_dp2_qln = numSlopeAr(p_sat, ds_dp_ql)
# vap side
dE_dp_qv = d2s_dp2_Tv + d2s_dpTv*dT_dp_q
dC_dp_qv = d2s_dpTv + d2s_dT2_pv*dT_dp_q
d2s_dp2_qva = dE_dp_qv + dC_dp_qv*dT_dp_q + ds_dT_pv*d2T_dp2_q
d2s_dp2_qvn = numSlopeAr(p_sat, ds_dp_qv)
#print(d2s_dp2_qla - d2s_dp2_qln)
#print(d2s_dp2_qva - d2s_dp2_qvn)
# G=dh_dT_p and K=dh_dp_T
# liq side
dG_dT_ql = d2h_dT2_pl + d2h_dpTl*dp_dT_q
dK_dT_ql = d2h_dpTl + d2h_dp2_Tl*dp_dT_q
d2h_dT2_qla = dG_dT_ql + dK_dT_ql*dp_dT_q + dh_dp_Tl*d2p_dT2_q
d2h_dT2_qln = numSlopeAr(T_sat, dh_dT_ql)
# vap side
dG_dT_qv = d2h_dT2_pv + d2h_dpTv*dp_dT_q
dK_dT_qv = d2h_dpTv + d2h_dp2_Tv*dp_dT_q
d2h_dT2_qva = dG_dT_qv + dK_dT_qv*dp_dT_q + dh_dp_Tv*d2p_dT2_q
d2h_dT2_qvn = numSlopeAr(T_sat, dh_dT_qv)
#print(d2h_dT2_qla - d2h_dT2_qln)
#print(d2h_dT2_qva - d2h_dT2_qvn)
# liq side
d2d_dh2_qla = (d2d_dT2_qla*dh_dT_ql - dd_dT_ql*d2h_dT2_qla) / dh_dT_ql**3
d2d_dh2_qln = numSlopeAr(h_sat_liq, dd_dh_ql)
# vap side
d2d_dh2_qva = (d2d_dT2_qva*dh_dT_qv - dd_dT_qv*d2h_dT2_qva) / dh_dT_qv**3
d2d_dh2_qvn = numSlopeAr(h_sat_vap, dd_dh_qv)
#print(d2d_dh2_qla - d2d_dh2_qln)
#print(d2d_dh2_qva - d2d_dh2_qvn)
# liq side
d2s_dh2_qla = (d2s_dT2_qla*dh_dT_ql - ds_dT_ql*d2h_dT2_qla) / dh_dT_ql**3
d2s_dh2_qln = numSlopeAr(h_sat_liq, ds_dh_ql)
# vap side
d2s_dh2_qva = (d2s_dT2_qva*dh_dT_qv - ds_dT_qv*d2h_dT2_qva) / dh_dT_qv**3
d2s_dh2_qvn = numSlopeAr(h_sat_vap, ds_dh_qv)
#print(d2s_dh2_qla - d2s_dh2_qln)
#print(d2s_dh2_qva - d2s_dh2_qvn)
In [8]:
# vapor pressure, Clausius-Clapeyron
# pick a point and set figure size
mySatPoint = int(nPoints-50)
print("T_sat = " + str(T_sat[mySatPoint]))
print("p_sat = " + str(p_sat[mySatPoint]))
plt.figure(figsize=(width,width*3/2/golden))
plt.subplot(3,2,1)
plt.plot(T_sat, p_sat, color='blue')
#plt.yscale('log')
plt.ticklabel_format(style='sci', axis='y', scilimits=(0,0))
plt.grid(b=True, linestyle=':')
plt.minorticks_on()
plt.xlabel('Temperature in K')
plt.ylabel('Pressure in Pa')
drawTangent(T_sat, p_sat, dp_dT_q, mySatPoint)
#print(dp_dT_q - dp_dT_qn)
plt.subplot(3,2,2)
plt.plot(p_sat, T_sat, color='blue')
#plt.yscale('log')
plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
plt.grid(b=True, linestyle=':')
plt.minorticks_on()
plt.xlabel('Pressure in Pa')
plt.ylabel('Temperature in K')
drawTangent(p_sat, T_sat, dT_dp_q, mySatPoint)
#print(dT_dp_q - dT_dp_qn)
plt.subplot(3,2,3)
plt.plot(T_sat, dp_dT_q, color='blue')
#plt.yscale('log')
plt.grid(b=True, linestyle=':')
plt.minorticks_on()
plt.xlabel('Temperature in K')
plt.ylabel('dp/dT in Pa/K')
drawTangent(T_sat, dp_dT_q, d2p_dT2_q, mySatPoint)
#print(d2p_dT2_q - d2p_dT2_qn)
plt.subplot(3,2,4)
plt.plot(p_sat, dT_dp_q, color='blue')
plt.yscale('log')
plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
plt.grid(b=True, linestyle=':')
plt.minorticks_on()
plt.xlabel('Pressure in Pa')
plt.ylabel('dT/dp in K/Pa')
drawTangent(p_sat, dT_dp_q, d2T_dp2_q, mySatPoint)
#print(d2T_dp2_q - d2T_dp2_qn)
plt.subplot(3,2,5)
plt.plot(T_sat, d2p_dT2_q, color='blue')
plt.grid(b=True, linestyle=':')
plt.minorticks_on()
plt.xlabel('Temperature in K')
plt.ylabel('d2p/dT2 in Pa/K2')
plt.subplot(3,2,6)
plt.plot(p_sat, abs(d2T_dp2_q), color='blue')
plt.yscale('log')
plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
plt.grid(b=True, linestyle=':')
plt.minorticks_on()
plt.xlabel('Pressure in Pa')
plt.ylabel('|d2T/dp2| in K/Pa2')
Out[8]:
In [9]:
# Pick a point and set figure size
mySatPoint = int(nPoints-50)
print("T_sat = " + str(T_sat[mySatPoint]))
print("p_sat = " + str(p_sat[mySatPoint]))
plt.figure(figsize=(width,width*3/2/golden))
# d versus T
plt.subplot(3,2,1)
plt.plot(T_sat, d_sat_liq, color='blue')
plt.plot(T_sat, d_sat_vap, color='red')
#plt.plot(T_sat, (d_sat_liq+d_sat_vap)/2, color='black')
plt.xlabel('Temperature in K')
plt.ylabel('Density in kg/m³')
drawTangent(T_sat, d_sat_liq, dd_dT_ql, mySatPoint)
drawTangent(T_sat, d_sat_vap, dd_dT_qv, mySatPoint)
# s versus T
plt.subplot(3,2,2)
plt.plot(T_sat, s_sat_liq, color='blue')
plt.plot(T_sat, s_sat_vap, color='red')
plt.xlabel('Temperature in K')
plt.ylabel('Specific entropy in J/(kg·K)')
drawTangent(T_sat, s_sat_liq, ds_dT_ql, mySatPoint)
drawTangent(T_sat, s_sat_vap, ds_dT_qv, mySatPoint)
# d versus p
plt.subplot(3,2,3)
plt.plot(p_sat, d_sat_liq, color='blue')
plt.plot(p_sat, d_sat_vap, color='red')
plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
plt.xlabel('Pressure in Pa')
plt.ylabel('Density in kg/m³')
drawTangent(p_sat, d_sat_liq, dd_dp_ql, mySatPoint)
drawTangent(p_sat, d_sat_vap, dd_dp_qv, mySatPoint)
#print(dd_dp_ql - numSlopeAr(p_sat, d_sat_liq))
#print(dd_dp_qv - numSlopeAr(p_sat, d_sat_vap))
# s versus p
plt.subplot(3,2,4)
plt.plot(p_sat, s_sat_liq, color='blue')
plt.plot(p_sat, s_sat_vap, color='red')
#plt.yscale('log')
plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
plt.xlabel('Pressure in Pa')
plt.ylabel('Specific entropy in J/(kg·K)')
drawTangent(p_sat, s_sat_liq, ds_dp_ql, mySatPoint)
drawTangent(p_sat, s_sat_vap, ds_dp_qv, mySatPoint)
#print(ds_dp_ql - numSlopeAr(p_sat, s_sat_liq))
#print(ds_dp_qv - numSlopeAr(p_sat, s_sat_vap))
# d versus h
plt.subplot(3,2,5)
plt.plot(h_sat_liq, d_sat_liq, color='blue')
plt.plot(h_sat_vap, d_sat_vap, color='red')
plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
plt.xlabel('Specific enthalpy in J/kg')
plt.ylabel('Density in kg/m³')
drawTangent(h_sat_liq, d_sat_liq, dd_dh_ql, mySatPoint)
drawTangent(h_sat_vap, d_sat_vap, dd_dh_qv, mySatPoint)
# s versus h
plt.subplot(3,2,6)
plt.plot(h_sat_liq, s_sat_liq, color='blue')
plt.plot(h_sat_vap, s_sat_vap, color='red')
plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
plt.xlabel('Specific enthalpy in J/kg')
plt.ylabel('Specific entropy in J/(kg·K)')
drawTangent(h_sat_liq, s_sat_liq, ds_dh_ql, mySatPoint)
drawTangent(h_sat_vap, s_sat_vap, ds_dh_qv, mySatPoint)
In [10]:
# Pick a point and set figure size
mySatPoint = int(nPoints-50)
print("T_sat = " + str(T_sat[mySatPoint]))
print("p_sat = " + str(p_sat[mySatPoint]))
plt.figure(figsize=(width,width*3/2/golden))
# dd_dT versus T
plt.subplot(3,2,1)
plt.plot(T_sat, dd_dT_ql, color='blue')
plt.plot(T_sat, dd_dT_qv, color='red')
plt.xlabel('Temperature in K')
plt.ylabel('dd/dT in kg/m³/K')
drawTangent(T_sat, dd_dT_ql, d2d_dT2_qla, mySatPoint)
drawTangent(T_sat, dd_dT_qv, d2d_dT2_qva, mySatPoint)
# ds_dT versus T
plt.subplot(3,2,2)
plt.plot(T_sat, ds_dT_ql, color='blue')
plt.plot(T_sat, ds_dT_qv, color='red')
plt.xlabel('Temperature in K')
plt.ylabel('ds/dT in J//(kg·K)/K')
drawTangent(T_sat, ds_dT_ql, d2s_dT2_qla, mySatPoint)
drawTangent(T_sat, ds_dT_qv, d2s_dT2_qva, mySatPoint)
# dd_dp versus p
plt.subplot(3,2,3)
#plt.plot(p_sat, dd_dp_ql, color='blue')
plt.plot(p_sat, dd_dp_qv, color='red')
plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
plt.xlabel('Pressure in Pa')
plt.ylabel('dd/dp in kg/m³/Pa')
#drawTangent(p_sat, dd_dp_ql, d2d_dp2_qla, mySatPoint)
drawTangent(p_sat, dd_dp_qv, d2d_dp2_qva, mySatPoint)
# ds_dp versus p
plt.subplot(3,2,4)
plt.plot(p_sat, ds_dp_ql, color='blue')
#plt.plot(p_sat, ds_dp_qv, color='red')
#plt.yscale('log')
plt.ylim([0,10*min(ds_dp_ql)])
plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
plt.xlabel('Pressure in Pa')
plt.ylabel('ds/dp in J//(kg·K)/Pa')
drawTangent(p_sat, ds_dp_ql, d2s_dp2_qla, mySatPoint)
#drawTangent(p_sat, ds_dp_qv, d2s_dp2_qva, mySatPoint)
# dd_dh versus h
plt.subplot(3,2,5)
plt.plot(h_sat_liq, dd_dh_ql, color='blue')
#plt.plot(h_sat_vap, dd_dh_qv, color='red')
plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
plt.xlabel('Specific enthalpy in J/kg')
plt.ylabel('dd/dh')
drawTangent(h_sat_liq, dd_dh_ql, d2d_dh2_qla, mySatPoint)
#drawTangent(h_sat_vap, dd_dh_qv, d2d_dh2_qva, mySatPoint)
# ds_dh versus h
plt.subplot(3,2,6)
plt.plot(h_sat_liq, ds_dh_ql, color='blue')
#plt.plot(h_sat_vap, ds_dh_qv, color='red')
plt.ticklabel_format(style='sci', axis='x', scilimits=(0,0))
plt.xlabel('Specific enthalpy in J/kg')
plt.ylabel('ds/dh')
drawTangent(h_sat_liq, ds_dh_ql, d2s_dh2_qla, mySatPoint)
#drawTangent(h_sat_vap, ds_dh_qv, d2s_dh2_qva, mySatPoint)