Skip to content

Commit c0c4d2e

Browse files
Use of triple point of water in GetSatVapPres
This change is more physically correct and simplifies considerably the NR convergence procedure in GetTDewPointFromVapPres.
1 parent 31df87d commit c0c4d2e

File tree

1 file changed

+21
-24
lines changed

1 file changed

+21
-24
lines changed

src/python/psychrolib.py

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,16 @@
8484
8585
"""
8686

87+
TRIPLE_POINT_WATER_SI = 0.01
88+
"""float: Triple point of water in Celsius.
89+
90+
"""
91+
92+
TRIPLE_POINT_WATER_IP = 32.018
93+
"""float: Triple point of water in Fahrenheit.
94+
95+
"""
96+
8797

8898
#######################################################################################################
8999
# Helper functions
@@ -403,15 +413,15 @@ def dLnPws_(TDryBulb: float) -> float:
403413
"""
404414
if isIP():
405415
T = GetTRankineFromTFahrenheit(TDryBulb)
406-
if TDryBulb <= 32.:
416+
if TDryBulb <= TRIPLE_POINT_WATER_IP:
407417
dLnPws = 1.0214165E+04 / math.pow(T, 2) - 5.3765794E-03 + 2 * 1.9202377E-07 * T \
408418
+ 2 * 3.5575832E-10 * math.pow(T, 2) - 4 * 9.0344688E-14 * math.pow(T, 3) + 4.1635019 / T
409419
else:
410420
dLnPws = 1.0440397E+04 / math.pow(T, 2) - 2.7022355E-02 + 2 * 1.2890360E-05 * T \
411421
- 3 * 2.4780681E-09 * math.pow(T, 2) + 6.5459673 / T
412422
else:
413423
T = GetTKelvinFromTCelsius(TDryBulb)
414-
if TDryBulb <= 0.:
424+
if TDryBulb <= TRIPLE_POINT_WATER_SI:
415425
dLnPws = 5.6745359E+03 / math.pow(T, 2) - 9.677843E-03 + 2 * 6.2215701E-07 * T \
416426
+ 3 * 2.0747825E-09 * math.pow(T, 2) - 4 * 9.484024E-13 * math.pow(T, 3) + 4.1635019 / T
417427
else:
@@ -441,38 +451,19 @@ def GetTDewPointFromVapPres(TDryBulb: float, VapPres: float) -> float:
441451
narrower range of validity.
442452
The Newton-Raphson (NR) method is used on the logarithm of water vapour
443453
pressure as a function of temperature, which is a very smooth function
444-
Convergence is usually achieved in 3 to 5 iterations.
454+
Convergence is usually achieved in 3 to 5 iterations.
445455
TDryBulb is not really needed here, just used for convenience.
446456
447457
"""
448458
if isIP():
449459
BOUNDS = [-148, 392]
450-
T_WATER_FREEZE = 32.
451460
else:
452461
BOUNDS = [-100, 200]
453-
T_WATER_FREEZE = 0.
454462

455463
# Validity check -- bounds outside which a solution cannot be found
456464
if VapPres < GetSatVapPres(BOUNDS[0]) or VapPres > GetSatVapPres(BOUNDS[1]):
457465
raise ValueError("Partial pressure of water vapor is outside range of validity of equations")
458466

459-
# Vapor pressure contained within the discontinuity of the Pws function: return temperature of freezing
460-
T_WATER_FREEZE_LOW = T_WATER_FREEZE - PSYCHROLIB_TOLERANCE / 10. # Temperature just below freezing
461-
T_WATER_FREEZE_HIGH = T_WATER_FREEZE + PSYCHROLIB_TOLERANCE / 10. # Temperature just above freezing
462-
PWS_FREEZE_LOW = GetSatVapPres(T_WATER_FREEZE_LOW)
463-
PWS_FREEZE_HIGH = GetSatVapPres(T_WATER_FREEZE_HIGH)
464-
465-
# Restrict iteration to either left or right part of the saturation vapor pressure curve
466-
# to avoid iterating back and forth across the discontinuity of the curve at the freezing point
467-
# When the partial pressure of water vapor is within the discontinuity of GetSatVapPres,
468-
# simply return the freezing point of water.
469-
if (VapPres < PWS_FREEZE_LOW):
470-
BOUNDS[1] = T_WATER_FREEZE_LOW
471-
elif (VapPres > PWS_FREEZE_HIGH):
472-
BOUNDS[0] = T_WATER_FREEZE_HIGH
473-
else:
474-
return T_WATER_FREEZE
475-
476467
# We use NR to approximate the solution.
477468
# First guess
478469
TDewPoint = TDryBulb # Calculated value of dew point temperatures, solved for iteratively
@@ -949,6 +940,12 @@ def GetSatVapPres(TDryBulb: float) -> float:
949940
950941
Reference:
951942
ASHRAE Handbook - Fundamentals (2017) ch. 1 eqn 5 & 6
943+
Important note: the ASHRAE formulae are defined above and below the freezing point but have
944+
a discontinuity at the freezing point. This is a small inaccuracy on ASHRAE's part: the formulae
945+
should be define above and below the triple point of water (not the feezing point) in which case
946+
the discontinuity vanishes. It is essential to use the triple point of water otherwise function
947+
GetTDewPointFromVapPres, which inverts the present function, does not converge properly around
948+
the freezing point.
952949
953950
"""
954951
if isIP():
@@ -957,7 +954,7 @@ def GetSatVapPres(TDryBulb: float) -> float:
957954

958955
T = GetTRankineFromTFahrenheit(TDryBulb)
959956

960-
if (TDryBulb <= 32.):
957+
if (TDryBulb <= TRIPLE_POINT_WATER_IP):
961958
LnPws = (-1.0214165E+04 / T - 4.8932428 - 5.3765794E-03 * T + 1.9202377E-07 * T**2 \
962959
+ 3.5575832E-10 * math.pow(T, 3) - 9.0344688E-14 * math.pow(T, 4) + 4.1635019 * math.log(T))
963960
else:
@@ -969,7 +966,7 @@ def GetSatVapPres(TDryBulb: float) -> float:
969966

970967
T = GetTKelvinFromTCelsius(TDryBulb)
971968

972-
if (TDryBulb <= 0):
969+
if (TDryBulb <= TRIPLE_POINT_WATER_SI):
973970
LnPws = -5.6745359E+03 / T + 6.3925247 - 9.677843E-03 * T + 6.2215701E-07 * T**2 \
974971
+ 2.0747825E-09 * math.pow(T, 3) - 9.484024E-13 * math.pow(T, 4) + 4.1635019 * math.log(T)
975972
else:

0 commit comments

Comments
 (0)