FieldEcksteinHechlerPropagator.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.propagation.analytical;

  18. import java.util.Collections;
  19. import java.util.List;

  20. import org.hipparchus.CalculusFieldElement;
  21. import org.hipparchus.Field;
  22. import org.hipparchus.analysis.differentiation.FieldUnivariateDerivative2;
  23. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  24. import org.hipparchus.util.FastMath;
  25. import org.hipparchus.util.FieldSinCos;
  26. import org.hipparchus.util.MathArrays;
  27. import org.hipparchus.util.MathUtils;
  28. import org.orekit.attitudes.AttitudeProvider;
  29. import org.orekit.attitudes.FrameAlignedProvider;
  30. import org.orekit.errors.OrekitException;
  31. import org.orekit.errors.OrekitMessages;
  32. import org.orekit.forces.gravity.potential.UnnormalizedSphericalHarmonicsProvider;
  33. import org.orekit.forces.gravity.potential.UnnormalizedSphericalHarmonicsProvider.UnnormalizedSphericalHarmonics;
  34. import org.orekit.orbits.FieldCartesianOrbit;
  35. import org.orekit.orbits.FieldCircularOrbit;
  36. import org.orekit.orbits.FieldOrbit;
  37. import org.orekit.orbits.OrbitType;
  38. import org.orekit.orbits.PositionAngleType;
  39. import org.orekit.propagation.FieldSpacecraftState;
  40. import org.orekit.propagation.PropagationType;
  41. import org.orekit.time.FieldAbsoluteDate;
  42. import org.orekit.utils.FieldTimeSpanMap;
  43. import org.orekit.utils.ParameterDriver;
  44. import org.orekit.utils.TimeStampedFieldPVCoordinates;

  45. /** This class propagates a {@link org.orekit.propagation.FieldSpacecraftState}
  46.  *  using the analytical Eckstein-Hechler model.
  47.  * <p>The Eckstein-Hechler model is suited for near circular orbits
  48.  * (e &lt; 0.1, with poor accuracy between 0.005 and 0.1) and inclination
  49.  * neither equatorial (direct or retrograde) nor critical (direct or
  50.  * retrograde).</p>
  51.  * @see FieldOrbit
  52.  * @author Guylaine Prat
  53.  * @param <T> type of the field elements
  54.  */
  55. public class FieldEcksteinHechlerPropagator<T extends CalculusFieldElement<T>> extends FieldAbstractAnalyticalPropagator<T> {

  56.     /** Default convergence threshold for mean parameters conversion. */
  57.     private static final double EPSILON_DEFAULT = 1.0e-13;

  58.     /** Default value for maxIterations. */
  59.     private static final int MAX_ITERATIONS_DEFAULT = 100;

  60.     /** Initial Eckstein-Hechler model. */
  61.     private FieldEHModel<T> initialModel;

  62.     /** All models. */
  63.     private transient FieldTimeSpanMap<FieldEHModel<T>, T> models;

  64.     /** Reference radius of the central body attraction model (m). */
  65.     private double referenceRadius;

  66.     /** Central attraction coefficient (m³/s²). */
  67.     private T mu;

  68.     /** Un-normalized zonal coefficients. */
  69.     private double[] ck0;

  70.     /** Build a propagator from FieldOrbit and potential provider.
  71.      * <p>Mass and attitude provider are set to unspecified non-null arbitrary values.</p>
  72.      *
  73.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  74.      *
  75.      * @param initialOrbit initial FieldOrbit
  76.      * @param provider for un-normalized zonal coefficients
  77.      * @see #FieldEcksteinHechlerPropagator(FieldOrbit, AttitudeProvider,
  78.      * UnnormalizedSphericalHarmonicsProvider)
  79.      * @see #FieldEcksteinHechlerPropagator(FieldOrbit, UnnormalizedSphericalHarmonicsProvider,
  80.      * PropagationType)
  81.      */
  82.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  83.                                           final UnnormalizedSphericalHarmonicsProvider provider) {
  84.         this(initialOrbit, FrameAlignedProvider.of(initialOrbit.getFrame()),
  85.              initialOrbit.getMu().newInstance(DEFAULT_MASS), provider,
  86.              provider.onDate(initialOrbit.getDate().toAbsoluteDate()));
  87.     }

  88.     /**
  89.      * Private helper constructor.
  90.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  91.      * @param initialOrbit initial FieldOrbit
  92.      * @param attitude attitude provider
  93.      * @param mass spacecraft mass
  94.      * @param provider for un-normalized zonal coefficients
  95.      * @param harmonics {@code provider.onDate(initialOrbit.getDate())}
  96.      * @see #FieldEcksteinHechlerPropagator(FieldOrbit, AttitudeProvider, CalculusFieldElement,
  97.      * UnnormalizedSphericalHarmonicsProvider, UnnormalizedSphericalHarmonicsProvider.UnnormalizedSphericalHarmonics, PropagationType)
  98.      */
  99.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  100.                                           final AttitudeProvider attitude,
  101.                                           final T mass,
  102.                                           final UnnormalizedSphericalHarmonicsProvider provider,
  103.                                           final UnnormalizedSphericalHarmonicsProvider.UnnormalizedSphericalHarmonics harmonics) {
  104.         this(initialOrbit, attitude,  mass, provider.getAe(), initialOrbit.getMu().newInstance(provider.getMu()),
  105.              harmonics.getUnnormalizedCnm(2, 0),
  106.              harmonics.getUnnormalizedCnm(3, 0),
  107.              harmonics.getUnnormalizedCnm(4, 0),
  108.              harmonics.getUnnormalizedCnm(5, 0),
  109.              harmonics.getUnnormalizedCnm(6, 0));
  110.     }

  111.     /** Build a propagator from FieldOrbit and potential.
  112.      * <p>Mass and attitude provider are set to unspecified non-null arbitrary values.</p>
  113.      * <p>The C<sub>n,0</sub> coefficients are the denormalized zonal coefficients, they
  114.      * are related to both the normalized coefficients
  115.      * <span style="text-decoration: overline">C</span><sub>n,0</sub>
  116.      *  and the J<sub>n</sub> one as follows:
  117.      * <p>
  118.      *   C<sub>n,0</sub> = [(2-δ<sub>0,m</sub>)(2n+1)(n-m)!/(n+m)!]<sup>½</sup>
  119.      *                      <span style="text-decoration: overline">C</span><sub>n,0</sub>
  120.      * <p>
  121.      *   C<sub>n,0</sub> = -J<sub>n</sub>
  122.      *
  123.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  124.      *
  125.      * @param initialOrbit initial FieldOrbit
  126.      * @param referenceRadius reference radius of the Earth for the potential model (m)
  127.      * @param mu central attraction coefficient (m³/s²)
  128.      * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
  129.      * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
  130.      * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
  131.      * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
  132.      * @param c60 un-normalized zonal coefficient (about -5.41e-7 for Earth)
  133.      * @see org.orekit.utils.Constants
  134.      * @see #FieldEcksteinHechlerPropagator(FieldOrbit, AttitudeProvider, double,
  135.      * CalculusFieldElement, double, double, double, double, double)
  136.      */
  137.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  138.                                           final double referenceRadius, final T mu,
  139.                                           final double c20, final double c30, final double c40,
  140.                                           final double c50, final double c60) {
  141.         this(initialOrbit, FrameAlignedProvider.of(initialOrbit.getFrame()),
  142.              initialOrbit.getMu().newInstance(DEFAULT_MASS),
  143.              referenceRadius, mu, c20, c30, c40, c50, c60);
  144.     }

  145.     /** Build a propagator from FieldOrbit, mass and potential provider.
  146.      * <p>Attitude law is set to an unspecified non-null arbitrary value.</p>
  147.      *
  148.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  149.      *
  150.      * @param initialOrbit initial FieldOrbit
  151.      * @param mass spacecraft mass
  152.      * @param provider for un-normalized zonal coefficients
  153.      * @see #FieldEcksteinHechlerPropagator(FieldOrbit, AttitudeProvider,
  154.      * CalculusFieldElement, UnnormalizedSphericalHarmonicsProvider)
  155.      */
  156.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit, final T mass,
  157.                                           final UnnormalizedSphericalHarmonicsProvider provider) {
  158.         this(initialOrbit, FrameAlignedProvider.of(initialOrbit.getFrame()),
  159.              mass, provider, provider.onDate(initialOrbit.getDate().toAbsoluteDate()));
  160.     }

  161.     /** Build a propagator from FieldOrbit, mass and potential.
  162.      * <p>Attitude law is set to an unspecified non-null arbitrary value.</p>
  163.      * <p>The C<sub>n,0</sub> coefficients are the denormalized zonal coefficients, they
  164.      * are related to both the normalized coefficients
  165.      * <span style="text-decoration: overline">C</span><sub>n,0</sub>
  166.      *  and the J<sub>n</sub> one as follows:</p>
  167.      * <p>
  168.      *   C<sub>n,0</sub> = [(2-δ<sub>0,m</sub>)(2n+1)(n-m)!/(n+m)!]<sup>½</sup>
  169.      *                      <span style="text-decoration: overline">C</span><sub>n,0</sub>
  170.      * <p>
  171.      *   C<sub>n,0</sub> = -J<sub>n</sub>
  172.      *
  173.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  174.      *
  175.      * @param initialOrbit initial FieldOrbit
  176.      * @param mass spacecraft mass
  177.      * @param referenceRadius reference radius of the Earth for the potential model (m)
  178.      * @param mu central attraction coefficient (m³/s²)
  179.      * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
  180.      * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
  181.      * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
  182.      * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
  183.      * @param c60 un-normalized zonal coefficient (about -5.41e-7 for Earth)
  184.      * @see #FieldEcksteinHechlerPropagator(FieldOrbit, AttitudeProvider,
  185.      * CalculusFieldElement, double, CalculusFieldElement, double, double, double, double, double)
  186.      */
  187.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit, final T mass,
  188.                                           final double referenceRadius, final T mu,
  189.                                           final double c20, final double c30, final double c40,
  190.                                           final double c50, final double c60) {
  191.         this(initialOrbit, FrameAlignedProvider.of(initialOrbit.getFrame()),
  192.              mass, referenceRadius, mu, c20, c30, c40, c50, c60);
  193.     }

  194.     /** Build a propagator from FieldOrbit, attitude provider and potential provider.
  195.      * <p>Mass is set to an unspecified non-null arbitrary value.</p>
  196.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  197.      * @param initialOrbit initial FieldOrbit
  198.      * @param attitudeProv attitude provider
  199.      * @param provider for un-normalized zonal coefficients
  200.      */
  201.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  202.                                           final AttitudeProvider attitudeProv,
  203.                                           final UnnormalizedSphericalHarmonicsProvider provider) {
  204.         this(initialOrbit, attitudeProv, initialOrbit.getMu().newInstance(DEFAULT_MASS), provider, provider.onDate(initialOrbit.getDate().toAbsoluteDate()));
  205.     }

  206.     /** Build a propagator from FieldOrbit, attitude provider and potential.
  207.      * <p>Mass is set to an unspecified non-null arbitrary value.</p>
  208.      * <p>The C<sub>n,0</sub> coefficients are the denormalized zonal coefficients, they
  209.      * are related to both the normalized coefficients
  210.      * <span style="text-decoration: overline">C</span><sub>n,0</sub>
  211.      *  and the J<sub>n</sub> one as follows:</p>
  212.      * <p>
  213.      *   C<sub>n,0</sub> = [(2-δ<sub>0,m</sub>)(2n+1)(n-m)!/(n+m)!]<sup>½</sup>
  214.      *                     <span style="text-decoration: overline">C</span><sub>n,0</sub>
  215.      * <p>
  216.      *   C<sub>n,0</sub> = -J<sub>n</sub>
  217.      *
  218.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  219.      *
  220.      * @param initialOrbit initial FieldOrbit
  221.      * @param attitudeProv attitude provider
  222.      * @param referenceRadius reference radius of the Earth for the potential model (m)
  223.      * @param mu central attraction coefficient (m³/s²)
  224.      * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
  225.      * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
  226.      * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
  227.      * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
  228.      * @param c60 un-normalized zonal coefficient (about -5.41e-7 for Earth)
  229.      */
  230.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  231.                                           final AttitudeProvider attitudeProv,
  232.                                           final double referenceRadius, final T mu,
  233.                                           final double c20, final double c30, final double c40,
  234.                                           final double c50, final double c60) {
  235.         this(initialOrbit, attitudeProv, initialOrbit.getMu().newInstance(DEFAULT_MASS),
  236.              referenceRadius, mu, c20, c30, c40, c50, c60);
  237.     }

  238.     /** Build a propagator from FieldOrbit, attitude provider, mass and potential provider.
  239.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  240.      * @param initialOrbit initial FieldOrbit
  241.      * @param attitudeProv attitude provider
  242.      * @param mass spacecraft mass
  243.      * @param provider for un-normalized zonal coefficients
  244.      * @see #FieldEcksteinHechlerPropagator(FieldOrbit, AttitudeProvider, CalculusFieldElement,
  245.      * UnnormalizedSphericalHarmonicsProvider, PropagationType)
  246.      */
  247.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  248.                                           final AttitudeProvider attitudeProv,
  249.                                           final T mass,
  250.                                           final UnnormalizedSphericalHarmonicsProvider provider) {
  251.         this(initialOrbit, attitudeProv, mass, provider, provider.onDate(initialOrbit.getDate().toAbsoluteDate()));
  252.     }

  253.     /** Build a propagator from FieldOrbit, attitude provider, mass and potential.
  254.      * <p>The C<sub>n,0</sub> coefficients are the denormalized zonal coefficients, they
  255.      * are related to both the normalized coefficients
  256.      * <span style="text-decoration: overline">C</span><sub>n,0</sub>
  257.      *  and the J<sub>n</sub> one as follows:</p>
  258.      * <p>
  259.      *   C<sub>n,0</sub> = [(2-δ<sub>0,m</sub>)(2n+1)(n-m)!/(n+m)!]<sup>½</sup>
  260.      *                      <span style="text-decoration: overline">C</span><sub>n,0</sub>
  261.      * <p>
  262.      *   C<sub>n,0</sub> = -J<sub>n</sub>
  263.      *
  264.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  265.      *
  266.      * @param initialOrbit initial FieldOrbit
  267.      * @param attitudeProv attitude provider
  268.      * @param mass spacecraft mass
  269.      * @param referenceRadius reference radius of the Earth for the potential model (m)
  270.      * @param mu central attraction coefficient (m³/s²)
  271.      * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
  272.      * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
  273.      * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
  274.      * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
  275.      * @param c60 un-normalized zonal coefficient (about -5.41e-7 for Earth)
  276.      * @see #FieldEcksteinHechlerPropagator(FieldOrbit, AttitudeProvider, CalculusFieldElement, double,
  277.      *                                      CalculusFieldElement, double, double, double, double, double, PropagationType)
  278.      */
  279.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  280.                                           final AttitudeProvider attitudeProv,
  281.                                           final T mass,
  282.                                           final double referenceRadius, final T mu,
  283.                                           final double c20, final double c30, final double c40,
  284.                                           final double c50, final double c60) {
  285.         this(initialOrbit, attitudeProv, mass, referenceRadius, mu, c20, c30, c40, c50, c60, PropagationType.OSCULATING);
  286.     }

  287.     /** Build a propagator from orbit and potential provider.
  288.      * <p>Mass and attitude provider are set to unspecified non-null arbitrary values.</p>
  289.      *
  290.      * <p>Using this constructor, it is possible to define the initial orbit as
  291.      * a mean Eckstein-Hechler orbit or an osculating one.</p>
  292.      *
  293.      * @param initialOrbit initial orbit
  294.      * @param provider for un-normalized zonal coefficients
  295.      * @param initialType initial orbit type (mean Eckstein-Hechler orbit or osculating orbit)
  296.      * @since 10.2
  297.      */
  298.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  299.                                           final UnnormalizedSphericalHarmonicsProvider provider,
  300.                                           final PropagationType initialType) {
  301.         this(initialOrbit, FrameAlignedProvider.of(initialOrbit.getFrame()),
  302.              initialOrbit.getMu().newInstance(DEFAULT_MASS), provider,
  303.              provider.onDate(initialOrbit.getDate().toAbsoluteDate()), initialType);
  304.     }

  305.     /** Build a propagator from orbit, attitude provider, mass and potential provider.
  306.      * <p>Using this constructor, it is possible to define the initial orbit as
  307.      * a mean Eckstein-Hechler orbit or an osculating one.</p>
  308.      * @param initialOrbit initial orbit
  309.      * @param attitudeProv attitude provider
  310.      * @param mass spacecraft mass
  311.      * @param provider for un-normalized zonal coefficients
  312.      * @param initialType initial orbit type (mean Eckstein-Hechler orbit or osculating orbit)
  313.      * @since 10.2
  314.      */
  315.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  316.                                           final AttitudeProvider attitudeProv,
  317.                                           final T mass,
  318.                                           final UnnormalizedSphericalHarmonicsProvider provider,
  319.                                           final PropagationType initialType) {
  320.         this(initialOrbit, attitudeProv, mass, provider, provider.onDate(initialOrbit.getDate().toAbsoluteDate()), initialType);
  321.     }

  322.     /**
  323.      * Private helper constructor.
  324.      * <p>Using this constructor, it is possible to define the initial orbit as
  325.      * a mean Eckstein-Hechler orbit or an osculating one.</p>
  326.      * @param initialOrbit initial orbit
  327.      * @param attitude attitude provider
  328.      * @param mass spacecraft mass
  329.      * @param provider for un-normalized zonal coefficients
  330.      * @param harmonics {@code provider.onDate(initialOrbit.getDate())}
  331.      * @param initialType initial orbit type (mean Eckstein-Hechler orbit or osculating orbit)
  332.      * @since 10.2
  333.      */
  334.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  335.                                           final AttitudeProvider attitude,
  336.                                           final T mass,
  337.                                           final UnnormalizedSphericalHarmonicsProvider provider,
  338.                                           final UnnormalizedSphericalHarmonics harmonics,
  339.                                           final PropagationType initialType) {
  340.         this(initialOrbit, attitude, mass, provider.getAe(), initialOrbit.getMu().newInstance(provider.getMu()),
  341.              harmonics.getUnnormalizedCnm(2, 0),
  342.              harmonics.getUnnormalizedCnm(3, 0),
  343.              harmonics.getUnnormalizedCnm(4, 0),
  344.              harmonics.getUnnormalizedCnm(5, 0),
  345.              harmonics.getUnnormalizedCnm(6, 0),
  346.              initialType);
  347.     }

  348.     /** Build a propagator from FieldOrbit, attitude provider, mass and potential.
  349.      * <p>The C<sub>n,0</sub> coefficients are the denormalized zonal coefficients, they
  350.      * are related to both the normalized coefficients
  351.      * <span style="text-decoration: overline">C</span><sub>n,0</sub>
  352.      *  and the J<sub>n</sub> one as follows:</p>
  353.      * <p>
  354.      *   C<sub>n,0</sub> = [(2-δ<sub>0,m</sub>)(2n+1)(n-m)!/(n+m)!]<sup>½</sup>
  355.      *                      <span style="text-decoration: overline">C</span><sub>n,0</sub>
  356.      * <p>
  357.      *   C<sub>n,0</sub> = -J<sub>n</sub>
  358.      *
  359.      * <p>Using this constructor, it is possible to define the initial orbit as
  360.      * a mean Eckstein-Hechler orbit or an osculating one.</p>
  361.      *
  362.      * @param initialOrbit initial FieldOrbit
  363.      * @param attitudeProv attitude provider
  364.      * @param mass spacecraft mass
  365.      * @param referenceRadius reference radius of the Earth for the potential model (m)
  366.      * @param mu central attraction coefficient (m³/s²)
  367.      * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
  368.      * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
  369.      * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
  370.      * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
  371.      * @param c60 un-normalized zonal coefficient (about -5.41e-7 for Earth)
  372.      * @param initialType initial orbit type (mean Eckstein-Hechler orbit or osculating orbit)
  373.      * @since 10.2
  374.      */
  375.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  376.                                           final AttitudeProvider attitudeProv,
  377.                                           final T mass,
  378.                                           final double referenceRadius, final T mu,
  379.                                           final double c20, final double c30, final double c40,
  380.                                           final double c50, final double c60,
  381.                                           final PropagationType initialType) {
  382.         this(initialOrbit, attitudeProv, mass, referenceRadius, mu,
  383.              c20, c30, c40, c50, c60, initialType, EPSILON_DEFAULT, MAX_ITERATIONS_DEFAULT);
  384.     }

  385.     /** Build a propagator from FieldOrbit, attitude provider, mass and potential.
  386.      * <p>The C<sub>n,0</sub> coefficients are the denormalized zonal coefficients, they
  387.      * are related to both the normalized coefficients
  388.      * <span style="text-decoration: overline">C</span><sub>n,0</sub>
  389.      *  and the J<sub>n</sub> one as follows:</p>
  390.      * <p>
  391.      *   C<sub>n,0</sub> = [(2-δ<sub>0,m</sub>)(2n+1)(n-m)!/(n+m)!]<sup>½</sup>
  392.      *                      <span style="text-decoration: overline">C</span><sub>n,0</sub>
  393.      * <p>
  394.      *   C<sub>n,0</sub> = -J<sub>n</sub>
  395.      *
  396.      * <p>Using this constructor, it is possible to define the initial orbit as
  397.      * a mean Eckstein-Hechler orbit or an osculating one.</p>
  398.      *
  399.      * @param initialOrbit initial FieldOrbit
  400.      * @param attitudeProv attitude provider
  401.      * @param mass spacecraft mass
  402.      * @param referenceRadius reference radius of the Earth for the potential model (m)
  403.      * @param mu central attraction coefficient (m³/s²)
  404.      * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
  405.      * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
  406.      * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
  407.      * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
  408.      * @param c60 un-normalized zonal coefficient (about -5.41e-7 for Earth)
  409.      * @param initialType initial orbit type (mean Eckstein-Hechler orbit or osculating orbit)
  410.      * @param epsilon convergence threshold for mean parameters conversion
  411.      * @param maxIterations maximum iterations for mean parameters conversion
  412.      * @since 11.2
  413.      */
  414.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  415.                                           final AttitudeProvider attitudeProv,
  416.                                           final T mass,
  417.                                           final double referenceRadius, final T mu,
  418.                                           final double c20, final double c30, final double c40,
  419.                                           final double c50, final double c60,
  420.                                           final PropagationType initialType,
  421.                                           final double epsilon, final int maxIterations) {
  422.         super(mass.getField(), attitudeProv);
  423.         try {

  424.             // store model coefficients
  425.             this.referenceRadius = referenceRadius;
  426.             this.mu  = mu;
  427.             this.ck0 = new double[] {
  428.                 0.0, 0.0, c20, c30, c40, c50, c60
  429.             };

  430.             // compute mean parameters if needed
  431.             // transform into circular adapted parameters used by the Eckstein-Hechler model
  432.             resetInitialState(new FieldSpacecraftState<>(initialOrbit,
  433.                                                          attitudeProv.getAttitude(initialOrbit,
  434.                                                                                   initialOrbit.getDate(),
  435.                                                                                   initialOrbit.getFrame()),
  436.                                                          mass),
  437.                               initialType, epsilon, maxIterations);

  438.         } catch (OrekitException oe) {
  439.             throw new OrekitException(oe);
  440.         }
  441.     }

  442.     /** Conversion from osculating to mean orbit.
  443.      * <p>
  444.      * Compute mean orbit <b>in a Eckstein-Hechler sense</b>, corresponding to the
  445.      * osculating SpacecraftState in input.
  446.      * </p>
  447.      * <p>
  448.      * Since the osculating orbit is obtained with the computation of
  449.      * short-periodic variation, the resulting output will depend on
  450.      * the gravity field parameterized in input.
  451.      * </p>
  452.      * <p>
  453.      * The computation is done through a fixed-point iteration process.
  454.      * </p>
  455.      * @param <T> type of the filed elements
  456.      * @param osculating osculating orbit to convert
  457.      * @param provider for un-normalized zonal coefficients
  458.      * @param harmonics {@code provider.onDate(osculating.getDate())}
  459.      * @return mean orbit in a Eckstein-Hechler sense
  460.      * @since 11.2
  461.      */
  462.     public static <T extends CalculusFieldElement<T>> FieldCircularOrbit<T> computeMeanOrbit(final FieldOrbit<T> osculating,
  463.                                                                                              final UnnormalizedSphericalHarmonicsProvider provider,
  464.                                                                                              final UnnormalizedSphericalHarmonics harmonics) {
  465.         return computeMeanOrbit(osculating, provider, harmonics, EPSILON_DEFAULT, MAX_ITERATIONS_DEFAULT);
  466.     }

  467.     /** Conversion from osculating to mean orbit.
  468.      * <p>
  469.      * Compute mean orbit <b>in a Eckstein-Hechler sense</b>, corresponding to the
  470.      * osculating SpacecraftState in input.
  471.      * </p>
  472.      * <p>
  473.      * Since the osculating orbit is obtained with the computation of
  474.      * short-periodic variation, the resulting output will depend on
  475.      * the gravity field parameterized in input.
  476.      * </p>
  477.      * <p>
  478.      * The computation is done through a fixed-point iteration process.
  479.      * </p>
  480.      * @param <T> type of the filed elements
  481.      * @param osculating osculating orbit to convert
  482.      * @param provider for un-normalized zonal coefficients
  483.      * @param harmonics {@code provider.onDate(osculating.getDate())}
  484.      * @param epsilon convergence threshold for mean parameters conversion
  485.      * @param maxIterations maximum iterations for mean parameters conversion
  486.      * @return mean orbit in a Eckstein-Hechler sense
  487.      * @since 11.2
  488.      */
  489.     public static <T extends CalculusFieldElement<T>> FieldCircularOrbit<T> computeMeanOrbit(final FieldOrbit<T> osculating,
  490.                                                                                              final UnnormalizedSphericalHarmonicsProvider provider,
  491.                                                                                              final UnnormalizedSphericalHarmonics harmonics,
  492.                                                                                              final double epsilon, final int maxIterations) {
  493.         return computeMeanOrbit(osculating,
  494.                                 provider.getAe(), provider.getMu(),
  495.                                 harmonics.getUnnormalizedCnm(2, 0),
  496.                                 harmonics.getUnnormalizedCnm(3, 0),
  497.                                 harmonics.getUnnormalizedCnm(4, 0),
  498.                                 harmonics.getUnnormalizedCnm(5, 0),
  499.                                 harmonics.getUnnormalizedCnm(6, 0),
  500.                                 epsilon, maxIterations);
  501.     }

  502.     /** Conversion from osculating to mean orbit.
  503.      * <p>
  504.      * Compute mean orbit <b>in a Eckstein-Hechler sense</b>, corresponding to the
  505.      * osculating SpacecraftState in input.
  506.      * </p>
  507.      * <p>
  508.      * Since the osculating orbit is obtained with the computation of
  509.      * short-periodic variation, the resulting output will depend on
  510.      * the gravity field parameterized in input.
  511.      * </p>
  512.      * <p>
  513.      * The computation is done through a fixed-point iteration process.
  514.      * </p>
  515.      * @param <T> type of the filed elements
  516.      * @param osculating osculating orbit to convert
  517.      * @param referenceRadius reference radius of the Earth for the potential model (m)
  518.      * @param mu central attraction coefficient (m³/s²)
  519.      * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
  520.      * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
  521.      * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
  522.      * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
  523.      * @param c60 un-normalized zonal coefficient (about -5.41e-7 for Earth)
  524.      * @param epsilon convergence threshold for mean parameters conversion
  525.      * @param maxIterations maximum iterations for mean parameters conversion
  526.      * @return mean orbit in a Eckstein-Hechler sense
  527.      * @since 11.2
  528.      */
  529.     public static <T extends CalculusFieldElement<T>> FieldCircularOrbit<T> computeMeanOrbit(final FieldOrbit<T> osculating,
  530.                                                                                              final double referenceRadius, final double mu,
  531.                                                                                              final double c20, final double c30, final double c40,
  532.                                                                                              final double c50, final double c60,
  533.                                                                                              final double epsilon, final int maxIterations) {
  534.         final FieldEcksteinHechlerPropagator<T> propagator =
  535.                         new FieldEcksteinHechlerPropagator<>(osculating,
  536.                                                              FrameAlignedProvider.of(osculating.getFrame()),
  537.                                                              osculating.getMu().newInstance(DEFAULT_MASS),
  538.                                                              referenceRadius, osculating.getMu().newInstance(mu),
  539.                                                              c20, c30, c40, c50, c60,
  540.                                                              PropagationType.OSCULATING, epsilon, maxIterations);
  541.         return propagator.initialModel.mean;
  542.     }

  543.     /** {@inheritDoc}
  544.      * <p>The new initial state to consider
  545.      * must be defined with an osculating orbit.</p>
  546.      * @see #resetInitialState(FieldSpacecraftState, PropagationType)
  547.      */
  548.     @Override
  549.     public void resetInitialState(final FieldSpacecraftState<T> state) {
  550.         resetInitialState(state, PropagationType.OSCULATING);
  551.     }

  552.     /** Reset the propagator initial state.
  553.      * @param state new initial state to consider
  554.      * @param stateType mean Eckstein-Hechler orbit or osculating orbit
  555.      * @since 10.2
  556.      */
  557.     public void resetInitialState(final FieldSpacecraftState<T> state, final PropagationType stateType) {
  558.         resetInitialState(state, stateType, EPSILON_DEFAULT, MAX_ITERATIONS_DEFAULT);
  559.     }

  560.     /** Reset the propagator initial state.
  561.      * @param state new initial state to consider
  562.      * @param stateType mean Eckstein-Hechler orbit or osculating orbit
  563.      * @param epsilon convergence threshold for mean parameters conversion
  564.      * @param maxIterations maximum iterations for mean parameters conversion
  565.      * @since 11.2
  566.      */
  567.     public void resetInitialState(final FieldSpacecraftState<T> state, final PropagationType stateType,
  568.                                   final double epsilon, final int maxIterations) {
  569.         super.resetInitialState(state);
  570.         final FieldCircularOrbit<T> circular = (FieldCircularOrbit<T>) OrbitType.CIRCULAR.convertType(state.getOrbit());
  571.         this.initialModel = (stateType == PropagationType.MEAN) ?
  572.                              new FieldEHModel<>(circular, state.getMass(), referenceRadius, mu, ck0) :
  573.                              computeMeanParameters(circular, state.getMass(), epsilon, maxIterations);
  574.         this.models = new FieldTimeSpanMap<FieldEHModel<T>, T>(initialModel, state.getA().getField());
  575.     }

  576.     /** {@inheritDoc} */
  577.     @Override
  578.     protected void resetIntermediateState(final FieldSpacecraftState<T> state, final boolean forward) {
  579.         resetIntermediateState(state, forward, EPSILON_DEFAULT, MAX_ITERATIONS_DEFAULT);
  580.     }

  581.     /** Reset an intermediate state.
  582.      * @param state new intermediate state to consider
  583.      * @param forward if true, the intermediate state is valid for
  584.      * propagations after itself
  585.      * @param epsilon convergence threshold for mean parameters conversion
  586.      * @param maxIterations maximum iterations for mean parameters conversion
  587.      * @since 11.2
  588.      */
  589.     protected void resetIntermediateState(final FieldSpacecraftState<T> state, final boolean forward,
  590.                                           final double epsilon, final int maxIterations) {
  591.         final FieldEHModel<T> newModel = computeMeanParameters((FieldCircularOrbit<T>) OrbitType.CIRCULAR.convertType(state.getOrbit()),
  592.                                                                state.getMass(), epsilon, maxIterations);
  593.         if (forward) {
  594.             models.addValidAfter(newModel, state.getDate());
  595.         } else {
  596.             models.addValidBefore(newModel, state.getDate());
  597.         }
  598.         stateChanged(state);
  599.     }

  600.     /** Compute mean parameters according to the Eckstein-Hechler analytical model.
  601.      * @param osculating osculating FieldOrbit
  602.      * @param mass constant mass
  603.      * @param epsilon convergence threshold for mean parameters conversion
  604.      * @param maxIterations maximum iterations for mean parameters conversion
  605.      * @return Eckstein-Hechler mean model
  606.      */
  607.     private FieldEHModel<T> computeMeanParameters(final FieldCircularOrbit<T> osculating, final T mass,
  608.                                                   final double epsilon, final int maxIterations) {

  609.         // sanity check
  610.         if (osculating.getA().getReal() < referenceRadius) {
  611.             throw new OrekitException(OrekitMessages.TRAJECTORY_INSIDE_BRILLOUIN_SPHERE,
  612.                                            osculating.getA());
  613.         }
  614.         final Field<T> field = mass.getField();
  615.         final T one = field.getOne();
  616.         final T zero = field.getZero();
  617.         // rough initialization of the mean parameters
  618.         FieldEHModel<T> current = new FieldEHModel<>(osculating, mass, referenceRadius, mu, ck0);
  619.         // threshold for each parameter
  620.         final T thresholdA      = current.mean.getA().abs().add(1.0).multiply(epsilon);
  621.         final T thresholdE      = current.mean.getE().add(1.0).multiply(epsilon);
  622.         final T thresholdAngles = one.getPi().multiply(2).multiply(epsilon);


  623.         int i = 0;
  624.         while (i++ < maxIterations) {

  625.             // recompute the osculating parameters from the current mean parameters
  626.             final FieldUnivariateDerivative2<T>[] parameters = current.propagateParameters(current.mean.getDate());
  627.             // adapted parameters residuals
  628.             final T deltaA      = osculating.getA()         .subtract(parameters[0].getValue());
  629.             final T deltaEx     = osculating.getCircularEx().subtract(parameters[1].getValue());
  630.             final T deltaEy     = osculating.getCircularEy().subtract(parameters[2].getValue());
  631.             final T deltaI      = osculating.getI()         .subtract(parameters[3].getValue());
  632.             final T deltaRAAN   = MathUtils.normalizeAngle(osculating.getRightAscensionOfAscendingNode().subtract(
  633.                                                                 parameters[4].getValue()),
  634.                                                                 zero);
  635.             final T deltaAlphaM = MathUtils.normalizeAngle(osculating.getAlphaM().subtract(parameters[5].getValue()), zero);
  636.             // update mean parameters
  637.             current = new FieldEHModel<>(new FieldCircularOrbit<>(current.mean.getA().add(deltaA),
  638.                                                                   current.mean.getCircularEx().add( deltaEx),
  639.                                                                   current.mean.getCircularEy().add( deltaEy),
  640.                                                                   current.mean.getI()         .add( deltaI ),
  641.                                                                   current.mean.getRightAscensionOfAscendingNode().add(deltaRAAN),
  642.                                                                   current.mean.getAlphaM().add(deltaAlphaM),
  643.                                                                   PositionAngleType.MEAN,
  644.                                                                   current.mean.getFrame(),
  645.                                                                   current.mean.getDate(), mu),
  646.                                   mass, referenceRadius, mu, ck0);
  647.             // check convergence
  648.             if (FastMath.abs(deltaA.getReal())      < thresholdA.getReal() &&
  649.                 FastMath.abs(deltaEx.getReal())     < thresholdE.getReal() &&
  650.                 FastMath.abs(deltaEy.getReal())     < thresholdE.getReal() &&
  651.                 FastMath.abs(deltaI.getReal())      < thresholdAngles.getReal() &&
  652.                 FastMath.abs(deltaRAAN.getReal())   < thresholdAngles.getReal() &&
  653.                 FastMath.abs(deltaAlphaM.getReal()) < thresholdAngles.getReal()) {
  654.                 return current;
  655.             }

  656.         }

  657.         throw new OrekitException(OrekitMessages.UNABLE_TO_COMPUTE_ECKSTEIN_HECHLER_MEAN_PARAMETERS, i);

  658.     }

  659.     /** {@inheritDoc} */
  660.     @Override
  661.     public FieldCartesianOrbit<T> propagateOrbit(final FieldAbsoluteDate<T> date, final T[] parameters) {
  662.         // compute Cartesian parameters, taking derivatives into account
  663.         // to make sure velocity and acceleration are consistent
  664.         final FieldEHModel<T> current = models.get(date);
  665.         return new FieldCartesianOrbit<>(toCartesian(date, current.propagateParameters(date)),
  666.                                          current.mean.getFrame(), mu);
  667.     }

  668.     /** Local class for Eckstein-Hechler model, with fixed mean parameters. */
  669.     private static class FieldEHModel<T extends CalculusFieldElement<T>> {

  670.         /** Mean FieldOrbit. */
  671.         private final FieldCircularOrbit<T> mean;

  672.         /** Constant mass. */
  673.         private final T mass;
  674.         // CHECKSTYLE: stop JavadocVariable check

  675.         // preprocessed values
  676.         private final T xnotDot;
  677.         private final T rdpom;
  678.         private final T rdpomp;
  679.         private final T eps1;
  680.         private final T eps2;
  681.         private final T xim;
  682.         private final T ommD;
  683.         private final T rdl;
  684.         private final T aMD;

  685.         private final T kh;
  686.         private final T kl;

  687.         private final T ax1;
  688.         private final T ay1;
  689.         private final T as1;
  690.         private final T ac2;
  691.         private final T axy3;
  692.         private final T as3;
  693.         private final T ac4;
  694.         private final T as5;
  695.         private final T ac6;

  696.         private final T ex1;
  697.         private final T exx2;
  698.         private final T exy2;
  699.         private final T ex3;
  700.         private final T ex4;

  701.         private final T ey1;
  702.         private final T eyx2;
  703.         private final T eyy2;
  704.         private final T ey3;
  705.         private final T ey4;

  706.         private final T rx1;
  707.         private final T ry1;
  708.         private final T r2;
  709.         private final T r3;
  710.         private final T rl;

  711.         private final T iy1;
  712.         private final T ix1;
  713.         private final T i2;
  714.         private final T i3;
  715.         private final T ih;

  716.         private final T lx1;
  717.         private final T ly1;
  718.         private final T l2;
  719.         private final T l3;
  720.         private final T ll;

  721.         // CHECKSTYLE: resume JavadocVariable check

  722.         /** Create a model for specified mean FieldOrbit.
  723.          * @param mean mean FieldOrbit
  724.          * @param mass constant mass
  725.          * @param referenceRadius reference radius of the central body attraction model (m)
  726.          * @param mu central attraction coefficient (m³/s²)
  727.          * @param ck0 un-normalized zonal coefficients
  728.          */
  729.         FieldEHModel(final FieldCircularOrbit<T> mean, final T mass,
  730.                      final double referenceRadius, final T mu, final double[] ck0) {

  731.             this.mean            = mean;
  732.             this.mass            = mass;
  733.             final T zero = mass.getField().getZero();
  734.             final T one  = mass.getField().getOne();
  735.             // preliminary processing
  736.             T q =  zero.newInstance(referenceRadius).divide(mean.getA());
  737.             T ql = q.multiply(q);
  738.             final T g2 = ql.multiply(ck0[2]);
  739.             ql = ql.multiply(q);
  740.             final T g3 = ql.multiply(ck0[3]);
  741.             ql = ql.multiply(q);
  742.             final T g4 = ql.multiply(ck0[4]);
  743.             ql = ql.multiply(q);
  744.             final T g5 = ql.multiply(ck0[5]);
  745.             ql = ql.multiply(q);
  746.             final T g6 = ql.multiply(ck0[6]);

  747.             final FieldSinCos<T> sc = FastMath.sinCos(mean.getI());
  748.             final T cosI1 = sc.cos();
  749.             final T sinI1 = sc.sin();
  750.             final T sinI2 = sinI1.multiply(sinI1);
  751.             final T sinI4 = sinI2.multiply(sinI2);
  752.             final T sinI6 = sinI2.multiply(sinI4);

  753.             if (sinI2.getReal() < 1.0e-10) {
  754.                 throw new OrekitException(OrekitMessages.ALMOST_EQUATORIAL_ORBIT,
  755.                                                FastMath.toDegrees(mean.getI().getReal()));
  756.             }

  757.             if (FastMath.abs(sinI2.getReal() - 4.0 / 5.0) < 1.0e-3) {
  758.                 throw new OrekitException(OrekitMessages.ALMOST_CRITICALLY_INCLINED_ORBIT,
  759.                                                FastMath.toDegrees(mean.getI().getReal()));
  760.             }

  761.             if (mean.getE().getReal() > 0.1) {
  762.                 // if 0.005 < e < 0.1 no error is triggered, but accuracy is poor
  763.                 throw new OrekitException(OrekitMessages.TOO_LARGE_ECCENTRICITY_FOR_PROPAGATION_MODEL,
  764.                                                mean.getE());
  765.             }

  766.             xnotDot = mu.divide(mean.getA()).sqrt().divide(mean.getA());

  767.             rdpom = g2.multiply(-0.75).multiply(sinI2.multiply(-5.0).add(4.0));
  768.             rdpomp = g4.multiply(7.5).multiply(sinI2.multiply(-31.0 / 8.0).add(1.0).add( sinI4.multiply(49.0 / 16.0))).subtract(
  769.                     g6.multiply(13.125).multiply(one.subtract(sinI2.multiply(8.0)).add(sinI4.multiply(129.0 / 8.0)).subtract(sinI6.multiply(297.0 / 32.0)) ));


  770.             q = zero.newInstance(3.0).divide(rdpom.multiply(32.0));
  771.             eps1 = q.multiply(g4).multiply(sinI2).multiply(sinI2.multiply(-35.0).add(30.0)).subtract(
  772.                    q.multiply(175.0).multiply(g6).multiply(sinI2).multiply(sinI2.multiply(-3.0).add(sinI4.multiply(2.0625)).add(1.0)));
  773.             q = sinI1.multiply(3.0).divide(rdpom.multiply(8.0));
  774.             eps2 = q.multiply(g3).multiply(sinI2.multiply(-5.0).add(4.0)).subtract(q.multiply(g5).multiply(sinI2.multiply(-35.0).add(sinI4.multiply(26.25)).add(10.0)));

  775.             xim = mean.getI();
  776.             ommD = cosI1.multiply(g2.multiply(1.50).subtract(g2.multiply(2.25).multiply(g2).multiply(sinI2.multiply(-19.0 / 6.0).add(2.5))).add(
  777.                             g4.multiply(0.9375).multiply(sinI2.multiply(7.0).subtract(4.0))).add(
  778.                             g6.multiply(3.28125).multiply(sinI2.multiply(-9.0).add(2.0).add(sinI4.multiply(8.25)))));

  779.             rdl = g2.multiply(-1.50).multiply(sinI2.multiply(-4.0).add(3.0)).add(1.0);
  780.             aMD = rdl.add(
  781.                     g2.multiply(2.25).multiply(g2.multiply(sinI2.multiply(-263.0 / 12.0 ).add(9.0).add(sinI4.multiply(341.0 / 24.0))))).add(
  782.                     g4.multiply(15.0 / 16.0).multiply(sinI2.multiply(-31.0).add(8.0).add(sinI4.multiply(24.5)))).add(
  783.                     g6.multiply(105.0 / 32.0).multiply(sinI2.multiply(25.0).add(-10.0 / 3.0).subtract(sinI4.multiply(48.75)).add(sinI6.multiply(27.5))));

  784.             final T qq   = g2.divide(rdl).multiply(-1.5);
  785.             final T qA   = g2.multiply(0.75).multiply(g2).multiply(sinI2);
  786.             final T qB   = g4.multiply(0.25).multiply(sinI2);
  787.             final T qC   = g6.multiply(105.0 / 16.0).multiply(sinI2);
  788.             final T qD   = g3.multiply(-0.75).multiply(sinI1);
  789.             final T qE   = g5.multiply(3.75).multiply(sinI1);
  790.             kh = zero.newInstance(0.375).divide(rdpom);
  791.             kl = kh.divide(sinI1);

  792.             ax1 = qq.multiply(sinI2.multiply(-3.5).add(2.0));
  793.             ay1 = qq.multiply(sinI2.multiply(-2.5).add(2.0));
  794.             as1 = qD.multiply(sinI2.multiply(-5.0).add(4.0)).add(
  795.                   qE.multiply(sinI4.multiply(2.625).add(sinI2.multiply(-3.5)).add(1.0)));
  796.             ac2 = qq.multiply(sinI2).add(
  797.                   qA.multiply(7.0).multiply(sinI2.multiply(-3.0).add(2.0))).add(
  798.                   qB.multiply(sinI2.multiply(-17.5).add(15.0))).add(
  799.                   qC.multiply(sinI2.multiply(3.0).subtract(1.0).subtract(sinI4.multiply(33.0 / 16.0))));
  800.             axy3 = qq.multiply(3.5).multiply(sinI2);
  801.             as3 = qD.multiply(5.0 / 3.0).multiply(sinI2).add(
  802.                   qE.multiply(7.0 / 6.0).multiply(sinI2).multiply(sinI2.multiply(-1.125).add(1)));
  803.             ac4 = qA.multiply(sinI2).add(
  804.                   qB.multiply(4.375).multiply(sinI2)).add(
  805.                   qC.multiply(0.75).multiply(sinI4.multiply(1.1).subtract(sinI2)));

  806.             as5 = qE.multiply(21.0 / 80.0).multiply(sinI4);

  807.             ac6 = qC.multiply(-11.0 / 80.0).multiply(sinI4);

  808.             ex1 = qq.multiply(sinI2.multiply(-1.25).add(1.0));
  809.             exx2 = qq.multiply(0.5).multiply(sinI2.multiply(-5.0).add(3.0));
  810.             exy2 = qq.multiply(sinI2.multiply(-1.5).add(2.0));
  811.             ex3 = qq.multiply(7.0 / 12.0).multiply(sinI2);
  812.             ex4 = qq.multiply(17.0 / 8.0).multiply(sinI2);

  813.             ey1 = qq.multiply(sinI2.multiply(-1.75).add(1.0));
  814.             eyx2 = qq.multiply(sinI2.multiply(-3.0).add(1.0));
  815.             eyy2 = qq.multiply(sinI2.multiply(2.0).subtract(1.5));
  816.             ey3 = qq.multiply(7.0 / 12.0).multiply(sinI2);
  817.             ey4 = qq.multiply(17.0 / 8.0).multiply(sinI2);

  818.             q  = cosI1.multiply(qq).negate();
  819.             rx1 = q.multiply(3.5);
  820.             ry1 = q.multiply(-2.5);
  821.             r2 = q.multiply(-0.5);
  822.             r3 =  q.multiply(7.0 / 6.0);
  823.             rl = g3 .multiply( cosI1).multiply(sinI2.multiply(-15.0).add(4.0)).subtract(
  824.                  g5.multiply(2.5).multiply(cosI1).multiply(sinI2.multiply(-42.0).add(4.0).add(sinI4.multiply(52.5))));

  825.             q = qq.multiply(0.5).multiply(sinI1).multiply(cosI1);
  826.             iy1 =  q;
  827.             ix1 = q.negate();
  828.             i2 =  q;
  829.             i3 =  q.multiply(7.0 / 3.0);
  830.             ih = g3.negate().multiply(cosI1).multiply(sinI2.multiply(-5.0).add(4)).add(
  831.                  g5.multiply(2.5).multiply(cosI1).multiply(sinI2.multiply(-14.0).add(4.0).add(sinI4.multiply(10.5))));
  832.             lx1 = qq.multiply(sinI2.multiply(-77.0 / 8.0).add(7.0));
  833.             ly1 = qq.multiply(sinI2.multiply(55.0 / 8.0).subtract(7.50));
  834.             l2 = qq.multiply(sinI2.multiply(1.25).subtract(0.5));
  835.             l3 = qq.multiply(sinI2.multiply(77.0 / 24.0).subtract(7.0 / 6.0));
  836.             ll = g3.multiply(sinI2.multiply(53.0).subtract(4.0).add(sinI4.multiply(-57.5))).add(
  837.                  g5.multiply(2.5).multiply(sinI2.multiply(-96.0).add(4.0).add(sinI4.multiply(269.5).subtract(sinI6.multiply(183.75)))));

  838.         }

  839.         /** Extrapolate a FieldOrbit up to a specific target date.
  840.          * @param date target date for the FieldOrbit
  841.          * @return propagated parameters
  842.          */
  843.         public FieldUnivariateDerivative2<T>[] propagateParameters(final FieldAbsoluteDate<T> date) {
  844.             final Field<T> field = date.durationFrom(mean.getDate()).getField();
  845.             final T one = field.getOne();
  846.             final T zero = field.getZero();
  847.             // Keplerian evolution
  848.             final FieldUnivariateDerivative2<T> dt = new FieldUnivariateDerivative2<>(date.durationFrom(mean.getDate()), one, zero);
  849.             final FieldUnivariateDerivative2<T> xnot = dt.multiply(xnotDot);

  850.             // secular effects

  851.             // eccentricity
  852.             final FieldUnivariateDerivative2<T> x   = xnot.multiply(rdpom.add(rdpomp));
  853.             final FieldUnivariateDerivative2<T> cx  = x.cos();
  854.             final FieldUnivariateDerivative2<T> sx  = x.sin();
  855.             final FieldUnivariateDerivative2<T> exm = cx.multiply(mean.getCircularEx()).
  856.                                             add(sx.multiply(eps2.subtract(one.subtract(eps1).multiply(mean.getCircularEy()))));
  857.             final FieldUnivariateDerivative2<T> eym = sx.multiply(eps1.add(1.0).multiply(mean.getCircularEx())).
  858.                                             add(cx.multiply(mean.getCircularEy().subtract(eps2))).
  859.                                             add(eps2);
  860.             // no secular effect on inclination

  861.             // right ascension of ascending node
  862.             final FieldUnivariateDerivative2<T> omm =
  863.                            new FieldUnivariateDerivative2<>(MathUtils.normalizeAngle(mean.getRightAscensionOfAscendingNode().add(ommD.multiply(xnot.getValue())),
  864.                                                                                      one.getPi()),
  865.                                                             ommD.multiply(xnotDot),
  866.                                                             zero);
  867.             // latitude argument
  868.             final FieldUnivariateDerivative2<T> xlm =
  869.                             new FieldUnivariateDerivative2<>(MathUtils.normalizeAngle(mean.getAlphaM().add(aMD.multiply(xnot.getValue())),
  870.                                                                                       one.getPi()),
  871.                                                            aMD.multiply(xnotDot),
  872.                                                            zero);

  873.             // periodical terms
  874.             final FieldUnivariateDerivative2<T> cl1 = xlm.cos();
  875.             final FieldUnivariateDerivative2<T> sl1 = xlm.sin();
  876.             final FieldUnivariateDerivative2<T> cl2 = cl1.multiply(cl1).subtract(sl1.multiply(sl1));
  877.             final FieldUnivariateDerivative2<T> sl2 = cl1.multiply(sl1).add(sl1.multiply(cl1));
  878.             final FieldUnivariateDerivative2<T> cl3 = cl2.multiply(cl1).subtract(sl2.multiply(sl1));
  879.             final FieldUnivariateDerivative2<T> sl3 = cl2.multiply(sl1).add(sl2.multiply(cl1));
  880.             final FieldUnivariateDerivative2<T> cl4 = cl3.multiply(cl1).subtract(sl3.multiply(sl1));
  881.             final FieldUnivariateDerivative2<T> sl4 = cl3.multiply(sl1).add(sl3.multiply(cl1));
  882.             final FieldUnivariateDerivative2<T> cl5 = cl4.multiply(cl1).subtract(sl4.multiply(sl1));
  883.             final FieldUnivariateDerivative2<T> sl5 = cl4.multiply(sl1).add(sl4.multiply(cl1));
  884.             final FieldUnivariateDerivative2<T> cl6 = cl5.multiply(cl1).subtract(sl5.multiply(sl1));

  885.             final FieldUnivariateDerivative2<T> qh  = eym.subtract(eps2).multiply(kh);
  886.             final FieldUnivariateDerivative2<T> ql  = exm.multiply(kl);

  887.             final FieldUnivariateDerivative2<T> exmCl1 = exm.multiply(cl1);
  888.             final FieldUnivariateDerivative2<T> exmSl1 = exm.multiply(sl1);
  889.             final FieldUnivariateDerivative2<T> eymCl1 = eym.multiply(cl1);
  890.             final FieldUnivariateDerivative2<T> eymSl1 = eym.multiply(sl1);
  891.             final FieldUnivariateDerivative2<T> exmCl2 = exm.multiply(cl2);
  892.             final FieldUnivariateDerivative2<T> exmSl2 = exm.multiply(sl2);
  893.             final FieldUnivariateDerivative2<T> eymCl2 = eym.multiply(cl2);
  894.             final FieldUnivariateDerivative2<T> eymSl2 = eym.multiply(sl2);
  895.             final FieldUnivariateDerivative2<T> exmCl3 = exm.multiply(cl3);
  896.             final FieldUnivariateDerivative2<T> exmSl3 = exm.multiply(sl3);
  897.             final FieldUnivariateDerivative2<T> eymCl3 = eym.multiply(cl3);
  898.             final FieldUnivariateDerivative2<T> eymSl3 = eym.multiply(sl3);
  899.             final FieldUnivariateDerivative2<T> exmCl4 = exm.multiply(cl4);
  900.             final FieldUnivariateDerivative2<T> exmSl4 = exm.multiply(sl4);
  901.             final FieldUnivariateDerivative2<T> eymCl4 = eym.multiply(cl4);
  902.             final FieldUnivariateDerivative2<T> eymSl4 = eym.multiply(sl4);

  903.             // semi major axis
  904.             final FieldUnivariateDerivative2<T> rda = exmCl1.multiply(ax1).
  905.                                             add(eymSl1.multiply(ay1)).
  906.                                             add(sl1.multiply(as1)).
  907.                                             add(cl2.multiply(ac2)).
  908.                                             add(exmCl3.add(eymSl3).multiply(axy3)).
  909.                                             add(sl3.multiply(as3)).
  910.                                             add(cl4.multiply(ac4)).
  911.                                             add(sl5.multiply(as5)).
  912.                                             add(cl6.multiply(ac6));

  913.             // eccentricity
  914.             final FieldUnivariateDerivative2<T> rdex = cl1.multiply(ex1).
  915.                                              add(exmCl2.multiply(exx2)).
  916.                                              add(eymSl2.multiply(exy2)).
  917.                                              add(cl3.multiply(ex3)).
  918.                                              add(exmCl4.add(eymSl4).multiply(ex4));
  919.             final FieldUnivariateDerivative2<T> rdey = sl1.multiply(ey1).
  920.                                              add(exmSl2.multiply(eyx2)).
  921.                                              add(eymCl2.multiply(eyy2)).
  922.                                              add(sl3.multiply(ey3)).
  923.                                              add(exmSl4.subtract(eymCl4).multiply(ey4));

  924.             // ascending node
  925.             final FieldUnivariateDerivative2<T> rdom = exmSl1.multiply(rx1).
  926.                                              add(eymCl1.multiply(ry1)).
  927.                                              add(sl2.multiply(r2)).
  928.                                              add(eymCl3.subtract(exmSl3).multiply(r3)).
  929.                                              add(ql.multiply(rl));

  930.             // inclination
  931.             final FieldUnivariateDerivative2<T> rdxi = eymSl1.multiply(iy1).
  932.                                              add(exmCl1.multiply(ix1)).
  933.                                              add(cl2.multiply(i2)).
  934.                                              add(exmCl3.add(eymSl3).multiply(i3)).
  935.                                              add(qh.multiply(ih));

  936.             // latitude argument
  937.             final FieldUnivariateDerivative2<T> rdxl = exmSl1.multiply(lx1).
  938.                                              add(eymCl1.multiply(ly1)).
  939.                                              add(sl2.multiply(l2)).
  940.                                              add(exmSl3.subtract(eymCl3).multiply(l3)).
  941.                                              add(ql.multiply(ll));
  942.             // osculating parameters
  943.             final FieldUnivariateDerivative2<T>[] FTD = MathArrays.buildArray(rdxl.getField(), 6);

  944.             FTD[0] = rda.add(1.0).multiply(mean.getA());
  945.             FTD[1] = rdex.add(exm);
  946.             FTD[2] = rdey.add(eym);
  947.             FTD[3] = rdxi.add(xim);
  948.             FTD[4] = rdom.add(omm);
  949.             FTD[5] = rdxl.add(xlm);
  950.             return FTD;

  951.         }

  952.     }

  953.     /** Convert circular parameters <em>with derivatives</em> to Cartesian coordinates.
  954.      * @param date date of the parameters
  955.      * @param parameters circular parameters (a, ex, ey, i, raan, alphaM)
  956.      * @return Cartesian coordinates consistent with values and derivatives
  957.      */
  958.     private TimeStampedFieldPVCoordinates<T> toCartesian(final FieldAbsoluteDate<T> date, final FieldUnivariateDerivative2<T>[] parameters) {

  959.         // evaluate coordinates in the FieldOrbit canonical reference frame
  960.         final FieldUnivariateDerivative2<T> cosOmega = parameters[4].cos();
  961.         final FieldUnivariateDerivative2<T> sinOmega = parameters[4].sin();
  962.         final FieldUnivariateDerivative2<T> cosI     = parameters[3].cos();
  963.         final FieldUnivariateDerivative2<T> sinI     = parameters[3].sin();
  964.         final FieldUnivariateDerivative2<T> alphaE   = meanToEccentric(parameters[5], parameters[1], parameters[2]);
  965.         final FieldUnivariateDerivative2<T> cosAE    = alphaE.cos();
  966.         final FieldUnivariateDerivative2<T> sinAE    = alphaE.sin();
  967.         final FieldUnivariateDerivative2<T> ex2      = parameters[1].square();
  968.         final FieldUnivariateDerivative2<T> ey2      = parameters[2].square();
  969.         final FieldUnivariateDerivative2<T> exy      = parameters[1].multiply(parameters[2]);
  970.         final FieldUnivariateDerivative2<T> q        = ex2.add(ey2).subtract(1).negate().sqrt();
  971.         final FieldUnivariateDerivative2<T> beta     = q.add(1).reciprocal();
  972.         final FieldUnivariateDerivative2<T> bx2      = beta.multiply(ex2);
  973.         final FieldUnivariateDerivative2<T> by2      = beta.multiply(ey2);
  974.         final FieldUnivariateDerivative2<T> bxy      = beta.multiply(exy);
  975.         final FieldUnivariateDerivative2<T> u        = bxy.multiply(sinAE).subtract(parameters[1].add(by2.subtract(1).multiply(cosAE)));
  976.         final FieldUnivariateDerivative2<T> v        = bxy.multiply(cosAE).subtract(parameters[2].add(bx2.subtract(1).multiply(sinAE)));
  977.         final FieldUnivariateDerivative2<T> x        = parameters[0].multiply(u);
  978.         final FieldUnivariateDerivative2<T> y        = parameters[0].multiply(v);

  979.         // canonical FieldOrbit reference frame
  980.         final FieldVector3D<FieldUnivariateDerivative2<T>> p =
  981.                 new FieldVector3D<>(x.multiply(cosOmega).subtract(y.multiply(cosI.multiply(sinOmega))),
  982.                                     x.multiply(sinOmega).add(y.multiply(cosI.multiply(cosOmega))),
  983.                                     y.multiply(sinI));

  984.         // dispatch derivatives
  985.         final FieldVector3D<T> p0 = new FieldVector3D<>(p.getX().getValue(),
  986.                                                         p.getY().getValue(),
  987.                                                         p.getZ().getValue());
  988.         final FieldVector3D<T> p1 = new FieldVector3D<>(p.getX().getFirstDerivative(),
  989.                                                         p.getY().getFirstDerivative(),
  990.                                                         p.getZ().getFirstDerivative());
  991.         final FieldVector3D<T> p2 = new FieldVector3D<>(p.getX().getSecondDerivative(),
  992.                                                         p.getY().getSecondDerivative(),
  993.                                                         p.getZ().getSecondDerivative());
  994.         return new TimeStampedFieldPVCoordinates<>(date, p0, p1, p2);

  995.     }

  996.     /** Computes the eccentric latitude argument from the mean latitude argument.
  997.      * @param alphaM = M + Ω mean latitude argument (rad)
  998.      * @param ex e cos(Ω), first component of circular eccentricity vector
  999.      * @param ey e sin(Ω), second component of circular eccentricity vector
  1000.      * @return the eccentric latitude argument.
  1001.      */
  1002.     private FieldUnivariateDerivative2<T> meanToEccentric(final FieldUnivariateDerivative2<T> alphaM,
  1003.                                                 final FieldUnivariateDerivative2<T> ex,
  1004.                                                 final FieldUnivariateDerivative2<T> ey) {
  1005.         // Generalization of Kepler equation to circular parameters
  1006.         // with alphaE = PA + E and
  1007.         //      alphaM = PA + M = alphaE - ex.sin(alphaE) + ey.cos(alphaE)
  1008.         FieldUnivariateDerivative2<T> alphaE        = alphaM;
  1009.         FieldUnivariateDerivative2<T> shift         = alphaM.getField().getZero();
  1010.         FieldUnivariateDerivative2<T> alphaEMalphaM = alphaM.getField().getZero();
  1011.         FieldUnivariateDerivative2<T> cosAlphaE     = alphaE.cos();
  1012.         FieldUnivariateDerivative2<T> sinAlphaE     = alphaE.sin();
  1013.         int                 iter          = 0;
  1014.         do {
  1015.             final FieldUnivariateDerivative2<T> f2 = ex.multiply(sinAlphaE).subtract(ey.multiply(cosAlphaE));
  1016.             final FieldUnivariateDerivative2<T> f1 = alphaM.getField().getOne().subtract(ex.multiply(cosAlphaE)).subtract(ey.multiply(sinAlphaE));
  1017.             final FieldUnivariateDerivative2<T> f0 = alphaEMalphaM.subtract(f2);

  1018.             final FieldUnivariateDerivative2<T> f12 = f1.multiply(2);
  1019.             shift = f0.multiply(f12).divide(f1.multiply(f12).subtract(f0.multiply(f2)));

  1020.             alphaEMalphaM  = alphaEMalphaM.subtract(shift);
  1021.             alphaE         = alphaM.add(alphaEMalphaM);
  1022.             cosAlphaE      = alphaE.cos();
  1023.             sinAlphaE      = alphaE.sin();

  1024.         } while (++iter < 50 && FastMath.abs(shift.getValue().getReal()) > 1.0e-12);

  1025.         return alphaE;

  1026.     }

  1027.     /** {@inheritDoc} */
  1028.     @Override
  1029.     protected T getMass(final FieldAbsoluteDate<T> date) {
  1030.         return models.get(date).mass;
  1031.     }

  1032.     /** {@inheritDoc} */
  1033.     @Override
  1034.     public List<ParameterDriver> getParametersDrivers() {
  1035.         // Eckstein Hechler propagation model does not have parameter drivers.
  1036.         return Collections.emptyList();
  1037.     }

  1038. }