ArthurY's picture
update source
c3d0544
# ignore_header_test
# climt/LICENSE
# @mcgibbon
# BSD License
# Copyright (c) 2016, Rodrigo Caballero
# All rights reserved.
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice, this
# list of conditions and the following disclaimer in the documentation and/or
# other materials provided with the distribution.
# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# OF THE POSSIBILITY OF SUCH DAMAGE.
import datetime
import numpy as np
import pytz
try:
import nvidia.dali as dali
except ImportError:
raise ImportError(
"DALI dataset requires NVIDIA DALI package to be installed. "
+ "The package can be installed at:\n"
+ "https://docs.nvidia.com/deeplearning/dali/user-guide/docs/installation.html"
)
RAD_PER_DEG = np.pi / 180.0
DATETIME_2000 = datetime.datetime(2000, 1, 1, 12, 0, 0, tzinfo=pytz.utc).timestamp()
def _dali_mod(a, b):
return a - b * dali.math.floor(a / b)
def cos_zenith_angle(
time: dali.types.DALIDataType,
latlon: dali.types.DALIDataType,
):
"""
Dali datapipe for computing Cosine of sun-zenith angle for lon, lat at time (UTC).
Parameters
----------
time : dali.types.DALIDataType
Time in seconds since 2000-01-01 12:00:00 UTC. Shape `(seq_length,)`.
latlon : dali.types.DALIDataType
Latitude and longitude in degrees. Shape `(2, nr_lat, nr_lon)`.
Returns
-------
dali.types.DALIDataType
Cosine of sun-zenith angle. Shape `(seq_length, 1, nr_lat, nr_lon)`.
"""
lat = latlon[dali.newaxis, 0:1, :, :] * RAD_PER_DEG
lon = latlon[dali.newaxis, 1:2, :, :] * RAD_PER_DEG
time = time[:, dali.newaxis, dali.newaxis, dali.newaxis]
return _star_cos_zenith(time, lat, lon)
def _days_from_2000(model_time): # pragma: no cover
"""Get the days since year 2000."""
return (model_time - DATETIME_2000) / (24.0 * 3600.0)
def _greenwich_mean_sidereal_time(model_time):
"""
Greenwich mean sidereal time, in radians.
Reference:
The AIAA 2006 implementation:
http://www.celestrak.com/publications/AIAA/2006-6753/
"""
jul_centuries = _days_from_2000(model_time) / 36525.0
theta = 67310.54841 + jul_centuries * (
876600 * 3600
+ 8640184.812866
+ jul_centuries * (0.093104 - jul_centuries * 6.2 * 10e-6)
)
theta_radians = _dali_mod((theta / 240.0) * RAD_PER_DEG, 2 * np.pi)
return theta_radians
def _local_mean_sidereal_time(model_time, longitude):
"""
Local mean sidereal time. requires longitude in radians.
Ref:
http://www.setileague.org/askdr/lmst.htm
"""
return _greenwich_mean_sidereal_time(model_time) + longitude
def _sun_ecliptic_longitude(model_time):
"""
Ecliptic longitude of the sun.
Reference:
http://www.geoastro.de/elevaz/basics/meeus.htm
"""
julian_centuries = _days_from_2000(model_time) / 36525.0
# mean anomaly calculation
mean_anomaly = (
357.52910
+ 35999.05030 * julian_centuries
- 0.0001559 * julian_centuries * julian_centuries
- 0.00000048 * julian_centuries * julian_centuries * julian_centuries
) * RAD_PER_DEG
# mean longitude
mean_longitude = (
280.46645 + 36000.76983 * julian_centuries + 0.0003032 * (julian_centuries**2)
) * RAD_PER_DEG
d_l = (
(1.914600 - 0.004817 * julian_centuries - 0.000014 * (julian_centuries**2))
* dali.math.sin(mean_anomaly)
+ (0.019993 - 0.000101 * julian_centuries) * dali.math.sin(2 * mean_anomaly)
+ 0.000290 * dali.math.sin(3 * mean_anomaly)
) * RAD_PER_DEG
# true longitude
return mean_longitude + d_l
def _obliquity_star(julian_centuries):
"""
return obliquity of the sun
Use 5th order equation from
https://en.wikipedia.org/wiki/Ecliptic#Obliquity_of_the_ecliptic
"""
return (
23.0
+ 26.0 / 60
+ 21.406 / 3600.0
- (
46.836769 * julian_centuries
- 0.0001831 * (julian_centuries**2)
+ 0.00200340 * (julian_centuries**3)
- 0.576e-6 * (julian_centuries**4)
- 4.34e-8 * (julian_centuries**5)
)
/ 3600.0
) * RAD_PER_DEG
def _right_ascension_declination(model_time):
"""
Right ascension and declination of the sun.
"""
julian_centuries = _days_from_2000(model_time) / 36525.0
eps = _obliquity_star(julian_centuries)
eclon = _sun_ecliptic_longitude(model_time)
x = dali.math.cos(eclon)
y = dali.math.cos(eps) * dali.math.sin(eclon)
z = dali.math.sin(eps) * dali.math.sin(eclon)
r = dali.math.sqrt(1.0 - z * z)
# sun declination
declination = dali.math.atan2(z, r)
# right ascension
right_ascension = 2 * dali.math.atan2(y, (x + r))
return right_ascension, declination
def _local_hour_angle(model_time, longitude, right_ascension):
"""
Hour angle at model_time for the given longitude and right_ascension
longitude in radians
Ref:
https://en.wikipedia.org/wiki/Hour_angle#Relation_with_the_right_ascension
"""
return _local_mean_sidereal_time(model_time, longitude) - right_ascension
def _star_cos_zenith(model_time, lat, lon):
"""
Return cosine of star zenith angle
lon,lat in radians
Ref:
Azimuth:
https://en.wikipedia.org/wiki/Solar_azimuth_angle#Formulas
Zenith:
https://en.wikipedia.org/wiki/Solar_zenith_angle
"""
ra, dec = _right_ascension_declination(model_time)
h_angle = _local_hour_angle(model_time, lon, ra)
cosine_zenith = dali.math.sin(lat) * dali.math.sin(dec) + dali.math.cos(
lat
) * dali.math.cos(dec) * dali.math.cos(h_angle)
return cosine_zenith