FieldKeplerianOrbit.java

  1. /* Copyright 2002-2024 CS GROUP
  2.  * Licensed to CS GROUP (CS) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * CS licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *   http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.orekit.orbits;


  18. import java.lang.reflect.Array;

  19. import org.hipparchus.CalculusFieldElement;
  20. import org.hipparchus.Field;
  21. import org.hipparchus.analysis.differentiation.FieldUnivariateDerivative1;
  22. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  23. import org.hipparchus.util.FastMath;
  24. import org.hipparchus.util.FieldSinCos;
  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.time.FieldAbsoluteDate;
  32. import org.orekit.utils.FieldPVCoordinates;
  33. import org.orekit.utils.TimeStampedFieldPVCoordinates;


  34. /**
  35.  * This class handles traditional Keplerian orbital parameters.

  36.  * <p>
  37.  * The parameters used internally are the classical Keplerian elements:
  38.  *   <pre>
  39.  *     a
  40.  *     e
  41.  *     i
  42.  *     ω
  43.  *     Ω
  44.  *     v
  45.  *   </pre>
  46.  * where ω stands for the Perigee Argument, Ω stands for the
  47.  * Right Ascension of the Ascending Node and v stands for the true anomaly.
  48.  * <p>
  49.  * This class supports hyperbolic orbits, using the convention that semi major
  50.  * axis is negative for such orbits (and of course eccentricity is greater than 1).
  51.  * </p>
  52.  * <p>
  53.  * When orbit is either equatorial or circular, some Keplerian elements
  54.  * (more precisely ω and Ω) become ambiguous so this class should not
  55.  * be used for such orbits. For this reason, {@link EquinoctialOrbit equinoctial
  56.  * orbits} is the recommended way to represent orbits.
  57.  * </p>

  58.  * <p>
  59.  * The instance <code>KeplerianOrbit</code> is guaranteed to be immutable.
  60.  * </p>
  61.  * @see     Orbit
  62.  * @see    CircularOrbit
  63.  * @see    CartesianOrbit
  64.  * @see    EquinoctialOrbit
  65.  * @author Luc Maisonobe
  66.  * @author Guylaine Prat
  67.  * @author Fabien Maussion
  68.  * @author V&eacute;ronique Pommier-Maurussane
  69.  * @author Andrea Antolino
  70.  * @since 9.0
  71.  * @param <T> type of the field elements
  72.  */
  73. public class FieldKeplerianOrbit<T extends CalculusFieldElement<T>> extends FieldOrbit<T>
  74.         implements PositionAngleBased {

  75.     /** Name of the eccentricity parameter. */
  76.     private static final String ECCENTRICITY = "eccentricity";

  77.     /** Semi-major axis (m). */
  78.     private final T a;

  79.     /** Eccentricity. */
  80.     private final T e;

  81.     /** Inclination (rad). */
  82.     private final T i;

  83.     /** Perigee Argument (rad). */
  84.     private final T pa;

  85.     /** Right Ascension of Ascending Node (rad). */
  86.     private final T raan;

  87.     /** True anomaly (rad). */
  88.     private final T v;

  89.     /** Semi-major axis derivative (m/s). */
  90.     private final T aDot;

  91.     /** Eccentricity derivative. */
  92.     private final T eDot;

  93.     /** Inclination derivative (rad/s). */
  94.     private final T iDot;

  95.     /** Perigee Argument derivative (rad/s). */
  96.     private final T paDot;

  97.     /** Right Ascension of Ascending Node derivative (rad/s). */
  98.     private final T raanDot;

  99.     /** True anomaly derivative (rad/s). */
  100.     private final T vDot;

  101.     /** Partial Cartesian coordinates (position and velocity are valid, acceleration may be missing). */
  102.     private FieldPVCoordinates<T> partialPV;

  103.     /** PThird Canonical Vector. */
  104.     private final FieldVector3D<T> PLUS_K;

  105.     /** Creates a new instance.
  106.      * @param a  semi-major axis (m), negative for hyperbolic orbits
  107.      * @param e eccentricity (positive or equal to 0)
  108.      * @param i inclination (rad)
  109.      * @param pa perigee argument (ω, rad)
  110.      * @param raan right ascension of ascending node (Ω, rad)
  111.      * @param anomaly mean, eccentric or true anomaly (rad)
  112.      * @param type type of anomaly
  113.      * @param frame the frame in which the parameters are defined
  114.      * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame})
  115.      * @param date date of the orbital parameters
  116.      * @param mu central attraction coefficient (m³/s²)
  117.      * @exception IllegalArgumentException if frame is not a {@link
  118.      * Frame#isPseudoInertial pseudo-inertial frame} or a and e don't match for hyperbolic orbits,
  119.      * or v is out of range for hyperbolic orbits
  120.      */
  121.     public FieldKeplerianOrbit(final T a, final T e, final T i,
  122.                                final T pa, final T raan,
  123.                                final T anomaly, final PositionAngleType type,
  124.                                final Frame frame, final FieldAbsoluteDate<T> date, final T mu)
  125.         throws IllegalArgumentException {
  126.         this(a, e, i, pa, raan, anomaly,
  127.              null, null, null, null, null, null,
  128.              type, frame, date, mu);
  129.     }

  130.     /** Creates a new instance.
  131.      * @param a  semi-major axis (m), negative for hyperbolic orbits
  132.      * @param e eccentricity (positive or equal to 0)
  133.      * @param i inclination (rad)
  134.      * @param pa perigee argument (ω, rad)
  135.      * @param raan right ascension of ascending node (Ω, rad)
  136.      * @param anomaly mean, eccentric or true anomaly (rad)
  137.      * @param aDot  semi-major axis derivative, null if unknown (m/s)
  138.      * @param eDot eccentricity derivative, null if unknown
  139.      * @param iDot inclination derivative, null if unknown (rad/s)
  140.      * @param paDot perigee argument derivative, null if unknown (rad/s)
  141.      * @param raanDot right ascension of ascending node derivative, null if unknown (rad/s)
  142.      * @param anomalyDot mean, eccentric or true anomaly derivative, null if unknown (rad/s)
  143.      * @param type type of anomaly
  144.      * @param frame the frame in which the parameters are defined
  145.      * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame})
  146.      * @param date date of the orbital parameters
  147.      * @param mu central attraction coefficient (m³/s²)
  148.      * @exception IllegalArgumentException if frame is not a {@link
  149.      * Frame#isPseudoInertial pseudo-inertial frame} or a and e don't match for hyperbolic orbits,
  150.      * or v is out of range for hyperbolic orbits
  151.      */
  152.     public FieldKeplerianOrbit(final T a, final T e, final T i,
  153.                                final T pa, final T raan, final T anomaly,
  154.                                final T aDot, final T eDot, final T iDot,
  155.                                final T paDot, final T raanDot, final T anomalyDot,
  156.                                final PositionAngleType type,
  157.                                final Frame frame, final FieldAbsoluteDate<T> date, final T mu)
  158.         throws IllegalArgumentException {
  159.         super(frame, date, mu);
  160.         if (a.multiply(e.negate().add(1)).getReal() < 0) {
  161.             throw new OrekitIllegalArgumentException(OrekitMessages.ORBIT_A_E_MISMATCH_WITH_CONIC_TYPE, a.getReal(), e.getReal());
  162.         }

  163.         // Checking eccentricity range
  164.         checkParameterRangeInclusive(ECCENTRICITY, e.getReal(), 0.0, Double.POSITIVE_INFINITY);

  165.         this.a       =    a;
  166.         this.aDot    =    aDot;
  167.         this.e       =    e;
  168.         this.eDot    =    eDot;
  169.         this.i       =    i;
  170.         this.iDot    =    iDot;
  171.         this.pa      =    pa;
  172.         this.paDot   =    paDot;
  173.         this.raan    =    raan;
  174.         this.raanDot =    raanDot;

  175.         this.PLUS_K = FieldVector3D.getPlusK(a.getField());  // third canonical vector

  176.         if (hasDerivatives()) {
  177.             final FieldUnivariateDerivative1<T> eUD        = new FieldUnivariateDerivative1<>(e, eDot);
  178.             final FieldUnivariateDerivative1<T> anomalyUD  = new FieldUnivariateDerivative1<>(anomaly,  anomalyDot);
  179.             final FieldUnivariateDerivative1<T> vUD;
  180.             switch (type) {
  181.                 case MEAN :
  182.                     vUD = (a.getReal() < 0) ?
  183.                           FieldKeplerianAnomalyUtility.hyperbolicMeanToTrue(eUD, anomalyUD) :
  184.                           FieldKeplerianAnomalyUtility.ellipticMeanToTrue(eUD, anomalyUD);
  185.                     break;
  186.                 case ECCENTRIC :
  187.                     vUD = (a.getReal() < 0) ?
  188.                           FieldKeplerianAnomalyUtility.hyperbolicEccentricToTrue(eUD, anomalyUD) :
  189.                           FieldKeplerianAnomalyUtility.ellipticEccentricToTrue(eUD, anomalyUD);
  190.                     break;
  191.                 case TRUE :
  192.                     vUD = anomalyUD;
  193.                     break;
  194.                 default : // this should never happen
  195.                     throw new OrekitInternalError(null);
  196.             }
  197.             this.v    = vUD.getValue();
  198.             this.vDot = vUD.getDerivative(1);
  199.         } else {
  200.             switch (type) {
  201.                 case MEAN :

  202.                     this.v = (a.getReal() < 0) ?
  203.                              FieldKeplerianAnomalyUtility.hyperbolicMeanToTrue(e, anomaly) :
  204.                              FieldKeplerianAnomalyUtility.ellipticMeanToTrue(e, anomaly);

  205.                     break;
  206.                 case ECCENTRIC :
  207.                     this.v = (a.getReal() < 0) ?
  208.                              FieldKeplerianAnomalyUtility.hyperbolicEccentricToTrue(e, anomaly) :
  209.                              FieldKeplerianAnomalyUtility.ellipticEccentricToTrue(e, anomaly);

  210.                     break;
  211.                 case TRUE :
  212.                     this.v = anomaly;
  213.                     break;
  214.                 default : // this should never happen
  215.                     throw new OrekitInternalError(null);
  216.             }
  217.             this.vDot = null;
  218.         }

  219.         // check true anomaly range
  220.         if (e.multiply(v.cos()).add(1).getReal() <= 0) {
  221.             final double vMax = e.reciprocal().negate().acos().getReal();
  222.             throw new OrekitIllegalArgumentException(OrekitMessages.ORBIT_ANOMALY_OUT_OF_HYPERBOLIC_RANGE,
  223.                                                      v.getReal(), e.getReal(), -vMax, vMax);
  224.         }

  225.         this.partialPV = null;

  226.     }

  227.     /** Constructor from Cartesian parameters.
  228.      *
  229.      * <p> The acceleration provided in {@code FieldPVCoordinates} is accessible using
  230.      * {@link #getPVCoordinates()} and {@link #getPVCoordinates(Frame)}. All other methods
  231.      * use {@code mu} and the position to compute the acceleration, including
  232.      * {@link #shiftedBy(CalculusFieldElement)} and {@link #getPVCoordinates(FieldAbsoluteDate, Frame)}.
  233.      *
  234.      * @param pvCoordinates the PVCoordinates of the satellite
  235.      * @param frame the frame in which are defined the {@link FieldPVCoordinates}
  236.      * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame})
  237.      * @param mu central attraction coefficient (m³/s²)
  238.      * @exception IllegalArgumentException if frame is not a {@link
  239.      * Frame#isPseudoInertial pseudo-inertial frame}
  240.      */
  241.     public FieldKeplerianOrbit(final TimeStampedFieldPVCoordinates<T> pvCoordinates,
  242.                                final Frame frame, final T mu)
  243.         throws IllegalArgumentException {
  244.         this(pvCoordinates, frame, mu, hasNonKeplerianAcceleration(pvCoordinates, mu));
  245.     }

  246.     /** Constructor from Cartesian parameters.
  247.      *
  248.      * <p> The acceleration provided in {@code FieldPVCoordinates} is accessible using
  249.      * {@link #getPVCoordinates()} and {@link #getPVCoordinates(Frame)}. All other methods
  250.      * use {@code mu} and the position to compute the acceleration, including
  251.      * {@link #shiftedBy(CalculusFieldElement)} and {@link #getPVCoordinates(FieldAbsoluteDate, Frame)}.
  252.      *
  253.      * @param pvCoordinates the PVCoordinates of the satellite
  254.      * @param frame the frame in which are defined the {@link FieldPVCoordinates}
  255.      * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame})
  256.      * @param mu central attraction coefficient (m³/s²)
  257.      * @param reliableAcceleration if true, the acceleration is considered to be reliable
  258.      * @exception IllegalArgumentException if frame is not a {@link
  259.      * Frame#isPseudoInertial pseudo-inertial frame}
  260.      */
  261.     private FieldKeplerianOrbit(final TimeStampedFieldPVCoordinates<T> pvCoordinates,
  262.                                 final Frame frame, final T mu,
  263.                                 final boolean reliableAcceleration)
  264.         throws IllegalArgumentException {

  265.         super(pvCoordinates, frame, mu);

  266.         // third canonical vector
  267.         this.PLUS_K = FieldVector3D.getPlusK(getOne().getField());

  268.         // compute inclination
  269.         final FieldVector3D<T> momentum = pvCoordinates.getMomentum();
  270.         final T m2 = momentum.getNormSq();

  271.         i = FieldVector3D.angle(momentum, PLUS_K);
  272.         // compute right ascension of ascending node
  273.         raan = FieldVector3D.crossProduct(PLUS_K, momentum).getAlpha();
  274.         // preliminary computations for parameters depending on orbit shape (elliptic or hyperbolic)
  275.         final FieldVector3D<T> pvP     = pvCoordinates.getPosition();
  276.         final FieldVector3D<T> pvV     = pvCoordinates.getVelocity();
  277.         final FieldVector3D<T> pvA     = pvCoordinates.getAcceleration();

  278.         final T   r2      = pvP.getNormSq();
  279.         final T   r       = r2.sqrt();
  280.         final T   V2      = pvV.getNormSq();
  281.         final T   rV2OnMu = r.multiply(V2).divide(mu);

  282.         // compute semi-major axis (will be negative for hyperbolic orbits)
  283.         a = r.divide(rV2OnMu.negate().add(2.0));
  284.         final T muA = a.multiply(mu);

  285.         // compute true anomaly
  286.         if (isElliptical()) {
  287.             // elliptic or circular orbit
  288.             final T eSE = FieldVector3D.dotProduct(pvP, pvV).divide(muA.sqrt());
  289.             final T eCE = rV2OnMu.subtract(1);
  290.             e = (eSE.multiply(eSE).add(eCE.multiply(eCE))).sqrt();
  291.             v = FieldKeplerianAnomalyUtility.ellipticEccentricToTrue(e, eSE.atan2(eCE));
  292.         } else {
  293.             // hyperbolic orbit
  294.             final T eSH = FieldVector3D.dotProduct(pvP, pvV).divide(muA.negate().sqrt());
  295.             final T eCH = rV2OnMu.subtract(1);
  296.             e = (m2.negate().divide(muA).add(1)).sqrt();
  297.             v = FieldKeplerianAnomalyUtility.hyperbolicEccentricToTrue(e, (eCH.add(eSH)).divide(eCH.subtract(eSH)).log().divide(2));
  298.         }

  299.         // Checking eccentricity range
  300.         checkParameterRangeInclusive(ECCENTRICITY, e.getReal(), 0.0, Double.POSITIVE_INFINITY);

  301.         // compute perigee argument
  302.         final FieldVector3D<T> node = new FieldVector3D<>(raan, getZero());
  303.         final T px = FieldVector3D.dotProduct(pvP, node);
  304.         final T py = FieldVector3D.dotProduct(pvP, FieldVector3D.crossProduct(momentum, node)).divide(m2.sqrt());
  305.         pa = py.atan2(px).subtract(v);

  306.         partialPV = pvCoordinates;

  307.         if (reliableAcceleration) {
  308.             // we have a relevant acceleration, we can compute derivatives

  309.             final T[][] jacobian = MathArrays.buildArray(a.getField(), 6, 6);
  310.             getJacobianWrtCartesian(PositionAngleType.MEAN, jacobian);

  311.             final FieldVector3D<T> keplerianAcceleration    = new FieldVector3D<>(r.multiply(r2).reciprocal().multiply(mu.negate()), pvP);
  312.             final FieldVector3D<T> nonKeplerianAcceleration = pvA.subtract(keplerianAcceleration);
  313.             final T   aX                       = nonKeplerianAcceleration.getX();
  314.             final T   aY                       = nonKeplerianAcceleration.getY();
  315.             final T   aZ                       = nonKeplerianAcceleration.getZ();
  316.             aDot    = jacobian[0][3].multiply(aX).add(jacobian[0][4].multiply(aY)).add(jacobian[0][5].multiply(aZ));
  317.             eDot    = jacobian[1][3].multiply(aX).add(jacobian[1][4].multiply(aY)).add(jacobian[1][5].multiply(aZ));
  318.             iDot    = jacobian[2][3].multiply(aX).add(jacobian[2][4].multiply(aY)).add(jacobian[2][5].multiply(aZ));
  319.             paDot   = jacobian[3][3].multiply(aX).add(jacobian[3][4].multiply(aY)).add(jacobian[3][5].multiply(aZ));
  320.             raanDot = jacobian[4][3].multiply(aX).add(jacobian[4][4].multiply(aY)).add(jacobian[4][5].multiply(aZ));

  321.             // in order to compute true anomaly derivative, we must compute
  322.             // mean anomaly derivative including Keplerian motion and convert to true anomaly
  323.             final T MDot = getKeplerianMeanMotion().
  324.                            add(jacobian[5][3].multiply(aX)).add(jacobian[5][4].multiply(aY)).add(jacobian[5][5].multiply(aZ));
  325.             final FieldUnivariateDerivative1<T> eUD = new FieldUnivariateDerivative1<>(e, eDot);
  326.             final FieldUnivariateDerivative1<T> MUD = new FieldUnivariateDerivative1<>(getMeanAnomaly(), MDot);
  327.             final FieldUnivariateDerivative1<T> vUD = (a.getReal() < 0) ?
  328.                                             FieldKeplerianAnomalyUtility.hyperbolicMeanToTrue(eUD, MUD) :
  329.                                             FieldKeplerianAnomalyUtility.ellipticMeanToTrue(eUD, MUD);
  330.             vDot = vUD.getDerivative(1);

  331.         } else {
  332.             // acceleration is either almost zero or NaN,
  333.             // we assume acceleration was not known
  334.             // we don't set up derivatives
  335.             aDot    = null;
  336.             eDot    = null;
  337.             iDot    = null;
  338.             paDot   = null;
  339.             raanDot = null;
  340.             vDot    = null;
  341.         }

  342.     }

  343.     /** Constructor from Cartesian parameters.
  344.      *
  345.      * <p> The acceleration provided in {@code FieldPVCoordinates} is accessible using
  346.      * {@link #getPVCoordinates()} and {@link #getPVCoordinates(Frame)}. All other methods
  347.      * use {@code mu} and the position to compute the acceleration, including
  348.      * {@link #shiftedBy(CalculusFieldElement)} and {@link #getPVCoordinates(FieldAbsoluteDate, Frame)}.
  349.      *
  350.      * @param FieldPVCoordinates the PVCoordinates of the satellite
  351.      * @param frame the frame in which are defined the {@link FieldPVCoordinates}
  352.      * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame})
  353.      * @param date date of the orbital parameters
  354.      * @param mu central attraction coefficient (m³/s²)
  355.      * @exception IllegalArgumentException if frame is not a {@link
  356.      * Frame#isPseudoInertial pseudo-inertial frame}
  357.      */
  358.     public FieldKeplerianOrbit(final FieldPVCoordinates<T> FieldPVCoordinates,
  359.                                final Frame frame, final FieldAbsoluteDate<T> date, final T mu)
  360.         throws IllegalArgumentException {
  361.         this(new TimeStampedFieldPVCoordinates<>(date, FieldPVCoordinates), frame, mu);
  362.     }

  363.     /** Constructor from any kind of orbital parameters.
  364.      * @param op orbital parameters to copy
  365.      */
  366.     public FieldKeplerianOrbit(final FieldOrbit<T> op) {
  367.         this(op.getPVCoordinates(), op.getFrame(), op.getMu(), op.hasDerivatives());
  368.     }

  369.     /** Constructor from Field and KeplerianOrbit.
  370.      * <p>Build a FieldKeplerianOrbit from non-Field KeplerianOrbit.</p>
  371.      * @param field CalculusField to base object on
  372.      * @param op non-field orbit with only "constant" terms
  373.      * @since 12.0
  374.      */
  375.     public FieldKeplerianOrbit(final Field<T> field, final KeplerianOrbit op) {
  376.         this(field.getZero().add(op.getA()), field.getZero().add(op.getE()), field.getZero().add(op.getI()),
  377.                 field.getZero().add(op.getPerigeeArgument()), field.getZero().add(op.getRightAscensionOfAscendingNode()),
  378.                 field.getZero().add(op.getTrueAnomaly()),
  379.                 (op.hasDerivatives()) ? field.getZero().add(op.getADot()) : null,
  380.                 (op.hasDerivatives()) ? field.getZero().add(op.getEDot()) : null,
  381.                 (op.hasDerivatives()) ? field.getZero().add(op.getIDot()) : null,
  382.                 (op.hasDerivatives()) ? field.getZero().add(op.getPerigeeArgumentDot()) : null,
  383.                 (op.hasDerivatives()) ? field.getZero().add(op.getRightAscensionOfAscendingNodeDot()) : null,
  384.                 (op.hasDerivatives()) ? field.getZero().add(op.getTrueAnomalyDot()) : null, PositionAngleType.TRUE,
  385.                 op.getFrame(), new FieldAbsoluteDate<>(field, op.getDate()), field.getZero().add(op.getMu()));
  386.     }

  387.     /** Constructor from Field and Orbit.
  388.      * <p>Build a FieldKeplerianOrbit from any non-Field Orbit.</p>
  389.      * @param field CalculusField to base object on
  390.      * @param op non-field orbit with only "constant" terms
  391.      * @since 12.0
  392.      */
  393.     public FieldKeplerianOrbit(final Field<T> field, final Orbit op) {
  394.         this(field, new KeplerianOrbit(op));
  395.     }

  396.     /** {@inheritDoc} */
  397.     public OrbitType getType() {
  398.         return OrbitType.KEPLERIAN;
  399.     }

  400.     /** {@inheritDoc} */
  401.     public T getA() {
  402.         return a;
  403.     }

  404.     /** {@inheritDoc} */
  405.     public T getADot() {
  406.         return aDot;
  407.     }

  408.     /** {@inheritDoc} */
  409.     public T getE() {
  410.         return e;
  411.     }

  412.     /** {@inheritDoc} */
  413.     public T getEDot() {
  414.         return eDot;
  415.     }

  416.     /** {@inheritDoc} */
  417.     public T getI() {
  418.         return i;
  419.     }

  420.     /** {@inheritDoc} */
  421.     public T getIDot() {
  422.         return iDot;
  423.     }

  424.     /** Get the perigee argument.
  425.      * @return perigee argument (rad)
  426.      */
  427.     public T getPerigeeArgument() {
  428.         return pa;
  429.     }

  430.     /** Get the perigee argument derivative.
  431.      * <p>
  432.      * If the orbit was created without derivatives, the value returned is null.
  433.      * </p>
  434.      * @return perigee argument derivative (rad/s)
  435.      */
  436.     public T getPerigeeArgumentDot() {
  437.         return paDot;
  438.     }

  439.     /** Get the right ascension of the ascending node.
  440.      * @return right ascension of the ascending node (rad)
  441.      */
  442.     public T getRightAscensionOfAscendingNode() {
  443.         return raan;
  444.     }

  445.     /** Get the right ascension of the ascending node derivative.
  446.      * <p>
  447.      * If the orbit was created without derivatives, the value returned is null.
  448.      * </p>
  449.      * @return right ascension of the ascending node derivative (rad/s)
  450.      */
  451.     public T getRightAscensionOfAscendingNodeDot() {
  452.         return raanDot;
  453.     }

  454.     /** Get the true anomaly.
  455.      * @return true anomaly (rad)
  456.      */
  457.     public T getTrueAnomaly() {
  458.         return v;
  459.     }

  460.     /** Get the true anomaly derivative.
  461.      * <p>
  462.      * If the orbit was created without derivatives, the value returned is null.
  463.      * </p>
  464.      * @return true anomaly derivative (rad/s)
  465.      */
  466.     public T getTrueAnomalyDot() {
  467.         return vDot;
  468.     }

  469.     /** Get the eccentric anomaly.
  470.      * @return eccentric anomaly (rad)
  471.      */
  472.     public T getEccentricAnomaly() {
  473.         return (a.getReal() < 0) ?
  474.                FieldKeplerianAnomalyUtility.hyperbolicTrueToEccentric(e, v) :
  475.                FieldKeplerianAnomalyUtility.ellipticTrueToEccentric(e, v);
  476.     }

  477.     /** Get the eccentric anomaly derivative.
  478.      * <p>
  479.      * If the orbit was created without derivatives, the value returned is null.
  480.      * </p>
  481.      * @return eccentric anomaly derivative (rad/s)
  482.      */
  483.     public T getEccentricAnomalyDot() {

  484.         if (!hasDerivatives()) {
  485.             return null;
  486.         }

  487.         final FieldUnivariateDerivative1<T> eUD = new FieldUnivariateDerivative1<>(e, eDot);
  488.         final FieldUnivariateDerivative1<T> vUD = new FieldUnivariateDerivative1<>(v, vDot);
  489.         final FieldUnivariateDerivative1<T> EUD = (a.getReal() < 0) ?
  490.                                                 FieldKeplerianAnomalyUtility.hyperbolicTrueToEccentric(eUD, vUD) :
  491.                                                 FieldKeplerianAnomalyUtility.ellipticTrueToEccentric(eUD, vUD);
  492.         return EUD.getDerivative(1);

  493.     }

  494.     /** Get the mean anomaly.
  495.      * @return mean anomaly (rad)
  496.      */
  497.     public T getMeanAnomaly() {
  498.         return (a.getReal() < 0) ?
  499.                FieldKeplerianAnomalyUtility.hyperbolicTrueToMean(e, v) :
  500.                FieldKeplerianAnomalyUtility.ellipticTrueToMean(e, v);
  501.     }

  502.     /** Get the mean anomaly derivative.
  503.      * <p>
  504.      * If the orbit was created without derivatives, the value returned is null.
  505.      * </p>
  506.      * @return mean anomaly derivative (rad/s)
  507.      */
  508.     public T getMeanAnomalyDot() {

  509.         if (!hasDerivatives()) {
  510.             return null;
  511.         }

  512.         final FieldUnivariateDerivative1<T> eUD = new FieldUnivariateDerivative1<>(e, eDot);
  513.         final FieldUnivariateDerivative1<T> vUD = new FieldUnivariateDerivative1<>(v, vDot);
  514.         final FieldUnivariateDerivative1<T> MUD = (a.getReal() < 0) ?
  515.                                                 FieldKeplerianAnomalyUtility.hyperbolicTrueToMean(eUD, vUD) :
  516.                                                 FieldKeplerianAnomalyUtility.ellipticTrueToMean(eUD, vUD);
  517.         return MUD.getDerivative(1);

  518.     }

  519.     /** Get the anomaly.
  520.      * @param type type of the angle
  521.      * @return anomaly (rad)
  522.      */
  523.     public T getAnomaly(final PositionAngleType type) {
  524.         return (type == PositionAngleType.MEAN) ? getMeanAnomaly() :
  525.                                               ((type == PositionAngleType.ECCENTRIC) ? getEccentricAnomaly() :
  526.                                                                                    getTrueAnomaly());
  527.     }

  528.     /** Get the anomaly derivative.
  529.      * <p>
  530.      * If the orbit was created without derivatives, the value returned is null.
  531.      * </p>
  532.      * @param type type of the angle
  533.      * @return anomaly derivative (rad/s)
  534.      */
  535.     public T getAnomalyDot(final PositionAngleType type) {
  536.         return (type == PositionAngleType.MEAN) ? getMeanAnomalyDot() :
  537.                                               ((type == PositionAngleType.ECCENTRIC) ? getEccentricAnomalyDot() :
  538.                                                                                    getTrueAnomalyDot());
  539.     }

  540.     /** {@inheritDoc} */
  541.     @Override
  542.     public boolean hasDerivatives() {
  543.         return aDot != null;
  544.     }

  545.     /** {@inheritDoc} */
  546.     public T getEquinoctialEx() {
  547.         return e.multiply(pa.add(raan).cos());
  548.     }

  549.     /** {@inheritDoc} */
  550.     public T getEquinoctialExDot() {

  551.         if (!hasDerivatives()) {
  552.             return null;
  553.         }

  554.         final FieldUnivariateDerivative1<T> eUD    = new FieldUnivariateDerivative1<>(e,    eDot);
  555.         final FieldUnivariateDerivative1<T> paUD   = new FieldUnivariateDerivative1<>(pa,   paDot);
  556.         final FieldUnivariateDerivative1<T> raanUD = new FieldUnivariateDerivative1<>(raan, raanDot);
  557.         return eUD.multiply(paUD.add(raanUD).cos()).getDerivative(1);

  558.     }

  559.     /** {@inheritDoc} */
  560.     public T getEquinoctialEy() {
  561.         return  e.multiply((pa.add(raan)).sin());
  562.     }

  563.     /** {@inheritDoc} */
  564.     public T getEquinoctialEyDot() {

  565.         if (!hasDerivatives()) {
  566.             return null;
  567.         }

  568.         final FieldUnivariateDerivative1<T> eUD    = new FieldUnivariateDerivative1<>(e,    eDot);
  569.         final FieldUnivariateDerivative1<T> paUD   = new FieldUnivariateDerivative1<>(pa,   paDot);
  570.         final FieldUnivariateDerivative1<T> raanUD = new FieldUnivariateDerivative1<>(raan, raanDot);
  571.         return eUD.multiply(paUD.add(raanUD).sin()).getDerivative(1);

  572.     }

  573.     /** {@inheritDoc} */
  574.     public T getHx() {
  575.         // Check for equatorial retrograde orbit
  576.         if (FastMath.abs(i.subtract(i.getPi()).getReal()) < 1.0e-10) {
  577.             return getZero().add(Double.NaN);
  578.         }
  579.         return  raan.cos().multiply(i.divide(2).tan());
  580.     }

  581.     /** {@inheritDoc} */
  582.     public T getHxDot() {

  583.         if (!hasDerivatives()) {
  584.             return null;
  585.         }

  586.         // Check for equatorial retrograde orbit
  587.         if (FastMath.abs(i.subtract(i.getPi()).getReal()) < 1.0e-10) {
  588.             return getZero().add(Double.NaN);
  589.         }

  590.         final FieldUnivariateDerivative1<T> iUD    = new FieldUnivariateDerivative1<>(i,    iDot);
  591.         final FieldUnivariateDerivative1<T> raanUD = new FieldUnivariateDerivative1<>(raan, raanDot);
  592.         return raanUD.cos().multiply(iUD.multiply(0.5).tan()).getDerivative(1);

  593.     }

  594.     /** {@inheritDoc} */
  595.     public T getHy() {
  596.         // Check for equatorial retrograde orbit
  597.         if (FastMath.abs(i.subtract(i.getPi()).getReal()) < 1.0e-10) {
  598.             return getZero().add(Double.NaN);
  599.         }
  600.         return  raan.sin().multiply(i.divide(2).tan());
  601.     }

  602.     /** {@inheritDoc} */
  603.     public T getHyDot() {

  604.         if (!hasDerivatives()) {
  605.             return null;
  606.         }

  607.         // Check for equatorial retrograde orbit
  608.         if (FastMath.abs(i.subtract(i.getPi()).getReal()) < 1.0e-10) {
  609.             return getZero().add(Double.NaN);
  610.         }

  611.         final FieldUnivariateDerivative1<T> iUD    = new FieldUnivariateDerivative1<>(i,    iDot);
  612.         final FieldUnivariateDerivative1<T> raanUD = new FieldUnivariateDerivative1<>(raan, raanDot);
  613.         return raanUD.sin().multiply(iUD.multiply(0.5).tan()).getDerivative(1);

  614.     }

  615.     /** {@inheritDoc} */
  616.     public T getLv() {
  617.         return pa.add(raan).add(v);
  618.     }

  619.     /** {@inheritDoc} */
  620.     public T getLvDot() {
  621.         return hasDerivatives() ?
  622.                paDot.add(raanDot).add(vDot) :
  623.                null;
  624.     }

  625.     /** {@inheritDoc} */
  626.     public T getLE() {
  627.         return pa.add(raan).add(getEccentricAnomaly());
  628.     }

  629.     /** {@inheritDoc} */
  630.     public T getLEDot() {
  631.         return hasDerivatives() ?
  632.                paDot.add(raanDot).add(getEccentricAnomalyDot()) :
  633.                null;
  634.     }

  635.     /** {@inheritDoc} */
  636.     public T getLM() {
  637.         return pa.add(raan).add(getMeanAnomaly());
  638.     }

  639.     /** {@inheritDoc} */
  640.     public T getLMDot() {
  641.         return hasDerivatives() ?
  642.                paDot.add(raanDot).add(getMeanAnomalyDot()) :
  643.                null;
  644.     }

  645.     /** Compute reference axes.
  646.      * @return referecne axes
  647.      * @since 12.0
  648.      */
  649.     private FieldVector3D<T>[] referenceAxes() {

  650.         // preliminary variables
  651.         final FieldSinCos<T> scRaan = FastMath.sinCos(raan);
  652.         final FieldSinCos<T> scPa   = FastMath.sinCos(pa);
  653.         final FieldSinCos<T> scI    = FastMath.sinCos(i);
  654.         final T cosRaan = scRaan.cos();
  655.         final T sinRaan = scRaan.sin();
  656.         final T cosPa   = scPa.cos();
  657.         final T sinPa   = scPa.sin();
  658.         final T cosI    = scI.cos();
  659.         final T sinI    = scI.sin();
  660.         final T crcp    = cosRaan.multiply(cosPa);
  661.         final T crsp    = cosRaan.multiply(sinPa);
  662.         final T srcp    = sinRaan.multiply(cosPa);
  663.         final T srsp    = sinRaan.multiply(sinPa);

  664.         // reference axes defining the orbital plane
  665.         @SuppressWarnings("unchecked")
  666.         final FieldVector3D<T>[] axes = (FieldVector3D<T>[]) Array.newInstance(FieldVector3D.class, 2);
  667.         axes[0] = new FieldVector3D<>(crcp.subtract(cosI.multiply(srsp)),  srcp.add(cosI.multiply(crsp)), sinI.multiply(sinPa));
  668.         axes[1] = new FieldVector3D<>(crsp.add(cosI.multiply(srcp)).negate(), cosI.multiply(crcp).subtract(srsp), sinI.multiply(cosPa));

  669.         return axes;

  670.     }

  671.     /** Compute position and velocity but not acceleration.
  672.      */
  673.     private void computePVWithoutA() {

  674.         if (partialPV != null) {
  675.             // already computed
  676.             return;
  677.         }

  678.         final FieldVector3D<T>[] axes = referenceAxes();

  679.         if (isElliptical()) {

  680.             // elliptical case

  681.             // elliptic eccentric anomaly
  682.             final T uME2             = e.negate().add(1).multiply(e.add(1));
  683.             final T s1Me2            = uME2.sqrt();
  684.             final FieldSinCos<T> scE = FastMath.sinCos(getEccentricAnomaly());
  685.             final T cosE             = scE.cos();
  686.             final T sinE             = scE.sin();

  687.             // coordinates of position and velocity in the orbital plane
  688.             final T x      = a.multiply(cosE.subtract(e));
  689.             final T y      = a.multiply(sinE).multiply(s1Me2);
  690.             final T factor = FastMath.sqrt(getMu().divide(a)).divide(e.negate().multiply(cosE).add(1));
  691.             final T xDot   = sinE.negate().multiply(factor);
  692.             final T yDot   = cosE.multiply(s1Me2).multiply(factor);

  693.             final FieldVector3D<T> position = new FieldVector3D<>(x, axes[0], y, axes[1]);
  694.             final FieldVector3D<T> velocity = new FieldVector3D<>(xDot, axes[0], yDot, axes[1]);
  695.             partialPV = new FieldPVCoordinates<>(position, velocity);

  696.         } else {

  697.             // hyperbolic case

  698.             // compute position and velocity factors
  699.             final FieldSinCos<T> scV = FastMath.sinCos(v);
  700.             final T sinV             = scV.sin();
  701.             final T cosV             = scV.cos();
  702.             final T f                = a.multiply(e.multiply(e).negate().add(1));
  703.             final T posFactor        = f.divide(e.multiply(cosV).add(1));
  704.             final T velFactor        = FastMath.sqrt(getMu().divide(f));

  705.             final FieldVector3D<T> position     = new FieldVector3D<>(posFactor.multiply(cosV), axes[0], posFactor.multiply(sinV), axes[1]);
  706.             final FieldVector3D<T> velocity     = new FieldVector3D<>(velFactor.multiply(sinV).negate(), axes[0], velFactor.multiply(e.add(cosV)), axes[1]);
  707.             partialPV = new FieldPVCoordinates<>(position, velocity);

  708.         }

  709.     }

  710.     /** Compute non-Keplerian part of the acceleration from first time derivatives.
  711.      * <p>
  712.      * This method should be called only when {@link #hasDerivatives()} returns true.
  713.      * </p>
  714.      * @return non-Keplerian part of the acceleration
  715.      */
  716.     private FieldVector3D<T> nonKeplerianAcceleration() {

  717.         final T[][] dCdP = MathArrays.buildArray(a.getField(), 6, 6);
  718.         getJacobianWrtParameters(PositionAngleType.MEAN, dCdP);

  719.         final T nonKeplerianMeanMotion = getMeanAnomalyDot().subtract(getKeplerianMeanMotion());
  720.         final T nonKeplerianAx =     dCdP[3][0].multiply(aDot).
  721.                                  add(dCdP[3][1].multiply(eDot)).
  722.                                  add(dCdP[3][2].multiply(iDot)).
  723.                                  add(dCdP[3][3].multiply(paDot)).
  724.                                  add(dCdP[3][4].multiply(raanDot)).
  725.                                  add(dCdP[3][5].multiply(nonKeplerianMeanMotion));
  726.         final T nonKeplerianAy =     dCdP[4][0].multiply(aDot).
  727.                                  add(dCdP[4][1].multiply(eDot)).
  728.                                  add(dCdP[4][2].multiply(iDot)).
  729.                                  add(dCdP[4][3].multiply(paDot)).
  730.                                  add(dCdP[4][4].multiply(raanDot)).
  731.                                  add(dCdP[4][5].multiply(nonKeplerianMeanMotion));
  732.         final T nonKeplerianAz =     dCdP[5][0].multiply(aDot).
  733.                                  add(dCdP[5][1].multiply(eDot)).
  734.                                  add(dCdP[5][2].multiply(iDot)).
  735.                                  add(dCdP[5][3].multiply(paDot)).
  736.                                  add(dCdP[5][4].multiply(raanDot)).
  737.                                  add(dCdP[5][5].multiply(nonKeplerianMeanMotion));

  738.         return new FieldVector3D<>(nonKeplerianAx, nonKeplerianAy, nonKeplerianAz);

  739.     }

  740.     /** {@inheritDoc} */
  741.     protected FieldVector3D<T> initPosition() {
  742.         final FieldVector3D<T>[] axes = referenceAxes();

  743.         if (isElliptical()) {

  744.             // elliptical case

  745.             // elliptic eccentric anomaly
  746.             final T uME2             = e.negate().add(1).multiply(e.add(1));
  747.             final T s1Me2            = uME2.sqrt();
  748.             final FieldSinCos<T> scE = FastMath.sinCos(getEccentricAnomaly());
  749.             final T cosE             = scE.cos();
  750.             final T sinE             = scE.sin();

  751.             return new FieldVector3D<>(a.multiply(cosE.subtract(e)), axes[0], a.multiply(sinE).multiply(s1Me2), axes[1]);

  752.         } else {

  753.             // hyperbolic case

  754.             // compute position and velocity factors
  755.             final FieldSinCos<T> scV = FastMath.sinCos(v);
  756.             final T sinV             = scV.sin();
  757.             final T cosV             = scV.cos();
  758.             final T f                = a.multiply(e.multiply(e).negate().add(1));
  759.             final T posFactor        = f.divide(e.multiply(cosV).add(1));

  760.             return new FieldVector3D<>(posFactor.multiply(cosV), axes[0], posFactor.multiply(sinV), axes[1]);

  761.         }

  762.     }

  763.     /** {@inheritDoc} */
  764.     protected TimeStampedFieldPVCoordinates<T> initPVCoordinates() {

  765.         // position and velocity
  766.         computePVWithoutA();

  767.         // acceleration
  768.         final T r2 = partialPV.getPosition().getNormSq();
  769.         final FieldVector3D<T> keplerianAcceleration = new FieldVector3D<>(r2.multiply(FastMath.sqrt(r2)).reciprocal().multiply(getMu().negate()),
  770.                                                                            partialPV.getPosition());
  771.         final FieldVector3D<T> acceleration = hasDerivatives() ?
  772.                                               keplerianAcceleration.add(nonKeplerianAcceleration()) :
  773.                                               keplerianAcceleration;

  774.         return new TimeStampedFieldPVCoordinates<>(getDate(), partialPV.getPosition(), partialPV.getVelocity(), acceleration);

  775.     }

  776.     /** {@inheritDoc} */
  777.     public FieldKeplerianOrbit<T> shiftedBy(final double dt) {
  778.         return shiftedBy(getZero().add(dt));
  779.     }

  780.     /** {@inheritDoc} */
  781.     public FieldKeplerianOrbit<T> shiftedBy(final T dt) {

  782.         // use Keplerian-only motion
  783.         final FieldKeplerianOrbit<T> keplerianShifted = new FieldKeplerianOrbit<>(a, e, i, pa, raan,
  784.                                                                                   getKeplerianMeanMotion().multiply(dt).add(getMeanAnomaly()),
  785.                                                                                   PositionAngleType.MEAN, getFrame(), getDate().shiftedBy(dt), getMu());

  786.         if (hasDerivatives()) {

  787.             // extract non-Keplerian acceleration from first time derivatives
  788.             final FieldVector3D<T> nonKeplerianAcceleration = nonKeplerianAcceleration();

  789.             // add quadratic effect of non-Keplerian acceleration to Keplerian-only shift
  790.             keplerianShifted.computePVWithoutA();
  791.             final FieldVector3D<T> fixedP   = new FieldVector3D<>(getOne(), keplerianShifted.partialPV.getPosition(),
  792.                                                                   dt.multiply(dt).multiply(0.5), nonKeplerianAcceleration);
  793.             final T   fixedR2 = fixedP.getNormSq();
  794.             final T   fixedR  = fixedR2.sqrt();
  795.             final FieldVector3D<T> fixedV  = new FieldVector3D<>(getOne(), keplerianShifted.partialPV.getVelocity(),
  796.                                                                  dt, nonKeplerianAcceleration);
  797.             final FieldVector3D<T> fixedA  = new FieldVector3D<>(fixedR2.multiply(fixedR).reciprocal().multiply(getMu().negate()),
  798.                                                                  keplerianShifted.partialPV.getPosition(),
  799.                                                                  getOne(), nonKeplerianAcceleration);

  800.             // build a new orbit, taking non-Keplerian acceleration into account
  801.             return new FieldKeplerianOrbit<>(new TimeStampedFieldPVCoordinates<>(keplerianShifted.getDate(),
  802.                                                                                  fixedP, fixedV, fixedA),
  803.                                              keplerianShifted.getFrame(), keplerianShifted.getMu());

  804.         } else {
  805.             // Keplerian-only motion is all we can do
  806.             return keplerianShifted;
  807.         }

  808.     }

  809.     /** {@inheritDoc} */
  810.     protected T[][] computeJacobianMeanWrtCartesian() {
  811.         if (isElliptical()) {
  812.             return computeJacobianMeanWrtCartesianElliptical();
  813.         } else {
  814.             return computeJacobianMeanWrtCartesianHyperbolic();
  815.         }
  816.     }

  817.     /** Compute the Jacobian of the orbital parameters with respect to the Cartesian parameters.
  818.      * <p>
  819.      * Element {@code jacobian[i][j]} is the derivative of parameter i of the orbit with
  820.      * respect to Cartesian coordinate j (x for j=0, y for j=1, z for j=2, xDot for j=3,
  821.      * yDot for j=4, zDot for j=5).
  822.      * </p>
  823.      * @return 6x6 Jacobian matrix
  824.      */
  825.     private T[][] computeJacobianMeanWrtCartesianElliptical() {

  826.         final T[][] jacobian = MathArrays.buildArray(getA().getField(), 6, 6);

  827.         // compute various intermediate parameters
  828.         computePVWithoutA();
  829.         final FieldVector3D<T> position = partialPV.getPosition();
  830.         final FieldVector3D<T> velocity = partialPV.getVelocity();
  831.         final FieldVector3D<T> momentum = partialPV.getMomentum();
  832.         final T v2         = velocity.getNormSq();
  833.         final T r2         = position.getNormSq();
  834.         final T r          = r2.sqrt();
  835.         final T r3         = r.multiply(r2);

  836.         final T px         = position.getX();
  837.         final T py         = position.getY();
  838.         final T pz         = position.getZ();
  839.         final T vx         = velocity.getX();
  840.         final T vy         = velocity.getY();
  841.         final T vz         = velocity.getZ();
  842.         final T mx         = momentum.getX();
  843.         final T my         = momentum.getY();
  844.         final T mz         = momentum.getZ();

  845.         final T mu         = getMu();
  846.         final T sqrtMuA    = FastMath.sqrt(a.multiply(mu));
  847.         final T sqrtAoMu   = FastMath.sqrt(a.divide(mu));
  848.         final T a2         = a.multiply(a);
  849.         final T twoA       = a.multiply(2);
  850.         final T rOnA       = r.divide(a);

  851.         final T oMe2       = e.multiply(e).negate().add(1);
  852.         final T epsilon    = oMe2.sqrt();
  853.         final T sqrtRec    = epsilon.reciprocal();

  854.         final FieldSinCos<T> scI  = FastMath.sinCos(i);
  855.         final FieldSinCos<T> scPA = FastMath.sinCos(pa);
  856.         final T cosI       = scI.cos();
  857.         final T sinI       = scI.sin();
  858.         final T cosPA      = scPA.cos();
  859.         final T sinPA      = scPA.sin();

  860.         final T pv         = FieldVector3D.dotProduct(position, velocity);
  861.         final T cosE       = a.subtract(r).divide(a.multiply(e));
  862.         final T sinE       = pv.divide(e.multiply(sqrtMuA));

  863.         // da
  864.         final FieldVector3D<T> vectorAR = new FieldVector3D<>(a2.multiply(2).divide(r3), position);
  865.         final FieldVector3D<T> vectorARDot = velocity.scalarMultiply(a2.multiply(mu.divide(2.).reciprocal()));
  866.         fillHalfRow(getOne(), vectorAR,    jacobian[0], 0);
  867.         fillHalfRow(getOne(), vectorARDot, jacobian[0], 3);

  868.         // de
  869.         final T factorER3 = pv.divide(twoA);
  870.         final FieldVector3D<T> vectorER   = new FieldVector3D<>(cosE.multiply(v2).divide(r.multiply(mu)), position,
  871.                                                                 sinE.divide(sqrtMuA), velocity,
  872.                                                                 factorER3.negate().multiply(sinE).divide(sqrtMuA), vectorAR);
  873.         final FieldVector3D<T> vectorERDot = new FieldVector3D<>(sinE.divide(sqrtMuA), position,
  874.                                                                  cosE.multiply(mu.divide(2.).reciprocal()).multiply(r), velocity,
  875.                                                                  factorER3.negate().multiply(sinE).divide(sqrtMuA), vectorARDot);
  876.         fillHalfRow(getOne(), vectorER,    jacobian[1], 0);
  877.         fillHalfRow(getOne(), vectorERDot, jacobian[1], 3);

  878.         // dE / dr (Eccentric anomaly)
  879.         final T coefE = cosE.divide(e.multiply(sqrtMuA));
  880.         final FieldVector3D<T>  vectorEAnR =
  881.             new FieldVector3D<>(sinE.negate().multiply(v2).divide(e.multiply(r).multiply(mu)), position, coefE, velocity,
  882.                                 factorER3.negate().multiply(coefE), vectorAR);

  883.         // dE / drDot
  884.         final FieldVector3D<T>  vectorEAnRDot =
  885.             new FieldVector3D<>(sinE.multiply(-2).multiply(r).divide(e.multiply(mu)), velocity, coefE, position,
  886.                                 factorER3.negate().multiply(coefE), vectorARDot);

  887.         // precomputing some more factors
  888.         final T s1 = sinE.negate().multiply(pz).divide(r).subtract(cosE.multiply(vz).multiply(sqrtAoMu));
  889.         final T s2 = cosE.negate().multiply(pz).divide(r3);
  890.         final T s3 = sinE.multiply(vz).divide(sqrtMuA.multiply(-2));
  891.         final T t1 = sqrtRec.multiply(cosE.multiply(pz).divide(r).subtract(sinE.multiply(vz).multiply(sqrtAoMu)));
  892.         final T t2 = sqrtRec.multiply(sinE.negate().multiply(pz).divide(r3));
  893.         final T t3 = sqrtRec.multiply(cosE.subtract(e)).multiply(vz).divide(sqrtMuA.multiply(2));
  894.         final T t4 = sqrtRec.multiply(e.multiply(sinI).multiply(cosPA).multiply(sqrtRec).subtract(vz.multiply(sqrtAoMu)));
  895.         final FieldVector3D<T> s = new FieldVector3D<>(cosE.divide(r), this.PLUS_K,
  896.                                                        s1,       vectorEAnR,
  897.                                                        s2,       position,
  898.                                                        s3,       vectorAR);
  899.         final FieldVector3D<T> sDot = new FieldVector3D<>(sinE.negate().multiply(sqrtAoMu), this.PLUS_K,
  900.                                                           s1,               vectorEAnRDot,
  901.                                                           s3,               vectorARDot);
  902.         final FieldVector3D<T> t =
  903.             new FieldVector3D<>(sqrtRec.multiply(sinE).divide(r), this.PLUS_K).add(new FieldVector3D<>(t1, vectorEAnR,
  904.                                                                                                        t2, position,
  905.                                                                                                        t3, vectorAR,
  906.                                                                                                        t4, vectorER));
  907.         final FieldVector3D<T> tDot = new FieldVector3D<>(sqrtRec.multiply(cosE.subtract(e)).multiply(sqrtAoMu), this.PLUS_K,
  908.                                                           t1,                                                    vectorEAnRDot,
  909.                                                           t3,                                                    vectorARDot,
  910.                                                           t4,                                                    vectorERDot);

  911.         // di
  912.         final T factorI1 = sinI.negate().multiply(sqrtRec).divide(sqrtMuA);
  913.         final T i1 =  factorI1;
  914.         final T i2 =  factorI1.negate().multiply(mz).divide(twoA);
  915.         final T i3 =  factorI1.multiply(mz).multiply(e).divide(oMe2);
  916.         final T i4 = cosI.multiply(sinPA);
  917.         final T i5 = cosI.multiply(cosPA);
  918.         fillHalfRow(i1, new FieldVector3D<>(vy, vx.negate(), getZero()), i2, vectorAR, i3, vectorER, i4, s, i5, t,
  919.                     jacobian[2], 0);
  920.         fillHalfRow(i1, new FieldVector3D<>(py.negate(), px, getZero()), i2, vectorARDot, i3, vectorERDot, i4, sDot, i5, tDot,
  921.                     jacobian[2], 3);

  922.         // dpa
  923.         fillHalfRow(cosPA.divide(sinI), s,    sinPA.negate().divide(sinI), t,    jacobian[3], 0);
  924.         fillHalfRow(cosPA.divide(sinI), sDot, sinPA.negate().divide(sinI), tDot, jacobian[3], 3);

  925.         // dRaan
  926.         final T factorRaanR = (a.multiply(mu).multiply(oMe2).multiply(sinI).multiply(sinI)).reciprocal();
  927.         fillHalfRow( factorRaanR.negate().multiply(my), new FieldVector3D<>(getZero(), vz, vy.negate()),
  928.                      factorRaanR.multiply(mx), new FieldVector3D<>(vz.negate(), getZero(),  vx),
  929.                      jacobian[4], 0);
  930.         fillHalfRow(factorRaanR.negate().multiply(my), new FieldVector3D<>(getZero(), pz.negate(),  py),
  931.                      factorRaanR.multiply(mx), new FieldVector3D<>(pz, getZero(), px.negate()),
  932.                      jacobian[4], 3);

  933.         // dM
  934.         fillHalfRow(rOnA, vectorEAnR,    sinE.negate(), vectorER,    jacobian[5], 0);
  935.         fillHalfRow(rOnA, vectorEAnRDot, sinE.negate(), vectorERDot, jacobian[5], 3);

  936.         return jacobian;

  937.     }

  938.     /** Compute the Jacobian of the orbital parameters with respect to the Cartesian parameters.
  939.      * <p>
  940.      * Element {@code jacobian[i][j]} is the derivative of parameter i of the orbit with
  941.      * respect to Cartesian coordinate j (x for j=0, y for j=1, z for j=2, xDot for j=3,
  942.      * yDot for j=4, zDot for j=5).
  943.      * </p>
  944.      * @return 6x6 Jacobian matrix
  945.      */
  946.     private T[][] computeJacobianMeanWrtCartesianHyperbolic() {

  947.         final T[][] jacobian = MathArrays.buildArray(getA().getField(), 6, 6);

  948.         // compute various intermediate parameters
  949.         computePVWithoutA();
  950.         final FieldVector3D<T> position = partialPV.getPosition();
  951.         final FieldVector3D<T> velocity = partialPV.getVelocity();
  952.         final FieldVector3D<T> momentum = partialPV.getMomentum();
  953.         final T r2         = position.getNormSq();
  954.         final T r          = r2.sqrt();
  955.         final T r3         = r.multiply(r2);

  956.         final T x          = position.getX();
  957.         final T y          = position.getY();
  958.         final T z          = position.getZ();
  959.         final T vx         = velocity.getX();
  960.         final T vy         = velocity.getY();
  961.         final T vz         = velocity.getZ();
  962.         final T mx         = momentum.getX();
  963.         final T my         = momentum.getY();
  964.         final T mz         = momentum.getZ();

  965.         final T mu         = getMu();
  966.         final T absA       = a.negate();
  967.         final T sqrtMuA    = absA.multiply(mu).sqrt();
  968.         final T a2         = a.multiply(a);
  969.         final T rOa        = r.divide(absA);

  970.         final FieldSinCos<T> scI = FastMath.sinCos(i);
  971.         final T cosI       = scI.cos();
  972.         final T sinI       = scI.sin();

  973.         final T pv         = FieldVector3D.dotProduct(position, velocity);

  974.         // da
  975.         final FieldVector3D<T> vectorAR = new FieldVector3D<>(a2.multiply(-2).divide(r3), position);
  976.         final FieldVector3D<T> vectorARDot = velocity.scalarMultiply(a2.multiply(-2).divide(mu));
  977.         fillHalfRow(getOne().negate(), vectorAR,    jacobian[0], 0);
  978.         fillHalfRow(getOne().negate(), vectorARDot, jacobian[0], 3);

  979.         // differentials of the momentum
  980.         final T m      = momentum.getNorm();
  981.         final T oOm    = m.reciprocal();
  982.         final FieldVector3D<T> dcXP = new FieldVector3D<>(getZero(), vz, vy.negate());
  983.         final FieldVector3D<T> dcYP = new FieldVector3D<>(vz.negate(),   getZero(),  vx);
  984.         final FieldVector3D<T> dcZP = new FieldVector3D<>( vy, vx.negate(),   getZero());
  985.         final FieldVector3D<T> dcXV = new FieldVector3D<>(  getZero(),  z.negate(),   y);
  986.         final FieldVector3D<T> dcYV = new FieldVector3D<>(  z,   getZero(),  x.negate());
  987.         final FieldVector3D<T> dcZV = new FieldVector3D<>( y.negate(),   x,   getZero());
  988.         final FieldVector3D<T> dCP  = new FieldVector3D<>(mx.multiply(oOm), dcXP, my.multiply(oOm), dcYP, mz.multiply(oOm), dcZP);
  989.         final FieldVector3D<T> dCV  = new FieldVector3D<>(mx.multiply(oOm), dcXV, my.multiply(oOm), dcYV, mz.multiply(oOm), dcZV);

  990.         // dp
  991.         final T mOMu   = m.divide(mu);
  992.         final FieldVector3D<T> dpP  = new FieldVector3D<>(mOMu.multiply(2), dCP);
  993.         final FieldVector3D<T> dpV  = new FieldVector3D<>(mOMu.multiply(2), dCV);

  994.         // de
  995.         final T p      = m.multiply(mOMu);
  996.         final T moO2ae = absA.multiply(2).multiply(e).reciprocal();
  997.         final T m2OaMu = p.negate().divide(absA);
  998.         fillHalfRow(moO2ae, dpP, m2OaMu.multiply(moO2ae), vectorAR,    jacobian[1], 0);
  999.         fillHalfRow(moO2ae, dpV, m2OaMu.multiply(moO2ae), vectorARDot, jacobian[1], 3);

  1000.         // di
  1001.         final T cI1 = m.multiply(sinI).reciprocal();
  1002.         final T cI2 = cosI.multiply(cI1);
  1003.         fillHalfRow(cI2, dCP, cI1.negate(), dcZP, jacobian[2], 0);
  1004.         fillHalfRow(cI2, dCV, cI1.negate(), dcZV, jacobian[2], 3);


  1005.         // dPA
  1006.         final T cP1     =  y.multiply(oOm);
  1007.         final T cP2     =  x.negate().multiply(oOm);
  1008.         final T cP3     =  mx.multiply(cP1).add(my.multiply(cP2)).negate();
  1009.         final T cP4     =  cP3.multiply(oOm);
  1010.         final T cP5     =  r2.multiply(sinI).multiply(sinI).negate().reciprocal();
  1011.         final T cP6     = z.multiply(cP5);
  1012.         final T cP7     = cP3.multiply(cP5);
  1013.         final FieldVector3D<T> dacP  = new FieldVector3D<>(cP1, dcXP, cP2, dcYP, cP4, dCP, oOm, new FieldVector3D<>(my.negate(), mx, getZero()));
  1014.         final FieldVector3D<T> dacV  = new FieldVector3D<>(cP1, dcXV, cP2, dcYV, cP4, dCV);
  1015.         final FieldVector3D<T> dpoP  = new FieldVector3D<>(cP6, dacP, cP7, this.PLUS_K);
  1016.         final FieldVector3D<T> dpoV  = new FieldVector3D<>(cP6, dacV);

  1017.         final T re2     = r2.multiply(e).multiply(e);
  1018.         final T recOre2 = p.subtract(r).divide(re2);
  1019.         final T resOre2 = pv.multiply(mOMu).divide(re2);
  1020.         final FieldVector3D<T> dreP  = new FieldVector3D<>(mOMu, velocity, pv.divide(mu), dCP);
  1021.         final FieldVector3D<T> dreV  = new FieldVector3D<>(mOMu, position, pv.divide(mu), dCV);
  1022.         final FieldVector3D<T> davP  = new FieldVector3D<>(resOre2.negate(), dpP, recOre2, dreP, resOre2.divide(r), position);
  1023.         final FieldVector3D<T> davV  = new FieldVector3D<>(resOre2.negate(), dpV, recOre2, dreV);
  1024.         fillHalfRow(getOne(), dpoP, getOne().negate(), davP, jacobian[3], 0);
  1025.         fillHalfRow(getOne(), dpoV, getOne().negate(), davV, jacobian[3], 3);

  1026.         // dRAAN
  1027.         final T cO0 = cI1.multiply(cI1);
  1028.         final T cO1 =  mx.multiply(cO0);
  1029.         final T cO2 =  my.negate().multiply(cO0);
  1030.         fillHalfRow(cO1, dcYP, cO2, dcXP, jacobian[4], 0);
  1031.         fillHalfRow(cO1, dcYV, cO2, dcXV, jacobian[4], 3);

  1032.         // dM
  1033.         final T s2a    = pv.divide(absA.multiply(2));
  1034.         final T oObux  = m.multiply(m).add(absA.multiply(mu)).sqrt().reciprocal();
  1035.         final T scasbu = pv.multiply(oObux);
  1036.         final FieldVector3D<T> dauP = new FieldVector3D<>(sqrtMuA.reciprocal(), velocity, s2a.negate().divide(sqrtMuA), vectorAR);
  1037.         final FieldVector3D<T> dauV = new FieldVector3D<>(sqrtMuA.reciprocal(), position, s2a.negate().divide(sqrtMuA), vectorARDot);
  1038.         final FieldVector3D<T> dbuP = new FieldVector3D<>(oObux.multiply(mu.divide(2.)), vectorAR,    m.multiply(oObux), dCP);
  1039.         final FieldVector3D<T> dbuV = new FieldVector3D<>(oObux.multiply(mu.divide(2.)), vectorARDot, m.multiply(oObux), dCV);
  1040.         final FieldVector3D<T> dcuP = new FieldVector3D<>(oObux, velocity, scasbu.negate().multiply(oObux), dbuP);
  1041.         final FieldVector3D<T> dcuV = new FieldVector3D<>(oObux, position, scasbu.negate().multiply(oObux), dbuV);
  1042.         fillHalfRow(getOne(), dauP, e.negate().divide(rOa.add(1)), dcuP, jacobian[5], 0);
  1043.         fillHalfRow(getOne(), dauV, e.negate().divide(rOa.add(1)), dcuV, jacobian[5], 3);

  1044.         return jacobian;

  1045.     }

  1046.     /** {@inheritDoc} */
  1047.     protected T[][] computeJacobianEccentricWrtCartesian() {
  1048.         if (isElliptical()) {
  1049.             return computeJacobianEccentricWrtCartesianElliptical();
  1050.         } else {
  1051.             return computeJacobianEccentricWrtCartesianHyperbolic();
  1052.         }
  1053.     }

  1054.     /** Compute the Jacobian of the orbital parameters with respect to the Cartesian parameters.
  1055.      * <p>
  1056.      * Element {@code jacobian[i][j]} is the derivative of parameter i of the orbit with
  1057.      * respect to Cartesian coordinate j (x for j=0, y for j=1, z for j=2, xDot for j=3,
  1058.      * yDot for j=4, zDot for j=5).
  1059.      * </p>
  1060.      * @return 6x6 Jacobian matrix
  1061.      */
  1062.     private T[][] computeJacobianEccentricWrtCartesianElliptical() {

  1063.         // start by computing the Jacobian with mean angle
  1064.         final T[][] jacobian = computeJacobianMeanWrtCartesianElliptical();

  1065.         // Differentiating the Kepler equation M = E - e sin E leads to:
  1066.         // dM = (1 - e cos E) dE - sin E de
  1067.         // which is inverted and rewritten as:
  1068.         // dE = a/r dM + sin E a/r de
  1069.         final FieldSinCos<T> scE = FastMath.sinCos(getEccentricAnomaly());
  1070.         final T aOr              = e.negate().multiply(scE.cos()).add(1).reciprocal();

  1071.         // update anomaly row
  1072.         final T[] eRow           = jacobian[1];
  1073.         final T[] anomalyRow     = jacobian[5];
  1074.         for (int j = 0; j < anomalyRow.length; ++j) {
  1075.             anomalyRow[j] = aOr.multiply(anomalyRow[j].add(scE.sin().multiply(eRow[j])));
  1076.         }

  1077.         return jacobian;

  1078.     }

  1079.     /** Compute the Jacobian of the orbital parameters with respect to the Cartesian parameters.
  1080.      * <p>
  1081.      * Element {@code jacobian[i][j]} is the derivative of parameter i of the orbit with
  1082.      * respect to Cartesian coordinate j (x for j=0, y for j=1, z for j=2, xDot for j=3,
  1083.      * yDot for j=4, zDot for j=5).
  1084.      * </p>
  1085.      * @return 6x6 Jacobian matrix
  1086.      */
  1087.     private T[][] computeJacobianEccentricWrtCartesianHyperbolic() {

  1088.         // start by computing the Jacobian with mean angle
  1089.         final T[][] jacobian = computeJacobianMeanWrtCartesianHyperbolic();

  1090.         // Differentiating the Kepler equation M = e sinh H - H leads to:
  1091.         // dM = (e cosh H - 1) dH + sinh H de
  1092.         // which is inverted and rewritten as:
  1093.         // dH = 1 / (e cosh H - 1) dM - sinh H / (e cosh H - 1) de
  1094.         final T H      = getEccentricAnomaly();
  1095.         final T coshH  = H.cosh();
  1096.         final T sinhH  = H.sinh();
  1097.         final T absaOr = e.multiply(coshH).subtract(1).reciprocal();
  1098.         // update anomaly row
  1099.         final T[] eRow       = jacobian[1];
  1100.         final T[] anomalyRow = jacobian[5];

  1101.         for (int j = 0; j < anomalyRow.length; ++j) {
  1102.             anomalyRow[j] = absaOr.multiply(anomalyRow[j].subtract(sinhH.multiply(eRow[j])));

  1103.         }

  1104.         return jacobian;

  1105.     }

  1106.     /** {@inheritDoc} */
  1107.     protected T[][] computeJacobianTrueWrtCartesian() {
  1108.         if (isElliptical()) {
  1109.             return computeJacobianTrueWrtCartesianElliptical();
  1110.         } else {
  1111.             return computeJacobianTrueWrtCartesianHyperbolic();
  1112.         }
  1113.     }

  1114.     /** Compute the Jacobian of the orbital parameters with respect to the Cartesian parameters.
  1115.      * <p>
  1116.      * Element {@code jacobian[i][j]} is the derivative of parameter i of the orbit with
  1117.      * respect to Cartesian coordinate j (x for j=0, y for j=1, z for j=2, xDot for j=3,
  1118.      * yDot for j=4, zDot for j=5).
  1119.      * </p>
  1120.      * @return 6x6 Jacobian matrix
  1121.      */
  1122.     private T[][] computeJacobianTrueWrtCartesianElliptical() {

  1123.         // start by computing the Jacobian with eccentric angle
  1124.         final T[][] jacobian = computeJacobianEccentricWrtCartesianElliptical();
  1125.         // Differentiating the eccentric anomaly equation sin E = sqrt(1-e^2) sin v / (1 + e cos v)
  1126.         // and using cos E = (e + cos v) / (1 + e cos v) to get rid of cos E leads to:
  1127.         // dE = [sqrt (1 - e^2) / (1 + e cos v)] dv - [sin E / (1 - e^2)] de
  1128.         // which is inverted and rewritten as:
  1129.         // dv = sqrt (1 - e^2) a/r dE + [sin E / sqrt (1 - e^2)] a/r de
  1130.         final T e2               = e.multiply(e);
  1131.         final T oMe2             = e2.negate().add(1);
  1132.         final T epsilon          = oMe2.sqrt();
  1133.         final FieldSinCos<T> scE = FastMath.sinCos(getEccentricAnomaly());
  1134.         final T aOr              = e.multiply(scE.cos()).negate().add(1).reciprocal();
  1135.         final T aFactor          = epsilon.multiply(aOr);
  1136.         final T eFactor          = scE.sin().multiply(aOr).divide(epsilon);

  1137.         // update anomaly row
  1138.         final T[] eRow           = jacobian[1];
  1139.         final T[] anomalyRow     = jacobian[5];
  1140.         for (int j = 0; j < anomalyRow.length; ++j) {
  1141.             anomalyRow[j] = aFactor.multiply(anomalyRow[j]).add(eFactor.multiply(eRow[j]));
  1142.         }
  1143.         return jacobian;

  1144.     }

  1145.     /** Compute the Jacobian of the orbital parameters with respect to the Cartesian parameters.
  1146.      * <p>
  1147.      * Element {@code jacobian[i][j]} is the derivative of parameter i of the orbit with
  1148.      * respect to Cartesian coordinate j (x for j=0, y for j=1, z for j=2, xDot for j=3,
  1149.      * yDot for j=4, zDot for j=5).
  1150.      * </p>
  1151.      * @return 6x6 Jacobian matrix
  1152.      */
  1153.     private T[][] computeJacobianTrueWrtCartesianHyperbolic() {

  1154.         // start by computing the Jacobian with eccentric angle
  1155.         final T[][] jacobian = computeJacobianEccentricWrtCartesianHyperbolic();

  1156.         // Differentiating the eccentric anomaly equation sinh H = sqrt(e^2-1) sin v / (1 + e cos v)
  1157.         // and using cosh H = (e + cos v) / (1 + e cos v) to get rid of cosh H leads to:
  1158.         // dH = [sqrt (e^2 - 1) / (1 + e cos v)] dv + [sinh H / (e^2 - 1)] de
  1159.         // which is inverted and rewritten as:
  1160.         // dv = sqrt (1 - e^2) a/r dH - [sinh H / sqrt (e^2 - 1)] a/r de
  1161.         final T e2       = e.multiply(e);
  1162.         final T e2Mo     = e2.subtract(1);
  1163.         final T epsilon  = e2Mo.sqrt();
  1164.         final T H        = getEccentricAnomaly();
  1165.         final T coshH    = H.cosh();
  1166.         final T sinhH    = H.sinh();
  1167.         final T aOr      = e.multiply(coshH).subtract(1).reciprocal();
  1168.         final T aFactor  = epsilon.multiply(aOr);
  1169.         final T eFactor  = sinhH .multiply(aOr).divide(epsilon);

  1170.         // update anomaly row
  1171.         final T[] eRow           = jacobian[1];
  1172.         final T[] anomalyRow     = jacobian[5];
  1173.         for (int j = 0; j < anomalyRow.length; ++j) {
  1174.             anomalyRow[j] = aFactor.multiply(anomalyRow[j]).subtract(eFactor.multiply(eRow[j]));
  1175.         }

  1176.         return jacobian;

  1177.     }

  1178.     /** {@inheritDoc} */
  1179.     public void addKeplerContribution(final PositionAngleType type, final T gm,
  1180.                                       final T[] pDot) {
  1181.         final T oMe2;
  1182.         final T ksi;
  1183.         final T absA = a.abs();
  1184.         final T n    = absA.reciprocal().multiply(gm).sqrt().divide(absA);
  1185.         switch (type) {
  1186.             case MEAN :
  1187.                 pDot[5] = pDot[5].add(n);
  1188.                 break;
  1189.             case ECCENTRIC :
  1190.                 oMe2 = e.multiply(e).negate().add(1).abs();
  1191.                 ksi  = e.multiply(v.cos()).add(1);
  1192.                 pDot[5] = pDot[5].add( n.multiply(ksi).divide(oMe2));
  1193.                 break;
  1194.             case TRUE :
  1195.                 oMe2 = e.multiply(e).negate().add(1).abs();
  1196.                 ksi  = e.multiply(v.cos()).add(1);
  1197.                 pDot[5] = pDot[5].add(n.multiply(ksi).multiply(ksi).divide(oMe2.multiply(oMe2.sqrt())));
  1198.                 break;
  1199.             default :
  1200.                 throw new OrekitInternalError(null);
  1201.         }
  1202.     }

  1203.     /**  Returns a string representation of this Keplerian parameters object.
  1204.      * @return a string representation of this object
  1205.      */
  1206.     public String toString() {
  1207.         return new StringBuilder().append("Keplerian parameters: ").append('{').
  1208.                                   append("a: ").append(a.getReal()).
  1209.                                   append("; e: ").append(e.getReal()).
  1210.                                   append("; i: ").append(FastMath.toDegrees(i.getReal())).
  1211.                                   append("; pa: ").append(FastMath.toDegrees(pa.getReal())).
  1212.                                   append("; raan: ").append(FastMath.toDegrees(raan.getReal())).
  1213.                                   append("; v: ").append(FastMath.toDegrees(v.getReal())).
  1214.                                   append(";}").toString();
  1215.     }

  1216.     /** {@inheritDoc} */
  1217.     @Override
  1218.     public PositionAngleType getCachedPositionAngleType() {
  1219.         return PositionAngleType.TRUE;
  1220.     }

  1221.     /** {@inheritDoc} */
  1222.     @Override
  1223.     public boolean hasRates() {
  1224.         return hasDerivatives();
  1225.     }

  1226.     /** {@inheritDoc} */
  1227.     @Override
  1228.     public FieldKeplerianOrbit<T> removeRates() {
  1229.         final PositionAngleType positionAngleType = getCachedPositionAngleType();
  1230.         return new FieldKeplerianOrbit<>(getA(), getE(), getI(), getPerigeeArgument(), getRightAscensionOfAscendingNode(),
  1231.                 getAnomaly(positionAngleType), positionAngleType, getFrame(), getDate(), getMu());
  1232.     }


  1233.     /** Check if the given parameter is within an acceptable range.
  1234.      * The bounds are inclusive: an exception is raised when either of those conditions are met:
  1235.      * <ul>
  1236.      *     <li>The parameter is strictly greater than upperBound</li>
  1237.      *     <li>The parameter is strictly lower than lowerBound</li>
  1238.      * </ul>
  1239.      * <p>
  1240.      * In either of these cases, an OrekitException is raised.
  1241.      * </p>
  1242.      * @param parameterName name of the parameter
  1243.      * @param parameter value of the parameter
  1244.      * @param lowerBound lower bound of the acceptable range (inclusive)
  1245.      * @param upperBound upper bound of the acceptable range (inclusive)
  1246.      */
  1247.     private void checkParameterRangeInclusive(final String parameterName, final double parameter,
  1248.                                               final double lowerBound, final double upperBound) {
  1249.         if (parameter < lowerBound || parameter > upperBound) {
  1250.             throw new OrekitException(OrekitMessages.INVALID_PARAMETER_RANGE, parameterName,
  1251.                                       parameter, lowerBound, upperBound);
  1252.         }
  1253.     }

  1254.     /** {@inheritDoc} */
  1255.     @Override
  1256.     public KeplerianOrbit toOrbit() {
  1257.         if (hasDerivatives()) {
  1258.             return new KeplerianOrbit(a.getReal(), e.getReal(), i.getReal(),
  1259.                                       pa.getReal(), raan.getReal(), v.getReal(),
  1260.                                       aDot.getReal(), eDot.getReal(), iDot.getReal(),
  1261.                                       paDot.getReal(), raanDot.getReal(), vDot.getReal(),
  1262.                                       PositionAngleType.TRUE,
  1263.                                       getFrame(), getDate().toAbsoluteDate(), getMu().getReal());
  1264.         } else {
  1265.             return new KeplerianOrbit(a.getReal(), e.getReal(), i.getReal(),
  1266.                                       pa.getReal(), raan.getReal(), v.getReal(),
  1267.                                       PositionAngleType.TRUE,
  1268.                                       getFrame(), getDate().toAbsoluteDate(), getMu().getReal());
  1269.         }
  1270.     }


  1271. }