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