elp-mpp02 0.0.3__py3-none-any.whl → 0.0.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
elp_mpp02/__init__.py ADDED
@@ -0,0 +1,27 @@
1
+ # -*- coding: utf-8 -*-
2
+ # SPDX-License-Identifier: EUPL-1.2
3
+ #
4
+ # Copyright (c) 2019-2025 Marc van der Sluys - Nikhef/Utrecht University - marc.vandersluys.nl
5
+ #
6
+ # This file is part of the evTool Python package:
7
+ # Analyse and display output from the binary stellar-evolution code ev (a.k.a. STARS or TWIN).
8
+ # See: https://github.com/MarcvdSluys/evTool
9
+ #
10
+ # This is free software: you can redistribute it and/or modify it under the terms of the European Union
11
+ # Public Licence 1.2 (EUPL 1.2). This software is distributed in the hope that it will be useful, but
12
+ # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13
+ # PURPOSE. See the EU Public Licence for more details. You should have received a copy of the European
14
+ # Union Public Licence along with this code. If not, see <https://www.eupl.eu/1.2/en/>.
15
+
16
+
17
+ """Accurate Moon positions using the Lunar solution ELP/MPP02
18
+
19
+ This module uses the semi-analytical Lunar solution ELP2000/MPP02 to compute the geocentric position of the
20
+ Moon in the dynamical mean ecliptic and equinox of J2000. This Python code has been adapted from the Fortran
21
+ version in libTheSky.
22
+
23
+ """
24
+
25
+
26
+ name = "elp-mpp02"
27
+ __author__ = 'Marc van der Sluys - Nikhef/Utrecht University - marc.vandersluys.nl'
elp_mpp02/mpp02.py ADDED
@@ -0,0 +1,649 @@
1
+ """Accurate Moon positions using the Lunar solution ELP/MPP02
2
+
3
+ This module uses the semi-analytical Lunar solution ELP2000/MPP02 to compute the geocentric position of the
4
+ Moon in the dynamical mean ecliptic and equinox of J2000. This Python code has been adapted from the Fortran
5
+ version in libTheSky.
6
+
7
+
8
+
9
+ Remarks:
10
+
11
+ The nominal values of some constants have to be corrected. There are two sets of corrections, one of which
12
+ can be chosen using the parameter 'mode' (used in e.g. initialise()):
13
+
14
+ - mode=0, the constants are fitted to LLR observations provided from 1970 to 2001 (default);
15
+
16
+ - mode=1, the constants are fitted to DE405 ephemeris over one century (1950-2060); the lunar angles W1, W2,
17
+ W3 receive also additive corrections to the secular coefficients. This is known as the 'historical mode'.
18
+
19
+ When the mode is changed, the constants will be reinitialised and the data file reread.
20
+
21
+
22
+ References:
23
+
24
+ - ELPdoc: Lunar solution ELP, version ELP/MPP02, Jean Chapront and Gerard Francou, October 2002
25
+
26
+ - Data files and Fortran code: ftp://cyrano-se.obspm.fr/pub/2_lunar_solutions/2_elpmpp02/
27
+
28
+ - Refereed article: Chapront J., Francou G., A&A 404, 735 (2003)
29
+
30
+ - libTheSky: https://libthesky.sourceforge.net/
31
+
32
+
33
+ Dependencies:
34
+
35
+ Apart from the standard Python modules math and sys, numpy and fortranformat must be installed.
36
+
37
+
38
+ Copyright:
39
+
40
+ Copyright (c) 2019-2025 Marc van der Sluys, Department of Physics, Utrecht University, The Netherlands
41
+ and Nikhef (Netherlands institute for high-energy physics and gravitational waves), Amsterdam, The Netherlands -
42
+ https://www.nikhef.nl/~sluys/ (this Python code)
43
+
44
+ This file is part of the ELP/MPP02 Python package,
45
+ see: https://pypi.org/project/elp_mpp02/ / https://github.com/MarcvdSluys/ELP-MPP02
46
+
47
+ This is free software: you can redistribute it and/or modify it under the terms of the European Union Public
48
+ Licence 1.2 (EUPL 1.2). This software is distributed in the hope that it will be useful, but WITHOUT ANY
49
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
50
+ EU Public Licence for more details. You should have received a copy of the European Union Public Licence
51
+ along with this code. If not, see <https://www.eupl.eu/1.2/en/>.
52
+
53
+
54
+ Acknowledgements:
55
+ - Thanks to A. Vähäkangas for bug reports.
56
+
57
+ """
58
+
59
+
60
+ import math as m
61
+ import numpy.core as np
62
+ import sys
63
+
64
+
65
+ # Global constants:
66
+ d2r = m.radians(1) # Degrees to radians
67
+ r2d = m.degrees(1) # Radians to degrees
68
+ r2as = r2d*3600 # Radians to arcseconds
69
+ pi = m.pi
70
+ pi2 = pi*2
71
+ pio2 = pi/2
72
+ jd2000 = 2451545
73
+
74
+
75
+ # Global variables:
76
+ modeInit = 999 # := uninitialised
77
+ dataDir = '.' # Directory where the data files are located (default '.': the current directory)
78
+
79
+ nmpb = np.zeros((3,3))
80
+ cmpb = np.zeros(2645)
81
+ fmpb = np.zeros((5,2645))
82
+ nper = np.zeros((3,4,3))
83
+ cper = np.zeros(33256)
84
+ fper = np.zeros((5,33256))
85
+
86
+ w = np.zeros((3,5))
87
+ p1=0.;p2=0.;p3=0.;p4=0.;p5=0.; q1=0.;q2=0.;q3=0.;q4=0.;q5=0.
88
+
89
+ eart = np.zeros(5)
90
+ peri = np.zeros(5)
91
+ dela = np.zeros((4,5))
92
+ zeta = np.zeros(5)
93
+ p = np.zeros((8,5))
94
+ delnu=0.; dele=0.; delg=0.; delnp=0.; delep=0.; dtasm=0.; am=0.
95
+
96
+
97
+ def initialise_and_read_files(mode=0):
98
+ """Initialise ELP/MPP02 constants and read the data files if necessary
99
+
100
+ Input parameters:
101
+
102
+ - mode: Index of the corrections to the constants: 0-Fit to LLR observations (default), 1-Fit to DE405
103
+ 1950-2060 (historical)
104
+
105
+ """
106
+
107
+ global modeInit
108
+ # print("Initialise and read files:", modeInit)
109
+
110
+ # Initializing of constants and reading the files:
111
+ ierr = 0
112
+ if mode!=modeInit:
113
+ initialise(mode)
114
+ ierr = read_files()
115
+ if ierr!=0: return ierr
116
+
117
+ modeInit = mode # Indicate that the data have been initialised
118
+ # print("modeInit:", modeInit)
119
+ return ierr
120
+
121
+ return ierr
122
+
123
+
124
+
125
+ def initialise(mode=0):
126
+ """Initialization of the constants and parameters used for the evaluation of the ELP/MPP02 series
127
+
128
+ Input parameters:
129
+
130
+ - mode: Index of the corrections to the constants: 0-Fit to LLR observations (default), 1-Fit to DE405
131
+ 1950-2060 (historical)
132
+
133
+ """
134
+
135
+
136
+ global modeInit, w,eart,peri, dela,zeta, p,delnu,dele,delg,delnp,delep,dtasm,am
137
+ global p1,p2,p3,p4,p5, q1,q2,q3,q4,q5
138
+ # print("Initialise:", modeInit)
139
+
140
+ Dprec = -0.29965 # Constant for the correction to the constant of precession - source: IAU 2000A
141
+
142
+ bp = np.array([
143
+ [ 0.311079095, -0.103837907 ],
144
+ [ -0.4482398e-2, 0.668287e-3 ],
145
+ [ -0.1102485e-2, -0.1298072e-2 ],
146
+ [ 0.1056062e-2, -0.178028e-3 ],
147
+ [ 0.50928e-4, -0.37342e-4 ]
148
+ ]) # (2,5)
149
+
150
+ if mode<0 or mode>1: sys.exit('elp_mpp02.mpp02.initialise(): mode must have value 0 or 1, not %i' % mode)
151
+
152
+ # Constants for the evaluation of the partial derivatives:
153
+ am = 0.074801329 # Ratio of the mean motions (EMB / Moon)
154
+ alpha = 0.002571881 # Ratio of the semi-major axis (Moon / EMB)
155
+ dtasm = (2*alpha)/(3*am) # (2*alpha) / (3*am)
156
+ xa = (2*alpha)/3
157
+
158
+
159
+ # Corrections to constants:
160
+ if mode==0: # LLR
161
+ # Values of the corrections to the constants fitted to LLR. Fit 13-05-02 (2 iterations) except Phi
162
+ # and eps w2_1 and w3_1. See ELPdoc, Table 3 and paper, Table 1
163
+ Dw1_0 = -0.10525
164
+ Dw2_0 = 0.16826
165
+ Dw3_0 = -0.10760
166
+ Deart_0 = -0.04012
167
+ Dperi = -0.04854
168
+ Dw1_1 = -0.32311
169
+ Dgam = 0.00069
170
+ De = 0.00005
171
+ Deart_1 = 0.01442
172
+ Dep = 0.00226
173
+ Dw2_1 = 0.08017
174
+ Dw3_1 = -0.04317
175
+ Dw1_2 = -0.03794
176
+ else: # DE 405 ('historical')
177
+ # Values of the corrections to the constants fitted to DE405 over the time interval (1950-2060)
178
+ Dw1_0 = -0.07008
179
+ Dw2_0 = 0.20794
180
+ Dw3_0 = -0.07215
181
+ Deart_0 = -0.00033
182
+ Dperi = -0.00749
183
+ Dw1_1 = -0.35106
184
+ Dgam = 0.00085
185
+ De = -0.00006
186
+ Deart_1 = 0.00732
187
+ Dep = 0.00224
188
+ Dw2_1 = 0.08017
189
+ Dw3_1 = -0.04317
190
+ Dw1_2 = -0.03743
191
+
192
+ # Fundamental arguments (Moon and EMB - ELPdoc, Table 1):
193
+ # W1: mean longitude of the Moon:
194
+ w[0,0] = elp_dms2rad(218,18,59.95571+Dw1_0) # Source: ELP - mean motion of the Moon (nu)
195
+ w[0,1] = (1732559343.73604+Dw1_1)/r2as # Source: ELP
196
+ w[0,2] = ( -6.8084 +Dw1_2)/r2as # Source: DE405
197
+ w[0,3] = 0.66040e-2/r2as # Source: ELP
198
+ w[0,4] = -0.31690e-4/r2as # Source: ELP
199
+
200
+ # W2: mean longitude of the lunar perigee:
201
+ w[1,0] = elp_dms2rad( 83,21,11.67475+Dw2_0) # Source: ELP
202
+ w[1,1] = ( 14643420.3171 +Dw2_1)/r2as # Source: DE405
203
+ w[1,2] = ( -38.2631)/r2as # Source: DE405
204
+ w[1,3] = -0.45047e-1/r2as # Source: ELP
205
+ w[1,4] = 0.21301e-3/r2as # Source: ELP
206
+
207
+ # W3: mean longitude of the lunar ascending node:
208
+ w[2,0] = elp_dms2rad(125, 2,40.39816+Dw3_0) # Source: ELP
209
+ w[2,1] = ( -6967919.5383 +Dw3_1)/r2as # Source: DE405
210
+ w[2,2] = 6.3590/r2as # Source: DE405
211
+ w[2,3] = 0.76250e-2/r2as # Source: ELP
212
+ w[2,4] = -0.35860e-4/r2as # Source: ELP
213
+
214
+ # Earth-Moon (EMB) elements:
215
+ # Te: mean longitude of EMB:
216
+ eart[0] = elp_dms2rad(100,27,59.13885+Deart_0) # Source: VSOP2000 - mean motion of EMB (n')
217
+ eart[1] = (129597742.29300 +Deart_1)/r2as # Source: VSOP2000
218
+ eart[2] = -0.020200/r2as # Source: ELP
219
+ eart[3] = 0.90000e-5/r2as # Source: ELP
220
+ eart[4] = 0.15000e-6/r2as # Source: ELP
221
+
222
+ # Pip: mean longitude of the perihelion of EMB:
223
+ peri[0] = elp_dms2rad(102,56,14.45766+Dperi) # Source: VSOP2000
224
+ peri[1] = 1161.24342/r2as # Source: VSOP2000
225
+ peri[2] = 0.529265/r2as # Source: VSOP2000
226
+ peri[3] = -0.11814e-3/r2as # Source: VSOP2000
227
+ peri[4] = 0.11379e-4/r2as # Source: VSOP2000
228
+
229
+ # Corrections to the secular terms of Moon angles. This gives a better (long-term?) fit
230
+ # to DE 406. See ELPdoc, Table 6/paper, Table 4, line 2:
231
+ if mode==1: # DE 405 / DE 406
232
+ w[0,3] -= 0.00018865/r2as
233
+ w[0,4] -= 0.00001024/r2as
234
+
235
+ w[1,2] += 0.00470602/r2as
236
+ w[1,3] -= 0.00025213/r2as
237
+
238
+ w[2,2] -= 0.00261070/r2as
239
+ w[2,3] -= 0.00010712/r2as
240
+
241
+
242
+ # Corrections to the mean motions of the Moon angles W2 and W3, infered from the modifications of the
243
+ # constants:
244
+ x2 = w[1,1] / w[0,1]
245
+ x3 = w[2,1] / w[0,1]
246
+ y2 = am*bp[0,0] + xa*bp[4,0]
247
+ y3 = am*bp[0,1] + xa*bp[4,1]
248
+
249
+ d21 = x2 - y2
250
+ d22 = w[0,1] * bp[1,0]
251
+ d23 = w[0,1] * bp[2,0]
252
+ d24 = w[0,1] * bp[3,0]
253
+ d25 = y2/am
254
+
255
+ d31 = x3 - y3
256
+ d32 = w[0,1] * bp[1,1]
257
+ d33 = w[0,1] * bp[2,1]
258
+ d34 = w[0,1] * bp[3,1]
259
+ d35 = y3/am
260
+
261
+ Cw2_1 = d21*Dw1_1+d25*Deart_1+d22*Dgam+d23*De+d24*Dep
262
+ Cw3_1 = d31*Dw1_1+d35*Deart_1+d32*Dgam+d33*De+d34*Dep
263
+
264
+ w[1,1] += Cw2_1/r2as
265
+ w[2,1] += Cw3_1/r2as
266
+
267
+ # Arguments of Delaunay:
268
+ for iD in range(5):
269
+ dela[0,iD] = w[0,iD] - eart[iD] # D = W1 - Te + 180 degrees
270
+ dela[1,iD] = w[0,iD] - w[2,iD] # F = W1 - W3
271
+ dela[2,iD] = w[0,iD] - w[1,iD] # l = W1 - W2 mean anomaly of the Moon
272
+ dela[3,iD] = eart[iD] - peri[iD] # l' = Te - Pip mean anomaly of EMB
273
+
274
+ dela[0,0] += pi
275
+
276
+ # Planetary arguments: mean longitudes for J2000 (from VSOP2000):
277
+ p[0,0] = elp_dms2rad(252, 15, 3.216919) # Mercury
278
+ p[1,0] = elp_dms2rad(181, 58, 44.758419) # Venus
279
+ p[2,0] = elp_dms2rad(100, 27, 59.138850) # EMB (eart(0))
280
+ p[3,0] = elp_dms2rad(355, 26, 3.642778) # Mars
281
+ p[4,0] = elp_dms2rad( 34, 21, 5.379392) # Jupiter
282
+ p[5,0] = elp_dms2rad( 50, 4, 38.902495) # Saturn
283
+ p[6,0] = elp_dms2rad(314, 3, 4.354234) # Uranus
284
+ p[7,0] = elp_dms2rad(304, 20, 56.808371) # Neptune
285
+
286
+ # Planetary arguments: mean motions (from VSOP2000):
287
+ p[0,1] = 538101628.66888/r2as # Mercury
288
+ p[1,1] = 210664136.45777/r2as # Venus
289
+ p[2,1] = 129597742.29300/r2as # EMB (eart(1))
290
+ p[3,1] = 68905077.65936/r2as # Mars
291
+ p[4,1] = 10925660.57335/r2as # Jupiter
292
+ p[5,1] = 4399609.33632/r2as # Saturn
293
+ p[6,1] = 1542482.57845/r2as # Uranus
294
+ p[7,1] = 786547.89700/r2as # Neptune
295
+
296
+ p[0:8,2:5] = 0
297
+
298
+
299
+ # Mean longitude of the Moon W1 + Rate of precession (pt):
300
+ zeta[0] = w[0,0]
301
+ zeta[1] = w[0,1] + (5029.0966+Dprec)/r2as
302
+ zeta[2] = w[0,2]
303
+ zeta[3] = w[0,3]
304
+ zeta[4] = w[0,4]
305
+
306
+ # Corrections to the parameters: Nu, E, Gamma, n' et e' (Source: ELP):
307
+ delnu = (+0.55604+Dw1_1)/r2as/w[0,1] # Correction to the mean motion of the Moon
308
+ dele = (+0.01789+De)/r2as # Correction to the half coefficient of sin(l) in longitude
309
+ delg = (-0.08066+Dgam)/r2as # Correction to the half coefficient of sin(F) in latitude
310
+ delnp = (-0.06424+Deart_1)/r2as/w[0,1] # Correction to the mean motion of EMB
311
+ delep = (-0.12879+Dep)/r2as # Correction to the eccentricity of EMB
312
+
313
+ # Precession of the longitude of the ascending node of the mean ecliptic of date on fixed ecliptic J2000
314
+ # (Laskar, 1986):
315
+ # P: sine coefficients:
316
+ p1 = 0.10180391e-4
317
+ p2 = 0.47020439e-6
318
+ p3 = -0.5417367e-9
319
+ p4 = -0.2507948e-11
320
+ p5 = 0.463486e-14
321
+
322
+ # Q: cosine coefficients:
323
+ q1 = -0.113469002e-3
324
+ q2 = 0.12372674e-6
325
+ q3 = 0.1265417e-8
326
+ q4 = -0.1371808e-11
327
+ q5 = -0.320334e-14
328
+
329
+ return
330
+
331
+
332
+ def read_files():
333
+ """Read the six data files containing the ELP/MPP02 series
334
+
335
+ Return values:
336
+
337
+ - ierr: File error index: ierr=0: no error, ierr=1: file error
338
+
339
+ """
340
+
341
+ # print("Read files:")
342
+ global nmpb,cmpb,fmpb, nper,cper,fper
343
+ global w,eart,peri, dela,zeta, p,delnu,dele,delg,delnp,delep,dtasm,am
344
+
345
+ # Read the Main Problem series:
346
+ ir = 0
347
+ ilu = np.zeros(4) # will contain ints
348
+ a = 0.
349
+ b = np.zeros(5)
350
+ # ierr=1
351
+ # nerr=0
352
+
353
+ import fortranformat as ff
354
+ formatMainHeader = ff.FortranRecordReader('(25x,I10)') # Block header format
355
+ formatMainBody = ff.FortranRecordReader('(4I3,2x,F13.5,5F12.2)') # Block body format
356
+
357
+
358
+ for iFile in range(3): # Main-problem files 1-3
359
+ fileName = dataDir+'/ELP_MAIN.S'+str(iFile+1)
360
+ try:
361
+ inFile = open(fileName,'r')
362
+ except Exception as err:
363
+ sys.stderr.write(str(err)+'\n\n')
364
+ sys.stderr.write('Please ensure that:\n')
365
+ sys.stderr.write(' 1) you downloaded the data files ELP_*.S[123] from '+
366
+ 'ftp://cyrano-se.obspm.fr/pub/2_lunar_solutions/2_elpmpp02/\n')
367
+ sys.stderr.write(' 2) you set the variable mpp.dataDir to the correct value\n')
368
+ exit(1)
369
+
370
+ line = inFile.readline()
371
+ nmpb[iFile,0] = formatMainHeader.read(line)[0]
372
+ # if nerr!=0: return 3
373
+
374
+ nmpb[iFile,1] = ir+1
375
+ nmpb[iFile,2] = nmpb[iFile,0] + nmpb[iFile,1] - 1
376
+
377
+ nLines = int(round(nmpb[iFile,0]))
378
+ for iLine in range(nLines):
379
+ line = inFile.readline()
380
+ ilu[0],ilu[1],ilu[2],ilu[3], a, b[0],b[1],b[2],b[3],b[4] = formatMainBody.read(line)
381
+ # if nerr!=0: return 4
382
+
383
+ tgv = b[0] + dtasm*b[4]
384
+ if iFile==2: a -= 2*a*delnu/3
385
+ cmpb[ir] = a + tgv*(delnp-am*delnu) + b[1]*delg + b[2]*dele + b[3]*delep
386
+
387
+ for k in range(5):
388
+ fmpb[k,ir] = 0
389
+ for i in range(4):
390
+ fmpb[k,ir] += ilu[i] * dela[i,k]
391
+
392
+ if iFile==2: fmpb[0,ir] += pio2
393
+ ir += 1
394
+
395
+ inFile.close()
396
+
397
+
398
+ # Read the Perturbations series:
399
+ ir = 0
400
+ ipt = 0
401
+ icount = 0
402
+ s = 0.0
403
+ c = 0.0
404
+ ifi = np.zeros(16) # will contain ints
405
+
406
+ formatPertHeader = ff.FortranRecordReader('(25x,2I10)') # Perturbation header format
407
+ formatPertBody = ff.FortranRecordReader('(I5,2D20.13,16I3)') # Perturbation body format
408
+
409
+ for iFile in range(3): # Perturbation files 1-3
410
+ fileName = dataDir+'/ELP_PERT.S'+str(iFile+1)
411
+ try:
412
+ inFile = open(fileName,'r')
413
+ except Exception as err:
414
+ sys.stderr.write(str(err)+'\n')
415
+ exit(1)
416
+
417
+ for it in range(4):
418
+ # if nerr!=0: return 6
419
+ line = inFile.readline()
420
+ nper[iFile,it,0],ipt = formatPertHeader.read(line)
421
+
422
+ nper[iFile,it,1] = ir+1
423
+ nper[iFile,it,2] = nper[iFile,it,0] + nper[iFile,it,1] - 1
424
+ if nper[iFile,it,0]==0: continue # cycle to next it
425
+
426
+ nLines = int(round(nper[iFile,it,0]))
427
+ for iLine in range(nLines):
428
+ line = inFile.readline()
429
+ ( icount,s,c,ifi[0],ifi[1],ifi[2],ifi[3],ifi[4],ifi[5],ifi[6],ifi[7],ifi[8],ifi[9],ifi[10],
430
+ ifi[11],ifi[12],ifi[13],ifi[14],ifi[15] ) = formatPertBody.read(line)
431
+ # if nerr!=0: return 7
432
+
433
+ cper[ir] = m.sqrt(c**2+s**2)
434
+ pha = m.atan2(c,s)
435
+ if pha<0: pha = pha+pi2
436
+
437
+ for k in range(5):
438
+ fper[k,ir] = 0
439
+ if k==0: fper[k,ir] = pha
440
+ for i in range(4):
441
+ fper[k,ir] += ifi[i] * dela[i,k]
442
+
443
+ for i in range(4,12):
444
+ fper[k,ir] += ifi[i] * p[i-4,k]
445
+
446
+ fper[k,ir] += ifi[12] * zeta[k]
447
+ ir = ir+1
448
+
449
+ inFile.close()
450
+
451
+ return 0
452
+
453
+
454
+
455
+ def elp_dms2rad(deg,min,sec):
456
+ """Function for the conversion sexagesimal degrees -> radians in initialise()"""
457
+
458
+ return (deg+min/60+sec/3600) * d2r
459
+
460
+
461
+
462
+ def compute_lbr(jd, mode=0):
463
+ """Compute the spherical lunar coordinates using the ELP2000/MPP02 lunar theory in the dynamical mean ecliptic
464
+ and equinox of J2000.
465
+
466
+ Input parameters:
467
+
468
+ - jd: Julian day to compute Moon position for
469
+
470
+ - mode: Index of the corrections to the constants: 0-Fit to LLR observations (default), 1-Fit to DE405
471
+ 1950-2060 (historical)
472
+
473
+ Return values:
474
+
475
+ - lon: Ecliptic longitude (rad)
476
+
477
+ - lat: Ecliptic latitude (rad)
478
+
479
+ - rad: Distance (km)
480
+
481
+ """
482
+
483
+ # print("Compute lbr:")
484
+
485
+ xyz,vxyz, ierr = compute_xyz(jd, mode)
486
+
487
+ # Compute ecliptic l,b,r:
488
+ rad = m.sqrt(sum(xyz**2))
489
+ lon = m.atan2(xyz[1], xyz[0])
490
+ lat = m.asin(xyz[2]/rad)
491
+
492
+ # rad = rad/1.49597870700e8 # km -> AU
493
+
494
+ # print('jd, xyz: ', jd, xyz[0:3])
495
+ # print(jd, (lon%pi2)*r2d, lat*r2d, rad)
496
+
497
+ return lon,lat,rad
498
+
499
+
500
+
501
+ def compute_xyz(jd, mode=0):
502
+ """Compute the rectangular lunar coordinates using the ELP/MPP02 lunar theory in the dynamical mean ecliptic
503
+ and equinox of J2000.
504
+
505
+ Input parameters:
506
+
507
+ - jd: Julian day to compute Moon position for
508
+
509
+ - mode: Index of the corrections to the constants: 0-Fit to LLR observations, 1-Fit to DE405 1950-2060
510
+ (historical)
511
+
512
+ Return value:
513
+
514
+ - xyz(3): Geocentric rectangular coordinates (km)
515
+
516
+ - vxyz(3): Geocentric rectangular velocities (km/day):
517
+
518
+ - ierr: File error index - ierr=0: no error, ierr=1: file error
519
+
520
+ """
521
+
522
+ # print("Compute xyz:")
523
+ global nmpb,cmpb,fmpb, nper,cper,fper
524
+ global w, p1,p2,p3,p4,p5, q1,q2,q3,q4,q5
525
+
526
+ # Constants:
527
+ a405 = 384747.9613701725 # Moon mean distance for DE405
528
+ aelp = 384747.980674318 # Moon mean distance for ELP
529
+ sc = 36525 # Julian century in days
530
+
531
+ # Initialise data and read files if needed:
532
+ ierr = initialise_and_read_files(mode)
533
+ if ierr!=0: sys.exit('Could not read ELP-MPP02 files')
534
+
535
+
536
+ # Initialization of time powers:
537
+ rjd = jd - jd2000 # Reduced JD - JD since 2000
538
+ t = np.zeros(5)
539
+ t[0] = 1
540
+ t[1] = rjd/sc # t: time since 2000 in Julian centuries
541
+ t[2] = t[1]**2 # t^2
542
+ t[3] = t[2]*t[1] # t^3
543
+ t[4] = t[2]**2 # t^4
544
+
545
+ # Evaluation of the series: substitution of time in the series
546
+ v = np.zeros(6)
547
+ for iVar in range(3): # iVar=0,1,2: Longitude, Latitude, Distance
548
+
549
+ # Main Problem series:
550
+ nLineStart = int(round(nmpb[iVar,1]))
551
+ nLineEnd = int(round(nmpb[iVar,2]))
552
+ for iLine in range(nLineStart-1, nLineEnd):
553
+ x = cmpb[iLine]
554
+ y = fmpb[0,iLine]
555
+ yp = 0
556
+
557
+ for k in range(1,5): # k=1,4
558
+ y += fmpb[k,iLine] * t[k]
559
+ yp += k*fmpb[k,iLine] * t[k-1]
560
+
561
+ v[iVar] += x * m.sin(y)
562
+ v[iVar+3] += x * yp * m.cos(y)
563
+
564
+
565
+ # Perturbations series:
566
+ for it in range(4):
567
+ nLineStart = int(round(nper[iVar,it,1]))
568
+ nLineEnd = int(round(nper[iVar,it,2]))
569
+ for iLine in range(nLineStart-1, nLineEnd):
570
+ x = cper[iLine]
571
+ y = fper[0,iLine]
572
+ xp = 0
573
+ yp = 0
574
+ if it!=0: xp = it * x * t[it-1]
575
+
576
+ for k in range(1,5): # k=1,4
577
+ y += fper[k,iLine] * t[k]
578
+ yp += k * fper[k,iLine] * t[k-1]
579
+
580
+ v[iVar] += x * t[it] * m.sin(y)
581
+ v[iVar+3] += xp * m.sin(y) + x * t[it] * yp * m.cos(y)
582
+
583
+
584
+ # Compute the spherical coordinates for the mean inertial ecliptic and equinox of date:
585
+ v[0] = v[0]/r2as + w[0,0] + w[0,1]*t[1] + w[0,2]*t[2] + w[0,3]*t[3] + w[0,4]*t[4] # Longitude + mean lon. (rad)
586
+ v[1] = v[1]/r2as # Latitude (rad)
587
+ v[2] = v[2] * a405 / aelp # Distance (km)
588
+
589
+ # v[0] = v[0] % pi2
590
+
591
+ # print('t: ', t[0],t[1],t[2],t[3],t[4])
592
+ # print('v: ', v[0]*r2d,v[1]*r2d,v[2], v[3],v[4],v[5])
593
+
594
+ # compute the rectangular coordinates (for the EoD?):
595
+ clamb = m.cos(v[0])
596
+ slamb = m.sin(v[0])
597
+ cbeta = m.cos(v[1])
598
+ sbeta = m.sin(v[1])
599
+ cw = v[2]*cbeta
600
+ sw = v[2]*sbeta
601
+ # print("c/s l/b: ", clamb,slamb, cbeta,sbeta)
602
+
603
+ x0 = cw*clamb
604
+ x1 = cw*slamb
605
+ x2 = sw
606
+ # print("x1,x2,x3: ", x0,x1,x2)
607
+ # print("p,q: ", p1,p2,p3,p4,p5, q1,q2,q3,q4,q5)
608
+
609
+ # Is this simply precession in rectangular coordinates to J2000? From?
610
+ pw = (p1 + p2*t[1] + p3*t[2] + p4*t[3] + p5*t[4]) * t[1]
611
+ qw = (q1 + q2*t[1] + q3*t[2] + q4*t[3] + q5*t[4]) * t[1]
612
+
613
+ ra = 2*m.sqrt(1 - pw**2 - qw**2)
614
+ pwqw = 2*pw*qw
615
+ pw2 = 1 - 2*pw**2
616
+ qw2 = 1 - 2*qw**2
617
+ pwra = pw*ra
618
+ qwra = qw*ra
619
+
620
+ xyz = np.zeros(3)
621
+ xyz[0] = pw2*x0 + pwqw*x1 + pwra*x2
622
+ xyz[1] = pwqw*x0 + qw2*x1 - qwra*x2
623
+ xyz[2] = -pwra*x0 + qwra*x1 + (pw2+qw2-1)*x2
624
+
625
+
626
+ # Compute the rectangular velocities for the equinox J2000:
627
+ v[3] = v[3]/r2as + w[0,1] + 2*w[0,2]*t[1] + 3*w[0,3]*t[2] + 4*w[0,4]*t[3]
628
+ v[4] = v[4]/r2as
629
+
630
+ xp1 = (v[5]*cbeta - v[4]*sw)*clamb - v[3]*x1
631
+ xp2 = (v[5]*cbeta - v[4]*sw)*slamb + v[3]*x0
632
+ xp3 = v[5]*sbeta + v[4]*cw
633
+
634
+ ppw = p1 + (2*p2 + 3*p3*t[1] + 4*p4*t[2] + 5*p5*t[3]) * t[1]
635
+ qpw = q1 + (2*q2 + 3*q3*t[1] + 4*q4*t[2] + 5*q5*t[3]) * t[1]
636
+ ppw2 = -4*pw*ppw
637
+ qpw2 = -4*qw*qpw
638
+ ppwqpw = 2*(ppw*qw + pw*qpw)
639
+ rap = (ppw2+qpw2)/ra
640
+ ppwra = ppw*ra + pw*rap
641
+ qpwra = qpw*ra + qw*rap
642
+
643
+ vxyz = np.zeros(3)
644
+ vxyz[0] = (pw2*xp1 + pwqw*xp2 + pwra*xp3 + ppw2*x0 + ppwqpw*x1 + ppwra*x2) / sc
645
+ vxyz[1] = (pwqw*xp1 + qw2*xp2 - qwra*xp3 + ppwqpw*x0 + qpw2*x1 - qpwra*x2) / sc
646
+ vxyz[2] = (-pwra*xp1 + qwra*xp2 + (pw2+qw2-1)*xp3 - ppwra*x0 + qpwra*x1 + (ppw2+qpw2)*x2) / sc
647
+
648
+ return xyz,vxyz, ierr
649
+