FieldCircularOrbit.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 org.hipparchus.CalculusFieldElement;
  19. import org.hipparchus.Field;
  20. import org.hipparchus.analysis.differentiation.FieldUnivariateDerivative1;
  21. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  22. import org.hipparchus.util.FastMath;
  23. import org.hipparchus.util.FieldSinCos;
  24. import org.hipparchus.util.MathArrays;
  25. import org.orekit.errors.OrekitIllegalArgumentException;
  26. import org.orekit.errors.OrekitInternalError;
  27. import org.orekit.errors.OrekitMessages;
  28. import org.orekit.frames.Frame;
  29. import org.orekit.time.FieldAbsoluteDate;
  30. import org.orekit.utils.FieldPVCoordinates;
  31. import org.orekit.utils.TimeStampedFieldPVCoordinates;


  32. /**
  33.  * This class handles circular orbital parameters.

  34.  * <p>
  35.  * The parameters used internally are the circular elements which can be
  36.  * related to Keplerian elements as follows:
  37.  *   <ul>
  38.  *     <li>a</li>
  39.  *     <li>e<sub>x</sub> = e cos(ω)</li>
  40.  *     <li>e<sub>y</sub> = e sin(ω)</li>
  41.  *     <li>i</li>
  42.  *     <li>Ω</li>
  43.  *     <li>α<sub>v</sub> = v + ω</li>
  44.  *   </ul>
  45.  * where Ω stands for the Right Ascension of the Ascending Node and
  46.  * α<sub>v</sub> stands for the true latitude argument
  47.  * <p>
  48.  * The conversion equations from and to Keplerian elements given above hold only
  49.  * when both sides are unambiguously defined, i.e. when orbit is neither equatorial
  50.  * nor circular. When orbit is circular (but not equatorial), the circular
  51.  * parameters are still unambiguously defined whereas some Keplerian elements
  52.  * (more precisely ω and Ω) become ambiguous. When orbit is equatorial,
  53.  * neither the Keplerian nor the circular parameters can be defined unambiguously.
  54.  * {@link EquinoctialOrbit equinoctial orbits} is the recommended way to represent
  55.  * orbits.
  56.  * </p>
  57.  * <p>
  58.  * The instance <code>CircularOrbit</code> is guaranteed to be immutable.
  59.  * </p>
  60.  * @see    Orbit
  61.  * @see    KeplerianOrbit
  62.  * @see    CartesianOrbit
  63.  * @see    EquinoctialOrbit
  64.  * @author Luc Maisonobe
  65.  * @author Fabien Maussion
  66.  * @author V&eacute;ronique Pommier-Maurussane
  67.  * @since 9.0
  68.  * @param <T> type of the field elements
  69.  */

  70. public class FieldCircularOrbit<T extends CalculusFieldElement<T>> extends FieldOrbit<T> implements PositionAngleBased {

  71.     /** Semi-major axis (m). */
  72.     private final T a;

  73.     /** First component of the circular eccentricity vector. */
  74.     private final T ex;

  75.     /** Second component of the circular eccentricity vector. */
  76.     private final T ey;

  77.     /** Inclination (rad). */
  78.     private final T i;

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

  81.     /** Cached latitude argument (rad). */
  82.     private final T cachedAlpha;

  83.     /** Type of cached position angle (latitude argument). */
  84.     private final PositionAngleType cachedPositionAngleType;

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

  87.     /** First component of the circular eccentricity vector derivative. */
  88.     private final T exDot;

  89.     /** Second component of the circular eccentricity vector derivative. */
  90.     private final T eyDot;

  91.     /** Inclination derivative (rad/s). */
  92.     private final T iDot;

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

  95.     /** True latitude argument derivative (rad/s). */
  96.     private final T cachedAlphaDot;

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

  99.     /** Creates a new instance.
  100.      * @param a  semi-major axis (m)
  101.      * @param ex e cos(ω), first component of circular eccentricity vector
  102.      * @param ey e sin(ω), second component of circular eccentricity vector
  103.      * @param i inclination (rad)
  104.      * @param raan right ascension of ascending node (Ω, rad)
  105.      * @param alpha  an + ω, mean, eccentric or true latitude argument (rad)
  106.      * @param type type of latitude argument
  107.      * @param cachedPositionAngleType type of cached latitude argument
  108.      * @param frame the frame in which are defined the parameters
  109.      * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame})
  110.      * @param date date of the orbital parameters
  111.      * @param mu central attraction coefficient (m³/s²)
  112.      * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or
  113.      * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame}
  114.      * @since 12.1
  115.      */
  116.     public FieldCircularOrbit(final T a, final T ex, final T ey, final T i, final T raan,
  117.                               final T alpha, final PositionAngleType type,
  118.                               final PositionAngleType cachedPositionAngleType,
  119.                               final Frame frame, final FieldAbsoluteDate<T> date, final T mu)
  120.         throws IllegalArgumentException {
  121.         this(a, ex, ey, i, raan, alpha,
  122.              null, null, null, null, null, null,
  123.              type, cachedPositionAngleType, frame, date, mu);
  124.     }

  125.     /** Creates a new instance without derivatives and with cached position angle same as value inputted.
  126.      * @param a  semi-major axis (m)
  127.      * @param ex e cos(ω), first component of circular eccentricity vector
  128.      * @param ey e sin(ω), second component of circular eccentricity vector
  129.      * @param i inclination (rad)
  130.      * @param raan right ascension of ascending node (Ω, rad)
  131.      * @param alpha  an + ω, mean, eccentric or true latitude argument (rad)
  132.      * @param type type of latitude argument
  133.      * @param frame the frame in which are defined the parameters
  134.      * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame})
  135.      * @param date date of the orbital parameters
  136.      * @param mu central attraction coefficient (m³/s²)
  137.      * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or
  138.      * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame}
  139.      */
  140.     public FieldCircularOrbit(final T a, final T ex, final T ey, final T i, final T raan,
  141.                               final T alpha, final PositionAngleType type,
  142.                               final Frame frame, final FieldAbsoluteDate<T> date, final T mu)
  143.             throws IllegalArgumentException {
  144.         this(a, ex, ey, i, raan, alpha, type, type, frame, date, mu);
  145.     }

  146.     /** Creates a new instance.
  147.      * @param a  semi-major axis (m)
  148.      * @param ex e cos(ω), first component of circular eccentricity vector
  149.      * @param ey e sin(ω), second component of circular eccentricity vector
  150.      * @param i inclination (rad)
  151.      * @param raan right ascension of ascending node (Ω, rad)
  152.      * @param alpha  an + ω, mean, eccentric or true latitude argument (rad)
  153.      * @param aDot  semi-major axis derivative (m/s)
  154.      * @param exDot d(e cos(ω))/dt, first component of circular eccentricity vector derivative
  155.      * @param eyDot d(e sin(ω))/dt, second component of circular eccentricity vector derivative
  156.      * @param iDot inclination  derivative(rad/s)
  157.      * @param raanDot right ascension of ascending node derivative (rad/s)
  158.      * @param alphaDot  d(an + ω), mean, eccentric or true latitude argument derivative (rad/s)
  159.      * @param type type of latitude argument
  160.      * @param frame the frame in which are defined the parameters
  161.      * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame})
  162.      * @param date date of the orbital parameters
  163.      * @param mu central attraction coefficient (m³/s²)
  164.      * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or
  165.      * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame}
  166.      */
  167.     public FieldCircularOrbit(final T a, final T ex, final T ey,
  168.                               final T i, final T raan, final T alpha,
  169.                               final T aDot, final T exDot, final T eyDot,
  170.                               final T iDot, final T raanDot, final T alphaDot, final PositionAngleType type,
  171.                               final Frame frame, final FieldAbsoluteDate<T> date, final T mu)
  172.             throws IllegalArgumentException {
  173.         this(a, ex, ey, i, raan, alpha, aDot, exDot, eyDot, iDot, raanDot, alphaDot, type, type, frame, date, mu);
  174.     }

  175.     /** Creates a new instance.
  176.      * @param a  semi-major axis (m)
  177.      * @param ex e cos(ω), first component of circular eccentricity vector
  178.      * @param ey e sin(ω), second component of circular eccentricity vector
  179.      * @param i inclination (rad)
  180.      * @param raan right ascension of ascending node (Ω, rad)
  181.      * @param alpha  an + ω, mean, eccentric or true latitude argument (rad)
  182.      * @param aDot  semi-major axis derivative (m/s)
  183.      * @param exDot d(e cos(ω))/dt, first component of circular eccentricity vector derivative
  184.      * @param eyDot d(e sin(ω))/dt, second component of circular eccentricity vector derivative
  185.      * @param iDot inclination  derivative(rad/s)
  186.      * @param raanDot right ascension of ascending node derivative (rad/s)
  187.      * @param alphaDot  d(an + ω), mean, eccentric or true latitude argument derivative (rad/s)
  188.      * @param type type of latitude argument
  189.      * @param cachedPositionAngleType type of cached latitude argument
  190.      * @param frame the frame in which are defined the parameters
  191.      * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame})
  192.      * @param date date of the orbital parameters
  193.      * @param mu central attraction coefficient (m³/s²)
  194.      * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or
  195.      * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame}
  196.      * @since 12.1
  197.      */
  198.     public FieldCircularOrbit(final T a, final T ex, final T ey,
  199.                               final T i, final T raan, final T alpha,
  200.                               final T aDot, final T exDot, final T eyDot,
  201.                               final T iDot, final T raanDot, final T alphaDot,
  202.                               final PositionAngleType type, final PositionAngleType cachedPositionAngleType,
  203.                               final Frame frame, final FieldAbsoluteDate<T> date, final T mu)
  204.         throws IllegalArgumentException {
  205.         super(frame, date, mu);
  206.         if (ex.getReal() * ex.getReal() + ey.getReal() * ey.getReal() >= 1.0) {
  207.             throw new OrekitIllegalArgumentException(OrekitMessages.HYPERBOLIC_ORBIT_NOT_HANDLED_AS,
  208.                                                      getClass().getName());
  209.         }

  210.         this.a       =  a;
  211.         this.aDot    =  aDot;
  212.         this.ex      = ex;
  213.         this.exDot   = exDot;
  214.         this.ey      = ey;
  215.         this.eyDot   = eyDot;
  216.         this.i       = i;
  217.         this.iDot    = iDot;
  218.         this.raan    = raan;
  219.         this.raanDot = raanDot;
  220.         this.cachedPositionAngleType = cachedPositionAngleType;

  221.         if (hasDerivatives()) {
  222.             final FieldUnivariateDerivative1<T> alphaUD = initializeCachedAlpha(alpha, alphaDot, type);
  223.             this.cachedAlpha = alphaUD.getValue();
  224.             this.cachedAlphaDot = alphaUD.getFirstDerivative();
  225.         } else {
  226.             this.cachedAlpha = initializeCachedAlpha(alpha, type);
  227.             this.cachedAlphaDot = null;
  228.         }

  229.         partialPV   = null;

  230.     }

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

  250.         // compute semi-major axis
  251.         final FieldVector3D<T> pvP = pvCoordinates.getPosition();
  252.         final FieldVector3D<T> pvV = pvCoordinates.getVelocity();
  253.         final FieldVector3D<T> pvA = pvCoordinates.getAcceleration();
  254.         final T r2 = pvP.getNormSq();
  255.         final T r  = r2.sqrt();
  256.         final T V2 = pvV.getNormSq();
  257.         final T rV2OnMu = r.multiply(V2).divide(mu);

  258.         a = r.divide(rV2OnMu.negate().add(2));

  259.         if (!isElliptical()) {
  260.             throw new OrekitIllegalArgumentException(OrekitMessages.HYPERBOLIC_ORBIT_NOT_HANDLED_AS,
  261.                                                      getClass().getName());
  262.         }

  263.         // compute inclination
  264.         final FieldVector3D<T> momentum = pvCoordinates.getMomentum();
  265.         final FieldVector3D<T> plusK = FieldVector3D.getPlusK(r.getField());
  266.         i = FieldVector3D.angle(momentum, plusK);

  267.         // compute right ascension of ascending node
  268.         final FieldVector3D<T> node  = FieldVector3D.crossProduct(plusK, momentum);
  269.         raan = node.getY().atan2(node.getX());

  270.         // 2D-coordinates in the canonical frame
  271.         final FieldSinCos<T> scRaan = FastMath.sinCos(raan);
  272.         final FieldSinCos<T> scI    = FastMath.sinCos(i);
  273.         final T xP      = pvP.getX();
  274.         final T yP      = pvP.getY();
  275.         final T zP      = pvP.getZ();
  276.         final T x2      = (xP.multiply(scRaan.cos()).add(yP .multiply(scRaan.sin()))).divide(a);
  277.         final T y2      = (yP.multiply(scRaan.cos()).subtract(xP.multiply(scRaan.sin()))).multiply(scI.cos()).add(zP.multiply(scI.sin())).divide(a);

  278.         // compute eccentricity vector
  279.         final T eSE    = FieldVector3D.dotProduct(pvP, pvV).divide(a.multiply(mu).sqrt());
  280.         final T eCE    = rV2OnMu.subtract(1);
  281.         final T e2     = eCE.multiply(eCE).add(eSE.multiply(eSE));
  282.         final T f      = eCE.subtract(e2);
  283.         final T g      = eSE.multiply(e2.negate().add(1).sqrt());
  284.         final T aOnR   = a.divide(r);
  285.         final T a2OnR2 = aOnR.square();
  286.         ex = a2OnR2.multiply(f.multiply(x2).add(g.multiply(y2)));
  287.         ey = a2OnR2.multiply(f.multiply(y2).subtract(g.multiply(x2)));

  288.         // compute latitude argument
  289.         final T beta = (ex.multiply(ex).add(ey.multiply(ey)).negate().add(1)).sqrt().add(1).reciprocal();
  290.         cachedAlpha = FieldCircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, y2.add(ey).add(eSE.multiply(beta).multiply(ex)).atan2(x2.add(ex).subtract(eSE.multiply(beta).multiply(ey)))
  291.         );

  292.         partialPV = pvCoordinates;

  293.         if (hasNonKeplerianAcceleration(pvCoordinates, mu)) {
  294.             // we have a relevant acceleration, we can compute derivatives

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

  297.             final FieldVector3D<T> keplerianAcceleration    = new FieldVector3D<>(r.multiply(r2).reciprocal().multiply(mu.negate()), pvP);
  298.             final FieldVector3D<T> nonKeplerianAcceleration = pvA.subtract(keplerianAcceleration);
  299.             final T   aX                       = nonKeplerianAcceleration.getX();
  300.             final T   aY                       = nonKeplerianAcceleration.getY();
  301.             final T   aZ                       = nonKeplerianAcceleration.getZ();
  302.             aDot    = jacobian[0][3].multiply(aX).add(jacobian[0][4].multiply(aY)).add(jacobian[0][5].multiply(aZ));
  303.             exDot   = jacobian[1][3].multiply(aX).add(jacobian[1][4].multiply(aY)).add(jacobian[1][5].multiply(aZ));
  304.             eyDot   = jacobian[2][3].multiply(aX).add(jacobian[2][4].multiply(aY)).add(jacobian[2][5].multiply(aZ));
  305.             iDot    = jacobian[3][3].multiply(aX).add(jacobian[3][4].multiply(aY)).add(jacobian[3][5].multiply(aZ));
  306.             raanDot = jacobian[4][3].multiply(aX).add(jacobian[4][4].multiply(aY)).add(jacobian[4][5].multiply(aZ));

  307.             // in order to compute true anomaly derivative, we must compute
  308.             // mean anomaly derivative including Keplerian motion and convert to true anomaly
  309.             final T alphaMDot = getKeplerianMeanMotion().
  310.                                 add(jacobian[5][3].multiply(aX)).add(jacobian[5][4].multiply(aY)).add(jacobian[5][5].multiply(aZ));
  311.             final FieldUnivariateDerivative1<T> exUD     = new FieldUnivariateDerivative1<>(ex, exDot);
  312.             final FieldUnivariateDerivative1<T> eyUD     = new FieldUnivariateDerivative1<>(ey, eyDot);
  313.             final FieldUnivariateDerivative1<T> alphaMUD = new FieldUnivariateDerivative1<>(getAlphaM(), alphaMDot);
  314.             final FieldUnivariateDerivative1<T> alphavUD = FieldCircularLatitudeArgumentUtility.meanToTrue(exUD, eyUD, alphaMUD);
  315.             cachedAlphaDot = alphavUD.getFirstDerivative();

  316.         } else {
  317.             // acceleration is either almost zero or NaN,
  318.             // we assume acceleration was not known
  319.             // we don't set up derivatives
  320.             aDot      = null;
  321.             exDot     = null;
  322.             eyDot     = null;
  323.             iDot      = null;
  324.             raanDot   = null;
  325.             cachedAlphaDot = null;
  326.         }

  327.     }

  328.     /** Constructor from Cartesian parameters.
  329.      *
  330.      * <p> The acceleration provided in {@code FieldPVCoordinates} is accessible using
  331.      * {@link #getPVCoordinates()} and {@link #getPVCoordinates(Frame)}. All other methods
  332.      * use {@code mu} and the position to compute the acceleration, including
  333.      * {@link #shiftedBy(CalculusFieldElement)} and {@link #getPVCoordinates(FieldAbsoluteDate, Frame)}.
  334.      *
  335.      * @param PVCoordinates the {@link FieldPVCoordinates} in inertial frame
  336.      * @param frame the frame in which are defined the {@link FieldPVCoordinates}
  337.      * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame})
  338.      * @param date date of the orbital parameters
  339.      * @param mu central attraction coefficient (m³/s²)
  340.      * @exception IllegalArgumentException if frame is not a {@link
  341.      * Frame#isPseudoInertial pseudo-inertial frame}
  342.      */
  343.     public FieldCircularOrbit(final FieldPVCoordinates<T> PVCoordinates, final Frame frame,
  344.                               final FieldAbsoluteDate<T> date, final T mu)
  345.         throws IllegalArgumentException {
  346.         this(new TimeStampedFieldPVCoordinates<>(date, PVCoordinates), frame, mu);
  347.     }

  348.     /** Constructor from any kind of orbital parameters.
  349.      * @param op orbital parameters to copy
  350.      */
  351.     public FieldCircularOrbit(final FieldOrbit<T> op) {
  352.         super(op.getFrame(), op.getDate(), op.getMu());
  353.         a    = op.getA();
  354.         i    = op.getI();
  355.         final T hx = op.getHx();
  356.         final T hy = op.getHy();
  357.         final T h2 = hx.square().add(hy.square());
  358.         final T h  = h2.sqrt();
  359.         raan = hy.atan2(hx);
  360.         final FieldSinCos<T> scRaan = FastMath.sinCos(raan);
  361.         final T cosRaan = h.getReal() == 0 ? scRaan.cos() : hx.divide(h);
  362.         final T sinRaan = h.getReal() == 0 ? scRaan.sin() : hy.divide(h);
  363.         final T equiEx = op.getEquinoctialEx();
  364.         final T equiEy = op.getEquinoctialEy();
  365.         ex   = equiEx.multiply(cosRaan).add(equiEy.multiply(sinRaan));
  366.         ey   = equiEy.multiply(cosRaan).subtract(equiEx.multiply(sinRaan));
  367.         cachedPositionAngleType = PositionAngleType.TRUE;
  368.         cachedAlpha = op.getLv().subtract(raan);

  369.         if (op.hasDerivatives()) {
  370.             aDot      = op.getADot();
  371.             final T      hxDot = op.getHxDot();
  372.             final T      hyDot = op.getHyDot();
  373.             iDot      = cosRaan.multiply(hxDot).add(sinRaan.multiply(hyDot)).multiply(2).divide(h2.add(1));
  374.             raanDot   = hx.multiply(hyDot).subtract(hy.multiply(hxDot)).divide(h2);
  375.             final T equiExDot = op.getEquinoctialExDot();
  376.             final T equiEyDot = op.getEquinoctialEyDot();
  377.             exDot     = equiExDot.add(equiEy.multiply(raanDot)).multiply(cosRaan).
  378.                         add(equiEyDot.subtract(equiEx.multiply(raanDot)).multiply(sinRaan));
  379.             eyDot     = equiEyDot.subtract(equiEx.multiply(raanDot)).multiply(cosRaan).
  380.                         subtract(equiExDot.add(equiEy.multiply(raanDot)).multiply(sinRaan));
  381.             cachedAlphaDot = op.getLvDot().subtract(raanDot);
  382.         } else {
  383.             aDot      = null;
  384.             exDot     = null;
  385.             eyDot     = null;
  386.             iDot      = null;
  387.             raanDot   = null;
  388.             cachedAlphaDot = null;
  389.         }

  390.         partialPV = null;

  391.     }

  392.     /** Constructor from Field and CircularOrbit.
  393.      * <p>Build a FieldCircularOrbit from non-Field CircularOrbit.</p>
  394.      * @param field CalculusField to base object on
  395.      * @param op non-field orbit with only "constant" terms
  396.      * @since 12.0
  397.      */
  398.     public FieldCircularOrbit(final Field<T> field, final CircularOrbit op) {
  399.         super(op.getFrame(), new FieldAbsoluteDate<>(field, op.getDate()), field.getZero().newInstance(op.getMu()));

  400.         a    = getZero().newInstance(op.getA());
  401.         i    = getZero().newInstance(op.getI());
  402.         raan = getZero().newInstance(op.getRightAscensionOfAscendingNode());
  403.         ex   = getZero().newInstance(op.getCircularEx());
  404.         ey   = getZero().newInstance(op.getCircularEy());
  405.         cachedPositionAngleType = op.getCachedPositionAngleType();
  406.         cachedAlpha = getZero().newInstance(op.getAlpha(cachedPositionAngleType));

  407.         if (op.hasDerivatives()) {
  408.             aDot      = getZero().newInstance(op.getADot());
  409.             iDot      = getZero().newInstance(op.getIDot());
  410.             raanDot   = getZero().newInstance(op.getRightAscensionOfAscendingNodeDot());
  411.             exDot     = getZero().newInstance(op.getCircularExDot());
  412.             eyDot     = getZero().newInstance(op.getCircularEyDot());
  413.             cachedAlphaDot = getZero().newInstance(op.getAlphaDot(cachedPositionAngleType));
  414.         } else {
  415.             aDot      = null;
  416.             exDot     = null;
  417.             eyDot     = null;
  418.             iDot      = null;
  419.             raanDot   = null;
  420.             cachedAlphaDot = null;
  421.         }

  422.         partialPV = null;

  423.     }

  424.     /** Constructor from Field and Orbit.
  425.      * <p>Build a FieldCircularOrbit from any non-Field Orbit.</p>
  426.      * @param field CalculusField to base object on
  427.      * @param op non-field orbit with only "constant" terms
  428.      * @since 12.0
  429.      */
  430.     public FieldCircularOrbit(final Field<T> field, final Orbit op) {
  431.         this(field, (CircularOrbit) OrbitType.CIRCULAR.convertType(op));
  432.     }

  433.     /** {@inheritDoc} */
  434.     @Override
  435.     public OrbitType getType() {
  436.         return OrbitType.CIRCULAR;
  437.     }

  438.     /** {@inheritDoc} */
  439.     @Override
  440.     public T getA() {
  441.         return a;
  442.     }

  443.     /** {@inheritDoc} */
  444.     @Override
  445.     public T getADot() {
  446.         return aDot;
  447.     }

  448.     /** {@inheritDoc} */
  449.     @Override
  450.     public T getEquinoctialEx() {
  451.         final FieldSinCos<T> sc = FastMath.sinCos(raan);
  452.         return ex.multiply(sc.cos()).subtract(ey.multiply(sc.sin()));
  453.     }

  454.     /** {@inheritDoc} */
  455.     @Override
  456.     public T getEquinoctialExDot() {

  457.         if (!hasDerivatives()) {
  458.             return null;
  459.         }

  460.         final FieldSinCos<T> sc = FastMath.sinCos(raan);
  461.         return exDot.subtract(ey.multiply(raanDot)).multiply(sc.cos()).
  462.                subtract(eyDot.add(ex.multiply(raanDot)).multiply(sc.sin()));

  463.     }

  464.     /** {@inheritDoc} */
  465.     @Override
  466.     public T getEquinoctialEy() {
  467.         final FieldSinCos<T> sc = FastMath.sinCos(raan);
  468.         return ey.multiply(sc.cos()).add(ex.multiply(sc.sin()));
  469.     }

  470.     /** {@inheritDoc} */
  471.     @Override
  472.     public T getEquinoctialEyDot() {

  473.         if (!hasDerivatives()) {
  474.             return null;
  475.         }

  476.         final FieldSinCos<T> sc = FastMath.sinCos(raan);
  477.         return eyDot.add(ex.multiply(raanDot)).multiply(sc.cos()).
  478.                add(exDot.subtract(ey.multiply(raanDot)).multiply(sc.sin()));

  479.     }

  480.     /** Get the first component of the circular eccentricity vector.
  481.      * @return ex = e cos(ω), first component of the circular eccentricity vector
  482.      */
  483.     public T getCircularEx() {
  484.         return ex;
  485.     }

  486.     /** Get the first component of the circular eccentricity vector derivative.
  487.      * @return d(ex)/dt = d(e cos(ω))/dt, first component of the circular eccentricity vector derivative
  488.      */
  489.     public T getCircularExDot() {
  490.         return exDot;
  491.     }

  492.     /** Get the second component of the circular eccentricity vector.
  493.      * @return ey = e sin(ω), second component of the circular eccentricity vector
  494.      */
  495.     public T getCircularEy() {
  496.         return ey;
  497.     }

  498.     /** Get the second component of the circular eccentricity vector derivative.
  499.      * @return d(ey)/dt = d(e sin(ω))/dt, second component of the circular eccentricity vector derivative
  500.      */
  501.     public T getCircularEyDot() {
  502.         return eyDot;
  503.     }

  504.     /** {@inheritDoc} */
  505.     @Override
  506.     public T getHx() {
  507.         // Check for equatorial retrograde orbit
  508.         if (FastMath.abs(i.subtract(i.getPi()).getReal()) < 1.0e-10) {
  509.             return getZero().add(Double.NaN);
  510.         }
  511.         return raan.cos().multiply(i.divide(2).tan());
  512.     }

  513.     /** {@inheritDoc} */
  514.     @Override
  515.     public T getHxDot() {

  516.         if (!hasDerivatives()) {
  517.             return null;
  518.         }

  519.         // Check for equatorial retrograde orbit
  520.         if (FastMath.abs(i.subtract(i.getPi()).getReal()) < 1.0e-10) {
  521.             return getZero().add(Double.NaN);
  522.         }

  523.         final FieldSinCos<T> sc = FastMath.sinCos(raan);
  524.         final T tan             = i.multiply(0.5).tan();
  525.         return sc.cos().multiply(0.5).multiply(tan.multiply(tan).add(1)).multiply(iDot).
  526.                subtract(sc.sin().multiply(tan).multiply(raanDot));

  527.     }

  528.     /** {@inheritDoc} */
  529.     @Override
  530.     public T getHy() {
  531.         // Check for equatorial retrograde orbit
  532.         if (FastMath.abs(i.subtract(i.getPi()).getReal()) < 1.0e-10) {
  533.             return getZero().add(Double.NaN);
  534.         }
  535.         return raan.sin().multiply(i.divide(2).tan());
  536.     }

  537.     /** {@inheritDoc} */
  538.     @Override
  539.     public T getHyDot() {

  540.         if (!hasDerivatives()) {
  541.             return null;
  542.         }

  543.         // Check for equatorial retrograde orbit
  544.         if (FastMath.abs(i.subtract(i.getPi()).getReal()) < 1.0e-10) {
  545.             return getZero().add(Double.NaN);
  546.         }

  547.         final FieldSinCos<T> sc = FastMath.sinCos(raan);
  548.         final T tan     = i.multiply(0.5).tan();
  549.         return sc.sin().multiply(0.5).multiply(tan.multiply(tan).add(1)).multiply(iDot).
  550.                add(sc.cos().multiply(tan).multiply(raanDot));

  551.     }

  552.     /** Get the true latitude argument.
  553.      * @return v + ω true latitude argument (rad)
  554.      */
  555.     public T getAlphaV() {
  556.         switch (cachedPositionAngleType) {
  557.             case TRUE:
  558.                 return cachedAlpha;

  559.             case ECCENTRIC:
  560.                 return FieldCircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, cachedAlpha);

  561.             case MEAN:
  562.                 return FieldCircularLatitudeArgumentUtility.meanToTrue(ex, ey, cachedAlpha);

  563.             default:
  564.                 throw new OrekitInternalError(null);
  565.         }
  566.     }

  567.     /** Get the true latitude argument derivative.
  568.      * @return d(v + ω)/dt true latitude argument derivative (rad/s)
  569.      */
  570.     public T getAlphaVDot() {

  571.         if (!hasDerivatives()) {
  572.             return null;
  573.         }
  574.         switch (cachedPositionAngleType) {
  575.             case ECCENTRIC:
  576.                 final FieldUnivariateDerivative1<T> alphaEUD = new FieldUnivariateDerivative1<>(cachedAlpha, cachedAlphaDot);
  577.                 final FieldUnivariateDerivative1<T> exUD     = new FieldUnivariateDerivative1<>(ex,     exDot);
  578.                 final FieldUnivariateDerivative1<T> eyUD     = new FieldUnivariateDerivative1<>(ey,     eyDot);
  579.                 final FieldUnivariateDerivative1<T> alphaVUD = FieldCircularLatitudeArgumentUtility.eccentricToTrue(exUD, eyUD,
  580.                         alphaEUD);
  581.                 return alphaVUD.getFirstDerivative();

  582.             case TRUE:
  583.                 return cachedAlphaDot;

  584.             case MEAN:
  585.                 final FieldUnivariateDerivative1<T> alphaMUD = new FieldUnivariateDerivative1<>(cachedAlpha, cachedAlphaDot);
  586.                 final FieldUnivariateDerivative1<T> exUD2    = new FieldUnivariateDerivative1<>(ex,     exDot);
  587.                 final FieldUnivariateDerivative1<T> eyUD2    = new FieldUnivariateDerivative1<>(ey,     eyDot);
  588.                 final FieldUnivariateDerivative1<T> alphaVUD2 = FieldCircularLatitudeArgumentUtility.meanToTrue(exUD2,
  589.                         eyUD2, alphaMUD);
  590.                 return alphaVUD2.getFirstDerivative();

  591.             default:
  592.                 throw new OrekitInternalError(null);
  593.         }
  594.     }

  595.     /** Get the eccentric latitude argument.
  596.      * @return E + ω eccentric latitude argument (rad)
  597.      */
  598.     public T getAlphaE() {
  599.         switch (cachedPositionAngleType) {
  600.             case TRUE:
  601.                 return FieldCircularLatitudeArgumentUtility.trueToEccentric(ex, ey, cachedAlpha);

  602.             case ECCENTRIC:
  603.                 return cachedAlpha;

  604.             case MEAN:
  605.                 return FieldCircularLatitudeArgumentUtility.meanToEccentric(ex, ey, cachedAlpha);

  606.             default:
  607.                 throw new OrekitInternalError(null);
  608.         }
  609.     }

  610.     /** Get the eccentric latitude argument derivative.
  611.      * @return d(E + ω)/dt eccentric latitude argument derivative (rad/s)
  612.      */
  613.     public T getAlphaEDot() {

  614.         if (!hasDerivatives()) {
  615.             return null;
  616.         }
  617.         switch (cachedPositionAngleType) {
  618.             case TRUE:
  619.                 final FieldUnivariateDerivative1<T> alphaVUD = new FieldUnivariateDerivative1<>(cachedAlpha, cachedAlphaDot);
  620.                 final FieldUnivariateDerivative1<T> exUD = new FieldUnivariateDerivative1<>(ex, exDot);
  621.                 final FieldUnivariateDerivative1<T> eyUD = new FieldUnivariateDerivative1<>(ey, eyDot);
  622.                 final FieldUnivariateDerivative1<T> alphaEUD = FieldCircularLatitudeArgumentUtility.trueToEccentric(exUD, eyUD,
  623.                         alphaVUD);
  624.                 return alphaEUD.getFirstDerivative();

  625.             case ECCENTRIC:
  626.                 return cachedAlphaDot;

  627.             case MEAN:
  628.                 final FieldUnivariateDerivative1<T> alphaMUD = new FieldUnivariateDerivative1<>(cachedAlpha, cachedAlphaDot);
  629.                 final FieldUnivariateDerivative1<T> exUD2 = new FieldUnivariateDerivative1<>(ex, exDot);
  630.                 final FieldUnivariateDerivative1<T> eyUD2 = new FieldUnivariateDerivative1<>(ey, eyDot);
  631.                 final FieldUnivariateDerivative1<T> alphaVUD2 = FieldCircularLatitudeArgumentUtility.meanToEccentric(exUD2,
  632.                         eyUD2, alphaMUD);
  633.                 return alphaVUD2.getFirstDerivative();

  634.             default:
  635.                 throw new OrekitInternalError(null);
  636.         }

  637.     }

  638.     /** Get the mean latitude argument.
  639.      * @return M + ω mean latitude argument (rad)
  640.      */
  641.     public T getAlphaM() {
  642.         switch (cachedPositionAngleType) {
  643.             case TRUE:
  644.                 return FieldCircularLatitudeArgumentUtility.trueToMean(ex, ey, cachedAlpha);

  645.             case MEAN:
  646.                 return cachedAlpha;

  647.             case ECCENTRIC:
  648.                 return FieldCircularLatitudeArgumentUtility.eccentricToMean(ex, ey, cachedAlpha);

  649.             default:
  650.                 throw new OrekitInternalError(null);
  651.         }
  652.     }

  653.     /** Get the mean latitude argument derivative.
  654.      * @return d(M + ω)/dt mean latitude argument derivative (rad/s)
  655.      */
  656.     public T getAlphaMDot() {

  657.         if (!hasDerivatives()) {
  658.             return null;
  659.         }
  660.         switch (cachedPositionAngleType) {
  661.             case TRUE:
  662.                 final FieldUnivariateDerivative1<T> alphaVUD = new FieldUnivariateDerivative1<>(cachedAlpha, cachedAlphaDot);
  663.                 final FieldUnivariateDerivative1<T> exUD = new FieldUnivariateDerivative1<>(ex, exDot);
  664.                 final FieldUnivariateDerivative1<T> eyUD = new FieldUnivariateDerivative1<>(ey, eyDot);
  665.                 final FieldUnivariateDerivative1<T> alphaMUD = FieldCircularLatitudeArgumentUtility.trueToMean(exUD, eyUD,
  666.                         alphaVUD);
  667.                 return alphaMUD.getFirstDerivative();

  668.             case MEAN:
  669.                 return cachedAlphaDot;

  670.             case ECCENTRIC:
  671.                 final FieldUnivariateDerivative1<T> alphaEUD = new FieldUnivariateDerivative1<>(cachedAlpha, cachedAlphaDot);
  672.                 final FieldUnivariateDerivative1<T> exUD2 = new FieldUnivariateDerivative1<>(ex, exDot);
  673.                 final FieldUnivariateDerivative1<T> eyUD2 = new FieldUnivariateDerivative1<>(ey, eyDot);
  674.                 final FieldUnivariateDerivative1<T> alphaMUD2 = FieldCircularLatitudeArgumentUtility.eccentricToMean(exUD2,
  675.                         eyUD2, alphaEUD);
  676.                 return alphaMUD2.getFirstDerivative();

  677.             default:
  678.                 throw new OrekitInternalError(null);
  679.         }
  680.     }

  681.     /** Get the latitude argument.
  682.      * @param type type of the angle
  683.      * @return latitude argument (rad)
  684.      */
  685.     public T getAlpha(final PositionAngleType type) {
  686.         return (type == PositionAngleType.MEAN) ? getAlphaM() :
  687.                                               ((type == PositionAngleType.ECCENTRIC) ? getAlphaE() :
  688.                                                                                    getAlphaV());
  689.     }

  690.     /** Get the latitude argument derivative.
  691.      * @param type type of the angle
  692.      * @return latitude argument derivative (rad/s)
  693.      */
  694.     public T getAlphaDot(final PositionAngleType type) {
  695.         return (type == PositionAngleType.MEAN) ? getAlphaMDot() :
  696.                                               ((type == PositionAngleType.ECCENTRIC) ? getAlphaEDot() :
  697.                                                                                    getAlphaVDot());
  698.     }

  699.     /** Computes the true latitude argument from the eccentric latitude argument.
  700.      * @param alphaE = E + ω eccentric latitude argument (rad)
  701.      * @param ex e cos(ω), first component of circular eccentricity vector
  702.      * @param ey e sin(ω), second component of circular eccentricity vector
  703.      * @param <T> Type of the field elements
  704.      * @return the true latitude argument.
  705.      */
  706.     @Deprecated
  707.     public static <T extends CalculusFieldElement<T>> T eccentricToTrue(final T alphaE, final T ex, final T ey) {
  708.         return FieldCircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, alphaE);
  709.     }

  710.     /** Computes the eccentric latitude argument from the true latitude argument.
  711.      * @param alphaV = v + ω true latitude argument (rad)
  712.      * @param ex e cos(ω), first component of circular eccentricity vector
  713.      * @param ey e sin(ω), second component of circular eccentricity vector
  714.      * @param <T> Type of the field elements
  715.      * @return the eccentric latitude argument.
  716.      */
  717.     @Deprecated
  718.     public static <T extends CalculusFieldElement<T>> T trueToEccentric(final T alphaV, final T ex, final T ey) {
  719.         return FieldCircularLatitudeArgumentUtility.trueToEccentric(ex, ey, alphaV);
  720.     }

  721.     /** Computes the eccentric latitude argument from the mean latitude argument.
  722.      * @param alphaM = M + ω  mean latitude argument (rad)
  723.      * @param ex e cos(ω), first component of circular eccentricity vector
  724.      * @param ey e sin(ω), second component of circular eccentricity vector
  725.      * @param <T> Type of the field elements
  726.      * @return the eccentric latitude argument.
  727.      */
  728.     @Deprecated
  729.     public static <T extends CalculusFieldElement<T>> T meanToEccentric(final T alphaM, final T ex, final T ey) {
  730.         return FieldCircularLatitudeArgumentUtility.meanToEccentric(ex, ey, alphaM);
  731.     }

  732.     /** Computes the mean latitude argument from the eccentric latitude argument.
  733.      * @param alphaE = E + ω  eccentric latitude argument (rad)
  734.      * @param ex e cos(ω), first component of circular eccentricity vector
  735.      * @param ey e sin(ω), second component of circular eccentricity vector
  736.      * @param <T> Type of the field elements
  737.      * @return the mean latitude argument.
  738.      */
  739.     @Deprecated
  740.     public static <T extends CalculusFieldElement<T>> T eccentricToMean(final T alphaE, final T ex, final T ey) {
  741.         return FieldCircularLatitudeArgumentUtility.eccentricToMean(ex, ey, alphaE);
  742.     }

  743.     /** {@inheritDoc} */
  744.     @Override
  745.     public T getE() {
  746.         return ex.multiply(ex).add(ey.multiply(ey)).sqrt();
  747.     }

  748.     /** {@inheritDoc} */
  749.     @Override
  750.     public T getEDot() {

  751.         if (!hasDerivatives()) {
  752.             return null;
  753.         }

  754.         return ex.multiply(exDot).add(ey.multiply(eyDot)).divide(getE());

  755.     }

  756.     /** {@inheritDoc} */
  757.     @Override
  758.     public T getI() {
  759.         return i;
  760.     }

  761.     /** {@inheritDoc} */
  762.     @Override
  763.     public T getIDot() {
  764.         return iDot;
  765.     }

  766.     /** Get the right ascension of the ascending node.
  767.      * @return right ascension of the ascending node (rad)
  768.      */
  769.     public T getRightAscensionOfAscendingNode() {
  770.         return raan;
  771.     }

  772.     /** Get the right ascension of the ascending node derivative.
  773.      * @return right ascension of the ascending node derivative (rad/s)
  774.      */
  775.     public T getRightAscensionOfAscendingNodeDot() {
  776.         return raanDot;
  777.     }

  778.     /** {@inheritDoc} */
  779.     @Override
  780.     public T getLv() {
  781.         return getAlphaV().add(raan);
  782.     }

  783.     /** {@inheritDoc} */
  784.     @Override
  785.     public T getLvDot() {
  786.         return hasDerivatives() ? getAlphaVDot().add(raanDot) : null;
  787.     }

  788.     /** {@inheritDoc} */
  789.     @Override
  790.     public T getLE() {
  791.         return getAlphaE().add(raan);
  792.     }

  793.     /** {@inheritDoc} */
  794.     @Override
  795.     public T getLEDot() {
  796.         return hasDerivatives() ? getAlphaEDot().add(raanDot) : null;
  797.     }

  798.     /** {@inheritDoc} */
  799.     @Override
  800.     public T getLM() {
  801.         return getAlphaM().add(raan);
  802.     }

  803.     /** {@inheritDoc} */
  804.     @Override
  805.     public T getLMDot() {
  806.         return hasDerivatives() ? getAlphaMDot().add(raanDot) : null;
  807.     }

  808.     /** {@inheritDoc} */
  809.     @Override
  810.     public boolean hasDerivatives() {
  811.         return aDot != null;
  812.     }

  813.     /** Compute position and velocity but not acceleration.
  814.      */
  815.     private void computePVWithoutA() {

  816.         if (partialPV != null) {
  817.             // already computed
  818.             return;
  819.         }

  820.         // get equinoctial parameters
  821.         final T equEx = getEquinoctialEx();
  822.         final T equEy = getEquinoctialEy();
  823.         final T hx = getHx();
  824.         final T hy = getHy();
  825.         final T lE = getLE();
  826.         // inclination-related intermediate parameters
  827.         final T hx2   = hx.multiply(hx);
  828.         final T hy2   = hy.multiply(hy);
  829.         final T factH = (hx2.add(1).add(hy2)).reciprocal();

  830.         // reference axes defining the orbital plane
  831.         final T ux = (hx2.add(1).subtract(hy2)).multiply(factH);
  832.         final T uy =  hx.multiply(2).multiply(hy).multiply(factH);
  833.         final T uz = hy.multiply(-2).multiply(factH);

  834.         final T vx = uy;
  835.         final T vy = (hy2.subtract(hx2).add(1)).multiply(factH);
  836.         final T vz =  hx.multiply(factH).multiply(2);

  837.         // eccentricity-related intermediate parameters
  838.         final T exey = equEx.multiply(equEy);
  839.         final T ex2  = equEx.square();
  840.         final T ey2  = equEy.square();
  841.         final T e2   = ex2.add(ey2);
  842.         final T eta  = e2.negate().add(1).sqrt().add(1);
  843.         final T beta = eta.reciprocal();

  844.         // eccentric latitude argument
  845.         final FieldSinCos<T> scLe = FastMath.sinCos(lE);
  846.         final T cLe    = scLe.cos();
  847.         final T sLe    = scLe.sin();
  848.         final T exCeyS = equEx.multiply(cLe).add(equEy.multiply(sLe));
  849.         // coordinates of position and velocity in the orbital plane
  850.         final T x      = a.multiply(beta.negate().multiply(ey2).add(1).multiply(cLe).add(beta.multiply(exey).multiply(sLe)).subtract(equEx));
  851.         final T y      = a.multiply(beta.negate().multiply(ex2).add(1).multiply(sLe).add(beta.multiply(exey).multiply(cLe)).subtract(equEy));

  852.         final T factor = getOne().add(getMu()).divide(a).sqrt().divide(exCeyS.negate().add(1));
  853.         final T xdot   = factor.multiply( beta.multiply(equEy).multiply(exCeyS).subtract(sLe ));
  854.         final T ydot   = factor.multiply( cLe.subtract(beta.multiply(equEx).multiply(exCeyS)));

  855.         final FieldVector3D<T> position = new FieldVector3D<>(x.multiply(ux).add(y.multiply(vx)),
  856.                                                               x.multiply(uy).add(y.multiply(vy)),
  857.                                                               x.multiply(uz).add(y.multiply(vz)));
  858.         final FieldVector3D<T> velocity = new FieldVector3D<>(xdot.multiply(ux).add(ydot.multiply(vx)),
  859.                                                               xdot.multiply(uy).add(ydot.multiply(vy)),
  860.                                                               xdot.multiply(uz).add(ydot.multiply(vz)));

  861.         partialPV = new FieldPVCoordinates<>(position, velocity);

  862.     }


  863.     /** Initialize cached alpha with rate.
  864.      * @param alpha input alpha
  865.      * @param alphaDot rate of input alpha
  866.      * @param inputType position angle type passed as input
  867.      * @return alpha to cache with rate
  868.      * @since 12.1
  869.      */
  870.     private FieldUnivariateDerivative1<T> initializeCachedAlpha(final T alpha, final T alphaDot,
  871.                                                                 final PositionAngleType inputType) {
  872.         if (cachedPositionAngleType == inputType) {
  873.             return new FieldUnivariateDerivative1<>(alpha, alphaDot);

  874.         } else {
  875.             final FieldUnivariateDerivative1<T> exUD = new FieldUnivariateDerivative1<>(ex, exDot);
  876.             final FieldUnivariateDerivative1<T> eyUD = new FieldUnivariateDerivative1<>(ey, eyDot);
  877.             final FieldUnivariateDerivative1<T> alphaUD = new FieldUnivariateDerivative1<>(alpha, alphaDot);

  878.             switch (cachedPositionAngleType) {

  879.                 case ECCENTRIC:
  880.                     if (inputType == PositionAngleType.MEAN) {
  881.                         return FieldCircularLatitudeArgumentUtility.meanToEccentric(exUD, eyUD, alphaUD);
  882.                     } else {
  883.                         return FieldCircularLatitudeArgumentUtility.trueToEccentric(exUD, eyUD, alphaUD);
  884.                     }

  885.                 case TRUE:
  886.                     if (inputType == PositionAngleType.MEAN) {
  887.                         return FieldCircularLatitudeArgumentUtility.meanToTrue(exUD, eyUD, alphaUD);
  888.                     } else {
  889.                         return FieldCircularLatitudeArgumentUtility.eccentricToTrue(exUD, eyUD, alphaUD);
  890.                     }

  891.                 case MEAN:
  892.                     if (inputType == PositionAngleType.TRUE) {
  893.                         return FieldCircularLatitudeArgumentUtility.trueToMean(exUD, eyUD, alphaUD);
  894.                     } else {
  895.                         return FieldCircularLatitudeArgumentUtility.eccentricToMean(exUD, eyUD, alphaUD);
  896.                     }

  897.                 default:
  898.                     throw new OrekitInternalError(null);

  899.             }

  900.         }

  901.     }

  902.     /** Initialize cached alpha.
  903.      * @param alpha input alpha
  904.      * @param positionAngleType position angle type passed as input
  905.      * @return alpha to cache
  906.      * @since 12.1
  907.      */
  908.     private T initializeCachedAlpha(final T alpha, final PositionAngleType positionAngleType) {
  909.         return FieldCircularLatitudeArgumentUtility.convertAlpha(positionAngleType, alpha, ex, ey, cachedPositionAngleType);
  910.     }

  911.     /** Compute non-Keplerian part of the acceleration from first time derivatives.
  912.      * <p>
  913.      * This method should be called only when {@link #hasDerivatives()} returns true.
  914.      * </p>
  915.      * @return non-Keplerian part of the acceleration
  916.      */
  917.     private FieldVector3D<T> nonKeplerianAcceleration() {

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

  920.         final T nonKeplerianMeanMotion = getAlphaMDot().subtract(getKeplerianMeanMotion());
  921.         final T nonKeplerianAx =     dCdP[3][0].multiply(aDot).
  922.                                  add(dCdP[3][1].multiply(exDot)).
  923.                                  add(dCdP[3][2].multiply(eyDot)).
  924.                                  add(dCdP[3][3].multiply(iDot)).
  925.                                  add(dCdP[3][4].multiply(raanDot)).
  926.                                  add(dCdP[3][5].multiply(nonKeplerianMeanMotion));
  927.         final T nonKeplerianAy =     dCdP[4][0].multiply(aDot).
  928.                                  add(dCdP[4][1].multiply(exDot)).
  929.                                  add(dCdP[4][2].multiply(eyDot)).
  930.                                  add(dCdP[4][3].multiply(iDot)).
  931.                                  add(dCdP[4][4].multiply(raanDot)).
  932.                                  add(dCdP[4][5].multiply(nonKeplerianMeanMotion));
  933.         final T nonKeplerianAz =     dCdP[5][0].multiply(aDot).
  934.                                  add(dCdP[5][1].multiply(exDot)).
  935.                                  add(dCdP[5][2].multiply(eyDot)).
  936.                                  add(dCdP[5][3].multiply(iDot)).
  937.                                  add(dCdP[5][4].multiply(raanDot)).
  938.                                  add(dCdP[5][5].multiply(nonKeplerianMeanMotion));

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

  940.     }

  941.     /** {@inheritDoc} */
  942.     @Override
  943.     protected FieldVector3D<T> initPosition() {
  944.         // get equinoctial parameters
  945.         final T equEx = getEquinoctialEx();
  946.         final T equEy = getEquinoctialEy();
  947.         final T hx = getHx();
  948.         final T hy = getHy();
  949.         final T lE = getLE();
  950.         // inclination-related intermediate parameters
  951.         final T hx2   = hx.multiply(hx);
  952.         final T hy2   = hy.multiply(hy);
  953.         final T factH = (hx2.add(1).add(hy2)).reciprocal();

  954.         // reference axes defining the orbital plane
  955.         final T ux = (hx2.add(1).subtract(hy2)).multiply(factH);
  956.         final T uy =  hx.multiply(2).multiply(hy).multiply(factH);
  957.         final T uz = hy.multiply(-2).multiply(factH);

  958.         final T vx = uy;
  959.         final T vy = (hy2.subtract(hx2).add(1)).multiply(factH);
  960.         final T vz =  hx.multiply(factH).multiply(2);

  961.         // eccentricity-related intermediate parameters
  962.         final T exey = equEx.multiply(equEy);
  963.         final T ex2  = equEx.square();
  964.         final T ey2  = equEy.square();
  965.         final T e2   = ex2.add(ey2);
  966.         final T eta  = e2.negate().add(1).sqrt().add(1);
  967.         final T beta = eta.reciprocal();

  968.         // eccentric latitude argument
  969.         final FieldSinCos<T> scLe = FastMath.sinCos(lE);
  970.         final T cLe    = scLe.cos();
  971.         final T sLe    = scLe.sin();

  972.         // coordinates of position and velocity in the orbital plane
  973.         final T x      = a.multiply(beta.negate().multiply(ey2).add(1).multiply(cLe).add(beta.multiply(exey).multiply(sLe)).subtract(equEx));
  974.         final T y      = a.multiply(beta.negate().multiply(ex2).add(1).multiply(sLe).add(beta.multiply(exey).multiply(cLe)).subtract(equEy));

  975.         return new FieldVector3D<>(x.multiply(ux).add(y.multiply(vx)),
  976.                                    x.multiply(uy).add(y.multiply(vy)),
  977.                                    x.multiply(uz).add(y.multiply(vz)));

  978.     }

  979.     /** {@inheritDoc} */
  980.     @Override
  981.     protected TimeStampedFieldPVCoordinates<T> initPVCoordinates() {

  982.         // position and velocity
  983.         computePVWithoutA();

  984.         // acceleration
  985.         final T r2 = partialPV.getPosition().getNormSq();
  986.         final FieldVector3D<T> keplerianAcceleration = new FieldVector3D<>(r2.multiply(r2.sqrt()).reciprocal().multiply(getMu().negate()),
  987.                                                                            partialPV.getPosition());
  988.         final FieldVector3D<T> acceleration = hasDerivatives() ?
  989.                                               keplerianAcceleration.add(nonKeplerianAcceleration()) :
  990.                                               keplerianAcceleration;

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

  992.     }

  993.     /** {@inheritDoc} */
  994.     @Override
  995.     public FieldCircularOrbit<T> shiftedBy(final double dt) {
  996.         return shiftedBy(getZero().newInstance(dt));
  997.     }

  998.     /** {@inheritDoc} */
  999.     @Override
  1000.     public FieldCircularOrbit<T> shiftedBy(final T dt) {

  1001.         // use Keplerian-only motion
  1002.         final FieldCircularOrbit<T> keplerianShifted = new FieldCircularOrbit<>(a, ex, ey, i, raan,
  1003.                                                                                 getAlphaM().add(getKeplerianMeanMotion().multiply(dt)),
  1004.                                                                                 PositionAngleType.MEAN, cachedPositionAngleType, getFrame(),
  1005.                                                                                 getDate().shiftedBy(dt), getMu());

  1006.         if (hasDerivatives()) {

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

  1009.             // add quadratic effect of non-Keplerian acceleration to Keplerian-only shift
  1010.             keplerianShifted.computePVWithoutA();
  1011.             final FieldVector3D<T> fixedP   = new FieldVector3D<>(getOne(), keplerianShifted.partialPV.getPosition(),
  1012.                                                                   dt.square().multiply(0.5), nonKeplerianAcceleration);
  1013.             final T   fixedR2 = fixedP.getNormSq();
  1014.             final T   fixedR  = fixedR2.sqrt();
  1015.             final FieldVector3D<T> fixedV  = new FieldVector3D<>(getOne(), keplerianShifted.partialPV.getVelocity(),
  1016.                                                                  dt, nonKeplerianAcceleration);
  1017.             final FieldVector3D<T> fixedA  = new FieldVector3D<>(fixedR2.multiply(fixedR).reciprocal().multiply(getMu().negate()),
  1018.                                                                  keplerianShifted.partialPV.getPosition(),
  1019.                                                                  getOne(), nonKeplerianAcceleration);

  1020.             // build a new orbit, taking non-Keplerian acceleration into account
  1021.             return new FieldCircularOrbit<>(new TimeStampedFieldPVCoordinates<>(keplerianShifted.getDate(),
  1022.                                                                                 fixedP, fixedV, fixedA),
  1023.                                             keplerianShifted.getFrame(), keplerianShifted.getMu());

  1024.         } else {
  1025.             // Keplerian-only motion is all we can do
  1026.             return keplerianShifted;
  1027.         }

  1028.     }

  1029.     /** {@inheritDoc} */
  1030.     @Override
  1031.     protected T[][] computeJacobianMeanWrtCartesian() {

  1032.         final T[][] jacobian = MathArrays.buildArray(getOne().getField(), 6, 6);

  1033.         // compute various intermediate parameters
  1034.         computePVWithoutA();
  1035.         final FieldVector3D<T> position = partialPV.getPosition();
  1036.         final FieldVector3D<T> velocity = partialPV.getVelocity();

  1037.         final T x          = position.getX();
  1038.         final T y          = position.getY();
  1039.         final T z          = position.getZ();
  1040.         final T vx         = velocity.getX();
  1041.         final T vy         = velocity.getY();
  1042.         final T vz         = velocity.getZ();
  1043.         final T pv         = FieldVector3D.dotProduct(position, velocity);
  1044.         final T r2         = position.getNormSq();
  1045.         final T r          = r2.sqrt();
  1046.         final T v2         = velocity.getNormSq();

  1047.         final T mu         = getMu();
  1048.         final T oOsqrtMuA  = getOne().divide(a.multiply(mu).sqrt());
  1049.         final T rOa        = r.divide(a);
  1050.         final T aOr        = a.divide(r);
  1051.         final T aOr2       = a.divide(r2);
  1052.         final T a2         = a.square();

  1053.         final T ex2        = ex.square();
  1054.         final T ey2        = ey.square();
  1055.         final T e2         = ex2.add(ey2);
  1056.         final T epsilon    = e2.negate().add(1.0).sqrt();
  1057.         final T beta       = epsilon.add(1).reciprocal();

  1058.         final T eCosE      = rOa.negate().add(1);
  1059.         final T eSinE      = pv.multiply(oOsqrtMuA);

  1060.         final FieldSinCos<T> scI    = FastMath.sinCos(i);
  1061.         final FieldSinCos<T> scRaan = FastMath.sinCos(raan);
  1062.         final T cosI       = scI.cos();
  1063.         final T sinI       = scI.sin();
  1064.         final T cosRaan    = scRaan.cos();
  1065.         final T sinRaan    = scRaan.sin();

  1066.         // da
  1067.         fillHalfRow(aOr.multiply(2.0).multiply(aOr2), position, jacobian[0], 0);
  1068.         fillHalfRow(a2.multiply(mu.divide(2.).reciprocal()), velocity, jacobian[0], 3);

  1069.         // differentials of the normalized momentum
  1070.         final FieldVector3D<T> danP = new FieldVector3D<>(v2, position, pv.negate(), velocity);
  1071.         final FieldVector3D<T> danV = new FieldVector3D<>(r2, velocity, pv.negate(), position);
  1072.         final T recip   = partialPV.getMomentum().getNorm().reciprocal();
  1073.         final T recip2  = recip.multiply(recip);
  1074.         final T recip2N = recip2.negate();
  1075.         final FieldVector3D<T> dwXP = new FieldVector3D<>(recip,
  1076.                                                           new FieldVector3D<>(getZero(), vz, vy.negate()),
  1077.                                                           recip2N.multiply(sinRaan).multiply(sinI),
  1078.                                                           danP);
  1079.         final FieldVector3D<T> dwYP = new FieldVector3D<>(recip,
  1080.                                                           new FieldVector3D<>(vz.negate(), getZero(), vx),
  1081.                                                           recip2.multiply(cosRaan).multiply(sinI),
  1082.                                                           danP);
  1083.         final FieldVector3D<T> dwZP = new FieldVector3D<>(recip,
  1084.                                                           new FieldVector3D<>(vy, vx.negate(), getZero()),
  1085.                                                           recip2N.multiply(cosI),
  1086.                                                           danP);
  1087.         final FieldVector3D<T> dwXV = new FieldVector3D<>(recip,
  1088.                                                           new FieldVector3D<>(getZero(), z.negate(), y),
  1089.                                                           recip2N.multiply(sinRaan).multiply(sinI),
  1090.                                                           danV);
  1091.         final FieldVector3D<T> dwYV = new FieldVector3D<>(recip,
  1092.                                                           new FieldVector3D<>(z, getZero(), x.negate()),
  1093.                                                           recip2.multiply(cosRaan).multiply(sinI),
  1094.                                                           danV);
  1095.         final FieldVector3D<T> dwZV = new FieldVector3D<>(recip,
  1096.                                                           new FieldVector3D<>(y.negate(), x, getZero()),
  1097.                                                           recip2N.multiply(cosI),
  1098.                                                           danV);

  1099.         // di
  1100.         fillHalfRow(sinRaan.multiply(cosI), dwXP, cosRaan.negate().multiply(cosI), dwYP, sinI.negate(), dwZP, jacobian[3], 0);
  1101.         fillHalfRow(sinRaan.multiply(cosI), dwXV, cosRaan.negate().multiply(cosI), dwYV, sinI.negate(), dwZV, jacobian[3], 3);

  1102.         // dRaan
  1103.         fillHalfRow(sinRaan.divide(sinI), dwYP, cosRaan.divide(sinI), dwXP, jacobian[4], 0);
  1104.         fillHalfRow(sinRaan.divide(sinI), dwYV, cosRaan.divide(sinI), dwXV, jacobian[4], 3);

  1105.         // orbital frame: (p, q, w) p along ascending node, w along momentum
  1106.         // the coordinates of the spacecraft in this frame are: (u, v, 0)
  1107.         final T u     =  x.multiply(cosRaan).add(y.multiply(sinRaan));
  1108.         final T cv    =  x.negate().multiply(sinRaan).add(y.multiply(cosRaan));
  1109.         final T v     = cv.multiply(cosI).add(z.multiply(sinI));

  1110.         // du
  1111.         final FieldVector3D<T> duP = new FieldVector3D<>(cv.multiply(cosRaan).divide(sinI), dwXP,
  1112.                                                          cv.multiply(sinRaan).divide(sinI), dwYP,
  1113.                                                          getOne(), new FieldVector3D<>(cosRaan, sinRaan, getZero()));
  1114.         final FieldVector3D<T> duV = new FieldVector3D<>(cv.multiply(cosRaan).divide(sinI), dwXV,
  1115.                                                          cv.multiply(sinRaan).divide(sinI), dwYV);

  1116.         // dv
  1117.         final FieldVector3D<T> dvP = new FieldVector3D<>(u.negate().multiply(cosRaan).multiply(cosI).divide(sinI).add(sinRaan.multiply(z)), dwXP,
  1118.                                                          u.negate().multiply(sinRaan).multiply(cosI).divide(sinI).subtract(cosRaan.multiply(z)), dwYP,
  1119.                                                          cv, dwZP,
  1120.                                                          getOne(), new FieldVector3D<>(sinRaan.negate().multiply(cosI), cosRaan.multiply(cosI), sinI));
  1121.         final FieldVector3D<T> dvV = new FieldVector3D<>(u.negate().multiply(cosRaan).multiply(cosI).divide(sinI).add(sinRaan.multiply(z)), dwXV,
  1122.                                                          u.negate().multiply(sinRaan).multiply(cosI).divide(sinI).subtract(cosRaan.multiply(z)), dwYV,
  1123.                                                          cv, dwZV);

  1124.         final FieldVector3D<T> dc1P = new FieldVector3D<>(aOr2.multiply(eSinE.multiply(eSinE).multiply(2).add(1).subtract(eCosE)).divide(r2), position,
  1125.                                                           aOr2.multiply(-2).multiply(eSinE).multiply(oOsqrtMuA), velocity);
  1126.         final FieldVector3D<T> dc1V = new FieldVector3D<>(aOr2.multiply(-2).multiply(eSinE).multiply(oOsqrtMuA), position,
  1127.                                                           getZero().newInstance(2).divide(mu), velocity);
  1128.         final FieldVector3D<T> dc2P = new FieldVector3D<>(aOr2.multiply(eSinE).multiply(eSinE.multiply(eSinE).subtract(e2.negate().add(1))).divide(r2.multiply(epsilon)), position,
  1129.                                                           aOr2.multiply(e2.negate().add(1).subtract(eSinE.multiply(eSinE))).multiply(oOsqrtMuA).divide(epsilon), velocity);
  1130.         final FieldVector3D<T> dc2V = new FieldVector3D<>(aOr2.multiply(e2.negate().add(1).subtract(eSinE.multiply(eSinE))).multiply(oOsqrtMuA).divide(epsilon), position,
  1131.                                                           eSinE.divide(epsilon.multiply(mu)), velocity);

  1132.         final T cof1   = aOr2.multiply(eCosE.subtract(e2));
  1133.         final T cof2   = aOr2.multiply(epsilon).multiply(eSinE);
  1134.         final FieldVector3D<T> dexP = new FieldVector3D<>(u, dc1P,  v, dc2P, cof1, duP,  cof2, dvP);
  1135.         final FieldVector3D<T> dexV = new FieldVector3D<>(u, dc1V,  v, dc2V, cof1, duV,  cof2, dvV);
  1136.         final FieldVector3D<T> deyP = new FieldVector3D<>(v, dc1P, u.negate(), dc2P, cof1, dvP, cof2.negate(), duP);
  1137.         final FieldVector3D<T> deyV = new FieldVector3D<>(v, dc1V, u.negate(), dc2V, cof1, dvV, cof2.negate(), duV);
  1138.         fillHalfRow(getOne(), dexP, jacobian[1], 0);
  1139.         fillHalfRow(getOne(), dexV, jacobian[1], 3);
  1140.         fillHalfRow(getOne(), deyP, jacobian[2], 0);
  1141.         fillHalfRow(getOne(), deyV, jacobian[2], 3);

  1142.         final T cle = u.divide(a).add(ex).subtract(eSinE.multiply(beta).multiply(ey));
  1143.         final T sle = v.divide(a).add(ey).add(eSinE.multiply(beta).multiply(ex));
  1144.         final T m1  = beta.multiply(eCosE);
  1145.         final T m2  = m1.multiply(eCosE).negate().add(1);
  1146.         final T m3  = (u.multiply(ey).subtract(v.multiply(ex))).add(eSinE.multiply(beta).multiply(u.multiply(ex).add(v.multiply(ey))));
  1147.         final T m4  = sle.negate().add(cle.multiply(eSinE).multiply(beta));
  1148.         final T m5  = cle.add(sle.multiply(eSinE).multiply(beta));
  1149.         final T kk = m3.multiply(2).divide(r).add(aOr.multiply(eSinE)).add(m1.multiply(eSinE).multiply(m1.add(1).subtract(aOr.add(1).multiply(m2))).divide(epsilon)).divide(r2);
  1150.         final T jj = (m1.multiply(m2).divide(epsilon).subtract(1)).multiply(oOsqrtMuA);
  1151.         fillHalfRow(kk, position,
  1152.                     jj, velocity,
  1153.                     m4, dexP,
  1154.                     m5, deyP,
  1155.                     sle.negate().divide(a), duP,
  1156.                     cle.divide(a), dvP,
  1157.                     jacobian[5], 0);
  1158.         final T ll = (m1.multiply(m2).divide(epsilon ).subtract(1)).multiply(oOsqrtMuA);
  1159.         final T mm = m3.multiply(2).add(eSinE.multiply(a)).add(m1.multiply(eSinE).multiply(r).multiply(eCosE.multiply(beta).multiply(2).subtract(aOr.multiply(m2))).divide(epsilon)).divide(mu);

  1160.         fillHalfRow(ll, position,
  1161.                     mm, velocity,
  1162.                     m4, dexV,
  1163.                     m5, deyV,
  1164.                     sle.negate().divide(a), duV,
  1165.                     cle.divide(a), dvV,
  1166.                     jacobian[5], 3);
  1167.         return jacobian;

  1168.     }

  1169.     /** {@inheritDoc} */
  1170.     @Override
  1171.     protected T[][] computeJacobianEccentricWrtCartesian() {

  1172.         // start by computing the Jacobian with mean angle
  1173.         final T[][] jacobian = computeJacobianMeanWrtCartesian();

  1174.         // Differentiating the Kepler equation aM = aE - ex sin aE + ey cos aE leads to:
  1175.         // daM = (1 - ex cos aE - ey sin aE) dE - sin aE dex + cos aE dey
  1176.         // which is inverted and rewritten as:
  1177.         // daE = a/r daM + sin aE a/r dex - cos aE a/r dey
  1178.         final T alphaE            = getAlphaE();
  1179.         final FieldSinCos<T> scAe = FastMath.sinCos(alphaE);
  1180.         final T cosAe             = scAe.cos();
  1181.         final T sinAe             = scAe.sin();
  1182.         final T aOr               = getOne().divide(getOne().subtract(ex.multiply(cosAe)).subtract(ey.multiply(sinAe)));

  1183.         // update longitude row
  1184.         final T[] rowEx = jacobian[1];
  1185.         final T[] rowEy = jacobian[2];
  1186.         final T[] rowL  = jacobian[5];
  1187.         for (int j = 0; j < 6; ++j) {
  1188.          // rowL[j] = aOr * (      rowL[j] +   sinAe *        rowEx[j]   -         cosAe *        rowEy[j]);
  1189.             rowL[j] = aOr.multiply(rowL[j].add(sinAe.multiply(rowEx[j])).subtract( cosAe.multiply(rowEy[j])));
  1190.         }
  1191.         jacobian[5] = rowL;
  1192.         return jacobian;

  1193.     }
  1194.     /** {@inheritDoc} */
  1195.     @Override
  1196.     protected T[][] computeJacobianTrueWrtCartesian() {

  1197.         // start by computing the Jacobian with eccentric angle
  1198.         final T[][] jacobian = computeJacobianEccentricWrtCartesian();
  1199.         // Differentiating the eccentric latitude equation
  1200.         // tan((aV - aE)/2) = [ex sin aE - ey cos aE] / [sqrt(1-ex^2-ey^2) + 1 - ex cos aE - ey sin aE]
  1201.         // leads to
  1202.         // cT (daV - daE) = cE daE + cX dex + cY dey
  1203.         // with
  1204.         // cT = [d^2 + (ex sin aE - ey cos aE)^2] / 2
  1205.         // d  = 1 + sqrt(1-ex^2-ey^2) - ex cos aE - ey sin aE
  1206.         // cE = (ex cos aE + ey sin aE) (sqrt(1-ex^2-ey^2) + 1) - ex^2 - ey^2
  1207.         // cX =  sin aE (sqrt(1-ex^2-ey^2) + 1) - ey + ex (ex sin aE - ey cos aE) / sqrt(1-ex^2-ey^2)
  1208.         // cY = -cos aE (sqrt(1-ex^2-ey^2) + 1) + ex + ey (ex sin aE - ey cos aE) / sqrt(1-ex^2-ey^2)
  1209.         // which can be solved to find the differential of the true latitude
  1210.         // daV = (cT + cE) / cT daE + cX / cT deX + cY / cT deX
  1211.         final T alphaE            = getAlphaE();
  1212.         final FieldSinCos<T> scAe = FastMath.sinCos(alphaE);
  1213.         final T cosAe             = scAe.cos();
  1214.         final T sinAe             = scAe.sin();
  1215.         final T eSinE             = ex.multiply(sinAe).subtract(ey.multiply(cosAe));
  1216.         final T ecosE             = ex.multiply(cosAe).add(ey.multiply(sinAe));
  1217.         final T e2                = ex.multiply(ex).add(ey.multiply(ey));
  1218.         final T epsilon           = (getOne().subtract(e2)).sqrt();
  1219.         final T onePeps           = getOne().add(epsilon);
  1220.         final T d                 = onePeps.subtract(ecosE);
  1221.         final T cT                = (d.multiply(d).add(eSinE.multiply(eSinE))).divide(2);
  1222.         final T cE                = ecosE.multiply(onePeps).subtract(e2);
  1223.         final T cX                = ex.multiply(eSinE).divide(epsilon).subtract(ey).add(sinAe.multiply(onePeps));
  1224.         final T cY                = ey.multiply(eSinE).divide(epsilon).add(ex).subtract(cosAe.multiply(onePeps));
  1225.         final T factorLe          = (cT.add(cE)).divide(cT);
  1226.         final T factorEx          = cX.divide(cT);
  1227.         final T factorEy          = cY.divide(cT);

  1228.         // update latitude row
  1229.         final T[] rowEx = jacobian[1];
  1230.         final T[] rowEy = jacobian[2];
  1231.         final T[] rowA = jacobian[5];
  1232.         for (int j = 0; j < 6; ++j) {
  1233.             rowA[j] = factorLe.multiply(rowA[j]).add(factorEx.multiply(rowEx[j])).add(factorEy.multiply(rowEy[j]));
  1234.         }
  1235.         return jacobian;

  1236.     }

  1237.     /** {@inheritDoc} */
  1238.     @Override
  1239.     public void addKeplerContribution(final PositionAngleType type, final T gm, final T[] pDot) {
  1240.         pDot[5] = pDot[5].add(computeKeplerianAlphaDot(type, a, ex, ey, gm, cachedAlpha, cachedPositionAngleType));
  1241.     }

  1242.     /**
  1243.      * Compute rate of argument of latitude.
  1244.      * @param type position angle type of rate
  1245.      * @param a semi major axis
  1246.      * @param ex ex
  1247.      * @param ey ey
  1248.      * @param mu mu
  1249.      * @param alpha argument of latitude
  1250.      * @param cachedType position angle type of passed alpha
  1251.      * @param <T> field type
  1252.      * @return first-order time derivative for alpha
  1253.      * @since 12.2
  1254.      */
  1255.     private static <T extends CalculusFieldElement<T>> T computeKeplerianAlphaDot(final PositionAngleType type, final T a,
  1256.                                                                                   final T ex, final T ey, final T mu,
  1257.                                                                                   final T alpha, final PositionAngleType cachedType) {
  1258.         final T n = a.reciprocal().multiply(mu).sqrt().divide(a);
  1259.         if (type == PositionAngleType.MEAN) {
  1260.             return n;
  1261.         }
  1262.         final FieldSinCos<T> sc;
  1263.         final T ksi;
  1264.         if (type == PositionAngleType.ECCENTRIC) {
  1265.             sc = FastMath.sinCos(FieldCircularLatitudeArgumentUtility.convertAlpha(cachedType, alpha, ex, ey, type));
  1266.             ksi  = ((ex.multiply(sc.cos())).add(ey.multiply(sc.sin()))).negate().add(1).reciprocal();
  1267.             return n.multiply(ksi);
  1268.         } else {  // TRUE
  1269.             sc = FastMath.sinCos(FieldCircularLatitudeArgumentUtility.convertAlpha(cachedType, alpha, ex, ey, type));
  1270.             final T one = n.getField().getOne();
  1271.             final T oMe2  = one.subtract(ex.square()).subtract(ey.square());
  1272.             ksi   = one.add(ex.multiply(sc.cos())).add(ey.multiply(sc.sin()));
  1273.             return n.multiply(ksi.square()).divide(oMe2.multiply(oMe2.sqrt()));
  1274.         }
  1275.     }

  1276.     /**  Returns a string representation of this Orbit object.
  1277.      * @return a string representation of this object
  1278.      */
  1279.     public String toString() {
  1280.         return new StringBuilder().append("circular parameters: ").append('{').
  1281.                                   append("a: ").append(a.getReal()).
  1282.                                   append(", ex: ").append(ex.getReal()).append(", ey: ").append(ey.getReal()).
  1283.                                   append(", i: ").append(FastMath.toDegrees(i.getReal())).
  1284.                                   append(", raan: ").append(FastMath.toDegrees(raan.getReal())).
  1285.                                   append(", alphaV: ").append(FastMath.toDegrees(getAlphaV().getReal())).
  1286.                                   append(";}").toString();
  1287.     }

  1288.     /** {@inheritDoc} */
  1289.     @Override
  1290.     public PositionAngleType getCachedPositionAngleType() {
  1291.         return cachedPositionAngleType;
  1292.     }

  1293.     /** {@inheritDoc} */
  1294.     @Override
  1295.     public boolean hasRates() {
  1296.         return hasDerivatives();
  1297.     }

  1298.     /** {@inheritDoc} */
  1299.     @Override
  1300.     public FieldCircularOrbit<T> removeRates() {
  1301.         return new FieldCircularOrbit<>(getA(), getCircularEx(), getCircularEy(),
  1302.                 getI(), getRightAscensionOfAscendingNode(), cachedAlpha,
  1303.                 cachedPositionAngleType, getFrame(), getDate(), getMu());
  1304.     }

  1305.     /** {@inheritDoc} */
  1306.     @Override
  1307.     public CircularOrbit toOrbit() {
  1308.         final double cachedPositionAngle = cachedAlpha.getReal();
  1309.         if (hasDerivatives()) {
  1310.             return new CircularOrbit(a.getReal(), ex.getReal(), ey.getReal(),
  1311.                                      i.getReal(), raan.getReal(), cachedPositionAngle,
  1312.                                      aDot.getReal(), exDot.getReal(), eyDot.getReal(),
  1313.                                      iDot.getReal(), raanDot.getReal(), cachedAlphaDot.getReal(),
  1314.                                      cachedPositionAngleType, getFrame(),
  1315.                                      getDate().toAbsoluteDate(), getMu().getReal());
  1316.         } else {
  1317.             return new CircularOrbit(a.getReal(), ex.getReal(), ey.getReal(),
  1318.                                      i.getReal(), raan.getReal(), cachedPositionAngle,
  1319.                                      cachedPositionAngleType, getFrame(),
  1320.                                      getDate().toAbsoluteDate(), getMu().getReal());
  1321.         }
  1322.     }


  1323. }