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