1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.time.clocks;
18
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.List;
22 import java.util.Map;
23
24 import org.hipparchus.CalculusFieldElement;
25 import org.hipparchus.analysis.differentiation.Gradient;
26 import org.hipparchus.analysis.polynomials.PolynomialFunction;
27 import org.hipparchus.util.FastMath;
28 import org.orekit.errors.OrekitException;
29 import org.orekit.errors.OrekitMessages;
30 import org.orekit.time.AbsoluteDate;
31 import org.orekit.time.FieldAbsoluteDate;
32 import org.orekit.utils.ParameterDriver;
33
34
35
36
37
38
39
40 public class PolynomialClockModel implements ClockModel {
41
42
43
44
45
46
47
48
49 private static final double CLOCK_OFFSET_SCALE = FastMath.scalb(1.0, -10);
50
51
52 private final List<ParameterDriver> terms;
53
54
55
56
57
58
59 public PolynomialClockModel(final AbsoluteDate referenceDate) {
60 this.terms = new ArrayList<>();
61 final ParameterDriver parameterTerm = new ParameterDriver("-clock-bias", 0.0, CLOCK_OFFSET_SCALE,
62 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
63 parameterTerm.setValue(0);
64 parameterTerm.setReferenceDate(referenceDate);
65 this.terms.add(parameterTerm);
66 }
67
68
69
70
71
72
73
74 public PolynomialClockModel(final AbsoluteDate referenceDate,
75 final double... terms) {
76 Integer ii = 0;
77 final List<ParameterDriver> convertedTerms = new ArrayList<>();
78 for (double term : terms) {
79 final String name = getAcceptedTermName(ii);
80 final ParameterDriver parameterTerm = new ParameterDriver(name, 0.0, CLOCK_OFFSET_SCALE,
81 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
82 parameterTerm.setValue(term);
83 parameterTerm.setReferenceDate(referenceDate);
84 convertedTerms.add(parameterTerm);
85 ++ii;
86 }
87 this.terms = convertedTerms;
88 }
89
90
91
92
93
94
95 public PolynomialClockModel(final ParameterDriver... terms) {
96 Integer idx = 0;
97 for (final ParameterDriver term : terms) {
98 final String accepted_name_format = getAcceptedTermName(idx);
99 if (!term.getName().contains(accepted_name_format)) {
100 throw new OrekitException(OrekitMessages.UNSUPPORTED_PARAMETER_NAME, term.getName(), accepted_name_format);
101 }
102 idx++;
103 }
104 this.terms = Arrays.asList(terms);
105 }
106
107
108
109
110
111
112 public PolynomialClockModel(final List<ParameterDriver> terms) {
113 this(terms.toArray(new ParameterDriver[0]));
114 }
115
116
117 @Override
118 public AbsoluteDate getValidityStart() {
119 return AbsoluteDate.PAST_INFINITY;
120 }
121
122
123 @Override
124 public AbsoluteDate getValidityEnd() {
125 return AbsoluteDate.FUTURE_INFINITY;
126 }
127
128
129 @Override
130 public List<ParameterDriver> getParametersDrivers() {
131 return terms;
132 }
133
134
135
136
137
138
139
140
141 public void addParameterDriver(final Integer index, final ParameterDriver driver) {
142 final List<ParameterDriver> parameters = getParametersDrivers();
143 if (parameters.size() < index) {
144
145 addParameterDriver(index - 1, null);
146
147 addParameterDriver(index, driver);
148 } else if (parameters.size() == index && driver != null) {
149
150 parameters.add(driver);
151 } else if (parameters.size() == index && driver == null) {
152
153 final ParameterDriver empty = new ParameterDriver(getAcceptedTermName(index), 0.0, CLOCK_OFFSET_SCALE,
154 Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
155 empty.setReferenceDate(AbsoluteDate.ARBITRARY_EPOCH);
156 parameters.add(empty);
157 }
158 }
159
160
161 @Override
162 public ClockOffset getOffset(final AbsoluteDate date) {
163 final double[] result = new double[3];
164 if (terms.isEmpty()) {
165 return new ClockOffset(date, result);
166 }
167 final double dt = date.durationFrom(getSafeReference(date));
168 final double[] convertedTerms = terms.stream().map(x -> x.getValue(date)).mapToDouble(Double::doubleValue).toArray();
169
170 PolynomialFunction function = new PolynomialFunction(convertedTerms);
171
172 for (int ii = 0; ii < 3; ii++) {
173 result[ii] = function.value(dt);
174 function = function.polynomialDerivative();
175 }
176 return new ClockOffset(date, result);
177 }
178
179
180 @Override
181 public <T extends CalculusFieldElement<T>> FieldClockOffset<T> getFieldOffset(final FieldAbsoluteDate<T> date) {
182 final AbsoluteDate aDate = date.toAbsoluteDate();
183 final T dt = date.durationFrom(getSafeReference(aDate));
184 final List<T> result = new ArrayList<>(3);
185
186
187 final double[] convertedTerms = terms.stream().map(x -> x.getValue(aDate)).mapToDouble(Double::doubleValue).toArray();
188
189 PolynomialFunction function = new PolynomialFunction(convertedTerms);
190 for (int ii = 0; ii < 3; ii++) {
191 final T newValue = function.value(dt);
192 result.add(newValue);
193
194 function = function.polynomialDerivative();
195 }
196 return new FieldClockOffset<>(date, result);
197 }
198
199
200 @Override
201 public FieldClockModel<Gradient> getFieldModel(final int freeParameters,
202 final Map<String, Integer> indices, final AbsoluteDate date) {
203 if (terms.isEmpty()) {
204 return null;
205 }
206 final Gradient[] gradients = terms.stream().map(x -> x.getValue(freeParameters, indices, date))
207 .toArray(Gradient[]::new);
208 final FieldAbsoluteDate<Gradient> referenceDate = new FieldAbsoluteDate<>(gradients[0].getField(),
209 getSafeReference(date));
210 return new PolynomialFieldClockModel<>(referenceDate, gradients);
211 }
212
213
214
215
216
217
218
219
220
221
222
223
224 private AbsoluteDate getSafeReference(final AbsoluteDate date) {
225
226 final double EPS = 1e-9;
227 if (terms.isEmpty()) {
228 return date;
229 }
230 final ParameterDriver firstTerm = terms.getFirst();
231 if (firstTerm.getReferenceDate() == null) {
232 boolean allOtherDatesZero = true;
233 for (final ParameterDriver term: terms) {
234 if (FastMath.abs(term.getValue(date)) > EPS) {
235 allOtherDatesZero = false;
236 }
237 }
238 if (allOtherDatesZero) {
239
240 return date;
241 } else {
242 throw new OrekitException(OrekitMessages.NO_REFERENCE_DATE_FOR_PARAMETER,
243 firstTerm.getName());
244 }
245 } else {
246 return firstTerm.getReferenceDate();
247 }
248 }
249
250 }