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.forces.gravity.potential;
18  
19  import org.hipparchus.util.FastMath;
20  import org.hipparchus.util.Precision;
21  import org.junit.jupiter.api.Assertions;
22  import org.junit.jupiter.api.Test;
23  import org.orekit.Utils;
24  import org.orekit.errors.OrekitException;
25  import org.orekit.forces.gravity.potential.NormalizedSphericalHarmonicsProvider.NormalizedSphericalHarmonics;
26  import org.orekit.forces.gravity.potential.UnnormalizedSphericalHarmonicsProvider.UnnormalizedSphericalHarmonics;
27  import org.orekit.time.AbsoluteDate;
28  import org.orekit.utils.Constants;
29  
30  public class EGMFormatReaderTest {
31  
32      @Test
33      void testReadNormalized() {
34          Utils.setDataRoot("potential");
35          GravityFieldFactory.addPotentialCoefficientsReader(new EGMFormatReader("egm96_to5.ascii", true));
36          NormalizedSphericalHarmonicsProvider provider = GravityFieldFactory.getNormalizedProvider(5, 5);
37          NormalizedSphericalHarmonics harmonics = provider.onDate(AbsoluteDate.FUTURE_INFINITY);
38          Assertions.assertEquals(TideSystem.TIDE_FREE, provider.getTideSystem());
39          Assertions.assertEquals( 0.957254173792E-06, harmonics.getNormalizedCnm(3, 0), 1.0e-15);
40          Assertions.assertEquals( 0.174971983203E-06, harmonics.getNormalizedCnm(5, 5), 1.0e-15);
41          Assertions.assertEquals( 0.0,                harmonics.getNormalizedSnm(4, 0), 1.0e-15);
42          Assertions.assertEquals( 0.308853169333E-06, harmonics.getNormalizedSnm(4, 4), 1.0e-15);
43          Assertions.assertEquals(-0.295301647654E-06, harmonics.getNormalizedCnm(5, 4), 1.0e-15);
44      }
45  
46      @Test
47      void testReadUnnormalized() {
48          Utils.setDataRoot("potential");
49          GravityFieldFactory.addPotentialCoefficientsReader(new EGMFormatReader("egm96_to5.ascii", true));
50          UnnormalizedSphericalHarmonicsProvider provider = GravityFieldFactory.getUnnormalizedProvider(5, 5);
51          UnnormalizedSphericalHarmonics harmonics = provider.onDate(AbsoluteDate.FUTURE_INFINITY);
52          Assertions.assertEquals(TideSystem.TIDE_FREE, provider.getTideSystem());
53          int maxUlps = 1;
54          checkValue(harmonics.getUnnormalizedCnm(3, 0), 3, 0, 0.957254173792E-06, maxUlps);
55          checkValue(harmonics.getUnnormalizedCnm(5, 5), 5, 5, 0.174971983203E-06, maxUlps);
56          checkValue(harmonics.getUnnormalizedSnm(4, 0), 4, 0, 0.0,                maxUlps);
57          checkValue(harmonics.getUnnormalizedSnm(4, 4), 4, 4, 0.308853169333E-06, maxUlps);
58  
59          double a = (-0.295301647654E-06);
60          double b = 9*8*7*6*5*4*3*2;
61          double c = 2*11/b;
62          double result = a*FastMath.sqrt(c);
63  
64          Assertions.assertEquals(result, harmonics.getUnnormalizedCnm(5, 4), 1.0e-20);
65  
66          a = -0.188560802735E-06;
67          b = 8*7*6*5*4*3*2;
68          c=2*9/b;
69          result = a*FastMath.sqrt(c);
70          Assertions.assertEquals(result, harmonics.getUnnormalizedCnm(4, 4), 1.0e-20);
71  
72          Assertions.assertEquals(1.0826266835531513e-3, -harmonics.getUnnormalizedCnm(2, 0), 1.0e-20);
73  
74      }
75  
76      @Test
77      void testReadLimits() {
78          Utils.setDataRoot("potential");
79          GravityFieldFactory.addPotentialCoefficientsReader(new EGMFormatReader("egm96_to5.ascii", true));
80          UnnormalizedSphericalHarmonicsProvider provider = GravityFieldFactory.getUnnormalizedProvider(3, 2);
81          UnnormalizedSphericalHarmonics harmonics = provider.onDate(null);
82          try {
83              harmonics.getUnnormalizedCnm(3, 3);
84              Assertions.fail("an exception should have been thrown");
85          } catch (OrekitException oe) {
86              // expected
87          } catch (Exception e) {
88              Assertions.fail("wrong exception caught: " + e.getLocalizedMessage());
89          }
90          try {
91              harmonics.getUnnormalizedCnm(4, 2);
92              Assertions.fail("an exception should have been thrown");
93          } catch (OrekitException oe) {
94              // expected
95          } catch (Exception e) {
96              Assertions.fail("wrong exception caught: " + e.getLocalizedMessage());
97          }
98          harmonics.getUnnormalizedCnm(3, 2);
99          Assertions.assertEquals(3, provider.getMaxDegree());
100         Assertions.assertEquals(2, provider.getMaxOrder());
101     }
102 
103     @Test
104     void testCorruptedFile1() {
105         Assertions.assertThrows(OrekitException.class, () -> {
106             Utils.setDataRoot("potential");
107             GravityFieldFactory.addPotentialCoefficientsReader(new EGMFormatReader("corrupted-1-egm96_to5", false));
108             GravityFieldFactory.getUnnormalizedProvider(5, 5);
109         });
110     }
111 
112     @Test
113     void testCorruptedFile2() {
114         Assertions.assertThrows(OrekitException.class, () -> {
115             Utils.setDataRoot("potential");
116             GravityFieldFactory.addPotentialCoefficientsReader(new EGMFormatReader("corrupted-2-egm96_to5", false));
117             GravityFieldFactory.getUnnormalizedProvider(5, 5);
118         });
119     }
120 
121     @Test
122     void testCorruptedFile3() {
123         Assertions.assertThrows(OrekitException.class, () -> {
124             Utils.setDataRoot("potential");
125             GravityFieldFactory.addPotentialCoefficientsReader(new EGMFormatReader("corrupted-3-egm96_to5", false));
126             GravityFieldFactory.getUnnormalizedProvider(5, 5);
127         });
128     }
129 
130     @Test
131     void testZeroTidePattern1() {
132         Utils.setDataRoot("potential");
133         GravityFieldFactory.addPotentialCoefficientsReader(new EGMFormatReader("dummy_egm2008", true));
134         Assertions.assertEquals(TideSystem.ZERO_TIDE,
135                             GravityFieldFactory.getUnnormalizedProvider(5, 5).getTideSystem());
136     }
137 
138     @Test
139     void testZeroTidePattern2() {
140         Utils.setDataRoot("potential");
141         GravityFieldFactory.addPotentialCoefficientsReader(new EGMFormatReader("dummy_zerotide", true));
142         Assertions.assertEquals(TideSystem.ZERO_TIDE,
143                             GravityFieldFactory.getUnnormalizedProvider(5, 5).getTideSystem());
144     }
145 
146     @Test
147     void testWgs84CoefficientOverride()
148         {
149         final double epsilon = Precision.EPSILON;
150 
151         Utils.setDataRoot("potential");
152         EGMFormatReader egm96Reader = new EGMFormatReader("egm96_to5.ascii", true);
153         GravityFieldFactory.addPotentialCoefficientsReader(egm96Reader);
154         GravityFieldFactory.getNormalizedProvider(5, 5);
155         Assertions.assertEquals(Constants.EGM96_EARTH_EQUATORIAL_RADIUS, egm96Reader.getAe(), epsilon);
156         Assertions.assertEquals(Constants.EGM96_EARTH_MU, egm96Reader.getMu(), epsilon);
157 
158         Utils.setDataRoot("potential");
159         EGMFormatReader wgs84Egm96Reader = new EGMFormatReader("egm96_to5.ascii", true, true);
160         GravityFieldFactory.addPotentialCoefficientsReader(wgs84Egm96Reader);
161         GravityFieldFactory.getNormalizedProvider(5, 5);
162         Assertions.assertEquals(Constants.WGS84_EARTH_EQUATORIAL_RADIUS, wgs84Egm96Reader.getAe(), epsilon);
163         Assertions.assertEquals(Constants.WGS84_EARTH_MU, wgs84Egm96Reader.getMu(), epsilon);
164 
165     }
166 
167     private void checkValue(final double value, final int n, final int m,
168                             final double constant, final int maxUlps)
169         {
170         double factor = GravityFieldFactory.getUnnormalizationFactors(n, m)[n][m];
171         double normalized = factor * constant;
172         double epsilon = maxUlps * FastMath.ulp(normalized);
173         Assertions.assertEquals(normalized, value, epsilon);
174     }
175 
176 }