FramesFactory.java

  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.frames;

  18. import org.hipparchus.CalculusFieldElement;
  19. import org.orekit.annotation.DefaultDataContext;
  20. import org.orekit.data.DataContext;
  21. import org.orekit.time.AbsoluteDate;
  22. import org.orekit.time.FieldAbsoluteDate;
  23. import org.orekit.utils.IERSConventions;


  24. /** Factory for predefined reference frames.
  25.  *
  26.  * <h2> FramesFactory Presentation </h2>
  27.  * <p>
  28.  * Several predefined reference {@link Frame frames} are implemented in OREKIT.
  29.  * They are linked together in a tree with the <i>Geocentric
  30.  * Celestial Reference Frame</i> (GCRF) as the root of the tree.
  31.  * This factory is designed to:
  32.  * </p>
  33.  * <ul>
  34.  *   <li>build the frames tree consistently,</li>
  35.  *   <li>avoid rebuilding some frames that may be costly to recreate all the time,</li>
  36.  *   <li>set up interpolation/caching features for some frames that may induce costly computation</li>
  37.  *   <li>streamline the {@link EOPHistory Earth Orientation Parameters} history loading.</li>
  38.  * </ul>
  39.  * <h2> Reference Frames </h2>
  40.  * <p>
  41.  * The user can retrieve those reference frames using various static methods, the most
  42.  * important ones being: {@link #getFrame(Predefined)}, {@link #getGCRF()},
  43.  * {@link #getCIRF(IERSConventions, boolean)} {@link #getTIRF(IERSConventions, boolean)},
  44.  * {@link #getITRF(IERSConventions, boolean)}, {@link #getITRF(ITRFVersion, IERSConventions, boolean)},
  45.  * {@link #getEME2000()}, {@link #getMOD(IERSConventions)}, {@link #getTOD(IERSConventions, boolean)},
  46.  * {@link #getGTOD(IERSConventions, boolean)}, {@link #getITRFEquinox(IERSConventions, boolean)},
  47.  * {@link #getTEME()} and {@link #getVeis1950()}.
  48.  * </p>
  49.  * <h2> International Terrestrial Reference Frame</h2>
  50.  * <p>
  51.  * This frame is the current (as of 2013) reference realization of
  52.  * the International Terrestrial Reference System produced by IERS.
  53.  * It is described in <a href="ftp://tai.bipm.org/iers/conv2010/tn36.pdf">
  54.  * IERS conventions (2010)</a>. It replaces the Earth Centered Earth Fixed
  55.  * frame which is the reference frame for GPS satellites.
  56.  * </p>
  57.  * <p>
  58.  * This frame is used to define position on solid Earth. It rotates with
  59.  * the Earth and includes the pole motion with respect to Earth crust as
  60.  * provided by IERS {@link EOPHistory Earth Orientation Parameters}.
  61.  * Its pole axis is the IERS Reference Pole (IRP).
  62.  * </p>
  63.  * <p>
  64.  * Depending on the  {@link EOPHistory Earth Orientation Parameters} source,
  65.  * different ITRS realization may be returned by {@link #getITRF(IERSConventions, boolean)},
  66.  * and if EOP are mixed, the ITRF may even jump from one realization to another one.
  67.  * This is not a problem for most users as different ITRS realizations are very close
  68.  * to each other (a few millimeters at Earth surface). If however a specific ITRF version
  69.  * (i.e. an ITRS realization) is needed for very high accuracy, Orekit provides the
  70.  * {@link FramesFactory#getITRF(ITRFVersion, IERSConventions, boolean)} method
  71.  * to get it and take care of jumps in EOP.
  72.  * </p>
  73.  * <p>
  74.  * ITRF can be built using the new non-rotating origin paradigm
  75.  * mandated by IAU 2000 resolution B1.8 and any supported {@link IERSConventions
  76.  * IERS conventions} (even IERS 1996 can be used with non-rotating origin paradigm,
  77.  * despite the resolution was not yet adopted at conventions publication time).
  78.  * </p>
  79.  * <p>
  80.  * ITRF can also be built using the classical equinox paradigm used prior to IAU 2000
  81.  * resolution B1.8 and any supported {@link IERSConventions IERS conventions} (even
  82.  * IERS 2003 and 2010 can be used with equinox paradigm, despite the resolution is
  83.  * in effect now). The choice of paradigm (non-rotating origin or equinox) and the
  84.  * choice of IERS conventions (i.e. the choice of precession/nutation models) can
  85.  * be made independently by user, Orekit provides all alternatives.
  86.  * </p>
  87.  * <h2>Intermediate frames</h2>
  88.  * <p>
  89.  * Orekit also provides all the intermediate frames that are needed to transform
  90.  * between GCRF and ITRF, along the two paths: ITRF/TIRF/CIRF/GCRF for the
  91.  * non-rotating origin paradigm and ITRF/GTOD/TOD/MOD/EME2000/GCRF for the equinox
  92.  * paradigm.
  93.  * </p>
  94.  * <h2> Earth Orientation Parameters </h2>
  95.  * <p>
  96.  * This factory also handles loading of Earth Orientation Parameters (EOP) needed
  97.  * for accurate transformations between inertial and Earth fixed frames, using
  98.  * {@link org.orekit.data.DataProvidersManager} features. EOP are IERS conventions
  99.  * dependent, because they correspond to correction to the precession/nutation
  100.  * models. When EOP should be applied, but EOP data are not available, then a null
  101.  * (0.0) correction is used. This can occur when no EOP data is loaded, or when the
  102.  * requested date is beyond the time span of the loaded EOP data. Using a null
  103.  * correction can result in coarse accuracy. To check the time span covered by EOP data use
  104.  * {@link #getEOPHistory(IERSConventions, boolean)}, {@link EOPHistory#getStartDate()},
  105.  * and {@link EOPHistory#getEndDate()}.
  106.  * <p>
  107.  * For more information on configuring the EOP data Orekit uses see
  108.  * <a href="https://gitlab.orekit.org/orekit/orekit/blob/master/src/site/markdown/configuration.md">
  109.  * https://gitlab.orekit.org/orekit/orekit/blob/master/src/site/markdown/configuration.md</a>.
  110.  * <p>
  111.  * Here is a schematic representation of the predefined reference frames tree:
  112.  * </p>
  113.  * <pre>
  114.  *                                                                  GCRF
  115.  *                                                                    |
  116.  *                                                 |-----------------------------------------------
  117.  *                                                 |                         |     Frame bias     |
  118.  *                                                 |                         |                 EME2000
  119.  *                                                 |                         |                    |
  120.  *                                                 |                         | Precession effects |
  121.  *                                                 |                         |                    |
  122.  *           Bias, Precession and Nutation effects |                        MOD                  MOD  (Mean Equator Of Date)
  123.  *                                                 |                         |             w/o EOP corrections
  124.  *                                                 |                         |  Nutation effects  |
  125.  *    (Celestial Intermediate Reference Frame)   CIRF                        |                    |
  126.  *                                                 |                        TOD                  TOD  (True Equator Of Date)
  127.  *                          Earth natural rotation |                         |             w/o EOP corrections
  128.  *                                                 |-------------            |    Sidereal Time   |
  129.  *                                                 |            |            |                    |
  130.  *  (Terrestrial Intermediate Reference Frame)   TIRF         TIRF         GTOD                 GTOD  (Greenwich True Of Date)
  131.  *                                                 |    w/o tidal effects                  w/o EOP corrections
  132.  *                                     Pole motion |            |                                 |
  133.  *                                                 |            |                                 |-------------
  134.  *                                                 |            |                                 |            |
  135.  * (International Terrestrial Reference Frame)   ITRF         ITRF                              ITRF        VEIS1950
  136.  *                                                 |    w/o tidal effects                   equinox-based
  137.  *                                                 |            |
  138.  *                                           other ITRF     other ITRF
  139.  *                                                      w/o tidal effects
  140.  * </pre>
  141.  * <p>
  142.  * This is a utility class, so its constructor is private.
  143.  * </p>
  144.  * @author Guylaine Prat
  145.  * @author Luc Maisonobe
  146.  * @author Pascal Parraud
  147.  * @see Frames
  148.  */
  149. public class FramesFactory {

  150.     /* These constants were left here instead of being moved to LazyLoadedFrames because
  151.      * they are public.
  152.      */

  153.     /** Default regular expression for the Rapid Data and Prediction EOP columns files (IAU1980 compatibles). */
  154.     public static final String RAPID_DATA_PREDICTION_COLUMNS_1980_FILENAME = "^finals\\.[^.]*$";

  155.     /** Default regular expression for the Rapid Data and Prediction EOP XML files (IAU1980 compatibles). */
  156.     public static final String RAPID_DATA_PREDICTION_XML_1980_FILENAME = "^finals\\..*\\.xml$";

  157.     /** Default regular expression for the EOPC04 files (IAU1980 compatibles). */
  158.     public static final String EOPC04_1980_FILENAME = "^eopc04_\\d\\d\\.(\\d\\d)$";

  159.     /** Default regular expression for the BulletinB files (IAU1980 compatibles). */
  160.     public static final String BULLETINB_1980_FILENAME = "^bulletinb(_IAU1980)?((-\\d\\d\\d\\.txt)|(\\.\\d\\d\\d))$";

  161.     /** Default regular expression for the Rapid Data and Prediction EOP columns files (IAU2000 compatibles). */
  162.     public static final String RAPID_DATA_PREDICITON_COLUMNS_2000_FILENAME = "^finals2000A\\.[^.]*$";

  163.     /** Default regular expression for the Rapid Data and Prediction EOP XML files (IAU2000 compatibles). */
  164.     public static final String RAPID_DATA_PREDICITON_XML_2000_FILENAME = "^finals2000A\\..*\\.xml$";

  165.     /** Default regular expression for the EOPC04 files (IAU2000 compatibles). */
  166.     public static final String EOPC04_2000_FILENAME = "^eopc04_\\d\\d_IAU2000\\.(\\d\\d)$";

  167.     /** Default regular expression for the BulletinB files (IAU2000 compatibles). */
  168.     public static final String BULLETINB_2000_FILENAME = "^bulletinb(_IAU2000)?((-\\d\\d\\d\\.txt)|(\\.\\d\\d\\d))$";

  169.     /** Default regular expression for the BulletinA files (IAU1980 and IAU2000 compatibles). */
  170.     public static final String BULLETINA_FILENAME = "^bulletina-[ivxlcdm]+-\\d\\d\\d\\.txt$";

  171.     /** Private constructor.
  172.      * <p>This class is a utility class, it should neither have a public
  173.      * nor a default constructor. This private constructor prevents
  174.      * the compiler from generating one automatically.</p>
  175.      */
  176.     private FramesFactory() {
  177.     }

  178.     /**
  179.      * Get the instance of {@link Frames} that is called by the static methods in this
  180.      * class.
  181.      *
  182.      * @return the reference frames used by this factory.
  183.      */
  184.     @DefaultDataContext
  185.     public static LazyLoadedFrames getFrames() {
  186.         return DataContext.getDefault().getFrames();
  187.     }

  188.     /** Add the default loaders EOP history (IAU 1980 precession/nutation).
  189.      * <p>
  190.      * The default loaders look for IERS EOP C04 and bulletins B files. They
  191.      * correspond to {@link IERSConventions#IERS_1996 IERS 1996} conventions.
  192.      * </p>
  193.      * @param rapidDataColumnsSupportedNames regular expression for supported
  194.      * rapid data columns EOP files names
  195.      * (may be null if the default IERS file names are used)
  196.      * @param rapidDataXMLSupportedNames regular expression for supported
  197.      * rapid data XML EOP files names
  198.      * (may be null if the default IERS file names are used)
  199.      * @param eopC04SupportedNames regular expression for supported EOP C04 files names
  200.      * (may be null if the default IERS file names are used)
  201.      * @param bulletinBSupportedNames regular expression for supported bulletin B files names
  202.      * (may be null if the default IERS file names are used)
  203.      * @param bulletinASupportedNames regular expression for supported bulletin A files names
  204.      * (may be null if the default IERS file names are used)
  205.      * @see <a href="http://hpiers.obspm.fr/eoppc/eop/eopc04/">IERS EOP C04 files</a>
  206.      * @see #addEOPHistoryLoader(IERSConventions, EOPHistoryLoader)
  207.      * @see #clearEOPHistoryLoaders()
  208.      * @see #addDefaultEOP2000HistoryLoaders(String, String, String, String, String)
  209.      */
  210.     @DefaultDataContext
  211.     public static void addDefaultEOP1980HistoryLoaders(final String rapidDataColumnsSupportedNames,
  212.                                                        final String rapidDataXMLSupportedNames,
  213.                                                        final String eopC04SupportedNames,
  214.                                                        final String bulletinBSupportedNames,
  215.                                                        final String bulletinASupportedNames) {
  216.         getFrames().addDefaultEOP1980HistoryLoaders(
  217.                 rapidDataColumnsSupportedNames,
  218.                 rapidDataXMLSupportedNames,
  219.                 eopC04SupportedNames,
  220.                 bulletinBSupportedNames,
  221.                 bulletinASupportedNames);
  222.     }

  223.     /** Add the default loaders for EOP history (IAU 2000/2006 precession/nutation).
  224.      * <p>
  225.      * The default loaders look for IERS EOP C04 and bulletins B files. They
  226.      * correspond to both {@link IERSConventions#IERS_2003 IERS 2003} and {@link
  227.      * IERSConventions#IERS_2010 IERS 2010} conventions.
  228.      * </p>
  229.      * @param rapidDataColumnsSupportedNames regular expression for supported
  230.      * rapid data columns EOP files names
  231.      * (may be null if the default IERS file names are used)
  232.      * @param rapidDataXMLSupportedNames regular expression for supported
  233.      * rapid data XML EOP files names
  234.      * (may be null if the default IERS file names are used)
  235.      * @param eopC04SupportedNames regular expression for supported EOP C04 files names
  236.      * (may be null if the default IERS file names are used)
  237.      * @param bulletinBSupportedNames regular expression for supported bulletin B files names
  238.      * (may be null if the default IERS file names are used)
  239.      * @param bulletinASupportedNames regular expression for supported bulletin A files names
  240.      * (may be null if the default IERS file names are used)
  241.      * @see <a href="http://hpiers.obspm.fr/eoppc/eop/eopc04/">IERS EOP C04 files</a>
  242.      * @see #addEOPHistoryLoader(IERSConventions, EOPHistoryLoader)
  243.      * @see #clearEOPHistoryLoaders()
  244.      * @see #addDefaultEOP1980HistoryLoaders(String, String, String, String, String)
  245.      */
  246.     @DefaultDataContext
  247.     public static void addDefaultEOP2000HistoryLoaders(final String rapidDataColumnsSupportedNames,
  248.                                                        final String rapidDataXMLSupportedNames,
  249.                                                        final String eopC04SupportedNames,
  250.                                                        final String bulletinBSupportedNames,
  251.                                                        final String bulletinASupportedNames) {
  252.         getFrames().addDefaultEOP2000HistoryLoaders(
  253.                 rapidDataColumnsSupportedNames,
  254.                 rapidDataXMLSupportedNames,
  255.                 eopC04SupportedNames,
  256.                 bulletinBSupportedNames,
  257.                 bulletinASupportedNames);
  258.     }

  259.     /** Add a loader for Earth Orientation Parameters history.
  260.      * @param conventions IERS conventions to which EOP history applies
  261.      * @param loader custom loader to add for the EOP history
  262.      * @see #addDefaultEOP1980HistoryLoaders(String, String, String, String, String)
  263.      * @see #clearEOPHistoryLoaders()
  264.      */
  265.     @DefaultDataContext
  266.     public static void addEOPHistoryLoader(final IERSConventions conventions, final EOPHistoryLoader loader) {
  267.         getFrames().addEOPHistoryLoader(conventions, loader);
  268.     }

  269.     /** Clear loaders for Earth Orientation Parameters history.
  270.      * @see #addEOPHistoryLoader(IERSConventions, EOPHistoryLoader)
  271.      * @see #addDefaultEOP1980HistoryLoaders(String, String, String, String, String)
  272.      */
  273.     @DefaultDataContext
  274.     public static void clearEOPHistoryLoaders() {
  275.         getFrames().clearEOPHistoryLoaders();
  276.     }

  277.     /** Set the threshold to check EOP continuity.
  278.      * <p>
  279.      * The default threshold (used if this method is never called)
  280.      * is 5 Julian days. If after loading EOP entries some holes
  281.      * between entries exceed this threshold, an exception will
  282.      * be triggered.
  283.      * </p>
  284.      * <p>
  285.      * One case when calling this method is really useful is for
  286.      * applications that use a single Bulletin A, as these bulletins
  287.      * have a roughly one month wide hole for the first bulletin of
  288.      * each month, which contains older final data in addition to the
  289.      * rapid data and the predicted data.
  290.      * </p>
  291.      * @param threshold threshold to use for checking EOP continuity (in seconds)
  292.      */
  293.     @DefaultDataContext
  294.     public static void setEOPContinuityThreshold(final double threshold) {
  295.         getFrames().setEOPContinuityThreshold(threshold);
  296.     }

  297.     /** Get Earth Orientation Parameters history.
  298.      * <p>
  299.      * If no {@link EOPHistoryLoader} has been added by calling {@link
  300.      * #addEOPHistoryLoader(IERSConventions, EOPHistoryLoader) addEOPHistoryLoader}
  301.      * or if {@link #clearEOPHistoryLoaders() clearEOPHistoryLoaders} has been
  302.      * called afterwards, the {@link #addDefaultEOP1980HistoryLoaders(String, String,
  303.      * String, String, String)} and {@link #addDefaultEOP2000HistoryLoaders(String,
  304.      * String, String, String, String)} methods will be called automatically with
  305.      * supported file names parameters all set to null, in order to get the default
  306.      * loaders configuration.
  307.      * </p>
  308.      * @param conventions conventions for which EOP history is requested
  309.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  310.      * @return Earth Orientation Parameters history
  311.      */
  312.     @DefaultDataContext
  313.     public static EOPHistory getEOPHistory(final IERSConventions conventions, final boolean simpleEOP) {
  314.         return getFrames().getEOPHistory(conventions, simpleEOP);
  315.     }

  316.     /** Get one of the predefined frames.
  317.      * @param factoryKey key of the frame within the factory
  318.      * @return the predefined frame
  319.      */
  320.     @DefaultDataContext
  321.     public static Frame getFrame(final Predefined factoryKey) {
  322.         return getFrames().getFrame(factoryKey);
  323.     }

  324.     /** Get the unique GCRF frame.
  325.      * <p>The GCRF frame is the root frame in the frame tree.</p>
  326.      * @return the unique instance of the GCRF frame
  327.      */
  328.     @DefaultDataContext
  329.     public static Frame getGCRF() {
  330.         return getFrames().getGCRF();
  331.     }

  332.     /** Get the unique ICRF frame.
  333.      * <p>The ICRF frame is centered at solar system barycenter and aligned
  334.      * with GCRF.</p>
  335.      * @return the unique instance of the ICRF frame
  336.      */
  337.     @DefaultDataContext
  338.     public static Frame getICRF() {
  339.         return getFrames().getICRF();
  340.     }

  341.     /** Get the ecliptic frame.
  342.      * The IAU defines the ecliptic as "the plane perpendicular to the mean heliocentric
  343.      * orbital angular momentum vector of the Earth-Moon barycentre in the BCRS (IAU 2006
  344.      * Resolution B1)." The +z axis is aligned with the angular momentum vector, and the +x
  345.      * axis is aligned with +x axis of {@link FramesFactory#getMOD(IERSConventions) MOD}.
  346.      *
  347.      * <p> This implementation agrees with the JPL 406 ephemerides to within 0.5 arc seconds.
  348.      * @param conventions IERS conventions to apply
  349.      * @return the selected reference frame singleton.
  350.      */
  351.     @DefaultDataContext
  352.     public static Frame getEcliptic(final IERSConventions conventions) {
  353.         return getFrames().getEcliptic(conventions);
  354.     }

  355.     /** Get the unique EME2000 frame.
  356.      * <p>The EME2000 frame is also called the J2000 frame.
  357.      * The former denomination is preferred in Orekit.</p>
  358.      * @return the unique instance of the EME2000 frame
  359.      */
  360.     @DefaultDataContext
  361.     public static FactoryManagedFrame getEME2000() {
  362.         return getFrames().getEME2000();
  363.     }

  364.     /** Get an unspecified International Terrestrial Reference Frame.
  365.      * <p>
  366.      * The frame returned uses the {@link EOPEntry Earth Orientation Parameters}
  367.      * blindly. So if for example one loads only EOP 14 C04 files to retrieve
  368.      * the parameters, the frame will be an {@link ITRFVersion#ITRF_2014}. However,
  369.      * if parameters are loaded from different files types, or even for file
  370.      * types that changed their reference (like Bulletin A switching from
  371.      * {@link ITRFVersion#ITRF_2008} to {@link ITRFVersion#ITRF_2014} starting
  372.      * with Vol. XXXI No. 013 published on 2018-03-29), then the ITRF returned
  373.      * by this method will jump from one version to another version.
  374.      * </p>
  375.      * <p>
  376.      * IF a specific version of ITRF is needed, then {@link #getITRF(ITRFVersion,
  377.      * IERSConventions, boolean)} should be used instead.
  378.      * </p>
  379.      * @param conventions IERS conventions to apply
  380.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  381.      * @return the selected reference frame singleton.
  382.           * @see #getITRF(ITRFVersion, IERSConventions, boolean)
  383.      * @since 6.1
  384.      */
  385.     @DefaultDataContext
  386.     public static FactoryManagedFrame getITRF(final IERSConventions conventions,
  387.                                               final boolean simpleEOP) {
  388.         return getFrames().getITRF(conventions, simpleEOP);
  389.     }

  390.     /** Get the TIRF reference frame, ignoring tidal effects.
  391.      * @param conventions IERS conventions to apply
  392.      * @return the selected reference frame singleton.
  393.           * library cannot be read.
  394.      */
  395.     @DefaultDataContext
  396.     public static FactoryManagedFrame getTIRF(final IERSConventions conventions) {
  397.         return getFrames().getTIRF(conventions);
  398.     }

  399.     /** Get an specific International Terrestrial Reference Frame.
  400.      * <p>
  401.      * Note that if a specific version of ITRF is required, then {@code simpleEOP}
  402.      * should most probably be set to {@code false}, as ignoring tidal effects
  403.      * has an effect of the same order of magnitude as the differences between
  404.      * the various {@link ITRFVersion ITRF versions}.
  405.      * </p>
  406.      * @param version ITRF version
  407.      * @param conventions IERS conventions to apply
  408.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  409.      * @return the selected reference frame singleton.
  410.           * @since 9.2
  411.      */
  412.     @DefaultDataContext
  413.     public static VersionedITRF getITRF(final ITRFVersion version,
  414.                                         final IERSConventions conventions,
  415.                                         final boolean simpleEOP) {
  416.         return getFrames().getITRF(version, conventions, simpleEOP);
  417.     }

  418.     /** Get the TIRF reference frame.
  419.      * @param conventions IERS conventions to apply
  420.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  421.      * @return the selected reference frame singleton.
  422.      * @since 6.1
  423.      */
  424.     @DefaultDataContext
  425.     public static FactoryManagedFrame getTIRF(final IERSConventions conventions,
  426.                                               final boolean simpleEOP) {
  427.         return getFrames().getTIRF(conventions, simpleEOP);
  428.     }

  429.     /** Get the CIRF2000 reference frame.
  430.      * @param conventions IERS conventions to apply
  431.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  432.      * @return the selected reference frame singleton.
  433.      */
  434.     @DefaultDataContext
  435.     public static FactoryManagedFrame getCIRF(final IERSConventions conventions,
  436.                                               final boolean simpleEOP) {
  437.         return getFrames().getCIRF(conventions, simpleEOP);
  438.     }

  439.     /** Get the VEIS 1950 reference frame.
  440.      * <p>Its parent frame is the GTOD frame with IERS 1996 conventions without EOP corrections.<p>
  441.      * @return the selected reference frame singleton.
  442.      */
  443.     @DefaultDataContext
  444.     public static FactoryManagedFrame getVeis1950() {
  445.         return getFrames().getVeis1950();
  446.     }

  447.     /** Get the equinox-based ITRF reference frame.
  448.      * @param conventions IERS conventions to apply
  449.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  450.      * @return the selected reference frame singleton.
  451.           * @since 6.1
  452.      */
  453.     @DefaultDataContext
  454.     public static FactoryManagedFrame getITRFEquinox(final IERSConventions conventions,
  455.                                                      final boolean simpleEOP) {
  456.         return getFrames().getITRFEquinox(conventions, simpleEOP);
  457.     }

  458.     /** Get the GTOD reference frame.
  459.      * <p>
  460.      * The applyEOPCorr parameter is available mainly for testing purposes or for
  461.      * consistency with legacy software that don't handle EOP correction parameters.
  462.      * Beware that setting this parameter to {@code false} leads to crude accuracy
  463.      * (order of magnitudes for errors might be above 250m in LEO and 1400m in GEO).
  464.      * For this reason, setting this parameter to false is restricted to {@link
  465.      * IERSConventions#IERS_1996 IERS 1996} conventions, and hence the {@link
  466.      * IERSConventions IERS conventions} cannot be freely chosen here.
  467.      * </p>
  468.      * @param applyEOPCorr if true, EOP corrections are applied (here, dut1 and lod)
  469.      * @return the selected reference frame singleton.
  470.      */
  471.     @DefaultDataContext
  472.     public static FactoryManagedFrame getGTOD(final boolean applyEOPCorr) {
  473.         return getFrames().getGTOD(applyEOPCorr);
  474.     }

  475.     /** Get the GTOD reference frame.
  476.      * @param conventions IERS conventions to apply
  477.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  478.      * @return the selected reference frame singleton.
  479.      */
  480.     @DefaultDataContext
  481.     public static FactoryManagedFrame getGTOD(final IERSConventions conventions,
  482.                                               final boolean simpleEOP) {
  483.         return getFrames().getGTOD(conventions, simpleEOP);
  484.     }

  485.     /** Get the TOD reference frame.
  486.      * <p>
  487.      * The applyEOPCorr parameter is available mainly for testing purposes or for
  488.      * consistency with legacy software that don't handle EOP correction parameters.
  489.      * Beware that setting this parameter to {@code false} leads to crude accuracy
  490.      * (order of magnitudes for errors might be above 1m in LEO and 10m in GEO).
  491.      * For this reason, setting this parameter to false is restricted to {@link
  492.      * IERSConventions#IERS_1996 IERS 1996} conventions, and hence the {@link
  493.      * IERSConventions IERS conventions} cannot be freely chosen here.
  494.      * </p>
  495.      * @param applyEOPCorr if true, EOP corrections are applied (here, nutation)
  496.      * @return the selected reference frame singleton.
  497.      */
  498.     @DefaultDataContext
  499.     public static FactoryManagedFrame getTOD(final boolean applyEOPCorr) {
  500.         return getFrames().getTOD(applyEOPCorr);
  501.     }

  502.     /** Get the TOD reference frame.
  503.      * @param conventions IERS conventions to apply
  504.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  505.      * @return the selected reference frame singleton.
  506.      */
  507.     @DefaultDataContext
  508.     public static FactoryManagedFrame getTOD(final IERSConventions conventions,
  509.                                              final boolean simpleEOP) {
  510.         return getFrames().getTOD(conventions, simpleEOP);
  511.     }

  512.     /** Get the MOD reference frame.
  513.      * <p>
  514.      * The applyEOPCorr parameter is available mainly for testing purposes or for
  515.      * consistency with legacy software that don't handle EOP correction parameters.
  516.      * Beware that setting this parameter to {@code false} leads to crude accuracy
  517.      * (order of magnitudes for errors might be above 1m in LEO and 10m in GEO).
  518.      * For this reason, setting this parameter to false is restricted to {@link
  519.      * IERSConventions#IERS_1996 IERS 1996} conventions, and hence the {@link
  520.      * IERSConventions IERS conventions} cannot be freely chosen here.
  521.      * </p>
  522.      * @param applyEOPCorr if true, EOP corrections are applied (EME2000/GCRF bias compensation)
  523.      * @return the selected reference frame singleton.
  524.      */
  525.     @DefaultDataContext
  526.     public static FactoryManagedFrame getMOD(final boolean applyEOPCorr) {
  527.         return getFrames().getMOD(applyEOPCorr);
  528.     }

  529.     /** Get the MOD reference frame.
  530.      * @param conventions IERS conventions to apply
  531.      * @return the selected reference frame singleton.
  532.      */
  533.     @DefaultDataContext
  534.     public static FactoryManagedFrame getMOD(final IERSConventions conventions) {
  535.         return getFrames().getMOD(conventions);
  536.     }

  537.     /** Get the TEME reference frame.
  538.      * <p>
  539.      * The TEME frame is used for the SGP4 model in TLE propagation. This frame has <em>no</em>
  540.      * official definition and there are some ambiguities about whether it should be used
  541.      * as "of date" or "of epoch". This frame should therefore be used <em>only</em> for
  542.      * TLE propagation and not for anything else, as recommended by the CCSDS Orbit Data Message
  543.      * blue book.
  544.      * </p>
  545.      * @return the selected reference frame singleton.
  546.      */
  547.     @DefaultDataContext
  548.     public static FactoryManagedFrame getTEME() {
  549.         return getFrames().getTEME();
  550.     }

  551.     /** Get the PZ-90.11 (Parametry Zemly  – 1990.11) reference frame.
  552.      * <p>
  553.      * The PZ-90.11 reference system was updated on all operational
  554.      * GLONASS satellites starting from 3:00 pm on December 31, 2013.
  555.      * </p>
  556.      * <p>
  557.      * The transition between parent frame (ITRF-2008) and PZ-90.11 frame is performed using
  558.      * a seven parameters Helmert transformation.
  559.      * <pre>
  560.      *    From       To      ΔX(m)   ΔY(m)   ΔZ(m)   RX(mas)   RY(mas)  RZ(mas)   Epoch
  561.      * ITRF-2008  PZ-90.11  +0.003  +0.001  -0.000   +0.019    -0.042   +0.002     2010
  562.      * </pre>
  563.      * @see "Springer Handbook of Global Navigation Satellite Systems, Peter Teunissen & Oliver Montenbruck"
  564.      *
  565.      * @param convention IERS conventions to apply
  566.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  567.      * @return the selected reference frame singleton.
  568.      */
  569.     @DefaultDataContext
  570.     public static FactoryManagedFrame getPZ9011(final IERSConventions convention,
  571.                                                 final boolean simpleEOP) {
  572.         return getFrames().getPZ9011(convention, simpleEOP);
  573.     }

  574.     /** Get the transform between two frames, suppressing all interpolation.
  575.      * <p>
  576.      * This method is similar to {@link Frame#getTransformTo(Frame, AbsoluteDate)}
  577.      * except it removes the performance enhancing interpolation features that are
  578.      * added by the {@link FramesFactory factory} to some frames, in order to focus
  579.      * on accuracy. The interpolation features are intended to save processing time
  580.      * by avoiding doing some lengthy computation like nutation evaluation at each
  581.      * time step and caching some results. This method can be used to avoid this,
  582.      * when very high accuracy is desired, or for testing purposes. It should be
  583.      * used with care, as doing the full computation is <em>really</em> costly for
  584.      * some frames.
  585.      * </p>
  586.      * @param from frame from which transformation starts
  587.      * @param to frame to which transformation ends
  588.      * @param date date of the transform
  589.      * @return transform between the two frames, avoiding interpolation
  590.      */
  591.     public static Transform getNonInterpolatingTransform(final Frame from, final Frame to,
  592.                                                          final AbsoluteDate date) {

  593.         // common ancestor to both frames in the frames tree
  594.         Frame currentF = from.getDepth() > to.getDepth() ? from.getAncestor(from.getDepth() - to.getDepth()) : from;
  595.         Frame currentT = from.getDepth() > to.getDepth() ? to : to.getAncestor(to.getDepth() - from.getDepth());
  596.         while (currentF != currentT) {
  597.             currentF = currentF.getParent();
  598.             currentT = currentT.getParent();
  599.         }
  600.         final Frame common = currentF;

  601.         // transform from common to origin
  602.         Transform commonToOrigin = Transform.IDENTITY;
  603.         for (Frame frame = from; frame != common; frame = frame.getParent()) {
  604.             commonToOrigin = new Transform(date,
  605.                                              peel(frame.getTransformProvider()).getTransform(date),
  606.                                              commonToOrigin);
  607.         }

  608.         // transform from destination up to common
  609.         Transform commonToDestination = Transform.IDENTITY;
  610.         for (Frame frame = to; frame != common; frame = frame.getParent()) {
  611.             commonToDestination = new Transform(date,
  612.                                                 peel(frame.getTransformProvider()).getTransform(date),
  613.                                                 commonToDestination);
  614.         }

  615.         // transform from origin to destination via common
  616.         return new Transform(date, commonToOrigin.getInverse(), commonToDestination);

  617.     }

  618.     /* The methods below are static helper methods for Frame and TransformProvider. */

  619.     /** Get the transform between two frames, suppressing all interpolation.
  620.      * <p>
  621.      * This method is similar to {@link Frame#getTransformTo(Frame, AbsoluteDate)}
  622.      * except it removes the performance enhancing interpolation features that are
  623.      * added by the {@link FramesFactory factory} to some frames, in order to focus
  624.      * on accuracy. The interpolation features are intended to save processing time
  625.      * by avoiding doing some lengthy computation like nutation evaluation at each
  626.      * time step and caching some results. This method can be used to avoid this,
  627.      * when very high accuracy is desired, or for testing purposes. It should be
  628.      * used with care, as doing the full computation is <em>really</em> costly for
  629.      * some frames.
  630.      * </p>
  631.      * @param from frame from which transformation starts
  632.      * @param to frame to which transformation ends
  633.      * @param date date of the transform
  634.      * @param <T> type of the field elements
  635.      * @return transform between the two frames, avoiding interpolation
  636.      * @since 9.0
  637.      */
  638.     public static <T extends CalculusFieldElement<T>> FieldTransform<T> getNonInterpolatingTransform(final Frame from, final Frame to,
  639.                                                                                                  final FieldAbsoluteDate<T> date) {

  640.         // common ancestor to both frames in the frames tree
  641.         Frame currentF = from.getDepth() > to.getDepth() ? from.getAncestor(from.getDepth() - to.getDepth()) : from;
  642.         Frame currentT = from.getDepth() > to.getDepth() ? to : to.getAncestor(to.getDepth() - from.getDepth());
  643.         while (currentF != currentT) {
  644.             currentF = currentF.getParent();
  645.             currentT = currentT.getParent();
  646.         }
  647.         final Frame common = currentF;

  648.         // transform from common to origin
  649.         FieldTransform<T> commonToOrigin = FieldTransform.getIdentity(date.getField());
  650.         for (Frame frame = from; frame != common; frame = frame.getParent()) {
  651.             commonToOrigin = new FieldTransform<>(date,
  652.                                                    peel(frame.getTransformProvider()).getTransform(date),
  653.                                                    commonToOrigin);
  654.         }

  655.         // transform from destination up to common
  656.         FieldTransform<T> commonToDestination = FieldTransform.getIdentity(date.getField());
  657.         for (Frame frame = to; frame != common; frame = frame.getParent()) {
  658.             commonToDestination = new FieldTransform<>(date,
  659.                                                        peel(frame.getTransformProvider()).getTransform(date),
  660.                                                        commonToDestination);
  661.         }

  662.         // transform from origin to destination via common
  663.         return new FieldTransform<>(date, commonToOrigin.getInverse(), commonToDestination);

  664.     }

  665.     /** Retrieve EOP from a frame hierarchy.
  666.      * <p>
  667.      * The frame hierarchy tree is walked from specified frame up to root
  668.      * traversing parent frames, and the providers are checked to see if they
  669.      * reference EOP history. The first EOP history found is returned.
  670.      * </p>
  671.      * @param start frame from which to start search, will typically be some
  672.      * Earth related frame, like a topocentric frame or an ITRF frame
  673.      * @return EOP history found while walking the frames tree, or null if
  674.      * no EOP history is found
  675.      * @since 9.1
  676.      */
  677.     public static EOPHistory findEOP(final Frame start) {

  678.         for (Frame frame = start; frame != null; frame = frame.getParent()) {

  679.             TransformProvider peeled = frame.getTransformProvider();

  680.             boolean peeling = true;
  681.             while (peeling) {
  682.                 if (peeled instanceof InterpolatingTransformProvider) {
  683.                     peeled = ((InterpolatingTransformProvider) peeled).getRawProvider();
  684.                 } else if (peeled instanceof ShiftingTransformProvider) {
  685.                     peeled = ((ShiftingTransformProvider) peeled).getRawProvider();
  686.                 } else if (peeled instanceof EOPBasedTransformProvider &&
  687.                            ((EOPBasedTransformProvider) peeled).getEOPHistory() != null) {
  688.                     return ((EOPBasedTransformProvider) peeled).getEOPHistory();
  689.                 } else {
  690.                     peeling = false;
  691.                 }
  692.             }

  693.         }

  694.         // no history found
  695.         return null;

  696.     }

  697.     /** Peel interpolation and shifting from a transform provider.
  698.      * @param provider transform provider to peel
  699.      * @return peeled transform provider
  700.      */
  701.     private static TransformProvider peel(final TransformProvider provider) {

  702.         TransformProvider peeled = provider;

  703.         boolean peeling = true;
  704.         while (peeling) {
  705.             if (peeled instanceof InterpolatingTransformProvider) {
  706.                 peeled = ((InterpolatingTransformProvider) peeled).getRawProvider();
  707.             } else if (peeled instanceof ShiftingTransformProvider) {
  708.                 peeled = ((ShiftingTransformProvider) peeled).getRawProvider();
  709.             } else if (peeled instanceof EOPBasedTransformProvider &&
  710.                        ((EOPBasedTransformProvider) peeled).getEOPHistory() != null &&
  711.                        ((EOPBasedTransformProvider) peeled).getEOPHistory().usesInterpolation()) {
  712.                 peeled = ((EOPBasedTransformProvider) peeled).getNonInterpolatingProvider();
  713.             } else {
  714.                 peeling = false;
  715.             }
  716.         }

  717.         return peeled;

  718.     }

  719. }