Drought-PET-Thornthwaite
view release on metacpan or search on metacpan
lib/Drought/PET/Thornthwaite.pm view on Meta::CPAN
=head1 VERSION
Version 0.50
=cut
our $VERSION = '0.50';
=head1 SYNOPSIS
use Drought::PET::Thornthwaite qw(pet_thornthwaite tei_thornthwaite);
=head1 DESCRIPTION
Evapotranspiration is the amount of water removed from the soil due to both evaporation and
vegetative consumption. Factors such as sun angle, temperature, soil type, the amount of
available water, and the types of vegetation all affect the amount of evapotranspiration
that occurs in a given location. The potential evapotranspiration (PET) is defined as the
amount of evapotranspiration that would occur under a defined set of conditions if the amount
of available water in the soil was limitless and accessible. The PET is a component of various
drought and water balance models. Numerous techniques have been developed to calculate
and estimate potential evapotranspiration.
The Drought::PET::Thornthwaite package provides functions that can calculate the PET
based on the Thornthwaite Equation (Thornthwaite 1948). This equation estimates PET based
on the day of year, the latitude of the target location, the temperature observed during
the period for which PET is calculated, and a monthly temperature-based climatological index
specific to the target region. This index is typically called the Thornthwaite heat index,
or the temperature efficiency index. The documentation for this package refers to this index
as the temperature efficiency index (TEI).
=head1 EXPORT
The following functions provided by the Drought::PET::Thornthwaite package
are exportable.
=head2 pet_thornthwaite
my $pet = pet_thornthwaite($yday,$ndays,$lat,$temp,$tei,$missing_val);
Calculate the potential evapotranspiration in millimeters using the Thornthwaite Equation.
Temperatures at or below zero return a zero PET. For temperatures at or above 26.5 degrees,
an adjusted equation described in Huang et al. 1996 is used to estimate the PET, since the
original Thornthwaite Equation becomes increasingly inaccurate at higher temperatures.
This function requires five arguments:
=over 4
=item * C<$yday>: The day of the year (1 - 366). If the PET is calculated for a period of more than one day, supply the midpoint date
=item * C<$ndays>: The number of days in the period over which the PET is calculated, e.g., 7 for a weekly PET. Must be 1 or greater
=item * C<$lat>: The latitude of the location for which the PET is calculated in degrees (must be 0 to 90)
=item * C<$temp>: The average temperature observed during the period in degrees Celsius
=item * C<$tei>: The climatological "temperature efficiency index" defined in Thornthwaite (1948)
An optional sixth argument can be supplied, which would be considered the missing data value.
The default missing value is NaN. If the YDAY, NDAYS, or LAT arguments are non-numeric or
invalid, the pet_thornthwaite function will L<croak|https://perldoc.perl.org/Carp>.
If the TEMP or TEI arguments are undefined, missing, or invalid, the function will return
the missing value.
This function currently only works for Northern Hemisphere locations.
=back
=cut
sub pet_thornthwaite {
# Define a NaN value for later use
my $inf = exp(~0 >> 1);
my $nan = $inf / $inf;
# Make sure the caller supplied sufficient arguments
unless(@_ and @_ >= 5) { croak "Insufficient arguments supplied"; }
# Get the arguments
my $yday = shift;
my $ndays = shift;
my $lat = shift;
my $temperature = shift;
my $tei = shift;
my $missing_val = $nan;
# Replace the default missing value if the caller supplied one
if(@_) { $missing_val = shift; }
# Validate the non-data arguments
if(not looks_like_number($yday)) { croak "YDAY arg must be numeric"; }
$yday = int($yday);
if(not $yday >= 1 or not $yday <= 366) { croak "YDAY arg must be between 1 and 366"; }
if(not looks_like_number($ndays)) { croak "NDAYS arg must be numeric"; }
$ndays = int($ndays);
if(not $ndays >= 1) { croak "NDAYS arg must be 1 or greater"; }
if(not looks_like_number($lat)) { croak "LAT arg must be numeric"; }
if(not $lat >= 0 or not $lat <= 90) { croak "LAT arg must be between 0 and 90"; }
# Return the missing value if the data arguments are missing or invalid
if(
not defined($temperature) or
not defined($tei) or
not looks_like_number($temperature) or
not looks_like_number($tei) or
$temperature == $missing_val or
$tei == $missing_val or
not defined($temperature <=> 0) or
not defined($tei <=> 0)
) { return $missing_val; }
# Calculate the PET!
if($temperature <= 0) { return 0; }
elsif($temperature > 0 and $temperature < 26.5) {
# Calculate the hours of sunlight
my $lat_radians = (pi/180)*$lat;
my $solar_declination = 0.409*sin((2*pi/365)*$yday - 1.39);
my $sunset_angle = acos(-tan($lat_radians)*tan($solar_declination));
my $daylength = (24/pi)*$sunset_angle;
# Calculate alpha term
my $alpha = (6.75e-7)*($tei**3) - (7.71e-5)*($tei**2) + 0.01792*$tei + 0.49239;
# Apply the original Thornthwaite Equation
my $pet_gross = 16*((10*$temperature)/($tei))**$alpha;
return $pet_gross*($daylength/12)*($ndays/30);
}
else {
# Apply the hot temperature formula described in Huang et al. 1996
return (-415.85 + 32.25*$temperature - 0.43*($temperature**2))*($ndays/30);
}
}
=head2 tei_thornthwaite
my $tei = tei_thornthwaite($jan,$feb,$mar,$apr,$may,$jun,$jul,$aug,$sep,$oct,$nov,$dec);
Calculates and returns the temperature efficiency index (TEI, sometimes called the
Thornthwaite heat index) based on a monthly average temperature climatology for a given
location. Since the equation involves a summation of adjusted monthly temperatures, 12
arguments are required, consisting of the average temperature for each calendar month of
the year. An optional 13th argument can also be supplied to define a numeric value
interpreted as missing data. If not supplied, the default missing value is NaN.
The missing value will be returned if any of the temperature values are missing,
undef, or invalid (e.g., non-numeric).
=cut
sub tei_thornthwaite {
# Define a NaN value for later use
my $inf = exp(~0 >> 1);
my $nan = $inf / $inf;
# Make sure the caller supplied sufficient arguments
unless(@_ and @_ >= 12) { croak "Insufficient arguments supplied"; }
# Get the arguments
my @monthly_temperatures;
my $invalid = 0;
for(my $i=0; $i<12; $i++) { push(@monthly_temperatures,shift); }
my $missing_val = $nan;
# Replace the default missing value if the caller supplied one
if(@_) { $missing_val = shift; }
# Calculate the TEI!
my $tei = 0;
for(my $i=0; $i<12; $i++) {
# Return a missing value if any of the monthly temps are missing or invalid
if(
not defined($monthly_temperatures[$i]) or
not looks_like_number($monthly_temperatures[$i]) or
$monthly_temperatures[$i] == $missing_val or
not defined($monthly_temperatures[$i] <=> 0)
) { return $missing_val; }
# Set any monthly mean temp below 0 to 0
$monthly_temperatures[$i] = $monthly_temperatures[$i] > 0 ? $monthly_temperatures[$i] : 0;
$tei += ($monthly_temperatures[$i]/5)**1.514;
}
return $tei;
}
=head1 INSTALLATION
The best way to install this module is with a CPAN client, which will resolve and
install the dependencies:
cpan Drought::PET::Thornthwaite
cpanm Drought::PET::Thornthwaite
You can also install the module directly from the distribution directory after
downloading it and extracting the files, which will also install the dependencies:
cpan .
cpanm .
If you want to install the module manually do the following in the distribution
directory:
perl Makefile.PL
make
make test
make install
=head1 SUPPORT AND DOCUMENTATION
After installing, you can find documentation for this module with the
perldoc command.
( run in 1.240 second using v1.01-cache-2.11-cpan-d80b1682f3f )