1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.rugged;
18
19
20 import static org.junit.jupiter.api.Assertions.assertEquals;
21
22 import java.lang.reflect.Field;
23 import java.lang.reflect.Modifier;
24 import java.util.ArrayList;
25 import java.util.List;
26 import java.util.Map;
27
28 import org.hipparchus.geometry.euclidean.threed.Rotation;
29 import org.hipparchus.geometry.euclidean.threed.RotationConvention;
30 import org.hipparchus.geometry.euclidean.threed.Vector3D;
31 import org.hipparchus.ode.nonstiff.DormandPrince853Integrator;
32 import org.hipparchus.util.FastMath;
33 import org.junit.jupiter.api.Assertions;
34 import org.orekit.attitudes.AttitudeProvider;
35 import org.orekit.attitudes.NadirPointing;
36 import org.orekit.attitudes.YawCompensation;
37 import org.orekit.bodies.BodyShape;
38 import org.orekit.bodies.CelestialBodyFactory;
39 import org.orekit.bodies.GeodeticPoint;
40 import org.orekit.bodies.OneAxisEllipsoid;
41 import org.orekit.data.DataContext;
42 import org.orekit.forces.gravity.HolmesFeatherstoneAttractionModel;
43 import org.orekit.forces.gravity.ThirdBodyAttraction;
44 import org.orekit.forces.gravity.potential.GravityFieldFactory;
45 import org.orekit.forces.gravity.potential.NormalizedSphericalHarmonicsProvider;
46 import org.orekit.frames.Frame;
47 import org.orekit.frames.FramesFactory;
48 import org.orekit.frames.Transform;
49 import org.orekit.orbits.CircularOrbit;
50 import org.orekit.orbits.FieldCartesianOrbit;
51 import org.orekit.orbits.FieldCircularOrbit;
52 import org.orekit.orbits.FieldEquinoctialOrbit;
53 import org.orekit.orbits.FieldKeplerianOrbit;
54 import org.orekit.orbits.Orbit;
55 import org.orekit.orbits.OrbitType;
56 import org.orekit.orbits.PositionAngleType;
57 import org.orekit.propagation.CartesianToleranceProvider;
58 import org.orekit.propagation.Propagator;
59 import org.orekit.propagation.SpacecraftState;
60 import org.orekit.propagation.ToleranceProvider;
61 import org.orekit.propagation.analytical.KeplerianPropagator;
62 import org.orekit.propagation.numerical.NumericalPropagator;
63 import org.orekit.propagation.semianalytical.dsst.utilities.JacobiPolynomials;
64 import org.orekit.propagation.semianalytical.dsst.utilities.NewcombOperators;
65 import org.orekit.rugged.linesensor.SensorPixel;
66 import org.orekit.rugged.los.LOSBuilder;
67 import org.orekit.rugged.los.TimeDependentLOS;
68 import org.orekit.time.AbsoluteDate;
69 import org.orekit.time.TimeScale;
70 import org.orekit.time.TimeScalesFactory;
71 import org.orekit.utils.Constants;
72 import org.orekit.utils.IERSConventions;
73 import org.orekit.utils.PVCoordinates;
74 import org.orekit.utils.TimeStampedAngularCoordinates;
75 import org.orekit.utils.TimeStampedPVCoordinates;
76
77
78
79
80
81 public class TestUtils {
82
83
84
85
86
87
88 public static void clearFactories() {
89
90 clearFactoryMaps(CelestialBodyFactory.class);
91 CelestialBodyFactory.clearCelestialBodyLoaders();
92 clearFactoryMaps(FramesFactory.class);
93 clearFactoryMaps(TimeScalesFactory.class);
94 clearFactory(TimeScalesFactory.class, TimeScale.class);
95 clearFactoryMaps(FieldCartesianOrbit.class);
96 clearFactoryMaps(FieldKeplerianOrbit.class);
97 clearFactoryMaps(FieldCircularOrbit.class);
98 clearFactoryMaps(FieldEquinoctialOrbit.class);
99 clearFactoryMaps(JacobiPolynomials.class);
100 clearFactoryMaps(NewcombOperators.class);
101 for (final Class<?> c : NewcombOperators.class.getDeclaredClasses()) {
102 if (c.getName().endsWith("PolynomialsGenerator")) {
103 clearFactoryMaps(c);
104 }
105 }
106 FramesFactory.clearEOPHistoryLoaders();
107 FramesFactory.setEOPContinuityThreshold(5 * Constants.JULIAN_DAY);
108 TimeScalesFactory.clearUTCTAIOffsetsLoaders();
109 GravityFieldFactory.clearPotentialCoefficientsReaders();
110 GravityFieldFactory.clearOceanTidesReaders();
111 DataContext.getDefault().getDataProvidersManager().clearProviders();
112 DataContext.getDefault().getDataProvidersManager().clearLoadedDataNames();
113 }
114
115
116
117
118
119 private static void clearFactoryMaps(Class<?> factoryClass) {
120 try {
121
122 for (Field field : factoryClass.getDeclaredFields()) {
123 if (Modifier.isStatic(field.getModifiers()) &&
124 Map.class.isAssignableFrom(field.getType())) {
125 field.setAccessible(true);
126 ((Map<?, ?>) field.get(null)).clear();
127 }
128 }
129 } catch (IllegalAccessException iae) {
130 Assertions.fail(iae.getMessage());
131 }
132 }
133
134
135
136
137
138
139 private static void clearFactory(Class<?> factoryClass, Class<?> cachedFieldsClass) {
140 try {
141
142 for (Field field : factoryClass.getDeclaredFields()) {
143 if (Modifier.isStatic(field.getModifiers()) &&
144 cachedFieldsClass.isAssignableFrom(field.getType())) {
145 field.setAccessible(true);
146 field.set(null, null);
147 }
148 }
149 } catch (IllegalAccessException iae) {
150 Assertions.fail(iae.getMessage());
151 }
152 }
153
154
155
156
157
158 public static void addSatellitePV(TimeScale gps, Frame eme2000, Frame itrf,
159 ArrayList<TimeStampedPVCoordinates> satellitePVList,
160 String absDate,
161 double px, double py, double pz, double vx, double vy, double vz) {
162
163 AbsoluteDate ephemerisDate = new AbsoluteDate(absDate, gps);
164 Vector3D position = new Vector3D(px, py, pz);
165 Vector3D velocity = new Vector3D(vx, vy, vz);
166 PVCoordinates pvITRF = new PVCoordinates(position, velocity);
167 Transform transform = itrf.getTransformTo(eme2000, ephemerisDate);
168 Vector3D pEME2000 = transform.transformPosition(pvITRF.getPosition());
169 Vector3D vEME2000 = transform.transformVector(pvITRF.getVelocity());
170 satellitePVList.add(new TimeStampedPVCoordinates(ephemerisDate, pEME2000, vEME2000, Vector3D.ZERO));
171 }
172
173
174
175
176 public static void addSatelliteQ(TimeScale gps, ArrayList<TimeStampedAngularCoordinates> satelliteQList,
177 String absDate, double q0, double q1, double q2, double q3) {
178
179 AbsoluteDate attitudeDate = new AbsoluteDate(absDate, gps);
180 Rotation rotation = new Rotation(q0, q1, q2, q3, true);
181 TimeStampedAngularCoordinates pair =
182 new TimeStampedAngularCoordinates(attitudeDate, rotation, Vector3D.ZERO, Vector3D.ZERO);
183 satelliteQList.add(pair);
184 }
185
186
187
188 public static BodyShape createEarth() {
189
190 return new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
191 Constants.WGS84_EARTH_FLATTENING,
192 FramesFactory.getITRF(IERSConventions.IERS_2010, true));
193 }
194
195
196
197
198 public static NormalizedSphericalHarmonicsProvider createGravityField() {
199
200 return GravityFieldFactory.getNormalizedProvider(12, 12);
201 }
202
203
204
205
206
207 public static Orbit createOrbit(double mu) {
208
209
210
211
212
213
214
215
216
217
218
219
220 AbsoluteDate date = new AbsoluteDate("2012-01-01T00:00:00.000", TimeScalesFactory.getUTC());
221 Frame eme2000 = FramesFactory.getEME2000();
222
223
224 return new CircularOrbit(7173352.811913891,
225 -4.029194321683225E-4, 0.0013530362644647786,
226 FastMath.toRadians(98.63218182243709),
227 FastMath.toRadians(77.55565567747836),
228 FastMath.PI, PositionAngleType.TRUE,
229 eme2000, date, mu);
230 }
231
232
233
234
235 public static Propagator createPropagator(BodyShape earth,
236 NormalizedSphericalHarmonicsProvider gravityField,
237 Orbit orbit) {
238
239 AttitudeProvider yawCompensation = new YawCompensation(orbit.getFrame(), new NadirPointing(orbit.getFrame(), earth));
240 SpacecraftState state = new SpacecraftState(orbit,
241 yawCompensation.getAttitude(orbit,
242 orbit.getDate(),
243 orbit.getFrame())).withMass(1180.0);
244
245
246 OrbitType type = OrbitType.CIRCULAR;
247 double[][] tolerances = ToleranceProvider.of(CartesianToleranceProvider.of(0.1)).getTolerances(orbit, type);
248 DormandPrince853Integrator integrator =
249 new DormandPrince853Integrator(1.0e-4 * orbit.getKeplerianPeriod(),
250 1.0e-1 * orbit.getKeplerianPeriod(),
251 tolerances[0], tolerances[1]);
252 integrator.setInitialStepSize(1.0e-2 * orbit.getKeplerianPeriod());
253 NumericalPropagator numericalPropagator = new NumericalPropagator(integrator);
254 numericalPropagator.addForceModel(new HolmesFeatherstoneAttractionModel(earth.getBodyFrame(), gravityField));
255 numericalPropagator.addForceModel(new ThirdBodyAttraction(CelestialBodyFactory.getSun()));
256 numericalPropagator.addForceModel(new ThirdBodyAttraction(CelestialBodyFactory.getMoon()));
257 numericalPropagator.setOrbitType(type);
258 numericalPropagator.setInitialState(state);
259 numericalPropagator.setAttitudeProvider(yawCompensation);
260 return numericalPropagator;
261
262 }
263
264
265
266
267 public static LOSBuilder createLOSPerfectLine(Vector3D center, Vector3D normal, double halfAperture, int n) {
268
269 List<Vector3D> list = new ArrayList<Vector3D>(n);
270 for (int i = 0; i < n; ++i) {
271 double alpha = (halfAperture * (2 * i + 1 - n)) / (n - 1);
272 list.add(new Rotation(normal, alpha, RotationConvention.VECTOR_OPERATOR).applyTo(center));
273 }
274 return new LOSBuilder(list);
275 }
276
277
278
279
280 public static TimeDependentLOS createLOSCurvedLine(Vector3D center, Vector3D normal,
281 double halfAperture, double sagitta, int n) {
282
283 Vector3D u = Vector3D.crossProduct(center, normal);
284 List<Vector3D> list = new ArrayList<Vector3D>(n);
285 for (int i = 0; i < n; ++i) {
286 double x = (2.0 * i + 1.0 - n) / (n - 1);
287 double alpha = x * halfAperture;
288 double beta = x * x * sagitta;
289 list.add(new Rotation(normal, alpha, RotationConvention.VECTOR_OPERATOR).
290 applyTo(new Rotation(u, beta, RotationConvention.VECTOR_OPERATOR).
291 applyTo(center)));
292 }
293 return new LOSBuilder(list).build();
294 }
295
296
297
298
299 public static List<TimeStampedPVCoordinates> orbitToPV(Orbit orbit, BodyShape earth,
300 AbsoluteDate minDate, AbsoluteDate maxDate,
301 double step) {
302
303 Propagator propagator = new KeplerianPropagator(orbit);
304 propagator.setAttitudeProvider(new YawCompensation(orbit.getFrame(), new NadirPointing(orbit.getFrame(), earth)));
305 propagator.propagate(minDate);
306 final List<TimeStampedPVCoordinates> list = new ArrayList<TimeStampedPVCoordinates>();
307 propagator.getMultiplexer().add(step, currentState -> list.add(new TimeStampedPVCoordinates(currentState.getDate(),
308 currentState.getPVCoordinates().getPosition(),
309 currentState.getPVCoordinates().getVelocity(),
310 Vector3D.ZERO)));
311 propagator.propagate(maxDate);
312 return list;
313 }
314
315
316
317
318 public static List<TimeStampedAngularCoordinates> orbitToQ(Orbit orbit, BodyShape earth,
319 AbsoluteDate minDate, AbsoluteDate maxDate,
320 double step) {
321
322 Propagator propagator = new KeplerianPropagator(orbit);
323 propagator.setAttitudeProvider(new YawCompensation(orbit.getFrame(), new NadirPointing(orbit.getFrame(), earth)));
324 propagator.propagate(minDate);
325 final List<TimeStampedAngularCoordinates> list = new ArrayList<TimeStampedAngularCoordinates>();
326 propagator.getMultiplexer().add(step, currentState -> list.add(new TimeStampedAngularCoordinates(currentState.getDate(),
327 currentState.getAttitude().getRotation(),
328 Vector3D.ZERO, Vector3D.ZERO)));
329 propagator.propagate(maxDate);
330 return list;
331 }
332
333
334
335
336
337
338 static public void sensorPixelAssertEquals(SensorPixel expected, SensorPixel result, double delta) {
339
340 assertEquals(expected.getLineNumber(), result.getLineNumber(), delta);
341 assertEquals(expected.getPixelNumber(), result.getPixelNumber(), delta);
342 }
343
344
345
346
347
348
349
350
351
352
353 static public Boolean sameSensorPixels(SensorPixel expected, SensorPixel result, double delta) {
354
355 Boolean sameSensorPixel = false;
356
357
358 sameSensorPixel = !(isDifferent(expected.getLineNumber(), result.getLineNumber(), delta) ||
359 isDifferent(expected.getPixelNumber(), result.getPixelNumber(), delta));
360
361 return sameSensorPixel;
362 }
363
364
365
366
367
368
369
370
371
372
373 static public Boolean sameGeodeticPoints(GeodeticPoint expected, GeodeticPoint result, double delta) {
374
375 Boolean sameGeodeticPoint = false;
376
377
378 sameGeodeticPoint = !(isDifferent(expected.getLatitude(), result.getLatitude(), delta) ||
379 isDifferent(expected.getLongitude(), result.getLongitude(), delta) ||
380 isDifferent(expected.getAltitude(), result.getAltitude(), delta));
381
382 return sameGeodeticPoint;
383 }
384
385
386
387
388
389
390
391
392 static private boolean isDifferent(double val1, double val2, double delta) {
393
394 if (Double.compare(val1, val2) == 0) {
395 return false;
396 }
397 if ((FastMath.abs(val1 - val2) <= delta)) {
398 return false;
399 }
400 return true;
401 }
402
403
404 }
405