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