1 /* Copyright 2002-2021 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.frames;
18
19 import org.hipparchus.CalculusFieldElement;
20 import org.orekit.annotation.DefaultDataContext;
21 import org.orekit.data.DataContext;
22 import org.orekit.time.AbsoluteDate;
23 import org.orekit.time.FieldAbsoluteDate;
24 import org.orekit.utils.IERSConventions;
25
26
27 /** Factory for predefined reference frames.
28 *
29 * <h2> FramesFactory Presentation </h2>
30 * <p>
31 * Several predefined reference {@link Frame frames} are implemented in OREKIT.
32 * They are linked together in a tree with the <i>Geocentric
33 * Celestial Reference Frame</i> (GCRF) as the root of the tree.
34 * This factory is designed to:
35 * </p>
36 * <ul>
37 * <li>build the frames tree consistently,</li>
38 * <li>avoid rebuilding some frames that may be costly to recreate all the time,</li>
39 * <li>set up interpolation/caching features for some frames that may induce costly computation</li>
40 * <li>streamline the {@link EOPHistory Earth Orientation Parameters} history loading.</li>
41 * </ul>
42 * <h2> Reference Frames </h2>
43 * <p>
44 * The user can retrieve those reference frames using various static methods, the most
45 * important ones being: {@link #getFrame(Predefined)}, {@link #getGCRF()},
46 * {@link #getCIRF(IERSConventions, boolean)} {@link #getTIRF(IERSConventions, boolean)},
47 * {@link #getITRF(IERSConventions, boolean)}, {@link #getITRF(ITRFVersion, IERSConventions, boolean)},
48 * {@link #getEME2000()}, {@link #getMOD(IERSConventions)}, {@link #getTOD(IERSConventions, boolean)},
49 * {@link #getGTOD(IERSConventions, boolean)}, {@link #getITRFEquinox(IERSConventions, boolean)},
50 * {@link #getTEME()} and {@link #getVeis1950()}.
51 * </p>
52 * <h2> International Terrestrial Reference Frame</h2>
53 * <p>
54 * This frame is the current (as of 2013) reference realization of
55 * the International Terrestrial Reference System produced by IERS.
56 * It is described in <a href="ftp://tai.bipm.org/iers/conv2010/tn36.pdf">
57 * IERS conventions (2010)</a>. It replaces the Earth Centered Earth Fixed
58 * frame which is the reference frame for GPS satellites.
59 * </p>
60 * <p>
61 * This frame is used to define position on solid Earth. It rotates with
62 * the Earth and includes the pole motion with respect to Earth crust as
63 * provided by IERS {@link EOPHistory Earth Orientation Parameters}.
64 * Its pole axis is the IERS Reference Pole (IRP).
65 * </p>
66 * <p>
67 * Depending on the {@link EOPHistory Earth Orientation Parameters} source,
68 * different ITRS realization may be returned by {@link #getITRF(IERSConventions, boolean)},
69 * and if EOP are mixed, the ITRF may even jump from one realization to another one.
70 * This is not a problem for most users as different ITRS realizations are very close
71 * to each other (a few millimeters at Earth surface). If however a specific ITRF version
72 * (i.e. an ITRS realization) is needed for very high accuracy, Orekit provides the
73 * {@link FramesFactory#getITRF(ITRFVersion, IERSConventions, boolean)} method
74 * to get it and take care of jumps in EOP.
75 * </p>
76 * <p>
77 * ITRF can be built using the new non-rotating origin paradigm
78 * mandated by IAU 2000 resolution B1.8 and any supported {@link IERSConventions
79 * IERS conventions} (even IERS 1996 can be used with non-rotating origin paradigm,
80 * despite the resolution was not yet adopted at conventions publication time).
81 * </p>
82 * <p>
83 * ITRF can also be built using the classical equinox paradigm used prior to IAU 2000
84 * resolution B1.8 and any supported {@link IERSConventions IERS conventions} (even
85 * IERS 2003 and 2010 can be used with equinox paradigm, despite the resolution is
86 * in effect now). The choice of paradigm (non-rotating origin or equinox) and the
87 * choice of IERS conventions (i.e. the choice of precession/nutation models) can
88 * be made independently by user, Orekit provides all alternatives.
89 * </p>
90 * <h2>Intermediate frames</h2>
91 * <p>
92 * Orekit also provides all the intermediate frames that are needed to transform
93 * between GCRF and ITRF, along the two paths: ITRF/TIRF/CIRF/GCRF for the
94 * non-rotating origin paradigm and ITRF/GTOD/TOD/MOD/EME2000/GCRF for the equinox
95 * paradigm.
96 * </p>
97 * <h2> Earth Orientation Parameters </h2>
98 * <p>
99 * This factory also handles loading of Earth Orientation Parameters (EOP) needed
100 * for accurate transformations between inertial and Earth fixed frames, using
101 * {@link org.orekit.data.DataProvidersManager} features. EOP are IERS conventions
102 * dependent, because they correspond to correction to the precession/nutation
103 * models. When EOP should be applied, but EOP data are not available, then a null
104 * (0.0) correction is used. This can occur when no EOP data is loaded, or when the
105 * requested date is beyond the time span of the loaded EOP data. Using a null
106 * correction can result in coarse accuracy. To check the time span covered by EOP data use
107 * {@link #getEOPHistory(IERSConventions, boolean)}, {@link EOPHistory#getStartDate()},
108 * and {@link EOPHistory#getEndDate()}.
109 * <p>
110 * For more information on configuring the EOP data Orekit uses see
111 * <a href="https://gitlab.orekit.org/orekit/orekit/blob/master/src/site/markdown/configuration.md">
112 * https://gitlab.orekit.org/orekit/orekit/blob/master/src/site/markdown/configuration.md</a>.
113 * <p>
114 * Here is a schematic representation of the predefined reference frames tree:
115 * </p>
116 * <pre>
117 * GCRF
118 * |
119 * |-----------------------------------------------
120 * | | Frame bias |
121 * | | EME2000
122 * | | |
123 * | | Precession effects |
124 * | | |
125 * Bias, Precession and Nutation effects | MOD MOD (Mean Equator Of Date)
126 * | | w/o EOP corrections
127 * | | Nutation effects |
128 * (Celestial Intermediate Reference Frame) CIRF | |
129 * | TOD TOD (True Equator Of Date)
130 * Earth natural rotation | | w/o EOP corrections
131 * |------------- | Sidereal Time |
132 * | | | |
133 * (Terrestrial Intermediate Reference Frame) TIRF TIRF GTOD GTOD (Greenwich True Of Date)
134 * | w/o tidal effects w/o EOP corrections
135 * Pole motion | | |
136 * | | |-------------
137 * | | | |
138 * (International Terrestrial Reference Frame) ITRF ITRF ITRF VEIS1950
139 * | w/o tidal effects equinox-based
140 * | |
141 * other ITRF other ITRF
142 * w/o tidal effects
143 * </pre>
144 * <p>
145 * This is a utility class, so its constructor is private.
146 * </p>
147 * @author Guylaine Prat
148 * @author Luc Maisonobe
149 * @author Pascal Parraud
150 * @see Frames
151 */
152 public class FramesFactory {
153
154 /* These constants were left here instead of being moved to LazyLoadedFrames because
155 * they are public.
156 */
157
158 /** Default regular expression for the Rapid Data and Prediction EOP columns files (IAU1980 compatibles). */
159 public static final String RAPID_DATA_PREDICTION_COLUMNS_1980_FILENAME = "^finals\\.[^.]*$";
160
161 /** Default regular expression for the Rapid Data and Prediction EOP XML files (IAU1980 compatibles). */
162 public static final String RAPID_DATA_PREDICTION_XML_1980_FILENAME = "^finals\\..*\\.xml$";
163
164 /** Default regular expression for the EOPC04 files (IAU1980 compatibles). */
165 public static final String EOPC04_1980_FILENAME = "^eopc04_\\d\\d\\.(\\d\\d)$";
166
167 /** Default regular expression for the BulletinB files (IAU1980 compatibles). */
168 public static final String BULLETINB_1980_FILENAME = "^bulletinb(_IAU1980)?((-\\d\\d\\d\\.txt)|(\\.\\d\\d\\d))$";
169
170 /** Default regular expression for the Rapid Data and Prediction EOP columns files (IAU2000 compatibles). */
171 public static final String RAPID_DATA_PREDICITON_COLUMNS_2000_FILENAME = "^finals2000A\\.[^.]*$";
172
173 /** Default regular expression for the Rapid Data and Prediction EOP XML files (IAU2000 compatibles). */
174 public static final String RAPID_DATA_PREDICITON_XML_2000_FILENAME = "^finals2000A\\..*\\.xml$";
175
176 /** Default regular expression for the EOPC04 files (IAU2000 compatibles). */
177 public static final String EOPC04_2000_FILENAME = "^eopc04_\\d\\d_IAU2000\\.(\\d\\d)$";
178
179 /** Default regular expression for the BulletinB files (IAU2000 compatibles). */
180 public static final String BULLETINB_2000_FILENAME = "^bulletinb(_IAU2000)?((-\\d\\d\\d\\.txt)|(\\.\\d\\d\\d))$";
181
182 /** Default regular expression for the BulletinA files (IAU1980 and IAU2000 compatibles). */
183 public static final String BULLETINA_FILENAME = "^bulletina-[ivxlcdm]+-\\d\\d\\d\\.txt$";
184
185 /** Private constructor.
186 * <p>This class is a utility class, it should neither have a public
187 * nor a default constructor. This private constructor prevents
188 * the compiler from generating one automatically.</p>
189 */
190 private FramesFactory() {
191 }
192
193 /**
194 * Get the instance of {@link Frames} that is called by the static methods in this
195 * class.
196 *
197 * @return the reference frames used by this factory.
198 */
199 @DefaultDataContext
200 public static LazyLoadedFrames getFrames() {
201 return DataContext.getDefault().getFrames();
202 }
203
204 /** Add the default loaders EOP history (IAU 1980 precession/nutation).
205 * <p>
206 * The default loaders look for IERS EOP C04 and bulletins B files. They
207 * correspond to {@link IERSConventions#IERS_1996 IERS 1996} conventions.
208 * </p>
209 * @param rapidDataColumnsSupportedNames regular expression for supported
210 * rapid data columns EOP files names
211 * (may be null if the default IERS file names are used)
212 * @param rapidDataXMLSupportedNames regular expression for supported
213 * rapid data XML EOP files names
214 * (may be null if the default IERS file names are used)
215 * @param eopC04SupportedNames regular expression for supported EOP C04 files names
216 * (may be null if the default IERS file names are used)
217 * @param bulletinBSupportedNames regular expression for supported bulletin B files names
218 * (may be null if the default IERS file names are used)
219 * @param bulletinASupportedNames regular expression for supported bulletin A files names
220 * (may be null if the default IERS file names are used)
221 * @see <a href="http://hpiers.obspm.fr/eoppc/eop/eopc04/">IERS EOP C04 files</a>
222 * @see #addEOPHistoryLoader(IERSConventions, EOPHistoryLoader)
223 * @see #clearEOPHistoryLoaders()
224 * @see #addDefaultEOP2000HistoryLoaders(String, String, String, String, String)
225 */
226 @DefaultDataContext
227 public static void addDefaultEOP1980HistoryLoaders(final String rapidDataColumnsSupportedNames,
228 final String rapidDataXMLSupportedNames,
229 final String eopC04SupportedNames,
230 final String bulletinBSupportedNames,
231 final String bulletinASupportedNames) {
232 getFrames().addDefaultEOP1980HistoryLoaders(
233 rapidDataColumnsSupportedNames,
234 rapidDataXMLSupportedNames,
235 eopC04SupportedNames,
236 bulletinBSupportedNames,
237 bulletinASupportedNames);
238 }
239
240 /** Add the default loaders for EOP history (IAU 2000/2006 precession/nutation).
241 * <p>
242 * The default loaders look for IERS EOP C04 and bulletins B files. They
243 * correspond to both {@link IERSConventions#IERS_2003 IERS 2003} and {@link
244 * IERSConventions#IERS_2010 IERS 2010} conventions.
245 * </p>
246 * @param rapidDataColumnsSupportedNames regular expression for supported
247 * rapid data columns EOP files names
248 * (may be null if the default IERS file names are used)
249 * @param rapidDataXMLSupportedNames regular expression for supported
250 * rapid data XML EOP files names
251 * (may be null if the default IERS file names are used)
252 * @param eopC04SupportedNames regular expression for supported EOP C04 files names
253 * (may be null if the default IERS file names are used)
254 * @param bulletinBSupportedNames regular expression for supported bulletin B files names
255 * (may be null if the default IERS file names are used)
256 * @param bulletinASupportedNames regular expression for supported bulletin A files names
257 * (may be null if the default IERS file names are used)
258 * @see <a href="http://hpiers.obspm.fr/eoppc/eop/eopc04/">IERS EOP C04 files</a>
259 * @see #addEOPHistoryLoader(IERSConventions, EOPHistoryLoader)
260 * @see #clearEOPHistoryLoaders()
261 * @see #addDefaultEOP1980HistoryLoaders(String, String, String, String, String)
262 */
263 @DefaultDataContext
264 public static void addDefaultEOP2000HistoryLoaders(final String rapidDataColumnsSupportedNames,
265 final String rapidDataXMLSupportedNames,
266 final String eopC04SupportedNames,
267 final String bulletinBSupportedNames,
268 final String bulletinASupportedNames) {
269 getFrames().addDefaultEOP2000HistoryLoaders(
270 rapidDataColumnsSupportedNames,
271 rapidDataXMLSupportedNames,
272 eopC04SupportedNames,
273 bulletinBSupportedNames,
274 bulletinASupportedNames);
275 }
276
277 /** Add a loader for Earth Orientation Parameters history.
278 * @param conventions IERS conventions to which EOP history applies
279 * @param loader custom loader to add for the EOP history
280 * @see #addDefaultEOP1980HistoryLoaders(String, String, String, String, String)
281 * @see #clearEOPHistoryLoaders()
282 */
283 @DefaultDataContext
284 public static void addEOPHistoryLoader(final IERSConventions conventions, final EOPHistoryLoader loader) {
285 getFrames().addEOPHistoryLoader(conventions, loader);
286 }
287
288 /** Clear loaders for Earth Orientation Parameters history.
289 * @see #addEOPHistoryLoader(IERSConventions, EOPHistoryLoader)
290 * @see #addDefaultEOP1980HistoryLoaders(String, String, String, String, String)
291 */
292 @DefaultDataContext
293 public static void clearEOPHistoryLoaders() {
294 getFrames().clearEOPHistoryLoaders();
295 }
296
297 /** Set the threshold to check EOP continuity.
298 * <p>
299 * The default threshold (used if this method is never called)
300 * is 5 Julian days. If after loading EOP entries some holes
301 * between entries exceed this threshold, an exception will
302 * be triggered.
303 * </p>
304 * <p>
305 * One case when calling this method is really useful is for
306 * applications that use a single Bulletin A, as these bulletins
307 * have a roughly one month wide hole for the first bulletin of
308 * each month, which contains older final data in addition to the
309 * rapid data and the predicted data.
310 * </p>
311 * @param threshold threshold to use for checking EOP continuity (in seconds)
312 */
313 @DefaultDataContext
314 public static void setEOPContinuityThreshold(final double threshold) {
315 getFrames().setEOPContinuityThreshold(threshold);
316 }
317
318 /** Get Earth Orientation Parameters history.
319 * <p>
320 * If no {@link EOPHistoryLoader} has been added by calling {@link
321 * #addEOPHistoryLoader(IERSConventions, EOPHistoryLoader) addEOPHistoryLoader}
322 * or if {@link #clearEOPHistoryLoaders() clearEOPHistoryLoaders} has been
323 * called afterwards, the {@link #addDefaultEOP1980HistoryLoaders(String, String,
324 * String, String, String)} and {@link #addDefaultEOP2000HistoryLoaders(String,
325 * String, String, String, String)} methods will be called automatically with
326 * supported file names parameters all set to null, in order to get the default
327 * loaders configuration.
328 * </p>
329 * @param conventions conventions for which EOP history is requested
330 * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
331 * @return Earth Orientation Parameters history
332 */
333 @DefaultDataContext
334 public static EOPHistory getEOPHistory(final IERSConventions conventions, final boolean simpleEOP) {
335 return getFrames().getEOPHistory(conventions, simpleEOP);
336 }
337
338 /** Get one of the predefined frames.
339 * @param factoryKey key of the frame within the factory
340 * @return the predefined frame
341 */
342 @DefaultDataContext
343 public static Frame getFrame(final Predefined factoryKey) {
344 return getFrames().getFrame(factoryKey);
345 }
346
347 /** Get the unique GCRF frame.
348 * <p>The GCRF frame is the root frame in the frame tree.</p>
349 * @return the unique instance of the GCRF frame
350 */
351 @DefaultDataContext
352 public static Frame getGCRF() {
353 return getFrames().getGCRF();
354 }
355
356 /** Get the unique ICRF frame.
357 * <p>The ICRF frame is centered at solar system barycenter and aligned
358 * with GCRF.</p>
359 * @return the unique instance of the ICRF frame
360 */
361 @DefaultDataContext
362 public static Frame getICRF() {
363 return getFrames().getICRF();
364 }
365
366 /** Get the ecliptic frame.
367 * The IAU defines the ecliptic as "the plane perpendicular to the mean heliocentric
368 * orbital angular momentum vector of the Earth-Moon barycentre in the BCRS (IAU 2006
369 * Resolution B1)." The +z axis is aligned with the angular momentum vector, and the +x
370 * axis is aligned with +x axis of {@link FramesFactory#getMOD(IERSConventions) MOD}.
371 *
372 * <p> This implementation agrees with the JPL 406 ephemerides to within 0.5 arc seconds.
373 * @param conventions IERS conventions to apply
374 * @return the selected reference frame singleton.
375 */
376 @DefaultDataContext
377 public static Frame getEcliptic(final IERSConventions conventions) {
378 return getFrames().getEcliptic(conventions);
379 }
380
381 /** Get the unique EME2000 frame.
382 * <p>The EME2000 frame is also called the J2000 frame.
383 * The former denomination is preferred in Orekit.</p>
384 * @return the unique instance of the EME2000 frame
385 */
386 @DefaultDataContext
387 public static FactoryManagedFrame getEME2000() {
388 return getFrames().getEME2000();
389 }
390
391 /** Get an unspecified International Terrestrial Reference Frame.
392 * <p>
393 * The frame returned uses the {@link EOPEntry Earth Orientation Parameters}
394 * blindly. So if for example one loads only EOP 14 C04 files to retrieve
395 * the parameters, the frame will be an {@link ITRFVersion#ITRF_2014}. However,
396 * if parameters are loaded from different files types, or even for file
397 * types that changed their reference (like Bulletin A switching from
398 * {@link ITRFVersion#ITRF_2008} to {@link ITRFVersion#ITRF_2014} starting
399 * with Vol. XXXI No. 013 published on 2018-03-29), then the ITRF returned
400 * by this method will jump from one version to another version.
401 * </p>
402 * <p>
403 * IF a specific version of ITRF is needed, then {@link #getITRF(ITRFVersion,
404 * IERSConventions, boolean)} should be used instead.
405 * </p>
406 * @param conventions IERS conventions to apply
407 * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
408 * @return the selected reference frame singleton.
409 * @see #getITRF(ITRFVersion, IERSConventions, boolean)
410 * @since 6.1
411 */
412 @DefaultDataContext
413 public static FactoryManagedFrame getITRF(final IERSConventions conventions,
414 final boolean simpleEOP) {
415 return getFrames().getITRF(conventions, simpleEOP);
416 }
417
418 /** Get the TIRF reference frame, ignoring tidal effects.
419 * @param conventions IERS conventions to apply
420 * @return the selected reference frame singleton.
421 * library cannot be read.
422 */
423 @DefaultDataContext
424 public static FactoryManagedFrame getTIRF(final IERSConventions conventions) {
425 return getFrames().getTIRF(conventions);
426 }
427
428 /** Get an specific International Terrestrial Reference Frame.
429 * <p>
430 * Note that if a specific version of ITRF is required, then {@code simpleEOP}
431 * should most probably be set to {@code false}, as ignoring tidal effects
432 * has an effect of the same order of magnitude as the differences between
433 * the various {@link ITRFVersion ITRF versions}.
434 * </p>
435 * @param version ITRF version
436 * @param conventions IERS conventions to apply
437 * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
438 * @return the selected reference frame singleton.
439 * @since 9.2
440 */
441 @DefaultDataContext
442 public static VersionedITRF getITRF(final ITRFVersion version,
443 final IERSConventions conventions,
444 final boolean simpleEOP) {
445 return getFrames().getITRF(version, conventions, simpleEOP);
446 }
447
448 /** Get the TIRF reference frame.
449 * @param conventions IERS conventions to apply
450 * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
451 * @return the selected reference frame singleton.
452 * @since 6.1
453 */
454 @DefaultDataContext
455 public static FactoryManagedFrame getTIRF(final IERSConventions conventions,
456 final boolean simpleEOP) {
457 return getFrames().getTIRF(conventions, simpleEOP);
458 }
459
460 /** Get the CIRF2000 reference frame.
461 * @param conventions IERS conventions to apply
462 * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
463 * @return the selected reference frame singleton.
464 */
465 @DefaultDataContext
466 public static FactoryManagedFrame getCIRF(final IERSConventions conventions,
467 final boolean simpleEOP) {
468 return getFrames().getCIRF(conventions, simpleEOP);
469 }
470
471 /** Get the VEIS 1950 reference frame.
472 * <p>Its parent frame is the GTOD frame with IERS 1996 conventions without EOP corrections.<p>
473 * @return the selected reference frame singleton.
474 */
475 @DefaultDataContext
476 public static FactoryManagedFrame getVeis1950() {
477 return getFrames().getVeis1950();
478 }
479
480 /** Get the equinox-based ITRF reference frame.
481 * @param conventions IERS conventions to apply
482 * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
483 * @return the selected reference frame singleton.
484 * @since 6.1
485 */
486 @DefaultDataContext
487 public static FactoryManagedFrame getITRFEquinox(final IERSConventions conventions,
488 final boolean simpleEOP) {
489 return getFrames().getITRFEquinox(conventions, simpleEOP);
490 }
491
492 /** Get the GTOD reference frame.
493 * <p>
494 * The applyEOPCorr parameter is available mainly for testing purposes or for
495 * consistency with legacy software that don't handle EOP correction parameters.
496 * Beware that setting this parameter to {@code false} leads to crude accuracy
497 * (order of magnitudes for errors might be above 250m in LEO and 1400m in GEO).
498 * For this reason, setting this parameter to false is restricted to {@link
499 * IERSConventions#IERS_1996 IERS 1996} conventions, and hence the {@link
500 * IERSConventions IERS conventions} cannot be freely chosen here.
501 * </p>
502 * @param applyEOPCorr if true, EOP corrections are applied (here, dut1 and lod)
503 * @return the selected reference frame singleton.
504 */
505 @DefaultDataContext
506 public static FactoryManagedFrame getGTOD(final boolean applyEOPCorr) {
507 return getFrames().getGTOD(applyEOPCorr);
508 }
509
510 /** Get the GTOD reference frame.
511 * @param conventions IERS conventions to apply
512 * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
513 * @return the selected reference frame singleton.
514 */
515 @DefaultDataContext
516 public static FactoryManagedFrame getGTOD(final IERSConventions conventions,
517 final boolean simpleEOP) {
518 return getFrames().getGTOD(conventions, simpleEOP);
519 }
520
521 /** Get the TOD reference frame.
522 * <p>
523 * The applyEOPCorr parameter is available mainly for testing purposes or for
524 * consistency with legacy software that don't handle EOP correction parameters.
525 * Beware that setting this parameter to {@code false} leads to crude accuracy
526 * (order of magnitudes for errors might be above 1m in LEO and 10m in GEO).
527 * For this reason, setting this parameter to false is restricted to {@link
528 * IERSConventions#IERS_1996 IERS 1996} conventions, and hence the {@link
529 * IERSConventions IERS conventions} cannot be freely chosen here.
530 * </p>
531 * @param applyEOPCorr if true, EOP corrections are applied (here, nutation)
532 * @return the selected reference frame singleton.
533 */
534 @DefaultDataContext
535 public static FactoryManagedFrame getTOD(final boolean applyEOPCorr) {
536 return getFrames().getTOD(applyEOPCorr);
537 }
538
539 /** Get the TOD reference frame.
540 * @param conventions IERS conventions to apply
541 * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
542 * @return the selected reference frame singleton.
543 */
544 @DefaultDataContext
545 public static FactoryManagedFrame getTOD(final IERSConventions conventions,
546 final boolean simpleEOP) {
547 return getFrames().getTOD(conventions, simpleEOP);
548 }
549
550 /** Get the MOD reference frame.
551 * <p>
552 * The applyEOPCorr parameter is available mainly for testing purposes or for
553 * consistency with legacy software that don't handle EOP correction parameters.
554 * Beware that setting this parameter to {@code false} leads to crude accuracy
555 * (order of magnitudes for errors might be above 1m in LEO and 10m in GEO).
556 * For this reason, setting this parameter to false is restricted to {@link
557 * IERSConventions#IERS_1996 IERS 1996} conventions, and hence the {@link
558 * IERSConventions IERS conventions} cannot be freely chosen here.
559 * </p>
560 * @param applyEOPCorr if true, EOP corrections are applied (EME2000/GCRF bias compensation)
561 * @return the selected reference frame singleton.
562 */
563 @DefaultDataContext
564 public static FactoryManagedFrame getMOD(final boolean applyEOPCorr) {
565 return getFrames().getMOD(applyEOPCorr);
566 }
567
568 /** Get the MOD reference frame.
569 * @param conventions IERS conventions to apply
570 * @return the selected reference frame singleton.
571 */
572 @DefaultDataContext
573 public static FactoryManagedFrame getMOD(final IERSConventions conventions) {
574 return getFrames().getMOD(conventions);
575 }
576
577 /** Get the TEME reference frame.
578 * <p>
579 * The TEME frame is used for the SGP4 model in TLE propagation. This frame has <em>no</em>
580 * official definition and there are some ambiguities about whether it should be used
581 * as "of date" or "of epoch". This frame should therefore be used <em>only</em> for
582 * TLE propagation and not for anything else, as recommended by the CCSDS Orbit Data Message
583 * blue book.
584 * </p>
585 * @return the selected reference frame singleton.
586 */
587 @DefaultDataContext
588 public static FactoryManagedFrame getTEME() {
589 return getFrames().getTEME();
590 }
591
592 /** Get the PZ-90.11 (Parametry Zemly – 1990.11) reference frame.
593 * <p>
594 * The PZ-90.11 reference system was updated on all operational
595 * GLONASS satellites starting from 3:00 pm on December 31, 2013.
596 * </p>
597 * <p>
598 * The transition between parent frame (ITRF-2008) and PZ-90.11 frame is performed using
599 * a seven parameters Helmert transformation.
600 * <pre>
601 * From To ΔX(m) ΔY(m) ΔZ(m) RX(mas) RY(mas) RZ(mas) Epoch
602 * ITRF-2008 PZ-90.11 +0.003 +0.001 -0.000 +0.019 -0.042 +0.002 2010
603 * </pre>
604 * @see "Springer Handbook of Global Navigation Satellite Systems, Peter Teunissen & Oliver Montenbruck"
605 *
606 * @param convention IERS conventions to apply
607 * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
608 * @return the selected reference frame singleton.
609 */
610 @DefaultDataContext
611 public static FactoryManagedFrame getPZ9011(final IERSConventions convention,
612 final boolean simpleEOP) {
613 return getFrames().getPZ9011(convention, simpleEOP);
614 }
615
616 /** Get the transform between two frames, suppressing all interpolation.
617 * <p>
618 * This method is similar to {@link Frame#getTransformTo(Frame, AbsoluteDate)}
619 * except it removes the performance enhancing interpolation features that are
620 * added by the {@link FramesFactory factory} to some frames, in order to focus
621 * on accuracy. The interpolation features are intended to save processing time
622 * by avoiding doing some lengthy computation like nutation evaluation at each
623 * time step and caching some results. This method can be used to avoid this,
624 * when very high accuracy is desired, or for testing purposes. It should be
625 * used with care, as doing the full computation is <em>really</em> costly for
626 * some frames.
627 * </p>
628 * @param from frame from which transformation starts
629 * @param to frame to which transformation ends
630 * @param date date of the transform
631 * @return transform between the two frames, avoiding interpolation
632 */
633 public static Transform getNonInterpolatingTransform(final Frame from, final Frame to,
634 final AbsoluteDate date) {
635
636 // common ancestor to both frames in the frames tree
637 Frame currentF = from.getDepth() > to.getDepth() ? from.getAncestor(from.getDepth() - to.getDepth()) : from;
638 Frame currentT = from.getDepth() > to.getDepth() ? to : to.getAncestor(to.getDepth() - from.getDepth());
639 while (currentF != currentT) {
640 currentF = currentF.getParent();
641 currentT = currentT.getParent();
642 }
643 final Frame common = currentF;
644
645 // transform from common to origin
646 Transform commonToOrigin = Transform.IDENTITY;
647 for (Frame frame = from; frame != common; frame = frame.getParent()) {
648 commonToOrigin = new Transform(date,
649 peel(frame.getTransformProvider()).getTransform(date),
650 commonToOrigin);
651 }
652
653 // transform from destination up to common
654 Transform commonToDestination = Transform.IDENTITY;
655 for (Frame frame = to; frame != common; frame = frame.getParent()) {
656 commonToDestination = new Transform(date,
657 peel(frame.getTransformProvider()).getTransform(date),
658 commonToDestination);
659 }
660
661 // transform from origin to destination via common
662 return new Transform(date, commonToOrigin.getInverse(), commonToDestination);
663
664 }
665
666 /* The methods below are static helper methods for Frame and TransformProvider. */
667
668 /** Get the transform between two frames, suppressing all interpolation.
669 * <p>
670 * This method is similar to {@link Frame#getTransformTo(Frame, AbsoluteDate)}
671 * except it removes the performance enhancing interpolation features that are
672 * added by the {@link FramesFactory factory} to some frames, in order to focus
673 * on accuracy. The interpolation features are intended to save processing time
674 * by avoiding doing some lengthy computation like nutation evaluation at each
675 * time step and caching some results. This method can be used to avoid this,
676 * when very high accuracy is desired, or for testing purposes. It should be
677 * used with care, as doing the full computation is <em>really</em> costly for
678 * some frames.
679 * </p>
680 * @param from frame from which transformation starts
681 * @param to frame to which transformation ends
682 * @param date date of the transform
683 * @param <T> type of the field elements
684 * @return transform between the two frames, avoiding interpolation
685 * @since 9.0
686 */
687 public static <T extends CalculusFieldElement<T>> FieldTransform<T> getNonInterpolatingTransform(final Frame from, final Frame to,
688 final FieldAbsoluteDate<T> date) {
689
690 // common ancestor to both frames in the frames tree
691 Frame currentF = from.getDepth() > to.getDepth() ? from.getAncestor(from.getDepth() - to.getDepth()) : from;
692 Frame currentT = from.getDepth() > to.getDepth() ? to : to.getAncestor(to.getDepth() - from.getDepth());
693 while (currentF != currentT) {
694 currentF = currentF.getParent();
695 currentT = currentT.getParent();
696 }
697 final Frame common = currentF;
698
699 // transform from common to origin
700 FieldTransform<T> commonToOrigin = FieldTransform.getIdentity(date.getField());
701 for (Frame frame = from; frame != common; frame = frame.getParent()) {
702 commonToOrigin = new FieldTransform<>(date,
703 peel(frame.getTransformProvider()).getTransform(date),
704 commonToOrigin);
705 }
706
707 // transform from destination up to common
708 FieldTransform<T> commonToDestination = FieldTransform.getIdentity(date.getField());
709 for (Frame frame = to; frame != common; frame = frame.getParent()) {
710 commonToDestination = new FieldTransform<>(date,
711 peel(frame.getTransformProvider()).getTransform(date),
712 commonToDestination);
713 }
714
715 // transform from origin to destination via common
716 return new FieldTransform<>(date, commonToOrigin.getInverse(), commonToDestination);
717
718 }
719
720 /** Retrieve EOP from a frame hierarchy.
721 * <p>
722 * The frame hierarchy tree is walked from specified frame up to root
723 * traversing parent frames, and the providers are checked to see if they
724 * reference EOP history. The first EOP history found is returned.
725 * </p>
726 * @param start frame from which to start search, will typically be some
727 * Earth related frame, like a topocentric frame or an ITRF frame
728 * @return EOP history found while walking the frames tree, or null if
729 * no EOP history is found
730 * @since 9.1
731 */
732 public static EOPHistory findEOP(final Frame start) {
733
734 for (Frame frame = start; frame != null; frame = frame.getParent()) {
735
736 TransformProvider peeled = frame.getTransformProvider();
737
738 boolean peeling = true;
739 while (peeling) {
740 if (peeled instanceof InterpolatingTransformProvider) {
741 peeled = ((InterpolatingTransformProvider) peeled).getRawProvider();
742 } else if (peeled instanceof ShiftingTransformProvider) {
743 peeled = ((ShiftingTransformProvider) peeled).getRawProvider();
744 } else if (peeled instanceof EOPBasedTransformProvider &&
745 ((EOPBasedTransformProvider) peeled).getEOPHistory() != null) {
746 return ((EOPBasedTransformProvider) peeled).getEOPHistory();
747 } else {
748 peeling = false;
749 }
750 }
751
752 }
753
754 // no history found
755 return null;
756
757 }
758
759 /** Peel interpolation and shifting from a transform provider.
760 * @param provider transform provider to peel
761 * @return peeled transform provider
762 */
763 private static TransformProvider peel(final TransformProvider provider) {
764
765 TransformProvider peeled = provider;
766
767 boolean peeling = true;
768 while (peeling) {
769 if (peeled instanceof InterpolatingTransformProvider) {
770 peeled = ((InterpolatingTransformProvider) peeled).getRawProvider();
771 } else if (peeled instanceof ShiftingTransformProvider) {
772 peeled = ((ShiftingTransformProvider) peeled).getRawProvider();
773 } else if (peeled instanceof EOPBasedTransformProvider &&
774 ((EOPBasedTransformProvider) peeled).getEOPHistory() != null &&
775 ((EOPBasedTransformProvider) peeled).getEOPHistory().usesInterpolation()) {
776 peeled = ((EOPBasedTransformProvider) peeled).getNonInterpolatingProvider();
777 } else {
778 peeling = false;
779 }
780 }
781
782 return peeled;
783
784 }
785
786 }