DSSTTesseral.java
- /* Copyright 2002-2023 CS GROUP
- * Licensed to CS GROUP (CS) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * CS licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.orekit.propagation.semianalytical.dsst.forces;
- import java.lang.reflect.Array;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Collections;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- import java.util.SortedMap;
- import java.util.TreeMap;
- import org.hipparchus.CalculusFieldElement;
- import org.hipparchus.Field;
- import org.hipparchus.analysis.differentiation.FieldGradient;
- import org.hipparchus.exception.LocalizedCoreFormats;
- import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
- import org.hipparchus.geometry.euclidean.threed.Vector3D;
- import org.hipparchus.util.FastMath;
- import org.hipparchus.util.FieldSinCos;
- import org.hipparchus.util.MathArrays;
- import org.hipparchus.util.MathUtils;
- import org.hipparchus.util.SinCos;
- import org.orekit.attitudes.AttitudeProvider;
- import org.orekit.errors.OrekitException;
- import org.orekit.errors.OrekitInternalError;
- import org.orekit.forces.gravity.potential.UnnormalizedSphericalHarmonicsProvider;
- import org.orekit.forces.gravity.potential.UnnormalizedSphericalHarmonicsProvider.UnnormalizedSphericalHarmonics;
- import org.orekit.frames.FieldStaticTransform;
- import org.orekit.frames.Frame;
- import org.orekit.frames.StaticTransform;
- import org.orekit.orbits.FieldOrbit;
- import org.orekit.orbits.Orbit;
- import org.orekit.propagation.FieldSpacecraftState;
- import org.orekit.propagation.PropagationType;
- import org.orekit.propagation.SpacecraftState;
- import org.orekit.propagation.semianalytical.dsst.utilities.AuxiliaryElements;
- import org.orekit.propagation.semianalytical.dsst.utilities.CoefficientsFactory;
- import org.orekit.propagation.semianalytical.dsst.utilities.FieldAuxiliaryElements;
- import org.orekit.propagation.semianalytical.dsst.utilities.FieldGHmsjPolynomials;
- import org.orekit.propagation.semianalytical.dsst.utilities.FieldGammaMnsFunction;
- import org.orekit.propagation.semianalytical.dsst.utilities.FieldShortPeriodicsInterpolatedCoefficient;
- import org.orekit.propagation.semianalytical.dsst.utilities.GHmsjPolynomials;
- import org.orekit.propagation.semianalytical.dsst.utilities.GammaMnsFunction;
- import org.orekit.propagation.semianalytical.dsst.utilities.JacobiPolynomials;
- import org.orekit.propagation.semianalytical.dsst.utilities.ShortPeriodicsInterpolatedCoefficient;
- import org.orekit.propagation.semianalytical.dsst.utilities.hansen.FieldHansenTesseralLinear;
- import org.orekit.propagation.semianalytical.dsst.utilities.hansen.HansenTesseralLinear;
- import org.orekit.time.AbsoluteDate;
- import org.orekit.time.FieldAbsoluteDate;
- import org.orekit.utils.FieldTimeSpanMap;
- import org.orekit.utils.ParameterDriver;
- import org.orekit.utils.TimeSpanMap;
- /** Tesseral contribution to the central body gravitational perturbation.
- * <p>
- * Only resonant tesserals are considered.
- * </p>
- *
- * @author Romain Di Costanzo
- * @author Pascal Parraud
- * @author Bryan Cazabonne (field translation)
- */
- public class DSSTTesseral implements DSSTForceModel {
- /** Name of the prefix for short period coefficients keys. */
- public static final String SHORT_PERIOD_PREFIX = "DSST-central-body-tesseral-";
- /** Identifier for cMm coefficients. */
- public static final String CM_COEFFICIENTS = "cM";
- /** Identifier for sMm coefficients. */
- public static final String SM_COEFFICIENTS = "sM";
- /** Retrograde factor I.
- * <p>
- * DSST model needs equinoctial orbit as internal representation.
- * Classical equinoctial elements have discontinuities when inclination
- * is close to zero. In this representation, I = +1. <br>
- * To avoid this discontinuity, another representation exists and equinoctial
- * elements can be expressed in a different way, called "retrograde" orbit.
- * This implies I = -1. <br>
- * As Orekit doesn't implement the retrograde orbit, I is always set to +1.
- * But for the sake of consistency with the theory, the retrograde factor
- * has been kept in the formulas.
- * </p>
- */
- private static final int I = 1;
- /** Central attraction scaling factor.
- * <p>
- * We use a power of 2 to avoid numeric noise introduction
- * in the multiplications/divisions sequences.
- * </p>
- */
- private static final double MU_SCALE = FastMath.scalb(1.0, 32);
- /** Minimum period for analytically averaged high-order resonant
- * central body spherical harmonics in seconds.
- */
- private static final double MIN_PERIOD_IN_SECONDS = 864000.;
- /** Minimum period for analytically averaged high-order resonant
- * central body spherical harmonics in satellite revolutions.
- */
- private static final double MIN_PERIOD_IN_SAT_REV = 10.;
- /** Number of points for interpolation. */
- private static final int INTERPOLATION_POINTS = 3;
- /** Provider for spherical harmonics. */
- private final UnnormalizedSphericalHarmonicsProvider provider;
- /** Central body rotating frame. */
- private final Frame bodyFrame;
- /** Central body rotation rate (rad/s). */
- private final double centralBodyRotationRate;
- /** Central body rotation period (seconds). */
- private final double bodyPeriod;
- /** Maximal degree to consider for harmonics potential. */
- private final int maxDegree;
- /** Maximal degree to consider for short periodics tesseral harmonics potential (without m-daily). */
- private final int maxDegreeTesseralSP;
- /** Maximal degree to consider for short periodics m-daily tesseral harmonics potential . */
- private final int maxDegreeMdailyTesseralSP;
- /** Maximal order to consider for harmonics potential. */
- private final int maxOrder;
- /** Maximal order to consider for short periodics tesseral harmonics potential (without m-daily). */
- private final int maxOrderTesseralSP;
- /** Maximal order to consider for short periodics m-daily tesseral harmonics potential . */
- private final int maxOrderMdailyTesseralSP;
- /** Maximum power of the eccentricity to use in summation over s for
- * short periodic tesseral harmonics (without m-daily). */
- private final int maxEccPowTesseralSP;
- /** Maximum power of the eccentricity to use in summation over s for
- * m-daily tesseral harmonics. */
- private final int maxEccPowMdailyTesseralSP;
- /** Maximum value for j. */
- private final int maxFrequencyShortPeriodics;
- /** Maximum power of the eccentricity to use in summation over s. */
- private int maxEccPow;
- /** Maximum power of the eccentricity to use in Hansen coefficient Kernel expansion. */
- private int maxHansen;
- /** Maximum value between maxOrderMdailyTesseralSP and maxOrderTesseralSP. */
- private int mMax;
- /** List of non resonant orders with j != 0. */
- private final SortedMap<Integer, List<Integer> > nonResOrders;
- /** List of resonant orders. */
- private final List<Integer> resOrders;
- /** Short period terms. */
- private TesseralShortPeriodicCoefficients shortPeriodTerms;
- /** Short period terms. */
- private Map<Field<?>, FieldTesseralShortPeriodicCoefficients<?>> fieldShortPeriodTerms;
- /** Driver for gravitational parameter. */
- private final ParameterDriver gmParameterDriver;
- /** Hansen objects. */
- private HansenObjects hansen;
- /** Hansen objects for field elements. */
- private Map<Field<?>, FieldHansenObjects<?>> fieldHansen;
- /** Simple constructor with default reference values.
- * <p>
- * When this constructor is used, maximum allowed values are used
- * for the short periodic coefficients:
- * </p>
- * <ul>
- * <li> {@link #maxDegreeTesseralSP} is set to {@code provider.getMaxDegree()} </li>
- * <li> {@link #maxOrderTesseralSP} is set to {@code provider.getMaxOrder()}. </li>
- * <li> {@link #maxEccPowTesseralSP} is set to {@code min(4, provider.getMaxOrder())} </li>
- * <li> {@link #maxFrequencyShortPeriodics} is set to {@code min(provider.getMaxDegree() + 4, 12)}.
- * This parameter should not exceed 12 as higher values will exceed computer capacity </li>
- * <li> {@link #maxDegreeMdailyTesseralSP} is set to {@code provider.getMaxDegree()} </li>
- * <li> {@link #maxOrderMdailyTesseralSP} is set to {@code provider.getMaxOrder()} </li>
- * <li> {@link #maxEccPowMdailyTesseralSP} is set to min(provider.getMaxDegree() - 2, 4).
- * This parameter should not exceed 4 as higher values will exceed computer capacity </li>
- * </ul>
- * @param centralBodyFrame rotating body frame
- * @param centralBodyRotationRate central body rotation rate (rad/s)
- * @param provider provider for spherical harmonics
- * @since 10.1
- */
- public DSSTTesseral(final Frame centralBodyFrame,
- final double centralBodyRotationRate,
- final UnnormalizedSphericalHarmonicsProvider provider) {
- this(centralBodyFrame, centralBodyRotationRate, provider, provider.getMaxDegree(),
- provider.getMaxOrder(), FastMath.min(4, provider.getMaxOrder()), FastMath.min(12, provider.getMaxDegree() + 4),
- provider.getMaxDegree(), provider.getMaxOrder(), FastMath.min(4, provider.getMaxDegree() - 2));
- }
- /** Simple constructor.
- * @param centralBodyFrame rotating body frame
- * @param centralBodyRotationRate central body rotation rate (rad/s)
- * @param provider provider for spherical harmonics
- * @param maxDegreeTesseralSP maximal degree to consider for short periodics tesseral harmonics potential
- * (must be between 2 and {@code provider.getMaxDegree()})
- * @param maxOrderTesseralSP maximal order to consider for short periodics tesseral harmonics potential
- * (must be between 0 and {@code provider.getMaxOrder()})
- * @param maxEccPowTesseralSP maximum power of the eccentricity to use in summation over s for
- * short periodic tesseral harmonics (without m-daily), should typically not exceed 4 as higher
- * values will exceed computer capacity
- * (must be between 0 and {@code provider.getMaxOrder()} though, however if order = 0 the value can be anything
- * since it won't be used in the code)
- * @param maxFrequencyShortPeriodics maximum frequency in mean longitude for short periodic computations
- * (typically {@code maxDegreeTesseralSP} + {@code maxEccPowTesseralSP and no more than 12})
- * @param maxDegreeMdailyTesseralSP maximal degree to consider for short periodics m-daily tesseral harmonics potential
- * (must be between 2 and {@code provider.getMaxDegree()})
- * @param maxOrderMdailyTesseralSP maximal order to consider for short periodics m-daily tesseral harmonics potential
- * (must be between 0 and {@code provider.getMaxOrder()})
- * @param maxEccPowMdailyTesseralSP maximum power of the eccentricity to use in summation over s for
- * m-daily tesseral harmonics, (must be between 0 and {@code maxDegreeMdailyTesseralSP - 2},
- * but should typically not exceed 4 as higher values will exceed computer capacity)
- * @since 7.2
- */
- public DSSTTesseral(final Frame centralBodyFrame,
- final double centralBodyRotationRate,
- final UnnormalizedSphericalHarmonicsProvider provider,
- final int maxDegreeTesseralSP, final int maxOrderTesseralSP,
- final int maxEccPowTesseralSP, final int maxFrequencyShortPeriodics,
- final int maxDegreeMdailyTesseralSP, final int maxOrderMdailyTesseralSP,
- final int maxEccPowMdailyTesseralSP) {
- gmParameterDriver = new ParameterDriver(DSSTNewtonianAttraction.CENTRAL_ATTRACTION_COEFFICIENT,
- provider.getMu(), MU_SCALE,
- 0.0, Double.POSITIVE_INFINITY);
- // Central body rotating frame
- this.bodyFrame = centralBodyFrame;
- //Save the rotation rate
- this.centralBodyRotationRate = centralBodyRotationRate;
- // Central body rotation period in seconds
- this.bodyPeriod = MathUtils.TWO_PI / centralBodyRotationRate;
- // Provider for spherical harmonics
- this.provider = provider;
- this.maxDegree = provider.getMaxDegree();
- this.maxOrder = provider.getMaxOrder();
- //set the maximum degree order for short periodics
- checkIndexRange(maxDegreeTesseralSP, 2, maxDegree);
- this.maxDegreeTesseralSP = maxDegreeTesseralSP;
- checkIndexRange(maxDegreeMdailyTesseralSP, 2, maxDegree);
- this.maxDegreeMdailyTesseralSP = maxDegreeMdailyTesseralSP;
- checkIndexRange(maxOrderTesseralSP, 0, maxOrder);
- this.maxOrderTesseralSP = maxOrderTesseralSP;
- checkIndexRange(maxOrderMdailyTesseralSP, 0, maxOrder);
- this.maxOrderMdailyTesseralSP = maxOrderMdailyTesseralSP;
- // set the maximum value for eccentricity power
- if (maxOrder > 0) {
- // Range check can be silently ignored if order = 0
- checkIndexRange(maxEccPowTesseralSP, 0, maxOrder);
- }
- this.maxEccPowTesseralSP = maxEccPowTesseralSP;
- checkIndexRange(maxEccPowMdailyTesseralSP, 0, maxDegreeMdailyTesseralSP - 2);
- this.maxEccPowMdailyTesseralSP = maxEccPowMdailyTesseralSP;
- // set the maximum value for frequency
- this.maxFrequencyShortPeriodics = maxFrequencyShortPeriodics;
- // Initialize default values
- this.resOrders = new ArrayList<Integer>();
- this.nonResOrders = new TreeMap<Integer, List <Integer>>();
- // Initialize default values
- this.fieldShortPeriodTerms = new HashMap<>();
- this.fieldHansen = new HashMap<>();
- this.maxEccPow = 0;
- this.maxHansen = 0;
- }
- /** Check an index range.
- * @param index index value
- * @param min minimum value for index
- * @param max maximum value for index
- */
- private void checkIndexRange(final int index, final int min, final int max) {
- if (index < min || index > max) {
- throw new OrekitException(LocalizedCoreFormats.OUT_OF_RANGE_SIMPLE, index, min, max);
- }
- }
- /** {@inheritDoc} */
- @Override
- public List<ShortPeriodTerms> initializeShortPeriodTerms(final AuxiliaryElements auxiliaryElements,
- final PropagationType type,
- final double[] parameters) {
- // Initializes specific parameters.
- final DSSTTesseralContext context = initializeStep(auxiliaryElements, parameters);
- // Set the highest power of the eccentricity in the analytical power
- // series expansion for the averaged high order resonant central body
- // spherical harmonic perturbation
- maxEccPow = getMaxEccPow(auxiliaryElements.getEcc());
- // Set the maximum power of the eccentricity to use in Hansen coefficient Kernel expansion.
- maxHansen = maxEccPow / 2;
- // The following terms are only used for hansen objects initialization
- final double ratio = context.getRatio();
- // Compute the non resonant tesseral harmonic terms if not set by the user
- getResonantAndNonResonantTerms(type, context.getOrbitPeriod(), ratio);
- hansen = new HansenObjects(ratio, type);
- mMax = FastMath.max(maxOrderTesseralSP, maxOrderMdailyTesseralSP);
- shortPeriodTerms = new TesseralShortPeriodicCoefficients(bodyFrame, maxOrderMdailyTesseralSP,
- maxDegreeTesseralSP < 0, nonResOrders,
- mMax, maxFrequencyShortPeriodics, INTERPOLATION_POINTS,
- new TimeSpanMap<Slot>(new Slot(mMax, maxFrequencyShortPeriodics,
- INTERPOLATION_POINTS)));
- final List<ShortPeriodTerms> list = new ArrayList<ShortPeriodTerms>();
- list.add(shortPeriodTerms);
- return list;
- }
- /** {@inheritDoc} */
- @Override
- public <T extends CalculusFieldElement<T>> List<FieldShortPeriodTerms<T>> initializeShortPeriodTerms(final FieldAuxiliaryElements<T> auxiliaryElements,
- final PropagationType type,
- final T[] parameters) {
- // Field used by default
- final Field<T> field = auxiliaryElements.getDate().getField();
- // Initializes specific parameters.
- final FieldDSSTTesseralContext<T> context = initializeStep(auxiliaryElements, parameters);
- // Set the highest power of the eccentricity in the analytical power
- // series expansion for the averaged high order resonant central body
- // spherical harmonic perturbation
- maxEccPow = getMaxEccPow(auxiliaryElements.getEcc().getReal());
- // Set the maximum power of the eccentricity to use in Hansen coefficient Kernel expansion.
- maxHansen = maxEccPow / 2;
- // The following terms are only used for hansen objects initialization
- final T ratio = context.getRatio();
- // Compute the non resonant tesseral harmonic terms if not set by the user
- // Field information is not important here
- getResonantAndNonResonantTerms(type, context.getOrbitPeriod().getReal(), ratio.getReal());
- mMax = FastMath.max(maxOrderTesseralSP, maxOrderMdailyTesseralSP);
- fieldHansen.put(field, new FieldHansenObjects<>(ratio, type));
- final FieldTesseralShortPeriodicCoefficients<T> ftspc =
- new FieldTesseralShortPeriodicCoefficients<>(bodyFrame, maxOrderMdailyTesseralSP,
- maxDegreeTesseralSP < 0, nonResOrders,
- mMax, maxFrequencyShortPeriodics, INTERPOLATION_POINTS,
- new FieldTimeSpanMap<>(new FieldSlot<>(mMax,
- maxFrequencyShortPeriodics,
- INTERPOLATION_POINTS),
- field));
- fieldShortPeriodTerms.put(field, ftspc);
- return Collections.singletonList(ftspc);
- }
- /**
- * Get the maximum power of the eccentricity to use in summation over s.
- * @param e eccentricity
- * @return the maximum power of the eccentricity
- */
- private int getMaxEccPow(final double e) {
- // maxEccPow depends on satellite eccentricity
- if (e <= 0.005) {
- return 3;
- } else if (e <= 0.02) {
- return 4;
- } else if (e <= 0.1) {
- return 7;
- } else if (e <= 0.2) {
- return 10;
- } else if (e <= 0.3) {
- return 12;
- } else if (e <= 0.4) {
- return 15;
- } else {
- return 20;
- }
- }
- /** Performs initialization at each integration step for the current force model.
- * <p>
- * This method aims at being called before mean elements rates computation.
- * </p>
- * @param auxiliaryElements auxiliary elements related to the current orbit
- * @param parameters values of the force model parameters (only 1 value for each parameter)
- * that is to say that the extract parameter method {@link #extractParameters(double[], AbsoluteDate)}
- * should have be called before or the parameters list given in argument must correspond
- * to the extraction of parameter for a precise date {@link #getParameters(AbsoluteDate)}.
- * @return new force model context
- */
- private DSSTTesseralContext initializeStep(final AuxiliaryElements auxiliaryElements, final double[] parameters) {
- return new DSSTTesseralContext(auxiliaryElements, bodyFrame, provider, maxFrequencyShortPeriodics, bodyPeriod, parameters);
- }
- /** Performs initialization at each integration step for the current force model.
- * <p>
- * This method aims at being called before mean elements rates computation.
- * </p>
- * @param <T> type of the elements
- * @param auxiliaryElements auxiliary elements related to the current orbit
- * @param parameters list of each estimated values for each driver of the force model parameters
- * (each span of each driver)
- * @return new force model context
- */
- private <T extends CalculusFieldElement<T>> FieldDSSTTesseralContext<T> initializeStep(final FieldAuxiliaryElements<T> auxiliaryElements,
- final T[] parameters) {
- return new FieldDSSTTesseralContext<>(auxiliaryElements, bodyFrame, provider, maxFrequencyShortPeriodics, bodyPeriod, parameters);
- }
- /** {@inheritDoc} */
- @Override
- public double[] getMeanElementRate(final SpacecraftState spacecraftState,
- final AuxiliaryElements auxiliaryElements, final double[] parameters) {
- // Container for attributes
- final DSSTTesseralContext context = initializeStep(auxiliaryElements, parameters);
- // Access to potential U derivatives
- final UAnddU udu = new UAnddU(spacecraftState.getDate(), context, hansen);
- // Compute the cross derivative operator :
- final double UAlphaGamma = auxiliaryElements.getAlpha() * udu.getdUdGa() - auxiliaryElements.getGamma() * udu.getdUdAl();
- final double UAlphaBeta = auxiliaryElements.getAlpha() * udu.getdUdBe() - auxiliaryElements.getBeta() * udu.getdUdAl();
- final double UBetaGamma = auxiliaryElements.getBeta() * udu.getdUdGa() - auxiliaryElements.getGamma() * udu.getdUdBe();
- final double Uhk = auxiliaryElements.getH() * udu.getdUdk() - auxiliaryElements.getK() * udu.getdUdh();
- final double pUagmIqUbgoAB = (auxiliaryElements.getP() * UAlphaGamma - I * auxiliaryElements.getQ() * UBetaGamma) * context.getOoAB();
- final double UhkmUabmdUdl = Uhk - UAlphaBeta - udu.getdUdl();
- final double da = context.getAx2oA() * udu.getdUdl();
- final double dh = context.getBoA() * udu.getdUdk() + auxiliaryElements.getK() * pUagmIqUbgoAB - auxiliaryElements.getH() * context.getBoABpo() * udu.getdUdl();
- final double dk = -(context.getBoA() * udu.getdUdh() + auxiliaryElements.getH() * pUagmIqUbgoAB + auxiliaryElements.getK() * context.getBoABpo() * udu.getdUdl());
- final double dp = context.getCo2AB() * (auxiliaryElements.getP() * UhkmUabmdUdl - UBetaGamma);
- final double dq = context.getCo2AB() * (auxiliaryElements.getQ() * UhkmUabmdUdl - I * UAlphaGamma);
- final double dM = -context.getAx2oA() * udu.getdUda() + context.getBoABpo() * (auxiliaryElements.getH() * udu.getdUdh() + auxiliaryElements.getK() * udu.getdUdk()) + pUagmIqUbgoAB;
- return new double[] {da, dk, dh, dq, dp, dM};
- }
- /** {@inheritDoc} */
- @Override
- public <T extends CalculusFieldElement<T>> T[] getMeanElementRate(final FieldSpacecraftState<T> spacecraftState,
- final FieldAuxiliaryElements<T> auxiliaryElements,
- final T[] parameters) {
- // Field used by default
- final Field<T> field = auxiliaryElements.getDate().getField();
- // Container for attributes
- final FieldDSSTTesseralContext<T> context = initializeStep(auxiliaryElements, parameters);
- @SuppressWarnings("unchecked")
- final FieldHansenObjects<T> fho = (FieldHansenObjects<T>) fieldHansen.get(field);
- // Access to potential U derivatives
- final FieldUAnddU<T> udu = new FieldUAnddU<>(spacecraftState.getDate(), context, fho);
- // Compute the cross derivative operator :
- final T UAlphaGamma = udu.getdUdGa().multiply(auxiliaryElements.getAlpha()).subtract(udu.getdUdAl().multiply(auxiliaryElements.getGamma()));
- final T UAlphaBeta = udu.getdUdBe().multiply(auxiliaryElements.getAlpha()).subtract(udu.getdUdAl().multiply(auxiliaryElements.getBeta()));
- final T UBetaGamma = udu.getdUdGa().multiply(auxiliaryElements.getBeta()).subtract(udu.getdUdBe().multiply(auxiliaryElements.getGamma()));
- final T Uhk = udu.getdUdk().multiply(auxiliaryElements.getH()).subtract(udu.getdUdh().multiply(auxiliaryElements.getK()));
- final T pUagmIqUbgoAB = (UAlphaGamma.multiply(auxiliaryElements.getP()).subtract(UBetaGamma.multiply(auxiliaryElements.getQ()).multiply(I))).multiply(context.getOoAB());
- final T UhkmUabmdUdl = Uhk.subtract(UAlphaBeta).subtract(udu.getdUdl());
- final T da = udu.getdUdl().multiply(context.getAx2oA());
- final T dh = udu.getdUdk().multiply(context.getBoA()).add(pUagmIqUbgoAB.multiply(auxiliaryElements.getK())).subtract(udu.getdUdl().multiply(auxiliaryElements.getH()).multiply(context.getBoABpo()));
- final T dk = (udu.getdUdh().multiply(context.getBoA()).add(pUagmIqUbgoAB.multiply(auxiliaryElements.getH())).add(udu.getdUdl().multiply(context.getBoABpo()).multiply(auxiliaryElements.getK()))).negate();
- final T dp = context.getCo2AB().multiply(auxiliaryElements.getP().multiply(UhkmUabmdUdl).subtract(UBetaGamma));
- final T dq = context.getCo2AB().multiply(auxiliaryElements.getQ().multiply(UhkmUabmdUdl).subtract(UAlphaGamma.multiply(I)));
- 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()));
- final T[] elements = MathArrays.buildArray(field, 6);
- elements[0] = da;
- elements[1] = dk;
- elements[2] = dh;
- elements[3] = dq;
- elements[4] = dp;
- elements[5] = dM;
- return elements;
- }
- /** {@inheritDoc} */
- @Override
- public void updateShortPeriodTerms(final double[] parameters, final SpacecraftState... meanStates) {
- final Slot slot = shortPeriodTerms.createSlot(meanStates);
- for (final SpacecraftState meanState : meanStates) {
- final AuxiliaryElements auxiliaryElements = new AuxiliaryElements(meanState.getOrbit(), I);
- // Extract the proper parameters valid at date from the input array
- final double[] extractedParameters = this.extractParameters(parameters, auxiliaryElements.getDate());
- final DSSTTesseralContext context = initializeStep(auxiliaryElements, extractedParameters);
- // Initialise the Hansen coefficients
- for (int s = -maxDegree; s <= maxDegree; s++) {
- // coefficients with j == 0 are always needed
- hansen.computeHansenObjectsInitValues(context, s + maxDegree, 0);
- if (maxDegreeTesseralSP >= 0) {
- // initialize other objects only if required
- for (int j = 1; j <= maxFrequencyShortPeriodics; j++) {
- hansen.computeHansenObjectsInitValues(context, s + maxDegree, j);
- }
- }
- }
- final FourierCjSjCoefficients cjsjFourier = new FourierCjSjCoefficients(maxFrequencyShortPeriodics, mMax);
- // Compute coefficients
- // Compute only if there is at least one non-resonant tesseral
- if (!nonResOrders.isEmpty() || maxDegreeTesseralSP < 0) {
- // Generate the fourrier coefficients
- cjsjFourier.generateCoefficients(meanState.getDate(), context, hansen);
- // the coefficient 3n / 2a
- final double tnota = 1.5 * context.getMeanMotion() / auxiliaryElements.getSma();
- // build the mDaily coefficients
- for (int m = 1; m <= maxOrderMdailyTesseralSP; m++) {
- // build the coefficients
- buildCoefficients(cjsjFourier, meanState.getDate(), slot, m, 0, tnota, context);
- }
- if (maxDegreeTesseralSP >= 0) {
- // generate the other coefficients, if required
- for (final Map.Entry<Integer, List<Integer>> entry : nonResOrders.entrySet()) {
- for (int j : entry.getValue()) {
- // build the coefficients
- buildCoefficients(cjsjFourier, meanState.getDate(), slot, entry.getKey(), j, tnota, context);
- }
- }
- }
- }
- }
- }
- /** {@inheritDoc} */
- @Override
- @SuppressWarnings("unchecked")
- public <T extends CalculusFieldElement<T>> void updateShortPeriodTerms(final T[] parameters,
- final FieldSpacecraftState<T>... meanStates) {
- // Field used by default
- final Field<T> field = meanStates[0].getDate().getField();
- final FieldTesseralShortPeriodicCoefficients<T> ftspc = (FieldTesseralShortPeriodicCoefficients<T>) fieldShortPeriodTerms.get(field);
- final FieldSlot<T> slot = ftspc.createSlot(meanStates);
- for (final FieldSpacecraftState<T> meanState : meanStates) {
- final FieldAuxiliaryElements<T> auxiliaryElements = new FieldAuxiliaryElements<>(meanState.getOrbit(), I);
- // Extract the proper parameters valid at date from the input array
- final T[] extractedParameters = this.extractParameters(parameters, auxiliaryElements.getDate());
- final FieldDSSTTesseralContext<T> context = initializeStep(auxiliaryElements, extractedParameters);
- final FieldHansenObjects<T> fho = (FieldHansenObjects<T>) fieldHansen.get(field);
- // Initialise the Hansen coefficients
- for (int s = -maxDegree; s <= maxDegree; s++) {
- // coefficients with j == 0 are always needed
- fho.computeHansenObjectsInitValues(context, s + maxDegree, 0);
- if (maxDegreeTesseralSP >= 0) {
- // initialize other objects only if required
- for (int j = 1; j <= maxFrequencyShortPeriodics; j++) {
- fho.computeHansenObjectsInitValues(context, s + maxDegree, j);
- }
- }
- }
- final FieldFourierCjSjCoefficients<T> cjsjFourier = new FieldFourierCjSjCoefficients<>(maxFrequencyShortPeriodics, mMax, field);
- // Compute coefficients
- // Compute only if there is at least one non-resonant tesseral
- if (!nonResOrders.isEmpty() || maxDegreeTesseralSP < 0) {
- // Generate the fourrier coefficients
- cjsjFourier.generateCoefficients(meanState.getDate(), context, fho, field);
- // the coefficient 3n / 2a
- final T tnota = context.getMeanMotion().multiply(1.5).divide(auxiliaryElements.getSma());
- // build the mDaily coefficients
- for (int m = 1; m <= maxOrderMdailyTesseralSP; m++) {
- // build the coefficients
- buildCoefficients(cjsjFourier, meanState.getDate(), slot, m, 0, tnota, context, field);
- }
- if (maxDegreeTesseralSP >= 0) {
- // generate the other coefficients, if required
- for (final Map.Entry<Integer, List<Integer>> entry : nonResOrders.entrySet()) {
- for (int j : entry.getValue()) {
- // build the coefficients
- buildCoefficients(cjsjFourier, meanState.getDate(), slot, entry.getKey(), j, tnota, context, field);
- }
- }
- }
- }
- }
- }
- /** {@inheritDoc} */
- public List<ParameterDriver> getParametersDrivers() {
- return Collections.singletonList(gmParameterDriver);
- }
- /** Build a set of coefficients.
- * @param cjsjFourier the fourier coefficients C<sub>i</sub><sup>j</sup> and the S<sub>i</sub><sup>j</sup>
- * @param date the current date
- * @param slot slot to which the coefficients belong
- * @param m m index
- * @param j j index
- * @param tnota 3n/2a
- * @param context container for attributes
- */
- private void buildCoefficients(final FourierCjSjCoefficients cjsjFourier,
- final AbsoluteDate date, final Slot slot,
- final int m, final int j, final double tnota, final DSSTTesseralContext context) {
- // Create local arrays
- final double[] currentCijm = new double[] {0., 0., 0., 0., 0., 0.};
- final double[] currentSijm = new double[] {0., 0., 0., 0., 0., 0.};
- // compute the term 1 / (jn - mθ<sup>.</sup>)
- final double oojnmt = 1. / (j * context.getMeanMotion() - m * centralBodyRotationRate);
- // initialise the coeficients
- for (int i = 0; i < 6; i++) {
- currentCijm[i] = -cjsjFourier.getSijm(i, j, m);
- currentSijm[i] = cjsjFourier.getCijm(i, j, m);
- }
- // Add the separate part for δ<sub>6i</sub>
- currentCijm[5] += tnota * oojnmt * cjsjFourier.getCijm(0, j, m);
- currentSijm[5] += tnota * oojnmt * cjsjFourier.getSijm(0, j, m);
- //Multiply by 1 / (jn - mθ<sup>.</sup>)
- for (int i = 0; i < 6; i++) {
- currentCijm[i] *= oojnmt;
- currentSijm[i] *= oojnmt;
- }
- // Add the coefficients to the interpolation grid
- slot.cijm[m][j + maxFrequencyShortPeriodics].addGridPoint(date, currentCijm);
- slot.sijm[m][j + maxFrequencyShortPeriodics].addGridPoint(date, currentSijm);
- }
- /** Build a set of coefficients.
- * @param <T> the type of the field elements
- * @param cjsjFourier the fourier coefficients C<sub>i</sub><sup>j</sup> and the S<sub>i</sub><sup>j</sup>
- * @param date the current date
- * @param slot slot to which the coefficients belong
- * @param m m index
- * @param j j index
- * @param tnota 3n/2a
- * @param context container for attributes
- * @param field field used by default
- */
- private <T extends CalculusFieldElement<T>> void buildCoefficients(final FieldFourierCjSjCoefficients<T> cjsjFourier,
- final FieldAbsoluteDate<T> date,
- final FieldSlot<T> slot,
- final int m, final int j, final T tnota,
- final FieldDSSTTesseralContext<T> context,
- final Field<T> field) {
- // Zero
- final T zero = field.getZero();
- // Create local arrays
- final T[] currentCijm = MathArrays.buildArray(field, 6);
- final T[] currentSijm = MathArrays.buildArray(field, 6);
- Arrays.fill(currentCijm, zero);
- Arrays.fill(currentSijm, zero);
- // compute the term 1 / (jn - mθ<sup>.</sup>)
- final T oojnmt = (context.getMeanMotion().multiply(j).subtract(m * centralBodyRotationRate)).reciprocal();
- // initialise the coeficients
- for (int i = 0; i < 6; i++) {
- currentCijm[i] = cjsjFourier.getSijm(i, j, m).negate();
- currentSijm[i] = cjsjFourier.getCijm(i, j, m);
- }
- // Add the separate part for δ<sub>6i</sub>
- currentCijm[5] = currentCijm[5].add(tnota.multiply(oojnmt).multiply(cjsjFourier.getCijm(0, j, m)));
- currentSijm[5] = currentSijm[5].add(tnota.multiply(oojnmt).multiply(cjsjFourier.getSijm(0, j, m)));
- //Multiply by 1 / (jn - mθ<sup>.</sup>)
- for (int i = 0; i < 6; i++) {
- currentCijm[i] = currentCijm[i].multiply(oojnmt);
- currentSijm[i] = currentSijm[i].multiply(oojnmt);
- }
- // Add the coefficients to the interpolation grid
- slot.cijm[m][j + maxFrequencyShortPeriodics].addGridPoint(date, currentCijm);
- slot.sijm[m][j + maxFrequencyShortPeriodics].addGridPoint(date, currentSijm);
- }
- /**
- * Get the resonant and non-resonant tesseral terms in the central body spherical harmonic field.
- *
- * @param type type of the elements used during the propagation
- * @param orbitPeriod Keplerian period
- * @param ratio ratio of satellite period to central body rotation period
- */
- private void getResonantAndNonResonantTerms(final PropagationType type, final double orbitPeriod,
- final double ratio) {
- // Compute natural resonant terms
- final double tolerance = 1. / FastMath.max(MIN_PERIOD_IN_SAT_REV,
- MIN_PERIOD_IN_SECONDS / orbitPeriod);
- // Search the resonant orders in the tesseral harmonic field
- resOrders.clear();
- nonResOrders.clear();
- for (int m = 1; m <= maxOrder; m++) {
- final double resonance = ratio * m;
- int jRes = 0;
- final int jComputedRes = (int) FastMath.round(resonance);
- if (jComputedRes > 0 && jComputedRes <= maxFrequencyShortPeriodics && FastMath.abs(resonance - jComputedRes) <= tolerance) {
- // Store each resonant index and order
- resOrders.add(m);
- jRes = jComputedRes;
- }
- if (type == PropagationType.OSCULATING && maxDegreeTesseralSP >= 0 && m <= maxOrderTesseralSP) {
- //compute non resonant orders in the tesseral harmonic field
- final List<Integer> listJofM = new ArrayList<Integer>();
- //for the moment we take only the pairs (j,m) with |j| <= maxDegree + maxEccPow (from |s-j| <= maxEccPow and |s| <= maxDegree)
- for (int j = -maxFrequencyShortPeriodics; j <= maxFrequencyShortPeriodics; j++) {
- if (j != 0 && j != jRes) {
- listJofM.add(j);
- }
- }
- nonResOrders.put(m, listJofM);
- }
- }
- }
- /** Compute the n-SUM for potential derivatives components.
- * @param date current date
- * @param j resonant index <i>j</i>
- * @param m resonant order <i>m</i>
- * @param s d'Alembert characteristic <i>s</i>
- * @param maxN maximum possible value for <i>n</i> index
- * @param roaPow powers of R/a up to degree <i>n</i>
- * @param ghMSJ G<sup>j</sup><sub>m,s</sub> and H<sup>j</sup><sub>m,s</sub> polynomials
- * @param gammaMNS Γ<sup>m</sup><sub>n,s</sub>(γ) function
- * @param context container for attributes
- * @param hansenObjects initialization of hansen objects
- * @return Components of U<sub>n</sub> derivatives for fixed j, m, s
- */
- private double[][] computeNSum(final AbsoluteDate date,
- final int j, final int m, final int s, final int maxN, final double[] roaPow,
- final GHmsjPolynomials ghMSJ, final GammaMnsFunction gammaMNS, final DSSTTesseralContext context,
- final HansenObjects hansenObjects) {
- // Auxiliary elements related to the current orbit
- final AuxiliaryElements auxiliaryElements = context.getAuxiliaryElements();
- //spherical harmonics
- final UnnormalizedSphericalHarmonics harmonics = provider.onDate(date);
- // Potential derivatives components
- double dUdaCos = 0.;
- double dUdaSin = 0.;
- double dUdhCos = 0.;
- double dUdhSin = 0.;
- double dUdkCos = 0.;
- double dUdkSin = 0.;
- double dUdlCos = 0.;
- double dUdlSin = 0.;
- double dUdAlCos = 0.;
- double dUdAlSin = 0.;
- double dUdBeCos = 0.;
- double dUdBeSin = 0.;
- double dUdGaCos = 0.;
- double dUdGaSin = 0.;
- // I^m
- @SuppressWarnings("unused")
- final int Im = I > 0 ? 1 : (m % 2 == 0 ? 1 : -1);
- // jacobi v, w, indices from 2.7.1-(15)
- final int v = FastMath.abs(m - s);
- final int w = FastMath.abs(m + s);
- // Initialise lower degree nmin = (Max(2, m, |s|)) for summation over n
- final int nmin = FastMath.max(FastMath.max(2, m), FastMath.abs(s));
- //Get the corresponding Hansen object
- final int sIndex = maxDegree + (j < 0 ? -s : s);
- final int jIndex = FastMath.abs(j);
- final HansenTesseralLinear hans = hansenObjects.getHansenObjects()[sIndex][jIndex];
- // n-SUM from nmin to N
- for (int n = nmin; n <= maxN; n++) {
- // If (n - s) is odd, the contribution is null because of Vmns
- if ((n - s) % 2 == 0) {
- // Vmns coefficient
- final double vMNS = CoefficientsFactory.getVmns(m, n, s);
- // Inclination function Gamma and derivative
- final double gaMNS = gammaMNS.getValue(m, n, s);
- final double dGaMNS = gammaMNS.getDerivative(m, n, s);
- // Hansen kernel value and derivative
- final double kJNS = hans.getValue(-n - 1, context.getChi());
- final double dkJNS = hans.getDerivative(-n - 1, context.getChi());
- // Gjms, Hjms polynomials and derivatives
- final double gMSJ = ghMSJ.getGmsj(m, s, j);
- final double hMSJ = ghMSJ.getHmsj(m, s, j);
- final double dGdh = ghMSJ.getdGmsdh(m, s, j);
- final double dGdk = ghMSJ.getdGmsdk(m, s, j);
- final double dGdA = ghMSJ.getdGmsdAlpha(m, s, j);
- final double dGdB = ghMSJ.getdGmsdBeta(m, s, j);
- final double dHdh = ghMSJ.getdHmsdh(m, s, j);
- final double dHdk = ghMSJ.getdHmsdk(m, s, j);
- final double dHdA = ghMSJ.getdHmsdAlpha(m, s, j);
- final double dHdB = ghMSJ.getdHmsdBeta(m, s, j);
- // Jacobi l-index from 2.7.1-(15)
- final int l = FastMath.min(n - m, n - FastMath.abs(s));
- // Jacobi polynomial and derivative
- final double[] jacobi = JacobiPolynomials.getValueAndDerivative(l, v, w, auxiliaryElements.getGamma());
- // Geopotential coefficients
- final double cnm = harmonics.getUnnormalizedCnm(n, m);
- final double snm = harmonics.getUnnormalizedSnm(n, m);
- // Common factors from expansion of equations 3.3-4
- final double cf_0 = roaPow[n] * Im * vMNS;
- final double cf_1 = cf_0 * gaMNS * jacobi[0]; //jacobi.getValue();
- final double cf_2 = cf_1 * kJNS;
- final double gcPhs = gMSJ * cnm + hMSJ * snm;
- final double gsMhc = gMSJ * snm - hMSJ * cnm;
- final double dKgcPhsx2 = 2. * dkJNS * gcPhs;
- final double dKgsMhcx2 = 2. * dkJNS * gsMhc;
- final double dUdaCoef = (n + 1) * cf_2;
- final double dUdlCoef = j * cf_2;
- //final double dUdGaCoef = cf_0 * kJNS * (jacobi.getValue() * dGaMNS + gaMNS * jacobi.getGradient()[0]);
- final double dUdGaCoef = cf_0 * kJNS * (jacobi[0] * dGaMNS + gaMNS * jacobi[1]);
- // dU / da components
- dUdaCos += dUdaCoef * gcPhs;
- dUdaSin += dUdaCoef * gsMhc;
- // dU / dh components
- dUdhCos += cf_1 * (kJNS * (cnm * dGdh + snm * dHdh) + auxiliaryElements.getH() * dKgcPhsx2);
- dUdhSin += cf_1 * (kJNS * (snm * dGdh - cnm * dHdh) + auxiliaryElements.getH() * dKgsMhcx2);
- // dU / dk components
- dUdkCos += cf_1 * (kJNS * (cnm * dGdk + snm * dHdk) + auxiliaryElements.getK() * dKgcPhsx2);
- dUdkSin += cf_1 * (kJNS * (snm * dGdk - cnm * dHdk) + auxiliaryElements.getK() * dKgsMhcx2);
- // dU / dLambda components
- dUdlCos += dUdlCoef * gsMhc;
- dUdlSin += -dUdlCoef * gcPhs;
- // dU / alpha components
- dUdAlCos += cf_2 * (dGdA * cnm + dHdA * snm);
- dUdAlSin += cf_2 * (dGdA * snm - dHdA * cnm);
- // dU / dBeta components
- dUdBeCos += cf_2 * (dGdB * cnm + dHdB * snm);
- dUdBeSin += cf_2 * (dGdB * snm - dHdB * cnm);
- // dU / dGamma components
- dUdGaCos += dUdGaCoef * gcPhs;
- dUdGaSin += dUdGaCoef * gsMhc;
- }
- }
- return new double[][] { { dUdaCos, dUdaSin },
- { dUdhCos, dUdhSin },
- { dUdkCos, dUdkSin },
- { dUdlCos, dUdlSin },
- { dUdAlCos, dUdAlSin },
- { dUdBeCos, dUdBeSin },
- { dUdGaCos, dUdGaSin } };
- }
- /** Compute the n-SUM for potential derivatives components.
- * @param <T> the type of the field elements
- * @param date current date
- * @param j resonant index <i>j</i>
- * @param m resonant order <i>m</i>
- * @param s d'Alembert characteristic <i>s</i>
- * @param maxN maximum possible value for <i>n</i> index
- * @param roaPow powers of R/a up to degree <i>n</i>
- * @param ghMSJ G<sup>j</sup><sub>m,s</sub> and H<sup>j</sup><sub>m,s</sub> polynomials
- * @param gammaMNS Γ<sup>m</sup><sub>n,s</sub>(γ) function
- * @param context container for attributes
- * @param hansenObjects initialization of hansen objects
- * @return Components of U<sub>n</sub> derivatives for fixed j, m, s
- */
- private <T extends CalculusFieldElement<T>> T[][] computeNSum(final FieldAbsoluteDate<T> date,
- final int j, final int m, final int s, final int maxN,
- final T[] roaPow,
- final FieldGHmsjPolynomials<T> ghMSJ,
- final FieldGammaMnsFunction<T> gammaMNS,
- final FieldDSSTTesseralContext<T> context,
- final FieldHansenObjects<T> hansenObjects) {
- // Auxiliary elements related to the current orbit
- final FieldAuxiliaryElements<T> auxiliaryElements = context.getFieldAuxiliaryElements();
- // Zero for initialization
- final Field<T> field = date.getField();
- final T zero = field.getZero();
- //spherical harmonics
- final UnnormalizedSphericalHarmonics harmonics = provider.onDate(date.toAbsoluteDate());
- // Potential derivatives components
- T dUdaCos = zero;
- T dUdaSin = zero;
- T dUdhCos = zero;
- T dUdhSin = zero;
- T dUdkCos = zero;
- T dUdkSin = zero;
- T dUdlCos = zero;
- T dUdlSin = zero;
- T dUdAlCos = zero;
- T dUdAlSin = zero;
- T dUdBeCos = zero;
- T dUdBeSin = zero;
- T dUdGaCos = zero;
- T dUdGaSin = zero;
- // I^m
- @SuppressWarnings("unused")
- final int Im = I > 0 ? 1 : (m % 2 == 0 ? 1 : -1);
- // jacobi v, w, indices from 2.7.1-(15)
- final int v = FastMath.abs(m - s);
- final int w = FastMath.abs(m + s);
- // Initialise lower degree nmin = (Max(2, m, |s|)) for summation over n
- final int nmin = FastMath.max(FastMath.max(2, m), FastMath.abs(s));
- //Get the corresponding Hansen object
- final int sIndex = maxDegree + (j < 0 ? -s : s);
- final int jIndex = FastMath.abs(j);
- final FieldHansenTesseralLinear<T> hans = hansenObjects.getHansenObjects()[sIndex][jIndex];
- // n-SUM from nmin to N
- for (int n = nmin; n <= maxN; n++) {
- // If (n - s) is odd, the contribution is null because of Vmns
- if ((n - s) % 2 == 0) {
- // Vmns coefficient
- final T vMNS = zero.add(CoefficientsFactory.getVmns(m, n, s));
- // Inclination function Gamma and derivative
- final T gaMNS = gammaMNS.getValue(m, n, s);
- final T dGaMNS = gammaMNS.getDerivative(m, n, s);
- // Hansen kernel value and derivative
- final T kJNS = hans.getValue(-n - 1, context.getChi());
- final T dkJNS = hans.getDerivative(-n - 1, context.getChi());
- // Gjms, Hjms polynomials and derivatives
- final T gMSJ = ghMSJ.getGmsj(m, s, j);
- final T hMSJ = ghMSJ.getHmsj(m, s, j);
- final T dGdh = ghMSJ.getdGmsdh(m, s, j);
- final T dGdk = ghMSJ.getdGmsdk(m, s, j);
- final T dGdA = ghMSJ.getdGmsdAlpha(m, s, j);
- final T dGdB = ghMSJ.getdGmsdBeta(m, s, j);
- final T dHdh = ghMSJ.getdHmsdh(m, s, j);
- final T dHdk = ghMSJ.getdHmsdk(m, s, j);
- final T dHdA = ghMSJ.getdHmsdAlpha(m, s, j);
- final T dHdB = ghMSJ.getdHmsdBeta(m, s, j);
- // Jacobi l-index from 2.7.1-(15)
- final int l = FastMath.min(n - m, n - FastMath.abs(s));
- // Jacobi polynomial and derivative
- final FieldGradient<T> jacobi =
- JacobiPolynomials.getValue(l, v, w, FieldGradient.variable(1, 0, auxiliaryElements.getGamma()));
- // Geopotential coefficients
- final T cnm = zero.add(harmonics.getUnnormalizedCnm(n, m));
- final T snm = zero.add(harmonics.getUnnormalizedSnm(n, m));
- // Common factors from expansion of equations 3.3-4
- final T cf_0 = roaPow[n].multiply(Im).multiply(vMNS);
- final T cf_1 = cf_0.multiply(gaMNS).multiply(jacobi.getValue());
- final T cf_2 = cf_1.multiply(kJNS);
- final T gcPhs = gMSJ.multiply(cnm).add(hMSJ.multiply(snm));
- final T gsMhc = gMSJ.multiply(snm).subtract(hMSJ.multiply(cnm));
- final T dKgcPhsx2 = dkJNS.multiply(gcPhs).multiply(2.);
- final T dKgsMhcx2 = dkJNS.multiply(gsMhc).multiply(2.);
- final T dUdaCoef = cf_2.multiply(n + 1);
- final T dUdlCoef = cf_2.multiply(j);
- final T dUdGaCoef = cf_0.multiply(kJNS).multiply(dGaMNS.multiply(jacobi.getValue()).add(gaMNS.multiply(jacobi.getGradient()[0])));
- // dU / da components
- dUdaCos = dUdaCos.add(dUdaCoef.multiply(gcPhs));
- dUdaSin = dUdaSin.add(dUdaCoef.multiply(gsMhc));
- // dU / dh components
- dUdhCos = dUdhCos.add(cf_1.multiply(kJNS.multiply(cnm.multiply(dGdh).add(snm.multiply(dHdh))).add(dKgcPhsx2.multiply(auxiliaryElements.getH()))));
- dUdhSin = dUdhSin.add(cf_1.multiply(kJNS.multiply(snm.multiply(dGdh).subtract(cnm.multiply(dHdh))).add(dKgsMhcx2.multiply(auxiliaryElements.getH()))));
- // dU / dk components
- dUdkCos = dUdkCos.add(cf_1.multiply(kJNS.multiply(cnm.multiply(dGdk).add(snm.multiply(dHdk))).add(dKgcPhsx2.multiply(auxiliaryElements.getK()))));
- dUdkSin = dUdkSin.add(cf_1.multiply(kJNS.multiply(snm.multiply(dGdk).subtract(cnm.multiply(dHdk))).add(dKgsMhcx2.multiply(auxiliaryElements.getK()))));
- // dU / dLambda components
- dUdlCos = dUdlCos.add(dUdlCoef.multiply(gsMhc));
- dUdlSin = dUdlSin.add(dUdlCoef.multiply(gcPhs).negate());
- // dU / alpha components
- dUdAlCos = dUdAlCos.add(cf_2.multiply(dGdA.multiply(cnm).add(dHdA.multiply(snm))));
- dUdAlSin = dUdAlSin.add(cf_2.multiply(dGdA.multiply(snm).subtract(dHdA.multiply(cnm))));
- // dU / dBeta components
- dUdBeCos = dUdBeCos.add(cf_2.multiply(dGdB.multiply(cnm).add(dHdB.multiply(snm))));
- dUdBeSin = dUdBeSin.add(cf_2.multiply(dGdB.multiply(snm).subtract(dHdB.multiply(cnm))));
- // dU / dGamma components
- dUdGaCos = dUdGaCos.add(dUdGaCoef.multiply(gcPhs));
- dUdGaSin = dUdGaSin.add(dUdGaCoef.multiply(gsMhc));
- }
- }
- final T[][] derivatives = MathArrays.buildArray(field, 7, 2);
- derivatives[0][0] = dUdaCos;
- derivatives[0][1] = dUdaSin;
- derivatives[1][0] = dUdhCos;
- derivatives[1][1] = dUdhSin;
- derivatives[2][0] = dUdkCos;
- derivatives[2][1] = dUdkSin;
- derivatives[3][0] = dUdlCos;
- derivatives[3][1] = dUdlSin;
- derivatives[4][0] = dUdAlCos;
- derivatives[4][1] = dUdAlSin;
- derivatives[5][0] = dUdBeCos;
- derivatives[5][1] = dUdBeSin;
- derivatives[6][0] = dUdGaCos;
- derivatives[6][1] = dUdGaSin;
- return derivatives;
- }
- /** {@inheritDoc} */
- @Override
- public void registerAttitudeProvider(final AttitudeProvider attitudeProvider) {
- //nothing is done since this contribution is not sensitive to attitude
- }
- /** Compute the C<sup>j</sup> and the S<sup>j</sup> coefficients.
- * <p>
- * Those coefficients are given in Danielson paper by substituting the
- * disturbing function (2.7.1-16) with m != 0 into (2.2-10)
- * </p>
- */
- private class FourierCjSjCoefficients {
- /** Absolute limit for j ( -jMax <= j <= jMax ). */
- private final int jMax;
- /** The C<sub>i</sub><sup>jm</sup> coefficients.
- * <p>
- * The index order is [m][j][i] <br/>
- * The i index corresponds to the C<sub>i</sub><sup>jm</sup> coefficients used to
- * compute the following: <br/>
- * - da/dt <br/>
- * - dk/dt <br/>
- * - dh/dt / dk <br/>
- * - dq/dt <br/>
- * - dp/dt / dα <br/>
- * - dλ/dt / dβ <br/>
- * </p>
- */
- private final double[][][] cCoef;
- /** The S<sub>i</sub><sup>jm</sup> coefficients.
- * <p>
- * The index order is [m][j][i] <br/>
- * The i index corresponds to the C<sub>i</sub><sup>jm</sup> coefficients used to
- * compute the following: <br/>
- * - da/dt <br/>
- * - dk/dt <br/>
- * - dh/dt / dk <br/>
- * - dq/dt <br/>
- * - dp/dt / dα <br/>
- * - dλ/dt / dβ <br/>
- * </p>
- */
- private final double[][][] sCoef;
- /** G<sub>ms</sub><sup>j</sup> and H<sub>ms</sub><sup>j</sup> polynomials. */
- private GHmsjPolynomials ghMSJ;
- /** Γ<sub>ns</sub><sup>m</sup> function. */
- private GammaMnsFunction gammaMNS;
- /** R / a up to power degree. */
- private final double[] roaPow;
- /** Create a set of C<sub>i</sub><sup>jm</sup> and S<sub>i</sub><sup>jm</sup> coefficients.
- * @param jMax absolute limit for j ( -jMax <= j <= jMax )
- * @param mMax maximum value for m
- */
- FourierCjSjCoefficients(final int jMax, final int mMax) {
- // initialise fields
- final int rows = mMax + 1;
- final int columns = 2 * jMax + 1;
- this.jMax = jMax;
- this.cCoef = new double[rows][columns][6];
- this.sCoef = new double[rows][columns][6];
- this.roaPow = new double[maxDegree + 1];
- roaPow[0] = 1.;
- }
- /**
- * Generate the coefficients.
- * @param date the current date
- * @param context container for attributes
- * @param hansenObjects initialization of hansen objects
- */
- public void generateCoefficients(final AbsoluteDate date, final DSSTTesseralContext context,
- final HansenObjects hansenObjects) {
- final AuxiliaryElements auxiliaryElements = context.getAuxiliaryElements();
- // Compute only if there is at least one non-resonant tesseral
- if (!nonResOrders.isEmpty() || maxDegreeTesseralSP < 0) {
- // Gmsj and Hmsj polynomials
- ghMSJ = new GHmsjPolynomials(auxiliaryElements.getK(), auxiliaryElements.getH(), auxiliaryElements.getAlpha(), auxiliaryElements.getBeta(), I);
- // GAMMAmns function
- gammaMNS = new GammaMnsFunction(maxDegree, auxiliaryElements.getGamma(), I);
- final int maxRoaPower = FastMath.max(maxDegreeTesseralSP, maxDegreeMdailyTesseralSP);
- // R / a up to power degree
- for (int i = 1; i <= maxRoaPower; i++) {
- roaPow[i] = context.getRoa() * roaPow[i - 1];
- }
- //generate the m-daily coefficients
- for (int m = 1; m <= maxOrderMdailyTesseralSP; m++) {
- buildFourierCoefficients(date, m, 0, maxDegreeMdailyTesseralSP, context, hansenObjects);
- }
- // generate the other coefficients only if required
- if (maxDegreeTesseralSP >= 0) {
- for (int m: nonResOrders.keySet()) {
- final List<Integer> listJ = nonResOrders.get(m);
- for (int j: listJ) {
- buildFourierCoefficients(date, m, j, maxDegreeTesseralSP, context, hansenObjects);
- }
- }
- }
- }
- }
- /** Build a set of fourier coefficients for a given m and j.
- *
- * @param date the date of the coefficients
- * @param m m index
- * @param j j index
- * @param maxN maximum value for n index
- * @param context container for attributes
- * @param hansenObjects initialization of hansen objects
- */
- private void buildFourierCoefficients(final AbsoluteDate date,
- final int m, final int j, final int maxN, final DSSTTesseralContext context,
- final HansenObjects hansenObjects) {
- final AuxiliaryElements auxiliaryElements = context.getAuxiliaryElements();
- // Potential derivatives components for a given non-resonant pair {j,m}
- double dRdaCos = 0.;
- double dRdaSin = 0.;
- double dRdhCos = 0.;
- double dRdhSin = 0.;
- double dRdkCos = 0.;
- double dRdkSin = 0.;
- double dRdlCos = 0.;
- double dRdlSin = 0.;
- double dRdAlCos = 0.;
- double dRdAlSin = 0.;
- double dRdBeCos = 0.;
- double dRdBeSin = 0.;
- double dRdGaCos = 0.;
- double dRdGaSin = 0.;
- // s-SUM from -sMin to sMax
- final int sMin = j == 0 ? maxEccPowMdailyTesseralSP : maxEccPowTesseralSP;
- final int sMax = j == 0 ? maxEccPowMdailyTesseralSP : maxEccPowTesseralSP;
- for (int s = 0; s <= sMax; s++) {
- // n-SUM for s positive
- final double[][] nSumSpos = computeNSum(date, j, m, s, maxN,
- roaPow, ghMSJ, gammaMNS, context, hansenObjects);
- dRdaCos += nSumSpos[0][0];
- dRdaSin += nSumSpos[0][1];
- dRdhCos += nSumSpos[1][0];
- dRdhSin += nSumSpos[1][1];
- dRdkCos += nSumSpos[2][0];
- dRdkSin += nSumSpos[2][1];
- dRdlCos += nSumSpos[3][0];
- dRdlSin += nSumSpos[3][1];
- dRdAlCos += nSumSpos[4][0];
- dRdAlSin += nSumSpos[4][1];
- dRdBeCos += nSumSpos[5][0];
- dRdBeSin += nSumSpos[5][1];
- dRdGaCos += nSumSpos[6][0];
- dRdGaSin += nSumSpos[6][1];
- // n-SUM for s negative
- if (s > 0 && s <= sMin) {
- final double[][] nSumSneg = computeNSum(date, j, m, -s, maxN,
- roaPow, ghMSJ, gammaMNS, context, hansenObjects);
- dRdaCos += nSumSneg[0][0];
- dRdaSin += nSumSneg[0][1];
- dRdhCos += nSumSneg[1][0];
- dRdhSin += nSumSneg[1][1];
- dRdkCos += nSumSneg[2][0];
- dRdkSin += nSumSneg[2][1];
- dRdlCos += nSumSneg[3][0];
- dRdlSin += nSumSneg[3][1];
- dRdAlCos += nSumSneg[4][0];
- dRdAlSin += nSumSneg[4][1];
- dRdBeCos += nSumSneg[5][0];
- dRdBeSin += nSumSneg[5][1];
- dRdGaCos += nSumSneg[6][0];
- dRdGaSin += nSumSneg[6][1];
- }
- }
- dRdaCos *= -context.getMoa() / auxiliaryElements.getSma();
- dRdaSin *= -context.getMoa() / auxiliaryElements.getSma();
- dRdhCos *= context.getMoa();
- dRdhSin *= context.getMoa();
- dRdkCos *= context.getMoa();
- dRdkSin *= context.getMoa();
- dRdlCos *= context.getMoa();
- dRdlSin *= context.getMoa();
- dRdAlCos *= context.getMoa();
- dRdAlSin *= context.getMoa();
- dRdBeCos *= context.getMoa();
- dRdBeSin *= context.getMoa();
- dRdGaCos *= context.getMoa();
- dRdGaSin *= context.getMoa();
- // Compute the cross derivative operator :
- final double RAlphaGammaCos = auxiliaryElements.getAlpha() * dRdGaCos - auxiliaryElements.getGamma() * dRdAlCos;
- final double RAlphaGammaSin = auxiliaryElements.getAlpha() * dRdGaSin - auxiliaryElements.getGamma() * dRdAlSin;
- final double RAlphaBetaCos = auxiliaryElements.getAlpha() * dRdBeCos - auxiliaryElements.getBeta() * dRdAlCos;
- final double RAlphaBetaSin = auxiliaryElements.getAlpha() * dRdBeSin - auxiliaryElements.getBeta() * dRdAlSin;
- final double RBetaGammaCos = auxiliaryElements.getBeta() * dRdGaCos - auxiliaryElements.getGamma() * dRdBeCos;
- final double RBetaGammaSin = auxiliaryElements.getBeta() * dRdGaSin - auxiliaryElements.getGamma() * dRdBeSin;
- final double RhkCos = auxiliaryElements.getH() * dRdkCos - auxiliaryElements.getK() * dRdhCos;
- final double RhkSin = auxiliaryElements.getH() * dRdkSin - auxiliaryElements.getK() * dRdhSin;
- final double pRagmIqRbgoABCos = (auxiliaryElements.getP() * RAlphaGammaCos - I * auxiliaryElements.getQ() * RBetaGammaCos) * context.getOoAB();
- final double pRagmIqRbgoABSin = (auxiliaryElements.getP() * RAlphaGammaSin - I * auxiliaryElements.getQ() * RBetaGammaSin) * context.getOoAB();
- final double RhkmRabmdRdlCos = RhkCos - RAlphaBetaCos - dRdlCos;
- final double RhkmRabmdRdlSin = RhkSin - RAlphaBetaSin - dRdlSin;
- // da/dt
- cCoef[m][j + jMax][0] = context.getAx2oA() * dRdlCos;
- sCoef[m][j + jMax][0] = context.getAx2oA() * dRdlSin;
- // dk/dt
- cCoef[m][j + jMax][1] = -(context.getBoA() * dRdhCos + auxiliaryElements.getH() * pRagmIqRbgoABCos + auxiliaryElements.getK() * context.getBoABpo() * dRdlCos);
- sCoef[m][j + jMax][1] = -(context.getBoA() * dRdhSin + auxiliaryElements.getH() * pRagmIqRbgoABSin + auxiliaryElements.getK() * context.getBoABpo() * dRdlSin);
- // dh/dt
- cCoef[m][j + jMax][2] = context.getBoA() * dRdkCos + auxiliaryElements.getK() * pRagmIqRbgoABCos - auxiliaryElements.getH() * context.getBoABpo() * dRdlCos;
- sCoef[m][j + jMax][2] = context.getBoA() * dRdkSin + auxiliaryElements.getK() * pRagmIqRbgoABSin - auxiliaryElements.getH() * context.getBoABpo() * dRdlSin;
- // dq/dt
- cCoef[m][j + jMax][3] = context.getCo2AB() * (auxiliaryElements.getQ() * RhkmRabmdRdlCos - I * RAlphaGammaCos);
- sCoef[m][j + jMax][3] = context.getCo2AB() * (auxiliaryElements.getQ() * RhkmRabmdRdlSin - I * RAlphaGammaSin);
- // dp/dt
- cCoef[m][j + jMax][4] = context.getCo2AB() * (auxiliaryElements.getP() * RhkmRabmdRdlCos - RBetaGammaCos);
- sCoef[m][j + jMax][4] = context.getCo2AB() * (auxiliaryElements.getP() * RhkmRabmdRdlSin - RBetaGammaSin);
- // dλ/dt
- cCoef[m][j + jMax][5] = -context.getAx2oA() * dRdaCos + context.getBoABpo() * (auxiliaryElements.getH() * dRdhCos + auxiliaryElements.getK() * dRdkCos) + pRagmIqRbgoABCos;
- sCoef[m][j + jMax][5] = -context.getAx2oA() * dRdaSin + context.getBoABpo() * (auxiliaryElements.getH() * dRdhSin + auxiliaryElements.getK() * dRdkSin) + pRagmIqRbgoABSin;
- }
- /** Get the coefficient C<sub>i</sub><sup>jm</sup>.
- * @param i i index - corresponds to the required variation
- * @param j j index
- * @param m m index
- * @return the coefficient C<sub>i</sub><sup>jm</sup>
- */
- public double getCijm(final int i, final int j, final int m) {
- return cCoef[m][j + jMax][i];
- }
- /** Get the coefficient S<sub>i</sub><sup>jm</sup>.
- * @param i i index - corresponds to the required variation
- * @param j j index
- * @param m m index
- * @return the coefficient S<sub>i</sub><sup>jm</sup>
- */
- public double getSijm(final int i, final int j, final int m) {
- return sCoef[m][j + jMax][i];
- }
- }
- /** Compute the C<sup>j</sup> and the S<sup>j</sup> coefficients.
- * <p>
- * Those coefficients are given in Danielson paper by substituting the
- * disturbing function (2.7.1-16) with m != 0 into (2.2-10)
- * </p>
- */
- private class FieldFourierCjSjCoefficients <T extends CalculusFieldElement<T>> {
- /** Absolute limit for j ( -jMax <= j <= jMax ). */
- private final int jMax;
- /** The C<sub>i</sub><sup>jm</sup> coefficients.
- * <p>
- * The index order is [m][j][i] <br/>
- * The i index corresponds to the C<sub>i</sub><sup>jm</sup> coefficients used to
- * compute the following: <br/>
- * - da/dt <br/>
- * - dk/dt <br/>
- * - dh/dt / dk <br/>
- * - dq/dt <br/>
- * - dp/dt / dα <br/>
- * - dλ/dt / dβ <br/>
- * </p>
- */
- private final T[][][] cCoef;
- /** The S<sub>i</sub><sup>jm</sup> coefficients.
- * <p>
- * The index order is [m][j][i] <br/>
- * The i index corresponds to the C<sub>i</sub><sup>jm</sup> coefficients used to
- * compute the following: <br/>
- * - da/dt <br/>
- * - dk/dt <br/>
- * - dh/dt / dk <br/>
- * - dq/dt <br/>
- * - dp/dt / dα <br/>
- * - dλ/dt / dβ <br/>
- * </p>
- */
- private final T[][][] sCoef;
- /** G<sub>ms</sub><sup>j</sup> and H<sub>ms</sub><sup>j</sup> polynomials. */
- private FieldGHmsjPolynomials<T> ghMSJ;
- /** Γ<sub>ns</sub><sup>m</sup> function. */
- private FieldGammaMnsFunction<T> gammaMNS;
- /** R / a up to power degree. */
- private final T[] roaPow;
- /** Create a set of C<sub>i</sub><sup>jm</sup> and S<sub>i</sub><sup>jm</sup> coefficients.
- * @param jMax absolute limit for j ( -jMax <= j <= jMax )
- * @param mMax maximum value for m
- * @param field field used by default
- */
- FieldFourierCjSjCoefficients(final int jMax, final int mMax, final Field<T> field) {
- // initialise fields
- final T zero = field.getZero();
- final int rows = mMax + 1;
- final int columns = 2 * jMax + 1;
- this.jMax = jMax;
- this.cCoef = MathArrays.buildArray(field, rows, columns, 6);
- this.sCoef = MathArrays.buildArray(field, rows, columns, 6);
- this.roaPow = MathArrays.buildArray(field, maxDegree + 1);
- roaPow[0] = zero.add(1.);
- }
- /**
- * Generate the coefficients.
- * @param date the current date
- * @param context container for attributes
- * @param hansenObjects initialization of hansen objects
- * @param field field used by default
- */
- public void generateCoefficients(final FieldAbsoluteDate<T> date,
- final FieldDSSTTesseralContext<T> context,
- final FieldHansenObjects<T> hansenObjects,
- final Field<T> field) {
- final FieldAuxiliaryElements<T> auxiliaryElements = context.getFieldAuxiliaryElements();
- // Compute only if there is at least one non-resonant tesseral
- if (!nonResOrders.isEmpty() || maxDegreeTesseralSP < 0) {
- // Gmsj and Hmsj polynomials
- ghMSJ = new FieldGHmsjPolynomials<>(auxiliaryElements.getK(), auxiliaryElements.getH(), auxiliaryElements.getAlpha(), auxiliaryElements.getBeta(), I, field);
- // GAMMAmns function
- gammaMNS = new FieldGammaMnsFunction<>(maxDegree, auxiliaryElements.getGamma(), I, field);
- final int maxRoaPower = FastMath.max(maxDegreeTesseralSP, maxDegreeMdailyTesseralSP);
- // R / a up to power degree
- for (int i = 1; i <= maxRoaPower; i++) {
- roaPow[i] = context.getRoa().multiply(roaPow[i - 1]);
- }
- //generate the m-daily coefficients
- for (int m = 1; m <= maxOrderMdailyTesseralSP; m++) {
- buildFourierCoefficients(date, m, 0, maxDegreeMdailyTesseralSP, context, hansenObjects, field);
- }
- // generate the other coefficients only if required
- if (maxDegreeTesseralSP >= 0) {
- for (int m: nonResOrders.keySet()) {
- final List<Integer> listJ = nonResOrders.get(m);
- for (int j: listJ) {
- buildFourierCoefficients(date, m, j, maxDegreeTesseralSP, context, hansenObjects, field);
- }
- }
- }
- }
- }
- /** Build a set of fourier coefficients for a given m and j.
- *
- * @param date the date of the coefficients
- * @param m m index
- * @param j j index
- * @param maxN maximum value for n index
- * @param context container for attributes
- * @param hansenObjects initialization of hansen objects
- * @param field field used by default
- */
- private void buildFourierCoefficients(final FieldAbsoluteDate<T> date,
- final int m, final int j, final int maxN,
- final FieldDSSTTesseralContext<T> context,
- final FieldHansenObjects<T> hansenObjects,
- final Field<T> field) {
- // Zero
- final T zero = field.getZero();
- // Common parameters
- final FieldAuxiliaryElements<T> auxiliaryElements = context.getFieldAuxiliaryElements();
- // Potential derivatives components for a given non-resonant pair {j,m}
- T dRdaCos = zero;
- T dRdaSin = zero;
- T dRdhCos = zero;
- T dRdhSin = zero;
- T dRdkCos = zero;
- T dRdkSin = zero;
- T dRdlCos = zero;
- T dRdlSin = zero;
- T dRdAlCos = zero;
- T dRdAlSin = zero;
- T dRdBeCos = zero;
- T dRdBeSin = zero;
- T dRdGaCos = zero;
- T dRdGaSin = zero;
- // s-SUM from -sMin to sMax
- final int sMin = j == 0 ? maxEccPowMdailyTesseralSP : maxEccPowTesseralSP;
- final int sMax = j == 0 ? maxEccPowMdailyTesseralSP : maxEccPowTesseralSP;
- for (int s = 0; s <= sMax; s++) {
- // n-SUM for s positive
- final T[][] nSumSpos = computeNSum(date, j, m, s, maxN,
- roaPow, ghMSJ, gammaMNS, context, hansenObjects);
- dRdaCos = dRdaCos.add(nSumSpos[0][0]);
- dRdaSin = dRdaSin.add(nSumSpos[0][1]);
- dRdhCos = dRdhCos.add(nSumSpos[1][0]);
- dRdhSin = dRdhSin.add(nSumSpos[1][1]);
- dRdkCos = dRdkCos.add(nSumSpos[2][0]);
- dRdkSin = dRdkSin.add(nSumSpos[2][1]);
- dRdlCos = dRdlCos.add(nSumSpos[3][0]);
- dRdlSin = dRdlSin.add(nSumSpos[3][1]);
- dRdAlCos = dRdAlCos.add(nSumSpos[4][0]);
- dRdAlSin = dRdAlSin.add(nSumSpos[4][1]);
- dRdBeCos = dRdBeCos.add(nSumSpos[5][0]);
- dRdBeSin = dRdBeSin.add(nSumSpos[5][1]);
- dRdGaCos = dRdGaCos.add(nSumSpos[6][0]);
- dRdGaSin = dRdGaSin.add(nSumSpos[6][1]);
- // n-SUM for s negative
- if (s > 0 && s <= sMin) {
- final T[][] nSumSneg = computeNSum(date, j, m, -s, maxN,
- roaPow, ghMSJ, gammaMNS, context, hansenObjects);
- dRdaCos = dRdaCos.add(nSumSneg[0][0]);
- dRdaSin = dRdaSin.add(nSumSneg[0][1]);
- dRdhCos = dRdhCos.add(nSumSneg[1][0]);
- dRdhSin = dRdhSin.add(nSumSneg[1][1]);
- dRdkCos = dRdkCos.add(nSumSneg[2][0]);
- dRdkSin = dRdkSin.add(nSumSneg[2][1]);
- dRdlCos = dRdlCos.add(nSumSneg[3][0]);
- dRdlSin = dRdlSin.add(nSumSneg[3][1]);
- dRdAlCos = dRdAlCos.add(nSumSneg[4][0]);
- dRdAlSin = dRdAlSin.add(nSumSneg[4][1]);
- dRdBeCos = dRdBeCos.add(nSumSneg[5][0]);
- dRdBeSin = dRdBeSin.add(nSumSneg[5][1]);
- dRdGaCos = dRdGaCos.add(nSumSneg[6][0]);
- dRdGaSin = dRdGaSin.add(nSumSneg[6][1]);
- }
- }
- dRdaCos = dRdaCos.multiply(context.getMoa().negate().divide(auxiliaryElements.getSma()));
- dRdaSin = dRdaSin.multiply(context.getMoa().negate().divide(auxiliaryElements.getSma()));
- dRdhCos = dRdhCos.multiply(context.getMoa());
- dRdhSin = dRdhSin.multiply(context.getMoa());
- dRdkCos = dRdkCos.multiply(context.getMoa());
- dRdkSin = dRdkSin.multiply(context.getMoa());
- dRdlCos = dRdlCos.multiply(context.getMoa());
- dRdlSin = dRdlSin.multiply(context.getMoa());
- dRdAlCos = dRdAlCos.multiply(context.getMoa());
- dRdAlSin = dRdAlSin.multiply(context.getMoa());
- dRdBeCos = dRdBeCos.multiply(context.getMoa());
- dRdBeSin = dRdBeSin.multiply(context.getMoa());
- dRdGaCos = dRdGaCos.multiply(context.getMoa());
- dRdGaSin = dRdGaSin.multiply(context.getMoa());
- // Compute the cross derivative operator :
- final T RAlphaGammaCos = auxiliaryElements.getAlpha().multiply(dRdGaCos).subtract(auxiliaryElements.getGamma().multiply(dRdAlCos));
- final T RAlphaGammaSin = auxiliaryElements.getAlpha().multiply(dRdGaSin).subtract(auxiliaryElements.getGamma().multiply(dRdAlSin));
- final T RAlphaBetaCos = auxiliaryElements.getAlpha().multiply(dRdBeCos).subtract(auxiliaryElements.getBeta().multiply(dRdAlCos));
- final T RAlphaBetaSin = auxiliaryElements.getAlpha().multiply(dRdBeSin).subtract(auxiliaryElements.getBeta().multiply(dRdAlSin));
- final T RBetaGammaCos = auxiliaryElements.getBeta().multiply(dRdGaCos).subtract(auxiliaryElements.getGamma().multiply(dRdBeCos));
- final T RBetaGammaSin = auxiliaryElements.getBeta().multiply(dRdGaSin).subtract(auxiliaryElements.getGamma().multiply(dRdBeSin));
- final T RhkCos = auxiliaryElements.getH().multiply(dRdkCos).subtract(auxiliaryElements.getK().multiply(dRdhCos));
- final T RhkSin = auxiliaryElements.getH().multiply(dRdkSin).subtract(auxiliaryElements.getK().multiply(dRdhSin));
- final T pRagmIqRbgoABCos = (auxiliaryElements.getP().multiply(RAlphaGammaCos).subtract(auxiliaryElements.getQ().multiply(RBetaGammaCos).multiply(I))).multiply(context.getOoAB());
- final T pRagmIqRbgoABSin = (auxiliaryElements.getP().multiply(RAlphaGammaSin).subtract(auxiliaryElements.getQ().multiply(RBetaGammaSin).multiply(I))).multiply(context.getOoAB());
- final T RhkmRabmdRdlCos = RhkCos.subtract(RAlphaBetaCos).subtract(dRdlCos);
- final T RhkmRabmdRdlSin = RhkSin.subtract(RAlphaBetaSin).subtract(dRdlSin);
- // da/dt
- cCoef[m][j + jMax][0] = context.getAx2oA().multiply(dRdlCos);
- sCoef[m][j + jMax][0] = context.getAx2oA().multiply(dRdlSin);
- // dk/dt
- cCoef[m][j + jMax][1] = (context.getBoA().multiply(dRdhCos).add(auxiliaryElements.getH().multiply(pRagmIqRbgoABCos)).add(auxiliaryElements.getK().multiply(context.getBoABpo()).multiply(dRdlCos))).negate();
- sCoef[m][j + jMax][1] = (context.getBoA().multiply(dRdhSin).add(auxiliaryElements.getH().multiply(pRagmIqRbgoABSin)).add(auxiliaryElements.getK().multiply(context.getBoABpo()).multiply(dRdlSin))).negate();
- // dh/dt
- cCoef[m][j + jMax][2] = context.getBoA().multiply(dRdkCos).add(auxiliaryElements.getK().multiply(pRagmIqRbgoABCos)).subtract(auxiliaryElements.getH().multiply(context.getBoABpo()).multiply(dRdlCos));
- sCoef[m][j + jMax][2] = context.getBoA().multiply(dRdkSin).add(auxiliaryElements.getK().multiply(pRagmIqRbgoABSin)).subtract(auxiliaryElements.getH().multiply(context.getBoABpo()).multiply(dRdlSin));
- // dq/dt
- cCoef[m][j + jMax][3] = context.getCo2AB().multiply(auxiliaryElements.getQ().multiply(RhkmRabmdRdlCos).subtract(RAlphaGammaCos.multiply(I)));
- sCoef[m][j + jMax][3] = context.getCo2AB().multiply(auxiliaryElements.getQ().multiply(RhkmRabmdRdlSin).subtract(RAlphaGammaSin.multiply(I)));
- // dp/dt
- cCoef[m][j + jMax][4] = context.getCo2AB().multiply(auxiliaryElements.getP().multiply(RhkmRabmdRdlCos).subtract(RBetaGammaCos));
- sCoef[m][j + jMax][4] = context.getCo2AB().multiply(auxiliaryElements.getP().multiply(RhkmRabmdRdlSin).subtract(RBetaGammaSin));
- // dλ/dt
- cCoef[m][j + jMax][5] = context.getAx2oA().negate().multiply(dRdaCos).add(context.getBoABpo().multiply(auxiliaryElements.getH().multiply(dRdhCos).add(auxiliaryElements.getK().multiply(dRdkCos)))).add(pRagmIqRbgoABCos);
- sCoef[m][j + jMax][5] = context.getAx2oA().negate().multiply(dRdaSin).add(context.getBoABpo().multiply(auxiliaryElements.getH().multiply(dRdhSin).add(auxiliaryElements.getK().multiply(dRdkSin)))).add(pRagmIqRbgoABSin);
- }
- /** Get the coefficient C<sub>i</sub><sup>jm</sup>.
- * @param i i index - corresponds to the required variation
- * @param j j index
- * @param m m index
- * @return the coefficient C<sub>i</sub><sup>jm</sup>
- */
- public T getCijm(final int i, final int j, final int m) {
- return cCoef[m][j + jMax][i];
- }
- /** Get the coefficient S<sub>i</sub><sup>jm</sup>.
- * @param i i index - corresponds to the required variation
- * @param j j index
- * @param m m index
- * @return the coefficient S<sub>i</sub><sup>jm</sup>
- */
- public T getSijm(final int i, final int j, final int m) {
- return sCoef[m][j + jMax][i];
- }
- }
- /** The C<sup>i</sup><sub>m</sub><sub>t</sub> and S<sup>i</sup><sub>m</sub><sub>t</sub> coefficients used to compute
- * the short-periodic zonal contribution.
- * <p>
- * Those coefficients are given by expression 2.5.4-5 from the Danielson paper.
- * </p>
- *
- * @author Sorin Scortan
- *
- */
- private static class TesseralShortPeriodicCoefficients implements ShortPeriodTerms {
- /** Retrograde factor I.
- * <p>
- * DSST model needs equinoctial orbit as internal representation.
- * Classical equinoctial elements have discontinuities when inclination
- * is close to zero. In this representation, I = +1. <br>
- * To avoid this discontinuity, another representation exists and equinoctial
- * elements can be expressed in a different way, called "retrograde" orbit.
- * This implies I = -1. <br>
- * As Orekit doesn't implement the retrograde orbit, I is always set to +1.
- * But for the sake of consistency with the theory, the retrograde factor
- * has been kept in the formulas.
- * </p>
- */
- private static final int I = 1;
- /** Central body rotating frame. */
- private final Frame bodyFrame;
- /** Maximal order to consider for short periodics m-daily tesseral harmonics potential. */
- private final int maxOrderMdailyTesseralSP;
- /** Flag to take into account only M-dailies harmonic tesserals for short periodic perturbations. */
- private final boolean mDailiesOnly;
- /** List of non resonant orders with j != 0. */
- private final SortedMap<Integer, List<Integer> > nonResOrders;
- /** Maximum value for m index. */
- private final int mMax;
- /** Maximum value for j index. */
- private final int jMax;
- /** Number of points used in the interpolation process. */
- private final int interpolationPoints;
- /** All coefficients slots. */
- private final transient TimeSpanMap<Slot> slots;
- /** Constructor.
- * @param bodyFrame central body rotating frame
- * @param maxOrderMdailyTesseralSP maximal order to consider for short periodics m-daily tesseral harmonics potential
- * @param mDailiesOnly flag to take into account only M-dailies harmonic tesserals for short periodic perturbations
- * @param nonResOrders lst of non resonant orders with j != 0
- * @param mMax maximum value for m index
- * @param jMax maximum value for j index
- * @param interpolationPoints number of points used in the interpolation process
- * @param slots all coefficients slots
- */
- TesseralShortPeriodicCoefficients(final Frame bodyFrame, final int maxOrderMdailyTesseralSP,
- final boolean mDailiesOnly, final SortedMap<Integer, List<Integer> > nonResOrders,
- final int mMax, final int jMax, final int interpolationPoints,
- final TimeSpanMap<Slot> slots) {
- this.bodyFrame = bodyFrame;
- this.maxOrderMdailyTesseralSP = maxOrderMdailyTesseralSP;
- this.mDailiesOnly = mDailiesOnly;
- this.nonResOrders = nonResOrders;
- this.mMax = mMax;
- this.jMax = jMax;
- this.interpolationPoints = interpolationPoints;
- this.slots = slots;
- }
- /** Get the slot valid for some date.
- * @param meanStates mean states defining the slot
- * @return slot valid at the specified date
- */
- public Slot createSlot(final SpacecraftState... meanStates) {
- final Slot slot = new Slot(mMax, jMax, interpolationPoints);
- final AbsoluteDate first = meanStates[0].getDate();
- final AbsoluteDate last = meanStates[meanStates.length - 1].getDate();
- final int compare = first.compareTo(last);
- if (compare < 0) {
- slots.addValidAfter(slot, first, false);
- } else if (compare > 0) {
- slots.addValidBefore(slot, first, false);
- } else {
- // single date, valid for all time
- slots.addValidAfter(slot, AbsoluteDate.PAST_INFINITY, false);
- }
- return slot;
- }
- /** {@inheritDoc} */
- @Override
- public double[] value(final Orbit meanOrbit) {
- // select the coefficients slot
- final Slot slot = slots.get(meanOrbit.getDate());
- // Initialise the short periodic variations
- final double[] shortPeriodicVariation = new double[6];
- // Compute only if there is at least one non-resonant tesseral or
- // only the m-daily tesseral should be taken into account
- if (!nonResOrders.isEmpty() || mDailiesOnly) {
- //Build an auxiliary object
- final AuxiliaryElements auxiliaryElements = new AuxiliaryElements(meanOrbit, I);
- // Central body rotation angle from equation 2.7.1-(3)(4).
- final StaticTransform t = bodyFrame.getStaticTransformTo(
- auxiliaryElements.getFrame(),
- auxiliaryElements.getDate());
- final Vector3D xB = t.transformVector(Vector3D.PLUS_I);
- final Vector3D yB = t.transformVector(Vector3D.PLUS_J);
- final Vector3D f = auxiliaryElements.getVectorF();
- final Vector3D g = auxiliaryElements.getVectorG();
- final double currentTheta = FastMath.atan2(-f.dotProduct(yB) + I * g.dotProduct(xB),
- f.dotProduct(xB) + I * g.dotProduct(yB));
- //Add the m-daily contribution
- for (int m = 1; m <= maxOrderMdailyTesseralSP; m++) {
- // Phase angle
- final double jlMmt = -m * currentTheta;
- final SinCos scPhi = FastMath.sinCos(jlMmt);
- final double sinPhi = scPhi.sin();
- final double cosPhi = scPhi.cos();
- // compute contribution for each element
- final double[] c = slot.getCijm(0, m, meanOrbit.getDate());
- final double[] s = slot.getSijm(0, m, meanOrbit.getDate());
- for (int i = 0; i < 6; i++) {
- shortPeriodicVariation[i] += c[i] * cosPhi + s[i] * sinPhi;
- }
- }
- // loop through all non-resonant (j,m) pairs
- for (final Map.Entry<Integer, List<Integer>> entry : nonResOrders.entrySet()) {
- final int m = entry.getKey();
- final List<Integer> listJ = entry.getValue();
- for (int j : listJ) {
- // Phase angle
- final double jlMmt = j * meanOrbit.getLM() - m * currentTheta;
- final SinCos scPhi = FastMath.sinCos(jlMmt);
- final double sinPhi = scPhi.sin();
- final double cosPhi = scPhi.cos();
- // compute contribution for each element
- final double[] c = slot.getCijm(j, m, meanOrbit.getDate());
- final double[] s = slot.getSijm(j, m, meanOrbit.getDate());
- for (int i = 0; i < 6; i++) {
- shortPeriodicVariation[i] += c[i] * cosPhi + s[i] * sinPhi;
- }
- }
- }
- }
- return shortPeriodicVariation;
- }
- /** {@inheritDoc} */
- @Override
- public String getCoefficientsKeyPrefix() {
- return DSSTTesseral.SHORT_PERIOD_PREFIX;
- }
- /** {@inheritDoc}
- * <p>
- * For tesseral terms contributions,there are maxOrderMdailyTesseralSP
- * m-daily cMm coefficients, maxOrderMdailyTesseralSP m-daily sMm
- * coefficients, nbNonResonant cjm coefficients and nbNonResonant
- * sjm coefficients, where maxOrderMdailyTesseralSP and nbNonResonant both
- * depend on the orbit. The j index is the integer multiplier for the true
- * longitude argument and the m index is the integer multiplier for m-dailies.
- * </p>
- */
- @Override
- public Map<String, double[]> getCoefficients(final AbsoluteDate date, final Set<String> selected) {
- // select the coefficients slot
- final Slot slot = slots.get(date);
- if (!nonResOrders.isEmpty() || mDailiesOnly) {
- final Map<String, double[]> coefficients =
- new HashMap<String, double[]>(12 * maxOrderMdailyTesseralSP +
- 12 * nonResOrders.size());
- for (int m = 1; m <= maxOrderMdailyTesseralSP; m++) {
- storeIfSelected(coefficients, selected, slot.getCijm(0, m, date), DSSTTesseral.CM_COEFFICIENTS, m);
- storeIfSelected(coefficients, selected, slot.getSijm(0, m, date), DSSTTesseral.SM_COEFFICIENTS, m);
- }
- for (final Map.Entry<Integer, List<Integer>> entry : nonResOrders.entrySet()) {
- final int m = entry.getKey();
- final List<Integer> listJ = entry.getValue();
- for (int j : listJ) {
- for (int i = 0; i < 6; ++i) {
- storeIfSelected(coefficients, selected, slot.getCijm(j, m, date), "c", j, m);
- storeIfSelected(coefficients, selected, slot.getSijm(j, m, date), "s", j, m);
- }
- }
- }
- return coefficients;
- } else {
- return Collections.emptyMap();
- }
- }
- /** Put a coefficient in a map if selected.
- * @param map map to populate
- * @param selected set of coefficients that should be put in the map
- * (empty set means all coefficients are selected)
- * @param value coefficient value
- * @param id coefficient identifier
- * @param indices list of coefficient indices
- */
- private void storeIfSelected(final Map<String, double[]> map, final Set<String> selected,
- final double[] value, final String id, final int... indices) {
- final StringBuilder keyBuilder = new StringBuilder(getCoefficientsKeyPrefix());
- keyBuilder.append(id);
- for (int index : indices) {
- keyBuilder.append('[').append(index).append(']');
- }
- final String key = keyBuilder.toString();
- if (selected.isEmpty() || selected.contains(key)) {
- map.put(key, value);
- }
- }
- }
- /** The C<sup>i</sup><sub>m</sub><sub>t</sub> and S<sup>i</sup><sub>m</sub><sub>t</sub> coefficients used to compute
- * the short-periodic zonal contribution.
- * <p>
- * Those coefficients are given by expression 2.5.4-5 from the Danielson paper.
- * </p>
- *
- * @author Sorin Scortan
- *
- */
- private static class FieldTesseralShortPeriodicCoefficients <T extends CalculusFieldElement<T>> implements FieldShortPeriodTerms<T> {
- /** Retrograde factor I.
- * <p>
- * DSST model needs equinoctial orbit as internal representation.
- * Classical equinoctial elements have discontinuities when inclination
- * is close to zero. In this representation, I = +1. <br>
- * To avoid this discontinuity, another representation exists and equinoctial
- * elements can be expressed in a different way, called "retrograde" orbit.
- * This implies I = -1. <br>
- * As Orekit doesn't implement the retrograde orbit, I is always set to +1.
- * But for the sake of consistency with the theory, the retrograde factor
- * has been kept in the formulas.
- * </p>
- */
- private static final int I = 1;
- /** Central body rotating frame. */
- private final Frame bodyFrame;
- /** Maximal order to consider for short periodics m-daily tesseral harmonics potential. */
- private final int maxOrderMdailyTesseralSP;
- /** Flag to take into account only M-dailies harmonic tesserals for short periodic perturbations. */
- private final boolean mDailiesOnly;
- /** List of non resonant orders with j != 0. */
- private final SortedMap<Integer, List<Integer> > nonResOrders;
- /** Maximum value for m index. */
- private final int mMax;
- /** Maximum value for j index. */
- private final int jMax;
- /** Number of points used in the interpolation process. */
- private final int interpolationPoints;
- /** All coefficients slots. */
- private final transient FieldTimeSpanMap<FieldSlot<T>, T> slots;
- /** Constructor.
- * @param bodyFrame central body rotating frame
- * @param maxOrderMdailyTesseralSP maximal order to consider for short periodics m-daily tesseral harmonics potential
- * @param mDailiesOnly flag to take into account only M-dailies harmonic tesserals for short periodic perturbations
- * @param nonResOrders lst of non resonant orders with j != 0
- * @param mMax maximum value for m index
- * @param jMax maximum value for j index
- * @param interpolationPoints number of points used in the interpolation process
- * @param slots all coefficients slots
- */
- FieldTesseralShortPeriodicCoefficients(final Frame bodyFrame, final int maxOrderMdailyTesseralSP,
- final boolean mDailiesOnly, final SortedMap<Integer, List<Integer> > nonResOrders,
- final int mMax, final int jMax, final int interpolationPoints,
- final FieldTimeSpanMap<FieldSlot<T>, T> slots) {
- this.bodyFrame = bodyFrame;
- this.maxOrderMdailyTesseralSP = maxOrderMdailyTesseralSP;
- this.mDailiesOnly = mDailiesOnly;
- this.nonResOrders = nonResOrders;
- this.mMax = mMax;
- this.jMax = jMax;
- this.interpolationPoints = interpolationPoints;
- this.slots = slots;
- }
- /** Get the slot valid for some date.
- * @param meanStates mean states defining the slot
- * @return slot valid at the specified date
- */
- @SuppressWarnings("unchecked")
- public FieldSlot<T> createSlot(final FieldSpacecraftState<T>... meanStates) {
- final FieldSlot<T> slot = new FieldSlot<>(mMax, jMax, interpolationPoints);
- final FieldAbsoluteDate<T> first = meanStates[0].getDate();
- final FieldAbsoluteDate<T> last = meanStates[meanStates.length - 1].getDate();
- if (first.compareTo(last) <= 0) {
- slots.addValidAfter(slot, first);
- } else {
- slots.addValidBefore(slot, first);
- }
- return slot;
- }
- /** {@inheritDoc} */
- @Override
- public T[] value(final FieldOrbit<T> meanOrbit) {
- // select the coefficients slot
- final FieldSlot<T> slot = slots.get(meanOrbit.getDate());
- // Initialise the short periodic variations
- final T[] shortPeriodicVariation = MathArrays.buildArray(meanOrbit.getDate().getField(), 6);
- // Compute only if there is at least one non-resonant tesseral or
- // only the m-daily tesseral should be taken into account
- if (!nonResOrders.isEmpty() || mDailiesOnly) {
- //Build an auxiliary object
- final FieldAuxiliaryElements<T> auxiliaryElements = new FieldAuxiliaryElements<>(meanOrbit, I);
- // Central body rotation angle from equation 2.7.1-(3)(4).
- final FieldStaticTransform<T> t = bodyFrame.getStaticTransformTo(auxiliaryElements.getFrame(), auxiliaryElements.getDate());
- final FieldVector3D<T> xB = t.transformVector(Vector3D.PLUS_I);
- final FieldVector3D<T> yB = t.transformVector(Vector3D.PLUS_J);
- final FieldVector3D<T> f = auxiliaryElements.getVectorF();
- final FieldVector3D<T> g = auxiliaryElements.getVectorG();
- final T currentTheta = FastMath.atan2(f.dotProduct(yB).negate().add(g.dotProduct(xB).multiply(I)),
- f.dotProduct(xB).add(g.dotProduct(yB).multiply(I)));
- //Add the m-daily contribution
- for (int m = 1; m <= maxOrderMdailyTesseralSP; m++) {
- // Phase angle
- final T jlMmt = currentTheta.multiply(-m);
- final FieldSinCos<T> scPhi = FastMath.sinCos(jlMmt);
- final T sinPhi = scPhi.sin();
- final T cosPhi = scPhi.cos();
- // compute contribution for each element
- final T[] c = slot.getCijm(0, m, meanOrbit.getDate());
- final T[] s = slot.getSijm(0, m, meanOrbit.getDate());
- for (int i = 0; i < 6; i++) {
- shortPeriodicVariation[i] = shortPeriodicVariation[i].add(c[i].multiply(cosPhi).add(s[i].multiply(sinPhi)));
- }
- }
- // loop through all non-resonant (j,m) pairs
- for (final Map.Entry<Integer, List<Integer>> entry : nonResOrders.entrySet()) {
- final int m = entry.getKey();
- final List<Integer> listJ = entry.getValue();
- for (int j : listJ) {
- // Phase angle
- final T jlMmt = meanOrbit.getLM().multiply(j).subtract(currentTheta.multiply(m));
- final FieldSinCos<T> scPhi = FastMath.sinCos(jlMmt);
- final T sinPhi = scPhi.sin();
- final T cosPhi = scPhi.cos();
- // compute contribution for each element
- final T[] c = slot.getCijm(j, m, meanOrbit.getDate());
- final T[] s = slot.getSijm(j, m, meanOrbit.getDate());
- for (int i = 0; i < 6; i++) {
- shortPeriodicVariation[i] = shortPeriodicVariation[i].add(c[i].multiply(cosPhi).add(s[i].multiply(sinPhi)));
- }
- }
- }
- }
- return shortPeriodicVariation;
- }
- /** {@inheritDoc} */
- @Override
- public String getCoefficientsKeyPrefix() {
- return DSSTTesseral.SHORT_PERIOD_PREFIX;
- }
- /** {@inheritDoc}
- * <p>
- * For tesseral terms contributions,there are maxOrderMdailyTesseralSP
- * m-daily cMm coefficients, maxOrderMdailyTesseralSP m-daily sMm
- * coefficients, nbNonResonant cjm coefficients and nbNonResonant
- * sjm coefficients, where maxOrderMdailyTesseralSP and nbNonResonant both
- * depend on the orbit. The j index is the integer multiplier for the true
- * longitude argument and the m index is the integer multiplier for m-dailies.
- * </p>
- */
- @Override
- public Map<String, T[]> getCoefficients(final FieldAbsoluteDate<T> date, final Set<String> selected) {
- // select the coefficients slot
- final FieldSlot<T> slot = slots.get(date);
- if (!nonResOrders.isEmpty() || mDailiesOnly) {
- final Map<String, T[]> coefficients =
- new HashMap<String, T[]>(12 * maxOrderMdailyTesseralSP +
- 12 * nonResOrders.size());
- for (int m = 1; m <= maxOrderMdailyTesseralSP; m++) {
- storeIfSelected(coefficients, selected, slot.getCijm(0, m, date), DSSTTesseral.CM_COEFFICIENTS, m);
- storeIfSelected(coefficients, selected, slot.getSijm(0, m, date), DSSTTesseral.SM_COEFFICIENTS, m);
- }
- for (final Map.Entry<Integer, List<Integer>> entry : nonResOrders.entrySet()) {
- final int m = entry.getKey();
- final List<Integer> listJ = entry.getValue();
- for (int j : listJ) {
- for (int i = 0; i < 6; ++i) {
- storeIfSelected(coefficients, selected, slot.getCijm(j, m, date), "c", j, m);
- storeIfSelected(coefficients, selected, slot.getSijm(j, m, date), "s", j, m);
- }
- }
- }
- return coefficients;
- } else {
- return Collections.emptyMap();
- }
- }
- /** Put a coefficient in a map if selected.
- * @param map map to populate
- * @param selected set of coefficients that should be put in the map
- * (empty set means all coefficients are selected)
- * @param value coefficient value
- * @param id coefficient identifier
- * @param indices list of coefficient indices
- */
- private void storeIfSelected(final Map<String, T[]> map, final Set<String> selected,
- final T[] value, final String id, final int... indices) {
- final StringBuilder keyBuilder = new StringBuilder(getCoefficientsKeyPrefix());
- keyBuilder.append(id);
- for (int index : indices) {
- keyBuilder.append('[').append(index).append(']');
- }
- final String key = keyBuilder.toString();
- if (selected.isEmpty() || selected.contains(key)) {
- map.put(key, value);
- }
- }
- }
- /** Coefficients valid for one time slot. */
- private static class Slot {
- /** The coefficients C<sub>i</sub><sup>j</sup><sup>m</sup>.
- * <p>
- * The index order is cijm[m][j][i] <br/>
- * i corresponds to the equinoctial element, as follows: <br/>
- * - i=0 for a <br/>
- * - i=1 for k <br/>
- * - i=2 for h <br/>
- * - i=3 for q <br/>
- * - i=4 for p <br/>
- * - i=5 for λ <br/>
- * </p>
- */
- private final ShortPeriodicsInterpolatedCoefficient[][] cijm;
- /** The coefficients S<sub>i</sub><sup>j</sup><sup>m</sup>.
- * <p>
- * The index order is sijm[m][j][i] <br/>
- * i corresponds to the equinoctial element, as follows: <br/>
- * - i=0 for a <br/>
- * - i=1 for k <br/>
- * - i=2 for h <br/>
- * - i=3 for q <br/>
- * - i=4 for p <br/>
- * - i=5 for λ <br/>
- * </p>
- */
- private final ShortPeriodicsInterpolatedCoefficient[][] sijm;
- /** Simple constructor.
- * @param mMax maximum value for m index
- * @param jMax maximum value for j index
- * @param interpolationPoints number of points used in the interpolation process
- */
- Slot(final int mMax, final int jMax, final int interpolationPoints) {
- final int rows = mMax + 1;
- final int columns = 2 * jMax + 1;
- cijm = new ShortPeriodicsInterpolatedCoefficient[rows][columns];
- sijm = new ShortPeriodicsInterpolatedCoefficient[rows][columns];
- for (int m = 1; m <= mMax; m++) {
- for (int j = -jMax; j <= jMax; j++) {
- cijm[m][j + jMax] = new ShortPeriodicsInterpolatedCoefficient(interpolationPoints);
- sijm[m][j + jMax] = new ShortPeriodicsInterpolatedCoefficient(interpolationPoints);
- }
- }
- }
- /** Get C<sub>i</sub><sup>j</sup><sup>m</sup>.
- *
- * @param j j index
- * @param m m index
- * @param date the date
- * @return C<sub>i</sub><sup>j</sup><sup>m</sup>
- */
- double[] getCijm(final int j, final int m, final AbsoluteDate date) {
- final int jMax = (cijm[m].length - 1) / 2;
- return cijm[m][j + jMax].value(date);
- }
- /** Get S<sub>i</sub><sup>j</sup><sup>m</sup>.
- *
- * @param j j index
- * @param m m index
- * @param date the date
- * @return S<sub>i</sub><sup>j</sup><sup>m</sup>
- */
- double[] getSijm(final int j, final int m, final AbsoluteDate date) {
- final int jMax = (cijm[m].length - 1) / 2;
- return sijm[m][j + jMax].value(date);
- }
- }
- /** Coefficients valid for one time slot. */
- private static class FieldSlot <T extends CalculusFieldElement<T>> {
- /** The coefficients C<sub>i</sub><sup>j</sup><sup>m</sup>.
- * <p>
- * The index order is cijm[m][j][i] <br/>
- * i corresponds to the equinoctial element, as follows: <br/>
- * - i=0 for a <br/>
- * - i=1 for k <br/>
- * - i=2 for h <br/>
- * - i=3 for q <br/>
- * - i=4 for p <br/>
- * - i=5 for λ <br/>
- * </p>
- */
- private final FieldShortPeriodicsInterpolatedCoefficient<T>[][] cijm;
- /** The coefficients S<sub>i</sub><sup>j</sup><sup>m</sup>.
- * <p>
- * The index order is sijm[m][j][i] <br/>
- * i corresponds to the equinoctial element, as follows: <br/>
- * - i=0 for a <br/>
- * - i=1 for k <br/>
- * - i=2 for h <br/>
- * - i=3 for q <br/>
- * - i=4 for p <br/>
- * - i=5 for λ <br/>
- * </p>
- */
- private final FieldShortPeriodicsInterpolatedCoefficient<T>[][] sijm;
- /** Simple constructor.
- * @param mMax maximum value for m index
- * @param jMax maximum value for j index
- * @param interpolationPoints number of points used in the interpolation process
- */
- @SuppressWarnings("unchecked")
- FieldSlot(final int mMax, final int jMax, final int interpolationPoints) {
- final int rows = mMax + 1;
- final int columns = 2 * jMax + 1;
- cijm = (FieldShortPeriodicsInterpolatedCoefficient<T>[][]) Array.newInstance(FieldShortPeriodicsInterpolatedCoefficient.class, rows, columns);
- sijm = (FieldShortPeriodicsInterpolatedCoefficient<T>[][]) Array.newInstance(FieldShortPeriodicsInterpolatedCoefficient.class, rows, columns);
- for (int m = 1; m <= mMax; m++) {
- for (int j = -jMax; j <= jMax; j++) {
- cijm[m][j + jMax] = new FieldShortPeriodicsInterpolatedCoefficient<>(interpolationPoints);
- sijm[m][j + jMax] = new FieldShortPeriodicsInterpolatedCoefficient<>(interpolationPoints);
- }
- }
- }
- /** Get C<sub>i</sub><sup>j</sup><sup>m</sup>.
- *
- * @param j j index
- * @param m m index
- * @param date the date
- * @return C<sub>i</sub><sup>j</sup><sup>m</sup>
- */
- T[] getCijm(final int j, final int m, final FieldAbsoluteDate<T> date) {
- final int jMax = (cijm[m].length - 1) / 2;
- return cijm[m][j + jMax].value(date);
- }
- /** Get S<sub>i</sub><sup>j</sup><sup>m</sup>.
- *
- * @param j j index
- * @param m m index
- * @param date the date
- * @return S<sub>i</sub><sup>j</sup><sup>m</sup>
- */
- T[] getSijm(final int j, final int m, final FieldAbsoluteDate<T> date) {
- final int jMax = (cijm[m].length - 1) / 2;
- return sijm[m][j + jMax].value(date);
- }
- }
- /** Compute potential and potential derivatives with respect to orbital parameters.
- * <p>The following elements are computed from expression 3.3 - (4).
- * <pre>
- * dU / da
- * dU / dh
- * dU / dk
- * dU / dλ
- * dU / dα
- * dU / dβ
- * dU / dγ
- * </pre>
- * </p>
- */
- private class UAnddU {
- /** dU / da. */
- private double dUda;
- /** dU / dk. */
- private double dUdk;
- /** dU / dh. */
- private double dUdh;
- /** dU / dl. */
- private double dUdl;
- /** dU / dAlpha. */
- private double dUdAl;
- /** dU / dBeta. */
- private double dUdBe;
- /** dU / dGamma. */
- private double dUdGa;
- /** Simple constuctor.
- * @param date current date
- * @param context container for attributes
- * @param hansen hansen objects
- */
- UAnddU(final AbsoluteDate date, final DSSTTesseralContext context, final HansenObjects hansen) {
- // Auxiliary elements related to the current orbit
- final AuxiliaryElements auxiliaryElements = context.getAuxiliaryElements();
- // Potential derivatives
- dUda = 0.;
- dUdh = 0.;
- dUdk = 0.;
- dUdl = 0.;
- dUdAl = 0.;
- dUdBe = 0.;
- dUdGa = 0.;
- // Compute only if there is at least one resonant tesseral
- if (!resOrders.isEmpty()) {
- // Gmsj and Hmsj polynomials
- final GHmsjPolynomials ghMSJ = new GHmsjPolynomials(auxiliaryElements.getK(), auxiliaryElements.getH(), auxiliaryElements.getAlpha(), auxiliaryElements.getBeta(), I);
- // GAMMAmns function
- final GammaMnsFunction gammaMNS = new GammaMnsFunction(maxDegree, auxiliaryElements.getGamma(), I);
- // R / a up to power degree
- final double[] roaPow = new double[maxDegree + 1];
- roaPow[0] = 1.;
- for (int i = 1; i <= maxDegree; i++) {
- roaPow[i] = context.getRoa() * roaPow[i - 1];
- }
- // SUM over resonant terms {j,m}
- for (int m : resOrders) {
- // Resonant index for the current resonant order
- final int j = FastMath.max(1, (int) FastMath.round(context.getRatio() * m));
- // Phase angle
- final double jlMmt = j * auxiliaryElements.getLM() - m * context.getTheta();
- final SinCos scPhi = FastMath.sinCos(jlMmt);
- final double sinPhi = scPhi.sin();
- final double cosPhi = scPhi.cos();
- // Potential derivatives components for a given resonant pair {j,m}
- double dUdaCos = 0.;
- double dUdaSin = 0.;
- double dUdhCos = 0.;
- double dUdhSin = 0.;
- double dUdkCos = 0.;
- double dUdkSin = 0.;
- double dUdlCos = 0.;
- double dUdlSin = 0.;
- double dUdAlCos = 0.;
- double dUdAlSin = 0.;
- double dUdBeCos = 0.;
- double dUdBeSin = 0.;
- double dUdGaCos = 0.;
- double dUdGaSin = 0.;
- // s-SUM from -sMin to sMax
- final int sMin = FastMath.min(maxEccPow - j, maxDegree);
- final int sMax = FastMath.min(maxEccPow + j, maxDegree);
- for (int s = 0; s <= sMax; s++) {
- //Compute the initial values for Hansen coefficients using newComb operators
- hansen.computeHansenObjectsInitValues(context, s + maxDegree, j);
- // n-SUM for s positive
- final double[][] nSumSpos = computeNSum(date, j, m, s, maxDegree,
- roaPow, ghMSJ, gammaMNS, context, hansen);
- dUdaCos += nSumSpos[0][0];
- dUdaSin += nSumSpos[0][1];
- dUdhCos += nSumSpos[1][0];
- dUdhSin += nSumSpos[1][1];
- dUdkCos += nSumSpos[2][0];
- dUdkSin += nSumSpos[2][1];
- dUdlCos += nSumSpos[3][0];
- dUdlSin += nSumSpos[3][1];
- dUdAlCos += nSumSpos[4][0];
- dUdAlSin += nSumSpos[4][1];
- dUdBeCos += nSumSpos[5][0];
- dUdBeSin += nSumSpos[5][1];
- dUdGaCos += nSumSpos[6][0];
- dUdGaSin += nSumSpos[6][1];
- // n-SUM for s negative
- if (s > 0 && s <= sMin) {
- //Compute the initial values for Hansen coefficients using newComb operators
- hansen.computeHansenObjectsInitValues(context, maxDegree - s, j);
- final double[][] nSumSneg = computeNSum(date, j, m, -s, maxDegree,
- roaPow, ghMSJ, gammaMNS, context, hansen);
- dUdaCos += nSumSneg[0][0];
- dUdaSin += nSumSneg[0][1];
- dUdhCos += nSumSneg[1][0];
- dUdhSin += nSumSneg[1][1];
- dUdkCos += nSumSneg[2][0];
- dUdkSin += nSumSneg[2][1];
- dUdlCos += nSumSneg[3][0];
- dUdlSin += nSumSneg[3][1];
- dUdAlCos += nSumSneg[4][0];
- dUdAlSin += nSumSneg[4][1];
- dUdBeCos += nSumSneg[5][0];
- dUdBeSin += nSumSneg[5][1];
- dUdGaCos += nSumSneg[6][0];
- dUdGaSin += nSumSneg[6][1];
- }
- }
- // Assembly of potential derivatives componants
- dUda += cosPhi * dUdaCos + sinPhi * dUdaSin;
- dUdh += cosPhi * dUdhCos + sinPhi * dUdhSin;
- dUdk += cosPhi * dUdkCos + sinPhi * dUdkSin;
- dUdl += cosPhi * dUdlCos + sinPhi * dUdlSin;
- dUdAl += cosPhi * dUdAlCos + sinPhi * dUdAlSin;
- dUdBe += cosPhi * dUdBeCos + sinPhi * dUdBeSin;
- dUdGa += cosPhi * dUdGaCos + sinPhi * dUdGaSin;
- }
- this.dUda = dUda * (-context.getMoa() / auxiliaryElements.getSma());
- this.dUdh = dUdh * context.getMoa();
- this.dUdk = dUdk * context.getMoa();
- this.dUdl = dUdl * context.getMoa();
- this.dUdAl = dUdAl * context.getMoa();
- this.dUdBe = dUdBe * context.getMoa();
- this.dUdGa = dUdGa * context.getMoa();
- }
- }
- /** Return value of dU / da.
- * @return dUda
- */
- public double getdUda() {
- return dUda;
- }
- /** Return value of dU / dk.
- * @return dUdk
- */
- public double getdUdk() {
- return dUdk;
- }
- /** Return value of dU / dh.
- * @return dUdh
- */
- public double getdUdh() {
- return dUdh;
- }
- /** Return value of dU / dl.
- * @return dUdl
- */
- public double getdUdl() {
- return dUdl;
- }
- /** Return value of dU / dAlpha.
- * @return dUdAl
- */
- public double getdUdAl() {
- return dUdAl;
- }
- /** Return value of dU / dBeta.
- * @return dUdBe
- */
- public double getdUdBe() {
- return dUdBe;
- }
- /** Return value of dU / dGamma.
- * @return dUdGa
- */
- public double getdUdGa() {
- return dUdGa;
- }
- }
- /** Computes the potential U derivatives.
- * <p>The following elements are computed from expression 3.3 - (4).
- * <pre>
- * dU / da
- * dU / dh
- * dU / dk
- * dU / dλ
- * dU / dα
- * dU / dβ
- * dU / dγ
- * </pre>
- * </p>
- */
- private class FieldUAnddU <T extends CalculusFieldElement<T>> {
- /** dU / da. */
- private T dUda;
- /** dU / dk. */
- private T dUdk;
- /** dU / dh. */
- private T dUdh;
- /** dU / dl. */
- private T dUdl;
- /** dU / dAlpha. */
- private T dUdAl;
- /** dU / dBeta. */
- private T dUdBe;
- /** dU / dGamma. */
- private T dUdGa;
- /** Simple constuctor.
- * @param date current date
- * @param context container for attributes
- * @param hansen hansen objects
- */
- FieldUAnddU(final FieldAbsoluteDate<T> date, final FieldDSSTTesseralContext<T> context,
- final FieldHansenObjects<T> hansen) {
- // Auxiliary elements related to the current orbit
- final FieldAuxiliaryElements<T> auxiliaryElements = context.getFieldAuxiliaryElements();
- // Zero for initialization
- final Field<T> field = date.getField();
- final T zero = field.getZero();
- // Potential derivatives
- dUda = zero;
- dUdh = zero;
- dUdk = zero;
- dUdl = zero;
- dUdAl = zero;
- dUdBe = zero;
- dUdGa = zero;
- // Compute only if there is at least one resonant tesseral
- if (!resOrders.isEmpty()) {
- // Gmsj and Hmsj polynomials
- final FieldGHmsjPolynomials<T> ghMSJ = new FieldGHmsjPolynomials<>(auxiliaryElements.getK(), auxiliaryElements.getH(), auxiliaryElements.getAlpha(), auxiliaryElements.getBeta(), I, field);
- // GAMMAmns function
- final FieldGammaMnsFunction<T> gammaMNS = new FieldGammaMnsFunction<>(maxDegree, auxiliaryElements.getGamma(), I, field);
- // R / a up to power degree
- final T[] roaPow = MathArrays.buildArray(field, maxDegree + 1);
- roaPow[0] = zero.add(1.);
- for (int i = 1; i <= maxDegree; i++) {
- roaPow[i] = roaPow[i - 1].multiply(context.getRoa());
- }
- // SUM over resonant terms {j,m}
- for (int m : resOrders) {
- // Resonant index for the current resonant order
- final int j = FastMath.max(1, (int) FastMath.round(context.getRatio().multiply(m)));
- // Phase angle
- final T jlMmt = auxiliaryElements.getLM().multiply(j).subtract(context.getTheta().multiply(m));
- final FieldSinCos<T> scPhi = FastMath.sinCos(jlMmt);
- final T sinPhi = scPhi.sin();
- final T cosPhi = scPhi.cos();
- // Potential derivatives components for a given resonant pair {j,m}
- T dUdaCos = zero;
- T dUdaSin = zero;
- T dUdhCos = zero;
- T dUdhSin = zero;
- T dUdkCos = zero;
- T dUdkSin = zero;
- T dUdlCos = zero;
- T dUdlSin = zero;
- T dUdAlCos = zero;
- T dUdAlSin = zero;
- T dUdBeCos = zero;
- T dUdBeSin = zero;
- T dUdGaCos = zero;
- T dUdGaSin = zero;
- // s-SUM from -sMin to sMax
- final int sMin = FastMath.min(maxEccPow - j, maxDegree);
- final int sMax = FastMath.min(maxEccPow + j, maxDegree);
- for (int s = 0; s <= sMax; s++) {
- //Compute the initial values for Hansen coefficients using newComb operators
- hansen.computeHansenObjectsInitValues(context, s + maxDegree, j);
- // n-SUM for s positive
- final T[][] nSumSpos = computeNSum(date, j, m, s, maxDegree,
- roaPow, ghMSJ, gammaMNS, context, hansen);
- dUdaCos = dUdaCos.add(nSumSpos[0][0]);
- dUdaSin = dUdaSin.add(nSumSpos[0][1]);
- dUdhCos = dUdhCos.add(nSumSpos[1][0]);
- dUdhSin = dUdhSin.add(nSumSpos[1][1]);
- dUdkCos = dUdkCos.add(nSumSpos[2][0]);
- dUdkSin = dUdkSin.add(nSumSpos[2][1]);
- dUdlCos = dUdlCos.add(nSumSpos[3][0]);
- dUdlSin = dUdlSin.add(nSumSpos[3][1]);
- dUdAlCos = dUdAlCos.add(nSumSpos[4][0]);
- dUdAlSin = dUdAlSin.add(nSumSpos[4][1]);
- dUdBeCos = dUdBeCos.add(nSumSpos[5][0]);
- dUdBeSin = dUdBeSin.add(nSumSpos[5][1]);
- dUdGaCos = dUdGaCos.add(nSumSpos[6][0]);
- dUdGaSin = dUdGaSin.add(nSumSpos[6][1]);
- // n-SUM for s negative
- if (s > 0 && s <= sMin) {
- //Compute the initial values for Hansen coefficients using newComb operators
- hansen.computeHansenObjectsInitValues(context, maxDegree - s, j);
- final T[][] nSumSneg = computeNSum(date, j, m, -s, maxDegree,
- roaPow, ghMSJ, gammaMNS, context, hansen);
- dUdaCos = dUdaCos.add(nSumSneg[0][0]);
- dUdaSin = dUdaSin.add(nSumSneg[0][1]);
- dUdhCos = dUdhCos.add(nSumSneg[1][0]);
- dUdhSin = dUdhSin.add(nSumSneg[1][1]);
- dUdkCos = dUdkCos.add(nSumSneg[2][0]);
- dUdkSin = dUdkSin.add(nSumSneg[2][1]);
- dUdlCos = dUdlCos.add(nSumSneg[3][0]);
- dUdlSin = dUdlSin.add(nSumSneg[3][1]);
- dUdAlCos = dUdAlCos.add(nSumSneg[4][0]);
- dUdAlSin = dUdAlSin.add(nSumSneg[4][1]);
- dUdBeCos = dUdBeCos.add(nSumSneg[5][0]);
- dUdBeSin = dUdBeSin.add(nSumSneg[5][1]);
- dUdGaCos = dUdGaCos.add(nSumSneg[6][0]);
- dUdGaSin = dUdGaSin.add(nSumSneg[6][1]);
- }
- }
- // Assembly of potential derivatives componants
- dUda = dUda.add(dUdaCos.multiply(cosPhi).add(dUdaSin.multiply(sinPhi)));
- dUdh = dUdh.add(dUdhCos.multiply(cosPhi).add(dUdhSin.multiply(sinPhi)));
- dUdk = dUdk.add(dUdkCos.multiply(cosPhi).add(dUdkSin.multiply(sinPhi)));
- dUdl = dUdl.add(dUdlCos.multiply(cosPhi).add(dUdlSin.multiply(sinPhi)));
- dUdAl = dUdAl.add(dUdAlCos.multiply(cosPhi).add(dUdAlSin.multiply(sinPhi)));
- dUdBe = dUdBe.add(dUdBeCos.multiply(cosPhi).add(dUdBeSin.multiply(sinPhi)));
- dUdGa = dUdGa.add(dUdGaCos.multiply(cosPhi).add(dUdGaSin.multiply(sinPhi)));
- }
- dUda = dUda.multiply(context.getMoa().divide(auxiliaryElements.getSma())).negate();
- dUdh = dUdh.multiply(context.getMoa());
- dUdk = dUdk.multiply(context.getMoa());
- dUdl = dUdl.multiply(context.getMoa());
- dUdAl = dUdAl.multiply(context.getMoa());
- dUdBe = dUdBe.multiply(context.getMoa());
- dUdGa = dUdGa.multiply(context.getMoa());
- }
- }
- /** Return value of dU / da.
- * @return dUda
- */
- public T getdUda() {
- return dUda;
- }
- /** Return value of dU / dk.
- * @return dUdk
- */
- public T getdUdk() {
- return dUdk;
- }
- /** Return value of dU / dh.
- * @return dUdh
- */
- public T getdUdh() {
- return dUdh;
- }
- /** Return value of dU / dl.
- * @return dUdl
- */
- public T getdUdl() {
- return dUdl;
- }
- /** Return value of dU / dAlpha.
- * @return dUdAl
- */
- public T getdUdAl() {
- return dUdAl;
- }
- /** Return value of dU / dBeta.
- * @return dUdBe
- */
- public T getdUdBe() {
- return dUdBe;
- }
- /** Return value of dU / dGamma.
- * @return dUdGa
- */
- public T getdUdGa() {
- return dUdGa;
- }
- }
- /** Computes init values of the Hansen Objects. */
- private class HansenObjects {
- /** A two dimensional array that contains the objects needed to build the Hansen coefficients. <br/>
- * The indexes are s + maxDegree and j */
- private HansenTesseralLinear[][] hansenObjects;
- /** Simple constructor.
- * @param ratio Ratio of satellite period to central body rotation period
- * @param type type of the elements used during the propagation
- */
- HansenObjects(final double ratio,
- final PropagationType type) {
- //Allocate the two dimensional array
- final int rows = 2 * maxDegree + 1;
- final int columns = maxFrequencyShortPeriodics + 1;
- this.hansenObjects = new HansenTesseralLinear[rows][columns];
- switch (type) {
- case MEAN:
- // loop through the resonant orders
- for (int m : resOrders) {
- //Compute the corresponding j term
- final int j = FastMath.max(1, (int) FastMath.round(ratio * m));
- //Compute the sMin and sMax values
- final int sMin = FastMath.min(maxEccPow - j, maxDegree);
- final int sMax = FastMath.min(maxEccPow + j, maxDegree);
- //loop through the s values
- for (int s = 0; s <= sMax; s++) {
- //Compute the n0 value
- final int n0 = FastMath.max(FastMath.max(2, m), s);
- //Create the object for the pair j, s
- this.hansenObjects[s + maxDegree][j] = new HansenTesseralLinear(maxDegree, s, j, n0, maxHansen);
- if (s > 0 && s <= sMin) {
- //Also create the object for the pair j, -s
- this.hansenObjects[maxDegree - s][j] = new HansenTesseralLinear(maxDegree, -s, j, n0, maxHansen);
- }
- }
- }
- break;
- case OSCULATING:
- // create all objects
- for (int j = 0; j <= maxFrequencyShortPeriodics; j++) {
- for (int s = -maxDegree; s <= maxDegree; s++) {
- //Compute the n0 value
- final int n0 = FastMath.max(2, FastMath.abs(s));
- this.hansenObjects[s + maxDegree][j] = new HansenTesseralLinear(maxDegree, s, j, n0, maxHansen);
- }
- }
- break;
- default:
- throw new OrekitInternalError(null);
- }
- }
- /** Compute init values for hansen objects.
- * @param context container for attributes
- * @param rows number of rows of the hansen matrix
- * @param columns columns number of columns of the hansen matrix
- */
- public void computeHansenObjectsInitValues(final DSSTTesseralContext context, final int rows, final int columns) {
- hansenObjects[rows][columns].computeInitValues(context.getE2(), context.getChi(), context.getChi2());
- }
- /** Get hansen object.
- * @return hansenObjects
- */
- public HansenTesseralLinear[][] getHansenObjects() {
- return hansenObjects;
- }
- }
- /** Computes init values of the Hansen Objects. */
- private class FieldHansenObjects<T extends CalculusFieldElement<T>> {
- /** A two dimensional array that contains the objects needed to build the Hansen coefficients. <br/>
- * The indexes are s + maxDegree and j */
- private FieldHansenTesseralLinear<T>[][] hansenObjects;
- /** Simple constructor.
- * @param ratio Ratio of satellite period to central body rotation period
- * @param type type of the elements used during the propagation
- */
- @SuppressWarnings("unchecked")
- FieldHansenObjects(final T ratio,
- final PropagationType type) {
- // Set the maximum power of the eccentricity to use in Hansen coefficient Kernel expansion.
- maxHansen = maxEccPow / 2;
- //Allocate the two dimensional array
- final int rows = 2 * maxDegree + 1;
- final int columns = maxFrequencyShortPeriodics + 1;
- this.hansenObjects = (FieldHansenTesseralLinear<T>[][]) Array.newInstance(FieldHansenTesseralLinear.class, rows, columns);
- switch (type) {
- case MEAN:
- // loop through the resonant orders
- for (int m : resOrders) {
- //Compute the corresponding j term
- final int j = FastMath.max(1, (int) FastMath.round(ratio.multiply(m)));
- //Compute the sMin and sMax values
- final int sMin = FastMath.min(maxEccPow - j, maxDegree);
- final int sMax = FastMath.min(maxEccPow + j, maxDegree);
- //loop through the s values
- for (int s = 0; s <= sMax; s++) {
- //Compute the n0 value
- final int n0 = FastMath.max(FastMath.max(2, m), s);
- //Create the object for the pair j, s
- this.hansenObjects[s + maxDegree][j] = new FieldHansenTesseralLinear<>(maxDegree, s, j, n0, maxHansen, ratio.getField());
- if (s > 0 && s <= sMin) {
- //Also create the object for the pair j, -s
- this.hansenObjects[maxDegree - s][j] = new FieldHansenTesseralLinear<>(maxDegree, -s, j, n0, maxHansen, ratio.getField());
- }
- }
- }
- break;
- case OSCULATING:
- // create all objects
- for (int j = 0; j <= maxFrequencyShortPeriodics; j++) {
- for (int s = -maxDegree; s <= maxDegree; s++) {
- //Compute the n0 value
- final int n0 = FastMath.max(2, FastMath.abs(s));
- this.hansenObjects[s + maxDegree][j] = new FieldHansenTesseralLinear<>(maxDegree, s, j, n0, maxHansen, ratio.getField());
- }
- }
- break;
- default:
- throw new OrekitInternalError(null);
- }
- }
- /** Compute init values for hansen objects.
- * @param context container for attributes
- * @param rows number of rows of the hansen matrix
- * @param columns columns number of columns of the hansen matrix
- */
- public void computeHansenObjectsInitValues(final FieldDSSTTesseralContext<T> context,
- final int rows, final int columns) {
- hansenObjects[rows][columns].computeInitValues(context.getE2(), context.getChi(), context.getChi2());
- }
- /** Get hansen object.
- * @return hansenObjects
- */
- public FieldHansenTesseralLinear<T>[][] getHansenObjects() {
- return hansenObjects;
- }
- }
- }