🔬
Solver Purpose & Physical Scope
Psychrometrics is the study of moist air properties. Key definitions include relative humidity ($RH$), humidity ratio (specific humidity $\omega$), and dew-point temperature:
📂 Discipline: Thermo
⚡ Precision: IEEE-754 64-bit Real(`real(8)`)
📥 Total Downloads: 375 times
📄 Source File:
psychrometrics.f90
📁 calcul/Thermodynamics /
psychrometrics.f90
program psychrometrics
implicit none
! Constants
double precision, parameter :: R_a = 0.28705d0 ! kJ/(kg.K) gas constant for dry air
double precision, parameter :: Cp_da = 1.006d0 ! kJ/(kg.K) specific heat of dry air
double precision, parameter :: Cp_wv = 1.86d0 ! kJ/(kg.K) specific heat of water vapor
double precision, parameter :: h_fg = 2501.0d0 ! kJ/kg latent heat at 0 C
! Inputs
integer :: mode ! 1 = T & RH, 2 = T & Twb, 3 = T & Tdp, 4 = T & w
double precision :: T, P, val
! Solved properties
double precision :: RH, T_wb, T_dp, w, h, v, Pv, Psat_T
! Solver bounds
double precision :: a, b, mid, w_calc, eps
integer :: i, max_iter
logical :: has_error
! Read inputs from stdin
read(*,*,iostat=i) mode
if (i /= 0) then
write(*,*) 'ERROR: Invalid input mode.'
stop
end if
read(*,*,iostat=i) T
if (i /= 0) then
write(*,*) 'ERROR: Invalid dry-bulb temperature.'
stop
end if
read(*,*,iostat=i) P
if (i /= 0) then
write(*,*) 'ERROR: Invalid barometric pressure.'
stop
end if
read(*,*,iostat=i) val
if (i /= 0) then
write(*,*) 'ERROR: Invalid second parameter value.'
stop
end if
! Basic validations
if (P <= 0.0d0) then
write(*,*) 'ERROR: Barometric pressure must be positive.'
stop
end if
has_error = .false.
Psat_T = psat(T)
! Compute based on combination mode
select case (mode)
case (1)
! Mode 1: Dry-Bulb T & Relative Humidity RH (%)
RH = val
if (RH < 0.0d0) RH = 0.0d0
if (RH > 100.0d0) RH = 100.0d0
Pv = (RH / 100.0d0) * Psat_T
if (Pv >= P) then
Pv = P - 1.0d-4
RH = (Pv / Psat_T) * 100.0d0
end if
w = 0.62198d0 * Pv / (P - Pv)
T_dp = T_dew(Pv)
call solve_twb(T, P, w, T_dp, T_wb)
case (2)
! Mode 2: Dry-Bulb T & Wet-Bulb T_wb (C)
T_wb = val
if (T_wb > T) then
write(*,*) 'ERROR: Wet-bulb temperature cannot exceed dry-bulb temperature.'
stop
end if
w = calculate_w_from_twb(T, P, T_wb)
if (w < 0.0d0) then
w = 0.0d0
Pv = 0.0d0
RH = 0.0d0
T_dp = -100.0d0
else
Pv = P * w / (0.62198d0 + w)
if (Pv > Psat_T) then
! Clamping to saturation if solver yields physically impossible state
Pv = Psat_T
w = 0.62198d0 * Pv / (P - Pv)
RH = 100.0d0
T_dp = T
T_wb = T
else
RH = (Pv / Psat_T) * 100.0d0
T_dp = T_dew(Pv)
end if
end if
case (3)
! Mode 3: Dry-Bulb T & Dew-Point T_dp (C)
T_dp = val
if (T_dp > T) then
write(*,*) 'ERROR: Dew-point temperature cannot exceed dry-bulb temperature.'
stop
end if
Pv = psat(T_dp)
if (Pv >= P) then
write(*,*) 'ERROR: Dew-point saturation pressure exceeds barometric pressure.'
stop
end if
w = 0.62198d0 * Pv / (P - Pv)
RH = (Pv / Psat_T) * 100.0d0
call solve_twb(T, P, w, T_dp, T_wb)
case (4)
! Mode 4: Dry-Bulb T & Humidity Ratio w (kg/kg)
w = val
if (w < 0.0d0) then
write(*,*) 'ERROR: Humidity ratio cannot be negative.'
stop
end if
Pv = P * w / (0.62198d0 + w)
if (Pv > Psat_T) then
write(*,*) 'ERROR: Specified humidity ratio exceeds saturation state at T.'
stop
end if
RH = (Pv / Psat_T) * 100.0d0
T_dp = T_dew(Pv)
call solve_twb(T, P, w, T_dp, T_wb)
case default
write(*,*) 'ERROR: Unknown input combination mode.'
stop
end select
! Calculate Enthalpy (h in kJ/kg dry air)
h = Cp_da * T + w * (h_fg + Cp_wv * T)
! Calculate Specific Volume (v in m3/kg dry air)
v = R_a * (T + 273.15d0) / (P - Pv)
! Print outputs to stdout in clear key-value pairs
write(*,'(A,I2)') 'MODE=', mode
write(*,'(A,F14.4)') 'T=', T
write(*,'(A,F14.4)') 'P=', P
write(*,'(A,F14.4)') 'T_WB=', T_wb
write(*,'(A,F14.4)') 'T_DP=', T_dp
write(*,'(A,F14.4)') 'RH=', RH
write(*,'(A,F14.8)') 'W=', w
write(*,'(A,F14.4)') 'H=', h
write(*,'(A,F14.6)') 'V=', v
write(*,'(A,F14.6)') 'PV=', Pv
write(*,'(A,F14.6)') 'PSAT=', Psat_T
contains
! Saturation pressure of liquid water or ice (Buck equation) in kPa
double precision function psat(T_c)
double precision, intent(in) :: T_c
if (T_c >= 0.0d0) then
psat = 0.61121d0 * exp((17.67d0 * T_c) / (T_c + 243.5d0))
else
psat = 0.61115d0 * exp((22.452d0 * T_c) / (T_c + 272.62d0))
end if
end function psat
! Dew point calculation from partial vapor pressure (Buck equation inverse) in C
double precision function T_dew(Pv_val)
double precision, intent(in) :: Pv_val
double precision :: y
if (Pv_val <= 1.0d-8) then
T_dew = -100.0d0
return
end if
if (Pv_val >= 0.61121d0) then
y = log(Pv_val / 0.61121d0)
T_dew = (243.5d0 * y) / (17.67d0 - y)
else
y = log(Pv_val / 0.61115d0)
T_dew = (272.62d0 * y) / (22.452d0 - y)
end if
end function T_dew
! adiabatic saturation relation for humidity ratio w given dry-bulb T and wet-bulb Twb
double precision function calculate_w_from_twb(T_db, P_bar, T_wb_val)
double precision, intent(in) :: T_db, P_bar, T_wb_val
double precision :: psat_twb, w_sat_twb
psat_twb = psat(T_wb_val)
if (P_bar > psat_twb) then
w_sat_twb = 0.62198d0 * psat_twb / (P_bar - psat_twb)
else
w_sat_twb = 9999.0d0
end if
calculate_w_from_twb = ((2501.0d0 - 2.381d0 * T_wb_val) * w_sat_twb - Cp_da * (T_db - T_wb_val)) / &
(2501.0d0 + Cp_wv * T_db - 4.186d0 * T_wb_val)
end function calculate_w_from_twb
! Numerical Bisection solver for wet-bulb temperature
subroutine solve_twb(T_db, P_bar, w_act, T_dp_val, T_wb_res)
double precision, intent(in) :: T_db, P_bar, w_act, T_dp_val
double precision, intent(out) :: T_wb_res
double precision :: t_low, t_high, t_m, w_m
integer :: iter
t_low = T_dp_val
t_high = T_db
! Check if already saturated or bounds close
if (abs(t_high - t_low) < 1.0d-4) then
T_wb_res = T_db
return
end if
do iter = 1, 80
t_m = 0.5d0 * (t_low + t_high)
w_m = calculate_w_from_twb(T_db, P_bar, t_m)
if (w_m > w_act) then
t_high = t_m
else
t_low = t_m
end if
if (abs(t_high - t_low) < 1.0d-5) exit
end do
T_wb_res = 0.5d0 * (t_low + t_high)
end subroutine solve_twb
end program psychrometrics
💻 How to Compile & Run Locally
1. Compilation (GNU Fortran / Intel oneAPI):
gfortran -O3 psychrometrics.f90 -o psychro_calc
2. Execution with input.txt redirection:
psychro_calc < input.txt
📄 Sample input.txt File Structure
Sample Data:
1 25.0 101.325 50.0
Parameter Description:
Input mode (1=T_db/RH, 2=T_db/T_wb, 3=T_db/T_dp, 4=T_db/W) Dry-Bulb Temperature (Tdb) [°C] Barometric Pressure (P) [kPa] Second Value (RH [%] or Twb [°C] or Tdp [°C] or W [g/kg_da])