1 /* Copyright 2002-2017 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 /** Earliest supported date. */
64 private final AbsoluteDate earliest;
65
66 /** Latest supported date. */
67 private final AbsoluteDate latest;
68
69 /** Grid points time step. */
70 private final double step;
71
72 /** Cache for sample points. */
73 private final transient GenericTimeStampedCache<Transform> cache;
74
75 /** Field caches for sample points. */
76 // we use Object as the value of fieldCaches because despite numerous attempts,
77 // we could not find a way to use GenericTimeStampedCache<FieldTransform<? extends RealFieldElement<?>>
78 // without the compiler complaining
79 private final transient Map<Field<? extends RealFieldElement<?>>, Object> fieldCaches;
80
81 /** Simple constructor.
82 * @param rawProvider provider for raw (non-interpolated) transforms
83 * @param cFilter filter for derivatives from the sample to use in interpolation
84 * @param aFilter filter for derivatives from the sample to use in interpolation
85 * @param earliest earliest supported date
86 * @param latest latest supported date
87 * @param gridPoints number of interpolation grid points
88 * @param step grid points time step
89 * @param maxSlots maximum number of independent cached time slots
90 * in the {@link GenericTimeStampedCache time-stamped cache}
91 * @param maxSpan maximum duration span in seconds of one slot
92 * in the {@link GenericTimeStampedCache time-stamped cache}
93 * @param newSlotInterval time interval above which a new slot is created
94 * in the {@link GenericTimeStampedCache time-stamped cache}
95 */
96 public InterpolatingTransformProvider(final TransformProvider rawProvider,
97 final CartesianDerivativesFilter cFilter,
98 final AngularDerivativesFilter aFilter,
99 final AbsoluteDate earliest, final AbsoluteDate latest,
100 final int gridPoints, final double step,
101 final int maxSlots, final double maxSpan, final double newSlotInterval) {
102 this.rawProvider = rawProvider;
103 this.cFilter = cFilter;
104 this.aFilter = aFilter;
105 this.earliest = earliest;
106 this.latest = latest;
107 this.step = step;
108 this.cache = new GenericTimeStampedCache<Transform>(gridPoints, maxSlots, maxSpan, newSlotInterval,
109 new TransformGenerator(gridPoints,
110 rawProvider,
111 step));
112 this.fieldCaches = new HashMap<>();
113 }
114
115 /** Get the underlying provider for raw (non-interpolated) transforms.
116 * @return provider for raw (non-interpolated) transforms
117 */
118 public TransformProvider getRawProvider() {
119 return rawProvider;
120 }
121
122 /** Get the number of interpolation grid points.
123 * @return number of interpolation grid points
124 */
125 public int getGridPoints() {
126 return cache.getNeighborsSize();
127 }
128
129 /** Get the grid points time step.
130 * @return grid points time step
131 */
132 public double getStep() {
133 return step;
134 }
135
136 /** {@inheritDoc} */
137 @Override
138 public Transform getTransform(final AbsoluteDate date) throws OrekitException {
139 try {
140
141 // retrieve a sample from the thread-safe cache
142 final List<Transform> sample = cache.getNeighbors(date).collect(Collectors.toList());
143
144 // interpolate to specified date
145 return Transform.interpolate(date, cFilter, aFilter, sample);
146
147 } catch (OrekitExceptionWrapper oew) {
148 // something went wrong while generating the sample,
149 // we just forward the exception up
150 throw oew.getException();
151 }
152 }
153
154 /** {@inheritDoc} */
155 @Override
156 public <T extends RealFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date)
157 throws OrekitException {
158 try {
159
160 @SuppressWarnings("unchecked")
161 GenericTimeStampedCache<FieldTransform<T>> fieldCache =
162 (GenericTimeStampedCache<FieldTransform<T>>) fieldCaches.get(date.getField());
163 if (fieldCache == null) {
164 fieldCache =
165 new GenericTimeStampedCache<FieldTransform<T>>(cache.getNeighborsSize(),
166 cache.getMaxSlots(),
167 cache.getMaxSpan(),
168 cache.getNewSlotQuantumGap(),
169 new FieldTransformGenerator<>(date.getField(),
170 cache.getNeighborsSize(),
171 rawProvider,
172 step));
173 fieldCaches.put(date.getField(), fieldCache);
174 }
175
176 // retrieve a sample from the thread-safe cache
177 final Stream<FieldTransform<T>> sample = fieldCache.getNeighbors(date.toAbsoluteDate());
178
179 // interpolate to specified date
180 return FieldTransform.interpolate(date, cFilter, aFilter, sample);
181
182 } catch (OrekitExceptionWrapper oew) {
183 // something went wrong while generating the sample,
184 // we just forward the exception up
185 throw oew.getException();
186 }
187 }
188
189 /** Replace the instance with a data transfer object for serialization.
190 * <p>
191 * This intermediate class serializes only the data needed for generation,
192 * but does <em>not</em> serializes the cache itself (in fact the cache is
193 * not serializable).
194 * </p>
195 * @return data transfer object that will be serialized
196 */
197 private Object writeReplace() {
198 return new DTO(rawProvider, cFilter.getMaxOrder(), aFilter.getMaxOrder(),
199 earliest, latest, cache.getNeighborsSize(), step,
200 cache.getMaxSlots(), cache.getMaxSpan(), cache.getNewSlotQuantumGap());
201 }
202
203 /** Internal class used only for serialization. */
204 private static class DTO implements Serializable {
205
206 /** Serializable UID. */
207 private static final long serialVersionUID = 20140723L;
208
209 /** Provider for raw (non-interpolated) transforms. */
210 private final TransformProvider rawProvider;
211
212 /** Cartesian derivatives to use in interpolation. */
213 private final int cDerivatives;
214
215 /** Angular derivatives to use in interpolation. */
216 private final int aDerivatives;
217
218 /** Earliest supported date. */
219 private final AbsoluteDate earliest;
220
221 /** Latest supported date. */
222 private final AbsoluteDate latest;
223
224 /** Number of grid points. */
225 private final int gridPoints;
226
227 /** Grid points time step. */
228 private final double step;
229
230 /** Maximum number of independent cached time slots. */
231 private final int maxSlots;
232
233 /** Maximum duration span in seconds of one slot. */
234 private final double maxSpan;
235
236 /** Time interval above which a new slot is created. */
237 private final double newSlotInterval;
238
239 /** Simple constructor.
240 * @param rawProvider provider for raw (non-interpolated) transforms
241 * @param cDerivatives derivation order for Cartesian coordinates
242 * @param aDerivatives derivation order for angular coordinates
243 * @param earliest earliest supported date
244 * @param latest latest supported date
245 * @param gridPoints number of interpolation grid points
246 * @param step grid points time step
247 * @param maxSlots maximum number of independent cached time slots
248 * in the {@link GenericTimeStampedCache time-stamped cache}
249 * @param maxSpan maximum duration span in seconds of one slot
250 * in the {@link GenericTimeStampedCache time-stamped cache}
251 * @param newSlotInterval time interval above which a new slot is created
252 * in the {@link GenericTimeStampedCache time-stamped cache}
253 */
254 private DTO(final TransformProvider rawProvider, final int cDerivatives, final int aDerivatives,
255 final AbsoluteDate earliest, final AbsoluteDate latest,
256 final int gridPoints, final double step,
257 final int maxSlots, final double maxSpan, final double newSlotInterval) {
258 this.rawProvider = rawProvider;
259 this.cDerivatives = cDerivatives;
260 this.aDerivatives = aDerivatives;
261 this.earliest = earliest;
262 this.latest = latest;
263 this.gridPoints = gridPoints;
264 this.step = step;
265 this.maxSlots = maxSlots;
266 this.maxSpan = maxSpan;
267 this.newSlotInterval = newSlotInterval;
268 }
269
270 /** Replace the deserialized data transfer object with a {@link InterpolatingTransformProvider}.
271 * @return replacement {@link InterpolatingTransformProvider}
272 */
273 private Object readResolve() {
274 // build a new provider, with an empty cache
275 return new InterpolatingTransformProvider(rawProvider,
276 CartesianDerivativesFilter.getFilter(cDerivatives),
277 AngularDerivativesFilter.getFilter(aDerivatives),
278 earliest, latest, gridPoints, step,
279 maxSlots, maxSpan, newSlotInterval);
280 }
281
282 }
283
284 }