1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.propagation.events;
18
19 import java.io.File;
20 import java.util.ArrayList;
21 import java.util.Comparator;
22
23 import org.hipparchus.geometry.euclidean.twod.PolygonsSet;
24 import org.hipparchus.geometry.euclidean.twod.Vector2D;
25 import org.hipparchus.geometry.partitioning.Region.Location;
26 import org.hipparchus.ode.events.Action;
27 import org.hipparchus.util.FastMath;
28 import org.junit.After;
29 import org.junit.Assert;
30 import org.junit.Before;
31 import org.junit.Test;
32 import org.orekit.bodies.GeodeticPoint;
33 import org.orekit.bodies.OneAxisEllipsoid;
34 import org.orekit.data.DataContext;
35 import org.orekit.data.DirectoryCrawler;
36 import org.orekit.frames.Frame;
37 import org.orekit.frames.FramesFactory;
38 import org.orekit.models.earth.GeoMagneticField;
39 import org.orekit.models.earth.GeoMagneticFieldFactory;
40 import org.orekit.models.earth.GeoMagneticFieldFactory.FieldModel;
41 import org.orekit.orbits.CircularOrbit;
42 import org.orekit.orbits.Orbit;
43 import org.orekit.orbits.PositionAngle;
44 import org.orekit.propagation.Propagator;
45 import org.orekit.propagation.SpacecraftState;
46 import org.orekit.propagation.analytical.KeplerianPropagator;
47 import org.orekit.propagation.events.handlers.EventHandler;
48 import org.orekit.time.AbsoluteDate;
49 import org.orekit.time.TimeScale;
50 import org.orekit.time.TimeScalesFactory;
51 import org.orekit.utils.Constants;
52 import org.orekit.utils.IERSConventions;
53
54
55
56
57
58 public class MagneticFieldDetectorTest {
59
60 Propagator propagator;
61 Frame eme2000;
62 Frame itrf;
63 TimeScale utc;
64 AbsoluteDate initialDate;
65 OneAxisEllipsoid earth;
66 GeoMagneticField wmm;
67 GeoMagneticField igrf;
68
69 double saaValidationThreshold = 500;
70 double saaValidationWidth = 200;
71
72
73
74
75
76 @Before
77 public void setup()
78 {
79
80 final String orekitCfgPath = "src/test/resources";
81
82
83 DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(orekitCfgPath)));
84
85
86 eme2000 = FramesFactory.getEME2000();
87 itrf = FramesFactory.getITRF(IERSConventions.IERS_2010, false);
88 utc = TimeScalesFactory.getUTC();
89 initialDate = new AbsoluteDate("2019-01-01T12:00:00.000", utc);
90 earth = new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, Constants.WGS84_EARTH_FLATTENING, itrf);
91
92
93 wmm = GeoMagneticFieldFactory.getField(FieldModel.WMM, 2019);
94 igrf = GeoMagneticFieldFactory.getField(FieldModel.IGRF, 2019);
95
96 }
97
98
99
100
101 @After
102 public void tearDown()
103 {
104 DataContext.getDefault().getDataProvidersManager().clearProviders();
105 DataContext.getDefault().getDataProvidersManager().clearLoadedDataNames();
106 }
107
108
109
110
111 private void initializePropagator() {
112 double a = Constants.WGS84_EARTH_EQUATORIAL_RADIUS + 600000;
113 double i = FastMath.toRadians(80);
114 Orbit initialOrbit = new CircularOrbit(a, 0, 0, i, 0, 0, PositionAngle.TRUE, eme2000, initialDate, Constants.WGS84_EARTH_MU);
115 propagator = new KeplerianPropagator(initialOrbit);
116 }
117
118
119
120
121 @Test
122 public void magneticFieldDetectorWMMSeaLevelTest() {
123 initializePropagator();
124 double threshold = 45000;
125
126 CustomEventHandler handler = new CustomEventHandler();
127 MagneticFieldDetector detector = new MagneticFieldDetector(threshold, FieldModel.WMM, earth, true).withHandler(handler);
128 propagator.addEventDetector(detector);
129 propagator.propagate(initialDate, initialDate.shiftedBy(864000));
130
131 checkEvents(handler.getEvents(), threshold, wmm, true);
132 }
133
134
135
136
137 @Test
138 public void magneticFieldDetectorIGRFSeaLevelTest() {
139 initializePropagator();
140 double threshold = 45000;
141
142 CustomEventHandler handler = new CustomEventHandler();
143 MagneticFieldDetector detector = new MagneticFieldDetector(threshold, FieldModel.IGRF, earth, true).withHandler(handler);
144 propagator.addEventDetector(detector);
145 propagator.propagate(initialDate, initialDate.shiftedBy(864000));
146
147 checkEvents(handler.getEvents(), threshold, igrf, true);
148 }
149
150
151
152
153 @Test
154 public void magneticFieldDetectorWMMTrueAltitudeTest() {
155 initializePropagator();
156 double threshold = 45000;
157
158 CustomEventHandler handler = new CustomEventHandler();
159 MagneticFieldDetector detector = new MagneticFieldDetector(threshold, FieldModel.WMM, earth).withHandler(handler);
160 propagator.addEventDetector(detector);
161 propagator.propagate(initialDate, initialDate.shiftedBy(864000));
162
163 checkEvents(handler.getEvents(), threshold, wmm, false);
164 }
165
166
167
168
169 @Test
170 public void magneticFieldDetectorIGRFTrueAltitudeTest() {
171 initializePropagator();
172 double threshold = 45000;
173
174 CustomEventHandler handler = new CustomEventHandler();
175 MagneticFieldDetector detector = new MagneticFieldDetector(threshold, FieldModel.IGRF, earth).withHandler(handler);
176 propagator.addEventDetector(detector);
177 propagator.propagate(initialDate, initialDate.shiftedBy(864000));
178
179 checkEvents(handler.getEvents(), threshold, igrf, false);
180 }
181
182
183
184
185 @Test
186 public void saaDetectorWMMSeaLevelTest() {
187 initializePropagator();
188
189 double altitude = 0;
190 double threshold = 32000;
191
192 PolygonsSet saaIn = generateGeomagneticMap(wmm, altitude, threshold - saaValidationThreshold, saaValidationWidth);
193 PolygonsSet saaOut = generateGeomagneticMap(wmm, altitude, threshold + saaValidationThreshold, saaValidationWidth);
194
195 CustomEventHandler handler = new CustomEventHandler();
196 MagneticFieldDetector detector = new MagneticFieldDetector(threshold, FieldModel.WMM, earth, true).withHandler(handler);
197 propagator.addEventDetector(detector);
198 propagator.propagate(initialDate, initialDate.shiftedBy(864000));
199
200 checkEvents(handler.getEvents(), threshold, wmm, true);
201 checkSaa(handler.getEvents(), saaIn, saaOut);
202 }
203
204
205
206
207 @Test
208 public void saaDetectorIGRFSeaLevelTest() {
209 initializePropagator();
210
211 double altitude = 0;
212 double threshold = 32000;
213
214 PolygonsSet saaIn = generateGeomagneticMap(igrf, altitude, threshold - saaValidationThreshold, saaValidationWidth);
215 PolygonsSet saaOut = generateGeomagneticMap(igrf, altitude, threshold + saaValidationThreshold, saaValidationWidth);
216
217 CustomEventHandler handler = new CustomEventHandler();
218 MagneticFieldDetector detector = new MagneticFieldDetector(threshold, FieldModel.IGRF, earth, true).withHandler(handler);
219 propagator.addEventDetector(detector);
220 propagator.propagate(initialDate, initialDate.shiftedBy(864000));
221
222 checkEvents(handler.getEvents(), threshold, igrf, true);
223 checkSaa(handler.getEvents(), saaIn, saaOut);
224 }
225
226
227
228
229 @Test
230 public void saaDetectorWMMTrueAltitudeTest() {
231 initializePropagator();
232
233 double altitude = 600000;
234 double threshold = 23000;
235
236 PolygonsSet saaIn = generateGeomagneticMap(wmm, altitude, threshold - saaValidationThreshold, saaValidationWidth);
237 PolygonsSet saaOut = generateGeomagneticMap(wmm, altitude, threshold + saaValidationThreshold, saaValidationWidth);
238
239 CustomEventHandler handler = new CustomEventHandler();
240 MagneticFieldDetector detector = new MagneticFieldDetector(threshold, FieldModel.WMM, earth).withHandler(handler);
241 propagator.addEventDetector(detector);
242 propagator.propagate(initialDate, initialDate.shiftedBy(864000));
243
244 checkEvents(handler.getEvents(), threshold, wmm, false);
245 checkSaa(handler.getEvents(), saaIn, saaOut);
246 }
247
248
249
250
251 @Test
252 public void saaDetectorIGRFTrueAltitudeTest() {
253 initializePropagator();
254
255 double altitude = 600000;
256 double threshold = 23000;
257
258 PolygonsSet saaIn = generateGeomagneticMap(igrf, altitude, threshold - saaValidationThreshold, saaValidationWidth);
259 PolygonsSet saaOut = generateGeomagneticMap(igrf, altitude, threshold + saaValidationThreshold, saaValidationWidth);
260
261 CustomEventHandler handler = new CustomEventHandler();
262 MagneticFieldDetector detector = new MagneticFieldDetector(threshold, FieldModel.IGRF, earth).withHandler(handler);
263 propagator.addEventDetector(detector);
264 propagator.propagate(initialDate, initialDate.shiftedBy(864000));
265
266 checkEvents(handler.getEvents(), threshold, igrf, false);
267 checkSaa(handler.getEvents(), saaIn, saaOut);
268 }
269
270
271
272
273
274
275 private PolygonsSet generateGeomagneticMap(GeoMagneticField field, double altitude, double threshold, double width) {
276
277
278
279 ArrayList<Double[]> points = new ArrayList<Double[]>();
280
281 for(int latitude = -89; latitude < 90; latitude++) {
282 for(int longitude = -179; longitude < 180; longitude++) {
283
284
285 double value = field.calculateField(FastMath.toRadians(latitude), FastMath.toRadians(longitude), altitude).getTotalIntensity();
286
287
288 if (value - threshold > -0.5*width && value - threshold < 0.5*width) {
289 Double[] point = {(double)latitude, (double)longitude};
290 points.add(point);
291 }
292 }
293 }
294
295
296 double[][] arrayPoints = new double[points.size()][2];
297
298 for(int i = 0; i < points.size(); i++) {
299 arrayPoints[i][0] = points.get(i)[0];
300 arrayPoints[i][1] = points.get(i)[1];
301 }
302
303
304 return buildZone(arrayPoints);
305 }
306
307
308
309
310
311
312 private PolygonsSet buildZone(double[][] points) {
313
314 final Vector2D[] vertices = new Vector2D[points.length];
315 for (int i = 0; i < points.length; ++i) {
316 vertices[i] = new Vector2D(FastMath.toRadians(points[i][1]),
317 FastMath.toRadians(points[i][0]));
318 }
319
320
321 final Vector2D[] sortedVertices = sortVertices(vertices);
322
323
324 return new PolygonsSet(1.0e-10, sortedVertices);
325 }
326
327
328
329
330
331
332
333
334
335 private Vector2D[] sortVertices(Vector2D[] vertices) {
336
337
338
339 double midLat = 0;
340 double midLon = 0;
341
342 double minLon = vertices[0].getX();
343 double maxLon = vertices[0].getX();
344 double minLat = vertices[0].getY();
345 double maxLat = vertices[0].getY();
346 for(int i = 0; i < vertices.length; i++) {
347 if(vertices[i].getX() < minLon) minLon = vertices[i].getX();
348 if(vertices[i].getX() > maxLon) maxLon = vertices[i].getX();
349 if(vertices[i].getY() < minLat) minLat = vertices[i].getY();
350 if(vertices[i].getY() > maxLat) maxLat = vertices[i].getY();
351 }
352 midLat = (minLat + maxLat)/2;
353 midLon = (minLon + maxLon)/2;
354
355 Vector2D mid = new Vector2D(midLon, midLat);
356
357
358 ArrayList<Vector2D> angularVerticesList = new ArrayList<Vector2D>();
359 Vector2D ref = new Vector2D(1, 0);
360 Vector2D angularVertice;
361 Vector2D centeredVertice;
362 for(int i = 0; i < vertices.length; i++) {
363 centeredVertice = vertices[i].subtract(mid);
364 double norm = centeredVertice.getNorm();
365 double angle = Vector2D.angle(ref, centeredVertice);
366 if(centeredVertice.getY() < 0) {
367 angle = -angle;
368 }
369 angularVertice = new Vector2D(norm, angle);
370 angularVerticesList.add(angularVertice);
371 }
372
373
374 Comparator<Vector2D> comparator = new Comparator<Vector2D>() {
375
376 @Override
377 public int compare(Vector2D o1, Vector2D o2) {
378 return Double.compare(o1.getY(),o2.getY());
379 }
380 };
381
382 angularVerticesList.sort(comparator);
383
384
385 Vector2D[] sortedVertices = new Vector2D[vertices.length];
386 Vector2D originalVertice;
387 for(int i = 0; i < vertices.length; i++) {
388 angularVertice = angularVerticesList.get(i);
389 double longitude = angularVertice.getX()*Math.cos(angularVertice.getY());
390 double latitude = angularVertice.getX()*Math.sin(angularVertice.getY());
391 centeredVertice = new Vector2D(longitude, latitude);
392 originalVertice = centeredVertice.add(mid);
393 sortedVertices[i] = originalVertice;
394 }
395
396 return sortedVertices;
397 }
398
399
400
401
402
403 private class CustomEventHandler implements EventHandler<EventDetector>{
404
405 ArrayList<SpacecraftState> events = new ArrayList<SpacecraftState>();
406
407 @Override
408 public Action eventOccurred(SpacecraftState s, EventDetector detector, boolean increasing) {
409
410 events.add(s);
411
412 return Action.CONTINUE;
413 }
414
415 public ArrayList<SpacecraftState> getEvents(){
416 return events;
417 }
418 }
419
420
421
422
423
424
425
426
427 private void checkEvents(ArrayList<SpacecraftState> events, double threshold, GeoMagneticField field, boolean sea) {
428
429 for (SpacecraftState s : events) {
430
431 GeodeticPoint geo = earth.transform(s.getPVCoordinates().getPosition(), s.getFrame(), s.getDate());
432 double altitude = geo.getAltitude();
433 if(sea) {
434 altitude = 0;
435 }
436 double meas = field.calculateField(geo.getLatitude(), geo.getLongitude(), altitude).getTotalIntensity();
437 Assert.assertEquals(threshold, meas, 1e-3);
438 }
439 }
440
441
442
443
444
445
446
447 private void checkSaa(ArrayList<SpacecraftState> events, PolygonsSet saaIn, PolygonsSet saaOut) {
448
449 for (SpacecraftState s : events) {
450
451 GeodeticPoint geo = earth.transform(s.getPVCoordinates(itrf).getPosition(), itrf, s.getDate());
452 Vector2D point = new Vector2D(geo.getLongitude(), geo.getLatitude());
453
454
455 Assert.assertTrue(saaIn.checkPoint(point).equals(Location.OUTSIDE));
456
457 Assert.assertTrue(saaOut.checkPoint(point).equals(Location.INSIDE));
458
459 }
460 }
461 }