-
Notifications
You must be signed in to change notification settings - Fork 1
/
cal_opp.py
156 lines (135 loc) · 5.04 KB
/
cal_opp.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#########################################################################
#
# Astronomy Club Event Generator
# file: cal_opp.py
#
# Copyright (C) 2016 Teruo Utsumi, San Jose Astronomical Association
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# Contributors:
# 2016-02-25 Teruo Utsumi, initial code
#
#########################################################################
import sys
import datetime
import ephem
import pdb
from cal_const import *
EPHEM_SECOND = ephem.second
EPHEM_DAY = ephem.hour*24
EPHEM_MONTH = EPHEM_DAY*30
def ephem_elong(ephem_date, planet):
planet.compute(ephem_date)
return planet.elong
def calc(year, planet):
'''
Calculate opposition to solar system object. Opposition occurs when
elongation goes from -pi to +pi.
'ephem.elong' is elongation (angle between object and sun) in radians.
As string 'ephem.elong' is deg:min:sec.
Note: Elongation monotonically (?) decreases towards -pi until past
opposition, at which point elongation jumps to about +pi
elongation vs time:
|\ |\
\ | \ | \
\ | \ | \
--\---|---\---|---\-
\ | \ | \
\ | \ |
\| \|
Notes: - Times within two minutes of Sky Safari in most cases, but not
identical.
- Tried the following, but the calcuated minimum point was off by a
few minutes:
http://stackoverflow.com/questions/10146924/finding-the-maximum-of-a-function
solution = scipy.optimize.minimize_scalar(lambda x: -f(x),
bounds=[0,1],
method='bounded')
- ephem uses 'float' data type to represent time, not datetime
input
year int year to be generated
planet ephem.<planet>() planet object
output
return datetime time of opposition of 'planet'
'''
# set start_date as one month before New Year's
# Jan 1, midnight, local time
new_years = datetime.datetime(year, 1, 1, 0, 0)
new_years = TZ_LOCAL.localize(new_years)
start_date = ephem.Date(new_years) - EPHEM_MONTH
# set end_date as one month after New Year's of following year
end_date = ephem.Date(new_years) + EPHEM_MONTH*13
date = start_date
min_elong = +4
min_elong_date = date
# sample elong every month and find min
while date < end_date:
planet.compute(date)
elong = planet.elong
if elong < min_elong:
min_elong = elong
min_elong_date = date
date = ephem.Date(date) + EPHEM_MONTH
if min_elong_date==start_date or min_elong_date==end_date:
# min elongation is outside year -> return nothing
return None
# elongation the month after opposition should be positive
end_date = ephem.Date(min_elong_date) + EPHEM_MONTH
end_date_elong = ephem_elong(end_date, planet) # should be < 0
# binary search - find min elongation until interval becomes <= 1 second
start_date = min_elong_date
while end_date-start_date > EPHEM_SECOND:
mid_date = (start_date + end_date) / 2
mid_date_elong = ephem_elong(mid_date, planet)
if mid_date_elong > 0:
end_date = mid_date
else:
start_date = mid_date
d = ephem.Date(start_date)
# change 'start_date' to datetime format
d = ephem.Date(start_date)
date = ephem.localtime(d)
date = TZ_LOCAL.localize(date)
if date.year == year:
return date
return None
def calc_planets(year):
'''
Calculate opposition to solar system objects.
input
year int year to be considered
output
return list list of datetime/planet string tuples
'''
l_events = []
for planet in PLANETS:
date_opp = calc(year, planet)
if date_opp:
# spaces for formatting
event = (date_opp, " {} at opposition".format(planet.name))
l_events.append(event)
return l_events
if __name__ == '__main__':
year = '2016'
if len(sys.argv) > 1:
year = sys.argv[1]
else:
tmp = input("Specify year [{}]: ".format(year))
if tmp:
year = tmp
if not year.isdigit():
print("{} is not a number".format(year))
print(" opp.py [year]")
exit()
year = int(year)
for date, s in calc_planets(year):
print("{} - {}".format(date.strftime(FMT_YEAR_DATE_HM), s))