1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.models.earth.atmosphere;
18
19 import java.io.BufferedReader;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.InputStreamReader;
23 import java.nio.charset.StandardCharsets;
24 import java.util.Arrays;
25
26 import org.hipparchus.CalculusFieldElement;
27 import org.hipparchus.exception.DummyLocalizable;
28 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
29 import org.hipparchus.geometry.euclidean.threed.Vector3D;
30 import org.hipparchus.util.FastMath;
31 import org.hipparchus.util.FieldSinCos;
32 import org.hipparchus.util.MathArrays;
33 import org.hipparchus.util.SinCos;
34 import org.orekit.annotation.DefaultDataContext;
35 import org.orekit.bodies.BodyShape;
36 import org.orekit.bodies.FieldGeodeticPoint;
37 import org.orekit.bodies.GeodeticPoint;
38 import org.orekit.data.DataContext;
39 import org.orekit.errors.OrekitException;
40 import org.orekit.errors.OrekitMessages;
41 import org.orekit.frames.Frame;
42 import org.orekit.time.AbsoluteDate;
43 import org.orekit.time.FieldAbsoluteDate;
44 import org.orekit.time.TimeScale;
45 import org.orekit.utils.PVCoordinatesProvider;
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83 public class DTM2000 implements Atmosphere {
84
85
86 public static final int HYDROGEN = 1;
87
88
89 public static final int HELIUM = 2;
90
91
92 public static final int ATOMIC_OXYGEN = 3;
93
94
95 public static final int MOLECULAR_NITROGEN = 4;
96
97
98 public static final int MOLECULAR_OXYGEN = 5;
99
100
101 public static final int ATOMIC_NITROGEN = 6;
102
103
104 private static final long serialVersionUID = 20170705L;
105
106
107
108
109 private static final int NLATM = 96;
110
111
112 private static final double[] ALEFA = {
113 0, -0.40, -0.38, 0, 0, 0, 0
114 };
115
116
117 private static final double[] MA = {
118 0, 1, 4, 16, 28, 32, 14
119 };
120
121
122 private static final double[] VMA = {
123 0, 1.6606e-24, 6.6423e-24, 26.569e-24, 46.4958e-24, 53.1381e-24, 23.2479e-24
124 };
125
126
127 private static final double RE = 6356.77;
128
129
130 private static final double ZLB0 = 120.0;
131
132
133 private static final double CPMG = .19081;
134
135
136 private static final double SPMG = .98163;
137
138
139 private static final double XLMG = -1.2392;
140
141
142 private static final double GSURF = 980.665;
143
144
145 private static final double RGAS = 831.4;
146
147
148 private static final double ROT = 0.017214206;
149
150
151 private static final double ROT2 = 0.034428412;
152
153
154 private static final String DTM2000 = "/assets/org/orekit/dtm_2000.txt";
155
156
157
158
159 private static double[] tt = null;
160 private static double[] h = null;
161 private static double[] he = null;
162 private static double[] o = null;
163 private static double[] az2 = null;
164 private static double[] o2 = null;
165 private static double[] az = null;
166 private static double[] t0 = null;
167 private static double[] tp = null;
168
169
170 private PVCoordinatesProvider sun;
171
172
173 private DTM2000InputParameters inputParams;
174
175
176 private BodyShape earth;
177
178
179 private final TimeScale utc;
180
181
182
183
184
185
186
187
188
189
190 @DefaultDataContext
191 public DTM2000(final DTM2000InputParameters parameters,
192 final PVCoordinatesProvider sun, final BodyShape earth) {
193 this(parameters, sun, earth, DataContext.getDefault().getTimeScales().getUTC());
194 }
195
196
197
198
199
200
201
202
203 public DTM2000(final DTM2000InputParameters parameters,
204 final PVCoordinatesProvider sun,
205 final BodyShape earth,
206 final TimeScale utc) {
207
208 synchronized (DTM2000.class) {
209
210 if (tt == null) {
211 readcoefficients();
212 }
213 }
214
215 this.earth = earth;
216 this.sun = sun;
217 this.inputParams = parameters;
218
219 this.utc = utc;
220 }
221
222
223 public Frame getFrame() {
224 return earth.getBodyFrame();
225 }
226
227
228
229
230
231
232
233
234
235
236
237
238
239 public double getDensity(final int day,
240 final double alti, final double lon, final double lat,
241 final double hl, final double f, final double fbar,
242 final double akp3, final double akp24) {
243 final double threshold = 120000;
244 if (alti < threshold) {
245 throw new OrekitException(OrekitMessages.ALTITUDE_BELOW_ALLOWED_THRESHOLD,
246 alti, threshold);
247 }
248 final Computation result = new Computation(day, alti / 1000, lon, lat, hl,
249 new double[] {
250 0, f, 0
251 }, new double[] {
252 0, fbar, 0
253 }, new double[] {
254 0, akp3, 0, akp24, 0
255 });
256 return result.ro * 1000;
257 }
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273 public <T extends CalculusFieldElement<T>> T getDensity(final int day,
274 final T alti, final T lon, final T lat,
275 final T hl, final double f, final double fbar,
276 final double akp3, final double akp24) {
277 final double threshold = 120000;
278 if (alti.getReal() < threshold) {
279 throw new OrekitException(OrekitMessages.ALTITUDE_BELOW_ALLOWED_THRESHOLD,
280 alti, threshold);
281 }
282 final FieldComputation<T> result = new FieldComputation<>(day, alti.divide(1000), lon, lat, hl,
283 new double[] {
284 0, f, 0
285 }, new double[] {
286 0, fbar, 0
287 }, new double[] {
288 0, akp3, 0, akp24, 0
289 });
290 return result.ro.multiply(1000);
291 }
292
293
294
295 private static void readcoefficients() {
296
297 final int size = NLATM + 1;
298 tt = new double[size];
299 h = new double[size];
300 he = new double[size];
301 o = new double[size];
302 az2 = new double[size];
303 o2 = new double[size];
304 az = new double[size];
305 t0 = new double[size];
306 tp = new double[size];
307
308 try (InputStream in = checkNull(DTM2000.class.getResourceAsStream(DTM2000));
309 BufferedReader r = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
310
311 r.readLine();
312 r.readLine();
313 for (String line = r.readLine(); line != null; line = r.readLine()) {
314 final int num = Integer.parseInt(line.substring(0, 4).replace(' ', '0'));
315 line = line.substring(4);
316 tt[num] = Double.parseDouble(line.substring(0, 13).replace(' ', '0'));
317 line = line.substring(13 + 9);
318 h[num] = Double.parseDouble(line.substring(0, 13).replace(' ', '0'));
319 line = line.substring(13 + 9);
320 he[num] = Double.parseDouble(line.substring(0, 13).replace(' ', '0'));
321 line = line.substring(13 + 9);
322 o[num] = Double.parseDouble(line.substring(0, 13).replace(' ', '0'));
323 line = line.substring(13 + 9);
324 az2[num] = Double.parseDouble(line.substring(0, 13).replace(' ', '0'));
325 line = line.substring(13 + 9);
326 o2[num] = Double.parseDouble(line.substring(0, 13).replace(' ', '0'));
327 line = line.substring(13 + 9);
328 az[num] = Double.parseDouble(line.substring(0, 13).replace(' ', '0'));
329 line = line.substring(13 + 9);
330 t0[num] = Double.parseDouble(line.substring(0, 13).replace(' ', '0'));
331 line = line.substring(13 + 9);
332 tp[num] = Double.parseDouble(line.substring(0, 13).replace(' ', '0'));
333 }
334 } catch (IOException ioe) {
335 throw new OrekitException(ioe, new DummyLocalizable(ioe.getMessage()));
336 }
337 }
338
339
340
341
342
343
344
345 public double getDensity(final AbsoluteDate date, final Vector3D position,
346 final Frame frame) {
347
348
349 if (date.compareTo(inputParams.getMaxDate()) > 0 ||
350 date.compareTo(inputParams.getMinDate()) < 0) {
351 throw new OrekitException(OrekitMessages.NO_SOLAR_ACTIVITY_AT_DATE,
352 date, inputParams.getMinDate(), inputParams.getMaxDate());
353 }
354
355
356 final int day = date.getComponents(utc).getDate().getDayOfYear();
357
358 final Frame ecef = earth.getBodyFrame();
359 final Vector3D pEcef = frame.getTransformTo(ecef, date)
360 .transformPosition(position);
361
362 final GeodeticPoint inBody = earth.transform(pEcef, ecef, date);
363 final double alti = inBody.getAltitude();
364 final double lon = inBody.getLongitude();
365 final double lat = inBody.getLatitude();
366
367
368 final Vector3D sunPos = sun.getPVCoordinates(date, ecef).getPosition();
369 final double hl = FastMath.PI + FastMath.atan2(
370 sunPos.getX() * pEcef.getY() - sunPos.getY() * pEcef.getX(),
371 sunPos.getX() * pEcef.getX() + sunPos.getY() * pEcef.getY());
372
373
374 return getDensity(day, alti, lon, lat, hl, inputParams.getInstantFlux(date),
375 inputParams.getMeanFlux(date), inputParams.getThreeHourlyKP(date),
376 inputParams.get24HoursKp(date));
377
378 }
379
380
381 @Override
382 public <T extends CalculusFieldElement<T>> T
383 getDensity(final FieldAbsoluteDate<T> date, final FieldVector3D<T> position,
384 final Frame frame) {
385
386 final AbsoluteDate dateD = date.toAbsoluteDate();
387 if (dateD.compareTo(inputParams.getMaxDate()) > 0 ||
388 dateD.compareTo(inputParams.getMinDate()) < 0) {
389 throw new OrekitException(OrekitMessages.NO_SOLAR_ACTIVITY_AT_DATE,
390 dateD, inputParams.getMinDate(), inputParams.getMaxDate());
391 }
392
393
394 final int day = date.getComponents(utc).getDate().getDayOfYear();
395
396 final Frame ecef = earth.getBodyFrame();
397 final FieldVector3D<T> pEcef = frame.getTransformTo(ecef, date).transformPosition(position);
398
399 final FieldGeodeticPoint<T> inBody = earth.transform(pEcef, ecef, date);
400 final T alti = inBody.getAltitude();
401 final T lon = inBody.getLongitude();
402 final T lat = inBody.getLatitude();
403
404
405 final Vector3D sunPos = sun.getPVCoordinates(dateD, ecef).getPosition();
406 final T y = pEcef.getY().multiply(sunPos.getX()).subtract(pEcef.getX().multiply(sunPos.getY()));
407 final T x = pEcef.getX().multiply(sunPos.getX()).add(pEcef.getY().multiply(sunPos.getY()));
408 final T hl = y.atan2(x).add(y.getPi());
409
410
411 return getDensity(day, alti, lon, lat, hl, inputParams.getInstantFlux(dateD),
412 inputParams.getMeanFlux(dateD), inputParams.getThreeHourlyKP(dateD),
413 inputParams.get24HoursKp(dateD));
414 }
415
416
417
418
419
420
421
422
423 private static InputStream checkNull(final InputStream stream) {
424 if (stream == null) {
425 throw new OrekitException(OrekitMessages.UNABLE_TO_FIND_RESOURCE, DTM2000);
426 }
427 return stream;
428 }
429
430
431 private static class Computation {
432
433
434 private final int day;
435
436
437 private final double[] f;
438
439
440 private final double[] fbar;
441
442
443
444
445
446
447
448
449
450 private final double[] akp;
451
452
453 private final double clfl;
454
455
456 private final double slfl;
457
458
459 private final double ro;
460
461
462
463
464 private final double p10;
465 private final double p20;
466 private final double p30;
467 private final double p40;
468 private final double p50;
469 private final double p60;
470 private final double p11;
471 private final double p21;
472 private final double p31;
473 private final double p41;
474 private final double p51;
475 private final double p22;
476 private final double p32;
477 private final double p42;
478 private final double p52;
479 private final double p62;
480 private final double p33;
481 private final double p10mg;
482 private final double p20mg;
483 private final double p40mg;
484
485
486 private final double hl0;
487 private final double ch;
488 private final double sh;
489 private final double c2h;
490 private final double s2h;
491 private final double c3h;
492 private final double s3h;
493
494
495
496
497
498
499
500
501
502
503
504 Computation(final int day,
505 final double altiKM, final double lon, final double lat,
506 final double hl, final double[] f, final double[] fbar,
507 final double[] akp) {
508
509 this.day = day;
510 this.f = f;
511 this.fbar = fbar;
512 this.akp = akp;
513
514
515 final SinCos scLat = FastMath.sinCos(lat);
516 final SinCos scLon = FastMath.sinCos(lon);
517
518
519 final double c = scLat.sin();
520 final double c2 = c * c;
521 final double c4 = c2 * c2;
522 final double s = scLat.cos();
523 final double s2 = s * s;
524 p10 = c;
525 p20 = 1.5 * c2 - 0.5;
526 p30 = c * (2.5 * c2 - 1.5);
527 p40 = 4.375 * c4 - 3.75 * c2 + 0.375;
528 p50 = c * (7.875 * c4 - 8.75 * c2 + 1.875);
529 p60 = (5.5 * c * p50 - 2.5 * p40) / 3.0;
530 p11 = s;
531 p21 = 3.0 * c * s;
532 p31 = s * (7.5 * c2 - 1.5);
533 p41 = c * s * (17.5 * c2 - 7.5);
534 p51 = s * (39.375 * c4 - 26.25 * c2 + 1.875);
535 p22 = 3.0 * s2;
536 p32 = 15.0 * c * s2;
537 p42 = s2 * (52.5 * c2 - 7.5);
538 p52 = 3.0 * c * p42 - 2.0 * p32;
539 p62 = 2.75 * c * p52 - 1.75 * p42;
540 p33 = 15.0 * s * s2;
541
542
543 final double clmlmg = FastMath.cos(lon - XLMG);
544 final double cmg = s * CPMG * clmlmg + c * SPMG;
545 final double cmg2 = cmg * cmg;
546 final double cmg4 = cmg2 * cmg2;
547 p10mg = cmg;
548 p20mg = 1.5 * cmg2 - 0.5;
549 p40mg = 4.375 * cmg4 - 3.75 * cmg2 + 0.375;
550
551 clfl = scLon.cos();
552 slfl = scLon.sin();
553
554
555 hl0 = hl;
556 final SinCos scHlo = FastMath.sinCos(hl0);
557 ch = scHlo.cos();
558 sh = scHlo.sin();
559 c2h = ch * ch - sh * sh;
560 s2h = 2.0 * ch * sh;
561 c3h = c2h * ch - s2h * sh;
562 s3h = s2h * ch + c2h * sh;
563
564 final double zlb = ZLB0;
565
566 final double[] dtt = new double[tt.length];
567 final double[] dh = new double[tt.length];
568 final double[] dhe = new double[tt.length];
569 final double[] dox = new double[tt.length];
570 final double[] daz2 = new double[tt.length];
571 final double[] do2 = new double[tt.length];
572 final double[] daz = new double[tt.length];
573 final double[] dt0 = new double[tt.length];
574 final double[] dtp = new double[tt.length];
575
576 Arrays.fill(dtt, Double.NaN);
577 Arrays.fill(dh, Double.NaN);
578 Arrays.fill(dhe, Double.NaN);
579 Arrays.fill(dox, Double.NaN);
580 Arrays.fill(daz2, Double.NaN);
581 Arrays.fill(do2, Double.NaN);
582 Arrays.fill(daz, Double.NaN);
583 Arrays.fill(dt0, Double.NaN);
584 Arrays.fill(dtp, Double.NaN);
585
586
587 int kleq = 1;
588 final double gdelt = gFunction(tt, dtt, 1, kleq);
589 dtt[1] = 1.0 + gdelt;
590 final double tinf = tt[1] * dtt[1];
591
592 kleq = 0;
593
594 if (day < 59 || day > 284) {
595 kleq = -1;
596 }
597 if (day > 99 && day < 244) {
598 kleq = 1;
599 }
600
601 final double gdelt0 = gFunction(t0, dt0, 0, kleq);
602 dt0[1] = (t0[1] + gdelt0) / t0[1];
603 final double t120 = t0[1] + gdelt0;
604 final double gdeltp = gFunction(tp, dtp, 0, kleq);
605 dtp[1] = (tp[1] + gdeltp) / tp[1];
606 final double tp120 = tp[1] + gdeltp;
607
608
609 final double sigma = tp120 / (tinf - t120);
610 final double dzeta = (RE + zlb) / (RE + altiKM);
611 final double zeta = (altiKM - zlb) * dzeta;
612 final double sigzeta = sigma * zeta;
613 final double expsz = FastMath.exp(-sigzeta);
614 final double tz = tinf - (tinf - t120) * expsz;
615
616 final double[] dbase = new double[7];
617
618 kleq = 1;
619
620 final double gdelh = gFunction(h, dh, 0, kleq);
621 dh[1] = FastMath.exp(gdelh);
622 dbase[1] = h[1] * dh[1];
623
624 final double gdelhe = gFunction(he, dhe, 0, kleq);
625 dhe[1] = FastMath.exp(gdelhe);
626 dbase[2] = he[1] * dhe[1];
627
628 final double gdelo = gFunction(o, dox, 1, kleq);
629 dox[1] = FastMath.exp(gdelo);
630 dbase[3] = o[1] * dox[1];
631
632 final double gdelaz2 = gFunction(az2, daz2, 1, kleq);
633 daz2[1] = FastMath.exp(gdelaz2);
634 dbase[4] = az2[1] * daz2[1];
635
636 final double gdelo2 = gFunction(o2, do2, 1, kleq);
637 do2[1] = FastMath.exp(gdelo2);
638 dbase[5] = o2[1] * do2[1];
639
640 final double gdelaz = gFunction(az, daz, 1, kleq);
641 daz[1] = FastMath.exp(gdelaz);
642 dbase[6] = az[1] * daz[1];
643
644 final double zlbre = 1.0 + zlb / RE;
645 final double glb = (GSURF / (zlbre * zlbre)) / (sigma * RGAS * tinf);
646 final double t120tz = t120 / tz;
647
648
649
650
651
652
653
654
655 double tmpro = 0;
656 for (int i = 1; i <= 6; i++) {
657 final double gamma = MA[i] * glb;
658 final double upapg = 1.0 + ALEFA[i] + gamma;
659 final double fzI = FastMath.pow(t120tz, upapg) * FastMath.exp(-sigzeta * gamma);
660
661 final double ccI = dbase[i] * fzI;
662
663 tmpro += ccI * VMA[i];
664 }
665 this.ro = tmpro;
666
667 }
668
669
670
671
672
673
674
675
676 private double gFunction(final double[] a, final double[] da,
677 final int ff0, final int kle_eq) {
678
679 final double[] fmfb = new double[3];
680 final double[] fbm150 = new double[3];
681
682
683 da[2] = p20;
684 da[3] = p40;
685 da[74] = p10;
686 double a74 = a[74];
687 double a77 = a[77];
688 double a78 = a[78];
689 if (kle_eq == -1) {
690
691 a74 = -a74;
692 a77 = -a77;
693 a78 = -a78;
694 }
695 if (kle_eq == 0 ) {
696
697 a74 = semestrialCorrection(a74);
698 a77 = semestrialCorrection(a77);
699 a78 = semestrialCorrection(a78);
700 }
701 da[77] = p30;
702 da[78] = p50;
703 da[79] = p60;
704
705
706 fmfb[1] = f[1] - fbar[1];
707 fmfb[2] = f[2] - fbar[2];
708 fbm150[1] = fbar[1] - 150.0;
709 fbm150[2] = fbar[2];
710 da[4] = fmfb[1];
711 da[6] = fbm150[1];
712 da[4] = da[4] + a[70] * fmfb[2];
713 da[6] = da[6] + a[71] * fbm150[2];
714 da[70] = fmfb[2] * (a[4] + 2.0 * a[5] * da[4] + a[82] * p10 +
715 a[83] * p20 + a[84] * p30);
716 da[71] = fbm150[2] * (a[6] + 2.0 * a[69] * da[6] + a[85] * p10 +
717 a[86] * p20 + a[87] * p30);
718 da[5] = da[4] * da[4];
719 da[69] = da[6] * da[6];
720 da[82] = da[4] * p10;
721 da[83] = da[4] * p20;
722 da[84] = da[4] * p30;
723 da[85] = da[6] * p20;
724 da[86] = da[6] * p30;
725 da[87] = da[6] * p40;
726
727
728 final int ikp = 62;
729 final int ikpm = 67;
730 final double c2fi = 1.0 - p10mg * p10mg;
731 final double dkp = akp[1] + (a[ikp] + c2fi * a[ikp + 1]) * akp[2];
732 double dakp = a[7] + a[8] * p20mg + a[68] * p40mg +
733 2.0 * dkp * (a[60] + a[61] * p20mg +
734 a[75] * 2.0 * dkp * dkp);
735 da[ikp] = dakp * akp[2];
736 da[ikp + 1] = da[ikp] * c2fi;
737 final double dkpm = akp[3] + a[ikpm] * akp[4];
738 final double dakpm = a[64] + a[65] * p20mg + a[72] * p40mg +
739 2.0 * dkpm * (a[66] + a[73] * p20mg +
740 a[76] * 2.0 * dkpm * dkpm);
741 da[ikpm] = dakpm * akp[4];
742 da[7] = dkp;
743 da[8] = p20mg * dkp;
744 da[68] = p40mg * dkp;
745 da[60] = dkp * dkp;
746 da[61] = p20mg * da[60];
747 da[75] = da[60] * da[60];
748 da[64] = dkpm;
749 da[65] = p20mg * dkpm;
750 da[72] = p40mg * dkpm;
751 da[66] = dkpm * dkpm;
752 da[73] = p20mg * da[66];
753 da[76] = da[66] * da[66];
754
755
756 double f0 = a[4] * da[4] + a[5] * da[5] + a[6] * da[6] +
757 a[69] * da[69] + a[82] * da[82] + a[83] * da[83] +
758 a[84] * da[84] + a[85] * da[85] + a[86] * da[86] +
759 a[87] * da[87];
760 final double f1f = 1.0 + f0 * ff0;
761
762 f0 = f0 + a[2] * da[2] + a[3] * da[3] + a74 * da[74] +
763 a77 * da[77] + a[7] * da[7] + a[8] * da[8] +
764 a[60] * da[60] + a[61] * da[61] + a[68] * da[68] +
765 a[64] * da[64] + a[65] * da[65] + a[66] * da[66] +
766 a[72] * da[72] + a[73] * da[73] + a[75] * da[75] +
767 a[76] * da[76] + a78 * da[78] + a[79] * da[79];
768
769 da[9] = FastMath.cos(ROT * (day - a[11]));
770 da[10] = p20 * da[9];
771
772 da[12] = FastMath.cos(ROT2 * (day - a[14]));
773 da[13] = p20 * da[12];
774
775 final double coste = FastMath.cos(ROT * (day - a[18]));
776 da[15] = p10 * coste;
777 da[16] = p30 * coste;
778 da[17] = p50 * coste;
779
780 final double cos2te = FastMath.cos(ROT2 * (day - a[20]));
781 da[19] = p10 * cos2te;
782 da[39] = p30 * cos2te;
783 da[59] = p50 * cos2te;
784
785 da[21] = p11 * ch;
786 da[22] = p31 * ch;
787 da[23] = p51 * ch;
788 da[24] = da[21] * coste;
789 da[25] = p21 * ch * coste;
790 da[26] = p11 * sh;
791 da[27] = p31 * sh;
792 da[28] = p51 * sh;
793 da[29] = da[26] * coste;
794 da[30] = p21 * sh * coste;
795
796 da[31] = p22 * c2h;
797 da[37] = p42 * c2h;
798 da[32] = p32 * c2h * coste;
799 da[33] = p22 * s2h;
800 da[38] = p42 * s2h;
801 da[34] = p32 * s2h * coste;
802 da[88] = p32 * c2h;
803 da[89] = p32 * s2h;
804 da[90] = p52 * c2h;
805 da[91] = p52 * s2h;
806 double a88 = a[88];
807 double a89 = a[89];
808 double a90 = a[90];
809 double a91 = a[91];
810 if (kle_eq == -1) {
811 a88 = -a88;
812 a89 = -a89;
813 a90 = -a90;
814 a91 = -a91;
815 }
816 if (kle_eq == 0) {
817 a88 = semestrialCorrection(a88);
818 a89 = semestrialCorrection(a89);
819 a90 = semestrialCorrection(a90);
820 a91 = semestrialCorrection(a91);
821 }
822 da[92] = p62 * c2h;
823 da[93] = p62 * s2h;
824
825 da[35] = p33 * c3h;
826 da[36] = p33 * s3h;
827
828 double fp = a[9] * da[9] + a[10] * da[10] + a[12] * da[12] + a[13] * da[13] +
829 a[15] * da[15] + a[16] * da[16] + a[17] * da[17] + a[19] * da[19] +
830 a[21] * da[21] + a[22] * da[22] + a[23] * da[23] + a[24] * da[24] +
831 a[25] * da[25] + a[26] * da[26] + a[27] * da[27] + a[28] * da[28] +
832 a[29] * da[29] + a[30] * da[30] + a[31] * da[31] + a[32] * da[32] +
833 a[33] * da[33] + a[34] * da[34] + a[35] * da[35] + a[36] * da[36] +
834 a[37] * da[37] + a[38] * da[38] + a[39] * da[39] + a[59] * da[59] +
835 a88 * da[88] + a89 * da[89] + a90 * da[90] + a91 * da[91] +
836 a[92] * da[92] + a[93] * da[93];
837
838 da[40] = p10 * coste * dkp;
839 da[41] = p30 * coste * dkp;
840 da[42] = p50 * coste * dkp;
841 da[43] = p11 * ch * dkp;
842 da[44] = p31 * ch * dkp;
843 da[45] = p51 * ch * dkp;
844 da[46] = p11 * sh * dkp;
845 da[47] = p31 * sh * dkp;
846 da[48] = p51 * sh * dkp;
847
848
849 fp += a[40] * da[40] + a[41] * da[41] + a[42] * da[42] + a[43] * da[43] +
850 a[44] * da[44] + a[45] * da[45] + a[46] * da[46] + a[47] * da[47] +
851 a[48] * da[48];
852
853 dakp = (a[40] * p10 + a[41] * p30 + a[42] * p50) * coste +
854 (a[43] * p11 + a[44] * p31 + a[45] * p51) * ch +
855 (a[46] * p11 + a[47] * p31 + a[48] * p51) * sh;
856 da[ikp] += dakp * akp[2];
857 da[ikp + 1] = da[ikp] + dakp * c2fi * akp[2];
858
859 da[49] = p11 * clfl;
860 da[50] = p21 * clfl;
861 da[51] = p31 * clfl;
862 da[52] = p41 * clfl;
863 da[53] = p51 * clfl;
864 da[54] = p11 * slfl;
865 da[55] = p21 * slfl;
866 da[56] = p31 * slfl;
867 da[57] = p41 * slfl;
868 da[58] = p51 * slfl;
869
870
871 fp += a[49] * da[49] + a[50] * da[50] + a[51] * da[51] + a[52] * da[52] +
872 a[53] * da[53] + a[54] * da[54] + a[55] * da[55] + a[56] * da[56] +
873 a[57] * da[57] + a[58] * da[58];
874
875
876 return f0 + fp * f1f;
877
878 }
879
880
881
882
883
884
885 private double semestrialCorrection(final double param) {
886 final int debeq_pr = 59;
887 final int debeq_au = 244;
888 final double result;
889 if (day >= 100) {
890 final double xmult = (day - debeq_au) / 40.0;
891 result = param - 2.0 * param * xmult;
892 } else {
893 final double xmult = (day - debeq_pr) / 40.0;
894 result = 2.0 * param * xmult - param;
895 }
896 return result;
897 }
898
899
900 }
901
902
903
904
905 private static class FieldComputation<T extends CalculusFieldElement<T>> {
906
907
908 private int day;
909
910
911 private double[] f = new double[3];
912
913
914 private double[] fbar = new double[3];
915
916
917
918
919
920
921
922
923
924 private double[] akp = new double[5];
925
926
927 private final T clfl;
928
929
930 private final T slfl;
931
932
933 private final T ro;
934
935
936
937
938 private final T p10;
939 private final T p20;
940 private final T p30;
941 private final T p40;
942 private final T p50;
943 private final T p60;
944 private final T p11;
945 private final T p21;
946 private final T p31;
947 private final T p41;
948 private final T p51;
949 private final T p22;
950 private final T p32;
951 private final T p42;
952 private final T p52;
953 private final T p62;
954 private final T p33;
955 private final T p10mg;
956 private final T p20mg;
957 private final T p40mg;
958
959
960 private final T hl0;
961 private final T ch;
962 private final T sh;
963 private final T c2h;
964 private final T s2h;
965 private final T c3h;
966 private final T s3h;
967
968
969
970
971
972
973
974
975
976
977
978 FieldComputation(final int day,
979 final T altiKM, final T lon, final T lat,
980 final T hl, final double[] f, final double[] far,
981 final double[] akp) {
982
983 this.day = day;
984 this.f = f;
985 this.fbar = far;
986 this.akp = akp;
987
988
989 final FieldSinCos<T> scLat = FastMath.sinCos(lat);
990 final FieldSinCos<T> scLon = FastMath.sinCos(lon);
991
992
993 final T c = scLat.sin();
994 final T c2 = c.multiply(c);
995 final T c4 = c2.multiply(c2);
996 final T s = scLat.cos();
997 final T s2 = s.multiply(s);
998 p10 = c;
999 p20 = c2.multiply(1.5).subtract(0.5);
1000 p30 = c.multiply(c2.multiply(2.5).subtract(1.5));
1001 p40 = c4.multiply(4.375).subtract(c2.multiply(3.75)).add(0.375);
1002 p50 = c.multiply(c4.multiply(7.875).subtract(c2.multiply(8.75)).add(1.875));
1003 p60 = (c.multiply(5.5).multiply(p50).subtract(p40.multiply(2.5))).divide(3.0);
1004 p11 = s;
1005 p21 = c.multiply(3.0).multiply(s);
1006 p31 = s.multiply(c2.multiply(7.5).subtract(1.5));
1007 p41 = c.multiply(s).multiply(c2.multiply(17.5).subtract(7.5));
1008 p51 = s.multiply(c4.multiply(39.375).subtract(c2.multiply(26.25)).add(1.875));
1009 p22 = s2.multiply(3.0);
1010 p32 = c.multiply(15.0).multiply(s2);
1011 p42 = s2.multiply(c2.multiply(52.5).subtract(7.5));
1012 p52 = c.multiply(3.0).multiply(p42).subtract(p32.multiply(2.0));
1013 p62 = c.multiply(2.75).multiply(p52).subtract(p42.multiply(1.75));
1014 p33 = s.multiply(15.0).multiply(s2);
1015
1016
1017 final T clmlmg = lon.subtract(XLMG).cos();
1018 final T cmg = s.multiply(CPMG).multiply(clmlmg).add(c.multiply(SPMG));
1019 final T cmg2 = cmg.multiply(cmg);
1020 final T cmg4 = cmg2.multiply(cmg2);
1021 p10mg = cmg;
1022 p20mg = cmg2.multiply(1.5).subtract(0.5);
1023 p40mg = cmg4.multiply(4.375).subtract(cmg2.multiply(3.75)).add(0.375);
1024
1025 clfl = scLon.cos();
1026 slfl = scLon.sin();
1027
1028
1029 hl0 = hl;
1030 final FieldSinCos<T> scHlo = FastMath.sinCos(hl0);
1031 ch = scHlo.cos();
1032 sh = scHlo.sin();
1033 c2h = ch.multiply(ch).subtract(sh.multiply(sh));
1034 s2h = ch.multiply(sh).multiply(2);
1035 c3h = c2h.multiply(ch).subtract(s2h.multiply(sh));
1036 s3h = s2h.multiply(ch).add(c2h.multiply(sh));
1037
1038 final double zlb = ZLB0;
1039
1040 final T[] dtt = MathArrays.buildArray(altiKM.getField(), tt.length);
1041 final T[] dh = MathArrays.buildArray(altiKM.getField(), tt.length);
1042 final T[] dhe = MathArrays.buildArray(altiKM.getField(), tt.length);
1043 final T[] dox = MathArrays.buildArray(altiKM.getField(), tt.length);
1044 final T[] daz2 = MathArrays.buildArray(altiKM.getField(), tt.length);
1045 final T[] do2 = MathArrays.buildArray(altiKM.getField(), tt.length);
1046 final T[] daz = MathArrays.buildArray(altiKM.getField(), tt.length);
1047 final T[] dt0 = MathArrays.buildArray(altiKM.getField(), tt.length);
1048 final T[] dtp = MathArrays.buildArray(altiKM.getField(), tt.length);
1049
1050
1051 int kleq = 1;
1052 final T gdelt = gFunction(tt, dtt, 1, kleq);
1053 dtt[1] = gdelt.add(1);
1054 final T tinf = dtt[1].multiply(tt[1]);
1055
1056 kleq = 0;
1057
1058 if (day < 59 || day > 284) {
1059 kleq = -1;
1060 }
1061 if (day > 99 && day < 244) {
1062 kleq = 1;
1063 }
1064
1065 final T gdelt0 = gFunction(t0, dt0, 0, kleq);
1066 dt0[1] = gdelt0.add(t0[1]).divide(t0[1]);
1067 final T t120 = gdelt0.add(t0[1]);
1068 final T gdeltp = gFunction(tp, dtp, 0, kleq);
1069 dtp[1] = gdeltp.add(tp[1]).divide(tp[1]);
1070 final T tp120 = gdeltp.add(tp[1]);
1071
1072
1073 final T sigma = tp120.divide(tinf.subtract(t120));
1074 final T dzeta = altiKM.add(RE).reciprocal().multiply(zlb + RE);
1075 final T zeta = altiKM.subtract(zlb).multiply(dzeta);
1076 final T sigzeta = sigma.multiply(zeta);
1077 final T expsz = sigzeta.negate().exp();
1078 final T tz = tinf.subtract(tinf.subtract(t120).multiply(expsz));
1079
1080 final T[] dbase = MathArrays.buildArray(altiKM.getField(), 7);
1081
1082 kleq = 1;
1083
1084 final T gdelh = gFunction(h, dh, 0, kleq);
1085 dh[1] = gdelh.exp();
1086 dbase[1] = dh[1].multiply(h[1]);
1087
1088 final T gdelhe = gFunction(he, dhe, 0, kleq);
1089 dhe[1] = gdelhe.exp();
1090 dbase[2] = dhe[1].multiply(he[1]);
1091
1092 final T gdelo = gFunction(o, dox, 1, kleq);
1093 dox[1] = gdelo.exp();
1094 dbase[3] = dox[1].multiply(o[1]);
1095
1096 final T gdelaz2 = gFunction(az2, daz2, 1, kleq);
1097 daz2[1] = gdelaz2.exp();
1098 dbase[4] = daz2[1].multiply(az2[1]);
1099
1100 final T gdelo2 = gFunction(o2, do2, 1, kleq);
1101 do2[1] = gdelo2.exp();
1102 dbase[5] = do2[1].multiply(o2[1]);
1103
1104 final T gdelaz = gFunction(az, daz, 1, kleq);
1105 daz[1] = gdelaz.exp();
1106 dbase[6] = daz[1].multiply(az[1]);
1107
1108 final double zlbre = 1.0 + zlb / RE;
1109 final T glb = sigma.multiply(RGAS).multiply(tinf).reciprocal().multiply(GSURF / (zlbre * zlbre));
1110 final T t120tz = t120.divide(tz);
1111
1112
1113
1114
1115
1116
1117
1118
1119 T tmpro = altiKM.getField().getZero();
1120 for (int i = 1; i <= 6; i++) {
1121 final T gamma = glb.multiply(MA[i]);
1122 final T upapg = gamma.add(1.0 + ALEFA[i]);
1123 final T fzI = t120tz.pow(upapg).multiply(sigzeta.negate().multiply(gamma).exp());
1124
1125 final T ccI = dbase[i].multiply(fzI);
1126
1127 tmpro = tmpro.add(ccI.multiply(VMA[i]));
1128 }
1129 this.ro = tmpro;
1130
1131 }
1132
1133
1134
1135
1136
1137
1138
1139
1140 private T gFunction(final double[] a, final T[] da,
1141 final int ff0, final int kle_eq) {
1142
1143 final T zero = da[0].getField().getZero();
1144 final double[] fmfb = new double[3];
1145 final double[] fbm150 = new double[3];
1146
1147
1148 da[2] = p20;
1149 da[3] = p40;
1150 da[74] = p10;
1151 double a74 = a[74];
1152 double a77 = a[77];
1153 double a78 = a[78];
1154 if (kle_eq == -1) {
1155
1156 a74 = -a74;
1157 a77 = -a77;
1158 a78 = -a78;
1159 }
1160 if (kle_eq == 0 ) {
1161
1162 a74 = semestrialCorrection(a74);
1163 a77 = semestrialCorrection(a77);
1164 a78 = semestrialCorrection(a78);
1165 }
1166 da[77] = p30;
1167 da[78] = p50;
1168 da[79] = p60;
1169
1170
1171 fmfb[1] = f[1] - fbar[1];
1172 fmfb[2] = f[2] - fbar[2];
1173 fbm150[1] = fbar[1] - 150.0;
1174 fbm150[2] = fbar[2];
1175 da[4] = zero.add(fmfb[1]);
1176 da[6] = zero.add(fbm150[1]);
1177 da[4] = da[4].add(a[70] * fmfb[2]);
1178 da[6] = da[6].add(a[71] * fbm150[2]);
1179 da[70] = da[4].multiply(a[ 5]).multiply(2).
1180 add(p10.multiply(a[82])).
1181 add(p20.multiply(a[83])).
1182 add(p30.multiply(a[84])).
1183 add(a[4]).
1184 multiply(fmfb[2]);
1185 da[71] = da[6].multiply(a[69]).multiply(2).
1186 add(p10.multiply(a[85])).
1187 add(p20.multiply(a[86])).
1188 add(p30.multiply(a[87])).
1189 add(a[6]).
1190 multiply(fbm150[2]);
1191 da[5] = da[4].multiply(da[4]);
1192 da[69] = da[6].multiply(da[6]);
1193 da[82] = da[4].multiply(p10);
1194 da[83] = da[4].multiply(p20);
1195 da[84] = da[4].multiply(p30);
1196 da[85] = da[6].multiply(p20);
1197 da[86] = da[6].multiply(p30);
1198 da[87] = da[6].multiply(p40);
1199
1200
1201 final int ikp = 62;
1202 final int ikpm = 67;
1203 final T c2fi = p10mg.multiply(p10mg).negate().add(1);
1204 final T dkp = c2fi.multiply(a[ikp + 1]).add(a[ikp]).multiply(akp[2]).add(akp[1]);
1205 T dakp = p20mg.multiply(a[8]).add(p40mg.multiply(a[68])).
1206 add(p20mg.multiply(a[61]).add(dkp.multiply(dkp).multiply(2 * a[75]).add(a[60])).multiply(dkp.multiply(2))).
1207 add(a[7]);
1208 da[ikp] = dakp.multiply(akp[2]);
1209 da[ikp + 1] = da[ikp].multiply(c2fi);
1210 final double dkpm = akp[3] + a[ikpm] * akp[4];
1211 final T dakpm = p20mg.multiply(a[65]).add(p40mg.multiply(a[72])).
1212 add(p20mg.multiply(a[73]).add(a[66] + a[76] * 2.0 * dkpm * dkpm).multiply( 2.0 * dkpm)).
1213 add(a[64]);
1214 da[ikpm] = dakpm.multiply(akp[4]);
1215 da[7] = dkp;
1216 da[8] = p20mg.multiply(dkp);
1217 da[68] = p40mg.multiply(dkp);
1218 da[60] = dkp.multiply(dkp);
1219 da[61] = p20mg.multiply(da[60]);
1220 da[75] = da[60].multiply(da[60]);
1221 da[64] = zero.add(dkpm);
1222 da[65] = p20mg.multiply(dkpm);
1223 da[72] = p40mg.multiply(dkpm);
1224 da[66] = zero.add(dkpm * dkpm);
1225 da[73] = p20mg.multiply(da[66]);
1226 da[76] = da[66].multiply(da[66]);
1227
1228
1229 T f0 = da[4].multiply(a[4]).
1230 add(da[5].multiply(a[5])).
1231 add(da[6].multiply(a[6])).
1232 add(da[69].multiply(a[69])).
1233 add(da[82].multiply(a[82])).
1234 add(da[83].multiply(a[83])).
1235 add(da[84].multiply(a[84])).
1236 add(da[85].multiply(a[85])).
1237 add(da[86].multiply(a[86])).
1238 add(da[87].multiply(a[87]));
1239 final T f1f = f0.multiply(ff0).add(1);
1240
1241 f0 = f0.
1242 add(da[2].multiply(a[2])).
1243 add(da[3].multiply(a[3])).
1244 add(da[7].multiply(a[7])).
1245 add(da[8].multiply(a[8])).
1246 add(da[60].multiply(a[60])).
1247 add(da[61].multiply(a[61])).
1248 add(da[68].multiply(a[68])).
1249 add(da[64].multiply(a[64])).
1250 add(da[65].multiply(a[65])).
1251 add(da[66].multiply(a[66])).
1252 add(da[72].multiply(a[72])).
1253 add(da[73].multiply(a[73])).
1254 add(da[74].multiply(a74)).
1255 add(da[75].multiply(a[75])).
1256 add(da[76].multiply(a[76])).
1257 add(da[77].multiply(a77)).
1258 add(da[78].multiply(a78)).
1259 add(da[79].multiply(a[79]));
1260
1261 da[9] = zero.add(FastMath.cos(ROT * (day - a[11])));
1262 da[10] = p20.multiply(da[9]);
1263
1264 da[12] = zero.add(FastMath.cos(ROT2 * (day - a[14])));
1265 da[13] = p20.multiply(da[12]);
1266
1267 final double coste = FastMath.cos(ROT * (day - a[18]));
1268 da[15] = p10.multiply(coste);
1269 da[16] = p30.multiply(coste);
1270 da[17] = p50.multiply(coste);
1271
1272 final double cos2te = FastMath.cos(ROT2 * (day - a[20]));
1273 da[19] = p10.multiply(cos2te);
1274 da[39] = p30.multiply(cos2te);
1275 da[59] = p50.multiply(cos2te);
1276
1277 da[21] = p11.multiply(ch);
1278 da[22] = p31.multiply(ch);
1279 da[23] = p51.multiply(ch);
1280 da[24] = da[21].multiply(coste);
1281 da[25] = p21.multiply(ch).multiply(coste);
1282 da[26] = p11.multiply(sh);
1283 da[27] = p31.multiply(sh);
1284 da[28] = p51.multiply(sh);
1285 da[29] = da[26].multiply(coste);
1286 da[30] = p21.multiply(sh).multiply(coste);
1287
1288 da[31] = p22.multiply(c2h);
1289 da[37] = p42.multiply(c2h);
1290 da[32] = p32.multiply(c2h).multiply(coste);
1291 da[33] = p22.multiply(s2h);
1292 da[38] = p42.multiply(s2h);
1293 da[34] = p32.multiply(s2h).multiply(coste);
1294 da[88] = p32.multiply(c2h);
1295 da[89] = p32.multiply(s2h);
1296 da[90] = p52.multiply(c2h);
1297 da[91] = p52.multiply(s2h);
1298 double a88 = a[88];
1299 double a89 = a[89];
1300 double a90 = a[90];
1301 double a91 = a[91];
1302 if (kle_eq == -1) {
1303 a88 = -a88;
1304 a89 = -a89;
1305 a90 = -a90;
1306 a91 = -a91;
1307 }
1308 if (kle_eq == 0) {
1309 a88 = semestrialCorrection(a88);
1310 a89 = semestrialCorrection(a89);
1311 a90 = semestrialCorrection(a90);
1312 a91 = semestrialCorrection(a91);
1313 }
1314 da[92] = p62.multiply(c2h);
1315 da[93] = p62.multiply(s2h);
1316
1317 da[35] = p33.multiply(c3h);
1318 da[36] = p33.multiply(s3h);
1319
1320 T fp = da[ 9].multiply(a[ 9]) .add(da[10].multiply(a[10])).add(da[12].multiply(a[12])).add(da[13].multiply(a[13])).
1321 add(da[15].multiply(a[15])).add(da[16].multiply(a[16])).add(da[17].multiply(a[17])).add(da[19].multiply(a[19])).
1322 add(da[21].multiply(a[21])).add(da[22].multiply(a[22])).add(da[23].multiply(a[23])).add(da[24].multiply(a[24])).
1323 add(da[25].multiply(a[25])).add(da[26].multiply(a[26])).add(da[27].multiply(a[27])).add(da[28].multiply(a[28])).
1324 add(da[29].multiply(a[29])).add(da[30].multiply(a[30])).add(da[31].multiply(a[31])).add(da[32].multiply(a[32])).
1325 add(da[33].multiply(a[33])).add(da[34].multiply(a[34])).add(da[35].multiply(a[35])).add(da[36].multiply(a[36])).
1326 add(da[37].multiply(a[37])).add(da[38].multiply(a[38])).add(da[39].multiply(a[39])).add(da[59].multiply(a[59])).
1327 add(da[88].multiply(a88)) .add(da[89].multiply(a89) ).add(da[90].multiply(a90) ).add(da[91].multiply(a91) ).
1328 add(da[92].multiply(a[92])).add(da[93].multiply(a[93]));
1329
1330 da[40] = p10.multiply(coste).multiply(dkp);
1331 da[41] = p30.multiply(coste).multiply(dkp);
1332 da[42] = p50.multiply(coste).multiply(dkp);
1333 da[43] = p11.multiply(ch).multiply(dkp);
1334 da[44] = p31.multiply(ch).multiply(dkp);
1335 da[45] = p51.multiply(ch).multiply(dkp);
1336 da[46] = p11.multiply(sh).multiply(dkp);
1337 da[47] = p31.multiply(sh).multiply(dkp);
1338 da[48] = p51.multiply(sh).multiply(dkp);
1339
1340
1341 fp = fp.
1342 add(da[40].multiply(a[40])).
1343 add(da[41].multiply(a[41])).
1344 add(da[42].multiply(a[42])).
1345 add(da[43].multiply(a[43])).
1346 add(da[44].multiply(a[44])).
1347 add(da[45].multiply(a[45])).
1348 add(da[46].multiply(a[46])).
1349 add(da[47].multiply(a[47])).
1350 add(da[48].multiply(a[48]));
1351
1352 dakp = p10.multiply(a[40]).add(p30.multiply(a[41])).add(p50.multiply(a[42])).multiply(coste).
1353 add(p11.multiply(a[40]).add(p31.multiply(a[44])).add(p51.multiply(a[45])).multiply(ch)).
1354 add(p11.multiply(a[46]).add(p31.multiply(a[47])).add(p51.multiply(a[48])).multiply(sh));
1355 da[ikp] = da[ikp].add(dakp.multiply(akp[2]));
1356 da[ikp + 1] = da[ikp].add(dakp.multiply(c2fi).multiply(akp[2]));
1357
1358 da[49] = p11.multiply(clfl);
1359 da[50] = p21.multiply(clfl);
1360 da[51] = p31.multiply(clfl);
1361 da[52] = p41.multiply(clfl);
1362 da[53] = p51.multiply(clfl);
1363 da[54] = p11.multiply(slfl);
1364 da[55] = p21.multiply(slfl);
1365 da[56] = p31.multiply(slfl);
1366 da[57] = p41.multiply(slfl);
1367 da[58] = p51.multiply(slfl);
1368
1369
1370 fp = fp.
1371 add(da[49].multiply(a[49])).
1372 add(da[50].multiply(a[50])).
1373 add(da[51].multiply(a[51])).
1374 add(da[52].multiply(a[52])).
1375 add(da[53].multiply(a[53])).
1376 add(da[54].multiply(a[54])).
1377 add(da[55].multiply(a[55])).
1378 add(da[56].multiply(a[56])).
1379 add(da[57].multiply(a[57])).
1380 add(da[58].multiply(a[58]));
1381
1382
1383 return f0.add(fp.multiply(f1f));
1384
1385 }
1386
1387
1388
1389
1390
1391
1392 private double semestrialCorrection(final double param) {
1393 final int debeq_pr = 59;
1394 final int debeq_au = 244;
1395 final double result;
1396 if (day >= 100) {
1397 final double xmult = (day - debeq_au) / 40.0;
1398 result = param - 2.0 * param * xmult;
1399 } else {
1400 final double xmult = (day - debeq_pr) / 40.0;
1401 result = 2.0 * param * xmult - param;
1402 }
1403 return result;
1404 }
1405
1406 }
1407
1408 }