-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Add analytical azimuth method to solarposition.py. #349
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
52cfb3b
5395164
4e56576
c0698d4
e3c7530
9c2b89b
b6d6fb9
d1b38b5
2c346c4
3728f15
31bf30d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -420,3 +420,40 @@ def test_analytical_zenith(): | |
zenith_2 = solarposition.solar_zenith_analytical(lat_rad, hour_angle, decl) | ||
assert np.allclose(zenith_1, solar_zenith, atol=0.015) | ||
assert np.allclose(zenith_2, solar_zenith, atol=0.025) | ||
|
||
|
||
def test_analytical_azimuth(): | ||
times = pd.DatetimeIndex(start="1/1/2015 0:00", end="12/31/2015 23:00", | ||
freq="H").tz_localize('Etc/GMT+8') | ||
lat, lon = 37.8, -122.25 | ||
lat_rad = np.deg2rad(lat) | ||
output = solarposition.spa_python(times, lat, lon, 100) | ||
solar_azimuth = np.deg2rad(output['azimuth']) # spa | ||
# spencer | ||
eot = solarposition.equation_of_time_spencer71(times.dayofyear) | ||
hour_angle = np.deg2rad(solarposition.hour_angle(times, lon, eot)) | ||
decl = solarposition.declination_spencer71(times.dayofyear) | ||
zenith = solarposition.solar_zenith_analytical(lat_rad, hour_angle, decl) | ||
azimuth_1 = solarposition.solar_azimuth_analytical(lat_rad, hour_angle, | ||
decl, zenith) | ||
# pvcdrom and cooper | ||
eot = solarposition.equation_of_time_pvcdrom(times.dayofyear) | ||
hour_angle = np.deg2rad(solarposition.hour_angle(times, lon, eot)) | ||
decl = solarposition.declination_cooper69(times.dayofyear) | ||
zenith = solarposition.solar_zenith_analytical(lat_rad, hour_angle, decl) | ||
azimuth_2 = solarposition.solar_azimuth_analytical(lat_rad, hour_angle, | ||
decl, zenith) | ||
for idx, a in enumerate(azimuth_1): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you add some comments as to why you've structured the for loop and the assert statements this way? Please also replace There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure. The analytical azimuth formula is quite accurate in every direction, with an error or 1-2 degrees, except when the sun is in the north. So I separated those cases out through the for loops and if statements and gave them different |
||
if a < 0.7: | ||
assert np.allclose(a, solar_azimuth[idx], atol=0.025) or \ | ||
np.allclose(a + np.pi * 2, solar_azimuth[idx], atol=0.55) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In case a system in the Southern hemisphere is analyzed, the sun will be in the North during the day. Shouldn't the code also be able to correctly handle this case? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks @trichrt for pointing it out. The analytical formula actually takes care of it inherently. When in the Southern hemisphere, the calculation is less accurate when the sun is in the south during midnight. The current test is for a Northern hemisphere location. I can put together a test for Southern hemisphere if desired. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In that case we should restrict the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed. The discrepancies start to appear within a 30-degree range around 0/360, i.e. from 345 to 15 degree. Have updated the azimuth threshold in the latest commit. |
||
else: | ||
assert np.allclose(a, solar_azimuth[idx], atol=0.025) | ||
|
||
for idx, a in enumerate(azimuth_2): | ||
if a < 0.7: | ||
assert np.allclose(a, solar_azimuth[idx], atol=0.025) or \ | ||
np.allclose(a + np.pi * 2, solar_azimuth[idx], atol=0.55) | ||
else: | ||
assert np.allclose(a, solar_azimuth[idx], atol=0.025) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@veronicaguo and @wholmgren sorry for super late review, and just a tiny nitpick, but I don't think
np.abs
is necessary here because according to numpy documentation onnp.arccos
it is only defined from on[0, pi]
Therefore, it will never return a negative number, so no need for absolute value.