122 lines
3.7 KiB
Python
122 lines
3.7 KiB
Python
#!/usr/bin/env python
|
|
# Common Utilities
|
|
|
|
from astropy.coordinates import SkyCoord, FK5, get_sun
|
|
from astropy.time import Time
|
|
import astropy.units as u
|
|
import numpy as np
|
|
from scipy import interpolate
|
|
|
|
|
|
# Sunrise/sunset algorithm from Astronomical Algorithms by Jean Meeus
|
|
def get_sunset_and_sunrise(tnow, loc, refalt_set, refalt_rise):
|
|
# Get time
|
|
nmjd = 64
|
|
mjd0 = np.floor(tnow.mjd)
|
|
mnow = tnow.mjd - mjd0
|
|
mjd = np.linspace(mjd0 - 1.0, mjd0 + 3.0, nmjd)
|
|
t = Time(mjd, format='mjd', scale='utc')
|
|
|
|
# Get sun position
|
|
psun = get_sun(t)
|
|
|
|
# Correct for precession by converting to FK5
|
|
pos = SkyCoord(ra=psun.ra.degree,
|
|
dec=psun.dec.degree,
|
|
frame='icrs',
|
|
unit='deg').transform_to(FK5(equinox=t))
|
|
|
|
# Compute altitude extrema
|
|
de = np.mean(pos.dec)
|
|
minalt = np.arcsin(
|
|
np.sin(loc.lat) * np.sin(de) - np.cos(loc.lat) * np.cos(de))
|
|
maxalt = np.arcsin(
|
|
np.sin(loc.lat) * np.sin(de) + np.cos(loc.lat) * np.cos(de))
|
|
|
|
# Never sets, never rises?
|
|
if minalt > min(refalt_set, refalt_rise):
|
|
return "sun never sets", t[0], t[0]
|
|
elif maxalt < max(refalt_set, refalt_rise):
|
|
return "sun never rises", t[0], t[0]
|
|
|
|
# Prevent discontinuities in right ascension
|
|
dra = pos[-1].ra - pos[0].ra
|
|
ra = pos.ra.degree
|
|
if dra < 0.0:
|
|
c = pos.ra.degree < 180.0
|
|
ra[c] = pos[c].ra.degree + 360.0
|
|
|
|
# Set up interpolating function
|
|
fra = interpolate.interp1d(t.mjd, ra)
|
|
fde = interpolate.interp1d(t.mjd, pos.dec.degree)
|
|
|
|
# Get GMST
|
|
gmst0 = Time(mjd0, format='mjd',
|
|
scale='utc').sidereal_time('mean', 'greenwich')
|
|
|
|
# Get transit time
|
|
mtransit = np.mod(
|
|
(fra(mjd0) * u.degree - loc.lon - gmst0) / (360.0 * u.degree), 1.0)
|
|
while True:
|
|
gmst = gmst0 + 360.985647 * u.deg * mtransit
|
|
ra = fra(mjd0 + mtransit) * u.deg
|
|
ha = gmst + loc.lon - ra
|
|
mtransit -= ha / (360.0 * u.deg)
|
|
if np.abs(ha.degree) < 1e-9:
|
|
break
|
|
|
|
# Hour angle offset
|
|
ha0 = np.arccos(
|
|
(np.sin(refalt_set) - np.sin(loc.lat) * np.sin(np.mean(pos.dec))) /
|
|
(np.cos(loc.lat) * np.cos(np.mean(pos.dec))))
|
|
|
|
# Get set time
|
|
mset = mtransit + ha0 / (360.0 * u.deg)
|
|
while True:
|
|
gmst = gmst0 + 360.985647 * u.deg * mset
|
|
ra = fra(mjd0 + mset) * u.deg
|
|
de = fde(mjd0 + mset) * u.deg
|
|
ha = gmst + loc.lon - ra
|
|
alt = np.arcsin(
|
|
np.sin(loc.lat) * np.sin(de) +
|
|
np.cos(loc.lat) * np.cos(de) * np.cos(ha))
|
|
dm = (alt - refalt_set) / (360.0 * u.deg * np.cos(de) *
|
|
np.cos(loc.lat) * np.sin(ha))
|
|
mset += dm
|
|
|
|
# Break loop or find sunset on next day
|
|
if np.abs(dm) < 1e-9:
|
|
if mset >= mnow:
|
|
break
|
|
else:
|
|
mset += 1.0
|
|
|
|
# Set set time
|
|
tset = Time(mjd0 + mset.value, format='mjd', scale='utc')
|
|
|
|
# Get rise time
|
|
mrise = mtransit - ha0 / (360.0 * u.deg)
|
|
while True:
|
|
gmst = gmst0 + 360.985647 * u.deg * mrise
|
|
ra = fra(mjd0 + mrise) * u.deg
|
|
de = fde(mjd0 + mrise) * u.deg
|
|
ha = gmst + loc.lon - ra
|
|
alt = np.arcsin(
|
|
np.sin(loc.lat) * np.sin(de) +
|
|
np.cos(loc.lat) * np.cos(de) * np.cos(ha))
|
|
dm = (alt - refalt_rise) / (360.0 * u.deg * np.cos(de) *
|
|
np.cos(loc.lat) * np.sin(ha))
|
|
mrise += dm
|
|
|
|
# Break loop or find sunrise on next day
|
|
if np.abs(dm) < 1e-9:
|
|
if mrise >= mnow:
|
|
break
|
|
else:
|
|
mrise += 1.0
|
|
|
|
# Set rise time
|
|
trise = Time(mjd0 + mrise.value, format='mjd', scale='utc')
|
|
|
|
return "sun rises and sets", tset, trise
|