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 PotentialCoefficientsReader reader = readGravityField(degree, order);
252 final RawSphericalHarmonicsProvider provider = reader.getConstantProvider(true, degree, order);
253 return new WrappingNormalizedProvider(provider);
254 }
255
256 /**
257 * {@inheritDoc}
258 *
259 * <p>If no {@link PotentialCoefficientsReader} has been added by calling {@link
260 * #addPotentialCoefficientsReader(PotentialCoefficientsReader)
261 * addPotentialCoefficientsReader} or if {@link #clearPotentialCoefficientsReaders()
262 * clearPotentialCoefficientsReaders} has been called afterwards, the {@link
263 * #addDefaultPotentialCoefficientsReaders() addDefaultPotentialCoefficientsReaders}
264 * method will be called automatically.
265 */
266 @Override
267 public NormalizedSphericalHarmonicsProvider getNormalizedProvider(final int degree,
268 final int order) {
269 final PotentialCoefficientsReader reader = readGravityField(degree, order);
270 final RawSphericalHarmonicsProvider provider = reader.getProvider(true, degree, order);
271 return new WrappingNormalizedProvider(provider);
272 }
273
274 /**
275 * {@inheritDoc}
276 *
277 * <p>If no {@link PotentialCoefficientsReader} has been added by calling {@link
278 * #addPotentialCoefficientsReader(PotentialCoefficientsReader)
279 * addPotentialCoefficientsReader} or if {@link #clearPotentialCoefficientsReaders()
280 * clearPotentialCoefficientsReaders} has been called afterwards, the {@link
281 * #addDefaultPotentialCoefficientsReaders() addDefaultPotentialCoefficientsReaders}
282 * method will be called automatically.
283 */
284 @Override
285 public UnnormalizedSphericalHarmonicsProvider getConstantUnnormalizedProvider(final int degree,
286 final int order) {
287 final PotentialCoefficientsReader reader = readGravityField(degree, order);
288 final RawSphericalHarmonicsProvider provider = reader.getConstantProvider(false, degree, order);
289 return new WrappingUnnormalizedProvider(provider);
290 }
291
292 /**
293 * {@inheritDoc}
294 *
295 * <p>If no {@link PotentialCoefficientsReader} has been added by calling {@link
296 * #addPotentialCoefficientsReader(PotentialCoefficientsReader)
297 * addPotentialCoefficientsReader} or if {@link #clearPotentialCoefficientsReaders()
298 * clearPotentialCoefficientsReaders} has been called afterwards, the {@link
299 * #addDefaultPotentialCoefficientsReaders() addDefaultPotentialCoefficientsReaders}
300 * method will be called automatically.
301 */
302 @Override
303 public UnnormalizedSphericalHarmonicsProvider getUnnormalizedProvider(final int degree,
304 final int order) {
305 final PotentialCoefficientsReader reader = readGravityField(degree, order);
306 final RawSphericalHarmonicsProvider provider = reader.getProvider(false, degree, order);
307 return new WrappingUnnormalizedProvider(provider);
308 }
309
310 /**
311 * {@inheritDoc}
312 *
313 * <p>If no {@link OceanTidesReader} has been added by calling {@link
314 * #addOceanTidesReader(OceanTidesReader)
315 * addOceanTidesReader} or if {@link #clearOceanTidesReaders()
316 * clearOceanTidesReaders} has been called afterwards, the {@link
317 * #addDefaultOceanTidesReaders() addDefaultOceanTidesReaders}
318 * method will be called automatically.
319 */
320 @Override
321 public List<OceanTidesWave> getOceanTidesWaves(final int degree, final int order) {
322
323 synchronized (oceanTidesReaders) {
324
325 if (oceanTidesReaders.isEmpty()) {
326 addDefaultOceanTidesReaders();
327 }
328
329 // test the available readers
330 for (final OceanTidesReader reader : oceanTidesReaders) {
331 reader.setMaxParseDegree(degree);
332 reader.setMaxParseOrder(order);
333 dataProvidersManager.feed(reader.getSupportedNames(), reader);
334 if (!reader.stillAcceptsData()) {
335 return reader.getWaves();
336 }
337 }
338 }
339
340 throw new OrekitException(OrekitMessages.NO_OCEAN_TIDE_DATA_LOADED);
341
342 }
343
344 }