Rewrote the almanac so it now supports star ephemeris. For example,

$almanac.rigel.next_rising. Fixes issue #79.
This commit is contained in:
Tom Keffer
2015-11-19 18:00:01 -08:00
parent a6d7ae1aab
commit ac2e564c10
2 changed files with 28 additions and 88 deletions

View File

@@ -21,9 +21,8 @@ try:
except ImportError:
import weeutil.Sun
# NB: In order to avoid an 'autocall' bug in Cheetah versions before 2.1,
# this class must not be a "new-style" class. However, that version seems
# to be long gone, so we use 'object'
# NB: Have Almanac inherit from 'object'. However, this will cause
# an 'autocall' bug in Cheetah versions before 2.1.
class Almanac(object):
"""Almanac data.
@@ -160,7 +159,7 @@ class Almanac(object):
time_ts: A unix epoch timestamp with the time of the almanac. If None, the
present time will be used.
lat, lon: Observer's location
lat, lon: Observer's location in degrees.
altitude: Observer's elevation in **meters**. [Optional. Default is 0 (sea level)]
@@ -178,12 +177,12 @@ class Almanac(object):
"""
self.time_ts = time_ts if time_ts else time.time()
self.time_djd = timestamp_to_djd(self.time_ts)
self.lat = math.radians(lat)
self.lon = math.radians(lon)
self.lat = lat
self.lon = lon
self.altitude = altitude if altitude is not None else 0.0
self.temperature = temperature if temperature is not None else 15.0
self.pressure = pressure if pressure is not None else 1010.0
self.horizon = math.radians(horizon) if horizon is not None else 0.0
self.horizon = horizon if horizon is not None else 0.0
self.moon_phases = moon_phases
self.formatter = formatter
@@ -234,22 +233,13 @@ class Almanac(object):
pressure: The observer's pressure (used to calculate refraction)
"""
# Set a new value for any named arguments. If not named, then the value
# should stay unchanged
if 'almanac_time' in kwargs:
self.time_ts = kwargs['almanac_time']
self.time_djd = timestamp_to_djd(self.time_ts)
if 'lat' in kwargs:
self.lat = math.radians(kwargs['lat'])
if 'lon' in kwargs:
self.lon = math.radians(kwargs['lon'])
if 'altitude' in kwargs:
self.altitude = kwargs['altitude']
if 'horizon' in kwargs:
self.horizon = math.radians(kwargs['horizon'])
if 'temperature' in kwargs:
self.temperature = kwargs['temperature']
if 'pressure' in kwargs:
self.pressure = kwargs['pressure']
# should remain unchanged
for key in kwargs:
if 'almanac_time' in kwargs:
self.time_ts = kwargs['almanac_time']
self.time_djd = timestamp_to_djd(self.time_ts)
else:
setattr(self, key, kwargs[key])
return self
@@ -323,7 +313,9 @@ class AlmanacBinder(object):
# being examined. So, create a temporary body and then throw it away
ephem_body = _get_ephem_body(self.heavenly_body)
if self.heavenly_body == 'sun' and attr in ['rise', 'set', 'transit']:
if attr in ['rise', 'set', 'transit']:
# These verbs refer to the time the event occurs anytime in the day, which
# is not necessarily the *next* sunrise.
attr = fn_map[attr]
# These functions require the time at the start of day
observer = self._get_observer(self.sod_djd)
@@ -337,11 +329,9 @@ class AlmanacBinder(object):
time_djd = None
return weewx.units.ValueHelper((time_djd, "dublin_jd", "group_time"), context="ephem_day", formatter=self.formatter)
elif attr in fn_map or attr in ['next_rising', 'next_setting', 'next_transit', 'next_antitransit',
'previous_rising', 'previous_setting', 'previous_transit', 'previous_antitransit']:
if attr in fn_map:
attr = fn_map[attr]
# These functions require the time
elif attr in ['next_rising', 'next_setting', 'next_transit', 'next_antitransit',
'previous_rising', 'previous_setting', 'previous_transit', 'previous_antitransit']:
# These functions require the time of the observation
observer = self._get_observer(self.time_djd)
# Call the function. Be prepared to catch an exception if the body is always up.
try:
@@ -357,13 +347,13 @@ class AlmanacBinder(object):
observer = self._get_observer(self.time_djd)
ephem_body.compute(observer)
if attr in ['az', 'alt', 'a_ra', 'a_dec', 'g_ra', 'ra', 'g_dec', 'dec',
'elong', 'radius', 'hlong', 'hlat', 'sublat', 'sublong']:
'elong', 'radius', 'hlong', 'hlat', 'sublat', 'sublong']:
# Return the results in degrees rather than radians
return math.degrees(getattr(ephem_body, attr))
elif attr=='moon_fullness':
# The attribute "moon_fullness" is the percentage of the moon surface that is illuminated.
# Unfortunately, phephem calls it "moon_phase"
# Return the result in percent
# Unfortunately, phephem calls it "moon_phase", so call ephem with that name.
# Return the result in percent.
return 100.0 * ephem_body.moon_phase
else:
# Just return the result unchanged.
@@ -372,10 +362,10 @@ class AlmanacBinder(object):
def _get_observer(self, time_ts):
# Build an ephem Observer object
observer = ephem.Observer()
observer.lat = self.lat
observer.long = self.lon
observer.lat = math.radians(self.lat)
observer.long = math.radians(self.lon)
observer.elevation = self.altitude
observer.horizon = self.horizon
observer.horizon = math.radians(self.horizon)
observer.temp = self.temperature
observer.pressure = self.pressure
observer.date = time_ts
@@ -408,49 +398,6 @@ def djd_to_timestamp(djd):
"""Convert from number of days since 12/31/1899 12:00 UTC ("Dublin Julian Days") to unix time stamp"""
return (djd-25567.5) * 86400.0
def dummy_test_ephem():
"""
#
# Ephem can be used in various ways. This DOCTEST illustrates and exercises
# these patterns.
#
# First, query a heavenly body based on a time, observer position not needed
>>> jupiter = ephem.Jupiter()
>>> jupiter.compute(t_djd)
>>> print jupiter.ra
21:23:40.13
>>> print "%.2f" % jupiter.phase
99.45
# Similar, but for the moon.
>>> moon = ephem.Moon()
>>> moon.compute(t_djd)
>>> print "%.2f" % moon.phase
1.68
# Now try some queries that require not only time, but the position of an observer
>>> seattle = ephem.city('Seattle')
>>> seattle.date = t_djd
>>> jupiter.compute(seattle)
>>> print jupiter.alt
22:04:25.9
# These require the start of day for the observer, because they are asking
# for the "next" episode
# Calculate the local start of day, Dublin time
>>> (y,m,d) = time.localtime(t)[0:3]
>>> sod_djd = timestamp_to_djd(time.mktime((y,m,d,0,0,0,0,0,-1)))
>>> seattle.date = sod_djd
>>> print "%.3f" % seattle.next_transit(jupiter)
39898.217
>>> sun = ephem.Sun()
>>> sun.compute(seattle)
>>> print seattle.next_rising(sun)
2009/3/27 13:57:08
"""
def dummy_no_ephem():
"""Final test that does not use ephem.
@@ -474,15 +421,5 @@ if __name__ == '__main__':
import doctest
from weeutil.weeutil import timestamp_to_string, timestamp_to_gmtime #@UnusedImport
# t = 1252256400
# print timestamp_to_gmtime(t)
# atlanta = Almanac(t, 33.8, -84.4, pressure=0, horizon=-34.0/60.0)
# # Print it in GMT, so it can easily be compared to the example:
# print timestamp_to_gmtime(atlanta.sun.previous_rising.raw)
# print timestamp_to_gmtime(atlanta.moon.next_setting.raw)
# print timestamp_to_gmtime(atlanta(horizon=-6).sun(use_center=1).previous_rising.raw)
# print timestamp_to_gmtime(atlanta(horizon=-6).sun(use_center=1).next_setting.raw)
# exit()
if not doctest.testmod().failed:
print("PASSED")

View File

@@ -6,6 +6,9 @@ weewx change history
Now really includes wunderfixer. It was inadvertently left out of the install
script.
Rewrote the almanac so it now supports star ephemeris. For example,
$almanac.rigel.next_rising. Fixes issue #79.
Uninstalling an extension with a skin now deletes all empty directories. This
fixes issue #43.