1   /* Copyright 2022-2025 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  
19  import java.util.ArrayList;
20  import java.util.Collection;
21  import java.util.List;
22  
23  import org.hipparchus.util.FastMath;
24  import org.orekit.time.AbsoluteDate;
25  import org.orekit.utils.Constants;
26  import org.orekit.utils.IERSConventions.NutationCorrectionConverter;
27  import org.orekit.utils.SecularAndHarmonic;
28  
29  /** This class extends an {@link EOPHistory} for some weeks using fitting.
30   * <p>
31   * The goal of this class is to provide a reasonable prediction of
32   * Earth Orientation Parameters past the last date available in
33   * regular {@link EOPHistory}, which just generated corrections set
34   * to 0 when they have no data.
35   * </p>
36   * <p>
37   * The prediction is based on fitting of last data, with both
38   * {@link SecularAndHarmonic secular (polynomial) and harmonic (periodic)}
39   * terms. The extended entries are generated at one point per day
40   * and are continuous (i.e. no leap seconds are introduced)
41   * </p>
42   * <p>
43   * After construction, the history contains both the initial
44   * raw history and an extension part appended after it.
45   * </p>
46   * @see EOPFitter
47   * @see SecularAndHarmonic
48   * @since 12.0
49   * @author Luc Maisonobe
50   */
51  public class PredictedEOPHistory extends EOPHistory {
52  
53      /** Raw EOP history to extend. */
54      private final EOPHistory rawHistory;
55  
56      /** Duration of the extension period (s). */
57      private final double extensionDuration;
58  
59      /** Fitter for all Earth Orientation Parameters. */
60      private final EOPFitter fitter;
61  
62      /** Simple constructor.
63       * @param rawHistory raw EOP history to extend.
64       * @param extensionDuration duration of the extension period (s)
65       * @param fitter fitter for all Earth Orientation Parameters
66       */
67      public PredictedEOPHistory(final EOPHistory rawHistory, final double extensionDuration,
68                                 final EOPFitter fitter) {
69          super(rawHistory.getConventions(), rawHistory.getInterpolationDegree(),
70                extendHistory(rawHistory, extensionDuration, fitter),
71                rawHistory.isSimpleEop(), rawHistory.getTimeScales());
72          this.rawHistory        = rawHistory;
73          this.extensionDuration = extensionDuration;
74          this.fitter            = fitter;
75      }
76  
77      /** Extends raw history.
78       * @param rawHistory raw EOP history to extend.
79       * @param extensionDuration duration of the extension period (s)
80       * @param fitter fitter for all Earth Orientation Parameters
81       * @return extended history
82       */
83      private static Collection<? extends EOPEntry> extendHistory(final EOPHistory rawHistory,
84                                                                  final double extensionDuration,
85                                                                  final EOPFitter fitter) {
86  
87  
88          // fit model
89          final EOPFittedModel model = fitter.fit(rawHistory);
90  
91          // create a converter for nutation corrections
92          final NutationCorrectionConverter converter =
93                          rawHistory.getConventions().getNutationCorrectionConverter(rawHistory.getTimeScales());
94  
95          // generate extension entries
96          final List<EOPEntry> rawEntries = rawHistory.getEntries();
97          final EOPEntry       last       = rawEntries.get(rawEntries.size() - 1);
98          final int n = (int) FastMath.rint(extensionDuration / Constants.JULIAN_DAY);
99          final List<EOPEntry> entries = new ArrayList<>(rawEntries.size() + n);
100         entries.addAll(rawEntries);
101         for (int i = 0; i < n; ++i) {
102             final AbsoluteDate date = last.getDate().shiftedBy((i + 1) * Constants.JULIAN_DAY);
103             final double dut1   = model.getDUT1().osculatingValue(date);
104             final double lod    = -Constants.JULIAN_DAY * model.getDUT1().osculatingDerivative(date);
105             final double xp     = model.getXp().osculatingValue(date);
106             final double yp     = model.getYp().osculatingValue(date);
107             final double xpRate = model.getXp().osculatingDerivative(date);
108             final double ypRate = model.getYp().osculatingDerivative(date);
109             final double dx     = model.getDx().osculatingValue(date);
110             final double dy     = model.getDy().osculatingValue(date);
111             final double[] equinox = converter.toEquinox(date, dx, dy);
112             entries.add(new EOPEntry(last.getMjd() + i + 1, dut1, lod, xp, yp, xpRate, ypRate,
113                                      equinox[0], equinox[1], dx, dy,
114                                      last.getITRFType(), date));
115         }
116 
117         return entries;
118 
119     }
120 
121 }