Calculate Potential Evapotranspiration (PET)

日本語はこちら(JP)

This chapter calculates potential evapotranspiration (PET) using the Thornthwaite method (Thornthwaite 1948) with the SPEI package (Beguería and Vicente-Serrano 2023).

Monthly equation and parameters

Thornthwaite is a temperature-based empirical method. It uses monthly mean temperature and a latitude-based day-length correction to estimate monthly PET. Precipitation, measured solar radiation, humidity and wind are not inputs. This chapter uses the 1991–2020 monthly climate normals described in the data-preparation chapter.

For month mm, the calculation is

Tm+=max⁡(Tm,0),I=∑j=112(Tj+5)1.514, T_m^+=\max(T_m,0),\qquad I=\sum_{j=1}^{12}\left(\frac{T_j^+}{5}\right)^{1.514},

a=6.75×10−7I3−7.71×10−5I2+1.792×10−2I+0.49239, a=6.75\times10^{-7}I^3-7.71\times10^{-5}I^2 +1.792\times10^{-2}I+0.49239,

PETm=16(Lm12)(dm30)(10Tm+I)a(I>0). PET_m=16\left(\frac{L_m}{12}\right)\left(\frac{d_m}{30}\right) \left(\frac{10T_m^+}{I}\right)^a\quad (I>0).

Symbol Meaning Unit
PETmPET_m Potential evapotranspiration for month mm mm/month (monthly total)
TmT_m, Tm+T_m^+ Monthly mean temperature and its value clipped at zero °C
II Annual heat index, calculated from all 12 monthly temperatures Dimensionless (temperature entered in °C)
aa Exponent calculated from II Dimensionless
LmL_m Astronomical day length approximated at the 15th of the month hours/day
dmd_m Number of days in the month days

The factor 16 gives PET in mm for a standard 30-day month with 12-hour days; Lm/12L_m/12 and dm/30d_m/30 adjust day length and month length. These are the coefficients used by the installed SPEI 1.8.1, rather than locally fitted parameters.

Day-length correction

For the January–December numeric vector used here, SPEI uses dm=(31,28,31,30,31,30,31,31,30,31,30,31)d_m=(31,28,31,30,31,30,31,31,30,31,30,31) and Jm=∑j<mdj+15J_m=\sum_{j<m}d_j+15, the day of year of the 15th of each month:

δm=0.4093sin⁡(2πJm365−1.405),Lm=24πarccos⁡[clip(−tanϕtanδm,−1,1)]. \delta_m=0.4093\sin\left(\frac{2\pi J_m}{365}-1.405\right),\qquad L_m=\frac{24}{\pi}\arccos\!\left[ \operatorname{clip}(-\tan\phi\tan\delta_m,-1,1)\right].

Here ϕ\phi is latitude in radians and δm\delta_m is solar declination in radians; the implementation converts latitude in degrees using division by 57.2957795. The clip operation restricts the argument to [−1,1][-1,1]. Day length is calculated from latitude and date; it is not observed sunshine duration. The calculation follows the SPEI 1.8.1 source.

Assumptions and missing values in this chapter

  • The 12 input temperatures are ordered from January to December. This numeric-vector input assumes a non-leap year; February has 28 days.
  • Negative monthly temperatures are set to zero inside the function. Months at or below 0°C have PET = 0; if all 12 months are at or below 0°C, I=0I=0 and PET is zero throughout the year.
  • Meshes with any missing monthly temperature are excluded before calculation. The function uses its default na.rm = FALSE; omitted meshes remain missing after the join.
  • Annual PET is the sum of the 12 monthly PET values, in mm/year.
  • Applying this nonlinear equation to monthly climate normals does not give exactly the same result as averaging PET calculated for each individual year.
  • PET assumes sufficient water supply. It is not measured forest evapotranspiration, and is distinct from the grass-reference quantity in the FAO-56 Penman–Monteith chapter.

Load libraries

Load data

data_dir <- Sys.getenv("PROJECT_DATA_DIR")
# data_dir <- "data" # if PROJECT_DATA_DIR is not set
sf_climate <- readRDS(file.path(
  data_dir,
  "climate_mesh_data_joined/climate_mesh_data.rds"
))

Create a data frame for PET calculation

After excluding incomplete temperature rows, take latitude from the same filtered mesh table so each temperature vector uses its own mesh’s latitude.

df_temp <- sf_climate[, grep("mean_temperature", names(sf_climate))]
df_temp <- st_drop_geometry(df_temp)
df_temp <- df_temp[, 1:12]

keep <- complete.cases(df_temp)
removed_rows <- which(!keep)

df_temp_clean <- df_temp[keep, ]
sf_climate_clean <- sf_climate[keep, ]
latitudes <- sf_climate_clean$latitude
row.names(df_temp_clean) <- sf_climate_clean$mesh_code_3rd

Calculate PET

n <- nrow(df_temp_clean)
pet_month <- matrix(NA, n, 12)
for (i in seq_len(n)) {
  pet_month[i, ] <- SPEI::thornthwaite(
    Tave = as.numeric(df_temp_clean[i, ]),
    lat = latitudes[i],
    verbose = FALSE
  )
}

Shape PET data

df_pet <- as.data.frame(pet_month)
names(df_pet) <- paste0("PET", 1:12)
df_pet$PET_year <- rowSums(df_pet)

Join PET to climate data

df_pet$mesh_code_3rd <- row.names(df_temp_clean)
sf_merged <- merge(
  sf_climate,
  df_pet,
  by = "mesh_code_3rd",
  all.x = TRUE,
  sort = FALSE
)
df_merged <- st_drop_geometry(sf_merged)

Save data

save_dir <- file.path(data_dir, "climate_mesh_data_joined")
saveRDS(sf_merged, file.path(save_dir, "climate_mesh_data_with_pet.rds"))
write.csv(
  df_merged,
  file.path(save_dir, "climate_mesh_data_with_pet.csv"),
  row.names = FALSE
)

References

Beguería, Santiago, and Sergio M. Vicente-Serrano. 2023. SPEI: Calculation of the Standardized Precipitation-Evapotranspiration Index. https://doi.org/10.32614/CRAN.package.SPEI.
Thornthwaite, C. W. 1948. “An Approach Toward a Rational Classification of Climate.” Geographical Review 38 (1): 55–94. https://doi.org/10.2307/210739.