├── LICENSE ├── README.md ├── angles.py ├── constants.py ├── contents.txt ├── coordinates.py ├── coordinates_corr.py ├── dynamical_time.py ├── earth_globe.py ├── easter.py ├── eclipse.py ├── elements.py ├── equinox.py ├── jul_dat.py ├── jup_sat.py ├── jupiter.py ├── kepler.py ├── moon.py ├── moon_declination.py ├── moon_disk.py ├── moon_libration.py ├── moon_nodes.py ├── moon_perigee.py ├── moon_phases.py ├── nutation_ecliptic.py ├── paralactic.py ├── perihelion.py ├── physical_sun.py ├── planets.py ├── position.py ├── precession.py ├── refraction.py ├── rising.py ├── separation.py ├── sidereal.py ├── sun.py ├── sun_coordinates.py └── vsop87 ├── VSOP87B.ear ├── VSOP87B.jup ├── VSOP87B.mar ├── VSOP87B.mer ├── VSOP87B.nep ├── VSOP87B.sat ├── VSOP87B.ura ├── VSOP87B.ven ├── readme.md └── vsop87.txt /LICENSE: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or 4 | distribute this software, either in source code form or as a compiled 5 | binary, for any purpose, commercial or non-commercial, and by any 6 | means. 7 | 8 | In jurisdictions that recognize copyright laws, the author or authors 9 | of this software dedicate any and all copyright interest in the 10 | software to the public domain. We make this dedication for the benefit 11 | of the public at large and to the detriment of our heirs and 12 | successors. We intend this dedication to be an overt act of 13 | relinquishment in perpetuity of all present and future rights to this 14 | software under copyright law. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 19 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | For more information, please refer to 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AstroAlgorithms4Python 2 | ### Python version of Meeus's Astronomical Algorithms 3 | 4 | [![DOI](https://zenodo.org/badge/128760106.svg)](https://zenodo.org/badge/latestdoi/128760106) 5 | ![GitHub top language](https://img.shields.io/github/languages/top/pavolgaj/AstroAlgorithms4Python.svg?style=flat) 6 | [![Codacy Badge](https://app.codacy.com/project/badge/Grade/cc0c4c467ddf4231b959c19a471b74d6)](https://www.codacy.com/gh/pavolgaj/AstroAlgorithms4Python/dashboard?utm_source=github.com&utm_medium=referral&utm_content=pavolgaj/AstroAlgorithms4Python&utm_campaign=Badge_Grade) 7 | ![GitHub issues](https://img.shields.io/github/issues/pavolgaj/AstroAlgorithms4Python.svg?style=flat) 8 | ![GitHub closed issues](https://img.shields.io/github/issues-closed/pavolgaj/AstroAlgorithms4Python.svg?style=flat) 9 | 10 | This package used only basic python packages and function but package numpy is required in some cases (e.g. coordinates calculations and conversions). 11 | 12 | ## Contents: 13 | Chap. 07: jul_dat.py 14 | 15 | Chap. 08: easter.py 16 | 17 | Chap. 10: dynamical_time.py 18 | 19 | Chap. 11: earth_globe.py 20 | 21 | Chap. 12: sidereal.py 22 | 23 | Chap. 13: coordinates.py 24 | 25 | Chap. 14: paralactic.py 26 | 27 | Chap. 15: rising.py 28 | 29 | Chap. 16: refraction.py 30 | 31 | Chap. 17: separation.py 32 | 33 | Chap. 21: precesion.py 34 | 35 | Chap. 22: nutation_ecliptic.py 36 | 37 | Chap. 23: coordinates_corr.py 38 | 39 | Chap. 25: sun.py 40 | 41 | Chap. 26: sun_coordinates.py 42 | 43 | Chap. 27: equinox.py 44 | 45 | Chap. 28: time_eq.py 46 | 47 | Chap. 29: physical_sun.py 48 | 49 | Chap. 30: kepler.py 50 | 51 | Chap. 31: elements.py 52 | 53 | Chap. 32: position.py 54 | 55 | Chap. 33: planets.py 56 | 57 | Chap. 38: perihelion.py 58 | 59 | Chap. 43: jupiter.py 60 | 61 | Chap. 44: jup_sat.py 62 | 63 | Chap. 47: moon.py 64 | 65 | Chap. 48: moon_disk.py 66 | 67 | Chap. 49: moon_phases.py 68 | 69 | Chap. 50: moon_perigee.py 70 | 71 | Chap. 51: moon_nodes.py 72 | 73 | Chap. 52: moon_declination.py 74 | 75 | Chap. 53: moon_libration.py 76 | 77 | Chap. 54: eclipse.py 78 | 79 | 80 | 81 | angles.py - not in AA 82 | 83 | constants.py - some common constants 84 | -------------------------------------------------------------------------------- /angles.py: -------------------------------------------------------------------------------- 1 | #simple routines with angles, not implamented in Meeus's Astronomical Algorithms 2 | 3 | def dms(deg): 4 | '''convert angle in degrees to degrees, minutes and seconds''' 5 | m=int((deg%1)*60) 6 | s=round((deg%1-m/60.)*3600,3) 7 | return int(deg),m,s 8 | 9 | def degree(d,m,s): 10 | '''convert angle in degrees, minutes and seconds to degrees''' 11 | return d+m/60.+s/3600. 12 | 13 | def deg2hour(deg): 14 | '''convert angle from degrees to hours''' 15 | return deg/15. 16 | 17 | def hour2deg(hour): 18 | '''convert angle from hours to degrees''' 19 | return hour*15. 20 | -------------------------------------------------------------------------------- /constants.py: -------------------------------------------------------------------------------- 1 | from math import radians 2 | 3 | eps=radians(23.4457889) #obliquity of ecliptic 4 | e=0.016708634 #eccentricity of Earth orbit 5 | AU=149597871 #astronomical unit in km 6 | 7 | #coordinates of North Galactic Pole 8 | raG=radians(192.85948) 9 | decG=radians(27.12825) 10 | lNP=radians(122.93192) #gal. longitude of North Celestial Pole 11 | -------------------------------------------------------------------------------- /contents.txt: -------------------------------------------------------------------------------- 1 | Meeus: Astronomical Algorithms (2nd ed.) 2 | 3 | Chap. 07: jul_dat.py 4 | Chap. 08: easter.py 5 | Chap. 10: dynamical_time.py 6 | Chap. 11: earth_globe.py 7 | Chap. 12: sidereal.py 8 | Chap. 13: coordinates.py 9 | Chap. 14: paralactic.py 10 | Chap. 15: rising.py 11 | Chap. 16: refraction.py 12 | Chap. 17: separation.py 13 | Chap. 21: precesion.py 14 | Chap. 22: nutation_ecliptic.py 15 | Chap. 23: coordinates_corr.py 16 | Chap. 25: sun.py 17 | Chap. 26: sun_coordinates.py 18 | Chap. 27: equinox.py 19 | Chap. 28: time_eq.py 20 | Chap. 29: physical_sun.py 21 | Chap. 30: kepler.py 22 | Chap. 31: elements.py 23 | Chap. 32: position.py 24 | Chap. 33: planets.py 25 | Chap. 36: 26 | Chap. 38: perihelion.py 27 | Chap. 40: ? 28 | Chap. 41: 29 | Chap. 42: 30 | Chap. 43: jupiter.py 31 | Chap. 44: jup_sat.py 32 | Chap. 45: 33 | Chap. 46: 34 | Chap. 47: moon.py 35 | Chap. 48: moon_disk.py 36 | Chap. 49: moon_phases.py 37 | Chap. 50: moon_perigee.py 38 | Chap. 51: moon_nodes.py 39 | Chap. 52: moon_declination.py 40 | Chap. 53: moon_libration.py 41 | Chap. 54: eclipse.py 42 | 43 | 44 | angles.py - not in AA 45 | constants.py - some common constants 46 | 47 | -------------------------------------------------------------------------------- /coordinates.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 13''' 2 | 3 | import numpy as np 4 | 5 | from constants import * 6 | 7 | def local_sid(sid,lon): 8 | '''calculation of local sidereal time from Greenwich sidereal time (in degrees)''' 9 | return sid+lon 10 | 11 | def ra2ha(ra,sid): 12 | '''calculation of hour angle from RA''' 13 | return sid-ra 14 | 15 | def ha2ra(ha,sid): 16 | '''calculation of RA from hour angle''' 17 | return sid-ha 18 | 19 | def eq2azm(ha,dec,lat,sid=None,ra=False): 20 | '''transformation of equatorial coordinates (Hour angle, DEC) to azimutal (Azm - from South!, Alt); 21 | or from (RA, DEC) - give RA as 1st arg. instead of ha, set ra=True and give sidereal time (sid)''' 22 | 23 | #type of output (same as input - number, list, numpy.array) 24 | if sid is None: sid=0 25 | out_type='lst' 26 | if (isinstance(ha,int) or isinstance(ha,float)) and (isinstance(dec,int) or isinstance(dec,float)) and (isinstance(sid,int) or isinstance(sid,float)) and (isinstance(lat,int) or isinstance(lat,float)): 27 | #all input args are numbers 28 | out_type='num' 29 | 30 | if isinstance(ha,np.ndarray) or isinstance(dec,np.ndarray) or isinstance(sid,np.ndarray) or isinstance(lat,np.ndarray): 31 | #numpy.array 32 | out_type='np' 33 | 34 | if isinstance(ha,list): ha=np.array(ha) 35 | if isinstance(dec,list): dec=np.array(dec) 36 | if isinstance(sid,list): sid=np.array(sid) 37 | if isinstance(lat,list): lat=np.array(lat) 38 | 39 | if ra: t=sid-ha 40 | else: t=ha #HA given 41 | 42 | if out_type=='num': t=np.array([t]) 43 | 44 | t=np.deg2rad(t) 45 | dec=np.deg2rad(dec) 46 | lat=np.deg2rad(lat) 47 | 48 | alt=np.arcsin(np.sin(dec)*np.sin(lat)+np.cos(dec)*np.cos(lat)*np.cos(t)) 49 | sinA=np.cos(dec)*np.sin(t)/np.cos(alt) 50 | cosA=(-np.cos(lat)*np.sin(dec)+np.sin(lat)*np.cos(dec)*np.cos(t))/np.cos(alt) 51 | azm=np.arctan2(sinA,cosA) 52 | azm[np.where(azm<0)]+=2*np.pi 53 | 54 | azm=np.rad2deg(azm) 55 | alt=np.rad2deg(alt) 56 | 57 | if out_type=='num': 58 | alt=alt[0] 59 | azm=azm[0] 60 | elif out_type=='lst': 61 | alt=alt.tolist() 62 | azm=azm.tolist() 63 | return azm,alt 64 | 65 | 66 | def azm2eq(azm,alt,lat,sid=None,ra=False): 67 | '''transformation of azimutal coordinates (Azm - from South!, Alt) to equatorial (Hour angle, DEC); 68 | or to (RA, DEC) - set ra=True and give sidereal time (sid)''' 69 | 70 | #type of output (same as input - number, list, numpy.array) 71 | if sid is None: sid=0 72 | out_type='lst' 73 | if (isinstance(azm,int) or isinstance(azm,float)) and (isinstance(alt,int) or isinstance(alt,float)) and (isinstance(sid,int) or isinstance(sid,float)) and (isinstance(lat,int) or isinstance(lat,float)): 74 | #all input args are numbers 75 | out_type='num' 76 | 77 | if isinstance(azm,np.ndarray) or isinstance(alt,np.ndarray) or isinstance(sid,np.ndarray) or isinstance(lat,np.ndarray): 78 | #numpy.array 79 | out_type='np' 80 | 81 | if isinstance(azm,list): azm=np.array(azm) 82 | if isinstance(alt,list): alt=np.array(alt) 83 | if isinstance(sid,list): sid=np.array(sid) 84 | if isinstance(lat,list): lat=np.array(lat) 85 | 86 | if out_type=='num': azm=np.array([azm]) 87 | 88 | azm=np.deg2rad(azm) 89 | alt=np.deg2rad(alt) 90 | lat=np.deg2rad(lat) 91 | 92 | dec=np.arcsin(np.sin(lat)*np.sin(alt)-np.cos(lat)*np.cos(alt)*np.cos(azm)) 93 | sinH=np.cos(alt)*np.sin(azm)/np.cos(dec) 94 | cosH=(np.sin(alt)*np.cos(lat)+np.cos(alt)*np.sin(lat)*np.cos(azm))/np.cos(dec) 95 | 96 | ha=np.arctan2(sinH,cosH) 97 | ha[np.where(ha<0)]+=2*np.pi 98 | 99 | ha=np.rad2deg(ha) 100 | dec=np.rad2deg(dec) 101 | 102 | if ra: ha=sid-ha 103 | 104 | if out_type=='num': 105 | dec=dec[0] 106 | ha=ha[0] 107 | elif out_type=='lst': 108 | dec=dec.tolist() 109 | ha=ha.tolist() 110 | return ha,dec 111 | 112 | 113 | def eq2ecl(ra,dec): 114 | '''transformation of equatorial coordinates (RA, DEC) to ecliptical (lamda, beta)''' 115 | 116 | #type of output (same as input - number, list, numpy.array) 117 | out_type='lst' 118 | if (isinstance(ra,int) or isinstance(ra,float)) and (isinstance(dec,int) or isinstance(dec,float)): 119 | #all input args are numbers 120 | out_type='num' 121 | 122 | if isinstance(ra,np.ndarray) or isinstance(dec,np.ndarray): 123 | #numpy.array 124 | out_type='np' 125 | 126 | if isinstance(ra,list): ra=np.array(ra) 127 | if isinstance(dec,list): dec=np.array(dec) 128 | 129 | if out_type=='num': ra=np.array([ra]) 130 | 131 | ra=np.deg2rad(ra) 132 | dec=np.deg2rad(dec) 133 | 134 | beta=np.arcsin(np.sin(dec)*np.cos(eps)-np.cos(dec)*np.sin(eps)*np.sin(ra)) 135 | sinL=(np.sin(ra)*np.cos(dec)*np.cos(eps)+np.sin(dec)*np.sin(eps))/np.cos(beta) 136 | cosL=np.cos(ra)*np.cos(dec)/np.cos(beta) 137 | 138 | lam=np.arctan2(sinL,cosL) 139 | lam[np.where(lam<0)]+=2*np.pi 140 | 141 | lam=np.rad2deg(lam) 142 | beta=np.rad2deg(beta) 143 | 144 | if out_type=='num': 145 | beta=beta[0] 146 | lam=lam[0] 147 | elif out_type=='lst': 148 | beta=beta.tolist() 149 | lam=lam.tolist() 150 | return lam,beta 151 | 152 | 153 | def ecl2eq(lam,beta): 154 | '''transformation of ecliptical coordinates (lamda, beta) to equatorial (RA, DEC)''' 155 | 156 | #type of output (same as input - number, list, numpy.array) 157 | out_type='lst' 158 | if (isinstance(lam,int) or isinstance(lam,float)) and (isinstance(beta,int) or isinstance(beta,float)): 159 | #all input args are numbers 160 | out_type='num' 161 | 162 | if isinstance(lam,np.ndarray) or isinstance(beta,np.ndarray): 163 | #numpy.array 164 | out_type='np' 165 | 166 | if isinstance(lam,list): lam=np.array(lam) 167 | if isinstance(beta,list): beta=np.array(beta) 168 | 169 | if out_type=='num': lam=np.array([lam]) 170 | 171 | lam=np.deg2rad(lam) 172 | beta=np.deg2rad(beta) 173 | 174 | dec=np.arcsin(np.sin(beta)*np.cos(eps)+np.cos(beta)*np.sin(eps)*np.sin(lam)) 175 | sinR=(np.sin(lam)*np.cos(beta)*np.cos(eps)-np.sin(beta)*np.sin(eps))/np.cos(dec) 176 | cosR=np.cos(lam)*np.cos(beta)/np.cos(dec) 177 | 178 | ra=np.arctan2(sinR,cosR) 179 | ra[np.where(ra<0)]+=2*np.pi 180 | 181 | ra=np.rad2deg(ra) 182 | dec=np.rad2deg(dec) 183 | 184 | if out_type=='num': 185 | dec=dec[0] 186 | ra=ra[0] 187 | elif out_type=='lst': 188 | dec=dec.tolist() 189 | ra=ra.tolist() 190 | return ra,dec 191 | 192 | 193 | def eq2gal(ra,dec): 194 | '''transformation of equatorial coordinates (RA, DEC) to galactic (l, b)''' 195 | 196 | #type of output (same as input - number, list, numpy.array) 197 | out_type='lst' 198 | if (isinstance(ra,int) or isinstance(ra,float)) and (isinstance(dec,int) or isinstance(dec,float)): 199 | #all input args are numbers 200 | out_type='num' 201 | 202 | if isinstance(ra,np.ndarray) or isinstance(dec,np.ndarray): 203 | #numpy.array 204 | out_type='np' 205 | 206 | if isinstance(ra,list): ra=np.array(ra) 207 | if isinstance(dec,list): dec=np.array(dec) 208 | 209 | if out_type=='num': ra=np.array([ra]) 210 | 211 | ra=np.deg2rad(ra)-raG 212 | dec=np.deg2rad(dec) 213 | 214 | b=np.arcsin(np.sin(dec)*np.sin(decG)+np.cos(dec)*np.cos(decG)*np.cos(ra)) 215 | sinL=np.cos(dec)*np.sin(ra)/np.cos(b) 216 | cosL=(np.sin(dec)*np.cos(decG)-np.cos(dec)*np.sin(decG)*np.cos(ra))/np.cos(b) 217 | 218 | l=np.arctan2(sinL,cosL) 219 | l=lNP-l 220 | l[np.where(l>=2*np.pi)]-=2*np.pi 221 | l[np.where(l<0)]+=2*np.pi 222 | 223 | l=np.rad2deg(l) 224 | b=np.rad2deg(b) 225 | 226 | if out_type=='num': 227 | b=b[0] 228 | l=l[0] 229 | elif out_type=='lst': 230 | b=b.tolist() 231 | l=l.tolist() 232 | return l,b 233 | 234 | 235 | def gal2eq(l,b): 236 | '''transformation of galactic coordinates (l, b) to equatorial (RA, DEC)''' 237 | 238 | #type of output (same as input - number, list, numpy.array) 239 | out_type='lst' 240 | if (isinstance(l,int) or isinstance(l,float)) and (isinstance(b,int) or isinstance(b,float)): 241 | #all input args are numbers 242 | out_type='num' 243 | 244 | if isinstance(l,np.ndarray) or isinstance(b,np.ndarray): 245 | #numpy.array 246 | out_type='np' 247 | 248 | if isinstance(l,list): l=np.array(l) 249 | if isinstance(b,list): b=np.array(b) 250 | 251 | if out_type=='num': b=np.array([b]) 252 | 253 | l=lNP-np.deg2rad(l) 254 | b=np.deg2rad(b) 255 | 256 | dec=np.arcsin(np.sin(decG)*np.sin(b)+np.cos(decG)*np.cos(b)*np.cos(l)) 257 | sinR=np.cos(b)*np.sin(l)/np.cos(dec) 258 | cosR=(np.cos(decG)*np.sin(b)-np.sin(decG)*np.cos(b)*np.cos(l))/np.cos(dec) 259 | 260 | ra=np.arctan2(sinR,cosR) 261 | ra+=raG 262 | ra[np.where(ra>=2*np.pi)]-=2*np.pi 263 | ra[np.where(ra<0)]+=2*np.pi 264 | 265 | ra=np.rad2deg(ra) 266 | dec=np.rad2deg(dec) 267 | 268 | if out_type=='num': 269 | ra=ra[0] 270 | dec=dec[0] 271 | elif out_type=='lst': 272 | ra=ra.tolist() 273 | dec=dec.tolist() 274 | return ra,dec 275 | -------------------------------------------------------------------------------- /coordinates_corr.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 23 ''' 2 | 3 | import numpy as np 4 | 5 | import nutation_ecliptic as nut 6 | 7 | def nutation(jd,ra,dec,correction=False): 8 | '''correction due to nutation (with optional correction of coordinates)''' 9 | 10 | #type of output (same as input - number, list, numpy.array) 11 | out_type='lst' 12 | if (isinstance(ra,int) or isinstance(ra,float)) and (isinstance(dec,int) or isinstance(dec,float)): 13 | #all input args are numbers 14 | out_type='num' 15 | 16 | if isinstance(ra,np.ndarray) or isinstance(dec,np.ndarray): 17 | #numpy.array 18 | out_type='np' 19 | 20 | if isinstance(ra,list): ra=np.array(ra) 21 | if isinstance(dec,list): dec=np.array(dec) 22 | 23 | if out_type=='num': ra=np.array([ra]) 24 | 25 | dpsi,deps=nut.nutation(jd) 26 | eps=nut.ecliptic(jd) 27 | 28 | eps=np.deg2rad(eps) 29 | ra=np.deg2rad(ra) 30 | dec=np.deg2rad(dec) 31 | 32 | dra=(np.cos(eps)+np.sin(eps)*np.sin(ra)*np.tan(dec))*dpsi-(np.cos(ra)*np.tan(dec))*deps 33 | ddec=(np.sin(eps)*np.cos(ra))*dpsi+np.sin(ra)*deps 34 | 35 | if correction: 36 | dra+=np.rad2deg(ra) 37 | ddec+=np.rad2deg(dec) 38 | 39 | if out_type=='num': 40 | dra=dra[0] 41 | ddec=ddec[0] 42 | elif out_type=='lst': 43 | dra=dra.tolist() 44 | ddec=ddec.tolist() 45 | 46 | return dra,ddec 47 | 48 | 49 | def aberration(jd,ra,dec,correction=False): 50 | '''correction due to aberration (with optional correction of coordinates) - for non-corrected (on precession and nutation) RA, DEC''' 51 | 52 | #type of output (same as input - number, list, numpy.array) 53 | out_type='lst' 54 | if (isinstance(ra,int) or isinstance(ra,float)) and (isinstance(dec,int) or isinstance(dec,float)): 55 | #all input args are numbers 56 | out_type='num' 57 | 58 | if isinstance(ra,np.ndarray) or isinstance(dec,np.ndarray): 59 | #numpy.array 60 | out_type='np' 61 | 62 | if isinstance(ra,list): ra=np.array(ra) 63 | if isinstance(dec,list): dec=np.array(dec) 64 | 65 | if out_type=='num': ra=np.array([ra]) 66 | 67 | T=(jd-2451545)/36525. 68 | 69 | L2=3.1761467+1021.3285546*T 70 | L3=1.7534703+628.3075849*T 71 | L4=6.2034809+334.0642431*T 72 | L5=0.5995465+52.9690965*T 73 | L6=0.8740168+21.3299095*T 74 | L7=5.4812939+7.4781599*T 75 | L8=5.3118863+3.8133036*T 76 | L=3.8103444+8399.6847337*T 77 | D=5.1984667+7771.3771486*T 78 | M=2.3555559+8328.6914289*T 79 | F=1.6279052+8433.4661601*T 80 | 81 | 82 | args=[L3,2*L3,L5,L,3*L3,L6,F,L+M,2*L5,2*L3-L5,3*L3-8*L4+3*L5,5*L3-8*L4+3*L5,2*L2-L3,L2,L7,L3-2*L5,L8,L3+L5,2*L2-2*L3,L3-L5,4*L3,3*L3-2*L5,L2-2*L3,2*L2-3*L3,2*L6,2*L2-4*L3,3*L3-2*L4,\ 83 | L+2*D-M,8*L2-12*L3,8*L2-14*L3,2*L4,3*L2-4*L3,2*L3-2*L5,3*L2-3*L3,2*L3-2*L4,L-2*D] 84 | sinX=[-1719914-2*T,6434+141*T,715,715,486-5*T,159,0,39,33,31,8,8,21,-19,17,16,16,11,0,-11,-7,-10,-9,-9,0,0,8,8,-4,-4,-6,-1,4,0,5,5] 85 | cosX=[-25,28007-107*T,0,0,-236-4*T,0,0,0,-10,1,-28,-28,0,0,0,0,0,-1,-11,-2,-8,0,0,0,-9,-9,0,0,-7,-7,-5,-1,-6,-7,-5,0] 86 | sinY=[25-13*T,25697-95*T,6,0,-216-4*T,2,0,0,-9,1,25,-25,0,0,0,0,1,-1,-10,-2,-8,0,0,0,-8,8,0,0,-6,6,-4,-2,-5,-6,-4,0] 87 | cosY=[1578089+156*T,-5904-130*T,-657,-656,-446+5*T,-147,26,-36,-30,-28,8,-8,-19,17,-16,15,-15,-10,0,9,6,9,-9,-8,0,0,-8,-7,4,-4,5,-7,-4,0,-5,-5] 88 | sinZ=[10+32*T,11141-48*T,-15,0,-94,-6,0,0,-5,0,11,-11,0,0,0,1,-3,-1,-4,-1,-3,0,0,0,-3,3,0,0,-3,3,-2,1,-2,-3,-2,0] 89 | cosZ=[684185-358*T,-2559-55*T,-282,-285,-193,-61,-59,-16,-13,-12,3,-3,-8,8,-7,7,-6,-5,0,4,3,4,-4,-4,0,0,-3,-3,2,-2,2,-4,-2,0,-2,-2] 90 | 91 | X=0 92 | Y=0 93 | Z=0 94 | 95 | for i in range(len(args)): 96 | s=np.sin(args[i]) 97 | c=np.cos(args[i]) 98 | 99 | X+=sinX[i]*s+cosX[i]*c 100 | Y+=sinY[i]*s+cosY[i]*c 101 | Z+=sinZ[i]*s+cosZ[i]*c 102 | 103 | c=17314463350. #speed of light in 1e-8 AU per day 104 | 105 | ra=np.deg2rad(ra) 106 | dec=np.deg2rad(dec) 107 | 108 | dra=(Y*np.cos(ra)-X*np.sin(ra))/(c*np.cos(dec)) 109 | ddec=-((X*np.cos(ra)+Y*np.sin(ra))*np.sin(dec)-Z*np.cos(dec))/c 110 | 111 | if correction: 112 | dra+=ra 113 | ddec+=dec 114 | 115 | dra=np.rad2deg(dra) 116 | ddec=np.rad2deg(ddec) 117 | 118 | if out_type=='num': 119 | dra=dra[0] 120 | ddec=ddec[0] 121 | elif out_type=='lst': 122 | dra=dra.tolist() 123 | ddec=ddec.tolist() 124 | 125 | return dra,ddec 126 | 127 | -------------------------------------------------------------------------------- /dynamical_time.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 10''' 2 | '''based on https://eclipse.gsfc.nasa.gov/SEhelp/deltatpoly2004.html''' 3 | 4 | def dT(jd): 5 | '''calculate dT = TD - UT in seconds for years 1986-2150''' 6 | t=(jd-2451545)/365.25 7 | 8 | if jd<2453371: return 63.86+0.3345*t-0.060374*t**2+0.0017275*t**3+0.000651814*t**4+0.00002373599*t**5 #years 1986-2005 9 | elif jd<2469807: return 62.92+0.32217*t+0.005589*t**2 #years 2005-2050 10 | else: return -20+32*((jd-2385800)/36525.)**22-0.5628*((2506331-jd)/365.25) 11 | -------------------------------------------------------------------------------- /earth_globe.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 11''' 2 | 3 | import math 4 | 5 | def distance(lat1,lon1,lat2,lon2): 6 | '''distance between 2 points on Earth''' 7 | a=6378.14 8 | f=1/298.257 9 | 10 | F=math.radians((lat1+lat2)/2.) 11 | G=math.radians((lat1-lat2)/2.) 12 | l=math.radians((lon1-lon2)/2.) 13 | S=math.sin(G)**2*math.cos(l)**2+math.cos(F)**2*math.sin(l)**2 14 | C=math.cos(G)**2*math.cos(l)**2+math.sin(F)**2*math.sin(l)**2 15 | w=math.atan(math.sqrt(S/C)) 16 | R=math.sqrt(S*C)/w 17 | D=2*w*a 18 | H1=(3*R-1)/(2*C) 19 | H2=(3*R+1)/(2*S) 20 | return D*(1+f*H1*math.sin(F)**2*math.cos(G)**2-f*H2*math.cos(F)**2*math.sin(G)**2) 21 | -------------------------------------------------------------------------------- /easter.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 8''' 2 | 3 | def gregorian(year): 4 | '''find Gregorian Easter''' 5 | a=year%19 6 | b=year//100 7 | c=year%100 8 | d=b//4 9 | e=b%4 10 | f=(b+8)//25 11 | g=(b-f+1)//3 12 | h=(19*a+b-d-g+15)%30 13 | i=c//4 14 | k=c%4 15 | l=(32+2*e+2*i-h-k)%7 16 | m=(a+11*h+22*l)//451 17 | n=(h+l-7*m+114)//31 18 | p=(h+l-7*m+114)%31 19 | 20 | return n,p+1 #moon and day of Easter Sunday 21 | 22 | 23 | def julian(year,greg=True): 24 | '''find Julian Easter, date in gregorian or julian calendar''' 25 | a=year%4 26 | b=year%7 27 | c=year%19 28 | d=(19*c+15)%30 29 | e=(2*a+4*b-d+34)%7 30 | if greg: e+=13 #difference between gregorian and julian calendar - valid from 1900 to 2100 31 | f=(d+e+114)//31 32 | g=(d+e+114)%31 33 | 34 | return f,g+1 #moon and day of Easter Sunday 35 | 36 | -------------------------------------------------------------------------------- /eclipse.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 54''' 2 | 3 | import math 4 | 5 | import moon_phases 6 | 7 | def _common(jd,k): 8 | T=(jd-2451545)/36525. 9 | 10 | F=math.radians(160.7108+390.67050284*k-0.0016118*T**2-0.00000227*T**3+0.000000011*T**4) 11 | 12 | E=1-0.002516*T-0.0000047*T**2 13 | 14 | M=math.radians(2.5534+29.10535670*k-0.0000014*T**2-0.00000011*T**3) 15 | Mm=math.radians(201.5643+385.81693528*k+0.0107582*T**2+0.00001238*T**3-0.000000058*T**4) 16 | W=math.radians(124.7746-1.56375588*k+0.0020672*T**2+0.00000215*T**3) 17 | 18 | F1=F-math.radians(0.02665)*math.sin(W) 19 | 20 | P=0.2070*E*math.sin(M)+0.0024*E*math.sin(2*M)-0.0392*math.sin(Mm)+0.0116*math.sin(2*Mm)-0.0073*E*math.sin(Mm+M)+0.0067*E*math.sin(Mm-M)+0.0118*math.sin(2*F1) 21 | Q=5.2207-0.0048*E*math.cos(M)+0.0020*E*math.cos(2*M)-0.3299*math.cos(Mm)-0.0060*E*math.cos(Mm+M)+0.0041*E*math.cos(Mm-M) 22 | 23 | W=abs(math.cos(F1)) 24 | g=(P*math.cos(F1)+Q*math.sin(F1))*(1-0.0048*W) 25 | u=0.0059+0.0046*E*math.cos(M)-0.0182*math.cos(Mm)+0.0004*math.cos(2*Mm)-0.0005*E*math.cos(M+Mm) 26 | 27 | return u,g,Mm 28 | 29 | def lunar(jd0,full=False): 30 | '''find next lunar eclipse''' 31 | jd=moon_phases.full(jd0) 32 | k=(((jd-2451545)/365.25)*12.3685)//1+0.5 33 | 34 | found=False 35 | while not found: 36 | T=(jd-2451545)/36525. 37 | F=math.radians(160.7108+390.67050284*k-0.0016118*T**2-0.00000227*T**3+0.000000011*T**4) 38 | while abs(math.sin(F))>0.36: 39 | jd+=29.530588861 40 | T=(jd-2451545)/36525. 41 | k+=1 42 | F=math.radians(160.7108+390.67050284*k-0.0016118*T**2-0.00000227*T**3+0.000000011*T**4) 43 | 44 | jd=moon_phases.full(jd-1) 45 | 46 | u,g,Mm=_common(jd,k) 47 | 48 | mp=(1.5573+u-abs(g))/0.5450 49 | if mp<0: 50 | jd+=29.530588861 51 | k+=1 52 | else: found=True 53 | 54 | if not full: return jd 55 | 56 | mu=(1.0128-u-abs(g))/0.5450 57 | 58 | p=1.0128-u 59 | t=0.4687-u 60 | n=0.5458+0.0400*math.cos(Mm) 61 | 62 | pt=1./n*math.sqrt(p**2-g**2)/24. 63 | tt=1./n*math.sqrt(t**2-g**2)/24. 64 | 65 | h=1.5573+u 66 | put=1./n*math.sqrt(h**2-g**2)/24. 67 | 68 | info={} 69 | info['max']=jd 70 | info['P1']=jd-put 71 | info['P4']=jd+put 72 | if mu<0: 73 | info['type']='penumbral' 74 | info['mag']=mp 75 | else: 76 | info['mag']=mu 77 | info['U1']=jd-pt 78 | info['U4']=jd+pt 79 | if mu<1: info['type']='partial' 80 | else: 81 | info['type']='total' 82 | info['U2']=jd-tt 83 | info['U3']=jd+tt 84 | 85 | return info 86 | 87 | 88 | 89 | def solar(jd0,full=False): 90 | '''find next solar eclipse''' 91 | jd=moon_phases.new(jd0) 92 | k=(((jd-2451545)/365.25)*12.3685)//1 93 | 94 | found=False 95 | while not found: 96 | T=(jd-2451545)/36525. 97 | F=math.radians(160.7108+390.67050284*k-0.0016118*T**2-0.00000227*T**3+0.000000011*T**4) 98 | 99 | while abs(math.sin(F))>0.36: 100 | jd+=29.530588861 101 | T=(jd-2451545)/36525. 102 | k+=1 103 | F=math.radians(160.7108+390.67050284*k-0.0016118*T**2-0.00000227*T**3+0.000000011*T**4) 104 | 105 | jd=moon_phases.new(jd-1) 106 | 107 | u,g,Mm=_common(jd,k) 108 | 109 | if abs(g)>1.5433+u: 110 | jd+=29.530588861 111 | k+=1 112 | else: found=True 113 | 114 | if not full: return jd 115 | 116 | mag=(1.5433+u-abs(g))/(0.5461+2*u) 117 | 118 | info={} 119 | info['max']=jd 120 | info['mag']=mag 121 | 122 | if abs(g)>=0.9972+abs(u): info['type']='partial' 123 | elif abs(g)>0.9972: info['type']='non-central annular/total' 124 | elif u<0: info['type']='total' 125 | elif u>0.0047: info['type']='annular' 126 | elif u<0.00464*math.sqrt(1-g**2): info['type']='hybrid' 127 | else: info['type']='annular' 128 | 129 | return info 130 | 131 | 132 | -------------------------------------------------------------------------------- /elements.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 31''' 2 | 3 | def _common(jd,Li,ai,ei,ii,Wi,pi): 4 | '''common cycle for all planets''' 5 | T=(jd-2451545)/36525. 6 | L=0 7 | a=0 8 | e=0 9 | i=0 10 | W=0 11 | p=0 12 | 13 | for j in range(len(Li)): 14 | L+=Li[j]*T**j 15 | a+=ai[j]*T**j 16 | e+=ei[j]*T**j 17 | i+=ii[j]*T**j 18 | W+=Wi[j]*T**j 19 | p+=pi[j]*T**j 20 | 21 | L=L%360 22 | i=i%360 23 | W=W%360 24 | p=p%360 25 | return L,a,e,i,W,p 26 | 27 | 28 | def Mercury(jd,j2k=True): 29 | '''orbital elements (mean longitude, semimajor axis, eccentricity, inclination, long. of ascedinf node, long. of perihelium, arg. of perihelium, mean anomaly) of Mercury for equinox J2000.0 or mean equinox''' 30 | if j2k: 31 | Li=[252.250906,149472.6746358,-0.00000536,0.000000002] 32 | ai=[0.387098310,0,0,0] 33 | ei=[0.20563175,0.000020407,-0.0000000283,-0.00000000018] 34 | ii=[7.004986,-0.0059516,0.00000080,0.000000043] 35 | Wi=[48.330893,-0.1254227,-0.00008833,-0.000000200] 36 | pi=[77.456119,0.1588643,-0.00001342,-0.000000007] 37 | else: 38 | Li=[252.250906,149474.0272491,0.00030350,0.000000018] 39 | ai=[0.387098310,0,0,0] 40 | ei=[0.20563175,0.000020407,-0.0000000283,-0.00000000018] 41 | ii=[7.004986,0.0018215,-0.00001810,0.000000056] 42 | Wi=[48.330893,1.1861883,0.00017542,0.000000215] 43 | pi=[77.456119,1.5564776,0.00029544,0.000000009] 44 | 45 | L,a,e,i,W,p=_common(jd,Li,ai,ei,ii,Wi,pi) 46 | w=p-W 47 | if w<0: w+=360 48 | 49 | M=L-p 50 | if M<0: M+=360 51 | return L,a,e,i,W,p,w,M 52 | 53 | 54 | def Venus(jd,j2k=True): 55 | '''orbital elements (mean longitude, semimajor axis, eccentricity, inclination, long. of ascedinf node, long. of perihelium, arg. of perihelium, mean anomaly) of Venus for equinox J2000.0 or mean equinox''' 56 | if j2k: 57 | Li=[181.979801,58517.8156760,0.00000165,-0.000000002] 58 | ai=[0.723329820,0,0,0] 59 | ei=[0.00677192,-0.000047765,0.0000000981,0.00000000046] 60 | ii=[3.394662,-0.0008568,-0.00003244,0.000000009] 61 | Wi=[76.679920,-0.2780134,-0.00014257,-0.000000164] 62 | pi=[131.563703,0.0048746,-0.00138467,-0.000005695] 63 | else: 64 | Li=[181.979801,58519.2130302,0.00031014,0.000000015] 65 | ai=[0.723329820,0,0,0] 66 | ei=[0.00677192,-0.000047765,0.0000000981,0.00000000046] 67 | ii=[3.394662,0.0010037,-0.00000088,-0.000000007] 68 | Wi=[76.679920,0.9011206,0.00040618,-0.000000093] 69 | pi=[131.563703,1.4022288,-0.00107618,-0.000005678] 70 | 71 | L,a,e,i,W,p=_common(jd,Li,ai,ei,ii,Wi,pi) 72 | w=p-W 73 | if w<0: w+=360 74 | 75 | M=L-p 76 | if M<0: M+=360 77 | return L,a,e,i,W,p,w,M 78 | 79 | 80 | def Earth(jd,j2k=True): 81 | '''orbital elements (mean longitude, semimajor axis, eccentricity, inclination, long. of ascedinf node, long. of perihelium, arg. of perihelium, mean anomaly) of Earth for equinox J2000.0 or mean equinox''' 82 | if j2k: 83 | Li=[100.466457,35999.3728565,-0.00000568,-0.000000001] 84 | ai=[1.000001018,0,0,0] 85 | ei=[0.01670863,-0.000042037,-0.0000001267,0.00000000014] 86 | ii=[0,0.0130548,-0.00000931,-0.000000034] 87 | Wi=[174.873176,-0.2410908,0.00004262,0.000000001] 88 | pi=[102.937348,0.3225654,0.00014799,-0.000000039] 89 | else: 90 | Li=[100.466457,36000.7698278,0.00030322,0.000000020] 91 | ai=[1.000001018,0,0,0] 92 | ei=[0.01670863,-0.000042037,-0.0000001267,0.00000000014] 93 | ii=[0,0,0,0] 94 | Wi=[180,0,0,0] 95 | pi=[102.937348,1.7195366,0.00045688,-0.000000018] 96 | 97 | L,a,e,i,W,p=_common(jd,Li,ai,ei,ii,Wi,pi) 98 | w=p-W 99 | if w<0: w+=360 100 | 101 | M=L-p 102 | if M<0: M+=360 103 | return L,a,e,i,W,p,w,M 104 | 105 | 106 | def Mars(jd,j2k=True): 107 | '''orbital elements (mean longitude, semimajor axis, eccentricity, inclination, long. of ascedinf node, long. of perihelium, arg. of perihelium, mean anomaly) of Mars for equinox J2000.0 or mean equinox''' 108 | if j2k: 109 | Li=[355.433000,19140.2993039,0.00000262,-0.000000003] 110 | ai=[1.523679342,0,0,0] 111 | ei=[0.09340065,0.000090484,-0.0000000806,-0.00000000025] 112 | ii=[1.849726,-0.0081477,-0.00002255,-0.000000029] 113 | Wi=[49.558093,-0.2950250,-0.00064048,-0.000001964] 114 | pi=[336.060234,0.4439016,-0.00017313,0.000000518] 115 | else: 116 | Li=[355.433000,19141.6964471,0.00031052,0.000000016] 117 | ai=[1.523679342,0,0,0] 118 | ei=[0.09340065,0.000090484,-0.0000000806,-0.00000000025] 119 | ii=[1.849726,-0.0006011,0.00001276,-0.000000007] 120 | Wi=[49.558093,0.7720959,0.00001557,0.000002267] 121 | pi=[336.060234,1.8410449,0.00013477,0.000000536] 122 | 123 | L,a,e,i,W,p=_common(jd,Li,ai,ei,ii,Wi,pi) 124 | w=p-W 125 | if w<0: w+=360 126 | 127 | M=L-p 128 | if M<0: M+=360 129 | return L,a,e,i,W,p,w,M 130 | 131 | 132 | def Jupiter(jd,j2k=True): 133 | '''orbital elements (mean longitude, semimajor axis, eccentricity, inclination, long. of ascedinf node, long. of perihelium, arg. of perihelium, mean anomaly) of Jupiter for equinox J2000.0 or mean equinox''' 134 | if j2k: 135 | Li=[34.351519,3034.9056606,-0.00008501,0.000000016] 136 | ai=[5.202603209,0.0000001913,0,0] 137 | ei=[0.04849793,0.000163225,-0.0000004714,-0.00000000201] 138 | ii=[1.303267,-0.0019877,0.00003320,0.000000097] 139 | Wi=[100.464407,0.1767232,0.00090700,-0.000007272] 140 | pi=[14.331207,0.2155209,0.00072211,-0.000004485] 141 | else: 142 | Li=[34.351519,3036.3027748,0.00022330,0.000000037] 143 | ai=[5.202603209,0.0000001913,0,0] 144 | ei=[0.04849793,0.000163225,-0.0000004714,-0.00000000201] 145 | ii=[1.303267,-0.0054965,0.00000466,-0.000000002] 146 | Wi=[100.464407,1.0209774,0.00040315,0.000000404] 147 | pi=[14.331207,1.6126352,0.00103042,-0.000004464] 148 | 149 | L,a,e,i,W,p=_common(jd,Li,ai,ei,ii,Wi,pi) 150 | w=p-W 151 | if w<0: w+=360 152 | 153 | M=L-p 154 | if M<0: M+=360 155 | return L,a,e,i,W,p,w,M 156 | 157 | 158 | def Saturn(jd,j2k=True): 159 | '''orbital elements (mean longitude, semimajor axis, eccentricity, inclination, long. of ascedinf node, long. of perihelium, arg. of perihelium, mean anomaly) of Saturn for equinox J2000.0 or mean equinox''' 160 | if j2k: 161 | Li=[50.077444,1222.1138488,0.00021004,-0.000000046] 162 | ai=[9.554909192,-0.0000021930,0.000000004,0] 163 | ei=[0.05554814,-0.000346641,-0.0000006436,0.00000000340] 164 | ii=[2.488879,0.0025514,-0.00004906,0.000000017] 165 | Wi=[113.665503,-0.2566722,-0.00018399,0.000000480] 166 | pi=[93.057237,0.5665415,0.00052850,0.000004912] 167 | else: 168 | Li=[50.077444,1223.5110686,0.00051908,-0.000000030] 169 | ai=[9.554909192,-0.0000021930,0.000000004,0] 170 | ei=[0.05554814,-0.000346641,-0.0000006436,0.00000000340] 171 | ii=[2.488879,-0.0037362,-0.00001519,0.000000087] 172 | Wi=[113.665503,0.8770880,-0.00012176,-0.000002249] 173 | pi=[93.057237,1.9637613,0.00083753,0.000004928] 174 | 175 | L,a,e,i,W,p=_common(jd,Li,ai,ei,ii,Wi,pi) 176 | w=p-W 177 | if w<0: w+=360 178 | 179 | M=L-p 180 | if M<0: M+=360 181 | return L,a,e,i,W,p,w,M 182 | 183 | 184 | def Uranus(jd,j2k=True): 185 | '''orbital elements (mean longitude, semimajor axis, eccentricity, inclination, long. of ascedinf node, long. of perihelium, arg. of perihelium, mean anomaly) of Uranus for equinox J2000.0 or mean equinox''' 186 | if j2k: 187 | Li=[314.055005,428.4669983,-0.00000486,0.000000006] 188 | ai=[19.218446062,-0.0000000372,0.00000000098,0] 189 | ei=[0.04638122,-0.000027293,0.0000000789,0.00000000024] 190 | ii=[0.773197,-0.0016869,0.00000349,0.000000016] 191 | Wi=[74.005957,0.0741431,0.00040539,0.000000119] 192 | pi=[173.005291,0.0893212,-0.00009470,0.000000414] 193 | else: 194 | Li=[314.055005,429.8640561,0.00030390,0.000000026] 195 | ai=[19.218446062,-0.0000000372,0.00000000098,0] 196 | ei=[0.04638122,-0.000027293,0.0000000789,0.00000000024] 197 | ii=[0.773197,0.0007744,0.00003749,-0.000000092] 198 | Wi=[74.005957,0.5211278,0.00133947,0.000018484] 199 | pi=[173.005291,1.4863790,0.00021406,0.000000434] 200 | 201 | L,a,e,i,W,p=_common(jd,Li,ai,ei,ii,Wi,pi) 202 | w=p-W 203 | if w<0: w+=360 204 | 205 | M=L-p 206 | if M<0: M+=360 207 | return L,a,e,i,W,p,w,M 208 | 209 | 210 | def Neptune(jd,j2k=True): 211 | '''orbital elements (mean longitude, semimajor axis, eccentricity, inclination, long. of ascedinf node, long. of perihelium, arg. of perihelium, mean anomaly) of Neptune for equinox J2000.0 or mean equinox''' 212 | if j2k: 213 | Li=[304.348665,218.4862002,0.00000059,-0.000000002] 214 | ai=[30.110386869,-0.0000001663,0.00000000069,0] 215 | ei=[0.00945575,0.000006033,0,-0.00000000005] 216 | ii=[1.769953,0.0002256,0.00000023,0] 217 | Wi=[131.784057,-0.0061651,-0.00000219,-0.000000078] 218 | pi=[48.120276,0.0291866,0.00007610,0] 219 | else: 220 | Li=[304.348665,219.8833092,0.00030882,0.00000018] 221 | ai=[30.110386869,-0.0000001663,0.00000000069,0] 222 | ei=[0.00945575,0.000006033,0,-0.00000000005] 223 | ii=[1.769953,-0.0093082,-0.00000708,0.000000027] 224 | Wi=[131.784057,1.1022039,0.00025952,-0.000000637] 225 | pi=[48.120276,1.4262957,0.00038434,0.000000020] 226 | 227 | L,a,e,i,W,p=_common(jd,Li,ai,ei,ii,Wi,pi) 228 | w=p-W 229 | if w<0: w+=360 230 | 231 | M=L-p 232 | if M<0: M+=360 233 | return L,a,e,i,W,p,w,M 234 | -------------------------------------------------------------------------------- /equinox.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 27''' 2 | 3 | import math 4 | 5 | def _corrections(jd): 6 | '''corrections to times of equinox/solstice''' 7 | T=(jd-2451545)/36525. 8 | 9 | W=math.radians(35999.373*T-2.47) 10 | dl=1+0.0334*math.cos(W)+0.0007*math.cos(2*W) 11 | 12 | A=[485,203,199,182,156,136,77,74,70,58,52,50,45,44,29,18,17,16,14,12,12,12,9,8] 13 | B=[324.96,337.23,342.08,27.85,73.14,171.52,222.54,296.72,243.58,119.81,297.17,21.02,247.54,325.15,60.93,155.12,288.79,198.04,199.76,95.39,287.11,320.81,227.73,15.45] 14 | C=[1934.136,32964.467,20.186,445267.112,45036.886,22518.443,65928.934,3034.906,9037.513,33718.147,150.678,2281.226,29929.562,31555.956,4443.417,67555.328,4562.452,62894.029,31436.921, 15 | 14577.848,31931.756,34777.259,1222.114,16859.074] 16 | 17 | S=0 18 | for i in range(len(A)): S+=A[i]*math.cos(math.radians(B[i]+C[i]*T)) 19 | return jd+0.00001*S/dl 20 | 21 | 22 | def spring(year): 23 | '''calculate spring (March) equinox for given year''' 24 | Y=(year-2000)/1000. 25 | jd0=2451623.80984+365242.37404*Y+0.05169*Y**2-0.00411*Y**3-0.00057*Y**4 26 | return _corrections(jd0) 27 | 28 | def summer(year): 29 | '''calculate summer (June) solstice for given year''' 30 | Y=(year-2000)/1000. 31 | jd0=2451716.56767+365241.62603*Y+0.00325*Y**2+0.00888*Y**3-0.00030*Y**4 32 | return _corrections(jd0) 33 | 34 | def autumn(year): 35 | '''calculate autumn (September) equinox for given year''' 36 | Y=(year-2000)/1000. 37 | jd0=2451810.21715+365242.01767*Y-0.11575*Y**2+0.00337*Y**3+0.00078*Y**4 38 | return _corrections(jd0) 39 | 40 | def winter(year): 41 | '''calculate winter (December) solstice for given year''' 42 | Y=(year-2000)/1000. 43 | jd0=2451900.05952+365242.74049*Y-0.06223*Y**2-0.00823*Y**3+0.00032*Y**4 44 | return _corrections(jd0) 45 | 46 | 47 | def year(year): 48 | '''calculate equinoxes and solstices for given year''' 49 | return spring(year),summer(year),autumn(year),winter(year) 50 | 51 | -------------------------------------------------------------------------------- /jul_dat.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 7''' 2 | 3 | def date2jd(year,mon,day,h=0,m=0,s=0): 4 | '''convert date and time to julian date''' 5 | if mon<=2: 6 | year-=1 7 | mon+=12 8 | a=int(year/100) 9 | b=2-a+int(a/4) 10 | jd=int(365.25*(year+4716))+int(30.6001*(mon+1))+day+h/24.+m/1440.+s/86400.+b-1524.5 11 | return jd 12 | 13 | def jd2date(jd): 14 | '''convert julian date to date and time''' 15 | jd+=0.5 16 | z=int(jd) 17 | f=jd%1 18 | if z<2299161: a=z 19 | else: 20 | alp=int((z-1867216.25)/36524.25) 21 | a=z+1+alp-int(alp/4) 22 | b=a+1524 23 | c=int((b-122.1)/365.25) 24 | d=int(365.25*c) 25 | e=int((b-d)/30.6001) 26 | 27 | h=int(f*24) 28 | m=int((f-h/24.)*1440) 29 | s=round((f-h/24.-m/1440.)*86400.,2) 30 | day=b-d-int(30.6001*e) 31 | if e<14: mon=e-1 32 | else: mon=e-13 33 | if mon>2: year=c-4716 34 | else: year=c-4715 35 | 36 | return year,mon,day,h,m,s 37 | 38 | def timeint(year1,mon1,day1,year2,mon2,day2): 39 | '''time interval between two dates in days''' 40 | jd1=date2jd(year1,mon1,day1) 41 | jd2=date2jd(year2,mon2,day2) 42 | return int(jd2-jd1) 43 | 44 | def weekday(year,mon,day): 45 | '''day of week for given date''' 46 | jd=date2jd(year,mon,day)+1.5 47 | if jd%7==0: return 'Sunday' 48 | if jd%7==1: return 'Monday' 49 | if jd%7==2: return 'Tuesday' 50 | if jd%7==3: return 'Wednesday' 51 | if jd%7==4: return 'Thursday' 52 | if jd%7==5: return 'Friday' 53 | if jd%7==6: return 'Saturday' 54 | 55 | 56 | -------------------------------------------------------------------------------- /jup_sat.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 44''' 2 | 3 | import math 4 | 5 | def _common(jd): 6 | d=jd-2451545.0 7 | 8 | V=math.radians(172.74+0.00111588*d) 9 | M=math.radians(357.529+0.9856003*d) 10 | N=math.radians(20.020+0.0830853*d+0.329*math.sin(V)) 11 | 12 | J=66.115+0.9025179*d-0.329*math.sin(V) 13 | 14 | A=1.915*math.sin(M)+0.020*math.sin(2*M) 15 | B=5.555*math.sin(N)+0.168*math.sin(2*N) 16 | 17 | K=math.radians(J+A-B) 18 | 19 | R=1.00014-0.01671*math.cos(M)-0.00014*math.cos(2*M) 20 | r=5.20872-0.25208*math.cos(N)-0.00611*math.cos(2*N) 21 | D=math.sqrt(r**2+R**2-2*r*R*math.cos(K)) 22 | 23 | psi=math.degrees(math.asin(R/D*math.sin(K))) 24 | 25 | l=34.35+0.083091*d+0.329*math.sin(V)+B 26 | 27 | DS=3.12*math.sin(math.radians(l+42.8)) 28 | DE=math.radians(DS-2.22*math.sin(math.radians(psi))*math.cos(math.radians(l+22))-1.30*(r-D)/D*math.sin(math.radians(l-100.5))) 29 | 30 | return d-D/173.,psi-B,DE 31 | 32 | def Io(jd): 33 | '''position of moon Io in units of Jupiter's equatorial radius''' 34 | dt,pB,DE=_common(jd) 35 | 36 | u=math.radians(163.8069+203.4058646*dt+pB) 37 | u2=math.radians(358.4140+101.2916335*dt+pB) 38 | 39 | u+=math.radians(0.473*math.sin(2*(u-u2))) 40 | r=5.9057-0.0244*math.cos(2*(u-u2)) 41 | 42 | x=r*math.sin(u) 43 | y=-r*math.cos(u)*math.sin(DE) 44 | 45 | return x,y 46 | 47 | def Europe(jd): 48 | '''position of moon Europe in units of Jupiter's equatorial radius''' 49 | dt,pB,DE=_common(jd) 50 | 51 | u=math.radians(358.4140+101.2916335*dt+pB) 52 | u3=math.radians(5.7176+50.2345180*dt+pB) 53 | 54 | u+=math.radians(1.065*math.sin(2*(u-u3))) 55 | r=9.3966-0.0882*math.cos(2*(u-u3)) 56 | 57 | x=r*math.sin(u) 58 | y=-r*math.cos(u)*math.sin(DE) 59 | 60 | return x,y 61 | 62 | def Ganymede(jd): 63 | '''position of moon Ganymede in units of Jupiter's equatorial radius''' 64 | dt,pB,DE=_common(jd) 65 | 66 | u=math.radians(5.7176+50.2345180*dt+pB) 67 | G=math.radians(331.18+50.310482*dt) 68 | 69 | u+=math.radians(0.165*math.sin(G)) 70 | r=14.9883-0.0216*math.cos(G) 71 | 72 | x=r*math.sin(u) 73 | y=-r*math.cos(u)*math.sin(DE) 74 | 75 | return x,y 76 | 77 | def Callisto(jd): 78 | '''position of moon Ganymedes in units of Jupiter's equatorial radius''' 79 | dt,pB,DE=_common(jd) 80 | 81 | u=math.radians(224.8092+21.4879800*dt+pB) 82 | H=math.radians(87.45+21.569231*dt) 83 | 84 | u+=math.radians(0.843*math.sin(H)) 85 | r=26.3627-0.1939*math.cos(H) 86 | 87 | x=r*math.sin(u) 88 | y=-r*math.cos(u)*math.sin(DE) 89 | 90 | return x,y 91 | -------------------------------------------------------------------------------- /jupiter.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 43''' 2 | 3 | import math 4 | 5 | def calculate(jd): 6 | '''calculation of Jupiter's parameters: Earth-Jup distance, longitudes of central meridian, planetocentric dec. of Earth and Sun''' 7 | d=jd-2451545.0 8 | 9 | V=math.radians(172.74+0.00111588*d) 10 | M=math.radians(357.529+0.9856003*d) 11 | N=math.radians(20.020+0.0830853*d+0.329*math.sin(V)) 12 | 13 | J=66.115+0.9025179*d-0.329*math.sin(V) 14 | 15 | A=1.915*math.sin(M)+0.020*math.sin(2*M) 16 | B=5.555*math.sin(N)+0.168*math.sin(2*N) 17 | 18 | K=math.radians(J+A-B) 19 | 20 | R=1.00014-0.01671*math.cos(M)-0.00014*math.cos(2*M) 21 | r=5.20872-0.25208*math.cos(N)-0.00611*math.cos(2*N) 22 | D=math.sqrt(r**2+R**2-2*r*R*math.cos(K)) 23 | 24 | psi=math.degrees(math.asin(R/D*math.sin(K))) 25 | 26 | w1=(210.98+877.8169088*(d-D/173.)+psi-B)%360. 27 | w2=(187.23+870.1869088*(d-D/173.)+psi-B)%360. 28 | 29 | l=34.35+0.083091*d+0.329*math.sin(V)+B 30 | 31 | DS=3.12*math.sin(math.radians(l+42.8)) 32 | DE=DS-2.22*math.sin(math.radians(psi))*math.cos(math.radians(l+22))-1.30*(r-D)/D*math.sin(math.radians(l-100.5)) 33 | 34 | return D,w1,w2,DE,DS 35 | 36 | 37 | -------------------------------------------------------------------------------- /kepler.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 30''' 2 | 3 | import numpy as np 4 | 5 | def method1(e,M,eps=1e-8): 6 | '''1st method for solving Kepler's equation''' 7 | 8 | #type of output (same as input - number, list, numpy.array) 9 | out_type='lst' 10 | if isinstance(M,int) or isinstance(M,float): 11 | #all input args are numbers 12 | out_type='num' 13 | 14 | if isinstance(M,np.ndarray): 15 | #numpy.array 16 | out_type='np' 17 | 18 | if isinstance(M,list): M=np.array(M) 19 | if out_type=='num': M=np.array([M]) 20 | 21 | M=np.deg2rad(M) 22 | E=M 23 | E0=E+1e3 24 | #i=0 25 | while max(abs(E-E0))>eps: 26 | E0=np.array(E) 27 | E=M+e*np.sin(E) 28 | #i+=1 29 | #print i 30 | 31 | E=np.rad2deg(E) 32 | if out_type=='num': E=E[0] 33 | elif out_type=='lst': E=E.tolist() 34 | return E 35 | 36 | 37 | def method2(e,M,eps=1e-8): 38 | '''2nd method for solving Kepler's equation''' 39 | 40 | #type of output (same as input - number, list, numpy.array) 41 | out_type='lst' 42 | if isinstance(M,int) or isinstance(M,float): 43 | #all input args are numbers 44 | out_type='num' 45 | 46 | if isinstance(M,np.ndarray): 47 | #numpy.array 48 | out_type='np' 49 | 50 | if isinstance(M,list): M=np.array(M) 51 | if out_type=='num': M=np.array([M]) 52 | 53 | M=np.deg2rad(M) 54 | E=M 55 | E0=E+1e3 56 | #i=0 57 | while max(abs(E-E0))>eps: 58 | E0=np.array(E) 59 | E=E+(M+e*np.sin(E)-E)/(1-e*np.cos(E)) 60 | #i+=1 61 | #print i 62 | 63 | E=np.rad2deg(E) 64 | if out_type=='num': E=E[0] 65 | elif out_type=='lst': E=E.tolist() 66 | return E 67 | 68 | def method3(e,M,eps=1e-8): 69 | '''3rd method for solving Kepler's equation''' 70 | 71 | #type of output (same as input - number, list, numpy.array) 72 | out_type='lst' 73 | if isinstance(M,int) or isinstance(M,float): 74 | #all input args are numbers 75 | out_type='num' 76 | 77 | if isinstance(M,np.ndarray): 78 | #numpy.array 79 | out_type='np' 80 | 81 | if isinstance(M,list): M=np.array(M) 82 | if out_type=='num': M=np.array([M]) 83 | 84 | M=np.deg2rad(M) 85 | 86 | F=np.sign(M) 87 | M=np.abs(M)/(2*np.pi) 88 | M=(M-M//1)*2*np.pi*F 89 | M[np.where(M<0)]+=2*np.pi 90 | F=np.ones(M.shape) 91 | F[np.where(M>np.pi)]=-1 92 | M[np.where(M>np.pi)]=2*np.pi-M[np.where(M>np.pi)] 93 | 94 | E=np.pi/2.*np.ones(M.shape) 95 | D=np.pi/4. 96 | E0=np.ones(M.shape) 97 | #i=0 98 | while max(abs(E-E0))>eps: 99 | E0=np.array(E) 100 | E+=D*np.sign(M-(E-e*np.sin(E))) 101 | D/=2. 102 | #i+=1 103 | #print i 104 | 105 | E*=F 106 | E[np.where(E<0)]+=2*np.pi 107 | E=np.rad2deg(E) 108 | if out_type=='num': E=E[0] 109 | elif out_type=='lst': E=E.tolist() 110 | return E 111 | 112 | 113 | def method4(e,M,eps=1e-8): 114 | '''4th method (approximation) for solving Kepler's equation''' 115 | 116 | #type of output (same as input - number, list, numpy.array) 117 | out_type='lst' 118 | if isinstance(M,int) or isinstance(M,float): 119 | #all input args are numbers 120 | out_type='num' 121 | 122 | if isinstance(M,np.ndarray): 123 | #numpy.array 124 | out_type='np' 125 | 126 | if isinstance(M,list): M=np.array(M) 127 | if out_type=='num': M=np.array([M]) 128 | 129 | M=np.deg2rad(M) 130 | 131 | E=np.arctan2(np.sin(M),np.cos(M)-e) 132 | 133 | E[np.where(E<0)]+=2*np.pi 134 | E=np.rad2deg(E) 135 | if out_type=='num': E=E[0] 136 | elif out_type=='lst': E=E.tolist() 137 | return E -------------------------------------------------------------------------------- /moon.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 47''' 2 | 3 | import math 4 | 5 | from nutation_ecliptic import nutation 6 | from coordinates import ecl2eq 7 | 8 | def position(jd,full=False): 9 | '''equatorial geocentric coordinates of Moon''' 10 | T=(jd-2451545)/36525. 11 | 12 | L=math.radians(218.3164477+481267.88123421*T-0.0015786*T**2+T**3/538841.-T**4/65194000.) 13 | D=math.radians(297.8501921+445267.1114034*T-0.0018819*T**2+T**3/545868.-T**4/113065000.) 14 | M=math.radians(357.5291092+35999.0502909*T-0.0001536*T**2+T**3/24490000.) 15 | Mm=math.radians(134.9633964+477198.8675055*T+0.0087414*T**2+T**3/69699.-T**4/14712000.) 16 | F=math.radians(93.2720950+483202.0175233*T-0.0036539*T**2-T**3/3526000.+T**4/863310000.) 17 | 18 | A1=math.radians(119.75+131.849*T) 19 | A2=math.radians(53.09+479264.290*T) 20 | A3=math.radians(313.45+481266.484*T) 21 | 22 | E=1-0.002516*T-0.0000047*T**2 23 | 24 | args=[[0,0,1,0],[2,0,-1,0],[2,0,0,0],[0,0,2,0],[0,1,0,0],[0,0,0,2],[2,0,-2,0],[2,-1,-1,0],[2,0,1,0],[2,-1,0,0],[0,1,-1,0],[1,0,0,0],[0,1,1,0],[2,0,0,-2],[0,0,1,2],[0,0,1,-2],[4,0,-1,0],\ 25 | [0,0,3,0],[4,0,-2,0],[2,1,-1,0],[2,1,0,0],[1,0,-1,0],[1,1,0,0],[2,-1,1,0],[2,0,2,0],[4,0,0,0],[2,0,-3,0],[0,1,-2,0],[2,0,-1,2],[2,-1,-2,0],[1,0,1,0],[2,-2,0,0],[0,1,2,0],[0,2,0,0],\ 26 | [2,-2,-1,0],[2,0,1,-2],[2,0,0,2],[4,-1,-1,0],[0,0,2,2],[3,0,-1,0],[2,1,1,0],[4,-1,-2,0],[0,2,-1,0],[2,2,-1,0],[2,1,-2,0],[2,-1,0,-2],[4,0,1,0],[0,0,4,0],[4,-1,0,0],[1,0,-2,0],\ 27 | [2,1,0,-2],[0,0,2,-2],[1,1,1,0],[3,0,-2,0],[4,0,-3,0],[2,-1,2,0],[0,2,1,0],[1,1,-1,0],[2,0,3,0],[2,0,-1,-2]] 28 | argsb=[[0,0,0,1],[0,0,1,1],[0,0,1,-1],[2,0,0,-1],[2,0,-1,1],[2,0,-1,-1],[2,0,0,1],[0,0,2,1],[2,0,1,-1],[0,0,2,-1],[2,-1,0,-1],[2,0,-2,-1],[2,0,1,1],[2,1,0,-1],[2,-1,-1,1],[2,-1,0,1],\ 29 | [2,-1,-1,-1],[0,1,-1,-1],[4,0,-1,-1],[0,1,0,1],[0,0,0,3],[0,1,-1,1],[1,0,0,1],[0,1,1,1],[0,1,1,-1],[0,1,0,-1],[1,0,0,-1],[0,0,3,1],[4,0,0,-1],[4,0,-1,1],[0,0,1,-3],[4,0,-2,1],\ 30 | [2,0,0,-3],[2,0,2,-1],[2,-1,1,-1],[2,0,-2,1],[0,0,3,-1],[2,0,2,1],[2,0,-3,-1],[2,1,-1,1],[2,1,0,1],[4,0,0,1],[2,-1,1,1],[2,-2,0,-1],[0,0,1,3],[2,1,1,-1],[1,1,0,-1],[1,1,0,1],\ 31 | [0,1,-2,-1],[2,1,-1,-1],[1,0,1,1],[2,-1,-2,-1],[0,1,2,1],[4,0,-2,-1],[4,-1,-1,-1],[1,0,1,-1],[4,0,1,-1],[1,0,-1,-1],[4,-1,0,-1],[2,-2,0,1]] 32 | args1=[D,M,Mm,F] 33 | 34 | sinC=[6288774,1274027,658314,213618,-185116,-114332,58793,57066,53322,45758,-40923,-34720,-30383,15327,-12528,10980,10675,10034,8548,-7888,-6766,-5163,4987,4036,3994,3861,3665,-2689,-2602,\ 35 | 2390,-2348,2236,-2120,-2069,2048,-1773,-1595,1215,-1110,-892,-810,759,-713,-700,691,596,549,537,520,-487,-399,-381,351,-340,330,327,-323,299,294,0] 36 | cosC=[-20905355,-3699111,-2955968,-569925,48888,-3149,246158,-152138,-170733,-204586,-129620,108743,104755,10321,0,79661,-34782,-23210,-21636,24208,30824,-8379,-16675,-12831,-10445,-11650,\ 37 | 14403,-7003,0,10056,6322,-9884,5751,0,-4950,4130,0,-3958,0,3258,2616,-1897,-2117,2354,0,0,-1423,-1117,-1571,-1739,0,-4421,0,0,0,0,1165,0,0,8752] 38 | bC=[5128122,280602,277693,173237,55413,46271,32573,17198,9266,8822,8216,4324,4200,-3359,2463,2211,2065,-1870,1828,-1794,-1749,-1565,-1491,-1475,-1410,-1344,-1335,1107,1021,833,777,671,607,\ 39 | 596,491,-451,439,422,421,-366,-351,331,315,302,-283,-229,223,223,-220,-220,-185,181,-177,176,166,-164,132,-119,115,107] 40 | 41 | l=0 42 | r=0 43 | b=0 44 | for i in range(len(args)): 45 | tmp=0 46 | tmpb=0 47 | for j in range(len(args1)): 48 | tmp+=args[i][j]*args1[j] 49 | tmpb+=argsb[i][j]*args1[j] 50 | coefE=1 51 | if abs(args[i][1])==1: coefE=E 52 | elif abs(args[i][1])==2: coefE=E**2 53 | l+=sinC[i]*math.sin(tmp)*coefE 54 | r+=cosC[i]*math.cos(tmp)*coefE 55 | coefE=1 56 | if abs(argsb[i][1])==1: coefE=E 57 | elif abs(argsb[i][1])==2: coefE=E**2 58 | b+=bC[i]*math.sin(tmpb)*coefE 59 | 60 | l+=3958*math.sin(A1)+1962*math.sin(L-F)+318*math.sin(A2) 61 | b+=-2235*math.sin(L)+382*math.sin(A3)+175*math.sin(A1-F)+175*math.sin(A1+F)+127*math.sin(L-Mm)-115*math.sin(L+Mm) 62 | 63 | lon=(math.degrees(L)+l/1e6)%360 64 | lat=b/1e6 65 | dist=385000.56+r/1000. 66 | 67 | par=math.degrees(math.asin(6378.14/dist)) 68 | 69 | psi,eps=nutation(jd) 70 | lon+=psi 71 | 72 | ra,dec=ecl2eq(lon,lat) 73 | 74 | if full: return ra,dec,lon,lat,dist,par 75 | return ra,dec 76 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /moon_declination.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 52''' 2 | 3 | import math 4 | 5 | def _common(k): 6 | '''some common values''' 7 | T=k/1336.86 8 | 9 | D=333.0705546*k-0.0004214*T**2+0.00000011*T**3 10 | M=26.9281592*k-0.00003555*T**2-0.00000010*T**3 11 | Mm=356.9562794*k+0.0103066*T**2+0.00001251*T**3 12 | F=1.4467807*k-0.0020690*T**2-0.00000215*T**3 13 | 14 | E=1-0.002516*T-0.0000047*T**2 15 | 16 | jd=27.321582247*k+0.000119804*T**2-0.000000141*T**3 17 | dec=23.6961-0.013004*T 18 | 19 | return D,M,Mm,F,E,jd,dec 20 | 21 | 22 | def north(jd0): 23 | '''maximum northern declination''' 24 | k=(jd0-2451554.4575)/365.25*13.3686 25 | 26 | k=k//1+1 27 | 28 | D,M,Mm,F,E,jd,dec=_common(k) 29 | 30 | D=math.radians(152.2029+D) 31 | M=math.radians(14.8591+M) 32 | Mm=math.radians(4.6881+Mm) 33 | F=math.radians(325.8867+F) 34 | 35 | jd+=2451562.5897 36 | 37 | coef=[0.8975,-0.4726,-0.1030,-0.0976,-0.0462,-0.0461,-0.0438,0.0162*E,-0.0157,0.0145,0.0136,-0.0095,-0.0091,-0.0089,0.0075,-0.0068,0.0061,-0.0047,-0.0043*E,-0.0040,-0.0037,0.0031,0.0030,\ 38 | -0.0029,-0.0029*E,-0.0027,0.0024*E,-0.0021,0.0019,0.0018,0.0018,0.0017,0.0017,-0.0014,0.0013,0.0013,0.0012,0.0011,-0.0011,0.0010,0.0010*E,-0.0009,0.0007,-0.0007] 39 | args=[F,Mm,2*F,2*D-Mm,Mm-F,Mm+F,2*D,M,3*F,Mm+2*F,2*D-F,2*D-Mm-F,2*D-Mm+F,2*D+F,2*Mm,Mm-2*F,2*Mm-F,Mm+3*F,2*D-M-Mm,Mm-2*F,2*D-2*Mm,F,2*D+Mm,Mm+2*F,2*D-M,Mm+F,M-Mm,Mm-3*F,2*Mm+F,2*D-2*Mm-F,\ 40 | 3*F,Mm+3*F,2*Mm,2*D-Mm,2*D+Mm+F,Mm,3*Mm+F,2*D-Mm+F,2*D-2*Mm,D+F,M+Mm,2*D-2*F,2*Mm+F,3*Mm+F] 41 | func=[math.cos,math.sin,math.sin,math.sin,math.cos,math.cos,math.sin,math.sin,math.cos,math.sin,math.cos,math.cos,math.cos,math.cos,math.sin,math.sin,math.cos,math.sin,math.sin,math.cos,\ 42 | math.sin,math.sin,math.sin,math.cos,math.sin,math.sin,math.sin,math.sin,math.sin,math.cos,math.sin,math.cos,math.cos,math.cos,math.cos,math.cos,math.sin,math.sin,math.cos,math.cos,\ 43 | math.sin,math.sin,math.cos,math.cos] 44 | 45 | for i in range(len(args)): jd+=coef[i]*func[i](args[i]) 46 | 47 | coef=[5.1093,0.2658,0.1448,-0.0322,0.0133,0.0125,-0.0124,-0.0101,0.0097,-0.0087*E,0.0074,0.0067,0.0063,0.0060*E,-0.0057,-0.0056,0.0052,0.0041,-0.0040,0.0038,-0.0034,-0.0029,0.0029,-0.0028*E,\ 48 | -0.0028,-0.0023,-0.0021,0.0019,0.0018,0.0017,0.0015,0.0014,-0.0012,-0.0012,-0.0010,-0.0010,0.0006] 49 | args=[F,2*F,2*D-F,3*F,2*D-2*F,2*D,Mm-F,Mm+2*F,F,2*D+M-F,Mm+3*F,D+F,Mm-2*F,2*D-M-F,2*D-Mm-F,Mm+F,Mm+2*F,2*Mm+F,Mm-3*F,2*Mm-F,Mm-2*F,2*Mm,3*Mm+F,2*D+M-F,Mm-F,3*F,2*D+F,Mm+3*F,D+F,2*Mm-F,\ 50 | 3*Mm+F,2*D+2*Mm+F,2*D-2*Mm-F,2*Mm,Mm,2*F,Mm+F] 51 | func=[math.sin,math.cos,math.sin,math.sin,math.cos,math.cos,math.sin,math.sin,math.cos,math.sin,math.sin,math.sin,math.sin,math.sin,math.sin,math.cos,math.cos,math.cos,math.cos,math.cos,\ 52 | math.cos,math.sin,math.sin,math.cos,math.cos,math.cos,math.sin,math.cos,math.cos,math.sin,math.cos,math.cos,math.sin,math.cos,math.cos,math.sin,math.sin] 53 | 54 | for i in range(len(args)): dec+=coef[i]*func[i](args[i]) 55 | 56 | return jd,dec 57 | 58 | 59 | def south(jd0): 60 | '''maximum southern declination''' 61 | k=(jd0-2451554.4575)/365.25*13.3686 62 | 63 | k=k//1+1 64 | 65 | D,M,Mm,F,E,jd,dec=_common(k) 66 | 67 | D=math.radians(345.6676+D) 68 | M=math.radians(1.3951+M) 69 | Mm=math.radians(186.2100+Mm) 70 | F=math.radians(145.1633+F) 71 | 72 | jd+=2451548.9289 73 | 74 | coef=[-0.8975,-0.4726,-0.1030,-0.0976,0.0541,0.0516,-0.0438,0.0112*E,0.0157,0.0023,-0.0136,0.0110,0.0091,0.0089,0.0075,-0.0030,-0.0061,-0.0047,-0.0043*E,0.0040,-0.0037,-0.0031,0.0030,0.0029,\ 75 | -0.0029*E,-0.0027,0.0024*E,-0.0021,-0.0019,-0.0006,-0.0018,-0.0017,0.0017,0.0014,-0.0013,-0.0013,0.0012,0.0011,0.0011,0.0010,0.0010*E,-0.0009,-0.0007,-0.0007] 76 | args=[F,Mm,2*F,2*D-Mm,Mm-F,Mm+F,2*D,M,3*F,Mm+2*F,2*D-F,2*D-Mm-F,2*D-Mm+F,2*D+F,2*Mm,Mm-2*F,2*Mm-F,Mm+3*F,2*D-M-Mm,Mm-2*F,2*D-2*Mm,F,2*D+Mm,Mm+2*F,2*D-M,Mm+F,M-Mm,Mm-3*F,2*Mm+F,2*D-2*Mm-F,\ 77 | 3*F,Mm+3*F,2*Mm,2*D-Mm,2*D+Mm+F,Mm,3*Mm+F,2*D-Mm+F,2*D-2*Mm,D+F,M+Mm,2*D-2*F,2*Mm+F,3*Mm+F] 78 | func=[math.cos,math.sin,math.sin,math.sin,math.cos,math.cos,math.sin,math.sin,math.cos,math.sin,math.cos,math.cos,math.cos,math.cos,math.sin,math.sin,math.cos,math.sin,math.sin,math.cos,\ 79 | math.sin,math.sin,math.sin,math.cos,math.sin,math.sin,math.sin,math.sin,math.sin,math.cos,math.sin,math.cos,math.cos,math.cos,math.cos,math.cos,math.sin,math.sin,math.cos,math.cos,\ 80 | math.sin,math.sin,math.cos,math.cos] 81 | 82 | for i in range(len(args)): jd+=coef[i]*func[i](args[i]) 83 | 84 | coef=[-5.1093,0.2658,-0.1448,0.0322,0.0133,0.0125,-0.0015,0.0101,-0.0097,0.0087*E,0.0074,0.0067,-0.0063,-0.0060*E,0.0057,-0.0056,-0.0052,-0.0041,-0.0040,-0.0038,0.0034,-0.0029,0.0029,\ 85 | 0.0028*E,-0.0028,0.0023,0.0021,0.0019,0.0018,-0.0017,0.0015,0.0014,0.0012,-0.0012,0.0010,-0.0010,0.0037] 86 | args=[F,2*F,2*D-F,3*F,2*D-2*F,2*D,Mm-F,Mm+2*F,F,2*D+M-F,Mm+3*F,D+F,Mm-2*F,2*D-M-F,2*D-Mm-F,Mm+F,Mm+2*F,2*Mm+F,Mm-3*F,2*Mm-F,Mm-2*F,2*Mm,3*Mm+F,2*D+M-F,Mm-F,3*F,2*D+F,Mm+3*F,D+F,2*Mm-F,\ 87 | 3*Mm+F,2*D+2*Mm+F,2*D-2*Mm-F,2*Mm,Mm,2*F,Mm+F] 88 | func=[math.sin,math.cos,math.sin,math.sin,math.cos,math.cos,math.sin,math.sin,math.cos,math.sin,math.sin,math.sin,math.sin,math.sin,math.sin,math.cos,math.cos,math.cos,math.cos,math.cos,\ 89 | math.cos,math.sin,math.sin,math.cos,math.cos,math.cos,math.sin,math.cos,math.cos,math.sin,math.cos,math.cos,math.sin,math.cos,math.cos,math.sin,math.sin] 90 | 91 | for i in range(len(args)): dec+=coef[i]*func[i](args[i]) 92 | 93 | return jd,-dec 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /moon_disk.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 48''' 2 | 3 | import math 4 | 5 | import sun 6 | import moon 7 | 8 | def fraction(jd,angle=False): 9 | '''illuminated fraction or phase angle of the Moon's disk''' 10 | raS,decS=sun.coordinates(jd) 11 | R=sun.distance(jd) 12 | raM,decM,lon,lat,dist,par=moon.position(jd,full=True) 13 | 14 | raS=math.radians(raS) 15 | decS=math.radians(decS) 16 | raM=math.radians(raM) 17 | decM=math.radians(decM) 18 | 19 | psi=math.acos(math.sin(decS)*math.sin(decM)+math.cos(decS)*math.cos(decM)*math.cos(raS-raM)) 20 | i=math.atan(R*math.sin(psi)/(dist-R*math.cos(psi))) 21 | 22 | k=(1+math.cos(i))/2. 23 | 24 | if angle: return math.degrees(i) 25 | return k 26 | 27 | def angle(jd): 28 | '''position angle of the Moon's bright limb''' 29 | raS,decS=sun.coordinates(jd) 30 | raM,decM=moon.position(jd) 31 | 32 | raS=math.radians(raS) 33 | decS=math.radians(decS) 34 | raM=math.radians(raM) 35 | decM=math.radians(decM) 36 | 37 | chi=math.atan2(math.cos(decS)*math.sin(raS-raM),math.sin(decS)*math.cos(decS)-math.cos(decS)*math.sin(decM)*math.cos(raS-raM)) 38 | return math.degrees(chi)%360 39 | -------------------------------------------------------------------------------- /moon_libration.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 53 ''' 2 | 3 | import math 4 | 5 | import moon 6 | import nutation_ecliptic 7 | import sidereal 8 | 9 | I=math.radians(1.54242) #inclination of mean lunar equator to ecliptic 10 | 11 | def optical(jd): 12 | '''optical librations of Moon''' 13 | T=(jd-2451545)/36525. 14 | 15 | F=math.radians(93.2720950+483202.0175233*T-0.0036539*T**2-T**3/3526000.+T**4/863310000.) 16 | w=math.radians(125.0445479-1934.1362891*T+0.0020754*T**2+T**3/467441.-T**4/60616000.) 17 | 18 | ra,dec,lon,lat,dist,par=moon.position(jd,full=True) 19 | psi,eps=nutation_ecliptic.nutation(jd) 20 | 21 | lon=math.radians(lon) 22 | lat=math.radians(lat) 23 | psi=math.radians(psi) 24 | 25 | W=lon-psi-w 26 | A=math.atan2(math.sin(W)*math.cos(lat)*math.cos(I)-math.sin(lat)*math.sin(I),math.cos(W)*math.cos(lat)) 27 | 28 | l=math.degrees(A-F)%360 29 | if l>180: l-=360 30 | 31 | b=math.degrees(math.asin(-math.sin(W)*math.cos(lat)*math.sin(I)-math.sin(lat)*math.cos(I)))%360 32 | if b>180: b-=360 33 | 34 | return l,b 35 | 36 | 37 | def physical(jd): 38 | '''physcial librations of Moon''' 39 | T=(jd-2451545)/36525. 40 | 41 | D=math.radians(297.8501921+445267.1114034*T-0.0018819*T**2+T**3/545868.-T**4/113065000.) 42 | M=math.radians(357.5291092+35999.0502909*T-0.0001536*T**2+T**3/24490000.) 43 | Mm=math.radians(134.9633964+477198.8675055*T+0.0087414*T**2+T**3/69699.-T**4/14712000.) 44 | F=math.radians(93.2720950+483202.0175233*T-0.0036539*T**2-T**3/3526000.+T**4/863310000.) 45 | W=math.radians(125.0445479-1934.1362891*T+0.0020754*T**2+T**3/467441.-T**4/60616000.) 46 | 47 | E=1-0.002516*T-0.0000047*T**2 48 | 49 | K1=math.radians(119.75+131.849*T) 50 | K2=math.radians(72.56+20.186*T) 51 | 52 | rho=-0.02752*math.cos(Mm)-0.02245*math.sin(F)+0.00684*math.cos(Mm-2*F)-0.00293*math.cos(2*F)-0.00085*math.cos(2*F-2*D)-0.00054*math.cos(Mm-2*D)-0.00020*math.sin(Mm+F)-0.00020*math.cos(Mm+2*F)\ 53 | -0.00020*math.cos(Mm-F)+0.00014*math.cos(Mm+2*F-2*D) 54 | sig=-0.02816*math.sin(Mm)+0.02244*math.cos(F)-0.00682*math.sin(Mm-2*F)-0.00279*math.sin(2*F)-0.00083*math.sin(2*F-2*D)+0.00069*math.sin(Mm-2*D)+0.00040*math.cos(Mm+F)-0.00025*math.sin(2*Mm)\ 55 | -0.00023*math.sin(Mm+2*F)+0.00020*math.cos(Mm-F)+0.00019*math.sin(Mm-F)+0.00013*math.sin(Mm+2*F-2*D)-0.00010*math.cos(Mm-3*F) 56 | tau=0.02520*E*math.sin(M)+0.00473*math.sin(2*Mm-2*F)-0.00467*math.sin(Mm)+0.00396*math.sin(K1)+0.00276*math.sin(2*Mm-2*D)+0.00196*math.sin(W)-0.00183*math.cos(Mm-F)+0.00115*math.sin(Mm-2*D)\ 57 | -0.00096*math.sin(Mm-D)+0.00046*math.sin(2*F-2*D)-0.00039*math.sin(Mm-F)-0.00032*E*math.sin(Mm-M-D)+0.00027*E*math.sin(2*Mm-M-2*D)+0.00023*math.sin(K2)-0.00014*math.sin(2*D)\ 58 | +0.00014*math.cos(2*Mm-2*F)-0.00012*math.sin(Mm-2*F)-0.00012*math.sin(2*Mm)+0.00011*E*math.sin(2*Mm-2*M-2*D) 59 | 60 | l1,b1=optical(jd) 61 | A=math.radians(l1)+F 62 | 63 | l=-tau+(rho*math.cos(A)+sig*math.sin(A))*math.tan(math.radians(b1)) 64 | b=sig*math.cos(A)-rho*math.sin(A) 65 | 66 | return l,b 67 | 68 | 69 | def topocentric(jd,lon,lat,correct=True): 70 | '''topocentric libration of Moon''' 71 | ra,dec,lon1,lat1,dist,par=moon.position(jd,full=True) 72 | 73 | sid=sidereal.sid_time(jd) 74 | 75 | ha=math.radians(sid-ra) 76 | dec=math.radians(dec) 77 | par=math.radians(par) 78 | 79 | Q=math.atan2(math.cos(lat)*math.sin(ha),math.cos(dec)*math.sin(lat)-math.sin(dec)*math.cos(lat)*math.cos(ha)) 80 | z=math.acos(math.sin(dec)*math.sin(lat)+math.cos(dec)*math.cos(lat)*math.cos(ha)) 81 | pi=par*(math.sin(z)+0.0084*math.sin(2*z)) 82 | 83 | T=(jd-2451545)/36525. 84 | 85 | D=math.radians(297.8501921+445267.1114034*T-0.0018819*T**2+T**3/545868.-T**4/113065000.) 86 | Mm=math.radians(134.9633964+477198.8675055*T+0.0087414*T**2+T**3/69699.-T**4/14712000.) 87 | F=math.radians(93.2720950+483202.0175233*T-0.0036539*T**2-T**3/3526000.+T**4/863310000.) 88 | W=math.radians(125.0445479-1934.1362891*T+0.0020754*T**2+T**3/467441.-T**4/60616000.) 89 | 90 | rho=-0.02752*math.cos(Mm)-0.02245*math.sin(F)+0.00684*math.cos(Mm-2*F)-0.00293*math.cos(2*F)-0.00085*math.cos(2*F-2*D)-0.00054*math.cos(Mm-2*D)-0.00020*math.sin(Mm+F)-0.00020*math.cos(Mm+2*F)\ 91 | -0.00020*math.cos(Mm-F)+0.00014*math.cos(Mm+2*F-2*D) 92 | sig=-0.02816*math.sin(Mm)+0.02244*math.cos(F)-0.00682*math.sin(Mm-2*F)-0.00279*math.sin(2*F)-0.00083*math.sin(2*F-2*D)+0.00069*math.sin(Mm-2*D)+0.00040*math.cos(Mm+F)-0.00025*math.sin(2*Mm)\ 93 | -0.00023*math.sin(Mm+2*F)+0.00020*math.cos(Mm-F)+0.00019*math.sin(Mm-F)+0.00013*math.sin(Mm+2*F-2*D)-0.00010*math.cos(Mm-3*F) 94 | 95 | psi,eps=nutation_ecliptic.nutation(jd) 96 | eps=math.radians(eps+nutation_ecliptic.ecliptic(jd)) 97 | 98 | V=W+math.radians(psi+sig/math.sin(I)) 99 | X=math.sin(I+rho)*math.sin(V) 100 | Y=math.sin(I+rho)*math.cos(V)*math.cos(eps)-math.cos(I+rho)*math.sin(eps) 101 | 102 | l,b=optical(jd) 103 | l1,b1=physical(jd) 104 | 105 | w=math.atan2(X,Y) 106 | P=math.asin(math.sqrt(X**2+Y**2)*math.cos(math.radians(ra)-w)/math.cos(math.radians(b+b1))) 107 | 108 | dl=-pi*math.sin(Q-P)/math.cos(b) 109 | db=pi*math.cos(Q-P) 110 | 111 | if correct: return l+l1+dl,b+b1+db 112 | 113 | return dl,db 114 | 115 | -------------------------------------------------------------------------------- /moon_nodes.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 51''' 2 | 3 | import math 4 | 5 | def _calculate(k): 6 | T=k/1342.23 7 | 8 | D=math.radians(183.6380+331.73735682*k+0.0014852*T**2+0.00000209*T**3-0.000000010*T**4) 9 | M=math.radians(17.4006+26.82037250*k+0.0001186*T**2+0.00000006*T**3) 10 | Mm=math.radians(38.3776+355.52747313*k+0.0123499*T**2+0.000014627*T**3-0.000000069*T**4) 11 | W=math.radians(123.9767-1.44098956*k+0.0020608*T**2+0.00000214*T**3-0.000000016*T**4) 12 | V=math.radians(299.75+132.85*T-0.009173*T**2) 13 | P=W+math.radians(272.75-2.3*T) 14 | 15 | E=1-0.002516*T-0.0000047*T**2 16 | 17 | jd=2451565.1619+27.212220817*k+0.0002762*T**2+0.000000021*T**3-0.000000000088*T**4 18 | 19 | coef=[-0.4721,-0.1649,-0.0868,0.0084,-0.0083*E,-0.0039*E,0.0034,-0.0031,0.0030*E,0.0028*E,0.0026*E,0.0025,0.0024,0.0022*E,0.0017,0.0014,0.0005*E,0.0004*E,-0.0003*E,0.0003*E,0.0003,0.0003] 20 | args=[Mm,2*D,2*D-Mm,2*D+Mm,2*D-M,2*D-M-Mm,2*Mm,2*D-2*Mm,2*D+M,M-Mm,M,4*D,D,M+Mm,W,4*D-Mm,2*D+M-Mm,2*D-M+Mm,2*D-2*M,4*D-M,V,P] 21 | for i in range(len(args)): 22 | jd+=coef[i]*math.sin(args[i]) 23 | return jd 24 | 25 | 26 | def nodes(jd,asc=True,desc=True): 27 | '''calculate times of passages Moon through the Nodes''' 28 | k=(jd-2451561.7625)/365.25*13.4223 29 | 30 | k0=k//1+1 31 | if k0-k>=0.5: k1=k0-0.5 32 | else: k1=k0+0.5 33 | 34 | out=() 35 | if asc: out+=(_calculate(k0),) 36 | if desc: out+=(_calculate(k1),) 37 | if len(out)==1: out=out[0] 38 | 39 | return out -------------------------------------------------------------------------------- /moon_perigee.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 50''' 2 | 3 | import math 4 | 5 | def _correctionsPeri(jd,k): 6 | T=(jd-2451545)/36525. 7 | 8 | D=math.radians(171.9179+335.9106046*k-0.0100383*T**2-0.00001156*T**3+0.000000055*T**4) 9 | M=math.radians(347.3477+27.1577721*k-0.0008130*T**2-0.0000010*T**3) 10 | F=math.radians(316.6109+364.5287911*k-0.0125053*T**2-0.0000148*T**3) 11 | 12 | args=[2*D,4*D,6*D,8*D,2*D-M,M,10*D,4*D-M,6*D-M,12*D,D,8*D-M,14*D,2*F,3*D,10*D-M,16*D,12*D-M,5*D,2*D+2*F,18*D,14*D-M,7*D,2*D+M,20*D,D+M,16*D-M,4*D+M,9*D,4*D+2*F,2*D-2*M,4*D-2*M,6*D-2*M,\ 13 | 22*D,18*D-M,6*D+M,11*D,8*D+M,4*D-2*F,6*D+2*F,3*D+M,5*D+M,13*D,20*D-M,3*D+2*M,4*D+2*F-2*M,D+2*M,22*D-M,4*F,6*D-2*F,2*D-2*F+M,2*M,2*F-M,2*D+4*F,2*F-2*M,2*D-2*F+2*M,24*D,4*D-4*F,2*D+2*M,D-M] 14 | coef=[-1.6769,0.4589,-0.1856,0.0883,-0.0773+0.00019*T,0.0502-0.00013*T,-0.0460,0.0422-0.00011*T,-0.0256,0.0253,0.0237,0.0162,-0.0145,0.0129,-0.0112,-0.0104,0.0086,0.0069,0.0066,-0.0053,\ 15 | -0.0052,-0.0046,-0.0041,0.0040,0.0032,-0.0032,0.0031,-0.0029,0.0027,0.0027,-0.0027,0.0024,-0.0021,-0.0021,-0.0021,0.0019,-0.0018,-0.0014,-0.0014,-0.0014,0.0014,-0.0014,0.0013,0.0013,\ 16 | 0.0011,-0.0011,-0.0010,-0.0009,-0.0008,0.0008,0.0008,0.0007,0.0007,0.0007,-0.0006,-0.0006,0.0006,0.0005,0.0005,-0.0004] 17 | 18 | for i in range(len(args)): jd+=coef[i]*math.sin(args[i]) 19 | return jd 20 | 21 | def _correctionsApo(jd,k): 22 | T=(jd-2451545)/36525. 23 | 24 | D=math.radians(171.9179+335.9106046*k-0.0100383*T**2-0.00001156*T**3+0.000000055*T**4) 25 | M=math.radians(347.3477+27.1577721*k-0.0008130*T**2-0.0000010*T**3) 26 | F=math.radians(316.6109+364.5287911*k-0.0125053*T**2-0.0000148*T**3) 27 | 28 | args=[2*D,4*D,M,2*D-M,2*F,D,6*D,4*D-M,2*D+2*F,D+M,8*D,6*D-M,2*D-2*F,2*D-2*M,3*D,4*D+2*F,8*D-M,4*D-2*M,10*D,3*D+M,2*M,2*D+M,2*D+2*M,6*D+2*F,6*D-2*M,10*D-M,5*D,4*D-2*F,2*F+M,12*D,2*D+2*F-M,D-M] 29 | coef=[0.4392,0.0684,0.0456-0.00011*T,0.0426-0.00011*T,0.0212,-0.0189,0.0144,0.0113,0.0047,0.0036,0.0035,0.0034,-0.0034,0.0022,-0.0017,0.0013,0.0011,0.0010,0.0009,0.0007,0.0006,0.0005,0.0005,\ 30 | 0.0004,0.0004,0.0004,-0.0004,-0.0004,0.0003,0.0003,0.0003,-0.0003] 31 | 32 | for i in range(len(args)): jd+=coef[i]*math.sin(args[i]) 33 | return jd 34 | 35 | def calculate(jd,perigee=True,apogee=True): 36 | '''calculate times of Moon's perigee and apogee''' 37 | k=(jd-2451534.6698)/365.25*13.2555 38 | 39 | k0=k//1+1 40 | if k0-k>=0.5: k1=k0-0.5 41 | else: k1=k0+0.5 42 | 43 | out=() 44 | if perigee: 45 | T=k0/1325.55 46 | jd0=2451534.6698+27.55454989*k0-0.0006691*T**2-0.000001098*T**3+0.0000000052*T**4 47 | out+=(_correctionsPeri(jd0,k0),) 48 | if apogee: 49 | T=k1/1325.55 50 | jd0=2451534.6698+27.55454989*k1-0.0006691*T**2-0.000001098*T**3+0.0000000052*T**4 51 | out+=(_correctionsApo(jd0,k1),) 52 | if len(out)==1: out=out[0] 53 | 54 | return out 55 | -------------------------------------------------------------------------------- /moon_phases.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 49''' 2 | 3 | import math 4 | 5 | def _corrections(jd,k): 6 | '''corrections to times of phases''' 7 | T=(jd-2451545)/36525. 8 | 9 | E=1-0.002516*T-0.0000047*T**2 10 | 11 | M=math.radians(2.5534+29.10535670*k-0.0000014*T**2-0.00000011*T**3) 12 | Mm=math.radians(201.5643+385.81693528*k+0.0107582*T**2+0.00001238*T**3-0.000000058*T**4) 13 | F=math.radians(160.7108+390.67050284*k-0.0016118*T**2-0.00000227*T**3+0.000000011*T**4) 14 | W=math.radians(124.7746-1.56375588*k+0.0020672*T**2+0.00000215*T**3) 15 | 16 | A=[math.degrees(299.77+0.107408*k-0.009173*T**2),math.degrees(251.88+0.016321*k),math.degrees(251.83+26.651886*k),math.degrees(349.42+36.412478*k),math.degrees(84.66+18.206239*k),\ 17 | math.degrees(141.74+53.303771*k),math.degrees(207.14+2.453732*k),math.degrees(154.84+7.306860*k),math.degrees(34.52+27.261239*k),math.degrees(207.19+0.121824*k),\ 18 | math.degrees(291.34+1.844379*k),math.degrees(161.72+24.198154*k),math.degrees(239.56+25.513099*k),math.degrees(331.55+3.592518*k)] 19 | Ac=[325,165,164,126,110,62,60,56,47,42,40,37,35,23] 20 | 21 | if (k*2)%1==0: 22 | #new or full moon 23 | args=[Mm,M,2*Mm,2*F,Mm-M,Mm+M,2*M,Mm-2*F,Mm+2*F,2*Mm+M,3*Mm,M+2*F,M-2*F,2*Mm-M,W,Mm+2*M,2*Mm-2*F,3*M,Mm+M-2*F,2*Mm+2*F,Mm+M+2*F,Mm-M+2*F,Mm-M-2*F,3*Mm+M,4*Mm] 24 | if k%1==0: 25 | #new moon 26 | coef=[-0.4072,0.17241*E,0.01608,0.01039,0.00739*E,-0.00514*E,0.00208*E**2,-0.00111,-0.00057,0.00056*E,-0.00042,0.00042*E,0.00038*E,-0.00024*E,-0.00017,-0.00007,0.00004,0.00004,\ 27 | 0.00003,0.00003,-0.00003,0.00003,-0.00002,-0.00002,0.00002] 28 | else: 29 | #full moon 30 | coef=[-0.40614,0.17302*E,0.01614,0.01043,0.00734*E,-0.00515*E,0.00209*E**2,-0.00111,-0.00057,0.00056*E,-0.00042,0.00042*E,0.00038*E,-0.00024*E,-0.00017,-0.00007,0.00004,0.00004,\ 31 | 0.00003,0.00003,-0.00003,0.00003,-0.00002,-0.00002,0.00002] 32 | else: 33 | #quaters 34 | args=[Mm,M,Mm+M,2*Mm,2*F,Mm-M,2*M,Mm-2*F,Mm+2*F,3*Mm,2*Mm-M,M+2*F,M-2*F,Mm+2*M,2*Mm+M,W,Mm-M-2*F,2*Mm+2*F,Mm+M+2*F,Mm-2*M,Mm+M-2*F,3*M,2*Mm-2*F,Mm-M+2*F,3*Mm+M] 35 | coef=[-0.62801,0.17172*E,-0.01183*E,0.00862,0.00804,0.00454*E,0.00204*E**2,-0.00180,-0.00070,0.00040,-0.00034*E,0.00032*E,0.00032*E,-0.00028*E**2,0.00027*E,-0.00017,-0.00005,0.00004,\ 36 | -0.00004,0.00004,0.00003,0.00003,0.00002,0.00002,-0.00002] 37 | W=0.00306-0.00038*E*math.cos(M)+0.00026*math.cos(Mm)-0.00002*math.cos(Mm-M)+0.00002*math.cos(Mm+M)+0.00002*math.cos(2*F) 38 | if (k*4)%4==1: jd+=W #first quater 39 | else: jd-=W #last quater 40 | 41 | for i in range(len(args)): jd+=coef[i]*math.sin(args[i]) 42 | for i in range(len(A)): jd+=Ac[i]*1e-6*math.sin(A[i]) 43 | 44 | return jd 45 | 46 | 47 | def _phase(jd,k): 48 | '''calculate time of phase''' 49 | T=k/1236.85 50 | 51 | jd0=2451550.09766+29.530588861*k+0.00015437*T**2-0.000000150*T**3+0.00000000073*T**4 52 | if jd0=0.5: k1=k0-0.5 8 | else: k1=k0+0.5 9 | out=() 10 | if peri: out+=(2451590.257+87.96934963*k0,) 11 | if aphe: out+=(2451590.257+87.96934963*k1,) 12 | if len(out)==1: return out[0] 13 | return out 14 | 15 | def Venus(jd,peri=True,aphe=True): 16 | '''perihelion and aphelion of Venus''' 17 | k=1.62549*(jd-2451738.233)/365.25 18 | k0=k//1+1 19 | if k0-k>=0.5: k1=k0-0.5 20 | else: k1=k0+0.5 21 | out=() 22 | if peri: out+=(2451738.233+224.7008188*k0-0.0000000327*k0**2,) 23 | if aphe: out+=(2451738.233+224.7008188*k1-0.0000000327*k1**2,) 24 | if len(out)==1: return out[0] 25 | return out 26 | 27 | def Earth(jd,peri=True,aphe=True): 28 | '''perihelion and aphelion of Earth''' 29 | k=0.99997*(jd-2451547.507)/365.25 30 | k0=k//1+1 31 | if k0-k>=0.5: k1=k0-0.5 32 | else: k1=k0+0.5 33 | out=() 34 | if peri: out+=(2451547.507+365.2596358*k0+0.0000000156*k0**2,) 35 | if aphe: out+=(2451547.507+365.2596358*k1+0.0000000156*k1**2,) 36 | if len(out)==1: return out[0] 37 | return out 38 | 39 | def Mars(jd,peri=True,aphe=True): 40 | '''perihelion and aphelion of Mars''' 41 | k=0.53166*(jd-2452195.026)/365.25 42 | k0=k//1+1 43 | if k0-k>=0.5: k1=k0-0.5 44 | else: k1=k0+0.5 45 | out=() 46 | if peri: out+=(2452195.026+686.9957857*k0-0.0000001187*k0**2,) 47 | if aphe: out+=(2452195.026+686.9957857*k1-0.0000001187*k1**2,) 48 | if len(out)==1: return out[0] 49 | return out 50 | 51 | def Jupiter(jd,peri=True,aphe=True): 52 | '''perihelion and aphelion of Jupiter''' 53 | k=0.08430*(jd-2455636.936)/365.25 54 | k0=k//1+1 55 | if k0-k>=0.5: k1=k0-0.5 56 | else: k1=k0+0.5 57 | out=() 58 | if peri: out+=(2455636.936+4332.897065*k0+0.0001367*k0**2,) 59 | if aphe: out+=(2455636.936+4332.897065*k1+0.0001367*k1**2,) 60 | if len(out)==1: return out[0] 61 | return out 62 | 63 | def Saturn(jd,peri=True,aphe=True): 64 | '''perihelion and aphelion of Saturn''' 65 | k=0.03393*(jd-2452830.120)/365.25 66 | k0=k//1+1 67 | if k0-k>=0.5: k1=k0-0.5 68 | else: k1=k0+0.5 69 | out=() 70 | if peri: out+=(2452830.120+10764.21676*k0+0.000827*k0**2,) 71 | if aphe: out+=(2452830.120+10764.21676*k1+0.000827*k1**2,) 72 | if len(out)==1: return out[0] 73 | return out 74 | 75 | def Uranus(jd,peri=True,aphe=True): 76 | '''perihelion and aphelion of Uranus''' 77 | k=0.01190*(jd-2470213.500)/365.25 78 | k0=k//1+1 79 | if k0-k>=0.5: k1=k0-0.5 80 | else: k1=k0+0.5 81 | out=() 82 | if peri: out+=(2470213.500+30694.8767*k0-0.00541*k0**2,) 83 | if aphe: out+=(2470213.500+30694.8767*k1-0.00541*k1**2,) 84 | if len(out)==1: return out[0] 85 | return out 86 | 87 | def Neptune(jd,peri=True,aphe=True): 88 | '''perihelion and aphelion of Neptune''' 89 | k=0.00607*(jd-2468895.100)/365.25 90 | k0=k//1+1 91 | if k0-k>=0.5: k1=k0-0.5 92 | else: k1=k0+0.5 93 | out=() 94 | if peri: out+=(2468895.100+60190.33*k0+0.03429*k0**2,) 95 | if aphe: out+=(2468895.100+60190.33*k1+0.03429*k1**2,) 96 | if len(out)==1: return out[0] 97 | return out 98 | -------------------------------------------------------------------------------- /physical_sun.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 29''' 2 | 3 | import math 4 | 5 | from nutation_ecliptic import nutation,ecliptic 6 | from sun import longitude 7 | 8 | def PBL(jd): 9 | '''calculate position angle P, heliographic lat. of center L0, hel. long. of center B0''' 10 | th=(jd-2398220)*360/25.38 11 | I=math.radians(7.25) 12 | K=math.radians(73.6667+1.3958333*(jd-2396758)/36525.) 13 | 14 | psi,eps=nutation(jd) 15 | eps=math.radians(eps+ecliptic(jd)) 16 | psi=math.radians(psi) 17 | 18 | lon=math.radians(longitude(jd)) 19 | 20 | x=math.degrees(math.atan(-math.cos(lon+psi)*math.tan(eps))) 21 | y=math.degrees(math.atan(-math.cos(lon-K)*math.tan(I))) 22 | 23 | P=x+y 24 | B=math.degrees(math.asin(math.sin(lon-K)*math.sin(I))) 25 | nu=math.degrees(math.atan2(-math.sin(lon-K)*math.cos(I),-math.cos(lon-K))) 26 | 27 | L=(nu-th)%360 28 | 29 | return P,B,L 30 | 31 | def rotation(jd): 32 | '''Carrington rotation number''' 33 | jd0=2398140.10155 34 | return int(((jd-jd0)/27.2752316)//1) 35 | 36 | def rotation_start(n): 37 | '''time of begining Carrington rotation''' 38 | jd=2398140.2270+27.2752316*n 39 | 40 | M=math.radians(281.96+26.882476*n) 41 | return jd+0.1454*math.sin(M)-0.0085*math.sin(2*M)-0.0141*math.cos(2*M) 42 | -------------------------------------------------------------------------------- /planets.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 33''' 2 | 3 | import math 4 | 5 | import position 6 | import coordinates 7 | 8 | def _calculate(L,B,r,jd): 9 | L0,B0,r0=position.Earth(jd) 10 | 11 | L=math.radians(L) 12 | B=math.radians(B) 13 | L0=math.radians(L0) 14 | B0=math.radians(B0) 15 | 16 | x=r*math.cos(B)*math.cos(L)-r0*math.cos(B0)*math.cos(L0) 17 | y=r*math.cos(B)*math.sin(L)-r0*math.cos(B0)*math.sin(L0) 18 | z=r*math.sin(B)-r0*math.sin(B0) 19 | 20 | l=math.degrees(math.atan2(y,x)) 21 | b=math.degrees(math.atan2(z,math.sqrt(x**2+y**2))) 22 | 23 | return coordinates.ecl2eq(l,b) 24 | 25 | def Mercury(jd): 26 | '''equatorial coordinates of Mercury''' 27 | L,B,r=position.Mercury(jd) 28 | return _calculate(L,B,r,jd) 29 | 30 | def Venus(jd): 31 | '''equatorial coordinates of Venus''' 32 | L,B,r=position.Venus(jd) 33 | return _calculate(L,B,r,jd) 34 | 35 | def Mars(jd): 36 | '''equatorial coordinates of Mars''' 37 | L,B,r=position.Mars(jd) 38 | return _calculate(L,B,r,jd) 39 | 40 | def Jupiter(jd): 41 | '''equatorial coordinates of Jupiter''' 42 | L,B,r=position.Jupiter(jd) 43 | return _calculate(L,B,r,jd) 44 | 45 | def Saturn(jd): 46 | '''equatorial coordinates of Saturn''' 47 | L,B,r=position.Saturn(jd) 48 | return _calculate(L,B,r,jd) 49 | 50 | def Uranus(jd): 51 | '''equatorial coordinates of Uranus''' 52 | L,B,r=position.Uranus(jd) 53 | return _calculate(L,B,r,jd) 54 | 55 | def Neptune(jd): 56 | '''equatorial coordinates of Neptune''' 57 | L,B,r=position.Neptune(jd) 58 | return _calculate(L,B,r,jd) 59 | -------------------------------------------------------------------------------- /position.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 32''' 2 | '''using VSOP87 data from http://cdsarc.u-strasbg.fr/viz-bin/Cat?cat=VI%2F81&target=brief&''' 3 | 4 | import math 5 | 6 | def _load(name,jd): 7 | T=(jd-2451545.0)/365250. 8 | 9 | f=open(name,'r') 10 | 11 | L=0 12 | B=0 13 | r=0 14 | tmp=0 15 | 16 | for l in f: 17 | temp=l.split() 18 | try: float(temp[0]) 19 | except: 20 | if abs(tmp)>0: 21 | if v==1: L+=tmp*T**n 22 | elif v==2: B+=tmp*T**n 23 | elif v==3: r+=tmp*T**n 24 | i=l.find('**') 25 | n=int(l[i+2:i+4]) 26 | i=l.find('VARIABLE') 27 | v=int(l[i+8:i+11]) 28 | tmp=0 29 | continue 30 | tmp+=float(temp[-3])*math.cos(float(temp[-2])+float(temp[-1])*T) 31 | if v==1: L+=tmp*T**n 32 | elif v==2: B+=tmp*T**n 33 | elif v==3: r+=tmp*T**n 34 | f.close() 35 | 36 | Ll=L-math.radians(1.397*T+0.00031*T**2) 37 | L+=math.radians((-0.09033+0.03916*(math.cos(Ll)+math.sin(Ll))*math.tan(B))/3600.) 38 | B+=math.radians(0.03916*(math.cos(Ll)-math.sin(Ll))/3600.) 39 | 40 | L=math.degrees(L)%360 41 | B=math.degrees(B)%360 42 | 43 | if B>180: B-=360 44 | 45 | return L,B,r 46 | 47 | def Mercury(jd): 48 | '''heliocentric coordinates of Mercury''' 49 | return _load('vsop87/VSOP87B.mer',jd) 50 | 51 | def Venus(jd): 52 | '''heliocentric coordinates of Venus''' 53 | return _load('vsop87/VSOP87B.ven',jd) 54 | 55 | def Earth(jd): 56 | '''heliocentric coordinates of Earth''' 57 | return _load('vsop87/VSOP87B.ear',jd) 58 | 59 | def Mars(jd): 60 | '''heliocentric coordinates of Mars''' 61 | return _load('vsop87/VSOP87B.mar',jd) 62 | 63 | def Jupiter(jd): 64 | '''heliocentric coordinates of Jupiter''' 65 | return _load('vsop87/VSOP87B.jup',jd) 66 | 67 | def Saturn(jd): 68 | '''heliocentric coordinates of Saturn''' 69 | return _load('vsop87/VSOP87B.sat',jd) 70 | 71 | def Uranus(jd): 72 | '''heliocentric coordinates of Uranus''' 73 | return _load('vsop87/VSOP87B.ura',jd) 74 | 75 | def Neptune(jd): 76 | '''heliocentric coordinates of Neptune''' 77 | return _load('vsop87/VSOP87B.nep',jd) 78 | -------------------------------------------------------------------------------- /precession.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 21''' 2 | 3 | #import numpy as np 4 | import math 5 | 6 | def precession(jd,jd0,ra,dec): 7 | '''calculate precession of (ra,dec) from epoch jd0 to jd''' 8 | T=(jd0-2451545)/36525. 9 | t=(jd-jd0)/36525. 10 | 11 | s=math.radians(((2306.2181+1.39656*T-0.000139*T**2)*t+(0.30188-0.000344*T)*t**2+0.017998*t**3)/3600.) 12 | z=math.radians(((2306.2181+1.39656*T-0.000139*T**2)*t+(1.09468+0.000066*T)*t**2+0.018203*t**3)/3600.) 13 | th=math.radians(((2004.3109-0.85330*T-0.000217*T**2)*t-(0.42665+0.000217*T)*t**2-0.041833*t**3)/3600.) 14 | 15 | ra=math.radians(ra) 16 | dec=math.radians(dec) 17 | 18 | A=math.cos(dec)*math.sin(ra+s) 19 | B=math.cos(th)*math.cos(dec)*math.cos(ra+s)-math.sin(th)*math.sin(dec) 20 | C=math.sin(th)*math.cos(dec)*math.cos(ra+s)+math.cos(th)*math.sin(dec) 21 | 22 | ra=math.degrees(z+math.atan2(A,B)) 23 | dec=math.degrees(math.asin(C)) 24 | 25 | return ra,dec 26 | 27 | def ecliptic(jd,jd0,lam,bet): 28 | '''calculate precession of (lam,bet) from epoch jd0 to jd''' 29 | T=(jd0-2451545)/36525. 30 | t=(jd-jd0)/36525. 31 | 32 | n=math.radians(((47.0029-0.06603*T+0.000598*T**2)*t+(-0.03302+0.000598*T)*t**2+0.000060*t**3)/3600.) 33 | P=math.radians(174.876384+(3289.4789*T+0.60622*T**2-(869.8089+0.50491*T)*t+0.03536*t**2)/3600.) 34 | p=math.radians(((5029.0966-2.22226*T-0.000042*T**2)*t+(1.11113-0.000042*T)*t**2-0.000006*t**3)/3600.) 35 | 36 | lam=math.radians(lam) 37 | bet=math.radians(bet) 38 | 39 | A=math.cos(n)*math.cos(bet)*math.sin(P-lam)-math.sin(n)*math.sin(bet) 40 | B=math.cos(bet)*math.cos(P-lam) 41 | C=math.cos(n)*math.sin(bet)+math.sin(n)*math.cos(bet)*math.sin(P-lam) 42 | 43 | lam=math.degrees(p+P-math.atan2(A,B)) 44 | bet=math.degrees(math.asin(C)) 45 | 46 | return lam,bet -------------------------------------------------------------------------------- /refraction.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 16''' 2 | 3 | import numpy as np 4 | 5 | def apparent(alt,correction=False): 6 | '''refraction for apparent altitude (with optional correction)''' 7 | 8 | #type of output (same as input - number, list, numpy.array) 9 | out_type='lst' 10 | if (isinstance(alt,int) or isinstance(alt,float)): 11 | #all input args are numbers 12 | out_type='num' 13 | 14 | if isinstance(alt,np.ndarray): 15 | #numpy.array 16 | out_type='np' 17 | 18 | if isinstance(alt,list): alt=np.array(alt) 19 | 20 | if out_type=='num': alt=np.array([alt]) 21 | 22 | R=1/np.tan(np.deg2rad(alt+7.31/(alt+4.4)))/60. 23 | 24 | if correction: R=alt-R 25 | 26 | if out_type=='num': 27 | R=R[0] 28 | elif out_type=='lst': 29 | R=R.tolist() 30 | return R 31 | 32 | 33 | def real(alt,correction=False): 34 | '''refraction for real altitude (with optional correction)''' 35 | 36 | #type of output (same as input - number, list, numpy.array) 37 | out_type='lst' 38 | if (isinstance(alt,int) or isinstance(alt,float)): 39 | #all input args are numbers 40 | out_type='num' 41 | 42 | if isinstance(alt,np.ndarray): 43 | #numpy.array 44 | out_type='np' 45 | 46 | if isinstance(alt,list): alt=np.array(alt) 47 | 48 | if out_type=='num': alt=np.array([alt]) 49 | 50 | R=1.02/np.tan(np.deg2rad(alt+10.3/(alt+5.11)))/60. 51 | 52 | if correction: R+=alt 53 | 54 | if out_type=='num': 55 | R=R[0] 56 | elif out_type=='lst': 57 | R=R.tolist() 58 | return R 59 | -------------------------------------------------------------------------------- /rising.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 15''' 2 | 3 | import numpy as np 4 | 5 | def rising(dec,lat): 6 | '''local hour angle for rising (alt=0 deg) - without refraction''' 7 | 8 | #type of output (same as input - number, list, numpy.array) 9 | out_type='lst' 10 | if (isinstance(dec,int) or isinstance(dec,float)) and (isinstance(lat,int) or isinstance(lat,float)): 11 | #all input args are numbers 12 | out_type='num' 13 | 14 | if isinstance(dec,np.ndarray) or isinstance(lat,np.ndarray): 15 | #numpy.array 16 | out_type='np' 17 | 18 | if isinstance(dec,list): dec=np.array(dec) 19 | if isinstance(lat,list): lat=np.array(lat) 20 | 21 | 22 | if out_type=='num': dec=np.array([dec]) 23 | 24 | dec=np.deg2rad(dec) 25 | lat=np.deg2rad(lat) 26 | 27 | ha=np.arccos(-np.tan(lat)*np.tan(dec)) 28 | 29 | ha=np.rad2deg(ha) 30 | 31 | if out_type=='num': 32 | ha=ha[0] 33 | elif out_type=='lst': 34 | ha=ha.tolist() 35 | return ha 36 | 37 | def times(dec,ra,lat,lon,sid0): 38 | '''calculate time of rising, transit and setting; sid0 - sidereal time at Oh UT at Greenwich''' 39 | #type of output (same as input - number, list, numpy.array) 40 | out_type='lst' 41 | if (isinstance(dec,int) or isinstance(dec,float)) and (isinstance(ra,int) or isinstance(ra,float)) and (isinstance(lat,int) or isinstance(lat,float)) and (isinstance(lon,int) or isinstance(lon,float)) and (isinstance(sid0,int) or isinstance(sid0,float)): 42 | #all input args are numbers 43 | out_type='num' 44 | 45 | if isinstance(dec,np.ndarray) or isinstance(ra,np.ndarray) or isinstance(lat,np.ndarray) or isinstance(lon,np.ndarray) or isinstance(sid0,np.ndarray): 46 | #numpy.array 47 | out_type='np' 48 | 49 | if isinstance(dec,list): dec=np.array(dec) 50 | if isinstance(ra,list): ra=np.array(ra) 51 | if isinstance(lat,list): lat=np.array(lat) 52 | if isinstance(lon,list): lon=np.array(lon) 53 | if isinstance(sid0,list): sid0=np.array(sid0) 54 | 55 | 56 | if out_type=='num': sid0=np.array([sid0]) 57 | 58 | dec=np.deg2rad(dec) 59 | lat=np.deg2rad(lat) 60 | 61 | ha=np.arccos(-np.tan(lat)*np.tan(dec)) 62 | 63 | ha=np.rad2deg(ha) 64 | 65 | t=(ra-lon-sid0)/360. #transit 66 | r=t-ha/360. #rise 67 | s=t+ha/360. #set 68 | 69 | r*=24 70 | t*=24 71 | s*=24 72 | 73 | r=r%24 74 | t=t%24 75 | s=s%24 76 | 77 | if out_type=='num': 78 | r=r[0] 79 | t=t[0] 80 | s=s[0] 81 | elif out_type=='lst': 82 | r=r.tolist() 83 | t=t.tolist() 84 | s=s.tolist() 85 | return r,t,s 86 | 87 | 88 | -------------------------------------------------------------------------------- /separation.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 17''' 2 | 3 | import math 4 | 5 | def separation(ra1,dec1,ra2,dec2): 6 | '''angular separation between 2 objects''' 7 | dec1=math.radians(dec1) 8 | dec2=math.radians(dec2) 9 | ra=math.radians(ra1-ra2) 10 | d=math.acos(math.sin(dec1)*math.sin(dec2)+math.cos(dec1)*math.cos(dec2)*math.cos(ra)) 11 | return math.degrees(d) 12 | 13 | def positionAngle(ra1,dec1,ra2,dec2): 14 | '''position angle of (ra1,dec1) with respect to (ra2,dec2)''' 15 | dec1=math.radians(dec1) 16 | dec2=math.radians(dec2) 17 | ra=math.radians(ra1-ra2) 18 | P=math.degrees(math.atan2(math.sin(ra),math.cos(dec2)*math.tan(dec1)-math.sin(dec2)*math.cos(ra))) 19 | P=P%360 20 | return P 21 | 22 | -------------------------------------------------------------------------------- /sidereal.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 12''' 2 | 3 | def sid_time(jd,deg=True): 4 | '''sidereal time on Greenwich in degrees or hours''' 5 | T=(jd-2451545.0)/36525 6 | sid=280.46061837+360.98564736629*(jd-2451545.0)+0.000387933*T**2-T**3/38710000 7 | sid=sid%360 8 | if deg: return sid 9 | else: return sid/15. 10 | -------------------------------------------------------------------------------- /sun.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 25''' 2 | 3 | import math 4 | 5 | from nutation_ecliptic import ecliptic 6 | from constants import AU 7 | 8 | def coordinates(jd): 9 | '''equatorial coordinates of Sun''' 10 | lon=math.radians(longitude(jd)) 11 | 12 | eps=math.radians(ecliptic(jd)) 13 | 14 | ra=math.degrees(math.atan2(math.cos(eps)*math.sin(lon),math.cos(lon))) 15 | dec=math.degrees(math.asin(math.sin(eps)*math.sin(lon))) 16 | 17 | return ra,dec 18 | 19 | 20 | def longitude(jd): 21 | '''longitude of Sun''' 22 | T=(jd-2451545)/36525. 23 | 24 | L=math.radians(280.46646+36000.76983*T+0.0003032*T**2) 25 | M=math.radians(357.52911+35999.05029*T-0.0001537*T**2) 26 | 27 | C=math.radians((1.914602-0.004817*T-0.000014*T**2)*math.sin(M)+(0.019993-0.000101*T)*math.sin(2*M)+0.000289*math.sin(3*M)) 28 | 29 | lon=L+C 30 | 31 | return math.degrees(lon) 32 | 33 | 34 | def distance(jd,km=True): 35 | '''Earth-Sun distance in km''' 36 | T=(jd-2451545)/36525. 37 | e=0.016708634-0.000042037*T-0.0000001267*T**2 38 | M=math.radians(357.52911+35999.05029*T-0.0001537*T**2) 39 | 40 | C=math.radians((1.914602-0.004817*T-0.000014*T**2)*math.sin(M)+(0.019993-0.000101*T)*math.sin(2*M)+0.000289*math.sin(3*M)) 41 | 42 | nu=M+C 43 | R=1.000001018*(1-e**2)/(1+e*math.cos(nu)) 44 | 45 | if km: R*=AU 46 | return R 47 | 48 | -------------------------------------------------------------------------------- /sun_coordinates.py: -------------------------------------------------------------------------------- 1 | '''Meeus: Astronomical Algorithms (2nd ed.), chapter 26''' 2 | 3 | import math 4 | 5 | import position 6 | import nutation_ecliptic 7 | 8 | def coordinates(jd): 9 | '''rectangular coordinates of Sun to mean equinox''' 10 | LE,BE,r=position.Earth(jd) 11 | 12 | L=math.radians(LE+180) 13 | B=-math.radians(BE) 14 | eps=math.radians(nutation_ecliptic.ecliptic(jd)) 15 | 16 | X=r*math.cos(B)*math.cos(L) 17 | Y=r*(math.cos(B)*math.sin(L)*math.cos(eps)-math.sin(B)*math.sin(eps)) 18 | Z=r*(math.cos(B)*math.sin(L)*math.sin(eps)+math.sin(B)*math.cos(eps)) 19 | 20 | return X,Y,Z 21 | -------------------------------------------------------------------------------- /vsop87/readme.md: -------------------------------------------------------------------------------- 1 | Files from webpage: http://cdsarc.u-strasbg.fr/viz-bin/Cat?cat=VI%2F81&target=brief&. 2 | -------------------------------------------------------------------------------- /vsop87/vsop87.txt: -------------------------------------------------------------------------------- 1 | ============ 2 | VSOP87 FILES BDL-9502 3 | ============ 4 | 5 | 6 | REFERENCE 7 | ========= 8 | 9 | Bretagnon P., Francou G., : 1988, Astron. Astrophys., 202, 309. 10 | 11 | 12 | ADRESS 13 | ====== 14 | 15 | Pierre Bretagnon, Gerard Francou 16 | Bureau des Longitudes 17 | 77, Avenue Denfert-Rochereau 18 | F75014, Paris, France 19 | Tel : (1) 40 51 22 69 (1) 40 51 22 60 20 | E-Mail : pierre@bdl.fr francou@bdl.fr 21 | Fax : (1) 46 33 28 34 22 | 23 | 24 | DESCRIPTION 25 | =========== 26 | 27 | The VSOP87 files contain the VSOP87 analytical solutions of the motion 28 | of the planets Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, 29 | Neptune and Earth-Moon Barycenter. 30 | 31 | There are six different versions of the theory VSOP87 which may be recognized 32 | by the type of coordinates and the reference frame. 33 | 34 | The main version VSOP87 consists of the series in elliptic elements as in the 35 | case of previous solution VSOP82 and the other versions VSOP87 are built in 36 | rectangular variables (versions A,C,E) or spherical variables (versions B,D). 37 | 38 | The reference frame is defined by the dynamical equinox and ecliptic J2000 for 39 | the main version VSOP87 and the versions A, B, E, and by the dynamical equinox 40 | and ecliptic of the date for the versions C and D. 41 | 42 | 43 | FILE SUMMARY 44 | ============ 45 | 46 | Name Size Kb Contents 47 | ---- ------- -------- 48 | 49 | VSOP87.mer 644.1 Mercury Heliocentric elliptic elements J2000 50 | VSOP87.ven 401.4 Venus Heliocentric elliptic elements J2000 51 | VSOP87.emb 563.0 Earth-Moon Heliocentric elliptic elements J2000 52 | VSOP87.mar 1002.8 Mars Heliocentric elliptic elements J2000 53 | VSOP87.jup 812.5 Jupiter Heliocentric elliptic elements J2000 54 | VSOP87.sat 1645.9 Saturn Heliocentric elliptic elements J2000 55 | VSOP87.ura 2023.2 Uranus Heliocentric elliptic elements J2000 56 | VSOP87.nep 1070.5 Neptune Heliocentric elliptic elements J2000 57 | 58 | VSOP87A.mer 848.1 Mercury Heliocentric rectangular variables J2000 59 | VSOP87A.ven 315.9 Venus Heliocentric rectangular variables J2000 60 | VSOP87A.ear 472.9 Earth Heliocentric rectangular variables J2000 61 | VSOP87A.emb 444.2 Earth-Moon Heliocentric rectangular variables J2000 62 | VSOP87A.mar 943.1 Mars Heliocentric rectangular variables J2000 63 | VSOP87A.jup 592.1 Jupiter Heliocentric rectangular variables J2000 64 | VSOP87A.sat 1001.5 Saturn Heliocentric rectangular variables J2000 65 | VSOP87A.ura 705.3 Uranus Heliocentric rectangular variables J2000 66 | VSOP87A.nep 352.5 Neptune Heliocentric rectangular variables J2000 67 | 68 | VSOP87B.mer 949.8 Mercury Heliocentric spherical variables J2000 69 | VSOP87B.ven 229.8 Venus Heliocentric spherical variables J2000 70 | VSOP87B.ear 343.4 Earth Heliocentric spherical variables J2000 71 | VSOP87B.mar 853.6 Mars Heliocentric spherical variables J2000 72 | VSOP87B.jup 484.5 Jupiter Heliocentric spherical variables J2000 73 | VSOP87B.sat 848.9 Saturn Heliocentric spherical variables J2000 74 | VSOP87B.ura 702.6 Uranus Heliocentric spherical variables J2000 75 | VSOP87B.nep 270.9 Neptune Heliocentric spherical variables J2000 76 | 77 | VSOP87C.mer 1087.0 Mercury Heliocentric rectangular variables of date 78 | VSOP87C.ven 386.6 Venus Heliocentric rectangular variables of date 79 | VSOP87C.ear 560.1 Earth Heliocentric rectangular variables of date 80 | VSOP87C.mar 1106.7 Mars Heliocentric rectangular variables of date 81 | VSOP87C.jup 741.2 Jupiter Heliocentric rectangular variables of date 82 | VSOP87C.sat 1170.5 Saturn Heliocentric rectangular variables of date 83 | VSOP87C.ura 932.3 Uranus Heliocentric rectangular variables of date 84 | VSOP87C.nep 385.4 Neptune Heliocentric rectangular variables of date 85 | 86 | VSOP87D.mer 910.4 Mercury Heliocentric spherical variables of date 87 | VSOP87D.ven 226.1 Venus Heliocentric spherical variables of date 88 | VSOP87D.ear 324.8 Earth Heliocentric spherical variables of date 89 | VSOP87D.mar 731.6 Mars Heliocentric spherical variables of date 90 | VSOP87D.jup 465.6 Jupiter Heliocentric spherical variables of date 91 | VSOP87D.sat 768.3 Saturn Heliocentric spherical variables of date 92 | VSOP87D.ura 532.7 Uranus Heliocentric spherical variables of date 93 | VSOP87D.nep 258.8 Neptune Heliocentric spherical variables of date 94 | 95 | VSOP87E.mer 1050.4 Mercury Barycentric rectangular variables J2000 96 | VSOP87E.ven 621.8 Venus Barycentric rectangular variables J2000 97 | VSOP87E.ear 741.3 Earth Barycentric rectangular variables J2000 98 | VSOP87E.mar 1009.9 Mars Barycentric rectangular variables J2000 99 | VSOP87E.jup 606.5 Jupiter Barycentric rectangular variables J2000 100 | VSOP87E.sat 1002.8 Saturn Barycentric rectangular variables J2000 101 | VSOP87E.ura 683.5 Uranus Barycentric rectangular variables J2000 102 | VSOP87E.nep 319.6 Neptune Barycentric rectangular variables J2000 103 | VSOP87E.sun 884.7 Sun Barycentric rectangular variables J2000 104 | -------------------------------------------------------------------------------- 105 | 106 | 107 | CONTENTS 108 | ======== 109 | 110 | A VSOP87 file deals with a body and a version of the theory. 111 | It contains trigonometric series which represent the coordinates of the body : 112 | elliptic, rectangular or spherical coordinates according to the version. 113 | 114 | These coordinates are functions of time, periodic and Poisson series, 115 | given under two forms : 116 | 117 | (1) T**alpha * (S sin phi + K cos phi) 118 | with : phi = SUM [i=1,12] [a(i)*lambda(i)] 119 | 120 | (2) T**alpha * A * cos(B+CT) 121 | 122 | where T : time expressed in Thousands of Julian Years (tjy) 123 | elapsed from J2000 (JD2451545.0). 124 | alpha : degree of time in-between 0 and 5. 125 | 126 | The amplitudes S, K and A are expressed in au/(tjy**alpha) for the distances 127 | and in rad/(tjy**alpha) for angular variables. 128 | The phase B is expressed in radians. 129 | The frequency C is expressed in rad/tjy. 130 | The coefficients a(i) are integers. 131 | 132 | The means longitudes lambda(i) are expressed in radians : 133 | lambda (1) = 4.40260884240 + 26087.9031415742 * T Mercury 134 | lambda (2) = 3.17614669689 + 10213.2855462110 * T Venus 135 | lambda (3) = 1.75347045953 + 6283.0758499914 * T Earth 136 | lambda (4) = 6.20347611291 + 3340.6124266998 * T Mars 137 | lambda (5) = 0.59954649739 + 529.6909650946 * T Jupiter 138 | lambda (6) = 0.87401675650 + 213.2990954380 * T Saturn 139 | lambda (7) = 5.48129387159 + 74.7815985673 * T Uranus 140 | lambda (8) = 5.31188628676 + 38.1330356378 * T Neptune 141 | lambda (9) = 5.19846674103 + 77713.7714681205 * T Moon D 142 | lambda (10) = 1.62790523337 + 84334.6615813083 * T Moon F 143 | lambda (11) = 2.35555589827 + 83286.9142695536 * T Moon l 144 | lambda (12) = 3.81034454697 + 83997.0911355954 * T Moon Lm 145 | 146 | In a VSOP87 file the series of each coordinates are recognized by the degree 147 | alpha of time variable T : 148 | - periodic series : alpha=0, 149 | - Poisson series : alpha>0. 150 | 151 | Series follow one another according to the order of coordinates and for each 152 | coordinate they follow one another by increasing order of time alpha. 153 | 154 | For each term of a serie there is one record in the file. 155 | 156 | The terms of the series are placed according to decreasing values of the sum 157 | of absolute value of S plus absolute value of K. 158 | 159 | The quantities related to one term are placed in the order : 160 | a(i) (i=1,12), S, K, A, B, C. 161 | 162 | 163 | ORGANIZATION 164 | ============ 165 | 166 | In VSOP87 files, there are two types of records : 167 | (a) "header record" : characteristics of the series. 168 | (b) "term record" : quantities linked to one term of a serie. 169 | 170 | For each file, a serie corresponds to one "header record" (a) followed 171 | by one or several "term records" (b). 172 | 173 | 174 | HEADER RECORD 175 | ============= 176 | 177 | Fortran format : 17x,i1,4x,a7,12x,i1,17x,i1,i7 178 | 179 | Specifications : 180 | - iv : code of VSOP87 version integer i1 col.18 181 | - bo : name of body character a7 col.23-29 182 | - ic : index of coordinate integer i1 col.42 183 | - it : degree alpha of time variable T integer i1 col.60 184 | - in : number of terms of series integer i7 col.61-67 185 | 186 | The code iv of the version is : 187 | iv = 0 for the main version VSOP87 188 | iv = 1 for the version VSOP87A 189 | iv = 2 for the version VSOP87B 190 | iv = 3 for the version VSOP87C 191 | iv = 4 for the version VSOP87D 192 | iv = 5 for the version VSOP87E 193 | 194 | The names bo of the bodies are : 195 | MERCURY, VENUS, EARTH, MARS, JUPITER, SATURN, URANUS, NEPTUNE, SUN, 196 | and EMB for the Earth-Moon Barycenter. 197 | 198 | The index ic of the coordinates are : 199 | - for the elliptic coordinates (main version) : 200 | 1 : semi-major axis 201 | 2 : mean longitude 202 | 3 : k = e cos(p) e : eccentricity 203 | 4 : h = e sin(p) p : perihelion longitude 204 | 5 : q = sin(g) cos(G) g : semi-inclination 205 | 6 : p = sin(g) sin(G) G : ascending node longitude 206 | - for the rectangular coordinates (versions A,C,E) : 207 | 1 : X 208 | 2 : Y 209 | 3 : Z 210 | - for the spherical coordinates (versions B,D) : 211 | 1 : Longitude 212 | 2 : Latitude 213 | 3 : Radius 214 | 215 | The degree alpha of the time variable is equal to : 216 | 0 for periodic series, 1 to 5 for Poisson series. 217 | 218 | 219 | TERM RECORD 220 | =========== 221 | 222 | Fortran format : 1x,4i1,i5,12i3,f15.11,2f18.11,f14.11,f20.11 223 | 224 | Specifications : 225 | iv : code of VSOP87 version integer i1 col.02 226 | ib : code of body integer i1 col.03 227 | ic : index of coordinate integer i1 col.04 228 | it : degree alpha of time variable T integer i1 col.05 229 | n : rank of the term in a serie integer i5 col.06-10 230 | a : 12 coefficients a of mean longitudes integer 12i3 col.11-46 231 | S : amplitude S real dp f15.11 col.47-61 232 | K : amplitude K real dp f18.11 col.62-79 233 | A : amplitude A real dp f18.11 col.80-97 234 | B : phase B real dp f14.11 col.98-111 235 | C : frequency C read dp f20.11 col.112-131 236 | 237 | The codes of the bodies are : 238 | 1 : Mercury 239 | 2 : Venus 240 | 3 : Earth for the versions A-E and Earth-Moon Barycenter for the main version 241 | 4 : Mars 242 | 5 : Jupiter 243 | 6 : Saturn 244 | 7 : Uranus 245 | 8 : Neptune 246 | 9 : Earth-Moon barycenter for the version A and Sun for the version E. 247 | 248 | 249 | TIME SCALE 250 | ========== 251 | 252 | The time used in VSOP87 theory is dynamical time. 253 | We can considered this time equal to Terrestrial Time (TT) which is 254 | measured by international atomic time TAI. 255 | So, the time argument in VSOP87 theory is equal to TAI + 32.184 s. 256 | 257 | 258 | REFERENCE SYSTEM 259 | ================ 260 | 261 | The coordinates of the main version VSOP87 and of the version A, B, and E are 262 | are given in the inertial frame defined by the dynamical equinox and ecliptic 263 | J2000 (JD2451545.0). 264 | 265 | The coordinates of the version C an D are given in the frame defined by the 266 | mean equinox and ecliptic of the date. This frame is deduced from the previous 267 | one by precessional moving between J2000 and the epoch of the date. 268 | 269 | The rectangular coordinates of VSOP87A and VSOP87E defined in dynamical ecliptic 270 | frame J2000 can be connected to the equatorial frame FK5 J2000 with the 271 | following rotation : 272 | 273 | X +1.000000000000 +0.000000440360 -0.000000190919 X 274 | Y = -0.000000479966 +0.917482137087 -0.397776982902 Y 275 | Z FK5 0.000000000000 +0.397776982902 +0.917482137087 Z VSOP87A 276 | 277 | 278 | PRECISION 279 | ========= 280 | 281 | The main version of VSOP87 is similar to the previous theory VSOP82. 282 | In the both cases the constants of integration have been determined by 283 | fitting to the numerical integration DE200 of the Jet Propulsion Laboratory. 284 | 285 | The differences between VSOP87 and VSOP82 mainly improve the validity time-span 286 | for Mercury, Venus, Earth-Moon barycenter and Mars with a precision of 1" for 287 | 4000 years before and after J2000. 288 | The same precision is ensured for Jupiter and Saturn over 2000 years and for 289 | Uranus and Neptune over 6000 years before and after J2000. 290 | 291 | The size of the relative precision p0 of VSOP87 solutions is given hereunder. 292 | That means that the actual precision is close by p0*a0 au for the distances 293 | (a0 being the semi-major axis) and close by p0 radian for the other variables. 294 | By derivation with respect to time expressed in day (d), the precision of the 295 | velocities is close by p0*a0 au/d for the distances and close by p0 radian/d 296 | for the other variables. 297 | 298 | Body a0 (au) p0 (10**-8) 299 | ---- ------- ----------- 300 | Mercury 0.3871 0.6 301 | Venus 0.7233 2.5 302 | Earth 1.0000 2.5 303 | Mars 1.5237 10.0 304 | Jupiter 5.2026 35.0 305 | Saturn 9.5547 70.0 306 | Uranus 19.2181 8.0 307 | Neptune 30.1096 42.0 308 | 309 | 310 | COMPUTATION 311 | =========== 312 | 313 | Being given a julian date JD expressed in dynamical time (TAI+32.184s) and a 314 | body (planets, Earth-Moon Barycenter, or Sun) associated to a version of the 315 | theory VSOP87 : 316 | 1/ select the file corresponding to the body and the version, 317 | 2/ read sequentially the terms of the series in the records of the file, 318 | 3/ apply for each term the formulae (1) or (2) with T=(JD-2451545)/365250, 319 | 4/ add up the terms so computed for every one coordinate. 320 | 321 | The file vsop87.f contains the Fortran 77 subroutine VSOP87 that computes the 322 | coordinates for each file of different versions of VSOP87 solutions. 323 | The VSOP87 file has to be defined and opened in the program which called this 324 | subroutine. 325 | 326 | A Fortran 77 program is also provided in file example.f which compute planetary 327 | ephemerides with the subroutine VSOP87. 328 | 329 | The subroutine VSOP87 and the program EXAMPLE (Fortran 77) are provided to 330 | illustrate the computation of an ephemeris. If the user wants to improve the 331 | rapidity of computation, it is recommanded to transform VSOP87 files in direct 332 | access and/or to read series in memory once at all. 333 | 334 | Some results of substitution of time in VSOP87 series are given in the file 335 | vsop87.chk to check up the validity of computation made by the users. 336 | 337 | 338 | End of document 339 | --------------------------------------------------------------------------------