1 /* Contributed in the public domain.
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 java.util.ArrayList;
20 import java.util.List;
21 import java.util.Map;
22
23 import org.hipparchus.util.FastMath;
24 import org.orekit.data.DataProvidersManager;
25 import org.orekit.errors.OrekitException;
26 import org.orekit.errors.OrekitMessages;
27 import org.orekit.time.TimeScale;
28
29 /**
30 * Loads gravity fields when first requested and can be configured until then. Designed to
31 * match the behavior of {@link GravityFieldFactory} in Orekit 10.0.
32 *
33 * @author Evan Ward
34 * @author Fabien Maussion
35 * @author Pascal Parraud
36 * @author Luc Maisonobe
37 * @see GravityFieldFactory
38 * @since 10.1
39 */
40 public class LazyLoadedGravityFields implements GravityFields {
41
42 /** Potential readers. */
43 private final List<PotentialCoefficientsReader> readers = new ArrayList<>();
44
45 /** Ocean tides readers. */
46 private final List<OceanTidesReader> oceanTidesReaders =
47 new ArrayList<>();
48
49 /** Ocean load deformation coefficients. */
50 private OceanLoadDeformationCoefficients oceanLoadDeformationCoefficients =
51 OceanLoadDeformationCoefficients.IERS_2010;
52
53 /** Provides access to auxiliary data files for loading gravity field files. */
54 private final DataProvidersManager dataProvidersManager;
55
56 /** Time scale for parsing dates. */
57 private final TimeScale timeScale;
58
59 /**
60 * Create a factory for gravity fields that uses the given data manager to load the
61 * gravity field files.
62 *
63 * @param dataProvidersManager provides access to auxiliary data files.
64 * @param timeScale use to parse dates for the {@link #addDefaultPotentialCoefficientsReaders()}.
65 * In Orekit 10.0 it is TT.
66 */
67 public LazyLoadedGravityFields(final DataProvidersManager dataProvidersManager,
68 final TimeScale timeScale) {
69 this.dataProvidersManager = dataProvidersManager;
70 this.timeScale = timeScale;
71 }
72
73 /** Add a reader for gravity fields.
74 * @param reader custom reader to add for the gravity field
75 * @see #addDefaultPotentialCoefficientsReaders()
76 * @see #clearPotentialCoefficientsReaders()
77 */
78 public void addPotentialCoefficientsReader(final PotentialCoefficientsReader reader) {
79 synchronized (readers) {
80 readers.add(reader);
81 }
82 }
83
84 /**
85 * Add the default readers for gravity fields.
86 *
87 * <p> The default readers support ICGEM, SHM, EGM and GRGS formats with the
88 * default names {@link GravityFieldFactory#ICGEM_FILENAME}, {@link
89 * GravityFieldFactory#SHM_FILENAME}, {@link GravityFieldFactory#EGM_FILENAME}, {@link
90 * GravityFieldFactory#GRGS_FILENAME} and don't allow missing coefficients.
91 *
92 * @see #addPotentialCoefficientsReader(PotentialCoefficientsReader)
93 * @see #clearPotentialCoefficientsReaders()
94 */
95 public void addDefaultPotentialCoefficientsReaders() {
96 synchronized (readers) {
97 readers.add(new ICGEMFormatReader(GravityFieldFactory.ICGEM_FILENAME, false, timeScale));
98 readers.add(new SHMFormatReader(GravityFieldFactory.SHM_FILENAME, false, timeScale));
99 readers.add(new EGMFormatReader(GravityFieldFactory.EGM_FILENAME, false));
100 readers.add(new GRGSFormatReader(GravityFieldFactory.GRGS_FILENAME, false, timeScale));
101 }
102 }
103
104 /** Clear gravity field readers.
105 * @see #addPotentialCoefficientsReader(PotentialCoefficientsReader)
106 * @see #addDefaultPotentialCoefficientsReaders()
107 */
108 public void clearPotentialCoefficientsReaders() {
109 synchronized (readers) {
110 readers.clear();
111 }
112 }
113
114 /** Add a reader for ocean tides.
115 * @param reader custom reader to add for the gravity field
116 * @see #addDefaultPotentialCoefficientsReaders()
117 * @see #clearPotentialCoefficientsReaders()
118 */
119 public void addOceanTidesReader(final OceanTidesReader reader) {
120 synchronized (oceanTidesReaders) {
121 oceanTidesReaders.add(reader);
122 }
123 }
124
125 /** Configure ocean load deformation coefficients.
126 * @param oldc ocean load deformation coefficients
127 * @see #getOceanLoadDeformationCoefficients()
128 */
129 public void configureOceanLoadDeformationCoefficients(final OceanLoadDeformationCoefficients oldc) {
130 oceanLoadDeformationCoefficients = oldc;
131 }
132
133 /** Get the configured ocean load deformation coefficients.
134 * <p>
135 * If {@link #configureOceanLoadDeformationCoefficients(OceanLoadDeformationCoefficients)
136 * configureOceanLoadDeformationCoefficients} has never been called, the default
137 * value will be the {@link OceanLoadDeformationCoefficients#IERS_2010 IERS 2010}
138 * coefficients.
139 * </p>
140 * @return ocean load deformation coefficients
141 * @see #configureOceanLoadDeformationCoefficients(OceanLoadDeformationCoefficients)
142 */
143 public OceanLoadDeformationCoefficients getOceanLoadDeformationCoefficients() {
144 return oceanLoadDeformationCoefficients;
145 }
146
147 /** Add the default readers for ocean tides.
148 * <p>
149 * The default readers support files similar to the fes2004_Cnm-Snm.dat and
150 * fes2004.dat as published by IERS, using the {@link
151 * #configureOceanLoadDeformationCoefficients(OceanLoadDeformationCoefficients)
152 * configured} ocean load deformation coefficients, which by default are the
153 * IERS 2010 coefficients, which are limited to degree 6. If higher degree
154 * coefficients are needed, the {@link
155 * #configureOceanLoadDeformationCoefficients(OceanLoadDeformationCoefficients)
156 * configureOceanLoadDeformationCoefficients} method can be called prior to
157 * loading the ocean tides model with the {@link
158 * OceanLoadDeformationCoefficients#GEGOUT high degree coefficients} computed
159 * by Pascal Gégout.
160 * </p>
161 * <p>
162 * WARNING: the files referenced in the published conventions have some errors.
163 * These errors have been corrected and the updated files can be found here:
164 * <a href="http://tai.bipm.org/iers/convupdt/convupdt_c6.html">
165 * http://tai.bipm.org/iers/convupdt/convupdt_c6.html</a>.
166 * </p>
167 * @see #addPotentialCoefficientsReader(PotentialCoefficientsReader)
168 * @see #clearPotentialCoefficientsReaders()
169 * @see #configureOceanLoadDeformationCoefficients(OceanLoadDeformationCoefficients)
170 * @see #getOceanLoadDeformationCoefficients()
171 */
172 public void addDefaultOceanTidesReaders() {
173 synchronized (oceanTidesReaders) {
174
175 oceanTidesReaders.add(new FESCnmSnmReader(GravityFieldFactory.FES_CNM_SNM_FILENAME, 1.0e-11));
176
177 final AstronomicalAmplitudeReader aaReader =
178 new AstronomicalAmplitudeReader(GravityFieldFactory.FES_HF_FILENAME, 5, 2, 3, 1.0);
179 dataProvidersManager.feed(aaReader.getSupportedNames(), aaReader);
180 final Map<Integer, Double> map = aaReader.getAstronomicalAmplitudesMap();
181 oceanTidesReaders.add(new FESCHatEpsilonReader(GravityFieldFactory.FES_CHAT_EPSILON_FILENAME,
182 0.01, FastMath.toRadians(1.0),
183 getOceanLoadDeformationCoefficients(),
184 map));
185
186
187 }
188 }
189
190 /** Clear ocean tides readers.
191 * @see #addPotentialCoefficientsReader(PotentialCoefficientsReader)
192 * @see #addDefaultPotentialCoefficientsReaders()
193 */
194 public void clearOceanTidesReaders() {
195 synchronized (oceanTidesReaders) {
196 oceanTidesReaders.clear();
197 }
198 }
199
200 /** Read a gravity field coefficients provider from the first supported file.
201 * <p>
202 * If no {@link PotentialCoefficientsReader} has been added by calling {@link
203 * #addPotentialCoefficientsReader(PotentialCoefficientsReader)
204 * addPotentialCoefficientsReader} or if {@link #clearPotentialCoefficientsReaders()
205 * clearPotentialCoefficientsReaders} has been called afterwards, the {@link
206 * #addDefaultPotentialCoefficientsReaders() addDefaultPotentialCoefficientsReaders}
207 * method will be called automatically.
208 * </p>
209 * @param maxParseDegree maximal degree to parse
210 * @param maxParseOrder maximal order to parse
211 * @return a reader containing already loaded data
212 * @since 6.0
213 */
214 public PotentialCoefficientsReader readGravityField(final int maxParseDegree,
215 final int maxParseOrder) {
216
217 synchronized (readers) {
218
219 if (readers.isEmpty()) {
220 addDefaultPotentialCoefficientsReaders();
221 }
222
223 // test the available readers
224 for (final PotentialCoefficientsReader reader : readers) {
225 reader.setMaxParseDegree(maxParseDegree);
226 reader.setMaxParseOrder(maxParseOrder);
227 dataProvidersManager.feed(reader.getSupportedNames(), reader);
228 if (!reader.stillAcceptsData()) {
229 return reader;
230 }
231 }
232 }
233
234 throw new OrekitException(OrekitMessages.NO_GRAVITY_FIELD_DATA_LOADED);
235
236 }
237
238 /**
239 * {@inheritDoc}
240 *
241 * <p> If no {@link PotentialCoefficientsReader} has been added by calling {@link
242 * #addPotentialCoefficientsReader(PotentialCoefficientsReader)
243 * addPotentialCoefficientsReader} or if {@link #clearPotentialCoefficientsReaders()
244 * clearPotentialCoefficientsReaders} has been called afterwards, the {@link
245 * #addDefaultPotentialCoefficientsReaders() addDefaultPotentialCoefficientsReaders}
246 * method will be called automatically.
247 */
248 @Override
249 public NormalizedSphericalHarmonicsProvider getConstantNormalizedProvider(final int degree,
250 final int order) {
251 final RawSphericalHarmonicsProvider provider;
252 synchronized (readers) {
253 final PotentialCoefficientsReader reader = readGravityField(degree, order);
254 provider = reader.getProvider(true, degree, order);
255 }
256 final ConstantSphericalHarmonics frozen = new ConstantSphericalHarmonics(provider.getReferenceDate(), provider);
257 return new WrappingNormalizedProvider(frozen);
258 }
259
260 /**
261 * {@inheritDoc}
262 *
263 * <p>If no {@link PotentialCoefficientsReader} has been added by calling {@link
264 * #addPotentialCoefficientsReader(PotentialCoefficientsReader)
265 * addPotentialCoefficientsReader} or if {@link #clearPotentialCoefficientsReaders()
266 * clearPotentialCoefficientsReaders} has been called afterwards, the {@link
267 * #addDefaultPotentialCoefficientsReaders() addDefaultPotentialCoefficientsReaders}
268 * method will be called automatically.
269 */
270 @Override
271 public NormalizedSphericalHarmonicsProvider getNormalizedProvider(final int degree,
272 final int order) {
273 final RawSphericalHarmonicsProvider provider;
274 synchronized (readers) {
275 final PotentialCoefficientsReader reader = readGravityField(degree, order);
276 provider = reader.getProvider(true, degree, order);
277 }
278 return new WrappingNormalizedProvider(provider);
279 }
280
281 /**
282 * {@inheritDoc}
283 *
284 * <p>If no {@link PotentialCoefficientsReader} has been added by calling {@link
285 * #addPotentialCoefficientsReader(PotentialCoefficientsReader)
286 * addPotentialCoefficientsReader} or if {@link #clearPotentialCoefficientsReaders()
287 * clearPotentialCoefficientsReaders} has been called afterwards, the {@link
288 * #addDefaultPotentialCoefficientsReaders() addDefaultPotentialCoefficientsReaders}
289 * method will be called automatically.
290 */
291 @Override
292 public UnnormalizedSphericalHarmonicsProvider getConstantUnnormalizedProvider(final int degree,
293 final int order) {
294 final RawSphericalHarmonicsProvider provider;
295 synchronized (readers) {
296 final PotentialCoefficientsReader reader = readGravityField(degree, order);
297 provider = reader.getProvider(false, degree, order);
298 }
299 final ConstantSphericalHarmonics frozen = new ConstantSphericalHarmonics(provider.getReferenceDate(), provider);
300 return new WrappingUnnormalizedProvider(frozen);
301 }
302
303 /**
304 * {@inheritDoc}
305 *
306 * <p>If no {@link PotentialCoefficientsReader} has been added by calling {@link
307 * #addPotentialCoefficientsReader(PotentialCoefficientsReader)
308 * addPotentialCoefficientsReader} or if {@link #clearPotentialCoefficientsReaders()
309 * clearPotentialCoefficientsReaders} has been called afterwards, the {@link
310 * #addDefaultPotentialCoefficientsReaders() addDefaultPotentialCoefficientsReaders}
311 * method will be called automatically.
312 */
313 @Override
314 public UnnormalizedSphericalHarmonicsProvider getUnnormalizedProvider(final int degree,
315 final int order) {
316 final RawSphericalHarmonicsProvider provider;
317 synchronized (readers) {
318 final PotentialCoefficientsReader reader = readGravityField(degree, order);
319 provider = reader.getProvider(false, degree, order);
320 }
321 return new WrappingUnnormalizedProvider(provider);
322 }
323
324 /**
325 * {@inheritDoc}
326 *
327 * <p>If no {@link OceanTidesReader} has been added by calling {@link
328 * #addOceanTidesReader(OceanTidesReader)
329 * addOceanTidesReader} or if {@link #clearOceanTidesReaders()
330 * clearOceanTidesReaders} has been called afterwards, the {@link
331 * #addDefaultOceanTidesReaders() addDefaultOceanTidesReaders}
332 * method will be called automatically.
333 */
334 @Override
335 public List<OceanTidesWave> getOceanTidesWaves(final int degree, final int order) {
336
337 synchronized (oceanTidesReaders) {
338
339 if (oceanTidesReaders.isEmpty()) {
340 addDefaultOceanTidesReaders();
341 }
342
343 // test the available readers
344 for (final OceanTidesReader reader : oceanTidesReaders) {
345 reader.setMaxParseDegree(degree);
346 reader.setMaxParseOrder(order);
347 dataProvidersManager.feed(reader.getSupportedNames(), reader);
348 if (!reader.stillAcceptsData()) {
349 return reader.getWaves();
350 }
351 }
352 }
353
354 throw new OrekitException(OrekitMessages.NO_OCEAN_TIDE_DATA_LOADED);
355
356 }
357
358 }