add holiday in AA lunar calendar.

This commit is contained in:
Chen Wei
2014-03-12 09:57:46 +08:00
parent c08c8e0db9
commit 7322476333
4 changed files with 121 additions and 178 deletions

109
aa.py
View File

@@ -120,72 +120,7 @@ IAU2000BNutationTable = array([
[ 1, 1, 2, -2, 2, 1290, 0, 0, -556, 0, 0 ]
])
# The abridged elp-2000 table from A&A p309, TABLE 45.A
moon_tableA = [
[ 0, 0, 1, 0, 6288744, -20905355 ],
[ 2, 0, -1, 0, 1274027, -3699111 ],
[ 2, 0, 0, 0, 658314, -2955968 ],
[ 0, 0, 2, 0, 213618, -569925 ],
[ 0, 1, 0, 0, -185116, 48888 ],
[ 0, 0, 0, 2, -114332, -3149 ],
[ 2, 0, -2, 0, 58793, 246158 ],
[ 2, -1, -1, 0, 57066, -152138 ],
[ 2, 0, 1, 0, 53322, -170733 ],
[ 2, -1, 0, 0, 45758, -204586 ],
[ 0, 1, -1, 0, -40923, -129620 ],
[ 1, 0, 0, 0, -34720, 108743 ],
[ 0, 1, 1, 0, -30383, 104755 ],
[ 2, 0, 0, -2, 15327, 10321 ],
[ 0, 0, 1, 2, -12528, 0 ],
[ 0, 0, 1, -2, 10980, 79661 ],
[ 4, 0, -1, 0, 10675, -34782 ],
[ 0, 0, 3, 0, 10034, -23210 ],
[ 4, 0, -2, 0, 8548, -21636 ],
[ 2, 1, -1, 0, -7888, 24208 ],
[ 2, 1, 0, 0, -6766, 30824 ],
[ 1, 0, -1, 0, -5163, -8379 ],
[ 1, 1, 0, 0, 4987, -16675 ],
[ 2, -1, 1, 0, 4036, -12831 ],
[ 2, 0, 2, 0, 3994, -10445 ],
[ 4, 0, 0, 0, 3861, -11650 ],
[ 2, 0, -3, 0, 3665, 14403 ],
[ 0, 1, -2, 0, -2689, -7003 ],
[ 2, 0, -1, 2, -2602, 0 ],
[ 2, -1, -2, 0, 2390, 10056 ],
[ 1, 0, 1, 0, -2348, 6322 ],
[ 2, -2, 0, 0, 2236, -9884 ],
[ 0, 1, 2, 0, -2120, 5751 ],
[ 0, 2, 0, 0, -2069, 0 ],
[ 2, -2, -1, 0, 2048, -4950 ],
[ 2, 0, 1, -2, -1773, 4130 ],
[ 2, 0, 0, 2, -1595, 0 ],
[ 4, -1, -1, 0, 1215, -3958 ],
[ 0, 0, 2, 2, -1110, 0 ],
[ 3, 0, -1, 0, -892, 3258 ],
[ 2, 1, 1, 0, -810, 2616 ],
[ 4, -1, -2, 0, 759, -1897 ],
[ 0, 2, -1, 0, -713, -2117 ],
[ 2, 2, -1, 0, -700, 2354 ],
[ 2, 1, -2, 0, 691, 0 ],
[ 2, -1, 0, -2, 596, 0 ],
[ 4, 0, 1, 0, 549, -1423 ],
[ 0, 0, 4, 0, 537, -1117 ],
[ 4, -1, 0, 0, 520, -1571 ],
[ 1, 0, -2, 0, -487, -1739 ],
[ 2, 1, 0, -2, -399, 0 ],
[ 0, 0, 2, -2, -381, -4421 ],
[ 1, 1, 1, 0, 351, 0 ],
[ 3, 0, -2, 0, -340, 0 ],
[ 4, 0, -3, 0, 330, 0 ],
[ 2, -1, 2, 0, 327, 0 ],
[ 0, 2, 1, 0, -323, 1165 ],
[ 1, 1, -1, 0, 299, 0 ],
[ 2, 0, 3, 0, 294, 0 ],
[ 2, 0, -1, -2, 0, 8752 ]
]
# VSOP87D tables
# Truncated VSOP87D tables
earth_L0 = array([
[ 1.75347045673, 0, 0 ],
[ 0.03341656456, 4.66925680417, 6283.0758499914 ],
@@ -830,10 +765,6 @@ earth_R5 = array([
# 0 terms retained
])
# table for LEA-406 moon solution. Those terms are linear combination
# of integer multipliers of 14 variables (Arg_j_, j=1,14):
# Delaunay variables l, l', F, D;
@@ -842,7 +773,7 @@ earth_R5 = array([
# and the general precession in longitude p_A_.
# terms of 3rd-degree and 4th-degree are ignored
# in arcsec
# generated with threshold 0.05, average error Moon = 0.73", max 1.5"
# average error Moon = 0.73", max 1.5"
M_ARG = array([
# 226 terms
[ 485868.249036, 1717915923.21779990, 31.87920 ],
@@ -1550,9 +1481,6 @@ CV = M_PHASE * DEG2RAD
C_V, CT_V, CTT_V = hsplit(CV, 3)
A_V, AT_V, ATT_V = hsplit(M_AMP, 3)
# for VSOP2010
# Mean Longituee J2000 (radian)
ci0 = [
@@ -1761,12 +1689,9 @@ class VSOP2010():
def vsopLx(vsopterms, t):
''' helper function for calculate VSOP87 '''
lx = vsopterms[:, 0] * cos(vsopterms[:, 1] + vsopterms[:, 2] * t)
#for vsopterm in vsopterms:
# A = vsopterm[0]
# B = vsopterm[1]
# C = vsopterm[2]
# Lx += A * math.cos(B + C * t)
return sum(lx)
@@ -1884,7 +1809,7 @@ def f_msangle(jd, angle):
Arg:
jd: time in JDTT
Return:
angle in radians, convert to -PI to + PI range
angle in radians, convert to -pi to +pi range
'''
return npitopi(apparentmoon(jd, ignorenutation=True)
@@ -1897,7 +1822,8 @@ def solarterm(year, angle):
The Sun's moving speed on ecliptical longitude is 0.04 argsecond / second,
The accuracy of abridged VSOP is 1", nutation by IAU2000B is 0.001"
The mean error of truncated VSOP is less than 0.1", nutation by IAU2000B is
0.001"
Args:
year: the year in integer
@@ -1907,7 +1833,7 @@ def solarterm(year, angle):
'''
# mean error when compare apparentsun to NASA(1900-2100) is 0.14"
# mean error when compare apparentsun to NASA(1900-2100) is 0.05"
# 0.000000005 radians = 0.001"
ERROR = 0.000000005
@@ -1917,7 +1843,6 @@ def solarterm(year, angle):
# we searching for
est_vejd = g2jd(year, 3, 20.5)
x0 = est_vejd + angle * 360.0 / 365.24 # estimate
#x0 -= solarangle(x0, r) / SUN_SPEED # further closing
x1 = x0 + 0.5
return rootbysecand(f_solarangle, r, x0, x1, precision=ERROR)
@@ -1927,11 +1852,11 @@ def newmoon(jd):
''' search newmoon near a given date.
Angle between Sun-Moon has been converted to [-pi, pi] range so the
function msangle is continuous in that range. Use Secand method to find
function f_msangle is continuous in that range. Use Secand method to find
root.
newmoon in 5 iterations, if the start is close enough, as the searching of
next newmoon usualy does, it may use only 3 iterations.
Test shows newmoon can be found in 5 iterations, if the start is close
enough, it may use only 3 iterations.
Arg:
jd: in JDTT
@@ -1941,7 +1866,7 @@ def newmoon(jd):
'''
# 0.0000001 radians is about 0.02 arcsecond, mean error of apparentmoon
# when compared to JPL Horizon is about 4 arcsecond
# when compared to JPL Horizon is about 0.7 arcsecond
ERROR = 0.0000001
# initilize x0 to the day close to newmoon
@@ -2003,7 +1928,6 @@ def apparentsun(jde, ignorenutation=False):
geolong += nutation(jde)
labbr = lightabbr_high(jde)
#print 'labbr = %s' % fmtdeg(math.degrees(labbr))
geolong += labbr
return normrad(geolong)
@@ -2493,11 +2417,8 @@ def nutation(jde):
# Long-term harmonic development of lunar ephemeris.
# Kudryavtsev S.M. <Astron. Astrophys. 471, 1069 (2007)>
#
# the tables M_AMP, M_PHASE, M_ARG are imported from aa_full_table
#------------------------------------------------------------------------------
FRM = [785939.924268, 1732564372.3047, -5.279, .006665, -5.522e-5 ]
RADEG = 1.7453292519943296e-2
RASEC = 4.8481368110953599e-6
RE_FORTRAN_FMT = re.compile(r'(\d*)([A-Z]+)(\d*)\.?\d*')
def fortran_parsefmt(fmt):
@@ -2686,9 +2607,9 @@ class LEA406():
self.A_V =array(A_V)
self.AT_V =array(AT_V)
self.ATT_V =array(ATT_V)
self.C_V =array(C_V) * RADEG
self.CT_V =array(CT_V) * RADEG
self.CTT_V =array(CTT_V) * RADEG
self.C_V =array(C_V) * DEG2RAD
self.CT_V =array(CT_V) * DEG2RAD
self.CTT_V =array(CTT_V) * DEG2RAD
self.F0_V = array(F0_V) * 3600
self.F1_V = array(F1_V)

View File

@@ -130,12 +130,9 @@ IAU2000BNutationTable = array([
def vsopLx(vsopterms, t):
''' helper function for calculate VSOP87 '''
lx = vsopterms[:, 0] * cos(vsopterms[:, 1] + vsopterms[:, 2] * t)
#for vsopterm in vsopterms:
# A = vsopterm[0]
# B = vsopterm[1]
# C = vsopterm[2]
# Lx += A * math.cos(B + C * t)
return sum(lx)
@@ -253,7 +250,7 @@ def f_msangle(jd, angle):
Arg:
jd: time in JDTT
Return:
angle in radians, convert to -PI to + PI range
angle in radians, convert to -pi to +pi range
'''
return npitopi(apparentmoon(jd, ignorenutation=True)
@@ -266,7 +263,7 @@ def solarterm(year, angle):
The Sun's moving speed on ecliptical longitude is 0.04 argsecond / second,
The accuracy of abridged VSOP is 1", nutation by IAU2000B is 0.001"
The accuracy of nutation by IAU2000B is 0.001"
Args:
year: the year in integer
@@ -276,7 +273,7 @@ def solarterm(year, angle):
'''
# mean error when compare apparentsun to NASA(1900-2100) is 0.14"
# mean error when compare apparentsun to NASA(1900-2100) is 0.05"
# 0.000000005 radians = 0.001"
ERROR = 0.000000005
@@ -296,11 +293,11 @@ def newmoon(jd):
''' search newmoon near a given date.
Angle between Sun-Moon has been converted to [-pi, pi] range so the
function msangle is continuous in that range. Use Secand method to find
function f_msangle is continuous in that range. Use Secand method to find
root.
newmoon in 5 iterations, if the start is close enough, as the searching of
next newmoon usualy does, it may use only 3 iterations.
Test shows newmoon can be found in 5 iterations, if the start is close
enough, it may use only 3 iterations.
Arg:
jd: in JDTT
@@ -310,7 +307,7 @@ def newmoon(jd):
'''
# 0.0000001 radians is about 0.02 arcsecond, mean error of apparentmoon
# when compared to JPL Horizon is about 4 arcsecond
# when compared to JPL Horizon is about 0.7 arcsecond
ERROR = 0.0000001
# initilize x0 to the day close to newmoon
@@ -372,7 +369,6 @@ def apparentsun(jde, ignorenutation=False):
geolong += nutation(jde)
labbr = lightabbr_high(jde)
#print 'labbr = %s' % fmtdeg(math.degrees(labbr))
geolong += labbr
return normrad(geolong)

View File

@@ -401,12 +401,12 @@ def verify_lunarcalendar():
hko.append((x[0], '%s %s' % (x[1], x[2])))
else:
hko.append((x[0], x[1]))
aalc = cn_lunarcal(start)
if start == 1900:
for x in aalc:
print x[0], x[1]
for i in xrange(len(aalc)):
aaday, aaldate = aalc[i]['date'], aalc[i]['lunardate']
if aalc[i]['jieqi']:
aaldate = '%s %s' % (aalc[i]['lunardate'], aalc[i]['jieqi'])
hkoday, hkoldate = hko[i]
#print aaday, aaldate
if aaday != hkoday or aaldate != hkoldate:

View File

@@ -1,6 +1,9 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
''' generate Chinese Lunar Calendar by astronomical algorithms. Also mark the
Chinese Traditional Holiday based on luar calendar '''
__license__ = 'BSD'
__copyright__ = '2014, Chen Wei <weichen302@gmail.com>'
__version__ = '0.0.3'
@@ -176,6 +179,84 @@ def scan_leap(clc):
return clc
def mark_lunarcal_day(clcmonth):
''' expand to whole year, mark the day of month and lunar calendar date in
Chinese'''
stdays= {} # days have solar terms
for d in clcmonth:
if d['astro'] != 'newmoon':
stdays[d['date']] = d['astro']
# expand to whole year
start = clcmonth[0]['date']
yearend = clcmonth[-1]['date'] + 1
lcdays = []
while start < yearend:
# scan the month start belongs
for d in clcmonth:
if d['date'] > start:
break
if d['astro'] == 'newmoon':
monthstart = d['date']
mname = d['month']
day = {'date': start, 'month': mname, 'jieqi': None, 'holiday': None}
day['day'] = int(start + 1 - monthstart)
if start in stdays:
day['jieqi'] = CN_SOLARTERM[stdays[start]]
if day['day'] == 1:
day['lunardate'] = CN_MON[day['month']]
else:
day['lunardate'] = CN_DAY[day['day']]
lcdays.append(day)
start += 1
return lcdays
def mark_holiday(clcdays):
''' mark Chinese Traditional Holiday
腊八节(腊月初八) 除夕(腊月的最后一天) 春节(一月一日)
元宵节(一月十五日) 寒食节(清明的前一天) 端午节(五月初五)
七夕节(七月初七) 中元节(七月十五日) 中秋节(八月十五日)
重阳节(九月九日) 下元节(十月十五日)
'''
for i in xrange(len(clcdays)):
m, d = clcdays[i]['month'], clcdays[i]['day']
if m == 12 and d == 8:
clcdays[i]['holiday'] = u'腊八'
elif m == 1 and d == 1:
clcdays[i]['holiday'] = u'春节'
clcdays[i - 1]['holiday'] = u'除夕'
elif m == 1 and d == 15:
clcdays[i]['holiday'] = u'元宵'
elif m == 5 and d == 5:
clcdays[i]['holiday'] = u'端午'
elif m == 7 and d == 7:
clcdays[i]['holiday'] = u'七夕'
elif m == 7 and d == 15:
clcdays[i]['holiday'] = u'中元'
elif m == 8 and d == 15:
clcdays[i]['holiday'] = u'中秋'
elif m == 9 and d == 9:
clcdays[i]['holiday'] = u'重阳'
elif m == 10 and d == 15:
clcdays[i]['holiday'] = u'下元'
if clcdays[i]['jieqi'] == u'清明':
clcdays[i - 1]['holiday'] = u'寒食'
return clcdays
def search_lunarcal(year):
''' search JieQi and Newmoon, step 1
@@ -192,61 +273,12 @@ def search_lunarcal(year):
clc = find_astro(year)
clcmonth = mark_lunarcal_month(clc)
ystart = clcmonth[0]['date']
yend = clcmonth[-1]['date'] + 1
clcdays = mark_lunarcal_day(clcmonth)
clcdays = mark_holiday(clcdays)
#debug
#print
#for x in clcmonth:
# print jdftime(x['date']), x['astro'], x['date']
FLAG_NEWMOON = 1
FLAG_ST = 2
output = {}
while ystart < yend:
flag = 0
# scan the month ystart belongs
for d in clcmonth:
if d['date'] > ystart:
break
if d['astro'] == 'newmoon':
monthstart = d['date']
mname = d['month']
# scan if the day happens to be the begining of month, or has ST, so we
# can choose the output date format accordingly. The day will be month
# name if it is the day 1 of a month; if it also has solarterm, then
# the name of solarterm will be append to month name; if it is not day
# 1 but has solarterm, then only solarterm will be displayed; if it is
# not begining of the month, or has solarterm, then only the date will
# be showed.
for d in clcmonth:
if d['date'] > ystart:
break
day = int(ystart + 1 - monthstart)
# the day we looking for is in the solarterms and newmoon table
if d['date'] == ystart:
if d['astro'] == 'newmoon':
flag |= FLAG_NEWMOON
else:
flag |= FLAG_ST
angle = d['astro']
if flag == (FLAG_NEWMOON | FLAG_ST):
label = '%s %s' % (CN_MON[mname], CN_SOLARTERM[angle])
elif flag == FLAG_NEWMOON:
label = CN_MON[mname]
elif flag == FLAG_ST:
label = '%s %s' % (CN_DAY[day], CN_SOLARTERM[angle])
else:
#print fmtjde2ut(jd,ut=False), s, nm, day
label = CN_DAY[day]
output[ystart] = label
ystart += 1
for d in clcdays:
output[d['date']] = d
CALCACHE[year] = output # cache it for future use
CALCACHE['cached'].append(year)
@@ -263,8 +295,8 @@ def cn_lunarcal(year):
Because there might be a leap month after this Winter Solstic, which can
only be found by compute Calendar of next year, for example, 2033 has a
leap 11, calendar for this and next year are computed and combined, then
trim to fit into this year scale.
leap 11 that belongs to the next year. Calendar for this and next year are
computed and combined, then trim to fit into scale of this year.
'''
@@ -276,27 +308,21 @@ def cn_lunarcal(year):
start = jdptime('%s-%s-%s' % (year, 1, 1), '%y-%m-%d')
end = jdptime('%s-%s-%s' % (year, 12, 31), '%y-%m-%d')
lc = []
for jd, mname in cal0.iteritems():
for jd, day in cal0.iteritems():
day['date'] = jdftime(jd, '%y-%m-%d', ut=False)
if jd >= start and jd <= end:
lc.append((
jdftime(jd, '%y-%m-%d', ut=False),
mname))
lc.append((jd, day))
lc.sort()
res = [x[1] for x in lc]
# convert to format that accepted by ical generator
rows = []
for x in lc:
rows.append({'date': x[0], 'lunardate': x[1],
'holiday': None, 'jieqi': None})
#sql = ('select date, lunardate, holiday, jieqi from ical '
return rows
return res
def main():
a = cn_lunarcal(2033)
for x in a:
print x['date'], x['lunardate']
print x['date'], x['lunardate'], x['jieqi'], x['holiday']
if __name__ == "__main__":