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 package org.orekit.utils;
18
19 import java.util.stream.Stream;
20
21 import org.hipparchus.CalculusFieldElement;
22 import org.hipparchus.analysis.differentiation.DerivativeStructure;
23 import org.hipparchus.analysis.differentiation.FieldDerivative;
24 import org.hipparchus.analysis.interpolation.FieldHermiteInterpolator;
25 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
26 import org.orekit.errors.OrekitException;
27 import org.orekit.errors.OrekitIllegalArgumentException;
28 import org.orekit.errors.OrekitInternalError;
29 import org.orekit.errors.OrekitMessages;
30 import org.orekit.frames.FieldTransform;
31 import org.orekit.frames.Frame;
32 import org.orekit.time.FieldAbsoluteDate;
33 import org.orekit.time.FieldTimeInterpolable;
34 import org.orekit.time.FieldTimeStamped;
35
36 /** Field implementation of AbsolutePVCoordinates.
37 * @see AbsolutePVCoordinates
38 * @author Vincent Mouraux
39 */
40 public class FieldAbsolutePVCoordinates<T extends CalculusFieldElement<T>> extends TimeStampedFieldPVCoordinates<T>
41 implements FieldTimeStamped<T>, FieldTimeInterpolable<FieldAbsolutePVCoordinates<T>, T>,
42 FieldPVCoordinatesProvider<T> {
43
44 /** Frame in which are defined the coordinates. */
45 private final Frame frame;
46
47 /** Build from position, velocity, acceleration.
48 * @param frame the frame in which the coordinates are defined
49 * @param date coordinates date
50 * @param position the position vector (m)
51 * @param velocity the velocity vector (m/s)
52 * @param acceleration the acceleration vector (m/sÂý)
53 */
54 public FieldAbsolutePVCoordinates(final Frame frame, final FieldAbsoluteDate<T> date,
55 final FieldVector3D<T> position, final FieldVector3D<T> velocity, final FieldVector3D<T> acceleration) {
56 super(date, position, velocity, acceleration);
57 this.frame = frame;
58 }
59
60 /** Build from position and velocity. Acceleration is set to zero.
61 * @param frame the frame in which the coordinates are defined
62 * @param date coordinates date
63 * @param position the position vector (m)
64 * @param velocity the velocity vector (m/s)
65 */
66 public FieldAbsolutePVCoordinates(final Frame frame, final FieldAbsoluteDate<T> date,
67 final FieldVector3D<T> position,
68 final FieldVector3D<T> velocity) {
69 this(frame, date, position, velocity, FieldVector3D.getZero(date.getField()));
70 }
71
72 /** Build from frame, date and FieldPVA coordinates.
73 * @param frame the frame in which the coordinates are defined
74 * @param date date of the coordinates
75 * @param pva TimeStampedPVCoordinates
76 */
77 public FieldAbsolutePVCoordinates(final Frame frame, final FieldAbsoluteDate<T> date, final FieldPVCoordinates<T> pva) {
78 super(date, pva);
79 this.frame = frame;
80 }
81
82 /** Build from frame and TimeStampedFieldPVCoordinates.
83 * @param frame the frame in which the coordinates are defined
84 * @param pva TimeStampedFieldPVCoordinates
85 */
86 public FieldAbsolutePVCoordinates(final Frame frame, final TimeStampedFieldPVCoordinates<T> pva) {
87 super(pva.getDate(), pva);
88 this.frame = frame;
89 }
90
91 /** Multiplicative constructor
92 * <p>Build a FieldAbsolutePVCoordinates from another one and a scale factor.</p>
93 * <p>The TimeStampedFieldPVCoordinates built will be a * AbsPva</p>
94 * @param date date of the built coordinates
95 * @param a scale factor
96 * @param AbsPva base (unscaled) FieldAbsolutePVCoordinates
97 */
98 public FieldAbsolutePVCoordinates(final FieldAbsoluteDate<T> date,
99 final T a, final FieldAbsolutePVCoordinates<T> AbsPva) {
100 super(date, a, AbsPva);
101 this.frame = AbsPva.frame;
102 }
103
104 /** Subtractive constructor
105 * <p>Build a relative FieldAbsolutePVCoordinates from a start and an end position.</p>
106 * <p>The FieldAbsolutePVCoordinates built will be end - start.</p>
107 * <p>In case start and end use two different pseudo-inertial frames,
108 * the new FieldAbsolutePVCoordinates arbitrarily be defined in the start frame. </p>
109 * @param date date of the built coordinates
110 * @param start Starting FieldAbsolutePVCoordinates
111 * @param end ending FieldAbsolutePVCoordinates
112 */
113 public FieldAbsolutePVCoordinates(final FieldAbsoluteDate<T> date,
114 final FieldAbsolutePVCoordinates<T> start, final FieldAbsolutePVCoordinates<T> end) {
115 super(date, start, end);
116 ensureIdenticalFrames(start, end);
117 this.frame = start.frame;
118 }
119
120 /** Linear constructor
121 * <p>Build a FieldAbsolutePVCoordinates from two other ones and corresponding scale factors.</p>
122 * <p>The FieldAbsolutePVCoordinates built will be a1 * u1 + a2 * u2</p>
123 * <p>In case the FieldAbsolutePVCoordinates use different pseudo-inertial frames,
124 * the new FieldAbsolutePVCoordinates arbitrarily be defined in the first frame. </p>
125 * @param date date of the built coordinates
126 * @param a1 first scale factor
127 * @param absPv1 first base (unscaled) FieldAbsolutePVCoordinates
128 * @param a2 second scale factor
129 * @param absPv2 second base (unscaled) FieldAbsolutePVCoordinates
130 */
131 public FieldAbsolutePVCoordinates(final FieldAbsoluteDate<T> date,
132 final T a1, final FieldAbsolutePVCoordinates<T> absPv1,
133 final T a2, final FieldAbsolutePVCoordinates<T> absPv2) {
134 super(date, a1, absPv1.getPVCoordinates(), a2, absPv2.getPVCoordinates());
135 ensureIdenticalFrames(absPv1, absPv2);
136 this.frame = absPv1.getFrame();
137 }
138
139 /** Linear constructor
140 * <p>Build a FieldAbsolutePVCoordinates from three other ones and corresponding scale factors.</p>
141 * <p>The FieldAbsolutePVCoordinates built will be a1 * u1 + a2 * u2 + a3 * u3</p>
142 * <p>In case the FieldAbsolutePVCoordinates use different pseudo-inertial frames,
143 * the new FieldAbsolutePVCoordinates arbitrarily be defined in the first frame. </p>
144 * @param date date of the built coordinates
145 * @param a1 first scale factor
146 * @param absPv1 first base (unscaled) FieldAbsolutePVCoordinates
147 * @param a2 second scale factor
148 * @param absPv2 second base (unscaled) FieldAbsolutePVCoordinates
149 * @param a3 third scale factor
150 * @param absPv3 third base (unscaled) FieldAbsolutePVCoordinates
151 */
152 public FieldAbsolutePVCoordinates(final FieldAbsoluteDate<T> date,
153 final T a1, final FieldAbsolutePVCoordinates<T> absPv1,
154 final T a2, final FieldAbsolutePVCoordinates<T> absPv2,
155 final T a3, final FieldAbsolutePVCoordinates<T> absPv3) {
156 super(date, a1, absPv1.getPVCoordinates(), a2, absPv2.getPVCoordinates(),
157 a3, absPv3.getPVCoordinates());
158 ensureIdenticalFrames(absPv1, absPv2);
159 ensureIdenticalFrames(absPv1, absPv3);
160 this.frame = absPv1.getFrame();
161 }
162
163 /** Linear constructor
164 * <p>Build a FieldAbsolutePVCoordinates from four other ones and corresponding scale factors.</p>
165 * <p>The FieldAbsolutePVCoordinates built will be a1 * u1 + a2 * u2 + a3 * u3 + a4 * u4</p>
166 * <p>In case the FieldAbsolutePVCoordinates use different pseudo-inertial frames,
167 * the new AbsolutePVCoordinates arbitrarily be defined in the first frame. </p>
168 * @param date date of the built coordinates
169 * @param a1 first scale factor
170 * @param absPv1 first base (unscaled) FieldAbsolutePVCoordinates
171 * @param a2 second scale factor
172 * @param absPv2 second base (unscaled) FieldAbsolutePVCoordinates
173 * @param a3 third scale factor
174 * @param absPv3 third base (unscaled) FieldAbsolutePVCoordinates
175 * @param a4 fourth scale factor
176 * @param absPv4 fourth base (unscaled) FieldAbsolutePVCoordinates
177 */
178 public FieldAbsolutePVCoordinates(final FieldAbsoluteDate<T> date,
179 final T a1, final FieldAbsolutePVCoordinates<T> absPv1,
180 final T a2, final FieldAbsolutePVCoordinates<T> absPv2,
181 final T a3, final FieldAbsolutePVCoordinates<T> absPv3,
182 final T a4, final FieldAbsolutePVCoordinates<T> absPv4) {
183 super(date, a1, absPv1.getPVCoordinates(), a2, absPv2.getPVCoordinates(),
184 a3, absPv3.getPVCoordinates(), a4, absPv4.getPVCoordinates());
185 ensureIdenticalFrames(absPv1, absPv2);
186 ensureIdenticalFrames(absPv1, absPv3);
187 ensureIdenticalFrames(absPv1, absPv4);
188 this.frame = absPv1.getFrame();
189 }
190
191 /** Builds a FieldAbsolutePVCoordinates triplet from a {@link FieldVector3D}<{@link DerivativeStructure}>.
192 * <p>
193 * The vector components must have time as their only derivation parameter and
194 * have consistent derivation orders.
195 * </p>
196 * @param frame the frame in which the parameters are defined
197 * @param date date of the built coordinates
198 * @param p vector with time-derivatives embedded within the coordinates
199 * @param <U> type of the derivative
200 */
201 public <U extends FieldDerivative<T, U>> FieldAbsolutePVCoordinates(final Frame frame, final FieldAbsoluteDate<T> date,
202 final FieldVector3D<U> p) {
203 super(date, p);
204 this.frame = frame;
205 }
206
207 /** Ensure that the frames from two FieldAbsolutePVCoordinates are identical.
208 * @param absPv1 first FieldAbsolutePVCoordinates
209 * @param absPv2 first FieldAbsolutePVCoordinates
210 * @param <T> the type of the field elements
211 * @throws OrekitIllegalArgumentException if frames are different
212 */
213 private static <T extends CalculusFieldElement<T>> void ensureIdenticalFrames(final FieldAbsolutePVCoordinates<T> absPv1, final FieldAbsolutePVCoordinates<T> absPv2)
214 throws OrekitIllegalArgumentException {
215 if (!absPv1.frame.equals(absPv2.frame)) {
216 throw new OrekitIllegalArgumentException(OrekitMessages.INCOMPATIBLE_FRAMES,
217 absPv1.frame.getName(), absPv2.frame.getName());
218 }
219 }
220
221 /** Get a time-shifted state.
222 * <p>
223 * The state can be slightly shifted to close dates. This shift is based on
224 * a simple Taylor expansion. It is <em>not</em> intended as a replacement for
225 * proper orbit propagation (it is not even Keplerian!) but should be sufficient
226 * for either small time shifts or coarse accuracy.
227 * </p>
228 * @param dt time shift in seconds
229 * @return a new state, shifted with respect to the instance (which is immutable)
230 */
231 public FieldAbsolutePVCoordinates<T> shiftedBy(final T dt) {
232 final TimeStampedFieldPVCoordinates<T> spv = super.shiftedBy(dt);
233 return new FieldAbsolutePVCoordinates<>(frame, spv);
234 }
235
236 /** Get a time-shifted state.
237 * <p>
238 * The state can be slightly shifted to close dates. This shift is based on
239 * a simple Taylor expansion. It is <em>not</em> intended as a replacement for
240 * proper orbit propagation (it is not even Keplerian!) but should be sufficient
241 * for either small time shifts or coarse accuracy.
242 * </p>
243 * @param dt time shift in seconds
244 * @return a new state, shifted with respect to the instance (which is immutable)
245 */
246 public FieldAbsolutePVCoordinates<T> shiftedBy(final double dt) {
247 final TimeStampedFieldPVCoordinates<T> spv = super.shiftedBy(dt);
248 return new FieldAbsolutePVCoordinates<>(frame, spv);
249 }
250
251 /** Create a local provider using simply Taylor expansion through {@link #shiftedBy(double)}.
252 * <p>
253 * The time evolution is based on a simple Taylor expansion. It is <em>not</em> intended as a
254 * replacement for proper orbit propagation (it is not even Keplerian!) but should be sufficient
255 * for either small time shifts or coarse accuracy.
256 * </p>
257 * @return provider based on Taylor expansion, for small time shifts around instance date
258 */
259 public FieldPVCoordinatesProvider<T> toTaylorProvider() {
260 return new FieldPVCoordinatesProvider<T>() {
261 /** {@inheritDoc} */
262 public TimeStampedFieldPVCoordinates<T> getPVCoordinates(final FieldAbsoluteDate<T> d, final Frame f) {
263 final TimeStampedFieldPVCoordinates<T> shifted = shiftedBy(d.durationFrom(getDate()));
264 final FieldTransform<T> transform = frame.getTransformTo(f, d);
265 return transform.transformPVCoordinates(shifted);
266 }
267 };
268 }
269
270 /** Get the frame in which the coordinates are defined.
271 * @return frame in which the coordinates are defined
272 */
273 public Frame getFrame() {
274 return frame;
275 }
276
277 /** Get the TimeStampedFieldPVCoordinates.
278 * @return TimeStampedFieldPVCoordinates
279 */
280 public TimeStampedFieldPVCoordinates<T> getPVCoordinates() {
281 return this;
282 }
283
284 /** Get the TimeStampedFieldPVCoordinates in a specified frame.
285 * @param outputFrame frame in which the position/velocity coordinates shall be computed
286 * @return TimeStampedFieldPVCoordinates
287 * @exception OrekitException if transformation between frames cannot be computed
288 * @see #getPVCoordinates()
289 */
290 public TimeStampedFieldPVCoordinates<T> getPVCoordinates(final Frame outputFrame) {
291 // If output frame requested is the same as definition frame,
292 // PV coordinates are returned directly
293 if (outputFrame == frame) {
294 return getPVCoordinates();
295 }
296
297 // Else, PV coordinates are transformed to output frame
298 final FieldTransform<T> t = frame.getTransformTo(outputFrame, getDate());
299 return t.transformPVCoordinates(getPVCoordinates());
300 }
301
302 @Override
303 public TimeStampedFieldPVCoordinates<T> getPVCoordinates(final FieldAbsoluteDate<T> otherDate, final Frame outputFrame) {
304 return shiftedBy(otherDate.durationFrom(getDate())).getPVCoordinates(outputFrame);
305 }
306
307 @Override
308 public FieldAbsolutePVCoordinates<T> interpolate(final FieldAbsoluteDate<T> date, final Stream<FieldAbsolutePVCoordinates<T>> sample) {
309 return interpolate(getFrame(), date, CartesianDerivativesFilter.USE_PVA, sample);
310 }
311
312 /** Interpolate position-velocity.
313 * <p>
314 * The interpolated instance is created by polynomial Hermite interpolation
315 * ensuring velocity remains the exact derivative of position.
316 * </p>
317 * <p>
318 * Note that even if first time derivatives (velocities)
319 * from sample can be ignored, the interpolated instance always includes
320 * interpolated derivatives. This feature can be used explicitly to
321 * compute these derivatives when it would be too complex to compute them
322 * from an analytical formula: just compute a few sample points from the
323 * explicit formula and set the derivatives to zero in these sample points,
324 * then use interpolation to add derivatives consistent with the positions.
325 * </p>
326 * @param frame frame for the interpolted instance
327 * @param date interpolation date
328 * @param filter filter for derivatives from the sample to use in interpolation
329 * @param sample sample points on which interpolation should be done
330 * @param <T> the type of the field elements
331 * @return a new position-velocity, interpolated at specified date
332 * @exception OrekitIllegalArgumentException if some elements in the sample do not
333 * have the same defining frame as other
334 */
335 public static <T extends CalculusFieldElement<T>> FieldAbsolutePVCoordinates<T> interpolate(final Frame frame, final FieldAbsoluteDate<T> date,
336 final CartesianDerivativesFilter filter,
337 final Stream<FieldAbsolutePVCoordinates<T>> sample) {
338
339
340 // set up an interpolator taking derivatives into account
341 final FieldHermiteInterpolator<T> interpolator = new FieldHermiteInterpolator<>();
342
343 // add sample points
344 switch (filter) {
345 case USE_P :
346 // populate sample with position data, ignoring velocity
347 sample.forEach(pv -> {
348 final FieldVector3D<T> position = pv.getPosition();
349 interpolator.addSamplePoint(pv.getDate().durationFrom(date),
350 position.toArray());
351 });
352 break;
353 case USE_PV :
354 // populate sample with position and velocity data
355 sample.forEach(pv -> {
356 final FieldVector3D<T> position = pv.getPosition();
357 final FieldVector3D<T> velocity = pv.getVelocity();
358 interpolator.addSamplePoint(pv.getDate().durationFrom(date),
359 position.toArray(), velocity.toArray());
360 });
361 break;
362 case USE_PVA :
363 // populate sample with position, velocity and acceleration data
364 sample.forEach(pv -> {
365 final FieldVector3D<T> position = pv.getPosition();
366 final FieldVector3D<T> velocity = pv.getVelocity();
367 final FieldVector3D<T> acceleration = pv.getAcceleration();
368 interpolator.addSamplePoint(pv.getDate().durationFrom(date),
369 position.toArray(), velocity.toArray(), acceleration.toArray());
370 });
371 break;
372 default :
373 // this should never happen
374 throw new OrekitInternalError(null);
375 }
376
377 // interpolate
378 final T[][] p = interpolator.derivatives(date.getField().getZero(), 2);
379
380 // build a new interpolated instance
381 return new FieldAbsolutePVCoordinates<>(frame, date, new FieldVector3D<>(p[0]), new FieldVector3D<>(p[1]), new FieldVector3D<>(p[2]));
382 }
383
384 /**
385 * Converts to an AbsolutePVCoordinates instance.
386 * @return AbsolutePVCoordinates with same properties
387 */
388 public AbsolutePVCoordinates toAbsolutePVCoordinates() {
389 return new AbsolutePVCoordinates(frame, this.getDate()
390 .toAbsoluteDate(), this.getPVCoordinates().toPVCoordinates());
391 }
392 }