Utilities functions#
Body Surface Area#
The body surface area (BSA) is the measured or calculated surface of a human body. It is used as a reference for the estimation of the metabolic rate of an individual. The BSA is usually measured in square meters. The most common formula to calculate the BSA is the Du Bois formula, which is based on the height and weight of the individual. All the equations implemented in pythermalcomfort are contained in pythermalcomfort.utilities.BodySurfaceAreaEquations
- pythermalcomfort.utilities.body_surface_area(weight, height, formula='dubois')[source]#
Calculate the body surface area (BSA) in square meters.
- Parameters:
weight (float) – Body weight in kilograms.
height (float) – Body height in meters.
formula (str, optional) – Formula used to calculate the body surface area. Default is “dubois”. Choose one from BodySurfaceAreaEquations.
- Returns:
float – Body surface area in square meters.
- Raises:
ValueError – If the specified formula is not recognized.
Examples
Calculate BSA using the DuBois formula:
bsa = body_surface_area(weight=70, height=1.75, formula="dubois") print(bsa)
Dew point temperature#
- pythermalcomfort.utilities.dew_point_tmp(tdb, rh)[source]#
Calculate the dew point temperature.
The equation use the Magnus formula using the coefficients from the 2024 edition of the Guide to Instruments and Methods of Observation. [WMO2024].
- Parameters:
tdb (float or list of floats) – Dry bulb air temperature, [°C]
rh (float or list of floats) – Relative humidity, [%]
- Returns:
dew_point_tmp (ndarray) – Dew point temperature, [°C]
- Raises:
ValueError – If relative humidity is outside the range [0, 100]%.
Examples
>>> from pythermalcomfort.utilities import dew_point_tmp >>> tdb = 25.0 # dry bulb temperature in °C >>> rh = 60.0 # relative humidity in % >>> t_d = dew_point_tmp(tdb, rh)
Enthalpy#
Mean radiant temperature#
- pythermalcomfort.utilities.mean_radiant_tmp(tg, tdb, v, d=0.15, emissivity=0.95, standard='Mixed Convection')[source]#
Convert the globe temperature reading into mean radiant temperature in accordance with either the Mixed Convection developed by Teitelbaum E. et al. (2022) or the ISO 7726:1998 Standard [7726ISO1998].
- Parameters:
tg (float or list of floats) – globe temperature, [°C]
tdb (float or list of floats) – air temperature, [°C]
v (float or list of floats) – air speed, [m/s]
d (float or list of floats) – diameter of the globe, [m] default 0.15 m
emissivity (float or list of floats) – emissivity of the globe temperature sensor, default 0.95
standard (str, optional) – Supported values are ‘Mixed Convection’ and ‘ISO’. Defaults to ‘Mixed Convection’. either choose between the Mixed Convection and ISO formulations. The Mixed Convection formulation has been proposed by Teitelbaum E. et al. (2022) to better determine the free and forced convection coefficient used in the calculation of the mean radiant temperature. They also showed that mean radiant temperature measured with ping-pong ball-sized globe thermometers is not reliable due to a stochastic convective bias [Teitelbaum2022]. The Mixed Convection model has only been validated for globe sensors with a diameter between 0.04 and 0.15 m.
- Returns:
tr (float or list of floats) – mean radiant temperature, [°C]
- Raises:
ValueError – If the standard is not recognized. Please choose either ‘Mixed Convection’ or ‘ISO’.
Examples
from pythermalcomfort.utilities import mean_radiant_tmp tg = 53.2 # globe temperature in °C tdb = 30.0 # dry bulb temperature in °C v = 0.3 # air speed in m/s d = 0.1 # diameter of the globe in m tr = mean_radiant_tmp(tg, tdb, v, d, standard="ISO") print(tr) # 74.8
Operative temperature#
- pythermalcomfort.utilities.operative_tmp(tdb, tr, v, standard='ISO')[source]#
Calculate the operative temperature in accordance with ISO 7726:1998 [7726ISO1998].
- Parameters:
tdb (float or list of floats) – air temperature, [°C]
tr (float or list of floats) – mean radiant temperature, [°C]
v (float or list of floats) – air speed, [m/s]
standard (str (default=”ISO”)) – either choose between ISO and ASHRAE
- Returns:
to (float) – operative temperature, [°C]
Psychrometric properties of air from dry-bulb temperature and relative humidity#
- pythermalcomfort.utilities.psy_ta_rh(tdb, rh, p_atm=101325)[source]#
Calculate psychrometric values of air based on dry bulb air temperature and relative humidity.
For more accurate results we recommend the use of the Python package psychrolib.
- Parameters:
tdb (float or list of floats) – air temperature, [°C]
rh (float or list of floats) – relative humidity, [%]
p_atm (float or list of floats) – atmospheric pressure, [Pa]
- Returns:
p_vap (float or list of floats) – partial pressure of water vapor in moist air, [Pa]
hr (float or list of floats) – humidity ratio, [kg water/kg dry air]
wet_bulb_tmp (float or list of floats) – wet bulb temperature, [°C]
dew_point_tmp (float or list of floats) – dew point temperature, [°C]
h (float or list of floats) – enthalpy_air [J/kg dry air]
Relative air speed#
- pythermalcomfort.utilities.v_relative(v, met)[source]#
Estimates the relative air speed which combines the average air speed of the space plus the relative air speed caused by the body movement. The same equation is used in the ASHRAE 55:2023 and ISO 7730:2005 standards.
- Parameters:
v (float or list of floats) – air speed measured by the sensor, [m/s]
met (float or list of floats) – metabolic rate, [met]
- Returns:
vr (float or list of floats) – relative air speed, [m/s]
Running mean outdoor temperature#
- pythermalcomfort.utilities.running_mean_outdoor_temperature(temp_array, alpha=0.8, units='SI')[source]#
Estimate the running mean temperature also known as prevailing mean outdoor temperature.
- Parameters:
temp_array (list) – array containing the mean daily temperature in descending order (i.e. from newest/yesterday to oldest) \([t_{day-1}, t_{day-2}, ... , t_{day-n}]\). Where \(t_{day-1}\) is yesterday’s daily mean temperature. The EN 16798-1 2019 [16798EN2019] states that n should be equal to 7
alpha (float) – constant between 0 and 1. The EN 16798-1 2019 [16798EN2019] recommends a value of 0.8, while the ASHRAE 55 2020 recommends to choose values between 0.9 and 0.6, corresponding to a slow- and fast- response running mean, respectively. Adaptive comfort theory suggests that a slow-response running mean (alpha = 0.9) could be more appropriate for climates in which synoptic-scale (day-to- day) temperature dynamics are relatively minor, such as the humid tropics.
units (str default=”SI”) – select the SI (International System of Units) or the IP (Imperial Units) system.
- Returns:
t_rm (float) – running mean outdoor temperature
Examples
from pythermalcomfort.utilities import running_mean_outdoor_temperature temp_array = [ 22.0, 20.5, 19.0, 21.0, 18.5, 17.0, 16.5, ] # daily mean temperatures t_rm = running_mean_outdoor_temperature(temp_array, alpha=0.8, units="SI") # Calculate the mean radiant temperature using the previous 7 days from an array of daily mean temperatures temp_array = [ 22.0, 20.5, 19.0, 21.0, 18.5, 17.0, 16.5, 15.0, 14.5, ] # daily mean temperatures days_to_consider = 7 results = [] for i in range(len(temp_array) - days_to_consider + 1): subset = temp_array[i : i + days_to_consider] print(f"Subset for days {i + 1} to {i + days_to_consider}: {subset}") t_rm = running_mean_outdoor_temperature(subset, alpha=0.8, units="SI") print(f"Days {i + 1} to {i + days_to_consider}: t_rm = {t_rm}") results.append(t_rm)
Calculate the running mean outdoor temperature from hourly data:
import pandas as pd import numpy as np from pythermalcomfort.utilities import running_mean_outdoor_temperature # Step 1: Create a DataFrame with hourly dry bulb temperature (tdb) data # for 10 days starting from January 1, 2025. We simulate hourly data with # a base temperature of 20°C plus sinusoidal daily variation and some noise. start_date = pd.Timestamp("2025-01-01") hourly_index = pd.date_range(start=start_date, periods=10 * 24, freq="h") # Simulate tdb with daily cycle: 20°C base + 10°C amplitude sinusoidal + noise t_out_hourly = ( 20 + 10 * np.sin(2 * np.pi * (hourly_index.hour / 24)) + np.random.normal(0, 2, len(hourly_index)) ) df = pd.DataFrame({"t_out": t_out_hourly}, index=hourly_index) # Step 2: Resample the hourly data to daily mean temperatures # This gives us the average temperature for each day. df_daily = df.resample("D").mean() # Step 3: Calculate the running mean outdoor temperature for each day # using the previous 7 days' daily means. The function requires the array # in descending order (newest to oldest). For the first 6 days, there is # insufficient data (less than 7 days), so they remain NaN. df_daily["running_mean"] = np.nan for i in range(7, len(df_daily)): # Get the previous 7 days' means (from i-7 to i-1), reverse to newest first prev_7_days = df_daily["t_out"].iloc[i - 7 : i].values[::-1] # Calculate the running mean and assign to the current day df_daily.loc[df_daily.index[i], "running_mean"] = ( running_mean_outdoor_temperature( prev_7_days.tolist(), alpha=0.8, units="SI" ) ) df["date"] = df.index.date df_daily["date"] = df_daily.index.date df.reset_index().merge( df_daily[["date", "running_mean"]], on="date", how="left" ).set_index("index").drop(columns=["date"])
Saturation vapor pressure#
Sky-vault view fraction#
- pythermalcomfort.utilities.f_svv(w, h, d)[source]#
Calculate the sky-vault view fraction.
- Parameters:
w (float) – width of the window, [m]
h (float) – height of the window, [m]
d (float) – distance between the occupant and the window, [m]
- Returns:
f_svv (float) – sky-vault view fraction ranges between 0 and 1
Units converter#
Wet bulb temperature#
- pythermalcomfort.utilities.wet_bulb_tmp(tdb, rh)[source]#
Calculate the wet-bulb temperature using the Stull equation [Stull2011].
- Parameters:
tdb (float or list of floats) – air temperature, [°C]
rh (float or list of floats) – relative humidity, [%]
- Returns:
tdb (float or list of floats) – wet-bulb temperature, [°C]
Utils functions#
Scale wind speed#
- pythermalcomfort.utils.scale_wind_speed_log(v_z1, z2, z1=10.0, z0=0.01, d=0.0, round_output=True)[source]#
Scale wind speed from the reference height to a user specified height using the logarithmic wind profile based on surface roughness length [Oke1987].
The logarithmic wind profile is a semi-empirical relationship that describes how wind speed changes with height above the ground in the surface layer of the atmosphere. This equation assumes neutral atmospheric stability and is valid for heights typically ranging from a few meters to about 100 meters above the ground. It is commonly used in meteorology, wind engineering, and environmental studies to estimate wind speeds at different heights based on a known reference height. The formula is given by:
\[v(h) = v_{ref} \times \frac{\ln((h - d)/z0)}{\ln((h_{ref} - d)/z0)}\]where:
\(v(h)\) is the wind speed at height \(h\)
\(v_{ref}\) is the wind speed at the reference height \(h_{ref}\) (commonly 10 m)
\(h\) is the height at which the wind speed is to be estimated
\(h_{ref}\) is the reference height (10 m)
\(z0\) is the surface roughness length, which characterizes the roughness of the terrain
\(d\) is the zero-plane displacement height, which accounts for flow obstruction by vegetation or buildings
Note
This function assumes neutral atmospheric stability conditions. For non-neutral conditions, more complex models such as the Monin-Obukhov similarity theory should be used. Moreover, this function does not account for obstacles or complex terrain effects which may require computational fluid dynamics (CFD) simulations or measurements.
- Parameters:
v_z1 (float or list of floats) – Wind speed at the reference height z1 (default 10 m), [m/s]
z2 (float or list of floats) – Height at which wind speed needs to be scaled, [m]
z1 (float or list of floats, optional) – Reference height, [m]. Default is 10.0 m.
z0 (float or list of floats, optional) – Surface roughness length, [m]. Default is 0.01 (open terrain). This value accounts for the roughness of the terrain and varies based on land use source [Sharples2023]:
0.005 m: Inland waterbodies (lakes, dams)
0.03 m: Irrigated Pasture (e.g., grassland, alfalfa)
0.1 m: Irrigated cropping (e.g., wheat, soybeans)
0.25 m: Irrigated Sugar (e.g., sugarcane, corn)
0.4 m: Towns, villages, agricultural land with many or high hedges, forests and very rough and uneven terrain
0.6 m: Large towns with tall buildings
1.0 m: Urban areas
1.6 m: Large cities with very tall buildings
d (float or list of floats, optional) – Zero-plane displacement height, [m]. Default is 0.0 (no displacement). This value accounts for the height at which the wind speed effectively becomes zero due to obstacles like trees or buildings. Based on [Sharples2023]:
0.0 m: Inland waterbodies (lakes, dams)
0.0 m: Irrigated Pasture (e.g., grassland, alfalfa)
0.5 m: Irrigated cropping (e.g., wheat, soybeans)
0.5 m: Irrigated Sugar (e.g., sugarcane, corn)
0.5 m: Urban areas
round_output (bool, optional) – If True, rounds output value. If False, it does not round it. Defaults to True.
- Returns:
ScaleWindSpeedLog – Dataclass with attribute
v_z2containing the scaled wind speed(s) at the target height z2, [m/s].- Raises:
TypeError – If input parameters are not of valid numeric types
ValueError – If any parameter values violate physical constraints
Examples
# Scale wind speed to 2m height (default open terrain z0=0.01) scale_wind_speed_log(v_z1=5.0, z2=2.0) # Scale wind speed to 2m height over rough terrain scale_wind_speed_log(v_z1=5.0, z2=2.0, z0=0.1) # Scale multiple wind speeds to different heights scale_wind_speed_log(v_z1=[3.0, 5.0], z2=[1.5, 2.5]) # Scale with different surface roughness for each measurement scale_wind_speed_log(v_z1=[3.0, 5.0], z2=[1.5, 2.5], z0=[0.02, 0.1])