1   /* Copyright 2022-2025 Romain Serra
2    * Licensed to CS GROUP (CS) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * CS licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.orekit.forces.maneuvers;
18  
19  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.Field;
21  import org.hipparchus.analysis.differentiation.Gradient;
22  import org.hipparchus.analysis.differentiation.GradientField;
23  import org.hipparchus.complex.Complex;
24  import org.hipparchus.complex.ComplexField;
25  import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
26  import org.hipparchus.geometry.euclidean.threed.Vector3D;
27  import org.hipparchus.util.Binary64;
28  import org.hipparchus.util.Binary64Field;
29  import org.hipparchus.util.MathArrays;
30  import org.junit.jupiter.api.Assertions;
31  import org.junit.jupiter.api.DisplayName;
32  import org.junit.jupiter.api.Test;
33  import org.mockito.Mockito;
34  import org.orekit.attitudes.*;
35  import org.orekit.forces.maneuvers.propulsion.BasicConstantThrustPropulsionModel;
36  import org.orekit.forces.maneuvers.propulsion.PropulsionModel;
37  import org.orekit.forces.maneuvers.propulsion.ThrustPropulsionModel;
38  import org.orekit.forces.maneuvers.trigger.DateBasedManeuverTriggers;
39  import org.orekit.forces.maneuvers.trigger.ManeuverTriggers;
40  import org.orekit.frames.Frame;
41  import org.orekit.frames.FramesFactory;
42  import org.orekit.orbits.CartesianOrbit;
43  import org.orekit.propagation.FieldSpacecraftState;
44  import org.orekit.propagation.SpacecraftState;
45  import org.orekit.time.AbsoluteDate;
46  import org.orekit.time.FieldAbsoluteDate;
47  import org.orekit.utils.PVCoordinates;
48  import org.orekit.utils.ParameterDriver;
49  
50  import java.util.ArrayList;
51  import java.util.List;
52  
53  class ManeuverTest {
54  
55      @Test
56      void testGetName() {
57          // GIVEN
58          final String tooShortName = "a";
59          final String expectedName = "aa";
60          final double arbitraryDuration = 0.;
61          final DateBasedManeuverTriggers triggers = new DateBasedManeuverTriggers(tooShortName, AbsoluteDate.ARBITRARY_EPOCH, arbitraryDuration);
62          final double arbitraryThrust = 1.;
63          final double arbitraryIsp = 1.;
64          final PropulsionModel propulsion = new BasicConstantThrustPropulsionModel(arbitraryThrust, arbitraryIsp, Vector3D.PLUS_I, expectedName);
65          // WHEN
66          final Maneuver maneuver = new Maneuver(null, triggers, propulsion);
67          final String actualName = maneuver.getName();
68          // THEN
69          Assertions.assertEquals(expectedName, actualName);
70      }
71  
72      @Test
73      void testGetParametersDrivers() {
74          // GIVEN
75          final ManeuverTriggers mockedTriggers = Mockito.mock(ManeuverTriggers.class);
76          final PropulsionModel mockedPropulsion = Mockito.mock(PropulsionModel.class);
77          final AttitudeProvider mocedkAttitudeProvider = Mockito.mock(AttitudeProvider.class);
78          final List<ParameterDriver> driverList = new ArrayList<>();
79          driverList.add(Mockito.mock(ParameterDriver.class));
80          Mockito.when(mocedkAttitudeProvider.getParametersDrivers()).thenReturn(driverList);
81          // WHEN
82          final Maneuver maneuver = new Maneuver(mocedkAttitudeProvider, mockedTriggers, mockedPropulsion);
83          final List<ParameterDriver> actualDrivers = maneuver.getParametersDrivers();
84          // THEN
85          Assertions.assertEquals(driverList.size(), actualDrivers.size());
86      }
87  
88      @Test
89      void testGetControl3DVectorCostType() {
90          // GIVEN
91          final ManeuverTriggers mockedTriggers = Mockito.mock(ManeuverTriggers.class);
92          final PropulsionModel mockedPropulsion = Mockito.mock(PropulsionModel.class);
93          Mockito.when(mockedPropulsion.getControl3DVectorCostType()).thenReturn(Control3DVectorCostType.TWO_NORM);
94          // WHEN
95          final Maneuver maneuver = new Maneuver(null, mockedTriggers, mockedPropulsion);
96          final Control3DVectorCostType actualCostType = maneuver.getControl3DVectorCostType();
97          // THEN
98          final Control3DVectorCostType expectedCostType = mockedPropulsion.getControl3DVectorCostType();
99          Assertions.assertEquals(expectedCostType, actualCostType);
100     }
101 
102     @Test
103     @DisplayName("Test comparing Field acceleration w/ and w/o attitude override.")
104     @SuppressWarnings("unchecked")
105     void testAccelerationFieldAttitudeOverride() {
106         // GIVEN
107         final ComplexField field = ComplexField.getInstance();
108 
109         // mock triggers
110         final ManeuverTriggers mockedTriggers = Mockito.mock(ManeuverTriggers.class);
111         Mockito.when(mockedTriggers.isFiring(Mockito.any(AbsoluteDate.class), Mockito.any(double[].class))).
112                 thenReturn(true);
113         Mockito.when(mockedTriggers.isFiring(Mockito.any(FieldAbsoluteDate.class), Mockito.any(Complex[].class))).
114                 thenReturn(true);
115         Mockito.when(mockedTriggers.getParametersDrivers()).thenReturn(new ArrayList<>());
116 
117         // mock propulsion model
118         final ThrustPropulsionModel mockedPropulsion = Mockito.mock(ThrustPropulsionModel.class);
119         final Vector3D returnedVector = Vector3D.MINUS_I;
120         final FieldVector3D<Complex> returnedFieldVector = new FieldVector3D<>(field, returnedVector);
121         Mockito.when(mockedPropulsion.getAcceleration(Mockito.any(SpacecraftState.class), Mockito.any(Attitude.class),
122                 Mockito.any(double[].class))).thenReturn(returnedVector);
123         Mockito.when(mockedPropulsion.getAcceleration(Mockito.any(FieldSpacecraftState.class), Mockito.any(FieldAttitude.class),
124                 Mockito.any(Complex[].class))).thenReturn(returnedFieldVector);
125         Mockito.when(mockedPropulsion.getParametersDrivers()).thenReturn(new ArrayList<>());
126 
127         // create FieldSpacecraftState
128         final int arbitraryNumber = 6;
129         final AbsoluteDate epoch = AbsoluteDate.ARBITRARY_EPOCH;
130         final Frame frame = FramesFactory.getGCRF();
131         final FieldSpacecraftState<Complex> fieldState = createFieldState(field, frame, epoch);
132 
133         // create Maneuver
134         final FrameAlignedProvider attitudeOverride = new FrameAlignedProvider(frame);
135         final Maneuver maneuverWithOverride = new Maneuver(attitudeOverride, mockedTriggers, mockedPropulsion);
136         final Complex[] fieldParameters = MathArrays.buildArray(field, arbitraryNumber);
137         
138         // WHEN
139         final FieldVector3D<Complex> actualAcceleration = maneuverWithOverride.acceleration(fieldState, fieldParameters);
140         
141         // THEN
142         final Maneuver maneuverWithoutOverride = new Maneuver(null, mockedTriggers, mockedPropulsion);
143         Assertions.assertNotEquals(0., actualAcceleration.toVector3D().getNorm());
144         final Vector3D expectedAcceleration = maneuverWithoutOverride.acceleration(fieldState.toSpacecraftState(),
145                 new double[fieldParameters.length]);
146         Assertions.assertEquals(expectedAcceleration, actualAcceleration.toVector3D());
147         Assertions.assertEquals(returnedVector, actualAcceleration.toVector3D());
148     }
149 
150     @Test
151     @DisplayName("Test comparing Field acceleration to standard one.")
152     @SuppressWarnings("unchecked")
153     void testAccelerationField() {
154         // GIVEN
155         final GradientField field = GradientField.getField(1);
156 
157         // mock triggers
158         final ManeuverTriggers mockedTriggers = Mockito.mock(ManeuverTriggers.class);
159         Mockito.when(mockedTriggers.isFiring(Mockito.any(AbsoluteDate.class), Mockito.any(double[].class))).
160                 thenReturn(true);
161         Mockito.when(mockedTriggers.isFiring(Mockito.any(FieldAbsoluteDate.class), Mockito.any(Gradient[].class))).
162                 thenReturn(true);
163         Mockito.when(mockedTriggers.getParametersDrivers()).thenReturn(new ArrayList<>());
164 
165         // mock propulsion model
166         final ThrustPropulsionModel mockedPropulsion = Mockito.mock(ThrustPropulsionModel.class);
167         final Vector3D returnedVector = Vector3D.MINUS_I;
168         final FieldVector3D<Gradient> returnedFieldVector = new FieldVector3D<>(field, returnedVector);
169         Mockito.when(mockedPropulsion.getAcceleration(Mockito.any(SpacecraftState.class), Mockito.any(Attitude.class),
170                         Mockito.any(double[].class))).thenReturn(returnedVector);
171         Mockito.when(mockedPropulsion.getAcceleration(Mockito.any(FieldSpacecraftState.class), Mockito.any(FieldAttitude.class),
172                 Mockito.any(Gradient[].class))).thenReturn(returnedFieldVector);
173         Mockito.when(mockedPropulsion.getParametersDrivers()).thenReturn(new ArrayList<>());
174 
175         // create FieldSpacecraftState
176         final int arbitraryNumber = 6;
177         final AbsoluteDate epoch = AbsoluteDate.ARBITRARY_EPOCH;
178         final FieldSpacecraftState<Gradient> fieldState = createFieldState(field, FramesFactory.getEME2000(), epoch);
179 
180         // create Maneuver
181         final Maneuver maneuver = new Maneuver(null, mockedTriggers, mockedPropulsion);
182         final Gradient[] fieldParameters = MathArrays.buildArray(field, arbitraryNumber);
183         
184         // WHEN
185         final FieldVector3D<Gradient> acceleration = maneuver.acceleration(fieldState, fieldParameters);
186         
187         // THEN
188         final Vector3D expectedAcceleration = maneuver.acceleration(fieldState.toSpacecraftState(), new double[arbitraryNumber]);
189         Assertions.assertNotEquals(0., acceleration.toVector3D().getNorm());
190         Assertions.assertEquals(expectedAcceleration, acceleration.toVector3D());
191     }
192 
193     private <T extends CalculusFieldElement<T>> FieldSpacecraftState<T> createFieldState(final Field<T> field, 
194                                                                                          final Frame frame, 
195                                                                                          final AbsoluteDate epoch) {
196         final double arbitraryMu = 1.;
197         final PVCoordinates pvCoordinates = new PVCoordinates(Vector3D.PLUS_I, Vector3D.PLUS_J);
198         final CartesianOrbit orbit = new CartesianOrbit(pvCoordinates, frame, epoch, arbitraryMu);
199         final SpacecraftState state = new SpacecraftState(orbit);
200         return new FieldSpacecraftState<>(field, state);
201     }
202 
203     @Test
204     void testGetAttitudeModelParametersNull() {
205         final double[] parameters = new double[] {1};
206         final Maneuver maneuver = new Maneuver(null, null, null);
207         final double[] actualDrivers = maneuver.getAttitudeModelParameters(parameters);
208         Assertions.assertArrayEquals(new double[0], actualDrivers);
209     }
210 
211     @Test
212     void testGetAttitudeModelParameters() {
213         final AttitudeRotationModel mockedRotationModel = Mockito.mock(AttitudeRotationModel.class);
214         final double[] parameters = new double[] {1};
215         Mockito.when(mockedRotationModel.getParameters()).thenReturn(parameters);
216         final List<ParameterDriver> drivers = new ArrayList<>();
217         drivers.add(Mockito.mock(ParameterDriver.class));
218         Mockito.when(mockedRotationModel.getParametersDrivers()).thenReturn(drivers);
219         final Maneuver maneuver = new Maneuver(mockedRotationModel, null, null);
220         final double[] actualDrivers = maneuver.getAttitudeModelParameters(parameters);
221         Assertions.assertArrayEquals(parameters, actualDrivers);
222     }
223 
224     @Test
225     void testGetAttitudeModelParametersFieldNull() {
226         final Binary64Field field = Binary64Field.getInstance();
227         final Binary64[] parameters = MathArrays.buildArray(field, 1);
228         parameters[0] = Binary64.ONE;
229         final Maneuver maneuver = new Maneuver(null, null, null);
230         final Binary64[] actualDrivers = maneuver.getAttitudeModelParameters(parameters);
231         Assertions.assertEquals(0, actualDrivers.length);
232     }
233 
234     @Test
235     void testGetAttitudeModelParametersField() {
236         final AttitudeRotationModel mockedRotationModel = Mockito.mock(AttitudeRotationModel.class);
237         final Binary64Field field = Binary64Field.getInstance();
238         final Binary64[] parameters = MathArrays.buildArray(field, 1);
239         parameters[0] = Binary64.ONE;
240         Mockito.when(mockedRotationModel.getParameters(field)).thenReturn(parameters);
241         final List<ParameterDriver> drivers = new ArrayList<>();
242         drivers.add(Mockito.mock(ParameterDriver.class));
243         Mockito.when(mockedRotationModel.getParametersDrivers()).thenReturn(drivers);
244         final Maneuver maneuver = new Maneuver(mockedRotationModel, null, null);
245         final Binary64[] actualDrivers = maneuver.getAttitudeModelParameters(parameters);
246         Assertions.assertArrayEquals(parameters, actualDrivers);
247     }
248 }