1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.forces.gravity;
18
19 import org.hipparchus.Field;
20 import org.hipparchus.analysis.differentiation.DSFactory;
21 import org.hipparchus.analysis.differentiation.DerivativeStructure;
22 import org.hipparchus.analysis.differentiation.Gradient;
23 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
24 import org.hipparchus.geometry.euclidean.threed.Vector3D;
25 import org.hipparchus.ode.AbstractIntegrator;
26 import org.hipparchus.ode.nonstiff.AdaptiveStepsizeFieldIntegrator;
27 import org.hipparchus.ode.nonstiff.AdaptiveStepsizeIntegrator;
28 import org.hipparchus.ode.nonstiff.DormandPrince853FieldIntegrator;
29 import org.hipparchus.ode.nonstiff.DormandPrince853Integrator;
30 import org.hipparchus.util.FastMath;
31 import org.junit.jupiter.api.Assertions;
32 import org.junit.jupiter.api.BeforeAll;
33 import org.junit.jupiter.api.Test;
34 import org.orekit.Utils;
35 import org.orekit.attitudes.LofOffset;
36 import org.orekit.forces.AbstractLegacyForceModelTest;
37 import org.orekit.forces.ForceModel;
38 import org.orekit.frames.Frame;
39 import org.orekit.frames.FramesFactory;
40 import org.orekit.frames.LOFType;
41 import org.orekit.orbits.CartesianOrbit;
42 import org.orekit.orbits.CircularOrbit;
43 import org.orekit.orbits.FieldKeplerianOrbit;
44 import org.orekit.orbits.KeplerianOrbit;
45 import org.orekit.orbits.Orbit;
46 import org.orekit.orbits.OrbitType;
47 import org.orekit.orbits.PositionAngleType;
48 import org.orekit.propagation.FieldSpacecraftState;
49 import org.orekit.propagation.SpacecraftState;
50 import org.orekit.propagation.numerical.FieldNumericalPropagator;
51 import org.orekit.propagation.numerical.NumericalPropagator;
52 import org.orekit.time.AbsoluteDate;
53 import org.orekit.time.FieldAbsoluteDate;
54 import org.orekit.utils.Constants;
55 import org.orekit.utils.FieldPVCoordinates;
56 import org.orekit.utils.PVCoordinates;
57
58
59 public class RelativityTest extends AbstractLegacyForceModelTest {
60
61
62 private static final double c = Constants.SPEED_OF_LIGHT;
63
64 private static final AbsoluteDate date = AbsoluteDate.J2000_EPOCH;
65
66 private static final Frame frame = FramesFactory.getGCRF();
67
68 @Override
69 protected FieldVector3D<DerivativeStructure> accelerationDerivatives(final ForceModel forceModel,
70 final FieldSpacecraftState<DerivativeStructure> state)
71 {
72 try {
73 final FieldVector3D<DerivativeStructure> position = state.getPVCoordinates().getPosition();
74 final FieldVector3D<DerivativeStructure> velocity = state.getPVCoordinates().getVelocity();
75 double gm = forceModel.
76 getParameterDriver(NewtonianAttraction.CENTRAL_ATTRACTION_COEFFICIENT).
77 getValue(state.getDate().toAbsoluteDate());
78
79 final DerivativeStructure r2 = position.getNormSq();
80 final DerivativeStructure r = r2.sqrt();
81
82 final DerivativeStructure s2 = velocity.getNormSq();
83 final double c2 = Constants.SPEED_OF_LIGHT * Constants.SPEED_OF_LIGHT;
84
85 return new FieldVector3D<>(r.reciprocal().multiply(4 * gm).subtract(s2),
86 position,
87 position.dotProduct(velocity).multiply(4),
88 velocity).scalarMultiply(r2.multiply(r).multiply(c2).reciprocal().multiply(gm));
89
90 } catch (IllegalArgumentException | SecurityException e) {
91 return null;
92 }
93 }
94
95 @Override
96 protected FieldVector3D<Gradient> accelerationDerivativesGradient(final ForceModel forceModel,
97 final FieldSpacecraftState<Gradient> state)
98 {
99 try {
100 final FieldVector3D<Gradient> position = state.getPVCoordinates().getPosition();
101 final FieldVector3D<Gradient> velocity = state.getPVCoordinates().getVelocity();
102 double gm = forceModel.
103 getParameterDriver(NewtonianAttraction.CENTRAL_ATTRACTION_COEFFICIENT).
104 getValue(state.getDate().toAbsoluteDate());
105
106 final Gradient r2 = position.getNormSq();
107 final Gradient r = r2.sqrt();
108
109 final Gradient s2 = velocity.getNormSq();
110 final double c2 = Constants.SPEED_OF_LIGHT * Constants.SPEED_OF_LIGHT;
111
112 return new FieldVector3D<>(r.reciprocal().multiply(4 * gm).subtract(s2),
113 position,
114 position.dotProduct(velocity).multiply(4),
115 velocity).scalarMultiply(r2.multiply(r).multiply(c2).reciprocal().multiply(gm));
116
117 } catch (IllegalArgumentException | SecurityException e) {
118 return null;
119 }
120 }
121
122
123 @BeforeAll
124 public static void setUpBefore() {
125 Utils.setDataRoot("regular-data");
126 }
127
128
129
130
131 @Test
132 public void testAcceleration() {
133 double gm = Constants.EIGEN5C_EARTH_MU;
134 Relativity relativity = new Relativity(gm);
135 Assertions.assertFalse(relativity.dependsOnPositionOnly());
136 final Vector3D p = new Vector3D(3777828.75000531, -5543949.549783845, 2563117.448578311);
137 final Vector3D v = new Vector3D(489.0060271721, -2849.9328929417, -6866.4671013153);
138 SpacecraftState s = new SpacecraftState(new CartesianOrbit(
139 new PVCoordinates(p, v),
140 frame,
141 date,
142 gm
143 ));
144
145
146 Vector3D acceleration = relativity.acceleration(s, relativity.getParameters(s.getDate()));
147
148
149
150 double tol = 2e-11;
151 Vector3D circularApproximation = p.normalize().scalarMultiply(
152 gm / p.getNormSq() * 3 * v.getNormSq() / (c * c));
153 Assertions.assertEquals(
154 0,
155 acceleration.subtract(circularApproximation).getNorm(),
156 tol);
157
158 FieldSpacecraftState<DerivativeStructure> sDS = toDS(s, new LofOffset(s.getFrame(), LOFType.LVLH_CCSDS));
159 final Vector3D actualDerivatives = relativity
160 .acceleration(sDS, relativity.getParameters(sDS.getDate().getField(), sDS.getDate()))
161 .toVector3D();
162 Assertions.assertEquals(
163 0,
164 actualDerivatives.subtract(circularApproximation).getNorm(),
165 tol);
166 }
167
168 @Test
169 public void testJacobianVs80Implementation() {
170 double gm = Constants.EIGEN5C_EARTH_MU;
171 Relativity relativity = new Relativity(gm);
172 final Vector3D p = new Vector3D(3777828.75000531, -5543949.549783845, 2563117.448578311);
173 final Vector3D v = new Vector3D(489.0060271721, -2849.9328929417, -6866.4671013153);
174 SpacecraftState s = new SpacecraftState(new CartesianOrbit(
175 new PVCoordinates(p, v),
176 frame,
177 date,
178 gm
179 ));
180
181 checkStateJacobianVs80Implementation(s, relativity,
182 new LofOffset(s.getFrame(), LOFType.LVLH_CCSDS),
183 1.0e-50, false);
184 }
185
186 @Test
187 public void testJacobianVs80ImplementationGradient() {
188 double gm = Constants.EIGEN5C_EARTH_MU;
189 Relativity relativity = new Relativity(gm);
190 final Vector3D p = new Vector3D(3777828.75000531, -5543949.549783845, 2563117.448578311);
191 final Vector3D v = new Vector3D(489.0060271721, -2849.9328929417, -6866.4671013153);
192 SpacecraftState s = new SpacecraftState(new CartesianOrbit(
193 new PVCoordinates(p, v),
194 frame,
195 date,
196 gm
197 ));
198
199 checkStateJacobianVs80ImplementationGradient(s, relativity,
200 new LofOffset(s.getFrame(), LOFType.LVLH_CCSDS),
201 1.0e-50, false);
202 }
203
204
205
206
207 @Test
208 public void testAccelerationCircular() {
209 double gm = Constants.EIGEN5C_EARTH_MU;
210 double re = Constants.WGS84_EARTH_EQUATORIAL_RADIUS;
211 Relativity relativity = new Relativity(gm);
212 final CircularOrbit orbit = new CircularOrbit(
213 re + 500e3, 0, 0, FastMath.toRadians(41.2), -1, 3, PositionAngleType.TRUE,
214 frame,
215 date,
216 gm
217 );
218 SpacecraftState state = new SpacecraftState(orbit);
219
220
221 Vector3D acceleration = relativity.acceleration(state, relativity.getParameters(state.getDate()));
222
223
224
225 double tol = 2e-10;
226 PVCoordinates pv = state.getPVCoordinates();
227 Vector3D p = pv.getPosition();
228 Vector3D v = pv.getVelocity();
229 Vector3D circularApproximation = p.normalize().scalarMultiply(
230 gm / p.getNormSq() * 3 * v.getNormSq() / (c * c));
231 Assertions.assertEquals(
232 0,
233 acceleration.subtract(circularApproximation).getNorm(),
234 tol);
235
236 FieldSpacecraftState<DerivativeStructure> sDS = toDS(state, new LofOffset(state.getFrame(), LOFType.LVLH_CCSDS));
237 FieldVector3D<DerivativeStructure> gradient =
238 relativity.acceleration(sDS, relativity.getParameters(sDS.getDate().getField(), sDS.getDate()));
239 Assertions.assertEquals(
240 0,
241 gradient.toVector3D().subtract(circularApproximation).getNorm(),
242 tol);
243 double r = p.getNorm();
244 double s = v.getNorm();
245 final double[] actualdx = gradient.getX().getAllDerivatives();
246 final double x = p.getX();
247 final double vx = v.getX();
248 double expectedDxDx = gm / (c * c * r * r * r * r * r) *
249 (-13 * x * x * s * s + 3 * r * r * s * s + 4 * r * r * vx * vx);
250 Assertions.assertEquals(expectedDxDx, actualdx[1], 2);
251 }
252
253
254
255
256
257
258 @Test
259 public void RealFieldTest() {
260 DSFactory factory = new DSFactory(6, 5);
261 DerivativeStructure a_0 = factory.variable(0, 7e7);
262 DerivativeStructure e_0 = factory.variable(1, 0.4);
263 DerivativeStructure i_0 = factory.variable(2, 85 * FastMath.PI / 180);
264 DerivativeStructure R_0 = factory.variable(3, 0.7);
265 DerivativeStructure O_0 = factory.variable(4, 0.5);
266 DerivativeStructure n_0 = factory.variable(5, 0.1);
267 DerivativeStructure mu = factory.constant(Constants.EIGEN5C_EARTH_MU);
268
269 Field<DerivativeStructure> field = a_0.getField();
270
271 FieldAbsoluteDate<DerivativeStructure> J2000 = new FieldAbsoluteDate<>(field);
272
273 Frame EME = FramesFactory.getEME2000();
274
275 FieldKeplerianOrbit<DerivativeStructure> FKO = new FieldKeplerianOrbit<>(a_0, e_0, i_0, R_0, O_0, n_0,
276 PositionAngleType.MEAN,
277 EME,
278 J2000,
279 mu);
280
281 FieldSpacecraftState<DerivativeStructure> initialState = new FieldSpacecraftState<>(FKO);
282
283 SpacecraftState iSR = initialState.toSpacecraftState();
284 OrbitType type = OrbitType.KEPLERIAN;
285 double[][] tolerance = NumericalPropagator.tolerances(0.001, FKO.toOrbit(), type);
286
287
288 AdaptiveStepsizeFieldIntegrator<DerivativeStructure> integrator =
289 new DormandPrince853FieldIntegrator<>(field, 0.001, 200, tolerance[0], tolerance[1]);
290 integrator.setInitialStepSize(60);
291 AdaptiveStepsizeIntegrator RIntegrator =
292 new DormandPrince853Integrator(0.001, 200, tolerance[0], tolerance[1]);
293 RIntegrator.setInitialStepSize(60);
294
295 FieldNumericalPropagator<DerivativeStructure> FNP = new FieldNumericalPropagator<>(field, integrator);
296 FNP.setOrbitType(type);
297 FNP.setInitialState(initialState);
298
299 NumericalPropagator NP = new NumericalPropagator(RIntegrator);
300 NP.setOrbitType(type);
301 NP.setInitialState(iSR);
302
303 final Relativity forceModel = new Relativity(Constants.EIGEN5C_EARTH_MU);
304
305 FNP.addForceModel(forceModel);
306 NP.addForceModel(forceModel);
307
308
309 checkRealFieldPropagation(FKO, PositionAngleType.MEAN, 1005., NP, FNP,
310 1.0e-15, 5.0e-10, 3.0e-11, 3.0e-10,
311 1, false);
312 }
313
314
315
316
317
318
319 @Test
320 public void RealFieldGradientTest() {
321
322 final int freeParameters = 6;
323 Gradient a_0 = Gradient.variable(freeParameters, 0, 7e7);
324 Gradient e_0 = Gradient.variable(freeParameters, 1, 0.4);
325 Gradient i_0 = Gradient.variable(freeParameters, 2, 85 * FastMath.PI / 180);
326 Gradient R_0 = Gradient.variable(freeParameters, 3, 0.7);
327 Gradient O_0 = Gradient.variable(freeParameters, 4, 0.5);
328 Gradient n_0 = Gradient.variable(freeParameters, 5, 0.1);
329 Gradient mu = Gradient.constant(freeParameters, Constants.EIGEN5C_EARTH_MU);
330
331 Field<Gradient> field = a_0.getField();
332
333 FieldAbsoluteDate<Gradient> J2000 = new FieldAbsoluteDate<>(field);
334
335 Frame EME = FramesFactory.getEME2000();
336
337 FieldKeplerianOrbit<Gradient> FKO = new FieldKeplerianOrbit<>(a_0, e_0, i_0, R_0, O_0, n_0,
338 PositionAngleType.MEAN,
339 EME,
340 J2000,
341 mu);
342
343 FieldSpacecraftState<Gradient> initialState = new FieldSpacecraftState<>(FKO);
344
345 SpacecraftState iSR = initialState.toSpacecraftState();
346 OrbitType type = OrbitType.KEPLERIAN;
347 double[][] tolerance = NumericalPropagator.tolerances(0.001, FKO.toOrbit(), type);
348
349
350 AdaptiveStepsizeFieldIntegrator<Gradient> integrator =
351 new DormandPrince853FieldIntegrator<>(field, 0.001, 200, tolerance[0], tolerance[1]);
352 integrator.setInitialStepSize(60);
353 AdaptiveStepsizeIntegrator RIntegrator =
354 new DormandPrince853Integrator(0.001, 200, tolerance[0], tolerance[1]);
355 RIntegrator.setInitialStepSize(60);
356
357 FieldNumericalPropagator<Gradient> FNP = new FieldNumericalPropagator<>(field, integrator);
358 FNP.setOrbitType(type);
359 FNP.setInitialState(initialState);
360
361 NumericalPropagator NP = new NumericalPropagator(RIntegrator);
362 NP.setOrbitType(type);
363 NP.setInitialState(iSR);
364
365 final Relativity forceModel = new Relativity(Constants.EIGEN5C_EARTH_MU);
366
367 FNP.addForceModel(forceModel);
368 NP.addForceModel(forceModel);
369
370
371 checkRealFieldPropagationGradient(FKO, PositionAngleType.MEAN, 1005., NP, FNP,
372 1.0e-15, 1.3e-2, 2.9e-4, 4.4e-3,
373 1, false);
374 }
375
376
377
378
379
380 @Test
381 public void RealFieldExpectErrorTest() {
382 DSFactory factory = new DSFactory(6, 0);
383 DerivativeStructure a_0 = factory.variable(0, 7e7);
384 DerivativeStructure e_0 = factory.variable(1, 0.4);
385 DerivativeStructure i_0 = factory.variable(2, 85 * FastMath.PI / 180);
386 DerivativeStructure R_0 = factory.variable(3, 0.7);
387 DerivativeStructure O_0 = factory.variable(4, 0.5);
388 DerivativeStructure n_0 = factory.variable(5, 0.1);
389
390 Field<DerivativeStructure> field = a_0.getField();
391 DerivativeStructure zero = field.getZero();
392
393 FieldAbsoluteDate<DerivativeStructure> J2000 = new FieldAbsoluteDate<>(field);
394
395 Frame EME = FramesFactory.getEME2000();
396
397 FieldKeplerianOrbit<DerivativeStructure> FKO = new FieldKeplerianOrbit<>(a_0, e_0, i_0, R_0, O_0, n_0,
398 PositionAngleType.MEAN,
399 EME,
400 J2000,
401 zero.add(Constants.EIGEN5C_EARTH_MU));
402
403 FieldSpacecraftState<DerivativeStructure> initialState = new FieldSpacecraftState<>(FKO);
404
405 SpacecraftState iSR = initialState.toSpacecraftState();
406
407 OrbitType type = OrbitType.KEPLERIAN;
408 double[][] tolerance = NumericalPropagator.tolerances(0.001, FKO.toOrbit(), type);
409
410
411 AdaptiveStepsizeFieldIntegrator<DerivativeStructure> integrator =
412 new DormandPrince853FieldIntegrator<>(field, 0.001, 200, tolerance[0], tolerance[1]);
413 integrator.setInitialStepSize(60);
414 AdaptiveStepsizeIntegrator RIntegrator =
415 new DormandPrince853Integrator(0.001, 200, tolerance[0], tolerance[1]);
416 RIntegrator.setInitialStepSize(60);
417
418 FieldNumericalPropagator<DerivativeStructure> FNP = new FieldNumericalPropagator<>(field, integrator);
419 FNP.setOrbitType(type);
420 FNP.setInitialState(initialState);
421
422 NumericalPropagator NP = new NumericalPropagator(RIntegrator);
423 NP.setOrbitType(type);
424 NP.setInitialState(iSR);
425
426 final Relativity forceModel = new Relativity(Constants.EIGEN5C_EARTH_MU);
427
428 FNP.addForceModel(forceModel);
429
430
431 FieldAbsoluteDate<DerivativeStructure> target = J2000.shiftedBy(1000.);
432 FieldSpacecraftState<DerivativeStructure> finalState_DS = FNP.propagate(target);
433 SpacecraftState finalState_R = NP.propagate(target.toAbsoluteDate());
434 FieldPVCoordinates<DerivativeStructure> finPVC_DS = finalState_DS.getPVCoordinates();
435 PVCoordinates finPVC_R = finalState_R.getPVCoordinates();
436
437 Assertions.assertEquals(0,
438 Vector3D.distance(finPVC_DS.toPVCoordinates().getPosition(), finPVC_R.getPosition()),
439 8.0e-13 * finPVC_R.getPosition().getNorm());
440 }
441
442
443
444
445
446 @Test
447 public void testSmallEffectOnOrbit() {
448
449 final double gm = Constants.EIGEN5C_EARTH_MU;
450 Orbit orbit =
451 new KeplerianOrbit(
452 7500e3, 0.025, FastMath.toRadians(41.2), 0, 0, 0, PositionAngleType.TRUE,
453 frame,
454 date,
455 gm
456 );
457 double[][] tol = NumericalPropagator.tolerances(0.00001, orbit, OrbitType.CARTESIAN);
458 AbstractIntegrator integrator = new DormandPrince853Integrator(1, 3600, tol[0], tol[1]);
459 NumericalPropagator propagator = new NumericalPropagator(integrator);
460 propagator.setOrbitType(OrbitType.CARTESIAN);
461 propagator.addForceModel(new Relativity(gm));
462 propagator.setInitialState(new SpacecraftState(orbit));
463
464
465 AbsoluteDate end = orbit.getDate().shiftedBy(30 * Constants.JULIAN_DAY);
466 PVCoordinates actual = propagator.getPVCoordinates(end, frame);
467
468
469 KeplerianOrbit endOrbit = new KeplerianOrbit(actual, frame, end, gm);
470 KeplerianOrbit startOrbit = new KeplerianOrbit(orbit);
471 double dp = endOrbit.getPerigeeArgument() - startOrbit.getPerigeeArgument();
472 double dtYears = end.durationFrom(orbit.getDate()) / Constants.JULIAN_YEAR;
473 double dpDeg = FastMath.toDegrees(dp);
474
475 double arcsecPerYear = dpDeg * 3600 / dtYears;
476 Assertions.assertEquals(11, arcsecPerYear, 0.5);
477 }
478
479
480
481
482
483 @Test
484 public void testGetSetGM() {
485
486 Relativity relativity = new Relativity(Constants.EIGEN5C_EARTH_MU);
487
488
489 Assertions.assertEquals(
490 Constants.EIGEN5C_EARTH_MU,
491 relativity.getParameterDriver(NewtonianAttraction.CENTRAL_ATTRACTION_COEFFICIENT).getValue(),
492 0);
493 relativity.getParameterDriver(NewtonianAttraction.CENTRAL_ATTRACTION_COEFFICIENT).setValue(1);
494 Assertions.assertEquals(
495 1,
496 relativity.getParameterDriver(NewtonianAttraction.CENTRAL_ATTRACTION_COEFFICIENT).getValue(),
497 0);
498 }
499
500 }