DEGREE-DAY CALCULATION FORMULAS

INTRODUCTION
At this time the USPEST.ORG IPM models - Weather Data website supports these types of degree-day calculations:
  1. [A] Simple Average (now w/horizontal upper threshold cutoff)
  2. [GD] Growing Degree Days (corn GDDs)
  3. [T1,T2] Single and Double Triangle (Sevacherian et al. 1977, J. Econ. Entomol. 70:399-402)
  4. [S1,S2] Single and Double Sine Curve (Baskerville & Emin 1969, Ecology 50:514-517)
  5. [I1,I2] Single and Double Sine Curve w/intermediate upper threshold cutoff (Roltsch et al 1999, Int J Biometeorol 42:169-176)
  6. [DH] Fire Blight Degree-Hours (fireblight model only; Smith 2010)
  7. [HD] Heating Degree-Days (power industry) (can be used as insect chilling units)
  8. [CD] Cooling Degree-Days (power industry)
  9. [WG] Bauer wheat model GDDs (Bauer et al. 1983 & 1984)
  10. [PD] Potato P-Days (used for potato early blight model)
  11. [XD] Max Temp only Heat Units (added for mountain pine beetle model)
  12. [XI] Max Temp only w/intermed. cutoff (Perry & Wehner 1996)
Below you will find the actual formulas used to calculate each of these. The formulas are written in Perl, but should be legible to anyone with a working understanding of any major programming language (e. g. C, Pascal, Fortran, BASIC, etc.)
Contact Len Coop at coopl@bcc.orst.edu or 541-737-5523 if you have questions or have a need for some other calculation method.

#
# These are the formulas used to calculate heat units:
# Note: single and double Triangle and Sine methods assume you run twice; 
# For "double" run once using $min from this morning and once using $min from tomorrow 
#   morning (then add them together)
# For "single" run twice using $min from this morning (then add them together)
sub docalcs1 { # SINGLE AND DOUBLE TRIANGLE METHODS
    local($max, $min) = @_;
    if (($min > $THI) && ($max > $THI)) {
        $ddtmp = ($THI - $TLOW) / 2;
    }
    elsif (($max < $TLOW) && ($min < $TLOW)) {
        $ddtmp = 0.0;
    }
    elsif (($min >= $TLOW) && ($max <= $THI)) {
        $ddtmp = 6 * (($max + $min) - 2 * $TLOW) / 24;
    }
    elsif (($min < $TLOW) && ($max >= $TLOW)) {
        $ddtmp = ((6 * ($max - $TLOW) ** 2) / ($max - $min)) / 24;
    }
    elsif (($min >= $TLOW) && ($max >= $THI)) {
        $ddtmp = 6 * ($max + $min - 2 * $TLOW) / 24 - (6 * ($max - $THI) ** 2
          / ($max - $min)) / 24;
    }
    elsif (($min < $TLOW) && ($max >= $THI)) {
        $ddtmp = (6 * ($max - $TLOW) ** 2 / ($max - $min) - 6 * ($max - $THI)
          ** 2 / ($max - $min)) / 24;
    }
    else {
        $ddtmp = -999.99;
    }
    $ddtmp;
}

sub sinec { # SUBROUTINE USED BY THE SINE CURVE METHODS
    local($sum, $diff, $fk1) = @_;
    $twopi = 6.2834;
    $pihlf = 1.5708;
    $d2 = $fk1 - $sum;
    $theta = atan2($d2, sqrt($diff * $diff - $d2 * $d2));
    if (($d2 < 0) && ($theta > 0)) {
        $theta = $theta - 3.1416;
    }
    $heat = ($diff * cos($theta) - $d2 * ($pihlf - $theta)) / $twopi;
    $heat;
}

sub docalcs2 { # SINGLE AND DOUBLE SINE CURVE METHODS
    local($max, $min) = @_;
    if ($min > $THI) {
        $heat = $THI - $TLOW;
    }
    else {
        if ($max <= $TLOW) {
            $heat = 0;
        }
        else {
            $fk1 = 2 * $TLOW;
            $diff = $max - $min;
            $sum = $max + $min;
            if ($min >= $TLOW) {
                $heat = ($sum - $fk1) / 2;
            }
            else {
                $heat = &sinec($sum, $diff, $fk1);
            }
            if ($max > $THI) {
                $fk1 = 2 * $THI;
                $zheat = $heat;
                $heat = &sinec($sum, $diff, $fk1);
                $heat = $zheat - $heat;
            }
        }
    }
    $ddtmp = $heat / 2;
    $ddtmp;
}

sub docalcs3 {  # SIMPLE AVERAGE METHOD - also called
                # growing degree-days for cereals and several
                # other crop growth models
                # more cases to handle ADDED MAY 2015 LC
                # 1. min > $THI (make this DD=0
                # 2. max > $THI (handle this w/horiz cutoff like with growing DDs)
    local($max, $min) = @_;
    if (($max < $TLOW) && ($min < $TLOW)) {
        $ddtmp = 0.0;
    }
    elsif ( ( $min > $THI ) && ( $max > $THI ) ) {
      $ddtmp = 0.0;
    }
    else { 
       if ($max > $THI) {
          $max = $THI;
          }
        $ddtmp = ($max + $min) / 2 - $TLOW;
    }
    if ($ddtmp < 0) {
        $ddtmp = 0.0;
    }
    $ddtmp;
}

sub docalcs4 { # CORN GROWING DEGREE-DAYS
    local($max, $min) = @_;
    if (($max < $TLOW) && ($min < $TLOW)) {
        $ddtmp = 0.0;
    }
    else {
        if ($min < $TLOW) {
            $min = $TLOW;
        }
        if ($max > $THI) {
            $max = $THI;
        }
        $ddtmp = ($max + $min) / 2 - $TLOW;
        if ($ddtmp < 0) {
            $ddtmp = 0.0;
        }
    }
    $ddtmp;
}

sub docalcs55 { # DEGREE-HOURS used by the OLD Fireblight model
    local($max, $min) = @_;
    $max = int($max + 0.5);
    if ($max < $TLOW) {
        $ddtmp = 0.0;
    }
    elsif ($min < 50) {
        $ddtmp = $entry{$max, 1};
    }
    else {
        $ddtmp = $entry{$max, 2};
    }
    $ddtmp;
}

sub docalcs5 {    # DEGREE-HOURS used by the 2010EZ Fireblight model
 # uses file fblookup.txt as a lookup table
  local ( $max, $min ) = @_;
  $max = int( $max + 0.5 );
  if ( $max < 50 || $max > 102) {
    $ddtmp = 0.0;
  }
  else {
    $ddtmp = $entry{ $max, 1 };
  }
  $ddtmp;
}

sub docalcs6 { # HEATING DEGREE_DAYS used by heating and cooling
               # industries - normally 65 is the TLOW with no
               # THI
    local($max, $min) = @_;
    $ddtmp = $TLOW - (($max + $min)/2);
    if ($ddtmp < 0) {
        $ddtmp = 0.0;
    }
    $ddtmp;
}

sub docalcs7 { # COOLING DEGREE-DAYS used by heating and cooling
               # industries - normally 65 is the TLOW with no
               # THI
    local($max, $min) = @_;
    $ddtmp = (($max + $min)/2) - $TLOW;
    if ($ddtmp < 0) {
        $ddtmp = 0.0;
    }
    $ddtmp;
}

sub docalcs8
{    # P-DAYS used for potato growth and early blight treatment initiation
      # added Dec 2010
      # this is the daily approx version of equation 2 by Sands
  local ( $max, $min ) = @_;
  local ( $dp1, $dp2, $dp3, $dp4 ) = 0;
  if ( $CELSIUS != 1 ) {
    $cmax = ( $max - 32 ) * 5 / 9;
    $cmin = ( $min - 32 ) * 5 / 9;

    #$cmax = $max;
    #$cmin = $min;
  }
  else {
    $cmax = $max;
    $cmin = $min;
  }
  $dp1 = &dp($cmin);
  $dp2 = &dp( 0.66667 * $cmin + 0.333333 * $cmax );
  $dp3 = &dp( 0.66667 * $cmax + 0.333333 * $cmin );
  $dp4 = &dp($cmax);

  #$ddtmp = 1.8/24 * (5*$dp1 + 8*$dp2 + 8*$dp3 + 3*$dp4);
  $ddtmp = 1 / 24 * ( 5 * $dp1 + 8 * $dp2 + 8 * $dp3 + 3 * $dp4 );
  $ddtmp;
}


sub dp {    #estimate delta-p with $t temperature
  local ($t) = @_;
  local $dp = 0;

  #local ($ta,$tb,$tc) = (7,21,30);
  if ( $t < 7 || $t > 30 ) { $dp = 0.0 }
  elsif ( ( $t >= 7 ) && ( $t < 21 ) ) {
    $dp = 10 * ( 1 - ( $t - 21 )**2 / 196 );
  }
  elsif ( ( $t >= 21 ) && ( $t <= 30 ) ) {
    $dp = 10 * ( 1 - ( $t - 21 )**2 / 81 );
  }
  if ( $dp < 0 ) { $dp = 0 }
  $dp;
}

sub docalcs9 {    # Exceed Tmax Heat Units w/upper horiz cutoff
      # e.g. tmax=54  TLOW=50 THI=100 result=4
      # e.g. tmax=104 TLOW=50 THI=100 result=50
      # added for mountain pine beetle, should be useful
      # as an insect adult activity threshold model
  local ( $max, $min ) = @_;
  if ( $max > $THI ) {
    $max = $THI;
  }
  $ddtmp =  $max - $TLOW;
  if ( $ddtmp < 0 ) {
    $ddtmp = 0.0;
  }
  $ddtmp;
}

sub docalcs_XI {  # MAX TEMP W/INTERMED UPPER CUTOFF METHOD - added MAY 2015
      # as per Perry & Wehner 1996 HortTechnology Jan/Mar 1996 27:30
      # other crop growth models:
      # ignore $min and
      # if max > $THI subt. diff betw $max and $THI as a "heat penalty"
  local ( $max, $min ) = @_;
  if ( $max < $TLOW ) {
    $ddtmp = 0.0;
  }
  elsif ($max > $THI) {
      $ddtmp = ( $THI - ( $max - $THI )) - $TLOW;
  }
  else { # more cases to handle ADDED MAY 2015 Len
    $ddtmp = $max - $TLOW;
  }
  if ( $ddtmp < 0 ) {
    $ddtmp = 0.0;
  }

  $ddtmp;
}


sub docalcs10 {    # WHEAT (Bauer model) GROWING DEGREE-DAYS
   # TLOW =32
   #    # use TMAX=70 if prior to 2nd Leaf Stage ( < 215 DD )
   #       # use TMAX=95 if not prior to 2nd Leaf Stage ( >= 215 DD )
   my $l_THI = 95;
      if ($CELSIUS == 1) {
        if ($dd_cum < 215*5/9 && $past_biofix == 1) {
          $l_THI = 21;
        }
        elsif ($dd_cum >= 215*5/9 && $past_biofix == 1) {
          $l_THI = 35;
        }
      }

      else { # FAHRENHEIT
        if ($dd_cum < 215 && $past_biofix == 1) {
          $l_THI = 70;
        }
        elsif ($dd_cum >= 215 && $past_biofix == 1) {
          $l_THI = 95;
        }
      }

      local ( $max, $min ) = @_;
      if ( ( $max < $TLOW ) && ( $min < $TLOW ) ) {
         $ddtmp = 0.0;
      }
   else {
    if ( $min < $TLOW ) {
      $min = $TLOW;
    }
    if ( $max > $l_THI ) {
      $max = $l_THI;
    }
    $ddtmp = ( $max + $min ) / 2 - $TLOW;
    if ( $ddtmp < 0 ) {
      $ddtmp = 0.0;
    }
  }
  $ddtmp;
}






Last updated Feb 6, 2023
prep. by L. Coop