Bill_Ritchie

Further to KH

Mar 21st, 2022 (edited)
84
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.06 KB | None | 0 0
  1. '''
  2. This is BR_Mods2.py
  3. Sequel to https://pastebin.com/YT28KrG0 (re BR_Mods.py) that should be read first.
  4.  
  5. My beginners learning curve continues. I have found the Skyfield method "from_altaz". It answers my comment
  6. "Whilst it must be possible to use altaz() to first create hypothetical body positions that compensate for refraction..."
  7.  
  8. I have added code (lines 86-90) to create such hypothetical positions.
  9. Skyfield's "separation_from" method then calculates the arc distance perfectly.
  10. The traditional code is on lines 74-84
  11.  
  12. Output compares KH's original, BR's conventional modifications and now the revised Skyfield code.
  13. The latter two agree.
  14.  
  15.  
  16. line 16
  17. '''
  18.  
  19.  
  20. import skyfield.api, skyfield.data.hipparcos
  21. import numpy, datetime, math, argparse, sys
  22. SkyfieldLoad = skyfield.api.Loader('~/skyfield-data')
  23. Ephemeris = SkyfieldLoad('de421.bsp') # 16.7 MB download
  24. with SkyfieldLoad.open(skyfield.data.hipparcos.URL) as f0:
  25. hippa = skyfield.data.hipparcos.load_dataframe(f0)
  26. from skyfield.api import wgs84, Angle
  27. SkyfieldTimescale = SkyfieldLoad.timescale() # timescale object with built-in UT1-tables
  28.  
  29.  
  30. def Calculate(Arguments) :
  31. EventUTC, GeoPos, Body1Name, Body2Name = Arguments # Unpack Arguments
  32.  
  33. # Assign and show time
  34. t = SkyfieldTimescale.ut1(EventUTC.year, EventUTC.month, EventUTC.day,
  35. EventUTC.hour, EventUTC.minute, EventUTC.second + EventUTC.microsecond / 1e6)
  36. print(); print(); print(f't : {t.ut1_strftime()}')
  37. print('================================')
  38.  
  39. # Observer Position
  40. ObsBodycentricPos = NameToBodyData('earth') # Observer at Earth centre
  41. if GeoPos:
  42. ObsPos = ObsBodycentricPos + GeoPos # Observer at specified 3D position (height relative to earth's WGS84 surface)
  43. else:
  44. ObsPos = ObsBodycentricPos
  45. ObsBaryPos = ObsPos.at(t) # Barycentric Observer BCRS position
  46.  
  47. # First body
  48. Body1Data = NameToBodyData(Body1Name)
  49. Apparent1 = ObsBaryPos.observe(Body1Data).apparent()
  50. print(f'Body1Name : {Body1Name}')
  51. print(f'RA : {Apparent1.radec("date")[0]}')
  52. print(f'Dec : {Apparent1.radec("date")[1]}')
  53. if GeoPos:
  54. print(f'Azimuth : {Apparent1.altaz("standard")[1]}')
  55. print(f'Altitude : {Apparent1.altaz("standard")[0]}')
  56. print('================================')
  57.  
  58. # Second body
  59. Body2Data = NameToBodyData(Body2Name)
  60. Apparent2 = ObsBaryPos.observe(Body2Data).apparent()
  61. print(f'Body2Name : {Body2Name}')
  62. print(f'RA : {Apparent2.radec("date")[0]}')
  63. print(f'Dec : {Apparent2.radec("date")[1]}')
  64. print(f'SD : {SemiDiameter(Apparent2).arcminutes():.4f}')
  65. if GeoPos:
  66. print(f'Azimuth : {Apparent2.altaz("standard")[1]}')
  67. print(f'Altitude : {Apparent2.altaz("standard")[0]}')
  68. print('================================')
  69.  
  70. # Get refracted values (dist unused)
  71. Ha1, Az1, dist1 = Apparent1.altaz("standard")
  72. Ha2, Az2, dist2 = Apparent2.altaz("standard")
  73.  
  74. # Calculate arc between centres - traditional method
  75. ArcBetweenCentres = math.degrees(
  76. (math.acos(
  77. math.sin(Ha1.radians) *
  78. math.sin(Ha2.radians) +
  79. math.cos(Ha1.radians) *
  80. math.cos(Ha2.radians) *
  81. math.cos(Az1.radians - Az2.radians)
  82. )
  83. )
  84. )
  85.  
  86. # Calculate arc between centres - revised Skyfield method
  87. # Hypothetical positions to compensate for refraction
  88. HypoRefrPos1 = ObsBaryPos.from_altaz(alt_degrees=Ha1.degrees, az_degrees=Az1.degrees)
  89. HypoRefrPos2 = ObsBaryPos.from_altaz(alt_degrees=Ha2.degrees, az_degrees=Az2.degrees)
  90. Separation = HypoRefrPos1.separation_from(HypoRefrPos2).degrees
  91.  
  92. # Show Arc between centre results
  93. print(f'Original code: Arc between centres: {Apparent1.separation_from(Apparent2)}')
  94. print('Trad method: Arc between centres:', skyfield.units.Angle(degrees=ArcBetweenCentres))
  95. print('Revised Skyfield: Arc between centres:', skyfield.units.Angle(degrees=Separation)) ; print()
  96.  
  97. # Show arc between near limbs
  98. # Original code
  99. NearArc1 = Apparent1.separation_from(Apparent2).degrees - SemiDiameter(Apparent1).degrees - SemiDiameter(Apparent2).degrees
  100. # Trad arc
  101. NearArc2 = ArcBetweenCentres - SemiDiameter(Apparent1).degrees - SemiDiameter(Apparent2).degrees
  102. # Revised arc
  103. Near3Arc = Separation - SemiDiameter(Apparent1).degrees - SemiDiameter(Apparent2).degrees
  104. print('Original code: Arc between near limbs: ', skyfield.units.Angle(degrees=NearArc1))
  105. print('Trad method: Arc between near limbs: ', skyfield.units.Angle(degrees=NearArc2))
  106. print('Revised Skyfield: Arc between near limbs: ', skyfield.units.Angle(degrees=Near3Arc)) ; print()
  107.  
  108.  
  109. #### Other Functions follow ####
  110. def SemiDiameter(BodyData): # Apparent
  111. if BodyData.target == 10: # sun
  112. radius = 696340.0 # km
  113. elif BodyData.target == 301: # moon
  114. # radius = 1737.1 # km
  115. radius = 1737.92
  116. else:
  117. radius = 0.0
  118. # print(f'## BodyData.distance().km : {BodyData.distance().km}')
  119. return skyfield.units.Angle(radians=numpy.arcsin(radius / BodyData.distance().km))
  120.  
  121. def NameToBodyData(Name) :
  122. Name = Name.lower()
  123. if Name in ['sun', 'earth', 'moon']:
  124. BodyData = Ephemeris[Name] # bodycentric
  125. elif Name in ['venus', 'mars', 'jupiter', 'saturn']:
  126. BodyData = Ephemeris[Name + ' barycenter'] # barycentric (why?)
  127. else:
  128. if Name == 'hamal': HipNumber = 9884
  129. elif Name == 'aldebaran': HipNumber = 21421
  130. elif Name == 'betelgeuse': HipNumber = 27989
  131. elif Name == 'sirius': HipNumber = 32349
  132. elif Name == 'pollux': HipNumber = 37826
  133. elif Name == 'regulus': HipNumber = 49669
  134. elif Name == 'spica': HipNumber = 65474
  135. elif Name == 'antares': HipNumber = 80763
  136. elif Name == 'altair': HipNumber = 97649
  137. elif Name == 'fomalhaut': HipNumber = 113368
  138. elif Name == 'markab': HipNumber = 113963
  139. elif Name == 'zubenelgenubi': HipNumber = 72622
  140. BodyData = skyfield.api.Star.from_dataframe(hippa.loc[HipNumber])
  141. # UnboundLocalError if Name not in above
  142. return BodyData
  143.  
  144. def ParseArguments(Arguments):
  145. Arguments = vars(Arguments) # usings vars() to create dict
  146. # --time
  147. if Arguments['time'] is None:
  148. EventUTC = datetime.datetime.utcnow()
  149. else:
  150. EventUTC = datetime.datetime.strptime(Arguments['time'], '%Y-%m-%dT%H:%M:%S')
  151. # --geo
  152. if Arguments['geo']:
  153. GeoArgs = Arguments['geo'].split(',')
  154. # use "parse" ? : r0 = '{lat:g},{:s}{lng:g}{}' # ignore Altitude
  155. # ITRS ECEF # XXX height used for "dip" calc (in altaz) ?
  156. GeoPos = skyfield.api.wgs84.latlon(float(GeoArgs[0]), float(GeoArgs[1]), float(GeoArgs[2]))
  157. else:
  158. GeoPos = None
  159. # -n1, n2
  160. Body1Name = Arguments['Body1Name']
  161. Body2Name = Arguments['Body2Name']
  162. # Do the hard work elsewhere
  163. return EventUTC, GeoPos, Body1Name, Body2Name
  164.  
  165. def main():
  166. parser = argparse.ArgumentParser(description="almanac")
  167. parser.add_argument("-n1", "--Body1Name", default = 'Aldebaran', type = str, help="heavenly body") # was -n
  168. parser.add_argument("-n2", "--Body2Name", default = 'Moon', type = str, help="heavenly body") # was -N
  169. parser.add_argument("-t", "--time", default = '2022-03-05T03:00:00', help="time : %Y-%m-%dT%H:%M:%S")
  170. parser.add_argument("-g", "--geo", default = '38.0,-122.0,0', help="assumed position : lat,lng,meters") # SF area
  171. parser.add_argument("-T", "--temp", default = "standard", help="temperature_C (for refraction)")
  172. Calculate(ParseArguments(parser.parse_args()))
  173.  
  174. if __name__ == '__main__':
  175. sys.exit(main())
  176.  
  177. '''
  178. Scratch pad for copy/paste command lines
  179. python BR_Mods2.py -t 2022-03-05T03:00:00 -n1 Aldebaran -n2 Moon -g 38.0,-122.0,0
  180. python BR_Mods2.py -t 2022-02-22T11:05:48 -n1 Zubenelgenubi -n2 Moon -g 32.0,-109,1400
  181. python BR_Mods2.py -t 2022-02-22T12:27:22 -n1 Zubenelgenubi -n2 Moon -g 32.0,-109,1400
  182. '''
Add Comment
Please, Sign In to add comment