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.ArrayList;
21 import java.util.Collections;
22 import java.util.List;
23 import java.util.stream.Stream;
24
25 import org.hipparchus.CalculusFieldElement;
26 import org.hipparchus.Field;
27 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
28 import org.hipparchus.geometry.euclidean.threed.Vector3D;
29 import org.hipparchus.util.FastMath;
30 import org.hipparchus.util.MathArrays;
31 import org.orekit.bodies.OneAxisEllipsoid;
32 import org.orekit.frames.Frame;
33 import org.orekit.propagation.events.EclipseDetector;
34 import org.orekit.propagation.events.EventDetector;
35 import org.orekit.propagation.events.EventDetectionSettings;
36 import org.orekit.propagation.events.FieldEclipseDetector;
37 import org.orekit.propagation.events.FieldEventDetector;
38 import org.orekit.propagation.events.FieldEventDetectionSettings;
39 import org.orekit.propagation.events.handlers.FieldResetDerivativesOnEvent;
40 import org.orekit.propagation.events.handlers.ResetDerivativesOnEvent;
41 import org.orekit.utils.Constants;
42 import org.orekit.utils.ExtendedPositionProviderAdapter;
43 import org.orekit.utils.ExtendedPositionProvider;
44 import org.orekit.utils.OccultationEngine;
45
46
47
48
49
50
51
52 public abstract class AbstractRadiationForceModel implements RadiationForceModel {
53
54
55 private static final double ANGULAR_MARGIN = 1.0e-10;
56
57
58 private static final double ECLIPSE_MAX_CHECK = 60.0;
59
60
61 private static final double ECLIPSE_THRESHOLD = 1.0e-7;
62
63
64 private static final double SPHERICAL_BODY_FLATNESS = 0.0;
65
66
67 private static final String OCCULTING_PREFIX = "occulting-";
68
69
70
71
72 private final List<OccultationEngine> occultingBodies;
73
74
75 private final EventDetectionSettings eclipseDetectionSettings;
76
77
78
79
80
81
82
83
84
85 protected AbstractRadiationForceModel(final ExtendedPositionProvider sun, final OneAxisEllipsoid centralBody,
86 final EventDetectionSettings eclipseDetectionSettings) {
87
88 occultingBodies = new ArrayList<>(2);
89 occultingBodies.add(new OccultationEngine(sun, Constants.SUN_RADIUS, centralBody));
90 this.eclipseDetectionSettings = eclipseDetectionSettings;
91 }
92
93
94 @Override
95 public Stream<EventDetector> getEventDetectors() {
96 final EventDetector[] detectors = new EventDetector[2 * occultingBodies.size()];
97 for (int i = 0; i < occultingBodies.size(); ++i) {
98 final OccultationEngine occulting = occultingBodies.get(i);
99 detectors[2 * i] = new EclipseDetector(occulting).
100 withUmbra().
101 withMargin(-ANGULAR_MARGIN).
102 withDetectionSettings(eclipseDetectionSettings).
103 withHandler(new ResetDerivativesOnEvent());
104 detectors[2 * i + 1] = new EclipseDetector(occulting).
105 withPenumbra().
106 withMargin(ANGULAR_MARGIN).
107 withDetectionSettings(eclipseDetectionSettings).
108 withHandler(new ResetDerivativesOnEvent());
109 }
110
111
112 return Stream.concat(Stream.of(detectors), RadiationForceModel.super.getEventDetectors());
113 }
114
115
116
117
118
119
120 public static EventDetectionSettings getDefaultEclipseDetectionSettings() {
121 return new EventDetectionSettings(ECLIPSE_MAX_CHECK, ECLIPSE_THRESHOLD, EventDetectionSettings.DEFAULT_MAX_ITER);
122 }
123
124
125 @Override
126 public <T extends CalculusFieldElement<T>> Stream<FieldEventDetector<T>> getFieldEventDetectors(final Field<T> field) {
127 final T zero = field.getZero();
128 @SuppressWarnings("unchecked")
129 final FieldEventDetector<T>[] detectors = (FieldEventDetector<T>[]) Array.newInstance(FieldEventDetector.class,
130 2 * occultingBodies.size());
131 for (int i = 0; i < occultingBodies.size(); ++i) {
132 final OccultationEngine occulting = occultingBodies.get(i);
133 detectors[2 * i] = new FieldEclipseDetector<>(field, occulting).
134 withUmbra().
135 withMargin(zero.newInstance(-ANGULAR_MARGIN)).
136 withDetectionSettings(new FieldEventDetectionSettings<>(field, eclipseDetectionSettings)).
137 withHandler(new FieldResetDerivativesOnEvent<>());
138 detectors[2 * i + 1] = new FieldEclipseDetector<>(field, occulting).
139 withPenumbra().
140 withMargin(zero.newInstance(ANGULAR_MARGIN)).
141 withDetectionSettings(new FieldEventDetectionSettings<>(field, eclipseDetectionSettings)).
142 withHandler(new FieldResetDerivativesOnEvent<>());
143 }
144 return Stream.concat(Stream.of(detectors), RadiationForceModel.super.getFieldEventDetectors(field));
145 }
146
147
148
149
150
151
152
153
154
155
156 protected double[] getGeneralEclipseAngles(final Vector3D position, final Vector3D occultingPosition, final double occultingRadius,
157 final Vector3D occultedPosition, final double occultedRadius) {
158 final double[] angle = new double[3];
159
160 final Vector3D satOccultedVector = occultedPosition.subtract(position);
161 final Vector3D satOccultingVector = occultingPosition.subtract(position);
162
163
164 angle[0] = Vector3D.angle(satOccultedVector, satOccultingVector);
165
166
167 angle[1] = FastMath.asin(occultingRadius / satOccultingVector.getNorm());
168
169
170 angle[2] = FastMath.asin(occultedRadius / satOccultedVector.getNorm());
171
172 return angle;
173 }
174
175
176
177
178
179
180
181
182
183
184
185 protected <T extends CalculusFieldElement<T>> T[] getGeneralEclipseAngles(final FieldVector3D<T> position,
186 final FieldVector3D<T> occultingPosition, final T occultingRadius,
187 final FieldVector3D<T> occultedPosition, final T occultedRadius) {
188 final T[] angle = MathArrays.buildArray(position.getX().getField(), 3);
189
190 final FieldVector3D<T> satOccultedVector = occultedPosition.subtract(position);
191 final FieldVector3D<T> satOccultingVector = occultingPosition.subtract(position);
192
193
194 angle[0] = FieldVector3D.angle(satOccultedVector, satOccultingVector);
195
196
197 angle[1] = occultingRadius.divide(satOccultingVector.getNorm()).asin();
198
199
200 angle[2] = occultedRadius.divide(satOccultedVector.getNorm()).asin();
201
202 return angle;
203 }
204
205
206
207
208
209
210
211
212
213
214 public void addOccultingBody(final ExtendedPositionProvider provider, final double radius) {
215
216
217
218 Frame parent = occultingBodies.get(0).getOcculting().getBodyFrame();
219 while (!parent.isPseudoInertial()) {
220 parent = parent.getParent();
221 }
222
223
224 final Frame inertiallyOrientedBodyFrame =
225 new ExtendedPositionProviderAdapter(parent,
226 provider,
227 OCCULTING_PREFIX + occultingBodies.size());
228
229
230 final OneAxisEllipsoid sphericalOccultingBody =
231 new OneAxisEllipsoid(radius, SPHERICAL_BODY_FLATNESS, inertiallyOrientedBodyFrame);
232
233 addOccultingBody(sphericalOccultingBody);
234
235 }
236
237
238
239
240
241
242
243
244
245
246 public void addOccultingBody(final OneAxisEllipsoid occulting) {
247
248
249 final OccultationEngine central = occultingBodies.get(0);
250
251
252 final OccultationEngine additional =
253 new OccultationEngine(central.getOcculted(), central.getOccultedRadius(), occulting);
254
255
256 occultingBodies.add(additional);
257
258 }
259
260
261
262
263
264
265
266
267
268
269 public List<OccultationEngine> getOccultingBodies() {
270 return Collections.unmodifiableList(occultingBodies);
271 }
272
273 }