AbstractFrames.java

  1. /* Contributed in the public domain.
  2.  * Licensed to CS GROUP (CS) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * CS licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *   http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.orekit.frames;

  18. import java.io.Serializable;
  19. import java.util.HashMap;
  20. import java.util.Map;
  21. import java.util.function.Supplier;

  22. import org.orekit.bodies.CelestialBodies;
  23. import org.orekit.errors.OrekitInternalError;
  24. import org.orekit.time.AbsoluteDate;
  25. import org.orekit.time.TimeScales;
  26. import org.orekit.utils.AngularDerivativesFilter;
  27. import org.orekit.utils.CartesianDerivativesFilter;
  28. import org.orekit.utils.Constants;
  29. import org.orekit.utils.IERSConventions;
  30. import org.orekit.utils.OrekitConfiguration;

  31. /**
  32.  * This class is an implementation of {@link Frames} that creates frames when they are
  33.  * first used and uses synchronization to ensure that each frame is only created once.
  34.  *
  35.  * @author Guylaine Prat
  36.  * @author Luc Maisonobe
  37.  * @author Pascal Parraud
  38.  * @author Evan Ward
  39.  * @see LazyLoadedFrames
  40.  * @see #getEOPHistory(IERSConventions, boolean)
  41.  * @since 10.1
  42.  */
  43. public abstract class AbstractFrames implements Frames {

  44.     /** Provider of common time scales. */
  45.     private final TimeScales timeScales;
  46.     /** Provider of the ICRF frame, usually delegated to {@link CelestialBodies}. */
  47.     private final Supplier<Frame> icrfSupplier;
  48.     /** Predefined frames. */
  49.     private transient Map<Predefined, FactoryManagedFrame> frames;
  50.     /** Predefined versioned ITRF frames. */
  51.     private transient Map<ITRFKey, VersionedITRF> versionedItrfFrames;

  52.     /**
  53.      * Simple constructor.
  54.      *
  55.      * @param timeScales   to use when creating frames.
  56.      * @param icrfSupplier used to implement {@link #getICRF()};
  57.      */
  58.     public AbstractFrames(final TimeScales timeScales,
  59.                           final Supplier<Frame> icrfSupplier) {
  60.         this.timeScales = timeScales;
  61.         this.icrfSupplier = icrfSupplier;
  62.         this.frames = new HashMap<>();
  63.         this.versionedItrfFrames = new HashMap<>();
  64.     }

  65.     @Override
  66.     public Frame getFrame(final Predefined factoryKey) {
  67.         switch (factoryKey) {
  68.             case GCRF :
  69.                 return getGCRF();
  70.             case ICRF :
  71.                 return getICRF();
  72.             case ECLIPTIC_CONVENTIONS_1996 :
  73.                 return getEcliptic(IERSConventions.IERS_1996);
  74.             case ECLIPTIC_CONVENTIONS_2003 :
  75.                 return getEcliptic(IERSConventions.IERS_2003);
  76.             case ECLIPTIC_CONVENTIONS_2010 :
  77.                 return getEcliptic(IERSConventions.IERS_2010);
  78.             case EME2000 :
  79.                 return getEME2000();
  80.             case ITRF_CIO_CONV_2010_SIMPLE_EOP :
  81.                 return getITRF(IERSConventions.IERS_2010, true);
  82.             case ITRF_CIO_CONV_2010_ACCURATE_EOP :
  83.                 return getITRF(IERSConventions.IERS_2010, false);
  84.             case ITRF_CIO_CONV_2003_SIMPLE_EOP :
  85.                 return getITRF(IERSConventions.IERS_2003, true);
  86.             case ITRF_CIO_CONV_2003_ACCURATE_EOP :
  87.                 return getITRF(IERSConventions.IERS_2003, false);
  88.             case ITRF_CIO_CONV_1996_SIMPLE_EOP :
  89.                 return getITRF(IERSConventions.IERS_1996, true);
  90.             case ITRF_CIO_CONV_1996_ACCURATE_EOP :
  91.                 return getITRF(IERSConventions.IERS_1996, false);
  92.             case ITRF_EQUINOX_CONV_2010_SIMPLE_EOP :
  93.                 return getITRFEquinox(IERSConventions.IERS_2010, true);
  94.             case ITRF_EQUINOX_CONV_2010_ACCURATE_EOP :
  95.                 return getITRFEquinox(IERSConventions.IERS_2010, false);
  96.             case ITRF_EQUINOX_CONV_2003_SIMPLE_EOP :
  97.                 return getITRFEquinox(IERSConventions.IERS_2003, true);
  98.             case ITRF_EQUINOX_CONV_2003_ACCURATE_EOP :
  99.                 return getITRFEquinox(IERSConventions.IERS_2003, false);
  100.             case ITRF_EQUINOX_CONV_1996_SIMPLE_EOP :
  101.                 return getITRFEquinox(IERSConventions.IERS_1996, true);
  102.             case ITRF_EQUINOX_CONV_1996_ACCURATE_EOP :
  103.                 return getITRFEquinox(IERSConventions.IERS_1996, false);
  104.             case TIRF_CONVENTIONS_2010_SIMPLE_EOP :
  105.                 return getTIRF(IERSConventions.IERS_2010, true);
  106.             case TIRF_CONVENTIONS_2010_ACCURATE_EOP :
  107.                 return getTIRF(IERSConventions.IERS_2010, false);
  108.             case TIRF_CONVENTIONS_2003_SIMPLE_EOP :
  109.                 return getTIRF(IERSConventions.IERS_2003, true);
  110.             case TIRF_CONVENTIONS_2003_ACCURATE_EOP :
  111.                 return getTIRF(IERSConventions.IERS_2003, false);
  112.             case TIRF_CONVENTIONS_1996_SIMPLE_EOP :
  113.                 return getTIRF(IERSConventions.IERS_1996, true);
  114.             case TIRF_CONVENTIONS_1996_ACCURATE_EOP :
  115.                 return getTIRF(IERSConventions.IERS_1996, false);
  116.             case CIRF_CONVENTIONS_2010_ACCURATE_EOP :
  117.                 return getCIRF(IERSConventions.IERS_2010, false);
  118.             case CIRF_CONVENTIONS_2010_SIMPLE_EOP :
  119.                 return getCIRF(IERSConventions.IERS_2010, true);
  120.             case CIRF_CONVENTIONS_2003_ACCURATE_EOP :
  121.                 return getCIRF(IERSConventions.IERS_2003, false);
  122.             case CIRF_CONVENTIONS_2003_SIMPLE_EOP :
  123.                 return getCIRF(IERSConventions.IERS_2003, true);
  124.             case CIRF_CONVENTIONS_1996_ACCURATE_EOP :
  125.                 return getCIRF(IERSConventions.IERS_1996, false);
  126.             case CIRF_CONVENTIONS_1996_SIMPLE_EOP :
  127.                 return getCIRF(IERSConventions.IERS_1996, true);
  128.             case VEIS_1950 :
  129.                 return getVeis1950();
  130.             case GTOD_WITHOUT_EOP_CORRECTIONS :
  131.                 return getGTOD(IERSConventions.IERS_1996, false, true);
  132.             case GTOD_CONVENTIONS_2010_ACCURATE_EOP :
  133.                 return getGTOD(IERSConventions.IERS_2010, true, false);
  134.             case GTOD_CONVENTIONS_2010_SIMPLE_EOP :
  135.                 return getGTOD(IERSConventions.IERS_2010, true, true);
  136.             case GTOD_CONVENTIONS_2003_ACCURATE_EOP :
  137.                 return getGTOD(IERSConventions.IERS_2003, true, false);
  138.             case GTOD_CONVENTIONS_2003_SIMPLE_EOP :
  139.                 return getGTOD(IERSConventions.IERS_2003, true, true);
  140.             case GTOD_CONVENTIONS_1996_ACCURATE_EOP :
  141.                 return getGTOD(IERSConventions.IERS_1996, true, false);
  142.             case GTOD_CONVENTIONS_1996_SIMPLE_EOP :
  143.                 return getGTOD(IERSConventions.IERS_1996, true, true);
  144.             case TOD_WITHOUT_EOP_CORRECTIONS :
  145.                 return getTOD(IERSConventions.IERS_1996, false, true);
  146.             case TOD_CONVENTIONS_2010_ACCURATE_EOP :
  147.                 return getTOD(IERSConventions.IERS_2010, true, false);
  148.             case TOD_CONVENTIONS_2010_SIMPLE_EOP :
  149.                 return getTOD(IERSConventions.IERS_2010, true, true);
  150.             case TOD_CONVENTIONS_2003_ACCURATE_EOP :
  151.                 return getTOD(IERSConventions.IERS_2003, true, false);
  152.             case TOD_CONVENTIONS_2003_SIMPLE_EOP :
  153.                 return getTOD(IERSConventions.IERS_2003, true, true);
  154.             case TOD_CONVENTIONS_1996_ACCURATE_EOP :
  155.                 return getTOD(IERSConventions.IERS_1996, true, false);
  156.             case TOD_CONVENTIONS_1996_SIMPLE_EOP :
  157.                 return getTOD(IERSConventions.IERS_1996, true, true);
  158.             case MOD_WITHOUT_EOP_CORRECTIONS :
  159.                 return getMOD(IERSConventions.IERS_1996, false);
  160.             case MOD_CONVENTIONS_2010 :
  161.                 return getMOD(IERSConventions.IERS_2010, true);
  162.             case MOD_CONVENTIONS_2003 :
  163.                 return getMOD(IERSConventions.IERS_2003, true);
  164.             case MOD_CONVENTIONS_1996 :
  165.                 return getMOD(IERSConventions.IERS_1996, true);
  166.             case TEME :
  167.                 return getTEME();
  168.             case PZ90_11 :
  169.                 return getPZ9011(IERSConventions.IERS_2010, true);
  170.             default :
  171.                 // this should never happen
  172.                 throw new OrekitInternalError(null);
  173.         }
  174.     }

  175.     @Override
  176.     public Frame getGCRF() {
  177.         return Frame.getRoot();
  178.     }

  179.     @Override
  180.     public Frame getICRF() {
  181.         return icrfSupplier.get();
  182.     }

  183.     @Override
  184.     public Frame getEcliptic(final IERSConventions conventions) {
  185.         synchronized (this) {

  186.             final Predefined factoryKey;
  187.             switch (conventions) {
  188.                 case IERS_1996 :
  189.                     factoryKey = Predefined.ECLIPTIC_CONVENTIONS_1996;
  190.                     break;
  191.                 case IERS_2003 :
  192.                     factoryKey = Predefined.ECLIPTIC_CONVENTIONS_2003;
  193.                     break;
  194.                 case IERS_2010 :
  195.                     factoryKey = Predefined.ECLIPTIC_CONVENTIONS_2010;
  196.                     break;
  197.                 default :
  198.                     // this should never happen
  199.                     throw new OrekitInternalError(null);
  200.             }
  201.             final Frame parent = getMOD(conventions);

  202.             // try to find an already built frame
  203.             FactoryManagedFrame frame = frames.get(factoryKey);

  204.             if (frame == null) {
  205.                 // it's the first time we need this frame, build it and store it
  206.                 final EclipticProvider provider =
  207.                         new EclipticProvider(conventions, getTimeScales());
  208.                 frame = new FactoryManagedFrame(parent, provider, true, factoryKey);
  209.                 frames.put(factoryKey, frame);
  210.             }

  211.             return frame;

  212.         }
  213.     }

  214.     @Override
  215.     public FactoryManagedFrame getEME2000() {
  216.         synchronized (this) {

  217.             // try to find an already built frame
  218.             FactoryManagedFrame frame = frames.get(Predefined.EME2000);

  219.             if (frame == null) {
  220.                 // it's the first time we need this frame, build it and store it
  221.                 frame = new FactoryManagedFrame(getGCRF(), new EME2000Provider(), true, Predefined.EME2000);
  222.                 frames.put(Predefined.EME2000, frame);
  223.             }

  224.             return frame;

  225.         }
  226.     }

  227.     @Override
  228.     public FactoryManagedFrame getITRF(final IERSConventions conventions,
  229.                                        final boolean simpleEOP) {
  230.         synchronized (this) {

  231.             // try to find an already built frame
  232.             final Predefined factoryKey;
  233.             switch (conventions) {
  234.                 case IERS_1996 :
  235.                     factoryKey = simpleEOP ?
  236.                             Predefined.ITRF_CIO_CONV_1996_SIMPLE_EOP :
  237.                             Predefined.ITRF_CIO_CONV_1996_ACCURATE_EOP;
  238.                     break;
  239.                 case IERS_2003 :
  240.                     factoryKey = simpleEOP ?
  241.                             Predefined.ITRF_CIO_CONV_2003_SIMPLE_EOP :
  242.                             Predefined.ITRF_CIO_CONV_2003_ACCURATE_EOP;
  243.                     break;
  244.                 case IERS_2010 :
  245.                     factoryKey = simpleEOP ?
  246.                             Predefined.ITRF_CIO_CONV_2010_SIMPLE_EOP :
  247.                             Predefined.ITRF_CIO_CONV_2010_ACCURATE_EOP;
  248.                     break;
  249.                 default :
  250.                     // this should never happen
  251.                     throw new OrekitInternalError(null);
  252.             }
  253.             FactoryManagedFrame frame = frames.get(factoryKey);

  254.             if (frame == null) {
  255.                 // it's the first time we need this frame, build it and store it
  256.                 final Frame tirfFrame = getTIRF(conventions, simpleEOP);
  257.                 final TIRFProvider tirfProvider = (TIRFProvider) tirfFrame.getTransformProvider();
  258.                 frame = new FactoryManagedFrame(tirfFrame,
  259.                         new ITRFProvider(tirfProvider.getEOPHistory()),
  260.                         false, factoryKey);
  261.                 frames.put(factoryKey, frame);
  262.             }

  263.             return frame;

  264.         }
  265.     }

  266.     @Override
  267.     public FactoryManagedFrame getTIRF(final IERSConventions conventions) {
  268.         return getTIRF(conventions, true);
  269.     }

  270.     @Override
  271.     public VersionedITRF getITRF(final ITRFVersion version,
  272.                                  final IERSConventions conventions,
  273.                                  final boolean simpleEOP) {
  274.         synchronized (this) {
  275.             // try to find an already built frame
  276.             final ITRFKey key = new ITRFKey(version, conventions, simpleEOP);
  277.             VersionedITRF frame = versionedItrfFrames.get(key);

  278.             if (frame == null) {
  279.                 // it's the first time we need this frame, build it and store it
  280.                 final FactoryManagedFrame rawITRF = getITRF(conventions, simpleEOP);
  281.                 frame = new VersionedITRF(rawITRF.getParent(), version,
  282.                         (ITRFProvider) rawITRF.getTransformProvider(),
  283.                         version.toString().replace('_', '-') +
  284.                                 "/" +
  285.                                 rawITRF.getName(),
  286.                         getTimeScales().getTT());
  287.                 versionedItrfFrames.put(key, frame);
  288.             }

  289.             return frame;

  290.         }
  291.     }

  292.     @Override
  293.     public FactoryManagedFrame getTIRF(final IERSConventions conventions,
  294.                                        final boolean simpleEOP) {
  295.         synchronized (this) {

  296.             // try to find an already built frame
  297.             final Predefined factoryKey;
  298.             switch (conventions) {
  299.                 case IERS_1996 :
  300.                     factoryKey = simpleEOP ?
  301.                             Predefined.TIRF_CONVENTIONS_1996_SIMPLE_EOP :
  302.                             Predefined.TIRF_CONVENTIONS_1996_ACCURATE_EOP;
  303.                     break;
  304.                 case IERS_2003 :
  305.                     factoryKey = simpleEOP ?
  306.                             Predefined.TIRF_CONVENTIONS_2003_SIMPLE_EOP :
  307.                             Predefined.TIRF_CONVENTIONS_2003_ACCURATE_EOP;
  308.                     break;
  309.                 case IERS_2010 :
  310.                     factoryKey = simpleEOP ?
  311.                             Predefined.TIRF_CONVENTIONS_2010_SIMPLE_EOP :
  312.                             Predefined.TIRF_CONVENTIONS_2010_ACCURATE_EOP;
  313.                     break;
  314.                 default :
  315.                     // this should never happen
  316.                     throw new OrekitInternalError(null);
  317.             }
  318.             FactoryManagedFrame frame = frames.get(factoryKey);

  319.             if (frame == null) {
  320.                 // it's the first time we need this frame, build it and store it
  321.                 final Frame cirf = getCIRF(conventions, simpleEOP);
  322.                 final ShiftingTransformProvider cirfInterpolating =
  323.                         (ShiftingTransformProvider) cirf.getTransformProvider();
  324.                 final CIRFProvider cirfRaw = (CIRFProvider) cirfInterpolating.getRawProvider();
  325.                 final EOPHistory eopHistory = cirfRaw.getEOPHistory();
  326.                 final TIRFProvider provider =
  327.                         new TIRFProvider(eopHistory, getTimeScales().getUT1(conventions, simpleEOP));
  328.                 frame = new FactoryManagedFrame(cirf, provider, false, factoryKey);
  329.                 frames.put(factoryKey, frame);
  330.             }

  331.             return frame;

  332.         }
  333.     }

  334.     @Override
  335.     public FactoryManagedFrame getCIRF(final IERSConventions conventions,
  336.                                        final boolean simpleEOP) {
  337.         synchronized (this) {

  338.             // try to find an already built frame
  339.             final Predefined factoryKey;
  340.             switch (conventions) {
  341.                 case IERS_1996 :
  342.                     factoryKey = simpleEOP ?
  343.                             Predefined.CIRF_CONVENTIONS_1996_SIMPLE_EOP :
  344.                             Predefined.CIRF_CONVENTIONS_1996_ACCURATE_EOP;
  345.                     break;
  346.                 case IERS_2003 :
  347.                     factoryKey = simpleEOP ?
  348.                             Predefined.CIRF_CONVENTIONS_2003_SIMPLE_EOP :
  349.                             Predefined.CIRF_CONVENTIONS_2003_ACCURATE_EOP;
  350.                     break;
  351.                 case IERS_2010 :
  352.                     factoryKey = simpleEOP ?
  353.                             Predefined.CIRF_CONVENTIONS_2010_SIMPLE_EOP :
  354.                             Predefined.CIRF_CONVENTIONS_2010_ACCURATE_EOP;
  355.                     break;
  356.                 default :
  357.                     // this should never happen
  358.                     throw new OrekitInternalError(null);
  359.             }
  360.             FactoryManagedFrame frame = frames.get(factoryKey);

  361.             if (frame == null) {
  362.                 // it's the first time we need this frame, build it and store it
  363.                 final EOPHistory eopHistory = getEOPHistory(conventions, simpleEOP);
  364.                 final TransformProvider shifting =
  365.                         new ShiftingTransformProvider(new CIRFProvider(eopHistory),
  366.                                 CartesianDerivativesFilter.USE_PVA,
  367.                                 AngularDerivativesFilter.USE_R,
  368.                                 6, Constants.JULIAN_DAY / 24,
  369.                                 OrekitConfiguration.getCacheSlotsNumber(),
  370.                                 Constants.JULIAN_YEAR, 30 * Constants.JULIAN_DAY);
  371.                 frame = new FactoryManagedFrame(getGCRF(), shifting, true, factoryKey);
  372.                 frames.put(factoryKey, frame);
  373.             }

  374.             return frame;

  375.         }
  376.     }

  377.     @Override
  378.     public FactoryManagedFrame getVeis1950() {
  379.         synchronized (this) {

  380.             // try to find an already built frame
  381.             final Predefined factoryKey = Predefined.VEIS_1950;
  382.             FactoryManagedFrame frame = frames.get(factoryKey);

  383.             if (frame == null) {
  384.                 // it's the first time we need this frame, build it and store it
  385.                 frame = new FactoryManagedFrame(getGTOD(IERSConventions.IERS_1996, false, true),
  386.                         new VEISProvider(getTimeScales()), true, factoryKey);
  387.                 frames.put(factoryKey, frame);
  388.             }

  389.             return frame;

  390.         }
  391.     }

  392.     @Override
  393.     public FactoryManagedFrame getITRFEquinox(final IERSConventions conventions,
  394.                                               final boolean simpleEOP) {
  395.         synchronized (this) {

  396.             // try to find an already built frame
  397.             final Predefined factoryKey;
  398.             switch (conventions) {
  399.                 case IERS_1996 :
  400.                     factoryKey = simpleEOP ?
  401.                             Predefined.ITRF_EQUINOX_CONV_1996_SIMPLE_EOP :
  402.                             Predefined.ITRF_EQUINOX_CONV_1996_ACCURATE_EOP;
  403.                     break;
  404.                 case IERS_2003 :
  405.                     factoryKey = simpleEOP ?
  406.                             Predefined.ITRF_EQUINOX_CONV_2003_SIMPLE_EOP :
  407.                             Predefined.ITRF_EQUINOX_CONV_2003_ACCURATE_EOP;
  408.                     break;
  409.                 case IERS_2010 :
  410.                     factoryKey = simpleEOP ?
  411.                             Predefined.ITRF_EQUINOX_CONV_2010_SIMPLE_EOP :
  412.                             Predefined.ITRF_EQUINOX_CONV_2010_ACCURATE_EOP;
  413.                     break;
  414.                 default :
  415.                     // this should never happen
  416.                     throw new OrekitInternalError(null);
  417.             }
  418.             FactoryManagedFrame frame = frames.get(factoryKey);

  419.             if (frame == null) {
  420.                 // it's the first time we need this frame, build it and store it
  421.                 final Frame gtod = getGTOD(conventions, true, simpleEOP);
  422.                 final ShiftingTransformProvider gtodShifting =
  423.                         (ShiftingTransformProvider) gtod.getTransformProvider();
  424.                 final GTODProvider gtodRaw    = (GTODProvider) gtodShifting.getRawProvider();
  425.                 final EOPHistory   eopHistory = gtodRaw.getEOPHistory();
  426.                 frame = new FactoryManagedFrame(gtod, new ITRFProvider(eopHistory), false, factoryKey);
  427.                 frames.put(factoryKey, frame);
  428.             }

  429.             return frame;

  430.         }
  431.     }

  432.     @Override
  433.     public FactoryManagedFrame getGTOD(final boolean applyEOPCorr) {
  434.         return getGTOD(IERSConventions.IERS_1996, applyEOPCorr, true);
  435.     }

  436.     @Override
  437.     public FactoryManagedFrame getGTOD(final IERSConventions conventions,
  438.                                        final boolean simpleEOP) {
  439.         return getGTOD(conventions, true, simpleEOP);
  440.     }

  441.     /** Get the GTOD reference frame.
  442.      * <p>
  443.      * The applyEOPCorr parameter is available mainly for testing purposes or for
  444.      * consistency with legacy software that don't handle EOP correction parameters.
  445.      * Beware that setting this parameter to {@code false} leads to crude accuracy
  446.      * (order of magnitudes for errors might be above 250m in LEO and 1400m in GEO).
  447.      * For this reason, setting this parameter to false is restricted to {@link
  448.      * IERSConventions#IERS_1996 IERS 1996} conventions, and hence this method is private.
  449.      * </p>
  450.      * @param conventions IERS conventions to apply
  451.      * @param applyEOPCorr if true, EOP corrections are applied (here, dut1 and lod)
  452.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  453.      * @return the selected reference frame singleton.
  454.      */
  455.     private FactoryManagedFrame getGTOD(final IERSConventions conventions,
  456.                                                final boolean applyEOPCorr,
  457.                                                final boolean simpleEOP) {

  458.         synchronized (this) {

  459.             // try to find an already built frame
  460.             final Predefined factoryKey;
  461.             switch (conventions) {
  462.                 case IERS_1996 :
  463.                     factoryKey = applyEOPCorr ?
  464.                             (simpleEOP ? Predefined.GTOD_CONVENTIONS_1996_SIMPLE_EOP : Predefined.GTOD_CONVENTIONS_1996_ACCURATE_EOP) :
  465.                             Predefined.GTOD_WITHOUT_EOP_CORRECTIONS;
  466.                     break;
  467.                 case IERS_2003 :
  468.                     factoryKey = simpleEOP ?
  469.                             Predefined.GTOD_CONVENTIONS_2003_SIMPLE_EOP :
  470.                             Predefined.GTOD_CONVENTIONS_2003_ACCURATE_EOP;
  471.                     break;
  472.                 case IERS_2010 :
  473.                     factoryKey = simpleEOP ? Predefined.GTOD_CONVENTIONS_2010_SIMPLE_EOP :
  474.                             Predefined.GTOD_CONVENTIONS_2010_ACCURATE_EOP;
  475.                     break;
  476.                 default :
  477.                     // this should never happen
  478.                     throw new OrekitInternalError(null);
  479.             }
  480.             FactoryManagedFrame frame = frames.get(factoryKey);

  481.             if (frame == null) {
  482.                 // it's the first time we need this frame, build it and store it
  483.                 final Frame tod = getTOD(conventions, applyEOPCorr, simpleEOP);
  484.                 final ShiftingTransformProvider todInterpolating =
  485.                         (ShiftingTransformProvider) tod.getTransformProvider();
  486.                 final TODProvider       todRaw     = (TODProvider) todInterpolating.getRawProvider();
  487.                 final EOPHistory        eopHistory = todRaw.getEOPHistory();
  488.                 final GTODProvider      gtodRaw    =
  489.                         new GTODProvider(conventions, eopHistory, getTimeScales());
  490.                 final TransformProvider gtodShifting =
  491.                         new ShiftingTransformProvider(gtodRaw,
  492.                                 CartesianDerivativesFilter.USE_PVA,
  493.                                 AngularDerivativesFilter.USE_R,
  494.                                 todInterpolating.getGridPoints(), todInterpolating.getStep(),
  495.                                 OrekitConfiguration.getCacheSlotsNumber(),
  496.                                 Constants.JULIAN_YEAR, 30 * Constants.JULIAN_DAY);
  497.                 frame = new FactoryManagedFrame(tod, gtodShifting, false, factoryKey);
  498.                 frames.put(factoryKey, frame);
  499.             }

  500.             return frame;

  501.         }
  502.     }

  503.     @Override
  504.     public FactoryManagedFrame getTOD(final boolean applyEOPCorr) {
  505.         return getTOD(IERSConventions.IERS_1996, applyEOPCorr, false);
  506.     }

  507.     @Override
  508.     public FactoryManagedFrame getTOD(final IERSConventions conventions,
  509.                                       final boolean simpleEOP) {
  510.         return getTOD(conventions, true, simpleEOP);
  511.     }

  512.     /** Get the TOD 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 this method is private.
  520.      * </p>
  521.      * @param conventions IERS conventions to apply
  522.      * @param applyEOPCorr if true, EOP corrections are applied (here, nutation)
  523.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  524.      * @return the selected reference frame singleton.
  525.      */
  526.     private FactoryManagedFrame getTOD(final IERSConventions conventions,
  527.                                               final boolean applyEOPCorr,
  528.                                               final boolean simpleEOP) {

  529.         synchronized (this) {

  530.             // try to find an already built frame
  531.             final Predefined factoryKey;
  532.             switch (conventions) {
  533.                 case IERS_1996 :
  534.                     factoryKey = applyEOPCorr ?
  535.                             (simpleEOP ? Predefined.TOD_CONVENTIONS_1996_SIMPLE_EOP : Predefined.TOD_CONVENTIONS_1996_ACCURATE_EOP) :
  536.                             Predefined.TOD_WITHOUT_EOP_CORRECTIONS;
  537.                     break;
  538.                 case IERS_2003 :
  539.                     factoryKey = simpleEOP ?
  540.                             Predefined.TOD_CONVENTIONS_2003_SIMPLE_EOP :
  541.                             Predefined.TOD_CONVENTIONS_2003_ACCURATE_EOP;
  542.                     break;
  543.                 case IERS_2010 :
  544.                     factoryKey = simpleEOP ?
  545.                             Predefined.TOD_CONVENTIONS_2010_SIMPLE_EOP :
  546.                             Predefined.TOD_CONVENTIONS_2010_ACCURATE_EOP;
  547.                     break;
  548.                 default :
  549.                     // this should never happen
  550.                     throw new OrekitInternalError(null);
  551.             }
  552.             final int interpolationPoints;
  553.             final int pointsPerDay;
  554.             if (applyEOPCorr) {
  555.                 interpolationPoints = 6;
  556.                 pointsPerDay        = 24;
  557.             } else {
  558.                 interpolationPoints = 6;
  559.                 pointsPerDay        = 8;
  560.             }
  561.             FactoryManagedFrame frame = frames.get(factoryKey);

  562.             if (frame == null) {
  563.                 // it's the first time we need this frame, build it and store it
  564.                 final EOPHistory eopHistory = applyEOPCorr ?
  565.                         getEOPHistory(conventions, simpleEOP) :
  566.                         null;
  567.                 final TransformProvider shifting =
  568.                         new ShiftingTransformProvider(
  569.                                 new TODProvider(conventions, eopHistory, getTimeScales()),
  570.                                 CartesianDerivativesFilter.USE_PVA,
  571.                                 AngularDerivativesFilter.USE_R,
  572.                                 interpolationPoints, Constants.JULIAN_DAY / pointsPerDay,
  573.                                 OrekitConfiguration.getCacheSlotsNumber(),
  574.                                 Constants.JULIAN_YEAR, 30 * Constants.JULIAN_DAY);
  575.                 frame = new FactoryManagedFrame(getMOD(conventions, applyEOPCorr), shifting, true, factoryKey);
  576.                 frames.put(factoryKey, frame);
  577.             }

  578.             return frame;

  579.         }
  580.     }

  581.     @Override
  582.     public FactoryManagedFrame getMOD(final boolean applyEOPCorr) {
  583.         return getMOD(IERSConventions.IERS_1996, applyEOPCorr);
  584.     }

  585.     @Override
  586.     public FactoryManagedFrame getMOD(final IERSConventions conventions) {
  587.         return getMOD(conventions, true);
  588.     }

  589.     /** Get the MOD reference frame.
  590.      * <p>
  591.      * The applyEOPCorr parameter is available mainly for testing purposes or for
  592.      * consistency with legacy software that don't handle EOP correction parameters.
  593.      * Beware that setting this parameter to {@code false} leads to crude accuracy
  594.      * (order of magnitudes for errors might be above 1m in LEO and 10m in GEO).
  595.      * For this reason, setting this parameter to false is restricted to {@link
  596.      * IERSConventions#IERS_1996 IERS 1996} conventions, and hence this method is private.
  597.      * </p>
  598.      * @param conventions IERS conventions to apply
  599.      * @param applyEOPCorr if true, EOP corrections are applied (EME2000/GCRF bias compensation)
  600.      * @return the selected reference frame singleton.
  601.      */
  602.     private FactoryManagedFrame getMOD(final IERSConventions conventions, final boolean applyEOPCorr) {

  603.         synchronized (this) {

  604.             final Predefined factoryKey;
  605.             final Frame parent;
  606.             switch (conventions) {
  607.                 case IERS_1996 :
  608.                     factoryKey = applyEOPCorr ? Predefined.MOD_CONVENTIONS_1996 : Predefined.MOD_WITHOUT_EOP_CORRECTIONS;
  609.                     parent     = applyEOPCorr ? getGCRF() : getEME2000();
  610.                     break;
  611.                 case IERS_2003 :
  612.                     factoryKey = Predefined.MOD_CONVENTIONS_2003;
  613.                     // in IERS conventions 2003, the precession angles zetaA, thetaA and zA
  614.                     // from equation 33 are computed from EME2000, not from GCRF
  615.                     parent     = getEME2000();
  616.                     break;
  617.                 case IERS_2010 :
  618.                     factoryKey = Predefined.MOD_CONVENTIONS_2010;
  619.                     // precession angles epsilon0, psiA, omegaA and chiA
  620.                     // from equations 5.39 and 5.40 are computed from EME2000
  621.                     parent     = getEME2000();
  622.                     break;
  623.                 default :
  624.                     // this should never happen
  625.                     throw new OrekitInternalError(null);
  626.             }

  627.             // try to find an already built frame
  628.             FactoryManagedFrame frame = frames.get(factoryKey);

  629.             if (frame == null) {
  630.                 // it's the first time we need this frame, build it and store it
  631.                 final MODProvider provider = new MODProvider(conventions, getTimeScales());
  632.                 frame = new FactoryManagedFrame(parent, provider, true, factoryKey);
  633.                 frames.put(factoryKey, frame);
  634.             }

  635.             return frame;

  636.         }
  637.     }

  638.     @Override
  639.     public FactoryManagedFrame getTEME() {
  640.         synchronized (this) {

  641.             // try to find an already built frame
  642.             final Predefined factoryKey = Predefined.TEME;
  643.             FactoryManagedFrame frame = frames.get(factoryKey);

  644.             if (frame == null) {
  645.                 // it's the first time we need this frame, build it and store it
  646.                 final Frame tod = getTOD(IERSConventions.IERS_1996, false, true);
  647.                 final ShiftingTransformProvider todShifting =
  648.                         (ShiftingTransformProvider) tod.getTransformProvider();
  649.                 final TEMEProvider temeRaw =
  650.                         new TEMEProvider(IERSConventions.IERS_1996, null, getTimeScales());
  651.                 final TransformProvider temeShifting =
  652.                         new ShiftingTransformProvider(temeRaw,
  653.                                 CartesianDerivativesFilter.USE_PVA,
  654.                                 AngularDerivativesFilter.USE_R,
  655.                                 todShifting.getGridPoints(), todShifting.getStep(),
  656.                                 OrekitConfiguration.getCacheSlotsNumber(),
  657.                                 Constants.JULIAN_YEAR, 30 * Constants.JULIAN_DAY);

  658.                 frame = new FactoryManagedFrame(tod, temeShifting, true, factoryKey);
  659.                 frames.put(factoryKey, frame);
  660.             }

  661.             return frame;

  662.         }
  663.     }

  664.     @Override
  665.     public FactoryManagedFrame getPZ9011(final IERSConventions convention,
  666.                                          final boolean simpleEOP) {
  667.         synchronized (this) {

  668.             // try to find an already built frame
  669.             final Predefined factoryKey = Predefined.PZ90_11;
  670.             FactoryManagedFrame frame = frames.get(factoryKey);

  671.             if (frame == null) {
  672.                 // it's the first time we need this frame, build it and store it
  673.                 final Frame itrf = getITRF(ITRFVersion.ITRF_2008, convention, simpleEOP);
  674.                 final HelmertTransformation pz90Raw = new HelmertTransformation(new AbsoluteDate(2010, 1, 1, 12, 0, 0, getTimeScales().getTT()),
  675.                         +3.0, +1.0, -0.0, +0.019, -0.042, +0.002, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
  676.                 frame = new FactoryManagedFrame(itrf, pz90Raw, false, factoryKey);
  677.                 frames.put(factoryKey, frame);
  678.             }

  679.             return frame;

  680.         }
  681.     }

  682.     /**
  683.      * Get the time scales.
  684.      *
  685.      * @return time scales used to define these frames.
  686.      */
  687.     protected TimeScales getTimeScales() {
  688.         return timeScales;
  689.     }

  690.     /** Local class for different ITRF versions keys.
  691.      * @since 9.2
  692.      */
  693.     private static class ITRFKey implements Serializable {

  694.         /** Serialized UID. */
  695.         private static final long serialVersionUID = 20180412L;

  696.         /** ITRF version. */
  697.         private final ITRFVersion version;

  698.         /** IERS conventions to apply. */
  699.         private final IERSConventions conventions;

  700.         /** Tidal effects flag. */
  701.         private final boolean simpleEOP;

  702.         /** Simple constructor.
  703.          * @param version ITRF version
  704.          * @param conventions IERS conventions to apply
  705.          * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  706.          */
  707.         ITRFKey(final ITRFVersion version, final IERSConventions conventions, final boolean simpleEOP) {
  708.             this.version     = version;
  709.             this.conventions = conventions;
  710.             this.simpleEOP   = simpleEOP;
  711.         }

  712.         /** {@inheritDoc} */
  713.         @Override
  714.         public int hashCode() {
  715.             return (version.ordinal()     << 5) +
  716.                     (conventions.ordinal() << 1) +
  717.                     (simpleEOP ? 0 : 1);
  718.         }

  719.         /** {@inheritDoc} */
  720.         @Override
  721.         public boolean equals(final Object other) {

  722.             if (this == other) {
  723.                 return true;
  724.             }

  725.             if (other instanceof ITRFKey) {
  726.                 final ITRFKey key = (ITRFKey) other;
  727.                 return version     == key.version     &&
  728.                        conventions == key.conventions &&
  729.                        simpleEOP   == key.simpleEOP;
  730.             }

  731.             return false;
  732.         }

  733.     }
  734. }