astro_chart 0.1.0

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