def test_floats(value): """Functional test to ensure the validate_datetime() method runs properly on float values.""" ensure_numeric(value, valid_types=[float], nan_acceptable=True, inf_acceptable=True)
def test_nan_inf(): """Tests to ensure ensure_numeric() throws ValueErrors for NaN and infinite values when those parameters are set to `False`.""" with pytest.raises(ValueError): # Test for NaN values assert ensure_numeric(nan, valid_types=[int, float], nan_acceptable=False) with pytest.raises(ValueError): # Test for infinite values assert ensure_numeric(inf, valid_types=[int, float], inf_acceptable=False)
def calculate_declination_degrees( B_degrees: Union[int, float, Iterable[Union[int, float]]] ) -> Union[float, Iterable[float]]: """ The declination is the angular position of the sun at solar noon with respect to the plane of the equator (north is positive). The declination angle must be between -23.45 and 23.45 degrees. The equation is from Spencer (1971). The equation used is from Duffie & Beckman (2006) Equation 1.6.1b. :param B_degrees: A numeric value (generally a float) which is calculated based on the day of the year, in units of degrees. :returns: A float value representing the declination angle of the sun. """ # Type-check `B_degrees` ensure_numeric( B_degrees, valid_types=[int, float, np.number], nan_acceptable=False, inf_acceptable=False, ) # Range-check `B_degrees` and `G_sc` validate_numeric_value( B_degrees, minimum=calculate_B_degrees(1), maximum=calculate_B_degrees(366), ) # Convert `B_degrees` to radians for use in the calculation B_radians = np.radians(B_degrees) declination_degrees = (180.0 / np.pi * (0.006918 - (0.399912 * np.cos(B_radians)) + (0.070257 * np.sin(B_radians)) - (0.006758 * np.cos(2 * B_radians)) + (0.000907 * np.sin(2 * B_radians)) - (0.002697 * np.cos(3 * B_radians)) + (0.00148 * np.sin(3 * B_radians)))) # Range-check `declination_degrees` before returning validate_numeric_value(declination_degrees, minimum=-23.45, maximum=23.45) return declination_degrees
def calculate_E_min( B_degrees: Union[int, float, Iterable[Union[int, float]]] ) -> Union[float, Iterable[float]]: """ E is the equation of time (in minutes), which is based on the day of the year. The equation is given by Spencer (1971). The equation used is from Duffie & Beckman (2006) Equation 1.5.3. :param B_degrees: A numeric value (generally a float) which is calculated based on the day of the year, in units of degrees. :returns: A float value representing the equation of time for the given `B_degrees`, in units of minutes. """ # Type-check `B_degrees` ensure_numeric( B_degrees, valid_types=[int, float, np.number], nan_acceptable=False, inf_acceptable=False, ) # Range-check `B_degrees` validate_numeric_value( B_degrees, minimum=calculate_B_degrees(1), maximum=calculate_B_degrees(366), ) # Convert `B_degrees` to radians for use in the calculation B_radians = np.radians(B_degrees) return 229.2 * (0.000075 + (0.001868 * np.cos(B_radians)) - (0.032077 * np.sin(B_radians)) - (0.014615 * np.cos(2 * B_radians)) - (0.04089 * np.sin(2 * B_radians)))
def calculate_B_degrees( day_number: Union[int, Iterable[int]]) -> Union[float, Iterable[float]]: """ B is a preliminary value used in calculating the extraterrestrial radiation incident on the plane normal to the radiation on the `day_number` day of the year (G_on), per an equation given by Spencer (1971). The equation used is from Duffie & Beckman (2006) Equation 1.4.2. :param day_number: An integer representing the day number (of the year) of a specific date. For example, January 1 corresponds to day number 1, and December 31 corresponds to day number 365 (or 366, if a leap year). :returns: A float value, in units of degrees. """ # Ensure `day_number` is an integer ensure_numeric( day_number, valid_types=[int, np.number], nan_acceptable=False, inf_acceptable=False, ) # Ensure `day_number` is in the proper range validate_numeric_value(day_number, minimum=1, maximum=366) try: return (day_number - 1) * 360.0 / 365.0 except TypeError: # When `day_number` is an iterable, but not a numpy array return (np.array(day_number) - 1) * 360.0 / 365
def test_iterable(): """Functional test to ensure the validate_datetime() method runs properly on iterables.""" ensure_numeric([1, 2, 3], valid_types=[int], nan_acceptable=True, inf_acceptable=True) ensure_numeric( [1.2, -2.4, 3.7, inf], valid_types=[float], nan_acceptable=True, inf_acceptable=True, ) ensure_numeric( [1, 2.5, inf, nan], valid_types=[int, float], nan_acceptable=True, inf_acceptable=True, )
def test_invalid_types(): """Tests to ensure ensure_numeric() throws TypeErrors for invalid types.""" with pytest.raises(TypeError): # Test for strings assert ensure_numeric("blah", valid_types=[int, float])
def test_integers(value): """Functional test to ensure the validate_datetime() method runs properly on integer values.""" ensure_numeric(value, valid_types=[int])
Equation 1.4.1b. :param B_degrees: A numeric value (generally a float) which is calculated based on the day of the year, in units of degrees. :param G_sc: The extraterrestrial solar radiation, assumed to be 1,367 W/m2 by default. :returns: A float value corresponding to `G_on` in units of W/m2. """ # Type-check `B_degrees` and `G_sc` ensure_numeric( B_degrees, valid_types=[int, float, np.number], nan_acceptable=False, inf_acceptable=False, ) ensure_numeric( G_sc, valid_types=[int, float, np.number], nan_acceptable=False, inf_acceptable=False, ) # Range-check `B_degrees` and `G_sc` validate_numeric_value( B_degrees, minimum=calculate_B_degrees(1), maximum=calculate_B_degrees(366), )