DSSTZonal.java

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

  18. import java.lang.reflect.Array;
  19. import java.util.ArrayList;
  20. import java.util.Arrays;
  21. import java.util.Collections;
  22. import java.util.HashMap;
  23. import java.util.List;
  24. import java.util.Map;
  25. import java.util.Set;
  26. import java.util.SortedMap;

  27. import org.hipparchus.CalculusFieldElement;
  28. import org.hipparchus.Field;
  29. import org.hipparchus.exception.LocalizedCoreFormats;
  30. import org.hipparchus.util.CombinatoricsUtils;
  31. import org.hipparchus.util.FastMath;
  32. import org.hipparchus.util.FieldSinCos;
  33. import org.hipparchus.util.MathArrays;
  34. import org.hipparchus.util.SinCos;
  35. import org.orekit.attitudes.AttitudeProvider;
  36. import org.orekit.errors.OrekitException;
  37. import org.orekit.errors.OrekitInternalError;
  38. import org.orekit.forces.gravity.potential.UnnormalizedSphericalHarmonicsProvider;
  39. import org.orekit.forces.gravity.potential.UnnormalizedSphericalHarmonicsProvider.UnnormalizedSphericalHarmonics;
  40. import org.orekit.frames.Frame;
  41. import org.orekit.orbits.FieldOrbit;
  42. import org.orekit.orbits.Orbit;
  43. import org.orekit.propagation.FieldSpacecraftState;
  44. import org.orekit.propagation.PropagationType;
  45. import org.orekit.propagation.SpacecraftState;
  46. import org.orekit.propagation.semianalytical.dsst.utilities.AuxiliaryElements;
  47. import org.orekit.propagation.semianalytical.dsst.utilities.CjSjCoefficient;
  48. import org.orekit.propagation.semianalytical.dsst.utilities.CoefficientsFactory;
  49. import org.orekit.propagation.semianalytical.dsst.utilities.CoefficientsFactory.NSKey;
  50. import org.orekit.propagation.semianalytical.dsst.utilities.FieldAuxiliaryElements;
  51. import org.orekit.propagation.semianalytical.dsst.utilities.FieldCjSjCoefficient;
  52. import org.orekit.propagation.semianalytical.dsst.utilities.FieldGHIJjsPolynomials;
  53. import org.orekit.propagation.semianalytical.dsst.utilities.FieldLnsCoefficients;
  54. import org.orekit.propagation.semianalytical.dsst.utilities.FieldShortPeriodicsInterpolatedCoefficient;
  55. import org.orekit.propagation.semianalytical.dsst.utilities.GHIJjsPolynomials;
  56. import org.orekit.propagation.semianalytical.dsst.utilities.LnsCoefficients;
  57. import org.orekit.propagation.semianalytical.dsst.utilities.ShortPeriodicsInterpolatedCoefficient;
  58. import org.orekit.propagation.semianalytical.dsst.utilities.UpperBounds;
  59. import org.orekit.propagation.semianalytical.dsst.utilities.hansen.FieldHansenZonalLinear;
  60. import org.orekit.propagation.semianalytical.dsst.utilities.hansen.HansenZonalLinear;
  61. import org.orekit.time.AbsoluteDate;
  62. import org.orekit.time.FieldAbsoluteDate;
  63. import org.orekit.utils.FieldTimeSpanMap;
  64. import org.orekit.utils.ParameterDriver;
  65. import org.orekit.utils.TimeSpanMap;

  66. /** Zonal contribution to the central body gravitational perturbation.
  67.  *
  68.  *   @author Romain Di Costanzo
  69.  *   @author Pascal Parraud
  70.  *   @author Bryan Cazabonne (field translation)
  71.  */
  72. public class DSSTZonal implements DSSTForceModel {

  73.     /**  Name of the prefix for short period coefficients keys. */
  74.     public static final String SHORT_PERIOD_PREFIX = "DSST-central-body-zonal-";

  75.     /** Retrograde factor I.
  76.      *  <p>
  77.      *  DSST model needs equinoctial orbit as internal representation.
  78.      *  Classical equinoctial elements have discontinuities when inclination
  79.      *  is close to zero. In this representation, I = +1. <br>
  80.      *  To avoid this discontinuity, another representation exists and equinoctial
  81.      *  elements can be expressed in a different way, called "retrograde" orbit.
  82.      *  This implies I = -1. <br>
  83.      *  As Orekit doesn't implement the retrograde orbit, I is always set to +1.
  84.      *  But for the sake of consistency with the theory, the retrograde factor
  85.      *  has been kept in the formulas.
  86.      *  </p>
  87.      */
  88.     private static final int I = 1;

  89.     /** Number of points for interpolation. */
  90.     private static final int INTERPOLATION_POINTS = 3;

  91.     /** Truncation tolerance. */
  92.     private static final double TRUNCATION_TOLERANCE = 1e-4;

  93.     /** Central attraction scaling factor.
  94.      * <p>
  95.      * We use a power of 2 to avoid numeric noise introduction
  96.      * in the multiplications/divisions sequences.
  97.      * </p>
  98.      */
  99.     private static final double MU_SCALE = FastMath.scalb(1.0, 32);

  100.     /** Coefficient used to define the mean disturbing function V<sub>ns</sub> coefficient. */
  101.     private final SortedMap<NSKey, Double> Vns;

  102.     /** Provider for spherical harmonics. */
  103.     private final UnnormalizedSphericalHarmonicsProvider provider;

  104.     /** Central body rotating frame (fixed with respect to body). */
  105.     private final Frame bodyFixedFrame;

  106.     /** Maximal degree to consider for harmonics potential. */
  107.     private final int maxDegree;

  108.     /** Maximal degree to consider for harmonics potential. */
  109.     private final int maxDegreeShortPeriodics;

  110.     /** Highest power of the eccentricity to be used in short periodic computations. */
  111.     private final int maxEccPowShortPeriodics;

  112.     /** Maximum frequency in true longitude for short periodic computations. */
  113.     private final int maxFrequencyShortPeriodics;

  114.     /** Highest power of the eccentricity to be used in mean elements computations. */
  115.     private int maxEccPowMeanElements;

  116.     /** Highest power of the eccentricity. */
  117.     private int maxEccPow;

  118.     /** Short period terms. */
  119.     private ZonalShortPeriodicCoefficients zonalSPCoefs;

  120.     /** Short period terms. */
  121.     private final Map<Field<?>, FieldZonalShortPeriodicCoefficients<?>> zonalFieldSPCoefs;

  122.     /** Driver for gravitational parameter. */
  123.     private final ParameterDriver gmParameterDriver;

  124.     /** Hansen objects. */
  125.     private HansenObjects hansen;

  126.     /** Hansen objects for field elements. */
  127.     private final Map<Field<?>, FieldHansenObjects<?>> fieldHansen;

  128.     /** Constructor with default reference values.
  129.      * <p>
  130.      * When this constructor is used, maximum allowed values are used
  131.      * for the short periodic coefficients:
  132.      * </p>
  133.      * <ul>
  134.      *    <li> {@link #maxDegreeShortPeriodics} is set to {@code provider.getMaxDegree()} </li>
  135.      *    <li> {@link #maxEccPowShortPeriodics} is set to {@code min(provider.getMaxDegree() - 1, 4)}.
  136.      *         This parameter should not exceed 4 as higher values will exceed computer capacity </li>
  137.      *    <li> {@link #maxFrequencyShortPeriodics} is set to {@code 2 * provider.getMaxDegree() + 1} </li>
  138.      * </ul>
  139.      * @param bodyFixedFrame rotating body frame
  140.      * <p>If set, this frame will be used to compute the Earth pole direction and the zonal contribution.
  141.      * If not, the inertial frame from the propagator will be used.<br>
  142.      * Ideally this frame should be always set to ITRF.
  143.      * However, using TOD is advised since it's generally a good trade-off between performance and precision.
  144.      *
  145.      * @param provider provider for spherical harmonics
  146.      * @since 12.1
  147.      */
  148.     public DSSTZonal(final Frame bodyFixedFrame, final UnnormalizedSphericalHarmonicsProvider provider) {
  149.         this(bodyFixedFrame, provider, provider.getMaxDegree(), FastMath.min(4, provider.getMaxDegree() - 1), 2 * provider.getMaxDegree() + 1);
  150.     }

  151.     /**
  152.      * Constructor with bodyFixedFrame = orbit frame, and default reference values.
  153.      * <p>
  154.      * Kept for compatibility with anterior versions.
  155.      * </p>
  156.      * <p>
  157.      * Setting bodyFixedFrame to null will lead to large errors if the orbit frame is far from Earth rotating frame (GCRF, EME2000...).
  158.      * The error gets smaller as the orbit frame gets closer to Earth rotating frame (MOD, then TOD).
  159.      * @see <a href="https://gitlab.orekit.org/orekit/orekit/-/issues/1104">issue-1104 on the forge</a>
  160.      * <p>
  161.      * When this constructor is used, maximum allowed values are used
  162.      * for the short periodic coefficients:
  163.      * </p>
  164.      * <ul>
  165.      *    <li> {@link #maxDegreeShortPeriodics} is set to {@code provider.getMaxDegree()} </li>
  166.      *    <li> {@link #maxEccPowShortPeriodics} is set to {@code min(provider.getMaxDegree() - 1, 4)}.
  167.      *         This parameter should not exceed 4 as higher values will exceed computer capacity </li>
  168.      *    <li> {@link #maxFrequencyShortPeriodics} is set to {@code 2 * provider.getMaxDegree() + 1} </li>
  169.      * </ul>
  170.      * @param provider provider for spherical harmonics
  171.      * @see <a href="https://gitlab.orekit.org/orekit/orekit/-/issues/1104">issue-1104 on the forge</a>
  172.      * @since 10.1
  173.      */
  174.     public DSSTZonal(final UnnormalizedSphericalHarmonicsProvider provider) {
  175.         this(null, provider);
  176.     }

  177.     /** Constructor.
  178.      * @param bodyFixedFrame rotating body frame
  179.      * <p>If set, this frame will be used to compute the Earth pole direction and the zonal contribution.
  180.      * If not, the inertial frame from the propagator will be used.<br>
  181.      * Ideally this frame should be always set to ITRF.
  182.      * However, using TOD is advised since it's a good trade-off between performance and precision.
  183.      *
  184.      * @param provider provider for spherical harmonics
  185.      * @param maxDegreeShortPeriodics maximum degree to consider for short periodics zonal harmonics potential
  186.      * (must be between 2 and {@code provider.getMaxDegree()})
  187.      * @param maxEccPowShortPeriodics maximum power of the eccentricity to be used in short periodic computations
  188.      * (must be between 0 and {@code maxDegreeShortPeriodics - 1}, but should typically not exceed 4 as higher
  189.      * values will exceed computer capacity)
  190.      * @param maxFrequencyShortPeriodics maximum frequency in true longitude for short periodic computations
  191.      * (must be between 1 and {@code 2 * maxDegreeShortPeriodics + 1})
  192.      * @since 12.1
  193.      */
  194.     public DSSTZonal(final Frame bodyFixedFrame,
  195.                      final UnnormalizedSphericalHarmonicsProvider provider,
  196.                      final int maxDegreeShortPeriodics,
  197.                      final int maxEccPowShortPeriodics,
  198.                      final int maxFrequencyShortPeriodics) {

  199.         gmParameterDriver = new ParameterDriver(DSSTNewtonianAttraction.CENTRAL_ATTRACTION_COEFFICIENT,
  200.                                                 provider.getMu(), MU_SCALE,
  201.                                                 0.0, Double.POSITIVE_INFINITY);

  202.         // Central body rotating frame
  203.         this.bodyFixedFrame = bodyFixedFrame;

  204.         // Vns coefficients
  205.         this.Vns = CoefficientsFactory.computeVns(provider.getMaxDegree() + 1);

  206.         this.provider  = provider;
  207.         this.maxDegree = provider.getMaxDegree();

  208.         checkIndexRange(maxDegreeShortPeriodics, 2, provider.getMaxDegree());
  209.         this.maxDegreeShortPeriodics = maxDegreeShortPeriodics;

  210.         checkIndexRange(maxEccPowShortPeriodics, 0, maxDegreeShortPeriodics - 1);
  211.         this.maxEccPowShortPeriodics = maxEccPowShortPeriodics;

  212.         checkIndexRange(maxFrequencyShortPeriodics, 1, 2 * maxDegreeShortPeriodics + 1);
  213.         this.maxFrequencyShortPeriodics = maxFrequencyShortPeriodics;

  214.         // Initialize default values
  215.         this.maxEccPowMeanElements = (maxDegree == 2) ? 0 : Integer.MIN_VALUE;

  216.         zonalFieldSPCoefs = new HashMap<>();
  217.         fieldHansen       = new HashMap<>();
  218.     }

  219.     /**
  220.      * Constructor with bodyFixedFrame = orbit frame.
  221.      * <p>
  222.      * Added for retro-compatibility with anterior versions for initialization.
  223.      * </p>
  224.      * <p>
  225.      * Setting bodyFixedFrame to null will lead to large errors if the orbit frame is far from Earth rotating frame (GCRF, EME2000...).
  226.      * The error gets smaller as the orbit frame gets closer to Earth rotating frame (MOD, then TOD).
  227.      * @see <a href="https://gitlab.orekit.org/orekit/orekit/-/issues/1104">issue-1104 on the forge</a>
  228.      * @param provider provider for spherical harmonics
  229.      * @param maxDegreeShortPeriodics maximum degree to consider for short periodics zonal harmonics potential
  230.      * (must be between 2 and {@code provider.getMaxDegree()})
  231.      * @param maxEccPowShortPeriodics maximum power of the eccentricity to be used in short periodic computations
  232.      * (must be between 0 and {@code maxDegreeShortPeriodics - 1}, but should typically not exceed 4 as higher
  233.      * values will exceed computer capacity)
  234.      * @param maxFrequencyShortPeriodics maximum frequency in true longitude for short periodic computations
  235.      * (must be between 1 and {@code 2 * maxDegreeShortPeriodics + 1})
  236.      * @see <a href="https://gitlab.orekit.org/orekit/orekit/-/issues/1104">issue-1104 on the forge</a>
  237.      * @since 7.2
  238.      */
  239.     public DSSTZonal(final UnnormalizedSphericalHarmonicsProvider provider,
  240.                      final int maxDegreeShortPeriodics,
  241.                      final int maxEccPowShortPeriodics,
  242.                      final int maxFrequencyShortPeriodics) {
  243.         this(null, provider, maxDegreeShortPeriodics, maxEccPowShortPeriodics, maxFrequencyShortPeriodics);
  244.     }

  245.     /** Check an index range.
  246.      * @param index index value
  247.      * @param min minimum value for index
  248.      * @param max maximum value for index
  249.      */
  250.     private void checkIndexRange(final int index, final int min, final int max) {
  251.         if (index < min || index > max) {
  252.             throw new OrekitException(LocalizedCoreFormats.OUT_OF_RANGE_SIMPLE, index, min, max);
  253.         }
  254.     }

  255.     /** Get the spherical harmonics provider.
  256.      *  @return the spherical harmonics provider
  257.      */
  258.     public UnnormalizedSphericalHarmonicsProvider getProvider() {
  259.         return provider;
  260.     }

  261.     /** {@inheritDoc}
  262.      *  <p>
  263.      *  Computes the highest power of the eccentricity to appear in the truncated
  264.      *  analytical power series expansion.
  265.      *  </p>
  266.      *  <p>
  267.      *  This method computes the upper value for the central body potential and
  268.      *  determines the maximal power for the eccentricity producing potential
  269.      *  terms bigger than a defined tolerance.
  270.      *  </p>
  271.      */
  272.     @Override
  273.     public List<ShortPeriodTerms> initializeShortPeriodTerms(final AuxiliaryElements auxiliaryElements,
  274.                                              final PropagationType type,
  275.                                              final double[] parameters) {

  276.         computeMeanElementsTruncations(auxiliaryElements, parameters);

  277.         switch (type) {
  278.             case MEAN:
  279.                 maxEccPow = maxEccPowMeanElements;
  280.                 break;
  281.             case OSCULATING:
  282.                 maxEccPow = FastMath.max(maxEccPowMeanElements, maxEccPowShortPeriodics);
  283.                 break;
  284.             default:
  285.                 throw new OrekitInternalError(null);
  286.         }

  287.         hansen = new HansenObjects();

  288.         final List<ShortPeriodTerms> list = new ArrayList<>();
  289.         zonalSPCoefs = new ZonalShortPeriodicCoefficients(maxFrequencyShortPeriodics,
  290.                                                           INTERPOLATION_POINTS,
  291.                                                           new TimeSpanMap<>(new Slot(maxFrequencyShortPeriodics, INTERPOLATION_POINTS)));
  292.         list.add(zonalSPCoefs);
  293.         return list;

  294.     }

  295.     /** {@inheritDoc}
  296.      *  <p>
  297.      *  Computes the highest power of the eccentricity to appear in the truncated
  298.      *  analytical power series expansion.
  299.      *  </p>
  300.      *  <p>
  301.      *  This method computes the upper value for the central body potential and
  302.      *  determines the maximal power for the eccentricity producing potential
  303.      *  terms bigger than a defined tolerance.
  304.      *  </p>
  305.      */
  306.     @Override
  307.     public <T extends CalculusFieldElement<T>> List<FieldShortPeriodTerms<T>> initializeShortPeriodTerms(final FieldAuxiliaryElements<T> auxiliaryElements,
  308.                                                                                      final PropagationType type,
  309.                                                                                      final T[] parameters) {

  310.         // Field used by default
  311.         final Field<T> field = auxiliaryElements.getDate().getField();
  312.         computeMeanElementsTruncations(auxiliaryElements, parameters, field);

  313.         switch (type) {
  314.             case MEAN:
  315.                 maxEccPow = maxEccPowMeanElements;
  316.                 break;
  317.             case OSCULATING:
  318.                 maxEccPow = FastMath.max(maxEccPowMeanElements, maxEccPowShortPeriodics);
  319.                 break;
  320.             default:
  321.                 throw new OrekitInternalError(null);
  322.         }

  323.         fieldHansen.put(field, new FieldHansenObjects<>(field));

  324.         final FieldZonalShortPeriodicCoefficients<T> fzspc =
  325.                         new FieldZonalShortPeriodicCoefficients<>(maxFrequencyShortPeriodics,
  326.                                                                   INTERPOLATION_POINTS,
  327.                                                                   new FieldTimeSpanMap<>(new FieldSlot<>(maxFrequencyShortPeriodics,
  328.                                                                                                          INTERPOLATION_POINTS),
  329.                                                                                          field));
  330.         zonalFieldSPCoefs.put(field, fzspc);
  331.         return Collections.singletonList(fzspc);

  332.     }

  333.     /** Compute indices truncations for mean elements computations.
  334.      * @param auxiliaryElements auxiliary elements
  335.      * @param parameters values of the force model parameters for state date (only 1 value for each parameter)
  336.      */
  337.     private void computeMeanElementsTruncations(final AuxiliaryElements auxiliaryElements, final double[] parameters) {

  338.         final DSSTZonalContext context = new DSSTZonalContext(auxiliaryElements, bodyFixedFrame, provider, parameters);
  339.         //Compute the max eccentricity power for the mean element rate expansion
  340.         if (maxDegree == 2) {
  341.             maxEccPowMeanElements = 0;
  342.         } else {
  343.             // Initializes specific parameters.
  344.             final UnnormalizedSphericalHarmonics harmonics = provider.onDate(auxiliaryElements.getDate());

  345.             // Utilities for truncation
  346.             final double ax2or = 2. * auxiliaryElements.getSma() / provider.getAe();
  347.             double xmuran = parameters[0] / auxiliaryElements.getSma();
  348.             // Set a lower bound for eccentricity
  349.             final double eo2  = FastMath.max(0.0025, auxiliaryElements.getEcc() / 2.);
  350.             final double x2o2 = context.getChi2() / 2.;
  351.             final double[] eccPwr = new double[maxDegree + 1];
  352.             final double[] chiPwr = new double[maxDegree + 1];
  353.             final double[] hafPwr = new double[maxDegree + 1];
  354.             eccPwr[0] = 1.;
  355.             chiPwr[0] = context.getChi();
  356.             hafPwr[0] = 1.;
  357.             for (int i = 1; i <= maxDegree; i++) {
  358.                 eccPwr[i] = eccPwr[i - 1] * eo2;
  359.                 chiPwr[i] = chiPwr[i - 1] * x2o2;
  360.                 hafPwr[i] = hafPwr[i - 1] * 0.5;
  361.                 xmuran  /= ax2or;
  362.             }

  363.             // Set highest power of e and degree of current spherical harmonic.
  364.             maxEccPowMeanElements = 0;
  365.             int maxDeg = maxDegree;
  366.             // Loop over n
  367.             do {
  368.                 // Set order of current spherical harmonic.
  369.                 int m = 0;
  370.                 // Loop over m
  371.                 do {
  372.                     // Compute magnitude of current spherical harmonic coefficient.
  373.                     final double cnm = harmonics.getUnnormalizedCnm(maxDeg, m);
  374.                     final double snm = harmonics.getUnnormalizedSnm(maxDeg, m);
  375.                     final double csnm = FastMath.hypot(cnm, snm);
  376.                     if (csnm == 0.) {
  377.                         break;
  378.                     }
  379.                     // Set magnitude of last spherical harmonic term.
  380.                     double lastTerm = 0.;
  381.                     // Set current power of e and related indices.
  382.                     int nsld2 = (maxDeg - maxEccPowMeanElements - 1) / 2;
  383.                     int l = maxDeg - 2 * nsld2;
  384.                     // Loop over l
  385.                     double term = 0.;
  386.                     do {
  387.                         // Compute magnitude of current spherical harmonic term.
  388.                         if (m < l) {
  389.                             term =  csnm * xmuran *
  390.                                     (CombinatoricsUtils.factorialDouble(maxDeg - l) / (CombinatoricsUtils.factorialDouble(maxDeg - m))) *
  391.                                     (CombinatoricsUtils.factorialDouble(maxDeg + l) / (CombinatoricsUtils.factorialDouble(nsld2) * CombinatoricsUtils.factorialDouble(nsld2 + l))) *
  392.                                     eccPwr[l] * UpperBounds.getDnl(context.getChi2(), chiPwr[l], maxDeg, l) *
  393.                                     (UpperBounds.getRnml(context.getGamma(), maxDeg, l, m, 1, I) + UpperBounds.getRnml(context.getGamma(), maxDeg, l, m, -1, I));
  394.                         } else {
  395.                             term =  csnm * xmuran *
  396.                                     (CombinatoricsUtils.factorialDouble(maxDeg + m) / (CombinatoricsUtils.factorialDouble(nsld2) * CombinatoricsUtils.factorialDouble(nsld2 + l))) *
  397.                                     eccPwr[l] * hafPwr[m - l] * UpperBounds.getDnl(context.getChi2(), chiPwr[l], maxDeg, l) *
  398.                                     (UpperBounds.getRnml(context.getGamma(), maxDeg, m, l, 1, I) + UpperBounds.getRnml(context.getGamma(), maxDeg, m, l, -1, I));
  399.                         }
  400.                         // Is the current spherical harmonic term bigger than the truncation tolerance ?
  401.                         if (term >= TRUNCATION_TOLERANCE) {
  402.                             maxEccPowMeanElements = l;
  403.                         } else {
  404.                             // Is the current term smaller than the last term ?
  405.                             if (term < lastTerm) {
  406.                                 break;
  407.                             }
  408.                         }
  409.                         // Proceed to next power of e.
  410.                         lastTerm = term;
  411.                         l += 2;
  412.                         nsld2--;
  413.                     } while (l < maxDeg);
  414.                     // Is the current spherical harmonic term bigger than the truncation tolerance ?
  415.                     if (term >= TRUNCATION_TOLERANCE) {
  416.                         maxEccPowMeanElements = FastMath.min(maxDegree - 2, maxEccPowMeanElements);
  417.                         return;
  418.                     }
  419.                     // Proceed to next order.
  420.                     m++;
  421.                 } while (m <= FastMath.min(maxDeg, provider.getMaxOrder()));
  422.                 // Proceed to next degree.
  423.                 xmuran *= ax2or;
  424.                 maxDeg--;
  425.             } while (maxDeg > maxEccPowMeanElements + 2);

  426.             maxEccPowMeanElements = FastMath.min(maxDegree - 2, maxEccPowMeanElements);
  427.         }
  428.     }

  429.     /** Compute indices truncations for mean elements computations.
  430.      * @param <T> type of the elements
  431.      * @param auxiliaryElements auxiliary elements
  432.      * @param parameters values of the force model parameters
  433.      * @param field field used by default
  434.      */
  435.     private <T extends CalculusFieldElement<T>> void computeMeanElementsTruncations(final FieldAuxiliaryElements<T> auxiliaryElements,
  436.                                                                                     final T[] parameters,
  437.                                                                                     final Field<T> field) {

  438.         final T zero = field.getZero();
  439.         final FieldDSSTZonalContext<T> context = new FieldDSSTZonalContext<>(auxiliaryElements, bodyFixedFrame, provider, parameters);
  440.         //Compute the max eccentricity power for the mean element rate expansion
  441.         if (maxDegree == 2) {
  442.             maxEccPowMeanElements = 0;
  443.         } else {
  444.             // Initializes specific parameters.
  445.             final UnnormalizedSphericalHarmonics harmonics = provider.onDate(auxiliaryElements.getDate().toAbsoluteDate());

  446.             // Utilities for truncation
  447.             final T ax2or = auxiliaryElements.getSma().multiply(2.).divide(provider.getAe());
  448.             T xmuran = parameters[0].divide(auxiliaryElements.getSma());
  449.             // Set a lower bound for eccentricity
  450.             final T eo2  = FastMath.max(zero.newInstance(0.0025), auxiliaryElements.getEcc().divide(2.));
  451.             final T x2o2 = context.getChi2().divide(2.);
  452.             final T[] eccPwr = MathArrays.buildArray(field, maxDegree + 1);
  453.             final T[] chiPwr = MathArrays.buildArray(field, maxDegree + 1);
  454.             final T[] hafPwr = MathArrays.buildArray(field, maxDegree + 1);
  455.             eccPwr[0] = zero.newInstance(1.);
  456.             chiPwr[0] = context.getChi();
  457.             hafPwr[0] = zero.newInstance(1.);
  458.             for (int i = 1; i <= maxDegree; i++) {
  459.                 eccPwr[i] = eccPwr[i - 1].multiply(eo2);
  460.                 chiPwr[i] = chiPwr[i - 1].multiply(x2o2);
  461.                 hafPwr[i] = hafPwr[i - 1].multiply(0.5);
  462.                 xmuran  = xmuran.divide(ax2or);
  463.             }

  464.             // Set highest power of e and degree of current spherical harmonic.
  465.             maxEccPowMeanElements = 0;
  466.             int maxDeg = maxDegree;
  467.             // Loop over n
  468.             do {
  469.                 // Set order of current spherical harmonic.
  470.                 int m = 0;
  471.                 // Loop over m
  472.                 do {
  473.                     // Compute magnitude of current spherical harmonic coefficient.
  474.                     final T cnm = zero.newInstance(harmonics.getUnnormalizedCnm(maxDeg, m));
  475.                     final T snm = zero.newInstance(harmonics.getUnnormalizedSnm(maxDeg, m));
  476.                     final T csnm = FastMath.hypot(cnm, snm);
  477.                     if (csnm.getReal() == 0.) {
  478.                         break;
  479.                     }
  480.                     // Set magnitude of last spherical harmonic term.
  481.                     T lastTerm = zero;
  482.                     // Set current power of e and related indices.
  483.                     int nsld2 = (maxDeg - maxEccPowMeanElements - 1) / 2;
  484.                     int l = maxDeg - 2 * nsld2;
  485.                     // Loop over l
  486.                     T term = zero;
  487.                     do {
  488.                         // Compute magnitude of current spherical harmonic term.
  489.                         if (m < l) {
  490.                             term = csnm.multiply(xmuran).
  491.                                    multiply((CombinatoricsUtils.factorialDouble(maxDeg - l) / (CombinatoricsUtils.factorialDouble(maxDeg - m))) *
  492.                                    (CombinatoricsUtils.factorialDouble(maxDeg + l) / (CombinatoricsUtils.factorialDouble(nsld2) * CombinatoricsUtils.factorialDouble(nsld2 + l)))).
  493.                                    multiply(eccPwr[l]).multiply(UpperBounds.getDnl(context.getChi2(), chiPwr[l], maxDeg, l)).
  494.                                    multiply(UpperBounds.getRnml(context.getGamma(), maxDeg, l, m, 1, I).add(UpperBounds.getRnml(context.getGamma(), maxDeg, l, m, -1, I)));
  495.                         } else {
  496.                             term = csnm.multiply(xmuran).
  497.                                    multiply(CombinatoricsUtils.factorialDouble(maxDeg + m) / (CombinatoricsUtils.factorialDouble(nsld2) * CombinatoricsUtils.factorialDouble(nsld2 + l))).
  498.                                    multiply(eccPwr[l]).multiply(hafPwr[m - l]).multiply(UpperBounds.getDnl(context.getChi2(), chiPwr[l], maxDeg, l)).
  499.                                    multiply(UpperBounds.getRnml(context.getGamma(), maxDeg, m, l, 1, I).add(UpperBounds.getRnml(context.getGamma(), maxDeg, m, l, -1, I)));
  500.                         }
  501.                         // Is the current spherical harmonic term bigger than the truncation tolerance ?
  502.                         if (term.getReal() >= TRUNCATION_TOLERANCE) {
  503.                             maxEccPowMeanElements = l;
  504.                         } else {
  505.                             // Is the current term smaller than the last term ?
  506.                             if (term.getReal() < lastTerm.getReal()) {
  507.                                 break;
  508.                             }
  509.                         }
  510.                         // Proceed to next power of e.
  511.                         lastTerm = term;
  512.                         l += 2;
  513.                         nsld2--;
  514.                     } while (l < maxDeg);
  515.                     // Is the current spherical harmonic term bigger than the truncation tolerance ?
  516.                     if (term.getReal() >= TRUNCATION_TOLERANCE) {
  517.                         maxEccPowMeanElements = FastMath.min(maxDegree - 2, maxEccPowMeanElements);
  518.                         return;
  519.                     }
  520.                     // Proceed to next order.
  521.                     m++;
  522.                 } while (m <= FastMath.min(maxDeg, provider.getMaxOrder()));
  523.                 // Proceed to next degree.
  524.                 xmuran = xmuran.multiply(ax2or);
  525.                 maxDeg--;
  526.             } while (maxDeg > maxEccPowMeanElements + 2);

  527.             maxEccPowMeanElements = FastMath.min(maxDegree - 2, maxEccPowMeanElements);
  528.         }
  529.     }

  530.     /** Performs initialization at each integration step for the current force model.
  531.      *  <p>
  532.      *  This method aims at being called before mean elements rates computation.
  533.      *  </p>
  534.      *  @param auxiliaryElements auxiliary elements related to the current orbit
  535.      *  @param parameters values of the force model parameters
  536.      *  @return new force model context
  537.      */
  538.     private DSSTZonalContext initializeStep(final AuxiliaryElements auxiliaryElements, final double[] parameters) {
  539.         return new DSSTZonalContext(auxiliaryElements, bodyFixedFrame, provider, parameters);
  540.     }

  541.     /** Performs initialization at each integration step for the current force model.
  542.      *  <p>
  543.      *  This method aims at being called before mean elements rates computation.
  544.      *  </p>
  545.      *  @param <T> type of the elements
  546.      *  @param auxiliaryElements auxiliary elements related to the current orbit
  547.      *  @param parameters values of the force model parameters
  548.      *  @return new force model context
  549.      */
  550.     private <T extends CalculusFieldElement<T>> FieldDSSTZonalContext<T> initializeStep(final FieldAuxiliaryElements<T> auxiliaryElements,
  551.                                                                                     final T[] parameters) {
  552.         return new FieldDSSTZonalContext<>(auxiliaryElements, bodyFixedFrame, provider, parameters);
  553.     }

  554.     /** {@inheritDoc} */
  555.     @Override
  556.     public double[] getMeanElementRate(final SpacecraftState spacecraftState,
  557.                                        final AuxiliaryElements auxiliaryElements, final double[] parameters) {

  558.         // Container of attributes

  559.         final DSSTZonalContext context = initializeStep(auxiliaryElements, parameters);
  560.         // Access to potential U derivatives
  561.         final UAnddU udu = new UAnddU(spacecraftState.getDate(), context, auxiliaryElements, hansen);

  562.         return computeMeanElementRates(context, udu);

  563.     }

  564.     /** {@inheritDoc} */
  565.     @Override
  566.     public <T extends CalculusFieldElement<T>> T[] getMeanElementRate(final FieldSpacecraftState<T> spacecraftState,
  567.                                                                   final FieldAuxiliaryElements<T> auxiliaryElements,
  568.                                                                   final T[] parameters) {

  569.         // Field used by default
  570.         final Field<T> field = auxiliaryElements.getDate().getField();
  571.         // Container of attributes
  572.         final FieldDSSTZonalContext<T> context = initializeStep(auxiliaryElements, parameters);

  573.         @SuppressWarnings("unchecked")
  574.         final FieldHansenObjects<T> fho = (FieldHansenObjects<T>) fieldHansen.get(field);

  575.         // Access to potential U derivatives
  576.         final FieldUAnddU<T> udu = new FieldUAnddU<>(spacecraftState.getDate(), context, auxiliaryElements, fho);

  577.         return computeMeanElementRates(spacecraftState.getDate(), context, udu);

  578.     }

  579.     /** Compute the mean element rates.
  580.      * @param context container for attributes
  581.      * @param udu derivatives of the gravitational potential U
  582.      * @return the mean element rates
  583.      */
  584.     private double[] computeMeanElementRates(final DSSTZonalContext context,
  585.                                              final UAnddU udu) {

  586.         // Auxiliary elements related to the current orbit
  587.         final AuxiliaryElements auxiliaryElements = context.getAuxiliaryElements();

  588.         // Compute cross derivatives [Eq. 2.2-(8)]
  589.         // U(alpha,gamma) = alpha * dU/dgamma - gamma * dU/dalpha
  590.         final double UAlphaGamma   = context.getAlpha() * udu.getdUdGa() - context.getGamma() * udu.getdUdAl();
  591.         // U(beta,gamma) = beta * dU/dgamma - gamma * dU/dbeta
  592.         final double UBetaGamma    =  context.getBeta() * udu.getdUdGa() - context.getGamma() * udu.getdUdBe();
  593.         // Common factor
  594.         final double pUAGmIqUBGoAB = (auxiliaryElements.getP() * UAlphaGamma - I * auxiliaryElements.getQ() * UBetaGamma) * context.getOoAB();

  595.         // Compute mean elements rates [Eq. 3.1-(1)]
  596.         final double da =  0.;
  597.         final double dh =  context.getBoA() * udu.getdUdk() + auxiliaryElements.getK() * pUAGmIqUBGoAB;
  598.         final double dk = -context.getBoA() * udu.getdUdh() - auxiliaryElements.getH() * pUAGmIqUBGoAB;
  599.         final double dp = -context.getCo2AB() * UBetaGamma;
  600.         final double dq = -context.getCo2AB() * UAlphaGamma * I;
  601.         final double dM = -context.getAx2oA() * udu.getdUda() + context.getBoABpo() * (auxiliaryElements.getH() * udu.getdUdh() + auxiliaryElements.getK() * udu.getdUdk()) + pUAGmIqUBGoAB;

  602.         return new double[] {da, dk, dh, dq, dp, dM};
  603.     }

  604.     /** Compute the mean element rates.
  605.      * @param <T> type of the elements
  606.      * @param date current date
  607.      * @param context container for attributes
  608.      * @param udu derivatives of the gravitational potential U
  609.      * @return the mean element rates
  610.      */
  611.     private <T extends CalculusFieldElement<T>> T[] computeMeanElementRates(final FieldAbsoluteDate<T> date,
  612.                                                                         final FieldDSSTZonalContext<T> context,
  613.                                                                         final FieldUAnddU<T> udu) {

  614.         // Auxiliary elements related to the current orbit
  615.         final FieldAuxiliaryElements<T> auxiliaryElements = context.getFieldAuxiliaryElements();

  616.         // Parameter for array building
  617.         final Field<T> field = date.getField();

  618.         // Compute cross derivatives [Eq. 2.2-(8)]
  619.         // U(alpha,gamma) = alpha * dU/dgamma - gamma * dU/dalpha
  620.         final T UAlphaGamma   = udu.getdUdGa().multiply(context.getAlpha()).subtract(udu.getdUdAl().multiply(context.getGamma()));
  621.         // U(beta,gamma) = beta * dU/dgamma - gamma * dU/dbeta
  622.         final T UBetaGamma    =  udu.getdUdGa().multiply(context.getBeta()).subtract(udu.getdUdBe().multiply(context.getGamma()));
  623.         // Common factor
  624.         final T pUAGmIqUBGoAB = (UAlphaGamma.multiply(auxiliaryElements.getP()).subtract(UBetaGamma.multiply(I).multiply(auxiliaryElements.getQ()))).multiply(context.getOoAB());

  625.         // Compute mean elements rates [Eq. 3.1-(1)]
  626.         final T da =  field.getZero();
  627.         final T dh =  udu.getdUdk().multiply(context.getBoA()).add(pUAGmIqUBGoAB.multiply(auxiliaryElements.getK()));
  628.         final T dk =  (udu.getdUdh().multiply(context.getBoA()).negate()).subtract(pUAGmIqUBGoAB.multiply(auxiliaryElements.getH()));
  629.         final T dp =  UBetaGamma.multiply(context.getCo2AB().negate());
  630.         final T dq =  UAlphaGamma.multiply(context.getCo2AB().negate()).multiply(I);
  631.         final T dM =  pUAGmIqUBGoAB.add(udu.getdUda().multiply(context.getAx2oA().negate())).add((udu.getdUdh().multiply(auxiliaryElements.getH()).add(udu.getdUdk().multiply(auxiliaryElements.getK()))).multiply(context.getBoABpo()));

  632.         final T[] elements =  MathArrays.buildArray(field, 6);
  633.         elements[0] = da;
  634.         elements[1] = dk;
  635.         elements[2] = dh;
  636.         elements[3] = dq;
  637.         elements[4] = dp;
  638.         elements[5] = dM;

  639.         return elements;
  640.     }

  641.     /** {@inheritDoc} */
  642.     @Override
  643.     public void registerAttitudeProvider(final AttitudeProvider attitudeProvider) {
  644.         //nothing is done since this contribution is not sensitive to attitude
  645.     }

  646.     /** Check if an index is within the accepted interval.
  647.      *
  648.      * @param index the index to check
  649.      * @param lowerBound the lower bound of the interval
  650.      * @param upperBound the upper bound of the interval
  651.      * @return true if the index is between the lower and upper bounds, false otherwise
  652.      */
  653.     private boolean isBetween(final int index, final int lowerBound, final int upperBound) {
  654.         return index >= lowerBound && index <= upperBound;
  655.     }

  656.     /** {@inheritDoc} */
  657.     @Override
  658.     public void updateShortPeriodTerms(final double[] parameters, final SpacecraftState... meanStates) {

  659.         final Slot slot = zonalSPCoefs.createSlot(meanStates);
  660.         for (final SpacecraftState meanState : meanStates) {

  661.             // Auxiliary elements related to the current orbit
  662.             final AuxiliaryElements auxiliaryElements = new AuxiliaryElements(meanState.getOrbit(), I);

  663.             // Container of attributes
  664.             // Extract the proper parameters valid for the corresponding meanState date from the input array
  665.             final double[] extractedParameters = this.extractParameters(parameters, auxiliaryElements.getDate());
  666.             final DSSTZonalContext context = initializeStep(auxiliaryElements, extractedParameters);

  667.             // Access to potential U derivatives
  668.             final UAnddU udu = new UAnddU(meanState.getDate(), context, auxiliaryElements, hansen);

  669.             // Compute rhoj and sigmaj
  670.             final double[][] rhoSigma = computeRhoSigmaCoefficients(slot, auxiliaryElements);

  671.             // Compute Di
  672.             computeDiCoefficients(meanState.getDate(), slot, context, udu);

  673.             // generate the Cij and Sij coefficients
  674.             final FourierCjSjCoefficients cjsj = new FourierCjSjCoefficients(meanState.getDate(),
  675.                                                                              maxDegreeShortPeriodics,
  676.                                                                              maxEccPowShortPeriodics,
  677.                                                                              maxFrequencyShortPeriodics,
  678.                                                                              context,
  679.                                                                              hansen);

  680.             computeCijSijCoefficients(meanState.getDate(), slot, cjsj, rhoSigma, context, auxiliaryElements, udu);
  681.         }

  682.     }

  683.     /** {@inheritDoc} */
  684.     @Override
  685.     @SuppressWarnings("unchecked")
  686.     public <T extends CalculusFieldElement<T>> void updateShortPeriodTerms(final T[] parameters,
  687.                                                                        final FieldSpacecraftState<T>... meanStates) {

  688.         // Field used by default
  689.         final Field<T> field = meanStates[0].getDate().getField();

  690.         final FieldZonalShortPeriodicCoefficients<T> fzspc = (FieldZonalShortPeriodicCoefficients<T>) zonalFieldSPCoefs.get(field);
  691.         final FieldSlot<T> slot = fzspc.createSlot(meanStates);
  692.         for (final FieldSpacecraftState<T> meanState : meanStates) {

  693.             // Auxiliary elements related to the current orbit
  694.             final FieldAuxiliaryElements<T> auxiliaryElements = new FieldAuxiliaryElements<>(meanState.getOrbit(), I);

  695.             // Container of attributes
  696.             // Extract the proper parameters valid for the corresponding meanState date from the input array
  697.             final T[] extractedParameters = this.extractParameters(parameters, auxiliaryElements.getDate());
  698.             final FieldDSSTZonalContext<T> context = initializeStep(auxiliaryElements, extractedParameters);

  699.             final FieldHansenObjects<T> fho = (FieldHansenObjects<T>) fieldHansen.get(field);

  700.             // Access to potential U derivatives
  701.             final FieldUAnddU<T> udu = new FieldUAnddU<>(meanState.getDate(), context, auxiliaryElements, fho);

  702.             // Compute rhoj and sigmaj
  703.             final T[][] rhoSigma = computeRhoSigmaCoefficients(slot, auxiliaryElements, field);

  704.             // Compute Di
  705.             computeDiCoefficients(meanState.getDate(), slot, context, field, udu);

  706.             // generate the Cij and Sij coefficients
  707.             final FieldFourierCjSjCoefficients<T> cjsj = new FieldFourierCjSjCoefficients<>(meanState.getDate(),
  708.                                                                                             maxDegreeShortPeriodics,
  709.                                                                                             maxEccPowShortPeriodics,
  710.                                                                                             maxFrequencyShortPeriodics,
  711.                                                                                             context,
  712.                                                                                             fho);


  713.             computeCijSijCoefficients(meanState.getDate(), slot, cjsj, rhoSigma, context, auxiliaryElements, field, udu);
  714.         }
  715.     }

  716.     /** {@inheritDoc} */
  717.     public List<ParameterDriver> getParametersDrivers() {
  718.         return Collections.singletonList(gmParameterDriver);
  719.     }

  720.     /** Generate the values for the D<sub>i</sub> coefficients.
  721.      * @param date target date
  722.      * @param slot slot to which the coefficients belong
  723.      * @param context container for attributes
  724.      * @param udu derivatives of the gravitational potential U
  725.      */
  726.     private void computeDiCoefficients(final AbsoluteDate date,
  727.                                        final Slot slot,
  728.                                        final DSSTZonalContext context,
  729.                                        final UAnddU udu) {

  730.         final double[] meanElementRates = computeMeanElementRates(context, udu);

  731.         final double[] currentDi = new double[6];

  732.         // Add the coefficients to the interpolation grid
  733.         for (int i = 0; i < 6; i++) {
  734.             currentDi[i] = meanElementRates[i] / context.getMeanMotion();

  735.             if (i == 5) {
  736.                 currentDi[i] += -1.5 * 2 * udu.getU() * context.getOON2A2();
  737.             }

  738.         }

  739.         slot.di.addGridPoint(date, currentDi);

  740.     }

  741.     /** Generate the values for the D<sub>i</sub> coefficients.
  742.      * @param <T> type of the elements
  743.      * @param date target date
  744.      * @param slot slot to which the coefficients belong
  745.      * @param context container for attributes
  746.      * @param field field used by default
  747.      * @param udu derivatives of the gravitational potential U
  748.      */
  749.     private <T extends CalculusFieldElement<T>> void computeDiCoefficients(final FieldAbsoluteDate<T> date,
  750.                                                                        final FieldSlot<T> slot,
  751.                                                                        final FieldDSSTZonalContext<T> context,
  752.                                                                        final Field<T> field,
  753.                                                                        final FieldUAnddU<T> udu) {

  754.         final T[] meanElementRates = computeMeanElementRates(date, context, udu);

  755.         final T[] currentDi = MathArrays.buildArray(field, 6);

  756.         // Add the coefficients to the interpolation grid
  757.         for (int i = 0; i < 6; i++) {
  758.             currentDi[i] = meanElementRates[i].divide(context.getMeanMotion());

  759.             if (i == 5) {
  760.                 currentDi[i] = currentDi[i].add(context.getOON2A2().multiply(udu.getU()).multiply(2.).multiply(-1.5));
  761.             }

  762.         }

  763.         slot.di.addGridPoint(date, currentDi);

  764.     }

  765.     /**
  766.      * Generate the values for the C<sub>i</sub><sup>j</sup> and the S<sub>i</sub><sup>j</sup> coefficients.
  767.      * @param date date of computation
  768.      * @param slot slot to which the coefficients belong
  769.      * @param cjsj Fourier coefficients
  770.      * @param rhoSigma ρ<sub>j</sub> and σ<sub>j</sub>
  771.      * @param context container for attributes
  772.      * @param auxiliaryElements auxiliary elements related to the current orbit
  773.      * @param udu derivatives of the gravitational potential U
  774.      */
  775.     private void computeCijSijCoefficients(final AbsoluteDate date, final Slot slot,
  776.                                            final FourierCjSjCoefficients cjsj,
  777.                                            final double[][] rhoSigma, final DSSTZonalContext context,
  778.                                            final AuxiliaryElements auxiliaryElements,
  779.                                            final UAnddU udu) {

  780.         final int nMax = maxDegreeShortPeriodics;

  781.         // The C<sub>i</sub>⁰ coefficients
  782.         final double[] currentCi0 = new double[] {0., 0., 0., 0., 0., 0.};
  783.         for (int j = 1; j < slot.cij.length; j++) {

  784.             // Create local arrays
  785.             final double[] currentCij = new double[] {0., 0., 0., 0., 0., 0.};
  786.             final double[] currentSij = new double[] {0., 0., 0., 0., 0., 0.};

  787.             // j == 1
  788.             if (j == 1) {
  789.                 final double coef1 = 4 * auxiliaryElements.getK() * udu.getU() - context.getHK() * cjsj.getCj(1) + context.getK2MH2O2() * cjsj.getSj(1);
  790.                 final double coef2 = 4 * auxiliaryElements.getH() * udu.getU() + context.getK2MH2O2() * cjsj.getCj(1) + context.getHK() * cjsj.getSj(1);
  791.                 final double coef3 = (auxiliaryElements.getK() * cjsj.getCj(1) + auxiliaryElements.getH() * cjsj.getSj(1)) / 4.;
  792.                 final double coef4 = (8 * udu.getU() - auxiliaryElements.getH() * cjsj.getCj(1) + auxiliaryElements.getK() * cjsj.getSj(1)) / 4.;

  793.                 //Coefficients for a
  794.                 currentCij[0] += coef1;
  795.                 currentSij[0] += coef2;

  796.                 //Coefficients for k
  797.                 currentCij[1] += coef4;
  798.                 currentSij[1] += coef3;

  799.                 //Coefficients for h
  800.                 currentCij[2] -= coef3;
  801.                 currentSij[2] += coef4;

  802.                 //Coefficients for λ
  803.                 currentCij[5] -= coef2 / 2;
  804.                 currentSij[5] += coef1 / 2;
  805.             }

  806.             // j == 2
  807.             if (j == 2) {
  808.                 final double coef1 = context.getK2MH2() * udu.getU();
  809.                 final double coef2 = 2 * context.getHK() * udu.getU();
  810.                 final double coef3 = auxiliaryElements.getH() * udu.getU() / 2;
  811.                 final double coef4 = auxiliaryElements.getK() * udu.getU() / 2;

  812.                 //Coefficients for a
  813.                 currentCij[0] += coef1;
  814.                 currentSij[0] += coef2;

  815.                 //Coefficients for k
  816.                 currentCij[1] += coef4;
  817.                 currentSij[1] += coef3;

  818.                 //Coefficients for h
  819.                 currentCij[2] -= coef3;
  820.                 currentSij[2] += coef4;

  821.                 //Coefficients for λ
  822.                 currentCij[5] -= coef2 / 2;
  823.                 currentSij[5] += coef1 / 2;
  824.             }

  825.             // j between 1 and 2N-3
  826.             if (isBetween(j, 1, 2 * nMax - 3) && j + 2 < cjsj.jMax) {
  827.                 final double coef1 = ( j + 2 ) * (-context.getHK() * cjsj.getCj(j + 2) + context.getK2MH2O2() * cjsj.getSj(j + 2));
  828.                 final double coef2 = ( j + 2 ) * (context.getK2MH2O2() * cjsj.getCj(j + 2) + context.getHK() * cjsj.getSj(j + 2));
  829.                 final double coef3 = ( j + 2 ) * (auxiliaryElements.getK() * cjsj.getCj(j + 2) + auxiliaryElements.getH() * cjsj.getSj(j + 2)) / 4;
  830.                 final double coef4 = ( j + 2 ) * (auxiliaryElements.getH() * cjsj.getCj(j + 2) - auxiliaryElements.getK() * cjsj.getSj(j + 2)) / 4;

  831.                 //Coefficients for a
  832.                 currentCij[0] += coef1;
  833.                 currentSij[0] -= coef2;

  834.                 //Coefficients for k
  835.                 currentCij[1] -= coef4;
  836.                 currentSij[1] -= coef3;

  837.                 //Coefficients for h
  838.                 currentCij[2] -= coef3;
  839.                 currentSij[2] += coef4;

  840.                 //Coefficients for λ
  841.                 currentCij[5] -= coef2 / 2;
  842.                 currentSij[5] += -coef1 / 2;
  843.             }

  844.             // j between 1 and 2N-2
  845.             if (isBetween(j, 1, 2 * nMax - 2) && j + 1 < cjsj.jMax) {
  846.                 final double coef1 = 2 * ( j + 1 ) * (-auxiliaryElements.getH() * cjsj.getCj(j + 1) + auxiliaryElements.getK() * cjsj.getSj(j + 1));
  847.                 final double coef2 = 2 * ( j + 1 ) * (auxiliaryElements.getK() * cjsj.getCj(j + 1) + auxiliaryElements.getH() * cjsj.getSj(j + 1));
  848.                 final double coef3 = ( j + 1 ) * cjsj.getCj(j + 1);
  849.                 final double coef4 = ( j + 1 ) * cjsj.getSj(j + 1);

  850.                 //Coefficients for a
  851.                 currentCij[0] += coef1;
  852.                 currentSij[0] -= coef2;

  853.                 //Coefficients for k
  854.                 currentCij[1] += coef4;
  855.                 currentSij[1] -= coef3;

  856.                 //Coefficients for h
  857.                 currentCij[2] -= coef3;
  858.                 currentSij[2] -= coef4;

  859.                 //Coefficients for λ
  860.                 currentCij[5] -= coef2 / 2;
  861.                 currentSij[5] += -coef1 / 2;
  862.             }

  863.             // j between 2 and 2N
  864.             if (isBetween(j, 2, 2 * nMax) && j - 1 < cjsj.jMax) {
  865.                 final double coef1 = 2 * ( j - 1 ) * (auxiliaryElements.getH() * cjsj.getCj(j - 1) + auxiliaryElements.getK() * cjsj.getSj(j - 1));
  866.                 final double coef2 = 2 * ( j - 1 ) * (auxiliaryElements.getK() * cjsj.getCj(j - 1) - auxiliaryElements.getH() * cjsj.getSj(j - 1));
  867.                 final double coef3 = ( j - 1 ) * cjsj.getCj(j - 1);
  868.                 final double coef4 = ( j - 1 ) * cjsj.getSj(j - 1);

  869.                 //Coefficients for a
  870.                 currentCij[0] += coef1;
  871.                 currentSij[0] -= coef2;

  872.                 //Coefficients for k
  873.                 currentCij[1] += coef4;
  874.                 currentSij[1] -= coef3;

  875.                 //Coefficients for h
  876.                 currentCij[2] += coef3;
  877.                 currentSij[2] += coef4;

  878.                 //Coefficients for λ
  879.                 currentCij[5] += coef2 / 2;
  880.                 currentSij[5] += coef1 / 2;
  881.             }

  882.             // j between 3 and 2N + 1
  883.             if (isBetween(j, 3, 2 * nMax + 1) && j - 2 < cjsj.jMax) {
  884.                 final double coef1 = ( j - 2 ) * (context.getHK() * cjsj.getCj(j - 2) + context.getK2MH2O2() * cjsj.getSj(j - 2));
  885.                 final double coef2 = ( j - 2 ) * (-context.getK2MH2O2() * cjsj.getCj(j - 2) + context.getHK() * cjsj.getSj(j - 2));
  886.                 final double coef3 = ( j - 2 ) * (auxiliaryElements.getK() * cjsj.getCj(j - 2) - auxiliaryElements.getH() * cjsj.getSj(j - 2)) / 4;
  887.                 final double coef4 = ( j - 2 ) * (auxiliaryElements.getH() * cjsj.getCj(j - 2) + auxiliaryElements.getK() * cjsj.getSj(j - 2)) / 4;
  888.                 final double coef5 = ( j - 2 ) * (context.getK2MH2O2() * cjsj.getCj(j - 2) - context.getHK() * cjsj.getSj(j - 2));

  889.                 //Coefficients for a
  890.                 currentCij[0] += coef1;
  891.                 currentSij[0] += coef2;

  892.                 //Coefficients for k
  893.                 currentCij[1] += coef4;
  894.                 currentSij[1] -= coef3;

  895.                 //Coefficients for h
  896.                 currentCij[2] += coef3;
  897.                 currentSij[2] += coef4;

  898.                 //Coefficients for λ
  899.                 currentCij[5] += coef5 / 2;
  900.                 currentSij[5] += coef1 / 2;
  901.             }

  902.             //multiply by the common factor
  903.             //for a (i == 0) -> χ³ / (n² * a)
  904.             currentCij[0] *= context.getX3ON2A();
  905.             currentSij[0] *= context.getX3ON2A();
  906.             //for k (i == 1) -> χ / (n² * a²)
  907.             currentCij[1] *= context.getXON2A2();
  908.             currentSij[1] *= context.getXON2A2();
  909.             //for h (i == 2) -> χ / (n² * a²)
  910.             currentCij[2] *= context.getXON2A2();
  911.             currentSij[2] *= context.getXON2A2();
  912.             //for λ (i == 5) -> (χ²) / (n² * a² * (χ + 1 ) )
  913.             currentCij[5] *= context.getX2ON2A2XP1();
  914.             currentSij[5] *= context.getX2ON2A2XP1();

  915.             // j is between 1 and 2 * N - 1
  916.             if (isBetween(j, 1, 2 * nMax - 1) && j < cjsj.jMax) {
  917.                 // Compute cross derivatives
  918.                 // Cj(alpha,gamma) = alpha * dC/dgamma - gamma * dC/dalpha
  919.                 final double CjAlphaGamma   = context.getAlpha() * cjsj.getdCjdGamma(j) - context.getGamma() * cjsj.getdCjdAlpha(j);
  920.                 // Cj(alpha,beta) = alpha * dC/dbeta - beta * dC/dalpha
  921.                 final double CjAlphaBeta   = context.getAlpha() * cjsj.getdCjdBeta(j) - context.getBeta() * cjsj.getdCjdAlpha(j);
  922.                 // Cj(beta,gamma) = beta * dC/dgamma - gamma * dC/dbeta
  923.                 final double CjBetaGamma    =  context.getBeta() * cjsj.getdCjdGamma(j) - context.getGamma() * cjsj.getdCjdBeta(j);
  924.                 // Cj(h,k) = h * dC/dk - k * dC/dh
  925.                 final double CjHK   = auxiliaryElements.getH() * cjsj.getdCjdK(j) - auxiliaryElements.getK() * cjsj.getdCjdH(j);
  926.                 // Sj(alpha,gamma) = alpha * dS/dgamma - gamma * dS/dalpha
  927.                 final double SjAlphaGamma   = context.getAlpha() * cjsj.getdSjdGamma(j) - context.getGamma() * cjsj.getdSjdAlpha(j);
  928.                 // Sj(alpha,beta) = alpha * dS/dbeta - beta * dS/dalpha
  929.                 final double SjAlphaBeta   = context.getAlpha() * cjsj.getdSjdBeta(j) - context.getBeta() * cjsj.getdSjdAlpha(j);
  930.                 // Sj(beta,gamma) = beta * dS/dgamma - gamma * dS/dbeta
  931.                 final double SjBetaGamma    =  context.getBeta() * cjsj.getdSjdGamma(j) - context.getGamma() * cjsj.getdSjdBeta(j);
  932.                 // Sj(h,k) = h * dS/dk - k * dS/dh
  933.                 final double SjHK   = auxiliaryElements.getH() * cjsj.getdSjdK(j) - auxiliaryElements.getK() * cjsj.getdSjdH(j);

  934.                 //Coefficients for a
  935.                 final double coef1 = context.getX3ON2A() * (3 - context.getBB()) * j;
  936.                 currentCij[0] += coef1 * cjsj.getSj(j);
  937.                 currentSij[0] -= coef1 * cjsj.getCj(j);

  938.                 //Coefficients for k and h
  939.                 final double coef2 = auxiliaryElements.getP() * CjAlphaGamma - I * auxiliaryElements.getQ() * CjBetaGamma;
  940.                 final double coef3 = auxiliaryElements.getP() * SjAlphaGamma - I * auxiliaryElements.getQ() * SjBetaGamma;
  941.                 currentCij[1] -= context.getXON2A2() * (auxiliaryElements.getH() * coef2 + context.getBB() * cjsj.getdCjdH(j) - 1.5 * auxiliaryElements.getK() * j * cjsj.getSj(j));
  942.                 currentSij[1] -= context.getXON2A2() * (auxiliaryElements.getH() * coef3 + context.getBB() * cjsj.getdSjdH(j) + 1.5 * auxiliaryElements.getK() * j * cjsj.getCj(j));
  943.                 currentCij[2] += context.getXON2A2() * (auxiliaryElements.getK() * coef2 + context.getBB() * cjsj.getdCjdK(j) + 1.5 * auxiliaryElements.getH() * j * cjsj.getSj(j));
  944.                 currentSij[2] += context.getXON2A2() * (auxiliaryElements.getK() * coef3 + context.getBB() * cjsj.getdSjdK(j) - 1.5 * auxiliaryElements.getH() * j * cjsj.getCj(j));

  945.                 //Coefficients for q and p
  946.                 final double coef4 = CjHK - CjAlphaBeta - j * cjsj.getSj(j);
  947.                 final double coef5 = SjHK - SjAlphaBeta + j * cjsj.getCj(j);
  948.                 currentCij[3] = context.getCXO2N2A2() * (-I * CjAlphaGamma + auxiliaryElements.getQ() * coef4);
  949.                 currentSij[3] = context.getCXO2N2A2() * (-I * SjAlphaGamma + auxiliaryElements.getQ() * coef5);
  950.                 currentCij[4] = context.getCXO2N2A2() * (-CjBetaGamma + auxiliaryElements.getP() * coef4);
  951.                 currentSij[4] = context.getCXO2N2A2() * (-SjBetaGamma + auxiliaryElements.getP() * coef5);

  952.                 //Coefficients for λ
  953.                 final double coef6 = auxiliaryElements.getH() * cjsj.getdCjdH(j) + auxiliaryElements.getK() * cjsj.getdCjdK(j);
  954.                 final double coef7 = auxiliaryElements.getH() * cjsj.getdSjdH(j) + auxiliaryElements.getK() * cjsj.getdSjdK(j);
  955.                 currentCij[5] += context.getOON2A2() * (-2 * auxiliaryElements.getSma() * cjsj.getdCjdA(j) + coef6 / (context.getChi() + 1) + context.getChi() * coef2 - 3 * cjsj.getCj(j));
  956.                 currentSij[5] += context.getOON2A2() * (-2 * auxiliaryElements.getSma() * cjsj.getdSjdA(j) + coef7 / (context.getChi() + 1) + context.getChi() * coef3 - 3 * cjsj.getSj(j));
  957.             }

  958.             for (int i = 0; i < 6; i++) {
  959.                 //Add the current coefficients contribution to C<sub>i</sub>⁰
  960.                 currentCi0[i] -= currentCij[i] * rhoSigma[j][0] + currentSij[i] * rhoSigma[j][1];
  961.             }

  962.             // Add the coefficients to the interpolation grid
  963.             slot.cij[j].addGridPoint(date, currentCij);
  964.             slot.sij[j].addGridPoint(date, currentSij);

  965.         }

  966.         //Add C<sub>i</sub>⁰ to the interpolation grid
  967.         slot.cij[0].addGridPoint(date, currentCi0);

  968.     }

  969.     /**
  970.      * Generate the values for the C<sub>i</sub><sup>j</sup> and the S<sub>i</sub><sup>j</sup> coefficients.
  971.      * @param <T> type of the elements
  972.      * @param date date of computation
  973.      * @param slot slot to which the coefficients belong
  974.      * @param cjsj Fourier coefficients
  975.      * @param rhoSigma ρ<sub>j</sub> and σ<sub>j</sub>
  976.      * @param context container for attributes
  977.      * @param auxiliaryElements auxiliary elements related to the current orbit
  978.      * @param field field used by default
  979.      * @param udu derivatives of the gravitational potential U
  980.      */
  981.     private <T extends CalculusFieldElement<T>> void computeCijSijCoefficients(final FieldAbsoluteDate<T> date,
  982.                                                                            final FieldSlot<T> slot,
  983.                                                                            final FieldFourierCjSjCoefficients<T> cjsj,
  984.                                                                            final T[][] rhoSigma,
  985.                                                                            final FieldDSSTZonalContext<T> context,
  986.                                                                            final FieldAuxiliaryElements<T> auxiliaryElements,
  987.                                                                            final Field<T> field,
  988.                                                                            final FieldUAnddU<T> udu) {

  989.         // Zero
  990.         final T zero = field.getZero();

  991.         final int nMax = maxDegreeShortPeriodics;

  992.         // The C<sub>i</sub>⁰ coefficients
  993.         final T[] currentCi0 = MathArrays.buildArray(field, 6);
  994.         Arrays.fill(currentCi0, zero);

  995.         for (int j = 1; j < slot.cij.length; j++) {

  996.             // Create local arrays
  997.             final T[] currentCij = MathArrays.buildArray(field, 6);
  998.             final T[] currentSij = MathArrays.buildArray(field, 6);

  999.             Arrays.fill(currentCij, zero);
  1000.             Arrays.fill(currentSij, zero);

  1001.             // j == 1
  1002.             if (j == 1) {
  1003.                 final T coef1 = auxiliaryElements.getK().multiply(udu.getU()).multiply(4.).subtract(context.getHK().multiply(cjsj.getCj(1))).add(context.getK2MH2O2().multiply(cjsj.getSj(1)));
  1004.                 final T coef2 = auxiliaryElements.getH().multiply(udu.getU()).multiply(4.).add(context.getK2MH2O2().multiply(cjsj.getCj(1))).add(context.getHK().multiply(cjsj.getSj(1)));
  1005.                 final T coef3 = auxiliaryElements.getK().multiply(cjsj.getCj(1)).add(auxiliaryElements.getH().multiply(cjsj.getSj(1))).divide(4.);
  1006.                 final T coef4 = udu.getU().multiply(8.).subtract(auxiliaryElements.getH().multiply(cjsj.getCj(1))).add(auxiliaryElements.getK().multiply(cjsj.getSj(1))).divide(4.);

  1007.                 //Coefficients for a
  1008.                 currentCij[0] = currentCij[0].add(coef1);
  1009.                 currentSij[0] = currentSij[0].add(coef2);

  1010.                 //Coefficients for k
  1011.                 currentCij[1] = currentCij[1].add(coef4);
  1012.                 currentSij[1] = currentSij[1].add(coef3);

  1013.                 //Coefficients for h
  1014.                 currentCij[2] = currentCij[2].subtract(coef3);
  1015.                 currentSij[2] = currentSij[2].add(coef4);

  1016.                 //Coefficients for λ
  1017.                 currentCij[5] = currentCij[5].subtract(coef2.divide(2.));
  1018.                 currentSij[5] = currentSij[5].add(coef1.divide(2.));
  1019.             }

  1020.             // j == 2
  1021.             if (j == 2) {
  1022.                 final T coef1 = context.getK2MH2().multiply(udu.getU());
  1023.                 final T coef2 = context.getHK().multiply(udu.getU()).multiply(2.);
  1024.                 final T coef3 = auxiliaryElements.getH().multiply(udu.getU()).divide(2.);
  1025.                 final T coef4 = auxiliaryElements.getK().multiply(udu.getU()).divide(2.);

  1026.                 //Coefficients for a
  1027.                 currentCij[0] = currentCij[0].add(coef1);
  1028.                 currentSij[0] = currentSij[0].add(coef2);

  1029.                 //Coefficients for k
  1030.                 currentCij[1] = currentCij[1].add(coef4);
  1031.                 currentSij[1] = currentSij[1].add(coef3);

  1032.                 //Coefficients for h
  1033.                 currentCij[2] = currentCij[2].subtract(coef3);
  1034.                 currentSij[2] = currentSij[2].add(coef4);

  1035.                 //Coefficients for λ
  1036.                 currentCij[5] = currentCij[5].subtract(coef2.divide(2.));
  1037.                 currentSij[5] = currentSij[5].add(coef1.divide(2.));
  1038.             }

  1039.             // j between 1 and 2N-3
  1040.             if (isBetween(j, 1, 2 * nMax - 3) && j + 2 < cjsj.jMax) {
  1041.                 final T coef1 = context.getHK().negate().multiply(cjsj.getCj(j + 2)).add(context.getK2MH2O2().multiply(cjsj.getSj(j + 2))).multiply(j + 2);
  1042.                 final T coef2 = context.getK2MH2O2().multiply(cjsj.getCj(j + 2)).add(context.getHK().multiply(cjsj.getSj(j + 2))).multiply(j + 2);
  1043.                 final T coef3 = auxiliaryElements.getK().multiply(cjsj.getCj(j + 2)).add(auxiliaryElements.getH().multiply(cjsj.getSj(j + 2))).multiply(j + 2).divide(4.);
  1044.                 final T coef4 = auxiliaryElements.getH().multiply(cjsj.getCj(j + 2)).subtract(auxiliaryElements.getK().multiply(cjsj.getSj(j + 2))).multiply(j + 2).divide(4.);

  1045.                 //Coefficients for a
  1046.                 currentCij[0] = currentCij[0].add(coef1);
  1047.                 currentSij[0] = currentSij[0].subtract(coef2);

  1048.                 //Coefficients for k
  1049.                 currentCij[1] = currentCij[1].add(coef4.negate());
  1050.                 currentSij[1] = currentSij[1].subtract(coef3);

  1051.                 //Coefficients for h
  1052.                 currentCij[2] = currentCij[2].subtract(coef3);
  1053.                 currentSij[2] = currentSij[2].add(coef4);

  1054.                 //Coefficients for λ
  1055.                 currentCij[5] = currentCij[5].subtract(coef2.divide(2.));
  1056.                 currentSij[5] = currentSij[5].add(coef1.negate().divide(2.));
  1057.             }

  1058.             // j between 1 and 2N-2
  1059.             if (isBetween(j, 1, 2 * nMax - 2) && j + 1 < cjsj.jMax) {
  1060.                 final T coef1 = auxiliaryElements.getH().negate().multiply(cjsj.getCj(j + 1)).add(auxiliaryElements.getK().multiply(cjsj.getSj(j + 1))).multiply(2. * (j + 1));
  1061.                 final T coef2 = auxiliaryElements.getK().multiply(cjsj.getCj(j + 1)).add(auxiliaryElements.getH().multiply(cjsj.getSj(j + 1))).multiply(2. * (j + 1));
  1062.                 final T coef3 = cjsj.getCj(j + 1).multiply(j + 1);
  1063.                 final T coef4 = cjsj.getSj(j + 1).multiply(j + 1);

  1064.                 //Coefficients for a
  1065.                 currentCij[0] = currentCij[0].add(coef1);
  1066.                 currentSij[0] = currentSij[0].subtract(coef2);

  1067.                 //Coefficients for k
  1068.                 currentCij[1] = currentCij[1].add(coef4);
  1069.                 currentSij[1] = currentSij[1].subtract(coef3);

  1070.                 //Coefficients for h
  1071.                 currentCij[2] = currentCij[2].subtract(coef3);
  1072.                 currentSij[2] = currentSij[2].subtract(coef4);

  1073.                 //Coefficients for λ
  1074.                 currentCij[5] = currentCij[5].subtract(coef2.divide(2.));
  1075.                 currentSij[5] = currentSij[5].add(coef1.negate().divide(2.));
  1076.             }

  1077.             // j between 2 and 2N
  1078.             if (isBetween(j, 2, 2 * nMax) && j - 1 < cjsj.jMax) {
  1079.                 final T coef1 = auxiliaryElements.getH().multiply(cjsj.getCj(j - 1)).add(auxiliaryElements.getK().multiply(cjsj.getSj(j - 1))).multiply(2 * ( j - 1 ));
  1080.                 final T coef2 = auxiliaryElements.getK().multiply(cjsj.getCj(j - 1)).subtract(auxiliaryElements.getH().multiply(cjsj.getSj(j - 1))).multiply(2 * ( j - 1 ));
  1081.                 final T coef3 = cjsj.getCj(j - 1).multiply(j - 1);
  1082.                 final T coef4 = cjsj.getSj(j - 1).multiply(j - 1);

  1083.                 //Coefficients for a
  1084.                 currentCij[0] = currentCij[0].add(coef1);
  1085.                 currentSij[0] = currentSij[0].subtract(coef2);

  1086.                 //Coefficients for k
  1087.                 currentCij[1] = currentCij[1].add(coef4);
  1088.                 currentSij[1] = currentSij[1].subtract(coef3);

  1089.                 //Coefficients for h
  1090.                 currentCij[2] = currentCij[2].add(coef3);
  1091.                 currentSij[2] = currentSij[2].add(coef4);

  1092.                 //Coefficients for λ
  1093.                 currentCij[5] = currentCij[5].add(coef2.divide(2.));
  1094.                 currentSij[5] = currentSij[5].add(coef1.divide(2.));
  1095.             }

  1096.             // j between 3 and 2N + 1
  1097.             if (isBetween(j, 3, 2 * nMax + 1) && j - 2 < cjsj.jMax) {
  1098.                 final T coef1 = context.getHK().multiply(cjsj.getCj(j - 2)).add(context.getK2MH2O2().multiply(cjsj.getSj(j - 2))).multiply(j - 2);
  1099.                 final T coef2 = context.getK2MH2O2().negate().multiply(cjsj.getCj(j - 2)).add(context.getHK().multiply(cjsj.getSj(j - 2))).multiply(j - 2);
  1100.                 final T coef3 = auxiliaryElements.getK().multiply(cjsj.getCj(j - 2)).subtract(auxiliaryElements.getH().multiply(cjsj.getSj(j - 2))).multiply(j - 2).divide(4.);
  1101.                 final T coef4 = auxiliaryElements.getH().multiply(cjsj.getCj(j - 2)).add(auxiliaryElements.getK().multiply(cjsj.getSj(j - 2))).multiply(j - 2).divide(4.);
  1102.                 final T coef5 = context.getK2MH2O2().multiply(cjsj.getCj(j - 2)).subtract(context.getHK().multiply(cjsj.getSj(j - 2))).multiply(j - 2);

  1103.                 //Coefficients for a
  1104.                 currentCij[0] = currentCij[0].add(coef1);
  1105.                 currentSij[0] = currentSij[0].add(coef2);

  1106.                 //Coefficients for k
  1107.                 currentCij[1] = currentCij[1].add(coef4);
  1108.                 currentSij[1] = currentSij[1].add(coef3.negate());

  1109.                 //Coefficients for h
  1110.                 currentCij[2] = currentCij[2].add(coef3);
  1111.                 currentSij[2] = currentSij[2].add(coef4);

  1112.                 //Coefficients for λ
  1113.                 currentCij[5] = currentCij[5].add(coef5.divide(2.));
  1114.                 currentSij[5] = currentSij[5].add(coef1.divide(2.));
  1115.             }

  1116.             //multiply by the common factor
  1117.             //for a (i == 0) -> χ³ / (n² * a)
  1118.             currentCij[0] = currentCij[0].multiply(context.getX3ON2A());
  1119.             currentSij[0] = currentSij[0].multiply(context.getX3ON2A());
  1120.             //for k (i == 1) -> χ / (n² * a²)
  1121.             currentCij[1] = currentCij[1].multiply(context.getXON2A2());
  1122.             currentSij[1] = currentSij[1].multiply(context.getXON2A2());
  1123.             //for h (i == 2) -> χ / (n² * a²)
  1124.             currentCij[2] = currentCij[2].multiply(context.getXON2A2());
  1125.             currentSij[2] = currentSij[2].multiply(context.getXON2A2());
  1126.             //for λ (i == 5) -> (χ²) / (n² * a² * (χ + 1 ) )
  1127.             currentCij[5] = currentCij[5].multiply(context.getX2ON2A2XP1());
  1128.             currentSij[5] = currentSij[5].multiply(context.getX2ON2A2XP1());

  1129.             // j is between 1 and 2 * N - 1
  1130.             if (isBetween(j, 1, 2 * nMax - 1) && j < cjsj.jMax) {
  1131.                 // Compute cross derivatives
  1132.                 // Cj(alpha,gamma) = alpha * dC/dgamma - gamma * dC/dalpha
  1133.                 final T CjAlphaGamma = context.getAlpha().multiply(cjsj.getdCjdGamma(j)).subtract(context.getGamma().multiply(cjsj.getdCjdAlpha(j)));
  1134.                 // Cj(alpha,beta) = alpha * dC/dbeta - beta * dC/dalpha
  1135.                 final T CjAlphaBeta  = context.getAlpha().multiply(cjsj.getdCjdBeta(j)).subtract(context.getBeta().multiply(cjsj.getdCjdAlpha(j)));
  1136.                 // Cj(beta,gamma) = beta * dC/dgamma - gamma * dC/dbeta
  1137.                 final T CjBetaGamma  = context.getBeta().multiply(cjsj.getdCjdGamma(j)).subtract(context.getGamma().multiply(cjsj.getdCjdBeta(j)));
  1138.                 // Cj(h,k) = h * dC/dk - k * dC/dh
  1139.                 final T CjHK         = auxiliaryElements.getH().multiply(cjsj.getdCjdK(j)).subtract(auxiliaryElements.getK().multiply(cjsj.getdCjdH(j)));
  1140.                 // Sj(alpha,gamma) = alpha * dS/dgamma - gamma * dS/dalpha
  1141.                 final T SjAlphaGamma = context.getAlpha().multiply(cjsj.getdSjdGamma(j)).subtract(context.getGamma().multiply(cjsj.getdSjdAlpha(j)));
  1142.                 // Sj(alpha,beta) = alpha * dS/dbeta - beta * dS/dalpha
  1143.                 final T SjAlphaBeta  = context.getAlpha().multiply(cjsj.getdSjdBeta(j)).subtract(context.getBeta().multiply(cjsj.getdSjdAlpha(j)));
  1144.                 // Sj(beta,gamma) = beta * dS/dgamma - gamma * dS/dbeta
  1145.                 final T SjBetaGamma  = context.getBeta().multiply(cjsj.getdSjdGamma(j)).subtract(context.getGamma().multiply(cjsj.getdSjdBeta(j)));
  1146.                 // Sj(h,k) = h * dS/dk - k * dS/dh
  1147.                 final T SjHK         = auxiliaryElements.getH().multiply(cjsj.getdSjdK(j)).subtract(auxiliaryElements.getK().multiply(cjsj.getdSjdH(j)));

  1148.                 //Coefficients for a
  1149.                 final T coef1 = context.getX3ON2A().multiply(context.getBB().negate().add(3.)).multiply(j);
  1150.                 currentCij[0] = currentCij[0].add(coef1.multiply(cjsj.getSj(j)));
  1151.                 currentSij[0] = currentSij[0].subtract(coef1.multiply(cjsj.getCj(j)));

  1152.                 //Coefficients for k and h
  1153.                 final T coef2 = auxiliaryElements.getP().multiply(CjAlphaGamma).subtract(auxiliaryElements.getQ().multiply(CjBetaGamma).multiply(I));
  1154.                 final T coef3 = auxiliaryElements.getP().multiply(SjAlphaGamma).subtract(auxiliaryElements.getQ().multiply(SjBetaGamma).multiply(I));
  1155.                 currentCij[1] = currentCij[1].subtract(context.getXON2A2().multiply(auxiliaryElements.getH().multiply(coef2).add(context.getBB().multiply(cjsj.getdCjdH(j))).subtract(auxiliaryElements.getK().multiply(1.5).multiply(j).multiply(cjsj.getSj(j)))));
  1156.                 currentSij[1] = currentSij[1].subtract(context.getXON2A2().multiply(auxiliaryElements.getH().multiply(coef3).add(context.getBB().multiply(cjsj.getdSjdH(j))).add(auxiliaryElements.getK().multiply(1.5).multiply(j).multiply(cjsj.getCj(j)))));
  1157.                 currentCij[2] = currentCij[2].add(context.getXON2A2().multiply(auxiliaryElements.getK().multiply(coef2).add(context.getBB().multiply(cjsj.getdCjdK(j))).add(auxiliaryElements.getH().multiply(1.5).multiply(j).multiply(cjsj.getSj(j)))));
  1158.                 currentSij[2] = currentSij[2].add(context.getXON2A2().multiply(auxiliaryElements.getK().multiply(coef3).add(context.getBB().multiply(cjsj.getdSjdK(j))).subtract(auxiliaryElements.getH().multiply(1.5).multiply(j).multiply(cjsj.getCj(j)))));

  1159.                 //Coefficients for q and p
  1160.                 final T coef4 = CjHK.subtract(CjAlphaBeta).subtract(cjsj.getSj(j).multiply(j));
  1161.                 final T coef5 = SjHK.subtract(SjAlphaBeta).add(cjsj.getCj(j).multiply(j));
  1162.                 currentCij[3] = context.getCXO2N2A2().multiply(CjAlphaGamma.multiply(-I).add(auxiliaryElements.getQ().multiply(coef4)));
  1163.                 currentSij[3] = context.getCXO2N2A2().multiply(SjAlphaGamma.multiply(-I).add(auxiliaryElements.getQ().multiply(coef5)));
  1164.                 currentCij[4] = context.getCXO2N2A2().multiply(CjBetaGamma.negate().add(auxiliaryElements.getP().multiply(coef4)));
  1165.                 currentSij[4] = context.getCXO2N2A2().multiply(SjBetaGamma.negate().add(auxiliaryElements.getP().multiply(coef5)));

  1166.                 //Coefficients for λ
  1167.                 final T coef6 = auxiliaryElements.getH().multiply(cjsj.getdCjdH(j)).add(auxiliaryElements.getK().multiply(cjsj.getdCjdK(j)));
  1168.                 final T coef7 = auxiliaryElements.getH().multiply(cjsj.getdSjdH(j)).add(auxiliaryElements.getK().multiply(cjsj.getdSjdK(j)));
  1169.                 currentCij[5] = currentCij[5].add(context.getOON2A2().multiply(auxiliaryElements.getSma().multiply(-2.).multiply(cjsj.getdCjdA(j)).add(coef6.divide(context.getChi().add(1.))).add(context.getChi().multiply(coef2)).subtract(cjsj.getCj(j).multiply(3.))));
  1170.                 currentSij[5] = currentSij[5].add(context.getOON2A2().multiply(auxiliaryElements.getSma().multiply(-2.).multiply(cjsj.getdSjdA(j)).add(coef7.divide(context.getChi().add(1.))).add(context.getChi().multiply(coef3)).subtract(cjsj.getSj(j).multiply(3.))));
  1171.             }

  1172.             for (int i = 0; i < 6; i++) {
  1173.                 //Add the current coefficients contribution to C<sub>i</sub>⁰
  1174.                 currentCi0[i] = currentCi0[i].subtract(currentCij[i].multiply(rhoSigma[j][0]).add(currentSij[i].multiply(rhoSigma[j][1])));
  1175.             }

  1176.             // Add the coefficients to the interpolation grid
  1177.             slot.cij[j].addGridPoint(date, currentCij);
  1178.             slot.sij[j].addGridPoint(date, currentSij);

  1179.         }

  1180.         //Add C<sub>i</sub>⁰ to the interpolation grid
  1181.         slot.cij[0].addGridPoint(date, currentCi0);

  1182.     }

  1183.     /**
  1184.      * Compute the auxiliary quantities ρ<sub>j</sub> and σ<sub>j</sub>.
  1185.      * <p>
  1186.      * The expressions used are equations 2.5.3-(4) from the Danielson paper. <br/>
  1187.      *  ρ<sub>j</sub> = (1+jB)(-b)<sup>j</sup>C<sub>j</sub>(k, h) <br/>
  1188.      *  σ<sub>j</sub> = (1+jB)(-b)<sup>j</sup>S<sub>j</sub>(k, h) <br/>
  1189.      * </p>
  1190.      * @param slot slot to which the coefficients belong
  1191.      * @param auxiliaryElements auxiliary elements related to the current orbit
  1192.      * @return array containing ρ<sub>j</sub> and σ<sub>j</sub>
  1193.      */
  1194.     private double[][] computeRhoSigmaCoefficients(final Slot slot,
  1195.                                                    final AuxiliaryElements auxiliaryElements) {

  1196.         final CjSjCoefficient cjsjKH = new CjSjCoefficient(auxiliaryElements.getK(), auxiliaryElements.getH());
  1197.         final double b = 1. / (1 + auxiliaryElements.getB());

  1198.         // (-b)<sup>j</sup>
  1199.         double mbtj = 1;

  1200.         final double[][] rhoSigma = new double[slot.cij.length][2];
  1201.         for (int j = 1; j < rhoSigma.length; j++) {

  1202.             //Compute current rho and sigma;
  1203.             mbtj *= -b;
  1204.             final double coef  = (1 + j * auxiliaryElements.getB()) * mbtj;
  1205.             final double rho   = coef * cjsjKH.getCj(j);
  1206.             final double sigma = coef * cjsjKH.getSj(j);

  1207.             // Add the coefficients to the interpolation grid
  1208.             rhoSigma[j][0] = rho;
  1209.             rhoSigma[j][1] = sigma;
  1210.         }

  1211.         return rhoSigma;

  1212.     }

  1213.     /**
  1214.      * Compute the auxiliary quantities ρ<sub>j</sub> and σ<sub>j</sub>.
  1215.      * <p>
  1216.      * The expressions used are equations 2.5.3-(4) from the Danielson paper. <br/>
  1217.      *  ρ<sub>j</sub> = (1+jB)(-b)<sup>j</sup>C<sub>j</sub>(k, h) <br/>
  1218.      *  σ<sub>j</sub> = (1+jB)(-b)<sup>j</sup>S<sub>j</sub>(k, h) <br/>
  1219.      * </p>
  1220.      * @param <T> type of the elements
  1221.      * @param slot slot to which the coefficients belong
  1222.      * @param auxiliaryElements auxiliary elements related to the current orbit
  1223.      * @param field field used by default
  1224.      * @return array containing ρ<sub>j</sub> and σ<sub>j</sub>
  1225.      */
  1226.     private <T extends CalculusFieldElement<T>> T[][] computeRhoSigmaCoefficients(final FieldSlot<T> slot,
  1227.                                                                                   final FieldAuxiliaryElements<T> auxiliaryElements,
  1228.                                                                                   final Field<T> field) {
  1229.         final T zero = field.getZero();

  1230.         final FieldCjSjCoefficient<T> cjsjKH = new FieldCjSjCoefficient<>(auxiliaryElements.getK(), auxiliaryElements.getH(), field);
  1231.         final T b = auxiliaryElements.getB().add(1.).reciprocal();

  1232.         // (-b)<sup>j</sup>
  1233.         T mbtj = zero.newInstance(1.);

  1234.         final T[][] rhoSigma = MathArrays.buildArray(field, slot.cij.length, 2);
  1235.         for (int j = 1; j < rhoSigma.length; j++) {

  1236.             //Compute current rho and sigma;
  1237.             mbtj = mbtj.multiply(b.negate());
  1238.             final T coef  = mbtj.multiply(auxiliaryElements.getB().multiply(j).add(1.));
  1239.             final T rho   = coef.multiply(cjsjKH.getCj(j));
  1240.             final T sigma = coef.multiply(cjsjKH.getSj(j));

  1241.             // Add the coefficients to the interpolation grid
  1242.             rhoSigma[j][0] = rho;
  1243.             rhoSigma[j][1] = sigma;
  1244.         }

  1245.         return rhoSigma;

  1246.     }

  1247.     /** The coefficients used to compute the short-periodic zonal contribution.
  1248.      *
  1249.      * <p>
  1250.      * Those coefficients are given in Danielson paper by expressions 4.1-(20) to 4.1.-(25)
  1251.      * </p>
  1252.      * <p>
  1253.      * The coefficients are: <br>
  1254.      * - C<sub>i</sub><sup>j</sup> and S<sub>i</sub><sup>j</sup> <br>
  1255.      * - ρ<sub>j</sub> and σ<sub>j</sub> <br>
  1256.      * - C<sub>i</sub>⁰
  1257.      * </p>
  1258.      *
  1259.      * @author Lucian Barbulescu
  1260.      */
  1261.     private static class ZonalShortPeriodicCoefficients implements ShortPeriodTerms {

  1262.         /** Maximum value for j index. */
  1263.         private final int maxFrequencyShortPeriodics;

  1264.         /** Number of points used in the interpolation process. */
  1265.         private final int interpolationPoints;

  1266.         /** All coefficients slots. */
  1267.         private final transient TimeSpanMap<Slot> slots;

  1268.         /** Constructor.
  1269.          * @param maxFrequencyShortPeriodics maximum value for j index
  1270.          * @param interpolationPoints number of points used in the interpolation process
  1271.          * @param slots all coefficients slots
  1272.          */
  1273.         ZonalShortPeriodicCoefficients(final int maxFrequencyShortPeriodics, final int interpolationPoints,
  1274.                                        final TimeSpanMap<Slot> slots) {

  1275.             // Save parameters
  1276.             this.maxFrequencyShortPeriodics = maxFrequencyShortPeriodics;
  1277.             this.interpolationPoints        = interpolationPoints;
  1278.             this.slots                      = slots;

  1279.         }

  1280.         /** Get the slot valid for some date.
  1281.          * @param meanStates mean states defining the slot
  1282.          * @return slot valid at the specified date
  1283.          */
  1284.         public Slot createSlot(final SpacecraftState... meanStates) {
  1285.             final Slot         slot  = new Slot(maxFrequencyShortPeriodics, interpolationPoints);
  1286.             final AbsoluteDate first = meanStates[0].getDate();
  1287.             final AbsoluteDate last  = meanStates[meanStates.length - 1].getDate();
  1288.             final int compare = first.compareTo(last);
  1289.             if (compare < 0) {
  1290.                 slots.addValidAfter(slot, first, false);
  1291.             } else if (compare > 0) {
  1292.                 slots.addValidBefore(slot, first, false);
  1293.             } else {
  1294.                 // single date, valid for all time
  1295.                 slots.addValidAfter(slot, AbsoluteDate.PAST_INFINITY, false);
  1296.             }
  1297.             return slot;
  1298.         }

  1299.         /** {@inheritDoc} */
  1300.         @Override
  1301.         public double[] value(final Orbit meanOrbit) {

  1302.             // select the coefficients slot
  1303.             final Slot slot = slots.get(meanOrbit.getDate());

  1304.             // Get the True longitude L
  1305.             final double L = meanOrbit.getLv();

  1306.             // Compute the center
  1307.             final double center = L - meanOrbit.getLM();

  1308.             // Initialize short periodic variations
  1309.             final double[] shortPeriodicVariation = slot.cij[0].value(meanOrbit.getDate());
  1310.             final double[] d = slot.di.value(meanOrbit.getDate());
  1311.             for (int i = 0; i < 6; i++) {
  1312.                 shortPeriodicVariation[i] +=  center * d[i];
  1313.             }

  1314.             for (int j = 1; j <= maxFrequencyShortPeriodics; j++) {
  1315.                 final double[] c = slot.cij[j].value(meanOrbit.getDate());
  1316.                 final double[] s = slot.sij[j].value(meanOrbit.getDate());
  1317.                 final SinCos sc  = FastMath.sinCos(j * L);
  1318.                 for (int i = 0; i < 6; i++) {
  1319.                     // add corresponding term to the short periodic variation
  1320.                     shortPeriodicVariation[i] += c[i] * sc.cos();
  1321.                     shortPeriodicVariation[i] += s[i] * sc.sin();
  1322.                 }
  1323.             }

  1324.             return shortPeriodicVariation;
  1325.         }

  1326.         /** {@inheritDoc} */
  1327.         @Override
  1328.         public String getCoefficientsKeyPrefix() {
  1329.             return DSSTZonal.SHORT_PERIOD_PREFIX;
  1330.         }

  1331.         /** {@inheritDoc}
  1332.          * <p>
  1333.          * For zonal terms contributions,there are maxJ cj coefficients,
  1334.          * maxJ sj coefficients and 2 dj coefficients, where maxJ depends
  1335.          * on the orbit. The j index is the integer multiplier for the true
  1336.          * longitude argument in the cj and sj coefficients and the degree
  1337.          * in the polynomial dj coefficients.
  1338.          * </p>
  1339.          */
  1340.         @Override
  1341.         public Map<String, double[]> getCoefficients(final AbsoluteDate date, final Set<String> selected) {

  1342.             // select the coefficients slot
  1343.             final Slot slot = slots.get(date);

  1344.             final Map<String, double[]> coefficients = new HashMap<>(2 * maxFrequencyShortPeriodics + 2);
  1345.             storeIfSelected(coefficients, selected, slot.cij[0].value(date), "d", 0);
  1346.             storeIfSelected(coefficients, selected, slot.di.value(date), "d", 1);
  1347.             for (int j = 1; j <= maxFrequencyShortPeriodics; j++) {
  1348.                 storeIfSelected(coefficients, selected, slot.cij[j].value(date), "c", j);
  1349.                 storeIfSelected(coefficients, selected, slot.sij[j].value(date), "s", j);
  1350.             }
  1351.             return coefficients;

  1352.         }

  1353.         /** Put a coefficient in a map if selected.
  1354.          * @param map map to populate
  1355.          * @param selected set of coefficients that should be put in the map
  1356.          * (empty set means all coefficients are selected)
  1357.          * @param value coefficient value
  1358.          * @param id coefficient identifier
  1359.          * @param indices list of coefficient indices
  1360.          */
  1361.         private void storeIfSelected(final Map<String, double[]> map, final Set<String> selected,
  1362.                                      final double[] value, final String id, final int... indices) {
  1363.             final StringBuilder keyBuilder = new StringBuilder(getCoefficientsKeyPrefix());
  1364.             keyBuilder.append(id);
  1365.             for (int index : indices) {
  1366.                 keyBuilder.append('[').append(index).append(']');
  1367.             }
  1368.             final String key = keyBuilder.toString();
  1369.             if (selected.isEmpty() || selected.contains(key)) {
  1370.                 map.put(key, value);
  1371.             }
  1372.         }

  1373.     }

  1374.     /** The coefficients used to compute the short-periodic zonal contribution.
  1375.     *
  1376.     * <p>
  1377.     * Those coefficients are given in Danielson paper by expressions 4.1-(20) to 4.1.-(25)
  1378.     * </p>
  1379.     * <p>
  1380.     * The coefficients are: <br>
  1381.     * - C<sub>i</sub><sup>j</sup> and S<sub>i</sub><sup>j</sup> <br>
  1382.     * - ρ<sub>j</sub> and σ<sub>j</sub> <br>
  1383.     * - C<sub>i</sub>⁰
  1384.     * </p>
  1385.     *
  1386.     * @author Lucian Barbulescu
  1387.     */
  1388.     private static class FieldZonalShortPeriodicCoefficients <T extends CalculusFieldElement<T>> implements FieldShortPeriodTerms<T> {

  1389.         /** Maximum value for j index. */
  1390.         private final int maxFrequencyShortPeriodics;

  1391.         /** Number of points used in the interpolation process. */
  1392.         private final int interpolationPoints;

  1393.         /** All coefficients slots. */
  1394.         private final transient FieldTimeSpanMap<FieldSlot<T>, T> slots;

  1395.        /** Constructor.
  1396.         * @param maxFrequencyShortPeriodics maximum value for j index
  1397.         * @param interpolationPoints number of points used in the interpolation process
  1398.         * @param slots all coefficients slots
  1399.         */
  1400.         FieldZonalShortPeriodicCoefficients(final int maxFrequencyShortPeriodics, final int interpolationPoints,
  1401.                                             final FieldTimeSpanMap<FieldSlot<T>, T> slots) {

  1402.             // Save parameters
  1403.             this.maxFrequencyShortPeriodics = maxFrequencyShortPeriodics;
  1404.             this.interpolationPoints        = interpolationPoints;
  1405.             this.slots                      = slots;

  1406.         }

  1407.        /** Get the slot valid for some date.
  1408.         * @param meanStates mean states defining the slot
  1409.         * @return slot valid at the specified date
  1410.         */
  1411.         @SuppressWarnings("unchecked")
  1412.         public FieldSlot<T> createSlot(final FieldSpacecraftState<T>... meanStates) {
  1413.             final FieldSlot<T>         slot  = new FieldSlot<>(maxFrequencyShortPeriodics, interpolationPoints);
  1414.             final FieldAbsoluteDate<T> first = meanStates[0].getDate();
  1415.             final FieldAbsoluteDate<T> last  = meanStates[meanStates.length - 1].getDate();
  1416.             if (first.compareTo(last) <= 0) {
  1417.                 slots.addValidAfter(slot, first);
  1418.             } else {
  1419.                 slots.addValidBefore(slot, first);
  1420.             }
  1421.             return slot;
  1422.         }

  1423.         /** {@inheritDoc} */
  1424.         @Override
  1425.         public T[] value(final FieldOrbit<T> meanOrbit) {

  1426.             // select the coefficients slot
  1427.             final FieldSlot<T> slot = slots.get(meanOrbit.getDate());

  1428.             // Get the True longitude L
  1429.             final T L = meanOrbit.getLv();

  1430.             // Compute the center
  1431.             final T center = L.subtract(meanOrbit.getLM());

  1432.             // Initialize short periodic variations
  1433.             final T[] shortPeriodicVariation = slot.cij[0].value(meanOrbit.getDate());
  1434.             final T[] d = slot.di.value(meanOrbit.getDate());
  1435.             for (int i = 0; i < 6; i++) {
  1436.                 shortPeriodicVariation[i] = shortPeriodicVariation[i].add(center.multiply(d[i]));
  1437.             }

  1438.             for (int j = 1; j <= maxFrequencyShortPeriodics; j++) {
  1439.                 final T[]            c   = slot.cij[j].value(meanOrbit.getDate());
  1440.                 final T[]            s   = slot.sij[j].value(meanOrbit.getDate());
  1441.                 final FieldSinCos<T> sc  = FastMath.sinCos(L.multiply(j));
  1442.                 for (int i = 0; i < 6; i++) {
  1443.                     // add corresponding term to the short periodic variation
  1444.                     shortPeriodicVariation[i] = shortPeriodicVariation[i].add(c[i].multiply(sc.cos()));
  1445.                     shortPeriodicVariation[i] = shortPeriodicVariation[i].add(s[i].multiply(sc.sin()));
  1446.                 }
  1447.             }

  1448.             return shortPeriodicVariation;
  1449.         }

  1450.         /** {@inheritDoc} */
  1451.         @Override
  1452.         public String getCoefficientsKeyPrefix() {
  1453.             return DSSTZonal.SHORT_PERIOD_PREFIX;
  1454.         }

  1455.        /** {@inheritDoc}
  1456.         * <p>
  1457.         * For zonal terms contributions,there are maxJ cj coefficients,
  1458.         * maxJ sj coefficients and 2 dj coefficients, where maxJ depends
  1459.         * on the orbit. The j index is the integer multiplier for the true
  1460.         * longitude argument in the cj and sj coefficients and the degree
  1461.         * in the polynomial dj coefficients.
  1462.         * </p>
  1463.         */
  1464.         @Override
  1465.         public Map<String, T[]> getCoefficients(final FieldAbsoluteDate<T> date, final Set<String> selected) {

  1466.             // select the coefficients slot
  1467.             final FieldSlot<T> slot = slots.get(date);

  1468.             final Map<String, T[]> coefficients = new HashMap<>(2 * maxFrequencyShortPeriodics + 2);
  1469.             storeIfSelected(coefficients, selected, slot.cij[0].value(date), "d", 0);
  1470.             storeIfSelected(coefficients, selected, slot.di.value(date), "d", 1);
  1471.             for (int j = 1; j <= maxFrequencyShortPeriodics; j++) {
  1472.                 storeIfSelected(coefficients, selected, slot.cij[j].value(date), "c", j);
  1473.                 storeIfSelected(coefficients, selected, slot.sij[j].value(date), "s", j);
  1474.             }
  1475.             return coefficients;

  1476.         }

  1477.        /** Put a coefficient in a map if selected.
  1478.         * @param map map to populate
  1479.         * @param selected set of coefficients that should be put in the map
  1480.         * (empty set means all coefficients are selected)
  1481.         * @param value coefficient value
  1482.         * @param id coefficient identifier
  1483.         * @param indices list of coefficient indices
  1484.         */
  1485.         private void storeIfSelected(final Map<String, T[]> map, final Set<String> selected,
  1486.                                      final T[] value, final String id, final int... indices) {
  1487.             final StringBuilder keyBuilder = new StringBuilder(getCoefficientsKeyPrefix());
  1488.             keyBuilder.append(id);
  1489.             for (int index : indices) {
  1490.                 keyBuilder.append('[').append(index).append(']');
  1491.             }
  1492.             final String key = keyBuilder.toString();
  1493.             if (selected.isEmpty() || selected.contains(key)) {
  1494.                 map.put(key, value);
  1495.             }
  1496.         }

  1497.     }

  1498.     /** Compute the C<sup>j</sup> and the S<sup>j</sup> coefficients.
  1499.      *  <p>
  1500.      *  Those coefficients are given in Danielson paper by expressions 4.1-(13) to 4.1.-(16b)
  1501.      *  </p>
  1502.      */
  1503.     private class FourierCjSjCoefficients {

  1504.         /** The G<sub>js</sub>, H<sub>js</sub>, I<sub>js</sub> and J<sub>js</sub> polynomials. */
  1505.         private final GHIJjsPolynomials ghijCoef;

  1506.         /** L<sub>n</sub><sup>s</sup>(γ). */
  1507.         private final LnsCoefficients lnsCoef;

  1508.         /** Maximum possible value for n. */
  1509.         private final int nMax;

  1510.         /** Maximum possible value for s. */
  1511.         private final int sMax;

  1512.         /** Maximum possible value for j. */
  1513.         private final int jMax;

  1514.         /** The C<sup>j</sup> coefficients and their derivatives.
  1515.          * <p>
  1516.          * Each column of the matrix contains the following values: <br/>
  1517.          * - C<sup>j</sup> <br/>
  1518.          * - dC<sup>j</sup> / da <br/>
  1519.          * - dC<sup>j</sup> / dh <br/>
  1520.          * - dC<sup>j</sup> / dk <br/>
  1521.          * - dC<sup>j</sup> / dα <br/>
  1522.          * - dC<sup>j</sup> / dβ <br/>
  1523.          * - dC<sup>j</sup> / dγ <br/>
  1524.          * </p>
  1525.          */
  1526.         private final double[][] cCoef;

  1527.         /** The S<sup>j</sup> coefficients and their derivatives.
  1528.          * <p>
  1529.          * Each column of the matrix contains the following values: <br/>
  1530.          * - S<sup>j</sup> <br/>
  1531.          * - dS<sup>j</sup> / da <br/>
  1532.          * - dS<sup>j</sup> / dh <br/>
  1533.          * - dS<sup>j</sup> / dk <br/>
  1534.          * - dS<sup>j</sup> / dα <br/>
  1535.          * - dS<sup>j</sup> / dβ <br/>
  1536.          * - dS<sup>j</sup> / dγ <br/>
  1537.          * </p>
  1538.          */
  1539.         private final double[][] sCoef;

  1540.         /** h * &Chi;³. */
  1541.         private final double hXXX;
  1542.         /** k * &Chi;³. */
  1543.         private final double kXXX;

  1544.         /** Create a set of C<sup>j</sup> and the S<sup>j</sup> coefficients.
  1545.          *  @param date the current date
  1546.          *  @param nMax maximum possible value for n
  1547.          *  @param sMax maximum possible value for s
  1548.          *  @param jMax maximum possible value for j
  1549.          *  @param context container for attributes
  1550.          *  @param hansenObjects initialization of hansen objects
  1551.          */
  1552.         FourierCjSjCoefficients(final AbsoluteDate date,
  1553.                                 final int nMax, final int sMax, final int jMax, final DSSTZonalContext context,
  1554.                                 final HansenObjects hansenObjects) {

  1555.             final AuxiliaryElements auxiliaryElements = context.getAuxiliaryElements();

  1556.             this.ghijCoef = new GHIJjsPolynomials(auxiliaryElements.getK(), auxiliaryElements.getH(), context.getAlpha(), context.getBeta());
  1557.             // Qns coefficients
  1558.             final double[][] Qns  = CoefficientsFactory.computeQns(context.getGamma(), nMax, nMax);

  1559.             this.lnsCoef = new LnsCoefficients(nMax, nMax, Qns, Vns, context.getRoa());
  1560.             this.nMax = nMax;
  1561.             this.sMax = sMax;
  1562.             this.jMax = jMax;

  1563.             // compute the common factors that depends on the mean elements
  1564.             this.hXXX = auxiliaryElements.getH() * context.getChi3();
  1565.             this.kXXX = auxiliaryElements.getK() * context.getChi3();

  1566.             this.cCoef = new double[7][jMax + 1];
  1567.             this.sCoef = new double[7][jMax + 1];

  1568.             for (int s = 0; s <= sMax; s++) {
  1569.                 //Initialise the Hansen roots
  1570.                 hansenObjects.computeHansenObjectsInitValues(context, s);
  1571.             }
  1572.             generateCoefficients(date, context, auxiliaryElements, hansenObjects);
  1573.         }

  1574.         /** Generate all coefficients.
  1575.          * @param date the current date
  1576.          * @param context container for attributes
  1577.          * @param auxiliaryElements auxiliary elements related to the current orbit
  1578.          * @param hansenObjects initialization of hansen objects
  1579.          */
  1580.         private void generateCoefficients(final AbsoluteDate date,
  1581.                                           final DSSTZonalContext context,
  1582.                                           final AuxiliaryElements auxiliaryElements,
  1583.                                           final HansenObjects hansenObjects) {

  1584.             final UnnormalizedSphericalHarmonics harmonics = provider.onDate(date);
  1585.             for (int j = 1; j <= jMax; j++) {

  1586.                 //init arrays
  1587.                 for (int i = 0; i <= 6; i++) {
  1588.                     cCoef[i][j] = 0.;
  1589.                     sCoef[i][j] = 0.;
  1590.                 }

  1591.                 if (isBetween(j, 1, nMax - 1)) {

  1592.                     //compute first double sum where s: j -> N-1 and n: s+1 -> N
  1593.                     for (int s = j; s <= FastMath.min(nMax - 1, sMax); s++) {
  1594.                         // j - s
  1595.                         final int jms = j - s;
  1596.                         // Kronecker symbols (2 - delta(0,s-j)) and (2 - delta(0,j-s))
  1597.                         final int d0smj = (s == j) ? 1 : 2;

  1598.                         for (int n = s + 1; n <= nMax; n++) {
  1599.                             // if n + (j-s) is odd, then the term is equal to zero due to the factor Vn,s-j
  1600.                             if ((n + jms) % 2 == 0) {
  1601.                                 // (2 - delta(0,s-j)) * J<sub>n</sub> * K₀<sup>-n-1,s</sup> * L<sub>n</sub><sup>j-s</sup>
  1602.                                 final double lns = lnsCoef.getLns(n, -jms);
  1603.                                 final double dlns = lnsCoef.getdLnsdGamma(n, -jms);

  1604.                                 final double hjs = ghijCoef.getHjs(s, -jms);
  1605.                                 final double dHjsdh = ghijCoef.getdHjsdh(s, -jms);
  1606.                                 final double dHjsdk = ghijCoef.getdHjsdk(s, -jms);
  1607.                                 final double dHjsdAlpha = ghijCoef.getdHjsdAlpha(s, -jms);
  1608.                                 final double dHjsdBeta = ghijCoef.getdHjsdBeta(s, -jms);

  1609.                                 final double gjs = ghijCoef.getGjs(s, -jms);
  1610.                                 final double dGjsdh = ghijCoef.getdGjsdh(s, -jms);
  1611.                                 final double dGjsdk = ghijCoef.getdGjsdk(s, -jms);
  1612.                                 final double dGjsdAlpha = ghijCoef.getdGjsdAlpha(s, -jms);
  1613.                                 final double dGjsdBeta = ghijCoef.getdGjsdBeta(s, -jms);

  1614.                                 // J<sub>n</sub>
  1615.                                 final double jn = -harmonics.getUnnormalizedCnm(n, 0);

  1616.                                 // K₀<sup>-n-1,s</sup>
  1617.                                 final double kns   = hansenObjects.getHansenObjects()[s].getValue(-n - 1, context.getChi());
  1618.                                 final double dkns  = hansenObjects.getHansenObjects()[s].getDerivative(-n - 1, context.getChi());

  1619.                                 final double coef0 = d0smj * jn;
  1620.                                 final double coef1 = coef0 * lns;
  1621.                                 final double coef2 = coef1 * kns;
  1622.                                 final double coef3 = coef2 * hjs;
  1623.                                 final double coef4 = coef2 * gjs;

  1624.                                 // Add the term to the coefficients
  1625.                                 cCoef[0][j] += coef3;
  1626.                                 cCoef[1][j] += coef3 * (n + 1);
  1627.                                 cCoef[2][j] += coef1 * (kns * dHjsdh + hjs * hXXX * dkns);
  1628.                                 cCoef[3][j] += coef1 * (kns * dHjsdk + hjs * kXXX * dkns);
  1629.                                 cCoef[4][j] += coef2 * dHjsdAlpha;
  1630.                                 cCoef[5][j] += coef2 * dHjsdBeta;
  1631.                                 cCoef[6][j] += coef0 * dlns * kns * hjs;

  1632.                                 sCoef[0][j] += coef4;
  1633.                                 sCoef[1][j] += coef4 * (n + 1);
  1634.                                 sCoef[2][j] += coef1 * (kns * dGjsdh + gjs * hXXX * dkns);
  1635.                                 sCoef[3][j] += coef1 * (kns * dGjsdk + gjs * kXXX * dkns);
  1636.                                 sCoef[4][j] += coef2 * dGjsdAlpha;
  1637.                                 sCoef[5][j] += coef2 * dGjsdBeta;
  1638.                                 sCoef[6][j] += coef0 * dlns * kns * gjs;
  1639.                             }
  1640.                         }
  1641.                     }

  1642.                     //compute second double sum where s: 0 -> N-j and n: max(j+s, j+1) -> N
  1643.                     for (int s = 0; s <= FastMath.min(nMax - j, sMax); s++) {
  1644.                         // j + s
  1645.                         final int jps = j + s;
  1646.                         // Kronecker symbols (2 - delta(0,j+s))
  1647.                         final double d0spj = (s == -j) ? 1 : 2;

  1648.                         for (int n = FastMath.max(j + s, j + 1); n <= nMax; n++) {
  1649.                             // if n + (j+s) is odd, then the term is equal to zero due to the factor Vn,s+j
  1650.                             if ((n + jps) % 2 == 0) {
  1651.                                 // (2 - delta(0,s+j)) * J<sub>n</sub> * K₀<sup>-n-1,s</sup> * L<sub>n</sub><sup>j+s</sup>
  1652.                                 final double lns = lnsCoef.getLns(n, jps);
  1653.                                 final double dlns = lnsCoef.getdLnsdGamma(n, jps);

  1654.                                 final double hjs = ghijCoef.getHjs(s, jps);
  1655.                                 final double dHjsdh = ghijCoef.getdHjsdh(s, jps);
  1656.                                 final double dHjsdk = ghijCoef.getdHjsdk(s, jps);
  1657.                                 final double dHjsdAlpha = ghijCoef.getdHjsdAlpha(s, jps);
  1658.                                 final double dHjsdBeta = ghijCoef.getdHjsdBeta(s, jps);

  1659.                                 final double gjs = ghijCoef.getGjs(s, jps);
  1660.                                 final double dGjsdh = ghijCoef.getdGjsdh(s, jps);
  1661.                                 final double dGjsdk = ghijCoef.getdGjsdk(s, jps);
  1662.                                 final double dGjsdAlpha = ghijCoef.getdGjsdAlpha(s, jps);
  1663.                                 final double dGjsdBeta = ghijCoef.getdGjsdBeta(s, jps);

  1664.                                 // J<sub>n</sub>
  1665.                                 final double jn = -harmonics.getUnnormalizedCnm(n, 0);

  1666.                                 // K₀<sup>-n-1,s</sup>
  1667.                                 final double kns   = hansenObjects.getHansenObjects()[s].getValue(-n - 1, context.getChi());
  1668.                                 final double dkns  = hansenObjects.getHansenObjects()[s].getDerivative(-n - 1, context.getChi());

  1669.                                 final double coef0 = d0spj * jn;
  1670.                                 final double coef1 = coef0 * lns;
  1671.                                 final double coef2 = coef1 * kns;

  1672.                                 final double coef3 = coef2 * hjs;
  1673.                                 final double coef4 = coef2 * gjs;

  1674.                                 // Add the term to the coefficients
  1675.                                 cCoef[0][j] -= coef3;
  1676.                                 cCoef[1][j] -= coef3 * (n + 1);
  1677.                                 cCoef[2][j] -= coef1 * (kns * dHjsdh + hjs * hXXX * dkns);
  1678.                                 cCoef[3][j] -= coef1 * (kns * dHjsdk + hjs * kXXX * dkns);
  1679.                                 cCoef[4][j] -= coef2 * dHjsdAlpha;
  1680.                                 cCoef[5][j] -= coef2 * dHjsdBeta;
  1681.                                 cCoef[6][j] -= coef0 * dlns * kns * hjs;

  1682.                                 sCoef[0][j] += coef4;
  1683.                                 sCoef[1][j] += coef4 * (n + 1);
  1684.                                 sCoef[2][j] += coef1 * (kns * dGjsdh + gjs * hXXX * dkns);
  1685.                                 sCoef[3][j] += coef1 * (kns * dGjsdk + gjs * kXXX * dkns);
  1686.                                 sCoef[4][j] += coef2 * dGjsdAlpha;
  1687.                                 sCoef[5][j] += coef2 * dGjsdBeta;
  1688.                                 sCoef[6][j] += coef0 * dlns * kns * gjs;
  1689.                             }
  1690.                         }
  1691.                     }

  1692.                     //compute third double sum where s: 1 -> j and  n: j+1 -> N
  1693.                     for (int s = 1; s <= FastMath.min(j, sMax); s++) {
  1694.                         // j - s
  1695.                         final int jms = j - s;
  1696.                         // Kronecker symbols (2 - delta(0,s-j)) and (2 - delta(0,j-s))
  1697.                         final int d0smj = (s == j) ? 1 : 2;

  1698.                         for (int n = j + 1; n <= nMax; n++) {
  1699.                             // if n + (j-s) is odd, then the term is equal to zero due to the factor Vn,s-j
  1700.                             if ((n + jms) % 2 == 0) {
  1701.                                 // (2 - delta(0,j-s)) * J<sub>n</sub> * K₀<sup>-n-1,s</sup> * L<sub>n</sub><sup>j-s</sup>
  1702.                                 final double lns = lnsCoef.getLns(n, jms);
  1703.                                 final double dlns = lnsCoef.getdLnsdGamma(n, jms);

  1704.                                 final double ijs = ghijCoef.getIjs(s, jms);
  1705.                                 final double dIjsdh = ghijCoef.getdIjsdh(s, jms);
  1706.                                 final double dIjsdk = ghijCoef.getdIjsdk(s, jms);
  1707.                                 final double dIjsdAlpha = ghijCoef.getdIjsdAlpha(s, jms);
  1708.                                 final double dIjsdBeta = ghijCoef.getdIjsdBeta(s, jms);

  1709.                                 final double jjs = ghijCoef.getJjs(s, jms);
  1710.                                 final double dJjsdh = ghijCoef.getdJjsdh(s, jms);
  1711.                                 final double dJjsdk = ghijCoef.getdJjsdk(s, jms);
  1712.                                 final double dJjsdAlpha = ghijCoef.getdJjsdAlpha(s, jms);
  1713.                                 final double dJjsdBeta = ghijCoef.getdJjsdBeta(s, jms);

  1714.                                 // J<sub>n</sub>
  1715.                                 final double jn = -harmonics.getUnnormalizedCnm(n, 0);

  1716.                                 // K₀<sup>-n-1,s</sup>
  1717.                                 final double kns   = hansenObjects.getHansenObjects()[s].getValue(-n - 1, context.getChi());
  1718.                                 final double dkns  = hansenObjects.getHansenObjects()[s].getDerivative(-n - 1, context.getChi());

  1719.                                 final double coef0 = d0smj * jn;
  1720.                                 final double coef1 = coef0 * lns;
  1721.                                 final double coef2 = coef1 * kns;

  1722.                                 final double coef3 = coef2 * ijs;
  1723.                                 final double coef4 = coef2 * jjs;

  1724.                                 // Add the term to the coefficients
  1725.                                 cCoef[0][j] -= coef3;
  1726.                                 cCoef[1][j] -= coef3 * (n + 1);
  1727.                                 cCoef[2][j] -= coef1 * (kns * dIjsdh + ijs * hXXX * dkns);
  1728.                                 cCoef[3][j] -= coef1 * (kns * dIjsdk + ijs * kXXX * dkns);
  1729.                                 cCoef[4][j] -= coef2 * dIjsdAlpha;
  1730.                                 cCoef[5][j] -= coef2 * dIjsdBeta;
  1731.                                 cCoef[6][j] -= coef0 * dlns * kns * ijs;

  1732.                                 sCoef[0][j] += coef4;
  1733.                                 sCoef[1][j] += coef4 * (n + 1);
  1734.                                 sCoef[2][j] += coef1 * (kns * dJjsdh + jjs * hXXX * dkns);
  1735.                                 sCoef[3][j] += coef1 * (kns * dJjsdk + jjs * kXXX * dkns);
  1736.                                 sCoef[4][j] += coef2 * dJjsdAlpha;
  1737.                                 sCoef[5][j] += coef2 * dJjsdBeta;
  1738.                                 sCoef[6][j] += coef0 * dlns * kns * jjs;
  1739.                             }
  1740.                         }
  1741.                     }
  1742.                 }

  1743.                 if (isBetween(j, 2, nMax)) {
  1744.                     //add first term
  1745.                     // J<sub>j</sub>
  1746.                     final double jj = -harmonics.getUnnormalizedCnm(j, 0);
  1747.                     double kns = hansenObjects.getHansenObjects()[0].getValue(-j - 1, context.getChi());
  1748.                     double dkns = hansenObjects.getHansenObjects()[0].getDerivative(-j - 1, context.getChi());

  1749.                     double lns = lnsCoef.getLns(j, j);
  1750.                     //dlns is 0 because n == s == j

  1751.                     final double hjs = ghijCoef.getHjs(0, j);
  1752.                     final double dHjsdh = ghijCoef.getdHjsdh(0, j);
  1753.                     final double dHjsdk = ghijCoef.getdHjsdk(0, j);
  1754.                     final double dHjsdAlpha = ghijCoef.getdHjsdAlpha(0, j);
  1755.                     final double dHjsdBeta = ghijCoef.getdHjsdBeta(0, j);

  1756.                     final double gjs = ghijCoef.getGjs(0, j);
  1757.                     final double dGjsdh = ghijCoef.getdGjsdh(0, j);
  1758.                     final double dGjsdk = ghijCoef.getdGjsdk(0, j);
  1759.                     final double dGjsdAlpha = ghijCoef.getdGjsdAlpha(0, j);
  1760.                     final double dGjsdBeta = ghijCoef.getdGjsdBeta(0, j);

  1761.                     // 2 * J<sub>j</sub> * K₀<sup>-j-1,0</sup> * L<sub>j</sub><sup>j</sup>
  1762.                     double coef0 = 2 * jj;
  1763.                     double coef1 = coef0 * lns;
  1764.                     double coef2 = coef1 * kns;

  1765.                     double coef3 = coef2 * hjs;
  1766.                     double coef4 = coef2 * gjs;

  1767.                     // Add the term to the coefficients
  1768.                     cCoef[0][j] -= coef3;
  1769.                     cCoef[1][j] -= coef3 * (j + 1);
  1770.                     cCoef[2][j] -= coef1 * (kns * dHjsdh + hjs * hXXX * dkns);
  1771.                     cCoef[3][j] -= coef1 * (kns * dHjsdk + hjs * kXXX * dkns);
  1772.                     cCoef[4][j] -= coef2 * dHjsdAlpha;
  1773.                     cCoef[5][j] -= coef2 * dHjsdBeta;
  1774.                     //no contribution to cCoef[6][j] because dlns is 0

  1775.                     sCoef[0][j] += coef4;
  1776.                     sCoef[1][j] += coef4 * (j + 1);
  1777.                     sCoef[2][j] += coef1 * (kns * dGjsdh + gjs * hXXX * dkns);
  1778.                     sCoef[3][j] += coef1 * (kns * dGjsdk + gjs * kXXX * dkns);
  1779.                     sCoef[4][j] += coef2 * dGjsdAlpha;
  1780.                     sCoef[5][j] += coef2 * dGjsdBeta;
  1781.                     //no contribution to sCoef[6][j] because dlns is 0

  1782.                     //compute simple sum where s: 1 -> j-1
  1783.                     for (int s = 1; s <= FastMath.min(j - 1, sMax); s++) {
  1784.                         // j - s
  1785.                         final int jms = j - s;
  1786.                         // Kronecker symbols (2 - delta(0,s-j)) and (2 - delta(0,j-s))
  1787.                         final int d0smj = (s == j) ? 1 : 2;

  1788.                         // if s is odd, then the term is equal to zero due to the factor Vj,s-j
  1789.                         if (s % 2 == 0) {
  1790.                             // (2 - delta(0,j-s)) * J<sub>j</sub> * K₀<sup>-j-1,s</sup> * L<sub>j</sub><sup>j-s</sup>
  1791.                             kns   = hansenObjects.getHansenObjects()[s].getValue(-j - 1, context.getChi());
  1792.                             dkns  = hansenObjects.getHansenObjects()[s].getDerivative(-j - 1, context.getChi());

  1793.                             lns = lnsCoef.getLns(j, jms);
  1794.                             final double dlns = lnsCoef.getdLnsdGamma(j, jms);

  1795.                             final double ijs = ghijCoef.getIjs(s, jms);
  1796.                             final double dIjsdh = ghijCoef.getdIjsdh(s, jms);
  1797.                             final double dIjsdk = ghijCoef.getdIjsdk(s, jms);
  1798.                             final double dIjsdAlpha = ghijCoef.getdIjsdAlpha(s, jms);
  1799.                             final double dIjsdBeta = ghijCoef.getdIjsdBeta(s, jms);

  1800.                             final double jjs = ghijCoef.getJjs(s, jms);
  1801.                             final double dJjsdh = ghijCoef.getdJjsdh(s, jms);
  1802.                             final double dJjsdk = ghijCoef.getdJjsdk(s, jms);
  1803.                             final double dJjsdAlpha = ghijCoef.getdJjsdAlpha(s, jms);
  1804.                             final double dJjsdBeta = ghijCoef.getdJjsdBeta(s, jms);

  1805.                             coef0 = d0smj * jj;
  1806.                             coef1 = coef0 * lns;
  1807.                             coef2 = coef1 * kns;

  1808.                             coef3 = coef2 * ijs;
  1809.                             coef4 = coef2 * jjs;

  1810.                             // Add the term to the coefficients
  1811.                             cCoef[0][j] -= coef3;
  1812.                             cCoef[1][j] -= coef3 * (j + 1);
  1813.                             cCoef[2][j] -= coef1 * (kns * dIjsdh + ijs * hXXX * dkns);
  1814.                             cCoef[3][j] -= coef1 * (kns * dIjsdk + ijs * kXXX * dkns);
  1815.                             cCoef[4][j] -= coef2 * dIjsdAlpha;
  1816.                             cCoef[5][j] -= coef2 * dIjsdBeta;
  1817.                             cCoef[6][j] -= coef0 * dlns * kns * ijs;

  1818.                             sCoef[0][j] += coef4;
  1819.                             sCoef[1][j] += coef4 * (j + 1);
  1820.                             sCoef[2][j] += coef1 * (kns * dJjsdh + jjs * hXXX * dkns);
  1821.                             sCoef[3][j] += coef1 * (kns * dJjsdk + jjs * kXXX * dkns);
  1822.                             sCoef[4][j] += coef2 * dJjsdAlpha;
  1823.                             sCoef[5][j] += coef2 * dJjsdBeta;
  1824.                             sCoef[6][j] += coef0 * dlns * kns * jjs;
  1825.                         }
  1826.                     }
  1827.                 }

  1828.                 if (isBetween(j, 3, 2 * nMax - 1)) {
  1829.                     //compute uppercase sigma expressions

  1830.                     //min(j-1,N)
  1831.                     final int minjm1on = FastMath.min(j - 1, nMax);

  1832.                     //if j is even
  1833.                     if (j % 2 == 0) {
  1834.                         //compute first double sum where s: j-min(j-1,N) -> j/2-1 and n: j-s -> min(j-1,N)
  1835.                         for (int s = j - minjm1on; s <= FastMath.min(j / 2 - 1, sMax); s++) {
  1836.                             // j - s
  1837.                             final int jms = j - s;
  1838.                             // Kronecker symbols (2 - delta(0,s-j)) and (2 - delta(0,j-s))
  1839.                             final int d0smj = (s == j) ? 1 : 2;

  1840.                             for (int n = j - s; n <= minjm1on; n++) {
  1841.                                 // if n + (j-s) is odd, then the term is equal to zero due to the factor Vn,s-j
  1842.                                 if ((n + jms) % 2 == 0) {
  1843.                                     // (2 - delta(0,j-s)) * J<sub>n</sub> * K₀<sup>-n-1,s</sup> * L<sub>n</sub><sup>j-s</sup>
  1844.                                     final double lns = lnsCoef.getLns(n, jms);
  1845.                                     final double dlns = lnsCoef.getdLnsdGamma(n, jms);

  1846.                                     final double ijs = ghijCoef.getIjs(s, jms);
  1847.                                     final double dIjsdh = ghijCoef.getdIjsdh(s, jms);
  1848.                                     final double dIjsdk = ghijCoef.getdIjsdk(s, jms);
  1849.                                     final double dIjsdAlpha = ghijCoef.getdIjsdAlpha(s, jms);
  1850.                                     final double dIjsdBeta = ghijCoef.getdIjsdBeta(s, jms);

  1851.                                     final double jjs = ghijCoef.getJjs(s, jms);
  1852.                                     final double dJjsdh = ghijCoef.getdJjsdh(s, jms);
  1853.                                     final double dJjsdk = ghijCoef.getdJjsdk(s, jms);
  1854.                                     final double dJjsdAlpha = ghijCoef.getdJjsdAlpha(s, jms);
  1855.                                     final double dJjsdBeta = ghijCoef.getdJjsdBeta(s, jms);

  1856.                                     // J<sub>n</sub>
  1857.                                     final double jn = -harmonics.getUnnormalizedCnm(n, 0);

  1858.                                     // K₀<sup>-n-1,s</sup>
  1859.                                     final double kns   = hansenObjects.getHansenObjects()[s].getValue(-n - 1, context.getChi());
  1860.                                     final double dkns  = hansenObjects.getHansenObjects()[s].getDerivative(-n - 1, context.getChi());

  1861.                                     final double coef0 = d0smj * jn;
  1862.                                     final double coef1 = coef0 * lns;
  1863.                                     final double coef2 = coef1 * kns;

  1864.                                     final double coef3 = coef2 * ijs;
  1865.                                     final double coef4 = coef2 * jjs;

  1866.                                     // Add the term to the coefficients
  1867.                                     cCoef[0][j] -= coef3;
  1868.                                     cCoef[1][j] -= coef3 * (n + 1);
  1869.                                     cCoef[2][j] -= coef1 * (kns * dIjsdh + ijs * hXXX * dkns);
  1870.                                     cCoef[3][j] -= coef1 * (kns * dIjsdk + ijs * kXXX * dkns);
  1871.                                     cCoef[4][j] -= coef2 * dIjsdAlpha;
  1872.                                     cCoef[5][j] -= coef2 * dIjsdBeta;
  1873.                                     cCoef[6][j] -= coef0 * dlns * kns * ijs;

  1874.                                     sCoef[0][j] += coef4;
  1875.                                     sCoef[1][j] += coef4 * (n + 1);
  1876.                                     sCoef[2][j] += coef1 * (kns * dJjsdh + jjs * hXXX * dkns);
  1877.                                     sCoef[3][j] += coef1 * (kns * dJjsdk + jjs * kXXX * dkns);
  1878.                                     sCoef[4][j] += coef2 * dJjsdAlpha;
  1879.                                     sCoef[5][j] += coef2 * dJjsdBeta;
  1880.                                     sCoef[6][j] += coef0 * dlns * kns * jjs;
  1881.                                 }
  1882.                             }
  1883.                         }

  1884.                         //compute second double sum where s: j/2 -> min(j-1,N)-1 and n: s+1 -> min(j-1,N)
  1885.                         for (int s = j / 2; s <=  FastMath.min(minjm1on - 1, sMax); s++) {
  1886.                             // j - s
  1887.                             final int jms = j - s;
  1888.                             // Kronecker symbols (2 - delta(0,s-j)) and (2 - delta(0,j-s))
  1889.                             final int d0smj = (s == j) ? 1 : 2;

  1890.                             for (int n = s + 1; n <= minjm1on; n++) {
  1891.                                 // if n + (j-s) is odd, then the term is equal to zero due to the factor Vn,s-j
  1892.                                 if ((n + jms) % 2 == 0) {
  1893.                                     // (2 - delta(0,j-s)) * J<sub>n</sub> * K₀<sup>-n-1,s</sup> * L<sub>n</sub><sup>j-s</sup>
  1894.                                     final double lns = lnsCoef.getLns(n, jms);
  1895.                                     final double dlns = lnsCoef.getdLnsdGamma(n, jms);

  1896.                                     final double ijs = ghijCoef.getIjs(s, jms);
  1897.                                     final double dIjsdh = ghijCoef.getdIjsdh(s, jms);
  1898.                                     final double dIjsdk = ghijCoef.getdIjsdk(s, jms);
  1899.                                     final double dIjsdAlpha = ghijCoef.getdIjsdAlpha(s, jms);
  1900.                                     final double dIjsdBeta = ghijCoef.getdIjsdBeta(s, jms);

  1901.                                     final double jjs = ghijCoef.getJjs(s, jms);
  1902.                                     final double dJjsdh = ghijCoef.getdJjsdh(s, jms);
  1903.                                     final double dJjsdk = ghijCoef.getdJjsdk(s, jms);
  1904.                                     final double dJjsdAlpha = ghijCoef.getdJjsdAlpha(s, jms);
  1905.                                     final double dJjsdBeta = ghijCoef.getdJjsdBeta(s, jms);

  1906.                                     // J<sub>n</sub>
  1907.                                     final double jn = -harmonics.getUnnormalizedCnm(n, 0);

  1908.                                     // K₀<sup>-n-1,s</sup>
  1909.                                     final double kns   = hansenObjects.getHansenObjects()[s].getValue(-n - 1, context.getChi());
  1910.                                     final double dkns  = hansenObjects.getHansenObjects()[s].getDerivative(-n - 1, context.getChi());

  1911.                                     final double coef0 = d0smj * jn;
  1912.                                     final double coef1 = coef0 * lns;
  1913.                                     final double coef2 = coef1 * kns;

  1914.                                     final double coef3 = coef2 * ijs;
  1915.                                     final double coef4 = coef2 * jjs;

  1916.                                     // Add the term to the coefficients
  1917.                                     cCoef[0][j] -= coef3;
  1918.                                     cCoef[1][j] -= coef3 * (n + 1);
  1919.                                     cCoef[2][j] -= coef1 * (kns * dIjsdh + ijs * hXXX * dkns);
  1920.                                     cCoef[3][j] -= coef1 * (kns * dIjsdk + ijs * kXXX * dkns);
  1921.                                     cCoef[4][j] -= coef2 * dIjsdAlpha;
  1922.                                     cCoef[5][j] -= coef2 * dIjsdBeta;
  1923.                                     cCoef[6][j] -= coef0 * dlns * kns * ijs;

  1924.                                     sCoef[0][j] += coef4;
  1925.                                     sCoef[1][j] += coef4 * (n + 1);
  1926.                                     sCoef[2][j] += coef1 * (kns * dJjsdh + jjs * hXXX * dkns);
  1927.                                     sCoef[3][j] += coef1 * (kns * dJjsdk + jjs * kXXX * dkns);
  1928.                                     sCoef[4][j] += coef2 * dJjsdAlpha;
  1929.                                     sCoef[5][j] += coef2 * dJjsdBeta;
  1930.                                     sCoef[6][j] += coef0 * dlns * kns * jjs;
  1931.                                 }
  1932.                             }
  1933.                         }
  1934.                     }

  1935.                     //if j is odd
  1936.                     else {
  1937.                         //compute first double sum where s: (j-1)/2 -> min(j-1,N)-1 and n: s+1 -> min(j-1,N)
  1938.                         for (int s = (j - 1) / 2; s <= FastMath.min(minjm1on - 1, sMax); s++) {
  1939.                             // j - s
  1940.                             final int jms = j - s;
  1941.                             // Kronecker symbols (2 - delta(0,s-j)) and (2 - delta(0,j-s))
  1942.                             final int d0smj = (s == j) ? 1 : 2;

  1943.                             for (int n = s + 1; n <= minjm1on; n++) {
  1944.                                 // if n + (j-s) is odd, then the term is equal to zero due to the factor Vn,s-j
  1945.                                 if ((n + jms) % 2 == 0) {
  1946.                                     // (2 - delta(0,j-s)) * J<sub>n</sub> * K₀<sup>-n-1,s</sup> * L<sub>n</sub><sup>j-s</sup>
  1947.                                     final double lns = lnsCoef.getLns(n, jms);
  1948.                                     final double dlns = lnsCoef.getdLnsdGamma(n, jms);

  1949.                                     final double ijs = ghijCoef.getIjs(s, jms);
  1950.                                     final double dIjsdh = ghijCoef.getdIjsdh(s, jms);
  1951.                                     final double dIjsdk = ghijCoef.getdIjsdk(s, jms);
  1952.                                     final double dIjsdAlpha = ghijCoef.getdIjsdAlpha(s, jms);
  1953.                                     final double dIjsdBeta = ghijCoef.getdIjsdBeta(s, jms);

  1954.                                     final double jjs = ghijCoef.getJjs(s, jms);
  1955.                                     final double dJjsdh = ghijCoef.getdJjsdh(s, jms);
  1956.                                     final double dJjsdk = ghijCoef.getdJjsdk(s, jms);
  1957.                                     final double dJjsdAlpha = ghijCoef.getdJjsdAlpha(s, jms);
  1958.                                     final double dJjsdBeta = ghijCoef.getdJjsdBeta(s, jms);

  1959.                                     // J<sub>n</sub>
  1960.                                     final double jn = -harmonics.getUnnormalizedCnm(n, 0);

  1961.                                     // K₀<sup>-n-1,s</sup>

  1962.                                     final double kns = hansenObjects.getHansenObjects()[s].getValue(-n - 1, context.getChi());
  1963.                                     final double dkns  = hansenObjects.getHansenObjects()[s].getDerivative(-n - 1, context.getChi());

  1964.                                     final double coef0 = d0smj * jn;
  1965.                                     final double coef1 = coef0 * lns;
  1966.                                     final double coef2 = coef1 * kns;

  1967.                                     final double coef3 = coef2 * ijs;
  1968.                                     final double coef4 = coef2 * jjs;

  1969.                                     // Add the term to the coefficients
  1970.                                     cCoef[0][j] -= coef3;
  1971.                                     cCoef[1][j] -= coef3 * (n + 1);
  1972.                                     cCoef[2][j] -= coef1 * (kns * dIjsdh + ijs * hXXX * dkns);
  1973.                                     cCoef[3][j] -= coef1 * (kns * dIjsdk + ijs * kXXX * dkns);
  1974.                                     cCoef[4][j] -= coef2 * dIjsdAlpha;
  1975.                                     cCoef[5][j] -= coef2 * dIjsdBeta;
  1976.                                     cCoef[6][j] -= coef0 * dlns * kns * ijs;

  1977.                                     sCoef[0][j] += coef4;
  1978.                                     sCoef[1][j] += coef4 * (n + 1);
  1979.                                     sCoef[2][j] += coef1 * (kns * dJjsdh + jjs * hXXX * dkns);
  1980.                                     sCoef[3][j] += coef1 * (kns * dJjsdk + jjs * kXXX * dkns);
  1981.                                     sCoef[4][j] += coef2 * dJjsdAlpha;
  1982.                                     sCoef[5][j] += coef2 * dJjsdBeta;
  1983.                                     sCoef[6][j] += coef0 * dlns * kns * jjs;
  1984.                                 }
  1985.                             }
  1986.                         }

  1987.                         //the second double sum is added only if N >= 4 and j between 5 and 2*N-3
  1988.                         if (nMax >= 4 && isBetween(j, 5, 2 * nMax - 3)) {
  1989.                             //compute second double sum where s: j-min(j-1,N) -> (j-3)/2 and n: j-s -> min(j-1,N)
  1990.                             for (int s = j - minjm1on; s <= FastMath.min((j - 3) / 2, sMax); s++) {
  1991.                                 // j - s
  1992.                                 final int jms = j - s;
  1993.                                 // Kronecker symbols (2 - delta(0,s-j)) and (2 - delta(0,j-s))
  1994.                                 final int d0smj = (s == j) ? 1 : 2;

  1995.                                 for (int n = j - s; n <= minjm1on; n++) {
  1996.                                     // if n + (j-s) is odd, then the term is equal to zero due to the factor Vn,s-j
  1997.                                     if ((n + jms) % 2 == 0) {
  1998.                                         // (2 - delta(0,j-s)) * J<sub>n</sub> * K₀<sup>-n-1,s</sup> * L<sub>n</sub><sup>j-s</sup>
  1999.                                         final double lns = lnsCoef.getLns(n, jms);
  2000.                                         final double dlns = lnsCoef.getdLnsdGamma(n, jms);

  2001.                                         final double ijs = ghijCoef.getIjs(s, jms);
  2002.                                         final double dIjsdh = ghijCoef.getdIjsdh(s, jms);
  2003.                                         final double dIjsdk = ghijCoef.getdIjsdk(s, jms);
  2004.                                         final double dIjsdAlpha = ghijCoef.getdIjsdAlpha(s, jms);
  2005.                                         final double dIjsdBeta = ghijCoef.getdIjsdBeta(s, jms);

  2006.                                         final double jjs = ghijCoef.getJjs(s, jms);
  2007.                                         final double dJjsdh = ghijCoef.getdJjsdh(s, jms);
  2008.                                         final double dJjsdk = ghijCoef.getdJjsdk(s, jms);
  2009.                                         final double dJjsdAlpha = ghijCoef.getdJjsdAlpha(s, jms);
  2010.                                         final double dJjsdBeta = ghijCoef.getdJjsdBeta(s, jms);

  2011.                                         // J<sub>n</sub>
  2012.                                         final double jn = -harmonics.getUnnormalizedCnm(n, 0);

  2013.                                         // K₀<sup>-n-1,s</sup>
  2014.                                         final double kns   = hansenObjects.getHansenObjects()[s].getValue(-n - 1, context.getChi());
  2015.                                         final double dkns  = hansenObjects.getHansenObjects()[s].getDerivative(-n - 1, context.getChi());

  2016.                                         final double coef0 = d0smj * jn;
  2017.                                         final double coef1 = coef0 * lns;
  2018.                                         final double coef2 = coef1 * kns;

  2019.                                         final double coef3 = coef2 * ijs;
  2020.                                         final double coef4 = coef2 * jjs;

  2021.                                         // Add the term to the coefficients
  2022.                                         cCoef[0][j] -= coef3;
  2023.                                         cCoef[1][j] -= coef3 * (n + 1);
  2024.                                         cCoef[2][j] -= coef1 * (kns * dIjsdh + ijs * hXXX * dkns);
  2025.                                         cCoef[3][j] -= coef1 * (kns * dIjsdk + ijs * kXXX * dkns);
  2026.                                         cCoef[4][j] -= coef2 * dIjsdAlpha;
  2027.                                         cCoef[5][j] -= coef2 * dIjsdBeta;
  2028.                                         cCoef[6][j] -= coef0 * dlns * kns * ijs;

  2029.                                         sCoef[0][j] += coef4;
  2030.                                         sCoef[1][j] += coef4 * (n + 1);
  2031.                                         sCoef[2][j] += coef1 * (kns * dJjsdh + jjs * hXXX * dkns);
  2032.                                         sCoef[3][j] += coef1 * (kns * dJjsdk + jjs * kXXX * dkns);
  2033.                                         sCoef[4][j] += coef2 * dJjsdAlpha;
  2034.                                         sCoef[5][j] += coef2 * dJjsdBeta;
  2035.                                         sCoef[6][j] += coef0 * dlns * kns * jjs;
  2036.                                     }
  2037.                                 }
  2038.                             }
  2039.                         }
  2040.                     }
  2041.                 }

  2042.                 cCoef[0][j] *= -context.getMuoa() / j;
  2043.                 cCoef[1][j] *=  context.getMuoa() / ( j * auxiliaryElements.getSma() );
  2044.                 cCoef[2][j] *= -context.getMuoa() / j;
  2045.                 cCoef[3][j] *= -context.getMuoa() / j;
  2046.                 cCoef[4][j] *= -context.getMuoa() / j;
  2047.                 cCoef[5][j] *= -context.getMuoa() / j;
  2048.                 cCoef[6][j] *= -context.getMuoa() / j;

  2049.                 sCoef[0][j] *= -context.getMuoa() / j;
  2050.                 sCoef[1][j] *=  context.getMuoa() / ( j * auxiliaryElements.getSma() );
  2051.                 sCoef[2][j] *= -context.getMuoa() / j;
  2052.                 sCoef[3][j] *= -context.getMuoa() / j;
  2053.                 sCoef[4][j] *= -context.getMuoa() / j;
  2054.                 sCoef[5][j] *= -context.getMuoa() / j;
  2055.                 sCoef[6][j] *= -context.getMuoa() / j;

  2056.             }
  2057.         }

  2058.         /** Check if an index is within the accepted interval.
  2059.          *
  2060.          * @param index the index to check
  2061.          * @param lowerBound the lower bound of the interval
  2062.          * @param upperBound the upper bound of the interval
  2063.          * @return true if the index is between the lower and upper bounds, false otherwise
  2064.          */
  2065.         private boolean isBetween(final int index, final int lowerBound, final int upperBound) {
  2066.             return index >= lowerBound && index <= upperBound;
  2067.         }

  2068.         /**Get the value of C<sup>j</sup>.
  2069.          *
  2070.          * @param j j index
  2071.          * @return C<sup>j</sup>
  2072.          */
  2073.         public double getCj(final int j) {
  2074.             return cCoef[0][j];
  2075.         }

  2076.         /**Get the value of dC<sup>j</sup> / da.
  2077.          *
  2078.          * @param j j index
  2079.          * @return dC<sup>j</sup> / da
  2080.          */
  2081.         public double getdCjdA(final int j) {
  2082.             return cCoef[1][j];
  2083.         }

  2084.         /**Get the value of dC<sup>j</sup> / dh.
  2085.          *
  2086.          * @param j j index
  2087.          * @return dC<sup>j</sup> / dh
  2088.          */
  2089.         public double getdCjdH(final int j) {
  2090.             return cCoef[2][j];
  2091.         }

  2092.         /**Get the value of dC<sup>j</sup> / dk.
  2093.          *
  2094.          * @param j j index
  2095.          * @return dC<sup>j</sup> / dk
  2096.          */
  2097.         public double getdCjdK(final int j) {
  2098.             return cCoef[3][j];
  2099.         }

  2100.         /**Get the value of dC<sup>j</sup> / dα.
  2101.          *
  2102.          * @param j j index
  2103.          * @return dC<sup>j</sup> / dα
  2104.          */
  2105.         public double getdCjdAlpha(final int j) {
  2106.             return cCoef[4][j];
  2107.         }

  2108.         /**Get the value of dC<sup>j</sup> / dβ.
  2109.          *
  2110.          * @param j j index
  2111.          * @return dC<sup>j</sup> / dβ
  2112.          */
  2113.         public double getdCjdBeta(final int j) {
  2114.             return cCoef[5][j];
  2115.         }

  2116.         /**Get the value of dC<sup>j</sup> / dγ.
  2117.          *
  2118.          * @param j j index
  2119.          * @return dC<sup>j</sup> / dγ
  2120.          */
  2121.         public double getdCjdGamma(final int j) {
  2122.             return cCoef[6][j];
  2123.         }

  2124.         /**Get the value of S<sup>j</sup>.
  2125.          *
  2126.          * @param j j index
  2127.          * @return S<sup>j</sup>
  2128.          */
  2129.         public double getSj(final int j) {
  2130.             return sCoef[0][j];
  2131.         }

  2132.         /**Get the value of dS<sup>j</sup> / da.
  2133.          *
  2134.          * @param j j index
  2135.          * @return dS<sup>j</sup> / da
  2136.          */
  2137.         public double getdSjdA(final int j) {
  2138.             return sCoef[1][j];
  2139.         }

  2140.         /**Get the value of dS<sup>j</sup> / dh.
  2141.          *
  2142.          * @param j j index
  2143.          * @return dS<sup>j</sup> / dh
  2144.          */
  2145.         public double getdSjdH(final int j) {
  2146.             return sCoef[2][j];
  2147.         }

  2148.         /**Get the value of dS<sup>j</sup> / dk.
  2149.          *
  2150.          * @param j j index
  2151.          * @return dS<sup>j</sup> / dk
  2152.          */
  2153.         public double getdSjdK(final int j) {
  2154.             return sCoef[3][j];
  2155.         }

  2156.         /**Get the value of dS<sup>j</sup> / dα.
  2157.          *
  2158.          * @param j j index
  2159.          * @return dS<sup>j</sup> / dα
  2160.          */
  2161.         public double getdSjdAlpha(final int j) {
  2162.             return sCoef[4][j];
  2163.         }

  2164.         /**Get the value of dS<sup>j</sup> / dβ.
  2165.          *
  2166.          * @param j j index
  2167.          * @return dS<sup>j</sup> / dβ
  2168.          */
  2169.         public double getdSjdBeta(final int j) {
  2170.             return sCoef[5][j];
  2171.         }

  2172.         /**Get the value of dS<sup>j</sup> /  dγ.
  2173.          *
  2174.          * @param j j index
  2175.          * @return dS<sup>j</sup> /  dγ
  2176.          */
  2177.         public double getdSjdGamma(final int j) {
  2178.             return sCoef[6][j];
  2179.         }
  2180.     }

  2181.     /** Compute the C<sup>j</sup> and the S<sup>j</sup> coefficients.
  2182.      *  <p>
  2183.      *  Those coefficients are given in Danielson paper by expressions 4.1-(13) to 4.1.-(16b)
  2184.      *  </p>
  2185.      */
  2186.     private class FieldFourierCjSjCoefficients <T extends CalculusFieldElement<T>> {

  2187.         /** The G<sub>js</sub>, H<sub>js</sub>, I<sub>js</sub> and J<sub>js</sub> polynomials. */
  2188.         private final FieldGHIJjsPolynomials<T> ghijCoef;

  2189.         /** L<sub>n</sub><sup>s</sup>(γ). */
  2190.         private final FieldLnsCoefficients<T> lnsCoef;

  2191.         /** Maximum possible value for n. */
  2192.         private final int nMax;

  2193.         /** Maximum possible value for s. */
  2194.         private final int sMax;

  2195.         /** Maximum possible value for j. */
  2196.         private final int jMax;

  2197.         /** The C<sup>j</sup> coefficients and their derivatives.
  2198.          * <p>
  2199.          * Each column of the matrix contains the following values: <br/>
  2200.          * - C<sup>j</sup> <br/>
  2201.          * - dC<sup>j</sup> / da <br/>
  2202.          * - dC<sup>j</sup> / dh <br/>
  2203.          * - dC<sup>j</sup> / dk <br/>
  2204.          * - dC<sup>j</sup> / dα <br/>
  2205.          * - dC<sup>j</sup> / dβ <br/>
  2206.          * - dC<sup>j</sup> / dγ <br/>
  2207.          * </p>
  2208.          */
  2209.         private final T[][] cCoef;

  2210.         /** The S<sup>j</sup> coefficients and their derivatives.
  2211.          * <p>
  2212.          * Each column of the matrix contains the following values: <br/>
  2213.          * - S<sup>j</sup> <br/>
  2214.          * - dS<sup>j</sup> / da <br/>
  2215.          * - dS<sup>j</sup> / dh <br/>
  2216.          * - dS<sup>j</sup> / dk <br/>
  2217.          * - dS<sup>j</sup> / dα <br/>
  2218.          * - dS<sup>j</sup> / dβ <br/>
  2219.          * - dS<sup>j</sup> / dγ <br/>
  2220.          * </p>
  2221.          */
  2222.         private final T[][] sCoef;

  2223.         /** h * &Chi;³. */
  2224.         private final T hXXX;
  2225.         /** k * &Chi;³. */
  2226.         private final T kXXX;

  2227.         /** Create a set of C<sup>j</sup> and the S<sup>j</sup> coefficients.
  2228.          *  @param date the current date
  2229.          *  @param nMax maximum possible value for n
  2230.          *  @param sMax maximum possible value for s
  2231.          *  @param jMax maximum possible value for j
  2232.          *  @param context container for attributes
  2233.          *  @param hansenObjects initialization of hansen objects
  2234.          */
  2235.         FieldFourierCjSjCoefficients(final FieldAbsoluteDate<T> date,
  2236.                                      final int nMax, final int sMax, final int jMax,
  2237.                                      final FieldDSSTZonalContext<T> context,
  2238.                                      final FieldHansenObjects<T> hansenObjects) {

  2239.             //Field used by default
  2240.             final Field<T> field = date.getField();

  2241.             final FieldAuxiliaryElements<T> auxiliaryElements = context.getFieldAuxiliaryElements();

  2242.             this.ghijCoef = new FieldGHIJjsPolynomials<>(auxiliaryElements.getK(), auxiliaryElements.getH(), context.getAlpha(), context.getBeta());
  2243.             // Qns coefficients
  2244.             final T[][] Qns = CoefficientsFactory.computeQns(context.getGamma(), nMax, nMax);

  2245.             this.lnsCoef = new FieldLnsCoefficients<>(nMax, nMax, Qns, Vns, context.getRoa(), field);
  2246.             this.nMax = nMax;
  2247.             this.sMax = sMax;
  2248.             this.jMax = jMax;

  2249.             // compute the common factors that depends on the mean elements
  2250.             this.hXXX = auxiliaryElements.getH().multiply(context.getChi3());
  2251.             this.kXXX = auxiliaryElements.getK().multiply(context.getChi3());

  2252.             this.cCoef = MathArrays.buildArray(field, 7, jMax + 1);
  2253.             this.sCoef = MathArrays.buildArray(field, 7, jMax + 1);

  2254.             for (int s = 0; s <= sMax; s++) {
  2255.                 //Initialise the Hansen roots
  2256.                 hansenObjects.computeHansenObjectsInitValues(context, s);
  2257.             }
  2258.             generateCoefficients(date, context, auxiliaryElements, hansenObjects, field);
  2259.         }

  2260.         /** Generate all coefficients.
  2261.          * @param date the current date
  2262.          * @param context container for attributes
  2263.          * @param hansenObjects initialization of hansen objects
  2264.          * @param auxiliaryElements auxiliary elements related to the current orbit
  2265.          * @param field field used by default
  2266.          */
  2267.         private void generateCoefficients(final FieldAbsoluteDate<T> date,
  2268.                                           final FieldDSSTZonalContext<T> context,
  2269.                                           final FieldAuxiliaryElements<T> auxiliaryElements,
  2270.                                           final FieldHansenObjects<T> hansenObjects,
  2271.                                           final Field<T> field) {

  2272.             //Zero
  2273.             final T zero = field.getZero();

  2274.             final UnnormalizedSphericalHarmonics harmonics = provider.onDate(date.toAbsoluteDate());
  2275.             for (int j = 1; j <= jMax; j++) {

  2276.                 //init arrays
  2277.                 for (int i = 0; i <= 6; i++) {
  2278.                     cCoef[i][j] = zero;
  2279.                     sCoef[i][j] = zero;
  2280.                 }

  2281.                 if (isBetween(j, 1, nMax - 1)) {

  2282.                     //compute first double sum where s: j -> N-1 and n: s+1 -> N
  2283.                     for (int s = j; s <= FastMath.min(nMax - 1, sMax); s++) {
  2284.                         // j - s
  2285.                         final int jms = j - s;
  2286.                         // Kronecker symbols (2 - delta(0,s-j)) and (2 - delta(0,j-s))
  2287.                         final int d0smj = (s == j) ? 1 : 2;

  2288.                         for (int n = s + 1; n <= nMax; n++) {
  2289.                             // if n + (j-s) is odd, then the term is equal to zero due to the factor Vn,s-j
  2290.                             if ((n + jms) % 2 == 0) {
  2291.                                 // (2 - delta(0,s-j)) * J<sub>n</sub> * K₀<sup>-n-1,s</sup> * L<sub>n</sub><sup>j-s</sup>
  2292.                                 final T lns  = lnsCoef.getLns(n, -jms);
  2293.                                 final T dlns = lnsCoef.getdLnsdGamma(n, -jms);

  2294.                                 final T hjs        = ghijCoef.getHjs(s, -jms);
  2295.                                 final T dHjsdh     = ghijCoef.getdHjsdh(s, -jms);
  2296.                                 final T dHjsdk     = ghijCoef.getdHjsdk(s, -jms);
  2297.                                 final T dHjsdAlpha = ghijCoef.getdHjsdAlpha(s, -jms);
  2298.                                 final T dHjsdBeta  = ghijCoef.getdHjsdBeta(s, -jms);

  2299.                                 final T gjs        = ghijCoef.getGjs(s, -jms);
  2300.                                 final T dGjsdh     = ghijCoef.getdGjsdh(s, -jms);
  2301.                                 final T dGjsdk     = ghijCoef.getdGjsdk(s, -jms);
  2302.                                 final T dGjsdAlpha = ghijCoef.getdGjsdAlpha(s, -jms);
  2303.                                 final T dGjsdBeta  = ghijCoef.getdGjsdBeta(s, -jms);

  2304.                                 // J<sub>n</sub>
  2305.                                 final T jn = zero.subtract(harmonics.getUnnormalizedCnm(n, 0));

  2306.                                 // K₀<sup>-n-1,s</sup>
  2307.                                 final T kns   = hansenObjects.getHansenObjects()[s].getValue(-n - 1, context.getChi());
  2308.                                 final T dkns  = hansenObjects.getHansenObjects()[s].getDerivative(-n - 1, context.getChi());

  2309.                                 final T coef0 = jn.multiply(d0smj);
  2310.                                 final T coef1 = coef0.multiply(lns);
  2311.                                 final T coef2 = coef1.multiply(kns);
  2312.                                 final T coef3 = coef2.multiply(hjs);
  2313.                                 final T coef4 = coef2.multiply(gjs);

  2314.                                 // Add the term to the coefficients
  2315.                                 cCoef[0][j] = cCoef[0][j].add(coef3);
  2316.                                 cCoef[1][j] = cCoef[1][j].add(coef3.multiply(n + 1));
  2317.                                 cCoef[2][j] = cCoef[2][j].add(coef1.multiply(kns.multiply(dHjsdh).add(hjs.multiply(hXXX).multiply(dkns))));
  2318.                                 cCoef[3][j] = cCoef[3][j].add(coef1.multiply(kns.multiply(dHjsdk).add(hjs.multiply(kXXX).multiply(dkns))));
  2319.                                 cCoef[4][j] = cCoef[4][j].add(coef2.multiply(dHjsdAlpha));
  2320.                                 cCoef[5][j] = cCoef[5][j].add(coef2.multiply(dHjsdBeta));
  2321.                                 cCoef[6][j] = cCoef[6][j].add(coef0.multiply(dlns).multiply(kns).multiply(hjs));

  2322.                                 sCoef[0][j] = sCoef[0][j].add(coef4);
  2323.                                 sCoef[1][j] = sCoef[1][j].add(coef4.multiply(n + 1));
  2324.                                 sCoef[2][j] = sCoef[2][j].add(coef1.multiply(kns.multiply(dGjsdh).add(gjs.multiply(hXXX).multiply(dkns))));
  2325.                                 sCoef[3][j] = sCoef[3][j].add(coef1.multiply(kns.multiply(dGjsdk).add(gjs.multiply(kXXX).multiply(dkns))));
  2326.                                 sCoef[4][j] = sCoef[4][j].add(coef2.multiply(dGjsdAlpha));
  2327.                                 sCoef[5][j] = sCoef[5][j].add(coef2.multiply(dGjsdBeta));
  2328.                                 sCoef[6][j] = sCoef[6][j].add(coef0.multiply(dlns).multiply(kns).multiply(gjs));
  2329.                             }
  2330.                         }
  2331.                     }

  2332.                     //compute second double sum where s: 0 -> N-j and n: max(j+s, j+1) -> N
  2333.                     for (int s = 0; s <= FastMath.min(nMax - j, sMax); s++) {
  2334.                         // j + s
  2335.                         final int jps = j + s;
  2336.                         // Kronecker symbols (2 - delta(0,j+s))
  2337.                         final double d0spj = (s == -j) ? 1 : 2;

  2338.                         for (int n = FastMath.max(j + s, j + 1); n <= nMax; n++) {
  2339.                             // if n + (j+s) is odd, then the term is equal to zero due to the factor Vn,s+j
  2340.                             if ((n + jps) % 2 == 0) {
  2341.                                 // (2 - delta(0,s+j)) * J<sub>n</sub> * K₀<sup>-n-1,s</sup> * L<sub>n</sub><sup>j+s</sup>
  2342.                                 final T lns  = lnsCoef.getLns(n, jps);
  2343.                                 final T dlns = lnsCoef.getdLnsdGamma(n, jps);

  2344.                                 final T hjs        = ghijCoef.getHjs(s, jps);
  2345.                                 final T dHjsdh     = ghijCoef.getdHjsdh(s, jps);
  2346.                                 final T dHjsdk     = ghijCoef.getdHjsdk(s, jps);
  2347.                                 final T dHjsdAlpha = ghijCoef.getdHjsdAlpha(s, jps);
  2348.                                 final T dHjsdBeta  = ghijCoef.getdHjsdBeta(s, jps);

  2349.                                 final T gjs        = ghijCoef.getGjs(s, jps);
  2350.                                 final T dGjsdh     = ghijCoef.getdGjsdh(s, jps);
  2351.                                 final T dGjsdk     = ghijCoef.getdGjsdk(s, jps);
  2352.                                 final T dGjsdAlpha = ghijCoef.getdGjsdAlpha(s, jps);
  2353.                                 final T dGjsdBeta  = ghijCoef.getdGjsdBeta(s, jps);

  2354.                                 // J<sub>n</sub>
  2355.                                 final T jn = zero.subtract(harmonics.getUnnormalizedCnm(n, 0));

  2356.                                 // K₀<sup>-n-1,s</sup>
  2357.                                 final T kns   = hansenObjects.getHansenObjects()[s].getValue(-n - 1, context.getChi());
  2358.                                 final T dkns  = hansenObjects.getHansenObjects()[s].getDerivative(-n - 1, context.getChi());

  2359.                                 final T coef0 = jn.multiply(d0spj);
  2360.                                 final T coef1 = coef0.multiply(lns);
  2361.                                 final T coef2 = coef1.multiply(kns);

  2362.                                 final T coef3 = coef2.multiply(hjs);
  2363.                                 final T coef4 = coef2.multiply(gjs);

  2364.                                 // Add the term to the coefficients
  2365.                                 cCoef[0][j] = cCoef[0][j].subtract(coef3);
  2366.                                 cCoef[1][j] = cCoef[1][j].subtract(coef3.multiply(n + 1));
  2367.                                 cCoef[2][j] = cCoef[2][j].subtract(coef1.multiply(kns.multiply(dHjsdh).add(hjs.multiply(hXXX).multiply(dkns))));
  2368.                                 cCoef[3][j] = cCoef[3][j].subtract(coef1.multiply(kns.multiply(dHjsdk).add(hjs.multiply(kXXX).multiply(dkns))));
  2369.                                 cCoef[4][j] = cCoef[4][j].subtract(coef2.multiply(dHjsdAlpha));
  2370.                                 cCoef[5][j] = cCoef[5][j].subtract(coef2.multiply(dHjsdBeta));
  2371.                                 cCoef[6][j] = cCoef[6][j].subtract(coef0.multiply(dlns).multiply(kns).multiply(hjs));

  2372.                                 sCoef[0][j] = sCoef[0][j].add(coef4);
  2373.                                 sCoef[1][j] = sCoef[1][j].add(coef4.multiply(n + 1));
  2374.                                 sCoef[2][j] = sCoef[2][j].add(coef1.multiply(kns.multiply(dGjsdh).add(gjs.multiply(hXXX).multiply(dkns))));
  2375.                                 sCoef[3][j] = sCoef[3][j].add(coef1.multiply(kns.multiply(dGjsdk).add(gjs.multiply(kXXX).multiply(dkns))));
  2376.                                 sCoef[4][j] = sCoef[4][j].add(coef2.multiply(dGjsdAlpha));
  2377.                                 sCoef[5][j] = sCoef[5][j].add(coef2.multiply(dGjsdBeta));
  2378.                                 sCoef[6][j] = sCoef[6][j].add(coef0.multiply(dlns).multiply(kns).multiply(gjs));
  2379.                             }
  2380.                         }
  2381.                     }

  2382.                     //compute third double sum where s: 1 -> j and  n: j+1 -> N
  2383.                     for (int s = 1; s <= FastMath.min(j, sMax); s++) {
  2384.                         // j - s
  2385.                         final int jms = j - s;
  2386.                         // Kronecker symbols (2 - delta(0,s-j)) and (2 - delta(0,j-s))
  2387.                         final int d0smj = (s == j) ? 1 : 2;

  2388.                         for (int n = j + 1; n <= nMax; n++) {
  2389.                             // if n + (j-s) is odd, then the term is equal to zero due to the factor Vn,s-j
  2390.                             if ((n + jms) % 2 == 0) {
  2391.                                 // (2 - delta(0,j-s)) * J<sub>n</sub> * K₀<sup>-n-1,s</sup> * L<sub>n</sub><sup>j-s</sup>
  2392.                                 final T lns  = lnsCoef.getLns(n, jms);
  2393.                                 final T dlns = lnsCoef.getdLnsdGamma(n, jms);

  2394.                                 final T ijs        = ghijCoef.getIjs(s, jms);
  2395.                                 final T dIjsdh     = ghijCoef.getdIjsdh(s, jms);
  2396.                                 final T dIjsdk     = ghijCoef.getdIjsdk(s, jms);
  2397.                                 final T dIjsdAlpha = ghijCoef.getdIjsdAlpha(s, jms);
  2398.                                 final T dIjsdBeta  = ghijCoef.getdIjsdBeta(s, jms);

  2399.                                 final T jjs        = ghijCoef.getJjs(s, jms);
  2400.                                 final T dJjsdh     = ghijCoef.getdJjsdh(s, jms);
  2401.                                 final T dJjsdk     = ghijCoef.getdJjsdk(s, jms);
  2402.                                 final T dJjsdAlpha = ghijCoef.getdJjsdAlpha(s, jms);
  2403.                                 final T dJjsdBeta  = ghijCoef.getdJjsdBeta(s, jms);

  2404.                                 // J<sub>n</sub>
  2405.                                 final T jn = zero.subtract(harmonics.getUnnormalizedCnm(n, 0));

  2406.                                 // K₀<sup>-n-1,s</sup>
  2407.                                 final T kns   = hansenObjects.getHansenObjects()[s].getValue(-n - 1, context.getChi());
  2408.                                 final T dkns  = hansenObjects.getHansenObjects()[s].getDerivative(-n - 1, context.getChi());

  2409.                                 final T coef0 = jn.multiply(d0smj);
  2410.                                 final T coef1 = coef0.multiply(lns);
  2411.                                 final T coef2 = coef1.multiply(kns);

  2412.                                 final T coef3 = coef2.multiply(ijs);
  2413.                                 final T coef4 = coef2.multiply(jjs);

  2414.                                 // Add the term to the coefficients
  2415.                                 cCoef[0][j] = cCoef[0][j].subtract(coef3);
  2416.                                 cCoef[1][j] = cCoef[1][j].subtract(coef3.multiply(n + 1));
  2417.                                 cCoef[2][j] = cCoef[2][j].subtract(coef1.multiply(kns.multiply(dIjsdh).add(ijs.multiply(hXXX).multiply(dkns))));
  2418.                                 cCoef[3][j] = cCoef[3][j].subtract(coef1.multiply(kns.multiply(dIjsdk).add(ijs.multiply(kXXX).multiply(dkns))));
  2419.                                 cCoef[4][j] = cCoef[4][j].subtract(coef2.multiply(dIjsdAlpha));
  2420.                                 cCoef[5][j] = cCoef[5][j].subtract(coef2.multiply(dIjsdBeta));
  2421.                                 cCoef[6][j] = cCoef[6][j].subtract(coef0.multiply(dlns).multiply(kns).multiply(ijs));

  2422.                                 sCoef[0][j] = sCoef[0][j].add(coef4);
  2423.                                 sCoef[1][j] = sCoef[1][j].add(coef4.multiply(n + 1));
  2424.                                 sCoef[2][j] = sCoef[2][j].add(coef1.multiply(kns.multiply(dJjsdh).add(jjs.multiply(hXXX).multiply(dkns))));
  2425.                                 sCoef[3][j] = sCoef[3][j].add(coef1.multiply(kns.multiply(dJjsdk).add(jjs.multiply(kXXX).multiply(dkns))));
  2426.                                 sCoef[4][j] = sCoef[4][j].add(coef2.multiply(dJjsdAlpha));
  2427.                                 sCoef[5][j] = sCoef[5][j].add(coef2.multiply(dJjsdBeta));
  2428.                                 sCoef[6][j] = sCoef[6][j].add(coef0.multiply(dlns).multiply(kns).multiply(jjs));
  2429.                             }
  2430.                         }
  2431.                     }
  2432.                 }

  2433.                 if (isBetween(j, 2, nMax)) {
  2434.                     //add first term
  2435.                     // J<sub>j</sub>
  2436.                     final T jj = zero.subtract(harmonics.getUnnormalizedCnm(j, 0));
  2437.                     T kns  = hansenObjects.getHansenObjects()[0].getValue(-j - 1, context.getChi());
  2438.                     T dkns = hansenObjects.getHansenObjects()[0].getDerivative(-j - 1, context.getChi());

  2439.                     T lns = lnsCoef.getLns(j, j);
  2440.                     //dlns is 0 because n == s == j

  2441.                     final T hjs        = ghijCoef.getHjs(0, j);
  2442.                     final T dHjsdh     = ghijCoef.getdHjsdh(0, j);
  2443.                     final T dHjsdk     = ghijCoef.getdHjsdk(0, j);
  2444.                     final T dHjsdAlpha = ghijCoef.getdHjsdAlpha(0, j);
  2445.                     final T dHjsdBeta  = ghijCoef.getdHjsdBeta(0, j);

  2446.                     final T gjs        = ghijCoef.getGjs(0, j);
  2447.                     final T dGjsdh     = ghijCoef.getdGjsdh(0, j);
  2448.                     final T dGjsdk     = ghijCoef.getdGjsdk(0, j);
  2449.                     final T dGjsdAlpha = ghijCoef.getdGjsdAlpha(0, j);
  2450.                     final T dGjsdBeta  = ghijCoef.getdGjsdBeta(0, j);

  2451.                     // 2 * J<sub>j</sub> * K₀<sup>-j-1,0</sup> * L<sub>j</sub><sup>j</sup>
  2452.                     T coef0 = jj.multiply(2.);
  2453.                     T coef1 = coef0.multiply(lns);
  2454.                     T coef2 = coef1.multiply(kns);

  2455.                     T coef3 = coef2.multiply(hjs);
  2456.                     T coef4 = coef2.multiply(gjs);

  2457.                     // Add the term to the coefficients
  2458.                     cCoef[0][j] = cCoef[0][j].subtract(coef3);
  2459.                     cCoef[1][j] = cCoef[1][j].subtract(coef3.multiply(j + 1));
  2460.                     cCoef[2][j] = cCoef[2][j].subtract(coef1.multiply(kns.multiply(dHjsdh).add(hjs.multiply(hXXX).multiply(dkns))));
  2461.                     cCoef[3][j] = cCoef[3][j].subtract(coef1.multiply(kns.multiply(dHjsdk).add(hjs.multiply(kXXX).multiply(dkns))));
  2462.                     cCoef[4][j] = cCoef[4][j].subtract(coef2.multiply(dHjsdAlpha));
  2463.                     cCoef[5][j] = cCoef[5][j].subtract(coef2.multiply(dHjsdBeta));
  2464.                     //no contribution to cCoef[6][j] because dlns is 0

  2465.                     sCoef[0][j] = sCoef[0][j].add(coef4);
  2466.                     sCoef[1][j] = sCoef[1][j].add(coef4.multiply(j + 1));
  2467.                     sCoef[2][j] = sCoef[2][j].add(coef1.multiply(kns.multiply(dGjsdh).add(gjs.multiply(hXXX).multiply(dkns))));
  2468.                     sCoef[3][j] = sCoef[3][j].add(coef1.multiply(kns.multiply(dGjsdk).add(gjs.multiply(kXXX).multiply(dkns))));
  2469.                     sCoef[4][j] = sCoef[4][j].add(coef2.multiply(dGjsdAlpha));
  2470.                     sCoef[5][j] = sCoef[5][j].add(coef2.multiply(dGjsdBeta));
  2471.                     //no contribution to sCoef[6][j] because dlns is 0

  2472.                     //compute simple sum where s: 1 -> j-1
  2473.                     for (int s = 1; s <= FastMath.min(j - 1, sMax); s++) {
  2474.                         // j - s
  2475.                         final int jms = j - s;
  2476.                         // Kronecker symbols (2 - delta(0,s-j)) and (2 - delta(0,j-s))
  2477.                         final int d0smj = (s == j) ? 1 : 2;

  2478.                         // if s is odd, then the term is equal to zero due to the factor Vj,s-j
  2479.                         if (s % 2 == 0) {
  2480.                             // (2 - delta(0,j-s)) * J<sub>j</sub> * K₀<sup>-j-1,s</sup> * L<sub>j</sub><sup>j-s</sup>
  2481.                             kns   = hansenObjects.getHansenObjects()[s].getValue(-j - 1, context.getChi());
  2482.                             dkns  = hansenObjects.getHansenObjects()[s].getDerivative(-j - 1, context.getChi());

  2483.                             lns = lnsCoef.getLns(j, jms);
  2484.                             final T dlns = lnsCoef.getdLnsdGamma(j, jms);

  2485.                             final T ijs        = ghijCoef.getIjs(s, jms);
  2486.                             final T dIjsdh     = ghijCoef.getdIjsdh(s, jms);
  2487.                             final T dIjsdk     = ghijCoef.getdIjsdk(s, jms);
  2488.                             final T dIjsdAlpha = ghijCoef.getdIjsdAlpha(s, jms);
  2489.                             final T dIjsdBeta  = ghijCoef.getdIjsdBeta(s, jms);

  2490.                             final T jjs        = ghijCoef.getJjs(s, jms);
  2491.                             final T dJjsdh     = ghijCoef.getdJjsdh(s, jms);
  2492.                             final T dJjsdk     = ghijCoef.getdJjsdk(s, jms);
  2493.                             final T dJjsdAlpha = ghijCoef.getdJjsdAlpha(s, jms);
  2494.                             final T dJjsdBeta  = ghijCoef.getdJjsdBeta(s, jms);

  2495.                             coef0 = jj.multiply(d0smj);
  2496.                             coef1 = coef0.multiply(lns);
  2497.                             coef2 = coef1.multiply(kns);

  2498.                             coef3 = coef2.multiply(ijs);
  2499.                             coef4 = coef2.multiply(jjs);

  2500.                             // Add the term to the coefficients
  2501.                             cCoef[0][j] = cCoef[0][j].subtract(coef3);
  2502.                             cCoef[1][j] = cCoef[1][j].subtract(coef3.multiply(j + 1));
  2503.                             cCoef[2][j] = cCoef[2][j].subtract(coef1.multiply(kns.multiply(dIjsdh).add(ijs.multiply(hXXX).multiply(dkns))));
  2504.                             cCoef[3][j] = cCoef[3][j].subtract(coef1.multiply(kns.multiply(dIjsdk).add(ijs.multiply(kXXX).multiply(dkns))));
  2505.                             cCoef[4][j] = cCoef[4][j].subtract(coef2.multiply(dIjsdAlpha));
  2506.                             cCoef[5][j] = cCoef[5][j].subtract(coef2.multiply(dIjsdBeta));
  2507.                             cCoef[6][j] = cCoef[6][j].subtract(coef0.multiply(dlns).multiply(kns).multiply(ijs));

  2508.                             sCoef[0][j] = sCoef[0][j].add(coef4);
  2509.                             sCoef[1][j] = sCoef[1][j].add(coef4.multiply(j + 1));
  2510.                             sCoef[2][j] = sCoef[2][j].add(coef1.multiply(kns.multiply(dJjsdh).add(jjs.multiply(hXXX).multiply(dkns))));
  2511.                             sCoef[3][j] = sCoef[3][j].add(coef1.multiply(kns.multiply(dJjsdk).add(jjs.multiply(kXXX).multiply(dkns))));
  2512.                             sCoef[4][j] = sCoef[4][j].add(coef2.multiply(dJjsdAlpha));
  2513.                             sCoef[5][j] = sCoef[5][j].add(coef2.multiply(dJjsdBeta));
  2514.                             sCoef[6][j] = sCoef[6][j].add(coef0.multiply(dlns).multiply(kns).multiply(jjs));
  2515.                         }
  2516.                     }
  2517.                 }

  2518.                 if (isBetween(j, 3, 2 * nMax - 1)) {
  2519.                     //compute uppercase sigma expressions

  2520.                     //min(j-1,N)
  2521.                     final int minjm1on = FastMath.min(j - 1, nMax);

  2522.                     //if j is even
  2523.                     if (j % 2 == 0) {
  2524.                         //compute first double sum where s: j-min(j-1,N) -> j/2-1 and n: j-s -> min(j-1,N)
  2525.                         for (int s = j - minjm1on; s <= FastMath.min(j / 2 - 1, sMax); s++) {
  2526.                             // j - s
  2527.                             final int jms = j - s;
  2528.                             // Kronecker symbols (2 - delta(0,s-j)) and (2 - delta(0,j-s))
  2529.                             final int d0smj = (s == j) ? 1 : 2;

  2530.                             for (int n = j - s; n <= minjm1on; n++) {
  2531.                                 // if n + (j-s) is odd, then the term is equal to zero due to the factor Vn,s-j
  2532.                                 if ((n + jms) % 2 == 0) {
  2533.                                     // (2 - delta(0,j-s)) * J<sub>n</sub> * K₀<sup>-n-1,s</sup> * L<sub>n</sub><sup>j-s</sup>
  2534.                                     final T lns  = lnsCoef.getLns(n, jms);
  2535.                                     final T dlns = lnsCoef.getdLnsdGamma(n, jms);

  2536.                                     final T ijs        = ghijCoef.getIjs(s, jms);
  2537.                                     final T dIjsdh     = ghijCoef.getdIjsdh(s, jms);
  2538.                                     final T dIjsdk     = ghijCoef.getdIjsdk(s, jms);
  2539.                                     final T dIjsdAlpha = ghijCoef.getdIjsdAlpha(s, jms);
  2540.                                     final T dIjsdBeta  = ghijCoef.getdIjsdBeta(s, jms);

  2541.                                     final T jjs        = ghijCoef.getJjs(s, jms);
  2542.                                     final T dJjsdh     = ghijCoef.getdJjsdh(s, jms);
  2543.                                     final T dJjsdk     = ghijCoef.getdJjsdk(s, jms);
  2544.                                     final T dJjsdAlpha = ghijCoef.getdJjsdAlpha(s, jms);
  2545.                                     final T dJjsdBeta  = ghijCoef.getdJjsdBeta(s, jms);

  2546.                                     // J<sub>n</sub>
  2547.                                     final T jn = zero.subtract(harmonics.getUnnormalizedCnm(n, 0));

  2548.                                     // K₀<sup>-n-1,s</sup>
  2549.                                     final T kns   = hansenObjects.getHansenObjects()[s].getValue(-n - 1, context.getChi());
  2550.                                     final T dkns  = hansenObjects.getHansenObjects()[s].getDerivative(-n - 1, context.getChi());

  2551.                                     final T coef0 = jn.multiply(d0smj);
  2552.                                     final T coef1 = coef0.multiply(lns);
  2553.                                     final T coef2 = coef1.multiply(kns);

  2554.                                     final T coef3 = coef2.multiply(ijs);
  2555.                                     final T coef4 = coef2.multiply(jjs);

  2556.                                     // Add the term to the coefficients
  2557.                                     cCoef[0][j] = cCoef[0][j].subtract(coef3);
  2558.                                     cCoef[1][j] = cCoef[1][j].subtract(coef3.multiply(n + 1));
  2559.                                     cCoef[2][j] = cCoef[2][j].subtract(coef1.multiply(kns.multiply(dIjsdh).add(ijs.multiply(hXXX).multiply(dkns))));
  2560.                                     cCoef[3][j] = cCoef[3][j].subtract(coef1.multiply(kns.multiply(dIjsdk).add(ijs.multiply(kXXX).multiply(dkns))));
  2561.                                     cCoef[4][j] = cCoef[4][j].subtract(coef2.multiply(dIjsdAlpha));
  2562.                                     cCoef[5][j] = cCoef[5][j].subtract(coef2.multiply(dIjsdBeta));
  2563.                                     cCoef[6][j] = cCoef[6][j].subtract(coef0.multiply(dlns).multiply(kns).multiply(ijs));

  2564.                                     sCoef[0][j] = sCoef[0][j].add(coef4);
  2565.                                     sCoef[1][j] = sCoef[1][j].add(coef4.multiply(n + 1));
  2566.                                     sCoef[2][j] = sCoef[2][j].add(coef1.multiply(kns.multiply(dJjsdh).add(jjs.multiply(hXXX).multiply(dkns))));
  2567.                                     sCoef[3][j] = sCoef[3][j].add(coef1.multiply(kns.multiply(dJjsdk).add(jjs.multiply(kXXX).multiply(dkns))));
  2568.                                     sCoef[4][j] = sCoef[4][j].add(coef2.multiply(dJjsdAlpha));
  2569.                                     sCoef[5][j] = sCoef[5][j].add(coef2.multiply(dJjsdBeta));
  2570.                                     sCoef[6][j] = sCoef[6][j].add(coef0.multiply(dlns).multiply(kns).multiply(jjs));
  2571.                                 }
  2572.                             }
  2573.                         }

  2574.                         //compute second double sum where s: j/2 -> min(j-1,N)-1 and n: s+1 -> min(j-1,N)
  2575.                         for (int s = j / 2; s <=  FastMath.min(minjm1on - 1, sMax); s++) {
  2576.                             // j - s
  2577.                             final int jms = j - s;
  2578.                             // Kronecker symbols (2 - delta(0,s-j)) and (2 - delta(0,j-s))
  2579.                             final int d0smj = (s == j) ? 1 : 2;

  2580.                             for (int n = s + 1; n <= minjm1on; n++) {
  2581.                                 // if n + (j-s) is odd, then the term is equal to zero due to the factor Vn,s-j
  2582.                                 if ((n + jms) % 2 == 0) {
  2583.                                     // (2 - delta(0,j-s)) * J<sub>n</sub> * K₀<sup>-n-1,s</sup> * L<sub>n</sub><sup>j-s</sup>
  2584.                                     final T lns  = lnsCoef.getLns(n, jms);
  2585.                                     final T dlns = lnsCoef.getdLnsdGamma(n, jms);

  2586.                                     final T ijs        = ghijCoef.getIjs(s, jms);
  2587.                                     final T dIjsdh     = ghijCoef.getdIjsdh(s, jms);
  2588.                                     final T dIjsdk     = ghijCoef.getdIjsdk(s, jms);
  2589.                                     final T dIjsdAlpha = ghijCoef.getdIjsdAlpha(s, jms);
  2590.                                     final T dIjsdBeta  = ghijCoef.getdIjsdBeta(s, jms);

  2591.                                     final T jjs        = ghijCoef.getJjs(s, jms);
  2592.                                     final T dJjsdh     = ghijCoef.getdJjsdh(s, jms);
  2593.                                     final T dJjsdk     = ghijCoef.getdJjsdk(s, jms);
  2594.                                     final T dJjsdAlpha = ghijCoef.getdJjsdAlpha(s, jms);
  2595.                                     final T dJjsdBeta  = ghijCoef.getdJjsdBeta(s, jms);

  2596.                                     // J<sub>n</sub>
  2597.                                     final T jn = zero.subtract(harmonics.getUnnormalizedCnm(n, 0));

  2598.                                     // K₀<sup>-n-1,s</sup>
  2599.                                     final T kns   = hansenObjects.getHansenObjects()[s].getValue(-n - 1, context.getChi());
  2600.                                     final T dkns  = hansenObjects.getHansenObjects()[s].getDerivative(-n - 1, context.getChi());

  2601.                                     final T coef0 = jn.multiply(d0smj);
  2602.                                     final T coef1 = coef0.multiply(lns);
  2603.                                     final T coef2 = coef1.multiply(kns);

  2604.                                     final T coef3 = coef2.multiply(ijs);
  2605.                                     final T coef4 = coef2.multiply(jjs);

  2606.                                     // Add the term to the coefficients
  2607.                                     cCoef[0][j] = cCoef[0][j].subtract(coef3);
  2608.                                     cCoef[1][j] = cCoef[1][j].subtract(coef3.multiply(n + 1));
  2609.                                     cCoef[2][j] = cCoef[2][j].subtract(coef1.multiply(kns.multiply(dIjsdh).add(ijs.multiply(hXXX).multiply(dkns))));
  2610.                                     cCoef[3][j] = cCoef[3][j].subtract(coef1.multiply(kns.multiply(dIjsdk).add(ijs.multiply(kXXX).multiply(dkns))));
  2611.                                     cCoef[4][j] = cCoef[4][j].subtract(coef2.multiply(dIjsdAlpha));
  2612.                                     cCoef[5][j] = cCoef[5][j].subtract(coef2.multiply(dIjsdBeta));
  2613.                                     cCoef[6][j] = cCoef[6][j].subtract(coef0.multiply(dlns).multiply(kns).multiply(ijs));

  2614.                                     sCoef[0][j] = sCoef[0][j].add(coef4);
  2615.                                     sCoef[1][j] = sCoef[1][j].add(coef4.multiply(n + 1));
  2616.                                     sCoef[2][j] = sCoef[2][j].add(coef1.multiply(kns.multiply(dJjsdh).add(jjs.multiply(hXXX).multiply(dkns))));
  2617.                                     sCoef[3][j] = sCoef[3][j].add(coef1.multiply(kns.multiply(dJjsdk).add(jjs.multiply(kXXX).multiply(dkns))));
  2618.                                     sCoef[4][j] = sCoef[4][j].add(coef2.multiply(dJjsdAlpha));
  2619.                                     sCoef[5][j] = sCoef[5][j].add(coef2.multiply(dJjsdBeta));
  2620.                                     sCoef[6][j] = sCoef[6][j].add(coef0.multiply(dlns).multiply(kns).multiply(jjs));
  2621.                                 }
  2622.                             }
  2623.                         }
  2624.                     }

  2625.                     //if j is odd
  2626.                     else {
  2627.                         //compute first double sum where s: (j-1)/2 -> min(j-1,N)-1 and n: s+1 -> min(j-1,N)
  2628.                         for (int s = (j - 1) / 2; s <= FastMath.min(minjm1on - 1, sMax); s++) {
  2629.                             // j - s
  2630.                             final int jms = j - s;
  2631.                             // Kronecker symbols (2 - delta(0,s-j)) and (2 - delta(0,j-s))
  2632.                             final int d0smj = (s == j) ? 1 : 2;

  2633.                             for (int n = s + 1; n <= minjm1on; n++) {
  2634.                                 // if n + (j-s) is odd, then the term is equal to zero due to the factor Vn,s-j
  2635.                                 if ((n + jms) % 2 == 0) {
  2636.                                     // (2 - delta(0,j-s)) * J<sub>n</sub> * K₀<sup>-n-1,s</sup> * L<sub>n</sub><sup>j-s</sup>
  2637.                                     final T lns  = lnsCoef.getLns(n, jms);
  2638.                                     final T dlns = lnsCoef.getdLnsdGamma(n, jms);

  2639.                                     final T ijs        = ghijCoef.getIjs(s, jms);
  2640.                                     final T dIjsdh     = ghijCoef.getdIjsdh(s, jms);
  2641.                                     final T dIjsdk     = ghijCoef.getdIjsdk(s, jms);
  2642.                                     final T dIjsdAlpha = ghijCoef.getdIjsdAlpha(s, jms);
  2643.                                     final T dIjsdBeta  = ghijCoef.getdIjsdBeta(s, jms);

  2644.                                     final T jjs        = ghijCoef.getJjs(s, jms);
  2645.                                     final T dJjsdh     = ghijCoef.getdJjsdh(s, jms);
  2646.                                     final T dJjsdk     = ghijCoef.getdJjsdk(s, jms);
  2647.                                     final T dJjsdAlpha = ghijCoef.getdJjsdAlpha(s, jms);
  2648.                                     final T dJjsdBeta  = ghijCoef.getdJjsdBeta(s, jms);

  2649.                                     // J<sub>n</sub>
  2650.                                     final T jn = zero.subtract(harmonics.getUnnormalizedCnm(n, 0));

  2651.                                     // K₀<sup>-n-1,s</sup>

  2652.                                     final T kns   = hansenObjects.getHansenObjects()[s].getValue(-n - 1, context.getChi());
  2653.                                     final T dkns  = hansenObjects.getHansenObjects()[s].getDerivative(-n - 1, context.getChi());

  2654.                                     final T coef0 = jn.multiply(d0smj);
  2655.                                     final T coef1 = coef0.multiply(lns);
  2656.                                     final T coef2 = coef1.multiply(kns);

  2657.                                     final T coef3 = coef2.multiply(ijs);
  2658.                                     final T coef4 = coef2.multiply(jjs);

  2659.                                     // Add the term to the coefficients
  2660.                                     cCoef[0][j] = cCoef[0][j].subtract(coef3);
  2661.                                     cCoef[1][j] = cCoef[1][j].subtract(coef3.multiply(n + 1));
  2662.                                     cCoef[2][j] = cCoef[2][j].subtract(coef1.multiply(kns.multiply(dIjsdh).add(ijs.multiply(hXXX).multiply(dkns))));
  2663.                                     cCoef[3][j] = cCoef[3][j].subtract(coef1.multiply(kns.multiply(dIjsdk).add(ijs.multiply(kXXX).multiply(dkns))));
  2664.                                     cCoef[4][j] = cCoef[4][j].subtract(coef2.multiply(dIjsdAlpha));
  2665.                                     cCoef[5][j] = cCoef[5][j].subtract(coef2.multiply(dIjsdBeta));
  2666.                                     cCoef[6][j] = cCoef[6][j].subtract(coef0.multiply(dlns).multiply(kns).multiply(ijs));

  2667.                                     sCoef[0][j] = sCoef[0][j].add(coef4);
  2668.                                     sCoef[1][j] = sCoef[1][j].add(coef4.multiply(n + 1));
  2669.                                     sCoef[2][j] = sCoef[2][j].add(coef1.multiply(kns.multiply(dJjsdh).add(jjs.multiply(hXXX).multiply(dkns))));
  2670.                                     sCoef[3][j] = sCoef[3][j].add(coef1.multiply(kns.multiply(dJjsdk).add(jjs.multiply(kXXX).multiply(dkns))));
  2671.                                     sCoef[4][j] = sCoef[4][j].add(coef2.multiply(dJjsdAlpha));
  2672.                                     sCoef[5][j] = sCoef[5][j].add(coef2.multiply(dJjsdBeta));
  2673.                                     sCoef[6][j] = sCoef[6][j].add(coef0.multiply(dlns).multiply(kns).multiply(jjs));
  2674.                                 }
  2675.                             }
  2676.                         }

  2677.                         //the second double sum is added only if N >= 4 and j between 5 and 2*N-3
  2678.                         if (nMax >= 4 && isBetween(j, 5, 2 * nMax - 3)) {
  2679.                             //compute second double sum where s: j-min(j-1,N) -> (j-3)/2 and n: j-s -> min(j-1,N)
  2680.                             for (int s = j - minjm1on; s <= FastMath.min((j - 3) / 2, sMax); s++) {
  2681.                                 // j - s
  2682.                                 final int jms = j - s;
  2683.                                 // Kronecker symbols (2 - delta(0,s-j)) and (2 - delta(0,j-s))
  2684.                                 final int d0smj = (s == j) ? 1 : 2;

  2685.                                 for (int n = j - s; n <= minjm1on; n++) {
  2686.                                     // if n + (j-s) is odd, then the term is equal to zero due to the factor Vn,s-j
  2687.                                     if ((n + jms) % 2 == 0) {
  2688.                                         // (2 - delta(0,j-s)) * J<sub>n</sub> * K₀<sup>-n-1,s</sup> * L<sub>n</sub><sup>j-s</sup>
  2689.                                         final T lns  = lnsCoef.getLns(n, jms);
  2690.                                         final T dlns = lnsCoef.getdLnsdGamma(n, jms);

  2691.                                         final T ijs        = ghijCoef.getIjs(s, jms);
  2692.                                         final T dIjsdh     = ghijCoef.getdIjsdh(s, jms);
  2693.                                         final T dIjsdk     = ghijCoef.getdIjsdk(s, jms);
  2694.                                         final T dIjsdAlpha = ghijCoef.getdIjsdAlpha(s, jms);
  2695.                                         final T dIjsdBeta  = ghijCoef.getdIjsdBeta(s, jms);

  2696.                                         final T jjs        = ghijCoef.getJjs(s, jms);
  2697.                                         final T dJjsdh     = ghijCoef.getdJjsdh(s, jms);
  2698.                                         final T dJjsdk     = ghijCoef.getdJjsdk(s, jms);
  2699.                                         final T dJjsdAlpha = ghijCoef.getdJjsdAlpha(s, jms);
  2700.                                         final T dJjsdBeta  = ghijCoef.getdJjsdBeta(s, jms);

  2701.                                         // J<sub>n</sub>
  2702.                                         final T jn = zero.subtract(harmonics.getUnnormalizedCnm(n, 0));

  2703.                                         // K₀<sup>-n-1,s</sup>
  2704.                                         final T kns   = hansenObjects.getHansenObjects()[s].getValue(-n - 1, context.getChi());
  2705.                                         final T dkns  = hansenObjects.getHansenObjects()[s].getDerivative(-n - 1, context.getChi());

  2706.                                         final T coef0 = jn.multiply(d0smj);
  2707.                                         final T coef1 = coef0.multiply(lns);
  2708.                                         final T coef2 = coef1.multiply(kns);

  2709.                                         final T coef3 = coef2.multiply(ijs);
  2710.                                         final T coef4 = coef2.multiply(jjs);

  2711.                                         // Add the term to the coefficients
  2712.                                         cCoef[0][j] = cCoef[0][j].subtract(coef3);
  2713.                                         cCoef[1][j] = cCoef[1][j].subtract(coef3.multiply(n + 1));
  2714.                                         cCoef[2][j] = cCoef[2][j].subtract(coef1.multiply(kns.multiply(dIjsdh).add(ijs.multiply(hXXX).multiply(dkns))));
  2715.                                         cCoef[3][j] = cCoef[3][j].subtract(coef1.multiply(kns.multiply(dIjsdk).add(ijs.multiply(kXXX).multiply(dkns))));
  2716.                                         cCoef[4][j] = cCoef[4][j].subtract(coef2.multiply(dIjsdAlpha));
  2717.                                         cCoef[5][j] = cCoef[5][j].subtract(coef2.multiply(dIjsdBeta));
  2718.                                         cCoef[6][j] = cCoef[6][j].subtract(coef0.multiply(dlns).multiply(kns).multiply(ijs));

  2719.                                         sCoef[0][j] = sCoef[0][j].add(coef4);
  2720.                                         sCoef[1][j] = sCoef[1][j].add(coef4.multiply(n + 1));
  2721.                                         sCoef[2][j] = sCoef[2][j].add(coef1.multiply(kns.multiply(dJjsdh).add(jjs.multiply(hXXX).multiply(dkns))));
  2722.                                         sCoef[3][j] = sCoef[3][j].add(coef1.multiply(kns.multiply(dJjsdk).add(jjs.multiply(kXXX).multiply(dkns))));
  2723.                                         sCoef[4][j] = sCoef[4][j].add(coef2.multiply(dJjsdAlpha));
  2724.                                         sCoef[5][j] = sCoef[5][j].add(coef2.multiply(dJjsdBeta));
  2725.                                         sCoef[6][j] = sCoef[6][j].add(coef0.multiply(dlns).multiply(kns).multiply(jjs));
  2726.                                     }
  2727.                                 }
  2728.                             }
  2729.                         }
  2730.                     }
  2731.                 }

  2732.                 cCoef[0][j] = cCoef[0][j].multiply(context.getMuoa().divide(j).negate());
  2733.                 cCoef[1][j] = cCoef[1][j].multiply(context.getMuoa().divide(auxiliaryElements.getSma().multiply(j)));
  2734.                 cCoef[2][j] = cCoef[2][j].multiply(context.getMuoa().divide(j).negate());
  2735.                 cCoef[3][j] = cCoef[3][j].multiply(context.getMuoa().divide(j).negate());
  2736.                 cCoef[4][j] = cCoef[4][j].multiply(context.getMuoa().divide(j).negate());
  2737.                 cCoef[5][j] = cCoef[5][j].multiply(context.getMuoa().divide(j).negate());
  2738.                 cCoef[6][j] = cCoef[6][j].multiply(context.getMuoa().divide(j).negate());

  2739.                 sCoef[0][j] = sCoef[0][j].multiply(context.getMuoa().divide(j).negate());
  2740.                 sCoef[1][j] = sCoef[1][j].multiply(context.getMuoa().divide(auxiliaryElements.getSma().multiply(j)));
  2741.                 sCoef[2][j] = sCoef[2][j].multiply(context.getMuoa().divide(j).negate());
  2742.                 sCoef[3][j] = sCoef[3][j].multiply(context.getMuoa().divide(j).negate());
  2743.                 sCoef[4][j] = sCoef[4][j].multiply(context.getMuoa().divide(j).negate());
  2744.                 sCoef[5][j] = sCoef[5][j].multiply(context.getMuoa().divide(j).negate());
  2745.                 sCoef[6][j] = sCoef[6][j].multiply(context.getMuoa().divide(j).negate());

  2746.             }
  2747.         }

  2748.         /** Check if an index is within the accepted interval.
  2749.          *
  2750.          * @param index the index to check
  2751.          * @param lowerBound the lower bound of the interval
  2752.          * @param upperBound the upper bound of the interval
  2753.          * @return true if the index is between the lower and upper bounds, false otherwise
  2754.          */
  2755.         private boolean isBetween(final int index, final int lowerBound, final int upperBound) {
  2756.             return index >= lowerBound && index <= upperBound;
  2757.         }

  2758.         /**Get the value of C<sup>j</sup>.
  2759.          *
  2760.          * @param j j index
  2761.          * @return C<sup>j</sup>
  2762.          */
  2763.         public T getCj(final int j) {
  2764.             return cCoef[0][j];
  2765.         }

  2766.         /**Get the value of dC<sup>j</sup> / da.
  2767.          *
  2768.          * @param j j index
  2769.          * @return dC<sup>j</sup> / da
  2770.          */
  2771.         public T getdCjdA(final int j) {
  2772.             return cCoef[1][j];
  2773.         }

  2774.         /**Get the value of dC<sup>j</sup> / dh.
  2775.          *
  2776.          * @param j j index
  2777.          * @return dC<sup>j</sup> / dh
  2778.          */
  2779.         public T getdCjdH(final int j) {
  2780.             return cCoef[2][j];
  2781.         }

  2782.         /**Get the value of dC<sup>j</sup> / dk.
  2783.          *
  2784.          * @param j j index
  2785.          * @return dC<sup>j</sup> / dk
  2786.          */
  2787.         public T getdCjdK(final int j) {
  2788.             return cCoef[3][j];
  2789.         }

  2790.         /**Get the value of dC<sup>j</sup> / dα.
  2791.          *
  2792.          * @param j j index
  2793.          * @return dC<sup>j</sup> / dα
  2794.          */
  2795.         public T getdCjdAlpha(final int j) {
  2796.             return cCoef[4][j];
  2797.         }

  2798.         /**Get the value of dC<sup>j</sup> / dβ.
  2799.          *
  2800.          * @param j j index
  2801.          * @return dC<sup>j</sup> / dβ
  2802.          */
  2803.         public T getdCjdBeta(final int j) {
  2804.             return cCoef[5][j];
  2805.         }

  2806.         /**Get the value of dC<sup>j</sup> / dγ.
  2807.          *
  2808.          * @param j j index
  2809.          * @return dC<sup>j</sup> / dγ
  2810.          */
  2811.         public T getdCjdGamma(final int j) {
  2812.             return cCoef[6][j];
  2813.         }

  2814.         /**Get the value of S<sup>j</sup>.
  2815.          *
  2816.          * @param j j index
  2817.          * @return S<sup>j</sup>
  2818.          */
  2819.         public T getSj(final int j) {
  2820.             return sCoef[0][j];
  2821.         }

  2822.         /**Get the value of dS<sup>j</sup> / da.
  2823.          *
  2824.          * @param j j index
  2825.          * @return dS<sup>j</sup> / da
  2826.          */
  2827.         public T getdSjdA(final int j) {
  2828.             return sCoef[1][j];
  2829.         }

  2830.         /**Get the value of dS<sup>j</sup> / dh.
  2831.          *
  2832.          * @param j j index
  2833.          * @return dS<sup>j</sup> / dh
  2834.          */
  2835.         public T getdSjdH(final int j) {
  2836.             return sCoef[2][j];
  2837.         }

  2838.         /**Get the value of dS<sup>j</sup> / dk.
  2839.          *
  2840.          * @param j j index
  2841.          * @return dS<sup>j</sup> / dk
  2842.          */
  2843.         public T getdSjdK(final int j) {
  2844.             return sCoef[3][j];
  2845.         }

  2846.         /**Get the value of dS<sup>j</sup> / dα.
  2847.          *
  2848.          * @param j j index
  2849.          * @return dS<sup>j</sup> / dα
  2850.          */
  2851.         public T getdSjdAlpha(final int j) {
  2852.             return sCoef[4][j];
  2853.         }

  2854.         /**Get the value of dS<sup>j</sup> / dβ.
  2855.          *
  2856.          * @param j j index
  2857.          * @return dS<sup>j</sup> / dβ
  2858.          */
  2859.         public T getdSjdBeta(final int j) {
  2860.             return sCoef[5][j];
  2861.         }

  2862.         /**Get the value of dS<sup>j</sup> /  dγ.
  2863.          *
  2864.          * @param j j index
  2865.          * @return dS<sup>j</sup> /  dγ
  2866.          */
  2867.         public T getdSjdGamma(final int j) {
  2868.             return sCoef[6][j];
  2869.         }
  2870.     }

  2871.     /** Coefficients valid for one time slot. */
  2872.     private static class Slot {

  2873.         /**The coefficients D<sub>i</sub>.
  2874.          * <p>
  2875.          * i corresponds to the equinoctial element, as follows:
  2876.          * - i=0 for a <br/>
  2877.          * - i=1 for k <br/>
  2878.          * - i=2 for h <br/>
  2879.          * - i=3 for q <br/>
  2880.          * - i=4 for p <br/>
  2881.          * - i=5 for λ <br/>
  2882.          * </p>
  2883.          */
  2884.         private final ShortPeriodicsInterpolatedCoefficient di;

  2885.         /** The coefficients C<sub>i</sub><sup>j</sup>.
  2886.          * <p>
  2887.          * The constant term C<sub>i</sub>⁰ is also stored in this variable at index j = 0 <br>
  2888.          * The index order is cij[j][i] <br/>
  2889.          * i corresponds to the equinoctial element, as follows: <br/>
  2890.          * - i=0 for a <br/>
  2891.          * - i=1 for k <br/>
  2892.          * - i=2 for h <br/>
  2893.          * - i=3 for q <br/>
  2894.          * - i=4 for p <br/>
  2895.          * - i=5 for λ <br/>
  2896.          * </p>
  2897.          */
  2898.         private final ShortPeriodicsInterpolatedCoefficient[] cij;

  2899.         /** The coefficients S<sub>i</sub><sup>j</sup>.
  2900.          * <p>
  2901.          * The index order is sij[j][i] <br/>
  2902.          * i corresponds to the equinoctial element, as follows: <br/>
  2903.          * - i=0 for a <br/>
  2904.          * - i=1 for k <br/>
  2905.          * - i=2 for h <br/>
  2906.          * - i=3 for q <br/>
  2907.          * - i=4 for p <br/>
  2908.          * - i=5 for λ <br/>
  2909.          * </p>
  2910.          */
  2911.         private final ShortPeriodicsInterpolatedCoefficient[] sij;

  2912.         /** Simple constructor.
  2913.          *  @param maxFrequencyShortPeriodics maximum value for j index
  2914.          *  @param interpolationPoints number of points used in the interpolation process
  2915.          */
  2916.         Slot(final int maxFrequencyShortPeriodics, final int interpolationPoints) {

  2917.             final int rows = maxFrequencyShortPeriodics + 1;
  2918.             di  = new ShortPeriodicsInterpolatedCoefficient(interpolationPoints);
  2919.             cij = new ShortPeriodicsInterpolatedCoefficient[rows];
  2920.             sij = new ShortPeriodicsInterpolatedCoefficient[rows];

  2921.             //Initialize the arrays
  2922.             for (int j = 0; j <= maxFrequencyShortPeriodics; j++) {
  2923.                 cij[j] = new ShortPeriodicsInterpolatedCoefficient(interpolationPoints);
  2924.                 sij[j] = new ShortPeriodicsInterpolatedCoefficient(interpolationPoints);
  2925.             }

  2926.         }

  2927.     }

  2928.     /** Coefficients valid for one time slot. */
  2929.     private static class FieldSlot <T extends CalculusFieldElement<T>> {

  2930.         /**The coefficients D<sub>i</sub>.
  2931.          * <p>
  2932.          * i corresponds to the equinoctial element, as follows:
  2933.          * - i=0 for a <br/>
  2934.          * - i=1 for k <br/>
  2935.          * - i=2 for h <br/>
  2936.          * - i=3 for q <br/>
  2937.          * - i=4 for p <br/>
  2938.          * - i=5 for λ <br/>
  2939.          * </p>
  2940.          */
  2941.         private final FieldShortPeriodicsInterpolatedCoefficient<T> di;

  2942.         /** The coefficients C<sub>i</sub><sup>j</sup>.
  2943.          * <p>
  2944.          * The constant term C<sub>i</sub>⁰ is also stored in this variable at index j = 0 <br>
  2945.          * The index order is cij[j][i] <br/>
  2946.          * i corresponds to the equinoctial element, as follows: <br/>
  2947.          * - i=0 for a <br/>
  2948.          * - i=1 for k <br/>
  2949.          * - i=2 for h <br/>
  2950.          * - i=3 for q <br/>
  2951.          * - i=4 for p <br/>
  2952.          * - i=5 for λ <br/>
  2953.          * </p>
  2954.          */
  2955.         private final FieldShortPeriodicsInterpolatedCoefficient<T>[] cij;

  2956.         /** The coefficients S<sub>i</sub><sup>j</sup>.
  2957.          * <p>
  2958.          * The index order is sij[j][i] <br/>
  2959.          * i corresponds to the equinoctial element, as follows: <br/>
  2960.          * - i=0 for a <br/>
  2961.          * - i=1 for k <br/>
  2962.          * - i=2 for h <br/>
  2963.          * - i=3 for q <br/>
  2964.          * - i=4 for p <br/>
  2965.          * - i=5 for λ <br/>
  2966.          * </p>
  2967.          */
  2968.         private final FieldShortPeriodicsInterpolatedCoefficient<T>[] sij;

  2969.         /** Simple constructor.
  2970.          *  @param maxFrequencyShortPeriodics maximum value for j index
  2971.          *  @param interpolationPoints number of points used in the interpolation process
  2972.          */
  2973.         @SuppressWarnings("unchecked")
  2974.         FieldSlot(final int maxFrequencyShortPeriodics, final int interpolationPoints) {

  2975.             final int rows = maxFrequencyShortPeriodics + 1;
  2976.             di  = new FieldShortPeriodicsInterpolatedCoefficient<>(interpolationPoints);
  2977.             cij = (FieldShortPeriodicsInterpolatedCoefficient<T>[]) Array.newInstance(FieldShortPeriodicsInterpolatedCoefficient.class, rows);
  2978.             sij = (FieldShortPeriodicsInterpolatedCoefficient<T>[]) Array.newInstance(FieldShortPeriodicsInterpolatedCoefficient.class, rows);

  2979.             //Initialize the arrays
  2980.             for (int j = 0; j <= maxFrequencyShortPeriodics; j++) {
  2981.                 cij[j] = new FieldShortPeriodicsInterpolatedCoefficient<>(interpolationPoints);
  2982.                 sij[j] = new FieldShortPeriodicsInterpolatedCoefficient<>(interpolationPoints);
  2983.             }

  2984.         }

  2985.     }

  2986.     /** Compute potential and potential derivatives with respect to orbital parameters. */
  2987.     private class UAnddU {

  2988.         /** The current value of the U function. <br/>
  2989.          * Needed for the short periodic contribution */
  2990.         private double U;

  2991.         /** dU / da. */
  2992.         private double dUda;

  2993.         /** dU / dk. */
  2994.         private double dUdk;

  2995.         /** dU / dh. */
  2996.         private double dUdh;

  2997.         /** dU / dAlpha. */
  2998.         private double dUdAl;

  2999.         /** dU / dBeta. */
  3000.         private double dUdBe;

  3001.         /** dU / dGamma. */
  3002.         private double dUdGa;

  3003.         /** Simple constuctor.
  3004.          *  @param date current date
  3005.          *  @param context container for attributes
  3006.          *  @param auxiliaryElements auxiliary elements related to the current orbit
  3007.          *  @param hansen initialization of hansen objects
  3008.          */
  3009.         UAnddU(final AbsoluteDate date,
  3010.                final DSSTZonalContext context,
  3011.                final AuxiliaryElements auxiliaryElements,
  3012.                final HansenObjects hansen) {

  3013.             final UnnormalizedSphericalHarmonics harmonics = provider.onDate(date);

  3014.             //Reset U
  3015.             U = 0.;

  3016.             // Gs and Hs coefficients
  3017.             final double[][] GsHs = CoefficientsFactory.computeGsHs(auxiliaryElements.getK(), auxiliaryElements.getH(), context.getAlpha(), context.getBeta(), maxEccPowMeanElements);
  3018.             // Qns coefficients
  3019.             final double[][] Qns  = CoefficientsFactory.computeQns(context.getGamma(), maxDegree, maxEccPowMeanElements);

  3020.             final double[] roaPow = new double[maxDegree + 1];
  3021.             roaPow[0] = 1.;
  3022.             for (int i = 1; i <= maxDegree; i++) {
  3023.                 roaPow[i] = context.getRoa() * roaPow[i - 1];
  3024.             }

  3025.             // Potential derivatives
  3026.             dUda  = 0.;
  3027.             dUdk  = 0.;
  3028.             dUdh  = 0.;
  3029.             dUdAl = 0.;
  3030.             dUdBe = 0.;
  3031.             dUdGa = 0.;

  3032.             for (int s = 0; s <= maxEccPowMeanElements; s++) {
  3033.                 //Initialize the Hansen roots
  3034.                 hansen.computeHansenObjectsInitValues(context, s);

  3035.                 // Get the current Gs coefficient
  3036.                 final double gs = GsHs[0][s];

  3037.                 // Compute Gs partial derivatives from 3.1-(9)
  3038.                 double dGsdh  = 0.;
  3039.                 double dGsdk  = 0.;
  3040.                 double dGsdAl = 0.;
  3041.                 double dGsdBe = 0.;
  3042.                 if (s > 0) {
  3043.                     // First get the G(s-1) and the H(s-1) coefficients
  3044.                     final double sxgsm1 = s * GsHs[0][s - 1];
  3045.                     final double sxhsm1 = s * GsHs[1][s - 1];
  3046.                     // Then compute derivatives
  3047.                     dGsdh  = context.getBeta()  * sxgsm1 - context.getAlpha() * sxhsm1;
  3048.                     dGsdk  = context.getAlpha() * sxgsm1 + context.getBeta()  * sxhsm1;
  3049.                     dGsdAl = auxiliaryElements.getK() * sxgsm1 - auxiliaryElements.getH() * sxhsm1;
  3050.                     dGsdBe = auxiliaryElements.getH() * sxgsm1 + auxiliaryElements.getK() * sxhsm1;
  3051.                 }

  3052.                 // Kronecker symbol (2 - delta(0,s))
  3053.                 final double d0s = (s == 0) ? 1 : 2;

  3054.                 for (int n = s + 2; n <= maxDegree; n++) {
  3055.                     // (n - s) must be even
  3056.                     if ((n - s) % 2 == 0) {

  3057.                         //Extract data from previous computation :
  3058.                         final double kns   = hansen.getHansenObjects()[s].getValue(-n - 1, context.getChi());
  3059.                         final double dkns  = hansen.getHansenObjects()[s].getDerivative(-n - 1, context.getChi());

  3060.                         final double vns   = Vns.get(new NSKey(n, s));
  3061.                         final double coef0 = d0s * roaPow[n] * vns * -harmonics.getUnnormalizedCnm(n, 0);
  3062.                         final double coef1 = coef0 * Qns[n][s];
  3063.                         final double coef2 = coef1 * kns;
  3064.                         final double coef3 = coef2 * gs;
  3065.                         // dQns/dGamma = Q(n, s + 1) from Equation 3.1-(8)
  3066.                         final double dqns  = Qns[n][s + 1];

  3067.                         // Compute U
  3068.                         U += coef3;
  3069.                         // Compute dU / da :
  3070.                         dUda += coef3 * (n + 1);
  3071.                         // Compute dU / dEx
  3072.                         dUdk += coef1 * (kns * dGsdk + auxiliaryElements.getK() * context.getChi3() * gs * dkns);
  3073.                         // Compute dU / dEy
  3074.                         dUdh += coef1 * (kns * dGsdh + auxiliaryElements.getH() * context.getChi3() * gs * dkns);
  3075.                         // Compute dU / dAlpha
  3076.                         dUdAl += coef2 * dGsdAl;
  3077.                         // Compute dU / dBeta
  3078.                         dUdBe += coef2 * dGsdBe;
  3079.                         // Compute dU / dGamma
  3080.                         dUdGa += coef0 * kns * dqns * gs;

  3081.                     }
  3082.                 }
  3083.             }

  3084.             // Multiply by -(μ / a)
  3085.             this.U = -context.getMuoa() * U;

  3086.             this.dUda = dUda *  context.getMuoa() / auxiliaryElements.getSma();
  3087.             this.dUdk = dUdk * -context.getMuoa();
  3088.             this.dUdh = dUdh * -context.getMuoa();
  3089.             this.dUdAl = dUdAl * -context.getMuoa();
  3090.             this.dUdBe = dUdBe * -context.getMuoa();
  3091.             this.dUdGa = dUdGa * -context.getMuoa();

  3092.         }

  3093.         /** Return value of U.
  3094.          * @return U
  3095.          */
  3096.         public double getU() {
  3097.             return U;
  3098.         }

  3099.         /** Return value of dU / da.
  3100.          * @return dUda
  3101.          */
  3102.         public double getdUda() {
  3103.             return dUda;
  3104.         }

  3105.         /** Return value of dU / dk.
  3106.          * @return dUdk
  3107.          */
  3108.         public double getdUdk() {
  3109.             return dUdk;
  3110.         }

  3111.         /** Return value of dU / dh.
  3112.          * @return dUdh
  3113.          */
  3114.         public double getdUdh() {
  3115.             return dUdh;
  3116.         }

  3117.         /** Return value of dU / dAlpha.
  3118.          * @return dUdAl
  3119.          */
  3120.         public double getdUdAl() {
  3121.             return dUdAl;
  3122.         }

  3123.         /** Return value of dU / dBeta.
  3124.          * @return dUdBe
  3125.          */
  3126.         public double getdUdBe() {
  3127.             return dUdBe;
  3128.         }

  3129.         /** Return value of dU / dGamma.
  3130.          * @return dUdGa
  3131.          */
  3132.         public double getdUdGa() {
  3133.             return dUdGa;
  3134.         }

  3135.     }

  3136.     /** Compute the derivatives of the gravitational potential U [Eq. 3.1-(6)].
  3137.      *  <p>
  3138.      *  The result is the array
  3139.      *  [dU/da, dU/dk, dU/dh, dU/dα, dU/dβ, dU/dγ]
  3140.      *  </p>
  3141.      */
  3142.     private class FieldUAnddU <T extends CalculusFieldElement<T>> {

  3143.          /** The current value of the U function. <br/>
  3144.           * Needed for the short periodic contribution */
  3145.         private T U;

  3146.          /** dU / da. */
  3147.         private T dUda;

  3148.          /** dU / dk. */
  3149.         private T dUdk;

  3150.          /** dU / dh. */
  3151.         private T dUdh;

  3152.          /** dU / dAlpha. */
  3153.         private T dUdAl;

  3154.          /** dU / dBeta. */
  3155.         private T dUdBe;

  3156.          /** dU / dGamma. */
  3157.         private T dUdGa;

  3158.          /** Simple constuctor.
  3159.           *  @param date current date
  3160.           *  @param context container for attributes
  3161.           *  @param auxiliaryElements auxiliary elements related to the current orbit
  3162.           *  @param hansen initialization of hansen objects
  3163.           */
  3164.         FieldUAnddU(final FieldAbsoluteDate<T> date,
  3165.                     final FieldDSSTZonalContext<T> context,
  3166.                     final FieldAuxiliaryElements<T> auxiliaryElements,
  3167.                     final FieldHansenObjects<T> hansen) {

  3168.             // Zero for initialization
  3169.             final Field<T> field = date.getField();
  3170.             final T zero = field.getZero();

  3171.             //spherical harmonics
  3172.             final UnnormalizedSphericalHarmonics harmonics = provider.onDate(date.toAbsoluteDate());

  3173.             //Reset U
  3174.             U = zero;

  3175.             // Gs and Hs coefficients
  3176.             final T[][] GsHs = CoefficientsFactory.computeGsHs(auxiliaryElements.getK(), auxiliaryElements.getH(),
  3177.                                                                context.getAlpha(), context.getBeta(),
  3178.                                                                maxEccPowMeanElements, field);
  3179.             // Qns coefficients
  3180.             final T[][] Qns  = CoefficientsFactory.computeQns(context.getGamma(), maxDegree, maxEccPowMeanElements);

  3181.             final T[] roaPow = MathArrays.buildArray(field, maxDegree + 1);
  3182.             roaPow[0] = zero.newInstance(1.);
  3183.             for (int i = 1; i <= maxDegree; i++) {
  3184.                 roaPow[i] = roaPow[i - 1].multiply(context.getRoa());
  3185.             }

  3186.             // Potential derivatives
  3187.             dUda  = zero;
  3188.             dUdk  = zero;
  3189.             dUdh  = zero;
  3190.             dUdAl = zero;
  3191.             dUdBe = zero;
  3192.             dUdGa = zero;

  3193.             for (int s = 0; s <= maxEccPowMeanElements; s++) {
  3194.                 //Initialize the Hansen roots
  3195.                 hansen.computeHansenObjectsInitValues(context, s);

  3196.                 // Get the current Gs coefficient
  3197.                 final T gs = GsHs[0][s];

  3198.                 // Compute Gs partial derivatives from 3.1-(9)
  3199.                 T dGsdh  = zero;
  3200.                 T dGsdk  = zero;
  3201.                 T dGsdAl = zero;
  3202.                 T dGsdBe = zero;
  3203.                 if (s > 0) {
  3204.                     // First get the G(s-1) and the H(s-1) coefficients
  3205.                     final T sxgsm1 = GsHs[0][s - 1].multiply(s);
  3206.                     final T sxhsm1 = GsHs[1][s - 1].multiply(s);
  3207.                     // Then compute derivatives
  3208.                     dGsdh  = sxgsm1.multiply(context.getBeta()).subtract(sxhsm1.multiply(context.getAlpha()));
  3209.                     dGsdk  = sxgsm1.multiply(context.getAlpha()).add(sxhsm1.multiply(context.getBeta()));
  3210.                     dGsdAl = sxgsm1.multiply(auxiliaryElements.getK()).subtract(sxhsm1.multiply(auxiliaryElements.getH()));
  3211.                     dGsdBe = sxgsm1.multiply(auxiliaryElements.getH()).add(sxhsm1.multiply(auxiliaryElements.getK()));
  3212.                 }

  3213.                 // Kronecker symbol (2 - delta(0,s))
  3214.                 final T d0s = zero.newInstance((s == 0) ? 1 : 2);

  3215.                 for (int n = s + 2; n <= maxDegree; n++) {
  3216.                     // (n - s) must be even
  3217.                     if ((n - s) % 2 == 0) {

  3218.                         //Extract data from previous computation :
  3219.                         final T kns   = hansen.getHansenObjects()[s].getValue(-n - 1, context.getChi());
  3220.                         final T dkns  = hansen.getHansenObjects()[s].getDerivative(-n - 1, context.getChi());

  3221.                         final double vns   = Vns.get(new NSKey(n, s));
  3222.                         final T coef0 = d0s.multiply(roaPow[n]).multiply(vns).multiply(-harmonics.getUnnormalizedCnm(n, 0));
  3223.                         final T coef1 = coef0.multiply(Qns[n][s]);
  3224.                         final T coef2 = coef1.multiply(kns);
  3225.                         final T coef3 = coef2.multiply(gs);
  3226.                         // dQns/dGamma = Q(n, s + 1) from Equation 3.1-(8)
  3227.                         final T dqns  = Qns[n][s + 1];

  3228.                         // Compute U
  3229.                         U = U.add(coef3);
  3230.                         // Compute dU / da :
  3231.                         dUda  = dUda.add(coef3.multiply(n + 1));
  3232.                         // Compute dU / dEx
  3233.                         dUdk  = dUdk.add(coef1.multiply(dGsdk.multiply(kns).add(auxiliaryElements.getK().multiply(context.getChi3()).multiply(dkns).multiply(gs))));
  3234.                         // Compute dU / dEy
  3235.                         dUdh  = dUdh.add(coef1.multiply(dGsdh.multiply(kns).add(auxiliaryElements.getH().multiply(context.getChi3()).multiply(dkns).multiply(gs))));
  3236.                         // Compute dU / dAlpha
  3237.                         dUdAl = dUdAl.add(coef2.multiply(dGsdAl));
  3238.                         // Compute dU / dBeta
  3239.                         dUdBe = dUdBe.add(coef2.multiply(dGsdBe));
  3240.                         // Compute dU / dGamma
  3241.                         dUdGa = dUdGa.add(coef0.multiply(kns).multiply(dqns).multiply(gs));
  3242.                     }
  3243.                 }
  3244.             }

  3245.             // Multiply by -(μ / a)
  3246.             U = U.multiply(context.getMuoa().negate());

  3247.             dUda  = dUda.multiply(context.getMuoa().divide(auxiliaryElements.getSma()));
  3248.             dUdk  = dUdk.multiply(context.getMuoa()).negate();
  3249.             dUdh  = dUdh.multiply(context.getMuoa()).negate();
  3250.             dUdAl = dUdAl.multiply(context.getMuoa()).negate();
  3251.             dUdBe = dUdBe.multiply(context.getMuoa()).negate();
  3252.             dUdGa = dUdGa.multiply(context.getMuoa()).negate();

  3253.         }

  3254.         /** Return value of U.
  3255.          * @return U
  3256.          */
  3257.         public T getU() {
  3258.             return U;
  3259.         }

  3260.          /** Return value of dU / da.
  3261.           * @return dUda
  3262.           */
  3263.         public T getdUda() {
  3264.             return dUda;
  3265.         }

  3266.          /** Return value of dU / dk.
  3267.           * @return dUdk
  3268.           */
  3269.         public T getdUdk() {
  3270.             return dUdk;
  3271.         }

  3272.          /** Return value of dU / dh.
  3273.           * @return dUdh
  3274.           */
  3275.         public T getdUdh() {
  3276.             return dUdh;
  3277.         }

  3278.          /** Return value of dU / dAlpha.
  3279.           * @return dUdAl
  3280.           */
  3281.         public T getdUdAl() {
  3282.             return dUdAl;
  3283.         }

  3284.          /** Return value of dU / dBeta.
  3285.           * @return dUdBe
  3286.           */
  3287.         public T getdUdBe() {
  3288.             return dUdBe;
  3289.         }

  3290.          /** Return value of dU / dGamma.
  3291.           * @return dUdGa
  3292.           */
  3293.         public T getdUdGa() {
  3294.             return dUdGa;
  3295.         }

  3296.     }

  3297.     /** Computes init values of the Hansen Objects. */
  3298.     private class HansenObjects {

  3299.         /** An array that contains the objects needed to build the Hansen coefficients. <br/>
  3300.          * The index is s*/
  3301.         private final HansenZonalLinear[] hansenObjects;

  3302.         /** Simple constructor. */
  3303.         HansenObjects() {
  3304.             this.hansenObjects = new HansenZonalLinear[maxEccPow + 1];
  3305.             for (int s = 0; s <= maxEccPow; s++) {
  3306.                 this.hansenObjects[s] = new HansenZonalLinear(maxDegree, s);
  3307.             }
  3308.         }

  3309.         /** Compute init values for hansen objects.
  3310.          * @param context container for attributes
  3311.          * @param element element of the array to compute the init values
  3312.          */
  3313.         public void computeHansenObjectsInitValues(final DSSTZonalContext context, final int element) {
  3314.             hansenObjects[element].computeInitValues(context.getChi());
  3315.         }

  3316.         /** Get the Hansen Objects.
  3317.          * @return hansenObjects
  3318.          */
  3319.         public HansenZonalLinear[] getHansenObjects() {
  3320.             return hansenObjects;
  3321.         }

  3322.     }

  3323.     /** Computes init values of the Hansen Objects.
  3324.      * @param <T> type of the elements
  3325.      */
  3326.     private class FieldHansenObjects<T extends CalculusFieldElement<T>> {

  3327.         /** An array that contains the objects needed to build the Hansen coefficients. <br/>
  3328.          * The index is s*/
  3329.         private final FieldHansenZonalLinear<T>[] hansenObjects;

  3330.         /** Simple constructor.
  3331.          * @param field field used by default
  3332.          */
  3333.         @SuppressWarnings("unchecked")
  3334.         FieldHansenObjects(final Field<T> field) {
  3335.             this.hansenObjects = (FieldHansenZonalLinear<T>[]) Array.newInstance(FieldHansenZonalLinear.class, maxEccPow + 1);
  3336.             for (int s = 0; s <= maxEccPow; s++) {
  3337.                 this.hansenObjects[s] = new FieldHansenZonalLinear<>(maxDegree, s, field);
  3338.             }
  3339.         }

  3340.         /** Compute init values for hansen objects.
  3341.          * @param context container for attributes
  3342.          * @param element element of the array to compute the init values
  3343.          */
  3344.         public void computeHansenObjectsInitValues(final FieldDSSTZonalContext<T> context, final int element) {
  3345.             hansenObjects[element].computeInitValues(context.getChi());
  3346.         }

  3347.         /** Get the Hansen Objects.
  3348.          * @return hansenObjects
  3349.          */
  3350.         public FieldHansenZonalLinear<T>[] getHansenObjects() {
  3351.             return hansenObjects;
  3352.         }

  3353.     }

  3354. }