CircularOrbit.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.io.Serializable;

  19. import org.hipparchus.analysis.differentiation.UnivariateDerivative1;
  20. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  21. import org.hipparchus.util.FastMath;
  22. import org.hipparchus.util.SinCos;
  23. import org.orekit.annotation.DefaultDataContext;
  24. import org.orekit.data.DataContext;
  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.AbsoluteDate;
  30. import org.orekit.utils.PVCoordinates;
  31. import org.orekit.utils.TimeStampedPVCoordinates;


  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.  *
  48.  * <p>
  49.  * The conversion equations from and to Keplerian elements given above hold only
  50.  * when both sides are unambiguously defined, i.e. when orbit is neither equatorial
  51.  * nor circular. When orbit is circular (but not equatorial), the circular
  52.  * parameters are still unambiguously defined whereas some Keplerian elements
  53.  * (more precisely ω and Ω) become ambiguous. When orbit is equatorial,
  54.  * neither the Keplerian nor the circular parameters can be defined unambiguously.
  55.  * {@link EquinoctialOrbit equinoctial orbits} is the recommended way to represent
  56.  * orbits.
  57.  * </p>
  58.  * <p>
  59.  * The instance <code>CircularOrbit</code> is guaranteed to be immutable.
  60.  * </p>
  61.  * @see    Orbit
  62.  * @see    KeplerianOrbit
  63.  * @see    CartesianOrbit
  64.  * @see    EquinoctialOrbit
  65.  * @author Luc Maisonobe
  66.  * @author Fabien Maussion
  67.  * @author V&eacute;ronique Pommier-Maurussane
  68.  */

  69. public class CircularOrbit extends Orbit implements PositionAngleBased {

  70.     /** Serializable UID. */
  71.     private static final long serialVersionUID = 20231217L;

  72.     /** Semi-major axis (m). */
  73.     private final double a;

  74.     /** First component of the circular eccentricity vector. */
  75.     private final double ex;

  76.     /** Second component of the circular eccentricity vector. */
  77.     private final double ey;

  78.     /** Inclination (rad). */
  79.     private final double i;

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

  82.     /** Cached latitude argument (rad). */
  83.     private final double cachedAlpha;

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

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

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

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

  92.     /** Inclination derivative (rad/s). */
  93.     private final double iDot;

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

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

  98.     /** Indicator for {@link PVCoordinates} serialization. */
  99.     private final boolean serializePV;

  100.     /** Partial Cartesian coordinates (position and velocity are valid, acceleration may be missing). */
  101.     private transient PVCoordinates partialPV;

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

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

  150.     /** Creates a new instance.
  151.      * @param a  semi-major axis (m)
  152.      * @param ex e cos(ω), first component of circular eccentricity vector
  153.      * @param ey e sin(ω), second component of circular eccentricity vector
  154.      * @param i inclination (rad)
  155.      * @param raan right ascension of ascending node (Ω, rad)
  156.      * @param alpha  an + ω, mean, eccentric or true latitude argument (rad)
  157.      * @param aDot  semi-major axis derivative (m/s)
  158.      * @param exDot d(e cos(ω))/dt, first component of circular eccentricity vector derivative
  159.      * @param eyDot d(e sin(ω))/dt, second component of circular eccentricity vector derivative
  160.      * @param iDot inclination  derivative(rad/s)
  161.      * @param raanDot right ascension of ascending node derivative (rad/s)
  162.      * @param alphaDot  d(an + ω), mean, eccentric or true latitude argument derivative (rad/s)
  163.      * @param type type of latitude argument
  164.      * @param cachedPositionAngleType type of cached latitude argument
  165.      * @param frame the frame in which are defined the parameters
  166.      * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame})
  167.      * @param date date of the orbital parameters
  168.      * @param mu central attraction coefficient (m³/s²)
  169.      * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or
  170.      * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame}
  171.      * @since 12.1
  172.      */
  173.     public CircularOrbit(final double a, final double ex, final double ey,
  174.                          final double i, final double raan, final double alpha,
  175.                          final double aDot, final double exDot, final double eyDot,
  176.                          final double iDot, final double raanDot, final double alphaDot,
  177.                          final PositionAngleType type, final PositionAngleType cachedPositionAngleType,
  178.                          final Frame frame, final AbsoluteDate date, final double mu)
  179.         throws IllegalArgumentException {
  180.         super(frame, date, mu);
  181.         if (ex * ex + ey * ey >= 1.0) {
  182.             throw new OrekitIllegalArgumentException(OrekitMessages.HYPERBOLIC_ORBIT_NOT_HANDLED_AS,
  183.                                                      getClass().getName());
  184.         }
  185.         this.a       =  a;
  186.         this.aDot    =  aDot;
  187.         this.ex      = ex;
  188.         this.exDot   = exDot;
  189.         this.ey      = ey;
  190.         this.eyDot   = eyDot;
  191.         this.i       = i;
  192.         this.iDot    = iDot;
  193.         this.raan    = raan;
  194.         this.raanDot = raanDot;
  195.         this.cachedPositionAngleType = cachedPositionAngleType;

  196.         if (hasDerivatives()) {
  197.             final UnivariateDerivative1 alphaUD = initializeCachedAlpha(alpha, alphaDot, type);
  198.             this.cachedAlpha = alphaUD.getValue();
  199.             this.cachedAlphaDot = alphaUD.getFirstDerivative();
  200.         } else {
  201.             this.cachedAlpha = initializeCachedAlpha(alpha, type);
  202.             this.cachedAlphaDot = Double.NaN;
  203.         }

  204.         serializePV = false;
  205.         partialPV   = null;

  206.     }

  207.     /** Creates a new instance with derivatives and with cached position angle same as value inputted.
  208.      * @param a  semi-major axis (m)
  209.      * @param ex e cos(ω), first component of circular eccentricity vector
  210.      * @param ey e sin(ω), second component of circular eccentricity vector
  211.      * @param i inclination (rad)
  212.      * @param raan right ascension of ascending node (Ω, rad)
  213.      * @param alpha  an + ω, mean, eccentric or true latitude argument (rad)
  214.      * @param aDot  semi-major axis derivative (m/s)
  215.      * @param exDot d(e cos(ω))/dt, first component of circular eccentricity vector derivative
  216.      * @param eyDot d(e sin(ω))/dt, second component of circular eccentricity vector derivative
  217.      * @param iDot inclination  derivative(rad/s)
  218.      * @param raanDot right ascension of ascending node derivative (rad/s)
  219.      * @param alphaDot  d(an + ω), mean, eccentric or true latitude argument derivative (rad/s)
  220.      * @param type type of latitude argument
  221.      * @param frame the frame in which are defined the parameters
  222.      * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame})
  223.      * @param date date of the orbital parameters
  224.      * @param mu central attraction coefficient (m³/s²)
  225.      * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or
  226.      * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame}
  227.      */
  228.     public CircularOrbit(final double a, final double ex, final double ey,
  229.                          final double i, final double raan, final double alpha,
  230.                          final double aDot, final double exDot, final double eyDot,
  231.                          final double iDot, final double raanDot, final double alphaDot,
  232.                          final PositionAngleType type,
  233.                          final Frame frame, final AbsoluteDate date, final double mu)
  234.             throws IllegalArgumentException {
  235.         this(a, ex, ey, i, raan, alpha, aDot, exDot, eyDot, iDot, raanDot, alphaDot, type, type,
  236.                 frame, date, mu);
  237.     }

  238.     /** Creates a new instance.
  239.      * @param a  semi-major axis (m)
  240.      * @param ex e cos(ω), first component of circular eccentricity vector
  241.      * @param ey e sin(ω), second component of circular eccentricity vector
  242.      * @param i inclination (rad)
  243.      * @param raan right ascension of ascending node (Ω, rad)
  244.      * @param alpha  input latitude argument (rad)
  245.      * @param aDot  semi-major axis derivative (m/s)
  246.      * @param exDot d(e cos(ω))/dt, first component of circular eccentricity vector derivative
  247.      * @param eyDot d(e sin(ω))/dt, second component of circular eccentricity vector derivative
  248.      * @param iDot inclination  derivative(rad/s)
  249.      * @param raanDot right ascension of ascending node derivative (rad/s)
  250.      * @param alphaDot  input latitude argument derivative (rad/s)
  251.      * @param pvCoordinates the {@link PVCoordinates} in inertial frame
  252.      * @param positionAngleType type of position angle
  253.      * @param frame the frame in which are defined the parameters
  254.      * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame})
  255.      * @param mu central attraction coefficient (m³/s²)
  256.      * @exception IllegalArgumentException if eccentricity is equal to 1 or larger or
  257.      * if frame is not a {@link Frame#isPseudoInertial pseudo-inertial frame}
  258.      */
  259.     private CircularOrbit(final double a, final double ex, final double ey,
  260.                           final double i, final double raan, final double alpha,
  261.                           final double aDot, final double exDot, final double eyDot,
  262.                           final double iDot, final double raanDot, final double alphaDot,
  263.                           final TimeStampedPVCoordinates pvCoordinates,
  264.                           final PositionAngleType positionAngleType, final Frame frame, final double mu)
  265.         throws IllegalArgumentException {
  266.         super(pvCoordinates, frame, mu);
  267.         this.a           =  a;
  268.         this.aDot        =  aDot;
  269.         this.ex          = ex;
  270.         this.exDot       = exDot;
  271.         this.ey          = ey;
  272.         this.eyDot       = eyDot;
  273.         this.i           = i;
  274.         this.iDot        = iDot;
  275.         this.raan        = raan;
  276.         this.raanDot     = raanDot;
  277.         this.cachedAlpha = alpha;
  278.         this.cachedAlphaDot = alphaDot;
  279.         this.cachedPositionAngleType = positionAngleType;
  280.         this.serializePV = true;
  281.         this.partialPV   = null;
  282.     }

  283.     /** Constructor from Cartesian parameters.
  284.      *
  285.      * <p> The acceleration provided in {@code pvCoordinates} is accessible using
  286.      * {@link #getPVCoordinates()} and {@link #getPVCoordinates(Frame)}. All other methods
  287.      * use {@code mu} and the position to compute the acceleration, including
  288.      * {@link #shiftedBy(double)} and {@link #getPVCoordinates(AbsoluteDate, Frame)}.
  289.      *
  290.      * @param pvCoordinates the {@link PVCoordinates} in inertial frame
  291.      * @param frame the frame in which are defined the {@link PVCoordinates}
  292.      * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame})
  293.      * @param mu central attraction coefficient (m³/s²)
  294.      * @exception IllegalArgumentException if frame is not a {@link
  295.      * Frame#isPseudoInertial pseudo-inertial frame}
  296.      */
  297.     public CircularOrbit(final TimeStampedPVCoordinates pvCoordinates, final Frame frame, final double mu)
  298.         throws IllegalArgumentException {
  299.         super(pvCoordinates, frame, mu);
  300.         this.cachedPositionAngleType = PositionAngleType.TRUE;

  301.         // compute semi-major axis
  302.         final Vector3D pvP = pvCoordinates.getPosition();
  303.         final Vector3D pvV = pvCoordinates.getVelocity();
  304.         final Vector3D pvA = pvCoordinates.getAcceleration();
  305.         final double r2 = pvP.getNormSq();
  306.         final double r  = FastMath.sqrt(r2);
  307.         final double V2 = pvV.getNormSq();
  308.         final double rV2OnMu = r * V2 / mu;
  309.         a = r / (2 - rV2OnMu);

  310.         if (!isElliptical()) {
  311.             throw new OrekitIllegalArgumentException(OrekitMessages.HYPERBOLIC_ORBIT_NOT_HANDLED_AS,
  312.                                                      getClass().getName());
  313.         }

  314.         // compute inclination
  315.         final Vector3D momentum = pvCoordinates.getMomentum();
  316.         i = Vector3D.angle(momentum, Vector3D.PLUS_K);

  317.         // compute right ascension of ascending node
  318.         final Vector3D node  = Vector3D.crossProduct(Vector3D.PLUS_K, momentum);
  319.         raan = FastMath.atan2(node.getY(), node.getX());

  320.         // 2D-coordinates in the canonical frame
  321.         final SinCos scRaan = FastMath.sinCos(raan);
  322.         final SinCos scI    = FastMath.sinCos(i);
  323.         final double xP     = pvP.getX();
  324.         final double yP     = pvP.getY();
  325.         final double zP     = pvP.getZ();
  326.         final double x2     = (xP * scRaan.cos() + yP * scRaan.sin()) / a;
  327.         final double y2     = ((yP * scRaan.cos() - xP * scRaan.sin()) * scI.cos() + zP * scI.sin()) / a;

  328.         // compute eccentricity vector
  329.         final double eSE    = Vector3D.dotProduct(pvP, pvV) / FastMath.sqrt(mu * a);
  330.         final double eCE    = rV2OnMu - 1;
  331.         final double e2     = eCE * eCE + eSE * eSE;
  332.         final double f      = eCE - e2;
  333.         final double g      = FastMath.sqrt(1 - e2) * eSE;
  334.         final double aOnR   = a / r;
  335.         final double a2OnR2 = aOnR * aOnR;
  336.         ex = a2OnR2 * (f * x2 + g * y2);
  337.         ey = a2OnR2 * (f * y2 - g * x2);

  338.         // compute latitude argument
  339.         final double beta = 1 / (1 + FastMath.sqrt(1 - ex * ex - ey * ey));
  340.         cachedAlpha = CircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, FastMath.atan2(y2 + ey + eSE * beta * ex, x2 + ex - eSE * beta * ey));

  341.         partialPV   = pvCoordinates;

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

  344.             final double[][] jacobian = new double[6][6];
  345.             getJacobianWrtCartesian(PositionAngleType.MEAN, jacobian);

  346.             final Vector3D keplerianAcceleration    = new Vector3D(-mu / (r * r2), pvP);
  347.             final Vector3D nonKeplerianAcceleration = pvA.subtract(keplerianAcceleration);
  348.             final double   aX                       = nonKeplerianAcceleration.getX();
  349.             final double   aY                       = nonKeplerianAcceleration.getY();
  350.             final double   aZ                       = nonKeplerianAcceleration.getZ();
  351.             aDot    = jacobian[0][3] * aX + jacobian[0][4] * aY + jacobian[0][5] * aZ;
  352.             exDot   = jacobian[1][3] * aX + jacobian[1][4] * aY + jacobian[1][5] * aZ;
  353.             eyDot   = jacobian[2][3] * aX + jacobian[2][4] * aY + jacobian[2][5] * aZ;
  354.             iDot    = jacobian[3][3] * aX + jacobian[3][4] * aY + jacobian[3][5] * aZ;
  355.             raanDot = jacobian[4][3] * aX + jacobian[4][4] * aY + jacobian[4][5] * aZ;

  356.             // in order to compute latitude argument derivative, we must compute
  357.             // mean latitude argument derivative including Keplerian motion and convert to true latitude argument
  358.             final double alphaMDot = getKeplerianMeanMotion() +
  359.                                      jacobian[5][3] * aX + jacobian[5][4] * aY + jacobian[5][5] * aZ;
  360.             final UnivariateDerivative1 exUD     = new UnivariateDerivative1(ex, exDot);
  361.             final UnivariateDerivative1 eyUD     = new UnivariateDerivative1(ey, eyDot);
  362.             final UnivariateDerivative1 alphaMUD = new UnivariateDerivative1(getAlphaM(), alphaMDot);
  363.             final UnivariateDerivative1 alphavUD = FieldCircularLatitudeArgumentUtility.meanToTrue(exUD, eyUD, alphaMUD);
  364.             cachedAlphaDot = alphavUD.getFirstDerivative();

  365.         } else {
  366.             // acceleration is either almost zero or NaN,
  367.             // we assume acceleration was not known
  368.             // we don't set up derivatives
  369.             aDot      = Double.NaN;
  370.             exDot     = Double.NaN;
  371.             eyDot     = Double.NaN;
  372.             iDot      = Double.NaN;
  373.             raanDot   = Double.NaN;
  374.             cachedAlphaDot = Double.NaN;
  375.         }

  376.         serializePV = true;

  377.     }

  378.     /** Constructor from Cartesian parameters.
  379.      *
  380.      * <p> The acceleration provided in {@code pvCoordinates} is accessible using
  381.      * {@link #getPVCoordinates()} and {@link #getPVCoordinates(Frame)}. All other methods
  382.      * use {@code mu} and the position to compute the acceleration, including
  383.      * {@link #shiftedBy(double)} and {@link #getPVCoordinates(AbsoluteDate, Frame)}.
  384.      *
  385.      * @param pvCoordinates the {@link PVCoordinates} in inertial frame
  386.      * @param frame the frame in which are defined the {@link PVCoordinates}
  387.      * (<em>must</em> be a {@link Frame#isPseudoInertial pseudo-inertial frame})
  388.      * @param date date of the orbital parameters
  389.      * @param mu central attraction coefficient (m³/s²)
  390.      * @exception IllegalArgumentException if frame is not a {@link
  391.      * Frame#isPseudoInertial pseudo-inertial frame}
  392.      */
  393.     public CircularOrbit(final PVCoordinates pvCoordinates, final Frame frame,
  394.                          final AbsoluteDate date, final double mu)
  395.         throws IllegalArgumentException {
  396.         this(new TimeStampedPVCoordinates(date, pvCoordinates), frame, mu);
  397.     }

  398.     /** Constructor from any kind of orbital parameters.
  399.      * @param op orbital parameters to copy
  400.      */
  401.     public CircularOrbit(final Orbit op) {

  402.         super(op.getFrame(), op.getDate(), op.getMu());

  403.         a    = op.getA();
  404.         i    = op.getI();
  405.         final double hx = op.getHx();
  406.         final double hy = op.getHy();
  407.         final double h2 = hx * hx + hy * hy;
  408.         final double h  = FastMath.sqrt(h2);
  409.         raan = FastMath.atan2(hy, hx);
  410.         final SinCos scRaan  = FastMath.sinCos(raan);
  411.         final double cosRaan = h == 0 ? scRaan.cos() : hx / h;
  412.         final double sinRaan = h == 0 ? scRaan.sin() : hy / h;
  413.         final double equiEx = op.getEquinoctialEx();
  414.         final double equiEy = op.getEquinoctialEy();
  415.         ex     = equiEx * cosRaan + equiEy * sinRaan;
  416.         ey     = equiEy * cosRaan - equiEx * sinRaan;
  417.         cachedPositionAngleType = PositionAngleType.TRUE;
  418.         cachedAlpha = op.getLv() - raan;

  419.         if (op.hasDerivatives()) {
  420.             aDot    = op.getADot();
  421.             final double hxDot = op.getHxDot();
  422.             final double hyDot = op.getHyDot();
  423.             iDot    = 2 * (cosRaan * hxDot + sinRaan * hyDot) / (1 + h2);
  424.             raanDot = (hx * hyDot - hy * hxDot) / h2;
  425.             final double equiExDot = op.getEquinoctialExDot();
  426.             final double equiEyDot = op.getEquinoctialEyDot();
  427.             exDot   = (equiExDot + equiEy * raanDot) * cosRaan +
  428.                       (equiEyDot - equiEx * raanDot) * sinRaan;
  429.             eyDot   = (equiEyDot - equiEx * raanDot) * cosRaan -
  430.                       (equiExDot + equiEy * raanDot) * sinRaan;
  431.             cachedAlphaDot = op.getLvDot() - raanDot;
  432.         } else {
  433.             aDot      = Double.NaN;
  434.             exDot     = Double.NaN;
  435.             eyDot     = Double.NaN;
  436.             iDot      = Double.NaN;
  437.             raanDot   = Double.NaN;
  438.             cachedAlphaDot = Double.NaN;
  439.         }

  440.         serializePV = false;
  441.         partialPV   = null;

  442.     }

  443.     /** {@inheritDoc} */
  444.     @Override
  445.     public OrbitType getType() {
  446.         return OrbitType.CIRCULAR;
  447.     }

  448.     /** {@inheritDoc} */
  449.     @Override
  450.     public double getA() {
  451.         return a;
  452.     }

  453.     /** {@inheritDoc} */
  454.     @Override
  455.     public double getADot() {
  456.         return aDot;
  457.     }

  458.     /** {@inheritDoc} */
  459.     @Override
  460.     public double getEquinoctialEx() {
  461.         final SinCos sc = FastMath.sinCos(raan);
  462.         return ex * sc.cos() - ey * sc.sin();
  463.     }

  464.     /** {@inheritDoc} */
  465.     @Override
  466.     public double getEquinoctialExDot() {
  467.         final SinCos sc = FastMath.sinCos(raan);
  468.         return (exDot - ey * raanDot) * sc.cos() - (eyDot + ex * raanDot) * sc.sin();
  469.     }

  470.     /** {@inheritDoc} */
  471.     @Override
  472.     public double getEquinoctialEy() {
  473.         final SinCos sc = FastMath.sinCos(raan);
  474.         return ey * sc.cos() + ex * sc.sin();
  475.     }

  476.     /** {@inheritDoc} */
  477.     @Override
  478.     public double getEquinoctialEyDot() {
  479.         final SinCos sc = FastMath.sinCos(raan);
  480.         return (eyDot + ex * raanDot) * sc.cos() + (exDot - ey * raanDot) * sc.sin();
  481.     }

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

  488.     /** Get the first component of the circular eccentricity vector derivative.
  489.      * @return ex = e cos(ω), first component of the circular eccentricity vector derivative
  490.      * @since 9.0
  491.      */
  492.     public double getCircularExDot() {
  493.         return exDot;
  494.     }

  495.     /** Get the second component of the circular eccentricity vector.
  496.      * @return ey = e sin(ω), second component of the circular eccentricity vector
  497.      */
  498.     public double getCircularEy() {
  499.         return ey;
  500.     }

  501.     /** Get the second component of the circular eccentricity vector derivative.
  502.      * @return ey = e sin(ω), second component of the circular eccentricity vector derivative
  503.      */
  504.     public double getCircularEyDot() {
  505.         return eyDot;
  506.     }

  507.     /** {@inheritDoc} */
  508.     @Override
  509.     public double getHx() {
  510.         // Check for equatorial retrograde orbit
  511.         if (FastMath.abs(i - FastMath.PI) < 1.0e-10) {
  512.             return Double.NaN;
  513.         }
  514.         return  FastMath.cos(raan) * FastMath.tan(i / 2);
  515.     }

  516.     /** {@inheritDoc} */
  517.     @Override
  518.     public double getHxDot() {
  519.         // Check for equatorial retrograde orbit
  520.         if (FastMath.abs(i - FastMath.PI) < 1.0e-10) {
  521.             return Double.NaN;
  522.         }
  523.         final SinCos sc  = FastMath.sinCos(raan);
  524.         final double tan = FastMath.tan(0.5 * i);
  525.         return 0.5 * sc.cos() * (1 + tan * tan) * iDot - sc.sin() * tan * raanDot;
  526.     }

  527.     /** {@inheritDoc} */
  528.     @Override
  529.     public double getHy() {
  530.         // Check for equatorial retrograde orbit
  531.         if (FastMath.abs(i - FastMath.PI) < 1.0e-10) {
  532.             return Double.NaN;
  533.         }
  534.         return  FastMath.sin(raan) * FastMath.tan(i / 2);
  535.     }

  536.     /** {@inheritDoc} */
  537.     @Override
  538.     public double getHyDot() {
  539.         // Check for equatorial retrograde orbit
  540.         if (FastMath.abs(i - FastMath.PI) < 1.0e-10) {
  541.             return Double.NaN;
  542.         }
  543.         final SinCos sc  = FastMath.sinCos(raan);
  544.         final double tan = FastMath.tan(0.5 * i);
  545.         return 0.5 * sc.sin() * (1 + tan * tan) * iDot + sc.cos() * tan * raanDot;
  546.     }

  547.     /** Get the true latitude argument.
  548.      * @return v + ω true latitude argument (rad)
  549.      */
  550.     public double getAlphaV() {
  551.         switch (cachedPositionAngleType) {
  552.             case TRUE:
  553.                 return cachedAlpha;

  554.             case ECCENTRIC:
  555.                 return CircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, cachedAlpha);

  556.             case MEAN:
  557.                 return CircularLatitudeArgumentUtility.meanToTrue(ex, ey, cachedAlpha);

  558.             default:
  559.                 throw new OrekitInternalError(null);
  560.         }
  561.     }

  562.     /** Get the true latitude argument derivative.
  563.      * <p>
  564.      * If the orbit was created without derivatives, the value returned is {@link Double#NaN}.
  565.      * </p>
  566.      * @return v + ω true latitude argument derivative (rad/s)
  567.      * @since 9.0
  568.      */
  569.     public double getAlphaVDot() {
  570.         switch (cachedPositionAngleType) {
  571.             case ECCENTRIC:
  572.                 final UnivariateDerivative1 alphaEUD = new UnivariateDerivative1(cachedAlpha, cachedAlphaDot);
  573.                 final UnivariateDerivative1 exUD     = new UnivariateDerivative1(ex,     exDot);
  574.                 final UnivariateDerivative1 eyUD     = new UnivariateDerivative1(ey,     eyDot);
  575.                 final UnivariateDerivative1 alphaVUD = FieldCircularLatitudeArgumentUtility.eccentricToTrue(exUD, eyUD,
  576.                         alphaEUD);
  577.                 return alphaVUD.getFirstDerivative();

  578.             case TRUE:
  579.                 return cachedAlphaDot;

  580.             case MEAN:
  581.                 final UnivariateDerivative1 alphaMUD = new UnivariateDerivative1(cachedAlpha, cachedAlphaDot);
  582.                 final UnivariateDerivative1 exUD2    = new UnivariateDerivative1(ex,     exDot);
  583.                 final UnivariateDerivative1 eyUD2    = new UnivariateDerivative1(ey,     eyDot);
  584.                 final UnivariateDerivative1 alphaVUD2 = FieldCircularLatitudeArgumentUtility.meanToTrue(exUD2,
  585.                         eyUD2, alphaMUD);
  586.                 return alphaVUD2.getFirstDerivative();

  587.             default:
  588.                 throw new OrekitInternalError(null);
  589.         }
  590.     }

  591.     /** Get the eccentric latitude argument.
  592.      * @return E + ω eccentric latitude argument (rad)
  593.      */
  594.     public double getAlphaE() {
  595.         switch (cachedPositionAngleType) {
  596.             case TRUE:
  597.                 return CircularLatitudeArgumentUtility.trueToEccentric(ex, ey, cachedAlpha);

  598.             case ECCENTRIC:
  599.                 return cachedAlpha;

  600.             case MEAN:
  601.                 return CircularLatitudeArgumentUtility.meanToEccentric(ex, ey, cachedAlpha);

  602.             default:
  603.                 throw new OrekitInternalError(null);
  604.         }
  605.     }

  606.     /** Get the eccentric latitude argument derivative.
  607.      * <p>
  608.      * If the orbit was created without derivatives, the value returned is {@link Double#NaN}.
  609.      * </p>
  610.      * @return d(E + ω)/dt eccentric latitude argument derivative (rad/s)
  611.      * @since 9.0
  612.      */
  613.     public double getAlphaEDot() {
  614.         switch (cachedPositionAngleType) {
  615.             case TRUE:
  616.                 final UnivariateDerivative1 alphaVUD = new UnivariateDerivative1(cachedAlpha, cachedAlphaDot);
  617.                 final UnivariateDerivative1 exUD     = new UnivariateDerivative1(ex,     exDot);
  618.                 final UnivariateDerivative1 eyUD     = new UnivariateDerivative1(ey,     eyDot);
  619.                 final UnivariateDerivative1 alphaEUD = FieldCircularLatitudeArgumentUtility.trueToEccentric(exUD, eyUD,
  620.                         alphaVUD);
  621.                 return alphaEUD.getFirstDerivative();

  622.             case ECCENTRIC:
  623.                 return cachedAlphaDot;

  624.             case MEAN:
  625.                 final UnivariateDerivative1 alphaMUD = new UnivariateDerivative1(cachedAlpha, cachedAlphaDot);
  626.                 final UnivariateDerivative1 exUD2    = new UnivariateDerivative1(ex,     exDot);
  627.                 final UnivariateDerivative1 eyUD2    = new UnivariateDerivative1(ey,     eyDot);
  628.                 final UnivariateDerivative1 alphaVUD2 = FieldCircularLatitudeArgumentUtility.meanToEccentric(exUD2,
  629.                         eyUD2, alphaMUD);
  630.                 return alphaVUD2.getFirstDerivative();

  631.             default:
  632.                 throw new OrekitInternalError(null);
  633.         }
  634.     }

  635.     /** Get the mean latitude argument.
  636.      * @return M + ω mean latitude argument (rad)
  637.      */
  638.     public double getAlphaM() {
  639.         switch (cachedPositionAngleType) {
  640.             case TRUE:
  641.                 return CircularLatitudeArgumentUtility.trueToMean(ex, ey, cachedAlpha);

  642.             case MEAN:
  643.                 return cachedAlpha;

  644.             case ECCENTRIC:
  645.                 return CircularLatitudeArgumentUtility.eccentricToMean(ex, ey, cachedAlpha);

  646.             default:
  647.                 throw new OrekitInternalError(null);
  648.         }
  649.     }

  650.     /** Get the mean latitude argument derivative.
  651.      * <p>
  652.      * If the orbit was created without derivatives, the value returned is {@link Double#NaN}.
  653.      * </p>
  654.      * @return d(M + ω)/dt mean latitude argument derivative (rad/s)
  655.      * @since 9.0
  656.      */
  657.     public double getAlphaMDot() {
  658.         switch (cachedPositionAngleType) {
  659.             case TRUE:
  660.                 final UnivariateDerivative1 alphaVUD = new UnivariateDerivative1(cachedAlpha, cachedAlphaDot);
  661.                 final UnivariateDerivative1 exUD     = new UnivariateDerivative1(ex,     exDot);
  662.                 final UnivariateDerivative1 eyUD     = new UnivariateDerivative1(ey,     eyDot);
  663.                 final UnivariateDerivative1 alphaMUD = FieldCircularLatitudeArgumentUtility.trueToMean(exUD, eyUD,
  664.                         alphaVUD);
  665.                 return alphaMUD.getFirstDerivative();

  666.             case MEAN:
  667.                 return cachedAlphaDot;

  668.             case ECCENTRIC:
  669.                 final UnivariateDerivative1 alphaEUD = new UnivariateDerivative1(cachedAlpha, cachedAlphaDot);
  670.                 final UnivariateDerivative1 exUD2    = new UnivariateDerivative1(ex,     exDot);
  671.                 final UnivariateDerivative1 eyUD2    = new UnivariateDerivative1(ey,     eyDot);
  672.                 final UnivariateDerivative1 alphaMUD2 = FieldCircularLatitudeArgumentUtility.eccentricToMean(exUD2,
  673.                         eyUD2, alphaEUD);
  674.                 return alphaMUD2.getFirstDerivative();

  675.             default:
  676.                 throw new OrekitInternalError(null);
  677.         }
  678.     }

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

  688.     /** Get the latitude argument derivative.
  689.      * <p>
  690.      * If the orbit was created without derivatives, the value returned is {@link Double#NaN}.
  691.      * </p>
  692.      * @param type type of the angle
  693.      * @return latitude argument derivative (rad/s)
  694.      * @since 9.0
  695.      */
  696.     public double getAlphaDot(final PositionAngleType type) {
  697.         return (type == PositionAngleType.MEAN) ? getAlphaMDot() :
  698.                                               ((type == PositionAngleType.ECCENTRIC) ? getAlphaEDot() :
  699.                                                                                    getAlphaVDot());
  700.     }

  701.     /** Computes the true latitude argument from the eccentric latitude argument.
  702.      * @param alphaE = E + ω eccentric latitude argument (rad)
  703.      * @param ex e cos(ω), first component of circular eccentricity vector
  704.      * @param ey e sin(ω), second component of circular eccentricity vector
  705.      * @return the true latitude argument.
  706.      */
  707.     @Deprecated
  708.     public static double eccentricToTrue(final double alphaE, final double ex, final double ey) {
  709.         return CircularLatitudeArgumentUtility.eccentricToTrue(ex, ey, alphaE);
  710.     }

  711.     /** Computes the eccentric latitude argument from the true latitude argument.
  712.      * @param alphaV = V + ω true latitude argument (rad)
  713.      * @param ex e cos(ω), first component of circular eccentricity vector
  714.      * @param ey e sin(ω), second component of circular eccentricity vector
  715.      * @return the eccentric latitude argument.
  716.      */
  717.     @Deprecated
  718.     public static double trueToEccentric(final double alphaV, final double ex, final double ey) {
  719.         return CircularLatitudeArgumentUtility.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.      * @return the eccentric latitude argument.
  726.      */
  727.     @Deprecated
  728.     public static double meanToEccentric(final double alphaM, final double ex, final double ey) {
  729.         return CircularLatitudeArgumentUtility.meanToEccentric(ex, ey, alphaM);
  730.     }

  731.     /** Computes the mean latitude argument from the eccentric latitude argument.
  732.      * @param alphaE = E + ω  mean latitude argument (rad)
  733.      * @param ex e cos(ω), first component of circular eccentricity vector
  734.      * @param ey e sin(ω), second component of circular eccentricity vector
  735.      * @return the mean latitude argument.
  736.      */
  737.     @Deprecated
  738.     public static double eccentricToMean(final double alphaE, final double ex, final double ey) {
  739.         return CircularLatitudeArgumentUtility.eccentricToMean(ex, ey, alphaE);
  740.     }

  741.     /** {@inheritDoc} */
  742.     @Override
  743.     public double getE() {
  744.         return FastMath.sqrt(ex * ex + ey * ey);
  745.     }

  746.     /** {@inheritDoc} */
  747.     @Override
  748.     public double getEDot() {
  749.         return (ex * exDot + ey * eyDot) / getE();
  750.     }

  751.     /** {@inheritDoc} */
  752.     @Override
  753.     public double getI() {
  754.         return i;
  755.     }

  756.     /** {@inheritDoc} */
  757.     @Override
  758.     public double getIDot() {
  759.         return iDot;
  760.     }

  761.     /** Get the right ascension of the ascending node.
  762.      * @return right ascension of the ascending node (rad)
  763.      */
  764.     public double getRightAscensionOfAscendingNode() {
  765.         return raan;
  766.     }

  767.     /** Get the right ascension of the ascending node derivative.
  768.      * <p>
  769.      * If the orbit was created without derivatives, the value returned is {@link Double#NaN}.
  770.      * </p>
  771.      * @return right ascension of the ascending node derivative (rad/s)
  772.      * @since 9.0
  773.      */
  774.     public double getRightAscensionOfAscendingNodeDot() {
  775.         return raanDot;
  776.     }

  777.     /** {@inheritDoc} */
  778.     @Override
  779.     public double getLv() {
  780.         return getAlphaV() + raan;
  781.     }

  782.     /** {@inheritDoc} */
  783.     @Override
  784.     public double getLvDot() {
  785.         return getAlphaVDot() + raanDot;
  786.     }

  787.     /** {@inheritDoc} */
  788.     @Override
  789.     public double getLE() {
  790.         return getAlphaE() + raan;
  791.     }

  792.     /** {@inheritDoc} */
  793.     @Override
  794.     public double getLEDot() {
  795.         return getAlphaEDot() + raanDot;
  796.     }

  797.     /** {@inheritDoc} */
  798.     @Override
  799.     public double getLM() {
  800.         return getAlphaM() + raan;
  801.     }

  802.     /** {@inheritDoc} */
  803.     @Override
  804.     public double getLMDot() {
  805.         return getAlphaMDot() + raanDot;
  806.     }

  807.     /** Compute position and velocity but not acceleration.
  808.      */
  809.     private void computePVWithoutA() {

  810.         if (partialPV != null) {
  811.             // already computed
  812.             return;
  813.         }

  814.         // get equinoctial parameters
  815.         final double equEx = getEquinoctialEx();
  816.         final double equEy = getEquinoctialEy();
  817.         final double hx = getHx();
  818.         final double hy = getHy();
  819.         final double lE = getLE();

  820.         // inclination-related intermediate parameters
  821.         final double hx2   = hx * hx;
  822.         final double hy2   = hy * hy;
  823.         final double factH = 1. / (1 + hx2 + hy2);

  824.         // reference axes defining the orbital plane
  825.         final double ux = (1 + hx2 - hy2) * factH;
  826.         final double uy =  2 * hx * hy * factH;
  827.         final double uz = -2 * hy * factH;

  828.         final double vx = uy;
  829.         final double vy = (1 - hx2 + hy2) * factH;
  830.         final double vz =  2 * hx * factH;

  831.         // eccentricity-related intermediate parameters
  832.         final double exey = equEx * equEy;
  833.         final double ex2  = equEx * equEx;
  834.         final double ey2  = equEy * equEy;
  835.         final double e2   = ex2 + ey2;
  836.         final double eta  = 1 + FastMath.sqrt(1 - e2);
  837.         final double beta = 1. / eta;

  838.         // eccentric latitude argument
  839.         final SinCos scLe   = FastMath.sinCos(lE);
  840.         final double cLe    = scLe.cos();
  841.         final double sLe    = scLe.sin();
  842.         final double exCeyS = equEx * cLe + equEy * sLe;

  843.         // coordinates of position and velocity in the orbital plane
  844.         final double x      = a * ((1 - beta * ey2) * cLe + beta * exey * sLe - equEx);
  845.         final double y      = a * ((1 - beta * ex2) * sLe + beta * exey * cLe - equEy);

  846.         final double factor = FastMath.sqrt(getMu() / a) / (1 - exCeyS);
  847.         final double xdot   = factor * (-sLe + beta * equEy * exCeyS);
  848.         final double ydot   = factor * ( cLe - beta * equEx * exCeyS);

  849.         final Vector3D position =
  850.                         new Vector3D(x * ux + y * vx, x * uy + y * vy, x * uz + y * vz);
  851.         final Vector3D velocity =
  852.                         new Vector3D(xdot * ux + ydot * vx, xdot * uy + ydot * vy, xdot * uz + ydot * vz);

  853.         partialPV = new PVCoordinates(position, velocity);

  854.     }

  855.     /** Initialize cached alpha with rate.
  856.      * @param alpha input alpha
  857.      * @param alphaDot rate of input alpha
  858.      * @param inputType position angle type passed as input
  859.      * @return alpha to cache with rate
  860.      * @since 12.1
  861.      */
  862.     private UnivariateDerivative1 initializeCachedAlpha(final double alpha, final double alphaDot,
  863.                                                         final PositionAngleType inputType) {
  864.         if (cachedPositionAngleType == inputType) {
  865.             return new UnivariateDerivative1(alpha, alphaDot);

  866.         } else {
  867.             final UnivariateDerivative1 exUD = new UnivariateDerivative1(ex, exDot);
  868.             final UnivariateDerivative1 eyUD = new UnivariateDerivative1(ey, eyDot);
  869.             final UnivariateDerivative1 alphaUD = new UnivariateDerivative1(alpha, alphaDot);

  870.             switch (cachedPositionAngleType) {

  871.                 case ECCENTRIC:
  872.                     if (inputType == PositionAngleType.MEAN) {
  873.                         return FieldCircularLatitudeArgumentUtility.meanToEccentric(exUD, eyUD, alphaUD);
  874.                     } else {
  875.                         return FieldCircularLatitudeArgumentUtility.trueToEccentric(exUD, eyUD, alphaUD);
  876.                     }

  877.                 case TRUE:
  878.                     if (inputType == PositionAngleType.MEAN) {
  879.                         return FieldCircularLatitudeArgumentUtility.meanToTrue(exUD, eyUD, alphaUD);
  880.                     } else {
  881.                         return FieldCircularLatitudeArgumentUtility.eccentricToTrue(exUD, eyUD, alphaUD);
  882.                     }

  883.                 case MEAN:
  884.                     if (inputType == PositionAngleType.TRUE) {
  885.                         return FieldCircularLatitudeArgumentUtility.trueToMean(exUD, eyUD, alphaUD);
  886.                     } else {
  887.                         return FieldCircularLatitudeArgumentUtility.eccentricToMean(exUD, eyUD, alphaUD);
  888.                     }

  889.                 default:
  890.                     throw new OrekitInternalError(null);

  891.             }

  892.         }

  893.     }

  894.     /** Initialize cached alpha.
  895.      * @param alpha input alpha
  896.      * @param positionAngleType position angle type passed as input
  897.      * @return alpha to cache
  898.      * @since 12.1
  899.      */
  900.     private double initializeCachedAlpha(final double alpha, final PositionAngleType positionAngleType) {
  901.         return CircularLatitudeArgumentUtility.convertAlpha(positionAngleType, alpha, ex, ey, cachedPositionAngleType);
  902.     }

  903.     /** Compute non-Keplerian part of the acceleration from first time derivatives.
  904.      * <p>
  905.      * This method should be called only when {@link #hasDerivatives()} returns true.
  906.      * </p>
  907.      * @return non-Keplerian part of the acceleration
  908.      */
  909.     private Vector3D nonKeplerianAcceleration() {

  910.         final double[][] dCdP = new double[6][6];
  911.         getJacobianWrtParameters(PositionAngleType.MEAN, dCdP);

  912.         final double nonKeplerianMeanMotion = getAlphaMDot() - getKeplerianMeanMotion();
  913.         final double nonKeplerianAx = dCdP[3][0] * aDot    + dCdP[3][1] * exDot   + dCdP[3][2] * eyDot   +
  914.                                       dCdP[3][3] * iDot    + dCdP[3][4] * raanDot + dCdP[3][5] * nonKeplerianMeanMotion;
  915.         final double nonKeplerianAy = dCdP[4][0] * aDot    + dCdP[4][1] * exDot   + dCdP[4][2] * eyDot   +
  916.                                       dCdP[4][3] * iDot    + dCdP[4][4] * raanDot + dCdP[4][5] * nonKeplerianMeanMotion;
  917.         final double nonKeplerianAz = dCdP[5][0] * aDot    + dCdP[5][1] * exDot   + dCdP[5][2] * eyDot   +
  918.                                       dCdP[5][3] * iDot    + dCdP[5][4] * raanDot + dCdP[5][5] * nonKeplerianMeanMotion;

  919.         return new Vector3D(nonKeplerianAx, nonKeplerianAy, nonKeplerianAz);

  920.     }

  921.     /** {@inheritDoc} */
  922.     @Override
  923.     protected Vector3D initPosition() {

  924.         // get equinoctial parameters
  925.         final double equEx = getEquinoctialEx();
  926.         final double equEy = getEquinoctialEy();
  927.         final double hx = getHx();
  928.         final double hy = getHy();
  929.         final double lE = getLE();

  930.         // inclination-related intermediate parameters
  931.         final double hx2   = hx * hx;
  932.         final double hy2   = hy * hy;
  933.         final double factH = 1. / (1 + hx2 + hy2);

  934.         // reference axes defining the orbital plane
  935.         final double ux = (1 + hx2 - hy2) * factH;
  936.         final double uy =  2 * hx * hy * factH;
  937.         final double uz = -2 * hy * factH;

  938.         final double vx = uy;
  939.         final double vy = (1 - hx2 + hy2) * factH;
  940.         final double vz =  2 * hx * factH;

  941.         // eccentricity-related intermediate parameters
  942.         final double exey = equEx * equEy;
  943.         final double ex2  = equEx * equEx;
  944.         final double ey2  = equEy * equEy;
  945.         final double e2   = ex2 + ey2;
  946.         final double eta  = 1 + FastMath.sqrt(1 - e2);
  947.         final double beta = 1. / eta;

  948.         // eccentric latitude argument
  949.         final SinCos scLe   = FastMath.sinCos(lE);
  950.         final double cLe    = scLe.cos();
  951.         final double sLe    = scLe.sin();

  952.         // coordinates of position and velocity in the orbital plane
  953.         final double x      = a * ((1 - beta * ey2) * cLe + beta * exey * sLe - equEx);
  954.         final double y      = a * ((1 - beta * ex2) * sLe + beta * exey * cLe - equEy);

  955.         return new Vector3D(x * ux + y * vx, x * uy + y * vy, x * uz + y * vz);

  956.     }

  957.     /** {@inheritDoc} */
  958.     @Override
  959.     protected TimeStampedPVCoordinates initPVCoordinates() {

  960.         // position and velocity
  961.         computePVWithoutA();

  962.         // acceleration
  963.         final double r2 = partialPV.getPosition().getNormSq();
  964.         final Vector3D keplerianAcceleration = new Vector3D(-getMu() / (r2 * FastMath.sqrt(r2)), partialPV.getPosition());
  965.         final Vector3D acceleration = hasDerivatives() ?
  966.                                       keplerianAcceleration.add(nonKeplerianAcceleration()) :
  967.                                       keplerianAcceleration;

  968.         return new TimeStampedPVCoordinates(getDate(), partialPV.getPosition(), partialPV.getVelocity(), acceleration);

  969.     }

  970.     /** {@inheritDoc} */
  971.     @Override
  972.     public CircularOrbit shiftedBy(final double dt) {

  973.         // use Keplerian-only motion
  974.         final CircularOrbit keplerianShifted = new CircularOrbit(a, ex, ey, i, raan,
  975.                                                                  getAlphaM() + getKeplerianMeanMotion() * dt,
  976.                                                                  PositionAngleType.MEAN, cachedPositionAngleType,
  977.                                                                  getFrame(), getDate().shiftedBy(dt), getMu());

  978.         if (hasDerivatives()) {

  979.             // extract non-Keplerian acceleration from first time derivatives
  980.             final Vector3D nonKeplerianAcceleration = nonKeplerianAcceleration();

  981.             // add quadratic effect of non-Keplerian acceleration to Keplerian-only shift
  982.             keplerianShifted.computePVWithoutA();
  983.             final Vector3D fixedP   = new Vector3D(1, keplerianShifted.partialPV.getPosition(),
  984.                                                    0.5 * dt * dt, nonKeplerianAcceleration);
  985.             final double   fixedR2 = fixedP.getNormSq();
  986.             final double   fixedR  = FastMath.sqrt(fixedR2);
  987.             final Vector3D fixedV  = new Vector3D(1, keplerianShifted.partialPV.getVelocity(),
  988.                                                   dt, nonKeplerianAcceleration);
  989.             final Vector3D fixedA  = new Vector3D(-getMu() / (fixedR2 * fixedR), keplerianShifted.partialPV.getPosition(),
  990.                                                   1, nonKeplerianAcceleration);

  991.             // build a new orbit, taking non-Keplerian acceleration into account
  992.             return new CircularOrbit(new TimeStampedPVCoordinates(keplerianShifted.getDate(),
  993.                                                                   fixedP, fixedV, fixedA),
  994.                                      keplerianShifted.getFrame(), keplerianShifted.getMu());

  995.         } else {
  996.             // Keplerian-only motion is all we can do
  997.             return keplerianShifted;
  998.         }

  999.     }

  1000.     /** {@inheritDoc} */
  1001.     @Override
  1002.     protected double[][] computeJacobianMeanWrtCartesian() {


  1003.         final double[][] jacobian = new double[6][6];

  1004.         computePVWithoutA();
  1005.         final Vector3D position = partialPV.getPosition();
  1006.         final Vector3D velocity = partialPV.getVelocity();
  1007.         final double x          = position.getX();
  1008.         final double y          = position.getY();
  1009.         final double z          = position.getZ();
  1010.         final double vx         = velocity.getX();
  1011.         final double vy         = velocity.getY();
  1012.         final double vz         = velocity.getZ();
  1013.         final double pv         = Vector3D.dotProduct(position, velocity);
  1014.         final double r2         = position.getNormSq();
  1015.         final double r          = FastMath.sqrt(r2);
  1016.         final double v2         = velocity.getNormSq();

  1017.         final double mu         = getMu();
  1018.         final double oOsqrtMuA  = 1 / FastMath.sqrt(mu * a);
  1019.         final double rOa        = r / a;
  1020.         final double aOr        = a / r;
  1021.         final double aOr2       = a / r2;
  1022.         final double a2         = a * a;

  1023.         final double ex2        = ex * ex;
  1024.         final double ey2        = ey * ey;
  1025.         final double e2         = ex2 + ey2;
  1026.         final double epsilon    = FastMath.sqrt(1 - e2);
  1027.         final double beta       = 1 / (1 + epsilon);

  1028.         final double eCosE      = 1 - rOa;
  1029.         final double eSinE      = pv * oOsqrtMuA;

  1030.         final SinCos scI    = FastMath.sinCos(i);
  1031.         final SinCos scRaan = FastMath.sinCos(raan);
  1032.         final double cosI       = scI.cos();
  1033.         final double sinI       = scI.sin();
  1034.         final double cosRaan    = scRaan.cos();
  1035.         final double sinRaan    = scRaan.sin();

  1036.         // da
  1037.         fillHalfRow(2 * aOr * aOr2, position, jacobian[0], 0);
  1038.         fillHalfRow(2 * a2 / mu, velocity, jacobian[0], 3);

  1039.         // differentials of the normalized momentum
  1040.         final Vector3D danP = new Vector3D(v2, position, -pv, velocity);
  1041.         final Vector3D danV = new Vector3D(r2, velocity, -pv, position);
  1042.         final double recip  = 1 / partialPV.getMomentum().getNorm();
  1043.         final double recip2 = recip * recip;
  1044.         final Vector3D dwXP = new Vector3D(recip, new Vector3D(  0,  vz, -vy), -recip2 * sinRaan * sinI, danP);
  1045.         final Vector3D dwYP = new Vector3D(recip, new Vector3D(-vz,   0,  vx),  recip2 * cosRaan * sinI, danP);
  1046.         final Vector3D dwZP = new Vector3D(recip, new Vector3D( vy, -vx,   0), -recip2 * cosI,           danP);
  1047.         final Vector3D dwXV = new Vector3D(recip, new Vector3D(  0,  -z,   y), -recip2 * sinRaan * sinI, danV);
  1048.         final Vector3D dwYV = new Vector3D(recip, new Vector3D(  z,   0,  -x),  recip2 * cosRaan * sinI, danV);
  1049.         final Vector3D dwZV = new Vector3D(recip, new Vector3D( -y,   x,   0), -recip2 * cosI,           danV);

  1050.         // di
  1051.         fillHalfRow(sinRaan * cosI, dwXP, -cosRaan * cosI, dwYP, -sinI, dwZP, jacobian[3], 0);
  1052.         fillHalfRow(sinRaan * cosI, dwXV, -cosRaan * cosI, dwYV, -sinI, dwZV, jacobian[3], 3);

  1053.         // dRaan
  1054.         fillHalfRow(sinRaan / sinI, dwYP, cosRaan / sinI, dwXP, jacobian[4], 0);
  1055.         fillHalfRow(sinRaan / sinI, dwYV, cosRaan / sinI, dwXV, jacobian[4], 3);

  1056.         // orbital frame: (p, q, w) p along ascending node, w along momentum
  1057.         // the coordinates of the spacecraft in this frame are: (u, v, 0)
  1058.         final double u     =  x * cosRaan + y * sinRaan;
  1059.         final double cv    = -x * sinRaan + y * cosRaan;
  1060.         final double v     = cv * cosI + z * sinI;

  1061.         // du
  1062.         final Vector3D duP = new Vector3D(cv * cosRaan / sinI, dwXP,
  1063.                                           cv * sinRaan / sinI, dwYP,
  1064.                                           1, new Vector3D(cosRaan, sinRaan, 0));
  1065.         final Vector3D duV = new Vector3D(cv * cosRaan / sinI, dwXV,
  1066.                                           cv * sinRaan / sinI, dwYV);

  1067.         // dv
  1068.         final Vector3D dvP = new Vector3D(-u * cosRaan * cosI / sinI + sinRaan * z, dwXP,
  1069.                                           -u * sinRaan * cosI / sinI - cosRaan * z, dwYP,
  1070.                                           cv, dwZP,
  1071.                                           1, new Vector3D(-sinRaan * cosI, cosRaan * cosI, sinI));
  1072.         final Vector3D dvV = new Vector3D(-u * cosRaan * cosI / sinI + sinRaan * z, dwXV,
  1073.                                           -u * sinRaan * cosI / sinI - cosRaan * z, dwYV,
  1074.                                           cv, dwZV);

  1075.         final Vector3D dc1P = new Vector3D(aOr2 * (2 * eSinE * eSinE + 1 - eCosE) / r2, position,
  1076.                                             -2 * aOr2 * eSinE * oOsqrtMuA, velocity);
  1077.         final Vector3D dc1V = new Vector3D(-2 * aOr2 * eSinE * oOsqrtMuA, position,
  1078.                                             2 / mu, velocity);
  1079.         final Vector3D dc2P = new Vector3D(aOr2 * eSinE * (eSinE * eSinE - (1 - e2)) / (r2 * epsilon), position,
  1080.                                             aOr2 * (1 - e2 - eSinE * eSinE) * oOsqrtMuA / epsilon, velocity);
  1081.         final Vector3D dc2V = new Vector3D(aOr2 * (1 - e2 - eSinE * eSinE) * oOsqrtMuA / epsilon, position,
  1082.                                             eSinE / (mu * epsilon), velocity);

  1083.         final double cof1   = aOr2 * (eCosE - e2);
  1084.         final double cof2   = aOr2 * epsilon * eSinE;
  1085.         final Vector3D dexP = new Vector3D(u, dc1P,  v, dc2P, cof1, duP,  cof2, dvP);
  1086.         final Vector3D dexV = new Vector3D(u, dc1V,  v, dc2V, cof1, duV,  cof2, dvV);
  1087.         final Vector3D deyP = new Vector3D(v, dc1P, -u, dc2P, cof1, dvP, -cof2, duP);
  1088.         final Vector3D deyV = new Vector3D(v, dc1V, -u, dc2V, cof1, dvV, -cof2, duV);
  1089.         fillHalfRow(1, dexP, jacobian[1], 0);
  1090.         fillHalfRow(1, dexV, jacobian[1], 3);
  1091.         fillHalfRow(1, deyP, jacobian[2], 0);
  1092.         fillHalfRow(1, deyV, jacobian[2], 3);

  1093.         final double cle = u / a + ex - eSinE * beta * ey;
  1094.         final double sle = v / a + ey + eSinE * beta * ex;
  1095.         final double m1  = beta * eCosE;
  1096.         final double m2  = 1 - m1 * eCosE;
  1097.         final double m3  = (u * ey - v * ex) + eSinE * beta * (u * ex + v * ey);
  1098.         final double m4  = -sle + cle * eSinE * beta;
  1099.         final double m5  = cle + sle * eSinE * beta;
  1100.         fillHalfRow((2 * m3 / r + aOr * eSinE + m1 * eSinE * (1 + m1 - (1 + aOr) * m2) / epsilon) / r2, position,
  1101.                     (m1 * m2 / epsilon - 1) * oOsqrtMuA, velocity,
  1102.                     m4, dexP, m5, deyP, -sle / a, duP, cle / a, dvP,
  1103.                     jacobian[5], 0);
  1104.         fillHalfRow((m1 * m2 / epsilon - 1) * oOsqrtMuA, position,
  1105.                     (2 * m3 + eSinE * a + m1 * eSinE * r * (eCosE * beta * 2 - aOr * m2) / epsilon) / mu, velocity,
  1106.                     m4, dexV, m5, deyV, -sle / a, duV, cle / a, dvV,
  1107.                     jacobian[5], 3);

  1108.         return jacobian;

  1109.     }

  1110.     /** {@inheritDoc} */
  1111.     @Override
  1112.     protected double[][] computeJacobianEccentricWrtCartesian() {

  1113.         // start by computing the Jacobian with mean angle
  1114.         final double[][] jacobian = computeJacobianMeanWrtCartesian();

  1115.         // Differentiating the Kepler equation aM = aE - ex sin aE + ey cos aE leads to:
  1116.         // daM = (1 - ex cos aE - ey sin aE) daE - sin aE dex + cos aE dey
  1117.         // which is inverted and rewritten as:
  1118.         // daE = a/r daM + sin aE a/r dex - cos aE a/r dey
  1119.         final double alphaE = getAlphaE();
  1120.         final SinCos scAe   = FastMath.sinCos(alphaE);
  1121.         final double cosAe  = scAe.cos();
  1122.         final double sinAe  = scAe.sin();
  1123.         final double aOr    = 1 / (1 - ex * cosAe - ey * sinAe);

  1124.         // update longitude row
  1125.         final double[] rowEx = jacobian[1];
  1126.         final double[] rowEy = jacobian[2];
  1127.         final double[] rowL  = jacobian[5];
  1128.         for (int j = 0; j < 6; ++j) {
  1129.             rowL[j] = aOr * (rowL[j] + sinAe * rowEx[j] - cosAe * rowEy[j]);
  1130.         }

  1131.         return jacobian;

  1132.     }

  1133.     /** {@inheritDoc} */
  1134.     @Override
  1135.     protected double[][] computeJacobianTrueWrtCartesian() {

  1136.         // start by computing the Jacobian with eccentric angle
  1137.         final double[][] jacobian = computeJacobianEccentricWrtCartesian();

  1138.         // Differentiating the eccentric latitude equation
  1139.         // tan((aV - aE)/2) = [ex sin aE - ey cos aE] / [sqrt(1-ex^2-ey^2) + 1 - ex cos aE - ey sin aE]
  1140.         // leads to
  1141.         // cT (daV - daE) = cE daE + cX dex + cY dey
  1142.         // with
  1143.         // cT = [d^2 + (ex sin aE - ey cos aE)^2] / 2
  1144.         // d  = 1 + sqrt(1-ex^2-ey^2) - ex cos aE - ey sin aE
  1145.         // cE = (ex cos aE + ey sin aE) (sqrt(1-ex^2-ey^2) + 1) - ex^2 - ey^2
  1146.         // cX =  sin aE (sqrt(1-ex^2-ey^2) + 1) - ey + ex (ex sin aE - ey cos aE) / sqrt(1-ex^2-ey^2)
  1147.         // cY = -cos aE (sqrt(1-ex^2-ey^2) + 1) + ex + ey (ex sin aE - ey cos aE) / sqrt(1-ex^2-ey^2)
  1148.         // which can be solved to find the differential of the true latitude
  1149.         // daV = (cT + cE) / cT daE + cX / cT deX + cY / cT deX
  1150.         final double alphaE    = getAlphaE();
  1151.         final SinCos scAe      = FastMath.sinCos(alphaE);
  1152.         final double cosAe     = scAe.cos();
  1153.         final double sinAe     = scAe.sin();
  1154.         final double eSinE     = ex * sinAe - ey * cosAe;
  1155.         final double ecosE     = ex * cosAe + ey * sinAe;
  1156.         final double e2        = ex * ex + ey * ey;
  1157.         final double epsilon   = FastMath.sqrt(1 - e2);
  1158.         final double onePeps   = 1 + epsilon;
  1159.         final double d         = onePeps - ecosE;
  1160.         final double cT        = (d * d + eSinE * eSinE) / 2;
  1161.         final double cE        = ecosE * onePeps - e2;
  1162.         final double cX        = ex * eSinE / epsilon - ey + sinAe * onePeps;
  1163.         final double cY        = ey * eSinE / epsilon + ex - cosAe * onePeps;
  1164.         final double factorLe  = (cT + cE) / cT;
  1165.         final double factorEx  = cX / cT;
  1166.         final double factorEy  = cY / cT;

  1167.         // update latitude row
  1168.         final double[] rowEx = jacobian[1];
  1169.         final double[] rowEy = jacobian[2];
  1170.         final double[] rowA = jacobian[5];
  1171.         for (int j = 0; j < 6; ++j) {
  1172.             rowA[j] = factorLe * rowA[j] + factorEx * rowEx[j] + factorEy * rowEy[j];
  1173.         }

  1174.         return jacobian;

  1175.     }

  1176.     /** {@inheritDoc} */
  1177.     @Override
  1178.     public void addKeplerContribution(final PositionAngleType type, final double gm,
  1179.                                       final double[] pDot) {
  1180.         pDot[5] += computeKeplerianAlphaDot(type, a, ex, ey, gm, cachedAlpha, cachedPositionAngleType);
  1181.     }

  1182.     /**
  1183.      * Compute rate of argument of latitude.
  1184.      * @param type position angle type of rate
  1185.      * @param a semi major axis
  1186.      * @param ex ex
  1187.      * @param ey ey
  1188.      * @param mu mu
  1189.      * @param alpha argument of latitude
  1190.      * @param cachedType position angle type of passed alpha
  1191.      * @return first-order time derivative for alpha
  1192.      * @since 12.2
  1193.      */
  1194.     private static double computeKeplerianAlphaDot(final PositionAngleType type, final double a, final double ex,
  1195.                                                    final double ey, final double mu,
  1196.                                                    final double alpha, final PositionAngleType cachedType) {
  1197.         final double n  = FastMath.sqrt(mu / a) / a;
  1198.         if (type == PositionAngleType.MEAN) {
  1199.             return n;
  1200.         }
  1201.         final double ksi;
  1202.         final SinCos sc;
  1203.         if (type == PositionAngleType.ECCENTRIC) {
  1204.             sc = FastMath.sinCos(CircularLatitudeArgumentUtility.convertAlpha(cachedType, alpha, ex, ey, type));
  1205.             ksi   = 1. / (1 - ex * sc.cos() - ey * sc.sin());
  1206.             return n * ksi;
  1207.         } else { // TRUE
  1208.             sc = FastMath.sinCos(CircularLatitudeArgumentUtility.convertAlpha(cachedType, alpha, ex, ey, type));
  1209.             final double oMe2  = 1 - ex * ex - ey * ey;
  1210.             ksi   = 1 + ex * sc.cos() + ey * sc.sin();
  1211.             return n * ksi * ksi / (oMe2 * FastMath.sqrt(oMe2));
  1212.         }
  1213.     }

  1214.     /**  Returns a string representation of this Orbit object.
  1215.      * @return a string representation of this object
  1216.      */
  1217.     public String toString() {
  1218.         return new StringBuilder().append("circular parameters: ").append('{').
  1219.                                   append("a: ").append(a).
  1220.                                   append(", ex: ").append(ex).append(", ey: ").append(ey).
  1221.                                   append(", i: ").append(FastMath.toDegrees(i)).
  1222.                                   append(", raan: ").append(FastMath.toDegrees(raan)).
  1223.                                   append(", alphaV: ").append(FastMath.toDegrees(getAlphaV())).
  1224.                                   append(";}").toString();
  1225.     }

  1226.     /** {@inheritDoc} */
  1227.     @Override
  1228.     public PositionAngleType getCachedPositionAngleType() {
  1229.         return cachedPositionAngleType;
  1230.     }

  1231.     /** {@inheritDoc} */
  1232.     @Override
  1233.     public boolean hasRates() {
  1234.         return hasDerivatives();
  1235.     }

  1236.     /** {@inheritDoc} */
  1237.     @Override
  1238.     public CircularOrbit removeRates() {
  1239.         final PositionAngleType positionAngleType = getCachedPositionAngleType();
  1240.         return new CircularOrbit(a, ex, ey, i, raan, cachedAlpha, positionAngleType, positionAngleType,
  1241.                 getFrame(), getDate(), getMu());
  1242.     }

  1243.     /** Replace the instance with a data transfer object for serialization.
  1244.      * @return data transfer object that will be serialized
  1245.      */
  1246.     @DefaultDataContext
  1247.     private Object writeReplace() {
  1248.         return new DTO(this);
  1249.     }

  1250.     /** Internal class used only for serialization. */
  1251.     @DefaultDataContext
  1252.     private static class DTO implements Serializable {

  1253.         /** Serializable UID. */
  1254.         private static final long serialVersionUID = 20231217L;

  1255.         /** Double values. */
  1256.         private final double[] d;

  1257.         /** Frame in which are defined the orbital parameters. */
  1258.         private final Frame frame;

  1259.         /** Type of cached position angle. */
  1260.         private final PositionAngleType positionAngleType;

  1261.         /** Simple constructor.
  1262.          * @param orbit instance to serialize
  1263.          */
  1264.         private DTO(final CircularOrbit orbit) {

  1265.             final AbsoluteDate date = orbit.getDate();
  1266.             positionAngleType = orbit.getCachedPositionAngleType();

  1267.             // decompose date
  1268.             final AbsoluteDate j2000Epoch =
  1269.                     DataContext.getDefault().getTimeScales().getJ2000Epoch();
  1270.             final double epoch  = FastMath.floor(date.durationFrom(j2000Epoch));
  1271.             final double offset = date.durationFrom(j2000Epoch.shiftedBy(epoch));

  1272.             if (orbit.serializePV) {
  1273.                 final TimeStampedPVCoordinates pv = orbit.getPVCoordinates();
  1274.                 if (orbit.hasDerivatives()) {
  1275.                     this.d = new double[] {
  1276.                         // date + mu + orbit + derivatives + Cartesian : 24 parameters
  1277.                         epoch, offset, orbit.getMu(),
  1278.                         orbit.a, orbit.ex, orbit.ey,
  1279.                         orbit.i, orbit.raan, orbit.cachedAlpha,
  1280.                         orbit.aDot, orbit.exDot, orbit.eyDot,
  1281.                         orbit.iDot, orbit.raanDot, orbit.cachedAlphaDot,
  1282.                         pv.getPosition().getX(),     pv.getPosition().getY(),     pv.getPosition().getZ(),
  1283.                         pv.getVelocity().getX(),     pv.getVelocity().getY(),     pv.getVelocity().getZ(),
  1284.                         pv.getAcceleration().getX(), pv.getAcceleration().getY(), pv.getAcceleration().getZ(),
  1285.                     };
  1286.                 } else {
  1287.                     this.d = new double[] {
  1288.                         // date + mu + orbit + Cartesian : 18 parameters
  1289.                         epoch, offset, orbit.getMu(),
  1290.                         orbit.a, orbit.ex, orbit.ey,
  1291.                         orbit.i, orbit.raan, orbit.cachedAlpha,
  1292.                         pv.getPosition().getX(),     pv.getPosition().getY(),     pv.getPosition().getZ(),
  1293.                         pv.getVelocity().getX(),     pv.getVelocity().getY(),     pv.getVelocity().getZ(),
  1294.                         pv.getAcceleration().getX(), pv.getAcceleration().getY(), pv.getAcceleration().getZ(),
  1295.                     };
  1296.                 }
  1297.             } else {
  1298.                 if (orbit.hasDerivatives()) {
  1299.                     // date + mu + orbit + derivatives: 15 parameters
  1300.                     this.d = new double[] {
  1301.                         epoch, offset, orbit.getMu(),
  1302.                         orbit.a, orbit.ex, orbit.ey,
  1303.                         orbit.i, orbit.raan, orbit.cachedAlpha,
  1304.                         orbit.aDot, orbit.exDot, orbit.eyDot,
  1305.                         orbit.iDot, orbit.raanDot, orbit.cachedAlphaDot
  1306.                     };
  1307.                 } else {
  1308.                     // date + mu + orbit: 9 parameters
  1309.                     this.d = new double[] {
  1310.                         epoch, offset, orbit.getMu(),
  1311.                         orbit.a, orbit.ex, orbit.ey,
  1312.                         orbit.i, orbit.raan, orbit.cachedAlpha
  1313.                     };
  1314.                 }
  1315.             }

  1316.             this.frame = orbit.getFrame();

  1317.         }

  1318.         /** Replace the deserialized data transfer object with a {@link CircularOrbit}.
  1319.          * @return replacement {@link CircularOrbit}
  1320.          */
  1321.         private Object readResolve() {
  1322.             final AbsoluteDate j2000Epoch =
  1323.                     DataContext.getDefault().getTimeScales().getJ2000Epoch();
  1324.             switch (d.length) {
  1325.                 case 24 : // date + mu + orbit + derivatives + Cartesian
  1326.                     return new CircularOrbit(d[ 3], d[ 4], d[ 5], d[ 6], d[ 7], d[ 8],
  1327.                                              d[ 9], d[10], d[11], d[12], d[13], d[14],
  1328.                                              new TimeStampedPVCoordinates(j2000Epoch.shiftedBy(d[0]).shiftedBy(d[1]),
  1329.                                                                           new Vector3D(d[15], d[16], d[17]),
  1330.                                                                           new Vector3D(d[18], d[19], d[20]),
  1331.                                                                           new Vector3D(d[21], d[22], d[23])),
  1332.                                              positionAngleType, frame,
  1333.                                              d[2]);
  1334.                 case 18 : // date + mu + orbit + Cartesian
  1335.                     return new CircularOrbit(d[3], d[4], d[5], d[6], d[7], d[8],
  1336.                                              Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN,
  1337.                                              new TimeStampedPVCoordinates(j2000Epoch.shiftedBy(d[0]).shiftedBy(d[1]),
  1338.                                                                           new Vector3D(d[ 9], d[10], d[11]),
  1339.                                                                           new Vector3D(d[12], d[13], d[14]),
  1340.                                                                           new Vector3D(d[15], d[16], d[17])),
  1341.                                              positionAngleType, frame,
  1342.                                              d[2]);
  1343.                 case 15 : // date + mu + orbit + derivatives
  1344.                     return new CircularOrbit(d[ 3], d[ 4], d[ 5], d[ 6], d[ 7], d[ 8],
  1345.                                              d[ 9], d[10], d[11], d[12], d[13], d[14],
  1346.                                              positionAngleType, positionAngleType,
  1347.                                              frame, j2000Epoch.shiftedBy(d[0]).shiftedBy(d[1]),
  1348.                                              d[2]);
  1349.                 default : // date + mu + orbit
  1350.                     return new CircularOrbit(d[3], d[4], d[5], d[6], d[7], d[8], positionAngleType, positionAngleType,
  1351.                                              frame, j2000Epoch.shiftedBy(d[0]).shiftedBy(d[1]),
  1352.                                              d[2]);

  1353.             }
  1354.         }

  1355.     }

  1356. }