# # 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; }