FieldEcksteinHechlerPropagator.java

  1. /* Copyright 2002-2020 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 org.hipparchus.Field;
  19. import org.hipparchus.RealFieldElement;
  20. import org.hipparchus.analysis.differentiation.FieldUnivariateDerivative2;
  21. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  22. import org.hipparchus.util.FastMath;
  23. import org.hipparchus.util.FieldSinCos;
  24. import org.hipparchus.util.MathArrays;
  25. import org.hipparchus.util.MathUtils;
  26. import org.orekit.annotation.DefaultDataContext;
  27. import org.orekit.attitudes.AttitudeProvider;
  28. import org.orekit.data.DataContext;
  29. import org.orekit.errors.OrekitException;
  30. import org.orekit.errors.OrekitMessages;
  31. import org.orekit.forces.gravity.potential.UnnormalizedSphericalHarmonicsProvider;
  32. import org.orekit.forces.gravity.potential.UnnormalizedSphericalHarmonicsProvider.UnnormalizedSphericalHarmonics;
  33. import org.orekit.orbits.FieldCartesianOrbit;
  34. import org.orekit.orbits.FieldCircularOrbit;
  35. import org.orekit.orbits.FieldOrbit;
  36. import org.orekit.orbits.OrbitType;
  37. import org.orekit.orbits.PositionAngle;
  38. import org.orekit.propagation.FieldSpacecraftState;
  39. import org.orekit.propagation.PropagationType;
  40. import org.orekit.propagation.Propagator;
  41. import org.orekit.time.FieldAbsoluteDate;
  42. import org.orekit.utils.FieldTimeSpanMap;
  43. import org.orekit.utils.TimeStampedFieldPVCoordinates;

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

  54.     /** Initial Eckstein-Hechler model. */
  55.     private FieldEHModel<T> initialModel;

  56.     /** All models. */
  57.     private transient FieldTimeSpanMap<FieldEHModel<T>, T> models;

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

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

  62.     /** Un-normalized zonal coefficients. */
  63.     private double[] ck0;

  64.     /** Build a propagator from FieldOrbit and potential provider.
  65.      * <p>Mass and attitude provider are set to unspecified non-null arbitrary values.</p>
  66.      *
  67.      * <p>This constructor uses the {@link DataContext#getDefault() default data context}.
  68.      *
  69.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  70.      *
  71.      * @param initialOrbit initial FieldOrbit
  72.      * @param provider for un-normalized zonal coefficients
  73.      * @see #FieldEcksteinHechlerPropagator(FieldOrbit, AttitudeProvider,
  74.      * UnnormalizedSphericalHarmonicsProvider)
  75.      * @see #FieldEcksteinHechlerPropagator(FieldOrbit, UnnormalizedSphericalHarmonicsProvider,
  76.      * PropagationType)
  77.      */
  78.     @DefaultDataContext
  79.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  80.                                           final UnnormalizedSphericalHarmonicsProvider provider) {
  81.         this(initialOrbit, Propagator.getDefaultLaw(DataContext.getDefault().getFrames()),
  82.              initialOrbit.getA().getField().getZero().add(DEFAULT_MASS), provider,
  83.              provider.onDate(initialOrbit.getDate().toAbsoluteDate()));
  84.     }

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

  108.     /** Build a propagator from FieldOrbit and potential.
  109.      * <p>Mass and attitude provider are set to unspecified non-null arbitrary values.</p>
  110.      * <p>The C<sub>n,0</sub> coefficients are the denormalized zonal coefficients, they
  111.      * are related to both the normalized coefficients
  112.      * <span style="text-decoration: overline">C</span><sub>n,0</sub>
  113.      *  and the J<sub>n</sub> one as follows:
  114.      * <p>
  115.      *   C<sub>n,0</sub> = [(2-δ<sub>0,m</sub>)(2n+1)(n-m)!/(n+m)!]<sup>½</sup>
  116.      *                      <span style="text-decoration: overline">C</span><sub>n,0</sub>
  117.      * <p>
  118.      *   C<sub>n,0</sub> = -J<sub>n</sub>
  119.      *
  120.      * <p>This constructor uses the {@link DataContext#getDefault() default data context}.
  121.      *
  122.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  123.      *
  124.      * @param initialOrbit initial FieldOrbit
  125.      * @param referenceRadius reference radius of the Earth for the potential model (m)
  126.      * @param mu central attraction coefficient (m³/s²)
  127.      * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
  128.      * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
  129.      * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
  130.      * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
  131.      * @param c60 un-normalized zonal coefficient (about -5.41e-7 for Earth)
  132.      * @see org.orekit.utils.Constants
  133.      * @see #FieldEcksteinHechlerPropagator(FieldOrbit, AttitudeProvider, double,
  134.      * RealFieldElement, double, double, double, double, double)
  135.      */
  136.     @DefaultDataContext
  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, Propagator.getDefaultLaw(DataContext.getDefault().getFrames()),
  142.              initialOrbit.getDate().getField().getZero().add(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>This constructor uses the {@link DataContext#getDefault() default data context}.
  149.      *
  150.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  151.      *
  152.      * @param initialOrbit initial FieldOrbit
  153.      * @param mass spacecraft mass
  154.      * @param provider for un-normalized zonal coefficients
  155.      * @see #FieldEcksteinHechlerPropagator(FieldOrbit, AttitudeProvider,
  156.      * RealFieldElement, UnnormalizedSphericalHarmonicsProvider)
  157.      */
  158.     @DefaultDataContext
  159.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit, final T mass,
  160.                                           final UnnormalizedSphericalHarmonicsProvider provider) {
  161.         this(initialOrbit, Propagator.getDefaultLaw(DataContext.getDefault().getFrames()),
  162.                 mass, provider, provider.onDate(initialOrbit.getDate().toAbsoluteDate()));
  163.     }

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

  200.     /** Build a propagator from FieldOrbit, attitude provider and potential provider.
  201.      * <p>Mass is set to an unspecified non-null arbitrary value.</p>
  202.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  203.      * @param initialOrbit initial FieldOrbit
  204.      * @param attitudeProv attitude provider
  205.      * @param provider for un-normalized zonal coefficients
  206.      */
  207.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  208.                                           final AttitudeProvider attitudeProv,
  209.                                           final UnnormalizedSphericalHarmonicsProvider provider) {
  210.         this(initialOrbit, attitudeProv, initialOrbit.getA().getField().getZero().add(DEFAULT_MASS), provider, provider.onDate(initialOrbit.getDate().toAbsoluteDate()));
  211.     }

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

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

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

  293.     /** Build a propagator from orbit and potential provider.
  294.      * <p>Mass and attitude provider are set to unspecified non-null arbitrary values.</p>
  295.      *
  296.      * <p>This constructor uses the {@link DataContext#getDefault() default data context}.
  297.      *
  298.      * <p>Using this constructor, it is possible to define the initial orbit as
  299.      * a mean Eckstein-Hechler orbit or an osculating one.</p>
  300.      *
  301.      * @param initialOrbit initial orbit
  302.      * @param provider for un-normalized zonal coefficients
  303.      * @param initialType initial orbit type (mean Eckstein-Hechler orbit or osculating orbit)
  304.      * @since 10.2
  305.      */
  306.     @DefaultDataContext
  307.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  308.                                           final UnnormalizedSphericalHarmonicsProvider provider,
  309.                                           final PropagationType initialType) {
  310.         this(initialOrbit, Propagator.getDefaultLaw(DataContext.getDefault().getFrames()),
  311.              initialOrbit.getA().getField().getZero().add(DEFAULT_MASS), provider,
  312.              provider.onDate(initialOrbit.getDate().toAbsoluteDate()), initialType);
  313.     }

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

  331.     /**
  332.      * Private helper constructor.
  333.      * <p>Using this constructor, it is possible to define the initial orbit as
  334.      * a mean Eckstein-Hechler orbit or an osculating one.</p>
  335.      * @param initialOrbit initial orbit
  336.      * @param attitude attitude provider
  337.      * @param mass spacecraft mass
  338.      * @param provider for un-normalized zonal coefficients
  339.      * @param harmonics {@code provider.onDate(initialOrbit.getDate())}
  340.      * @param initialType initial orbit type (mean Eckstein-Hechler orbit or osculating orbit)
  341.      * @since 10.2
  342.      */
  343.     public FieldEcksteinHechlerPropagator(final FieldOrbit<T> initialOrbit,
  344.                                           final AttitudeProvider attitude,
  345.                                           final T mass,
  346.                                           final UnnormalizedSphericalHarmonicsProvider provider,
  347.                                           final UnnormalizedSphericalHarmonics harmonics,
  348.                                           final PropagationType initialType) {
  349.         this(initialOrbit, attitude, mass, provider.getAe(), initialOrbit.getA().getField().getZero().add(provider.getMu()),
  350.              harmonics.getUnnormalizedCnm(2, 0),
  351.              harmonics.getUnnormalizedCnm(3, 0),
  352.              harmonics.getUnnormalizedCnm(4, 0),
  353.              harmonics.getUnnormalizedCnm(5, 0),
  354.              harmonics.getUnnormalizedCnm(6, 0),
  355.              initialType);
  356.     }

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

  391.         super(mass.getField(), attitudeProv);
  392.         try {

  393.             // store model coefficients
  394.             this.referenceRadius = referenceRadius;
  395.             this.mu  = mu;
  396.             this.ck0 = new double[] {
  397.                 0.0, 0.0, c20, c30, c40, c50, c60
  398.             };

  399.             // compute mean parameters if needed
  400.             // transform into circular adapted parameters used by the Eckstein-Hechler model
  401.             resetInitialState(new FieldSpacecraftState<>(initialOrbit,
  402.                                                          attitudeProv.getAttitude(initialOrbit,
  403.                                                                                   initialOrbit.getDate(),
  404.                                                                                   initialOrbit.getFrame()),
  405.                                                          mass),
  406.                               initialType);

  407.         } catch (OrekitException oe) {
  408.             throw new OrekitException(oe);
  409.         }
  410.     }

  411.     /** {@inheritDoc}
  412.      * <p>The new initial state to consider
  413.      * must be defined with an osculating orbit.</p>
  414.      * @see #resetInitialState(FieldSpacecraftState, PropagationType)
  415.      */
  416.     public void resetInitialState(final FieldSpacecraftState<T> state) {
  417.         resetInitialState(state, PropagationType.OSCULATING);
  418.     }

  419.     /** Reset the propagator initial state.
  420.      * @param state new initial state to consider
  421.      * @param stateType mean Eckstein-Hechler orbit or osculating orbit
  422.      * @since 10.2
  423.      */
  424.     public void resetInitialState(final FieldSpacecraftState<T> state, final PropagationType stateType) {
  425.         super.resetInitialState(state);
  426.         final FieldCircularOrbit<T> circular = (FieldCircularOrbit<T>) OrbitType.CIRCULAR.convertType(state.getOrbit());
  427.         this.initialModel = (stateType == PropagationType.MEAN) ?
  428.                              new FieldEHModel<>(circular, state.getMass(), referenceRadius, mu, ck0) :
  429.                              computeMeanParameters(circular, state.getMass());
  430.         this.models = new FieldTimeSpanMap<FieldEHModel<T>, T>(initialModel, state.getA().getField());
  431.     }

  432.     /** {@inheritDoc} */
  433.     protected void resetIntermediateState(final FieldSpacecraftState<T> state, final boolean forward) {
  434.         final FieldEHModel<T> newModel = computeMeanParameters((FieldCircularOrbit<T>) OrbitType.CIRCULAR.convertType(state.getOrbit()),
  435.                                                        state.getMass());
  436.         if (forward) {
  437.             models.addValidAfter(newModel, state.getDate());
  438.         } else {
  439.             models.addValidBefore(newModel, state.getDate());
  440.         }
  441.         stateChanged(state);
  442.     }

  443.     /** Compute mean parameters according to the Eckstein-Hechler analytical model.
  444.      * @param osculating osculating FieldOrbit
  445.      * @param mass constant mass
  446.      * @return Eckstein-Hechler mean model
  447.      */
  448.     private FieldEHModel<T> computeMeanParameters(final FieldCircularOrbit<T> osculating, final T mass) {

  449.         // sanity check
  450.         if (osculating.getA().getReal() < referenceRadius) {
  451.             throw new OrekitException(OrekitMessages.TRAJECTORY_INSIDE_BRILLOUIN_SPHERE,
  452.                                            osculating.getA());
  453.         }
  454.         final Field<T> field = mass.getField();
  455.         final T one = field.getOne();
  456.         final T zero = field.getZero();
  457.         // rough initialization of the mean parameters
  458.         FieldEHModel<T> current = new FieldEHModel<>(osculating, mass, referenceRadius, mu, ck0);
  459.         // threshold for each parameter
  460.         final T epsilon         = one .multiply(1.0e-13);
  461.         final T thresholdA      = epsilon.multiply(current.mean.getA().abs().add(1.0));
  462.         final T thresholdE      = epsilon.multiply(current.mean.getE().add(1.0));
  463.         final T thresholdAngles = epsilon.multiply(FastMath.PI);


  464.         int i = 0;
  465.         while (i++ < 100) {

  466.             // recompute the osculating parameters from the current mean parameters
  467.             final FieldUnivariateDerivative2<T>[] parameters = current.propagateParameters(current.mean.getDate());
  468.             // adapted parameters residuals
  469.             final T deltaA      = osculating.getA()         .subtract(parameters[0].getValue());
  470.             final T deltaEx     = osculating.getCircularEx().subtract(parameters[1].getValue());
  471.             final T deltaEy     = osculating.getCircularEy().subtract(parameters[2].getValue());
  472.             final T deltaI      = osculating.getI()         .subtract(parameters[3].getValue());
  473.             final T deltaRAAN   = MathUtils.normalizeAngle(osculating.getRightAscensionOfAscendingNode().subtract(
  474.                                                                 parameters[4].getValue()),
  475.                                                                 zero);
  476.             final T deltaAlphaM = MathUtils.normalizeAngle(osculating.getAlphaM().subtract(parameters[5].getValue()), zero);
  477.             // update mean parameters
  478.             current = new FieldEHModel<>(new FieldCircularOrbit<>(current.mean.getA().add(deltaA),
  479.                                                                   current.mean.getCircularEx().add( deltaEx),
  480.                                                                   current.mean.getCircularEy().add( deltaEy),
  481.                                                                   current.mean.getI()         .add( deltaI ),
  482.                                                                   current.mean.getRightAscensionOfAscendingNode().add(deltaRAAN),
  483.                                                                   current.mean.getAlphaM().add(deltaAlphaM),
  484.                                                                   PositionAngle.MEAN,
  485.                                                                   current.mean.getFrame(),
  486.                                                                   current.mean.getDate(), mu),
  487.                                   mass, referenceRadius, mu, ck0);
  488.             // check convergence
  489.             if ((FastMath.abs(deltaA.getReal())      < thresholdA.getReal()) &&
  490.                 (FastMath.abs(deltaEx.getReal())     < thresholdE.getReal()) &&
  491.                 (FastMath.abs(deltaEy.getReal())     < thresholdE.getReal()) &&
  492.                 (FastMath.abs(deltaI.getReal())      < thresholdAngles.getReal()) &&
  493.                 (FastMath.abs(deltaRAAN.getReal())   < thresholdAngles.getReal()) &&
  494.                 (FastMath.abs(deltaAlphaM.getReal()) < thresholdAngles.getReal())) {
  495.                 return current;
  496.             }

  497.         }

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

  499.     }

  500.     /** {@inheritDoc} */
  501.     public FieldCartesianOrbit<T> propagateOrbit(final FieldAbsoluteDate<T> date) {
  502.         // compute Cartesian parameters, taking derivatives into account
  503.         // to make sure velocity and acceleration are consistent
  504.         final FieldEHModel<T> current = models.get(date);
  505.         return new FieldCartesianOrbit<>(toCartesian(date, current.propagateParameters(date)),
  506.                                          current.mean.getFrame(), mu);
  507.     }

  508.     /** Local class for Eckstein-Hechler model, with fixed mean parameters. */
  509.     private static class FieldEHModel<T extends RealFieldElement<T>> {

  510.         /** Mean FieldOrbit. */
  511.         private final FieldCircularOrbit<T> mean;

  512.         /** Constant mass. */
  513.         private final T mass;
  514.         // CHECKSTYLE: stop JavadocVariable check

  515.         // preprocessed values
  516.         private final T xnotDot;
  517.         private final T rdpom;
  518.         private final T rdpomp;
  519.         private final T eps1;
  520.         private final T eps2;
  521.         private final T xim;
  522.         private final T ommD;
  523.         private final T rdl;
  524.         private final T aMD;

  525.         private final T kh;
  526.         private final T kl;

  527.         private final T ax1;
  528.         private final T ay1;
  529.         private final T as1;
  530.         private final T ac2;
  531.         private final T axy3;
  532.         private final T as3;
  533.         private final T ac4;
  534.         private final T as5;
  535.         private final T ac6;

  536.         private final T ex1;
  537.         private final T exx2;
  538.         private final T exy2;
  539.         private final T ex3;
  540.         private final T ex4;

  541.         private final T ey1;
  542.         private final T eyx2;
  543.         private final T eyy2;
  544.         private final T ey3;
  545.         private final T ey4;

  546.         private final T rx1;
  547.         private final T ry1;
  548.         private final T r2;
  549.         private final T r3;
  550.         private final T rl;

  551.         private final T iy1;
  552.         private final T ix1;
  553.         private final T i2;
  554.         private final T i3;
  555.         private final T ih;

  556.         private final T lx1;
  557.         private final T ly1;
  558.         private final T l2;
  559.         private final T l3;
  560.         private final T ll;

  561.         // CHECKSTYLE: resume JavadocVariable check

  562.         /** Create a model for specified mean FieldOrbit.
  563.          * @param mean mean FieldOrbit
  564.          * @param mass constant mass
  565.          * @param referenceRadius reference radius of the central body attraction model (m)
  566.          * @param mu central attraction coefficient (m³/s²)
  567.          * @param ck0 un-normalized zonal coefficients
  568.          */
  569.         FieldEHModel(final FieldCircularOrbit<T> mean, final T mass,
  570.                      final double referenceRadius, final T mu, final double[] ck0) {

  571.             this.mean            = mean;
  572.             this.mass            = mass;
  573.             final T zero = mass.getField().getZero();
  574.             final T one  = mass.getField().getOne();
  575.             // preliminary processing
  576.             T q =  zero.add(referenceRadius).divide(mean.getA());
  577.             T ql = q.multiply(q);
  578.             final T g2 = ql.multiply(ck0[2]);
  579.             ql = ql.multiply(q);
  580.             final T g3 = ql.multiply(ck0[3]);
  581.             ql = ql.multiply(q);
  582.             final T g4 = ql.multiply(ck0[4]);
  583.             ql = ql.multiply(q);
  584.             final T g5 = ql.multiply(ck0[5]);
  585.             ql = ql.multiply(q);
  586.             final T g6 = ql.multiply(ck0[6]);

  587.             final FieldSinCos<T> sc = FastMath.sinCos(mean.getI());
  588.             final T cosI1 = sc.cos();
  589.             final T sinI1 = sc.sin();
  590.             final T sinI2 = sinI1.multiply(sinI1);
  591.             final T sinI4 = sinI2.multiply(sinI2);
  592.             final T sinI6 = sinI2.multiply(sinI4);

  593.             if (sinI2.getReal() < 1.0e-10) {
  594.                 throw new OrekitException(OrekitMessages.ALMOST_EQUATORIAL_ORBIT,
  595.                                                FastMath.toDegrees(mean.getI().getReal()));
  596.             }

  597.             if (FastMath.abs(sinI2.getReal() - 4.0 / 5.0) < 1.0e-3) {
  598.                 throw new OrekitException(OrekitMessages.ALMOST_CRITICALLY_INCLINED_ORBIT,
  599.                                                FastMath.toDegrees(mean.getI().getReal()));
  600.             }

  601.             if (mean.getE().getReal() > 0.1) {
  602.                 // if 0.005 < e < 0.1 no error is triggered, but accuracy is poor
  603.                 throw new OrekitException(OrekitMessages.TOO_LARGE_ECCENTRICITY_FOR_PROPAGATION_MODEL,
  604.                                                mean.getE());
  605.             }

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

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


  610.             q = zero.add(3.0).divide(rdpom.multiply(32.0));
  611.             eps1 = q.multiply(g4).multiply(sinI2).multiply(sinI2.multiply(-35.0).add(30.0)).subtract(
  612.                    q.multiply(175.0).multiply(g6).multiply(sinI2).multiply(sinI2.multiply(-3.0).add(sinI4.multiply(2.0625)).add(1.0)));
  613.             q = sinI1.multiply(3.0).divide(rdpom.multiply(8.0));
  614.             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)));

  615.             xim = mean.getI();
  616.             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(
  617.                             g4.multiply(0.9375).multiply(sinI2.multiply(7.0).subtract(4.0))).add(
  618.                             g6.multiply(3.28125).multiply(sinI2.multiply(-9.0).add(2.0).add(sinI4.multiply(8.25)))));

  619.             rdl = g2.multiply(-1.50).multiply(sinI2.multiply(-4.0).add(3.0)).add(1.0);
  620.             aMD = rdl.add(
  621.                     g2.multiply(2.25).multiply(g2.multiply(sinI2.multiply(-263.0 / 12.0 ).add(9.0).add(sinI4.multiply(341.0 / 24.0))))).add(
  622.                     g4.multiply(15.0 / 16.0).multiply(sinI2.multiply(-31.0).add(8.0).add(sinI4.multiply(24.5)))).add(
  623.                     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))));

  624.             final T qq   = g2.divide(rdl).multiply(-1.5);
  625.             final T qA   = g2.multiply(0.75).multiply(g2).multiply(sinI2);
  626.             final T qB   = g4.multiply(0.25).multiply(sinI2);
  627.             final T qC   = g6.multiply(105.0 / 16.0).multiply(sinI2);
  628.             final T qD   = g3.multiply(-0.75).multiply(sinI1);
  629.             final T qE   = g5.multiply(3.75).multiply(sinI1);
  630.             kh = zero.add(0.375).divide(rdpom);
  631.             kl = kh.divide(sinI1);

  632.             ax1 = qq.multiply(sinI2.multiply(-3.5).add(2.0));
  633.             ay1 = qq.multiply(sinI2.multiply(-2.5).add(2.0));
  634.             as1 = qD.multiply(sinI2.multiply(-5.0).add(4.0)).add(
  635.                   qE.multiply(sinI4.multiply(2.625).add(sinI2.multiply(-3.5)).add(1.0)));
  636.             ac2 = qq.multiply(sinI2).add(
  637.                   qA.multiply(7.0).multiply(sinI2.multiply(-3.0).add(2.0))).add(
  638.                   qB.multiply(sinI2.multiply(-17.5).add(15.0))).add(
  639.                   qC.multiply(sinI2.multiply(3.0).subtract(1.0).subtract(sinI4.multiply(33.0 / 16.0))));
  640.             axy3 = qq.multiply(3.5).multiply(sinI2);
  641.             as3 = qD.multiply(5.0 / 3.0).multiply(sinI2).add(
  642.                   qE.multiply(7.0 / 6.0).multiply(sinI2).multiply(sinI2.multiply(-1.125).add(1)));
  643.             ac4 = qA.multiply(sinI2).add(
  644.                   qB.multiply(4.375).multiply(sinI2)).add(
  645.                   qC.multiply(0.75).multiply(sinI4.multiply(1.1).subtract(sinI2)));

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

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

  648.             ex1 = qq.multiply(sinI2.multiply(-1.25).add(1.0));
  649.             exx2 = qq.multiply(0.5).multiply(sinI2.multiply(-5.0).add(3.0));
  650.             exy2 = qq.multiply(sinI2.multiply(-1.5).add(2.0));
  651.             ex3 = qq.multiply(7.0 / 12.0).multiply(sinI2);
  652.             ex4 = qq.multiply(17.0 / 8.0).multiply(sinI2);

  653.             ey1 = qq.multiply(sinI2.multiply(-1.75).add(1.0));
  654.             eyx2 = qq.multiply(sinI2.multiply(-3.0).add(1.0));
  655.             eyy2 = qq.multiply(sinI2.multiply(2.0).subtract(1.5));
  656.             ey3 = qq.multiply(7.0 / 12.0).multiply(sinI2);
  657.             ey4 = qq.multiply(17.0 / 8.0).multiply(sinI2);

  658.             q  = cosI1.multiply(qq).negate();
  659.             rx1 = q.multiply(3.5);
  660.             ry1 = q.multiply(-2.5);
  661.             r2 = q.multiply(-0.5);
  662.             r3 =  q.multiply(7.0 / 6.0);
  663.             rl = g3 .multiply( cosI1).multiply(sinI2.multiply(-15.0).add(4.0)).subtract(
  664.                  g5.multiply(2.5).multiply(cosI1).multiply(sinI2.multiply(-42.0).add(4.0).add(sinI4.multiply(52.5))));

  665.             q = qq.multiply(0.5).multiply(sinI1).multiply(cosI1);
  666.             iy1 =  q;
  667.             ix1 = q.negate();
  668.             i2 =  q;
  669.             i3 =  q.multiply(7.0 / 3.0);
  670.             ih = g3.negate().multiply(cosI1).multiply(sinI2.multiply(-5.0).add(4)).add(
  671.                  g5.multiply(2.5).multiply(cosI1).multiply(sinI2.multiply(-14.0).add(4.0).add(sinI4.multiply(10.5))));
  672.             lx1 = qq.multiply(sinI2.multiply(-77.0 / 8.0).add(7.0));
  673.             ly1 = qq.multiply(sinI2.multiply(55.0 / 8.0).subtract(7.50));
  674.             l2 = qq.multiply(sinI2.multiply(1.25).subtract(0.5));
  675.             l3 = qq.multiply(sinI2.multiply(77.0 / 24.0).subtract(7.0 / 6.0));
  676.             ll = g3.multiply(sinI2.multiply(53.0).subtract(4.0).add(sinI4.multiply(-57.5))).add(
  677.                  g5.multiply(2.5).multiply(sinI2.multiply(-96.0).add(4.0).add(sinI4.multiply(269.5).subtract(sinI6.multiply(183.75)))));

  678.         }

  679.         /** Extrapolate a FieldOrbit up to a specific target date.
  680.          * @param date target date for the FieldOrbit
  681.          * @return propagated parameters
  682.          */
  683.         public FieldUnivariateDerivative2<T>[] propagateParameters(final FieldAbsoluteDate<T> date) {
  684.             final Field<T> field = date.durationFrom(mean.getDate()).getField();
  685.             final T one = field.getOne();
  686.             final T zero = field.getZero();
  687.             // Keplerian evolution
  688.             final FieldUnivariateDerivative2<T> dt = new FieldUnivariateDerivative2<>(date.durationFrom(mean.getDate()), one, zero);
  689.             final FieldUnivariateDerivative2<T> xnot = dt.multiply(xnotDot);

  690.             // secular effects

  691.             // eccentricity
  692.             final FieldUnivariateDerivative2<T> x   = xnot.multiply(rdpom.add(rdpomp));
  693.             final FieldUnivariateDerivative2<T> cx  = x.cos();
  694.             final FieldUnivariateDerivative2<T> sx  = x.sin();
  695.             final FieldUnivariateDerivative2<T> exm = cx.multiply(mean.getCircularEx()).
  696.                                             add(sx.multiply(eps2.subtract(one.subtract(eps1).multiply(mean.getCircularEy()))));
  697.             final FieldUnivariateDerivative2<T> eym = sx.multiply(eps1.add(1.0).multiply(mean.getCircularEx())).
  698.                                             add(cx.multiply(mean.getCircularEy().subtract(eps2))).
  699.                                             add(eps2);
  700.             // no secular effect on inclination

  701.             // right ascension of ascending node
  702.             final FieldUnivariateDerivative2<T> omm =
  703.                            new FieldUnivariateDerivative2<>(MathUtils.normalizeAngle(mean.getRightAscensionOfAscendingNode().add(ommD.multiply(xnot.getValue())),
  704.                                                                                      zero.add(FastMath.PI)),
  705.                                                             ommD.multiply(xnotDot),
  706.                                                             zero);
  707.             // latitude argument
  708.             final FieldUnivariateDerivative2<T> xlm =
  709.                             new FieldUnivariateDerivative2<>(MathUtils.normalizeAngle(mean.getAlphaM().add(aMD.multiply(xnot.getValue())),
  710.                                                                                     zero.add(FastMath.PI)),
  711.                                                            aMD.multiply(xnotDot),
  712.                                                            zero);

  713.             // periodical terms
  714.             final FieldUnivariateDerivative2<T> cl1 = xlm.cos();
  715.             final FieldUnivariateDerivative2<T> sl1 = xlm.sin();
  716.             final FieldUnivariateDerivative2<T> cl2 = cl1.multiply(cl1).subtract(sl1.multiply(sl1));
  717.             final FieldUnivariateDerivative2<T> sl2 = cl1.multiply(sl1).add(sl1.multiply(cl1));
  718.             final FieldUnivariateDerivative2<T> cl3 = cl2.multiply(cl1).subtract(sl2.multiply(sl1));
  719.             final FieldUnivariateDerivative2<T> sl3 = cl2.multiply(sl1).add(sl2.multiply(cl1));
  720.             final FieldUnivariateDerivative2<T> cl4 = cl3.multiply(cl1).subtract(sl3.multiply(sl1));
  721.             final FieldUnivariateDerivative2<T> sl4 = cl3.multiply(sl1).add(sl3.multiply(cl1));
  722.             final FieldUnivariateDerivative2<T> cl5 = cl4.multiply(cl1).subtract(sl4.multiply(sl1));
  723.             final FieldUnivariateDerivative2<T> sl5 = cl4.multiply(sl1).add(sl4.multiply(cl1));
  724.             final FieldUnivariateDerivative2<T> cl6 = cl5.multiply(cl1).subtract(sl5.multiply(sl1));

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

  727.             final FieldUnivariateDerivative2<T> exmCl1 = exm.multiply(cl1);
  728.             final FieldUnivariateDerivative2<T> exmSl1 = exm.multiply(sl1);
  729.             final FieldUnivariateDerivative2<T> eymCl1 = eym.multiply(cl1);
  730.             final FieldUnivariateDerivative2<T> eymSl1 = eym.multiply(sl1);
  731.             final FieldUnivariateDerivative2<T> exmCl2 = exm.multiply(cl2);
  732.             final FieldUnivariateDerivative2<T> exmSl2 = exm.multiply(sl2);
  733.             final FieldUnivariateDerivative2<T> eymCl2 = eym.multiply(cl2);
  734.             final FieldUnivariateDerivative2<T> eymSl2 = eym.multiply(sl2);
  735.             final FieldUnivariateDerivative2<T> exmCl3 = exm.multiply(cl3);
  736.             final FieldUnivariateDerivative2<T> exmSl3 = exm.multiply(sl3);
  737.             final FieldUnivariateDerivative2<T> eymCl3 = eym.multiply(cl3);
  738.             final FieldUnivariateDerivative2<T> eymSl3 = eym.multiply(sl3);
  739.             final FieldUnivariateDerivative2<T> exmCl4 = exm.multiply(cl4);
  740.             final FieldUnivariateDerivative2<T> exmSl4 = exm.multiply(sl4);
  741.             final FieldUnivariateDerivative2<T> eymCl4 = eym.multiply(cl4);
  742.             final FieldUnivariateDerivative2<T> eymSl4 = eym.multiply(sl4);

  743.             // semi major axis
  744.             final FieldUnivariateDerivative2<T> rda = exmCl1.multiply(ax1).
  745.                                             add(eymSl1.multiply(ay1)).
  746.                                             add(sl1.multiply(as1)).
  747.                                             add(cl2.multiply(ac2)).
  748.                                             add(exmCl3.add(eymSl3).multiply(axy3)).
  749.                                             add(sl3.multiply(as3)).
  750.                                             add(cl4.multiply(ac4)).
  751.                                             add(sl5.multiply(as5)).
  752.                                             add(cl6.multiply(ac6));

  753.             // eccentricity
  754.             final FieldUnivariateDerivative2<T> rdex = cl1.multiply(ex1).
  755.                                              add(exmCl2.multiply(exx2)).
  756.                                              add(eymSl2.multiply(exy2)).
  757.                                              add(cl3.multiply(ex3)).
  758.                                              add(exmCl4.add(eymSl4).multiply(ex4));
  759.             final FieldUnivariateDerivative2<T> rdey = sl1.multiply(ey1).
  760.                                              add(exmSl2.multiply(eyx2)).
  761.                                              add(eymCl2.multiply(eyy2)).
  762.                                              add(sl3.multiply(ey3)).
  763.                                              add(exmSl4.subtract(eymCl4).multiply(ey4));

  764.             // ascending node
  765.             final FieldUnivariateDerivative2<T> rdom = exmSl1.multiply(rx1).
  766.                                              add(eymCl1.multiply(ry1)).
  767.                                              add(sl2.multiply(r2)).
  768.                                              add(eymCl3.subtract(exmSl3).multiply(r3)).
  769.                                              add(ql.multiply(rl));

  770.             // inclination
  771.             final FieldUnivariateDerivative2<T> rdxi = eymSl1.multiply(iy1).
  772.                                              add(exmCl1.multiply(ix1)).
  773.                                              add(cl2.multiply(i2)).
  774.                                              add(exmCl3.add(eymSl3).multiply(i3)).
  775.                                              add(qh.multiply(ih));

  776.             // latitude argument
  777.             final FieldUnivariateDerivative2<T> rdxl = exmSl1.multiply(lx1).
  778.                                              add(eymCl1.multiply(ly1)).
  779.                                              add(sl2.multiply(l2)).
  780.                                              add(exmSl3.subtract(eymCl3).multiply(l3)).
  781.                                              add(ql.multiply(ll));
  782.             // osculating parameters
  783.             final FieldUnivariateDerivative2<T>[] FTD = MathArrays.buildArray(rdxl.getField(), 6);

  784.             FTD[0] = rda.add(1.0).multiply(mean.getA());
  785.             FTD[1] = rdex.add(exm);
  786.             FTD[2] = rdey.add(eym);
  787.             FTD[3] = rdxi.add(xim);
  788.             FTD[4] = rdom.add(omm);
  789.             FTD[5] = rdxl.add(xlm);
  790.             return FTD;

  791.         }

  792.     }

  793.     /** Convert circular parameters <em>with derivatives</em> to Cartesian coordinates.
  794.      * @param date date of the parameters
  795.      * @param parameters circular parameters (a, ex, ey, i, raan, alphaM)
  796.      * @return Cartesian coordinates consistent with values and derivatives
  797.      */
  798.     private TimeStampedFieldPVCoordinates<T> toCartesian(final FieldAbsoluteDate<T> date, final FieldUnivariateDerivative2<T>[] parameters) {

  799.         // evaluate coordinates in the FieldOrbit canonical reference frame
  800.         final FieldUnivariateDerivative2<T> cosOmega = parameters[4].cos();
  801.         final FieldUnivariateDerivative2<T> sinOmega = parameters[4].sin();
  802.         final FieldUnivariateDerivative2<T> cosI     = parameters[3].cos();
  803.         final FieldUnivariateDerivative2<T> sinI     = parameters[3].sin();
  804.         final FieldUnivariateDerivative2<T> alphaE   = meanToEccentric(parameters[5], parameters[1], parameters[2]);
  805.         final FieldUnivariateDerivative2<T> cosAE    = alphaE.cos();
  806.         final FieldUnivariateDerivative2<T> sinAE    = alphaE.sin();
  807.         final FieldUnivariateDerivative2<T> ex2      = parameters[1].multiply(parameters[1]);
  808.         final FieldUnivariateDerivative2<T> ey2      = parameters[2].multiply(parameters[2]);
  809.         final FieldUnivariateDerivative2<T> exy      = parameters[1].multiply(parameters[2]);
  810.         final FieldUnivariateDerivative2<T> q        = ex2.add(ey2).subtract(1).negate().sqrt();
  811.         final FieldUnivariateDerivative2<T> beta     = q.add(1).reciprocal();
  812.         final FieldUnivariateDerivative2<T> bx2      = beta.multiply(ex2);
  813.         final FieldUnivariateDerivative2<T> by2      = beta.multiply(ey2);
  814.         final FieldUnivariateDerivative2<T> bxy      = beta.multiply(exy);
  815.         final FieldUnivariateDerivative2<T> u        = bxy.multiply(sinAE).subtract(parameters[1].add(by2.subtract(1).multiply(cosAE)));
  816.         final FieldUnivariateDerivative2<T> v        = bxy.multiply(cosAE).subtract(parameters[2].add(bx2.subtract(1).multiply(sinAE)));
  817.         final FieldUnivariateDerivative2<T> x        = parameters[0].multiply(u);
  818.         final FieldUnivariateDerivative2<T> y        = parameters[0].multiply(v);

  819.         // canonical FieldOrbit reference frame
  820.         final FieldVector3D<FieldUnivariateDerivative2<T>> p =
  821.                 new FieldVector3D<>(x.multiply(cosOmega).subtract(y.multiply(cosI.multiply(sinOmega))),
  822.                                     x.multiply(sinOmega).add(y.multiply(cosI.multiply(cosOmega))),
  823.                                     y.multiply(sinI));

  824.         // dispatch derivatives
  825.         final FieldVector3D<T> p0 = new FieldVector3D<>(p.getX().getValue(),
  826.                                                         p.getY().getValue(),
  827.                                                         p.getZ().getValue());
  828.         final FieldVector3D<T> p1 = new FieldVector3D<>(p.getX().getFirstDerivative(),
  829.                                                         p.getY().getFirstDerivative(),
  830.                                                         p.getZ().getFirstDerivative());
  831.         final FieldVector3D<T> p2 = new FieldVector3D<>(p.getX().getSecondDerivative(),
  832.                                                         p.getY().getSecondDerivative(),
  833.                                                         p.getZ().getSecondDerivative());
  834.         return new TimeStampedFieldPVCoordinates<>(date, p0, p1, p2);

  835.     }

  836.     /** Computes the eccentric latitude argument from the mean latitude argument.
  837.      * @param alphaM = M + Ω mean latitude argument (rad)
  838.      * @param ex e cos(Ω), first component of circular eccentricity vector
  839.      * @param ey e sin(Ω), second component of circular eccentricity vector
  840.      * @return the eccentric latitude argument.
  841.      */
  842.     private FieldUnivariateDerivative2<T> meanToEccentric(final FieldUnivariateDerivative2<T> alphaM,
  843.                                                 final FieldUnivariateDerivative2<T> ex,
  844.                                                 final FieldUnivariateDerivative2<T> ey) {
  845.         // Generalization of Kepler equation to circular parameters
  846.         // with alphaE = PA + E and
  847.         //      alphaM = PA + M = alphaE - ex.sin(alphaE) + ey.cos(alphaE)
  848.         FieldUnivariateDerivative2<T> alphaE        = alphaM;
  849.         FieldUnivariateDerivative2<T> shift         = alphaM.getField().getZero();
  850.         FieldUnivariateDerivative2<T> alphaEMalphaM = alphaM.getField().getZero();
  851.         FieldUnivariateDerivative2<T> cosAlphaE     = alphaE.cos();
  852.         FieldUnivariateDerivative2<T> sinAlphaE     = alphaE.sin();
  853.         int                 iter          = 0;
  854.         do {
  855.             final FieldUnivariateDerivative2<T> f2 = ex.multiply(sinAlphaE).subtract(ey.multiply(cosAlphaE));
  856.             final FieldUnivariateDerivative2<T> f1 = alphaM.getField().getOne().subtract(ex.multiply(cosAlphaE)).subtract(ey.multiply(sinAlphaE));
  857.             final FieldUnivariateDerivative2<T> f0 = alphaEMalphaM.subtract(f2);

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

  860.             alphaEMalphaM  = alphaEMalphaM.subtract(shift);
  861.             alphaE         = alphaM.add(alphaEMalphaM);
  862.             cosAlphaE      = alphaE.cos();
  863.             sinAlphaE      = alphaE.sin();

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

  865.         return alphaE;

  866.     }

  867.     /** {@inheritDoc} */
  868.     protected T getMass(final FieldAbsoluteDate<T> date) {
  869.         return models.get(date).mass;
  870.     }
  871.     /**
  872.      * Normalize an angle in a 2&pi; wide interval around a center value.
  873.      * <p>This method has three main uses:</p>
  874.      * <ul>
  875.      *   <li>normalize an angle between 0 and 2&pi;:<br>
  876.      *       {@code a = MathUtils.normalizeAngle(a, FastMath.PI);}</li>
  877.      *   <li>normalize an angle between -&pi; and +&pi;<br>
  878.      *       {@code a = MathUtils.normalizeAngle(a, 0.0);}</li>
  879.      *   <li>compute the angle between two defining angular positions:<br>
  880.      *       {@code angle = MathUtils.normalizeAngle(end, start) - start;}</li>
  881.      * </ul>
  882.      * <p>Note that due to numerical accuracy and since &pi; cannot be represented
  883.      * exactly, the result interval is <em>closed</em>, it cannot be half-closed
  884.      * as would be more satisfactory in a purely mathematical view.</p>
  885.      * @param a angle to normalize
  886.      * @param center center of the desired 2&pi; interval for the result
  887.      * @param <T> the type of the field elements
  888.      * @return a-2k&pi; with integer k and center-&pi; &lt;= a-2k&pi; &lt;= center+&pi;
  889.      * @since 1.2
  890.      * @deprecated replaced by {@link MathUtils#normalizeAngle(RealFieldElement, RealFieldElement)}
  891.      */
  892.     @Deprecated
  893.     public static <T extends RealFieldElement<T>> T normalizeAngle(final T a, final T center) {
  894.         return a.subtract(2 * FastMath.PI * FastMath.floor((a.getReal() + FastMath.PI - center.getReal()) / (2 * FastMath.PI)));
  895.     }

  896. }