OrbitType.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.util.Arrays;

  19. import org.hipparchus.CalculusFieldElement;
  20. import org.hipparchus.Field;
  21. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  22. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  23. import org.hipparchus.util.FastMath;
  24. import org.hipparchus.util.MathUtils;
  25. import org.orekit.errors.OrekitException;
  26. import org.orekit.errors.OrekitMessages;
  27. import org.orekit.frames.Frame;
  28. import org.orekit.time.AbsoluteDate;
  29. import org.orekit.time.FieldAbsoluteDate;
  30. import org.orekit.utils.FieldPVCoordinates;
  31. import org.orekit.utils.PVCoordinates;
  32. import org.orekit.utils.ParameterDriver;
  33. import org.orekit.utils.ParameterDriversList;
  34. import org.orekit.utils.TimeStampedFieldPVCoordinates;

  35. /** Enumerate for {@link Orbit} and {@link FieldOrbit} parameters types.
  36.  */
  37. public enum OrbitType {

  38.     /** Type for orbital representation in {@link CartesianOrbit} and {@link FieldCartesianOrbit} parameters. */
  39.     CARTESIAN {

  40.         /** {@inheritDoc} */
  41.         @Override
  42.         public CartesianOrbit convertType(final Orbit orbit) {
  43.             return (orbit.getType() == this) ? (CartesianOrbit) orbit : new CartesianOrbit(orbit);
  44.         }

  45.         /** {@inheritDoc} */
  46.         @Override
  47.         public void mapOrbitToArray(final Orbit orbit, final PositionAngleType type,
  48.                                     final double[] stateVector, final double[] stateVectorDot) {

  49.             final PVCoordinates pv = orbit.getPVCoordinates();
  50.             final Vector3D      p  = pv.getPosition();
  51.             final Vector3D      v  = pv.getVelocity();

  52.             stateVector[0] = p.getX();
  53.             stateVector[1] = p.getY();
  54.             stateVector[2] = p.getZ();
  55.             stateVector[3] = v.getX();
  56.             stateVector[4] = v.getY();
  57.             stateVector[5] = v.getZ();

  58.             if (stateVectorDot != null) {
  59.                 final Vector3D a  = pv.getAcceleration();
  60.                 stateVectorDot[0] = v.getX();
  61.                 stateVectorDot[1] = v.getY();
  62.                 stateVectorDot[2] = v.getZ();
  63.                 stateVectorDot[3] = a.getX();
  64.                 stateVectorDot[4] = a.getY();
  65.                 stateVectorDot[5] = a.getZ();
  66.             }

  67.         }

  68.         /** {@inheritDoc} */
  69.         @Override
  70.         public CartesianOrbit mapArrayToOrbit(final double[] stateVector, final double[] stateVectorDot, final PositionAngleType type,
  71.                                               final AbsoluteDate date, final double mu, final Frame frame) {

  72.             final Vector3D p = new Vector3D(stateVector[0], stateVector[1], stateVector[2]);
  73.             final Vector3D v = new Vector3D(stateVector[3], stateVector[4], stateVector[5]);
  74.             final Vector3D a;
  75.             if (stateVectorDot == null) {
  76.                 // we don't have data about acceleration
  77.                 return new CartesianOrbit(new PVCoordinates(p, v), frame, date, mu);
  78.             } else {
  79.                 // we do have an acceleration
  80.                 a = new Vector3D(stateVectorDot[3], stateVectorDot[4], stateVectorDot[5]);
  81.                 return new CartesianOrbit(new PVCoordinates(p, v, a), frame, date, mu);
  82.             }

  83.         }

  84.         /** {@inheritDoc} */
  85.         @Override
  86.         public <T extends CalculusFieldElement<T>> FieldCartesianOrbit<T> convertType(final FieldOrbit<T> orbit) {
  87.             return (orbit.getType() == this) ? (FieldCartesianOrbit<T>) orbit : new FieldCartesianOrbit<>(orbit);
  88.         }

  89.         /** {@inheritDoc} */
  90.         @Override
  91.         public <T extends CalculusFieldElement<T>> void mapOrbitToArray(final FieldOrbit<T> orbit,
  92.                                                                         final PositionAngleType type,
  93.                                                                         final T[] stateVector,
  94.                                                                         final T[] stateVectorDot) {

  95.             final TimeStampedFieldPVCoordinates<T> pv = orbit.getPVCoordinates();
  96.             final FieldVector3D<T>                 p  = pv.getPosition();
  97.             final FieldVector3D<T>                 v  = pv.getVelocity();

  98.             stateVector[0] = p.getX();
  99.             stateVector[1] = p.getY();
  100.             stateVector[2] = p.getZ();
  101.             stateVector[3] = v.getX();
  102.             stateVector[4] = v.getY();
  103.             stateVector[5] = v.getZ();

  104.             if (stateVectorDot != null) {
  105.                 final FieldVector3D<T> a = pv.getAcceleration();
  106.                 stateVectorDot[0] = v.getX();
  107.                 stateVectorDot[1] = v.getY();
  108.                 stateVectorDot[2] = v.getZ();
  109.                 stateVectorDot[3] = a.getX();
  110.                 stateVectorDot[4] = a.getY();
  111.                 stateVectorDot[5] = a.getZ();
  112.             }

  113.         }

  114.         /** {@inheritDoc} */
  115.         @Override
  116.         public <T extends CalculusFieldElement<T>> FieldCartesianOrbit<T> mapArrayToOrbit(final T[] stateVector,
  117.                                                                                           final T[] stateVectorDot,
  118.                                                                                           final PositionAngleType type,
  119.                                                                                           final FieldAbsoluteDate<T> date,
  120.                                                                                           final T mu, final Frame frame) {
  121.             final FieldVector3D<T> p = new FieldVector3D<>(stateVector[0], stateVector[1], stateVector[2]);
  122.             final FieldVector3D<T> v = new FieldVector3D<>(stateVector[3], stateVector[4], stateVector[5]);
  123.             final FieldVector3D<T> a;
  124.             if (stateVectorDot == null) {
  125.                 // we don't have data about acceleration
  126.                 return new FieldCartesianOrbit<>(new FieldPVCoordinates<>(p, v), frame, date, mu);
  127.             } else {
  128.                 // we do have an acceleration
  129.                 a = new FieldVector3D<>(stateVectorDot[3], stateVectorDot[4], stateVectorDot[5]);
  130.                 return new FieldCartesianOrbit<>(new FieldPVCoordinates<>(p, v, a), frame, date, mu);
  131.             }

  132.         }

  133.         /** {@inheritDoc} */
  134.         @Override
  135.         public <T extends CalculusFieldElement<T>> FieldCartesianOrbit<T> convertToFieldOrbit(final Field<T> field,
  136.                                                                                               final Orbit orbit) {
  137.             return new FieldCartesianOrbit<>(field, CARTESIAN.convertType(orbit));
  138.         }

  139.         /** {@inheritDoc} */
  140.         @Override
  141.         public ParameterDriversList getDrivers(final double dP, final Orbit orbit, final PositionAngleType type) {
  142.             final ParameterDriversList drivers = new ParameterDriversList();
  143.             final double[] array = new double[6];
  144.             mapOrbitToArray(orbit, type, array, null);
  145.             final double[] scale = scale(dP, orbit);
  146.             drivers.add(new ParameterDriver(POS_X, array[0], scale[0], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
  147.             drivers.add(new ParameterDriver(POS_Y, array[1], scale[1], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
  148.             drivers.add(new ParameterDriver(POS_Z, array[2], scale[2], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
  149.             drivers.add(new ParameterDriver(VEL_X, array[3], scale[3], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
  150.             drivers.add(new ParameterDriver(VEL_Y, array[4], scale[4], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
  151.             drivers.add(new ParameterDriver(VEL_Z, array[5], scale[5], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
  152.             return drivers;
  153.         }

  154.         /** {@inheritDoc} */
  155.         @Override
  156.         public CartesianOrbit normalize(final Orbit orbit, final Orbit reference) {
  157.             // no angular parameters need normalization
  158.             return convertType(orbit);
  159.         }

  160.         /** {@inheritDoc} */
  161.         @Override
  162.         public <T extends CalculusFieldElement<T>> FieldCartesianOrbit<T> normalize(final FieldOrbit<T> orbit, final FieldOrbit<T> reference) {
  163.             // no angular parameters need normalization
  164.             return convertType(orbit);
  165.         }

  166.         /** {@inheritDoc} */
  167.         @Override
  168.         public boolean isPositionAngleBased() {
  169.             return false;
  170.         }

  171.     },

  172.     /** Type for orbital representation in {@link CircularOrbit} and {@link FieldCircularOrbit} parameters. */
  173.     CIRCULAR {

  174.         /** {@inheritDoc} */
  175.         @Override
  176.         public CircularOrbit convertType(final Orbit orbit) {
  177.             return (orbit.getType() == this) ? (CircularOrbit) orbit : new CircularOrbit(orbit);
  178.         }

  179.         /** {@inheritDoc} */
  180.         @Override
  181.         public void mapOrbitToArray(final Orbit orbit, final PositionAngleType type,
  182.                                     final double[] stateVector, final double[] stateVectorDot) {

  183.             final CircularOrbit circularOrbit = (CircularOrbit) OrbitType.CIRCULAR.convertType(orbit);

  184.             stateVector[0] = circularOrbit.getA();
  185.             stateVector[1] = circularOrbit.getCircularEx();
  186.             stateVector[2] = circularOrbit.getCircularEy();
  187.             stateVector[3] = circularOrbit.getI();
  188.             stateVector[4] = circularOrbit.getRightAscensionOfAscendingNode();
  189.             stateVector[5] = circularOrbit.getAlpha(type);

  190.             if (stateVectorDot != null) {
  191.                 if (orbit.hasDerivatives()) {
  192.                     stateVectorDot[0] = circularOrbit.getADot();
  193.                     stateVectorDot[1] = circularOrbit.getCircularExDot();
  194.                     stateVectorDot[2] = circularOrbit.getCircularEyDot();
  195.                     stateVectorDot[3] = circularOrbit.getIDot();
  196.                     stateVectorDot[4] = circularOrbit.getRightAscensionOfAscendingNodeDot();
  197.                     stateVectorDot[5] = circularOrbit.getAlphaDot(type);
  198.                 } else {
  199.                     Arrays.fill(stateVectorDot, 0, 6, Double.NaN);
  200.                 }
  201.             }

  202.         }

  203.         /** {@inheritDoc} */
  204.         @Override
  205.         public CircularOrbit mapArrayToOrbit(final double[] stateVector, final double[] stateVectorDot, final PositionAngleType type,
  206.                                              final AbsoluteDate date, final double mu, final Frame frame) {
  207.             if (stateVectorDot == null) {
  208.                 // we don't have orbit derivatives
  209.                 return new CircularOrbit(stateVector[0], stateVector[1], stateVector[2],
  210.                                          stateVector[3], stateVector[4], stateVector[5],
  211.                                          type, frame, date, mu);
  212.             } else {
  213.                 // we have orbit derivatives
  214.                 return new CircularOrbit(stateVector[0],    stateVector[1],    stateVector[2],
  215.                                          stateVector[3],    stateVector[4],    stateVector[5],
  216.                                          stateVectorDot[0], stateVectorDot[1], stateVectorDot[2],
  217.                                          stateVectorDot[3], stateVectorDot[4], stateVectorDot[5],
  218.                                          type, frame, date, mu);
  219.             }
  220.         }

  221.         /** {@inheritDoc} */
  222.         @Override
  223.         public <T extends CalculusFieldElement<T>> FieldCircularOrbit<T> convertType(final FieldOrbit<T> orbit) {
  224.             return (orbit.getType() == this) ? (FieldCircularOrbit<T>) orbit : new FieldCircularOrbit<>(orbit);
  225.         }

  226.         /** {@inheritDoc} */
  227.         @Override
  228.         public <T extends CalculusFieldElement<T>> void mapOrbitToArray(final FieldOrbit<T> orbit,
  229.                                                                         final PositionAngleType type,
  230.                                                                         final T[] stateVector,
  231.                                                                         final T[] stateVectorDot) {

  232.             final FieldCircularOrbit<T> circularOrbit = (FieldCircularOrbit<T>) OrbitType.CIRCULAR.convertType(orbit);

  233.             stateVector[0] = circularOrbit.getA();
  234.             stateVector[1] = circularOrbit.getCircularEx();
  235.             stateVector[2] = circularOrbit.getCircularEy();
  236.             stateVector[3] = circularOrbit.getI();
  237.             stateVector[4] = circularOrbit.getRightAscensionOfAscendingNode();
  238.             stateVector[5] = circularOrbit.getAlpha(type);

  239.             if (stateVectorDot != null) {
  240.                 if (orbit.hasDerivatives()) {
  241.                     stateVectorDot[0] = circularOrbit.getADot();
  242.                     stateVectorDot[1] = circularOrbit.getCircularExDot();
  243.                     stateVectorDot[2] = circularOrbit.getCircularEyDot();
  244.                     stateVectorDot[3] = circularOrbit.getIDot();
  245.                     stateVectorDot[4] = circularOrbit.getRightAscensionOfAscendingNodeDot();
  246.                     stateVectorDot[5] = circularOrbit.getAlphaDot(type);
  247.                 } else {
  248.                     Arrays.fill(stateVectorDot, 0, 6, orbit.getZero().add(Double.NaN));
  249.                 }
  250.             }

  251.         }

  252.         /** {@inheritDoc} */
  253.         @Override
  254.         public <T extends CalculusFieldElement<T>> FieldCircularOrbit<T> mapArrayToOrbit(final T[] stateVector,
  255.                                                                                          final T[] stateVectorDot, final PositionAngleType type,
  256.                                                                                          final FieldAbsoluteDate<T> date,
  257.                                                                                          final T mu, final Frame frame) {
  258.             if (stateVectorDot == null) {
  259.                 // we don't have orbit derivatives
  260.                 return new FieldCircularOrbit<>(stateVector[0], stateVector[1], stateVector[2],
  261.                                                 stateVector[3], stateVector[4], stateVector[5],
  262.                                                 type, frame, date, mu);
  263.             } else {
  264.                 // we have orbit derivatives
  265.                 return new FieldCircularOrbit<>(stateVector[0],    stateVector[1],    stateVector[2],
  266.                                                 stateVector[3],    stateVector[4],    stateVector[5],
  267.                                                 stateVectorDot[0], stateVectorDot[1], stateVectorDot[2],
  268.                                                 stateVectorDot[3], stateVectorDot[4], stateVectorDot[5],
  269.                                                 type, frame, date, mu);
  270.             }
  271.         }

  272.         /** {@inheritDoc} */
  273.         @Override
  274.         public <T extends CalculusFieldElement<T>> FieldCircularOrbit<T> convertToFieldOrbit(final Field<T> field,
  275.                                                                                              final Orbit orbit) {
  276.             return new FieldCircularOrbit<>(field, CIRCULAR.convertType(orbit));
  277.         }

  278.         /** {@inheritDoc} */
  279.         @Override
  280.         public ParameterDriversList getDrivers(final double dP, final Orbit orbit, final PositionAngleType type) {
  281.             final ParameterDriversList drivers = new ParameterDriversList();
  282.             final double[] array = new double[6];
  283.             mapOrbitToArray(orbit, type, array, null);
  284.             final double[] scale = scale(dP, orbit);
  285.             final String name = type == PositionAngleType.MEAN ?
  286.                                     MEAN_LAT_ARG :
  287.                                     type == PositionAngleType.ECCENTRIC ? ECC_LAT_ARG : TRUE_LAT_ARG;
  288.             drivers.add(new ParameterDriver(A,    array[0], scale[0],  0.0, Double.POSITIVE_INFINITY));
  289.             drivers.add(new ParameterDriver(E_X,  array[1], scale[1], -1.0, 1.0));
  290.             drivers.add(new ParameterDriver(E_Y,  array[2], scale[2], -1.0, 1.0));
  291.             drivers.add(new ParameterDriver(INC,  array[3], scale[3],  0.0, FastMath.PI));
  292.             drivers.add(new ParameterDriver(RAAN, array[4], scale[4], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
  293.             drivers.add(new ParameterDriver(name, array[5], scale[5], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
  294.             return drivers;
  295.         }

  296.         /** {@inheritDoc} */
  297.         @Override
  298.         public CircularOrbit normalize(final Orbit orbit, final Orbit reference) {

  299.             // convert input to proper type
  300.             final CircularOrbit cO = convertType(orbit);
  301.             final CircularOrbit cR = convertType(reference);
  302.             final PositionAngleType cachedPositionAngleType = cO.getCachedPositionAngleType();

  303.             // perform normalization
  304.             if (cO.hasDerivatives()) {
  305.                 return new CircularOrbit(cO.getA(),
  306.                                          cO.getCircularEx(),
  307.                                          cO.getCircularEy(),
  308.                                          cO.getI(),
  309.                                          MathUtils.normalizeAngle(cO.getRightAscensionOfAscendingNode(),
  310.                                                  cR.getRightAscensionOfAscendingNode()),
  311.                                          MathUtils.normalizeAngle(cO.getAlpha(cachedPositionAngleType),
  312.                                                  cR.getAlpha(cachedPositionAngleType)),
  313.                                          cO.getADot(),
  314.                                          cO.getCircularExDot(),
  315.                                          cO.getCircularEyDot(),
  316.                                          cO.getIDot(),
  317.                                          cO.getRightAscensionOfAscendingNodeDot(),
  318.                                          cO.getAlphaDot(cachedPositionAngleType),
  319.                                          cachedPositionAngleType,
  320.                                          cO.getFrame(),
  321.                                          cO.getDate(),
  322.                                          cO.getMu());
  323.             } else {
  324.                 return new CircularOrbit(cO.getA(),
  325.                                          cO.getCircularEx(),
  326.                                          cO.getCircularEy(),
  327.                                          cO.getI(),
  328.                                          MathUtils.normalizeAngle(cO.getRightAscensionOfAscendingNode(),
  329.                                                  cR.getRightAscensionOfAscendingNode()),
  330.                                          MathUtils.normalizeAngle(cO.getAlpha(cachedPositionAngleType),
  331.                                                  cR.getAlpha(cachedPositionAngleType)),
  332.                                          cachedPositionAngleType,
  333.                                          cO.getFrame(),
  334.                                          cO.getDate(),
  335.                                          cO.getMu());
  336.             }

  337.         }

  338.         /** {@inheritDoc} */
  339.         @Override
  340.         public <T extends CalculusFieldElement<T>> FieldCircularOrbit<T> normalize(final FieldOrbit<T> orbit, final FieldOrbit<T> reference) {

  341.             // convert input to proper type
  342.             final FieldCircularOrbit<T> cO = convertType(orbit);
  343.             final FieldCircularOrbit<T> cR = convertType(reference);
  344.             final PositionAngleType positionAngleType = cO.getCachedPositionAngleType();

  345.             // perform normalization
  346.             if (cO.hasDerivatives()) {
  347.                 return new FieldCircularOrbit<>(cO.getA(),
  348.                                                 cO.getCircularEx(),
  349.                                                 cO.getCircularEy(),
  350.                                                 cO.getI(),
  351.                                                 MathUtils.normalizeAngle(cO.getRightAscensionOfAscendingNode(),
  352.                                                         cR.getRightAscensionOfAscendingNode()),
  353.                                                 MathUtils.normalizeAngle(cO.getAlpha(positionAngleType),
  354.                                                         cR.getAlpha(positionAngleType)),
  355.                                                 cO.getADot(),
  356.                                                 cO.getCircularExDot(),
  357.                                                 cO.getCircularEyDot(),
  358.                                                 cO.getIDot(),
  359.                                                 cO.getRightAscensionOfAscendingNodeDot(),
  360.                                                 cO.getAlphaDot(positionAngleType),
  361.                                                 positionAngleType,
  362.                                                 cO.getFrame(),
  363.                                                 cO.getDate(),
  364.                                                 cO.getMu());
  365.             } else {
  366.                 return new FieldCircularOrbit<>(cO.getA(),
  367.                                                 cO.getCircularEx(),
  368.                                                 cO.getCircularEy(),
  369.                                                 cO.getI(),
  370.                                                 MathUtils.normalizeAngle(cO.getRightAscensionOfAscendingNode(),
  371.                                                         cR.getRightAscensionOfAscendingNode()),
  372.                                                 MathUtils.normalizeAngle(cO.getAlpha(positionAngleType),
  373.                                                         cR.getAlpha(positionAngleType)),
  374.                                                 positionAngleType,
  375.                                                 cO.getFrame(),
  376.                                                 cO.getDate(),
  377.                                                 cO.getMu());
  378.             }

  379.         }

  380.         /** {@inheritDoc} */
  381.         @Override
  382.         public boolean isPositionAngleBased() {
  383.             return true;
  384.         }

  385.     },

  386.     /** Type for orbital representation in {@link EquinoctialOrbit} and {@link FieldEquinoctialOrbit} parameters. */
  387.     EQUINOCTIAL {

  388.         /** {@inheritDoc} */
  389.         @Override
  390.         public EquinoctialOrbit convertType(final Orbit orbit) {
  391.             return (orbit.getType() == this) ? (EquinoctialOrbit) orbit : new EquinoctialOrbit(orbit);
  392.         }

  393.         /** {@inheritDoc} */
  394.         @Override
  395.         public void mapOrbitToArray(final Orbit orbit, final PositionAngleType type,
  396.                                     final double[] stateVector, final double[] stateVectorDot) {

  397.             final EquinoctialOrbit equinoctialOrbit =
  398.                 (EquinoctialOrbit) OrbitType.EQUINOCTIAL.convertType(orbit);

  399.             stateVector[0] = equinoctialOrbit.getA();
  400.             stateVector[1] = equinoctialOrbit.getEquinoctialEx();
  401.             stateVector[2] = equinoctialOrbit.getEquinoctialEy();
  402.             stateVector[3] = equinoctialOrbit.getHx();
  403.             stateVector[4] = equinoctialOrbit.getHy();
  404.             stateVector[5] = equinoctialOrbit.getL(type);

  405.             if (stateVectorDot != null) {
  406.                 if (orbit.hasDerivatives()) {
  407.                     stateVectorDot[0] = equinoctialOrbit.getADot();
  408.                     stateVectorDot[1] = equinoctialOrbit.getEquinoctialExDot();
  409.                     stateVectorDot[2] = equinoctialOrbit.getEquinoctialEyDot();
  410.                     stateVectorDot[3] = equinoctialOrbit.getHxDot();
  411.                     stateVectorDot[4] = equinoctialOrbit.getHyDot();
  412.                     stateVectorDot[5] = equinoctialOrbit.getLDot(type);
  413.                 } else {
  414.                     Arrays.fill(stateVectorDot, 0, 6, Double.NaN);
  415.                 }
  416.             }

  417.         }

  418.         /** {@inheritDoc} */
  419.         @Override
  420.         public EquinoctialOrbit mapArrayToOrbit(final double[] stateVector, final double[] stateVectorDot, final PositionAngleType type,
  421.                                                 final AbsoluteDate date, final double mu, final Frame frame) {
  422.             if (stateVectorDot == null) {
  423.                 // we don't have orbit derivatives
  424.                 return new EquinoctialOrbit(stateVector[0], stateVector[1], stateVector[2],
  425.                                             stateVector[3], stateVector[4], stateVector[5],
  426.                                             type, frame, date, mu);
  427.             } else {
  428.                 // we have orbit derivatives
  429.                 return new EquinoctialOrbit(stateVector[0],    stateVector[1],    stateVector[2],
  430.                                             stateVector[3],    stateVector[4],    stateVector[5],
  431.                                             stateVectorDot[0], stateVectorDot[1], stateVectorDot[2],
  432.                                             stateVectorDot[3], stateVectorDot[4], stateVectorDot[5],
  433.                                             type, frame, date, mu);
  434.             }
  435.         }

  436.         /** {@inheritDoc} */
  437.         @Override
  438.         public <T extends CalculusFieldElement<T>> FieldEquinoctialOrbit<T> convertType(final FieldOrbit<T> orbit) {
  439.             return (orbit.getType() == this) ? (FieldEquinoctialOrbit<T>) orbit : new FieldEquinoctialOrbit<>(orbit);
  440.         }

  441.         /** {@inheritDoc} */
  442.         @Override
  443.         public <T extends CalculusFieldElement<T>> void mapOrbitToArray(final FieldOrbit<T> orbit,
  444.                                                                         final PositionAngleType type,
  445.                                                                         final T[] stateVector,
  446.                                                                         final T[] stateVectorDot) {

  447.             final FieldEquinoctialOrbit<T> equinoctialOrbit =
  448.                 (FieldEquinoctialOrbit<T>) OrbitType.EQUINOCTIAL.convertType(orbit);

  449.             stateVector[0] = equinoctialOrbit.getA();
  450.             stateVector[1] = equinoctialOrbit.getEquinoctialEx();
  451.             stateVector[2] = equinoctialOrbit.getEquinoctialEy();
  452.             stateVector[3] = equinoctialOrbit.getHx();
  453.             stateVector[4] = equinoctialOrbit.getHy();
  454.             stateVector[5] = equinoctialOrbit.getL(type);

  455.             if (stateVectorDot != null) {
  456.                 if (orbit.hasDerivatives()) {
  457.                     stateVectorDot[0] = equinoctialOrbit.getADot();
  458.                     stateVectorDot[1] = equinoctialOrbit.getEquinoctialExDot();
  459.                     stateVectorDot[2] = equinoctialOrbit.getEquinoctialEyDot();
  460.                     stateVectorDot[3] = equinoctialOrbit.getHxDot();
  461.                     stateVectorDot[4] = equinoctialOrbit.getHyDot();
  462.                     stateVectorDot[5] = equinoctialOrbit.getLDot(type);
  463.                 } else {
  464.                     Arrays.fill(stateVectorDot, 0, 6, orbit.getZero().add(Double.NaN));
  465.                 }
  466.             }

  467.         }

  468.         /** {@inheritDoc} */
  469.         @Override
  470.         public <T extends CalculusFieldElement<T>> FieldEquinoctialOrbit<T> mapArrayToOrbit(final T[] stateVector,
  471.                                                                                             final T[] stateVectorDot,
  472.                                                                                             final PositionAngleType type,
  473.                                                                                             final FieldAbsoluteDate<T> date,
  474.                                                                                             final T mu, final Frame frame) {
  475.             if (stateVectorDot == null) {
  476.                 // we don't have orbit derivatives
  477.                 return new FieldEquinoctialOrbit<>(stateVector[0], stateVector[1], stateVector[2],
  478.                                                    stateVector[3], stateVector[4], stateVector[5],
  479.                                                    type, frame, date, mu);
  480.             } else {
  481.                 // we have orbit derivatives
  482.                 return new FieldEquinoctialOrbit<>(stateVector[0],    stateVector[1],    stateVector[2],
  483.                                                    stateVector[3],    stateVector[4],    stateVector[5],
  484.                                                    stateVectorDot[0], stateVectorDot[1], stateVectorDot[2],
  485.                                                    stateVectorDot[3], stateVectorDot[4], stateVectorDot[5],
  486.                                                    type, frame, date, mu);
  487.             }
  488.         }

  489.         /** {@inheritDoc} */
  490.         @Override
  491.         public <T extends CalculusFieldElement<T>> FieldEquinoctialOrbit<T> convertToFieldOrbit(final Field<T> field,
  492.                                                                                                 final Orbit orbit) {
  493.             return new FieldEquinoctialOrbit<>(field, EQUINOCTIAL.convertType(orbit));
  494.         }

  495.         /** {@inheritDoc} */
  496.         @Override
  497.         public ParameterDriversList getDrivers(final double dP, final Orbit orbit, final PositionAngleType type) {
  498.             final ParameterDriversList drivers = new ParameterDriversList();
  499.             final double[] array = new double[6];
  500.             mapOrbitToArray(orbit, type, array, null);
  501.             final double[] scale = scale(dP, orbit);
  502.             final String name = type == PositionAngleType.MEAN ?
  503.                                     MEAN_LON_ARG :
  504.                                     type == PositionAngleType.ECCENTRIC ? ECC_LON_ARG : TRUE_LON_ARG;
  505.             drivers.add(new ParameterDriver(A,    array[0], scale[0],  0.0, Double.POSITIVE_INFINITY));
  506.             drivers.add(new ParameterDriver(E_X,  array[1], scale[1], -1.0, 1.0));
  507.             drivers.add(new ParameterDriver(E_Y,  array[2], scale[2], -1.0, 1.0));
  508.             drivers.add(new ParameterDriver(H_X,  array[3], scale[3], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
  509.             drivers.add(new ParameterDriver(H_Y,  array[4], scale[4], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
  510.             drivers.add(new ParameterDriver(name, array[5], scale[5], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
  511.             return drivers;
  512.         }

  513.         /** {@inheritDoc} */
  514.         @Override
  515.         public EquinoctialOrbit normalize(final Orbit orbit, final Orbit reference) {

  516.             // convert input to proper type
  517.             final EquinoctialOrbit eO = convertType(orbit);
  518.             final EquinoctialOrbit eR = convertType(reference);
  519.             final PositionAngleType cachedPositionAngleType = eO.getCachedPositionAngleType();

  520.             // perform normalization
  521.             if (eO.hasDerivatives()) {
  522.                 return new EquinoctialOrbit(eO.getA(),
  523.                                             eO.getEquinoctialEx(),
  524.                                             eO.getEquinoctialEy(),
  525.                                             eO.getHx(),
  526.                                             eO.getHy(),
  527.                                             MathUtils.normalizeAngle(eO.getL(cachedPositionAngleType),
  528.                                             eR.getL(cachedPositionAngleType)),
  529.                                             eO.getADot(),
  530.                                             eO.getEquinoctialExDot(),
  531.                                             eO.getEquinoctialEyDot(),
  532.                                             eO.getHxDot(),
  533.                                             eO.getHyDot(),
  534.                                             eO.getLDot(cachedPositionAngleType),
  535.                                             cachedPositionAngleType,
  536.                                             eO.getFrame(),
  537.                                             eO.getDate(),
  538.                                             eO.getMu());
  539.             } else {
  540.                 return new EquinoctialOrbit(eO.getA(),
  541.                                             eO.getEquinoctialEx(),
  542.                                             eO.getEquinoctialEy(),
  543.                                             eO.getHx(),
  544.                                             eO.getHy(),
  545.                                             MathUtils.normalizeAngle(eO.getL(cachedPositionAngleType),
  546.                                                     eR.getL(cachedPositionAngleType)),
  547.                                             cachedPositionAngleType,
  548.                                             eO.getFrame(),
  549.                                             eO.getDate(),
  550.                                             eO.getMu());
  551.             }

  552.         }

  553.         /** {@inheritDoc} */
  554.         @Override
  555.         public <T extends CalculusFieldElement<T>> FieldEquinoctialOrbit<T> normalize(final FieldOrbit<T> orbit, final FieldOrbit<T> reference) {

  556.             // convert input to proper type
  557.             final FieldEquinoctialOrbit<T> eO = convertType(orbit);
  558.             final FieldEquinoctialOrbit<T> eR = convertType(reference);
  559.             final PositionAngleType positionAngleType = eO.getCachedPositionAngleType();

  560.             // perform normalization
  561.             if (eO.hasDerivatives()) {
  562.                 return new FieldEquinoctialOrbit<>(eO.getA(),
  563.                                                    eO.getEquinoctialEx(),
  564.                                                    eO.getEquinoctialEy(),
  565.                                                    eO.getHx(),
  566.                                                    eO.getHy(),
  567.                                                    MathUtils.normalizeAngle(eO.getL(positionAngleType),
  568.                                                            eR.getL(positionAngleType)),
  569.                                                    eO.getADot(),
  570.                                                    eO.getEquinoctialExDot(),
  571.                                                    eO.getEquinoctialEyDot(),
  572.                                                    eO.getHxDot(),
  573.                                                    eO.getHyDot(),
  574.                                                    eO.getLDot(positionAngleType),
  575.                                                    positionAngleType,
  576.                                                    eO.getFrame(),
  577.                                                    eO.getDate(),
  578.                                                    eO.getMu());
  579.             } else {
  580.                 return new FieldEquinoctialOrbit<>(eO.getA(),
  581.                                                    eO.getEquinoctialEx(),
  582.                                                    eO.getEquinoctialEy(),
  583.                                                    eO.getHx(),
  584.                                                    eO.getHy(),
  585.                                                    MathUtils.normalizeAngle(eO.getL(positionAngleType),
  586.                                                            eR.getL(positionAngleType)),
  587.                                                    positionAngleType,
  588.                                                    eO.getFrame(),
  589.                                                    eO.getDate(),
  590.                                                    eO.getMu());
  591.             }

  592.         }

  593.         /** {@inheritDoc} */
  594.         @Override
  595.         public boolean isPositionAngleBased() {
  596.             return true;
  597.         }

  598.     },

  599.     /** Type for orbital representation in {@link KeplerianOrbit} and {@link FieldKeplerianOrbit} parameters. */
  600.     KEPLERIAN {

  601.         /** {@inheritDoc} */
  602.         @Override
  603.         public KeplerianOrbit convertType(final Orbit orbit) {
  604.             return (orbit.getType() == this) ? (KeplerianOrbit) orbit : new KeplerianOrbit(orbit);
  605.         }

  606.         /** {@inheritDoc} */
  607.         @Override
  608.         public void mapOrbitToArray(final Orbit orbit, final PositionAngleType type,
  609.                                     final double[] stateVector, final double[] stateVectorDot) {

  610.             final KeplerianOrbit keplerianOrbit =
  611.                 (KeplerianOrbit) OrbitType.KEPLERIAN.convertType(orbit);

  612.             stateVector[0] = keplerianOrbit.getA();
  613.             stateVector[1] = keplerianOrbit.getE();
  614.             stateVector[2] = keplerianOrbit.getI();
  615.             stateVector[3] = keplerianOrbit.getPerigeeArgument();
  616.             stateVector[4] = keplerianOrbit.getRightAscensionOfAscendingNode();
  617.             stateVector[5] = keplerianOrbit.getAnomaly(type);

  618.             if (stateVectorDot != null) {
  619.                 if (orbit.hasDerivatives()) {
  620.                     stateVectorDot[0] = keplerianOrbit.getADot();
  621.                     stateVectorDot[1] = keplerianOrbit.getEDot();
  622.                     stateVectorDot[2] = keplerianOrbit.getIDot();
  623.                     stateVectorDot[3] = keplerianOrbit.getPerigeeArgumentDot();
  624.                     stateVectorDot[4] = keplerianOrbit.getRightAscensionOfAscendingNodeDot();
  625.                     stateVectorDot[5] = keplerianOrbit.getAnomalyDot(type);
  626.                 } else {
  627.                     Arrays.fill(stateVectorDot, 0, 6, Double.NaN);
  628.                 }
  629.             }

  630.         }

  631.         /** {@inheritDoc} */
  632.         @Override
  633.         public KeplerianOrbit mapArrayToOrbit(final double[] stateVector, final double[] stateVectorDot, final PositionAngleType type,
  634.                                               final AbsoluteDate date, final double mu, final Frame frame) {
  635.             if (stateVectorDot == null) {
  636.                 // we don't have orbit derivatives
  637.                 return new KeplerianOrbit(stateVector[0], stateVector[1], stateVector[2],
  638.                                           stateVector[3], stateVector[4], stateVector[5],
  639.                                           type, frame, date, mu);
  640.             } else {
  641.                 // we have orbit derivatives
  642.                 return new KeplerianOrbit(stateVector[0],    stateVector[1],    stateVector[2],
  643.                                           stateVector[3],    stateVector[4],    stateVector[5],
  644.                                           stateVectorDot[0], stateVectorDot[1], stateVectorDot[2],
  645.                                           stateVectorDot[3], stateVectorDot[4], stateVectorDot[5],
  646.                                           type, frame, date, mu);
  647.             }
  648.         }

  649.         /** {@inheritDoc} */
  650.         @Override
  651.         public <T extends CalculusFieldElement<T>> FieldKeplerianOrbit<T> convertType(final FieldOrbit<T> orbit) {
  652.             return (orbit.getType() == this) ? (FieldKeplerianOrbit<T>) orbit : new FieldKeplerianOrbit<>(orbit);
  653.         }

  654.         /** {@inheritDoc} */
  655.         @Override
  656.         public <T extends CalculusFieldElement<T>> void mapOrbitToArray(final FieldOrbit<T> orbit,
  657.                                                                         final PositionAngleType type,
  658.                                                                         final T[] stateVector,
  659.                                                                         final T[] stateVectorDot) {
  660.             final FieldKeplerianOrbit<T> keplerianOrbit =
  661.                             (FieldKeplerianOrbit<T>) OrbitType.KEPLERIAN.convertType(orbit);

  662.             stateVector[0] = keplerianOrbit.getA();
  663.             stateVector[1] = keplerianOrbit.getE();
  664.             stateVector[2] = keplerianOrbit.getI();
  665.             stateVector[3] = keplerianOrbit.getPerigeeArgument();
  666.             stateVector[4] = keplerianOrbit.getRightAscensionOfAscendingNode();
  667.             stateVector[5] = keplerianOrbit.getAnomaly(type);

  668.             if (stateVectorDot != null) {
  669.                 if (orbit.hasDerivatives()) {
  670.                     stateVectorDot[0] = keplerianOrbit.getADot();
  671.                     stateVectorDot[1] = keplerianOrbit.getEDot();
  672.                     stateVectorDot[2] = keplerianOrbit.getIDot();
  673.                     stateVectorDot[3] = keplerianOrbit.getPerigeeArgumentDot();
  674.                     stateVectorDot[4] = keplerianOrbit.getRightAscensionOfAscendingNodeDot();
  675.                     stateVectorDot[5] = keplerianOrbit.getAnomalyDot(type);
  676.                 } else {
  677.                     Arrays.fill(stateVectorDot, 0, 6, orbit.getZero().add(Double.NaN));
  678.                 }
  679.             }

  680.         }

  681.         /** {@inheritDoc} */
  682.         @Override
  683.         public <T extends CalculusFieldElement<T>> FieldKeplerianOrbit<T> mapArrayToOrbit(final T[] stateVector,
  684.                                                                                           final T[] stateVectorDot,
  685.                                                                                           final PositionAngleType type,
  686.                                                                                           final FieldAbsoluteDate<T> date,
  687.                                                                                           final T mu, final Frame frame) {
  688.             if (stateVectorDot == null) {
  689.                 // we don't have orbit derivatives
  690.                 return new FieldKeplerianOrbit<>(stateVector[0], stateVector[1], stateVector[2],
  691.                                                  stateVector[3], stateVector[4], stateVector[5],
  692.                                                  type, frame, date, mu);
  693.             } else {
  694.                 // we have orbit derivatives
  695.                 return new FieldKeplerianOrbit<>(stateVector[0],    stateVector[1],    stateVector[2],
  696.                                                  stateVector[3],    stateVector[4],    stateVector[5],
  697.                                                  stateVectorDot[0], stateVectorDot[1], stateVectorDot[2],
  698.                                                  stateVectorDot[3], stateVectorDot[4], stateVectorDot[5],
  699.                                                  type, frame, date, mu);
  700.             }
  701.         }

  702.         /** {@inheritDoc} */
  703.         @Override
  704.         public <T extends CalculusFieldElement<T>> FieldKeplerianOrbit<T> convertToFieldOrbit(final Field<T> field,
  705.                                                                                               final Orbit orbit) {
  706.             return new FieldKeplerianOrbit<>(field, KEPLERIAN.convertType(orbit));
  707.         }

  708.         /** {@inheritDoc} */
  709.         @Override
  710.         public ParameterDriversList getDrivers(final double dP, final Orbit orbit, final PositionAngleType type) {
  711.             final ParameterDriversList drivers = new ParameterDriversList();
  712.             final double[] array = new double[6];
  713.             mapOrbitToArray(orbit, type, array, null);
  714.             final double[] scale = scale(dP, orbit);
  715.             final String name = type == PositionAngleType.MEAN ?
  716.                                     MEAN_ANOM :
  717.                                     type == PositionAngleType.ECCENTRIC ? ECC_ANOM : TRUE_ANOM;
  718.             drivers.add(new ParameterDriver(A,    array[0], scale[0],  0.0, Double.POSITIVE_INFINITY));
  719.             drivers.add(new ParameterDriver(ECC,  array[1], scale[1],  0.0, 1.0));
  720.             drivers.add(new ParameterDriver(INC,  array[2], scale[2],  0.0, FastMath.PI));
  721.             drivers.add(new ParameterDriver(PA,   array[3], scale[3], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
  722.             drivers.add(new ParameterDriver(RAAN, array[4], scale[4], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
  723.             drivers.add(new ParameterDriver(name, array[5], scale[5], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
  724.             return drivers;
  725.         }

  726.         /** {@inheritDoc} */
  727.         @Override
  728.         public KeplerianOrbit normalize(final Orbit orbit, final Orbit reference) {

  729.             // convert input to proper type
  730.             final KeplerianOrbit kO = convertType(orbit);
  731.             final KeplerianOrbit kR = convertType(reference);
  732.             final PositionAngleType cachedPositionAngleType = kO.getCachedPositionAngleType();

  733.             // perform normalization
  734.             if (kO.hasDerivatives()) {
  735.                 return new KeplerianOrbit(kO.getA(),
  736.                                           kO.getE(),
  737.                                           kO.getI(),
  738.                                           MathUtils.normalizeAngle(kO.getPerigeeArgument(), kR.getPerigeeArgument()),
  739.                                           MathUtils.normalizeAngle(kO.getRightAscensionOfAscendingNode(),
  740.                                                   kR.getRightAscensionOfAscendingNode()),
  741.                                           MathUtils.normalizeAngle(kO.getAnomaly(cachedPositionAngleType),
  742.                                                   kR.getAnomaly(cachedPositionAngleType)),
  743.                                           kO.getADot(),
  744.                                           kO.getEDot(),
  745.                                           kO.getIDot(),
  746.                                           kO.getPerigeeArgumentDot(),
  747.                                           kO.getRightAscensionOfAscendingNodeDot(),
  748.                                           kO.getAnomalyDot(cachedPositionAngleType),
  749.                                           cachedPositionAngleType,
  750.                                           kO.getFrame(),
  751.                                           kO.getDate(),
  752.                                           kO.getMu());
  753.             } else {
  754.                 return new KeplerianOrbit(kO.getA(),
  755.                                           kO.getE(),
  756.                                           kO.getI(),
  757.                                           MathUtils.normalizeAngle(kO.getPerigeeArgument(), kR.getPerigeeArgument()),
  758.                                           MathUtils.normalizeAngle(kO.getRightAscensionOfAscendingNode(), kR.getRightAscensionOfAscendingNode()),
  759.                                           MathUtils.normalizeAngle(kO.getAnomaly(cachedPositionAngleType),
  760.                                                   kR.getAnomaly(cachedPositionAngleType)),
  761.                                           cachedPositionAngleType,
  762.                                           kO.getFrame(),
  763.                                           kO.getDate(),
  764.                                           kO.getMu());
  765.             }

  766.         }

  767.         /** {@inheritDoc} */
  768.         @Override
  769.         public <T extends CalculusFieldElement<T>> FieldKeplerianOrbit<T> normalize(final FieldOrbit<T> orbit, final FieldOrbit<T> reference) {

  770.             // convert input to proper type
  771.             final FieldKeplerianOrbit<T> kO = convertType(orbit);
  772.             final FieldKeplerianOrbit<T> kR = convertType(reference);
  773.             final PositionAngleType positionAngleType = kO.getCachedPositionAngleType();

  774.             // perform normalization
  775.             if (kO.hasDerivatives()) {
  776.                 return new FieldKeplerianOrbit<>(kO.getA(),
  777.                                                  kO.getE(),
  778.                                                  kO.getI(),
  779.                                                  MathUtils.normalizeAngle(kO.getPerigeeArgument(), kR.getPerigeeArgument()),
  780.                                                  MathUtils.normalizeAngle(kO.getRightAscensionOfAscendingNode(),
  781.                                                          kR.getRightAscensionOfAscendingNode()),
  782.                                                  MathUtils.normalizeAngle(kO.getAnomaly(positionAngleType),
  783.                                                          kR.getAnomaly(positionAngleType)),
  784.                                                  kO.getADot(),
  785.                                                  kO.getEDot(),
  786.                                                  kO.getIDot(),
  787.                                                  kO.getPerigeeArgumentDot(),
  788.                                                  kO.getRightAscensionOfAscendingNodeDot(),
  789.                                                  kO.getAnomalyDot(positionAngleType),
  790.                                                  positionAngleType,
  791.                                                  kO.getFrame(),
  792.                                                  kO.getDate(),
  793.                                                  kO.getMu());
  794.             } else {
  795.                 return new FieldKeplerianOrbit<>(kO.getA(),
  796.                                                  kO.getE(),
  797.                                                  kO.getI(),
  798.                                                  MathUtils.normalizeAngle(kO.getPerigeeArgument(), kR.getPerigeeArgument()),
  799.                                                  MathUtils.normalizeAngle(kO.getRightAscensionOfAscendingNode(),
  800.                                                          kR.getRightAscensionOfAscendingNode()),
  801.                                                  MathUtils.normalizeAngle(kO.getAnomaly(positionAngleType),
  802.                                                          kR.getAnomaly(positionAngleType)),
  803.                                                  positionAngleType,
  804.                                                  kO.getFrame(),
  805.                                                  kO.getDate(),
  806.                                                  kO.getMu());
  807.             }

  808.         }

  809.         /** {@inheritDoc} */
  810.         @Override
  811.         public boolean isPositionAngleBased() {
  812.             return true;
  813.         }

  814.     };

  815.     /** Name for position along X. */
  816.     public static final String POS_X = "Px";

  817.     /** Name for position along Y. */
  818.     public static final String POS_Y = "Py";

  819.     /** Name for position along Z. */
  820.     public static final String POS_Z = "Pz";

  821.     /** Name for velocity along X. */
  822.     public static final String VEL_X = "Vx";

  823.     /** Name for velocity along Y. */
  824.     public static final String VEL_Y = "Vy";

  825.     /** Name for velocity along Z. */
  826.     public static final String VEL_Z = "Vz";

  827.     /** Name for semi major axis. */
  828.     public static final String A     = "a";

  829.     /** Name for eccentricity. */
  830.     public static final String ECC   = "e";

  831.     /** Name for eccentricity vector first component. */
  832.     public static final String E_X   = "ex";

  833.     /** Name for eccentricity vector second component. */
  834.     public static final String E_Y   = "ey";

  835.     /** Name for inclination. */
  836.     public static final String INC   = "i";

  837.     /** Name for inclination vector first component. */
  838.     public static final String H_X   = "hx";

  839.     /** Name for inclination vector second component . */
  840.     public static final String H_Y   = "hy";

  841.     /** Name for perigee argument. */
  842.     public static final String PA    = "ω";

  843.     /** Name for right ascension of ascending node. */
  844.     public static final String RAAN    = "Ω";

  845.     /** Name for mean anomaly. */
  846.     public static final String MEAN_ANOM = "M";

  847.     /** Name for eccentric anomaly. */
  848.     public static final String ECC_ANOM  = "E";

  849.     /** Name for mean anomaly. */
  850.     public static final String TRUE_ANOM = "v";

  851.     /** Name for mean argument of latitude. */
  852.     public static final String MEAN_LAT_ARG = "αM";

  853.     /** Name for eccentric argument of latitude. */
  854.     public static final String ECC_LAT_ARG  = "αE";

  855.     /** Name for mean argument of latitude. */
  856.     public static final String TRUE_LAT_ARG = "αv";

  857.     /** Name for mean argument of longitude. */
  858.     public static final String MEAN_LON_ARG = "λM";

  859.     /** Name for eccentric argument of longitude. */
  860.     public static final String ECC_LON_ARG  = "λE";

  861.     /** Name for mean argument of longitude. */
  862.     public static final String TRUE_LON_ARG = "λv";

  863.     /** Convert an orbit to the instance type.
  864.      * <p>
  865.      * The returned orbit is the specified instance itself if its type already matches,
  866.      * otherwise, a new orbit of the proper type created
  867.      * </p>
  868.      * @param orbit orbit to convert
  869.      * @return converted orbit with type guaranteed to match (so it can be cast safely)
  870.      */
  871.     public abstract Orbit convertType(Orbit orbit);

  872.     /** Convert orbit to state array.
  873.      * <p>
  874.      * Note that all implementations of this method <em>must</em> be consistent with the
  875.      * implementation of the {@link org.orekit.orbits.Orbit#getJacobianWrtCartesian(
  876.      * PositionAngleType, double[][]) Orbit.getJacobianWrtCartesian}
  877.      * method for the corresponding orbit type in terms of parameters order and meaning.
  878.      * </p>
  879.      * @param orbit orbit to map
  880.      * @param type type of the angle
  881.      * @param stateVector flat array into which the state vector should be mapped
  882.      * (it can have more than 6 elements, extra elements are untouched)
  883.      * @param stateVectorDot flat array into which the state vector derivative should be mapped
  884.      * (it can be null if derivatives are not desired, and it can have more than 6 elements, extra elements are untouched)
  885.      */
  886.     public abstract void mapOrbitToArray(Orbit orbit, PositionAngleType type, double[] stateVector, double[] stateVectorDot);

  887.      /** Convert state array to orbital parameters.
  888.      * <p>
  889.      * Note that all implementations of this method <em>must</em> be consistent with the
  890.      * implementation of the {@link org.orekit.orbits.Orbit#getJacobianWrtCartesian(
  891.      * PositionAngleType, double[][]) Orbit.getJacobianWrtCartesian}
  892.      * method for the corresponding orbit type in terms of parameters order and meaning.
  893.      * </p>
  894.      * @param array state as a flat array
  895.      * (it can have more than 6 elements, extra elements are ignored)
  896.      * @param arrayDot state derivative as a flat array
  897.      * (it can be null, in which case Keplerian motion is assumed,
  898.      * and it can have more than 6 elements, extra elements are ignored)
  899.      * @param type type of the angle
  900.      * @param date integration date
  901.      * @param mu central attraction coefficient used for propagation (m³/s²)
  902.      * @param frame frame in which integration is performed
  903.      * @return orbit corresponding to the flat array as a space dynamics object
  904.      */
  905.     public abstract Orbit mapArrayToOrbit(double[] array, double[] arrayDot, PositionAngleType type,
  906.                                           AbsoluteDate date, double mu, Frame frame);

  907.     /** Convert an orbit to the instance type.
  908.      * <p>
  909.      * The returned orbit is the specified instance itself if its type already matches,
  910.      * otherwise, a new orbit of the proper type created
  911.      * </p>
  912.      * @param <T> CalculusFieldElement used
  913.      * @param orbit orbit to convert
  914.      * @return converted orbit with type guaranteed to match (so it can be cast safely)
  915.      */
  916.     public abstract <T extends CalculusFieldElement<T>> FieldOrbit<T> convertType(FieldOrbit<T> orbit);

  917.     /** Convert orbit to state array.
  918.      * <p>
  919.      * Note that all implementations of this method <em>must</em> be consistent with the
  920.      * implementation of the {@link org.orekit.orbits.Orbit#getJacobianWrtCartesian(
  921.      * PositionAngleType, double[][]) Orbit.getJacobianWrtCartesian}
  922.      * method for the corresponding orbit type in terms of parameters order and meaning.
  923.      * </p>
  924.      * @param <T> CalculusFieldElement used
  925.      * @param orbit orbit to map
  926.      * @param type type of the angle
  927.      * @param stateVector flat array into which the state vector should be mapped
  928.      * (it can have more than 6 elements, extra elements are untouched)
  929.      * @param stateVectorDot flat array into which the state vector derivative should be mapped
  930.      * (it can be null if derivatives are not desired, and it can have more than 6 elements, extra elements are untouched)
  931.      */
  932.     public abstract <T extends CalculusFieldElement<T>>void mapOrbitToArray(FieldOrbit<T> orbit, PositionAngleType type,
  933.                                                                             T[] stateVector, T[] stateVectorDot);


  934.     /** Convert state array to orbital parameters.
  935.      * <p>
  936.      * Note that all implementations of this method <em>must</em> be consistent with the
  937.      * implementation of the {@link org.orekit.orbits.Orbit#getJacobianWrtCartesian(
  938.      * PositionAngleType, double[][]) Orbit.getJacobianWrtCartesian}
  939.      * method for the corresponding orbit type in terms of parameters order and meaning.
  940.      * </p>
  941.      * @param <T> CalculusFieldElement used
  942.      * @param array state as a flat array
  943.      * (it can have more than 6 elements, extra elements are ignored)
  944.      * @param arrayDot state derivative as a flat array
  945.      * (it can be null, in which case Keplerian motion is assumed,
  946.      * @param type type of the angle
  947.      * @param date integration date
  948.      * @param mu central attraction coefficient used for propagation (m³/s²)
  949.      * @param frame frame in which integration is performed
  950.      * @return orbit corresponding to the flat array as a space dynamics object
  951.      */
  952.     public abstract <T extends CalculusFieldElement<T>> FieldOrbit<T> mapArrayToOrbit(T[] array,
  953.                                                                                       T[] arrayDot,
  954.                                                                                       PositionAngleType type,
  955.                                                                                       FieldAbsoluteDate<T> date,
  956.                                                                                       T mu, Frame frame);

  957.     /** Convert an orbit to the "Fielded" instance type.
  958.      * @param <T> CalculusFieldElement used
  959.      * @param field CalculusField
  960.      * @param orbit base orbit
  961.      * @return converted FieldOrbit with type guaranteed to match (so it can be cast safely)
  962.      * @since 12.0
  963.      */
  964.     public abstract <T extends CalculusFieldElement<T>> FieldOrbit<T> convertToFieldOrbit(Field<T> field,
  965.                                                                                            Orbit orbit);

  966.     /** Get parameters drivers initialized from a reference orbit.
  967.      * @param dP user specified position error
  968.      * @param orbit reference orbit
  969.      * @param type type of the angle
  970.      * @return parameters drivers initialized from reference orbit
  971.      */
  972.     public abstract ParameterDriversList getDrivers(double dP, Orbit orbit,
  973.                                                     PositionAngleType type);

  974.     /** Normalize one orbit with respect to a reference one.
  975.      * <p>
  976.      * Given a, angular component ζ of an orbit and the corresponding
  977.      * angular component ζᵣ in the reference orbit, the angular component
  978.      * ζₙ of the normalized orbit will be ζₙ = ζ + 2kπ
  979.      * where k is chosen such that ζᵣ - π ≤ ζₙ ≤ ζᵣ + π. This is intended
  980.      * to avoid too large discontinuities and is particularly useful
  981.      * for normalizing the orbit after an impulsive maneuver with respect
  982.      * to the reference picked up before the maneuver.
  983.      * </p>
  984.      * @param <T> CalculusFieldElement used
  985.      * @param orbit orbit to normalize
  986.      * @param reference reference orbit
  987.      * @return normalized orbit (the type is guaranteed to match {@link OrbitType})
  988.      * @since 11.1
  989.      */
  990.     public abstract <T extends CalculusFieldElement<T>> FieldOrbit<T> normalize(FieldOrbit<T> orbit,
  991.                                                                                 FieldOrbit<T> reference);

  992.     /** Normalize one orbit with respect to a reference one.
  993.      * <p>
  994.      * Given a, angular component ζ of an orbit and the corresponding
  995.      * angular component ζᵣ in the reference orbit, the angular component
  996.      * ζₙ of the normalized orbit will be ζₙ = ζ + 2kπ
  997.      * where k is chosen such that ζᵣ - π ≤ ζₙ ≤ ζᵣ + π. This is intended
  998.      * to avoid too large discontinuities and is particularly useful
  999.      * for normalizing the orbit after an impulsive maneuver with respect
  1000.      * to the reference picked up before the maneuver.
  1001.      * </p>
  1002.      * @param orbit orbit to normalize
  1003.      * @param reference reference orbit
  1004.      * @return normalized orbit (the type is guaranteed to match {@link OrbitType})
  1005.      * @since 11.1
  1006.      */
  1007.     public abstract Orbit normalize(Orbit orbit, Orbit reference);

  1008.     /** Tells if the orbit type is based on position angles or not.
  1009.      * @return true if based on {@link PositionAngleType}
  1010.      * @since 12.0
  1011.      */
  1012.     public abstract boolean isPositionAngleBased();

  1013.     /** Compute scaling factor for parameters drivers.
  1014.      * <p>
  1015.      * The scales are estimated from partial derivatives properties of orbits,
  1016.      * starting from a scalar position error specified by the user.
  1017.      * Considering the energy conservation equation V = sqrt(mu (2/r - 1/a)),
  1018.      * we get at constant energy (i.e. on a Keplerian trajectory):
  1019.      * <pre>
  1020.      * V r² |dV| = mu |dr|
  1021.      * </pre>
  1022.      * <p> So we deduce a scalar velocity error consistent with the position error.
  1023.      * From here, we apply orbits Jacobians matrices to get consistent scales
  1024.      * on orbital parameters.
  1025.      *
  1026.      * @param dP user specified position error
  1027.      * @param orbit reference orbit
  1028.      * @return scaling factor array
  1029.      */
  1030.     protected double[] scale(final double dP, final Orbit orbit) {

  1031.         // estimate the scalar velocity error
  1032.         final PVCoordinates pv = orbit.getPVCoordinates();
  1033.         final double r2 = pv.getPosition().getNormSq();
  1034.         final double v  = pv.getVelocity().getNorm();
  1035.         final double dV = orbit.getMu() * dP / (v * r2);

  1036.         final double[] scale = new double[6];

  1037.         // convert the orbit to the desired type
  1038.         final double[][] jacobian = new double[6][6];
  1039.         final Orbit converted = convertType(orbit);
  1040.         converted.getJacobianWrtCartesian(PositionAngleType.TRUE, jacobian);

  1041.         for (int i = 0; i < 6; ++i) {
  1042.             final double[] row = jacobian[i];
  1043.             scale[i] = FastMath.abs(row[0]) * dP +
  1044.                        FastMath.abs(row[1]) * dP +
  1045.                        FastMath.abs(row[2]) * dP +
  1046.                        FastMath.abs(row[3]) * dV +
  1047.                        FastMath.abs(row[4]) * dV +
  1048.                        FastMath.abs(row[5]) * dV;
  1049.             if (Double.isNaN(scale[i])) {
  1050.                 throw new OrekitException(OrekitMessages.SINGULAR_JACOBIAN_FOR_ORBIT_TYPE, this);
  1051.             }
  1052.         }

  1053.         return scale;

  1054.     }

  1055. }