Advertisement
Guest User

Untitled

a guest
Mar 11th, 2022
131
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.12 KB | None | 0 0
  1. #!/usr/bin/env python
  2.  
  3. # (c) Ken Harris, GPL, 2022
  4.  
  5. '''
  6. Basic (command line) celestial almanac app :
  7. Given a time and position, calculate the position of 2 bodies and the angle between them (minus the semi-diameter)
  8.  
  9. Default time is "now" and can be set on the command line w/ the --time flag
  10. Default position is near San Francisco (w/ height of 6 meters) and can be set w/ the --geo flag
  11. Default bodies are Aldebran and the moon, and can be set w/ the --name0 & --name1 flags
  12.  
  13. Example command line arguments :
  14.  
  15. python cel-nav-skyfield.py -t 2022-03-10T00:41:38 --geo 23.1553,-109.725,7 -n Sun
  16.  
  17. NB :
  18. The "height" in the --geo argument is used when calculating "altaz", so includes the "dip"
  19. The --geo info is used for calculations, so includes parallax
  20. '''
  21.  
  22. import skyfield.api # pip install skyfield
  23. import numpy
  24. import datetime
  25.  
  26. def semidiameter(app0): # Apparent
  27.     if app0.target == 10: # sun
  28.         radius = 696340.0 # km
  29.     elif app0.target == 301: # moon
  30.         radius = 1737.1 # km
  31.     else:
  32.         radius = 0.0
  33.     return skyfield.units.Angle(radians=numpy.arcsin(radius / app0.distance().km))
  34.     # XXX use math.arcsin ??
  35.  
  36. ############
  37.  
  38. sfload = skyfield.api.Loader('~/skyfield-data')
  39.  
  40. eph0 = sfload('de421.bsp') # 16.7 MB download
  41.  
  42. #print(f'# eph0.names() : {eph0.names()}')
  43. #print(f'# eph0 : {eph0}')
  44.  
  45. ############
  46.  
  47. '''
  48. import skyfield.data.stellarium
  49. url2 = ('https://raw.githubusercontent.com/Stellarium/stellarium/master'
  50.       '/skycultures/western_SnT/star_names.fab')
  51.  
  52. with sfload.open(url2) as f2:
  53.    star_names = skyfield.data.stellarium.parse_star_names(f2)
  54.  
  55. print(f'# star_names : {star_names}')
  56. '''
  57.  
  58. # late bind ? hippa = None ; ...
  59. import skyfield.data.hipparcos
  60. # hip_main.dat # 53 MB download
  61. with sfload.open(skyfield.data.hipparcos.URL) as f0:
  62.     hippa = skyfield.data.hipparcos.load_dataframe(f0)
  63.  
  64. ############
  65.  
  66. def name2body(name2):
  67.     # XXX 'aries' ??
  68.     name2 = name2.lower()
  69.     if name2 in ['sun', 'earth', 'moon']:
  70.         body0 = eph0[name2]
  71.     elif name2 in ['venus', 'mars', 'jupiter', 'saturn']:
  72.         body0 = eph0[name2 + ' barycenter'] # faster
  73.     else:
  74.         if name2 == 'hamal': hipnum0 = 9884
  75.         elif name2 == 'aldebaran': hipnum0 = 21421
  76.         elif name2 == 'betelgeuse': hipnum0 = 27989
  77.         elif name2 == 'sirius': hipnum0 = 32349
  78.         elif name2 == 'pollux': hipnum0 = 37826
  79.         elif name2 == 'regulus': hipnum0 = 49669
  80.         elif name2 == 'spica': hipnum0 = 65474
  81.         elif name2 == 'antares': hipnum0 = 80763
  82.         elif name2 == 'altair': hipnum0 = 97649
  83.         elif name2 == 'fomalhaut': hipnum0 = 113368
  84.         elif name2 == 'markab': hipnum0 = 113963
  85.         # else: print star names
  86.         body0 = skyfield.api.Star.from_dataframe(hippa.loc[hipnum0])
  87.  
  88.     return body0
  89.  
  90. def myprint(astrometric, apparent): # print lots of debug info
  91.  
  92.     #print(f'## astrometric : {astrometric}')
  93.     #print(f'## apparent : {apparent}')
  94.  
  95.     #print(f'## apparent.center : {apparent.center}')
  96.     #print(f'## apparent.target : {apparent.target}')
  97.  
  98.     #print(f'## eph0.names()[apparent.center] : {eph0.names()[apparent.center]}') # doesn't work w/ eph0 + latlon
  99.     #print(f'## eph0.names()[apparent.target] : {eph0.names()[apparent.target]}') # doesn't work w/ stars
  100.  
  101.     #print(f'# astrometric.radec("date") : {astrometric.radec("date")}')
  102.  
  103.     print(f'# apparent.radec("date") : {apparent.radec("date")}')
  104.     # if altaz-able ...
  105.     print(f'# apparent.altaz("standard") : {apparent.altaz("standard")}')
  106.     print(f'# semidiameter(apparent) : {semidiameter(apparent).arcminutes():.1f}')
  107.  
  108. def proc0(args1):
  109.     args0 = vars(args1) # usings vars() to create dict
  110.  
  111.     s0 = args0['geo'].split(',')
  112.     # use "parse" ? : r0 = '{lat:g},{:s}{lng:g}{}' # ignore Altitude
  113.     geo0 = skyfield.api.wgs84.latlon(float(s0[0]), float(s0[1]), float(s0[2])) # ITRS ECEF # XXX height used for "dip" calc (in altaz) ?
  114.  
  115.     ############ time
  116.  
  117.     #ts = sfload.timescale(builtin=False) # downloads finals2000A.all : Earth Orientation Parameters data file
  118.     ts = sfload.timescale() # timescale object with built-in UT1-tables
  119.  
  120.     if args0['time'] is None:
  121.         dt0 = datetime.datetime.utcnow()
  122.     else:
  123.         dt0 = datetime.datetime.strptime(args0['time'], '%Y-%m-%dT%H:%M:%S')
  124.  
  125.     # import dateparser
  126.     # t = dateparser.parse('12/12/12')
  127.  
  128.     # XXX ts.utc / ts.ut1 / ts.from_datetime ?? utc_strftime / ut1_strftime ?? TAI / TT / TDB / UT1 ?
  129.     t0 = ts.ut1(dt0.year, dt0.month, dt0.day,
  130.             dt0.hour, dt0.minute, dt0.second + dt0.microsecond / 1e6)
  131.  
  132.     t0._nutation_angles = skyfield.nutationlib.iau2000b(t0.tt) # XXX ??
  133.  
  134.     print(f'## t0 : {t0.ut1_strftime()}') # utc_strftime
  135.  
  136.     ############
  137.  
  138.     print('================================')
  139.  
  140.     observer0 = name2body('earth') + geo0 # parallax
  141.     print(f'# observer0 : {observer0}')
  142.     barycentric1 = observer0.at(t0) # Barycentric BCRS position and velocity
  143.     #print(f'## barycentric1 : {barycentric1}')
  144.  
  145.     print('================================')
  146.  
  147.     name0 = args0['name0'] ; print(f'# name0 : {name0}')
  148.     body0 = name2body(name0) ; print(f'# body0 : {body0}')
  149.  
  150.     astrometric0 = barycentric1.observe(body0) # Astrometric ICRS / ICRF position and velocity
  151.     apparent0 = astrometric0.apparent() # deflection & aberration : Apparent GCRS position and velocity
  152.     myprint(astrometric0, apparent0)
  153.  
  154.     print('================================')
  155.  
  156.     name1 = args0['name1'] ; print(f'# name1 : {name1}')
  157.     body1 = name2body(name1) ; print(f'# body1 : {body1}')
  158.  
  159.     astrometric1 = barycentric1.observe(body1) # Astrometric ICRS / ICRF position and velocity
  160.     apparent1 = astrometric1.apparent() # deflection & aberration : Apparent GCRS position and velocity
  161.     myprint(astrometric1, apparent1)
  162.  
  163.     print('================================')
  164.  
  165.     #print(f'# astrometric0.separation_from(astrometric1) : {astrometric0.separation_from(astrometric1)}')
  166.     print(f'# apparent0.separation_from(apparent1) : {apparent0.separation_from(apparent1)}')
  167.  
  168.     hc0 = apparent0.separation_from(apparent1).degrees - semidiameter(apparent0).degrees - semidiameter(apparent1).degrees
  169.     print('# separation_from minus semi-diameters : ', skyfield.units.Angle(degrees=hc0))
  170.  
  171. def main():
  172.     import argparse
  173.     parser = argparse.ArgumentParser(description="almanac")
  174.  
  175.     # sun, moon, venus, mars, saturn, jupiter
  176.     # Capella Procyon Sirius Rigel Betelgeuse
  177.     # Elnath Menkar
  178.     # lunar stars : Hamal Aldebaran Pollux Regulus Spica Antares Altair Fomalhaut Markab
  179.  
  180.     parser.add_argument("-n", "--name0", default = 'Aldebaran', type = str, help="heavenly body")
  181.     parser.add_argument("-N", "--name1", default = 'moon', type = str, help="heavenly body")
  182.     parser.add_argument("-t", "--time", default = None, help="time : %Y-%m-%dT%H:%M:%S")
  183.     parser.add_argument("-g", "--geo", default = '38.0,-122.0,6', help="assumed position : lat,lng,meters") # SF area
  184.     #parser.add_argument("-T", "--temp", default = "standard", help="temperature_C (for refraction)")
  185.  
  186.     proc0(parser.parse_args())
  187.  
  188. import sys
  189. if __name__ == '__main__':
  190.     sys.exit(main())
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement