PredictedEOPHistory.java
/* Copyright 2002-2024 Luc Maisonobe
* 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.ArrayList;
import java.util.Collection;
import java.util.List;
import org.hipparchus.util.FastMath;
import org.orekit.annotation.DefaultDataContext;
import org.orekit.errors.OrekitException;
import org.orekit.errors.OrekitInternalError;
import org.orekit.time.AbsoluteDate;
import org.orekit.utils.Constants;
import org.orekit.utils.IERSConventions.NutationCorrectionConverter;
import org.orekit.utils.SecularAndHarmonic;
/** This class extends an {@link EOPHistory} for some weeks using fitting.
* <p>
* The goal of this class is to provide a reasonable prediction of
* Earth Orientation Parameters past the last date available in
* regular {@link EOPHistory}, which just generated corrections set
* to 0 when they have no data.
* </p>
* <p>
* The prediction is based on fitting of last data, with both
* {@link SecularAndHarmonic secular (polynomial) and harmonic (periodic)}
* terms. The extended entries are generated at one point per day
* and are continuous (i.e. no leap seconds are introduced)
* </p>
* <p>
* After construction, the history contains both the initial
* raw history and an extension part appended after it.
* </p>
* @see EOPFitter
* @see SecularAndHarmonic
* @since 12.0
* @author Luc Maisonobe
*/
public class PredictedEOPHistory extends EOPHistory implements Serializable {
/** Serializable UID. */
private static final long serialVersionUID = 20230309L;
/** Raw EOP history to extend. */
private final EOPHistory rawHistory;
/** Duration of the extension period (s). */
private final double extensionDuration;
/** Fitter for all Earth Orientation Parameters. */
private final EOPFitter fitter;
/** Simple constructor.
* @param rawHistory raw EOP history to extend.
* @param extensionDuration duration of the extension period (s)
* @param fitter fitter for all Earth Orientation Parameters
*/
public PredictedEOPHistory(final EOPHistory rawHistory, final double extensionDuration,
final EOPFitter fitter) {
super(rawHistory.getConventions(), rawHistory.getInterpolationDegree(),
extendHistory(rawHistory, extensionDuration, fitter),
rawHistory.isSimpleEop(), rawHistory.getTimeScales());
this.rawHistory = rawHistory;
this.extensionDuration = extensionDuration;
this.fitter = fitter;
}
/** Extends raw history.
* @param rawHistory raw EOP history to extend.
* @param extensionDuration duration of the extension period (s)
* @param fitter fitter for all Earth Orientation Parameters
* @return extended history
*/
private static Collection<? extends EOPEntry> extendHistory(final EOPHistory rawHistory,
final double extensionDuration,
final EOPFitter fitter) {
// fit model
final EOPFittedModel model = fitter.fit(rawHistory);
// create a converter for nutation corrections
final NutationCorrectionConverter converter =
rawHistory.getConventions().getNutationCorrectionConverter(rawHistory.getTimeScales());
// generate extension entries
final List<EOPEntry> rawEntries = rawHistory.getEntries();
final EOPEntry last = rawEntries.get(rawEntries.size() - 1);
final int n = (int) FastMath.rint(extensionDuration / Constants.JULIAN_DAY);
final List<EOPEntry> entries = new ArrayList<>(rawEntries.size() + n);
entries.addAll(rawEntries);
for (int i = 0; i < n; ++i) {
final AbsoluteDate date = last.getDate().shiftedBy((i + 1) * Constants.JULIAN_DAY);
final double dut1 = model.getDUT1().osculatingValue(date);
final double lod = -Constants.JULIAN_DAY * model.getDUT1().osculatingDerivative(date);
final double xp = model.getXp().osculatingValue(date);
final double yp = model.getYp().osculatingValue(date);
final double xpRate = model.getXp().osculatingDerivative(date);
final double ypRate = model.getYp().osculatingDerivative(date);
final double dx = model.getDx().osculatingValue(date);
final double dy = model.getDy().osculatingValue(date);
final double[] equinox = converter.toEquinox(date, dx, dy);
entries.add(new EOPEntry(last.getMjd() + i + 1, dut1, lod, xp, yp, xpRate, ypRate,
equinox[0], equinox[1], dx, dy,
last.getITRFType(), date));
}
return entries;
}
/** Replace the instance with a data transfer object for serialization.
* @return data transfer object that will be serialized
*/
@DefaultDataContext
private Object writeReplace() {
return new DataTransferObject(rawHistory, extensionDuration, fitter);
}
/** Internal class used only for serialization. */
@DefaultDataContext
private static class DataTransferObject implements Serializable {
/** Serializable UID. */
private static final long serialVersionUID = 20230309L;
/** Raw EOP history to extend. */
private final EOPHistory rawHistory;
/** Duration of the extension period (s). */
private final double extensionDuration;
/** Fitter for all Earth Orientation Parameters. */
private final EOPFitter fitter;
/** Simple constructor.
* @param rawHistory raw EOP history to extend.
* @param extensionDuration duration of the extension period (s)
* @param fitter fitter for all Earth Orientation Parameters
*/
DataTransferObject(final EOPHistory rawHistory, final double extensionDuration, final EOPFitter fitter) {
this.rawHistory = rawHistory;
this.extensionDuration = extensionDuration;
this.fitter = fitter;
}
/** Replace the deserialized data transfer object with a {@link PredictedEOPHistory}.
* @return replacement {@link PredictedEOPHistory}
*/
private Object readResolve() {
try {
return new PredictedEOPHistory(rawHistory, extensionDuration, fitter);
} catch (OrekitException oe) {
throw new OrekitInternalError(oe);
}
}
}
}