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