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