t🎂rtchens-welt.

Cooling and heating degree days with CDO

Recently at work, I had to calculate cooling and heating degree days per annum for future climate projections. Eurostat provides both metrics only for the past. I found a convenient option to calculate both using a bash script and CDO for flexible base/threshold temperatures. This post presents my solution without any further ado.

Heating degree days for a certain day are defined as HDD(i) = b - t(i) if t(i) < b, where b is the base temperature and t(i) is the temperature at the selected date. Cooling degree days are defined as CDD(i) = t(i) - b if t(i) > b. You may sum both to the required timescale, e.g., monthly, seasonal, or yearly. The bash script below is commented to explain the relevant steps.

K=273.15

# Calculates annual Heating Degree Days (HDD)
# $1 Base temperature in Celsius
# $2 Temperature data in Kelvin (K)
# $3 Name of the output
function hdd {
  local threshold=${1-}
  local file=${2-}
  local path=${3:-}

  # HDD(t, x) = threshold - file(t, x) if file(t, x) < threshold
  # -yearsum := Calculate yearly sum of HDDs
  # -addc,"$threshold" -mulc,-1 := threshold - file(t, x) = threshold + (-1 * file(t, x))
  # -setvrange,"$(bc <<<"-1 * $K"),$threshold" := if file(t, x) < threshold; set each value smaller than absolute zero
  # OR greater than threshold to missing
  # -subc,"$K" := Convert Kelvin to Celsius
  echo "HDD... $file to $path"
  cdo \
    --timestat_date first \
    -yearsum \
    -addc,"$threshold" -mulc,-1 \
    -setvrange,"$(bc <<<"-1 * $K"),$threshold" \
    -subc,"$K" \
    "$file" "$path" >/dev/null 2>&1
}

# Calculates annual Cooling Degree Days (HDD)
# $1 Base temperature in Celsius
# $2 Temperature data in Kelvin (K)
# $3 Name of the output
function cdd {
  local threshold=${1-}
  local file=${2-}
  local path=${3:-}
 
  # CDD(t, x) = file(t, x) - threshold if file(t, x) > threshold
  # -yearsum := Calculate yearly sum of CDDs
  # -subc,"$threshold" := file(t, x) - threshold
  # -setrtomiss,"$(bc <<<"-1 * $K"),$threshold" := if file(t, x) > threshold; set each value smaller than threshold
  # AND greater than absolute zero to missing
  # -subc,"$K" := Convert Kelvin to Celsius
  echo "CDD... $file to $path"
  cdo \
    --timestat_date first \
    -yearsum \
    -subc,"$threshold" \
    -setrtomiss,"$(bc <<<"-1 * $K"),$threshold" \
    -subc,"$K" \
    "$file" "$path" >/dev/null 2>&1
}

In my case, I use daily mean temperatures from the EURO-CORDEX dataset provided for download by the climate data store, a base temperature of 15℃ for HDDs, and 21℃ for CDDs.