1 /* Copyright 2002-2018 CS Systèmes d'Information
2 * Licensed to CS Systèmes d'Information (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
18 package org.orekit.frames;
19
20 import java.io.Serializable;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.stream.Collectors;
25 import java.util.stream.Stream;
26
27 import org.hipparchus.Field;
28 import org.hipparchus.RealFieldElement;
29 import org.orekit.errors.OrekitException;
30 import org.orekit.errors.OrekitExceptionWrapper;
31 import org.orekit.time.AbsoluteDate;
32 import org.orekit.time.FieldAbsoluteDate;
33 import org.orekit.utils.AngularDerivativesFilter;
34 import org.orekit.utils.CartesianDerivativesFilter;
35 import org.orekit.utils.GenericTimeStampedCache;
36
37 /** Transform provider using thread-safe interpolation on transforms sample.
38 * <p>
39 * The interpolation is a polynomial Hermite interpolation, which
40 * can either use or ignore the derivatives provided by the raw
41 * provider. This means that simple raw providers that do not compute
42 * derivatives can be used, the derivatives will be added appropriately
43 * by the interpolation process.
44 * </p>
45 * @see GenericTimeStampedCache
46 * @see ShiftingTransformProvider
47 * @author Luc Maisonobe
48 */
49 public class InterpolatingTransformProvider implements TransformProvider {
50
51 /** Serializable UID. */
52 private static final long serialVersionUID = 20140723L;
53
54 /** Provider for raw (non-interpolated) transforms. */
55 private final TransformProvider rawProvider;
56
57 /** Filter for Cartesian derivatives to use in interpolation. */
58 private final CartesianDerivativesFilter cFilter;
59
60 /** Filter for angular derivatives to use in interpolation. */
61 private final AngularDerivativesFilter aFilter;
62
63 /** Grid points time step. */
64 private final double step;
65
66 /** Cache for sample points. */
67 private final transient GenericTimeStampedCache<Transform> cache;
68
69 /** Field caches for sample points. */
70 // we use Object as the value of fieldCaches because despite numerous attempts,
71 // we could not find a way to use GenericTimeStampedCache<FieldTransform<? extends RealFieldElement<?>>
72 // without the compiler complaining
73 private final transient Map<Field<? extends RealFieldElement<?>>, Object> fieldCaches;
74
75 /** Simple constructor.
76 * @param rawProvider provider for raw (non-interpolated) transforms
77 * @param cFilter filter for derivatives from the sample to use in interpolation
78 * @param aFilter filter for derivatives from the sample to use in interpolation
79 * @param gridPoints number of interpolation grid points
80 * @param step grid points time step
81 * @param maxSlots maximum number of independent cached time slots
82 * in the {@link GenericTimeStampedCache time-stamped cache}
83 * @param maxSpan maximum duration span in seconds of one slot
84 * in the {@link GenericTimeStampedCache time-stamped cache}
85 * @param newSlotInterval time interval above which a new slot is created
86 * in the {@link GenericTimeStampedCache time-stamped cache}
87 * @since 9.1
88 */
89 public InterpolatingTransformProvider(final TransformProvider rawProvider,
90 final CartesianDerivativesFilter cFilter,
91 final AngularDerivativesFilter aFilter,
92 final int gridPoints, final double step,
93 final int maxSlots, final double maxSpan, final double newSlotInterval) {
94 this.rawProvider = rawProvider;
95 this.cFilter = cFilter;
96 this.aFilter = aFilter;
97 this.step = step;
98 this.cache = new GenericTimeStampedCache<Transform>(gridPoints, maxSlots, maxSpan, newSlotInterval,
99 new TransformGenerator(gridPoints,
100 rawProvider,
101 step));
102 this.fieldCaches = new HashMap<>();
103 }
104
105 /** Simple constructor.
106 * @param rawProvider provider for raw (non-interpolated) transforms
107 * @param cFilter filter for derivatives from the sample to use in interpolation
108 * @param aFilter filter for derivatives from the sample to use in interpolation
109 * @param earliest was earliest supported date, but is ignored now and can safely be null
110 * @param latest was latest supported date, but is ignored now and can safely be null
111 * @param gridPoints number of interpolation grid points
112 * @param step grid points time step
113 * @param maxSlots maximum number of independent cached time slots
114 * in the {@link GenericTimeStampedCache time-stamped cache}
115 * @param maxSpan maximum duration span in seconds of one slot
116 * in the {@link GenericTimeStampedCache time-stamped cache}
117 * @param newSlotInterval time interval above which a new slot is created
118 * in the {@link GenericTimeStampedCache time-stamped cache}
119 * @deprecated as of 9.1, replaced by {@link #InterpolatingTransformProvider(TransformProvider,
120 * CartesianDerivativesFilter, AngularDerivativesFilter, int, double, int, double, double)}
121 */
122 @Deprecated
123 public InterpolatingTransformProvider(final TransformProvider rawProvider,
124 final CartesianDerivativesFilter cFilter,
125 final AngularDerivativesFilter aFilter,
126 final AbsoluteDate earliest, final AbsoluteDate latest,
127 final int gridPoints, final double step,
128 final int maxSlots, final double maxSpan, final double newSlotInterval) {
129 this(rawProvider, cFilter, aFilter, gridPoints, step, maxSlots, maxSpan, newSlotInterval);
130 }
131
132 /** Get the underlying provider for raw (non-interpolated) transforms.
133 * @return provider for raw (non-interpolated) transforms
134 */
135 public TransformProvider getRawProvider() {
136 return rawProvider;
137 }
138
139 /** Get the number of interpolation grid points.
140 * @return number of interpolation grid points
141 */
142 public int getGridPoints() {
143 return cache.getNeighborsSize();
144 }
145
146 /** Get the grid points time step.
147 * @return grid points time step
148 */
149 public double getStep() {
150 return step;
151 }
152
153 /** {@inheritDoc} */
154 @Override
155 public Transform getTransform(final AbsoluteDate date) throws OrekitException {
156 try {
157
158 // retrieve a sample from the thread-safe cache
159 final List<Transform> sample = cache.getNeighbors(date).collect(Collectors.toList());
160
161 // interpolate to specified date
162 return Transform.interpolate(date, cFilter, aFilter, sample);
163
164 } catch (OrekitExceptionWrapper oew) {
165 // something went wrong while generating the sample,
166 // we just forward the exception up
167 throw oew.getException();
168 }
169 }
170
171 /** {@inheritDoc} */
172 @Override
173 public <T extends RealFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date)
174 throws OrekitException {
175 try {
176
177 @SuppressWarnings("unchecked")
178 GenericTimeStampedCache<FieldTransform<T>> fieldCache =
179 (GenericTimeStampedCache<FieldTransform<T>>) fieldCaches.get(date.getField());
180 if (fieldCache == null) {
181 fieldCache =
182 new GenericTimeStampedCache<FieldTransform<T>>(cache.getNeighborsSize(),
183 cache.getMaxSlots(),
184 cache.getMaxSpan(),
185 cache.getNewSlotQuantumGap(),
186 new FieldTransformGenerator<>(date.getField(),
187 cache.getNeighborsSize(),
188 rawProvider,
189 step));
190 fieldCaches.put(date.getField(), fieldCache);
191 }
192
193 // retrieve a sample from the thread-safe cache
194 final Stream<FieldTransform<T>> sample = fieldCache.getNeighbors(date.toAbsoluteDate());
195
196 // interpolate to specified date
197 return FieldTransform.interpolate(date, cFilter, aFilter, sample);
198
199 } catch (OrekitExceptionWrapper oew) {
200 // something went wrong while generating the sample,
201 // we just forward the exception up
202 throw oew.getException();
203 }
204 }
205
206 /** Replace the instance with a data transfer object for serialization.
207 * <p>
208 * This intermediate class serializes only the data needed for generation,
209 * but does <em>not</em> serializes the cache itself (in fact the cache is
210 * not serializable).
211 * </p>
212 * @return data transfer object that will be serialized
213 */
214 private Object writeReplace() {
215 return new DTO(rawProvider, cFilter.getMaxOrder(), aFilter.getMaxOrder(),
216 cache.getNeighborsSize(), step,
217 cache.getMaxSlots(), cache.getMaxSpan(), cache.getNewSlotQuantumGap());
218 }
219
220 /** Internal class used only for serialization. */
221 private static class DTO implements Serializable {
222
223 /** Serializable UID. */
224 private static final long serialVersionUID = 20170823L;
225
226 /** Provider for raw (non-interpolated) transforms. */
227 private final TransformProvider rawProvider;
228
229 /** Cartesian derivatives to use in interpolation. */
230 private final int cDerivatives;
231
232 /** Angular derivatives to use in interpolation. */
233 private final int aDerivatives;
234
235 /** Number of grid points. */
236 private final int gridPoints;
237
238 /** Grid points time step. */
239 private final double step;
240
241 /** Maximum number of independent cached time slots. */
242 private final int maxSlots;
243
244 /** Maximum duration span in seconds of one slot. */
245 private final double maxSpan;
246
247 /** Time interval above which a new slot is created. */
248 private final double newSlotInterval;
249
250 /** Simple constructor.
251 * @param rawProvider provider for raw (non-interpolated) transforms
252 * @param cDerivatives derivation order for Cartesian coordinates
253 * @param aDerivatives derivation order for angular coordinates
254 * @param gridPoints number of interpolation grid points
255 * @param step grid points time step
256 * @param maxSlots maximum number of independent cached time slots
257 * in the {@link GenericTimeStampedCache time-stamped cache}
258 * @param maxSpan maximum duration span in seconds of one slot
259 * in the {@link GenericTimeStampedCache time-stamped cache}
260 * @param newSlotInterval time interval above which a new slot is created
261 * in the {@link GenericTimeStampedCache time-stamped cache}
262 */
263 private DTO(final TransformProvider rawProvider, final int cDerivatives, final int aDerivatives,
264 final int gridPoints, final double step,
265 final int maxSlots, final double maxSpan, final double newSlotInterval) {
266 this.rawProvider = rawProvider;
267 this.cDerivatives = cDerivatives;
268 this.aDerivatives = aDerivatives;
269 this.gridPoints = gridPoints;
270 this.step = step;
271 this.maxSlots = maxSlots;
272 this.maxSpan = maxSpan;
273 this.newSlotInterval = newSlotInterval;
274 }
275
276 /** Replace the deserialized data transfer object with a {@link InterpolatingTransformProvider}.
277 * @return replacement {@link InterpolatingTransformProvider}
278 */
279 private Object readResolve() {
280 // build a new provider, with an empty cache
281 return new InterpolatingTransformProvider(rawProvider,
282 CartesianDerivativesFilter.getFilter(cDerivatives),
283 AngularDerivativesFilter.getFilter(aDerivatives),
284 gridPoints, step,
285 maxSlots, maxSpan, newSlotInterval);
286 }
287
288 }
289
290 }