FieldBrouwerLyddanePropagator.java

  1. /* Copyright 2002-2024 CS GROUP
  2.  * Licensed to CS GROUP (CS) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * CS licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *   http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.orekit.propagation.analytical;

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

  20. import org.hipparchus.CalculusFieldElement;
  21. import org.hipparchus.Field;
  22. import org.hipparchus.analysis.differentiation.FieldUnivariateDerivative1;
  23. import org.hipparchus.util.CombinatoricsUtils;
  24. import org.hipparchus.util.FastMath;
  25. import org.hipparchus.util.FieldSinCos;
  26. import org.hipparchus.util.MathUtils;
  27. import org.orekit.attitudes.AttitudeProvider;
  28. import org.orekit.attitudes.FrameAlignedProvider;
  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.FieldKeplerianOrbit;
  34. import org.orekit.orbits.FieldOrbit;
  35. import org.orekit.orbits.FieldKeplerianAnomalyUtility;
  36. import org.orekit.orbits.OrbitType;
  37. import org.orekit.orbits.PositionAngleType;
  38. import org.orekit.propagation.FieldSpacecraftState;
  39. import org.orekit.propagation.PropagationType;
  40. import org.orekit.propagation.analytical.tle.FieldTLE;
  41. import org.orekit.time.AbsoluteDate;
  42. import org.orekit.time.FieldAbsoluteDate;
  43. import org.orekit.utils.FieldTimeSpanMap;
  44. import org.orekit.utils.ParameterDriver;

  45. /** This class propagates a {@link org.orekit.propagation.FieldSpacecraftState}
  46.  *  using the analytical Brouwer-Lyddane model (from J2 to J5 zonal harmonics).
  47.  * <p>
  48.  * At the opposite of the {@link FieldEcksteinHechlerPropagator}, the Brouwer-Lyddane model is
  49.  * suited for elliptical orbits, there is no problem having a rather small eccentricity or inclination
  50.  * (Lyddane helped to solve this issue with the Brouwer model). Singularity for the critical
  51.  * inclination i = 63.4° is avoided using the method developed in Warren Phipps' 1992 thesis.
  52.  * <p>
  53.  * By default, Brouwer-Lyddane model considers only the perturbations due to zonal harmonics.
  54.  * However, for low Earth orbits, the magnitude of the perturbative acceleration due to
  55.  * atmospheric drag can be significant. Warren Phipps' 1992 thesis considered the atmospheric
  56.  * drag by time derivatives of the <i>mean</i> mean anomaly using the catch-all coefficient
  57.  * {@link #M2Driver}.
  58.  *
  59.  * Usually, M2 is adjusted during an orbit determination process and it represents the
  60.  * combination of all unmodeled secular along-track effects (i.e. not just the atmospheric drag).
  61.  * The behavior of M2 is close to the {@link FieldTLE#getBStar()} parameter for the TLE.
  62.  *
  63.  * If the value of M2 is equal to {@link BrouwerLyddanePropagator#M2 0.0}, the along-track secular
  64.  * effects are not considered in the dynamical model. Typical values for M2 are not known.
  65.  * It depends on the orbit type. However, the value of M2 must be very small (e.g. between 1.0e-14 and 1.0e-15).
  66.  * The unit of M2 is rad/s².
  67.  *
  68.  * The along-track effects, represented by the secular rates of the mean semi-major axis
  69.  * and eccentricity, are computed following Eq. 2.38, 2.41, and 2.45 of Warren Phipps' thesis.
  70.  *
  71.  * @see "Brouwer, Dirk. Solution of the problem of artificial satellite theory without drag.
  72.  *       YALE UNIV NEW HAVEN CT NEW HAVEN United States, 1959."
  73.  *
  74.  * @see "Lyddane, R. H. Small eccentricities or inclinations in the Brouwer theory of the
  75.  *       artificial satellite. The Astronomical Journal 68 (1963): 555."
  76.  *
  77.  * @see "Phipps Jr, Warren E. Parallelization of the Navy Space Surveillance Center
  78.  *       (NAVSPASUR) Satellite Model. NAVAL POSTGRADUATE SCHOOL MONTEREY CA, 1992."
  79.  *
  80.  * @author Melina Vanel
  81.  * @author Bryan Cazabonne
  82.  * @since 11.1
  83.  * @param <T> type of the field elements
  84.  */
  85. public class FieldBrouwerLyddanePropagator<T extends CalculusFieldElement<T>> extends FieldAbstractAnalyticalPropagator<T> {

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

  88.     /** Default value for maxIterations. */
  89.     private static final int MAX_ITERATIONS_DEFAULT = 200;

  90.     /** Parameters scaling factor.
  91.      * <p>
  92.      * We use a power of 2 to avoid numeric noise introduction
  93.      * in the multiplications/divisions sequences.
  94.      * </p>
  95.      */
  96.     private static final double SCALE = FastMath.scalb(1.0, -20);

  97.     /** Beta constant used by T2 function. */
  98.     private static final double BETA = FastMath.scalb(100, -11);

  99.     /** Initial Brouwer-Lyddane model. */
  100.     private FieldBLModel<T> initialModel;

  101.     /** All models. */
  102.     private transient FieldTimeSpanMap<FieldBLModel<T>, T> models;

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

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

  107.     /** Un-normalized zonal coefficients. */
  108.     private double[] ck0;

  109.     /** Empirical coefficient used in the drag modeling. */
  110.     private final ParameterDriver M2Driver;

  111.     /** Build a propagator from orbit and potential provider.
  112.      * <p>Mass and attitude provider are set to unspecified non-null arbitrary values.</p>
  113.      *
  114.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  115.      *
  116.      * @param initialOrbit initial orbit
  117.      * @param provider for un-normalized zonal coefficients
  118.      * @param M2 value of empirical drag coefficient in rad/s².
  119.      *        If equal to {@link BrouwerLyddanePropagator#M2} drag is not computed
  120.      * @see #FieldBrouwerLyddanePropagator(FieldOrbit, UnnormalizedSphericalHarmonicsProvider, PropagationType, double)
  121.      */
  122.     public FieldBrouwerLyddanePropagator(final FieldOrbit<T> initialOrbit,
  123.                                          final UnnormalizedSphericalHarmonicsProvider provider,
  124.                                          final double M2) {
  125.         this(initialOrbit, FrameAlignedProvider.of(initialOrbit.getFrame()),
  126.              initialOrbit.getMu().newInstance(DEFAULT_MASS), provider,
  127.              provider.onDate(initialOrbit.getDate().toAbsoluteDate()), M2);
  128.     }

  129.     /**
  130.      * Private helper constructor.
  131.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  132.      * @param initialOrbit initial orbit
  133.      * @param attitude attitude provider
  134.      * @param mass spacecraft mass
  135.      * @param provider for un-normalized zonal coefficients
  136.      * @param harmonics {@code provider.onDate(initialOrbit.getDate())}
  137.      * @param M2 value of empirical drag coefficient in rad/s².
  138.      *        If equal to {@link BrouwerLyddanePropagator#M2} drag is not computed
  139.      * @see #FieldBrouwerLyddanePropagator(FieldOrbit, AttitudeProvider, CalculusFieldElement,
  140.      * UnnormalizedSphericalHarmonicsProvider, UnnormalizedSphericalHarmonicsProvider.UnnormalizedSphericalHarmonics, PropagationType, double)
  141.      */
  142.     public FieldBrouwerLyddanePropagator(final FieldOrbit<T> initialOrbit,
  143.                                          final AttitudeProvider attitude,
  144.                                          final T mass,
  145.                                          final UnnormalizedSphericalHarmonicsProvider provider,
  146.                                          final UnnormalizedSphericalHarmonics harmonics,
  147.                                          final double M2) {
  148.         this(initialOrbit, attitude,  mass, provider.getAe(), initialOrbit.getMu().newInstance(provider.getMu()),
  149.              harmonics.getUnnormalizedCnm(2, 0),
  150.              harmonics.getUnnormalizedCnm(3, 0),
  151.              harmonics.getUnnormalizedCnm(4, 0),
  152.              harmonics.getUnnormalizedCnm(5, 0),
  153.              M2);
  154.     }

  155.     /** Build a propagator from orbit and potential.
  156.      * <p>Mass and attitude provider are set to unspecified non-null arbitrary values.</p>
  157.      * <p>The C<sub>n,0</sub> coefficients are the denormalized zonal coefficients, they
  158.      * are related to both the normalized coefficients
  159.      * <span style="text-decoration: overline">C</span><sub>n,0</sub>
  160.      *  and the J<sub>n</sub> one as follows:</p>
  161.      *
  162.      * <p> C<sub>n,0</sub> = [(2-δ<sub>0,m</sub>)(2n+1)(n-m)!/(n+m)!]<sup>½</sup>
  163.      * <span style="text-decoration: overline">C</span><sub>n,0</sub>
  164.      *
  165.      * <p> C<sub>n,0</sub> = -J<sub>n</sub>
  166.      *
  167.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  168.      *
  169.      * @param initialOrbit initial orbit
  170.      * @param referenceRadius reference radius of the Earth for the potential model (m)
  171.      * @param mu central attraction coefficient (m³/s²)
  172.      * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
  173.      * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
  174.      * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
  175.      * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
  176.      * @param M2 value of empirical drag coefficient in rad/s².
  177.      *        If equal to {@link BrouwerLyddanePropagator#M2} drag is not computed
  178.      * @see org.orekit.utils.Constants
  179.      * @see #FieldBrouwerLyddanePropagator(FieldOrbit, AttitudeProvider, double, CalculusFieldElement, double, double, double, double, double)
  180.      */
  181.     public FieldBrouwerLyddanePropagator(final FieldOrbit<T> initialOrbit,
  182.                                          final double referenceRadius, final T mu,
  183.                                          final double c20, final double c30, final double c40,
  184.                                          final double c50, final double M2) {
  185.         this(initialOrbit, FrameAlignedProvider.of(initialOrbit.getFrame()),
  186.              initialOrbit.getMu().newInstance(DEFAULT_MASS),
  187.              referenceRadius, mu, c20, c30, c40, c50, M2);
  188.     }

  189.     /** Build a propagator from orbit, mass and potential provider.
  190.      * <p>Attitude law is set to an unspecified non-null arbitrary value.</p>
  191.      *
  192.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  193.      *
  194.      * @param initialOrbit initial orbit
  195.      * @param mass spacecraft mass
  196.      * @param provider for un-normalized zonal coefficients
  197.      * @param M2 value of empirical drag coefficient in rad/s².
  198.      *        If equal to {@link BrouwerLyddanePropagator#M2} drag is not computed
  199.      * @see #FieldBrouwerLyddanePropagator(FieldOrbit, AttitudeProvider, CalculusFieldElement, UnnormalizedSphericalHarmonicsProvider, double)
  200.      */
  201.     public FieldBrouwerLyddanePropagator(final FieldOrbit<T> initialOrbit, final T mass,
  202.                                          final UnnormalizedSphericalHarmonicsProvider provider,
  203.                                          final double M2) {
  204.         this(initialOrbit, FrameAlignedProvider.of(initialOrbit.getFrame()),
  205.              mass, provider, provider.onDate(initialOrbit.getDate().toAbsoluteDate()), M2);
  206.     }

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

  240.     /** Build a propagator from orbit, attitude provider and potential provider.
  241.      * <p>Mass is set to an unspecified non-null arbitrary value.</p>
  242.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  243.      * @param initialOrbit initial orbit
  244.      * @param attitudeProv attitude provider
  245.      * @param provider for un-normalized zonal coefficients
  246.      * @param M2 value of empirical drag coefficient in rad/s².
  247.      *        If equal to {@link BrouwerLyddanePropagator#M2} drag is not computed
  248.      */
  249.     public FieldBrouwerLyddanePropagator(final FieldOrbit<T> initialOrbit,
  250.                                          final AttitudeProvider attitudeProv,
  251.                                          final UnnormalizedSphericalHarmonicsProvider provider,
  252.                                          final double M2) {
  253.         this(initialOrbit, attitudeProv, initialOrbit.getMu().newInstance(DEFAULT_MASS), provider,
  254.              provider.onDate(initialOrbit.getDate().toAbsoluteDate()), M2);
  255.     }

  256.     /** Build a propagator from orbit, attitude provider and potential.
  257.      * <p>Mass is set to an unspecified non-null arbitrary value.</p>
  258.      * <p>The C<sub>n,0</sub> coefficients are the denormalized zonal coefficients, they
  259.      * are related to both the normalized coefficients
  260.      * <span style="text-decoration: overline">C</span><sub>n,0</sub>
  261.      *  and the J<sub>n</sub> one as follows:</p>
  262.      *
  263.      * <p> C<sub>n,0</sub> = [(2-δ<sub>0,m</sub>)(2n+1)(n-m)!/(n+m)!]<sup>½</sup>
  264.      * <span style="text-decoration: overline">C</span><sub>n,0</sub>
  265.      *
  266.      * <p> C<sub>n,0</sub> = -J<sub>n</sub>
  267.      *
  268.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  269.      *
  270.      * @param initialOrbit initial orbit
  271.      * @param attitudeProv attitude provider
  272.      * @param referenceRadius reference radius of the Earth for the potential model (m)
  273.      * @param mu central attraction coefficient (m³/s²)
  274.      * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
  275.      * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
  276.      * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
  277.      * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
  278.      * @param M2 value of empirical drag coefficient in rad/s².
  279.      *        If equal to {@link BrouwerLyddanePropagator#M2} drag is not computed
  280.      */
  281.     public FieldBrouwerLyddanePropagator(final FieldOrbit<T> initialOrbit,
  282.                                          final AttitudeProvider attitudeProv,
  283.                                          final double referenceRadius, final T mu,
  284.                                          final double c20, final double c30, final double c40,
  285.                                          final double c50, final double M2) {
  286.         this(initialOrbit, attitudeProv, initialOrbit.getMu().newInstance(DEFAULT_MASS),
  287.              referenceRadius, mu, c20, c30, c40, c50, M2);
  288.     }

  289.     /** Build a propagator from orbit, attitude provider, mass and potential provider.
  290.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  291.      * @param initialOrbit initial orbit
  292.      * @param attitudeProv attitude provider
  293.      * @param mass spacecraft mass
  294.      * @param provider for un-normalized zonal coefficients
  295.      * @param M2 value of empirical drag coefficient in rad/s².
  296.      *        If equal to {@link BrouwerLyddanePropagator#M2} drag is not computed
  297.      * @see #FieldBrouwerLyddanePropagator(FieldOrbit, AttitudeProvider, CalculusFieldElement, UnnormalizedSphericalHarmonicsProvider, PropagationType, double)
  298.      */
  299.     public FieldBrouwerLyddanePropagator(final FieldOrbit<T> initialOrbit,
  300.                                          final AttitudeProvider attitudeProv,
  301.                                          final T mass,
  302.                                          final UnnormalizedSphericalHarmonicsProvider provider,
  303.                                          final double M2) {
  304.         this(initialOrbit, attitudeProv, mass, provider, provider.onDate(initialOrbit.getDate().toAbsoluteDate()), M2);
  305.     }

  306.     /** Build a propagator from orbit, attitude provider, mass and potential.
  307.      * <p>The C<sub>n,0</sub> coefficients are the denormalized zonal coefficients, they
  308.      * are related to both the normalized coefficients
  309.      * <span style="text-decoration: overline">C</span><sub>n,0</sub>
  310.      *  and the J<sub>n</sub> one as follows:</p>
  311.      *
  312.      * <p> C<sub>n,0</sub> = [(2-δ<sub>0,m</sub>)(2n+1)(n-m)!/(n+m)!]<sup>½</sup>
  313.      * <span style="text-decoration: overline">C</span><sub>n,0</sub>
  314.      *
  315.      * <p> C<sub>n,0</sub> = -J<sub>n</sub>
  316.      *
  317.      * <p>Using this constructor, an initial osculating orbit is considered.</p>
  318.      *
  319.      * @param initialOrbit initial orbit
  320.      * @param attitudeProv attitude provider
  321.      * @param mass spacecraft mass
  322.      * @param referenceRadius reference radius of the Earth for the potential model (m)
  323.      * @param mu central attraction coefficient (m³/s²)
  324.      * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
  325.      * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
  326.      * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
  327.      * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
  328.      * @param M2 value of empirical drag coefficient in rad/s².
  329.      *        If equal to {@link BrouwerLyddanePropagator#M2} drag is not computed
  330.      * @see #FieldBrouwerLyddanePropagator(FieldOrbit, AttitudeProvider, CalculusFieldElement, double, CalculusFieldElement, double, double, double, double, PropagationType, double)
  331.      */
  332.     public FieldBrouwerLyddanePropagator(final FieldOrbit<T> initialOrbit,
  333.                                          final AttitudeProvider attitudeProv,
  334.                                          final T mass,
  335.                                          final double referenceRadius, final T mu,
  336.                                          final double c20, final double c30, final double c40,
  337.                                          final double c50, final double M2) {
  338.         this(initialOrbit, attitudeProv, mass, referenceRadius, mu, c20, c30, c40, c50, PropagationType.OSCULATING, M2);
  339.     }


  340.     /** Build a propagator from orbit and potential provider.
  341.      * <p>Mass and attitude provider are set to unspecified non-null arbitrary values.</p>
  342.      *
  343.      * <p>Using this constructor, it is possible to define the initial orbit as
  344.      * a mean Brouwer-Lyddane orbit or an osculating one.</p>
  345.      *
  346.      * @param initialOrbit initial orbit
  347.      * @param provider for un-normalized zonal coefficients
  348.      * @param initialType initial orbit type (mean Brouwer-Lyddane orbit or osculating orbit)
  349.      * @param M2 value of empirical drag coefficient in rad/s².
  350.      *        If equal to {@link BrouwerLyddanePropagator#M2} drag is not computed
  351.      */
  352.     public FieldBrouwerLyddanePropagator(final FieldOrbit<T> initialOrbit,
  353.                                          final UnnormalizedSphericalHarmonicsProvider provider,
  354.                                          final PropagationType initialType,
  355.                                          final double M2) {
  356.         this(initialOrbit, FrameAlignedProvider.of(initialOrbit.getFrame()),
  357.              initialOrbit.getMu().newInstance(DEFAULT_MASS), provider,
  358.              provider.onDate(initialOrbit.getDate().toAbsoluteDate()), initialType, M2);
  359.     }

  360.     /** Build a propagator from orbit, attitude provider, mass and potential provider.
  361.      * <p>Using this constructor, it is possible to define the initial orbit as
  362.      * a mean Brouwer-Lyddane orbit or an osculating one.</p>
  363.      * @param initialOrbit initial orbit
  364.      * @param attitudeProv attitude provider
  365.      * @param mass spacecraft mass
  366.      * @param provider for un-normalized zonal coefficients
  367.      * @param initialType initial orbit type (mean Brouwer-Lyddane orbit or osculating orbit)
  368.      * @param M2 value of empirical drag coefficient in rad/s².
  369.      *        If equal to {@link BrouwerLyddanePropagator#M2} drag is not computed
  370.      */
  371.     public FieldBrouwerLyddanePropagator(final FieldOrbit<T> initialOrbit,
  372.                                          final AttitudeProvider attitudeProv,
  373.                                          final T mass,
  374.                                          final UnnormalizedSphericalHarmonicsProvider provider,
  375.                                          final PropagationType initialType,
  376.                                          final double M2) {
  377.         this(initialOrbit, attitudeProv, mass, provider, provider.onDate(initialOrbit.getDate().toAbsoluteDate()), initialType, M2);
  378.     }

  379.     /**
  380.      * Private helper constructor.
  381.      * <p>Using this constructor, it is possible to define the initial orbit as
  382.      * a mean Brouwer-Lyddane orbit or an osculating one.</p>
  383.      * @param initialOrbit initial orbit
  384.      * @param attitude attitude provider
  385.      * @param mass spacecraft mass
  386.      * @param provider for un-normalized zonal coefficients
  387.      * @param harmonics {@code provider.onDate(initialOrbit.getDate())}
  388.      * @param initialType initial orbit type (mean Brouwer-Lyddane orbit or osculating orbit)
  389.      * @param M2 value of empirical drag coefficient in rad/s².
  390.      *        If equal to {@link BrouwerLyddanePropagator#M2} drag is not computed
  391.      */
  392.     public FieldBrouwerLyddanePropagator(final FieldOrbit<T> initialOrbit,
  393.                                          final AttitudeProvider attitude,
  394.                                          final T mass,
  395.                                          final UnnormalizedSphericalHarmonicsProvider provider,
  396.                                          final UnnormalizedSphericalHarmonics harmonics,
  397.                                          final PropagationType initialType,
  398.                                          final double M2) {
  399.         this(initialOrbit, attitude, mass, provider.getAe(), initialOrbit.getMu().newInstance(provider.getMu()),
  400.              harmonics.getUnnormalizedCnm(2, 0),
  401.              harmonics.getUnnormalizedCnm(3, 0),
  402.              harmonics.getUnnormalizedCnm(4, 0),
  403.              harmonics.getUnnormalizedCnm(5, 0),
  404.              initialType, M2);
  405.     }

  406.     /** Build a propagator from orbit, attitude provider, mass and potential.
  407.      * <p>The C<sub>n,0</sub> coefficients are the denormalized zonal coefficients, they
  408.      * are related to both the normalized coefficients
  409.      * <span style="text-decoration: overline">C</span><sub>n,0</sub>
  410.      *  and the J<sub>n</sub> one as follows:</p>
  411.      *
  412.      * <p> C<sub>n,0</sub> = [(2-δ<sub>0,m</sub>)(2n+1)(n-m)!/(n+m)!]<sup>½</sup>
  413.      * <span style="text-decoration: overline">C</span><sub>n,0</sub>
  414.      *
  415.      * <p> C<sub>n,0</sub> = -J<sub>n</sub>
  416.      *
  417.      * <p>Using this constructor, it is possible to define the initial orbit as
  418.      * a mean Brouwer-Lyddane orbit or an osculating one.</p>
  419.      *
  420.      * @param initialOrbit initial orbit
  421.      * @param attitudeProv attitude provider
  422.      * @param mass spacecraft mass
  423.      * @param referenceRadius reference radius of the Earth for the potential model (m)
  424.      * @param mu central attraction coefficient (m³/s²)
  425.      * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
  426.      * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
  427.      * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
  428.      * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
  429.      * @param initialType initial orbit type (mean Brouwer-Lyddane orbit or osculating orbit)
  430.      * @param M2 value of empirical drag coefficient in rad/s².
  431.      *        If equal to {@link BrouwerLyddanePropagator#M2} drag is not computed
  432.      */
  433.     public FieldBrouwerLyddanePropagator(final FieldOrbit<T> initialOrbit,
  434.                                          final AttitudeProvider attitudeProv,
  435.                                          final T mass,
  436.                                          final double referenceRadius, final T mu,
  437.                                          final double c20, final double c30, final double c40,
  438.                                          final double c50,
  439.                                          final PropagationType initialType,
  440.                                          final double M2) {
  441.         this(initialOrbit, attitudeProv, mass, referenceRadius, mu,
  442.              c20, c30, c40, c50, initialType, M2, EPSILON_DEFAULT, MAX_ITERATIONS_DEFAULT);
  443.     }

  444.     /** Build a propagator from orbit, attitude provider, mass and potential.
  445.      * <p>The C<sub>n,0</sub> coefficients are the denormalized zonal coefficients, they
  446.      * are related to both the normalized coefficients
  447.      * <span style="text-decoration: overline">C</span><sub>n,0</sub>
  448.      *  and the J<sub>n</sub> one as follows:</p>
  449.      *
  450.      * <p> C<sub>n,0</sub> = [(2-δ<sub>0,m</sub>)(2n+1)(n-m)!/(n+m)!]<sup>½</sup>
  451.      * <span style="text-decoration: overline">C</span><sub>n,0</sub>
  452.      *
  453.      * <p> C<sub>n,0</sub> = -J<sub>n</sub>
  454.      *
  455.      * <p>Using this constructor, it is possible to define the initial orbit as
  456.      * a mean Brouwer-Lyddane orbit or an osculating one.</p>
  457.      *
  458.      * @param initialOrbit initial orbit
  459.      * @param attitudeProv attitude provider
  460.      * @param mass spacecraft mass
  461.      * @param referenceRadius reference radius of the Earth for the potential model (m)
  462.      * @param mu central attraction coefficient (m³/s²)
  463.      * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
  464.      * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
  465.      * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
  466.      * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
  467.      * @param initialType initial orbit type (mean Brouwer-Lyddane orbit or osculating orbit)
  468.      * @param M2 value of empirical drag coefficient in rad/s².
  469.      *        If equal to {@link BrouwerLyddanePropagator#M2} drag is not computed
  470.      * @param epsilon convergence threshold for mean parameters conversion
  471.      * @param maxIterations maximum iterations for mean parameters conversion
  472.      * @since 11.2
  473.      */
  474.     public FieldBrouwerLyddanePropagator(final FieldOrbit<T> initialOrbit,
  475.                                          final AttitudeProvider attitudeProv,
  476.                                          final T mass,
  477.                                          final double referenceRadius, final T mu,
  478.                                          final double c20, final double c30, final double c40,
  479.                                          final double c50,
  480.                                          final PropagationType initialType,
  481.                                          final double M2, final double epsilon, final int maxIterations) {

  482.         super(mass.getField(), attitudeProv);

  483.         // store model coefficients
  484.         this.referenceRadius = referenceRadius;
  485.         this.mu  = mu;
  486.         this.ck0 = new double[] {0.0, 0.0, c20, c30, c40, c50};

  487.         // initialize M2 driver
  488.         this.M2Driver = new ParameterDriver(BrouwerLyddanePropagator.M2_NAME, M2, SCALE,
  489.                                             Double.NEGATIVE_INFINITY,
  490.                                             Double.POSITIVE_INFINITY);

  491.         // compute mean parameters if needed
  492.         resetInitialState(new FieldSpacecraftState<>(initialOrbit,
  493.                                                  attitudeProv.getAttitude(initialOrbit,
  494.                                                                           initialOrbit.getDate(),
  495.                                                                           initialOrbit.getFrame()),
  496.                                                  mass),
  497.                                                  initialType, epsilon, maxIterations);

  498.     }

  499.     /** Conversion from osculating to mean orbit.
  500.      * <p>
  501.      * Compute mean orbit <b>in a Brouwer-Lyddane sense</b>, corresponding to the
  502.      * osculating SpacecraftState in input.
  503.      * </p>
  504.      * <p>
  505.      * Since the osculating orbit is obtained with the computation of
  506.      * short-periodic variation, the resulting output will depend on
  507.      * both the gravity field parameterized in input and the
  508.      * atmospheric drag represented by the {@code m2} parameter.
  509.      * </p>
  510.      * <p>
  511.      * The computation is done through a fixed-point iteration process.
  512.      * </p>
  513.      * @param <T> type of the filed elements
  514.      * @param osculating osculating orbit to convert
  515.      * @param provider for un-normalized zonal coefficients
  516.      * @param harmonics {@code provider.onDate(osculating.getDate())}
  517.      * @param M2Value value of empirical drag coefficient in rad/s².
  518.      *        If equal to {@code BrouwerLyddanePropagator.M2} drag is not considered
  519.      * @return mean orbit in a Brouwer-Lyddane sense
  520.      * @since 11.2
  521.      */
  522.     public static <T extends CalculusFieldElement<T>> FieldKeplerianOrbit<T> computeMeanOrbit(final FieldOrbit<T> osculating,
  523.                                                                                               final UnnormalizedSphericalHarmonicsProvider provider,
  524.                                                                                               final UnnormalizedSphericalHarmonics harmonics,
  525.                                                                                               final double M2Value) {
  526.         return computeMeanOrbit(osculating, provider, harmonics, M2Value, EPSILON_DEFAULT, MAX_ITERATIONS_DEFAULT);
  527.     }

  528.     /** Conversion from osculating to mean orbit.
  529.      * <p>
  530.      * Compute mean orbit <b>in a Brouwer-Lyddane sense</b>, corresponding to the
  531.      * osculating SpacecraftState in input.
  532.      * </p>
  533.      * <p>
  534.      * Since the osculating orbit is obtained with the computation of
  535.      * short-periodic variation, the resulting output will depend on
  536.      * both the gravity field parameterized in input and the
  537.      * atmospheric drag represented by the {@code m2} parameter.
  538.      * </p>
  539.      * <p>
  540.      * The computation is done through a fixed-point iteration process.
  541.      * </p>
  542.      * @param <T> type of the filed elements
  543.      * @param osculating osculating orbit to convert
  544.      * @param provider for un-normalized zonal coefficients
  545.      * @param harmonics {@code provider.onDate(osculating.getDate())}
  546.      * @param M2Value value of empirical drag coefficient in rad/s².
  547.      *        If equal to {@code BrouwerLyddanePropagator.M2} drag is not considered
  548.      * @param epsilon convergence threshold for mean parameters conversion
  549.      * @param maxIterations maximum iterations for mean parameters conversion
  550.      * @return mean orbit in a Brouwer-Lyddane sense
  551.      * @since 11.2
  552.      */
  553.     public static <T extends CalculusFieldElement<T>> FieldKeplerianOrbit<T> computeMeanOrbit(final FieldOrbit<T> osculating,
  554.                                                                                               final UnnormalizedSphericalHarmonicsProvider provider,
  555.                                                                                               final UnnormalizedSphericalHarmonics harmonics,
  556.                                                                                               final double M2Value,
  557.                                                                                               final double epsilon, final int maxIterations) {
  558.         return computeMeanOrbit(osculating,
  559.                                 provider.getAe(), provider.getMu(),
  560.                                 harmonics.getUnnormalizedCnm(2, 0),
  561.                                 harmonics.getUnnormalizedCnm(3, 0),
  562.                                 harmonics.getUnnormalizedCnm(4, 0),
  563.                                 harmonics.getUnnormalizedCnm(5, 0),
  564.                                 M2Value, epsilon, maxIterations);
  565.     }

  566.     /** Conversion from osculating to mean orbit.
  567.      * <p>
  568.      * Compute mean orbit <b>in a Brouwer-Lyddane sense</b>, corresponding to the
  569.      * osculating SpacecraftState in input.
  570.      * </p>
  571.      * <p>
  572.      * Since the osculating orbit is obtained with the computation of
  573.      * short-periodic variation, the resulting output will depend on
  574.      * both the gravity field parameterized in input and the
  575.      * atmospheric drag represented by the {@code m2} parameter.
  576.      * </p>
  577.      * <p>
  578.      * The computation is done through a fixed-point iteration process.
  579.      * </p>
  580.      * @param <T> type of the filed elements
  581.      * @param osculating osculating orbit to convert
  582.      * @param referenceRadius reference radius of the Earth for the potential model (m)
  583.      * @param mu central attraction coefficient (m³/s²)
  584.      * @param c20 un-normalized zonal coefficient (about -1.08e-3 for Earth)
  585.      * @param c30 un-normalized zonal coefficient (about +2.53e-6 for Earth)
  586.      * @param c40 un-normalized zonal coefficient (about +1.62e-6 for Earth)
  587.      * @param c50 un-normalized zonal coefficient (about +2.28e-7 for Earth)
  588.      * @param M2Value value of empirical drag coefficient in rad/s².
  589.      *        If equal to {@code BrouwerLyddanePropagator.M2} drag is not considered
  590.      * @param epsilon convergence threshold for mean parameters conversion
  591.      * @param maxIterations maximum iterations for mean parameters conversion
  592.      * @return mean orbit in a Brouwer-Lyddane sense
  593.      * @since 11.2
  594.      */
  595.     public static <T extends CalculusFieldElement<T>> FieldKeplerianOrbit<T> computeMeanOrbit(final FieldOrbit<T> osculating,
  596.                                                                                              final double referenceRadius, final double mu,
  597.                                                                                              final double c20, final double c30, final double c40,
  598.                                                                                              final double c50, final double M2Value,
  599.                                                                                              final double epsilon, final int maxIterations) {
  600.         final FieldBrouwerLyddanePropagator<T> propagator =
  601.                         new FieldBrouwerLyddanePropagator<>(osculating,
  602.                                                             FrameAlignedProvider.of(osculating.getFrame()),
  603.                                                             osculating.getMu().newInstance(DEFAULT_MASS),
  604.                                                             referenceRadius, osculating.getMu().newInstance(mu),
  605.                                                             c20, c30, c40, c50,
  606.                                                             PropagationType.OSCULATING, M2Value,
  607.                                                             epsilon, maxIterations);
  608.         return propagator.initialModel.mean;
  609.     }

  610.     /** {@inheritDoc}
  611.      * <p>The new initial state to consider
  612.      * must be defined with an osculating orbit.</p>
  613.      * @see #resetInitialState(FieldSpacecraftState, PropagationType)
  614.      */
  615.     @Override
  616.     public void resetInitialState(final FieldSpacecraftState<T> state) {
  617.         resetInitialState(state, PropagationType.OSCULATING);
  618.     }

  619.     /** Reset the propagator initial state.
  620.      * @param state new initial state to consider
  621.      * @param stateType mean Brouwer-Lyddane orbit or osculating orbit
  622.      */
  623.     public void resetInitialState(final FieldSpacecraftState<T> state, final PropagationType stateType) {
  624.         resetInitialState(state, stateType, EPSILON_DEFAULT, MAX_ITERATIONS_DEFAULT);
  625.     }

  626.     /** Reset the propagator initial state.
  627.      * @param state new initial state to consider
  628.      * @param stateType mean Brouwer-Lyddane orbit or osculating orbit
  629.      * @param epsilon convergence threshold for mean parameters conversion
  630.      * @param maxIterations maximum iterations for mean parameters conversion
  631.      * @since 11.2
  632.      */
  633.     public void resetInitialState(final FieldSpacecraftState<T> state, final PropagationType stateType,
  634.                                   final double epsilon, final int maxIterations) {
  635.         super.resetInitialState(state);
  636.         final FieldKeplerianOrbit<T> keplerian = (FieldKeplerianOrbit<T>) OrbitType.KEPLERIAN.convertType(state.getOrbit());
  637.         this.initialModel = (stateType == PropagationType.MEAN) ?
  638.                              new FieldBLModel<>(keplerian, state.getMass(), referenceRadius, mu, ck0) :
  639.                              computeMeanParameters(keplerian, state.getMass(), epsilon, maxIterations);
  640.         this.models = new FieldTimeSpanMap<>(initialModel, state.getA().getField());
  641.     }

  642.     /** {@inheritDoc} */
  643.     @Override
  644.     protected void resetIntermediateState(final FieldSpacecraftState<T> state, final boolean forward) {
  645.         resetIntermediateState(state, forward, EPSILON_DEFAULT, MAX_ITERATIONS_DEFAULT);
  646.     }

  647.     /** Reset an intermediate state.
  648.      * @param state new intermediate state to consider
  649.      * @param forward if true, the intermediate state is valid for
  650.      * propagations after itself
  651.      * @param epsilon convergence threshold for mean parameters conversion
  652.      * @param maxIterations maximum iterations for mean parameters conversion
  653.      * @since 11.2
  654.      */
  655.     protected void resetIntermediateState(final FieldSpacecraftState<T> state, final boolean forward,
  656.                                           final double epsilon, final int maxIterations) {
  657.         final FieldBLModel<T> newModel = computeMeanParameters((FieldKeplerianOrbit<T>) OrbitType.KEPLERIAN.convertType(state.getOrbit()),
  658.                                                                state.getMass(), epsilon, maxIterations);
  659.         if (forward) {
  660.             models.addValidAfter(newModel, state.getDate());
  661.         } else {
  662.             models.addValidBefore(newModel, state.getDate());
  663.         }
  664.         stateChanged(state);
  665.     }

  666.     /** Compute mean parameters according to the Brouwer-Lyddane analytical model computation
  667.      * in order to do the propagation.
  668.      * @param osculating osculating orbit
  669.      * @param mass constant mass
  670.      * @param epsilon convergence threshold for mean parameters conversion
  671.      * @param maxIterations maximum iterations for mean parameters conversion
  672.      * @return Brouwer-Lyddane mean model
  673.      */
  674.     private FieldBLModel<T> computeMeanParameters(final FieldKeplerianOrbit<T> osculating, final T mass,
  675.                                                   final double epsilon, final int maxIterations) {

  676.         // sanity check
  677.         if (osculating.getA().getReal() < referenceRadius) {
  678.             throw new OrekitException(OrekitMessages.TRAJECTORY_INSIDE_BRILLOUIN_SPHERE,
  679.                                            osculating.getA());
  680.         }

  681.         final Field<T> field = mass.getField();
  682.         final T one = field.getOne();
  683.         final T zero = field.getZero();
  684.         // rough initialization of the mean parameters
  685.         FieldBLModel<T> current = new FieldBLModel<>(osculating, mass, referenceRadius, mu, ck0);

  686.         // threshold for each parameter
  687.         final T thresholdA      = current.mean.getA().abs().add(1.0).multiply(epsilon);
  688.         final T thresholdE      = current.mean.getE().add(1.0).multiply(epsilon);
  689.         final T thresholdAngles = one.getPi().multiply(epsilon);

  690.         int i = 0;
  691.         while (i++ < maxIterations) {

  692.             // recompute the osculating parameters from the current mean parameters
  693.             final FieldKeplerianOrbit<T> parameters = current.propagateParameters(current.mean.getDate(), getParameters(mass.getField(), current.mean.getDate()));

  694.             // adapted parameters residuals
  695.             final T deltaA     = osculating.getA()  .subtract(parameters.getA());
  696.             final T deltaE     = osculating.getE()  .subtract(parameters.getE());
  697.             final T deltaI     = osculating.getI()  .subtract(parameters.getI());
  698.             final T deltaOmega = MathUtils.normalizeAngle(osculating.getPerigeeArgument().subtract(parameters.getPerigeeArgument()), zero);
  699.             final T deltaRAAN  = MathUtils.normalizeAngle(osculating.getRightAscensionOfAscendingNode().subtract(parameters.getRightAscensionOfAscendingNode()), zero);
  700.             final T deltaAnom  = MathUtils.normalizeAngle(osculating.getMeanAnomaly().subtract(parameters.getMeanAnomaly()), zero);


  701.             // update mean parameters
  702.             current = new FieldBLModel<>(new FieldKeplerianOrbit<>(current.mean.getA()            .add(deltaA),
  703.                                                      FastMath.max(current.mean.getE().add(deltaE), zero),
  704.                                                      current.mean.getI()                            .add(deltaI),
  705.                                                      current.mean.getPerigeeArgument()              .add(deltaOmega),
  706.                                                      current.mean.getRightAscensionOfAscendingNode().add(deltaRAAN),
  707.                                                      current.mean.getMeanAnomaly()                  .add(deltaAnom),
  708.                                                      PositionAngleType.MEAN, PositionAngleType.MEAN,
  709.                                                      current.mean.getFrame(),
  710.                                                      current.mean.getDate(), mu),
  711.                                   mass, referenceRadius, mu, ck0);
  712.             // check convergence
  713.             if (FastMath.abs(deltaA.getReal())     < thresholdA.getReal() &&
  714.                 FastMath.abs(deltaE.getReal())     < thresholdE.getReal() &&
  715.                 FastMath.abs(deltaI.getReal())     < thresholdAngles.getReal() &&
  716.                 FastMath.abs(deltaOmega.getReal()) < thresholdAngles.getReal() &&
  717.                 FastMath.abs(deltaRAAN.getReal())  < thresholdAngles.getReal() &&
  718.                 FastMath.abs(deltaAnom.getReal())  < thresholdAngles.getReal()) {
  719.                 return current;
  720.             }
  721.         }
  722.         throw new OrekitException(OrekitMessages.UNABLE_TO_COMPUTE_BROUWER_LYDDANE_MEAN_PARAMETERS, i);
  723.     }


  724.     /** {@inheritDoc} */
  725.     public FieldKeplerianOrbit<T> propagateOrbit(final FieldAbsoluteDate<T> date, final T[] parameters) {
  726.         // compute Cartesian parameters, taking derivatives into account
  727.         final FieldBLModel<T> current = models.get(date);
  728.         return current.propagateParameters(date, parameters);
  729.     }

  730.     /**
  731.      * Get the value of the M2 drag parameter.
  732.      * @return the value of the M2 drag parameter
  733.      */
  734.     public double getM2() {
  735.         return M2Driver.getValue();
  736.     }

  737.     /**
  738.      * Get the value of the M2 drag parameter.
  739.      * @param date date at which the model parameters want to be known
  740.      * @return the value of the M2 drag parameter
  741.      */
  742.     public double getM2(final AbsoluteDate date) {
  743.         return M2Driver.getValue(date);
  744.     }

  745.     /** Local class for Brouwer-Lyddane model. */
  746.     private static class FieldBLModel<T extends CalculusFieldElement<T>> {

  747.         /** Mean orbit. */
  748.         private final FieldKeplerianOrbit<T> mean;

  749.         /** Constant mass. */
  750.         private final T mass;

  751.         /** Central attraction coefficient. */
  752.         private final T mu;

  753.         // CHECKSTYLE: stop JavadocVariable check

  754.         // preprocessed values

  755.         // Constant for secular terms l'', g'', h''
  756.         // l standing for mean anomaly, g for perigee argument and h for raan
  757.         private final T xnotDot;
  758.         private final T n;
  759.         private final T lt;
  760.         private final T gt;
  761.         private final T ht;


  762.         // Long periodT
  763.         private final T dei3sg;
  764.         private final T de2sg;
  765.         private final T deisg;
  766.         private final T de;


  767.         private final T dlgs2g;
  768.         private final T dlgc3g;
  769.         private final T dlgcg;


  770.         private final T dh2sgcg;
  771.         private final T dhsgcg;
  772.         private final T dhcg;


  773.         // Short perioTs
  774.         private final T aC;
  775.         private final T aCbis;
  776.         private final T ac2g2f;


  777.         private final T eC;
  778.         private final T ecf;
  779.         private final T e2cf;
  780.         private final T e3cf;
  781.         private final T ec2f2g;
  782.         private final T ecfc2f2g;
  783.         private final T e2cfc2f2g;
  784.         private final T e3cfc2f2g;
  785.         private final T ec2gf;
  786.         private final T ec2g3f;


  787.         private final T ide;
  788.         private final T isfs2f2g;
  789.         private final T icfc2f2g;
  790.         private final T ic2f2g;


  791.         private final T glf;
  792.         private final T gll;
  793.         private final T glsf;
  794.         private final T glosf;
  795.         private final T gls2f2g;
  796.         private final T gls2gf;
  797.         private final T glos2gf;
  798.         private final T gls2g3f;
  799.         private final T glos2g3f;


  800.         private final T hf;
  801.         private final T hl;
  802.         private final T hsf;
  803.         private final T hcfs2g2f;
  804.         private final T hs2g2f;
  805.         private final T hsfc2g2f;


  806.         private final T edls2g;
  807.         private final T edlcg;
  808.         private final T edlc3g;
  809.         private final T edlsf;
  810.         private final T edls2gf;
  811.         private final T edls2g3f;

  812.         // Drag terms
  813.         private final T aRate;
  814.         private final T eRate;

  815.         // CHECKSTYLE: resume JavadocVariable check

  816.         /** Create a model for specified mean orbit.
  817.          * @param mean mean Fieldorbit
  818.          * @param mass constant mass
  819.          * @param referenceRadius reference radius of the central body attraction model (m)
  820.          * @param mu central attraction coefficient (m³/s²)
  821.          * @param ck0 un-normalized zonal coefficients
  822.          */
  823.         FieldBLModel(final FieldKeplerianOrbit<T> mean, final T mass,
  824.                 final double referenceRadius, final T mu, final double[] ck0) {

  825.             this.mean = mean;
  826.             this.mass = mass;
  827.             this.mu   = mu;
  828.             final T one  = mass.getField().getOne();

  829.             final T app = mean.getA();
  830.             xnotDot = mu.divide(app).sqrt().divide(app);

  831.             // preliminary processing
  832.             final T q = app.divide(referenceRadius).reciprocal();
  833.             T ql = q.square();
  834.             final T y2 = ql.multiply(-0.5 * ck0[2]);

  835.             n = ((mean.getE().square().negate()).add(1.0)).sqrt();
  836.             final T n2 = n.square();
  837.             final T n3 = n2.multiply(n);
  838.             final T n4 = n2.square();
  839.             final T n6 = n4.multiply(n2);
  840.             final T n8 = n4.square();
  841.             final T n10 = n8.multiply(n2);

  842.             final T yp2 = y2.divide(n4);
  843.             ql = ql.multiply(q);
  844.             final T yp3 = ql.multiply(ck0[3]).divide(n6);
  845.             ql = ql.multiply(q);
  846.             final T yp4 = ql.multiply(0.375 * ck0[4]).divide(n8);
  847.             ql = ql.multiply(q);
  848.             final T yp5 = ql.multiply(ck0[5]).divide(n10);


  849.             final FieldSinCos<T> sc = FastMath.sinCos(mean.getI());
  850.             final T sinI1 = sc.sin();
  851.             final T sinI2 = sinI1.square();
  852.             final T cosI1 = sc.cos();
  853.             final T cosI2 = cosI1.square();
  854.             final T cosI3 = cosI2.multiply(cosI1);
  855.             final T cosI4 = cosI2.square();
  856.             final T cosI6 = cosI4.multiply(cosI2);
  857.             final T C5c2 = T2(cosI1).reciprocal();
  858.             final T C3c2 = cosI2.multiply(3.0).subtract(1.0);

  859.             final T epp = mean.getE();
  860.             final T epp2 = epp.square();
  861.             final T epp3 = epp2.multiply(epp);
  862.             final T epp4 = epp2.square();

  863.             if (epp.getReal() >= 1) {
  864.                 // Only for elliptical (e < 1) orbits
  865.                 throw new OrekitException(OrekitMessages.TOO_LARGE_ECCENTRICITY_FOR_PROPAGATION_MODEL,
  866.                                           mean.getE().getReal());
  867.             }

  868.             // secular multiplicative
  869.             lt = one.add(yp2.multiply(n).multiply(C3c2).multiply(1.5)).
  870.                      add(yp2.multiply(0.09375).multiply(yp2).multiply(n).multiply(n2.multiply(25.0).add(n.multiply(16.0)).add(-15.0).
  871.                              add(cosI2.multiply(n2.multiply(-90.0).add(n.multiply(-96.0)).add(30.0))).
  872.                              add(cosI4.multiply(n2.multiply(25.0).add(n.multiply(144.0)).add(105.0))))).
  873.                      add(yp4.multiply(0.9375).multiply(n).multiply(epp2).multiply(cosI4.multiply(35.0).add(cosI2.multiply(-30.0)).add(3.0)));

  874.             gt = yp2.multiply(-1.5).multiply(C5c2).
  875.                      add(yp2.multiply(0.09375).multiply(yp2).multiply(n2.multiply(25.0).add(n.multiply(24.0)).add(-35.0).
  876.                             add(cosI2.multiply(n2.multiply(-126.0).add(n.multiply(-192.0)).add(90.0))).
  877.                             add(cosI4.multiply(n2.multiply(45.0).add(n.multiply(360.0)).add(385.0))))).
  878.                      add(yp4.multiply(0.3125).multiply(n2.multiply(-9.0).add(21.0).
  879.                             add(cosI2.multiply(n2.multiply(126.0).add(-270.0))).
  880.                             add(cosI4.multiply(n2.multiply(-189.0).add(385.0)))));

  881.             ht = yp2.multiply(-3.0).multiply(cosI1).
  882.                      add(yp2.multiply(0.375).multiply(yp2).multiply(cosI1.multiply(n2.multiply(9.0).add(n.multiply(12.0)).add(-5.0)).
  883.                                                                     add(cosI3.multiply(n2.multiply(-5.0).add(n.multiply(-36.0)).add(-35.0))))).
  884.                      add(yp4.multiply(1.25).multiply(cosI1).multiply(n2.multiply(-3.0).add(5.0)).multiply(cosI2.multiply(-7.0).add(3.0)));

  885.             final T cA = one.subtract(cosI2.multiply(11.0)).subtract(cosI4.multiply(40.0).divide(C5c2));
  886.             final T cB = one.subtract(cosI2.multiply(3.0)).subtract(cosI4.multiply(8.0).divide(C5c2));
  887.             final T cC = one.subtract(cosI2.multiply(9.0)).subtract(cosI4.multiply(24.0).divide(C5c2));
  888.             final T cD = one.subtract(cosI2.multiply(5.0)).subtract(cosI4.multiply(16.0).divide(C5c2));

  889.             final T qyp2_4 = yp2.multiply(3.0).multiply(yp2).multiply(cA).
  890.                              subtract(yp4.multiply(10.0).multiply(cB));
  891.             final T qyp52 = cosI1.multiply(epp3).multiply(cD.multiply(0.5).divide(sinI1).
  892.                                                           add(sinI1.multiply(cosI4.divide(C5c2).divide(C5c2).multiply(80.0).
  893.                                                                              add(cosI2.divide(C5c2).multiply(32.0).
  894.                                                                              add(5.0)))));
  895.             final T qyp22 = epp2.add(2.0).subtract(epp2.multiply(3.0).add(2.0).multiply(11.0).multiply(cosI2)).
  896.                             subtract(epp2.multiply(5.0).add(2.0).multiply(40.0).multiply(cosI4.divide(C5c2))).
  897.                             subtract(epp2.multiply(400.0).multiply(cosI6).divide(C5c2).divide(C5c2));
  898.             final T qyp42 = one.divide(5.0).multiply(qyp22.
  899.                                                      add(one.newInstance(4.0).multiply(epp2.
  900.                                                                                     add(2.0).
  901.                                                                                     subtract(cosI2.multiply(epp2.multiply(3.0).add(2.0))))));
  902.             final T qyp52bis = cosI1.multiply(sinI1).multiply(epp).multiply(epp2.multiply(3.0).add(4.0)).
  903.                                                                    multiply(cosI4.divide(C5c2).divide(C5c2).multiply(40.0).
  904.                                                                             add(cosI2.divide(C5c2).multiply(16.0)).
  905.                                                                             add(3.0));
  906.            // long periodic multiplicative
  907.             dei3sg =  yp5.divide(yp2).multiply(35.0 / 96.0).multiply(epp2).multiply(n2).multiply(cD).multiply(sinI1);
  908.             de2sg = qyp2_4.divide(yp2).multiply(epp).multiply(n2).multiply(-1.0 / 12.0);
  909.             deisg = sinI1.multiply(yp5.multiply(-35.0 / 128.0).divide(yp2).multiply(epp2).multiply(n2).multiply(cD).
  910.                             add(n2.multiply(0.25).divide(yp2).multiply(yp3.add(yp5.multiply(5.0 / 16.0).multiply(epp2.multiply(3.0).add(4.0)).multiply(cC)))));
  911.             de = epp2.multiply(n2).multiply(qyp2_4).divide(24.0).divide(yp2);

  912.             final T qyp52quotient = epp.multiply(epp4.multiply(81.0).add(-32.0)).divide(n.multiply(epp2.multiply(9.0).add(4.0)).add(epp2.multiply(3.0)).add(4.0));
  913.             dlgs2g = yp2.multiply(48.0).reciprocal().multiply(yp2.multiply(-3.0).multiply(yp2).multiply(qyp22).
  914.                             add(yp4.multiply(10.0).multiply(qyp42))).
  915.                             add(n3.divide(yp2).multiply(qyp2_4).divide(24.0));
  916.             dlgc3g =  yp5.multiply(35.0 / 384.0).divide(yp2).multiply(n3).multiply(epp).multiply(cD).multiply(sinI1).
  917.                             add(yp5.multiply(35.0 / 1152.0).divide(yp2).multiply(qyp52.multiply(2.0).multiply(cosI1).subtract(epp.multiply(cD).multiply(sinI1).multiply(epp2.multiply(2.0).add(3.0)))));
  918.             dlgcg = yp3.negate().multiply(cosI2).multiply(epp).divide(yp2.multiply(sinI1).multiply(4.0)).
  919.                     add(yp5.divide(yp2).multiply(0.078125).multiply(cC).multiply(cosI2.divide(sinI1).multiply(epp.negate()).multiply(epp2.multiply(3.0).add(4.0)).
  920.                                                                     add(sinI1.multiply(epp2).multiply(epp2.multiply(9.0).add(26.0)))).
  921.                     subtract(yp5.divide(yp2).multiply(0.46875).multiply(qyp52bis).multiply(cosI1)).
  922.                     add(yp3.divide(yp2).multiply(0.25).multiply(sinI1).multiply(epp).divide(n3.add(1.0)).multiply(epp2.multiply(epp2.subtract(3.0)).add(3.0))).
  923.                     add(yp5.divide(yp2).multiply(0.078125).multiply(n2).multiply(cC).multiply(qyp52quotient).multiply(sinI1)));
  924.             final T qyp24 = yp2.multiply(yp2).multiply(3.0).multiply(cosI4.divide(sinI2).multiply(200.0).add(cosI2.divide(sinI1).multiply(80.0)).add(11.0)).
  925.                             subtract(yp4.multiply(10.0).multiply(cosI4.divide(sinI2).multiply(40.0).add(cosI2.divide(sinI1).multiply(16.0)).add(3.0)));
  926.             dh2sgcg = yp5.divide(yp2).multiply(qyp52).multiply(35.0 / 144.0);
  927.             dhsgcg = qyp24.multiply(cosI1).multiply(epp2.negate()).divide(yp2.multiply(12.0));
  928.             dhcg = yp5.divide(yp2).multiply(qyp52).multiply(-35.0 / 576.0).
  929.                    add(cosI1.multiply(epp).divide(yp2.multiply(sinI1).multiply(4.0)).multiply(yp3.add(yp5.multiply(0.3125).multiply(cC).multiply(epp2.multiply(3.0).add(4.0))))).
  930.                    add(yp5.multiply(qyp52bis).multiply(1.875).divide(yp2.multiply(4.0)));

  931.             // short periodic multiplicative
  932.             aC = yp2.negate().multiply(C3c2).multiply(app).divide(n3);
  933.             aCbis = y2.multiply(app).multiply(C3c2);
  934.             ac2g2f = y2.multiply(app).multiply(sinI2).multiply(3.0);

  935.             T qe = y2.multiply(C3c2).multiply(0.5).multiply(n2).divide(n6);
  936.             eC = qe.multiply(epp).divide(n3.add(1.0)).multiply(epp2.multiply(epp2.subtract(3.0)).add(3.0));
  937.             ecf = qe.multiply(3.0);
  938.             e2cf = qe.multiply(3.0).multiply(epp);
  939.             e3cf = qe.multiply(epp2);
  940.             qe = y2.multiply(0.5).multiply(n2).multiply(3.0).multiply(cosI2.negate().add(1.0)).divide(n6);
  941.             ec2f2g = qe.multiply(epp);
  942.             ecfc2f2g = qe.multiply(3.0);
  943.             e2cfc2f2g = qe.multiply(3.0).multiply(epp);
  944.             e3cfc2f2g = qe.multiply(epp2);
  945.             qe = yp2.multiply(-0.5).multiply(n2).multiply(cosI2.negate().add(1.0));
  946.             ec2gf = qe.multiply(3.0);
  947.             ec2g3f = qe;

  948.             T qi = yp2.multiply(epp).multiply(cosI1).multiply(sinI1);
  949.             ide = cosI1.multiply(epp.negate()).divide(sinI1.multiply(n2));
  950.             isfs2f2g = qi;
  951.             icfc2f2g = qi.multiply(2.0);
  952.             qi = yp2.multiply(cosI1).multiply(sinI1);
  953.             ic2f2g = qi.multiply(1.5);

  954.             T qgl1 = yp2.multiply(0.25);
  955.             T qgl2 =  yp2.multiply(epp).multiply(n2).multiply(0.25).divide(n.add(1.0));
  956.             glf = qgl1.multiply(C5c2).multiply(-6.0);
  957.             gll = qgl1.multiply(C5c2).multiply(6.0);
  958.             glsf = qgl1.multiply(C5c2).multiply(-6.0).multiply(epp).
  959.                    add(qgl2.multiply(C3c2).multiply(2.0));
  960.             glosf = qgl2.multiply(C3c2).multiply(2.0);
  961.             qgl1 = qgl1.multiply(cosI2.multiply(-5.0).add(3.0));
  962.             qgl2 = qgl2.multiply(3.0).multiply(cosI2.negate().add(1.0));
  963.             gls2f2g = qgl1.multiply(3.0);
  964.             gls2gf = qgl1.multiply(3.0).multiply(epp).
  965.                      add(qgl2);
  966.             glos2gf = qgl2.negate();
  967.             gls2g3f = qgl1.multiply(epp).
  968.                       add(qgl2.multiply(1.0 / 3.0));
  969.             glos2g3f = qgl2;

  970.             final T qh = yp2.multiply(cosI1).multiply(3.0);
  971.             hf = qh.negate();
  972.             hl = qh;
  973.             hsf = qh.multiply(epp).negate();
  974.             hcfs2g2f = yp2.multiply(cosI1).multiply(epp).multiply(2.0);
  975.             hs2g2f = yp2.multiply(cosI1).multiply(1.5);
  976.             hsfc2g2f = yp2.multiply(cosI1).multiply(epp).negate();

  977.             final T qedl = yp2.multiply(n3).multiply(-0.25);
  978.             edls2g = qyp2_4.multiply(1.0 / 24.0).multiply(epp).multiply(n3).divide(yp2);
  979.             edlcg = yp3.divide(yp2).multiply(-0.25).multiply(n3).multiply(sinI1).
  980.                     subtract(yp5.divide(yp2).multiply(0.078125).multiply(n3).multiply(sinI1).multiply(cC).multiply(epp2.multiply(9.0).add(4.0)));
  981.             edlc3g = yp5.divide(yp2).multiply(n3).multiply(epp2).multiply(cD).multiply(sinI1).multiply(35.0 / 384.0);
  982.             edlsf = qedl.multiply(C3c2).multiply(2.0);
  983.             edls2gf = qedl.multiply(3.0).multiply(cosI2.negate().add(1.0));
  984.             edls2g3f = qedl.multiply(1.0 / 3.0);

  985.             // secular rates of the mean semi-major axis and eccentricity
  986.             // Eq. 2.41 and Eq. 2.45 of Phipps' 1992 thesis
  987.             aRate = app.multiply(-4.0).divide(xnotDot.multiply(3.0));
  988.             eRate = epp.multiply(n).multiply(n).multiply(-4.0).divide(xnotDot.multiply(3.0));

  989.         }

  990.         /**
  991.          * Gets eccentric anomaly from mean anomaly.
  992.          * @param mk the mean anomaly (rad)
  993.          * @return the eccentric anomaly (rad)
  994.          */
  995.         private FieldUnivariateDerivative1<T> getEccentricAnomaly(final FieldUnivariateDerivative1<T> mk) {

  996.             final T zero = mean.getE().getField().getZero();

  997.             // reduce M to [-PI PI] interval
  998.             final FieldUnivariateDerivative1<T> reducedM = new FieldUnivariateDerivative1<>(MathUtils.normalizeAngle(mk.getValue(), zero ),
  999.                                                                              mk.getFirstDerivative());

  1000.             final FieldUnivariateDerivative1<T> meanE = new FieldUnivariateDerivative1<>(mean.getE(), zero);
  1001.             FieldUnivariateDerivative1<T> ek = FieldKeplerianAnomalyUtility.ellipticMeanToEccentric(meanE, mk);

  1002.             // expand the result back to original range
  1003.             ek = ek.add(mk.getValue().subtract(reducedM.getValue()));

  1004.             // Returns the eccentric anomaly
  1005.             return ek;
  1006.         }

  1007.         /**
  1008.          * This method is used in Brouwer-Lyddane model to avoid singularity at the
  1009.          * critical inclination (i = 63.4°).
  1010.          * <p>
  1011.          * This method, based on Warren Phipps's 1992 thesis (Eq. 2.47 and 2.48),
  1012.          * approximate the factor (1.0 - 5.0 * cos²(inc))^-1 (causing the singularity)
  1013.          * by a function, named T2 in the thesis.
  1014.          * </p>
  1015.          * @param cosInc cosine of the mean inclination
  1016.          * @return an approximation of (1.0 - 5.0 * cos²(inc))^-1 term
  1017.          */
  1018.         private T T2(final T cosInc) {

  1019.             // X = (1.0 - 5.0 * cos²(inc))
  1020.             final T x  = cosInc.square().multiply(-5.0).add(1.0);
  1021.             final T x2 = x.square();

  1022.             // Eq. 2.48
  1023.             T sum = x.getField().getZero();
  1024.             for (int i = 0; i <= 12; i++) {
  1025.                 final double sign = i % 2 == 0 ? +1.0 : -1.0;
  1026.                 sum = sum.add(FastMath.pow(x2, i).multiply(FastMath.pow(BETA, i)).multiply(sign).divide(CombinatoricsUtils.factorialDouble(i + 1)));
  1027.             }

  1028.             // Right term of equation 2.47
  1029.             T product = x.getField().getOne();
  1030.             for (int i = 0; i <= 10; i++) {
  1031.                 product = product.multiply(FastMath.exp(x2.multiply(BETA).multiply(FastMath.scalb(-1.0, i))).add(1.0));
  1032.             }

  1033.             // Return (Eq. 2.47)
  1034.             return x.multiply(BETA).multiply(sum).multiply(product);

  1035.         }

  1036.         /** Extrapolate an orbit up to a specific target date.
  1037.          * @param date target date for the orbit
  1038.          * @param parameters model parameters
  1039.          * @return propagated parameters
  1040.          */
  1041.         public FieldKeplerianOrbit<T> propagateParameters(final FieldAbsoluteDate<T> date, final T[] parameters) {

  1042.             // Field
  1043.             final Field<T> field = date.getField();
  1044.             final T one  = field.getOne();
  1045.             final T zero = field.getZero();

  1046.             // Empirical drag coefficient M2
  1047.             final T m2 = parameters[0];

  1048.             // Keplerian evolution
  1049.             final FieldUnivariateDerivative1<T> dt = new FieldUnivariateDerivative1<>(date.durationFrom(mean.getDate()), one);
  1050.             final FieldUnivariateDerivative1<T> xnot = dt.multiply(xnotDot);

  1051.             //____________________________________
  1052.             // secular effects

  1053.             // mean mean anomaly
  1054.             final FieldUnivariateDerivative1<T> dtM2  = dt.multiply(m2);
  1055.             final FieldUnivariateDerivative1<T> dt2M2 = dt.multiply(dtM2);
  1056.             final FieldUnivariateDerivative1<T> lpp = new FieldUnivariateDerivative1<>(MathUtils.normalizeAngle(mean.getMeanAnomaly().add(lt.multiply(xnot.getValue())).add(dt2M2.getValue()), zero),
  1057.                                                                                         lt.multiply(xnotDot).add(dtM2.multiply(2.0).getValue()));
  1058.             // mean argument of perigee
  1059.             final FieldUnivariateDerivative1<T> gpp = new FieldUnivariateDerivative1<>(MathUtils.normalizeAngle(mean.getPerigeeArgument().add(gt.multiply(xnot.getValue())), zero),
  1060.                                                                                         gt.multiply(xnotDot));
  1061.             // mean longitude of ascending node
  1062.             final FieldUnivariateDerivative1<T> hpp = new FieldUnivariateDerivative1<>(MathUtils.normalizeAngle(mean.getRightAscensionOfAscendingNode().add(ht.multiply(xnot.getValue())), zero),
  1063.                                                                                         ht.multiply(xnotDot));

  1064.             // ________________________________________________
  1065.             // secular rates of the mean semi-major axis and eccentricity

  1066.             // semi-major axis
  1067.             final FieldUnivariateDerivative1<T> appDrag = dt.multiply(aRate.multiply(m2));

  1068.             // eccentricity
  1069.             final FieldUnivariateDerivative1<T> eppDrag = dt.multiply(eRate.multiply(m2));

  1070.             //____________________________________
  1071.             // Long periodical terms
  1072.             final FieldSinCos<FieldUnivariateDerivative1<T>> sinCosGpp = gpp.sinCos();
  1073.             final FieldUnivariateDerivative1<T> cg1 = sinCosGpp.cos();
  1074.             final FieldUnivariateDerivative1<T> sg1 = sinCosGpp.sin();
  1075.             final FieldUnivariateDerivative1<T> c2g = cg1.multiply(cg1).subtract(sg1.multiply(sg1));
  1076.             final FieldUnivariateDerivative1<T> s2g = cg1.multiply(sg1).add(sg1.multiply(cg1));
  1077.             final FieldUnivariateDerivative1<T> c3g = c2g.multiply(cg1).subtract(s2g.multiply(sg1));
  1078.             final FieldUnivariateDerivative1<T> sg2 = sg1.square();
  1079.             final FieldUnivariateDerivative1<T> sg3 = sg1.multiply(sg2);


  1080.             // de eccentricity
  1081.             final FieldUnivariateDerivative1<T> d1e = sg3.multiply(dei3sg).
  1082.                                                add(sg1.multiply(deisg)).
  1083.                                                add(sg2.multiply(de2sg)).
  1084.                                                add(de);

  1085.             // l' + g'
  1086.             final FieldUnivariateDerivative1<T> lpPGp = s2g.multiply(dlgs2g).
  1087.                                                add(c3g.multiply(dlgc3g)).
  1088.                                                add(cg1.multiply(dlgcg)).
  1089.                                                add(lpp).
  1090.                                                add(gpp);

  1091.             // h'
  1092.             final FieldUnivariateDerivative1<T> hp = sg2.multiply(cg1).multiply(dh2sgcg).
  1093.                                                add(sg1.multiply(cg1).multiply(dhsgcg)).
  1094.                                                add(cg1.multiply(dhcg)).
  1095.                                                add(hpp);

  1096.             // Short periodical terms
  1097.             // eccentric anomaly
  1098.             final FieldUnivariateDerivative1<T> Ep = getEccentricAnomaly(lpp);
  1099.             final FieldSinCos<FieldUnivariateDerivative1<T>> sinCosEp = Ep.sinCos();
  1100.             final FieldUnivariateDerivative1<T> cf1 = (sinCosEp.cos().subtract(mean.getE())).divide(sinCosEp.cos().multiply(mean.getE().negate()).add(1.0));
  1101.             final FieldUnivariateDerivative1<T> sf1 = (sinCosEp.sin().multiply(n)).divide(sinCosEp.cos().multiply(mean.getE().negate()).add(1.0));
  1102.             final FieldUnivariateDerivative1<T> f = FastMath.atan2(sf1, cf1);

  1103.             final FieldUnivariateDerivative1<T> cf2 = cf1.square();
  1104.             final FieldUnivariateDerivative1<T> c2f = cf2.subtract(sf1.multiply(sf1));
  1105.             final FieldUnivariateDerivative1<T> s2f = cf1.multiply(sf1).add(sf1.multiply(cf1));
  1106.             final FieldUnivariateDerivative1<T> c3f = c2f.multiply(cf1).subtract(s2f.multiply(sf1));
  1107.             final FieldUnivariateDerivative1<T> s3f = c2f.multiply(sf1).add(s2f.multiply(cf1));
  1108.             final FieldUnivariateDerivative1<T> cf3 = cf1.multiply(cf2);

  1109.             final FieldUnivariateDerivative1<T> c2g1f = cf1.multiply(c2g).subtract(sf1.multiply(s2g));
  1110.             final FieldUnivariateDerivative1<T> c2g2f = c2f.multiply(c2g).subtract(s2f.multiply(s2g));
  1111.             final FieldUnivariateDerivative1<T> c2g3f = c3f.multiply(c2g).subtract(s3f.multiply(s2g));
  1112.             final FieldUnivariateDerivative1<T> s2g1f = cf1.multiply(s2g).add(c2g.multiply(sf1));
  1113.             final FieldUnivariateDerivative1<T> s2g2f = c2f.multiply(s2g).add(c2g.multiply(s2f));
  1114.             final FieldUnivariateDerivative1<T> s2g3f = c3f.multiply(s2g).add(c2g.multiply(s3f));

  1115.             final FieldUnivariateDerivative1<T> eE = (sinCosEp.cos().multiply(mean.getE().negate()).add(1.0)).reciprocal();
  1116.             final FieldUnivariateDerivative1<T> eE3 = eE.square().multiply(eE);
  1117.             final FieldUnivariateDerivative1<T> sigma = eE.multiply(n.square()).multiply(eE).add(eE);

  1118.             // Semi-major axis
  1119.             final FieldUnivariateDerivative1<T> a = eE3.multiply(aCbis).add(appDrag.add(mean.getA())).
  1120.                                             add(aC).
  1121.                                             add(eE3.multiply(c2g2f).multiply(ac2g2f));

  1122.             // Eccentricity
  1123.             final FieldUnivariateDerivative1<T> e = d1e.add(eppDrag.add(mean.getE())).
  1124.                                             add(eC).
  1125.                                             add(cf1.multiply(ecf)).
  1126.                                             add(cf2.multiply(e2cf)).
  1127.                                             add(cf3.multiply(e3cf)).
  1128.                                             add(c2g2f.multiply(ec2f2g)).
  1129.                                             add(c2g2f.multiply(cf1).multiply(ecfc2f2g)).
  1130.                                             add(c2g2f.multiply(cf2).multiply(e2cfc2f2g)).
  1131.                                             add(c2g2f.multiply(cf3).multiply(e3cfc2f2g)).
  1132.                                             add(c2g1f.multiply(ec2gf)).
  1133.                                             add(c2g3f.multiply(ec2g3f));

  1134.             // Inclination
  1135.             final FieldUnivariateDerivative1<T> i = d1e.multiply(ide).
  1136.                                             add(mean.getI()).
  1137.                                             add(sf1.multiply(s2g2f.multiply(isfs2f2g))).
  1138.                                             add(cf1.multiply(c2g2f.multiply(icfc2f2g))).
  1139.                                             add(c2g2f.multiply(ic2f2g));

  1140.             // Argument of perigee + mean anomaly
  1141.             final FieldUnivariateDerivative1<T> gPL = lpPGp.add(f.multiply(glf)).
  1142.                                              add(lpp.multiply(gll)).
  1143.                                              add(sf1.multiply(glsf)).
  1144.                                              add(sigma.multiply(sf1).multiply(glosf)).
  1145.                                              add(s2g2f.multiply(gls2f2g)).
  1146.                                              add(s2g1f.multiply(gls2gf)).
  1147.                                              add(sigma.multiply(s2g1f).multiply(glos2gf)).
  1148.                                              add(s2g3f.multiply(gls2g3f)).
  1149.                                              add(sigma.multiply(s2g3f).multiply(glos2g3f));

  1150.             // Longitude of ascending node
  1151.             final FieldUnivariateDerivative1<T> h = hp.add(f.multiply(hf)).
  1152.                                             add(lpp.multiply(hl)).
  1153.                                             add(sf1.multiply(hsf)).
  1154.                                             add(cf1.multiply(s2g2f).multiply(hcfs2g2f)).
  1155.                                             add(s2g2f.multiply(hs2g2f)).
  1156.                                             add(c2g2f.multiply(sf1).multiply(hsfc2g2f));

  1157.             final FieldUnivariateDerivative1<T> edl = s2g.multiply(edls2g).
  1158.                                             add(cg1.multiply(edlcg)).
  1159.                                             add(c3g.multiply(edlc3g)).
  1160.                                             add(sf1.multiply(edlsf)).
  1161.                                             add(s2g1f.multiply(edls2gf)).
  1162.                                             add(s2g3f.multiply(edls2g3f)).
  1163.                                             add(sf1.multiply(sigma).multiply(edlsf)).
  1164.                                             add(s2g1f.multiply(sigma).multiply(edls2gf.negate())).
  1165.                                             add(s2g3f.multiply(sigma).multiply(edls2g3f.multiply(3.0)));

  1166.             final FieldUnivariateDerivative1<T> A = e.multiply(lpp.cos()).subtract(edl.multiply(lpp.sin()));
  1167.             final FieldUnivariateDerivative1<T> B = e.multiply(lpp.sin()).add(edl.multiply(lpp.cos()));

  1168.             // Mean anomaly
  1169.             final FieldUnivariateDerivative1<T> l = FastMath.atan2(B, A);

  1170.             // Argument of perigee
  1171.             final FieldUnivariateDerivative1<T> g = gPL.subtract(l);

  1172.             // Return a Keplerian orbit
  1173.             return new FieldKeplerianOrbit<>(a.getValue(), e.getValue(), i.getValue(),
  1174.                                              g.getValue(), h.getValue(), l.getValue(),
  1175.                                              a.getFirstDerivative(), e.getFirstDerivative(), i.getFirstDerivative(),
  1176.                                              g.getFirstDerivative(), h.getFirstDerivative(), l.getFirstDerivative(),
  1177.                                              PositionAngleType.MEAN, mean.getFrame(), date, this.mu);

  1178.         }
  1179.     }

  1180.     /** {@inheritDoc} */
  1181.     @Override
  1182.     protected T getMass(final FieldAbsoluteDate<T> date) {
  1183.         return models.get(date).mass;
  1184.     }

  1185.     /** {@inheritDoc} */
  1186.     @Override
  1187.     public List<ParameterDriver> getParametersDrivers() {
  1188.         return Collections.singletonList(M2Driver);
  1189.     }

  1190. }