libTheSky
Routines to compute sky positions of Sun, Moon, planets and more
All Namespaces Files Functions Variables Pages
comets.f90
Go to the documentation of this file.
1!> \file comets.f90 Contains modules and procedures to compute comet positions and properties for libTheSky
2
3
4! Copyright (c) 2002-2025 Marc van der Sluys - Nikhef/Utrecht University - marc.vandersluys.nl
5!
6! This file is part of the libTheSky package,
7! see: https://libthesky.sf.net/
8!
9! This is free software: you can redistribute it and/or modify it under the terms of the
10! European Union Public Licence 1.2 (EUPL 1.2).
11!
12! This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13! without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14! See the EU Public Licence for more details.
15!
16! You should have received a copy of the European Union Public Licence along with this code.
17! If not, see <https://www.eupl.eu/1.2/en/>.
18
19
20!***********************************************************************************************************************************
21!> \brief Procedures for comets
22
24 implicit none
25 save
26
27contains
28
29 !*********************************************************************************************************************************
30 !> \brief Calculate heliocentric xyz coordinates for comet com at t1 (in J.mill DT). Usually called by cometgc() below.
31 !!
32 !! \param t1 Time in Julian millennia DT
33 !! \param comID Comet ID
34 !!
35 !! \param x Heliocentric x coordinate (output)
36 !! \param y Heliocentric y coordinate (output)
37 !! \param z Heliocentric z coordinate (output)
38 !!
39 !! \note x=y=z=0 is returned if the calculation does not converge.
40 !!
41 !! \see Meeus, Astronomical Algorithms, 1998, Ch. 30, 33-35. Equation and page numbers refer to this book.
42 !!
43 !! \todo Use "hyperbolic method" for 0.98 < e < 1 as well? - see CHECK
44
45 subroutine cometxyz(t1,comID, x,y,z)
46 use sufr_kinds, only: double
47 use sufr_constants, only: nlpname,enpname, jd2000
48 use sufr_numerics, only: deq
49
51 use thesky_nutation, only: nutation
53
54 implicit none
55 real(double), intent(in) :: t1
56 integer, intent(in) :: comID
57 real(double), intent(out) :: x,y,z
58
59 integer, parameter :: max_try_i = nint(1e5) ! Was 1e7 until 2023-05, but can take ages if diverging
60 integer :: i,j,j1,j2
61 real(double) :: k,jj,del, tp,q,a,e,o1,o2,in,nu,r,t,jde,te, m,n,ee,ee1,de, qq,gamma,tannu2,tannu2_0,tannu2_1,w,q2,q3,dq3
62 real(double) :: eps,dpsi,eps0,deps, ff,gg,hh,pp,qqq,rr,a1,a2,b1,b2,c1,c2
63
64 jde = t1*365250.d0 + jd2000 ! t1 is in Julian Millennia after 2000.0 in dynamical time
65
66 k = 0.01720209895d0 ! Gaussian gravitational constant
67 j1 = 0
68 j2 = 0
69 del = 1.d-10 ! Convergence criterion
70
71 comepoche = cometelems(comid,1) ! J2000.0
72 q = cometelems(comid,2) ! Perihelion distance (AU?)
73 e = cometelems(comid,3) ! Eccentricity
74 in = cometelems(comid,4) ! Inclination
75 o1 = cometelems(comid,5) ! Argument of perihelion (lowercase omega)
76 o2 = cometelems(comid,6) ! Longitude of ascending node (uppercase omega)
77 tp = cometelems(comid,7) ! Perihelion date (JD)
78 nlpname(11) = trim(cometnames(comid)) ! Warning: cometNames is much longer than nlpname
79 enpname(11) = trim(cometnames(comid)) ! Warning: cometNames is much longer than enpname
80
81 ! Calculation did not (yet) converge:
82 x = 0.d0
83 y = 0.d0
84 z = 0.d0
85
86 ! write(0,'(I9,9F15.5)') comID, o1,o2,in,q,e,tp,comepoche
87 ! write(6,'(I9,2x,A50,9F15.5)') comID, trim(cometNames(comID)), q,e,in*r2d, o1*r2d,o2*r2d, tp,comepoche
88
89
90
91 te = (comepoche - jd2000)/365250.d0
92 t = jde - tp ! In days since perihelion
93 nu = 0.d0 ! Avoid 'may be used uninitialized' warnings
94
95 ! call precess_orb(comepoche,jde,in,o1,o2)
96
97
98 if(e.lt.1.0d0) then
99 a = q/(1.d0 - e) ! Semi-major axis, Eq. 33.6a
100 n = k*a**(-1.5d0) ! Mean motion (rad/day), Eq. 33.6b
101 m = n*t ! Mean anomaly - M = 0 at perihelion (t=0)
102 ee = m ! Excentric anomaly - initial value
103
104 ! Solve Kepler's equation for mildly elliptic orbits ("first method", p.196):
105 if(e.lt.0.5d0) then
106 do i=1,max_try_i
107 ee1 = m + e*sin(ee) ! Eq. 30.6
108 de = ee-ee1
109 if(abs(de).lt.del) exit
110 ee = ee1
111 end do
112 ee = ee1
113
114
115 ! Solve Kepler's equation for strongly elliptic orbits ("second method", p.199):
116 else ! CHECK or 0.5 - 0.98?
117 do i=1,max_try_i
118 de = (m + e*sin(ee) - ee) / (1.d0 - e*cos(ee)) ! Eq. 30.7
119 ee = ee + de
120 if(abs(de).lt.del) exit
121 end do
122 end if
123 if(i.ge.max_try_i) write(0,'(A,I0,A,F8.5,A, I0,A, 2(ES10.3,A))') ' cometxyz(): WARNING: Kepler solution did not converge for comet '// &
124 trim(cometnames(comid))//' (',comid,'), with e =', e, ' (',i,' iterations; ', abs(de), ' >', del,').'
125
126 nu = 2.d0 * atan( sqrt( (1.d0+e)/(1.d0-e) ) * tan(ee/2.d0) ) ! True anomaly, elliptic orbits, Eq. 30.1
127
128
129 else ! e >= 1: Parabolic or hyperbolic orbits:
130
131 ! Get a starting value for tannu2 (s), for parabolic or hyperbolic orbits:
132 w = 3*k/(q*sqrt(2*q))*t ! Eq. 34.1
133 tannu2 = w/3.d0 ! 0.d0 Starting value for auxillary variable tannu2 = tan(nu/2) = s
134 do i=1,1000
135 tannu2_1 = (2*tannu2**3 + w)/(3*(tannu2**2+1.d0)) ! Eq. 34.4
136 if(abs(tannu2-tannu2_1).lt.del) exit
137 tannu2 = tannu2_1
138 end do ! i
139 tannu2 = tannu2_1
140
141
142 ! Parabolic orbit:
143 if(deq(e,1.d0)) then
144 !write(6,*)'iter, delta: ',i,tannu2-tannu2_0
145 nu = 2.d0*atan(tannu2) ! True anomaly, parabolic orbits, Eq. 34.2
146
147
148 ! Hyperbolic orbit:
149 else ! e > 1 CHECK - use this too for 0.98 < e < 1 ?
150 qq = k/(2.d0*q)*sqrt((1.d0+e)/q) ! Eq. "35.0a" - Q
151 gamma = (1.d0-e)/(1.d0+e) ! Eq. "35.0b" - gamma
152 q2 = qq*t ! Eq. 35.1a
153
154 iloop: do i=1,max_try_i ! Program p.246, loop lines 40-64
155 tannu2_0 = tannu2
156 ! q3 = q2 - (1.d0 - 2*gamma)*tannu2**3/3.d0 ! Eq. 35.1b
157 q3 = q2 + 2.d0*gamma*tannu2**3/3.d0 ! Eq. 35.1b, but version from program on next page (246), line 42
158
159 j1loop: do j=3,1000 ! Eq. 35.1c, d, ... - program p.246, loop lines 44-56
160 jj = dble(j)
161 dq3 = (-1)**(j-1) * gamma**(j-2) * ((jj-1.d0) - j*gamma) * tannu2**(2*j-1) / (2*jj-1.d0)
162 if(isnan(dq3)) return ! NaN -> will not converge...
163
164 q3 = q3 + dq3 ! Program p.246, loop line 52
165 if(abs(dq3).lt.del) exit j1loop ! j
166
167 if(j.eq.1000) j1 = j1+1
168
169 if(j1.eq.100) then
170 if(thesky_verbosity.gt.0) write(0,'(A,I0,A,F8.5,A, I0,A, 2(ES10.3,A))') ' cometxyz(): WARNING: j1-iteration did not converge for comet '// &
171 trim(cometnames(comid))//' (',comid,'), with e =', e, ' (',i,' iterations; ', abs(dq3), ' >', del,').'
172 return
173 end if
174 end do j1loop ! j
175
176 j2loop: do j=1,1000 ! Program p.246, loop lines 60-62
177 tannu2_1 = tannu2
178 tannu2 = (2.d0/3.d0*tannu2**3+q3) / (tannu2**2+1.d0) ! Program p.246, loop line 60
179 if(abs(tannu2-tannu2_1).lt.del) exit j2loop ! j
180
181 if(j.eq.1000) j2 = j2+1
182 if(j2.eq.100) then
183 if(thesky_verbosity.gt.0) write(0,'(A,I0,A,F8.5,A, I0,A, 2(ES10.3,A))') ' cometxyz(): WARNING: j2-iteration did not converge for comet '// &
184 trim(cometnames(comid))//' (',comid,'), with e =', e, ' (',i,' iterations; ', abs(tannu2-tannu2_1), ' >', del,').'
185 return
186 end if
187 end do j2loop ! j
188
189 if(abs(tannu2-tannu2_0).lt.del) then
190 nu = 2.d0*atan(tannu2) ! True anomaly, hyperbolic orbits, Eq. "35.2" / 34.2
191 exit iloop ! i
192 end if
193
194 if(i.ge.max_try_i) then
195 if(thesky_verbosity.gt.0) write(0,'(A,I0,A,F8.5,A, I0,A, 2(ES10.3,A))') ' cometxyz(): WARNING: i-iteration did not converge for comet '// &
196 trim(cometnames(comid))//' (',comid,'), with e =', e, ' (',i,' iterations; ', abs(tannu2-tannu2_0), ' >', del,').'
197 return
198 end if
199
200 end do iloop ! i
201 end if ! Hyperbolic orbit
202
203 end if ! e >= 1 ! Parabolic or hyperbolic orbit
204
205 ! r = a * (1.d0 - e*cos(ee)) ! Eq. 30.2
206 r = q * (1.d0+e) / (1.d0 + e*cos(nu)) ! Eq. 30.4
207
208 call nutation(te,dpsi,eps0,deps)
209 eps = eps0 !+ deps
210
211 ! Eq. 33.7:
212 ff = cos(o2) ! F
213 gg = sin(o2)*cos(eps) ! G
214 hh = sin(o2)*sin(eps) ! H
215
216 pp = -sin(o2)*cos(in) ! P
217 qqq = cos(o2)*cos(in)*cos(eps) - sin(in)*sin(eps) ! Q
218 rr = cos(o2)*cos(in)*sin(eps) + sin(in)*cos(eps) ! R
219
220 ! Eq. 33.8:
221 a1 = atan2(ff, pp) ! A
222 a2 = sqrt(ff*ff + pp*pp) ! a
223 b1 = atan2(gg, qqq) ! B
224 b2 = sqrt(gg*gg + qqq*qqq) ! b
225 c1 = atan2(hh, rr) ! C
226 c2 = sqrt(hh*hh + rr*rr) ! c
227
228 ! Eq. 33.9:
229 x = r * a2 * sin(a1 + o1 + nu)
230 y = r * b2 * sin(b1 + o1 + nu)
231 z = r * c2 * sin(c1 + o1 + nu)
232
233 end subroutine cometxyz
234 !*********************************************************************************************************************************
235
236
237
238
239
240
241
242
243
244
245
246
247 !*********************************************************************************************************************************
248 !> \brief Calc geocentric lbr coordinates for comet com at t1 (in Julian millennia Dynamical Time)
249 !!
250 !! \note
251 !! This a computational detour to allow correction for aberration,
252 !! fk5 and nutation in planet_position (and keep overview there)
253 !!
254 !! \param t Apparent time (taking light time into account) in Julian millennia Dynamical Time
255 !! \param t0 True time in Julian millennia DT
256 !! \param comID Comet ID
257 !!
258 !! \param r Apparent heliocentric distance of comet (output). Note: r=0 if calculation diverged!
259 !! \param l Apparent geocentric ecliptic longitude of comet (output)
260 !! \param b Apparent geocentric ecliptic latitude of comet (output)
261 !! \param d Apparent geocentric distance of comet (output)
262 !!
263
264 subroutine cometgc(t,t0, comID, r,l,b,d)
265 use sufr_kinds, only: double
266 use sufr_constants, only: pi, jd2000
267 use sufr_numerics, only: deq0
268 use sufr_angles, only: rev
269
271 use thesky_nutation, only: nutation
272 use thesky_vsop, only: vsop87d_lbr
273 use thesky_cometdata, only: comepoche
274
275 implicit none
276 real(double), intent(in) :: t,t0
277 integer, intent(in) :: comID
278 real(double),intent(out) :: l,b,r,d
279
280 real(double) :: l0,b0,r0,x0,y0,z0,x,y,z
281 real(double) :: ra,dec,dpsi,eps0,deps,eps,jd1,jd2
282
283
284 call vsop87d_lbr(t0,3, l0,b0,r0) ! Earth
285 call fk5(t, l0,b0)
286 call nutation(t, dpsi,eps0,deps)
287 eps = eps0 + deps
288
289 ! call calcsunxyz(t, l0,b0,r0, x0,y0,z0)
290 call cometxyz(t,comid, x,y,z) ! Heliocentric equatorial rectangular coordinates
291 ! NOTE: x=y=z=0 indicate divergence! -> r=0
292
293 call ecl_spher_2_eq_rect(rev(l0+pi),-b0,r0, eps0, x0,y0,z0) ! l0+pi,-b0,r0 is geocentric SPHERICAL ECLIPTICAL pos. of Sun,
294 ! convert to geocentric RECTANGULAR EQUATORIAL position of Sun
295 jd1 = t*365250.d0 + jd2000 ! From equinox of date...
296 jd2 = comepoche ! ... to equinox of elements
297 call precess_xyz(jd1,jd2, x0,y0,z0) ! Precess geocentric position of the Sun
298
299 r = sqrt(x*x + y*y + z*z) ! Heliocentric distance comet == 0 if computation diverged
300
301 ! Heliocentric -> geocentric position of the comet:
302 x = x + x0
303 y = y + y0
304 z = z + z0
305
306 d = sqrt(x*x + y*y + z*z) ! 'Delta' - geocentric distance
307 ra = atan2(y,x) ! Right ascension
308 dec = asin(z/d) ! Declination
309
310 ! call nutation(t,dpsi,eps0,deps)
311 ! eps = eps0 + deps
312 call eq_2_ecl(ra,dec,eps, l,b)
313
314 end subroutine cometgc
315 !*********************************************************************************************************************************
316
317
318end module thesky_comets
319!***********************************************************************************************************************************
320
Data to compute comet positions.
Definition modules.f90:322
real(double), dimension(ncometsmax, 9) cometelems
Orbital elements of the comets: 1: JD of epoch (often J2000), 2: Perihelion distance (AU?...
Definition modules.f90:332
real(double) comepoche
JD of epoch (often J2000) == cometelems(i,1)
Definition modules.f90:333
character, dimension(60) cometnames
Names of the comets.
Definition modules.f90:334
Procedures for comets.
Definition comets.f90:23
subroutine cometgc(t, t0, comid, r, l, b, d)
Calc geocentric lbr coordinates for comet com at t1 (in Julian millennia Dynamical Time)
Definition comets.f90:265
subroutine cometxyz(t1, comid, x, y, z)
Calculate heliocentric xyz coordinates for comet com at t1 (in J.mill DT). Usually called by cometgc(...
Definition comets.f90:46
Constants used in libTheSky.
Definition modules.f90:23
integer thesky_verbosity
Verbosity of libTheSky output.
Definition modules.f90:42
Procedures for coordinates.
subroutine precess_xyz(jd1, jd2, x, y, z)
Compute the precession of the equinoxes in rectangular coordinates, from jd1 to jd2.
subroutine eq_2_ecl(ra, dec, eps, l, b)
Convert (geocentric) spherical equatorial coordinates RA, Dec (and eps) to spherical ecliptical coord...
subroutine ecl_spher_2_eq_rect(l, b, r, eps, x, y, z)
Convert spherical, ecliptical coordinates to rectangular, equatorial coordinates of an object - both ...
subroutine fk5(t, l, b)
Convert coordinates to the FK5 system.
Procedures for nutation.
Definition nutation.f90:25
subroutine nutation(t, dpsi, eps0, deps)
Calculate nutation - cheap routine from Meeus - as well as the mean obliquity of the ecliptic.
Definition nutation.f90:46
Procedures for VSOP.
Definition vsop.f90:34
subroutine vsop87d_lbr(tm, pl, lon, lat, rad, lbaccur, raccur)
Calculate true heliocentric ecliptic coordinates l,b,r for planet pl and the mean ecliptic and equino...
Definition vsop.f90:59