1   /* Copyright 2002-2025 CS GROUP
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.propagation.conversion;
18  
19  import java.util.ArrayList;
20  import java.util.List;
21  
22  import org.hipparchus.geometry.euclidean.threed.Vector3D;
23  import org.junit.jupiter.api.Assertions;
24  import org.junit.jupiter.api.BeforeEach;
25  import org.junit.jupiter.api.Test;
26  import org.orekit.Utils;
27  import org.orekit.forces.gravity.potential.GravityFieldFactory;
28  import org.orekit.forces.gravity.potential.TideSystem;
29  import org.orekit.forces.gravity.potential.UnnormalizedSphericalHarmonicsProvider;
30  import org.orekit.forces.gravity.potential.UnnormalizedSphericalHarmonicsProvider.UnnormalizedSphericalHarmonics;
31  import org.orekit.frames.FramesFactory;
32  import org.orekit.orbits.CircularOrbit;
33  import org.orekit.orbits.EquinoctialOrbit;
34  import org.orekit.orbits.Orbit;
35  import org.orekit.orbits.OrbitType;
36  import org.orekit.orbits.PositionAngleType;
37  import org.orekit.propagation.Propagator;
38  import org.orekit.propagation.SpacecraftState;
39  import org.orekit.propagation.analytical.EcksteinHechlerPropagator;
40  import org.orekit.time.AbsoluteDate;
41  import org.orekit.utils.PVCoordinates;
42  import org.orekit.utils.TimeStampedPVCoordinates;
43  
44  public class EcksteinHechlerConverterTest {
45  
46      private Orbit orbit;
47      private UnnormalizedSphericalHarmonicsProvider provider;
48  
49      @Test
50      public void testConversionPositionVelocity() {
51          checkFit(orbit, 86400, 300, 1.0e-3, false, 2.446e-8);
52      }
53  
54      @Test
55      public void testConversionPositionOnly() {
56          checkFit(orbit, 86400, 300, 1.0e-3, true, 2.350e-8);
57      }
58  
59      protected void checkFit(final Orbit orbit,
60                              final double duration,
61                              final double stepSize,
62                              final double threshold,
63                              final boolean positionOnly,
64                              final double expectedRMS)
65          {
66  
67          // shift position by 3m
68          CircularOrbit modified = new CircularOrbit(new TimeStampedPVCoordinates(orbit.getDate(),
69                                                                                  new Vector3D(1, orbit.getPosition(),
70                                                                                               3.0, Vector3D.PLUS_J),
71                                                                                  orbit.getPVCoordinates().getVelocity()),
72                                                     orbit.getFrame(),
73                                                     orbit.getMu());
74          Propagator p = new EcksteinHechlerPropagator(modified, provider);
75          List<SpacecraftState> sample = new ArrayList<SpacecraftState>();
76          for (double dt = 0; dt < duration; dt += stepSize) {
77              sample.add(p.propagate(modified.getDate().shiftedBy(dt)));
78          }
79  
80          UnnormalizedSphericalHarmonics harmonics = provider.onDate(orbit.getDate());
81          PropagatorBuilder builder = new EcksteinHechlerPropagatorBuilder(orbit,
82                                                                           provider.getAe(),
83                                                                           provider.getMu(),
84                                                                           provider.getTideSystem(),
85                                                                           harmonics.getUnnormalizedCnm(2, 0),
86                                                                           harmonics.getUnnormalizedCnm(3, 0),
87                                                                           harmonics.getUnnormalizedCnm(4, 0),
88                                                                           harmonics.getUnnormalizedCnm(5, 0),
89                                                                           harmonics.getUnnormalizedCnm(6, 0),
90                                                                           OrbitType.CIRCULAR,
91                                                                           PositionAngleType.TRUE,
92                                                                           1.0);
93  
94          FiniteDifferencePropagatorConverter fitter = new FiniteDifferencePropagatorConverter(builder,
95                                                                                               threshold,
96                                                                                               1000);
97  
98          fitter.convert(sample, positionOnly);
99  
100         Assertions.assertEquals(expectedRMS, fitter.getRMS(), 0.01 * expectedRMS);
101 
102         EcksteinHechlerPropagator prop = (EcksteinHechlerPropagator)fitter.getAdaptedPropagator();
103         Orbit fitted = prop.getInitialState().getOrbit();
104 
105         final double eps = 1.0e-12;
106         Assertions.assertEquals(modified.getPosition().getX(),
107                             fitted.getPosition().getX(),
108                             eps * modified.getPosition().getX());
109         Assertions.assertEquals(modified.getPosition().getY(),
110                             fitted.getPosition().getY(),
111                             eps * modified.getPosition().getY());
112         Assertions.assertEquals(modified.getPosition().getZ(),
113                             fitted.getPosition().getZ(),
114                             eps * modified.getPosition().getZ());
115 
116         Assertions.assertEquals(modified.getPVCoordinates().getVelocity().getX(),
117                             fitted.getPVCoordinates().getVelocity().getX(),
118                             eps * modified.getPVCoordinates().getVelocity().getX());
119         Assertions.assertEquals(modified.getPVCoordinates().getVelocity().getY(),
120                             fitted.getPVCoordinates().getVelocity().getY(),
121                             -eps * modified.getPVCoordinates().getVelocity().getY());
122         Assertions.assertEquals(modified.getPVCoordinates().getVelocity().getZ(),
123                             fitted.getPVCoordinates().getVelocity().getZ(),
124                             -eps * modified.getPVCoordinates().getVelocity().getZ());
125 
126     }
127 
128     @BeforeEach
129     public void setUp() {
130         Utils.setDataRoot("regular-data");
131 
132         AbsoluteDate initDate = AbsoluteDate.J2000_EPOCH.shiftedBy(584.);
133 
134          double mu  = 3.9860047e14;
135          double ae  = 6.378137e6;
136          double[][] cnm = new double[][] {
137              { 0 }, { 0 }, { -1.08263e-3 }, { 2.54e-6 }, { 1.62e-6 }, { 2.3e-7 }, { -5.5e-7 }
138             };
139          double[][] snm = new double[][] {
140              { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }
141             };
142          provider = GravityFieldFactory.getUnnormalizedProvider(ae, mu, TideSystem.UNKNOWN, cnm, snm);
143 
144         orbit = new EquinoctialOrbit(new PVCoordinates(new Vector3D(3220103., 69623., 6449822.),
145                                                        new Vector3D(6414.7, -2006., -3180.)),
146                                      FramesFactory.getEME2000(), initDate, mu);
147     }
148 
149 }
150