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.time.UT1Scale;
  27. import org.orekit.utils.AngularDerivativesFilter;
  28. import org.orekit.utils.CartesianDerivativesFilter;
  29. import org.orekit.utils.Constants;
  30. import org.orekit.utils.IERSConventions;
  31. import org.orekit.utils.OrekitConfiguration;

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

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

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

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

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

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

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

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

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

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

  212.             return frame;

  213.         }
  214.     }

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

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

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

  225.             return frame;

  226.         }
  227.     }

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

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

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

  264.             return frame;

  265.         }
  266.     }

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

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

  286.             return frame;

  287.         }
  288.     }

  289.     @Override
  290.     public Frame buildUncachedITRF(final UT1Scale ut1) {

  291.         // extract EOP history
  292.         final EOPHistory eopHistory = ut1.getEOPHistory();

  293.         // build CIRF
  294.         final TransformProvider shifting =
  295.                         new ShiftingTransformProvider(new CIRFProvider(eopHistory),
  296.                                 CartesianDerivativesFilter.USE_PVA,
  297.                                 AngularDerivativesFilter.USE_R,
  298.                                 6, Constants.JULIAN_DAY / 24,
  299.                                 OrekitConfiguration.getCacheSlotsNumber(),
  300.                                 Constants.JULIAN_YEAR, 30 * Constants.JULIAN_DAY);
  301.         final Frame cirf = new Frame(getGCRF(), shifting, "CIRF (uncached)", true);

  302.         // build TIRF
  303.         final Frame tirf = new Frame(cirf, new TIRFProvider(eopHistory, ut1),
  304.                                           "TIRF (uncached)", false);

  305.         // build ITRF
  306.         return new Frame(tirf, new ITRFProvider(eopHistory),
  307.                          "ITRF (uncached)", false);

  308.     }

  309.     @Override
  310.     public FactoryManagedFrame getTIRF(final IERSConventions conventions) {
  311.         return getTIRF(conventions, true);
  312.     }

  313.     @Override
  314.     public FactoryManagedFrame getTIRF(final IERSConventions conventions,
  315.                                        final boolean simpleEOP) {
  316.         synchronized (this) {

  317.             // try to find an already built frame
  318.             final Predefined factoryKey;
  319.             switch (conventions) {
  320.                 case IERS_1996 :
  321.                     factoryKey = simpleEOP ?
  322.                             Predefined.TIRF_CONVENTIONS_1996_SIMPLE_EOP :
  323.                             Predefined.TIRF_CONVENTIONS_1996_ACCURATE_EOP;
  324.                     break;
  325.                 case IERS_2003 :
  326.                     factoryKey = simpleEOP ?
  327.                             Predefined.TIRF_CONVENTIONS_2003_SIMPLE_EOP :
  328.                             Predefined.TIRF_CONVENTIONS_2003_ACCURATE_EOP;
  329.                     break;
  330.                 case IERS_2010 :
  331.                     factoryKey = simpleEOP ?
  332.                             Predefined.TIRF_CONVENTIONS_2010_SIMPLE_EOP :
  333.                             Predefined.TIRF_CONVENTIONS_2010_ACCURATE_EOP;
  334.                     break;
  335.                 default :
  336.                     // this should never happen
  337.                     throw new OrekitInternalError(null);
  338.             }
  339.             FactoryManagedFrame frame = frames.get(factoryKey);

  340.             if (frame == null) {
  341.                 // it's the first time we need this frame, build it and store it
  342.                 final Frame cirf = getCIRF(conventions, simpleEOP);
  343.                 final ShiftingTransformProvider cirfInterpolating =
  344.                         (ShiftingTransformProvider) cirf.getTransformProvider();
  345.                 final CIRFProvider cirfRaw = (CIRFProvider) cirfInterpolating.getRawProvider();
  346.                 final EOPHistory eopHistory = cirfRaw.getEOPHistory();
  347.                 final TIRFProvider provider =
  348.                         new TIRFProvider(eopHistory, getTimeScales().getUT1(conventions, simpleEOP));
  349.                 frame = new FactoryManagedFrame(cirf, provider, false, factoryKey);
  350.                 frames.put(factoryKey, frame);
  351.             }

  352.             return frame;

  353.         }
  354.     }

  355.     @Override
  356.     public FactoryManagedFrame getCIRF(final IERSConventions conventions,
  357.                                        final boolean simpleEOP) {
  358.         synchronized (this) {

  359.             // try to find an already built frame
  360.             final Predefined factoryKey;
  361.             switch (conventions) {
  362.                 case IERS_1996 :
  363.                     factoryKey = simpleEOP ?
  364.                             Predefined.CIRF_CONVENTIONS_1996_SIMPLE_EOP :
  365.                             Predefined.CIRF_CONVENTIONS_1996_ACCURATE_EOP;
  366.                     break;
  367.                 case IERS_2003 :
  368.                     factoryKey = simpleEOP ?
  369.                             Predefined.CIRF_CONVENTIONS_2003_SIMPLE_EOP :
  370.                             Predefined.CIRF_CONVENTIONS_2003_ACCURATE_EOP;
  371.                     break;
  372.                 case IERS_2010 :
  373.                     factoryKey = simpleEOP ?
  374.                             Predefined.CIRF_CONVENTIONS_2010_SIMPLE_EOP :
  375.                             Predefined.CIRF_CONVENTIONS_2010_ACCURATE_EOP;
  376.                     break;
  377.                 default :
  378.                     // this should never happen
  379.                     throw new OrekitInternalError(null);
  380.             }
  381.             FactoryManagedFrame frame = frames.get(factoryKey);

  382.             if (frame == null) {
  383.                 // it's the first time we need this frame, build it and store it
  384.                 final EOPHistory eopHistory = getEOPHistory(conventions, simpleEOP);
  385.                 final TransformProvider shifting =
  386.                         new ShiftingTransformProvider(new CIRFProvider(eopHistory),
  387.                                 CartesianDerivativesFilter.USE_PVA,
  388.                                 AngularDerivativesFilter.USE_R,
  389.                                 6, Constants.JULIAN_DAY / 24,
  390.                                 OrekitConfiguration.getCacheSlotsNumber(),
  391.                                 Constants.JULIAN_YEAR, 30 * Constants.JULIAN_DAY);
  392.                 frame = new FactoryManagedFrame(getGCRF(), shifting, true, factoryKey);
  393.                 frames.put(factoryKey, frame);
  394.             }

  395.             return frame;

  396.         }
  397.     }

  398.     @Override
  399.     public FactoryManagedFrame getVeis1950() {
  400.         synchronized (this) {

  401.             // try to find an already built frame
  402.             final Predefined factoryKey = Predefined.VEIS_1950;
  403.             FactoryManagedFrame frame = frames.get(factoryKey);

  404.             if (frame == null) {
  405.                 // it's the first time we need this frame, build it and store it
  406.                 frame = new FactoryManagedFrame(getGTOD(IERSConventions.IERS_1996, false, true),
  407.                         new VEISProvider(getTimeScales()), true, factoryKey);
  408.                 frames.put(factoryKey, frame);
  409.             }

  410.             return frame;

  411.         }
  412.     }

  413.     @Override
  414.     public FactoryManagedFrame getITRFEquinox(final IERSConventions conventions,
  415.                                               final boolean simpleEOP) {
  416.         synchronized (this) {

  417.             // try to find an already built frame
  418.             final Predefined factoryKey;
  419.             switch (conventions) {
  420.                 case IERS_1996 :
  421.                     factoryKey = simpleEOP ?
  422.                             Predefined.ITRF_EQUINOX_CONV_1996_SIMPLE_EOP :
  423.                             Predefined.ITRF_EQUINOX_CONV_1996_ACCURATE_EOP;
  424.                     break;
  425.                 case IERS_2003 :
  426.                     factoryKey = simpleEOP ?
  427.                             Predefined.ITRF_EQUINOX_CONV_2003_SIMPLE_EOP :
  428.                             Predefined.ITRF_EQUINOX_CONV_2003_ACCURATE_EOP;
  429.                     break;
  430.                 case IERS_2010 :
  431.                     factoryKey = simpleEOP ?
  432.                             Predefined.ITRF_EQUINOX_CONV_2010_SIMPLE_EOP :
  433.                             Predefined.ITRF_EQUINOX_CONV_2010_ACCURATE_EOP;
  434.                     break;
  435.                 default :
  436.                     // this should never happen
  437.                     throw new OrekitInternalError(null);
  438.             }
  439.             FactoryManagedFrame frame = frames.get(factoryKey);

  440.             if (frame == null) {
  441.                 // it's the first time we need this frame, build it and store it
  442.                 final Frame gtod = getGTOD(conventions, true, simpleEOP);
  443.                 final ShiftingTransformProvider gtodShifting =
  444.                         (ShiftingTransformProvider) gtod.getTransformProvider();
  445.                 final GTODProvider gtodRaw    = (GTODProvider) gtodShifting.getRawProvider();
  446.                 final EOPHistory   eopHistory = gtodRaw.getEOPHistory();
  447.                 frame = new FactoryManagedFrame(gtod, new ITRFProvider(eopHistory), false, factoryKey);
  448.                 frames.put(factoryKey, frame);
  449.             }

  450.             return frame;

  451.         }
  452.     }

  453.     @Override
  454.     public FactoryManagedFrame getGTOD(final boolean applyEOPCorr) {
  455.         return getGTOD(IERSConventions.IERS_1996, applyEOPCorr, true);
  456.     }

  457.     @Override
  458.     public FactoryManagedFrame getGTOD(final IERSConventions conventions,
  459.                                        final boolean simpleEOP) {
  460.         return getGTOD(conventions, true, simpleEOP);
  461.     }

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

  479.         synchronized (this) {

  480.             // try to find an already built frame
  481.             final Predefined factoryKey;
  482.             switch (conventions) {
  483.                 case IERS_1996 :
  484.                     factoryKey = applyEOPCorr ?
  485.                             (simpleEOP ? Predefined.GTOD_CONVENTIONS_1996_SIMPLE_EOP : Predefined.GTOD_CONVENTIONS_1996_ACCURATE_EOP) :
  486.                             Predefined.GTOD_WITHOUT_EOP_CORRECTIONS;
  487.                     break;
  488.                 case IERS_2003 :
  489.                     factoryKey = simpleEOP ?
  490.                             Predefined.GTOD_CONVENTIONS_2003_SIMPLE_EOP :
  491.                             Predefined.GTOD_CONVENTIONS_2003_ACCURATE_EOP;
  492.                     break;
  493.                 case IERS_2010 :
  494.                     factoryKey = simpleEOP ? Predefined.GTOD_CONVENTIONS_2010_SIMPLE_EOP :
  495.                             Predefined.GTOD_CONVENTIONS_2010_ACCURATE_EOP;
  496.                     break;
  497.                 default :
  498.                     // this should never happen
  499.                     throw new OrekitInternalError(null);
  500.             }
  501.             FactoryManagedFrame frame = frames.get(factoryKey);

  502.             if (frame == null) {
  503.                 // it's the first time we need this frame, build it and store it
  504.                 final Frame tod = getTOD(conventions, applyEOPCorr, simpleEOP);
  505.                 final ShiftingTransformProvider todInterpolating =
  506.                         (ShiftingTransformProvider) tod.getTransformProvider();
  507.                 final TODProvider       todRaw     = (TODProvider) todInterpolating.getRawProvider();
  508.                 final EOPHistory        eopHistory = todRaw.getEOPHistory();
  509.                 final GTODProvider      gtodRaw    =
  510.                         new GTODProvider(conventions, eopHistory, getTimeScales());
  511.                 final TransformProvider gtodShifting =
  512.                         new ShiftingTransformProvider(gtodRaw,
  513.                                 CartesianDerivativesFilter.USE_PVA,
  514.                                 AngularDerivativesFilter.USE_R,
  515.                                 todInterpolating.getGridPoints(), todInterpolating.getStep(),
  516.                                 OrekitConfiguration.getCacheSlotsNumber(),
  517.                                 Constants.JULIAN_YEAR, 30 * Constants.JULIAN_DAY);
  518.                 frame = new FactoryManagedFrame(tod, gtodShifting, false, factoryKey);
  519.                 frames.put(factoryKey, frame);
  520.             }

  521.             return frame;

  522.         }
  523.     }

  524.     @Override
  525.     public FactoryManagedFrame getTOD(final boolean applyEOPCorr) {
  526.         return getTOD(IERSConventions.IERS_1996, applyEOPCorr, false);
  527.     }

  528.     @Override
  529.     public FactoryManagedFrame getTOD(final IERSConventions conventions,
  530.                                       final boolean simpleEOP) {
  531.         return getTOD(conventions, true, simpleEOP);
  532.     }

  533.     /** Get the TOD reference frame.
  534.      * <p>
  535.      * The applyEOPCorr parameter is available mainly for testing purposes or for
  536.      * consistency with legacy software that don't handle EOP correction parameters.
  537.      * Beware that setting this parameter to {@code false} leads to crude accuracy
  538.      * (order of magnitudes for errors might be above 1m in LEO and 10m in GEO).
  539.      * For this reason, setting this parameter to false is restricted to {@link
  540.      * IERSConventions#IERS_1996 IERS 1996} conventions, and hence this method is private.
  541.      * </p>
  542.      * @param conventions IERS conventions to apply
  543.      * @param applyEOPCorr if true, EOP corrections are applied (here, nutation)
  544.      * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  545.      * @return the selected reference frame singleton.
  546.      */
  547.     private FactoryManagedFrame getTOD(final IERSConventions conventions,
  548.                                               final boolean applyEOPCorr,
  549.                                               final boolean simpleEOP) {

  550.         synchronized (this) {

  551.             // try to find an already built frame
  552.             final Predefined factoryKey;
  553.             switch (conventions) {
  554.                 case IERS_1996 :
  555.                     factoryKey = applyEOPCorr ?
  556.                             (simpleEOP ? Predefined.TOD_CONVENTIONS_1996_SIMPLE_EOP : Predefined.TOD_CONVENTIONS_1996_ACCURATE_EOP) :
  557.                             Predefined.TOD_WITHOUT_EOP_CORRECTIONS;
  558.                     break;
  559.                 case IERS_2003 :
  560.                     factoryKey = simpleEOP ?
  561.                             Predefined.TOD_CONVENTIONS_2003_SIMPLE_EOP :
  562.                             Predefined.TOD_CONVENTIONS_2003_ACCURATE_EOP;
  563.                     break;
  564.                 case IERS_2010 :
  565.                     factoryKey = simpleEOP ?
  566.                             Predefined.TOD_CONVENTIONS_2010_SIMPLE_EOP :
  567.                             Predefined.TOD_CONVENTIONS_2010_ACCURATE_EOP;
  568.                     break;
  569.                 default :
  570.                     // this should never happen
  571.                     throw new OrekitInternalError(null);
  572.             }
  573.             final int interpolationPoints;
  574.             final int pointsPerDay;
  575.             if (applyEOPCorr) {
  576.                 interpolationPoints = 6;
  577.                 pointsPerDay        = 24;
  578.             } else {
  579.                 interpolationPoints = 6;
  580.                 pointsPerDay        = 8;
  581.             }
  582.             FactoryManagedFrame frame = frames.get(factoryKey);

  583.             if (frame == null) {
  584.                 // it's the first time we need this frame, build it and store it
  585.                 final EOPHistory eopHistory = applyEOPCorr ?
  586.                         getEOPHistory(conventions, simpleEOP) :
  587.                         null;
  588.                 final TransformProvider shifting =
  589.                         new ShiftingTransformProvider(
  590.                                 new TODProvider(conventions, eopHistory, getTimeScales()),
  591.                                 CartesianDerivativesFilter.USE_PVA,
  592.                                 AngularDerivativesFilter.USE_R,
  593.                                 interpolationPoints, Constants.JULIAN_DAY / pointsPerDay,
  594.                                 OrekitConfiguration.getCacheSlotsNumber(),
  595.                                 Constants.JULIAN_YEAR, 30 * Constants.JULIAN_DAY);
  596.                 frame = new FactoryManagedFrame(getMOD(conventions, applyEOPCorr), shifting, true, factoryKey);
  597.                 frames.put(factoryKey, frame);
  598.             }

  599.             return frame;

  600.         }
  601.     }

  602.     @Override
  603.     public FactoryManagedFrame getMOD(final boolean applyEOPCorr) {
  604.         return getMOD(IERSConventions.IERS_1996, applyEOPCorr);
  605.     }

  606.     @Override
  607.     public FactoryManagedFrame getMOD(final IERSConventions conventions) {
  608.         return getMOD(conventions, true);
  609.     }

  610.     /** Get the MOD reference frame.
  611.      * <p>
  612.      * The applyEOPCorr parameter is available mainly for testing purposes or for
  613.      * consistency with legacy software that don't handle EOP correction parameters.
  614.      * Beware that setting this parameter to {@code false} leads to crude accuracy
  615.      * (order of magnitudes for errors might be above 1m in LEO and 10m in GEO).
  616.      * For this reason, setting this parameter to false is restricted to {@link
  617.      * IERSConventions#IERS_1996 IERS 1996} conventions, and hence this method is private.
  618.      * </p>
  619.      * @param conventions IERS conventions to apply
  620.      * @param applyEOPCorr if true, EOP corrections are applied (EME2000/GCRF bias compensation)
  621.      * @return the selected reference frame singleton.
  622.      */
  623.     private FactoryManagedFrame getMOD(final IERSConventions conventions, final boolean applyEOPCorr) {

  624.         synchronized (this) {

  625.             final Predefined factoryKey;
  626.             final Frame parent;
  627.             switch (conventions) {
  628.                 case IERS_1996 :
  629.                     factoryKey = applyEOPCorr ? Predefined.MOD_CONVENTIONS_1996 : Predefined.MOD_WITHOUT_EOP_CORRECTIONS;
  630.                     parent     = applyEOPCorr ? getGCRF() : getEME2000();
  631.                     break;
  632.                 case IERS_2003 :
  633.                     factoryKey = Predefined.MOD_CONVENTIONS_2003;
  634.                     // in IERS conventions 2003, the precession angles zetaA, thetaA and zA
  635.                     // from equation 33 are computed from EME2000, not from GCRF
  636.                     parent     = getEME2000();
  637.                     break;
  638.                 case IERS_2010 :
  639.                     factoryKey = Predefined.MOD_CONVENTIONS_2010;
  640.                     // precession angles epsilon0, psiA, omegaA and chiA
  641.                     // from equations 5.39 and 5.40 are computed from EME2000
  642.                     parent     = getEME2000();
  643.                     break;
  644.                 default :
  645.                     // this should never happen
  646.                     throw new OrekitInternalError(null);
  647.             }

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

  650.             if (frame == null) {
  651.                 // it's the first time we need this frame, build it and store it
  652.                 final MODProvider provider = new MODProvider(conventions, getTimeScales());
  653.                 frame = new FactoryManagedFrame(parent, provider, true, factoryKey);
  654.                 frames.put(factoryKey, frame);
  655.             }

  656.             return frame;

  657.         }
  658.     }

  659.     @Override
  660.     public FactoryManagedFrame getTEME() {
  661.         synchronized (this) {

  662.             // try to find an already built frame
  663.             final Predefined factoryKey = Predefined.TEME;
  664.             FactoryManagedFrame frame = frames.get(factoryKey);

  665.             if (frame == null) {
  666.                 // it's the first time we need this frame, build it and store it
  667.                 final Frame tod = getTOD(IERSConventions.IERS_1996, false, true);
  668.                 final ShiftingTransformProvider todShifting =
  669.                         (ShiftingTransformProvider) tod.getTransformProvider();
  670.                 final TEMEProvider temeRaw =
  671.                         new TEMEProvider(IERSConventions.IERS_1996, null, getTimeScales());
  672.                 final TransformProvider temeShifting =
  673.                         new ShiftingTransformProvider(temeRaw,
  674.                                 CartesianDerivativesFilter.USE_PVA,
  675.                                 AngularDerivativesFilter.USE_R,
  676.                                 todShifting.getGridPoints(), todShifting.getStep(),
  677.                                 OrekitConfiguration.getCacheSlotsNumber(),
  678.                                 Constants.JULIAN_YEAR, 30 * Constants.JULIAN_DAY);

  679.                 frame = new FactoryManagedFrame(tod, temeShifting, true, factoryKey);
  680.                 frames.put(factoryKey, frame);
  681.             }

  682.             return frame;

  683.         }
  684.     }

  685.     @Override
  686.     public FactoryManagedFrame getPZ9011(final IERSConventions convention,
  687.                                          final boolean simpleEOP) {
  688.         synchronized (this) {

  689.             // try to find an already built frame
  690.             final Predefined factoryKey = Predefined.PZ90_11;
  691.             FactoryManagedFrame frame = frames.get(factoryKey);

  692.             if (frame == null) {
  693.                 // it's the first time we need this frame, build it and store it
  694.                 final Frame itrf = getITRF(ITRFVersion.ITRF_2008, convention, simpleEOP);
  695.                 final HelmertTransformation pz90Raw = new HelmertTransformation(new AbsoluteDate(2010, 1, 1, 12, 0, 0, getTimeScales().getTT()),
  696.                         +3.0, +1.0, -0.0, +0.019, -0.042, +0.002, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
  697.                 frame = new FactoryManagedFrame(itrf, pz90Raw, false, factoryKey);
  698.                 frames.put(factoryKey, frame);
  699.             }

  700.             return frame;

  701.         }
  702.     }

  703.     /**
  704.      * Get the time scales.
  705.      *
  706.      * @return time scales used to define these frames.
  707.      */
  708.     protected TimeScales getTimeScales() {
  709.         return timeScales;
  710.     }

  711.     /** Local class for different ITRF versions keys.
  712.      * @since 9.2
  713.      */
  714.     private static class ITRFKey implements Serializable {

  715.         /** Serialized UID. */
  716.         private static final long serialVersionUID = 20180412L;

  717.         /** ITRF version. */
  718.         private final ITRFVersion version;

  719.         /** IERS conventions to apply. */
  720.         private final IERSConventions conventions;

  721.         /** Tidal effects flag. */
  722.         private final boolean simpleEOP;

  723.         /** Simple constructor.
  724.          * @param version ITRF version
  725.          * @param conventions IERS conventions to apply
  726.          * @param simpleEOP if true, tidal effects are ignored when interpolating EOP
  727.          */
  728.         ITRFKey(final ITRFVersion version, final IERSConventions conventions, final boolean simpleEOP) {
  729.             this.version     = version;
  730.             this.conventions = conventions;
  731.             this.simpleEOP   = simpleEOP;
  732.         }

  733.         /** {@inheritDoc} */
  734.         @Override
  735.         public int hashCode() {
  736.             return (version.ordinal()     << 5) +
  737.                     (conventions.ordinal() << 1) +
  738.                     (simpleEOP ? 0 : 1);
  739.         }

  740.         /** {@inheritDoc} */
  741.         @Override
  742.         public boolean equals(final Object other) {

  743.             if (this == other) {
  744.                 return true;
  745.             }

  746.             if (other instanceof ITRFKey) {
  747.                 final ITRFKey key = (ITRFKey) other;
  748.                 return version     == key.version     &&
  749.                        conventions == key.conventions &&
  750.                        simpleEOP   == key.simpleEOP;
  751.             }

  752.             return false;
  753.         }

  754.     }
  755. }