Skip to content

Commit

Permalink
Merge pull request #29 from statnett/fix-hour-angle
Browse files Browse the repository at this point in the history
Correct hour angle for longitude
  • Loading branch information
halvorlu authored Jun 3, 2024
2 parents 99b0869 + b88ba0b commit b553036
Show file tree
Hide file tree
Showing 5 changed files with 31 additions and 12 deletions.
5 changes: 5 additions & 0 deletions docs/api/equations/solar_angles.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Solar angles
-------------

.. automodule:: linerate.equations.solar_angles
:members:
2 changes: 1 addition & 1 deletion examples/plot_solar_heating_comparison.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
# ^^^^^^^^^^^^^^^^^^^^^
time = np.datetime64("2022-06-01T13:00")

omega = solar_angles.compute_hour_angle_relative_to_noon(time)
omega = solar_angles.compute_hour_angle_relative_to_noon(time, 0)
delta = solar_angles.compute_solar_declination(time)

vals_with_range = {
Expand Down
14 changes: 10 additions & 4 deletions linerate/equations/solar_angles.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def _get_minute_of_hour(when: Date) -> Unitless:
return (when.astype(MinuteResolutionType) - when.astype(HourResolutionType)).astype(float)


def compute_hour_angle_relative_to_noon(when: Date) -> Radian:
def compute_hour_angle_relative_to_noon(when: Date, longitude: Degrees) -> Radian:
r"""Compute the hour angle.
Described in the text on p. 18 of :cite:p:`ieee738`. The hour angle is the number of hours
Expand All @@ -35,6 +35,9 @@ def compute_hour_angle_relative_to_noon(when: Date) -> Radian:
which is the same as 15^\circ.
The hour angle is used when calculating the solar altitude.
This function does not take into account the difference between apparent/actual
and mean solar time, which means that the result may be up to 15 minutes from the
correct hour angle.
Parameters
----------
Expand All @@ -46,10 +49,13 @@ def compute_hour_angle_relative_to_noon(when: Date) -> Radian:
Union[float, float64, ndarray[Any, dtype[float64]]]
:math:'\omega~\left[\text{radian}\right]`. The hour angle relative to noon.
"""
hour = _get_hour_of_day(when)
minute = _get_minute_of_hour(when)
utc_hour = _get_hour_of_day(when)
utc_minute = _get_minute_of_hour(when)
pi = np.pi
return (-12 + hour + minute / 60) * (pi / 12) # pi/12 is 15 degrees
# We add longitude/15 since 15 degrees of longitude increases solar hour by 1
return np.mod((-12 + utc_hour + utc_minute / 60 + longitude / 15), 24) * (
pi / 12
) # pi/12 is 15 degrees


def compute_solar_declination(
Expand Down
4 changes: 2 additions & 2 deletions linerate/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ def compute_solar_heating(
N_s = self.weather.clearness_ratio
D = self.span.conductor.conductor_diameter

omega = solar_angles.compute_hour_angle_relative_to_noon(self.time)
omega = solar_angles.compute_hour_angle_relative_to_noon(self.time, self.span.longitude)
delta = solar_angles.compute_solar_declination(self.time)
sin_H_s = solar_angles.compute_sin_solar_altitude(phi, delta, omega)
chi = solar_angles.compute_solar_azimuth_variable(phi, delta, omega)
Expand Down Expand Up @@ -491,7 +491,7 @@ def compute_solar_heating(
y = self.span.conductor_altitude # H_e in IEEE
D = self.span.conductor.conductor_diameter # D_0 in IEEE

omega = solar_angles.compute_hour_angle_relative_to_noon(self.time)
omega = solar_angles.compute_hour_angle_relative_to_noon(self.time, self.span.longitude)
delta = solar_angles.compute_solar_declination(self.time)
sin_H_c = solar_angles.compute_sin_solar_altitude(phi, delta, omega)
Q_s = ieee738.solar_heating.compute_total_heat_flux_density(sin_H_c, True)
Expand Down
18 changes: 13 additions & 5 deletions tests/equations/test_solar_angles.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,14 @@ def test_get_minute_of_hour_with_example():
def test_hour_angle_relative_to_noon_with_example():
when = np.datetime64("2022-06-01T12:00")
omega = 0
assert solar_angles.compute_hour_angle_relative_to_noon(when) == approx(omega)
assert solar_angles.compute_hour_angle_relative_to_noon(when, 0) == approx(omega)


def test_hour_angle_relative_to_noon_norway():
when = np.datetime64("2022-12-01T12:00+01:00")
omega = 0
longitude = 15 # Longitude at timezone +01:00
assert solar_angles.compute_hour_angle_relative_to_noon(when, longitude) == approx(omega)


def test_solar_azimuth_variable_with_example():
Expand Down Expand Up @@ -119,12 +126,13 @@ def test_solar_declination_scales_correctly_with_day_of_year(day):
when=st.datetimes(
min_value=datetime.datetime(2022, 1, 1, 1, 0),
max_value=datetime.datetime(2022, 12, 31, 23, 0),
)
),
longitude=st.floats(min_value=-180, max_value=180),
)
def test_solar_declination_scales_with_dates_and_times(when):
omega = (-12 + when.hour + when.minute / 60) * np.pi / 12
def test_solar_declination_scales_with_dates_and_times(when, longitude):
omega = ((-12 + when.hour + when.minute / 60 + longitude / 15) % 24) * np.pi / 12
when = np.datetime64(when)
assert omega == approx(solar_angles.compute_hour_angle_relative_to_noon(when))
assert omega == approx(solar_angles.compute_hour_angle_relative_to_noon(when, longitude))


def test_solar_declination_with_examples():
Expand Down

0 comments on commit b553036

Please sign in to comment.