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