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.             // perform normalization
  303.             if (cO.hasDerivatives()) {
  304.                 return new CircularOrbit(cO.getA(),
  305.                                          cO.getCircularEx(),
  306.                                          cO.getCircularEy(),
  307.                                          cO.getI(),
  308.                                          MathUtils.normalizeAngle(cO.getRightAscensionOfAscendingNode(), cR.getRightAscensionOfAscendingNode()),
  309.                                          MathUtils.normalizeAngle(cO.getAlphaV(), cR.getAlphaV()),
  310.                                          cO.getADot(),
  311.                                          cO.getCircularExDot(),
  312.                                          cO.getCircularEyDot(),
  313.                                          cO.getIDot(),
  314.                                          cO.getRightAscensionOfAscendingNodeDot(),
  315.                                          cO.getAlphaVDot(),
  316.                                          PositionAngleType.TRUE,
  317.                                          cO.getFrame(),
  318.                                          cO.getDate(),
  319.                                          cO.getMu());
  320.             } else {
  321.                 return new CircularOrbit(cO.getA(),
  322.                                          cO.getCircularEx(),
  323.                                          cO.getCircularEy(),
  324.                                          cO.getI(),
  325.                                          MathUtils.normalizeAngle(cO.getRightAscensionOfAscendingNode(), cR.getRightAscensionOfAscendingNode()),
  326.                                          MathUtils.normalizeAngle(cO.getAlphaV(), cR.getAlphaV()),
  327.                                          PositionAngleType.TRUE,
  328.                                          cO.getFrame(),
  329.                                          cO.getDate(),
  330.                                          cO.getMu());
  331.             }

  332.         }

  333.         /** {@inheritDoc} */
  334.         @Override
  335.         public <T extends CalculusFieldElement<T>> FieldCircularOrbit<T> normalize(final FieldOrbit<T> orbit, final FieldOrbit<T> reference) {

  336.             // convert input to proper type
  337.             final FieldCircularOrbit<T> cO = convertType(orbit);
  338.             final FieldCircularOrbit<T> cR = convertType(reference);

  339.             // perform normalization
  340.             if (cO.hasDerivatives()) {
  341.                 return new FieldCircularOrbit<>(cO.getA(),
  342.                                                 cO.getCircularEx(),
  343.                                                 cO.getCircularEy(),
  344.                                                 cO.getI(),
  345.                                                 MathUtils.normalizeAngle(cO.getRightAscensionOfAscendingNode(), cR.getRightAscensionOfAscendingNode()),
  346.                                                 MathUtils.normalizeAngle(cO.getAlphaV(), cR.getAlphaV()),
  347.                                                 cO.getADot(),
  348.                                                 cO.getCircularExDot(),
  349.                                                 cO.getCircularEyDot(),
  350.                                                 cO.getIDot(),
  351.                                                 cO.getRightAscensionOfAscendingNodeDot(),
  352.                                                 cO.getAlphaVDot(),
  353.                                                 PositionAngleType.TRUE,
  354.                                                 cO.getFrame(),
  355.                                                 cO.getDate(),
  356.                                                 cO.getMu());
  357.             } else {
  358.                 return new FieldCircularOrbit<>(cO.getA(),
  359.                                                 cO.getCircularEx(),
  360.                                                 cO.getCircularEy(),
  361.                                                 cO.getI(),
  362.                                                 MathUtils.normalizeAngle(cO.getRightAscensionOfAscendingNode(), cR.getRightAscensionOfAscendingNode()),
  363.                                                 MathUtils.normalizeAngle(cO.getAlphaV(), cR.getAlphaV()),
  364.                                                 PositionAngleType.TRUE,
  365.                                                 cO.getFrame(),
  366.                                                 cO.getDate(),
  367.                                                 cO.getMu());
  368.             }

  369.         }

  370.         /** {@inheritDoc} */
  371.         @Override
  372.         public boolean isPositionAngleBased() {
  373.             return true;
  374.         }

  375.     },

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

  378.         /** {@inheritDoc} */
  379.         @Override
  380.         public EquinoctialOrbit convertType(final Orbit orbit) {
  381.             return (orbit.getType() == this) ? (EquinoctialOrbit) orbit : new EquinoctialOrbit(orbit);
  382.         }

  383.         /** {@inheritDoc} */
  384.         @Override
  385.         public void mapOrbitToArray(final Orbit orbit, final PositionAngleType type,
  386.                                     final double[] stateVector, final double[] stateVectorDot) {

  387.             final EquinoctialOrbit equinoctialOrbit =
  388.                 (EquinoctialOrbit) OrbitType.EQUINOCTIAL.convertType(orbit);

  389.             stateVector[0] = equinoctialOrbit.getA();
  390.             stateVector[1] = equinoctialOrbit.getEquinoctialEx();
  391.             stateVector[2] = equinoctialOrbit.getEquinoctialEy();
  392.             stateVector[3] = equinoctialOrbit.getHx();
  393.             stateVector[4] = equinoctialOrbit.getHy();
  394.             stateVector[5] = equinoctialOrbit.getL(type);

  395.             if (stateVectorDot != null) {
  396.                 if (orbit.hasDerivatives()) {
  397.                     stateVectorDot[0] = equinoctialOrbit.getADot();
  398.                     stateVectorDot[1] = equinoctialOrbit.getEquinoctialExDot();
  399.                     stateVectorDot[2] = equinoctialOrbit.getEquinoctialEyDot();
  400.                     stateVectorDot[3] = equinoctialOrbit.getHxDot();
  401.                     stateVectorDot[4] = equinoctialOrbit.getHyDot();
  402.                     stateVectorDot[5] = equinoctialOrbit.getLDot(type);
  403.                 } else {
  404.                     Arrays.fill(stateVectorDot, 0, 6, Double.NaN);
  405.                 }
  406.             }

  407.         }

  408.         /** {@inheritDoc} */
  409.         @Override
  410.         public EquinoctialOrbit mapArrayToOrbit(final double[] stateVector, final double[] stateVectorDot, final PositionAngleType type,
  411.                                                 final AbsoluteDate date, final double mu, final Frame frame) {
  412.             if (stateVectorDot == null) {
  413.                 // we don't have orbit derivatives
  414.                 return new EquinoctialOrbit(stateVector[0], stateVector[1], stateVector[2],
  415.                                             stateVector[3], stateVector[4], stateVector[5],
  416.                                             type, frame, date, mu);
  417.             } else {
  418.                 // we have orbit derivatives
  419.                 return new EquinoctialOrbit(stateVector[0],    stateVector[1],    stateVector[2],
  420.                                             stateVector[3],    stateVector[4],    stateVector[5],
  421.                                             stateVectorDot[0], stateVectorDot[1], stateVectorDot[2],
  422.                                             stateVectorDot[3], stateVectorDot[4], stateVectorDot[5],
  423.                                             type, frame, date, mu);
  424.             }
  425.         }

  426.         /** {@inheritDoc} */
  427.         @Override
  428.         public <T extends CalculusFieldElement<T>> FieldEquinoctialOrbit<T> convertType(final FieldOrbit<T> orbit) {
  429.             return (orbit.getType() == this) ? (FieldEquinoctialOrbit<T>) orbit : new FieldEquinoctialOrbit<>(orbit);
  430.         }

  431.         /** {@inheritDoc} */
  432.         @Override
  433.         public <T extends CalculusFieldElement<T>> void mapOrbitToArray(final FieldOrbit<T> orbit,
  434.                                                                         final PositionAngleType type,
  435.                                                                         final T[] stateVector,
  436.                                                                         final T[] stateVectorDot) {

  437.             final FieldEquinoctialOrbit<T> equinoctialOrbit =
  438.                 (FieldEquinoctialOrbit<T>) OrbitType.EQUINOCTIAL.convertType(orbit);

  439.             stateVector[0] = equinoctialOrbit.getA();
  440.             stateVector[1] = equinoctialOrbit.getEquinoctialEx();
  441.             stateVector[2] = equinoctialOrbit.getEquinoctialEy();
  442.             stateVector[3] = equinoctialOrbit.getHx();
  443.             stateVector[4] = equinoctialOrbit.getHy();
  444.             stateVector[5] = equinoctialOrbit.getL(type);

  445.             if (stateVectorDot != null) {
  446.                 if (orbit.hasDerivatives()) {
  447.                     stateVectorDot[0] = equinoctialOrbit.getADot();
  448.                     stateVectorDot[1] = equinoctialOrbit.getEquinoctialExDot();
  449.                     stateVectorDot[2] = equinoctialOrbit.getEquinoctialEyDot();
  450.                     stateVectorDot[3] = equinoctialOrbit.getHxDot();
  451.                     stateVectorDot[4] = equinoctialOrbit.getHyDot();
  452.                     stateVectorDot[5] = equinoctialOrbit.getLDot(type);
  453.                 } else {
  454.                     Arrays.fill(stateVectorDot, 0, 6, orbit.getZero().add(Double.NaN));
  455.                 }
  456.             }

  457.         }

  458.         /** {@inheritDoc} */
  459.         @Override
  460.         public <T extends CalculusFieldElement<T>> FieldEquinoctialOrbit<T> mapArrayToOrbit(final T[] stateVector,
  461.                                                                                             final T[] stateVectorDot,
  462.                                                                                             final PositionAngleType type,
  463.                                                                                             final FieldAbsoluteDate<T> date,
  464.                                                                                             final T mu, final Frame frame) {
  465.             if (stateVectorDot == null) {
  466.                 // we don't have orbit derivatives
  467.                 return new FieldEquinoctialOrbit<>(stateVector[0], stateVector[1], stateVector[2],
  468.                                                    stateVector[3], stateVector[4], stateVector[5],
  469.                                                    type, frame, date, mu);
  470.             } else {
  471.                 // we have orbit derivatives
  472.                 return new FieldEquinoctialOrbit<>(stateVector[0],    stateVector[1],    stateVector[2],
  473.                                                    stateVector[3],    stateVector[4],    stateVector[5],
  474.                                                    stateVectorDot[0], stateVectorDot[1], stateVectorDot[2],
  475.                                                    stateVectorDot[3], stateVectorDot[4], stateVectorDot[5],
  476.                                                    type, frame, date, mu);
  477.             }
  478.         }

  479.         /** {@inheritDoc} */
  480.         @Override
  481.         public <T extends CalculusFieldElement<T>> FieldEquinoctialOrbit<T> convertToFieldOrbit(final Field<T> field,
  482.                                                                                                 final Orbit orbit) {
  483.             return new FieldEquinoctialOrbit<>(field, EQUINOCTIAL.convertType(orbit));
  484.         }

  485.         /** {@inheritDoc} */
  486.         @Override
  487.         public ParameterDriversList getDrivers(final double dP, final Orbit orbit, final PositionAngleType type) {
  488.             final ParameterDriversList drivers = new ParameterDriversList();
  489.             final double[] array = new double[6];
  490.             mapOrbitToArray(orbit, type, array, null);
  491.             final double[] scale = scale(dP, orbit);
  492.             final String name = type == PositionAngleType.MEAN ?
  493.                                     MEAN_LON_ARG :
  494.                                     type == PositionAngleType.ECCENTRIC ? ECC_LON_ARG : TRUE_LON_ARG;
  495.             drivers.add(new ParameterDriver(A,    array[0], scale[0],  0.0, Double.POSITIVE_INFINITY));
  496.             drivers.add(new ParameterDriver(E_X,  array[1], scale[1], -1.0, 1.0));
  497.             drivers.add(new ParameterDriver(E_Y,  array[2], scale[2], -1.0, 1.0));
  498.             drivers.add(new ParameterDriver(H_X,  array[3], scale[3], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
  499.             drivers.add(new ParameterDriver(H_Y,  array[4], scale[4], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
  500.             drivers.add(new ParameterDriver(name, array[5], scale[5], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
  501.             return drivers;
  502.         }

  503.         /** {@inheritDoc} */
  504.         @Override
  505.         public EquinoctialOrbit normalize(final Orbit orbit, final Orbit reference) {

  506.             // convert input to proper type
  507.             final EquinoctialOrbit eO = convertType(orbit);
  508.             final EquinoctialOrbit eR = convertType(reference);

  509.             // perform normalization
  510.             if (eO.hasDerivatives()) {
  511.                 return new EquinoctialOrbit(eO.getA(),
  512.                                             eO.getEquinoctialEx(),
  513.                                             eO.getEquinoctialEy(),
  514.                                             eO.getHx(),
  515.                                             eO.getHy(),
  516.                                             MathUtils.normalizeAngle(eO.getLv(), eR.getLv()),
  517.                                             eO.getADot(),
  518.                                             eO.getEquinoctialExDot(),
  519.                                             eO.getEquinoctialEyDot(),
  520.                                             eO.getHxDot(),
  521.                                             eO.getHyDot(),
  522.                                             eO.getLvDot(),
  523.                                             PositionAngleType.TRUE,
  524.                                             eO.getFrame(),
  525.                                             eO.getDate(),
  526.                                             eO.getMu());
  527.             } else {
  528.                 return new EquinoctialOrbit(eO.getA(),
  529.                                             eO.getEquinoctialEx(),
  530.                                             eO.getEquinoctialEy(),
  531.                                             eO.getHx(),
  532.                                             eO.getHy(),
  533.                                             MathUtils.normalizeAngle(eO.getLv(), eR.getLv()),
  534.                                             PositionAngleType.TRUE,
  535.                                             eO.getFrame(),
  536.                                             eO.getDate(),
  537.                                             eO.getMu());
  538.             }

  539.         }

  540.         /** {@inheritDoc} */
  541.         @Override
  542.         public <T extends CalculusFieldElement<T>> FieldEquinoctialOrbit<T> normalize(final FieldOrbit<T> orbit, final FieldOrbit<T> reference) {

  543.             // convert input to proper type
  544.             final FieldEquinoctialOrbit<T> eO = convertType(orbit);
  545.             final FieldEquinoctialOrbit<T> eR = convertType(reference);

  546.             // perform normalization
  547.             if (eO.hasDerivatives()) {
  548.                 return new FieldEquinoctialOrbit<>(eO.getA(),
  549.                                                    eO.getEquinoctialEx(),
  550.                                                    eO.getEquinoctialEy(),
  551.                                                    eO.getHx(),
  552.                                                    eO.getHy(),
  553.                                                    MathUtils.normalizeAngle(eO.getLv(), eR.getLv()),
  554.                                                    eO.getADot(),
  555.                                                    eO.getEquinoctialExDot(),
  556.                                                    eO.getEquinoctialEyDot(),
  557.                                                    eO.getHxDot(),
  558.                                                    eO.getHyDot(),
  559.                                                    eO.getLvDot(),
  560.                                                    PositionAngleType.TRUE,
  561.                                                    eO.getFrame(),
  562.                                                    eO.getDate(),
  563.                                                    eO.getMu());
  564.             } else {
  565.                 return new FieldEquinoctialOrbit<>(eO.getA(),
  566.                                                    eO.getEquinoctialEx(),
  567.                                                    eO.getEquinoctialEy(),
  568.                                                    eO.getHx(),
  569.                                                    eO.getHy(),
  570.                                                    MathUtils.normalizeAngle(eO.getLv(), eR.getLv()),
  571.                                                    PositionAngleType.TRUE,
  572.                                                    eO.getFrame(),
  573.                                                    eO.getDate(),
  574.                                                    eO.getMu());
  575.             }

  576.         }

  577.         /** {@inheritDoc} */
  578.         @Override
  579.         public boolean isPositionAngleBased() {
  580.             return true;
  581.         }

  582.     },

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

  585.         /** {@inheritDoc} */
  586.         @Override
  587.         public KeplerianOrbit convertType(final Orbit orbit) {
  588.             return (orbit.getType() == this) ? (KeplerianOrbit) orbit : new KeplerianOrbit(orbit);
  589.         }

  590.         /** {@inheritDoc} */
  591.         @Override
  592.         public void mapOrbitToArray(final Orbit orbit, final PositionAngleType type,
  593.                                     final double[] stateVector, final double[] stateVectorDot) {

  594.             final KeplerianOrbit keplerianOrbit =
  595.                 (KeplerianOrbit) OrbitType.KEPLERIAN.convertType(orbit);

  596.             stateVector[0] = keplerianOrbit.getA();
  597.             stateVector[1] = keplerianOrbit.getE();
  598.             stateVector[2] = keplerianOrbit.getI();
  599.             stateVector[3] = keplerianOrbit.getPerigeeArgument();
  600.             stateVector[4] = keplerianOrbit.getRightAscensionOfAscendingNode();
  601.             stateVector[5] = keplerianOrbit.getAnomaly(type);

  602.             if (stateVectorDot != null) {
  603.                 if (orbit.hasDerivatives()) {
  604.                     stateVectorDot[0] = keplerianOrbit.getADot();
  605.                     stateVectorDot[1] = keplerianOrbit.getEDot();
  606.                     stateVectorDot[2] = keplerianOrbit.getIDot();
  607.                     stateVectorDot[3] = keplerianOrbit.getPerigeeArgumentDot();
  608.                     stateVectorDot[4] = keplerianOrbit.getRightAscensionOfAscendingNodeDot();
  609.                     stateVectorDot[5] = keplerianOrbit.getAnomalyDot(type);
  610.                 } else {
  611.                     Arrays.fill(stateVectorDot, 0, 6, Double.NaN);
  612.                 }
  613.             }

  614.         }

  615.         /** {@inheritDoc} */
  616.         @Override
  617.         public KeplerianOrbit mapArrayToOrbit(final double[] stateVector, final double[] stateVectorDot, final PositionAngleType type,
  618.                                               final AbsoluteDate date, final double mu, final Frame frame) {
  619.             if (stateVectorDot == null) {
  620.                 // we don't have orbit derivatives
  621.                 return new KeplerianOrbit(stateVector[0], stateVector[1], stateVector[2],
  622.                                           stateVector[3], stateVector[4], stateVector[5],
  623.                                           type, frame, date, mu);
  624.             } else {
  625.                 // we have orbit derivatives
  626.                 return new KeplerianOrbit(stateVector[0],    stateVector[1],    stateVector[2],
  627.                                           stateVector[3],    stateVector[4],    stateVector[5],
  628.                                           stateVectorDot[0], stateVectorDot[1], stateVectorDot[2],
  629.                                           stateVectorDot[3], stateVectorDot[4], stateVectorDot[5],
  630.                                           type, frame, date, mu);
  631.             }
  632.         }

  633.         /** {@inheritDoc} */
  634.         @Override
  635.         public <T extends CalculusFieldElement<T>> FieldKeplerianOrbit<T> convertType(final FieldOrbit<T> orbit) {
  636.             return (orbit.getType() == this) ? (FieldKeplerianOrbit<T>) orbit : new FieldKeplerianOrbit<>(orbit);
  637.         }

  638.         /** {@inheritDoc} */
  639.         @Override
  640.         public <T extends CalculusFieldElement<T>> void mapOrbitToArray(final FieldOrbit<T> orbit,
  641.                                                                         final PositionAngleType type,
  642.                                                                         final T[] stateVector,
  643.                                                                         final T[] stateVectorDot) {
  644.             final FieldKeplerianOrbit<T> keplerianOrbit =
  645.                             (FieldKeplerianOrbit<T>) OrbitType.KEPLERIAN.convertType(orbit);

  646.             stateVector[0] = keplerianOrbit.getA();
  647.             stateVector[1] = keplerianOrbit.getE();
  648.             stateVector[2] = keplerianOrbit.getI();
  649.             stateVector[3] = keplerianOrbit.getPerigeeArgument();
  650.             stateVector[4] = keplerianOrbit.getRightAscensionOfAscendingNode();
  651.             stateVector[5] = keplerianOrbit.getAnomaly(type);

  652.             if (stateVectorDot != null) {
  653.                 if (orbit.hasDerivatives()) {
  654.                     stateVectorDot[0] = keplerianOrbit.getADot();
  655.                     stateVectorDot[1] = keplerianOrbit.getEDot();
  656.                     stateVectorDot[2] = keplerianOrbit.getIDot();
  657.                     stateVectorDot[3] = keplerianOrbit.getPerigeeArgumentDot();
  658.                     stateVectorDot[4] = keplerianOrbit.getRightAscensionOfAscendingNodeDot();
  659.                     stateVectorDot[5] = keplerianOrbit.getAnomalyDot(type);
  660.                 } else {
  661.                     Arrays.fill(stateVectorDot, 0, 6, orbit.getZero().add(Double.NaN));
  662.                 }
  663.             }

  664.         }

  665.         /** {@inheritDoc} */
  666.         @Override
  667.         public <T extends CalculusFieldElement<T>> FieldKeplerianOrbit<T> mapArrayToOrbit(final T[] stateVector,
  668.                                                                                           final T[] stateVectorDot,
  669.                                                                                           final PositionAngleType type,
  670.                                                                                           final FieldAbsoluteDate<T> date,
  671.                                                                                           final T mu, final Frame frame) {
  672.             if (stateVectorDot == null) {
  673.                 // we don't have orbit derivatives
  674.                 return new FieldKeplerianOrbit<>(stateVector[0], stateVector[1], stateVector[2],
  675.                                                  stateVector[3], stateVector[4], stateVector[5],
  676.                                                  type, frame, date, mu);
  677.             } else {
  678.                 // we have orbit derivatives
  679.                 return new FieldKeplerianOrbit<>(stateVector[0],    stateVector[1],    stateVector[2],
  680.                                                  stateVector[3],    stateVector[4],    stateVector[5],
  681.                                                  stateVectorDot[0], stateVectorDot[1], stateVectorDot[2],
  682.                                                  stateVectorDot[3], stateVectorDot[4], stateVectorDot[5],
  683.                                                  type, frame, date, mu);
  684.             }
  685.         }

  686.         /** {@inheritDoc} */
  687.         @Override
  688.         public <T extends CalculusFieldElement<T>> FieldKeplerianOrbit<T> convertToFieldOrbit(final Field<T> field,
  689.                                                                                               final Orbit orbit) {
  690.             return new FieldKeplerianOrbit<>(field, KEPLERIAN.convertType(orbit));
  691.         }

  692.         /** {@inheritDoc} */
  693.         @Override
  694.         public ParameterDriversList getDrivers(final double dP, final Orbit orbit, final PositionAngleType type) {
  695.             final ParameterDriversList drivers = new ParameterDriversList();
  696.             final double[] array = new double[6];
  697.             mapOrbitToArray(orbit, type, array, null);
  698.             final double[] scale = scale(dP, orbit);
  699.             final String name = type == PositionAngleType.MEAN ?
  700.                                     MEAN_ANOM :
  701.                                     type == PositionAngleType.ECCENTRIC ? ECC_ANOM : TRUE_ANOM;
  702.             drivers.add(new ParameterDriver(A,    array[0], scale[0],  0.0, Double.POSITIVE_INFINITY));
  703.             drivers.add(new ParameterDriver(ECC,  array[1], scale[1],  0.0, 1.0));
  704.             drivers.add(new ParameterDriver(INC,  array[2], scale[2],  0.0, FastMath.PI));
  705.             drivers.add(new ParameterDriver(PA,   array[3], scale[3], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
  706.             drivers.add(new ParameterDriver(RAAN, array[4], scale[4], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
  707.             drivers.add(new ParameterDriver(name, array[5], scale[5], Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY));
  708.             return drivers;
  709.         }

  710.         /** {@inheritDoc} */
  711.         @Override
  712.         public KeplerianOrbit normalize(final Orbit orbit, final Orbit reference) {

  713.             // convert input to proper type
  714.             final KeplerianOrbit kO = convertType(orbit);
  715.             final KeplerianOrbit kR = convertType(reference);

  716.             // perform normalization
  717.             if (kO.hasDerivatives()) {
  718.                 return new KeplerianOrbit(kO.getA(),
  719.                                           kO.getE(),
  720.                                           kO.getI(),
  721.                                           MathUtils.normalizeAngle(kO.getPerigeeArgument(), kR.getPerigeeArgument()),
  722.                                           MathUtils.normalizeAngle(kO.getRightAscensionOfAscendingNode(), kR.getRightAscensionOfAscendingNode()),
  723.                                           MathUtils.normalizeAngle(kO.getTrueAnomaly(), kR.getTrueAnomaly()),
  724.                                           kO.getADot(),
  725.                                           kO.getEDot(),
  726.                                           kO.getIDot(),
  727.                                           kO.getPerigeeArgumentDot(),
  728.                                           kO.getRightAscensionOfAscendingNodeDot(),
  729.                                           kO.getTrueAnomalyDot(),
  730.                                           PositionAngleType.TRUE,
  731.                                           kO.getFrame(),
  732.                                           kO.getDate(),
  733.                                           kO.getMu());
  734.             } else {
  735.                 return new KeplerianOrbit(kO.getA(),
  736.                                           kO.getE(),
  737.                                           kO.getI(),
  738.                                           MathUtils.normalizeAngle(kO.getPerigeeArgument(), kR.getPerigeeArgument()),
  739.                                           MathUtils.normalizeAngle(kO.getRightAscensionOfAscendingNode(), kR.getRightAscensionOfAscendingNode()),
  740.                                           MathUtils.normalizeAngle(kO.getTrueAnomaly(), kR.getTrueAnomaly()),
  741.                                           PositionAngleType.TRUE,
  742.                                           kO.getFrame(),
  743.                                           kO.getDate(),
  744.                                           kO.getMu());
  745.             }

  746.         }

  747.         /** {@inheritDoc} */
  748.         @Override
  749.         public <T extends CalculusFieldElement<T>> FieldKeplerianOrbit<T> normalize(final FieldOrbit<T> orbit, final FieldOrbit<T> reference) {

  750.             // convert input to proper type
  751.             final FieldKeplerianOrbit<T> kO = convertType(orbit);
  752.             final FieldKeplerianOrbit<T> kR = convertType(reference);

  753.             // perform normalization
  754.             if (kO.hasDerivatives()) {
  755.                 return new FieldKeplerianOrbit<>(kO.getA(),
  756.                                                  kO.getE(),
  757.                                                  kO.getI(),
  758.                                                  MathUtils.normalizeAngle(kO.getPerigeeArgument(), kR.getPerigeeArgument()),
  759.                                                  MathUtils.normalizeAngle(kO.getRightAscensionOfAscendingNode(), kR.getRightAscensionOfAscendingNode()),
  760.                                                  MathUtils.normalizeAngle(kO.getTrueAnomaly(), kR.getTrueAnomaly()),
  761.                                                  kO.getADot(),
  762.                                                  kO.getEDot(),
  763.                                                  kO.getIDot(),
  764.                                                  kO.getPerigeeArgumentDot(),
  765.                                                  kO.getRightAscensionOfAscendingNodeDot(),
  766.                                                  kO.getTrueAnomalyDot(),
  767.                                                  PositionAngleType.TRUE,
  768.                                                  kO.getFrame(),
  769.                                                  kO.getDate(),
  770.                                                  kO.getMu());
  771.             } else {
  772.                 return new FieldKeplerianOrbit<>(kO.getA(),
  773.                                                  kO.getE(),
  774.                                                  kO.getI(),
  775.                                                  MathUtils.normalizeAngle(kO.getPerigeeArgument(), kR.getPerigeeArgument()),
  776.                                                  MathUtils.normalizeAngle(kO.getRightAscensionOfAscendingNode(), kR.getRightAscensionOfAscendingNode()),
  777.                                                  MathUtils.normalizeAngle(kO.getTrueAnomaly(), kR.getTrueAnomaly()),
  778.                                                  PositionAngleType.TRUE,
  779.                                                  kO.getFrame(),
  780.                                                  kO.getDate(),
  781.                                                  kO.getMu());
  782.             }

  783.         }

  784.         /** {@inheritDoc} */
  785.         @Override
  786.         public boolean isPositionAngleBased() {
  787.             return true;
  788.         }

  789.     };

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

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

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

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

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

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

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

  804.     /** Name for eccentricity. */
  805.     public static final String ECC   = "e";

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

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

  810.     /** Name for inclination. */
  811.     public static final String INC   = "i";

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

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

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

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

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

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

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

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

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

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

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

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

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

  838.     /** Convert an orbit to the instance type.
  839.      * <p>
  840.      * The returned orbit is the specified instance itself if its type already matches,
  841.      * otherwise, a new orbit of the proper type created
  842.      * </p>
  843.      * @param orbit orbit to convert
  844.      * @return converted orbit with type guaranteed to match (so it can be cast safely)
  845.      */
  846.     public abstract Orbit convertType(Orbit orbit);

  847.     /** Convert orbit to state array.
  848.      * <p>
  849.      * Note that all implementations of this method <em>must</em> be consistent with the
  850.      * implementation of the {@link org.orekit.orbits.Orbit#getJacobianWrtCartesian(
  851.      * PositionAngleType, double[][]) Orbit.getJacobianWrtCartesian}
  852.      * method for the corresponding orbit type in terms of parameters order and meaning.
  853.      * </p>
  854.      * @param orbit orbit to map
  855.      * @param type type of the angle
  856.      * @param stateVector flat array into which the state vector should be mapped
  857.      * (it can have more than 6 elements, extra elements are untouched)
  858.      * @param stateVectorDot flat array into which the state vector derivative should be mapped
  859.      * (it can be null if derivatives are not desired, and it can have more than 6 elements, extra elements are untouched)
  860.      */
  861.     public abstract void mapOrbitToArray(Orbit orbit, PositionAngleType type, double[] stateVector, double[] stateVectorDot);

  862.      /** Convert state array to orbital parameters.
  863.      * <p>
  864.      * Note that all implementations of this method <em>must</em> be consistent with the
  865.      * implementation of the {@link org.orekit.orbits.Orbit#getJacobianWrtCartesian(
  866.      * PositionAngleType, double[][]) Orbit.getJacobianWrtCartesian}
  867.      * method for the corresponding orbit type in terms of parameters order and meaning.
  868.      * </p>
  869.      * @param array state as a flat array
  870.      * (it can have more than 6 elements, extra elements are ignored)
  871.      * @param arrayDot state derivative as a flat array
  872.      * (it can be null, in which case Keplerian motion is assumed,
  873.      * and it can have more than 6 elements, extra elements are ignored)
  874.      * @param type type of the angle
  875.      * @param date integration date
  876.      * @param mu central attraction coefficient used for propagation (m³/s²)
  877.      * @param frame frame in which integration is performed
  878.      * @return orbit corresponding to the flat array as a space dynamics object
  879.      */
  880.     public abstract Orbit mapArrayToOrbit(double[] array, double[] arrayDot, PositionAngleType type,
  881.                                           AbsoluteDate date, double mu, Frame frame);

  882.     /** Convert an orbit to the instance type.
  883.      * <p>
  884.      * The returned orbit is the specified instance itself if its type already matches,
  885.      * otherwise, a new orbit of the proper type created
  886.      * </p>
  887.      * @param <T> CalculusFieldElement used
  888.      * @param orbit orbit to convert
  889.      * @return converted orbit with type guaranteed to match (so it can be cast safely)
  890.      */
  891.     public abstract <T extends CalculusFieldElement<T>> FieldOrbit<T> convertType(FieldOrbit<T> orbit);

  892.     /** Convert orbit to state array.
  893.      * <p>
  894.      * Note that all implementations of this method <em>must</em> be consistent with the
  895.      * implementation of the {@link org.orekit.orbits.Orbit#getJacobianWrtCartesian(
  896.      * PositionAngleType, double[][]) Orbit.getJacobianWrtCartesian}
  897.      * method for the corresponding orbit type in terms of parameters order and meaning.
  898.      * </p>
  899.      * @param <T> CalculusFieldElement used
  900.      * @param orbit orbit to map
  901.      * @param type type of the angle
  902.      * @param stateVector flat array into which the state vector should be mapped
  903.      * (it can have more than 6 elements, extra elements are untouched)
  904.      * @param stateVectorDot flat array into which the state vector derivative should be mapped
  905.      * (it can be null if derivatives are not desired, and it can have more than 6 elements, extra elements are untouched)
  906.      */
  907.     public abstract <T extends CalculusFieldElement<T>>void mapOrbitToArray(FieldOrbit<T> orbit, PositionAngleType type,
  908.                                                                             T[] stateVector, T[] stateVectorDot);


  909.     /** Convert state array to orbital parameters.
  910.      * <p>
  911.      * Note that all implementations of this method <em>must</em> be consistent with the
  912.      * implementation of the {@link org.orekit.orbits.Orbit#getJacobianWrtCartesian(
  913.      * PositionAngleType, double[][]) Orbit.getJacobianWrtCartesian}
  914.      * method for the corresponding orbit type in terms of parameters order and meaning.
  915.      * </p>
  916.      * @param <T> CalculusFieldElement used
  917.      * @param array state as a flat array
  918.      * (it can have more than 6 elements, extra elements are ignored)
  919.      * @param arrayDot state derivative as a flat array
  920.      * (it can be null, in which case Keplerian motion is assumed,
  921.      * @param type type of the angle
  922.      * @param date integration date
  923.      * @param mu central attraction coefficient used for propagation (m³/s²)
  924.      * @param frame frame in which integration is performed
  925.      * @return orbit corresponding to the flat array as a space dynamics object
  926.      */
  927.     public abstract <T extends CalculusFieldElement<T>> FieldOrbit<T> mapArrayToOrbit(T[] array,
  928.                                                                                       T[] arrayDot,
  929.                                                                                       PositionAngleType type,
  930.                                                                                       FieldAbsoluteDate<T> date,
  931.                                                                                       T mu, Frame frame);

  932.     /** Convert an orbit to the "Fielded" instance type.
  933.      * @param <T> CalculusFieldElement used
  934.      * @param field CalculusField
  935.      * @param orbit base orbit
  936.      * @return converted FieldOrbit with type guaranteed to match (so it can be cast safely)
  937.      * @since 12.0
  938.      */
  939.     public abstract <T extends CalculusFieldElement<T>> FieldOrbit<T> convertToFieldOrbit(Field<T> field,
  940.                                                                                            Orbit orbit);

  941.     /** Get parameters drivers initialized from a reference orbit.
  942.      * @param dP user specified position error
  943.      * @param orbit reference orbit
  944.      * @param type type of the angle
  945.      * @return parameters drivers initialized from reference orbit
  946.      */
  947.     public abstract ParameterDriversList getDrivers(double dP, Orbit orbit,
  948.                                                     PositionAngleType type);

  949.     /** Normalize one orbit with respect to a reference one.
  950.      * <p>
  951.      * Given a, angular component ζ of an orbit and the corresponding
  952.      * angular component ζᵣ in the reference orbit, the angular component
  953.      * ζₙ of the normalized orbit will be ζₙ = ζ + 2kπ
  954.      * where k is chosen such that ζᵣ - π ≤ ζₙ ≤ ζᵣ + π. This is intended
  955.      * to avoid too large discontinuities and is particularly useful
  956.      * for normalizing the orbit after an impulsive maneuver with respect
  957.      * to the reference picked up before the maneuver.
  958.      * </p>
  959.      * @param <T> CalculusFieldElement used
  960.      * @param orbit orbit to normalize
  961.      * @param reference reference orbit
  962.      * @return normalized orbit (the type is guaranteed to match {@link OrbitType})
  963.      * @since 11.1
  964.      */
  965.     public abstract <T extends CalculusFieldElement<T>> FieldOrbit<T> normalize(FieldOrbit<T> orbit,
  966.                                                                                 FieldOrbit<T> reference);

  967.     /** Normalize one orbit with respect to a reference one.
  968.      * <p>
  969.      * Given a, angular component ζ of an orbit and the corresponding
  970.      * angular component ζᵣ in the reference orbit, the angular component
  971.      * ζₙ of the normalized orbit will be ζₙ = ζ + 2kπ
  972.      * where k is chosen such that ζᵣ - π ≤ ζₙ ≤ ζᵣ + π. This is intended
  973.      * to avoid too large discontinuities and is particularly useful
  974.      * for normalizing the orbit after an impulsive maneuver with respect
  975.      * to the reference picked up before the maneuver.
  976.      * </p>
  977.      * @param orbit orbit to normalize
  978.      * @param reference reference orbit
  979.      * @return normalized orbit (the type is guaranteed to match {@link OrbitType})
  980.      * @since 11.1
  981.      */
  982.     public abstract Orbit normalize(Orbit orbit, Orbit reference);

  983.     /** Tells if the orbit type is based on position angles or not.
  984.      * @return true if based on {@link PositionAngleType}
  985.      * @since 12.0
  986.      */
  987.     public abstract boolean isPositionAngleBased();

  988.     /** Compute scaling factor for parameters drivers.
  989.      * <p>
  990.      * The scales are estimated from partial derivatives properties of orbits,
  991.      * starting from a scalar position error specified by the user.
  992.      * Considering the energy conservation equation V = sqrt(mu (2/r - 1/a)),
  993.      * we get at constant energy (i.e. on a Keplerian trajectory):
  994.      * <pre>
  995.      * V r² |dV| = mu |dr|
  996.      * </pre>
  997.      * <p> So we deduce a scalar velocity error consistent with the position error.
  998.      * From here, we apply orbits Jacobians matrices to get consistent scales
  999.      * on orbital parameters.
  1000.      *
  1001.      * @param dP user specified position error
  1002.      * @param orbit reference orbit
  1003.      * @return scaling factor array
  1004.      */
  1005.     protected double[] scale(final double dP, final Orbit orbit) {

  1006.         // estimate the scalar velocity error
  1007.         final PVCoordinates pv = orbit.getPVCoordinates();
  1008.         final double r2 = pv.getPosition().getNormSq();
  1009.         final double v  = pv.getVelocity().getNorm();
  1010.         final double dV = orbit.getMu() * dP / (v * r2);

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

  1012.         // convert the orbit to the desired type
  1013.         final double[][] jacobian = new double[6][6];
  1014.         final Orbit converted = convertType(orbit);
  1015.         converted.getJacobianWrtCartesian(PositionAngleType.TRUE, jacobian);

  1016.         for (int i = 0; i < 6; ++i) {
  1017.             final double[] row = jacobian[i];
  1018.             scale[i] = FastMath.abs(row[0]) * dP +
  1019.                        FastMath.abs(row[1]) * dP +
  1020.                        FastMath.abs(row[2]) * dP +
  1021.                        FastMath.abs(row[3]) * dV +
  1022.                        FastMath.abs(row[4]) * dV +
  1023.                        FastMath.abs(row[5]) * dV;
  1024.             if (Double.isNaN(scale[i])) {
  1025.                 throw new OrekitException(OrekitMessages.SINGULAR_JACOBIAN_FOR_ORBIT_TYPE, this);
  1026.             }
  1027.         }

  1028.         return scale;

  1029.     }

  1030. }