PredictedEOPHistory.java

  1. /* Copyright 2002-2024 Luc Maisonobe
  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.ArrayList;
  20. import java.util.Collection;
  21. import java.util.List;

  22. import org.hipparchus.util.FastMath;
  23. import org.orekit.annotation.DefaultDataContext;
  24. import org.orekit.errors.OrekitException;
  25. import org.orekit.errors.OrekitInternalError;
  26. import org.orekit.time.AbsoluteDate;
  27. import org.orekit.utils.Constants;
  28. import org.orekit.utils.IERSConventions.NutationCorrectionConverter;
  29. import org.orekit.utils.SecularAndHarmonic;

  30. /** This class extends an {@link EOPHistory} for some weeks using fitting.
  31.  * <p>
  32.  * The goal of this class is to provide a reasonable prediction of
  33.  * Earth Orientation Parameters past the last date available in
  34.  * regular {@link EOPHistory}, which just generated corrections set
  35.  * to 0 when they have no data.
  36.  * </p>
  37.  * <p>
  38.  * The prediction is based on fitting of last data, with both
  39.  * {@link SecularAndHarmonic secular (polynomial) and harmonic (periodic)}
  40.  * terms. The extended entries are generated at one point per day
  41.  * and are continuous (i.e. no leap seconds are introduced)
  42.  * </p>
  43.  * <p>
  44.  * After construction, the history contains both the initial
  45.  * raw history and an extension part appended after it.
  46.  * </p>
  47.  * @see EOPFitter
  48.  * @see SecularAndHarmonic
  49.  * @since 12.0
  50.  * @author Luc Maisonobe
  51.  */
  52. public class PredictedEOPHistory extends EOPHistory implements Serializable {

  53.     /** Serializable UID. */
  54.     private static final long serialVersionUID = 20230309L;

  55.     /** Raw EOP history to extend. */
  56.     private final EOPHistory rawHistory;

  57.     /** Duration of the extension period (s). */
  58.     private final double extensionDuration;

  59.     /** Fitter for all Earth Orientation Parameters. */
  60.     private final EOPFitter fitter;

  61.     /** Simple constructor.
  62.      * @param rawHistory raw EOP history to extend.
  63.      * @param extensionDuration duration of the extension period (s)
  64.      * @param fitter fitter for all Earth Orientation Parameters
  65.      */
  66.     public PredictedEOPHistory(final EOPHistory rawHistory, final double extensionDuration,
  67.                                final EOPFitter fitter) {
  68.         super(rawHistory.getConventions(), rawHistory.getInterpolationDegree(),
  69.               extendHistory(rawHistory, extensionDuration, fitter),
  70.               rawHistory.isSimpleEop(), rawHistory.getTimeScales());
  71.         this.rawHistory        = rawHistory;
  72.         this.extensionDuration = extensionDuration;
  73.         this.fitter            = fitter;
  74.     }

  75.     /** Extends raw history.
  76.      * @param rawHistory raw EOP history to extend.
  77.      * @param extensionDuration duration of the extension period (s)
  78.      * @param fitter fitter for all Earth Orientation Parameters
  79.      * @return extended history
  80.      */
  81.     private static Collection<? extends EOPEntry> extendHistory(final EOPHistory rawHistory,
  82.                                                                 final double extensionDuration,
  83.                                                                 final EOPFitter fitter) {


  84.         // fit model
  85.         final EOPFittedModel model = fitter.fit(rawHistory);

  86.         // create a converter for nutation corrections
  87.         final NutationCorrectionConverter converter =
  88.                         rawHistory.getConventions().getNutationCorrectionConverter(rawHistory.getTimeScales());

  89.         // generate extension entries
  90.         final List<EOPEntry> rawEntries = rawHistory.getEntries();
  91.         final EOPEntry       last       = rawEntries.get(rawEntries.size() - 1);
  92.         final int n = (int) FastMath.rint(extensionDuration / Constants.JULIAN_DAY);
  93.         final List<EOPEntry> entries = new ArrayList<>(rawEntries.size() + n);
  94.         entries.addAll(rawEntries);
  95.         for (int i = 0; i < n; ++i) {
  96.             final AbsoluteDate date = last.getDate().shiftedBy((i + 1) * Constants.JULIAN_DAY);
  97.             final double dut1   = model.getDUT1().osculatingValue(date);
  98.             final double lod    = -Constants.JULIAN_DAY * model.getDUT1().osculatingDerivative(date);
  99.             final double xp     = model.getXp().osculatingValue(date);
  100.             final double yp     = model.getYp().osculatingValue(date);
  101.             final double xpRate = model.getXp().osculatingDerivative(date);
  102.             final double ypRate = model.getYp().osculatingDerivative(date);
  103.             final double dx     = model.getDx().osculatingValue(date);
  104.             final double dy     = model.getDy().osculatingValue(date);
  105.             final double[] equinox = converter.toEquinox(date, dx, dy);
  106.             entries.add(new EOPEntry(last.getMjd() + i + 1, dut1, lod, xp, yp, xpRate, ypRate,
  107.                                      equinox[0], equinox[1], dx, dy,
  108.                                      last.getITRFType(), date));
  109.         }

  110.         return entries;

  111.     }

  112.     /** Replace the instance with a data transfer object for serialization.
  113.      * @return data transfer object that will be serialized
  114.      */
  115.     @DefaultDataContext
  116.     private Object writeReplace() {
  117.         return new DataTransferObject(rawHistory, extensionDuration, fitter);
  118.     }

  119.     /** Internal class used only for serialization. */
  120.     @DefaultDataContext
  121.     private static class DataTransferObject implements Serializable {

  122.         /** Serializable UID. */
  123.         private static final long serialVersionUID = 20230309L;

  124.         /** Raw EOP history to extend. */
  125.         private final EOPHistory rawHistory;

  126.         /** Duration of the extension period (s). */
  127.         private final double extensionDuration;

  128.         /** Fitter for all Earth Orientation Parameters. */
  129.         private final EOPFitter fitter;

  130.         /** Simple constructor.
  131.          * @param rawHistory raw EOP history to extend.
  132.          * @param extensionDuration duration of the extension period (s)
  133.          * @param fitter fitter for all Earth Orientation Parameters
  134.          */
  135.         DataTransferObject(final EOPHistory rawHistory, final double extensionDuration, final EOPFitter fitter) {
  136.             this.rawHistory        = rawHistory;
  137.             this.extensionDuration = extensionDuration;
  138.             this.fitter            = fitter;
  139.         }

  140.         /** Replace the deserialized data transfer object with a {@link PredictedEOPHistory}.
  141.          * @return replacement {@link PredictedEOPHistory}
  142.          */
  143.         private Object readResolve() {
  144.             try {
  145.                 return new PredictedEOPHistory(rawHistory, extensionDuration, fitter);
  146.             } catch (OrekitException oe) {
  147.                 throw new OrekitInternalError(oe);
  148.             }
  149.         }

  150.     }

  151. }