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 package org.orekit.orbits;
18
19 import java.io.Serializable;
20
21 import org.hipparchus.geometry.euclidean.threed.Vector3D;
22 import org.hipparchus.linear.DecompositionSolver;
23 import org.hipparchus.linear.MatrixUtils;
24 import org.hipparchus.linear.QRDecomposition;
25 import org.hipparchus.linear.RealMatrix;
26 import org.hipparchus.util.FastMath;
27 import org.hipparchus.util.MathArrays;
28 import org.orekit.errors.OrekitIllegalArgumentException;
29 import org.orekit.errors.OrekitInternalError;
30 import org.orekit.errors.OrekitMessages;
31 import org.orekit.frames.Frame;
32 import org.orekit.frames.StaticTransform;
33 import org.orekit.frames.Transform;
34 import org.orekit.time.AbsoluteDate;
35 import org.orekit.time.TimeShiftable;
36 import org.orekit.time.TimeStamped;
37 import org.orekit.utils.PVCoordinates;
38 import org.orekit.utils.PVCoordinatesProvider;
39 import org.orekit.utils.TimeStampedPVCoordinates;
40
41 /**
42 * This class handles orbital parameters.
43
44 * <p>
45 * For user convenience, both the Cartesian and the equinoctial elements
46 * are provided by this class, regardless of the canonical representation
47 * implemented in the derived class (which may be classical Keplerian
48 * elements for example).
49 * </p>
50 * <p>
51 * The parameters are defined in a frame specified by the user. It is important
52 * to make sure this frame is consistent: it probably is inertial and centered
53 * on the central body. This information is used for example by some
54 * force models.
55 * </p>
56 * <p>
57 * Instance of this class are guaranteed to be immutable.
58 * </p>
59 * @author Luc Maisonobe
60 * @author Guylaine Prat
61 * @author Fabien Maussion
62 * @author Véronique Pommier-Maurussane
63 */
64 public abstract class Orbit
65 implements TimeStamped, TimeShiftable<Orbit>, Serializable, PVCoordinatesProvider {
66
67 /** Serializable UID. */
68 private static final long serialVersionUID = 438733454597999578L;
69
70 /** Frame in which are defined the orbital parameters. */
71 private final Frame frame;
72
73 /** Date of the orbital parameters. */
74 private final AbsoluteDate date;
75
76 /** Value of mu used to compute position and velocity (m³/s²). */
77 private final double mu;
78
79 /** Computed position.
80 * @since 12.0
81 */
82 private transient Vector3D position;
83
84 /** Computed PVCoordinates. */
85 private transient TimeStampedPVCoordinates pvCoordinates;
86
87 /** Jacobian of the orbital parameters with mean angle with respect to the Cartesian coordinates. */
88 private transient double[][] jacobianMeanWrtCartesian;
89
90 /** Jacobian of the Cartesian coordinates with respect to the orbital parameters with mean angle. */
91 private transient double[][] jacobianWrtParametersMean;
92
93 /** Jacobian of the orbital parameters with eccentric angle with respect to the Cartesian coordinates. */
94 private transient double[][] jacobianEccentricWrtCartesian;
95
96 /** Jacobian of the Cartesian coordinates with respect to the orbital parameters with eccentric angle. */
97 private transient double[][] jacobianWrtParametersEccentric;
98
99 /** Jacobian of the orbital parameters with true angle with respect to the Cartesian coordinates. */
100 private transient double[][] jacobianTrueWrtCartesian;
101
102 /** Jacobian of the Cartesian coordinates with respect to the orbital parameters with true angle. */
103 private transient double[][] jacobianWrtParametersTrue;
104
105 /** Default constructor.
106 * Build a new instance with arbitrary default elements.
107 * @param frame the frame in which the parameters are defined
108 * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame})
109 * @param date date of the orbital parameters
110 * @param mu central attraction coefficient (m^3/s^2)
111 * @exception IllegalArgumentException if frame is not a {@link
112 * Frame#isPseudoInertial pseudo-inertial frame}
113 */
114 protected Orbit(final Frame frame, final AbsoluteDate date, final double mu)
115 throws IllegalArgumentException {
116 ensurePseudoInertialFrame(frame);
117 this.date = date;
118 this.mu = mu;
119 this.pvCoordinates = null;
120 this.frame = frame;
121 jacobianMeanWrtCartesian = null;
122 jacobianWrtParametersMean = null;
123 jacobianEccentricWrtCartesian = null;
124 jacobianWrtParametersEccentric = null;
125 jacobianTrueWrtCartesian = null;
126 jacobianWrtParametersTrue = null;
127 }
128
129 /** Set the orbit from Cartesian parameters.
130 *
131 * <p> The acceleration provided in {@code pvCoordinates} is accessible using
132 * {@link #getPVCoordinates()} and {@link #getPVCoordinates(Frame)}. All other methods
133 * use {@code mu} and the position to compute the acceleration, including
134 * {@link #shiftedBy(double)} and {@link #getPVCoordinates(AbsoluteDate, Frame)}.
135 *
136 * @param pvCoordinates the position and velocity in the inertial frame
137 * @param frame the frame in which the {@link TimeStampedPVCoordinates} are defined
138 * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame})
139 * @param mu central attraction coefficient (m^3/s^2)
140 * @exception IllegalArgumentException if frame is not a {@link
141 * Frame#isPseudoInertial pseudo-inertial frame}
142 */
143 protected Orbit(final TimeStampedPVCoordinates pvCoordinates, final Frame frame, final double mu)
144 throws IllegalArgumentException {
145 ensurePseudoInertialFrame(frame);
146 this.date = pvCoordinates.getDate();
147 this.mu = mu;
148 if (pvCoordinates.getAcceleration().getNormSq() == 0) {
149 // the acceleration was not provided,
150 // compute it from Newtonian attraction
151 final double r2 = pvCoordinates.getPosition().getNormSq();
152 final double r3 = r2 * FastMath.sqrt(r2);
153 this.pvCoordinates = new TimeStampedPVCoordinates(pvCoordinates.getDate(),
154 pvCoordinates.getPosition(),
155 pvCoordinates.getVelocity(),
156 new Vector3D(-mu / r3, pvCoordinates.getPosition()));
157 } else {
158 this.pvCoordinates = pvCoordinates;
159 }
160 this.frame = frame;
161 }
162
163 /** Check if Cartesian coordinates include non-Keplerian acceleration.
164 * @param pva Cartesian coordinates
165 * @param mu central attraction coefficient
166 * @return true if Cartesian coordinates include non-Keplerian acceleration
167 */
168 protected static boolean hasNonKeplerianAcceleration(final PVCoordinates pva, final double mu) {
169
170 final Vector3D p = pva.getPosition();
171 final double r2 = p.getNormSq();
172 final double r = FastMath.sqrt(r2);
173 final Vector3D keplerianAcceleration = new Vector3D(-mu / (r * r2), p);
174
175 // Check if acceleration is null or relatively close to 0 compared to the keplerain acceleration
176 final Vector3D a = pva.getAcceleration();
177 if (a == null || a.getNorm() < 1e-9 * keplerianAcceleration.getNorm()) {
178 return false;
179 }
180
181 final Vector3D nonKeplerianAcceleration = a.subtract(keplerianAcceleration);
182
183 if ( nonKeplerianAcceleration.getNorm() > 1e-9 * keplerianAcceleration.getNorm()) {
184 // we have a relevant acceleration, we can compute derivatives
185 return true;
186 } else {
187 // the provided acceleration is either too small to be reliable (probably even 0), or NaN
188 return false;
189 }
190 }
191
192 /** Returns true if and only if the orbit is elliptical i.e. has a non-negative semi-major axis.
193 * @return true if getA() is strictly greater than 0
194 * @since 12.0
195 */
196 public boolean isElliptical() {
197 return getA() > 0.;
198 }
199
200 /** Get the orbit type.
201 * @return orbit type
202 */
203 public abstract OrbitType getType();
204
205 /** Ensure the defining frame is a pseudo-inertial frame.
206 * @param frame frame to check
207 * @exception IllegalArgumentException if frame is not a {@link
208 * Frame#isPseudoInertial pseudo-inertial frame}
209 */
210 private static void ensurePseudoInertialFrame(final Frame frame)
211 throws IllegalArgumentException {
212 if (!frame.isPseudoInertial()) {
213 throw new OrekitIllegalArgumentException(OrekitMessages.NON_PSEUDO_INERTIAL_FRAME,
214 frame.getName());
215 }
216 }
217
218 /** Get the frame in which the orbital parameters are defined.
219 * @return frame in which the orbital parameters are defined
220 */
221 public Frame getFrame() {
222 return frame;
223 }
224
225 /** Get the semi-major axis.
226 * <p>Note that the semi-major axis is considered negative for hyperbolic orbits.</p>
227 * @return semi-major axis (m)
228 */
229 public abstract double getA();
230
231 /** Get the semi-major axis derivative.
232 * <p>Note that the semi-major axis is considered negative for hyperbolic orbits.</p>
233 * <p>
234 * If the orbit was created without derivatives, the value returned is {@link Double#NaN}.
235 * </p>
236 * @return semi-major axis derivative (m/s)
237 * @see #hasDerivatives()
238 * @since 9.0
239 */
240 public abstract double getADot();
241
242 /** Get the first component of the equinoctial eccentricity vector derivative.
243 * @return first component of the equinoctial eccentricity vector derivative
244 */
245 public abstract double getEquinoctialEx();
246
247 /** Get the first component of the equinoctial eccentricity vector.
248 * <p>
249 * If the orbit was created without derivatives, the value returned is {@link Double#NaN}.
250 * </p>
251 * @return first component of the equinoctial eccentricity vector
252 * @see #hasDerivatives()
253 * @since 9.0
254 */
255 public abstract double getEquinoctialExDot();
256
257 /** Get the second component of the equinoctial eccentricity vector derivative.
258 * @return second component of the equinoctial eccentricity vector derivative
259 */
260 public abstract double getEquinoctialEy();
261
262 /** Get the second component of the equinoctial eccentricity vector.
263 * <p>
264 * If the orbit was created without derivatives, the value returned is {@link Double#NaN}.
265 * </p>
266 * @return second component of the equinoctial eccentricity vector
267 * @see #hasDerivatives()
268 * @since 9.0
269 */
270 public abstract double getEquinoctialEyDot();
271
272 /** Get the first component of the inclination vector.
273 * @return first component of the inclination vector
274 */
275 public abstract double getHx();
276
277 /** Get the first component of the inclination vector derivative.
278 * <p>
279 * If the orbit was created without derivatives, the value returned is {@link Double#NaN}.
280 * </p>
281 * @return first component of the inclination vector derivative
282 * @see #hasDerivatives()
283 * @since 9.0
284 */
285 public abstract double getHxDot();
286
287 /** Get the second component of the inclination vector.
288 * @return second component of the inclination vector
289 */
290 public abstract double getHy();
291
292 /** Get the second component of the inclination vector derivative.
293 * <p>
294 * If the orbit was created without derivatives, the value returned is {@link Double#NaN}.
295 * </p>
296 * @return second component of the inclination vector derivative
297 * @see #hasDerivatives()
298 * @since 9.0
299 */
300 public abstract double getHyDot();
301
302 /** Get the eccentric longitude argument.
303 * @return E + ω + Ω eccentric longitude argument (rad)
304 */
305 public abstract double getLE();
306
307 /** Get the eccentric longitude argument derivative.
308 * <p>
309 * If the orbit was created without derivatives, the value returned is {@link Double#NaN}.
310 * </p>
311 * @return d(E + ω + Ω)/dt eccentric longitude argument derivative (rad/s)
312 * @see #hasDerivatives()
313 * @since 9.0
314 */
315 public abstract double getLEDot();
316
317 /** Get the true longitude argument.
318 * @return v + ω + Ω true longitude argument (rad)
319 */
320 public abstract double getLv();
321
322 /** Get the true longitude argument derivative.
323 * <p>
324 * If the orbit was created without derivatives, the value returned is {@link Double#NaN}.
325 * </p>
326 * @return d(v + ω + Ω)/dt true longitude argument derivative (rad/s)
327 * @see #hasDerivatives()
328 * @since 9.0
329 */
330 public abstract double getLvDot();
331
332 /** Get the mean longitude argument.
333 * @return M + ω + Ω mean longitude argument (rad)
334 */
335 public abstract double getLM();
336
337 /** Get the mean longitude argument derivative.
338 * <p>
339 * If the orbit was created without derivatives, the value returned is {@link Double#NaN}.
340 * </p>
341 * @return d(M + ω + Ω)/dt mean longitude argument derivative (rad/s)
342 * @see #hasDerivatives()
343 * @since 9.0
344 */
345 public abstract double getLMDot();
346
347 // Additional orbital elements
348
349 /** Get the eccentricity.
350 * @return eccentricity
351 */
352 public abstract double getE();
353
354 /** Get the eccentricity derivative.
355 * <p>
356 * If the orbit was created without derivatives, the value returned is {@link Double#NaN}.
357 * </p>
358 * @return eccentricity derivative
359 * @see #hasDerivatives()
360 * @since 9.0
361 */
362 public abstract double getEDot();
363
364 /** Get the inclination.
365 * @return inclination (rad)
366 */
367 public abstract double getI();
368
369 /** Get the inclination derivative.
370 * <p>
371 * If the orbit was created without derivatives, the value returned is {@link Double#NaN}.
372 * </p>
373 * @return inclination derivative (rad/s)
374 * @see #hasDerivatives()
375 * @since 9.0
376 */
377 public abstract double getIDot();
378
379 /** Check if orbit includes derivatives.
380 * @return true if orbit includes derivatives
381 * @see #getADot()
382 * @see #getEquinoctialExDot()
383 * @see #getEquinoctialEyDot()
384 * @see #getHxDot()
385 * @see #getHyDot()
386 * @see #getLEDot()
387 * @see #getLvDot()
388 * @see #getLMDot()
389 * @see #getEDot()
390 * @see #getIDot()
391 * @since 9.0
392 */
393 public boolean hasDerivatives() {
394 return !Double.isNaN(getADot());
395 }
396
397 /** Get the central acceleration constant.
398 * @return central acceleration constant
399 */
400 public double getMu() {
401 return mu;
402 }
403
404 /** Get the Keplerian period.
405 * <p>The Keplerian period is computed directly from semi major axis
406 * and central acceleration constant.</p>
407 * @return Keplerian period in seconds, or positive infinity for hyperbolic orbits
408 */
409 public double getKeplerianPeriod() {
410 final double a = getA();
411 return isElliptical() ? 2.0 * FastMath.PI * a * FastMath.sqrt(a / mu) : Double.POSITIVE_INFINITY;
412 }
413
414 /** Get the Keplerian mean motion.
415 * <p>The Keplerian mean motion is computed directly from semi major axis
416 * and central acceleration constant.</p>
417 * @return Keplerian mean motion in radians per second
418 */
419 public double getKeplerianMeanMotion() {
420 final double absA = FastMath.abs(getA());
421 return FastMath.sqrt(mu / absA) / absA;
422 }
423
424 /** Get the derivative of the mean anomaly with respect to the semi major axis.
425 * @return derivative of the mean anomaly with respect to the semi major axis
426 */
427 public double getMeanAnomalyDotWrtA() {
428 return -1.5 * getKeplerianMeanMotion() / getA();
429 }
430
431 /** Get the date of orbital parameters.
432 * @return date of the orbital parameters
433 */
434 public AbsoluteDate getDate() {
435 return date;
436 }
437
438 /** Get the {@link TimeStampedPVCoordinates} in a specified frame.
439 * @param outputFrame frame in which the position/velocity coordinates shall be computed
440 * @return pvCoordinates in the specified output frame
441 * @see #getPVCoordinates()
442 */
443 public TimeStampedPVCoordinates getPVCoordinates(final Frame outputFrame) {
444 if (pvCoordinates == null) {
445 pvCoordinates = initPVCoordinates();
446 }
447
448 // If output frame requested is the same as definition frame,
449 // PV coordinates are returned directly
450 if (outputFrame == frame) {
451 return pvCoordinates;
452 }
453
454 // Else, PV coordinates are transformed to output frame
455 final Transform t = frame.getTransformTo(outputFrame, date);
456 return t.transformPVCoordinates(pvCoordinates);
457 }
458
459 /** {@inheritDoc} */
460 public TimeStampedPVCoordinates getPVCoordinates(final AbsoluteDate otherDate, final Frame otherFrame) {
461 return shiftedBy(otherDate.durationFrom(getDate())).getPVCoordinates(otherFrame);
462 }
463
464 /** Get the position in a specified frame.
465 * @param outputFrame frame in which the position coordinates shall be computed
466 * @return position in the specified output frame
467 * @see #getPosition()
468 * @since 12.0
469 */
470 public Vector3D getPosition(final Frame outputFrame) {
471 if (position == null) {
472 position = initPosition();
473 }
474
475 // If output frame requested is the same as definition frame,
476 // Position vector is returned directly
477 if (outputFrame == frame) {
478 return position;
479 }
480
481 // Else, position vector is transformed to output frame
482 final StaticTransform t = frame.getStaticTransformTo(outputFrame, date);
483 return t.transformPosition(position);
484
485 }
486
487 /** Get the position in definition frame.
488 * @return position in the definition frame
489 * @see #getPVCoordinates()
490 * @since 12.0
491 */
492 public Vector3D getPosition() {
493 if (position == null) {
494 position = initPosition();
495 }
496 return position;
497 }
498
499 /** Get the {@link TimeStampedPVCoordinates} in definition frame.
500 * @return pvCoordinates in the definition frame
501 * @see #getPVCoordinates(Frame)
502 */
503 public TimeStampedPVCoordinates getPVCoordinates() {
504 if (pvCoordinates == null) {
505 pvCoordinates = initPVCoordinates();
506 position = pvCoordinates.getPosition();
507 }
508 return pvCoordinates;
509 }
510
511 /** Compute the position coordinates from the canonical parameters.
512 * @return computed position coordinates
513 * @since 12.0
514 */
515 protected abstract Vector3D initPosition();
516
517 /** Compute the position/velocity coordinates from the canonical parameters.
518 * @return computed position/velocity coordinates
519 */
520 protected abstract TimeStampedPVCoordinates initPVCoordinates();
521
522 /** Get a time-shifted orbit.
523 * <p>
524 * The orbit can be slightly shifted to close dates. The shifting model is a
525 * Keplerian one if no derivatives are available in the orbit, or Keplerian
526 * plus quadratic effect of the non-Keplerian acceleration if derivatives are
527 * available. Shifting is <em>not</em> intended as a replacement for proper
528 * orbit propagation but should be sufficient for small time shifts or coarse
529 * accuracy.
530 * </p>
531 * @param dt time shift in seconds
532 * @return a new orbit, shifted with respect to the instance (which is immutable)
533 */
534 public abstract Orbit shiftedBy(double dt);
535
536 /** Compute the Jacobian of the orbital parameters with respect to the Cartesian parameters.
537 * <p>
538 * Element {@code jacobian[i][j]} is the derivative of parameter i of the orbit with
539 * respect to Cartesian coordinate j. This means each row corresponds to one orbital parameter
540 * whereas columns 0 to 5 correspond to the Cartesian coordinates x, y, z, xDot, yDot and zDot.
541 * </p>
542 * @param type type of the position angle to use
543 * @param jacobian placeholder 6x6 (or larger) matrix to be filled with the Jacobian, if matrix
544 * is larger than 6x6, only the 6x6 upper left corner will be modified
545 */
546 public void getJacobianWrtCartesian(final PositionAngleType type, final double[][] jacobian) {
547
548 final double[][] cachedJacobian;
549 synchronized (this) {
550 switch (type) {
551 case MEAN :
552 if (jacobianMeanWrtCartesian == null) {
553 // first call, we need to compute the Jacobian and cache it
554 jacobianMeanWrtCartesian = computeJacobianMeanWrtCartesian();
555 }
556 cachedJacobian = jacobianMeanWrtCartesian;
557 break;
558 case ECCENTRIC :
559 if (jacobianEccentricWrtCartesian == null) {
560 // first call, we need to compute the Jacobian and cache it
561 jacobianEccentricWrtCartesian = computeJacobianEccentricWrtCartesian();
562 }
563 cachedJacobian = jacobianEccentricWrtCartesian;
564 break;
565 case TRUE :
566 if (jacobianTrueWrtCartesian == null) {
567 // first call, we need to compute the Jacobian and cache it
568 jacobianTrueWrtCartesian = computeJacobianTrueWrtCartesian();
569 }
570 cachedJacobian = jacobianTrueWrtCartesian;
571 break;
572 default :
573 throw new OrekitInternalError(null);
574 }
575 }
576
577 // fill the user provided array
578 for (int i = 0; i < cachedJacobian.length; ++i) {
579 System.arraycopy(cachedJacobian[i], 0, jacobian[i], 0, cachedJacobian[i].length);
580 }
581
582 }
583
584 /** Compute the Jacobian of the Cartesian parameters with respect to the orbital parameters.
585 * <p>
586 * Element {@code jacobian[i][j]} is the derivative of Cartesian coordinate i of the orbit with
587 * respect to orbital parameter j. This means each row corresponds to one Cartesian coordinate
588 * x, y, z, xdot, ydot, zdot whereas columns 0 to 5 correspond to the orbital parameters.
589 * </p>
590 * @param type type of the position angle to use
591 * @param jacobian placeholder 6x6 (or larger) matrix to be filled with the Jacobian, if matrix
592 * is larger than 6x6, only the 6x6 upper left corner will be modified
593 */
594 public void getJacobianWrtParameters(final PositionAngleType type, final double[][] jacobian) {
595
596 final double[][] cachedJacobian;
597 synchronized (this) {
598 switch (type) {
599 case MEAN :
600 if (jacobianWrtParametersMean == null) {
601 // first call, we need to compute the Jacobian and cache it
602 jacobianWrtParametersMean = createInverseJacobian(type);
603 }
604 cachedJacobian = jacobianWrtParametersMean;
605 break;
606 case ECCENTRIC :
607 if (jacobianWrtParametersEccentric == null) {
608 // first call, we need to compute the Jacobian and cache it
609 jacobianWrtParametersEccentric = createInverseJacobian(type);
610 }
611 cachedJacobian = jacobianWrtParametersEccentric;
612 break;
613 case TRUE :
614 if (jacobianWrtParametersTrue == null) {
615 // first call, we need to compute the Jacobian and cache it
616 jacobianWrtParametersTrue = createInverseJacobian(type);
617 }
618 cachedJacobian = jacobianWrtParametersTrue;
619 break;
620 default :
621 throw new OrekitInternalError(null);
622 }
623 }
624
625 // fill the user-provided array
626 for (int i = 0; i < cachedJacobian.length; ++i) {
627 System.arraycopy(cachedJacobian[i], 0, jacobian[i], 0, cachedJacobian[i].length);
628 }
629
630 }
631
632 /** Create an inverse Jacobian.
633 * @param type type of the position angle to use
634 * @return inverse Jacobian
635 */
636 private double[][] createInverseJacobian(final PositionAngleType type) {
637
638 // get the direct Jacobian
639 final double[][] directJacobian = new double[6][6];
640 getJacobianWrtCartesian(type, directJacobian);
641
642 // invert the direct Jacobian
643 final RealMatrix matrix = MatrixUtils.createRealMatrix(directJacobian);
644 final DecompositionSolver solver = new QRDecomposition(matrix).getSolver();
645 return solver.getInverse().getData();
646
647 }
648
649 /** Compute the Jacobian of the orbital parameters with mean angle with respect to the Cartesian parameters.
650 * <p>
651 * Element {@code jacobian[i][j]} is the derivative of parameter i of the orbit with
652 * respect to Cartesian coordinate j. This means each row correspond to one orbital parameter
653 * whereas columns 0 to 5 correspond to the Cartesian coordinates x, y, z, xDot, yDot and zDot.
654 * </p>
655 * <p>
656 * The array returned by this method will not be modified.
657 * </p>
658 * @return 6x6 Jacobian matrix
659 * @see #computeJacobianEccentricWrtCartesian()
660 * @see #computeJacobianTrueWrtCartesian()
661 */
662 protected abstract double[][] computeJacobianMeanWrtCartesian();
663
664 /** Compute the Jacobian of the orbital parameters with eccentric angle with respect to the Cartesian parameters.
665 * <p>
666 * Element {@code jacobian[i][j]} is the derivative of parameter i of the orbit with
667 * respect to Cartesian coordinate j. This means each row correspond to one orbital parameter
668 * whereas columns 0 to 5 correspond to the Cartesian coordinates x, y, z, xDot, yDot and zDot.
669 * </p>
670 * <p>
671 * The array returned by this method will not be modified.
672 * </p>
673 * @return 6x6 Jacobian matrix
674 * @see #computeJacobianMeanWrtCartesian()
675 * @see #computeJacobianTrueWrtCartesian()
676 */
677 protected abstract double[][] computeJacobianEccentricWrtCartesian();
678
679 /** Compute the Jacobian of the orbital parameters with true angle with respect to the Cartesian parameters.
680 * <p>
681 * Element {@code jacobian[i][j]} is the derivative of parameter i of the orbit with
682 * respect to Cartesian coordinate j. This means each row correspond to one orbital parameter
683 * whereas columns 0 to 5 correspond to the Cartesian coordinates x, y, z, xDot, yDot and zDot.
684 * </p>
685 * <p>
686 * The array returned by this method will not be modified.
687 * </p>
688 * @return 6x6 Jacobian matrix
689 * @see #computeJacobianMeanWrtCartesian()
690 * @see #computeJacobianEccentricWrtCartesian()
691 */
692 protected abstract double[][] computeJacobianTrueWrtCartesian();
693
694 /** Add the contribution of the Keplerian motion to parameters derivatives
695 * <p>
696 * This method is used by integration-based propagators to evaluate the part of Keplerian
697 * motion to evolution of the orbital state.
698 * </p>
699 * @param type type of the position angle in the state
700 * @param gm attraction coefficient to use
701 * @param pDot array containing orbital state derivatives to update (the Keplerian
702 * part must be <em>added</em> to the array components, as the array may already
703 * contain some non-zero elements corresponding to non-Keplerian parts)
704 */
705 public abstract void addKeplerContribution(PositionAngleType type, double gm, double[] pDot);
706
707 /** Fill a Jacobian half row with a single vector.
708 * @param a coefficient of the vector
709 * @param v vector
710 * @param row Jacobian matrix row
711 * @param j index of the first element to set (row[j], row[j+1] and row[j+2] will all be set)
712 */
713 protected static void fillHalfRow(final double a, final Vector3D v, final double[] row, final int j) {
714 row[j] = a * v.getX();
715 row[j + 1] = a * v.getY();
716 row[j + 2] = a * v.getZ();
717 }
718
719 /** Fill a Jacobian half row with a linear combination of vectors.
720 * @param a1 coefficient of the first vector
721 * @param v1 first vector
722 * @param a2 coefficient of the second vector
723 * @param v2 second vector
724 * @param row Jacobian matrix row
725 * @param j index of the first element to set (row[j], row[j+1] and row[j+2] will all be set)
726 */
727 protected static void fillHalfRow(final double a1, final Vector3D v1, final double a2, final Vector3D v2,
728 final double[] row, final int j) {
729 row[j] = MathArrays.linearCombination(a1, v1.getX(), a2, v2.getX());
730 row[j + 1] = MathArrays.linearCombination(a1, v1.getY(), a2, v2.getY());
731 row[j + 2] = MathArrays.linearCombination(a1, v1.getZ(), a2, v2.getZ());
732 }
733
734 /** Fill a Jacobian half row with a linear combination of vectors.
735 * @param a1 coefficient of the first vector
736 * @param v1 first vector
737 * @param a2 coefficient of the second vector
738 * @param v2 second vector
739 * @param a3 coefficient of the third vector
740 * @param v3 third vector
741 * @param row Jacobian matrix row
742 * @param j index of the first element to set (row[j], row[j+1] and row[j+2] will all be set)
743 */
744 protected static void fillHalfRow(final double a1, final Vector3D v1, final double a2, final Vector3D v2,
745 final double a3, final Vector3D v3,
746 final double[] row, final int j) {
747 row[j] = MathArrays.linearCombination(a1, v1.getX(), a2, v2.getX(), a3, v3.getX());
748 row[j + 1] = MathArrays.linearCombination(a1, v1.getY(), a2, v2.getY(), a3, v3.getY());
749 row[j + 2] = MathArrays.linearCombination(a1, v1.getZ(), a2, v2.getZ(), a3, v3.getZ());
750 }
751
752 /** Fill a Jacobian half row with a linear combination of vectors.
753 * @param a1 coefficient of the first vector
754 * @param v1 first vector
755 * @param a2 coefficient of the second vector
756 * @param v2 second vector
757 * @param a3 coefficient of the third vector
758 * @param v3 third vector
759 * @param a4 coefficient of the fourth vector
760 * @param v4 fourth vector
761 * @param row Jacobian matrix row
762 * @param j index of the first element to set (row[j], row[j+1] and row[j+2] will all be set)
763 */
764 protected static void fillHalfRow(final double a1, final Vector3D v1, final double a2, final Vector3D v2,
765 final double a3, final Vector3D v3, final double a4, final Vector3D v4,
766 final double[] row, final int j) {
767 row[j] = MathArrays.linearCombination(a1, v1.getX(), a2, v2.getX(), a3, v3.getX(), a4, v4.getX());
768 row[j + 1] = MathArrays.linearCombination(a1, v1.getY(), a2, v2.getY(), a3, v3.getY(), a4, v4.getY());
769 row[j + 2] = MathArrays.linearCombination(a1, v1.getZ(), a2, v2.getZ(), a3, v3.getZ(), a4, v4.getZ());
770 }
771
772 /** Fill a Jacobian half row with a linear combination of vectors.
773 * @param a1 coefficient of the first vector
774 * @param v1 first vector
775 * @param a2 coefficient of the second vector
776 * @param v2 second vector
777 * @param a3 coefficient of the third vector
778 * @param v3 third vector
779 * @param a4 coefficient of the fourth vector
780 * @param v4 fourth vector
781 * @param a5 coefficient of the fifth vector
782 * @param v5 fifth vector
783 * @param row Jacobian matrix row
784 * @param j index of the first element to set (row[j], row[j+1] and row[j+2] will all be set)
785 */
786 protected static void fillHalfRow(final double a1, final Vector3D v1, final double a2, final Vector3D v2,
787 final double a3, final Vector3D v3, final double a4, final Vector3D v4,
788 final double a5, final Vector3D v5,
789 final double[] row, final int j) {
790 final double[] a = new double[] {
791 a1, a2, a3, a4, a5
792 };
793 row[j] = MathArrays.linearCombination(a, new double[] {
794 v1.getX(), v2.getX(), v3.getX(), v4.getX(), v5.getX()
795 });
796 row[j + 1] = MathArrays.linearCombination(a, new double[] {
797 v1.getY(), v2.getY(), v3.getY(), v4.getY(), v5.getY()
798 });
799 row[j + 2] = MathArrays.linearCombination(a, new double[] {
800 v1.getZ(), v2.getZ(), v3.getZ(), v4.getZ(), v5.getZ()
801 });
802 }
803
804 /** Fill a Jacobian half row with a linear combination of vectors.
805 * @param a1 coefficient of the first vector
806 * @param v1 first vector
807 * @param a2 coefficient of the second vector
808 * @param v2 second vector
809 * @param a3 coefficient of the third vector
810 * @param v3 third vector
811 * @param a4 coefficient of the fourth vector
812 * @param v4 fourth vector
813 * @param a5 coefficient of the fifth vector
814 * @param v5 fifth vector
815 * @param a6 coefficient of the sixth vector
816 * @param v6 sixth vector
817 * @param row Jacobian matrix row
818 * @param j index of the first element to set (row[j], row[j+1] and row[j+2] will all be set)
819 */
820 protected static void fillHalfRow(final double a1, final Vector3D v1, final double a2, final Vector3D v2,
821 final double a3, final Vector3D v3, final double a4, final Vector3D v4,
822 final double a5, final Vector3D v5, final double a6, final Vector3D v6,
823 final double[] row, final int j) {
824 final double[] a = new double[] {
825 a1, a2, a3, a4, a5, a6
826 };
827 row[j] = MathArrays.linearCombination(a, new double[] {
828 v1.getX(), v2.getX(), v3.getX(), v4.getX(), v5.getX(), v6.getX()
829 });
830 row[j + 1] = MathArrays.linearCombination(a, new double[] {
831 v1.getY(), v2.getY(), v3.getY(), v4.getY(), v5.getY(), v6.getY()
832 });
833 row[j + 2] = MathArrays.linearCombination(a, new double[] {
834 v1.getZ(), v2.getZ(), v3.getZ(), v4.getZ(), v5.getZ(), v6.getZ()
835 });
836 }
837
838 }