1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.forces.radiation;
18
19 import java.lang.reflect.Array;
20 import java.util.HashMap;
21 import java.util.Map;
22 import java.util.stream.Stream;
23
24 import org.hipparchus.Field;
25 import org.hipparchus.CalculusFieldElement;
26 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
27 import org.hipparchus.geometry.euclidean.threed.Vector3D;
28 import org.hipparchus.ode.events.Action;
29 import org.hipparchus.util.FastMath;
30 import org.hipparchus.util.MathArrays;
31 import org.orekit.errors.OrekitException;
32 import org.orekit.errors.OrekitMessages;
33 import org.orekit.forces.AbstractForceModel;
34 import org.orekit.propagation.FieldSpacecraftState;
35 import org.orekit.propagation.SpacecraftState;
36 import org.orekit.propagation.events.AbstractDetector;
37 import org.orekit.propagation.events.EventDetector;
38 import org.orekit.propagation.events.FieldAbstractDetector;
39 import org.orekit.propagation.events.FieldEventDetector;
40 import org.orekit.propagation.events.handlers.EventHandler;
41 import org.orekit.propagation.events.handlers.FieldEventHandler;
42 import org.orekit.utils.Constants;
43 import org.orekit.utils.ExtendedPVCoordinatesProvider;
44
45
46
47
48
49
50
51 public abstract class AbstractRadiationForceModel extends AbstractForceModel {
52
53
54 private static final double ANGULAR_MARGIN = 1.0e-10;
55
56
57 private final double equatorialRadius;
58
59
60 private final ExtendedPVCoordinatesProvider sun;
61
62
63 private final Map<ExtendedPVCoordinatesProvider, Double> otherOccultingBodies;
64
65
66
67
68
69
70
71 protected AbstractRadiationForceModel(final ExtendedPVCoordinatesProvider sun, final double equatorialRadius) {
72 this.sun = sun;
73 this.equatorialRadius = equatorialRadius;
74 this.otherOccultingBodies = new HashMap<>();
75 }
76
77
78 @Override
79 public boolean dependsOnPositionOnly() {
80 return false;
81 }
82
83
84 @Override
85 public Stream<EventDetector> getEventsDetectors() {
86 final EventDetector[] detectors = new EventDetector[2 + 2 * otherOccultingBodies.size()];
87 detectors[0] = new UmbraDetector();
88 detectors[1] = new PenumbraDetector();
89 int i = 2;
90 for (Map.Entry<ExtendedPVCoordinatesProvider, Double> entry : otherOccultingBodies.entrySet()) {
91 detectors[i] = new GeneralUmbraDetector(entry.getKey(), entry.getValue());
92 detectors[i + 1] = new GeneralPenumbraDetector(entry.getKey(), entry.getValue());
93 i = i + 2;
94 }
95 return Stream.of(detectors);
96 }
97
98
99 @Override
100 public <T extends CalculusFieldElement<T>> Stream<FieldEventDetector<T>> getFieldEventsDetectors(final Field<T> field) {
101 final T zero = field.getZero();
102 @SuppressWarnings("unchecked")
103 final FieldEventDetector<T>[] detectors = (FieldEventDetector<T>[]) Array.newInstance(FieldEventDetector.class,
104 2 + 2 * otherOccultingBodies.size());
105 detectors[0] = new FieldUmbraDetector<>(field);
106 detectors[1] = new FieldPenumbraDetector<>(field);
107 int i = 2;
108 for (Map.Entry<ExtendedPVCoordinatesProvider, Double> entry : otherOccultingBodies.entrySet()) {
109 detectors[i] = new FieldGeneralUmbraDetector<>(field, entry.getKey(), zero.newInstance(entry.getValue()));
110 detectors[i + 1] = new FieldGeneralPenumbraDetector<>(field, entry.getKey(), zero.newInstance(entry.getValue()));
111 i = i + 2;
112 }
113 return Stream.of(detectors);
114 }
115
116
117
118
119
120
121
122 protected double[] getEclipseAngles(final Vector3D sunPosition, final Vector3D position) {
123 final double[] angle = new double[3];
124
125 final Vector3D satSunVector = sunPosition.subtract(position);
126
127
128 angle[0] = Vector3D.angle(satSunVector, position.negate());
129
130
131 final double r = position.getNorm();
132 if (r <= equatorialRadius) {
133 throw new OrekitException(OrekitMessages.TRAJECTORY_INSIDE_BRILLOUIN_SPHERE, r);
134 }
135 angle[1] = FastMath.asin(equatorialRadius / r);
136
137
138 angle[2] = FastMath.asin(Constants.SUN_RADIUS / satSunVector.getNorm());
139
140 return angle;
141 }
142
143
144
145
146
147
148
149
150
151
152
153 protected double[] getGeneralEclipseAngles(final Vector3D position, final Vector3D occultingPosition, final double occultingRadius,
154 final Vector3D occultedPosition, final double occultedRadius) {
155 final double[] angle = new double[3];
156
157 final Vector3D satOccultedVector = occultedPosition.subtract(position);
158 final Vector3D satOccultingVector = occultingPosition.subtract(position);
159
160
161 angle[0] = Vector3D.angle(satOccultedVector, satOccultingVector);
162
163
164 angle[1] = FastMath.asin(occultingRadius / satOccultingVector.getNorm());
165
166
167 angle[2] = FastMath.asin(occultedRadius / satOccultedVector.getNorm());
168
169 return angle;
170 }
171
172
173
174
175
176
177
178
179 protected <T extends CalculusFieldElement<T>> T[] getEclipseAngles(final FieldVector3D<T> sunPosition, final FieldVector3D<T> position) {
180 final T[] angle = MathArrays.buildArray(position.getX().getField(), 3);
181
182 final FieldVector3D<T> mP = position.negate();
183 final FieldVector3D<T> satSunVector = mP.add(sunPosition);
184
185
186 angle[0] = FieldVector3D.angle(satSunVector, mP);
187
188
189 final T r = position.getNorm();
190 if (r.getReal() <= equatorialRadius) {
191 throw new OrekitException(OrekitMessages.TRAJECTORY_INSIDE_BRILLOUIN_SPHERE, r);
192 }
193 angle[1] = r.reciprocal().multiply(equatorialRadius).asin();
194
195
196 angle[2] = satSunVector.getNorm().reciprocal().multiply(Constants.SUN_RADIUS).asin();
197
198 return angle;
199 }
200
201
202
203
204
205
206
207
208
209
210
211 protected <T extends CalculusFieldElement<T>> T[] getGeneralEclipseAngles(final FieldVector3D<T> position,
212 final FieldVector3D<T> occultingPosition, final T occultingRadius,
213 final FieldVector3D<T> occultedPosition, final T occultedRadius) {
214 final T[] angle = MathArrays.buildArray(position.getX().getField(), 3);
215
216 final FieldVector3D<T> satOccultedVector = occultedPosition.subtract(position);
217 final FieldVector3D<T> satOccultingVector = occultingPosition.subtract(position);
218
219
220 angle[0] = FieldVector3D.angle(satOccultedVector, satOccultingVector);
221
222
223 angle[1] = occultingRadius.divide(satOccultingVector.getNorm()).asin();
224
225
226 angle[2] = occultedRadius.divide(satOccultedVector.getNorm()).asin();
227
228 return angle;
229 }
230
231
232
233
234
235
236
237 public void addOccultingBody(final ExtendedPVCoordinatesProvider provider, final double radius) {
238 otherOccultingBodies.put(provider, radius);
239 }
240
241
242
243
244
245 public Map<ExtendedPVCoordinatesProvider, Double> getOtherOccultingBodies() {
246 return otherOccultingBodies;
247 }
248
249
250
251
252
253 public double getEquatorialRadius() {
254 return equatorialRadius;
255 }
256
257
258
259 private class UmbraDetector extends AbstractDetector<UmbraDetector> {
260
261
262 UmbraDetector() {
263 super(60.0, 1.0e-3, DEFAULT_MAX_ITER, new EventHandler<UmbraDetector>() {
264
265
266 public Action eventOccurred(final SpacecraftState s, final UmbraDetector detector,
267 final boolean increasing) {
268 return Action.RESET_DERIVATIVES;
269 }
270
271 });
272 }
273
274
275
276
277
278
279
280
281
282
283
284
285
286 private UmbraDetector(final double maxCheck, final double threshold, final int maxIter,
287 final EventHandler<? super UmbraDetector> handler) {
288 super(maxCheck, threshold, maxIter, handler);
289 }
290
291
292 @Override
293 protected UmbraDetector create(final double newMaxCheck, final double newThreshold, final int newMaxIter,
294 final EventHandler<? super UmbraDetector> newHandler) {
295 return new UmbraDetector(newMaxCheck, newThreshold, newMaxIter, newHandler);
296 }
297
298
299
300
301
302
303 public double g(final SpacecraftState s) {
304 final double[] angle = getEclipseAngles(sun.getPVCoordinates(s.getDate(), s.getFrame()).getPosition(),
305 s.getPVCoordinates().getPosition());
306 return angle[0] - angle[1] + angle[2] - ANGULAR_MARGIN;
307 }
308
309 }
310
311
312 private class PenumbraDetector extends AbstractDetector<PenumbraDetector> {
313
314
315 PenumbraDetector() {
316 super(60.0, 1.0e-3, DEFAULT_MAX_ITER, new EventHandler<PenumbraDetector>() {
317
318
319 public Action eventOccurred(final SpacecraftState s, final PenumbraDetector detector,
320 final boolean increasing) {
321 return Action.RESET_DERIVATIVES;
322 }
323
324 });
325 }
326
327
328
329
330
331
332
333
334
335
336
337
338
339 private PenumbraDetector(final double maxCheck, final double threshold, final int maxIter,
340 final EventHandler<? super PenumbraDetector> handler) {
341 super(maxCheck, threshold, maxIter, handler);
342 }
343
344
345 @Override
346 protected PenumbraDetector create(final double newMaxCheck, final double newThreshold, final int newMaxIter,
347 final EventHandler<? super PenumbraDetector> newHandler) {
348 return new PenumbraDetector(newMaxCheck, newThreshold, newMaxIter, newHandler);
349 }
350
351
352
353
354
355
356 public double g(final SpacecraftState s) {
357 final double[] angle = getEclipseAngles(sun.getPVCoordinates(s.getDate(), s.getFrame()).getPosition(),
358 s.getPVCoordinates().getPosition());
359 return angle[0] - angle[1] - angle[2] + ANGULAR_MARGIN;
360 }
361
362 }
363
364
365 private class FieldUmbraDetector<T extends CalculusFieldElement<T>>
366 extends FieldAbstractDetector<FieldUmbraDetector<T>, T> {
367
368
369
370
371 FieldUmbraDetector(final Field<T> field) {
372 super(field.getZero().add(60.0), field.getZero().add(1.0e-3),
373 DEFAULT_MAX_ITER, new FieldEventHandler<FieldUmbraDetector<T>, T>() {
374
375
376 public Action eventOccurred(final FieldSpacecraftState<T> s,
377 final FieldUmbraDetector<T> detector,
378 final boolean increasing) {
379 return Action.RESET_DERIVATIVES;
380 }
381
382 });
383 }
384
385
386
387
388
389
390
391
392
393
394
395
396 private FieldUmbraDetector(final T maxCheck, final T threshold, final int maxIter,
397 final FieldEventHandler<? super FieldUmbraDetector<T>, T> handler) {
398 super(maxCheck, threshold, maxIter, handler);
399 }
400
401
402 @Override
403 protected FieldUmbraDetector<T> create(final T newMaxCheck, final T newThreshold, final int newMaxIter,
404 final FieldEventHandler<? super FieldUmbraDetector<T>, T> newHandler) {
405 return new FieldUmbraDetector<>(newMaxCheck, newThreshold, newMaxIter, newHandler);
406 }
407
408
409
410
411
412
413 public T g(final FieldSpacecraftState<T> s) {
414 final T[] angle = getEclipseAngles(sun.getPVCoordinates(s.getDate(), s.getFrame()).getPosition(),
415 s.getPVCoordinates().getPosition());
416 return angle[0].subtract(angle[1]).add(angle[2]).subtract(ANGULAR_MARGIN);
417 }
418
419 }
420
421
422 private class FieldPenumbraDetector<T extends CalculusFieldElement<T>>
423 extends FieldAbstractDetector<FieldPenumbraDetector<T>, T> {
424
425
426
427
428 FieldPenumbraDetector(final Field<T> field) {
429 super(field.getZero().add(60.0), field.getZero().add(1.0e-3),
430 DEFAULT_MAX_ITER, new FieldEventHandler<FieldPenumbraDetector<T>, T>() {
431
432
433 public Action eventOccurred(final FieldSpacecraftState<T> s,
434 final FieldPenumbraDetector<T> detector,
435 final boolean increasing) {
436 return Action.RESET_DERIVATIVES;
437 }
438
439 });
440 }
441
442
443
444
445
446
447
448
449
450
451
452
453 private FieldPenumbraDetector(final T maxCheck, final T threshold, final int maxIter,
454 final FieldEventHandler<? super FieldPenumbraDetector<T>, T> handler) {
455 super(maxCheck, threshold, maxIter, handler);
456 }
457
458
459 @Override
460 protected FieldPenumbraDetector<T> create(final T newMaxCheck, final T newThreshold, final int newMaxIter,
461 final FieldEventHandler<? super FieldPenumbraDetector<T>, T> newHandler) {
462 return new FieldPenumbraDetector<>(newMaxCheck, newThreshold, newMaxIter, newHandler);
463 }
464
465
466
467
468
469
470 public T g(final FieldSpacecraftState<T> s) {
471 final T[] angle = getEclipseAngles(sun.getPVCoordinates(s.getDate(), s.getFrame()).getPosition(),
472 s.getPVCoordinates().getPosition());
473 return angle[0].subtract(angle[1]).subtract(angle[2]).add(ANGULAR_MARGIN);
474 }
475
476 }
477
478
479 private class GeneralUmbraDetector extends AbstractDetector<GeneralUmbraDetector> {
480
481
482 private ExtendedPVCoordinatesProvider provider;
483
484
485 private double radius;
486
487
488
489
490
491 GeneralUmbraDetector(final ExtendedPVCoordinatesProvider provider, final double radius) {
492 super(60.0, 1.0e-3, DEFAULT_MAX_ITER, new EventHandler<GeneralUmbraDetector>() {
493
494
495 public Action eventOccurred(final SpacecraftState s, final GeneralUmbraDetector detector,
496 final boolean increasing) {
497 return Action.RESET_DERIVATIVES;
498 }
499
500 });
501 this.provider = provider;
502 this.radius = radius;
503 }
504
505
506
507
508
509
510
511
512
513
514
515
516
517 private GeneralUmbraDetector(final double maxCheck, final double threshold, final int maxIter,
518 final EventHandler<? super GeneralUmbraDetector> handler) {
519 super(maxCheck, threshold, maxIter, handler);
520 }
521
522
523 @Override
524 protected GeneralUmbraDetector create(final double newMaxCheck, final double newThreshold, final int newMaxIter,
525 final EventHandler<? super GeneralUmbraDetector> newHandler) {
526 return new GeneralUmbraDetector(newMaxCheck, newThreshold, newMaxIter, newHandler);
527 }
528
529
530
531
532
533
534 public double g(final SpacecraftState s) {
535 final double[] angle = getGeneralEclipseAngles(s.getPVCoordinates().getPosition(),
536 provider.getPVCoordinates(s.getDate(), s.getFrame()).getPosition(),
537 radius, sun.getPVCoordinates(s.getDate(), s.getFrame()).getPosition(),
538 Constants.SUN_RADIUS);
539 return angle[0] - angle[1] + angle[2] - ANGULAR_MARGIN;
540 }
541
542 }
543
544
545 private class GeneralPenumbraDetector extends AbstractDetector<GeneralPenumbraDetector> {
546
547
548 private ExtendedPVCoordinatesProvider provider;
549
550
551 private double radius;
552
553
554
555
556
557 GeneralPenumbraDetector(final ExtendedPVCoordinatesProvider provider, final double radius) {
558 super(60.0, 1.0e-3, DEFAULT_MAX_ITER, new EventHandler<GeneralPenumbraDetector>() {
559
560
561 public Action eventOccurred(final SpacecraftState s, final GeneralPenumbraDetector detector,
562 final boolean increasing) {
563 return Action.RESET_DERIVATIVES;
564 }
565
566 });
567 this.provider = provider;
568 this.radius = radius;
569 }
570
571
572
573
574
575
576
577
578
579
580
581
582
583 private GeneralPenumbraDetector(final double maxCheck, final double threshold, final int maxIter,
584 final EventHandler<? super GeneralPenumbraDetector> handler) {
585 super(maxCheck, threshold, maxIter, handler);
586 }
587
588
589 @Override
590 protected GeneralPenumbraDetector create(final double newMaxCheck, final double newThreshold, final int newMaxIter,
591 final EventHandler<? super GeneralPenumbraDetector> newHandler) {
592 return new GeneralPenumbraDetector(newMaxCheck, newThreshold, newMaxIter, newHandler);
593 }
594
595
596
597
598
599
600 public double g(final SpacecraftState s) {
601 final double[] angle = getGeneralEclipseAngles(s.getPVCoordinates().getPosition(),
602 provider.getPVCoordinates(s.getDate(), s.getFrame()).getPosition(),
603 radius, sun.getPVCoordinates(s.getDate(), s.getFrame()).getPosition(),
604 Constants.SUN_RADIUS);
605 return angle[0] - angle[1] - angle[2] + ANGULAR_MARGIN;
606 }
607
608 }
609
610
611 private class FieldGeneralUmbraDetector<T extends CalculusFieldElement<T>>
612 extends FieldAbstractDetector<FieldGeneralUmbraDetector<T>, T> {
613
614
615 private ExtendedPVCoordinatesProvider provider;
616
617
618 private T radius;
619
620
621
622
623
624
625 FieldGeneralUmbraDetector(final Field<T> field, final ExtendedPVCoordinatesProvider provider, final T radius) {
626 super(field.getZero().add(60.0), field.getZero().add(1.0e-3),
627 DEFAULT_MAX_ITER, new FieldEventHandler<FieldGeneralUmbraDetector<T>, T>() {
628
629
630 public Action eventOccurred(final FieldSpacecraftState<T> s,
631 final FieldGeneralUmbraDetector<T> detector,
632 final boolean increasing) {
633 return Action.RESET_DERIVATIVES;
634 }
635
636 });
637 this.provider = provider;
638 this.radius = radius;
639 }
640
641
642
643
644
645
646
647
648
649
650
651
652 private FieldGeneralUmbraDetector(final T maxCheck, final T threshold,
653 final int maxIter,
654 final FieldEventHandler<? super FieldGeneralUmbraDetector<T>, T> handler) {
655 super(maxCheck, threshold, maxIter, handler);
656 }
657
658
659 @Override
660 protected FieldGeneralUmbraDetector<T> create(final T newMaxCheck, final T newThreshold, final int newMaxIter,
661 final FieldEventHandler<? super FieldGeneralUmbraDetector<T>, T> newHandler) {
662 return new FieldGeneralUmbraDetector<>(newMaxCheck, newThreshold, newMaxIter, newHandler);
663 }
664
665
666
667
668
669
670 public T g(final FieldSpacecraftState<T> s) {
671 final T[] angle = getGeneralEclipseAngles(s.getPVCoordinates().getPosition(),
672 provider.getPVCoordinates(s.getDate(), s.getFrame()).getPosition(),
673 radius, sun.getPVCoordinates(s.getDate(), s.getFrame()).getPosition(),
674 s.getA().getField().getZero().add(Constants.SUN_RADIUS));
675 return angle[0].subtract(angle[1]).add(angle[2]).subtract(ANGULAR_MARGIN);
676 }
677
678 }
679
680
681 private class FieldGeneralPenumbraDetector<T extends CalculusFieldElement<T>>
682 extends FieldAbstractDetector<FieldGeneralPenumbraDetector<T>, T> {
683
684
685 private ExtendedPVCoordinatesProvider provider;
686
687
688 private T radius;
689
690
691
692
693
694
695 FieldGeneralPenumbraDetector(final Field<T> field, final ExtendedPVCoordinatesProvider provider, final T radius) {
696 super(field.getZero().add(60.0), field.getZero().add(1.0e-3),
697 DEFAULT_MAX_ITER, new FieldEventHandler<FieldGeneralPenumbraDetector<T>, T>() {
698
699
700 public Action eventOccurred(final FieldSpacecraftState<T> s,
701 final FieldGeneralPenumbraDetector<T> detector,
702 final boolean increasing) {
703 return Action.RESET_DERIVATIVES;
704 }
705
706 });
707 this.provider = provider;
708 this.radius = radius;
709 }
710
711
712
713
714
715
716
717
718
719
720
721
722 private FieldGeneralPenumbraDetector(final T maxCheck, final T threshold, final int maxIter,
723 final FieldEventHandler<? super FieldGeneralPenumbraDetector<T>, T> handler) {
724 super(maxCheck, threshold, maxIter, handler);
725 }
726
727
728 @Override
729 protected FieldGeneralPenumbraDetector<T> create(final T newMaxCheck, final T newThreshold, final int newMaxIter,
730 final FieldEventHandler<? super FieldGeneralPenumbraDetector<T>, T> newHandler) {
731 return new FieldGeneralPenumbraDetector<>(newMaxCheck, newThreshold, newMaxIter, newHandler);
732 }
733
734
735
736
737
738
739 public T g(final FieldSpacecraftState<T> s) {
740 final T[] angle = getGeneralEclipseAngles(s.getPVCoordinates().getPosition(),
741 provider.getPVCoordinates(s.getDate(), s.getFrame()).getPosition(),
742 radius, sun.getPVCoordinates(s.getDate(), s.getFrame()).getPosition(),
743 s.getA().getField().getZero().add(Constants.SUN_RADIUS));
744 return angle[0].subtract(angle[1]).subtract(angle[2]).add(ANGULAR_MARGIN);
745 }
746
747 }
748 }