1   /* Copyright 2002-2022 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;
18  
19  import java.lang.reflect.Field;
20  import java.lang.reflect.Modifier;
21  import java.net.URISyntaxException;
22  import java.util.ArrayList;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.SortedSet;
26  import java.util.concurrent.atomic.AtomicReference;
27  
28  import org.junit.Assert;
29  import org.orekit.attitudes.AttitudeProvider;
30  import org.orekit.attitudes.InertialProvider;
31  import org.orekit.bodies.CelestialBodyFactory;
32  import org.orekit.data.DataContext;
33  import org.orekit.data.DataProvidersManager;
34  import org.orekit.data.LazyLoadedDataContext;
35  import org.orekit.forces.gravity.potential.GravityFieldFactory;
36  import org.orekit.frames.EOPEntry;
37  import org.orekit.frames.EOPHistoryLoader;
38  import org.orekit.frames.FramesFactory;
39  import org.orekit.frames.ITRFVersion;
40  import org.orekit.models.earth.weather.GlobalPressureTemperature2Model;
41  import org.orekit.orbits.FieldCartesianOrbit;
42  import org.orekit.orbits.FieldCircularOrbit;
43  import org.orekit.orbits.FieldEquinoctialOrbit;
44  import org.orekit.orbits.FieldKeplerianOrbit;
45  import org.orekit.propagation.semianalytical.dsst.utilities.JacobiPolynomials;
46  import org.orekit.propagation.semianalytical.dsst.utilities.NewcombOperators;
47  import org.orekit.time.AbsoluteDate;
48  import org.orekit.time.DateComponents;
49  import org.orekit.time.GNSSDate;
50  import org.orekit.time.TimeScale;
51  import org.orekit.time.TimeScalesFactory;
52  import org.orekit.utils.Constants;
53  import org.orekit.utils.IERSConventions;
54  
55  public class Utils {
56  
57      // epsilon for tests
58      public static final double epsilonTest  = 1.e-12;
59  
60      // epsilon for eccentricity
61      public static final double epsilonE     = 1.e+5 * epsilonTest;
62  
63      // epsilon for circular eccentricity
64      public static final double epsilonEcir  = 1.e+8 * epsilonTest;
65  
66      // epsilon for angles
67      public static final double epsilonAngle = 1.e+5 * epsilonTest;
68  
69      public static final double ae =  6378136.460;
70      public static final double mu =  3.986004415e+14;
71  
72      public static void clearFactories() {
73          DataContext.setDefault(new LazyLoadedDataContext());
74          clearFactoryMaps(CelestialBodyFactory.class);
75          CelestialBodyFactory.clearCelestialBodyLoaders();
76          clearFactoryMaps(FramesFactory.class);
77          clearFactoryMaps(TimeScalesFactory.class);
78          clearFactory(TimeScalesFactory.class, TimeScale.class);
79          clearFactoryMaps(FieldCartesianOrbit.class);
80          clearFactoryMaps(FieldKeplerianOrbit.class);
81          clearFactoryMaps(FieldCircularOrbit.class);
82          clearFactoryMaps(FieldEquinoctialOrbit.class);
83          clearFactoryMaps(JacobiPolynomials.class);
84          clearFactoryMaps(NewcombOperators.class);
85          for (final Class<?> c : NewcombOperators.class.getDeclaredClasses()) {
86              if (c.getName().endsWith("PolynomialsGenerator")) {
87                  clearFactoryMaps(c);
88              }
89          }
90          clearAtomicReference(GlobalPressureTemperature2Model.class);
91          FramesFactory.clearEOPHistoryLoaders();
92          FramesFactory.setEOPContinuityThreshold(5 * Constants.JULIAN_DAY);
93          TimeScalesFactory.clearUTCTAIOffsetsLoaders();
94          GNSSDate.setRolloverReference(null);
95          GravityFieldFactory.clearPotentialCoefficientsReaders();
96          GravityFieldFactory.clearOceanTidesReaders();
97          DataContext.getDefault().getDataProvidersManager().clearProviders();
98          DataContext.getDefault().getDataProvidersManager().resetFiltersToDefault();
99          DataContext.getDefault().getDataProvidersManager().clearLoadedDataNames();
100         
101     }
102 
103     public static DataContext setDataRoot(String root) {
104         try {
105             clearFactories();
106             StringBuilder buffer = new StringBuilder();
107             for (String component : root.split(":")) {
108                 String componentPath;
109                 componentPath = Utils.class.getClassLoader().getResource(component).toURI().getPath();
110                 if (buffer.length() > 0) {
111                     buffer.append(System.getProperty("path.separator"));
112                 }
113                 buffer.append(componentPath);
114             }
115             System.setProperty(DataProvidersManager.OREKIT_DATA_PATH, buffer.toString());
116             return DataContext.getDefault();
117         } catch (URISyntaxException e) {
118             throw new RuntimeException(e);
119         }
120     }
121 
122     private static void clearFactoryMaps(Class<?> factoryClass) {
123         try {
124             for (Field field : factoryClass.getDeclaredFields()) {
125                 if (Modifier.isStatic(field.getModifiers()) &&
126                     Map.class.isAssignableFrom(field.getType())) {
127                     field.setAccessible(true);
128                     ((Map<?, ?>) field.get(null)).clear();
129                 }
130             }
131         } catch (IllegalAccessException iae) {
132             Assert.fail(iae.getMessage());
133         }
134     }
135 
136     private static void clearFactory(Class<?> factoryClass, Class<?> cachedFieldsClass) {
137         try {
138             for (Field field : factoryClass.getDeclaredFields()) {
139                 if (Modifier.isStatic(field.getModifiers()) &&
140                     cachedFieldsClass.isAssignableFrom(field.getType())) {
141                     field.setAccessible(true);
142                     field.set(null, null);
143                 }
144             }
145         } catch (IllegalAccessException iae) {
146             Assert.fail(iae.getMessage());
147         }
148     }
149 
150     private static void clearAtomicReference(Class<?> factoryClass) {
151         try {
152             for (Field field : factoryClass.getDeclaredFields()) {
153                 if (Modifier.isStatic(field.getModifiers()) &&
154                     AtomicReference.class.isAssignableFrom(field.getType())) {
155                     field.setAccessible(true);
156                     ((AtomicReference<?>) field.get(null)).set(null);
157                 }
158             }
159         } catch (IllegalAccessException iae) {
160             Assert.fail(iae.getMessage());
161         }
162     }
163 
164     public static List<EOPEntry> buildEOPList(IERSConventions conventions, ITRFVersion version,
165                                               double[][] data) {
166         IERSConventions.NutationCorrectionConverter converter =
167                 conventions.getNutationCorrectionConverter();
168         final TimeScale utc = DataContext.getDefault().getTimeScales().getUTC();
169         final List<EOPEntry> list = new ArrayList<EOPEntry>();
170         for (double[] row : data) {
171             final AbsoluteDate date =
172                     new AbsoluteDate(new DateComponents(DateComponents.MODIFIED_JULIAN_EPOCH, (int) row[0]),
173                                      TimeScalesFactory.getUTC());
174             final double[] nro;
175             final double[] equinox;
176             if (Double.isNaN(row[7])) {
177                 equinox = new double[] {
178                     Constants.ARC_SECONDS_TO_RADIANS * row[5],
179                     Constants.ARC_SECONDS_TO_RADIANS * row[6]
180                 };
181                 nro     = converter.toNonRotating(date, equinox[0], equinox[1]);
182             } else if (Double.isNaN(row[5])) {
183                 nro     = new double[] {
184                     Constants.ARC_SECONDS_TO_RADIANS * row[7],
185                     Constants.ARC_SECONDS_TO_RADIANS * row[8]
186                 };
187                 equinox = converter.toEquinox(date, nro[0], nro[1]);
188             } else {
189                 equinox = new double[] {
190                     Constants.ARC_SECONDS_TO_RADIANS * row[5],
191                     Constants.ARC_SECONDS_TO_RADIANS * row[6]
192                 };
193                 nro     = new double[] {
194                     Constants.ARC_SECONDS_TO_RADIANS * row[7],
195                     Constants.ARC_SECONDS_TO_RADIANS * row[8]
196                 };
197             }
198             list.add(new EOPEntry((int) row[0], row[1], row[2],
199                                   Constants.ARC_SECONDS_TO_RADIANS * row[3],
200                                   Constants.ARC_SECONDS_TO_RADIANS * row[4],
201                                   equinox[0], equinox[1],
202                                   nro[0], nro[1], version,
203                                   AbsoluteDate.createMJDDate((int) row[0], 0.0, utc)));
204         }
205         return list;
206     }
207 
208     public static void setLoaders(final IERSConventions conventions, final List<EOPEntry> eop) {
209 
210         clearFactories();
211 
212         FramesFactory.addEOPHistoryLoader(conventions, new EOPHistoryLoader() {
213             public void fillHistory(IERSConventions.NutationCorrectionConverter converter,
214                                     SortedSet<EOPEntry> history) {
215                 history.addAll(eop);
216             }
217         });
218 
219     }
220 
221     /**
222      * An attitude law compatible with the old Propagator.DEFAULT_LAW. This is used so as
223      * not to change the results of tests written against the old implementation.
224      *
225      * @return an attitude law.
226      */
227     public static AttitudeProvider defaultLaw() {
228         return InertialProvider.of(FramesFactory.getEME2000());
229     }
230 
231 }