1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.propagation.semianalytical.dsst.forces;
18
19 import java.util.List;
20
21 import org.hipparchus.CalculusFieldElement;
22 import org.hipparchus.Field;
23 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
24 import org.hipparchus.geometry.euclidean.threed.Vector3D;
25 import org.hipparchus.util.FastMath;
26 import org.hipparchus.util.MathArrays;
27 import org.hipparchus.util.MathUtils;
28 import org.hipparchus.util.Precision;
29 import org.orekit.bodies.OneAxisEllipsoid;
30 import org.orekit.forces.radiation.IsotropicRadiationSingleCoefficient;
31 import org.orekit.forces.radiation.RadiationSensitive;
32 import org.orekit.forces.radiation.SolarRadiationPressure;
33 import org.orekit.propagation.FieldSpacecraftState;
34 import org.orekit.propagation.SpacecraftState;
35 import org.orekit.propagation.semianalytical.dsst.utilities.AuxiliaryElements;
36 import org.orekit.propagation.semianalytical.dsst.utilities.FieldAuxiliaryElements;
37 import org.orekit.utils.ExtendedPositionProvider;
38 import org.orekit.utils.ParameterDriver;
39
40
41
42
43
44
45
46
47
48
49
50 public class DSSTSolarRadiationPressure extends AbstractGaussianContribution {
51
52
53 private static final double D_REF = 149597870000.0;
54
55
56 private static final double P_REF = 4.56e-6;
57
58
59 private static final double GAUSS_THRESHOLD = 1.0e-15;
60
61
62 private static final double S_ZERO = 1.0e-6;
63
64
65 private static final String PREFIX = "DSST-SRP-";
66
67
68 private final ExtendedPositionProvider sun;
69
70
71 private final double ae;
72
73
74 private final RadiationSensitive spacecraft;
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96 public DSSTSolarRadiationPressure(final double cr, final double area,
97 final ExtendedPositionProvider sun,
98 final OneAxisEllipsoid centralBody,
99 final double mu) {
100 this(D_REF, P_REF, cr, area, sun, centralBody, mu);
101 }
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119 public DSSTSolarRadiationPressure(final ExtendedPositionProvider sun,
120 final OneAxisEllipsoid centralBody,
121 final RadiationSensitive spacecraft,
122 final double mu) {
123 this(D_REF, P_REF, sun, centralBody, spacecraft, mu);
124 }
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144 public DSSTSolarRadiationPressure(final double dRef, final double pRef,
145 final double cr, final double area,
146 final ExtendedPositionProvider sun,
147 final OneAxisEllipsoid centralBody,
148 final double mu) {
149
150
151
152
153
154 this(dRef, pRef, sun, centralBody, new IsotropicRadiationSingleCoefficient(area, cr), mu);
155 }
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174 public DSSTSolarRadiationPressure(final double dRef, final double pRef,
175 final ExtendedPositionProvider sun,
176 final OneAxisEllipsoid centralBody,
177 final RadiationSensitive spacecraft,
178 final double mu) {
179
180
181 super(PREFIX, GAUSS_THRESHOLD,
182 new SolarRadiationPressure(dRef, pRef, sun, centralBody, spacecraft), mu);
183
184 this.sun = sun;
185 this.ae = centralBody.getEquatorialRadius();
186 this.spacecraft = spacecraft;
187 }
188
189
190
191
192 public RadiationSensitive getSpacecraft() {
193 return spacecraft;
194 }
195
196
197 protected List<ParameterDriver> getParametersDriversWithoutMu() {
198 return spacecraft.getRadiationParametersDrivers();
199 }
200
201
202 protected double[] getLLimits(final SpacecraftState state, final AuxiliaryElements auxiliaryElements) {
203
204
205 final double[] ll = {-FastMath.PI + MathUtils.normalizeAngle(state.getOrbit().getLv(), 0),
206 FastMath.PI + MathUtils.normalizeAngle(state.getOrbit().getLv(), 0)};
207
208
209 final Vector3D sunDir = sun.getPosition(state.getDate(), state.getFrame()).normalize();
210 final double alpha = sunDir.dotProduct(auxiliaryElements.getVectorF());
211 final double beta = sunDir.dotProduct(auxiliaryElements.getVectorG());
212 final double gamma = sunDir.dotProduct(auxiliaryElements.getVectorW());
213
214
215 if (FastMath.abs(gamma * auxiliaryElements.getSma() * (1. - auxiliaryElements.getEcc())) < ae) {
216
217
218 final double bet2 = beta * beta;
219 final double h2 = auxiliaryElements.getH() * auxiliaryElements.getH();
220 final double k2 = auxiliaryElements.getK() * auxiliaryElements.getK();
221 final double m = ae / (auxiliaryElements.getSma() * auxiliaryElements.getB());
222 final double m2 = m * m;
223 final double m4 = m2 * m2;
224 final double bb = alpha * beta + m2 * auxiliaryElements.getH() * auxiliaryElements.getK();
225 final double b2 = bb * bb;
226 final double cc = alpha * alpha - bet2 + m2 * (k2 - h2);
227 final double dd = 1. - bet2 - m2 * (1. + h2);
228 final double[] a = new double[5];
229 a[0] = 4. * b2 + cc * cc;
230 a[1] = 8. * bb * m2 * auxiliaryElements.getH() + 4. * cc * m2 * auxiliaryElements.getK();
231 a[2] = -4. * b2 + 4. * m4 * h2 - 2. * cc * dd + 4. * m4 * k2;
232 a[3] = -8. * bb * m2 * auxiliaryElements.getH() - 4. * dd * m2 * auxiliaryElements.getK();
233 a[4] = -4. * m4 * h2 + dd * dd;
234
235 final double[] roots = new double[4];
236 final int nbRoots = realQuarticRoots(a, roots);
237 if (nbRoots > 0) {
238
239 boolean entryFound = false;
240 boolean exitFound = false;
241
242 for (int i = 0; i < nbRoots; i++) {
243 final double cosL = roots[i];
244 final double sL = FastMath.sqrt((1. - cosL) * (1. + cosL));
245
246 for (int j = -1; j <= 1; j += 2) {
247 final double sinL = j * sL;
248 final double cPhi = alpha * cosL + beta * sinL;
249
250 if (cPhi < 0.) {
251 final double range = 1. + auxiliaryElements.getK() * cosL + auxiliaryElements.getH() * sinL;
252 final double S = 1. - m2 * range * range - cPhi * cPhi;
253
254 if (FastMath.abs(S) < S_ZERO) {
255
256 final double dSdL = m2 * range * (auxiliaryElements.getK() * sinL - auxiliaryElements.getH() * cosL) + cPhi * (alpha * sinL - beta * cosL);
257 if (dSdL > 0.) {
258
259 exitFound = true;
260 ll[0] = FastMath.atan2(sinL, cosL);
261 } else {
262
263 entryFound = true;
264 ll[1] = FastMath.atan2(sinL, cosL);
265 }
266 }
267 }
268 }
269 }
270
271 if (!(entryFound == exitFound)) {
272
273 ll[0] = -FastMath.PI;
274 ll[1] = FastMath.PI;
275 }
276
277 if (ll[0] > ll[1]) {
278
279 if (ll[1] < 0.) {
280 ll[1] += 2. * FastMath.PI;
281 } else {
282 ll[0] -= 2. * FastMath.PI;
283 }
284 }
285 }
286 }
287 return ll;
288 }
289
290
291 protected <T extends CalculusFieldElement<T>> T[] getLLimits(final FieldSpacecraftState<T> state,
292 final FieldAuxiliaryElements<T> auxiliaryElements) {
293
294 final Field<T> field = state.getDate().getField();
295 final T zero = field.getZero();
296 final T one = field.getOne();
297 final T pi = one.getPi();
298
299
300 final T[] ll = MathArrays.buildArray(field, 2);
301 ll[0] = MathUtils.normalizeAngle(state.getOrbit().getLv(), zero).subtract(pi);
302 ll[1] = MathUtils.normalizeAngle(state.getOrbit().getLv(), zero).add(pi);
303
304
305 final FieldVector3D<T> sunDir = sun.getPosition(state.getDate(), state.getFrame()).normalize();
306 final T alpha = sunDir.dotProduct(auxiliaryElements.getVectorF());
307 final T beta = sunDir.dotProduct(auxiliaryElements.getVectorG());
308 final T gamma = sunDir.dotProduct(auxiliaryElements.getVectorW());
309
310
311 if (FastMath.abs(gamma.multiply(auxiliaryElements.getSma()).multiply(auxiliaryElements.getEcc().negate().add(one))).getReal() < ae) {
312
313
314 final T bet2 = beta.multiply(beta);
315 final T h2 = auxiliaryElements.getH().multiply(auxiliaryElements.getH());
316 final T k2 = auxiliaryElements.getK().multiply(auxiliaryElements.getK());
317 final T m = (auxiliaryElements.getSma().multiply(auxiliaryElements.getB())).divide(ae).reciprocal();
318 final T m2 = m.square();
319 final T m4 = m2.square();
320 final T bb = alpha.multiply(beta).add(m2.multiply(auxiliaryElements.getH()).multiply(auxiliaryElements.getK()));
321 final T b2 = bb.multiply(bb);
322 final T cc = alpha.multiply(alpha).subtract(bet2).add(m2.multiply(k2.subtract(h2)));
323 final T dd = bet2.add(m2.multiply(h2.add(1.))).negate().add(one);
324 final T[] a = MathArrays.buildArray(field, 5);
325 a[0] = b2.multiply(4.).add(cc.multiply(cc));
326 a[1] = bb.multiply(8.).multiply(m2).multiply(auxiliaryElements.getH()).add(cc.multiply(4.).multiply(m2).multiply(auxiliaryElements.getK()));
327 a[2] = m4.multiply(h2).multiply(4.).subtract(cc.multiply(dd).multiply(2.)).add(m4.multiply(k2).multiply(4.)).subtract(b2.multiply(4.));
328 a[3] = auxiliaryElements.getH().multiply(m2).multiply(bb).multiply(8.).add(auxiliaryElements.getK().multiply(m2).multiply(dd).multiply(4.)).negate();
329 a[4] = dd.multiply(dd).subtract(m4.multiply(h2).multiply(4.));
330
331 final T[] roots = MathArrays.buildArray(field, 4);
332 final int nbRoots = realQuarticRoots(a, roots, field);
333 if (nbRoots > 0) {
334
335 boolean entryFound = false;
336 boolean exitFound = false;
337
338 for (int i = 0; i < nbRoots; i++) {
339 final T cosL = roots[i];
340 final T sL = FastMath.sqrt((cosL.negate().add(one)).multiply(cosL.add(one)));
341
342 for (int j = -1; j <= 1; j += 2) {
343 final T sinL = sL.multiply(j);
344 final T cPhi = cosL.multiply(alpha).add(sinL.multiply(beta));
345
346 if (cPhi.getReal() < 0.) {
347 final T range = cosL.multiply(auxiliaryElements.getK()).add(sinL.multiply(auxiliaryElements.getH())).add(one);
348 final T S = (range.multiply(range).multiply(m2).add(cPhi.multiply(cPhi))).negate().add(1.);
349
350 if (FastMath.abs(S).getReal() < S_ZERO) {
351
352 final T dSdL = m2.multiply(range).multiply(auxiliaryElements.getK().multiply(sinL).subtract(auxiliaryElements.getH().multiply(cosL))).add(cPhi.multiply(alpha.multiply(sinL).subtract(beta.multiply(cosL))));
353 if (dSdL.getReal() > 0.) {
354
355 exitFound = true;
356 ll[0] = FastMath.atan2(sinL, cosL);
357 } else {
358
359 entryFound = true;
360 ll[1] = FastMath.atan2(sinL, cosL);
361 }
362 }
363 }
364 }
365 }
366
367 if (!(entryFound == exitFound)) {
368
369 ll[0] = pi.negate();
370 ll[1] = pi;
371 }
372
373 if (ll[0].getReal() > ll[1].getReal()) {
374
375 if (ll[1].getReal() < 0.) {
376 ll[1] = ll[1].add(pi.multiply(2.0));
377 } else {
378 ll[0] = ll[0].subtract(pi.multiply(2.0));
379 }
380 }
381 }
382 }
383 return ll;
384 }
385
386
387
388
389 public double getEquatorialRadius() {
390 return ae;
391 }
392
393
394
395
396
397
398
399
400
401
402
403
404 private int realQuarticRoots(final double[] a, final double[] y) {
405
406 if (Precision.equals(a[0], 0.)) {
407 final double[] aa = new double[a.length - 1];
408 System.arraycopy(a, 1, aa, 0, aa.length);
409 return realCubicRoots(aa, y);
410 }
411
412
413 final double b = a[1] / a[0];
414 final double c = a[2] / a[0];
415 final double d = a[3] / a[0];
416 final double e = a[4] / a[0];
417 final double bh = b * 0.5;
418
419
420 final double[] z3 = new double[3];
421 final int i3 = realCubicRoots(new double[] {1.0, -c, b * d - 4. * e, e * (4. * c - b * b) - d * d}, z3);
422 if (i3 == 0) {
423 return 0;
424 }
425
426
427 final double z = z3[0];
428
429
430 final double zh = z * 0.5;
431 final double p = FastMath.max(z + bh * bh - c, 0.);
432 final double q = FastMath.max(zh * zh - e, 0.);
433 final double r = bh * z - d;
434 final double pp = FastMath.sqrt(p);
435 final double qq = FastMath.copySign(FastMath.sqrt(q), r);
436
437
438 final double[] y1 = new double[2];
439 final int n1 = realQuadraticRoots(new double[] {1.0, bh - pp, zh - qq}, y1);
440 final double[] y2 = new double[2];
441 final int n2 = realQuadraticRoots(new double[] {1.0, bh + pp, zh + qq}, y2);
442
443 if (n1 == 2) {
444 if (n2 == 2) {
445 y[0] = y1[0];
446 y[1] = y1[1];
447 y[2] = y2[0];
448 y[3] = y2[1];
449 return 4;
450 } else {
451 y[0] = y1[0];
452 y[1] = y1[1];
453 return 2;
454 }
455 } else {
456 if (n2 == 2) {
457 y[0] = y2[0];
458 y[1] = y2[1];
459 return 2;
460 } else {
461 return 0;
462 }
463 }
464 }
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479 private <T extends CalculusFieldElement<T>> int realQuarticRoots(final T[] a, final T[] y,
480 final Field<T> field) {
481
482 final T zero = field.getZero();
483
484
485 if (Precision.equals(a[0].getReal(), 0.)) {
486 final T[] aa = MathArrays.buildArray(field, a.length - 1);
487 System.arraycopy(a, 1, aa, 0, aa.length);
488 return realCubicRoots(aa, y, field);
489 }
490
491
492 final T b = a[1].divide(a[0]);
493 final T c = a[2].divide(a[0]);
494 final T d = a[3].divide(a[0]);
495 final T e = a[4].divide(a[0]);
496 final T bh = b.multiply(0.5);
497
498
499 final T[] z3 = MathArrays.buildArray(field, 3);
500 final T[] i = MathArrays.buildArray(field, 4);
501 i[0] = zero.newInstance(1.0);
502 i[1] = c.negate();
503 i[2] = b.multiply(d).subtract(e.multiply(4.0));
504 i[3] = e.multiply(c.multiply(4.).subtract(b.multiply(b))).subtract(d.multiply(d));
505 final int i3 = realCubicRoots(i, z3, field);
506 if (i3 == 0) {
507 return 0;
508 }
509
510
511 final T z = z3[0];
512
513
514 final T zh = z.multiply(0.5);
515 final T p = FastMath.max(z.add(bh.multiply(bh)).subtract(c), zero);
516 final T q = FastMath.max(zh.multiply(zh).subtract(e), zero);
517 final T r = bh.multiply(z).subtract(d);
518 final T pp = FastMath.sqrt(p);
519 final T qq = FastMath.copySign(FastMath.sqrt(q), r);
520
521
522 final T[] y1 = MathArrays.buildArray(field, 2);
523 final T[] n = MathArrays.buildArray(field, 3);
524 n[0] = zero.newInstance(1.0);
525 n[1] = bh.subtract(pp);
526 n[2] = zh.subtract(qq);
527 final int n1 = realQuadraticRoots(n, y1);
528 final T[] y2 = MathArrays.buildArray(field, 2);
529 final T[] nn = MathArrays.buildArray(field, 3);
530 nn[0] = zero.newInstance(1.0);
531 nn[1] = bh.add(pp);
532 nn[2] = zh.add(qq);
533 final int n2 = realQuadraticRoots(nn, y2);
534
535 if (n1 == 2) {
536 if (n2 == 2) {
537 y[0] = y1[0];
538 y[1] = y1[1];
539 y[2] = y2[0];
540 y[3] = y2[1];
541 return 4;
542 } else {
543 y[0] = y1[0];
544 y[1] = y1[1];
545 return 2;
546 }
547 } else {
548 if (n2 == 2) {
549 y[0] = y2[0];
550 y[1] = y2[1];
551 return 2;
552 } else {
553 return 0;
554 }
555 }
556 }
557
558
559
560
561
562
563
564
565
566
567
568
569 private int realCubicRoots(final double[] a, final double[] y) {
570 if (Precision.equals(a[0], 0.)) {
571
572 final double[] aa = new double[a.length - 1];
573 System.arraycopy(a, 1, aa, 0, aa.length);
574 return realQuadraticRoots(aa, y);
575 }
576
577
578 final double b = -a[1] / (3. * a[0]);
579 final double c = a[2] / a[0];
580 final double d = a[3] / a[0];
581 final double b2 = b * b;
582 final double p = b2 - c / 3.;
583 final double q = b * (b2 - c * 0.5) - d * 0.5;
584
585
586 final double disc = p * p * p - q * q;
587
588 if (disc < 0.) {
589
590 final double alpha = q + FastMath.copySign(FastMath.sqrt(-disc), q);
591 final double cbrtAl = FastMath.cbrt(alpha);
592 final double cbrtBe = p / cbrtAl;
593
594 if (p < 0.) {
595 y[0] = b + 2. * q / (cbrtAl * cbrtAl + cbrtBe * cbrtBe - p);
596 } else if (p > 0.) {
597 y[0] = b + cbrtAl + cbrtBe;
598 } else {
599 y[0] = b + cbrtAl;
600 }
601
602 return 1;
603
604 } else if (disc > 0.) {
605
606 final double phi = FastMath.atan2(FastMath.sqrt(disc), q) / 3.;
607 final double sqP = 2.0 * FastMath.sqrt(p);
608
609 y[0] = b + sqP * FastMath.cos(phi);
610 y[1] = b - sqP * FastMath.cos(FastMath.PI / 3. + phi);
611 y[2] = b - sqP * FastMath.cos(FastMath.PI / 3. - phi);
612
613 return 3;
614
615 } else {
616
617 final double cbrtQ = FastMath.cbrt(q);
618 final double root1 = b + 2. * cbrtQ;
619 final double root2 = b - cbrtQ;
620 if (q < 0.) {
621 y[0] = root2;
622 y[1] = root2;
623 y[2] = root1;
624 } else {
625 y[0] = root1;
626 y[1] = root2;
627 y[2] = root2;
628 }
629
630 return 3;
631 }
632 }
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647 private <T extends CalculusFieldElement<T>> int realCubicRoots(final T[] a, final T[] y,
648 final Field<T> field) {
649
650 if (Precision.equals(a[0].getReal(), 0.)) {
651
652 final T[] aa = MathArrays.buildArray(field, a.length - 1);
653 System.arraycopy(a, 1, aa, 0, aa.length);
654 return realQuadraticRoots(aa, y);
655 }
656
657
658 final T b = a[1].divide(a[0].multiply(3.)).negate();
659 final T c = a[2].divide(a[0]);
660 final T d = a[3].divide(a[0]);
661 final T b2 = b.square();
662 final T p = b2.subtract(c.divide(3.));
663 final T q = b.multiply(b2.subtract(c.multiply(0.5))).subtract(d.multiply(0.5));
664
665
666 final T disc = p.multiply(p).multiply(p).subtract(q.multiply(q));
667
668 if (disc.getReal() < 0.) {
669
670 final T alpha = FastMath.copySign(FastMath.sqrt(disc.negate()), q).add(q);
671 final T cbrtAl = FastMath.cbrt(alpha);
672 final T cbrtBe = p.divide(cbrtAl);
673
674 if (p .getReal() < 0.) {
675 y[0] = q.divide(cbrtAl.multiply(cbrtAl).add(cbrtBe.multiply(cbrtBe)).subtract(p)).multiply(2.).add(b);
676 } else if (p.getReal() > 0.) {
677 y[0] = b.add(cbrtAl).add(cbrtBe);
678 } else {
679 y[0] = b.add(cbrtAl);
680 }
681
682 return 1;
683
684 } else if (disc.getReal() > 0.) {
685
686 final T phi = FastMath.atan2(FastMath.sqrt(disc), q).divide(3.);
687 final T sqP = FastMath.sqrt(p).multiply(2.);
688
689 y[0] = b.add(sqP.multiply(FastMath.cos(phi)));
690 y[1] = b.subtract(sqP.multiply(FastMath.cos(phi.add(b.getPi().divide(3.)))));
691 y[2] = b.subtract(sqP.multiply(FastMath.cos(phi.negate().add(b.getPi().divide(3.)))));
692
693 return 3;
694
695 } else {
696
697 final T cbrtQ = FastMath.cbrt(q);
698 final T root1 = b.add(cbrtQ.multiply(2.0));
699 final T root2 = b.subtract(cbrtQ);
700 if (q.getReal() < 0.) {
701 y[0] = root2;
702 y[1] = root2;
703 y[2] = root1;
704 } else {
705 y[0] = root1;
706 y[1] = root2;
707 y[2] = root2;
708 }
709
710 return 3;
711 }
712 }
713
714
715
716
717
718
719
720
721
722
723
724
725 private int realQuadraticRoots(final double[] a, final double[] y) {
726 if (Precision.equals(a[0], 0.)) {
727
728 if (Precision.equals(a[1], 0.)) {
729
730 return 0;
731 }
732
733 y[0] = -a[2] / a[1];
734 return 1;
735 }
736
737
738 final double b = -0.5 * a[1] / a[0];
739 final double c = a[2] / a[0];
740
741
742 final double d = b * b - c;
743
744 if (d < 0.) {
745
746 return 0;
747 } else if (d > 0.) {
748
749 final double y0 = b + FastMath.copySign(FastMath.sqrt(d), b);
750 final double y1 = c / y0;
751 y[0] = FastMath.max(y0, y1);
752 y[1] = FastMath.min(y0, y1);
753 return 2;
754 } else {
755
756 y[0] = b;
757 y[1] = b;
758 return 2;
759 }
760 }
761
762
763
764
765
766
767
768
769
770
771
772
773
774 private <T extends CalculusFieldElement<T>> int realQuadraticRoots(final T[] a, final T[] y) {
775
776 if (Precision.equals(a[0].getReal(), 0.)) {
777
778 if (Precision.equals(a[1].getReal(), 0.)) {
779
780 return 0;
781 }
782
783 y[0] = a[2].divide(a[1]).negate();
784 return 1;
785 }
786
787
788 final T b = a[1].divide(a[0]).multiply(0.5).negate();
789 final T c = a[2].divide(a[0]);
790
791
792 final T d = b.square().subtract(c);
793
794 if (d.getReal() < 0.) {
795
796 return 0;
797 } else if (d.getReal() > 0.) {
798
799 final T y0 = b.add(FastMath.copySign(FastMath.sqrt(d), b));
800 final T y1 = c.divide(y0);
801 y[0] = FastMath.max(y0, y1);
802 y[1] = FastMath.min(y0, y1);
803 return 2;
804 } else {
805
806 y[0] = b;
807 y[1] = b;
808 return 2;
809 }
810 }
811
812 }