FieldEcksteinHechlerPropagator.java

  1. /* Copyright 2002-2025 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.propagation.conversion.osc2mean.EcksteinHechlerTheory;
  42. import org.orekit.propagation.conversion.osc2mean.FixedPointConverter;
  43. import org.orekit.propagation.conversion.osc2mean.MeanTheory;
  44. import org.orekit.propagation.conversion.osc2mean.OsculatingToMeanConverter;
  45. import org.orekit.time.FieldAbsoluteDate;
  46. import org.orekit.utils.FieldTimeSpanMap;
  47. import org.orekit.utils.ParameterDriver;
  48. import org.orekit.utils.TimeStampedFieldPVCoordinates;

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

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

  62.     /** Default value for maxIterations. */
  63.     private static final int MAX_ITERATIONS_DEFAULT = 100;

  64.     /** Initial Eckstein-Hechler model. */
  65.     private FieldEHModel<T> initialModel;

  66.     /** All models. */
  67.     private transient FieldTimeSpanMap<FieldEHModel<T>, T> models;

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

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

  72.     /** Un-normalized zonal coefficients. */
  73.     private double[] ck0;

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

  95.     /**
  96.      * Private helper constructor.
  97.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  98.      * <p>Conversion from osculating to mean orbit is done through a fixed-point iteration process.</p>
  99.      * @param initialOrbit initial FieldOrbit
  100.      * @param attitude attitude provider
  101.      * @param mass spacecraft mass
  102.      * @param provider for un-normalized zonal coefficients
  103.      * @param harmonics {@code provider.onDate(initialOrbit.getDate())}
  104.      * @see #FieldEcksteinHechlerPropagator(FieldOrbit, AttitudeProvider, CalculusFieldElement,
  105.      * UnnormalizedSphericalHarmonicsProvider, UnnormalizedSphericalHarmonicsProvider.UnnormalizedSphericalHarmonics, PropagationType)
  106.      */
  107.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  108.                                           final AttitudeProvider attitude,
  109.                                           final T mass,
  110.                                           final UnnormalizedSphericalHarmonicsProvider provider,
  111.                                           final UnnormalizedSphericalHarmonicsProvider.UnnormalizedSphericalHarmonics harmonics) {
  112.         this(initialOrbit, attitude,  mass, provider.getAe(), initialOrbit.getMu().newInstance(provider.getMu()),
  113.              harmonics.getUnnormalizedCnm(2, 0),
  114.              harmonics.getUnnormalizedCnm(3, 0),
  115.              harmonics.getUnnormalizedCnm(4, 0),
  116.              harmonics.getUnnormalizedCnm(5, 0),
  117.              harmonics.getUnnormalizedCnm(6, 0));
  118.     }

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

  158.     /** Build a propagator from FieldOrbit, mass and potential provider.
  159.      * <p>Attitude law is set to an unspecified non-null arbitrary value.</p>
  160.      *
  161.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  162.      * <p>Conversion from osculating to mean orbit is done through a fixed-point iteration process.</p>
  163.      *
  164.      * @param initialOrbit initial FieldOrbit
  165.      * @param mass spacecraft mass
  166.      * @param provider for un-normalized zonal coefficients
  167.      * @see #FieldEcksteinHechlerPropagator(FieldOrbit, AttitudeProvider,
  168.      * CalculusFieldElement, UnnormalizedSphericalHarmonicsProvider)
  169.      */
  170.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  171.                                           final T mass,
  172.                                           final UnnormalizedSphericalHarmonicsProvider provider) {
  173.         this(initialOrbit, FrameAlignedProvider.of(initialOrbit.getFrame()),
  174.              mass, provider, provider.onDate(initialOrbit.getDate().toAbsoluteDate()));
  175.     }

  176.     /** Build a propagator from FieldOrbit, mass and potential.
  177.      * <p>Attitude law is set to an unspecified non-null arbitrary value.</p>
  178.      * <p>The C<sub>n,0</sub> coefficients are the denormalized zonal coefficients, they
  179.      * are related to both the normalized coefficients
  180.      * <span style="text-decoration: overline">C</span><sub>n,0</sub>
  181.      *  and the J<sub>n</sub> one as follows:</p>
  182.      * <p>
  183.      *   C<sub>n,0</sub> = [(2-δ<sub>0,m</sub>)(2n+1)(n-m)!/(n+m)!]<sup>½</sup>
  184.      *                      <span style="text-decoration: overline">C</span><sub>n,0</sub>
  185.      * <p>
  186.      *   C<sub>n,0</sub> = -J<sub>n</sub>
  187.      *
  188.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  189.      * <p>Conversion from osculating to mean orbit is done through a fixed-point iteration process.</p>
  190.      *
  191.      * @param initialOrbit initial FieldOrbit
  192.      * @param mass spacecraft mass
  193.      * @param referenceRadius reference radius of the Earth for the potential model (m)
  194.      * @param mu central attraction coefficient (m³/s²)
  195.      * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
  196.      * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
  197.      * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
  198.      * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
  199.      * @param c60 un-normalized zonal coefficient (about -5.41e-7 for Earth)
  200.      * @see #FieldEcksteinHechlerPropagator(FieldOrbit, AttitudeProvider,
  201.      * CalculusFieldElement, double, CalculusFieldElement, double, double, double, double, double)
  202.      */
  203.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  204.                                           final T mass,
  205.                                           final double referenceRadius,
  206.                                           final T mu,
  207.                                           final double c20,
  208.                                           final double c30,
  209.                                           final double c40,
  210.                                           final double c50,
  211.                                           final double c60) {
  212.         this(initialOrbit, FrameAlignedProvider.of(initialOrbit.getFrame()),
  213.              mass, referenceRadius, mu, c20, c30, c40, c50, c60);
  214.     }

  215.     /** Build a propagator from FieldOrbit, attitude provider and potential provider.
  216.      * <p>Mass is set to an unspecified non-null arbitrary value.</p>
  217.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  218.      * <p>Conversion from osculating to mean orbit is done through a fixed-point iteration process.</p>
  219.      * @param initialOrbit initial FieldOrbit
  220.      * @param attitudeProv attitude provider
  221.      * @param provider for un-normalized zonal coefficients
  222.      */
  223.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  224.                                           final AttitudeProvider attitudeProv,
  225.                                           final UnnormalizedSphericalHarmonicsProvider provider) {
  226.         this(initialOrbit, attitudeProv, initialOrbit.getMu().newInstance(DEFAULT_MASS),
  227.              provider, provider.onDate(initialOrbit.getDate().toAbsoluteDate()));
  228.     }

  229.     /** Build a propagator from FieldOrbit, attitude provider and potential.
  230.      * <p>Mass is set to an unspecified non-null arbitrary value.</p>
  231.      * <p>The C<sub>n,0</sub> coefficients are the denormalized zonal coefficients, they
  232.      * are related to both the normalized coefficients
  233.      * <span style="text-decoration: overline">C</span><sub>n,0</sub>
  234.      *  and the J<sub>n</sub> one as follows:</p>
  235.      * <p>
  236.      *   C<sub>n,0</sub> = [(2-δ<sub>0,m</sub>)(2n+1)(n-m)!/(n+m)!]<sup>½</sup>
  237.      *                     <span style="text-decoration: overline">C</span><sub>n,0</sub>
  238.      * <p>
  239.      *   C<sub>n,0</sub> = -J<sub>n</sub>
  240.      *
  241.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  242.      * <p>Conversion from osculating to mean orbit is done through a fixed-point iteration process.</p>
  243.      *
  244.      * @param initialOrbit initial FieldOrbit
  245.      * @param attitudeProv attitude provider
  246.      * @param referenceRadius reference radius of the Earth for the potential model (m)
  247.      * @param mu central attraction coefficient (m³/s²)
  248.      * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
  249.      * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
  250.      * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
  251.      * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
  252.      * @param c60 un-normalized zonal coefficient (about -5.41e-7 for Earth)
  253.      */
  254.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  255.                                           final AttitudeProvider attitudeProv,
  256.                                           final double referenceRadius,
  257.                                           final T mu,
  258.                                           final double c20,
  259.                                           final double c30,
  260.                                           final double c40,
  261.                                           final double c50,
  262.                                           final double c60) {
  263.         this(initialOrbit, attitudeProv, initialOrbit.getMu().newInstance(DEFAULT_MASS),
  264.              referenceRadius, mu, c20, c30, c40, c50, c60);
  265.     }

  266.     /** Build a propagator from FieldOrbit, attitude provider, mass and potential provider.
  267.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  268.      * <p>Conversion from osculating to mean orbit is done through a fixed-point iteration process.</p>
  269.      * @param initialOrbit initial FieldOrbit
  270.      * @param attitudeProv attitude provider
  271.      * @param mass spacecraft mass
  272.      * @param provider for un-normalized zonal coefficients
  273.      * @see #FieldEcksteinHechlerPropagator(FieldOrbit, AttitudeProvider, CalculusFieldElement,
  274.      * UnnormalizedSphericalHarmonicsProvider, PropagationType)
  275.      */
  276.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  277.                                           final AttitudeProvider attitudeProv,
  278.                                           final T mass,
  279.                                           final UnnormalizedSphericalHarmonicsProvider provider) {
  280.         this(initialOrbit, attitudeProv, mass, provider, provider.onDate(initialOrbit.getDate().toAbsoluteDate()));
  281.     }

  282.     /** Build a propagator from FieldOrbit, attitude provider, mass and potential.
  283.      * <p>The C<sub>n,0</sub> coefficients are the denormalized zonal coefficients, they
  284.      * are related to both the normalized coefficients
  285.      * <span style="text-decoration: overline">C</span><sub>n,0</sub>
  286.      *  and the J<sub>n</sub> one as follows:</p>
  287.      * <p>
  288.      *   C<sub>n,0</sub> = [(2-δ<sub>0,m</sub>)(2n+1)(n-m)!/(n+m)!]<sup>½</sup>
  289.      *                      <span style="text-decoration: overline">C</span><sub>n,0</sub>
  290.      * <p>
  291.      *   C<sub>n,0</sub> = -J<sub>n</sub>
  292.      *
  293.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  294.      * <p>Conversion from osculating to mean orbit is done through a fixed-point iteration process.</p>
  295.      *
  296.      * @param initialOrbit initial FieldOrbit
  297.      * @param attitudeProv attitude provider
  298.      * @param mass spacecraft mass
  299.      * @param referenceRadius reference radius of the Earth for the potential model (m)
  300.      * @param mu central attraction coefficient (m³/s²)
  301.      * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
  302.      * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
  303.      * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
  304.      * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
  305.      * @param c60 un-normalized zonal coefficient (about -5.41e-7 for Earth)
  306.      * @see #FieldEcksteinHechlerPropagator(FieldOrbit, AttitudeProvider, CalculusFieldElement, double,
  307.      *                                      CalculusFieldElement, double, double, double, double, double, PropagationType)
  308.      */
  309.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  310.                                           final AttitudeProvider attitudeProv,
  311.                                           final T mass,
  312.                                           final double referenceRadius,
  313.                                           final T mu,
  314.                                           final double c20,
  315.                                           final double c30,
  316.                                           final double c40,
  317.                                           final double c50,
  318.                                           final double c60) {
  319.         this(initialOrbit, attitudeProv, mass, referenceRadius, mu, c20, c30, c40, c50, c60, PropagationType.OSCULATING);
  320.     }

  321.     /** Build a propagator from orbit and potential provider.
  322.      * <p>Mass and attitude provider are set to unspecified non-null arbitrary values.</p>
  323.      *
  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.      * <p>Conversion from osculating to mean orbit will be done through a fixed-point iteration process.</p>
  327.      *
  328.      * @param initialOrbit initial orbit
  329.      * @param provider for un-normalized zonal coefficients
  330.      * @param initialType initial orbit type (mean Eckstein-Hechler orbit or osculating orbit)
  331.      * @since 10.2
  332.      */
  333.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  334.                                           final UnnormalizedSphericalHarmonicsProvider provider,
  335.                                           final PropagationType initialType) {
  336.         this(initialOrbit, FrameAlignedProvider.of(initialOrbit.getFrame()),
  337.              initialOrbit.getMu().newInstance(DEFAULT_MASS), provider,
  338.              provider.onDate(initialOrbit.getDate().toAbsoluteDate()), initialType);
  339.     }

  340.     /** Build a propagator from orbit, attitude provider, mass and potential provider.
  341.      * <p>Using this constructor, it is possible to define the initial orbit as
  342.      * a mean Eckstein-Hechler orbit or an osculating one.</p>
  343.      * <p>Conversion from osculating to mean orbit will be done through a fixed-point iteration process.</p>
  344.      * @param initialOrbit initial orbit
  345.      * @param attitudeProv attitude provider
  346.      * @param mass spacecraft mass
  347.      * @param provider for un-normalized zonal coefficients
  348.      * @param initialType initial orbit type (mean Eckstein-Hechler orbit or osculating orbit)
  349.      * @since 10.2
  350.      */
  351.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  352.                                           final AttitudeProvider attitudeProv,
  353.                                           final T mass,
  354.                                           final UnnormalizedSphericalHarmonicsProvider provider,
  355.                                           final PropagationType initialType) {
  356.         this(initialOrbit, attitudeProv, mass, provider, provider.onDate(initialOrbit.getDate().toAbsoluteDate()), initialType);
  357.     }

  358.     /**
  359.      * Private helper constructor.
  360.      * <p>Using this constructor, it is possible to define the initial orbit as
  361.      * a mean Eckstein-Hechler orbit or an osculating one.</p>
  362.      * <p>Conversion from osculating to mean orbit will be done through a fixed-point iteration process.</p>
  363.      * @param initialOrbit initial orbit
  364.      * @param attitude attitude provider
  365.      * @param mass spacecraft mass
  366.      * @param provider for un-normalized zonal coefficients
  367.      * @param harmonics {@code provider.onDate(initialOrbit.getDate())}
  368.      * @param initialType initial orbit type (mean Eckstein-Hechler orbit or osculating orbit)
  369.      * @since 10.2
  370.      */
  371.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  372.                                           final AttitudeProvider attitude,
  373.                                           final T mass,
  374.                                           final UnnormalizedSphericalHarmonicsProvider provider,
  375.                                           final UnnormalizedSphericalHarmonics harmonics,
  376.                                           final PropagationType initialType) {
  377.         this(initialOrbit, attitude, mass, provider.getAe(), initialOrbit.getMu().newInstance(provider.getMu()),
  378.              harmonics.getUnnormalizedCnm(2, 0),
  379.              harmonics.getUnnormalizedCnm(3, 0),
  380.              harmonics.getUnnormalizedCnm(4, 0),
  381.              harmonics.getUnnormalizedCnm(5, 0),
  382.              harmonics.getUnnormalizedCnm(6, 0),
  383.              initialType);
  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.      * <p>Conversion from osculating to mean orbit will be done through a fixed-point iteration process.</p>
  399.      *
  400.      * @param initialOrbit initial FieldOrbit
  401.      * @param attitudeProv attitude provider
  402.      * @param mass spacecraft mass
  403.      * @param referenceRadius reference radius of the Earth for the potential model (m)
  404.      * @param mu central attraction coefficient (m³/s²)
  405.      * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
  406.      * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
  407.      * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
  408.      * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
  409.      * @param c60 un-normalized zonal coefficient (about -5.41e-7 for Earth)
  410.      * @param initialType initial orbit type (mean Eckstein-Hechler orbit or osculating orbit)
  411.      * @since 10.2
  412.      */
  413.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  414.                                           final AttitudeProvider attitudeProv,
  415.                                           final T mass,
  416.                                           final double referenceRadius,
  417.                                           final T mu,
  418.                                           final double c20,
  419.                                           final double c30,
  420.                                           final double c40,
  421.                                           final double c50,
  422.                                           final double c60,
  423.                                           final PropagationType initialType) {
  424.         this(initialOrbit, attitudeProv, mass, referenceRadius, mu,
  425.              c20, c30, c40, c50, c60, initialType, EPSILON_DEFAULT, MAX_ITERATIONS_DEFAULT);
  426.     }

  427.     /** Build a propagator from FieldOrbit, attitude provider, mass and potential.
  428.      * <p>The C<sub>n,0</sub> coefficients are the denormalized zonal coefficients, they
  429.      * are related to both the normalized coefficients
  430.      * <span style="text-decoration: overline">C</span><sub>n,0</sub>
  431.      *  and the J<sub>n</sub> one as follows:</p>
  432.      * <p>
  433.      *   C<sub>n,0</sub> = [(2-δ<sub>0,m</sub>)(2n+1)(n-m)!/(n+m)!]<sup>½</sup>
  434.      *                      <span style="text-decoration: overline">C</span><sub>n,0</sub>
  435.      * <p>
  436.      *   C<sub>n,0</sub> = -J<sub>n</sub>
  437.      *
  438.      * <p>Using this constructor, it is possible to define the initial orbit as
  439.      * a mean Eckstein-Hechler orbit or an osculating one.</p>
  440.      * <p>Conversion from osculating to mean orbit will be done through a fixed-point iteration process.</p>
  441.      *
  442.      * @param initialOrbit initial FieldOrbit
  443.      * @param attitudeProv attitude provider
  444.      * @param mass spacecraft mass
  445.      * @param referenceRadius reference radius of the Earth for the potential model (m)
  446.      * @param mu central attraction coefficient (m³/s²)
  447.      * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
  448.      * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
  449.      * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
  450.      * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
  451.      * @param c60 un-normalized zonal coefficient (about -5.41e-7 for Earth)
  452.      * @param initialType initial orbit type (mean Eckstein-Hechler orbit or osculating orbit)
  453.      * @param epsilon convergence threshold for mean parameters conversion
  454.      * @param maxIterations maximum iterations for mean parameters conversion
  455.      * @since 11.2
  456.      */
  457.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  458.                                           final AttitudeProvider attitudeProv,
  459.                                           final T mass,
  460.                                           final double referenceRadius,
  461.                                           final T mu,
  462.                                           final double c20,
  463.                                           final double c30,
  464.                                           final double c40,
  465.                                           final double c50,
  466.                                           final double c60,
  467.                                           final PropagationType initialType,
  468.                                           final double epsilon,
  469.                                           final int maxIterations) {
  470.         this(initialOrbit, attitudeProv, mass, referenceRadius, mu, c20, c30, c40, c50, c60,
  471.              initialType, new FixedPointConverter(epsilon, maxIterations,
  472.                                                   FixedPointConverter.DEFAULT_DAMPING));
  473.     }

  474.     /** Build a propagator from FieldOrbit, attitude provider, mass and potential.
  475.      * <p>The C<sub>n,0</sub> coefficients are the denormalized zonal coefficients, they
  476.      * are related to both the normalized coefficients
  477.      * <span style="text-decoration: overline">C</span><sub>n,0</sub>
  478.      *  and the J<sub>n</sub> one as follows:</p>
  479.      * <p>
  480.      *   C<sub>n,0</sub> = [(2-δ<sub>0,m</sub>)(2n+1)(n-m)!/(n+m)!]<sup>½</sup>
  481.      *                      <span style="text-decoration: overline">C</span><sub>n,0</sub>
  482.      * <p>
  483.      *   C<sub>n,0</sub> = -J<sub>n</sub>
  484.      *
  485.      * <p>Using this constructor, it is possible to define the initial orbit as
  486.      * a mean Eckstein-Hechler orbit or an osculating one.</p>
  487.      * <p>Conversion from osculating to mean orbit will be done through the given converter.</p>
  488.      *
  489.      * @param initialOrbit initial FieldOrbit
  490.      * @param attitudeProv attitude provider
  491.      * @param mass spacecraft mass
  492.      * @param referenceRadius reference radius of the Earth for the potential model (m)
  493.      * @param mu central attraction coefficient (m³/s²)
  494.      * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
  495.      * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
  496.      * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
  497.      * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
  498.      * @param c60 un-normalized zonal coefficient (about -5.41e-7 for Earth)
  499.      * @param initialType initial orbit type (mean Eckstein-Hechler orbit or osculating orbit)
  500.      * @param converter osculating to mean orbit converter
  501.      * @since 13.0
  502.      */
  503.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  504.                                           final AttitudeProvider attitudeProv,
  505.                                           final T mass,
  506.                                           final double referenceRadius,
  507.                                           final T mu,
  508.                                           final double c20,
  509.                                           final double c30,
  510.                                           final double c40,
  511.                                           final double c50,
  512.                                           final double c60,
  513.                                           final PropagationType initialType,
  514.                                           final OsculatingToMeanConverter converter) {
  515.         super(mass.getField(), attitudeProv);

  516.         // store model coefficients
  517.         this.referenceRadius = referenceRadius;
  518.         this.mu  = mu;
  519.         this.ck0 = new double[] {
  520.             0.0, 0.0, c20, c30, c40, c50, c60
  521.         };

  522.         // compute mean parameters if needed
  523.         // transform into circular adapted parameters used by the Eckstein-Hechler model
  524.         resetInitialState(new FieldSpacecraftState<>(initialOrbit,
  525.                                                      attitudeProv.getAttitude(initialOrbit,
  526.                                                                               initialOrbit.getDate(),
  527.                                                                               initialOrbit.getFrame())).withMass(mass),
  528.                           initialType, converter);
  529.     }

  530.     /** Conversion from osculating to mean orbit.
  531.      * <p>
  532.      * Compute mean orbit <b>in a Eckstein-Hechler sense</b>, corresponding to the
  533.      * osculating SpacecraftState in input.
  534.      * </p>
  535.      * <p>
  536.      * Since the osculating orbit is obtained with the computation of
  537.      * short-periodic variation, the resulting output will depend on
  538.      * the gravity field parameterized in input.
  539.      * </p>
  540.      * <p>
  541.      * The computation is done through a fixed-point iteration process.
  542.      * </p>
  543.      * @param <T> type of the filed elements
  544.      * @param osculating osculating orbit to convert
  545.      * @param provider for un-normalized zonal coefficients
  546.      * @param harmonics {@code provider.onDate(osculating.getDate())}
  547.      * @return mean orbit in a Eckstein-Hechler sense
  548.      * @since 11.2
  549.      */
  550.     public static <T extends CalculusFieldElement<T>> FieldCircularOrbit<T> computeMeanOrbit(final FieldOrbit<T> osculating,
  551.                                                                                              final UnnormalizedSphericalHarmonicsProvider provider,
  552.                                                                                              final UnnormalizedSphericalHarmonics harmonics) {
  553.         return computeMeanOrbit(osculating, provider, harmonics, EPSILON_DEFAULT, MAX_ITERATIONS_DEFAULT);
  554.     }

  555.     /** Conversion from osculating to mean orbit.
  556.      * <p>
  557.      * Compute mean orbit <b>in a Eckstein-Hechler sense</b>, corresponding to the
  558.      * osculating SpacecraftState in input.
  559.      * </p>
  560.      * <p>
  561.      * Since the osculating orbit is obtained with the computation of
  562.      * short-periodic variation, the resulting output will depend on
  563.      * the gravity field parameterized in input.
  564.      * </p>
  565.      * <p>
  566.      * The computation is done through a fixed-point iteration process.
  567.      * </p>
  568.      * @param <T> type of the filed elements
  569.      * @param osculating osculating orbit to convert
  570.      * @param provider for un-normalized zonal coefficients
  571.      * @param harmonics {@code provider.onDate(osculating.getDate())}
  572.      * @param epsilon convergence threshold for mean parameters conversion
  573.      * @param maxIterations maximum iterations for mean parameters conversion
  574.      * @return mean orbit in a Eckstein-Hechler sense
  575.      * @since 11.2
  576.      */
  577.     public static <T extends CalculusFieldElement<T>> FieldCircularOrbit<T> computeMeanOrbit(final FieldOrbit<T> osculating,
  578.                                                                                              final UnnormalizedSphericalHarmonicsProvider provider,
  579.                                                                                              final UnnormalizedSphericalHarmonics harmonics,
  580.                                                                                              final double epsilon, final int maxIterations) {
  581.         return computeMeanOrbit(osculating,
  582.                                 provider.getAe(), provider.getMu(),
  583.                                 harmonics.getUnnormalizedCnm(2, 0),
  584.                                 harmonics.getUnnormalizedCnm(3, 0),
  585.                                 harmonics.getUnnormalizedCnm(4, 0),
  586.                                 harmonics.getUnnormalizedCnm(5, 0),
  587.                                 harmonics.getUnnormalizedCnm(6, 0),
  588.                                 epsilon, maxIterations);
  589.     }

  590.     /** Conversion from osculating to mean orbit.
  591.      * <p>
  592.      * Compute mean orbit <b>in a Eckstein-Hechler sense</b>, corresponding to the
  593.      * osculating SpacecraftState in input.
  594.      * </p>
  595.      * <p>
  596.      * Since the osculating orbit is obtained with the computation of
  597.      * short-periodic variation, the resulting output will depend on
  598.      * the gravity field parameterized in input.
  599.      * </p>
  600.      * <p>
  601.      * The computation is done through a fixed-point iteration process.
  602.      * </p>
  603.      * @param <T> type of the filed elements
  604.      * @param osculating osculating orbit to convert
  605.      * @param referenceRadius reference radius of the Earth for the potential model (m)
  606.      * @param mu central attraction coefficient (m³/s²)
  607.      * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
  608.      * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
  609.      * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
  610.      * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
  611.      * @param c60 un-normalized zonal coefficient (about -5.41e-7 for Earth)
  612.      * @param epsilon convergence threshold for mean parameters conversion
  613.      * @param maxIterations maximum iterations for mean parameters conversion
  614.      * @return mean orbit in a Eckstein-Hechler sense
  615.      * @since 11.2
  616.      */
  617.     public static <T extends CalculusFieldElement<T>> FieldCircularOrbit<T> computeMeanOrbit(final FieldOrbit<T> osculating,
  618.                                                                                              final double referenceRadius,
  619.                                                                                              final double mu,
  620.                                                                                              final double c20,
  621.                                                                                              final double c30,
  622.                                                                                              final double c40,
  623.                                                                                              final double c50,
  624.                                                                                              final double c60,
  625.                                                                                              final double epsilon,
  626.                                                                                              final int maxIterations) {
  627.         // Build a fixed-point converter
  628.         final OsculatingToMeanConverter converter = new FixedPointConverter(epsilon, maxIterations,
  629.                                                                             FixedPointConverter.DEFAULT_DAMPING);
  630.         return computeMeanOrbit(osculating, referenceRadius, mu, c20, c30, c40, c50, c60, converter);
  631.     }

  632.     /** Conversion from osculating to mean orbit.
  633.      * <p>
  634.      * Compute mean orbit <b>in a Eckstein-Hechler sense</b>, corresponding to the
  635.      * osculating SpacecraftState in input.
  636.      * </p>
  637.      * <p>
  638.      * Since the osculating orbit is obtained with the computation of
  639.      * short-periodic variation, the resulting output will depend on
  640.      * the gravity field parameterized in input.
  641.      * </p>
  642.      * <p>
  643.      * The computation is done through the given osculating to mean orbit converter.
  644.      * </p>
  645.      * @param <T> type of the filed elements
  646.      * @param osculating osculating orbit to convert
  647.      * @param referenceRadius reference radius of the Earth for the potential model (m)
  648.      * @param mu central attraction coefficient (m³/s²)
  649.      * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
  650.      * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
  651.      * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
  652.      * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
  653.      * @param c60 un-normalized zonal coefficient (about -5.41e-7 for Earth)
  654.      * @param converter osculating to mean orbit converter
  655.      * @return mean orbit in a Eckstein-Hechler sense
  656.      * @since 13.0
  657.      */
  658.     public static <T extends CalculusFieldElement<T>> FieldCircularOrbit<T> computeMeanOrbit(final FieldOrbit<T> osculating,
  659.                                                                                              final double referenceRadius,
  660.                                                                                              final double mu,
  661.                                                                                              final double c20,
  662.                                                                                              final double c30,
  663.                                                                                              final double c40,
  664.                                                                                              final double c50,
  665.                                                                                              final double c60,
  666.                                                                                              final OsculatingToMeanConverter converter) {
  667.         // Set EH as the mean theory for converting
  668.         final MeanTheory theory = new EcksteinHechlerTheory(referenceRadius, mu, c20, c30, c40, c50, c60);
  669.         converter.setMeanTheory(theory);
  670.         return (FieldCircularOrbit<T>) OrbitType.CIRCULAR.convertType(converter.convertToMean(osculating));
  671.     }

  672.     /** {@inheritDoc}
  673.      * <p>The new initial state to consider
  674.      * must be defined with an osculating orbit.</p>
  675.      * @see #resetInitialState(FieldSpacecraftState, PropagationType)
  676.      */
  677.     @Override
  678.     public void resetInitialState(final FieldSpacecraftState<T> state) {
  679.         resetInitialState(state, PropagationType.OSCULATING);
  680.     }

  681.     /** Reset the propagator initial state.
  682.      * @param state new initial state to consider
  683.      * @param stateType mean Eckstein-Hechler orbit or osculating orbit
  684.      * @since 10.2
  685.      */
  686.     public void resetInitialState(final FieldSpacecraftState<T> state, final PropagationType stateType) {
  687.         final OsculatingToMeanConverter converter = new FixedPointConverter(EPSILON_DEFAULT,
  688.                                                                             MAX_ITERATIONS_DEFAULT,
  689.                                                                             FixedPointConverter.DEFAULT_DAMPING);
  690.         resetInitialState(state, stateType, converter);
  691.     }

  692.     /** Reset the propagator initial state.
  693.      * @param state new initial state to consider
  694.      * @param stateType mean Eckstein-Hechler orbit or osculating orbit
  695.      * @param epsilon convergence threshold for mean parameters conversion
  696.      * @param maxIterations maximum iterations for mean parameters conversion
  697.      * @since 11.2
  698.      */
  699.     public void resetInitialState(final FieldSpacecraftState<T> state,
  700.                                   final PropagationType stateType,
  701.                                   final double epsilon,
  702.                                   final int maxIterations) {
  703.         final OsculatingToMeanConverter converter = new FixedPointConverter(epsilon, maxIterations,
  704.                                                                             FixedPointConverter.DEFAULT_DAMPING);
  705.         resetInitialState(state, stateType, converter);
  706.     }

  707.     /** Reset the propagator initial state.
  708.      * @param state new initial state to consider
  709.      * @param stateType mean Eckstein-Hechler orbit or osculating orbit
  710.      * @param converter osculating to mean orbit converter
  711.      * @since 13.0
  712.      */
  713.     public void resetInitialState(final FieldSpacecraftState<T> state,
  714.                                   final PropagationType stateType,
  715.                                   final OsculatingToMeanConverter converter) {
  716.         super.resetInitialState(state);
  717.         FieldCircularOrbit<T> circular = (FieldCircularOrbit<T>) OrbitType.CIRCULAR.convertType(state.getOrbit());
  718.         if (stateType == PropagationType.OSCULATING) {
  719.             final MeanTheory theory = new EcksteinHechlerTheory(referenceRadius, mu.getReal(),
  720.                                                                 ck0[2], ck0[3], ck0[4], ck0[5], ck0[6]);
  721.             converter.setMeanTheory(theory);
  722.             circular = (FieldCircularOrbit<T>) OrbitType.CIRCULAR.convertType(converter.convertToMean(circular));
  723.         }
  724.         this.initialModel = new FieldEHModel<>(circular, state.getMass(), referenceRadius, mu, ck0);
  725.         this.models = new FieldTimeSpanMap<>(initialModel, state.getMass().getField());
  726.     }

  727.     /** {@inheritDoc} */
  728.     @Override
  729.     protected void resetIntermediateState(final FieldSpacecraftState<T> state, final boolean forward) {
  730.         resetIntermediateState(state, forward, EPSILON_DEFAULT, MAX_ITERATIONS_DEFAULT);
  731.     }

  732.     /** Reset an intermediate state.
  733.      * @param state new intermediate state to consider
  734.      * @param forward if true, the intermediate state is valid for
  735.      * propagations after itself
  736.      * @param epsilon convergence threshold for mean parameters conversion
  737.      * @param maxIterations maximum iterations for mean parameters conversion
  738.      * @since 11.2
  739.      */
  740.     protected void resetIntermediateState(final FieldSpacecraftState<T> state,
  741.                                           final boolean forward,
  742.                                           final double epsilon,
  743.                                           final int maxIterations) {
  744.         final OsculatingToMeanConverter converter = new FixedPointConverter(epsilon, maxIterations,
  745.                                                                             FixedPointConverter.DEFAULT_DAMPING);
  746.         resetIntermediateState(state, forward, converter);
  747.     }

  748.     /** Reset an intermediate state.
  749.      * @param state     new intermediate state to consider
  750.      * @param forward   if true, the intermediate state is valid for
  751.      *                  propagations after itself
  752.      * @param converter osculating to mean orbit converter
  753.      * @since 13.0
  754.      */
  755.     protected void resetIntermediateState(final FieldSpacecraftState<T> state,
  756.                                           final boolean forward,
  757.                                           final OsculatingToMeanConverter converter) {
  758.         final MeanTheory theory = new EcksteinHechlerTheory(referenceRadius, mu.getReal(),
  759.                                                             ck0[2], ck0[3], ck0[4], ck0[5], ck0[6]);
  760.         converter.setMeanTheory(theory);
  761.         final FieldCircularOrbit<T> mean = (FieldCircularOrbit<T>) OrbitType.CIRCULAR.convertType(converter.convertToMean(state.getOrbit()));
  762.         final FieldEHModel<T> newModel = new FieldEHModel<>(mean, state.getMass(), referenceRadius, mu, ck0);
  763.         if (forward) {
  764.             models.addValidAfter(newModel, state.getDate());
  765.         } else {
  766.             models.addValidBefore(newModel, state.getDate());
  767.         }
  768.         stateChanged(state);
  769.     }

  770.     /** {@inheritDoc} */
  771.     @Override
  772.     public FieldCartesianOrbit<T> propagateOrbit(final FieldAbsoluteDate<T> date, final T[] parameters) {
  773.         // compute Cartesian parameters, taking derivatives into account
  774.         // to make sure velocity and acceleration are consistent
  775.         final FieldEHModel<T> current = models.get(date);
  776.         return new FieldCartesianOrbit<>(toCartesian(date, current.propagateParameters(date)),
  777.                                          current.mean.getFrame(), mu);
  778.     }

  779.     /**
  780.      * Get the osculating circular orbit from the EH model.
  781.      * <p>This method is only relevant for the conversion from osculating to mean orbit.</p>
  782.      * @param date target date for the orbit
  783.      * @return the osculating circular orbite
  784.      */
  785.     public FieldCircularOrbit<T> getOsculatingCircularOrbit(final FieldAbsoluteDate<T> date) {
  786.         // compute circular parameters from the model
  787.         final FieldEHModel<T> current = models.get(date);
  788.         final FieldUnivariateDerivative2<T>[] parameter = current.propagateParameters(date);
  789.         return new FieldCircularOrbit<T>(parameter[0].getValue(),
  790.                                          parameter[1].getValue(),
  791.                                          parameter[2].getValue(),
  792.                                          parameter[3].getValue(),
  793.                                          parameter[4].getValue(),
  794.                                          parameter[5].getValue(),
  795.                                          PositionAngleType.MEAN,
  796.                                          current.mean.getFrame(),
  797.                                          date, mu);
  798.     }

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

  801.         /** Mean FieldOrbit. */
  802.         private final FieldCircularOrbit<T> mean;

  803.         /** Constant mass. */
  804.         private final T mass;
  805.         // CHECKSTYLE: stop JavadocVariable check

  806.         // preprocessed values
  807.         private final T xnotDot;
  808.         private final T rdpom;
  809.         private final T rdpomp;
  810.         private final T eps1;
  811.         private final T eps2;
  812.         private final T xim;
  813.         private final T ommD;
  814.         private final T rdl;
  815.         private final T aMD;

  816.         private final T kh;
  817.         private final T kl;

  818.         private final T ax1;
  819.         private final T ay1;
  820.         private final T as1;
  821.         private final T ac2;
  822.         private final T axy3;
  823.         private final T as3;
  824.         private final T ac4;
  825.         private final T as5;
  826.         private final T ac6;

  827.         private final T ex1;
  828.         private final T exx2;
  829.         private final T exy2;
  830.         private final T ex3;
  831.         private final T ex4;

  832.         private final T ey1;
  833.         private final T eyx2;
  834.         private final T eyy2;
  835.         private final T ey3;
  836.         private final T ey4;

  837.         private final T rx1;
  838.         private final T ry1;
  839.         private final T r2;
  840.         private final T r3;
  841.         private final T rl;

  842.         private final T iy1;
  843.         private final T ix1;
  844.         private final T i2;
  845.         private final T i3;
  846.         private final T ih;

  847.         private final T lx1;
  848.         private final T ly1;
  849.         private final T l2;
  850.         private final T l3;
  851.         private final T ll;

  852.         // CHECKSTYLE: resume JavadocVariable check

  853.         /** Create a model for specified mean FieldOrbit.
  854.          * @param mean mean FieldOrbit
  855.          * @param mass constant mass
  856.          * @param referenceRadius reference radius of the central body attraction model (m)
  857.          * @param mu central attraction coefficient (m³/s²)
  858.          * @param ck0 un-normalized zonal coefficients
  859.          */
  860.         FieldEHModel(final FieldCircularOrbit<T> mean, final T mass,
  861.                      final double referenceRadius, final T mu, final double[] ck0) {

  862.             this.mean            = mean;
  863.             this.mass            = mass;
  864.             final T zero = mass.getField().getZero();
  865.             final T one  = mass.getField().getOne();
  866.             // preliminary processing
  867.             T q =  zero.newInstance(referenceRadius).divide(mean.getA());
  868.             T ql = q.multiply(q);
  869.             final T g2 = ql.multiply(ck0[2]);
  870.             ql = ql.multiply(q);
  871.             final T g3 = ql.multiply(ck0[3]);
  872.             ql = ql.multiply(q);
  873.             final T g4 = ql.multiply(ck0[4]);
  874.             ql = ql.multiply(q);
  875.             final T g5 = ql.multiply(ck0[5]);
  876.             ql = ql.multiply(q);
  877.             final T g6 = ql.multiply(ck0[6]);

  878.             final FieldSinCos<T> sc = FastMath.sinCos(mean.getI());
  879.             final T cosI1 = sc.cos();
  880.             final T sinI1 = sc.sin();
  881.             final T sinI2 = sinI1.multiply(sinI1);
  882.             final T sinI4 = sinI2.multiply(sinI2);
  883.             final T sinI6 = sinI2.multiply(sinI4);

  884.             if (sinI2.getReal() < 1.0e-10) {
  885.                 throw new OrekitException(OrekitMessages.ALMOST_EQUATORIAL_ORBIT,
  886.                                                FastMath.toDegrees(mean.getI().getReal()));
  887.             }

  888.             if (FastMath.abs(sinI2.getReal() - 4.0 / 5.0) < 1.0e-3) {
  889.                 throw new OrekitException(OrekitMessages.ALMOST_CRITICALLY_INCLINED_ORBIT,
  890.                                                FastMath.toDegrees(mean.getI().getReal()));
  891.             }

  892.             if (mean.getE().getReal() > 0.1) {
  893.                 // if 0.005 < e < 0.1 no error is triggered, but accuracy is poor
  894.                 throw new OrekitException(OrekitMessages.TOO_LARGE_ECCENTRICITY_FOR_PROPAGATION_MODEL,
  895.                                                mean.getE());
  896.             }

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

  898.             rdpom = g2.multiply(-0.75).multiply(sinI2.multiply(-5.0).add(4.0));
  899.             rdpomp = g4.multiply(7.5).multiply(sinI2.multiply(-31.0 / 8.0).add(1.0).add( sinI4.multiply(49.0 / 16.0))).subtract(
  900.                     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)) ));


  901.             q = zero.newInstance(3.0).divide(rdpom.multiply(32.0));
  902.             eps1 = q.multiply(g4).multiply(sinI2).multiply(sinI2.multiply(-35.0).add(30.0)).subtract(
  903.                    q.multiply(175.0).multiply(g6).multiply(sinI2).multiply(sinI2.multiply(-3.0).add(sinI4.multiply(2.0625)).add(1.0)));
  904.             q = sinI1.multiply(3.0).divide(rdpom.multiply(8.0));
  905.             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)));

  906.             xim = mean.getI();
  907.             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(
  908.                             g4.multiply(0.9375).multiply(sinI2.multiply(7.0).subtract(4.0))).add(
  909.                             g6.multiply(3.28125).multiply(sinI2.multiply(-9.0).add(2.0).add(sinI4.multiply(8.25)))));

  910.             rdl = g2.multiply(-1.50).multiply(sinI2.multiply(-4.0).add(3.0)).add(1.0);
  911.             aMD = rdl.add(
  912.                     g2.multiply(2.25).multiply(g2.multiply(sinI2.multiply(-263.0 / 12.0 ).add(9.0).add(sinI4.multiply(341.0 / 24.0))))).add(
  913.                     g4.multiply(15.0 / 16.0).multiply(sinI2.multiply(-31.0).add(8.0).add(sinI4.multiply(24.5)))).add(
  914.                     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))));

  915.             final T qq   = g2.divide(rdl).multiply(-1.5);
  916.             final T qA   = g2.multiply(0.75).multiply(g2).multiply(sinI2);
  917.             final T qB   = g4.multiply(0.25).multiply(sinI2);
  918.             final T qC   = g6.multiply(105.0 / 16.0).multiply(sinI2);
  919.             final T qD   = g3.multiply(-0.75).multiply(sinI1);
  920.             final T qE   = g5.multiply(3.75).multiply(sinI1);
  921.             kh = zero.newInstance(0.375).divide(rdpom);
  922.             kl = kh.divide(sinI1);

  923.             ax1 = qq.multiply(sinI2.multiply(-3.5).add(2.0));
  924.             ay1 = qq.multiply(sinI2.multiply(-2.5).add(2.0));
  925.             as1 = qD.multiply(sinI2.multiply(-5.0).add(4.0)).add(
  926.                   qE.multiply(sinI4.multiply(2.625).add(sinI2.multiply(-3.5)).add(1.0)));
  927.             ac2 = qq.multiply(sinI2).add(
  928.                   qA.multiply(7.0).multiply(sinI2.multiply(-3.0).add(2.0))).add(
  929.                   qB.multiply(sinI2.multiply(-17.5).add(15.0))).add(
  930.                   qC.multiply(sinI2.multiply(3.0).subtract(1.0).subtract(sinI4.multiply(33.0 / 16.0))));
  931.             axy3 = qq.multiply(3.5).multiply(sinI2);
  932.             as3 = qD.multiply(5.0 / 3.0).multiply(sinI2).add(
  933.                   qE.multiply(7.0 / 6.0).multiply(sinI2).multiply(sinI2.multiply(-1.125).add(1)));
  934.             ac4 = qA.multiply(sinI2).add(
  935.                   qB.multiply(4.375).multiply(sinI2)).add(
  936.                   qC.multiply(0.75).multiply(sinI4.multiply(1.1).subtract(sinI2)));

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

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

  939.             ex1 = qq.multiply(sinI2.multiply(-1.25).add(1.0));
  940.             exx2 = qq.multiply(0.5).multiply(sinI2.multiply(-5.0).add(3.0));
  941.             exy2 = qq.multiply(sinI2.multiply(-1.5).add(2.0));
  942.             ex3 = qq.multiply(7.0 / 12.0).multiply(sinI2);
  943.             ex4 = qq.multiply(17.0 / 8.0).multiply(sinI2);

  944.             ey1 = qq.multiply(sinI2.multiply(-1.75).add(1.0));
  945.             eyx2 = qq.multiply(sinI2.multiply(-3.0).add(1.0));
  946.             eyy2 = qq.multiply(sinI2.multiply(2.0).subtract(1.5));
  947.             ey3 = qq.multiply(7.0 / 12.0).multiply(sinI2);
  948.             ey4 = qq.multiply(17.0 / 8.0).multiply(sinI2);

  949.             q  = cosI1.multiply(qq).negate();
  950.             rx1 = q.multiply(3.5);
  951.             ry1 = q.multiply(-2.5);
  952.             r2 = q.multiply(-0.5);
  953.             r3 =  q.multiply(7.0 / 6.0);
  954.             rl = g3 .multiply( cosI1).multiply(sinI2.multiply(-15.0).add(4.0)).subtract(
  955.                  g5.multiply(2.5).multiply(cosI1).multiply(sinI2.multiply(-42.0).add(4.0).add(sinI4.multiply(52.5))));

  956.             q = qq.multiply(0.5).multiply(sinI1).multiply(cosI1);
  957.             iy1 =  q;
  958.             ix1 = q.negate();
  959.             i2 =  q;
  960.             i3 =  q.multiply(7.0 / 3.0);
  961.             ih = g3.negate().multiply(cosI1).multiply(sinI2.multiply(-5.0).add(4)).add(
  962.                  g5.multiply(2.5).multiply(cosI1).multiply(sinI2.multiply(-14.0).add(4.0).add(sinI4.multiply(10.5))));
  963.             lx1 = qq.multiply(sinI2.multiply(-77.0 / 8.0).add(7.0));
  964.             ly1 = qq.multiply(sinI2.multiply(55.0 / 8.0).subtract(7.50));
  965.             l2 = qq.multiply(sinI2.multiply(1.25).subtract(0.5));
  966.             l3 = qq.multiply(sinI2.multiply(77.0 / 24.0).subtract(7.0 / 6.0));
  967.             ll = g3.multiply(sinI2.multiply(53.0).subtract(4.0).add(sinI4.multiply(-57.5))).add(
  968.                  g5.multiply(2.5).multiply(sinI2.multiply(-96.0).add(4.0).add(sinI4.multiply(269.5).subtract(sinI6.multiply(183.75)))));

  969.         }

  970.         /** Extrapolate a FieldOrbit up to a specific target date.
  971.          * @param date target date for the FieldOrbit
  972.          * @return propagated parameters
  973.          */
  974.         public FieldUnivariateDerivative2<T>[] propagateParameters(final FieldAbsoluteDate<T> date) {
  975.             final Field<T> field = date.durationFrom(mean.getDate()).getField();
  976.             final T one = field.getOne();
  977.             final T zero = field.getZero();
  978.             // Keplerian evolution
  979.             final FieldUnivariateDerivative2<T> dt = new FieldUnivariateDerivative2<>(date.durationFrom(mean.getDate()), one, zero);
  980.             final FieldUnivariateDerivative2<T> xnot = dt.multiply(xnotDot);

  981.             // secular effects

  982.             // eccentricity
  983.             final FieldUnivariateDerivative2<T> x   = xnot.multiply(rdpom.add(rdpomp));
  984.             final FieldUnivariateDerivative2<T> cx  = x.cos();
  985.             final FieldUnivariateDerivative2<T> sx  = x.sin();
  986.             final FieldUnivariateDerivative2<T> exm = cx.multiply(mean.getCircularEx()).
  987.                                             add(sx.multiply(eps2.subtract(one.subtract(eps1).multiply(mean.getCircularEy()))));
  988.             final FieldUnivariateDerivative2<T> eym = sx.multiply(eps1.add(1.0).multiply(mean.getCircularEx())).
  989.                                             add(cx.multiply(mean.getCircularEy().subtract(eps2))).
  990.                                             add(eps2);
  991.             // no secular effect on inclination

  992.             // right ascension of ascending node
  993.             final FieldUnivariateDerivative2<T> omm =
  994.                            new FieldUnivariateDerivative2<>(MathUtils.normalizeAngle(mean.getRightAscensionOfAscendingNode().add(ommD.multiply(xnot.getValue())),
  995.                                                                                      one.getPi()),
  996.                                                             ommD.multiply(xnotDot),
  997.                                                             zero);
  998.             // latitude argument
  999.             final FieldUnivariateDerivative2<T> xlm =
  1000.                             new FieldUnivariateDerivative2<>(MathUtils.normalizeAngle(mean.getAlphaM().add(aMD.multiply(xnot.getValue())),
  1001.                                                                                       one.getPi()),
  1002.                                                            aMD.multiply(xnotDot),
  1003.                                                            zero);

  1004.             // periodical terms
  1005.             final FieldUnivariateDerivative2<T> cl1 = xlm.cos();
  1006.             final FieldUnivariateDerivative2<T> sl1 = xlm.sin();
  1007.             final FieldUnivariateDerivative2<T> cl2 = cl1.multiply(cl1).subtract(sl1.multiply(sl1));
  1008.             final FieldUnivariateDerivative2<T> sl2 = cl1.multiply(sl1).add(sl1.multiply(cl1));
  1009.             final FieldUnivariateDerivative2<T> cl3 = cl2.multiply(cl1).subtract(sl2.multiply(sl1));
  1010.             final FieldUnivariateDerivative2<T> sl3 = cl2.multiply(sl1).add(sl2.multiply(cl1));
  1011.             final FieldUnivariateDerivative2<T> cl4 = cl3.multiply(cl1).subtract(sl3.multiply(sl1));
  1012.             final FieldUnivariateDerivative2<T> sl4 = cl3.multiply(sl1).add(sl3.multiply(cl1));
  1013.             final FieldUnivariateDerivative2<T> cl5 = cl4.multiply(cl1).subtract(sl4.multiply(sl1));
  1014.             final FieldUnivariateDerivative2<T> sl5 = cl4.multiply(sl1).add(sl4.multiply(cl1));
  1015.             final FieldUnivariateDerivative2<T> cl6 = cl5.multiply(cl1).subtract(sl5.multiply(sl1));

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

  1018.             final FieldUnivariateDerivative2<T> exmCl1 = exm.multiply(cl1);
  1019.             final FieldUnivariateDerivative2<T> exmSl1 = exm.multiply(sl1);
  1020.             final FieldUnivariateDerivative2<T> eymCl1 = eym.multiply(cl1);
  1021.             final FieldUnivariateDerivative2<T> eymSl1 = eym.multiply(sl1);
  1022.             final FieldUnivariateDerivative2<T> exmCl2 = exm.multiply(cl2);
  1023.             final FieldUnivariateDerivative2<T> exmSl2 = exm.multiply(sl2);
  1024.             final FieldUnivariateDerivative2<T> eymCl2 = eym.multiply(cl2);
  1025.             final FieldUnivariateDerivative2<T> eymSl2 = eym.multiply(sl2);
  1026.             final FieldUnivariateDerivative2<T> exmCl3 = exm.multiply(cl3);
  1027.             final FieldUnivariateDerivative2<T> exmSl3 = exm.multiply(sl3);
  1028.             final FieldUnivariateDerivative2<T> eymCl3 = eym.multiply(cl3);
  1029.             final FieldUnivariateDerivative2<T> eymSl3 = eym.multiply(sl3);
  1030.             final FieldUnivariateDerivative2<T> exmCl4 = exm.multiply(cl4);
  1031.             final FieldUnivariateDerivative2<T> exmSl4 = exm.multiply(sl4);
  1032.             final FieldUnivariateDerivative2<T> eymCl4 = eym.multiply(cl4);
  1033.             final FieldUnivariateDerivative2<T> eymSl4 = eym.multiply(sl4);

  1034.             // semi major axis
  1035.             final FieldUnivariateDerivative2<T> rda = exmCl1.multiply(ax1).
  1036.                                             add(eymSl1.multiply(ay1)).
  1037.                                             add(sl1.multiply(as1)).
  1038.                                             add(cl2.multiply(ac2)).
  1039.                                             add(exmCl3.add(eymSl3).multiply(axy3)).
  1040.                                             add(sl3.multiply(as3)).
  1041.                                             add(cl4.multiply(ac4)).
  1042.                                             add(sl5.multiply(as5)).
  1043.                                             add(cl6.multiply(ac6));

  1044.             // eccentricity
  1045.             final FieldUnivariateDerivative2<T> rdex = cl1.multiply(ex1).
  1046.                                              add(exmCl2.multiply(exx2)).
  1047.                                              add(eymSl2.multiply(exy2)).
  1048.                                              add(cl3.multiply(ex3)).
  1049.                                              add(exmCl4.add(eymSl4).multiply(ex4));
  1050.             final FieldUnivariateDerivative2<T> rdey = sl1.multiply(ey1).
  1051.                                              add(exmSl2.multiply(eyx2)).
  1052.                                              add(eymCl2.multiply(eyy2)).
  1053.                                              add(sl3.multiply(ey3)).
  1054.                                              add(exmSl4.subtract(eymCl4).multiply(ey4));

  1055.             // ascending node
  1056.             final FieldUnivariateDerivative2<T> rdom = exmSl1.multiply(rx1).
  1057.                                              add(eymCl1.multiply(ry1)).
  1058.                                              add(sl2.multiply(r2)).
  1059.                                              add(eymCl3.subtract(exmSl3).multiply(r3)).
  1060.                                              add(ql.multiply(rl));

  1061.             // inclination
  1062.             final FieldUnivariateDerivative2<T> rdxi = eymSl1.multiply(iy1).
  1063.                                              add(exmCl1.multiply(ix1)).
  1064.                                              add(cl2.multiply(i2)).
  1065.                                              add(exmCl3.add(eymSl3).multiply(i3)).
  1066.                                              add(qh.multiply(ih));

  1067.             // latitude argument
  1068.             final FieldUnivariateDerivative2<T> rdxl = exmSl1.multiply(lx1).
  1069.                                              add(eymCl1.multiply(ly1)).
  1070.                                              add(sl2.multiply(l2)).
  1071.                                              add(exmSl3.subtract(eymCl3).multiply(l3)).
  1072.                                              add(ql.multiply(ll));
  1073.             // osculating parameters
  1074.             final FieldUnivariateDerivative2<T>[] FTD = MathArrays.buildArray(rdxl.getField(), 6);

  1075.             FTD[0] = rda.add(1.0).multiply(mean.getA());
  1076.             FTD[1] = rdex.add(exm);
  1077.             FTD[2] = rdey.add(eym);
  1078.             FTD[3] = rdxi.add(xim);
  1079.             FTD[4] = rdom.add(omm);
  1080.             FTD[5] = rdxl.add(xlm);
  1081.             return FTD;

  1082.         }

  1083.     }

  1084.     /** Convert circular parameters <em>with derivatives</em> to Cartesian coordinates.
  1085.      * @param date date of the parameters
  1086.      * @param parameters circular parameters (a, ex, ey, i, raan, alphaM)
  1087.      * @return Cartesian coordinates consistent with values and derivatives
  1088.      */
  1089.     private TimeStampedFieldPVCoordinates<T> toCartesian(final FieldAbsoluteDate<T> date, final FieldUnivariateDerivative2<T>[] parameters) {

  1090.         // evaluate coordinates in the FieldOrbit canonical reference frame
  1091.         final FieldUnivariateDerivative2<T> cosOmega = parameters[4].cos();
  1092.         final FieldUnivariateDerivative2<T> sinOmega = parameters[4].sin();
  1093.         final FieldUnivariateDerivative2<T> cosI     = parameters[3].cos();
  1094.         final FieldUnivariateDerivative2<T> sinI     = parameters[3].sin();
  1095.         final FieldUnivariateDerivative2<T> alphaE   = meanToEccentric(parameters[5], parameters[1], parameters[2]);
  1096.         final FieldUnivariateDerivative2<T> cosAE    = alphaE.cos();
  1097.         final FieldUnivariateDerivative2<T> sinAE    = alphaE.sin();
  1098.         final FieldUnivariateDerivative2<T> ex2      = parameters[1].square();
  1099.         final FieldUnivariateDerivative2<T> ey2      = parameters[2].square();
  1100.         final FieldUnivariateDerivative2<T> exy      = parameters[1].multiply(parameters[2]);
  1101.         final FieldUnivariateDerivative2<T> q        = ex2.add(ey2).subtract(1).negate().sqrt();
  1102.         final FieldUnivariateDerivative2<T> beta     = q.add(1).reciprocal();
  1103.         final FieldUnivariateDerivative2<T> bx2      = beta.multiply(ex2);
  1104.         final FieldUnivariateDerivative2<T> by2      = beta.multiply(ey2);
  1105.         final FieldUnivariateDerivative2<T> bxy      = beta.multiply(exy);
  1106.         final FieldUnivariateDerivative2<T> u        = bxy.multiply(sinAE).subtract(parameters[1].add(by2.subtract(1).multiply(cosAE)));
  1107.         final FieldUnivariateDerivative2<T> v        = bxy.multiply(cosAE).subtract(parameters[2].add(bx2.subtract(1).multiply(sinAE)));
  1108.         final FieldUnivariateDerivative2<T> x        = parameters[0].multiply(u);
  1109.         final FieldUnivariateDerivative2<T> y        = parameters[0].multiply(v);

  1110.         // canonical FieldOrbit reference frame
  1111.         final FieldVector3D<FieldUnivariateDerivative2<T>> p =
  1112.                 new FieldVector3D<>(x.multiply(cosOmega).subtract(y.multiply(cosI.multiply(sinOmega))),
  1113.                                     x.multiply(sinOmega).add(y.multiply(cosI.multiply(cosOmega))),
  1114.                                     y.multiply(sinI));

  1115.         // dispatch derivatives
  1116.         final FieldVector3D<T> p0 = new FieldVector3D<>(p.getX().getValue(),
  1117.                                                         p.getY().getValue(),
  1118.                                                         p.getZ().getValue());
  1119.         final FieldVector3D<T> p1 = new FieldVector3D<>(p.getX().getFirstDerivative(),
  1120.                                                         p.getY().getFirstDerivative(),
  1121.                                                         p.getZ().getFirstDerivative());
  1122.         final FieldVector3D<T> p2 = new FieldVector3D<>(p.getX().getSecondDerivative(),
  1123.                                                         p.getY().getSecondDerivative(),
  1124.                                                         p.getZ().getSecondDerivative());
  1125.         return new TimeStampedFieldPVCoordinates<>(date, p0, p1, p2);

  1126.     }

  1127.     /** Computes the eccentric latitude argument from the mean latitude argument.
  1128.      * @param alphaM = M + Ω mean latitude argument (rad)
  1129.      * @param ex e cos(Ω), first component of circular eccentricity vector
  1130.      * @param ey e sin(Ω), second component of circular eccentricity vector
  1131.      * @return the eccentric latitude argument.
  1132.      */
  1133.     private FieldUnivariateDerivative2<T> meanToEccentric(final FieldUnivariateDerivative2<T> alphaM,
  1134.                                                 final FieldUnivariateDerivative2<T> ex,
  1135.                                                 final FieldUnivariateDerivative2<T> ey) {
  1136.         // Generalization of Kepler equation to circular parameters
  1137.         // with alphaE = PA + E and
  1138.         //      alphaM = PA + M = alphaE - ex.sin(alphaE) + ey.cos(alphaE)
  1139.         FieldUnivariateDerivative2<T> alphaE        = alphaM;
  1140.         FieldUnivariateDerivative2<T> shift         = alphaM.getField().getZero();
  1141.         FieldUnivariateDerivative2<T> alphaEMalphaM = alphaM.getField().getZero();
  1142.         FieldUnivariateDerivative2<T> cosAlphaE     = alphaE.cos();
  1143.         FieldUnivariateDerivative2<T> sinAlphaE     = alphaE.sin();
  1144.         int                 iter          = 0;
  1145.         do {
  1146.             final FieldUnivariateDerivative2<T> f2 = ex.multiply(sinAlphaE).subtract(ey.multiply(cosAlphaE));
  1147.             final FieldUnivariateDerivative2<T> f1 = alphaM.getField().getOne().subtract(ex.multiply(cosAlphaE)).subtract(ey.multiply(sinAlphaE));
  1148.             final FieldUnivariateDerivative2<T> f0 = alphaEMalphaM.subtract(f2);

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

  1151.             alphaEMalphaM  = alphaEMalphaM.subtract(shift);
  1152.             alphaE         = alphaM.add(alphaEMalphaM);
  1153.             cosAlphaE      = alphaE.cos();
  1154.             sinAlphaE      = alphaE.sin();

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

  1156.         return alphaE;

  1157.     }

  1158.     /** {@inheritDoc} */
  1159.     @Override
  1160.     protected T getMass(final FieldAbsoluteDate<T> date) {
  1161.         return models.get(date).mass;
  1162.     }

  1163.     /** {@inheritDoc} */
  1164.     @Override
  1165.     public List<ParameterDriver> getParametersDrivers() {
  1166.         // Eckstein Hechler propagation model does not have parameter drivers.
  1167.         return Collections.emptyList();
  1168.     }

  1169. }