AbstractFrames.java
/* Contributed in the public domain.
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.frames;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Supplier;
import org.orekit.bodies.CelestialBodies;
import org.orekit.errors.OrekitInternalError;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.TimeScales;
import org.orekit.time.UT1Scale;
import org.orekit.utils.AngularDerivativesFilter;
import org.orekit.utils.CartesianDerivativesFilter;
import org.orekit.utils.Constants;
import org.orekit.utils.IERSConventions;
import org.orekit.utils.OrekitConfiguration;
/**
* This class is an implementation of {@link Frames} that creates frames when they are
* first used and uses synchronization to ensure that each frame is only created once.
*
* @author Guylaine Prat
* @author Luc Maisonobe
* @author Pascal Parraud
* @author Evan Ward
* @see LazyLoadedFrames
* @see #getEOPHistory(IERSConventions, boolean)
* @since 10.1
*/
public abstract class AbstractFrames implements Frames {
/** Provider of common time scales. */
private final TimeScales timeScales;
/** Provider of the ICRF frame, usually delegated to {@link CelestialBodies}. */
private final Supplier<Frame> icrfSupplier;
/** Predefined frames. */
private transient Map<Predefined, FactoryManagedFrame> frames;
/** Predefined versioned ITRF frames. */
private transient Map<ITRFKey, VersionedITRF> versionedItrfFrames;
/**
* Simple constructor.
*
* @param timeScales to use when creating frames.
* @param icrfSupplier used to implement {@link #getICRF()};
*/
public AbstractFrames(final TimeScales timeScales,
final Supplier<Frame> icrfSupplier) {
this.timeScales = timeScales;
this.icrfSupplier = icrfSupplier;
this.frames = new HashMap<>();
this.versionedItrfFrames = new HashMap<>();
}
@Override
public Frame getFrame(final Predefined factoryKey) {
switch (factoryKey) {
case GCRF :
return getGCRF();
case ICRF :
return getICRF();
case ECLIPTIC_CONVENTIONS_1996 :
return getEcliptic(IERSConventions.IERS_1996);
case ECLIPTIC_CONVENTIONS_2003 :
return getEcliptic(IERSConventions.IERS_2003);
case ECLIPTIC_CONVENTIONS_2010 :
return getEcliptic(IERSConventions.IERS_2010);
case EME2000 :
return getEME2000();
case ITRF_CIO_CONV_2010_SIMPLE_EOP :
return getITRF(IERSConventions.IERS_2010, true);
case ITRF_CIO_CONV_2010_ACCURATE_EOP :
return getITRF(IERSConventions.IERS_2010, false);
case ITRF_CIO_CONV_2003_SIMPLE_EOP :
return getITRF(IERSConventions.IERS_2003, true);
case ITRF_CIO_CONV_2003_ACCURATE_EOP :
return getITRF(IERSConventions.IERS_2003, false);
case ITRF_CIO_CONV_1996_SIMPLE_EOP :
return getITRF(IERSConventions.IERS_1996, true);
case ITRF_CIO_CONV_1996_ACCURATE_EOP :
return getITRF(IERSConventions.IERS_1996, false);
case ITRF_EQUINOX_CONV_2010_SIMPLE_EOP :
return getITRFEquinox(IERSConventions.IERS_2010, true);
case ITRF_EQUINOX_CONV_2010_ACCURATE_EOP :
return getITRFEquinox(IERSConventions.IERS_2010, false);
case ITRF_EQUINOX_CONV_2003_SIMPLE_EOP :
return getITRFEquinox(IERSConventions.IERS_2003, true);
case ITRF_EQUINOX_CONV_2003_ACCURATE_EOP :
return getITRFEquinox(IERSConventions.IERS_2003, false);
case ITRF_EQUINOX_CONV_1996_SIMPLE_EOP :
return getITRFEquinox(IERSConventions.IERS_1996, true);
case ITRF_EQUINOX_CONV_1996_ACCURATE_EOP :
return getITRFEquinox(IERSConventions.IERS_1996, false);
case TIRF_CONVENTIONS_2010_SIMPLE_EOP :
return getTIRF(IERSConventions.IERS_2010, true);
case TIRF_CONVENTIONS_2010_ACCURATE_EOP :
return getTIRF(IERSConventions.IERS_2010, false);
case TIRF_CONVENTIONS_2003_SIMPLE_EOP :
return getTIRF(IERSConventions.IERS_2003, true);
case TIRF_CONVENTIONS_2003_ACCURATE_EOP :
return getTIRF(IERSConventions.IERS_2003, false);
case TIRF_CONVENTIONS_1996_SIMPLE_EOP :
return getTIRF(IERSConventions.IERS_1996, true);
case TIRF_CONVENTIONS_1996_ACCURATE_EOP :
return getTIRF(IERSConventions.IERS_1996, false);
case CIRF_CONVENTIONS_2010_ACCURATE_EOP :
return getCIRF(IERSConventions.IERS_2010, false);
case CIRF_CONVENTIONS_2010_SIMPLE_EOP :
return getCIRF(IERSConventions.IERS_2010, true);
case CIRF_CONVENTIONS_2003_ACCURATE_EOP :
return getCIRF(IERSConventions.IERS_2003, false);
case CIRF_CONVENTIONS_2003_SIMPLE_EOP :
return getCIRF(IERSConventions.IERS_2003, true);
case CIRF_CONVENTIONS_1996_ACCURATE_EOP :
return getCIRF(IERSConventions.IERS_1996, false);
case CIRF_CONVENTIONS_1996_SIMPLE_EOP :
return getCIRF(IERSConventions.IERS_1996, true);
case VEIS_1950 :
return getVeis1950();
case GTOD_WITHOUT_EOP_CORRECTIONS :
return getGTOD(IERSConventions.IERS_1996, false, true);
case GTOD_CONVENTIONS_2010_ACCURATE_EOP :
return getGTOD(IERSConventions.IERS_2010, true, false);
case GTOD_CONVENTIONS_2010_SIMPLE_EOP :
return getGTOD(IERSConventions.IERS_2010, true, true);
case GTOD_CONVENTIONS_2003_ACCURATE_EOP :
return getGTOD(IERSConventions.IERS_2003, true, false);
case GTOD_CONVENTIONS_2003_SIMPLE_EOP :
return getGTOD(IERSConventions.IERS_2003, true, true);
case GTOD_CONVENTIONS_1996_ACCURATE_EOP :
return getGTOD(IERSConventions.IERS_1996, true, false);
case GTOD_CONVENTIONS_1996_SIMPLE_EOP :
return getGTOD(IERSConventions.IERS_1996, true, true);
case TOD_WITHOUT_EOP_CORRECTIONS :
return getTOD(IERSConventions.IERS_1996, false, true);
case TOD_CONVENTIONS_2010_ACCURATE_EOP :
return getTOD(IERSConventions.IERS_2010, true, false);
case TOD_CONVENTIONS_2010_SIMPLE_EOP :
return getTOD(IERSConventions.IERS_2010, true, true);
case TOD_CONVENTIONS_2003_ACCURATE_EOP :
return getTOD(IERSConventions.IERS_2003, true, false);
case TOD_CONVENTIONS_2003_SIMPLE_EOP :
return getTOD(IERSConventions.IERS_2003, true, true);
case TOD_CONVENTIONS_1996_ACCURATE_EOP :
return getTOD(IERSConventions.IERS_1996, true, false);
case TOD_CONVENTIONS_1996_SIMPLE_EOP :
return getTOD(IERSConventions.IERS_1996, true, true);
case MOD_WITHOUT_EOP_CORRECTIONS :
return getMOD(IERSConventions.IERS_1996, false);
case MOD_CONVENTIONS_2010 :
return getMOD(IERSConventions.IERS_2010, true);
case MOD_CONVENTIONS_2003 :
return getMOD(IERSConventions.IERS_2003, true);
case MOD_CONVENTIONS_1996 :
return getMOD(IERSConventions.IERS_1996, true);
case TEME :
return getTEME();
case PZ90_11 :
return getPZ9011(IERSConventions.IERS_2010, true);
default :
// this should never happen
throw new OrekitInternalError(null);
}
}
@Override
public Frame getGCRF() {
return Frame.getRoot();
}
@Override
public Frame getICRF() {
return icrfSupplier.get();
}
@Override
public Frame getEcliptic(final IERSConventions conventions) {
synchronized (this) {
final Predefined factoryKey;
switch (conventions) {
case IERS_1996 :
factoryKey = Predefined.ECLIPTIC_CONVENTIONS_1996;
break;
case IERS_2003 :
factoryKey = Predefined.ECLIPTIC_CONVENTIONS_2003;
break;
case IERS_2010 :
factoryKey = Predefined.ECLIPTIC_CONVENTIONS_2010;
break;
default :
// this should never happen
throw new OrekitInternalError(null);
}
final Frame parent = getMOD(conventions);
// try to find an already built frame
FactoryManagedFrame frame = frames.get(factoryKey);
if (frame == null) {
// it's the first time we need this frame, build it and store it
final EclipticProvider provider =
new EclipticProvider(conventions, getTimeScales());
frame = new FactoryManagedFrame(parent, provider, true, factoryKey);
frames.put(factoryKey, frame);
}
return frame;
}
}
@Override
public FactoryManagedFrame getEME2000() {
synchronized (this) {
// try to find an already built frame
FactoryManagedFrame frame = frames.get(Predefined.EME2000);
if (frame == null) {
// it's the first time we need this frame, build it and store it
frame = new FactoryManagedFrame(getGCRF(), new EME2000Provider(), true, Predefined.EME2000);
frames.put(Predefined.EME2000, frame);
}
return frame;
}
}
@Override
public FactoryManagedFrame getITRF(final IERSConventions conventions,
final boolean simpleEOP) {
synchronized (this) {
// try to find an already built frame
final Predefined factoryKey;
switch (conventions) {
case IERS_1996 :
factoryKey = simpleEOP ?
Predefined.ITRF_CIO_CONV_1996_SIMPLE_EOP :
Predefined.ITRF_CIO_CONV_1996_ACCURATE_EOP;
break;
case IERS_2003 :
factoryKey = simpleEOP ?
Predefined.ITRF_CIO_CONV_2003_SIMPLE_EOP :
Predefined.ITRF_CIO_CONV_2003_ACCURATE_EOP;
break;
case IERS_2010 :
factoryKey = simpleEOP ?
Predefined.ITRF_CIO_CONV_2010_SIMPLE_EOP :
Predefined.ITRF_CIO_CONV_2010_ACCURATE_EOP;
break;
default :
// this should never happen
throw new OrekitInternalError(null);
}
FactoryManagedFrame frame = frames.get(factoryKey);
if (frame == null) {
// it's the first time we need this frame, build it and store it
final Frame tirfFrame = getTIRF(conventions, simpleEOP);
final TIRFProvider tirfProvider = (TIRFProvider) tirfFrame.getTransformProvider();
frame = new FactoryManagedFrame(tirfFrame,
new ITRFProvider(tirfProvider.getEOPHistory()),
false, factoryKey);
frames.put(factoryKey, frame);
}
return frame;
}
}
@Override
public VersionedITRF getITRF(final ITRFVersion version,
final IERSConventions conventions,
final boolean simpleEOP) {
synchronized (this) {
// try to find an already built frame
final ITRFKey key = new ITRFKey(version, conventions, simpleEOP);
VersionedITRF frame = versionedItrfFrames.get(key);
if (frame == null) {
// it's the first time we need this frame, build it and store it
final FactoryManagedFrame rawITRF = getITRF(conventions, simpleEOP);
frame = new VersionedITRF(rawITRF.getParent(), version,
(ITRFProvider) rawITRF.getTransformProvider(),
version.toString().replace('_', '-') +
"/" +
rawITRF.getName(),
getTimeScales().getTT());
versionedItrfFrames.put(key, frame);
}
return frame;
}
}
@Override
public Frame buildUncachedITRF(final UT1Scale ut1) {
// extract EOP history
final EOPHistory eopHistory = ut1.getEOPHistory();
// build CIRF
final TransformProvider shifting =
new ShiftingTransformProvider(new CIRFProvider(eopHistory),
CartesianDerivativesFilter.USE_PVA,
AngularDerivativesFilter.USE_R,
6, Constants.JULIAN_DAY / 24,
OrekitConfiguration.getCacheSlotsNumber(),
Constants.JULIAN_YEAR, 30 * Constants.JULIAN_DAY);
final Frame cirf = new Frame(getGCRF(), shifting, "CIRF (uncached)", true);
// build TIRF
final Frame tirf = new Frame(cirf, new TIRFProvider(eopHistory, ut1),
"TIRF (uncached)", false);
// build ITRF
return new Frame(tirf, new ITRFProvider(eopHistory),
"ITRF (uncached)", false);
}
@Override
public FactoryManagedFrame getTIRF(final IERSConventions conventions) {
return getTIRF(conventions, true);
}
@Override
public FactoryManagedFrame getTIRF(final IERSConventions conventions,
final boolean simpleEOP) {
synchronized (this) {
// try to find an already built frame
final Predefined factoryKey;
switch (conventions) {
case IERS_1996 :
factoryKey = simpleEOP ?
Predefined.TIRF_CONVENTIONS_1996_SIMPLE_EOP :
Predefined.TIRF_CONVENTIONS_1996_ACCURATE_EOP;
break;
case IERS_2003 :
factoryKey = simpleEOP ?
Predefined.TIRF_CONVENTIONS_2003_SIMPLE_EOP :
Predefined.TIRF_CONVENTIONS_2003_ACCURATE_EOP;
break;
case IERS_2010 :
factoryKey = simpleEOP ?
Predefined.TIRF_CONVENTIONS_2010_SIMPLE_EOP :
Predefined.TIRF_CONVENTIONS_2010_ACCURATE_EOP;
break;
default :
// this should never happen
throw new OrekitInternalError(null);
}
FactoryManagedFrame frame = frames.get(factoryKey);
if (frame == null) {
// it's the first time we need this frame, build it and store it
final Frame cirf = getCIRF(conventions, simpleEOP);
final ShiftingTransformProvider cirfInterpolating =
(ShiftingTransformProvider) cirf.getTransformProvider();
final CIRFProvider cirfRaw = (CIRFProvider) cirfInterpolating.getRawProvider();
final EOPHistory eopHistory = cirfRaw.getEOPHistory();
final TIRFProvider provider =
new TIRFProvider(eopHistory, getTimeScales().getUT1(conventions, simpleEOP));
frame = new FactoryManagedFrame(cirf, provider, false, factoryKey);
frames.put(factoryKey, frame);
}
return frame;
}
}
@Override
public FactoryManagedFrame getCIRF(final IERSConventions conventions,
final boolean simpleEOP) {
synchronized (this) {
// try to find an already built frame
final Predefined factoryKey;
switch (conventions) {
case IERS_1996 :
factoryKey = simpleEOP ?
Predefined.CIRF_CONVENTIONS_1996_SIMPLE_EOP :
Predefined.CIRF_CONVENTIONS_1996_ACCURATE_EOP;
break;
case IERS_2003 :
factoryKey = simpleEOP ?
Predefined.CIRF_CONVENTIONS_2003_SIMPLE_EOP :
Predefined.CIRF_CONVENTIONS_2003_ACCURATE_EOP;
break;
case IERS_2010 :
factoryKey = simpleEOP ?
Predefined.CIRF_CONVENTIONS_2010_SIMPLE_EOP :
Predefined.CIRF_CONVENTIONS_2010_ACCURATE_EOP;
break;
default :
// this should never happen
throw new OrekitInternalError(null);
}
FactoryManagedFrame frame = frames.get(factoryKey);
if (frame == null) {
// it's the first time we need this frame, build it and store it
final EOPHistory eopHistory = getEOPHistory(conventions, simpleEOP);
final TransformProvider shifting =
new ShiftingTransformProvider(new CIRFProvider(eopHistory),
CartesianDerivativesFilter.USE_PVA,
AngularDerivativesFilter.USE_R,
6, Constants.JULIAN_DAY / 24,
OrekitConfiguration.getCacheSlotsNumber(),
Constants.JULIAN_YEAR, 30 * Constants.JULIAN_DAY);
frame = new FactoryManagedFrame(getGCRF(), shifting, true, factoryKey);
frames.put(factoryKey, frame);
}
return frame;
}
}
@Override
public FactoryManagedFrame getVeis1950() {
synchronized (this) {
// try to find an already built frame
final Predefined factoryKey = Predefined.VEIS_1950;
FactoryManagedFrame frame = frames.get(factoryKey);
if (frame == null) {
// it's the first time we need this frame, build it and store it
frame = new FactoryManagedFrame(getGTOD(IERSConventions.IERS_1996, false, true),
new VEISProvider(getTimeScales()), true, factoryKey);
frames.put(factoryKey, frame);
}
return frame;
}
}
@Override
public FactoryManagedFrame getITRFEquinox(final IERSConventions conventions,
final boolean simpleEOP) {
synchronized (this) {
// try to find an already built frame
final Predefined factoryKey;
switch (conventions) {
case IERS_1996 :
factoryKey = simpleEOP ?
Predefined.ITRF_EQUINOX_CONV_1996_SIMPLE_EOP :
Predefined.ITRF_EQUINOX_CONV_1996_ACCURATE_EOP;
break;
case IERS_2003 :
factoryKey = simpleEOP ?
Predefined.ITRF_EQUINOX_CONV_2003_SIMPLE_EOP :
Predefined.ITRF_EQUINOX_CONV_2003_ACCURATE_EOP;
break;
case IERS_2010 :
factoryKey = simpleEOP ?
Predefined.ITRF_EQUINOX_CONV_2010_SIMPLE_EOP :
Predefined.ITRF_EQUINOX_CONV_2010_ACCURATE_EOP;
break;
default :
// this should never happen
throw new OrekitInternalError(null);
}
FactoryManagedFrame frame = frames.get(factoryKey);
if (frame == null) {
// it's the first time we need this frame, build it and store it
final Frame gtod = getGTOD(conventions, true, simpleEOP);
final ShiftingTransformProvider gtodShifting =
(ShiftingTransformProvider) gtod.getTransformProvider();
final GTODProvider gtodRaw = (GTODProvider) gtodShifting.getRawProvider();
final EOPHistory eopHistory = gtodRaw.getEOPHistory();
frame = new FactoryManagedFrame(gtod, new ITRFProvider(eopHistory), false, factoryKey);
frames.put(factoryKey, frame);
}
return frame;
}
}
@Override
public FactoryManagedFrame getGTOD(final boolean applyEOPCorr) {
return getGTOD(IERSConventions.IERS_1996, applyEOPCorr, true);
}
@Override
public FactoryManagedFrame getGTOD(final IERSConventions conventions,
final boolean simpleEOP) {
return getGTOD(conventions, true, simpleEOP);
}
/** Get the GTOD reference frame.
* <p>
* The applyEOPCorr parameter is available mainly for testing purposes or for
* consistency with legacy software that don't handle EOP correction parameters.
* Beware that setting this parameter to {@code false} leads to crude accuracy
* (order of magnitudes for errors might be above 250m in LEO and 1400m in GEO).
* For this reason, setting this parameter to false is restricted to {@link
* IERSConventions#IERS_1996 IERS 1996} conventions, and hence this method is private.
* </p>
* @param conventions IERS conventions to apply
* @param applyEOPCorr if true, EOP corrections are applied (here, dut1 and lod)
* @param simpleEOP if true, tidal effects are ignored when interpolating EOP
* @return the selected reference frame singleton.
*/
private FactoryManagedFrame getGTOD(final IERSConventions conventions,
final boolean applyEOPCorr,
final boolean simpleEOP) {
synchronized (this) {
// try to find an already built frame
final Predefined factoryKey;
switch (conventions) {
case IERS_1996 :
factoryKey = applyEOPCorr ?
(simpleEOP ? Predefined.GTOD_CONVENTIONS_1996_SIMPLE_EOP : Predefined.GTOD_CONVENTIONS_1996_ACCURATE_EOP) :
Predefined.GTOD_WITHOUT_EOP_CORRECTIONS;
break;
case IERS_2003 :
factoryKey = simpleEOP ?
Predefined.GTOD_CONVENTIONS_2003_SIMPLE_EOP :
Predefined.GTOD_CONVENTIONS_2003_ACCURATE_EOP;
break;
case IERS_2010 :
factoryKey = simpleEOP ? Predefined.GTOD_CONVENTIONS_2010_SIMPLE_EOP :
Predefined.GTOD_CONVENTIONS_2010_ACCURATE_EOP;
break;
default :
// this should never happen
throw new OrekitInternalError(null);
}
FactoryManagedFrame frame = frames.get(factoryKey);
if (frame == null) {
// it's the first time we need this frame, build it and store it
final Frame tod = getTOD(conventions, applyEOPCorr, simpleEOP);
final ShiftingTransformProvider todInterpolating =
(ShiftingTransformProvider) tod.getTransformProvider();
final TODProvider todRaw = (TODProvider) todInterpolating.getRawProvider();
final EOPHistory eopHistory = todRaw.getEOPHistory();
final GTODProvider gtodRaw =
new GTODProvider(conventions, eopHistory, getTimeScales());
final TransformProvider gtodShifting =
new ShiftingTransformProvider(gtodRaw,
CartesianDerivativesFilter.USE_PVA,
AngularDerivativesFilter.USE_R,
todInterpolating.getGridPoints(), todInterpolating.getStep(),
OrekitConfiguration.getCacheSlotsNumber(),
Constants.JULIAN_YEAR, 30 * Constants.JULIAN_DAY);
frame = new FactoryManagedFrame(tod, gtodShifting, false, factoryKey);
frames.put(factoryKey, frame);
}
return frame;
}
}
@Override
public FactoryManagedFrame getTOD(final boolean applyEOPCorr) {
return getTOD(IERSConventions.IERS_1996, applyEOPCorr, false);
}
@Override
public FactoryManagedFrame getTOD(final IERSConventions conventions,
final boolean simpleEOP) {
return getTOD(conventions, true, simpleEOP);
}
/** Get the TOD reference frame.
* <p>
* The applyEOPCorr parameter is available mainly for testing purposes or for
* consistency with legacy software that don't handle EOP correction parameters.
* Beware that setting this parameter to {@code false} leads to crude accuracy
* (order of magnitudes for errors might be above 1m in LEO and 10m in GEO).
* For this reason, setting this parameter to false is restricted to {@link
* IERSConventions#IERS_1996 IERS 1996} conventions, and hence this method is private.
* </p>
* @param conventions IERS conventions to apply
* @param applyEOPCorr if true, EOP corrections are applied (here, nutation)
* @param simpleEOP if true, tidal effects are ignored when interpolating EOP
* @return the selected reference frame singleton.
*/
private FactoryManagedFrame getTOD(final IERSConventions conventions,
final boolean applyEOPCorr,
final boolean simpleEOP) {
synchronized (this) {
// try to find an already built frame
final Predefined factoryKey;
switch (conventions) {
case IERS_1996 :
factoryKey = applyEOPCorr ?
(simpleEOP ? Predefined.TOD_CONVENTIONS_1996_SIMPLE_EOP : Predefined.TOD_CONVENTIONS_1996_ACCURATE_EOP) :
Predefined.TOD_WITHOUT_EOP_CORRECTIONS;
break;
case IERS_2003 :
factoryKey = simpleEOP ?
Predefined.TOD_CONVENTIONS_2003_SIMPLE_EOP :
Predefined.TOD_CONVENTIONS_2003_ACCURATE_EOP;
break;
case IERS_2010 :
factoryKey = simpleEOP ?
Predefined.TOD_CONVENTIONS_2010_SIMPLE_EOP :
Predefined.TOD_CONVENTIONS_2010_ACCURATE_EOP;
break;
default :
// this should never happen
throw new OrekitInternalError(null);
}
final int interpolationPoints;
final int pointsPerDay;
if (applyEOPCorr) {
interpolationPoints = 6;
pointsPerDay = 24;
} else {
interpolationPoints = 6;
pointsPerDay = 8;
}
FactoryManagedFrame frame = frames.get(factoryKey);
if (frame == null) {
// it's the first time we need this frame, build it and store it
final EOPHistory eopHistory = applyEOPCorr ?
getEOPHistory(conventions, simpleEOP) :
null;
final TransformProvider shifting =
new ShiftingTransformProvider(
new TODProvider(conventions, eopHistory, getTimeScales()),
CartesianDerivativesFilter.USE_PVA,
AngularDerivativesFilter.USE_R,
interpolationPoints, Constants.JULIAN_DAY / pointsPerDay,
OrekitConfiguration.getCacheSlotsNumber(),
Constants.JULIAN_YEAR, 30 * Constants.JULIAN_DAY);
frame = new FactoryManagedFrame(getMOD(conventions, applyEOPCorr), shifting, true, factoryKey);
frames.put(factoryKey, frame);
}
return frame;
}
}
@Override
public FactoryManagedFrame getMOD(final boolean applyEOPCorr) {
return getMOD(IERSConventions.IERS_1996, applyEOPCorr);
}
@Override
public FactoryManagedFrame getMOD(final IERSConventions conventions) {
return getMOD(conventions, true);
}
/** Get the MOD reference frame.
* <p>
* The applyEOPCorr parameter is available mainly for testing purposes or for
* consistency with legacy software that don't handle EOP correction parameters.
* Beware that setting this parameter to {@code false} leads to crude accuracy
* (order of magnitudes for errors might be above 1m in LEO and 10m in GEO).
* For this reason, setting this parameter to false is restricted to {@link
* IERSConventions#IERS_1996 IERS 1996} conventions, and hence this method is private.
* </p>
* @param conventions IERS conventions to apply
* @param applyEOPCorr if true, EOP corrections are applied (EME2000/GCRF bias compensation)
* @return the selected reference frame singleton.
*/
private FactoryManagedFrame getMOD(final IERSConventions conventions, final boolean applyEOPCorr) {
synchronized (this) {
final Predefined factoryKey;
final Frame parent;
switch (conventions) {
case IERS_1996 :
factoryKey = applyEOPCorr ? Predefined.MOD_CONVENTIONS_1996 : Predefined.MOD_WITHOUT_EOP_CORRECTIONS;
parent = applyEOPCorr ? getGCRF() : getEME2000();
break;
case IERS_2003 :
factoryKey = Predefined.MOD_CONVENTIONS_2003;
// in IERS conventions 2003, the precession angles zetaA, thetaA and zA
// from equation 33 are computed from EME2000, not from GCRF
parent = getEME2000();
break;
case IERS_2010 :
factoryKey = Predefined.MOD_CONVENTIONS_2010;
// precession angles epsilon0, psiA, omegaA and chiA
// from equations 5.39 and 5.40 are computed from EME2000
parent = getEME2000();
break;
default :
// this should never happen
throw new OrekitInternalError(null);
}
// try to find an already built frame
FactoryManagedFrame frame = frames.get(factoryKey);
if (frame == null) {
// it's the first time we need this frame, build it and store it
final MODProvider provider = new MODProvider(conventions, getTimeScales());
frame = new FactoryManagedFrame(parent, provider, true, factoryKey);
frames.put(factoryKey, frame);
}
return frame;
}
}
@Override
public FactoryManagedFrame getTEME() {
synchronized (this) {
// try to find an already built frame
final Predefined factoryKey = Predefined.TEME;
FactoryManagedFrame frame = frames.get(factoryKey);
if (frame == null) {
// it's the first time we need this frame, build it and store it
final Frame tod = getTOD(IERSConventions.IERS_1996, false, true);
final ShiftingTransformProvider todShifting =
(ShiftingTransformProvider) tod.getTransformProvider();
final TEMEProvider temeRaw =
new TEMEProvider(IERSConventions.IERS_1996, null, getTimeScales());
final TransformProvider temeShifting =
new ShiftingTransformProvider(temeRaw,
CartesianDerivativesFilter.USE_PVA,
AngularDerivativesFilter.USE_R,
todShifting.getGridPoints(), todShifting.getStep(),
OrekitConfiguration.getCacheSlotsNumber(),
Constants.JULIAN_YEAR, 30 * Constants.JULIAN_DAY);
frame = new FactoryManagedFrame(tod, temeShifting, true, factoryKey);
frames.put(factoryKey, frame);
}
return frame;
}
}
@Override
public FactoryManagedFrame getPZ9011(final IERSConventions convention,
final boolean simpleEOP) {
synchronized (this) {
// try to find an already built frame
final Predefined factoryKey = Predefined.PZ90_11;
FactoryManagedFrame frame = frames.get(factoryKey);
if (frame == null) {
// it's the first time we need this frame, build it and store it
final Frame itrf = getITRF(ITRFVersion.ITRF_2008, convention, simpleEOP);
final HelmertTransformation pz90Raw = new HelmertTransformation(new AbsoluteDate(2010, 1, 1, 12, 0, 0, getTimeScales().getTT()),
+3.0, +1.0, -0.0, +0.019, -0.042, +0.002, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
frame = new FactoryManagedFrame(itrf, pz90Raw, false, factoryKey);
frames.put(factoryKey, frame);
}
return frame;
}
}
/**
* Get the time scales.
*
* @return time scales used to define these frames.
*/
protected TimeScales getTimeScales() {
return timeScales;
}
/** Local class for different ITRF versions keys.
* @since 9.2
*/
private static class ITRFKey implements Serializable {
/** Serialized UID. */
private static final long serialVersionUID = 20180412L;
/** ITRF version. */
private final ITRFVersion version;
/** IERS conventions to apply. */
private final IERSConventions conventions;
/** Tidal effects flag. */
private final boolean simpleEOP;
/** Simple constructor.
* @param version ITRF version
* @param conventions IERS conventions to apply
* @param simpleEOP if true, tidal effects are ignored when interpolating EOP
*/
ITRFKey(final ITRFVersion version, final IERSConventions conventions, final boolean simpleEOP) {
this.version = version;
this.conventions = conventions;
this.simpleEOP = simpleEOP;
}
/** {@inheritDoc} */
@Override
public int hashCode() {
return (version.ordinal() << 5) +
(conventions.ordinal() << 1) +
(simpleEOP ? 0 : 1);
}
/** {@inheritDoc} */
@Override
public boolean equals(final Object other) {
if (this == other) {
return true;
}
if (other instanceof ITRFKey) {
final ITRFKey key = (ITRFKey) other;
return version == key.version &&
conventions == key.conventions &&
simpleEOP == key.simpleEOP;
}
return false;
}
}
}