swe4r 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,937 @@
1
+
2
+ /*
3
+ | $Header: /home/dieter/sweph/RCS/swejpl.c,v 1.76 2008/08/26 13:55:36 dieter Exp $
4
+ |
5
+ | Subroutines for reading JPL ephemerides.
6
+ | derived from testeph.f as contained in DE403 distribution July 1995.
7
+ | works with DE200, DE102, DE403, DE404, DE405, DE406.
8
+ | (attention, DE102 has 1950 reference frame and also DE4* has slightly
9
+ | different reference frame from DE200. With DE4*, use routine
10
+ | IERS_FK5().)
11
+
12
+ Authors: Dieter Koch and Alois Treindl, Astrodienst Zurich
13
+
14
+ ************************************************************/
15
+ /* Copyright (C) 1997 - 2008 Astrodienst AG, Switzerland. All rights reserved.
16
+
17
+ License conditions
18
+ ------------------
19
+
20
+ This file is part of Swiss Ephemeris.
21
+
22
+ Swiss Ephemeris is distributed with NO WARRANTY OF ANY KIND. No author
23
+ or distributor accepts any responsibility for the consequences of using it,
24
+ or for whether it serves any particular purpose or works at all, unless he
25
+ or she says so in writing.
26
+
27
+ Swiss Ephemeris is made available by its authors under a dual licensing
28
+ system. The software developer, who uses any part of Swiss Ephemeris
29
+ in his or her software, must choose between one of the two license models,
30
+ which are
31
+ a) GNU public license version 2 or later
32
+ b) Swiss Ephemeris Professional License
33
+
34
+ The choice must be made before the software developer distributes software
35
+ containing parts of Swiss Ephemeris to others, and before any public
36
+ service using the developed software is activated.
37
+
38
+ If the developer choses the GNU GPL software license, he or she must fulfill
39
+ the conditions of that license, which includes the obligation to place his
40
+ or her whole software project under the GNU GPL or a compatible license.
41
+ See http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
42
+
43
+ If the developer choses the Swiss Ephemeris Professional license,
44
+ he must follow the instructions as found in http://www.astro.com/swisseph/
45
+ and purchase the Swiss Ephemeris Professional Edition from Astrodienst
46
+ and sign the corresponding license contract.
47
+
48
+ The License grants you the right to use, copy, modify and redistribute
49
+ Swiss Ephemeris, but only under certain conditions described in the License.
50
+ Among other things, the License requires that the copyright notices and
51
+ this notice be preserved on all copies.
52
+
53
+ Authors of the Swiss Ephemeris: Dieter Koch and Alois Treindl
54
+
55
+ The authors of Swiss Ephemeris have no control or influence over any of
56
+ the derived works, i.e. over software or services created by other
57
+ programmers which use Swiss Ephemeris functions.
58
+
59
+ The names of the authors or of the copyright holder (Astrodienst) must not
60
+ be used for promoting any software, product or service which uses or contains
61
+ the Swiss Ephemeris. This copyright notice is the ONLY place where the
62
+ names of the authors can legally appear, except in cases where they have
63
+ given special permission in writing.
64
+
65
+ The trademarks 'Swiss Ephemeris' and 'Swiss Ephemeris inside' may be used
66
+ for promoting such software, products or services.
67
+ */
68
+
69
+
70
+ #include <string.h>
71
+ #include "swephexp.h"
72
+ #include "sweph.h"
73
+ #include "swejpl.h"
74
+
75
+ #define DEBUG_DO_SHOW FALSE
76
+
77
+ #ifndef NO_JPL
78
+ /*
79
+ * local globals
80
+ */
81
+ struct jpl_save {
82
+ char *jplfname;
83
+ char *jplfpath;
84
+ FILE *jplfptr;
85
+ short do_reorder;
86
+ double eh_cval[400];
87
+ double eh_ss[3], eh_au, eh_emrat;
88
+ int32 eh_denum, eh_ncon, eh_ipt[39];
89
+ char ch_cnam[6*400];
90
+ double pv[78];
91
+ double pvsun[6];
92
+ double buf[1500];
93
+ double pc[18], vc[18], ac[18], jc[18];
94
+ short do_km;
95
+ };
96
+
97
+ static struct jpl_save *FAR js;
98
+
99
+ static int state (double et, int32 *list, int do_bary,
100
+ double *pv, double *pvsun, double *nut, char *serr);
101
+ static int interp(double FAR *buf, double t, double intv, int32 ncfin,
102
+ int32 ncmin, int32 nain, int32 ifl, double *pv);
103
+ static int32 fsizer(char *serr);
104
+ static void reorder(char *x, int size, int number);
105
+ static int read_const_jpl(double *ss, char *serr);
106
+
107
+ /* information about eh_ipt[] and buf[]
108
+ DE200 DE102 DE403
109
+ 3 3 ipt[0] 3 body 0 (mercury) starts at buf[2]
110
+ 12 15 ipt[1] 14 body 0, ncf = coefficients per component
111
+ 4 2 ipt[2] 4 na = nintervals, tot 14*4*3=168
112
+ 147 93 ipt[3] 171 body 1 (venus) starts at buf[170]
113
+ 12 15 ipt[4] 10 ncf = coefficients per component
114
+ 1 1 ipt[5] 2 total 10*2*3=60
115
+ 183 138 ipt[6] 231 body 2 (earth) starts at buf[230]
116
+ 15 15 ipt[7] 13 ncf = coefficients per component
117
+ 2 2 ipt[8] 2 total 13*2*3=78
118
+ 273 228 ipt[9] 309 body 3 (mars) starts at buf[308]
119
+ 10 10 ipt[10] 11 ncf = coefficients per component
120
+ 1 1 ipt[11] 1 total 11*1*3=33
121
+ 303 258 ipt[12] 342 body 4 (jupiter) at buf[341]
122
+ 9 9 ipt[13] 8 total 8 * 1 * 3 = 24
123
+ 1 1 ipt[14] 1
124
+ 330 285 ipt[15] 366 body 5 (saturn) at buf[365]
125
+ 8 8 ipt[16] 7 total 7 * 1 * 3 = 21
126
+ 1 1 ipt[17] 1
127
+ 354 309 ipt[18] 387 body 6 (uranus) at buf[386]
128
+ 8 8 ipt[19] 6 total 6 * 1 * 3 = 18
129
+ 1 1 ipt[20] 1
130
+ 378 333 ipt[21] 405 body 7 (neptune) at buf[404]
131
+ 6 6 ipt[22] 6 total 18
132
+ 1 1 ipt[23] 1
133
+ 396 351 ipt[24] 423 body 8 (pluto) at buf[422]
134
+ 6 6 ipt[25] 6 total 18
135
+ 1 1 ipt[26] 1
136
+ 414 369 ipt[27] 441 body 9 (moon) at buf[440]
137
+ 12 15 ipt[28] 13 total 13 * 8 * 3 = 312
138
+ 8 8 ipt[29] 8
139
+ 702 729 ipt[30] 753 SBARY SUN, starts at buf[752]
140
+ 15 15 ipt[31] 11 SBARY SUN, ncf = coeff per component
141
+ 1 1 ipt[32] 2 total 11*2*3=66
142
+ 747 774 ipt[33] 819 nutations, starts at buf[818]
143
+ 10 0 ipt[34] 10 total 10 * 4 * 2 = 80
144
+ 4 0 ipt[35] 4 (nutation only two coordinates)
145
+ 0 0 ipt[36] 899 librations, start at buf[898]
146
+ 0 0 ipt[37] 10 total 10 * 4 * 3 = 120
147
+ 0 0 ipt[38] 4
148
+
149
+ last element of buf[1017]
150
+ buf[0] contains start jd and buf[1] end jd of segment;
151
+ each segment is 32 days in de403, 64 days in DE102, 32 days in DE200
152
+
153
+ Length of blocks: DE406 = 1456*4=5824 bytes = 728 double
154
+ DE405 = 2036*4=8144 bytes = 1018 double
155
+ DE404 = 1456*4=5824 bytes = 728 double
156
+ DE403 = 2036*4=8144 bytes = 1018 double
157
+ DE200 = 1652*4=6608 bytes = 826 double
158
+ DE102 = 1546*4=6184 bytes = 773 double
159
+ each DE102 record has 53*8=424 fill bytes so that
160
+ the records have the same length as DE200.
161
+ */
162
+
163
+ /*
164
+ * This subroutine opens the file jplfname, with a phony record length,
165
+ * reads the first record, and uses the info to compute ksize,
166
+ * the number of single precision words in a record.
167
+ * RETURN: ksize (record size of ephemeris data)
168
+ * jplfptr is opened on return.
169
+ * note 26-aug-2008: now record size is computed by fsizer(), not
170
+ * set to a fixed value depending as in previous releases. The caller of
171
+ * fsizer() will verify by data comparison whether it computed correctly.
172
+ */
173
+ static int32 fsizer(char *serr)
174
+ {
175
+ /* Local variables */
176
+ int32 ncon;
177
+ double emrat;
178
+ int32 numde;
179
+ double au, ss[3];
180
+ int i, kmx, khi, nd;
181
+ int32 ksize, lpt[3];
182
+ char ttl[6*14*3];
183
+ if ((js->jplfptr = swi_fopen(SEI_FILE_PLANET, js->jplfname, js->jplfpath, serr)) == NULL) {
184
+ return NOT_AVAILABLE;
185
+ }
186
+ /* ttl = ephemeris title, e.g.
187
+ * "JPL Planetary Ephemeris DE404/LE404
188
+ * Start Epoch: JED= 625296.5-3001 DEC 21 00:00:00
189
+ * Final Epoch: JED= 2817168.5 3001 JAN 17 00:00:00c */
190
+ fread((void *) &ttl[0], 1, 252, js->jplfptr);
191
+ /* cnam = names of constants */
192
+ fread((void *) js->ch_cnam, 1, 6*400, js->jplfptr);
193
+ /* ss[0] = start epoch of ephemeris
194
+ * ss[1] = end epoch
195
+ * ss[2] = segment size in days */
196
+ fread((void *) &ss[0], sizeof(double), 3, js->jplfptr);
197
+ /* reorder ? */
198
+ if (ss[2] < 1 || ss[2] > 200)
199
+ js->do_reorder = TRUE;
200
+ else
201
+ js->do_reorder = 0;
202
+ for (i = 0; i < 3; i++)
203
+ js->eh_ss[i] = ss[i];
204
+ if (js->do_reorder)
205
+ reorder((char *) &js->eh_ss[0], sizeof(double), 3);
206
+ /* plausibility test of these constants. Start and end date must be
207
+ * between -20000 and +20000, segment size >= 1 and <= 200 */
208
+ if (js->eh_ss[0] < -5583942 || js->eh_ss[1] > 9025909 || js->eh_ss[2] < 1 || js->eh_ss[2] > 200) {
209
+ if (serr != NULL)
210
+ sprintf(serr, "alleged ephemeris file (%s) has invalid format.", js->jplfname);
211
+ return(NOT_AVAILABLE);
212
+ }
213
+ /* ncon = number of constants */
214
+ fread((void *) &ncon, sizeof(int32), 1, js->jplfptr);
215
+ if (js->do_reorder)
216
+ reorder((char *) &ncon, sizeof(int32), 1);
217
+ /* au = astronomical unit */
218
+ fread((void *) &au, sizeof(double), 1, js->jplfptr);
219
+ if (js->do_reorder)
220
+ reorder((char *) &au, sizeof(double), 1);
221
+ /* emrat = earth moon mass ratio */
222
+ fread((void *) &emrat, sizeof(double), 1, js->jplfptr);
223
+ if (js->do_reorder)
224
+ reorder((char *) &emrat, sizeof(double), 1);
225
+ /* ipt[i+0]: coefficients of planet i start at buf[ipt[i+0]-1]
226
+ * ipt[i+1]: number of coefficients (interpolation order - 1)
227
+ * ipt[i+2]: number of intervals in segment */
228
+ fread((void *) &js->eh_ipt[0], sizeof(int32), 36, js->jplfptr);
229
+ if (js->do_reorder)
230
+ reorder((char *) &js->eh_ipt[0], sizeof(int32), 36);
231
+ /* numde = number of jpl ephemeris "404" with de404 */
232
+ fread((void *) &numde, sizeof(int32), 1, js->jplfptr);
233
+ if (js->do_reorder)
234
+ reorder((char *) &numde, sizeof(int32), 1);
235
+ /* read librations */
236
+ fread(&lpt[0], sizeof(int32), 3, js->jplfptr);
237
+ if (js->do_reorder)
238
+ reorder((char *) &lpt[0], sizeof(int32), 3);
239
+ /* fill librations into eh_ipt[36]..[38] */
240
+ for (i = 0; i < 3; ++i)
241
+ js->eh_ipt[i + 36] = lpt[i];
242
+ rewind(js->jplfptr);
243
+ /* find the number of ephemeris coefficients from the pointers */
244
+ /* re-activated this code on 26-aug-2008 */
245
+ kmx = 0;
246
+ khi = 0;
247
+ for (i = 0; i < 13; i++) {
248
+ if (js->eh_ipt[i * 3] > kmx) {
249
+ kmx = js->eh_ipt[i * 3];
250
+ khi = i + 1;
251
+ }
252
+ }
253
+ if (khi == 12)
254
+ nd = 2;
255
+ else
256
+ nd = 3;
257
+ ksize = (js->eh_ipt[khi * 3 - 3] + nd * js->eh_ipt[khi * 3 - 2] * js->eh_ipt[khi * 3 - 1] - 1L) * 2L;
258
+ /*
259
+ * de102 files give wrong ksize, because they contain 424 empty bytes
260
+ * per record. Fixed by hand!
261
+ */
262
+ if (ksize == 1546)
263
+ ksize = 1652;
264
+ #if 0 /* we prefer to compute ksize to be comaptible
265
+ with new DE releases */
266
+ switch (numde) {
267
+ case 403:
268
+ case 405:
269
+ case 410:
270
+ case 413:
271
+ case 414:
272
+ case 418:
273
+ case 421:
274
+ ksize = 2036;
275
+ break;
276
+ case 404:
277
+ case 406:
278
+ ksize = 1456;
279
+ break;
280
+ case 200:
281
+ ksize = 1652;
282
+ break;
283
+ case 102:
284
+ ksize = 1652; /* de102 is filled with blanks to length of de200 */
285
+ break;
286
+ default:
287
+ if (serr != NULL)
288
+ sprintf(serr,"unknown numde value %d;", numde);
289
+ return ERR;
290
+ }
291
+ #endif
292
+ if (ksize < 1000 || ksize > 5000) {
293
+ if (serr != NULL)
294
+ sprintf(serr, "JPL ephemeris file does not provide valid ksize (%d)", ksize);/**/
295
+ return NOT_AVAILABLE;
296
+ }
297
+ return ksize;
298
+ }
299
+
300
+ /*
301
+ * This subroutine reads the jpl planetary ephemeris
302
+ * and gives the position and velocity of the point 'ntarg'
303
+ * with respect to 'ncent'.
304
+ * calling sequence parameters:
305
+ * et = d.p. julian ephemeris date at which interpolation
306
+ * is wanted.
307
+ * ** note the entry dpleph for a doubly-dimensioned time **
308
+ * the reason for this option is discussed in the
309
+ * subroutine state
310
+ * ntarg = integer number of 'target' point.
311
+ * ncent = integer number of center point.
312
+ * the numbering convention for 'ntarg' and 'ncent' is:
313
+ * 0 = mercury 7 = neptune
314
+ * 1 = venus 8 = pluto
315
+ * 2 = earth 9 = moon
316
+ * 3 = mars 10 = sun
317
+ * 4 = jupiter 11 = solar-system barycenter
318
+ * 5 = saturn 12 = earth-moon barycenter
319
+ * 6 = uranus 13 = nutations (longitude and obliq)
320
+ * 14 = librations, if on eph file
321
+ * (if nutations are wanted, set ntarg = 13. for librations,
322
+ * set ntarg = 14. set ncent=0.)
323
+ * rrd = output 6-word d.p. array containing position and velocity
324
+ * of point 'ntarg' relative to 'ncent'. the units are au and
325
+ * au/day. for librations the units are radians and radians
326
+ * per day. in the case of nutations the first four words of
327
+ * rrd will be set to nutations and rates, having units of
328
+ * radians and radians/day.
329
+ * The option is available to have the units in km and km/sec.
330
+ * For this, set do_km=TRUE (default FALSE).
331
+ */
332
+ int swi_pleph(double et, int ntarg, int ncent, double *rrd, char *serr)
333
+ {
334
+ int i, retc;
335
+ int32 list[12];
336
+ double FAR *pv = js->pv;
337
+ double FAR *pvsun = js->pvsun;
338
+ for (i = 0; i < 6; ++i)
339
+ rrd[i] = 0.0;
340
+ if (ntarg == ncent)
341
+ return 0;
342
+ for (i = 0; i < 12; ++i)
343
+ list[i] = 0;
344
+ /* check for nutation call */
345
+ if (ntarg == J_NUT) {
346
+ if (js->eh_ipt[34] > 0) {
347
+ list[10] = 2;
348
+ return(state(et, list, FALSE, pv, pvsun, rrd, serr));
349
+ } else {
350
+ if (serr != NULL)
351
+ sprintf(serr,"No nutations on the JPL ephemeris file;");
352
+ return (NOT_AVAILABLE);
353
+ }
354
+ }
355
+ if (ntarg == J_LIB) {
356
+ if (js->eh_ipt[37] > 0) {
357
+ list[11] = 2;
358
+ if ((retc = state(et, list, FALSE, pv, pvsun, rrd, serr)) != OK)
359
+ return (retc);
360
+ for (i = 0; i < 6; ++i)
361
+ rrd[i] = pv[i + 60];
362
+ return 0;
363
+ } else {
364
+ if (serr != NULL)
365
+ sprintf(serr,"No librations on the ephemeris file;");
366
+ return (NOT_AVAILABLE);
367
+ }
368
+ }
369
+ /* set up proper entries in 'list' array for state call */
370
+ if (ntarg < J_SUN)
371
+ list[ntarg] = 2;
372
+ if (ntarg == J_MOON) /* Mooon needs Earth */
373
+ list[J_EARTH] = 2;
374
+ if (ntarg == J_EARTH) /* Earth needs Moon */
375
+ list[J_MOON] = 2;
376
+ if (ntarg == J_EMB) /* EMB needs Earth */
377
+ list[J_EARTH] = 2;
378
+ if (ncent < J_SUN)
379
+ list[ncent] = 2;
380
+ if (ncent == J_MOON) /* Mooon needs Earth */
381
+ list[J_EARTH] = 2;
382
+ if (ncent == J_EARTH) /* Earth needs Moon */
383
+ list[J_MOON] = 2;
384
+ if (ncent == J_EMB) /* EMB needs Earth */
385
+ list[J_EARTH] = 2;
386
+ if ((retc = state(et, list, TRUE, pv, pvsun, rrd, serr)) != OK)
387
+ return (retc);
388
+ if (ntarg == J_SUN || ncent == J_SUN) {
389
+ for (i = 0; i < 6; ++i)
390
+ pv[i + 6*J_SUN] = pvsun[i];
391
+ }
392
+ if (ntarg == J_SBARY || ncent == J_SBARY) {
393
+ for (i = 0; i < 6; ++i) {
394
+ pv[i + 6*J_SBARY] = 0.;
395
+ }
396
+ }
397
+ if (ntarg == J_EMB || ncent == J_EMB) {
398
+ for (i = 0; i < 6; ++i)
399
+ pv[i + 6*J_EMB] = pv[i + 6*J_EARTH];
400
+ }
401
+ if ((ntarg==J_EARTH && ncent==J_MOON) || (ntarg == J_MOON && ncent==J_EARTH)){
402
+ for (i = 0; i < 6; ++i)
403
+ pv[i + 6*J_EARTH] = 0.;
404
+
405
+ } else {
406
+ if (list[J_EARTH] == 2) {
407
+ for (i = 0; i < 6; ++i)
408
+ pv[i + 6*J_EARTH] -= pv[i + 6*J_MOON] / (js->eh_emrat + 1.);
409
+ }
410
+ if (list[J_MOON] == 2) {
411
+ for (i = 0; i < 6; ++i) {
412
+ pv[i + 6*J_MOON] += pv[i + 6*J_EARTH];
413
+ }
414
+ }
415
+ }
416
+ for (i = 0; i < 6; ++i)
417
+ rrd[i] = pv[i + ntarg * 6] - pv[i + ncent * 6];
418
+ return OK;
419
+ }
420
+
421
+ /*
422
+ * This subroutine differentiates and interpolates a
423
+ * set of chebyshev coefficients to give pos, vel, acc, and jerk
424
+ * calling sequence parameters:
425
+ * input:
426
+ * buf 1st location of array of d.p. chebyshev coefficients of position
427
+ * t is dp fractional time in interval covered by
428
+ * coefficients at which interpolation is wanted, 0 <= t <= 1
429
+ * intv is dp length of whole interval in input time units.
430
+ * ncf number of coefficients per component
431
+ * ncm number of components per set of coefficients
432
+ * na number of sets of coefficients in full array
433
+ * (i.e., number of sub-intervals in full interval)
434
+ * ifl int flag: =1 for positions only
435
+ * =2 for pos and vel
436
+ * =3 for pos, vel, and acc
437
+ * =4 for pos, vel, acc, and jerk
438
+ * output:
439
+ * pv d.p. interpolated quantities requested.
440
+ * assumed dimension is pv(ncm,fl).
441
+ */
442
+ static int interp(double FAR *buf, double t, double intv, int32 ncfin,
443
+ int32 ncmin, int32 nain, int32 ifl, double *pv)
444
+ {
445
+ /* Initialized data */
446
+ static int FAR np, nv;
447
+ static int FAR nac;
448
+ static int FAR njk;
449
+ static double FAR twot = 0.;
450
+ double FAR *pc = js->pc;
451
+ double FAR *vc = js->vc;
452
+ double FAR *ac = js->ac;
453
+ double FAR *jc = js->jc;
454
+ int ncf = (int) ncfin;
455
+ int ncm = (int) ncmin;
456
+ int na = (int) nain;
457
+ /* Local variables */
458
+ double temp;
459
+ int i, j, ni;
460
+ double tc;
461
+ double dt1, bma;
462
+ double bma2, bma3;
463
+ /*
464
+ | get correct sub-interval number for this set of coefficients and then
465
+ | get normalized chebyshev time within that subinterval.
466
+ */
467
+ if (t >= 0)
468
+ dt1 = floor(t);
469
+ else
470
+ dt1 = -floor(-t);
471
+ temp = na * t;
472
+ ni = (int) (temp - dt1);
473
+ /* tc is the normalized chebyshev time (-1 <= tc <= 1) */
474
+ tc = (fmod(temp, 1.0) + dt1) * 2. - 1.;
475
+ /*
476
+ * check to see whether chebyshev time has changed,
477
+ * and compute new polynomial values if it has.
478
+ * (the element pc(2) is the value of t1(tc) and hence
479
+ * contains the value of tc on the previous call.)
480
+ */
481
+ if (tc != pc[1]) {
482
+ np = 2;
483
+ nv = 3;
484
+ nac = 4;
485
+ njk = 5;
486
+ pc[1] = tc;
487
+ twot = tc + tc;
488
+ }
489
+ /*
490
+ * be sure that at least 'ncf' polynomials have been evaluated
491
+ * and are stored in the array 'pc'.
492
+ */
493
+ if (np < ncf) {
494
+ for (i = np; i < ncf; ++i)
495
+ pc[i] = twot * pc[i - 1] - pc[i - 2];
496
+ np = ncf;
497
+ }
498
+ /* interpolate to get position for each component */
499
+ for (i = 0; i < ncm; ++i) {
500
+ pv[i] = 0.;
501
+ for (j = ncf-1; j >= 0; --j)
502
+ pv[i] += pc[j] * buf[j + (i + ni * ncm) * ncf];
503
+ }
504
+ if (ifl <= 1)
505
+ return 0;
506
+ /*
507
+ * if velocity interpolation is wanted, be sure enough
508
+ * derivative polynomials have been generated and stored.
509
+ */
510
+ bma = (na + na) / intv;
511
+ vc[2] = twot + twot;
512
+ if (nv < ncf) {
513
+ for (i = nv; i < ncf; ++i)
514
+ vc[i] = twot * vc[i - 1] + pc[i - 1] + pc[i - 1] - vc[i - 2];
515
+ nv = ncf;
516
+ }
517
+ /* interpolate to get velocity for each component */
518
+ for (i = 0; i < ncm; ++i) {
519
+ pv[i + ncm] = 0.;
520
+ for (j = ncf-1; j >= 1; --j)
521
+ pv[i + ncm] += vc[j] * buf[j + (i + ni * ncm) * ncf];
522
+ pv[i + ncm] *= bma;
523
+ }
524
+ if (ifl == 2)
525
+ return 0;
526
+ /* check acceleration polynomial values, and */
527
+ /* re-do if necessary */
528
+ bma2 = bma * bma;
529
+ ac[3] = pc[1] * 24.;
530
+ if (nac < ncf) {
531
+ nac = ncf;
532
+ for (i = nac; i < ncf; ++i)
533
+ ac[i] = twot * ac[i - 1] + vc[i - 1] * 4. - ac[i - 2];
534
+ }
535
+ /* get acceleration for each component */
536
+ for (i = 0; i < ncm; ++i) {
537
+ pv[i + ncm * 2] = 0.;
538
+ for (j = ncf-1; j >= 2; --j)
539
+ pv[i + ncm * 2] += ac[j] * buf[j + (i + ni * ncm) * ncf];
540
+ pv[i + ncm * 2] *= bma2;
541
+ }
542
+ if (ifl == 3)
543
+ return 0;
544
+ /* check jerk polynomial values, and */
545
+ /* re-do if necessary */
546
+ bma3 = bma * bma2;
547
+ jc[4] = pc[1] * 192.;
548
+ if (njk < ncf) {
549
+ njk = ncf;
550
+ for (i = njk; i < ncf; ++i)
551
+ jc[i] = twot * jc[i - 1] + ac[i - 1] * 6. - jc[i - 2];
552
+ }
553
+ /* get jerk for each component */
554
+ for (i = 0; i < ncm; ++i) {
555
+ pv[i + ncm * 3] = 0.;
556
+ for (j = ncf-1; j >= 3; --j)
557
+ pv[i + ncm * 3] += jc[j] * buf[j + (i + ni * ncm) * ncf];
558
+ pv[i + ncm * 3] *= bma3;
559
+ }
560
+ return 0;
561
+ }
562
+
563
+ /*
564
+ | ********** state ********************
565
+ | this subroutine reads and interpolates the jpl planetary ephemeris file
566
+ | calling sequence parameters:
567
+ | input:
568
+ | et dp julian ephemeris epoch at which interpolation is wanted.
569
+ | list 12-word integer array specifying what interpolation
570
+ | is wanted for each of the bodies on the file.
571
+ | list(i)=0, no interpolation for body i
572
+ | =1, position only
573
+ | =2, position and velocity
574
+ | the designation of the astronomical bodies by i is:
575
+ | i = 0: mercury
576
+ | = 1: venus
577
+ | = 2: earth-moon barycenter, NOT earth!
578
+ | = 3: mars
579
+ | = 4: jupiter
580
+ | = 5: saturn
581
+ | = 6: uranus
582
+ | = 7: neptune
583
+ | = 8: pluto
584
+ | = 9: geocentric moon
585
+ | =10: nutations in longitude and obliquity
586
+ | =11: lunar librations (if on file)
587
+ | If called with list = NULL, only the header records are read and
588
+ | stored in the global areas.
589
+ | do_bary short, if true, barycentric, if false, heliocentric.
590
+ | only the 9 planets 0..8 are affected by it.
591
+ | output:
592
+ | pv dp 6 x 11 array that will contain requested interpolated
593
+ | quantities. the body specified by list(i) will have its
594
+ | state in the array starting at pv(1,i). (on any given
595
+ | call, only those words in 'pv' which are affected by the
596
+ | first 10 'list' entries (and by list(11) if librations are
597
+ | on the file) are set. the rest of the 'pv' array
598
+ | is untouched.) the order of components starting in
599
+ | pv is: x,y,z,dx,dy,dz.
600
+ | all output vectors are referenced to the earth mean
601
+ | equator and equinox of epoch. the moon state is always
602
+ | geocentric; the other nine states are either heliocentric
603
+ | or solar-system barycentric, depending on the setting of
604
+ | common flags (see below).
605
+ | lunar librations, if on file, are put into pv(k,10) if
606
+ | list(11) is 1 or 2.
607
+ | pvsun dp 6-word array containing the barycentric position and
608
+ | velocity of the sun.
609
+ | nut dp 4-word array that will contain nutations and rates,
610
+ | depending on the setting of list(10). the order of
611
+ | quantities in nut is:
612
+ | d psi (nutation in longitude)
613
+ | d epsilon (nutation in obliquity)
614
+ | d psi dot
615
+ | d epsilon dot
616
+ | globals used:
617
+ | do_km logical flag defining physical units of the output states.
618
+ | TRUE = return km and km/sec, FALSE = return au and au/day
619
+ | default value = FALSE (km determines time unit
620
+ | for nutations and librations. angle unit is always radians.)
621
+ */
622
+ static int state(double et, int32 *list, int do_bary,
623
+ double *pv, double *pvsun, double *nut, char *serr)
624
+ {
625
+ int i, j, k;
626
+ int32 flen, nseg, nb;
627
+ double FAR *buf = js->buf;
628
+ double aufac, s, t, intv, ts[4];
629
+ int32 nrecl, ksize;
630
+ int32 nr;
631
+ double et_mn, et_fr;
632
+ int32 FAR *ipt = js->eh_ipt;
633
+ char ch_ttl[252];
634
+ static int32 irecsz;
635
+ static int32 nrl, lpt[3], ncoeffs;
636
+ if (js->jplfptr == NULL) {
637
+ ksize = fsizer(serr); /* the number of single precision words in a record */
638
+ nrecl = 4;
639
+ if (ksize == NOT_AVAILABLE)
640
+ return NOT_AVAILABLE;
641
+ irecsz = nrecl * ksize; /* record size in bytes */
642
+ ncoeffs = ksize / 2; /* # of coefficients, doubles */
643
+ /* ttl = ephemeris title, e.g.
644
+ * "JPL Planetary Ephemeris DE404/LE404
645
+ * Start Epoch: JED= 625296.5-3001 DEC 21 00:00:00
646
+ * Final Epoch: JED= 2817168.5 3001 JAN 17 00:00:00c */
647
+ fread((void *) ch_ttl, 1, 252, js->jplfptr);
648
+ /* cnam = names of constants */
649
+ fread((void *) js->ch_cnam, 1, 2400, js->jplfptr);
650
+ /* ss[0] = start epoch of ephemeris
651
+ * ss[1] = end epoch
652
+ * ss[2] = segment size in days */
653
+ fread((void *) &js->eh_ss[0], sizeof(double), 3, js->jplfptr);
654
+ if (js->do_reorder)
655
+ reorder((char *) &js->eh_ss[0], sizeof(double), 3);
656
+ /* ncon = number of constants */
657
+ fread((void *) &js->eh_ncon, sizeof(int32), 1, js->jplfptr);
658
+ if (js->do_reorder)
659
+ reorder((char *) &js->eh_ncon, sizeof(int32), 1);
660
+ /* au = astronomical unit */
661
+ fread((void *) &js->eh_au, sizeof(double), 1, js->jplfptr);
662
+ if (js->do_reorder)
663
+ reorder((char *) &js->eh_au, sizeof(double), 1);
664
+ /* emrat = earth moon mass ratio */
665
+ fread((void *) &js->eh_emrat, sizeof(double), 1, js->jplfptr);
666
+ if (js->do_reorder)
667
+ reorder((char *) &js->eh_emrat, sizeof(double), 1);
668
+ /* ipt[i+0]: coefficients of planet i start at buf[ipt[i+0]-1]
669
+ * ipt[i+1]: number of coefficients (interpolation order - 1)
670
+ * ipt[i+2]: number of intervals in segment */
671
+ fread((void *) &ipt[0], sizeof(int32), 36, js->jplfptr);
672
+ if (js->do_reorder)
673
+ reorder((char *) &ipt[0], sizeof(int32), 36);
674
+ /* numde = number of jpl ephemeris "404" with de404 */
675
+ fread((void *) &js->eh_denum, sizeof(int32), 1, js->jplfptr);
676
+ if (js->do_reorder)
677
+ reorder((char *) &js->eh_denum, sizeof(int32), 1);
678
+ fread((void *) &lpt[0], sizeof(int32), 3, js->jplfptr);
679
+ if (js->do_reorder)
680
+ reorder((char *) &lpt[0], sizeof(int32), 3);
681
+ /* cval[]: other constants in next record */
682
+ fseek(js->jplfptr, 1L * irecsz, 0);
683
+ fread((void *) &js->eh_cval[0], sizeof(double), 400, js->jplfptr);
684
+ if (js->do_reorder)
685
+ reorder((char *) &js->eh_cval[0], sizeof(double), 400);
686
+ /* new 26-aug-2008: verify correct block size */
687
+ #if 0
688
+ sp = strstr(js->ch_cnam, "EMRAT ");
689
+ if (sp == NULL) {
690
+ if (serr != NULL)
691
+ sprintf(serr, "JPL ephemeris file strange, constant name 'EMRAT' missing");
692
+ return ERR;
693
+ }
694
+ i = (sp - js->ch_cnam);
695
+ if (i % 6 != 0) {
696
+ if (serr != NULL)
697
+ sprintf(serr, "JPL ephemeris file strange, constant name 'EMRAT' not at multiple of 6");
698
+ return ERR;
699
+ }
700
+ i = i / 6; /* position of EMRAT in constant array eh_cval */
701
+ if (js->eh_cval[i] != js->eh_emrat) {
702
+ if (serr != NULL)
703
+ sprintf(serr, "JPL ephemeris file error, record size failed EMRAT check");
704
+ return ERR;
705
+ }
706
+ #endif
707
+ for (i = 0; i < 3; ++i)
708
+ ipt[i + 36] = lpt[i];
709
+ nrl = 0;
710
+ /* is file length correct? */
711
+ /* file length */
712
+ fseek(js->jplfptr, 0L, SEEK_END);
713
+ flen = ftell(js->jplfptr);
714
+ /* # of segments in file */
715
+ nseg = (int32) ((js->eh_ss[1] - js->eh_ss[0]) / js->eh_ss[2]);
716
+ /* sum of all cheby coeffs of all planets and segments */
717
+ for(i = 0, nb = 0; i < 13; i++) {
718
+ k = 3;
719
+ if (i == 11)
720
+ k = 2;
721
+ nb += (ipt[i*3+1] * ipt[i*3+2]) * k * nseg;
722
+ }
723
+ /* add start and end epochs of segments */
724
+ nb += 2 * nseg;
725
+ /* doubles to bytes */
726
+ nb *= 8;
727
+ /* add size of header and constants section */
728
+ nb += 2 * ksize * nrecl;
729
+ #if 0
730
+ printf("hallo %d %d\n", nb, flen);
731
+ printf("hallo %d %d\n", nb-flen, ksize);
732
+ #endif
733
+ if (flen != nb
734
+ /* some of our files are one record too long */
735
+ && flen - nb != ksize * nrecl) {
736
+ if (serr != NULL) {
737
+ sprintf(serr, "JPL ephemeris file is mutilated; length = %d instead of %d.", flen, nb);
738
+ if (strlen(serr) + strlen(js->jplfname) < AS_MAXCH - 1)
739
+ sprintf(serr, "JPL ephemeris file %s is mutilated; length = %d instead of %d.", js->jplfname, flen, nb);
740
+ }
741
+ return(NOT_AVAILABLE);
742
+ }
743
+ /* check if start and end dates in segments are the same as in
744
+ * file header */
745
+ fseek(js->jplfptr, 2L * irecsz, 0);
746
+ fread((void *) &ts[0], sizeof(double), 2, js->jplfptr);
747
+ if (js->do_reorder)
748
+ reorder((char *) &ts[0], sizeof(double), 2);
749
+ fseek(js->jplfptr, (nseg + 2 - 1) * irecsz, 0);
750
+ fread((void *) &ts[2], sizeof(double), 2, js->jplfptr);
751
+ if (js->do_reorder)
752
+ reorder((char *) &ts[2], sizeof(double), 2);
753
+ if (ts[0] != js->eh_ss[0] || ts[3] != js->eh_ss[1]) {
754
+ if (serr != NULL)
755
+ strcpy(serr, "JPL ephemeris file is corrupt; start/end date check failed.");
756
+ return NOT_AVAILABLE;
757
+ }
758
+ }
759
+ if (list == NULL)
760
+ return 0;
761
+ s = et - .5;
762
+ et_mn = floor(s);
763
+ et_fr = s - et_mn; /* fraction of days since previous midnight */
764
+ et_mn += .5; /* midnight before epoch */
765
+ /* error return for epoch out of range */
766
+ if (et < js->eh_ss[0] || et > js->eh_ss[1]) {
767
+ if (serr != NULL)
768
+ sprintf(serr,"jd %f outside JPL eph. range %.2f .. %.2f;", et, js->eh_ss[0], js->eh_ss[1]);
769
+ return BEYOND_EPH_LIMITS;
770
+ }
771
+ /* calculate record # and relative time in interval */
772
+ nr = (int32) ((et_mn - js->eh_ss[0]) / js->eh_ss[2]) + 2;
773
+ if (et_mn == js->eh_ss[1])
774
+ --nr; /* end point of ephemeris, use last record */
775
+ t = (et_mn - ((nr - 2) * js->eh_ss[2] + js->eh_ss[0]) + et_fr) / js->eh_ss[2];
776
+ /* read correct record if not in core */
777
+ if (nr != nrl) {
778
+ nrl = nr;
779
+ if (fseek(js->jplfptr, nr * irecsz, 0) != 0) {
780
+ if (serr != NULL)
781
+ sprintf(serr, "Read error in JPL eph. at %f\n", et);
782
+ return NOT_AVAILABLE;
783
+ }
784
+ for (k = 1; k <= ncoeffs; ++k) {
785
+ if ( fread((void *) &buf[k - 1], sizeof(double), 1, js->jplfptr) != 1) {
786
+ if (serr != NULL)
787
+ sprintf(serr, "Read error in JPL eph. at %f\n", et);
788
+ return NOT_AVAILABLE;
789
+ }
790
+ if (js->do_reorder)
791
+ reorder((char *) &buf[k-1], sizeof(double), 1);
792
+ }
793
+ }
794
+ if (js->do_km) {
795
+ intv = js->eh_ss[2] * 86400.;
796
+ aufac = 1.;
797
+ } else {
798
+ intv = js->eh_ss[2];
799
+ aufac = 1. / js->eh_au;
800
+ }
801
+ /* interpolate ssbary sun */
802
+ interp(&buf[(int) ipt[30] - 1], t, intv, ipt[31], 3L, ipt[32], 2L, pvsun);
803
+ for (i = 0; i < 6; ++i) {
804
+ pvsun[i] *= aufac;
805
+ }
806
+ /* check and interpolate whichever bodies are requested */
807
+ for (i = 0; i < 10; ++i) {
808
+ if (list[i] > 0) {
809
+ interp(&buf[(int) ipt[i * 3] - 1], t, intv, ipt[i * 3 + 1], 3L,
810
+ ipt[i * 3 + 2], list[i], &pv[i * 6]);
811
+ for (j = 0; j < 6; ++j) {
812
+ if (i < 9 && ! do_bary) {
813
+ pv[j + i * 6] = pv[j + i * 6] * aufac - pvsun[j];
814
+ } else {
815
+ pv[j + i * 6] *= aufac;
816
+ }
817
+ }
818
+ }
819
+ }
820
+ /* do nutations if requested (and if on file) */
821
+ if (list[10] > 0 && ipt[34] > 0) {
822
+ interp(&buf[(int) ipt[33] - 1], t, intv, ipt[34], 2L, ipt[35],
823
+ list[10], nut);
824
+ }
825
+ /* get librations if requested (and if on file) */
826
+ if (list[11] > 0 && ipt[37] > 0) {
827
+ interp(&buf[(int) ipt[36] - 1], t, intv, ipt[37], 3L, ipt[38], list[1],
828
+ &pv[60]);
829
+ }
830
+ return OK;
831
+ }
832
+
833
+ /*
834
+ * this entry obtains the constants from the ephemeris file
835
+ * call state to initialize the ephemeris and read in the constants
836
+ */
837
+ static int read_const_jpl(double *ss, char *serr)
838
+ {
839
+ int i, retc;
840
+ retc = state(0.0, NULL, FALSE, NULL, NULL, NULL, serr);
841
+ if (retc != OK)
842
+ return (retc);
843
+ for (i = 0; i < 3; i++)
844
+ ss[i] = js->eh_ss[i];
845
+ #if DEBUG_DO_SHOW
846
+ {
847
+ static char FAR *bname[] = {
848
+ "Mercury", "Venus", "EMB", "Mars", "Jupiter", "Saturn",
849
+ "Uranus", "Neptune", "Pluto", "Moon", "SunBary", "Nut", "Libr"};
850
+ int j, k;
851
+ int32 nb, nc;
852
+ printf(" JPL TEST-EPHEMERIS program. Version October 1995.\n");
853
+ for (i = 0; i < 13; i++) {
854
+ j = i * 3;
855
+ k = 3;
856
+ if (i == 11) k = 2;
857
+ nb = js->eh_ipt[j+1] * js->eh_ipt[j+2] * k;
858
+ nc = (int32) (nb * 36525L / js->eh_ss[2] * 8L);
859
+ printf("%s\t%d\tipt[%d]\t%3ld %2ld %2ld,\t",
860
+ bname[i], i, j, js->eh_ipt[j], js->eh_ipt[j+1], js->eh_ipt[j+2]);
861
+ printf("%3ld double, bytes per century = %6ld\n", nb, nc);
862
+ fflush(stdout);
863
+ }
864
+ printf("%16.2f %16.2f %16.2f\n", js->eh_ss[0], js->eh_ss[1], js->eh_ss[2]);
865
+ for (i = 0; i < js->eh_ncon; ++i)
866
+ printf("%.6s\t%24.16f\n", js->ch_cnam + i * 6, js->eh_cval[i]);
867
+ fflush(stdout);
868
+ }
869
+ #endif
870
+ return OK;
871
+ }
872
+
873
+ static void reorder(char *x, int size, int number)
874
+ {
875
+ int i, j;
876
+ char s[8];
877
+ char *sp1 = x;
878
+ char *sp2 = &s[0];
879
+ for (i = 0; i < number; i++) {
880
+ for (j = 0; j < size; j++)
881
+ *(sp2 + j) = *(sp1 + size - j - 1);
882
+ for (j = 0; j < size; j++)
883
+ *(sp1 + j) = *(sp2 + j);
884
+ sp1 += size;
885
+ }
886
+ }
887
+
888
+ void swi_close_jpl_file(void)
889
+ {
890
+ if (js != NULL) {
891
+ if (js->jplfptr != NULL)
892
+ fclose(js->jplfptr);
893
+ if (js->jplfname != NULL)
894
+ FREE((void *) js->jplfname);
895
+ if (js->jplfpath != NULL)
896
+ FREE((void *) js->jplfpath);
897
+ FREE((void *) js);
898
+ js = NULL;
899
+ }
900
+ }
901
+
902
+ int swi_open_jpl_file(double *ss, char *fname, char *fpath, char *serr)
903
+ {
904
+ int retc = OK;
905
+ /* if open, return */
906
+ if (js != NULL && js->jplfptr != NULL)
907
+ return OK;
908
+ if ((js = (struct jpl_save *) CALLOC(1, sizeof(struct jpl_save))) == NULL
909
+ || (js->jplfname = MALLOC(strlen(fname)+1)) == NULL
910
+ || (js->jplfpath = MALLOC(strlen(fpath)+1)) == NULL
911
+ ) {
912
+ if (serr != NULL)
913
+ strcpy(serr, "error in malloc() with JPL ephemeris.");
914
+ return ERR;
915
+ }
916
+ strcpy(js->jplfname, fname);
917
+ strcpy(js->jplfpath, fpath);
918
+ retc = read_const_jpl(ss, serr);
919
+ if (retc != OK)
920
+ swi_close_jpl_file();
921
+ else {
922
+ /* intializations for function interpol() */
923
+ js->pc[0] = 1;
924
+ js->pc[1] = 2;
925
+ js->vc[1] = 1;
926
+ js->ac[2] = 4;
927
+ js->jc[3] = 24;
928
+ }
929
+ return retc;
930
+ }
931
+
932
+ int32 swi_get_jpl_denum()
933
+ {
934
+ return js->eh_denum;
935
+ }
936
+ #endif /* NO_JPL */
937
+