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
19 import java.io.Serializable;
20 import java.util.ArrayList;
21 import java.util.Collection;
22 import java.util.List;
23
24 import org.hipparchus.util.FastMath;
25 import org.orekit.annotation.DefaultDataContext;
26 import org.orekit.errors.OrekitException;
27 import org.orekit.errors.OrekitInternalError;
28 import org.orekit.time.AbsoluteDate;
29 import org.orekit.utils.Constants;
30 import org.orekit.utils.IERSConventions.NutationCorrectionConverter;
31 import org.orekit.utils.SecularAndHarmonic;
32
33 /** This class extends an {@link EOPHistory} for some weeks using fitting.
34 * <p>
35 * The goal of this class is to provide a reasonable prediction of
36 * Earth Orientation Parameters past the last date available in
37 * regular {@link EOPHistory}, which just generated corrections set
38 * to 0 when they have no data.
39 * </p>
40 * <p>
41 * The prediction is based on fitting of last data, with both
42 * {@link SecularAndHarmonic secular (polynomial) and harmonic (periodic)}
43 * terms. The extended entries are generated at one point per day
44 * and are continuous (i.e. no leap seconds are introduced)
45 * </p>
46 * <p>
47 * After construction, the history contains both the initial
48 * raw history and an extension part appended after it.
49 * </p>
50 * @see EOPFitter
51 * @see SecularAndHarmonic
52 * @since 12.0
53 * @author Luc Maisonobe
54 */
55 public class PredictedEOPHistory extends EOPHistory implements Serializable {
56
57 /** Serializable UID. */
58 private static final long serialVersionUID = 20230309L;
59
60 /** Raw EOP history to extend. */
61 private final EOPHistory rawHistory;
62
63 /** Duration of the extension period (s). */
64 private final double extensionDuration;
65
66 /** Fitter for all Earth Orientation Parameters. */
67 private final EOPFitter fitter;
68
69 /** Simple constructor.
70 * @param rawHistory raw EOP history to extend.
71 * @param extensionDuration duration of the extension period (s)
72 * @param fitter fitter for all Earth Orientation Parameters
73 */
74 public PredictedEOPHistory(final EOPHistory rawHistory, final double extensionDuration,
75 final EOPFitter fitter) {
76 super(rawHistory.getConventions(), rawHistory.getInterpolationDegree(),
77 extendHistory(rawHistory, extensionDuration, fitter),
78 rawHistory.isSimpleEop(), rawHistory.getTimeScales());
79 this.rawHistory = rawHistory;
80 this.extensionDuration = extensionDuration;
81 this.fitter = fitter;
82 }
83
84 /** Extends raw history.
85 * @param rawHistory raw EOP history to extend.
86 * @param extensionDuration duration of the extension period (s)
87 * @param fitter fitter for all Earth Orientation Parameters
88 * @return extended history
89 */
90 private static Collection<? extends EOPEntry> extendHistory(final EOPHistory rawHistory,
91 final double extensionDuration,
92 final EOPFitter fitter) {
93
94
95 // fit model
96 final EOPFittedModel model = fitter.fit(rawHistory);
97
98 // create a converter for nutation corrections
99 final NutationCorrectionConverter converter =
100 rawHistory.getConventions().getNutationCorrectionConverter(rawHistory.getTimeScales());
101
102 // generate extension entries
103 final List<EOPEntry> rawEntries = rawHistory.getEntries();
104 final EOPEntry last = rawEntries.get(rawEntries.size() - 1);
105 final int n = (int) FastMath.rint(extensionDuration / Constants.JULIAN_DAY);
106 final List<EOPEntry> entries = new ArrayList<>(rawEntries.size() + n);
107 entries.addAll(rawEntries);
108 for (int i = 0; i < n; ++i) {
109 final AbsoluteDate date = last.getDate().shiftedBy((i + 1) * Constants.JULIAN_DAY);
110 final double dut1 = model.getDUT1().osculatingValue(date);
111 final double lod = -Constants.JULIAN_DAY * model.getDUT1().osculatingDerivative(date);
112 final double xp = model.getXp().osculatingValue(date);
113 final double yp = model.getYp().osculatingValue(date);
114 final double xpRate = model.getXp().osculatingDerivative(date);
115 final double ypRate = model.getYp().osculatingDerivative(date);
116 final double dx = model.getDx().osculatingValue(date);
117 final double dy = model.getDy().osculatingValue(date);
118 final double[] equinox = converter.toEquinox(date, dx, dy);
119 entries.add(new EOPEntry(last.getMjd() + i + 1, dut1, lod, xp, yp, xpRate, ypRate,
120 equinox[0], equinox[1], dx, dy,
121 last.getITRFType(), date));
122 }
123
124 return entries;
125
126 }
127
128 /** Replace the instance with a data transfer object for serialization.
129 * @return data transfer object that will be serialized
130 */
131 @DefaultDataContext
132 private Object writeReplace() {
133 return new DataTransferObject(rawHistory, extensionDuration, fitter);
134 }
135
136 /** Internal class used only for serialization. */
137 @DefaultDataContext
138 private static class DataTransferObject implements Serializable {
139
140 /** Serializable UID. */
141 private static final long serialVersionUID = 20230309L;
142
143 /** Raw EOP history to extend. */
144 private final EOPHistory rawHistory;
145
146 /** Duration of the extension period (s). */
147 private final double extensionDuration;
148
149 /** Fitter for all Earth Orientation Parameters. */
150 private final EOPFitter fitter;
151
152 /** Simple constructor.
153 * @param rawHistory raw EOP history to extend.
154 * @param extensionDuration duration of the extension period (s)
155 * @param fitter fitter for all Earth Orientation Parameters
156 */
157 DataTransferObject(final EOPHistory rawHistory, final double extensionDuration, final EOPFitter fitter) {
158 this.rawHistory = rawHistory;
159 this.extensionDuration = extensionDuration;
160 this.fitter = fitter;
161 }
162
163 /** Replace the deserialized data transfer object with a {@link PredictedEOPHistory}.
164 * @return replacement {@link PredictedEOPHistory}
165 */
166 private Object readResolve() {
167 try {
168 return new PredictedEOPHistory(rawHistory, extensionDuration, fitter);
169 } catch (OrekitException oe) {
170 throw new OrekitInternalError(oe);
171 }
172 }
173
174 }
175
176 }