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 org.apache.commons.math3.analysis.differentiation.DerivativeStructure;
20 import org.apache.commons.math3.geometry.euclidean.threed.FieldRotation;
21 import org.apache.commons.math3.geometry.euclidean.threed.FieldVector3D;
22 import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
23 import org.apache.commons.math3.ode.AbstractParameterizable;
24 import org.apache.commons.math3.util.FastMath;
25 import org.orekit.errors.OrekitException;
26 import org.orekit.errors.OrekitMessages;
27 import org.orekit.forces.ForceModel;
28 import org.orekit.frames.Frame;
29 import org.orekit.propagation.SpacecraftState;
30 import org.orekit.propagation.events.AbstractDetector;
31 import org.orekit.propagation.events.EventDetector;
32 import org.orekit.propagation.events.handlers.EventHandler;
33 import org.orekit.propagation.numerical.TimeDerivativesEquations;
34 import org.orekit.time.AbsoluteDate;
35 import org.orekit.utils.Constants;
36 import org.orekit.utils.PVCoordinatesProvider;
37
38
39
40
41
42
43
44
45 public class SolarRadiationPressure extends AbstractParameterizable implements ForceModel {
46
47
48 private static final double D_REF = 149597870000.0;
49
50
51 private static final double P_REF = 4.56e-6;
52
53
54 private final double kRef;
55
56
57 private final PVCoordinatesProvider sun;
58
59
60 private final double equatorialRadius;
61
62
63 private final RadiationSensitive spacecraft;
64
65
66
67
68
69
70
71
72
73
74
75 public SolarRadiationPressure(final PVCoordinatesProvider sun, final double equatorialRadius,
76 final RadiationSensitive spacecraft) {
77 this(D_REF, P_REF, sun, equatorialRadius, spacecraft);
78 }
79
80
81
82
83
84
85
86
87
88
89
90
91
92 public SolarRadiationPressure(final double dRef, final double pRef,
93 final PVCoordinatesProvider sun,
94 final double equatorialRadius,
95 final RadiationSensitive spacecraft) {
96 super(RadiationSensitive.ABSORPTION_COEFFICIENT, RadiationSensitive.REFLECTION_COEFFICIENT);
97 this.kRef = pRef * dRef * dRef;
98 this.sun = sun;
99 this.equatorialRadius = equatorialRadius;
100 this.spacecraft = spacecraft;
101 }
102
103
104 public void addContribution(final SpacecraftState s, final TimeDerivativesEquations adder)
105 throws OrekitException {
106
107 final AbsoluteDate date = s.getDate();
108 final Frame frame = s.getFrame();
109 final Vector3D position = s.getPVCoordinates().getPosition();
110 final Vector3D sunSatVector = position.subtract(sun.getPVCoordinates(date, frame).getPosition());
111 final double r2 = sunSatVector.getNormSq();
112
113
114 final double rawP = kRef * getLightningRatio(position, frame, date) / r2;
115 final Vector3D flux = new Vector3D(rawP / FastMath.sqrt(r2), sunSatVector);
116
117 final Vector3D acceleration = spacecraft.radiationPressureAcceleration(date, frame, position, s.getAttitude().getRotation(),
118 s.getMass(), flux);
119
120
121 adder.addAcceleration(acceleration, s.getFrame());
122
123 }
124
125
126
127
128
129
130
131
132 public double getLightningRatio(final Vector3D position, final Frame frame, final AbsoluteDate date)
133 throws OrekitException {
134
135
136 final double[] angle = getEclipseAngles(position, frame, date);
137
138
139 final double sunEarthAngle = angle[0];
140
141
142 final double alphaCentral = angle[1];
143
144
145 final double alphaSun = angle[2];
146
147 double result = 1.0;
148
149
150 if (sunEarthAngle - alphaCentral + alphaSun <= 0.0) {
151 result = 0.0;
152 } else if (sunEarthAngle - alphaCentral - alphaSun < 0.0) {
153
154 final double sEA2 = sunEarthAngle * sunEarthAngle;
155 final double oo2sEA = 1.0 / (2. * sunEarthAngle);
156 final double aS2 = alphaSun * alphaSun;
157 final double aE2 = alphaCentral * alphaCentral;
158 final double aE2maS2 = aE2 - aS2;
159
160 final double alpha1 = (sEA2 - aE2maS2) * oo2sEA;
161 final double alpha2 = (sEA2 + aE2maS2) * oo2sEA;
162
163
164 final double a1oaS = FastMath.min(1.0, FastMath.max(-1.0, alpha1 / alphaSun));
165 final double aS2ma12 = FastMath.max(0.0, aS2 - alpha1 * alpha1);
166 final double a2oaE = FastMath.min(1.0, FastMath.max(-1.0, alpha2 / alphaCentral));
167 final double aE2ma22 = FastMath.max(0.0, aE2 - alpha2 * alpha2);
168
169 final double P1 = aS2 * FastMath.acos(a1oaS) - alpha1 * FastMath.sqrt(aS2ma12);
170 final double P2 = aE2 * FastMath.acos(a2oaE) - alpha2 * FastMath.sqrt(aE2ma22);
171
172 result = 1. - (P1 + P2) / (FastMath.PI * aS2);
173 }
174
175 return result;
176 }
177
178
179 public EventDetector[] getEventsDetectors() {
180 return new EventDetector[] {
181 new UmbraDetector(), new PenumbraDetector()
182 };
183 }
184
185
186 public FieldVector3D<DerivativeStructure> accelerationDerivatives(final AbsoluteDate date, final Frame frame,
187 final FieldVector3D<DerivativeStructure> position, final FieldVector3D<DerivativeStructure> velocity,
188 final FieldRotation<DerivativeStructure> rotation, final DerivativeStructure mass)
189 throws OrekitException {
190
191 final FieldVector3D<DerivativeStructure> sunSatVector = position.subtract(sun.getPVCoordinates(date, frame).getPosition());
192 final DerivativeStructure r2 = sunSatVector.getNormSq();
193
194
195 final double ratio = getLightningRatio(position.toVector3D(), frame, date);
196 final DerivativeStructure rawP = r2.reciprocal().multiply(kRef * ratio);
197 final FieldVector3D<DerivativeStructure> flux = new FieldVector3D<DerivativeStructure>(rawP.divide(r2.sqrt()), sunSatVector);
198
199
200 return spacecraft.radiationPressureAcceleration(date, frame, position, rotation, mass, flux);
201
202 }
203
204
205 public FieldVector3D<DerivativeStructure> accelerationDerivatives(final SpacecraftState s, final String paramName)
206 throws OrekitException {
207
208 complainIfNotSupported(paramName);
209 final AbsoluteDate date = s.getDate();
210 final Frame frame = s.getFrame();
211 final Vector3D position = s.getPVCoordinates().getPosition();
212 final Vector3D sunSatVector = position.subtract(sun.getPVCoordinates(date, frame).getPosition());
213 final double r2 = sunSatVector.getNormSq();
214
215
216 final double rawP = kRef * getLightningRatio(position, frame, date) / r2;
217 final Vector3D flux = new Vector3D(rawP / FastMath.sqrt(r2), sunSatVector);
218
219 return spacecraft.radiationPressureAcceleration(date, frame, position, s.getAttitude().getRotation(),
220 s.getMass(), flux, paramName);
221
222 }
223
224
225 public double getParameter(final String name)
226 throws IllegalArgumentException {
227 complainIfNotSupported(name);
228 if (name.equals(RadiationSensitive.ABSORPTION_COEFFICIENT)) {
229 return spacecraft.getAbsorptionCoefficient();
230 }
231 return spacecraft.getReflectionCoefficient();
232 }
233
234
235 public void setParameter(final String name, final double value)
236 throws IllegalArgumentException {
237 complainIfNotSupported(name);
238 if (name.equals(RadiationSensitive.ABSORPTION_COEFFICIENT)) {
239 spacecraft.setAbsorptionCoefficient(value);
240 } else {
241 spacecraft.setReflectionCoefficient(value);
242 }
243 }
244
245
246
247
248
249
250
251
252 private double[] getEclipseAngles(final Vector3D position,
253 final Frame frame,
254 final AbsoluteDate date)
255 throws OrekitException {
256 final double[] angle = new double[3];
257
258 final Vector3D satSunVector = sun.getPVCoordinates(date, frame).getPosition().subtract(position);
259
260
261 angle[0] = Vector3D.angle(satSunVector, position.negate());
262
263
264 final double r = position.getNorm();
265 if (r <= equatorialRadius) {
266 throw new OrekitException(OrekitMessages.TRAJECTORY_INSIDE_BRILLOUIN_SPHERE, r);
267 }
268 angle[1] = FastMath.asin(equatorialRadius / r);
269
270
271 angle[2] = FastMath.asin(Constants.SUN_RADIUS / satSunVector.getNorm());
272
273 return angle;
274 }
275
276
277 private class UmbraDetector extends AbstractDetector<UmbraDetector> {
278
279
280 private static final long serialVersionUID = 20141228L;
281
282
283 public UmbraDetector() {
284 super(60.0, 1.0e-3, DEFAULT_MAX_ITER, new EventHandler<UmbraDetector>() {
285
286
287 public Action eventOccurred(final SpacecraftState s, final UmbraDetector detector,
288 final boolean increasing) {
289 return Action.RESET_DERIVATIVES;
290 }
291
292
293 @Override
294 public SpacecraftState resetState(final UmbraDetector detector, final SpacecraftState oldState) {
295 return oldState;
296 }
297
298 });
299 }
300
301
302
303
304
305
306
307
308
309
310
311
312
313 private UmbraDetector(final double maxCheck, final double threshold,
314 final int maxIter, final EventHandler<UmbraDetector> handler) {
315 super(maxCheck, threshold, maxIter, handler);
316 }
317
318
319 @Override
320 protected UmbraDetector create(final double newMaxCheck, final double newThreshold,
321 final int newMaxIter, final EventHandler<UmbraDetector> newHandler) {
322 return new UmbraDetector(newMaxCheck, newThreshold, newMaxIter, newHandler);
323 }
324
325
326
327
328
329
330
331 public double g(final SpacecraftState s) throws OrekitException {
332 final double[] angle = getEclipseAngles(s.getPVCoordinates().getPosition(),
333 s.getFrame(), s.getDate());
334 return angle[0] - angle[1] + angle[2];
335 }
336
337 }
338
339
340 private class PenumbraDetector extends AbstractDetector<PenumbraDetector> {
341
342
343 private static final long serialVersionUID = 20141228L;
344
345
346 public PenumbraDetector() {
347 super(60.0, 1.0e-3, DEFAULT_MAX_ITER, new EventHandler<PenumbraDetector>() {
348
349
350 public Action eventOccurred(final SpacecraftState s, final PenumbraDetector detector,
351 final boolean increasing) {
352 return Action.RESET_DERIVATIVES;
353 }
354
355
356 @Override
357 public SpacecraftState resetState(final PenumbraDetector detector, final SpacecraftState oldState) {
358 return oldState;
359 }
360
361 });
362 }
363
364
365
366
367
368
369
370
371
372
373
374
375
376 private PenumbraDetector(final double maxCheck, final double threshold,
377 final int maxIter, final EventHandler<PenumbraDetector> handler) {
378 super(maxCheck, threshold, maxIter, handler);
379 }
380
381
382 @Override
383 protected PenumbraDetector create(final double newMaxCheck, final double newThreshold,
384 final int newMaxIter, final EventHandler<PenumbraDetector> newHandler) {
385 return new PenumbraDetector(newMaxCheck, newThreshold, newMaxIter, newHandler);
386 }
387
388
389
390
391
392
393
394 public double g(final SpacecraftState s) throws OrekitException {
395 final double[] angle = getEclipseAngles(s.getPVCoordinates().getPosition(),
396 s.getFrame(), s.getDate());
397 return angle[0] - angle[1] - angle[2];
398 }
399
400 }
401
402 }