1   package org.orekit.attitudes;
2   
3   import org.hipparchus.geometry.euclidean.threed.Rotation;
4   import org.hipparchus.geometry.euclidean.threed.Vector3D;
5   import org.hipparchus.util.Binary64;
6   import org.hipparchus.util.Binary64Field;
7   import org.hipparchus.util.FastMath;
8   import org.junit.jupiter.api.Assertions;
9   import org.junit.jupiter.api.BeforeEach;
10  import org.junit.jupiter.api.Test;
11  import org.junit.jupiter.params.ParameterizedTest;
12  import org.junit.jupiter.params.provider.ValueSource;
13  import org.orekit.Utils;
14  import org.orekit.frames.FramesFactory;
15  import org.orekit.frames.LOFType;
16  import org.orekit.orbits.*;
17  import org.orekit.propagation.SpacecraftState;
18  import org.orekit.propagation.analytical.FieldKeplerianPropagator;
19  import org.orekit.propagation.analytical.KeplerianPropagator;
20  import org.orekit.propagation.events.DateDetector;
21  import org.orekit.time.AbsoluteDate;
22  import org.orekit.time.TimeScalesFactory;
23  import org.orekit.utils.Constants;
24  import org.orekit.utils.PVCoordinates;
25  
26  class AttitudesSwitcherTest {
27  
28      @Test
29      void testAddSwitchingConditionUndetectable() {
30          // GIVEN
31          final Orbit orbit = getInitialOrbit();
32          final KeplerianPropagator propagator = new KeplerianPropagator(orbit);
33          final AttitudesSwitcher attitudesSwitcher = new AttitudesSwitcher();
34          final AttitudeProvider pastProvider = new FrameAlignedProvider(orbit.getFrame());
35          final AbsoluteDate switchingDate = orbit.getDate().shiftedBy(1e4);
36          final AttitudeProvider futureProvider = new LofOffset(orbit.getFrame(), LOFType.TNW);
37          final DateDetector detector = new DateDetector(switchingDate);
38          // WHEN
39          attitudesSwitcher.resetActiveProvider(pastProvider);
40          final TestSwitchHandler switchHandler = new TestSwitchHandler();
41          attitudesSwitcher.addSwitchingCondition(pastProvider, futureProvider, detector,
42                  false, false, switchHandler);
43          propagator.setAttitudeProvider(attitudesSwitcher);
44          final SpacecraftState initialState = new SpacecraftState(orbit,
45                  attitudesSwitcher.getAttitude(orbit, orbit.getDate(), orbit.getFrame()));
46          propagator.resetInitialState(initialState);
47          propagator.propagate(switchingDate.shiftedBy(1e2));
48          Assertions.assertEquals(0, switchHandler.count);
49      }
50  
51      @ParameterizedTest
52      @ValueSource(doubles = { -1e3, 1e3 })
53      void testAddSwitchingCondition(final double timeShift) {
54          // GIVEN
55          final Orbit orbit = getInitialOrbit();
56          final KeplerianPropagator propagator = new KeplerianPropagator(orbit);
57          final AttitudesSwitcher attitudesSwitcher = new AttitudesSwitcher();
58          final AttitudeProvider pastProvider = new FrameAlignedProvider(orbit.getFrame());
59          final AbsoluteDate switchingDate = orbit.getDate().shiftedBy(timeShift);
60          final AttitudeProvider futureProvider = new LofOffset(orbit.getFrame(), LOFType.TNW);
61          final DateDetector detector = new DateDetector(switchingDate);
62          final boolean isForward = (timeShift > 0);
63          // WHEN
64          if (isForward) {
65              attitudesSwitcher.resetActiveProvider(pastProvider);
66              attitudesSwitcher.addSwitchingCondition(pastProvider, futureProvider, detector,
67                      true, true, null);
68          } else {
69              attitudesSwitcher.resetActiveProvider(futureProvider);
70              attitudesSwitcher.addSwitchingCondition(pastProvider, futureProvider, detector,
71                      true, true, null);
72          }
73          propagator.setAttitudeProvider(attitudesSwitcher);
74          final SpacecraftState initialState = new SpacecraftState(orbit,
75                  attitudesSwitcher.getAttitude(orbit, orbit.getDate(), orbit.getFrame()));
76          propagator.resetInitialState(initialState);
77          // THEN
78          for (double step = 0; FastMath.abs(step) < FastMath.abs(timeShift) * 2; step += timeShift / 10) {
79              final SpacecraftState state = propagator.propagate(orbit.getDate().shiftedBy(step));
80              final Attitude attitude = state.getAttitude();
81              final AttitudeProvider expectedProvider;
82              if (FastMath.abs(step) < FastMath.abs(timeShift)) {
83                  expectedProvider = isForward ? pastProvider : futureProvider;
84              } else {
85                  expectedProvider = isForward ? futureProvider : pastProvider;
86              }
87              if (FastMath.abs(step - timeShift) > 1e-1) {
88                  final Attitude expectedAttitude = expectedProvider.getAttitude(state.getOrbit(), state.getDate(), state.getFrame());
89                  Assertions.assertEquals(0., Rotation.distance(expectedAttitude.getRotation(),
90                          attitude.getRotation()));
91                  Assertions.assertEquals(expectedAttitude.getSpin(), attitude.getSpin());
92                  Assertions.assertEquals(expectedAttitude.getRotationAcceleration(), attitude.getRotationAcceleration());
93              }
94          }
95      }
96  
97      private static Orbit getInitialOrbit() {
98          final AbsoluteDate initialDate = new AbsoluteDate(2004, 1, 1, 23, 30, 00.000, TimeScalesFactory.getUTC());
99          final Vector3D position  = new Vector3D(-6142438.668, 3492467.560, -25767.25680);
100         final Vector3D velocity  = new Vector3D(505.8479685, 942.7809215, 7435.922231);
101         return new KeplerianOrbit(new PVCoordinates(position, velocity),
102                 FramesFactory.getEME2000(), initialDate,
103                 Constants.EIGEN5C_EARTH_MU);
104     }
105 
106     @ParameterizedTest
107     @ValueSource(doubles = { -1e3, 1e3 })
108     void testAddSwitchingConditionField(final double timeShift) {
109         // GIVEN
110         final Orbit orbit = getInitialOrbit();
111         final Binary64Field field = Binary64Field.getInstance();
112         final FieldOrbit<Binary64> fieldOrbit = new FieldCartesianOrbit<>(field, orbit);
113         final FieldKeplerianPropagator<Binary64> propagator = new FieldKeplerianPropagator<>(fieldOrbit);
114         final AttitudesSwitcher attitudesSwitcher = new AttitudesSwitcher();
115         final AttitudeProvider pastProvider = new FrameAlignedProvider(orbit.getFrame());
116         final AbsoluteDate switchingDate = orbit.getDate().shiftedBy(timeShift);
117         final AttitudeProvider futureProvider = new LofOffset(orbit.getFrame(), LOFType.TNW);
118         final DateDetector detector = new DateDetector(switchingDate);
119         final boolean isForward = (timeShift > 0);
120         final TestSwitchHandler switchHandler = new TestSwitchHandler();
121         // WHEN
122         if (!isForward) {
123             attitudesSwitcher.resetActiveProvider(futureProvider);
124         }
125         attitudesSwitcher.addSwitchingCondition(pastProvider, futureProvider, detector,
126                 true, false, switchHandler);
127         propagator.setAttitudeProvider(attitudesSwitcher);
128         propagator.propagate(fieldOrbit.getDate().shiftedBy(timeShift * 2));
129         // THEN
130         Assertions.assertEquals(1, switchHandler.count);
131         Assertions.assertEquals(switchingDate, switchHandler.lastSwitchDate);
132     }
133 
134     private static class TestSwitchHandler implements AttitudeSwitchHandler {
135         private int count = 0;
136         private AbsoluteDate lastSwitchDate;
137 
138         @Override
139         public void switchOccurred(AttitudeProvider preceding, AttitudeProvider following, SpacecraftState state) {
140             count++;
141             lastSwitchDate = state.getDate();
142         }
143     }
144 
145     @BeforeEach
146     public void setUp() {
147         Utils.setDataRoot("regular-data:potential");
148     }
149 }