1 /* Copyright 2002-2021 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 public <T extends CalculusFieldElement<T>> FieldTransform<T> getTransform(final FieldAbsoluteDate<T> date) {
134 @SuppressWarnings("unchecked")
135 GenericTimeStampedCache<FieldTransform<T>> fieldCache =
136 (GenericTimeStampedCache<FieldTransform<T>>) fieldCaches.get(date.getField());
137 if (fieldCache == null) {
138 fieldCache =
139 new GenericTimeStampedCache<FieldTransform<T>>(cache.getNeighborsSize(),
140 cache.getMaxSlots(),
141 cache.getMaxSpan(),
142 cache.getNewSlotQuantumGap(),
143 new FieldTransformGenerator<>(date.getField(),
144 cache.getNeighborsSize(),
145 interpolatingProvider,
146 interpolatingProvider.getStep()));
147 fieldCaches.put(date.getField(), fieldCache);
148 }
149
150 // retrieve a sample from the thread-safe cache
151 final FieldTransform<T> closest = fieldCache.getNeighbors(date.toAbsoluteDate()).reduce((t0, t1) ->
152 date.durationFrom(t0.getDate()).abs().getReal() < date.durationFrom(t1.getDate()).abs().getReal() ?
153 t0 : t1
154 ).get();
155 return closest.shiftedBy(date.durationFrom(closest.getDate()));
156 }
157
158 /** Replace the instance with a data transfer object for serialization.
159 * <p>
160 * This intermediate class serializes only the data needed for generation,
161 * but does <em>not</em> serializes the cache itself (in fact the cache is
162 * not serializable).
163 * </p>
164 * @return data transfer object that will be serialized
165 */
166 private Object writeReplace() {
167 return new DTO(interpolatingProvider,
168 cache.getMaxSlots(), cache.getMaxSpan(), cache.getNewSlotQuantumGap());
169 }
170
171 /** Internal class used only for serialization. */
172 private static class DTO implements Serializable {
173
174 /** Serializable UID. */
175 private static final long serialVersionUID = 20150601L;
176
177 /** Provider for raw (non-interpolated) transforms. */
178 private final InterpolatingTransformProvider interpolatingProvider;
179
180 /** Maximum number of independent cached time slots. */
181 private final int maxSlots;
182
183 /** Maximum duration span in seconds of one slot. */
184 private final double maxSpan;
185
186 /** Time interval above which a new slot is created. */
187 private final double newSlotInterval;
188
189 /** Simple constructor.
190 * @param interpolatingProvider first level cache provider
191 * @param maxSlots maximum number of independent cached time slots
192 * in the {@link GenericTimeStampedCache time-stamped cache}
193 * @param maxSpan maximum duration span in seconds of one slot
194 * in the {@link GenericTimeStampedCache time-stamped cache}
195 * @param newSlotInterval time interval above which a new slot is created
196 * in the {@link GenericTimeStampedCache time-stamped cache}
197 */
198 private DTO(final InterpolatingTransformProvider interpolatingProvider,
199 final int maxSlots, final double maxSpan, final double newSlotInterval) {
200 this.interpolatingProvider = interpolatingProvider;
201 this.maxSlots = maxSlots;
202 this.maxSpan = maxSpan;
203 this.newSlotInterval = newSlotInterval;
204 }
205
206 /** Replace the deserialized data transfer object with a {@link ShiftingTransformProvider}.
207 * @return replacement {@link ShiftingTransformProvider}
208 */
209 private Object readResolve() {
210 // build a new provider, with an empty cache
211 return new ShiftingTransformProvider(interpolatingProvider,
212 maxSlots, maxSpan, newSlotInterval);
213 }
214
215 }
216
217 }