Example #1
0
def pet(temperature_celsius: np.ndarray, latitude_degrees: float,
        data_start_year: int) -> np.ndarray:
    """
    This function computes potential evapotranspiration (PET) using
    Thornthwaite's equation.

    :param temperature_celsius: an array of average temperature values,
        in degrees Celsius
    :param latitude_degrees: the latitude of the location, in degrees north,
        must be within range [-90.0 ... 90.0] (inclusive), otherwise a
        ValueError is raised
    :param data_start_year: the initial year of the input dataset
    :return: an array of PET values, of the same size and shape as the input
        temperature values array, in millimeters/time step
    :rtype: 1-D numpy.ndarray of floats
    """

    # make sure we're not dealing with all NaN values
    if np.ma.isMaskedArray(temperature_celsius) and (
            temperature_celsius.count() == 0):

        # we started with all NaNs for the temperature, so just return the same as PET
        return temperature_celsius

    else:

        # we were passed a vanilla Numpy array, look for indices where the value == NaN
        if np.all(np.isnan(temperature_celsius)):

            # we started with all NaNs for the temperature, so just return the same
            return temperature_celsius

    # If we've been passed an array of latitude values then just use
    # the first one -- useful when applying this function with xarray.GroupBy
    # or numpy.apply_along_axis() where we've had to duplicate values in a 3-D
    # array of latitudes in order to correspond with a 3-D array of temperatures.
    if isinstance(latitude_degrees,
                  np.ndarray) and (latitude_degrees.size > 1):
        latitude_degrees = latitude_degrees.flat[0]

    # make sure we're not dealing with a NaN or out-of-range latitude value
    if ((latitude_degrees is not None) and not np.isnan(latitude_degrees)
            and (latitude_degrees < 90.0) and (latitude_degrees > -90.0)):

        # compute and return the PET values using Thornthwaite's equation
        return eto.eto_thornthwaite(
            temperature_celsius,
            latitude_degrees,
            data_start_year,
        )

    else:
        message = ("Invalid latitude value: " + str(latitude_degrees) +
                   " (must be in degrees north, between -90.0 and " +
                   "90.0 inclusive)")
        _logger.error(message)
        raise ValueError(message)
Example #2
0
def test_eto_thornthwaite(temps_celsius,
                          latitude_degrees,
                          data_year_start_monthly,
                          pet_thornthwaite_mm):

    # compute PET from the monthly temperatures, latitude, and initial years
    computed_pet = eto.eto_thornthwaite(temps_celsius, latitude_degrees, data_year_start_monthly
                                        )

    # make sure PET is being computed as expected
    np.testing.assert_allclose(computed_pet,
                               pet_thornthwaite_mm.flatten(),
                               atol=0.001,
                               equal_nan=True,
                               err_msg="PET (Thornthwaite) values not computed as expected")

    # make sure that a 3-D array raises an error
    reshaped_temps = np.reshape(temps_celsius[0:1400], (123, 2, 6))
    pytest.raises(ValueError,
                  eto.eto_thornthwaite,
                  reshaped_temps,
                  latitude_degrees,
                  data_year_start_monthly)

    # make sure that an invalid latitude value (lat > 90) raises an error
    pytest.raises(ValueError,
                  eto.eto_thornthwaite,
                  temps_celsius,
                  91.0,  # latitude > 90 is invalid
                  data_year_start_monthly)

    # make sure that an invalid latitude value (lat < -90) raises an error
    pytest.raises(ValueError,
                  eto.eto_thornthwaite,
                  temps_celsius,
                  -91.0,  # latitude < -90 is invalid
                  data_year_start_monthly)

    # make sure that an invalid latitude value (None) raises an error
    pytest.raises(TypeError,
                  eto.eto_thornthwaite,
                  temps_celsius,
                  None,
                  data_year_start_monthly)

    # make sure that an invalid latitude value (NaN) raises an error
    pytest.raises(ValueError,
                  eto.eto_thornthwaite,
                  temps_celsius,
                  np.NaN,
                  data_year_start_monthly)