FramesFactory.java

  1. /* Copyright 2002-2016 CS Systèmes d'Information
  2.  * Licensed to CS Systèmes d'Information (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 java.util.ArrayList;
  19. import java.util.HashMap;
  20. import java.util.List;
  21. import java.util.Map;
  22. import java.util.SortedSet;
  23. import java.util.TreeSet;

  24. import org.orekit.bodies.CelestialBodyFactory;
  25. import org.orekit.errors.OrekitException;
  26. import org.orekit.errors.OrekitInternalError;
  27. import org.orekit.time.AbsoluteDate;
  28. import org.orekit.time.ChronologicalComparator;
  29. import org.orekit.utils.AngularDerivativesFilter;
  30. import org.orekit.utils.CartesianDerivativesFilter;
  31. import org.orekit.utils.Constants;
  32. import org.orekit.utils.IERSConventions;
  33. import org.orekit.utils.OrekitConfiguration;


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

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

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

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

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

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

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

  169.     /** Default regular expression for the EOPC04 files (IAU2000 compatibles). */
  170.     public static final String EOPC04_2000_FILENAME = "^eopc04_08_IAU2000\\.(\\d\\d)$";

  171.     /** Default regular expression for the BulletinB files (IAU2000 compatibles). */
  172.     public static final String BULLETINB_2000_FILENAME = "^bulletinb_IAU2000((-\\d\\d\\d\\.txt)|(\\.\\d\\d\\d))$";

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

  175.     /** Predefined frames. */
  176.     private static transient Map<Predefined, FactoryManagedFrame> FRAMES =
  177.         new HashMap<Predefined, FactoryManagedFrame>();

  178.     /** Loaders for Earth Orientation parameters. */
  179.     private static final Map<IERSConventions, List<EOPHistoryLoader>> EOP_HISTORY_LOADERS =
  180.         new HashMap<IERSConventions, List<EOPHistoryLoader>>();

  181.     /** Threshold for EOP continuity. */
  182.     private static double EOP_CONTINUITY_THRESHOLD = 5 * Constants.JULIAN_DAY;

  183.     /** Private constructor.
  184.      * <p>This class is a utility class, it should neither have a public
  185.      * nor a default constructor. This private constructor prevents
  186.      * the compiler from generating one automatically.</p>
  187.      */
  188.     private FramesFactory() {
  189.     }

  190.     /** Add the default loaders EOP history (IAU 1980 precession/nutation).
  191.      * <p>
  192.      * The default loaders look for IERS EOP 08 C04 and bulletins B files. They
  193.      * correspond to {@link IERSConventions#IERS_1996 IERS 1996} conventions.
  194.      * </p>
  195.      * @param rapidDataColumnsSupportedNames regular expression for supported
  196.      * rapid data columns EOP files names
  197.      * (may be null if the default IERS file names are used)
  198.      * @param rapidDataXMLSupportedNames regular expression for supported
  199.      * rapid data XML EOP files names
  200.      * (may be null if the default IERS file names are used)
  201.      * @param eopC04SupportedNames regular expression for supported EOP 08 C04 files names
  202.      * (may be null if the default IERS file names are used)
  203.      * @param bulletinBSupportedNames regular expression for supported bulletin B files names
  204.      * (may be null if the default IERS file names are used)
  205.      * @param bulletinASupportedNames regular expression for supported bulletin A files names
  206.      * (may be null if the default IERS file names are used)
  207.      * @see <a href="http://hpiers.obspm.fr/eoppc/eop/eopc04/">IERS EOP 08 C04 files</a>
  208.      * @see #addEOPHistoryLoader(IERSConventions, EOPHistoryLoader)
  209.      * @see #clearEOPHistoryLoaders()
  210.      * @see #addDefaultEOP2000HistoryLoaders(String, String, String, String, String)
  211.      */
  212.     public static void addDefaultEOP1980HistoryLoaders(final String rapidDataColumnsSupportedNames,
  213.                                                        final String rapidDataXMLSupportedNames,
  214.                                                        final String eopC04SupportedNames,
  215.                                                        final String bulletinBSupportedNames,
  216.                                                        final String bulletinASupportedNames) {
  217.         final String rapidColNames =
  218.                 (rapidDataColumnsSupportedNames == null) ?
  219.                 RAPID_DATA_PREDICTION_COLUMNS_1980_FILENAME : rapidDataColumnsSupportedNames;
  220.         addEOPHistoryLoader(IERSConventions.IERS_1996,
  221.                             new RapidDataAndPredictionColumnsLoader(false, rapidColNames));
  222.         final String rapidXmlNames =
  223.                 (rapidDataXMLSupportedNames == null) ?
  224.                 RAPID_DATA_PREDICTION_XML_1980_FILENAME : rapidDataXMLSupportedNames;
  225.         addEOPHistoryLoader(IERSConventions.IERS_1996,
  226.                             new RapidDataAndPredictionXMLLoader(rapidXmlNames));
  227.         final String eopcNames =
  228.                 (eopC04SupportedNames == null) ? EOPC04_1980_FILENAME : eopC04SupportedNames;
  229.         addEOPHistoryLoader(IERSConventions.IERS_1996,
  230.                             new EOP08C04FilesLoader(eopcNames));
  231.         final String bulBNames =
  232.                 (bulletinBSupportedNames == null) ? BULLETINB_1980_FILENAME : bulletinBSupportedNames;
  233.         addEOPHistoryLoader(IERSConventions.IERS_1996,
  234.                             new BulletinBFilesLoader(bulBNames));
  235.         final String bulANames =
  236.                     (bulletinASupportedNames == null) ? BULLETINA_FILENAME : bulletinASupportedNames;
  237.         addEOPHistoryLoader(IERSConventions.IERS_1996,
  238.                             new BulletinAFilesLoader(bulANames));
  239.     }

  240.     /** Add the default loaders for EOP history (IAU 2000/2006 precession/nutation).
  241.      * <p>
  242.      * The default loaders look for IERS EOP 08 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 08 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 08 C04 files</a>
  259.      * @see #addEOPHistoryLoader(IERSConventions, EOPHistoryLoader)
  260.      * @see #clearEOPHistoryLoaders()
  261.      * @see #addDefaultEOP1980HistoryLoaders(String, String, String, String, String)
  262.      */
  263.     public static void addDefaultEOP2000HistoryLoaders(final String rapidDataColumnsSupportedNames,
  264.                                                        final String rapidDataXMLSupportedNames,
  265.                                                        final String eopC04SupportedNames,
  266.                                                        final String bulletinBSupportedNames,
  267.                                                        final String bulletinASupportedNames) {
  268.         final String rapidColNames =
  269.                 (rapidDataColumnsSupportedNames == null) ?
  270.                 RAPID_DATA_PREDICITON_COLUMNS_2000_FILENAME : rapidDataColumnsSupportedNames;
  271.         addEOPHistoryLoader(IERSConventions.IERS_2003,
  272.                             new RapidDataAndPredictionColumnsLoader(true, rapidColNames));
  273.         addEOPHistoryLoader(IERSConventions.IERS_2010,
  274.                             new RapidDataAndPredictionColumnsLoader(true, rapidColNames));
  275.         final String rapidXmlNames =
  276.             (rapidDataXMLSupportedNames == null) ?
  277.             RAPID_DATA_PREDICITON_XML_2000_FILENAME : rapidDataXMLSupportedNames;
  278.         addEOPHistoryLoader(IERSConventions.IERS_2003,
  279.                             new RapidDataAndPredictionXMLLoader(rapidXmlNames));
  280.         addEOPHistoryLoader(IERSConventions.IERS_2010,
  281.                             new RapidDataAndPredictionXMLLoader(rapidXmlNames));
  282.         final String eopcNames =
  283.             (eopC04SupportedNames == null) ? EOPC04_2000_FILENAME : eopC04SupportedNames;
  284.         addEOPHistoryLoader(IERSConventions.IERS_2003,
  285.                             new EOP08C04FilesLoader(eopcNames));
  286.         addEOPHistoryLoader(IERSConventions.IERS_2010,
  287.                             new EOP08C04FilesLoader(eopcNames));
  288.         final String bulBNames =
  289.             (bulletinBSupportedNames == null) ? BULLETINB_2000_FILENAME : bulletinBSupportedNames;
  290.         addEOPHistoryLoader(IERSConventions.IERS_2003,
  291.                             new BulletinBFilesLoader(bulBNames));
  292.         addEOPHistoryLoader(IERSConventions.IERS_2010,
  293.                             new BulletinBFilesLoader(bulBNames));
  294.         final String bulANames =
  295.                 (bulletinASupportedNames == null) ? BULLETINA_FILENAME : bulletinASupportedNames;
  296.         addEOPHistoryLoader(IERSConventions.IERS_2003,
  297.                             new BulletinAFilesLoader(bulANames));
  298.         addEOPHistoryLoader(IERSConventions.IERS_2010,
  299.                             new BulletinAFilesLoader(bulANames));
  300.     }

  301.     /** Add a loader for Earth Orientation Parameters history.
  302.      * @param conventions IERS conventions to which EOP history applies
  303.      * @param loader custom loader to add for the EOP history
  304.      * @see #addDefaultEOP1980HistoryLoaders(String, String, String, String, String)
  305.      * @see #clearEOPHistoryLoaders()
  306.      */
  307.     public static void addEOPHistoryLoader(final IERSConventions conventions, final EOPHistoryLoader loader) {
  308.         synchronized (EOP_HISTORY_LOADERS) {
  309.             if (!EOP_HISTORY_LOADERS.containsKey(conventions)) {
  310.                 EOP_HISTORY_LOADERS.put(conventions, new ArrayList<EOPHistoryLoader>());
  311.             }
  312.             EOP_HISTORY_LOADERS.get(conventions).add(loader);
  313.         }
  314.     }

  315.     /** Clear loaders for Earth Orientation Parameters history.
  316.      * @see #addEOPHistoryLoader(IERSConventions, EOPHistoryLoader)
  317.      * @see #addDefaultEOP1980HistoryLoaders(String, String, String, String, String)
  318.      */
  319.     public static void clearEOPHistoryLoaders() {
  320.         synchronized (EOP_HISTORY_LOADERS) {
  321.             EOP_HISTORY_LOADERS.clear();
  322.         }
  323.     }

  324.     /** Set the threshold to check EOP continuity.
  325.      * <p>
  326.      * The default threshold (used if this method is never called)
  327.      * is 5 Julian days. If after loading EOP entries some holes
  328.      * between entries exceed this threshold, an exception will
  329.      * be triggered.
  330.      * </p>
  331.      * <p>
  332.      * One case when calling this method is really useful is for
  333.      * applications that use a single Bulletin A, as these bulletins
  334.      * have a roughly one month wide hole for the first bulletin of
  335.      * each month, which contains older final data in addition to the
  336.      * rapid data and the predicted data.
  337.      * </p>
  338.      * @param threshold threshold to use for checking EOP continuity (in seconds)
  339.      */
  340.     public static void setEOPContinuityThreshold(final double threshold) {
  341.         EOP_CONTINUITY_THRESHOLD = threshold;
  342.     }

  343.     /** Get Earth Orientation Parameters history.
  344.      * <p>
  345.      * If no {@link EOPHistoryLoader} has been added by calling {@link
  346.      * #addEOPHistoryLoader(IERSConventions, EOPHistoryLoader) addEOPHistoryLoader}
  347.      * or if {@link #clearEOPHistoryLoaders() clearEOPHistoryLoaders} has been
  348.      * called afterwards, the {@link #addDefaultEOP1980HistoryLoaders(String, String,
  349.      * String, String, String)} and {@link #addDefaultEOP2000HistoryLoaders(String,
  350.      * String, String, String, String)} methods will be called automatically with
  351.      * supported file names parameters all set to null, in order to get the default
  352.      * loaders configuration.
  353.      * </p>
  354.      * @param conventions conventions for which EOP history is requested
  355.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  356.      * @return Earth Orientation Parameters history
  357.      * @exception OrekitException if the data cannot be loaded
  358.      */
  359.     public static EOPHistory getEOPHistory(final IERSConventions conventions, final boolean simpleEOP)
  360.         throws OrekitException {

  361.         synchronized (EOP_HISTORY_LOADERS) {

  362.             if (EOP_HISTORY_LOADERS.isEmpty()) {
  363.                 // set up using default loaders
  364.                 addDefaultEOP2000HistoryLoaders(null, null, null, null, null);
  365.                 addDefaultEOP1980HistoryLoaders(null, null, null, null, null);
  366.             }

  367.             // TimeStamped based set needed to remove duplicates
  368.             OrekitException pendingException = null;
  369.             final SortedSet<EOPEntry> data = new TreeSet<EOPEntry>(new ChronologicalComparator());

  370.             // try to load canonical data if available
  371.             if (EOP_HISTORY_LOADERS.containsKey(conventions)) {
  372.                 for (final EOPHistoryLoader loader : EOP_HISTORY_LOADERS.get(conventions)) {
  373.                     try {
  374.                         loader.fillHistory(conventions.getNutationCorrectionConverter(), data);
  375.                     } catch (OrekitException oe) {
  376.                         pendingException = oe;
  377.                     }
  378.                 }
  379.             }

  380.             if (data.isEmpty() && pendingException != null) {
  381.                 throw pendingException;
  382.             }

  383.             final EOPHistory history = new EOPHistory(conventions, data, simpleEOP);
  384.             history.checkEOPContinuity(EOP_CONTINUITY_THRESHOLD);
  385.             return history;

  386.         }

  387.     }

  388.     /** Get one of the predefined frames.
  389.      * @param factoryKey key of the frame within the factory
  390.      * @return the predefined frame
  391.      * @exception OrekitException if frame cannot be built due to missing data
  392.      */
  393.     public static Frame getFrame(final Predefined factoryKey)
  394.         throws OrekitException {
  395.         switch (factoryKey) {
  396.             case GCRF :
  397.                 return getGCRF();
  398.             case ICRF :
  399.                 return getICRF();
  400.             case ECLIPTIC_CONVENTIONS_1996 :
  401.                 return getEcliptic(IERSConventions.IERS_1996);
  402.             case ECLIPTIC_CONVENTIONS_2003 :
  403.                 return getEcliptic(IERSConventions.IERS_2003);
  404.             case ECLIPTIC_CONVENTIONS_2010 :
  405.                 return getEcliptic(IERSConventions.IERS_2010);
  406.             case EME2000 :
  407.                 return getEME2000();
  408.             case ITRF_CIO_CONV_2010_SIMPLE_EOP :
  409.                 return getITRF(IERSConventions.IERS_2010, true);
  410.             case ITRF_CIO_CONV_2010_ACCURATE_EOP :
  411.                 return getITRF(IERSConventions.IERS_2010, false);
  412.             case ITRF_CIO_CONV_2003_SIMPLE_EOP :
  413.                 return getITRF(IERSConventions.IERS_2003, true);
  414.             case ITRF_CIO_CONV_2003_ACCURATE_EOP :
  415.                 return getITRF(IERSConventions.IERS_2003, false);
  416.             case ITRF_CIO_CONV_1996_SIMPLE_EOP :
  417.                 return getITRF(IERSConventions.IERS_1996, true);
  418.             case ITRF_CIO_CONV_1996_ACCURATE_EOP :
  419.                 return getITRF(IERSConventions.IERS_1996, false);
  420.             case ITRF_EQUINOX_CONV_2010_SIMPLE_EOP :
  421.                 return getITRFEquinox(IERSConventions.IERS_2010, true);
  422.             case ITRF_EQUINOX_CONV_2010_ACCURATE_EOP :
  423.                 return getITRFEquinox(IERSConventions.IERS_2010, false);
  424.             case ITRF_EQUINOX_CONV_2003_SIMPLE_EOP :
  425.                 return getITRFEquinox(IERSConventions.IERS_2003, true);
  426.             case ITRF_EQUINOX_CONV_2003_ACCURATE_EOP :
  427.                 return getITRFEquinox(IERSConventions.IERS_2003, false);
  428.             case ITRF_EQUINOX_CONV_1996_SIMPLE_EOP :
  429.                 return getITRFEquinox(IERSConventions.IERS_1996, true);
  430.             case ITRF_EQUINOX_CONV_1996_ACCURATE_EOP :
  431.                 return getITRFEquinox(IERSConventions.IERS_1996, false);
  432.             case TIRF_CONVENTIONS_2010_SIMPLE_EOP :
  433.                 return getTIRF(IERSConventions.IERS_2010, true);
  434.             case TIRF_CONVENTIONS_2010_ACCURATE_EOP :
  435.                 return getTIRF(IERSConventions.IERS_2010, false);
  436.             case TIRF_CONVENTIONS_2003_SIMPLE_EOP :
  437.                 return getTIRF(IERSConventions.IERS_2003, true);
  438.             case TIRF_CONVENTIONS_2003_ACCURATE_EOP :
  439.                 return getTIRF(IERSConventions.IERS_2003, false);
  440.             case TIRF_CONVENTIONS_1996_SIMPLE_EOP :
  441.                 return getTIRF(IERSConventions.IERS_1996, true);
  442.             case TIRF_CONVENTIONS_1996_ACCURATE_EOP :
  443.                 return getTIRF(IERSConventions.IERS_1996, false);
  444.             case CIRF_CONVENTIONS_2010_ACCURATE_EOP :
  445.                 return getCIRF(IERSConventions.IERS_2010, false);
  446.             case CIRF_CONVENTIONS_2010_SIMPLE_EOP :
  447.                 return getCIRF(IERSConventions.IERS_2010, true);
  448.             case CIRF_CONVENTIONS_2003_ACCURATE_EOP :
  449.                 return getCIRF(IERSConventions.IERS_2003, false);
  450.             case CIRF_CONVENTIONS_2003_SIMPLE_EOP :
  451.                 return getCIRF(IERSConventions.IERS_2003, true);
  452.             case CIRF_CONVENTIONS_1996_ACCURATE_EOP :
  453.                 return getCIRF(IERSConventions.IERS_1996, false);
  454.             case CIRF_CONVENTIONS_1996_SIMPLE_EOP :
  455.                 return getCIRF(IERSConventions.IERS_1996, true);
  456.             case VEIS_1950 :
  457.                 return getVeis1950();
  458.             case GTOD_WITHOUT_EOP_CORRECTIONS :
  459.                 return getGTOD(IERSConventions.IERS_1996, false, true);
  460.             case GTOD_CONVENTIONS_2010_ACCURATE_EOP :
  461.                 return getGTOD(IERSConventions.IERS_2010, true, false);
  462.             case GTOD_CONVENTIONS_2010_SIMPLE_EOP :
  463.                 return getGTOD(IERSConventions.IERS_2010, true, true);
  464.             case GTOD_CONVENTIONS_2003_ACCURATE_EOP :
  465.                 return getGTOD(IERSConventions.IERS_2003, true, false);
  466.             case GTOD_CONVENTIONS_2003_SIMPLE_EOP :
  467.                 return getGTOD(IERSConventions.IERS_2003, true, true);
  468.             case GTOD_CONVENTIONS_1996_ACCURATE_EOP :
  469.                 return getGTOD(IERSConventions.IERS_1996, true, false);
  470.             case GTOD_CONVENTIONS_1996_SIMPLE_EOP :
  471.                 return getGTOD(IERSConventions.IERS_1996, true, true);
  472.             case TOD_WITHOUT_EOP_CORRECTIONS :
  473.                 return getTOD(IERSConventions.IERS_1996, false, true);
  474.             case TOD_CONVENTIONS_2010_ACCURATE_EOP :
  475.                 return getTOD(IERSConventions.IERS_2010, true, false);
  476.             case TOD_CONVENTIONS_2010_SIMPLE_EOP :
  477.                 return getTOD(IERSConventions.IERS_2010, true, true);
  478.             case TOD_CONVENTIONS_2003_ACCURATE_EOP :
  479.                 return getTOD(IERSConventions.IERS_2003, true, false);
  480.             case TOD_CONVENTIONS_2003_SIMPLE_EOP :
  481.                 return getTOD(IERSConventions.IERS_2003, true, true);
  482.             case TOD_CONVENTIONS_1996_ACCURATE_EOP :
  483.                 return getTOD(IERSConventions.IERS_1996, true, false);
  484.             case TOD_CONVENTIONS_1996_SIMPLE_EOP :
  485.                 return getTOD(IERSConventions.IERS_1996, true, true);
  486.             case MOD_WITHOUT_EOP_CORRECTIONS :
  487.                 return getMOD(IERSConventions.IERS_1996, false);
  488.             case MOD_CONVENTIONS_2010 :
  489.                 return getMOD(IERSConventions.IERS_2010, true);
  490.             case MOD_CONVENTIONS_2003 :
  491.                 return getMOD(IERSConventions.IERS_2003, true);
  492.             case MOD_CONVENTIONS_1996 :
  493.                 return getMOD(IERSConventions.IERS_1996, true);
  494.             case TEME :
  495.                 return getTEME();
  496.             default :
  497.                 // this should never happen
  498.                 throw new OrekitInternalError(null);
  499.         }
  500.     }

  501.     /** Get the unique GCRF frame.
  502.      * <p>The GCRF frame is the root frame in the frame tree.</p>
  503.      * @return the unique instance of the GCRF frame
  504.      */
  505.     public static Frame getGCRF() {
  506.         return Frame.getRoot();
  507.     }

  508.     /** Get the unique ICRF frame.
  509.      * <p>The ICRF frame is centered at solar system barycenter and aligned
  510.      * with EME2000.</p>
  511.      * @return the unique instance of the ICRF frame
  512.      * @exception OrekitException if solar system ephemerides cannot be loaded
  513.      */
  514.     public static Frame getICRF() throws OrekitException {
  515.         return CelestialBodyFactory.getSolarSystemBarycenter().getInertiallyOrientedFrame();
  516.     }

  517.     /** Get the ecliptic frame.
  518.      * The IAU defines the ecliptic as "the plane perpendicular to the mean heliocentric
  519.      * orbital angular momentum vector of the Earth-Moon barycentre in the BCRS (IAU 2006
  520.      * Resolution B1)." The +z axis is aligned with the angular momentum vector, and the +x
  521.      * axis is aligned with +x axis of {@link FramesFactory#getMOD(IERSConventions) MOD}.
  522.      *
  523.      * <p> This implementation agrees with the JPL 406 ephemerides to within 0.5 arc seconds.
  524.      * @param conventions IERS conventions to apply
  525.      * @return the selected reference frame singleton.
  526.      * @exception OrekitException if data embedded in the library cannot be read
  527.      */
  528.     public static Frame getEcliptic(final IERSConventions conventions) throws OrekitException {
  529.         synchronized (FramesFactory.class) {

  530.             final Predefined factoryKey;
  531.             switch (conventions) {
  532.                 case IERS_1996 :
  533.                     factoryKey = Predefined.ECLIPTIC_CONVENTIONS_1996;
  534.                     break;
  535.                 case IERS_2003 :
  536.                     factoryKey = Predefined.ECLIPTIC_CONVENTIONS_2003;
  537.                     break;
  538.                 case IERS_2010 :
  539.                     factoryKey = Predefined.ECLIPTIC_CONVENTIONS_2010;
  540.                     break;
  541.                 default :
  542.                     // this should never happen
  543.                     throw new OrekitInternalError(null);
  544.             }
  545.             final Frame parent = getMOD(conventions);

  546.             // try to find an already built frame
  547.             FactoryManagedFrame frame = FRAMES.get(factoryKey);

  548.             if (frame == null) {
  549.                 // it's the first time we need this frame, build it and store it
  550.                 frame = new FactoryManagedFrame(parent, new EclipticProvider(conventions),
  551.                                                 true, factoryKey);
  552.                 FRAMES.put(factoryKey, frame);
  553.             }

  554.             return frame;

  555.         }
  556.     }

  557.     /** Get the unique EME2000 frame.
  558.      * <p>The EME2000 frame is also called the J2000 frame.
  559.      * The former denomination is preferred in Orekit.</p>
  560.      * @return the unique instance of the EME2000 frame
  561.      */
  562.     public static FactoryManagedFrame getEME2000() {
  563.         synchronized (FramesFactory.class) {

  564.             // try to find an already built frame
  565.             FactoryManagedFrame frame = FRAMES.get(Predefined.EME2000);

  566.             if (frame == null) {
  567.                 // it's the first time we need this frame, build it and store it
  568.                 frame = new FactoryManagedFrame(getGCRF(), new EME2000Provider(), true, Predefined.EME2000);
  569.                 FRAMES.put(Predefined.EME2000, frame);
  570.             }

  571.             return frame;

  572.         }
  573.     }

  574.     /** Get the ITRF2008 reference frame, using IERS 2010 conventions.
  575.      * @param conventions IERS conventions to apply
  576.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  577.      * @return the selected reference frame singleton.
  578.      * @exception OrekitException if data embedded in the library cannot be read
  579.      * @since 6.1
  580.      */
  581.     public static FactoryManagedFrame getITRF(final IERSConventions conventions,
  582.                                               final boolean simpleEOP)
  583.         throws OrekitException {
  584.         synchronized (FramesFactory.class) {

  585.             // try to find an already built frame
  586.             final Predefined factoryKey;
  587.             switch (conventions) {
  588.                 case IERS_1996 :
  589.                     factoryKey = simpleEOP ?
  590.                                  Predefined.ITRF_CIO_CONV_1996_SIMPLE_EOP :
  591.                                  Predefined.ITRF_CIO_CONV_1996_ACCURATE_EOP;
  592.                     break;
  593.                 case IERS_2003 :
  594.                     factoryKey = simpleEOP ?
  595.                                  Predefined.ITRF_CIO_CONV_2003_SIMPLE_EOP :
  596.                                  Predefined.ITRF_CIO_CONV_2003_ACCURATE_EOP;
  597.                     break;
  598.                 case IERS_2010 :
  599.                     factoryKey = simpleEOP ?
  600.                                  Predefined.ITRF_CIO_CONV_2010_SIMPLE_EOP :
  601.                                  Predefined.ITRF_CIO_CONV_2010_ACCURATE_EOP;
  602.                     break;
  603.                 default :
  604.                     // this should never happen
  605.                     throw new OrekitInternalError(null);
  606.             }
  607.             FactoryManagedFrame frame = FRAMES.get(factoryKey);

  608.             if (frame == null) {
  609.                 // it's the first time we need this frame, build it and store it
  610.                 final Frame tirfFrame = getTIRF(conventions, simpleEOP);
  611.                 final TIRFProvider tirfProvider = (TIRFProvider) tirfFrame.getTransformProvider();
  612.                 frame = new FactoryManagedFrame(tirfFrame,
  613.                                                 new ITRFProvider(tirfProvider.getEOPHistory()),
  614.                                                 false, factoryKey);
  615.                 FRAMES.put(factoryKey, frame);
  616.             }

  617.             return frame;

  618.         }
  619.     }

  620.     /** Get the TIRF reference frame, ignoring tidal effects.
  621.      * @param conventions IERS conventions to apply
  622.      * @return the selected reference frame singleton.
  623.      * @exception OrekitException if the precession-nutation model data embedded in the
  624.      * library cannot be read.
  625.      */
  626.     public static FactoryManagedFrame getTIRF(final IERSConventions conventions) throws OrekitException {
  627.         return getTIRF(conventions, true);
  628.     }

  629.     /** Get the TIRF reference frame.
  630.      * @param conventions IERS conventions to apply
  631.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  632.      * @return the selected reference frame singleton.
  633.      * @exception OrekitException if the precession-nutation model data embedded in the
  634.      * library cannot be read.
  635.      * @since 6.1
  636.      */
  637.     public static FactoryManagedFrame getTIRF(final IERSConventions conventions,
  638.                                               final boolean simpleEOP)
  639.         throws OrekitException {
  640.         synchronized (FramesFactory.class) {

  641.             // try to find an already built frame
  642.             final Predefined factoryKey;
  643.             switch (conventions) {
  644.                 case IERS_1996 :
  645.                     factoryKey = simpleEOP ?
  646.                                  Predefined.TIRF_CONVENTIONS_1996_SIMPLE_EOP :
  647.                                  Predefined.TIRF_CONVENTIONS_1996_ACCURATE_EOP;
  648.                     break;
  649.                 case IERS_2003 :
  650.                     factoryKey = simpleEOP ?
  651.                                  Predefined.TIRF_CONVENTIONS_2003_SIMPLE_EOP :
  652.                                  Predefined.TIRF_CONVENTIONS_2003_ACCURATE_EOP;
  653.                     break;
  654.                 case IERS_2010 :
  655.                     factoryKey = simpleEOP ?
  656.                                  Predefined.TIRF_CONVENTIONS_2010_SIMPLE_EOP :
  657.                                  Predefined.TIRF_CONVENTIONS_2010_ACCURATE_EOP;
  658.                     break;
  659.                 default :
  660.                     // this should never happen
  661.                     throw new OrekitInternalError(null);
  662.             }
  663.             FactoryManagedFrame frame = FRAMES.get(factoryKey);

  664.             if (frame == null) {
  665.                 // it's the first time we need this frame, build it and store it
  666.                 final Frame cirf = getCIRF(conventions, simpleEOP);
  667.                 final ShiftingTransformProvider cirfInterpolating =
  668.                         (ShiftingTransformProvider) cirf.getTransformProvider();
  669.                 final CIRFProvider cirfRaw = (CIRFProvider) cirfInterpolating.getRawProvider();
  670.                 final EOPHistory eopHistory = cirfRaw.getEOPHistory();
  671.                 frame = new FactoryManagedFrame(cirf, new TIRFProvider(eopHistory), false, factoryKey);
  672.                 FRAMES.put(factoryKey, frame);
  673.             }

  674.             return frame;

  675.         }
  676.     }

  677.     /** Get the CIRF2000 reference frame.
  678.      * @param conventions IERS conventions to apply
  679.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  680.      * @return the selected reference frame singleton.
  681.      * @exception OrekitException if the precession-nutation model data embedded in the
  682.      * library cannot be read.
  683.      */
  684.     public static FactoryManagedFrame getCIRF(final IERSConventions conventions,
  685.                                               final boolean simpleEOP)
  686.         throws OrekitException {
  687.         synchronized (FramesFactory.class) {

  688.             // try to find an already built frame
  689.             final Predefined factoryKey;
  690.             switch (conventions) {
  691.                 case IERS_1996 :
  692.                     factoryKey = simpleEOP ?
  693.                                  Predefined.CIRF_CONVENTIONS_1996_SIMPLE_EOP :
  694.                                  Predefined.CIRF_CONVENTIONS_1996_ACCURATE_EOP;
  695.                     break;
  696.                 case IERS_2003 :
  697.                     factoryKey = simpleEOP ?
  698.                                  Predefined.CIRF_CONVENTIONS_2003_SIMPLE_EOP :
  699.                                  Predefined.CIRF_CONVENTIONS_2003_ACCURATE_EOP;
  700.                     break;
  701.                 case IERS_2010 :
  702.                     factoryKey = simpleEOP ?
  703.                                  Predefined.CIRF_CONVENTIONS_2010_SIMPLE_EOP :
  704.                                  Predefined.CIRF_CONVENTIONS_2010_ACCURATE_EOP;
  705.                     break;
  706.                 default :
  707.                     // this should never happen
  708.                     throw new OrekitInternalError(null);
  709.             }
  710.             FactoryManagedFrame frame = FRAMES.get(factoryKey);

  711.             if (frame == null) {
  712.                 // it's the first time we need this frame, build it and store it
  713.                 final EOPHistory eopHistory = FramesFactory.getEOPHistory(conventions, simpleEOP);
  714.                 final TransformProvider shifting =
  715.                         new ShiftingTransformProvider(new CIRFProvider(eopHistory),
  716.                                                       CartesianDerivativesFilter.USE_PVA,
  717.                                                       AngularDerivativesFilter.USE_R,
  718.                                                       AbsoluteDate.PAST_INFINITY, AbsoluteDate.FUTURE_INFINITY,
  719.                                                       6, Constants.JULIAN_DAY / 24,
  720.                                                       OrekitConfiguration.getCacheSlotsNumber(),
  721.                                                       Constants.JULIAN_YEAR, 30 * Constants.JULIAN_DAY);
  722.                 frame = new FactoryManagedFrame(getGCRF(), shifting, true, factoryKey);
  723.                 FRAMES.put(factoryKey, frame);
  724.             }

  725.             return frame;

  726.         }
  727.     }

  728.     /** Get the VEIS 1950 reference frame.
  729.      * <p>Its parent frame is the GTOD frame with IERS 1996 conventions without EOP corrections.<p>
  730.      * @return the selected reference frame singleton.
  731.      * @exception OrekitException if data embedded in the library cannot be read
  732.      */
  733.     public static FactoryManagedFrame getVeis1950() throws OrekitException {
  734.         synchronized (FramesFactory.class) {

  735.             // try to find an already built frame
  736.             final Predefined factoryKey = Predefined.VEIS_1950;
  737.             FactoryManagedFrame frame = FRAMES.get(factoryKey);

  738.             if (frame == null) {
  739.                 // it's the first time we need this frame, build it and store it
  740.                 frame = new FactoryManagedFrame(FramesFactory.getGTOD(IERSConventions.IERS_1996, false, true),
  741.                                                 new VEISProvider(), true, factoryKey);
  742.                 FRAMES.put(factoryKey, frame);
  743.             }

  744.             return frame;

  745.         }
  746.     }

  747.     /** Get the equinox-based ITRF reference frame.
  748.      * @param conventions IERS conventions to apply
  749.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  750.      * @return the selected reference frame singleton.
  751.      * @exception OrekitException if data embedded in the library cannot be read
  752.      * @since 6.1
  753.      */
  754.     public static FactoryManagedFrame getITRFEquinox(final IERSConventions conventions,
  755.                                                      final boolean simpleEOP)
  756.         throws OrekitException {
  757.         synchronized (FramesFactory.class) {

  758.             // try to find an already built frame
  759.             final Predefined factoryKey;
  760.             switch (conventions) {
  761.                 case IERS_1996 :
  762.                     factoryKey = simpleEOP ?
  763.                                  Predefined.ITRF_EQUINOX_CONV_1996_SIMPLE_EOP :
  764.                                  Predefined.ITRF_EQUINOX_CONV_1996_ACCURATE_EOP;
  765.                     break;
  766.                 case IERS_2003 :
  767.                     factoryKey = simpleEOP ?
  768.                                  Predefined.ITRF_EQUINOX_CONV_2003_SIMPLE_EOP :
  769.                                  Predefined.ITRF_EQUINOX_CONV_2003_ACCURATE_EOP;
  770.                     break;
  771.                 case IERS_2010 :
  772.                     factoryKey = simpleEOP ?
  773.                                  Predefined.ITRF_EQUINOX_CONV_2010_SIMPLE_EOP :
  774.                                  Predefined.ITRF_EQUINOX_CONV_2010_ACCURATE_EOP;
  775.                     break;
  776.                 default :
  777.                     // this should never happen
  778.                     throw new OrekitInternalError(null);
  779.             }
  780.             FactoryManagedFrame frame = FRAMES.get(factoryKey);

  781.             if (frame == null) {
  782.                 // it's the first time we need this frame, build it and store it
  783.                 final Frame gtod = getGTOD(conventions, true, simpleEOP);
  784.                 final ShiftingTransformProvider gtodShifting =
  785.                         (ShiftingTransformProvider) gtod.getTransformProvider();
  786.                 final GTODProvider gtodRaw    = (GTODProvider) gtodShifting.getRawProvider();
  787.                 final EOPHistory   eopHistory = gtodRaw.getEOPHistory();
  788.                 frame = new FactoryManagedFrame(gtod, new ITRFProvider(eopHistory), false, factoryKey);
  789.                 FRAMES.put(factoryKey, frame);
  790.             }

  791.             return frame;

  792.         }
  793.     }

  794.     /** Get the GTOD reference frame.
  795.      * <p>
  796.      * The applyEOPCorr parameter is available mainly for testing purposes or for
  797.      * consistency with legacy software that don't handle EOP correction parameters.
  798.      * Beware that setting this parameter to {@code false} leads to crude accuracy
  799.      * (order of magnitudes for errors might be above 250m in LEO and 1400m in GEO).
  800.      * For this reason, setting this parameter to false is restricted to {@link
  801.      * IERSConventions#IERS_1996 IERS 1996} conventions, and hence the {@link
  802.      * IERSConventions IERS conventions} cannot be freely chosen here.
  803.      * </p>
  804.      * @param applyEOPCorr if true, EOP corrections are applied (here, dut1 and lod)
  805.      * @return the selected reference frame singleton.
  806.      * @exception OrekitException if data embedded in the library cannot be read
  807.      */
  808.     public static FactoryManagedFrame getGTOD(final boolean applyEOPCorr) throws OrekitException {
  809.         return getGTOD(IERSConventions.IERS_1996, applyEOPCorr, true);
  810.     }

  811.     /** Get the GTOD reference frame.
  812.      * @param conventions IERS conventions to apply
  813.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  814.      * @return the selected reference frame singleton.
  815.      * @exception OrekitException if data embedded in the library cannot be read
  816.      */
  817.     public static FactoryManagedFrame getGTOD(final IERSConventions conventions,
  818.                                               final boolean simpleEOP)
  819.         throws OrekitException {
  820.         return getGTOD(conventions, true, simpleEOP);
  821.     }

  822.     /** Get the GTOD reference frame.
  823.      * <p>
  824.      * The applyEOPCorr parameter is available mainly for testing purposes or for
  825.      * consistency with legacy software that don't handle EOP correction parameters.
  826.      * Beware that setting this parameter to {@code false} leads to crude accuracy
  827.      * (order of magnitudes for errors might be above 250m in LEO and 1400m in GEO).
  828.      * For this reason, setting this parameter to false is restricted to {@link
  829.      * IERSConventions#IERS_1996 IERS 1996} conventions, and hence this method is private.
  830.      * </p>
  831.      * @param conventions IERS conventions to apply
  832.      * @param applyEOPCorr if true, EOP corrections are applied (here, dut1 and lod)
  833.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  834.      * @return the selected reference frame singleton.
  835.      * @exception OrekitException if data embedded in the library cannot be read
  836.      */
  837.     private static FactoryManagedFrame getGTOD(final IERSConventions conventions,
  838.                                                final boolean applyEOPCorr,
  839.                                                final boolean simpleEOP)
  840.         throws OrekitException {

  841.         synchronized (FramesFactory.class) {

  842.             // try to find an already built frame
  843.             final Predefined factoryKey;
  844.             switch (conventions) {
  845.                 case IERS_1996 :
  846.                     factoryKey = applyEOPCorr ?
  847.                                  (simpleEOP ? Predefined.GTOD_CONVENTIONS_1996_SIMPLE_EOP : Predefined.GTOD_CONVENTIONS_1996_ACCURATE_EOP) :
  848.                                  Predefined.GTOD_WITHOUT_EOP_CORRECTIONS;
  849.                     break;
  850.                 case IERS_2003 :
  851.                     factoryKey = simpleEOP ?
  852.                                  Predefined.GTOD_CONVENTIONS_2003_SIMPLE_EOP :
  853.                                  Predefined.GTOD_CONVENTIONS_2003_ACCURATE_EOP;
  854.                     break;
  855.                 case IERS_2010 :
  856.                     factoryKey = simpleEOP ? Predefined.GTOD_CONVENTIONS_2010_SIMPLE_EOP :
  857.                                              Predefined.GTOD_CONVENTIONS_2010_ACCURATE_EOP;
  858.                     break;
  859.                 default :
  860.                     // this should never happen
  861.                     throw new OrekitInternalError(null);
  862.             }
  863.             FactoryManagedFrame frame = FRAMES.get(factoryKey);

  864.             if (frame == null) {
  865.                 // it's the first time we need this frame, build it and store it
  866.                 final Frame tod = getTOD(conventions, applyEOPCorr, simpleEOP);
  867.                 final ShiftingTransformProvider todInterpolating =
  868.                         (ShiftingTransformProvider) tod.getTransformProvider();
  869.                 final TODProvider       todRaw     = (TODProvider) todInterpolating.getRawProvider();
  870.                 final EOPHistory        eopHistory = todRaw.getEOPHistory();
  871.                 final GTODProvider      gtodRaw    = new GTODProvider(conventions, eopHistory);
  872.                 final TransformProvider gtodShifting =
  873.                         new ShiftingTransformProvider(gtodRaw,
  874.                                                       CartesianDerivativesFilter.USE_PVA,
  875.                                                       AngularDerivativesFilter.USE_R,
  876.                                                       AbsoluteDate.PAST_INFINITY, AbsoluteDate.FUTURE_INFINITY,
  877.                                                       todInterpolating.getGridPoints(), todInterpolating.getStep(),
  878.                                                       OrekitConfiguration.getCacheSlotsNumber(),
  879.                                                       Constants.JULIAN_YEAR, 30 * Constants.JULIAN_DAY);
  880.                 frame = new FactoryManagedFrame(tod, gtodShifting, false, factoryKey);
  881.                 FRAMES.put(factoryKey, frame);
  882.             }

  883.             return frame;

  884.         }
  885.     }

  886.     /** Get the TOD reference frame.
  887.      * <p>
  888.      * The applyEOPCorr parameter is available mainly for testing purposes or for
  889.      * consistency with legacy software that don't handle EOP correction parameters.
  890.      * Beware that setting this parameter to {@code false} leads to crude accuracy
  891.      * (order of magnitudes for errors might be above 1m in LEO and 10m in GEO).
  892.      * For this reason, setting this parameter to false is restricted to {@link
  893.      * IERSConventions#IERS_1996 IERS 1996} conventions, and hence the {@link
  894.      * IERSConventions IERS conventions} cannot be freely chosen here.
  895.      * </p>
  896.      * @param applyEOPCorr if true, EOP corrections are applied (here, nutation)
  897.      * @return the selected reference frame singleton.
  898.      * @exception OrekitException if data embedded in the library cannot be read
  899.      */
  900.     public static FactoryManagedFrame getTOD(final boolean applyEOPCorr)
  901.         throws OrekitException {
  902.         return getTOD(IERSConventions.IERS_1996, applyEOPCorr, false);
  903.     }

  904.     /** Get the TOD reference frame.
  905.      * @param conventions IERS conventions to apply
  906.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  907.      * @return the selected reference frame singleton.
  908.      * @exception OrekitException if data embedded in the library cannot be read
  909.      */
  910.     public static FactoryManagedFrame getTOD(final IERSConventions conventions,
  911.                                              final boolean simpleEOP)
  912.         throws OrekitException {
  913.         return getTOD(conventions, true, simpleEOP);
  914.     }

  915.     /** Get the TOD reference frame.
  916.      * <p>
  917.      * The applyEOPCorr parameter is available mainly for testing purposes or for
  918.      * consistency with legacy software that don't handle EOP correction parameters.
  919.      * Beware that setting this parameter to {@code false} leads to crude accuracy
  920.      * (order of magnitudes for errors might be above 1m in LEO and 10m in GEO).
  921.      * For this reason, setting this parameter to false is restricted to {@link
  922.      * IERSConventions#IERS_1996 IERS 1996} conventions, and hence this method is private.
  923.      * </p>
  924.      * @param conventions IERS conventions to apply
  925.      * @param applyEOPCorr if true, EOP corrections are applied (here, nutation)
  926.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  927.      * @return the selected reference frame singleton.
  928.      * @exception OrekitException if data embedded in the library cannot be read
  929.      */
  930.     private static FactoryManagedFrame getTOD(final IERSConventions conventions,
  931.                                               final boolean applyEOPCorr,
  932.                                               final boolean simpleEOP)
  933.         throws OrekitException {

  934.         synchronized (FramesFactory.class) {

  935.             // try to find an already built frame
  936.             final Predefined factoryKey;
  937.             switch (conventions) {
  938.                 case IERS_1996 :
  939.                     factoryKey = applyEOPCorr ?
  940.                                  (simpleEOP ? Predefined.TOD_CONVENTIONS_1996_SIMPLE_EOP : Predefined.TOD_CONVENTIONS_1996_ACCURATE_EOP) :
  941.                                  Predefined.TOD_WITHOUT_EOP_CORRECTIONS;
  942.                     break;
  943.                 case IERS_2003 :
  944.                     factoryKey = simpleEOP ?
  945.                                  Predefined.TOD_CONVENTIONS_2003_SIMPLE_EOP :
  946.                                      Predefined.TOD_CONVENTIONS_2003_ACCURATE_EOP;
  947.                     break;
  948.                 case IERS_2010 :
  949.                     factoryKey = simpleEOP ?
  950.                                  Predefined.TOD_CONVENTIONS_2010_SIMPLE_EOP :
  951.                                  Predefined.TOD_CONVENTIONS_2010_ACCURATE_EOP;
  952.                     break;
  953.                 default :
  954.                     // this should never happen
  955.                     throw new OrekitInternalError(null);
  956.             }
  957.             final int interpolationPoints;
  958.             final int pointsPerDay;
  959.             if (applyEOPCorr) {
  960.                 interpolationPoints = 6;
  961.                 pointsPerDay        = 24;
  962.             } else {
  963.                 interpolationPoints = 6;
  964.                 pointsPerDay        = 8;
  965.             }
  966.             FactoryManagedFrame frame = FRAMES.get(factoryKey);

  967.             if (frame == null) {
  968.                 // it's the first time we need this frame, build it and store it
  969.                 final EOPHistory eopHistory = applyEOPCorr ? getEOPHistory(conventions, simpleEOP) : null;
  970.                 final TransformProvider shifting =
  971.                         new ShiftingTransformProvider(new TODProvider(conventions, eopHistory),
  972.                                                       CartesianDerivativesFilter.USE_PVA,
  973.                                                       AngularDerivativesFilter.USE_R,
  974.                                                       AbsoluteDate.PAST_INFINITY, AbsoluteDate.FUTURE_INFINITY,
  975.                                                       interpolationPoints, Constants.JULIAN_DAY / pointsPerDay,
  976.                                                       OrekitConfiguration.getCacheSlotsNumber(),
  977.                                                       Constants.JULIAN_YEAR, 30 * Constants.JULIAN_DAY);
  978.                 frame = new FactoryManagedFrame(getMOD(conventions, applyEOPCorr), shifting, true, factoryKey);
  979.                 FRAMES.put(factoryKey, frame);
  980.             }

  981.             return frame;

  982.         }
  983.     }

  984.     /** Get the MOD reference frame.
  985.      * <p>
  986.      * The applyEOPCorr parameter is available mainly for testing purposes or for
  987.      * consistency with legacy software that don't handle EOP correction parameters.
  988.      * Beware that setting this parameter to {@code false} leads to crude accuracy
  989.      * (order of magnitudes for errors might be above 1m in LEO and 10m in GEO).
  990.      * For this reason, setting this parameter to false is restricted to {@link
  991.      * IERSConventions#IERS_1996 IERS 1996} conventions, and hence the {@link
  992.      * IERSConventions IERS conventions} cannot be freely chosen here.
  993.      * </p>
  994.      * @param applyEOPCorr if true, EOP corrections are applied (EME2000/GCRF bias compensation)
  995.      * @return the selected reference frame singleton.
  996.      * @exception OrekitException if data embedded in the library cannot be read
  997.      */
  998.     public static FactoryManagedFrame getMOD(final boolean applyEOPCorr)
  999.         throws OrekitException {
  1000.         return getMOD(IERSConventions.IERS_1996, applyEOPCorr);
  1001.     }

  1002.     /** Get the MOD reference frame.
  1003.      * @param conventions IERS conventions to apply
  1004.      * @return the selected reference frame singleton.
  1005.      * @exception OrekitException if data embedded in the library cannot be read
  1006.      */
  1007.     public static FactoryManagedFrame getMOD(final IERSConventions conventions)
  1008.         throws OrekitException {
  1009.         return getMOD(conventions, true);
  1010.     }

  1011.     /** Get the MOD reference frame.
  1012.      * <p>
  1013.      * The applyEOPCorr parameter is available mainly for testing purposes or for
  1014.      * consistency with legacy software that don't handle EOP correction parameters.
  1015.      * Beware that setting this parameter to {@code false} leads to crude accuracy
  1016.      * (order of magnitudes for errors might be above 1m in LEO and 10m in GEO).
  1017.      * For this reason, setting this parameter to false is restricted to {@link
  1018.      * IERSConventions#IERS_1996 IERS 1996} conventions, and hence this method is private.
  1019.      * </p>
  1020.      * @param conventions IERS conventions to apply
  1021.      * @param applyEOPCorr if true, EOP corrections are applied (EME2000/GCRF bias compensation)
  1022.      * @return the selected reference frame singleton.
  1023.      * @exception OrekitException if data embedded in the library cannot be read
  1024.      */
  1025.     private static FactoryManagedFrame getMOD(final IERSConventions conventions, final boolean applyEOPCorr)
  1026.         throws OrekitException {

  1027.         synchronized (FramesFactory.class) {

  1028.             final Predefined factoryKey;
  1029.             final Frame parent;
  1030.             switch (conventions) {
  1031.                 case IERS_1996 :
  1032.                     factoryKey = applyEOPCorr ? Predefined.MOD_CONVENTIONS_1996 : Predefined.MOD_WITHOUT_EOP_CORRECTIONS;
  1033.                     parent     = applyEOPCorr ? FramesFactory.getGCRF() : FramesFactory.getEME2000();
  1034.                     break;
  1035.                 case IERS_2003 :
  1036.                     factoryKey = Predefined.MOD_CONVENTIONS_2003;
  1037.                     // in IERS conventions 2003, the precession angles zetaA, thetaA and zA
  1038.                     // from equation 33 are computed from EME2000, not from GCRF
  1039.                     parent     = FramesFactory.getEME2000();
  1040.                     break;
  1041.                 case IERS_2010 :
  1042.                     factoryKey = Predefined.MOD_CONVENTIONS_2010;
  1043.                     // precession angles epsilon0, psiA, omegaA and chiA
  1044.                     // from equations 5.39 and 5.40 are computed from EME2000
  1045.                     parent     = FramesFactory.getEME2000();
  1046.                     break;
  1047.                 default :
  1048.                     // this should never happen
  1049.                     throw new OrekitInternalError(null);
  1050.             }

  1051.             // try to find an already built frame
  1052.             FactoryManagedFrame frame = FRAMES.get(factoryKey);

  1053.             if (frame == null) {
  1054.                 // it's the first time we need this frame, build it and store it
  1055.                 frame = new FactoryManagedFrame(parent, new MODProvider(conventions), true, factoryKey);
  1056.                 FRAMES.put(factoryKey, frame);
  1057.             }

  1058.             return frame;

  1059.         }
  1060.     }

  1061.     /** Get the TEME reference frame.
  1062.      * <p>
  1063.      * The TEME frame is used for the SGP4 model in TLE propagation. This frame has <em>no</em>
  1064.      * official definition and there are some ambiguities about whether it should be used
  1065.      * as "of date" or "of epoch". This frame should therefore be used <em>only</em> for
  1066.      * TLE propagation and not for anything else, as recommended by the CCSDS Orbit Data Message
  1067.      * blue book.
  1068.      * </p>
  1069.      * @return the selected reference frame singleton.
  1070.      * @exception OrekitException if data embedded in the library cannot be read
  1071.      */
  1072.     public static FactoryManagedFrame getTEME() throws OrekitException {
  1073.         synchronized (FramesFactory.class) {

  1074.             // try to find an already built frame
  1075.             final Predefined factoryKey = Predefined.TEME;
  1076.             FactoryManagedFrame frame = FRAMES.get(factoryKey);

  1077.             if (frame == null) {
  1078.                 // it's the first time we need this frame, build it and store it
  1079.                 final Frame tod = getTOD(IERSConventions.IERS_1996, false, true);
  1080.                 final ShiftingTransformProvider todShifting =
  1081.                         (ShiftingTransformProvider) tod.getTransformProvider();
  1082.                 final TEMEProvider temeRaw = new TEMEProvider(IERSConventions.IERS_1996, null);
  1083.                 final TransformProvider temeShifting =
  1084.                         new ShiftingTransformProvider(temeRaw,
  1085.                                                       CartesianDerivativesFilter.USE_PVA,
  1086.                                                       AngularDerivativesFilter.USE_R,
  1087.                                                       AbsoluteDate.PAST_INFINITY, AbsoluteDate.FUTURE_INFINITY,
  1088.                                                       todShifting.getGridPoints(), todShifting.getStep(),
  1089.                                                       OrekitConfiguration.getCacheSlotsNumber(),
  1090.                                                       Constants.JULIAN_YEAR, 30 * Constants.JULIAN_DAY);

  1091.                 frame = new FactoryManagedFrame(tod, temeShifting, true, factoryKey);
  1092.                 FRAMES.put(factoryKey, frame);
  1093.             }

  1094.             return frame;

  1095.         }
  1096.     }

  1097.     /** Get the transform between two frames, suppressing all interpolation.
  1098.      * <p>
  1099.      * This method is similar to {@link Frame#getTransformTo(Frame, AbsoluteDate)}
  1100.      * except it removes the performance enhancing interpolation features that are
  1101.      * added by the {@link FramesFactory factory} to some frames, in order to focus
  1102.      * on accuracy. The interpolation features are intended to save processing time
  1103.      * by avoiding doing some lengthy computation like nutation evaluation at each
  1104.      * time step and caching some results. This method can be used to avoid this,
  1105.      * when very high accuracy is desired, or for testing purposes. It should be
  1106.      * used with care, as doing the full computation is <em>really</em> costly for
  1107.      * some frames.
  1108.      * </p>
  1109.      * @param from frame from which transformation starts
  1110.      * @param to frame to which transformation ends
  1111.      * @param date date of the transform
  1112.      * @return transform between the two frames, avoiding interpolation
  1113.      * @throws OrekitException if transform cannot be computed at this date
  1114.      */
  1115.     public static Transform getNonInterpolatingTransform(final Frame from, final Frame to,
  1116.                                                          final AbsoluteDate date)
  1117.         throws OrekitException {

  1118.         // common ancestor to both frames in the frames tree
  1119.         Frame currentF = from.getDepth() > to.getDepth() ? from.getAncestor(from.getDepth() - to.getDepth()) : from;
  1120.         Frame currentT = from.getDepth() > to.getDepth() ? to : to.getAncestor(to.getDepth() - from.getDepth());
  1121.         while (currentF != currentT) {
  1122.             currentF = currentF.getParent();
  1123.             currentT = currentT.getParent();
  1124.         }
  1125.         final Frame common = currentF;

  1126.         // transform from common to origin
  1127.         Transform commonToOrigin = Transform.IDENTITY;
  1128.         for (Frame frame = from; frame != common; frame = frame.getParent()) {
  1129.             commonToOrigin = new Transform(date,
  1130.                                              peel(frame.getTransformProvider()).getTransform(date),
  1131.                                              commonToOrigin);
  1132.         }

  1133.         // transform from destination up to common
  1134.         Transform commonToDestination = Transform.IDENTITY;
  1135.         for (Frame frame = to; frame != common; frame = frame.getParent()) {
  1136.             commonToDestination = new Transform(date,
  1137.                                                 peel(frame.getTransformProvider()).getTransform(date),
  1138.                                                 commonToDestination);
  1139.         }

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

  1142.     }

  1143.     /** Peel interpolation and shifting from a transform provider.
  1144.      * @param provider transform provider to peel
  1145.      * @return peeled transform provider
  1146.      * @exception OrekitException if EOP cannot be retrieved
  1147.      */
  1148.     private static TransformProvider peel(final TransformProvider provider)
  1149.         throws OrekitException {

  1150.         TransformProvider peeled = provider;

  1151.         boolean peeling = true;
  1152.         while (peeling) {
  1153.             if (peeled instanceof InterpolatingTransformProvider) {
  1154.                 peeled = ((InterpolatingTransformProvider) peeled).getRawProvider();
  1155.             } else if (peeled instanceof ShiftingTransformProvider) {
  1156.                 peeled = ((ShiftingTransformProvider) peeled).getRawProvider();
  1157.             } else if (peeled instanceof EOPBasedTransformProvider &&
  1158.                        ((EOPBasedTransformProvider) peeled).getEOPHistory().usesInterpolation()) {
  1159.                 peeled = ((EOPBasedTransformProvider) peeled).getNonInterpolatingProvider();
  1160.             } else {
  1161.                 peeling = false;
  1162.             }
  1163.         }

  1164.         return peeled;

  1165.     }

  1166. }