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