FieldOrbit.java

  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. import org.hipparchus.RealFieldElement;
  19. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  20. import org.hipparchus.linear.FieldDecompositionSolver;
  21. import org.hipparchus.linear.FieldLUDecomposition;
  22. import org.hipparchus.linear.FieldMatrix;
  23. import org.hipparchus.linear.MatrixUtils;
  24. import org.hipparchus.util.FastMath;
  25. import org.hipparchus.util.MathArrays;
  26. import org.orekit.errors.OrekitException;
  27. import org.orekit.errors.OrekitIllegalArgumentException;
  28. import org.orekit.errors.OrekitInternalError;
  29. import org.orekit.errors.OrekitMessages;
  30. import org.orekit.frames.Frame;
  31. import org.orekit.frames.Transform;
  32. import org.orekit.time.FieldAbsoluteDate;
  33. import org.orekit.time.FieldTimeInterpolable;
  34. import org.orekit.time.FieldTimeShiftable;
  35. import org.orekit.time.FieldTimeStamped;
  36. import org.orekit.utils.FieldPVCoordinates;
  37. import org.orekit.utils.FieldPVCoordinatesProvider;
  38. import org.orekit.utils.TimeStampedFieldPVCoordinates;
  39. import org.orekit.utils.TimeStampedPVCoordinates;

  40. /**
  41.  * This class handles orbital parameters.

  42.  * <p>
  43.  * For user convenience, both the Cartesian and the equinoctial elements
  44.  * are provided by this class, regardless of the canonical representation
  45.  * implemented in the derived class (which may be classical Keplerian
  46.  * elements for example).
  47.  * </p>
  48.  * <p>
  49.  * The parameters are defined in a frame specified by the user. It is important
  50.  * to make sure this frame is consistent: it probably is inertial and centered
  51.  * on the central body. This information is used for example by some
  52.  * force models.
  53.  * </p>
  54.  * <p>
  55.  * Instance of this class are guaranteed to be immutable.
  56.  * </p>
  57.  * @author Luc Maisonobe
  58.  * @author Guylaine Prat
  59.  * @author Fabien Maussion
  60.  * @author V&eacute;ronique Pommier-Maurussane
  61.  * @since 9.0
  62.  */
  63. public abstract class FieldOrbit<T extends RealFieldElement<T>>
  64.     implements FieldPVCoordinatesProvider<T>, FieldTimeStamped<T>, FieldTimeShiftable<FieldOrbit<T>, T>, FieldTimeInterpolable<FieldOrbit<T>, T> {

  65.     /** Frame in which are defined the orbital parameters. */
  66.     private final Frame frame;

  67.     /** Date of the orbital parameters. */
  68.     private final FieldAbsoluteDate<T> date;

  69.     /** Value of mu used to compute position and velocity (m³/s²). */
  70.     private final double mu;

  71.     /** Computed PVCoordinates. */
  72.     private transient TimeStampedFieldPVCoordinates<T> pvCoordinates;

  73.     /** Jacobian of the orbital parameters with mean angle with respect to the Cartesian coordinates. */
  74.     private transient T[][] jacobianMeanWrtCartesian;

  75.     /** Jacobian of the Cartesian coordinates with respect to the orbital parameters with mean angle. */
  76.     private transient T[][] jacobianWrtParametersMean;

  77.     /** Jacobian of the orbital parameters with eccentric angle with respect to the Cartesian coordinates. */
  78.     private transient T[][] jacobianEccentricWrtCartesian;

  79.     /** Jacobian of the Cartesian coordinates with respect to the orbital parameters with eccentric angle. */
  80.     private transient T[][] jacobianWrtParametersEccentric;

  81.     /** Jacobian of the orbital parameters with true angle with respect to the Cartesian coordinates. */
  82.     private transient T[][] jacobianTrueWrtCartesian;

  83.     /** Jacobian of the Cartesian coordinates with respect to the orbital parameters with true angle. */
  84.     private transient T[][] jacobianWrtParametersTrue;

  85.     /** Default constructor.
  86.      * Build a new instance with arbitrary default elements.
  87.      * @param frame the frame in which the parameters are defined
  88.      * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame})
  89.      * @param date date of the orbital parameters
  90.      * @param mu central attraction coefficient (m^3/s^2)
  91.      * @exception IllegalArgumentException if frame is not a {@link
  92.      * Frame#isPseudoInertial pseudo-inertial frame}
  93.      */
  94.     protected FieldOrbit(final Frame frame, final FieldAbsoluteDate<T> date, final double mu)
  95.         throws IllegalArgumentException {
  96.         ensurePseudoInertialFrame(frame);
  97.         this.date                      = date;
  98.         this.mu                        = mu;
  99.         this.pvCoordinates             = null;
  100.         this.frame                     = frame;
  101.         jacobianMeanWrtCartesian       = null;
  102.         jacobianWrtParametersMean      = null;
  103.         jacobianEccentricWrtCartesian  = null;
  104.         jacobianWrtParametersEccentric = null;
  105.         jacobianTrueWrtCartesian       = null;
  106.         jacobianWrtParametersTrue      = null;
  107.     }

  108.     /** Set the orbit from Cartesian parameters.
  109.      *
  110.      * <p> The acceleration provided in {@code FieldPVCoordinates} is accessible using
  111.      * {@link #getPVCoordinates()} and {@link #getPVCoordinates(Frame)}. All other methods
  112.      * use {@code mu} and the position to compute the acceleration, including
  113.      * {@link #shiftedBy(RealFieldElement)} and {@link #getPVCoordinates(FieldAbsoluteDate, Frame)}.
  114.      *
  115.      * @param FieldPVCoordinates the position and velocity in the inertial frame
  116.      * @param frame the frame in which the {@link TimeStampedPVCoordinates} are defined
  117.      * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame})
  118.      * @param mu central attraction coefficient (m^3/s^2)
  119.      * @exception IllegalArgumentException if frame is not a {@link
  120.      * Frame#isPseudoInertial pseudo-inertial frame}
  121.      */
  122.     protected FieldOrbit(final TimeStampedFieldPVCoordinates<T> FieldPVCoordinates, final Frame frame, final double mu)
  123.         throws IllegalArgumentException {
  124.         ensurePseudoInertialFrame(frame);
  125.         this.date = FieldPVCoordinates.getDate();
  126.         this.mu = mu;
  127.         if (FieldPVCoordinates.getAcceleration().getNormSq().getReal() == 0.0) {
  128.             // the acceleration was not provided,
  129.             // compute it from Newtonian attraction
  130.             final T r2 = FieldPVCoordinates.getPosition().getNormSq();
  131.             final T r3 = r2.multiply(r2.sqrt());
  132.             this.pvCoordinates = new TimeStampedFieldPVCoordinates<>(FieldPVCoordinates.getDate(),
  133.                                                                      FieldPVCoordinates.getPosition(),
  134.                                                                      FieldPVCoordinates.getVelocity(),
  135.                                                                      new FieldVector3D<>(r3.reciprocal().multiply(-mu), FieldPVCoordinates.getPosition()));
  136.         } else {
  137.             this.pvCoordinates = FieldPVCoordinates;
  138.         }
  139.         this.frame = frame;
  140.     }

  141.     /** Check if Cartesian coordinates include non-Keplerian acceleration.
  142.      * @param pva Cartesian coordinates
  143.      * @param mu central attraction coefficient
  144.      * @param <T> type of the field elements
  145.      * @return true if Cartesian coordinates include non-Keplerian acceleration
  146.      */
  147.     protected static <T extends RealFieldElement<T>> boolean hasNonKeplerianAcceleration(final FieldPVCoordinates<T> pva, final double mu) {

  148.         final FieldVector3D<T> a = pva.getAcceleration();
  149.         if (a == null) {
  150.             return false;
  151.         }

  152.         final FieldVector3D<T> p = pva.getPosition();
  153.         final T r2 = p.getNormSq();
  154.         final T r  = r2.sqrt();
  155.         final FieldVector3D<T> keplerianAcceleration = new FieldVector3D<>(r.multiply(r2).reciprocal().multiply(-mu), p);
  156.         if (a.getNorm().getReal() > 1.0e-9 * keplerianAcceleration.getNorm().getReal()) {
  157.             // we have a relevant acceleration, we can compute derivatives
  158.             return true;
  159.         } else {
  160.             // the provided acceleration is either too small to be reliable (probably even 0), or NaN
  161.             return false;
  162.         }

  163.     }

  164.     /** Get the orbit type.
  165.      * @return orbit type
  166.      */
  167.     public abstract OrbitType getType();

  168.     /** Ensure the defining frame is a pseudo-inertial frame.
  169.      * @param frame frame to check
  170.      * @exception IllegalArgumentException if frame is not a {@link
  171.      * Frame#isPseudoInertial pseudo-inertial frame}
  172.      */
  173.     private static void ensurePseudoInertialFrame(final Frame frame)
  174.         throws IllegalArgumentException {
  175.         if (!frame.isPseudoInertial()) {
  176.             throw new OrekitIllegalArgumentException(OrekitMessages.NON_PSEUDO_INERTIAL_FRAME,
  177.                                                      frame.getName());
  178.         }
  179.     }

  180.     /** Get the frame in which the orbital parameters are defined.
  181.      * @return frame in which the orbital parameters are defined
  182.      */
  183.     public Frame getFrame() {
  184.         return frame;
  185.     }

  186.     /**Transforms the FieldOrbit instance into an Orbit instance.
  187.      * @return Orbit instance with same properties
  188.      */
  189.     public abstract Orbit toOrbit();

  190.     /** Get the semi-major axis.
  191.      * <p>Note that the semi-major axis is considered negative for hyperbolic orbits.</p>
  192.      * @return semi-major axis (m)
  193.      */
  194.     public abstract T getA();

  195.     /** Get the semi-major axis derivative.
  196.      * <p>Note that the semi-major axis is considered negative for hyperbolic orbits.</p>
  197.      * <p>
  198.      * If the orbit was created without derivatives, the value returned is null.
  199.      * </p>
  200.      * @return semi-major axis  derivative (m/s)
  201.      */
  202.     public abstract T getADot();

  203.     /** Get the first component of the equinoctial eccentricity vector.
  204.      * @return first component of the equinoctial eccentricity vector
  205.      */
  206.     public abstract T getEquinoctialEx();

  207.     /** Get the first component of the equinoctial eccentricity vector.
  208.      * <p>
  209.      * If the orbit was created without derivatives, the value returned is null.
  210.      * </p>
  211.      * @return first component of the equinoctial eccentricity vector
  212.      */
  213.     public abstract T getEquinoctialExDot();

  214.     /** Get the second component of the equinoctial eccentricity vector.
  215.      * @return second component of the equinoctial eccentricity vector
  216.      */
  217.     public abstract T getEquinoctialEy();

  218.     /** Get the second component of the equinoctial eccentricity vector.
  219.      * <p>
  220.      * If the orbit was created without derivatives, the value returned is null.
  221.      * </p>
  222.      * @return second component of the equinoctial eccentricity vector
  223.      */
  224.     public abstract T getEquinoctialEyDot();

  225.     /** Get the first component of the inclination vector.
  226.      * @return first component of the inclination vector
  227.      */
  228.     public abstract T getHx();

  229.     /** Get the first component of the inclination vector derivative.
  230.      * <p>
  231.      * If the orbit was created without derivatives, the value returned is null.
  232.      * </p>
  233.      * @return first component of the inclination vector derivative
  234.      */
  235.     public abstract T getHxDot();

  236.     /** Get the second component of the inclination vector.
  237.      * @return second component of the inclination vector
  238.      */
  239.     public abstract T getHy();

  240.     /** Get the second component of the inclination vector derivative.
  241.      * <p>
  242.      * </p>
  243.      * @return second component of the inclination vector derivative
  244.      */
  245.     public abstract T getHyDot();

  246.     /** Get the eccentric longitude argument.
  247.      * @return E + ω + Ω eccentric longitude argument (rad)
  248.      */
  249.     public abstract T getLE();

  250.     /** Get the eccentric longitude argument derivative.
  251.      * <p>
  252.      * If the orbit was created without derivatives, the value returned is null.
  253.      * </p>
  254.      * @return d(E + ω + Ω)/dt eccentric longitude argument derivative (rad/s)
  255.      */
  256.     public abstract T getLEDot();

  257.     /** Get the true longitude argument.
  258.      * @return v + ω + Ω true longitude argument (rad)
  259.      */
  260.     public abstract T getLv();

  261.     /** Get the true longitude argument derivative.
  262.      * <p>
  263.      * If the orbit was created without derivatives, the value returned is null.
  264.      * </p>
  265.      * @return d(v + ω + Ω)/dt true longitude argument derivative (rad/s)
  266.      */
  267.     public abstract T getLvDot();

  268.     /** Get the mean longitude argument.
  269.      * @return M + ω + Ω mean longitude argument (rad)
  270.      */
  271.     public abstract T getLM();

  272.     /** Get the mean longitude argument derivative.
  273.      * <p>
  274.      * If the orbit was created without derivatives, the value returned is null.
  275.      * </p>
  276.      * @return d(M + ω + Ω)/dt mean longitude argument derivative (rad/s)
  277.      */
  278.     public abstract T getLMDot();

  279.     // Additional orbital elements

  280.     /** Get the eccentricity.
  281.      * @return eccentricity
  282.      */
  283.     public abstract T getE();

  284.     /** Get the eccentricity derivative.
  285.      * <p>
  286.      * If the orbit was created without derivatives, the value returned is null.
  287.      * </p>
  288.      * @return eccentricity derivative
  289.      */
  290.     public abstract T getEDot();

  291.     /** Get the inclination.
  292.      * <p>
  293.      * If the orbit was created without derivatives, the value returned is null.
  294.      * </p>
  295.      * @return inclination (rad)
  296.      */
  297.     public abstract T getI();

  298.     /** Get the inclination derivative.
  299.      * @return inclination derivative (rad/s)
  300.      */
  301.     public abstract T getIDot();

  302.     /** Get the central acceleration constant.
  303.      * @return central acceleration constant
  304.      */

  305.     /** Check if orbit includes derivatives.
  306.      * @return true if orbit includes derivatives
  307.      * @see #getADot()
  308.      * @see #getEquinoctialExDot()
  309.      * @see #getEquinoctialEyDot()
  310.      * @see #getHxDot()
  311.      * @see #getHyDot()
  312.      * @see #getLEDot()
  313.      * @see #getLvDot()
  314.      * @see #getLMDot()
  315.      * @see #getEDot()
  316.      * @see #getIDot()
  317.      * @since 9.0
  318.      */
  319.     public abstract boolean hasDerivatives();

  320.     public double getMu() {
  321.         return mu;
  322.     }

  323.     /** Get the Keplerian period.
  324.      * <p>The Keplerian period is computed directly from semi major axis
  325.      * and central acceleration constant.</p>
  326.      * @return Keplerian period in seconds, or positive infinity for hyperbolic orbits
  327.      */
  328.     public T getKeplerianPeriod() {
  329.         final T a = getA();
  330.         return (a.getReal() < 0) ? getA().getField().getZero().add(Double.POSITIVE_INFINITY) : a.multiply(2 * FastMath.PI).multiply(a.divide(mu).sqrt());
  331.     }

  332.     /** Get the Keplerian mean motion.
  333.      * <p>The Keplerian mean motion is computed directly from semi major axis
  334.      * and central acceleration constant.</p>
  335.      * @return Keplerian mean motion in radians per second
  336.      */
  337.     public T getKeplerianMeanMotion() {
  338.         final T absA = getA().abs();
  339.         return absA.reciprocal().multiply(mu).sqrt().divide(absA);
  340.     }

  341.     /** Get the date of orbital parameters.
  342.      * @return date of the orbital parameters
  343.      */
  344.     public FieldAbsoluteDate<T> getDate() {
  345.         return date;
  346.     }

  347.     /** Get the {@link TimeStampedPVCoordinates} in a specified frame.
  348.      * @param outputFrame frame in which the position/velocity coordinates shall be computed
  349.      * @return FieldPVCoordinates in the specified output frame
  350.      * @exception OrekitException if transformation between frames cannot be computed
  351.      * @see #getPVCoordinates()
  352.      */
  353.     public TimeStampedFieldPVCoordinates<T> getPVCoordinates(final Frame outputFrame)
  354.         throws OrekitException {
  355.         if (pvCoordinates == null) {
  356.             pvCoordinates = initPVCoordinates();
  357.         }

  358.         // If output frame requested is the same as definition frame,
  359.         // PV coordinates are returned directly
  360.         if (outputFrame == frame) {
  361.             return pvCoordinates;
  362.         }

  363.         // Else, PV coordinates are transformed to output frame
  364.         final Transform t = frame.getTransformTo(outputFrame, date.toAbsoluteDate()); //TODO CHECK THIS
  365.         return t.transformPVCoordinates(pvCoordinates);
  366.     }

  367.     /** {@inheritDoc} */
  368.     public TimeStampedFieldPVCoordinates<T> getPVCoordinates(final FieldAbsoluteDate<T> otherDate, final Frame otherFrame)
  369.         throws OrekitException {
  370.         return shiftedBy(otherDate.durationFrom(getDate())).getPVCoordinates(otherFrame);
  371.     }


  372.     /** Get the {@link TimeStampedPVCoordinates} in definition frame.
  373.      * @return FieldPVCoordinates in the definition frame
  374.      * @see #getPVCoordinates(Frame)
  375.      */
  376.     public TimeStampedFieldPVCoordinates<T> getPVCoordinates() {
  377.         if (pvCoordinates == null) {
  378.             pvCoordinates = initPVCoordinates();

  379.         }
  380.         return pvCoordinates;
  381.     }

  382.     /** Compute the position/velocity coordinates from the canonical parameters.
  383.      * @return computed position/velocity coordinates
  384.      */
  385.     protected abstract TimeStampedFieldPVCoordinates<T> initPVCoordinates();

  386.     /** Get a time-shifted orbit.
  387.      * <p>
  388.      * The orbit can be slightly shifted to close dates. This shift is based on
  389.      * a simple Keplerian model. It is <em>not</em> intended as a replacement
  390.      * for proper orbit and attitude propagation but should be sufficient for
  391.      * small time shifts or coarse accuracy.
  392.      * </p>
  393.      * @param dt time shift in seconds
  394.      * @return a new orbit, shifted with respect to the instance (which is immutable)
  395.      */
  396.     public abstract FieldOrbit<T> shiftedBy(T dt);

  397.     /** Compute the Jacobian of the orbital parameters with respect to the Cartesian parameters.
  398.      * <p>
  399.      * Element {@code jacobian[i][j]} is the derivative of parameter i of the orbit with
  400.      * respect to Cartesian coordinate j. This means each row corresponds to one orbital parameter
  401.      * whereas columns 0 to 5 correspond to the Cartesian coordinates x, y, z, xDot, yDot and zDot.
  402.      * </p>
  403.      * @param type type of the position angle to use
  404.      * @param jacobian placeholder 6x6 (or larger) matrix to be filled with the Jacobian, if matrix
  405.      * is larger than 6x6, only the 6x6 upper left corner will be modified
  406.      */
  407.     public void getJacobianWrtCartesian(final PositionAngle type, final T[][] jacobian) {

  408.         final T[][] cachedJacobian;
  409.         synchronized (this) {
  410.             switch (type) {
  411.                 case MEAN :
  412.                     if (jacobianMeanWrtCartesian == null) {
  413.                         // first call, we need to compute the Jacobian and cache it
  414.                         jacobianMeanWrtCartesian = computeJacobianMeanWrtCartesian();
  415.                     }
  416.                     cachedJacobian = jacobianMeanWrtCartesian;
  417.                     break;
  418.                 case ECCENTRIC :
  419.                     if (jacobianEccentricWrtCartesian == null) {
  420.                         // first call, we need to compute the Jacobian and cache it
  421.                         jacobianEccentricWrtCartesian = computeJacobianEccentricWrtCartesian();
  422.                     }
  423.                     cachedJacobian = jacobianEccentricWrtCartesian;
  424.                     break;
  425.                 case TRUE :
  426.                     if (jacobianTrueWrtCartesian == null) {
  427.                         // first call, we need to compute the Jacobian and cache it
  428.                         jacobianTrueWrtCartesian = computeJacobianTrueWrtCartesian();
  429.                     }
  430.                     cachedJacobian = jacobianTrueWrtCartesian;
  431.                     break;
  432.                 default :
  433.                     throw new OrekitInternalError(null);
  434.             }
  435.         }

  436.         // fill the user provided array
  437.         for (int i = 0; i < cachedJacobian.length; ++i) {
  438.             System.arraycopy(cachedJacobian[i], 0, jacobian[i], 0, cachedJacobian[i].length);
  439.         }

  440.     }

  441.     /** Compute the Jacobian of the Cartesian parameters with respect to the orbital parameters.
  442.      * <p>
  443.      * Element {@code jacobian[i][j]} is the derivative of Cartesian coordinate i of the orbit with
  444.      * respect to orbital parameter j. This means each row corresponds to one Cartesian coordinate
  445.      * x, y, z, xdot, ydot, zdot whereas columns 0 to 5 correspond to the orbital parameters.
  446.      * </p>
  447.      * @param type type of the position angle to use
  448.      * @param jacobian placeholder 6x6 (or larger) matrix to be filled with the Jacobian, if matrix
  449.      * is larger than 6x6, only the 6x6 upper left corner will be modified
  450.      */
  451.     public void getJacobianWrtParameters(final PositionAngle type, final T[][] jacobian) {

  452.         final T[][] cachedJacobian;
  453.         synchronized (this) {
  454.             switch (type) {
  455.                 case MEAN :
  456.                     if (jacobianWrtParametersMean == null) {
  457.                         // first call, we need to compute the Jacobian and cache it
  458.                         jacobianWrtParametersMean = createInverseJacobian(type);
  459.                     }
  460.                     cachedJacobian = jacobianWrtParametersMean;
  461.                     break;
  462.                 case ECCENTRIC :
  463.                     if (jacobianWrtParametersEccentric == null) {
  464.                         // first call, we need to compute the Jacobian and cache it
  465.                         jacobianWrtParametersEccentric = createInverseJacobian(type);
  466.                     }
  467.                     cachedJacobian = jacobianWrtParametersEccentric;
  468.                     break;
  469.                 case TRUE :
  470.                     if (jacobianWrtParametersTrue == null) {
  471.                         // first call, we need to compute the Jacobian and cache it
  472.                         jacobianWrtParametersTrue = createInverseJacobian(type);
  473.                     }
  474.                     cachedJacobian = jacobianWrtParametersTrue;
  475.                     break;
  476.                 default :
  477.                     throw new OrekitInternalError(null);
  478.             }
  479.         }

  480.         // fill the user-provided array
  481.         for (int i = 0; i < cachedJacobian.length; ++i) {
  482.             System.arraycopy(cachedJacobian[i], 0, jacobian[i], 0, cachedJacobian[i].length);
  483.         }

  484.     }

  485.     /** Create an inverse Jacobian.
  486.      * @param type type of the position angle to use
  487.      * @return inverse Jacobian
  488.      */
  489.     private T[][] createInverseJacobian(final PositionAngle type) {

  490.         // get the direct Jacobian
  491.         final T[][] directJacobian = MathArrays.buildArray(getA().getField(), 6, 6);
  492.         getJacobianWrtCartesian(type, directJacobian);

  493.         // invert the direct Jacobian
  494.         final FieldMatrix<T> matrix = MatrixUtils.createFieldMatrix(directJacobian);
  495.         final FieldDecompositionSolver<T> solver = new FieldLUDecomposition<>(matrix).getSolver();
  496.         return solver.getInverse().getData();

  497.     }

  498.     /** Compute the Jacobian of the orbital parameters with mean angle with respect to the Cartesian parameters.
  499.      * <p>
  500.      * Element {@code jacobian[i][j]} is the derivative of parameter i of the orbit with
  501.      * respect to Cartesian coordinate j. This means each row correspond to one orbital parameter
  502.      * whereas columns 0 to 5 correspond to the Cartesian coordinates x, y, z, xDot, yDot and zDot.
  503.      * </p>
  504.      * @return 6x6 Jacobian matrix
  505.      * @see #computeJacobianEccentricWrtCartesian()
  506.      * @see #computeJacobianTrueWrtCartesian()
  507.      */
  508.     protected abstract T[][] computeJacobianMeanWrtCartesian();

  509.     /** Compute the Jacobian of the orbital parameters with eccentric angle with respect to the Cartesian parameters.
  510.      * <p>
  511.      * Element {@code jacobian[i][j]} is the derivative of parameter i of the orbit with
  512.      * respect to Cartesian coordinate j. This means each row correspond to one orbital parameter
  513.      * whereas columns 0 to 5 correspond to the Cartesian coordinates x, y, z, xDot, yDot and zDot.
  514.      * </p>
  515.      * @return 6x6 Jacobian matrix
  516.      * @see #computeJacobianMeanWrtCartesian()
  517.      * @see #computeJacobianTrueWrtCartesian()
  518.      */
  519.     protected abstract T[][] computeJacobianEccentricWrtCartesian();

  520.     /** Compute the Jacobian of the orbital parameters with true angle with respect to the Cartesian parameters.
  521.      * <p>
  522.      * Element {@code jacobian[i][j]} is the derivative of parameter i of the orbit with
  523.      * respect to Cartesian coordinate j. This means each row correspond to one orbital parameter
  524.      * whereas columns 0 to 5 correspond to the Cartesian coordinates x, y, z, xDot, yDot and zDot.
  525.      * </p>
  526.      * @return 6x6 Jacobian matrix
  527.      * @see #computeJacobianMeanWrtCartesian()
  528.      * @see #computeJacobianEccentricWrtCartesian()
  529.      */
  530.     protected abstract T[][] computeJacobianTrueWrtCartesian();

  531.     /** Add the contribution of the Keplerian motion to parameters derivatives
  532.      * <p>
  533.      * This method is used by integration-based propagators to evaluate the part of Keplerian
  534.      * motion to evolution of the orbital state.
  535.      * </p>
  536.      * @param type type of the position angle in the state
  537.      * @param gm attraction coefficient to use
  538.      * @param pDot array containing orbital state derivatives to update (the Keplerian
  539.      * part must be <em>added</em> to the array components, as the array may already
  540.      * contain some non-zero elements corresponding to non-Keplerian parts)
  541.      */
  542.     public abstract void addKeplerContribution(PositionAngle type, double gm, T[] pDot);

  543.         /** Fill a Jacobian half row with a single vector.
  544.      * @param a coefficient of the vector
  545.      * @param v vector
  546.      * @param row Jacobian matrix row
  547.      * @param j index of the first element to set (row[j], row[j+1] and row[j+2] will all be set)
  548.      */

  549.     protected void fillHalfRow(final T a, final FieldVector3D<T> v, final T[] row, final int j) {
  550.         row[j]     = a.multiply(v.getX());
  551.         row[j + 1] = a.multiply(v.getY());
  552.         row[j + 2] = a.multiply(v.getZ());
  553.     }

  554.     /** Fill a Jacobian half row with a linear combination of vectors.
  555.      * @param a1 coefficient of the first vector
  556.      * @param v1 first vector
  557.      * @param a2 coefficient of the second vector
  558.      * @param v2 second vector
  559.      * @param row Jacobian matrix row
  560.      * @param j index of the first element to set (row[j], row[j+1] and row[j+2] will all be set)
  561.      */
  562.     protected void fillHalfRow(final T a1, final FieldVector3D<T> v1, final T a2, final FieldVector3D<T> v2,
  563.                                       final T[] row, final int j) {
  564.         row[j]     = a1.linearCombination(a1, v1.getX(), a2, v2.getX());
  565.         row[j + 1] = a1.linearCombination(a1, v1.getY(), a2, v2.getY());
  566.         row[j + 2] = a1.linearCombination(a1, v1.getZ(), a2, v2.getZ());
  567. //        row[j]     = a1.multiply(v1.getX()).add(a2.multiply(v2.getX()));
  568. //        row[j + 1] = a1.multiply(v1.getY()).add(a2.multiply(v2.getY()));
  569. //        row[j + 2] = a1.multiply(v1.getZ()).add(a2.multiply(v2.getZ()));
  570.     }

  571.     /** Fill a Jacobian half row with a linear combination of vectors.
  572.      * @param a1 coefficient of the first vector
  573.      * @param v1 first vector
  574.      * @param a2 coefficient of the second vector
  575.      * @param v2 second vector
  576.      * @param a3 coefficient of the third vector
  577.      * @param v3 third vector
  578.      * @param row Jacobian matrix row
  579.      * @param j index of the first element to set (row[j], row[j+1] and row[j+2] will all be set)
  580.      */
  581.     protected void fillHalfRow(final T a1, final FieldVector3D<T> v1,
  582.                                final T a2, final FieldVector3D<T> v2,
  583.                                final T a3, final FieldVector3D<T> v3,
  584.                                       final T[] row, final int j) {
  585.         row[j]     = a1.linearCombination(a1, v1.getX(), a2, v2.getX(), a3, v3.getX());
  586.         row[j + 1] = a1.linearCombination(a1, v1.getY(), a2, v2.getY(), a3, v3.getY());
  587.         row[j + 2] = a1.linearCombination(a1, v1.getZ(), a2, v2.getZ(), a3, v3.getZ());



  588. //        row[j]     = a1.multiply(v1.getX()).add(a2.multiply(v2.getX())).add(a3.multiply(v3.getX()));
  589. //        row[j + 1] = a1.multiply(v1.getY()).add(a2.multiply(v2.getY())).add(a3.multiply(v3.getY()));
  590. //        row[j + 2] = a1.multiply(v1.getZ()).add(a2.multiply(v2.getZ())).add(a3.multiply(v3.getZ()));
  591.     }

  592.     /** Fill a Jacobian half row with a linear combination of vectors.
  593.      * @param a1 coefficient of the first vector
  594.      * @param v1 first vector
  595.      * @param a2 coefficient of the second vector
  596.      * @param v2 second vector
  597.      * @param a3 coefficient of the third vector
  598.      * @param v3 third vector
  599.      * @param a4 coefficient of the fourth vector
  600.      * @param v4 fourth vector
  601.      * @param row Jacobian matrix row
  602.      * @param j index of the first element to set (row[j], row[j+1] and row[j+2] will all be set)
  603.      */
  604.     protected void fillHalfRow(final T a1, final FieldVector3D<T> v1, final T a2, final FieldVector3D<T> v2,
  605.                                       final T a3, final FieldVector3D<T> v3, final T a4, final FieldVector3D<T> v4,
  606.                                       final T[] row, final int j) {
  607.         row[j]     = a1.linearCombination(a1, v1.getX(), a2, v2.getX(), a3, v3.getX(), a4, v4.getX());
  608.         row[j + 1] = a1.linearCombination(a1, v1.getY(), a2, v2.getY(), a3, v3.getY(), a4, v4.getY());
  609.         row[j + 2] = a1.linearCombination(a1, v1.getZ(), a2, v2.getZ(), a3, v3.getZ(), a4, v4.getZ());
  610. //        row[j]     = a1.multiply(v1.getX()).add(a2.multiply(v2.getX())).add(a3.multiply(v3.getX())).add(a4.multiply(v4.getX()));
  611. //        row[j + 1] = a1.multiply(v1.getY()).add(a2.multiply(v2.getY())).add(a3.multiply(v3.getY())).add(a4.multiply(v4.getY()));
  612. //        row[j + 2] = a1.multiply(v1.getZ()).add(a2.multiply(v2.getZ())).add(a3.multiply(v3.getZ())).add(a4.multiply(v4.getZ()));
  613.     }

  614.     /** Fill a Jacobian half row with a linear combination of vectors.
  615.      * @param a1 coefficient of the first vector
  616.      * @param v1 first vector
  617.      * @param a2 coefficient of the second vector
  618.      * @param v2 second vector
  619.      * @param a3 coefficient of the third vector
  620.      * @param v3 third vector
  621.      * @param a4 coefficient of the fourth vector
  622.      * @param v4 fourth vector
  623.      * @param a5 coefficient of the fifth vector
  624.      * @param v5 fifth vector
  625.      * @param row Jacobian matrix row
  626.      * @param j index of the first element to set (row[j], row[j+1] and row[j+2] will all be set)
  627.      */
  628.     protected void fillHalfRow(final T a1, final FieldVector3D<T> v1, final T a2, final FieldVector3D<T> v2,
  629.                                       final T a3, final FieldVector3D<T> v3, final T a4, final FieldVector3D<T> v4,
  630.                                       final T a5, final FieldVector3D<T> v5,
  631.                                       final T[] row, final int j) {
  632.         row[j]     = a1.linearCombination(a1, v1.getX(), a2, v2.getX(), a3, v3.getX(), a4, v4.getX()).add(a5.multiply(v5.getX()));
  633.         row[j + 1] = a1.linearCombination(a1, v1.getY(), a2, v2.getY(), a3, v3.getY(), a4, v4.getY()).add(a5.multiply(v5.getY()));
  634.         row[j + 2] = a1.linearCombination(a1, v1.getZ(), a2, v2.getZ(), a3, v3.getZ(), a4, v4.getZ()).add(a5.multiply(v5.getZ()));

  635. //        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()));
  636. //        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()));
  637. //        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()));
  638.     }

  639.     /** Fill a Jacobian half row with a linear combination of vectors.
  640.      * @param a1 coefficient of the first vector
  641.      * @param v1 first vector
  642.      * @param a2 coefficient of the second vector
  643.      * @param v2 second vector
  644.      * @param a3 coefficient of the third vector
  645.      * @param v3 third vector
  646.      * @param a4 coefficient of the fourth vector
  647.      * @param v4 fourth vector
  648.      * @param a5 coefficient of the fifth vector
  649.      * @param v5 fifth vector
  650.      * @param a6 coefficient of the sixth vector
  651.      * @param v6 sixth vector
  652.      * @param row Jacobian matrix row
  653.      * @param j index of the first element to set (row[j], row[j+1] and row[j+2] will all be set)
  654.      */
  655.     protected void fillHalfRow(final T a1, final FieldVector3D<T> v1, final T a2, final FieldVector3D<T> v2,
  656.                                       final T a3, final FieldVector3D<T> v3, final T a4, final FieldVector3D<T> v4,
  657.                                       final T a5, final FieldVector3D<T> v5, final T a6, final FieldVector3D<T> v6,
  658.                                       final T[] row, final int j) {
  659.         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()));
  660.         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()));
  661.         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()));


  662. //        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()));
  663. //        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()));
  664. //        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()));
  665.     }


  666. }