DSSTThirdBody.java

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

  18. import java.util.TreeMap;

  19. import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
  20. import org.apache.commons.math3.util.FastMath;
  21. import org.orekit.bodies.CelestialBody;
  22. import org.orekit.errors.OrekitException;
  23. import org.orekit.propagation.SpacecraftState;
  24. import org.orekit.propagation.events.EventDetector;
  25. import org.orekit.propagation.semianalytical.dsst.utilities.AuxiliaryElements;
  26. import org.orekit.propagation.semianalytical.dsst.utilities.CoefficientsFactory;
  27. import org.orekit.propagation.semianalytical.dsst.utilities.CoefficientsFactory.NSKey;
  28. import org.orekit.propagation.semianalytical.dsst.utilities.UpperBounds;
  29. import org.orekit.time.AbsoluteDate;

  30. /** Third body attraction perturbation to the
  31.  *  {@link org.orekit.propagation.semianalytical.dsst.DSSTPropagator DSSTPropagator}.
  32.  *
  33.  *  @author Romain Di Costanzo
  34.  *  @author Pascal Parraud
  35.  */
  36. public class DSSTThirdBody  implements DSSTForceModel {

  37.     /** Max power for summation. */
  38.     private static final int       MAX_POWER = 22;

  39.     /** Truncation tolerance for big, eccentric  orbits. */
  40.     private static final double    BIG_TRUNCATION_TOLERANCE = 1.e-1;

  41.     /** Truncation tolerance for small orbits. */
  42.     private static final double    SMALL_TRUNCATION_TOLERANCE = 1.e-4;

  43.     /** The 3rd body to consider. */
  44.     private final CelestialBody    body;

  45.     /** Standard gravitational parameter &mu; for the body in m<sup>3</sup>/s<sup>2</sup>. */
  46.     private final double           gm;

  47.     /** Factorial. */
  48.     private final double[]         fact;

  49.     /** V<sub>ns</sub> coefficients. */
  50.     private TreeMap<NSKey, Double> Vns;

  51.     /** Distance from center of mass of the central body to the 3rd body. */
  52.     private double R3;

  53.     // Equinoctial elements (according to DSST notation)
  54.     /** a. */
  55.     private double a;
  56.     /** e<sub>x</sub>. */
  57.     private double k;
  58.     /** e<sub>y</sub>. */
  59.     private double h;
  60.     /** h<sub>x</sub>. */
  61.     private double q;
  62.     /** h<sub>y</sub>. */
  63.     private double p;

  64.     /** Eccentricity. */
  65.     private double ecc;

  66.     // Direction cosines of the symmetry axis
  67.     /** &alpha;. */
  68.     private double alpha;
  69.     /** &beta;. */
  70.     private double beta;
  71.     /** &gamma;. */
  72.     private double gamma;

  73.     // Common factors for potential computation
  74.     /** &Chi; = 1 / sqrt(1 - e<sup>2</sup>) = 1 / B. */
  75.     private double X;
  76.     /** &Chi;<sup>2</sup>. */
  77.     private double XX;
  78.     /** &Chi;<sup>3</sup>. */
  79.     private double XXX;
  80.     /** -2 * a / A. */
  81.     private double m2aoA;
  82.     /** B / A. */
  83.     private double BoA;
  84.     /** 1 / (A * B). */
  85.     private double ooAB;
  86.     /** -C / (2 * A * B). */
  87.     private double mCo2AB;
  88.     /** B / A(1 + B). */
  89.     private double BoABpo;

  90.     /** Retrograde factor. */
  91.     private int    I;

  92.     /** Maw power for a/R3 in the serie expansion. */
  93.     private int    maxAR3Pow;

  94.     /** Maw power for e in the serie expansion. */
  95.     private int    maxEccPow;

  96.     /** Complete constructor.
  97.      *  @param body the 3rd body to consider
  98.      *  @see org.orekit.bodies.CelestialBodyFactory
  99.      */
  100.     public DSSTThirdBody(final CelestialBody body) {
  101.         this.body = body;
  102.         this.gm   = body.getGM();

  103.         this.maxAR3Pow = Integer.MIN_VALUE;
  104.         this.maxEccPow = Integer.MIN_VALUE;

  105.         this.Vns = CoefficientsFactory.computeVns(MAX_POWER);

  106.         // Factorials computation
  107.         final int dim = 2 * MAX_POWER;
  108.         this.fact = new double[dim];
  109.         fact[0] = 1.;
  110.         for (int i = 1; i < dim; i++) {
  111.             fact[i] = i * fact[i - 1];
  112.         }
  113.     }

  114.     /** Get third body.
  115.      *  @return third body
  116.      */
  117.     public CelestialBody getBody() {
  118.         return body;
  119.     }

  120.     /** Computes the highest power of the eccentricity and the highest power
  121.      *  of a/R3 to appear in the truncated analytical power series expansion.
  122.      *  <p>
  123.      *  This method computes the upper value for the 3rd body potential and
  124.      *  determines the maximal powers for the eccentricity and a/R3 producing
  125.      *  potential terms bigger than a defined tolerance.
  126.      *  </p>
  127.      *  @param aux auxiliary elements related to the current orbit
  128.      *  @throws OrekitException if some specific error occurs
  129.      */
  130.     public void initialize(final AuxiliaryElements aux)
  131.         throws OrekitException {

  132.         // Initializes specific parameters.
  133.         initializeStep(aux);

  134.         // Truncation tolerance.
  135.         final double aor = a / R3;
  136.         final double tol = ( aor > .3 || (aor > .15  && ecc > .25) ) ? BIG_TRUNCATION_TOLERANCE : SMALL_TRUNCATION_TOLERANCE;

  137.         // Utilities for truncation
  138.         // Set a lower bound for eccentricity
  139.         final double eo2  = FastMath.max(0.0025, ecc / 2.);
  140.         final double x2o2 = XX / 2.;
  141.         final double[] eccPwr = new double[MAX_POWER];
  142.         final double[] chiPwr = new double[MAX_POWER];
  143.         eccPwr[0] = 1.;
  144.         chiPwr[0] = X;
  145.         for (int i = 1; i < MAX_POWER; i++) {
  146.             eccPwr[i] = eccPwr[i - 1] * eo2;
  147.             chiPwr[i] = chiPwr[i - 1] * x2o2;
  148.         }

  149.         // Auxiliary quantities.
  150.         final double ao2rxx = aor / (2. * XX);
  151.         double xmuarn       = ao2rxx * ao2rxx * gm / (X * R3);
  152.         double term         = 0.;

  153.         // Compute max power for a/R3 and e.
  154.         maxAR3Pow = 2;
  155.         maxEccPow = 0;
  156.         int n     = 2;
  157.         int m     = 2;
  158.         int nsmd2 = 0;

  159.         do {
  160.             // Upper bound for Tnm.
  161.             term =  xmuarn *
  162.                    (fact[n + m] / (fact[nsmd2] * fact[nsmd2 + m])) *
  163.                    (fact[n + m + 1] / (fact[m] * fact[n + 1])) *
  164.                    (fact[n - m + 1] / fact[n + 1]) *
  165.                    eccPwr[m] * UpperBounds.getDnl(XX, chiPwr[m], n + 2, m);

  166.             if (term < tol) {
  167.                 if (m == 0) {
  168.                     break;
  169.                 } else if (m < 2) {
  170.                     xmuarn *= ao2rxx;
  171.                     m = 0;
  172.                     n++;
  173.                     nsmd2++;
  174.                 } else {
  175.                     m -= 2;
  176.                     nsmd2++;
  177.                 }
  178.             } else {
  179.                 maxAR3Pow = n;
  180.                 maxEccPow = FastMath.max(m, maxEccPow);
  181.                 xmuarn *= ao2rxx;
  182.                 m++;
  183.                 n++;
  184.             }
  185.         } while (n < MAX_POWER);

  186.         maxEccPow = FastMath.min(maxAR3Pow, maxEccPow);

  187.     }

  188.     /** {@inheritDoc} */
  189.     public void initializeStep(final AuxiliaryElements aux) throws OrekitException {

  190.         // Equinoctial elements
  191.         a = aux.getSma();
  192.         k = aux.getK();
  193.         h = aux.getH();
  194.         q = aux.getQ();
  195.         p = aux.getP();

  196.         // Retrograde factor
  197.         I = aux.getRetrogradeFactor();

  198.         // Eccentricity
  199.         ecc = aux.getEcc();

  200.         // Distance from center of mass of the central body to the 3rd body
  201.         final Vector3D bodyPos = body.getPVCoordinates(aux.getDate(), aux.getFrame()).getPosition();
  202.         R3 = bodyPos.getNorm();

  203.         // Direction cosines
  204.         final Vector3D bodyDir = bodyPos.normalize();
  205.         alpha = bodyDir.dotProduct(aux.getVectorF());
  206.         beta  = bodyDir.dotProduct(aux.getVectorG());
  207.         gamma = bodyDir.dotProduct(aux.getVectorW());

  208.         // Equinoctial coefficients
  209.         final double A = aux.getA();
  210.         final double B = aux.getB();
  211.         final double C = aux.getC();

  212.         // &Chi;
  213.         X = 1. / B;
  214.         XX = X * X;
  215.         XXX = X * XX;
  216.         // -2 * a / A
  217.         m2aoA = -2. * a / A;
  218.         // B / A
  219.         BoA = B / A;
  220.         // 1 / AB
  221.         ooAB = 1. / (A * B);
  222.         // -C / 2AB
  223.         mCo2AB = -C * ooAB / 2.;
  224.         // B / A(1 + B)
  225.         BoABpo = BoA / (1. + B);

  226.     }

  227.     /** {@inheritDoc} */
  228.     public double[] getMeanElementRate(final SpacecraftState currentState) throws OrekitException {

  229.         // Compute potential U derivatives
  230.         final double[] dU  = computeUDerivatives();
  231.         final double dUda  = dU[0];
  232.         final double dUdk  = dU[1];
  233.         final double dUdh  = dU[2];
  234.         final double dUdAl = dU[3];
  235.         final double dUdBe = dU[4];
  236.         final double dUdGa = dU[5];

  237.         // Compute cross derivatives [Eq. 2.2-(8)]
  238.         // U(alpha,gamma) = alpha * dU/dgamma - gamma * dU/dalpha
  239.         final double UAlphaGamma   = alpha * dUdGa - gamma * dUdAl;
  240.         // U(beta,gamma) = beta * dU/dgamma - gamma * dU/dbeta
  241.         final double UBetaGamma    =  beta * dUdGa - gamma * dUdBe;
  242.         // Common factor
  243.         final double pUAGmIqUBGoAB = (p * UAlphaGamma - I * q * UBetaGamma) * ooAB;

  244.         // Compute mean elements rates [Eq. 3.1-(1)]
  245.         final double da =  0.;
  246.         final double dh =  BoA * dUdk + k * pUAGmIqUBGoAB;
  247.         final double dk = -BoA * dUdh - h * pUAGmIqUBGoAB;
  248.         final double dp =  mCo2AB * UBetaGamma;
  249.         final double dq =  mCo2AB * UAlphaGamma * I;
  250.         final double dM =  m2aoA * dUda + BoABpo * (h * dUdh + k * dUdk) + pUAGmIqUBGoAB;

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

  252.     }

  253.     /** {@inheritDoc} */
  254.     public double[] getShortPeriodicVariations(final AbsoluteDate date,
  255.                                                final double[] meanElements) throws OrekitException {
  256.         // TODO: not implemented yet, Short Periodic Variations are set to null
  257.         return new double[] {0., 0., 0., 0., 0., 0.};
  258.     }

  259.     /** {@inheritDoc} */
  260.     public EventDetector[] getEventsDetectors() {
  261.         return null;
  262.     }

  263.     /** Compute potential derivatives.
  264.      *  @return derivatives of the potential with respect to orbital parameters
  265.      *  @throws OrekitException if Hansen coefficients cannot be computed
  266.      */
  267.     private double[] computeUDerivatives() throws OrekitException {

  268.         // Hansen coefficients
  269.         final HansenThirdBody hansen = new HansenThirdBody();
  270.         // Gs and Hs coefficients
  271.         final double[][] GsHs = CoefficientsFactory.computeGsHs(k, h, alpha, beta, maxEccPow);
  272.         // Qns coefficients
  273.         final double[][] Qns = CoefficientsFactory.computeQns(gamma, maxAR3Pow, maxEccPow);
  274.         // a / R3 up to power maxAR3Pow
  275.         final double aoR3 = a / R3;
  276.         final double[] aoR3Pow = new double[maxAR3Pow + 1];
  277.         aoR3Pow[0] = 1.;
  278.         for (int i = 1; i <= maxAR3Pow; i++) {
  279.             aoR3Pow[i] = aoR3 * aoR3Pow[i - 1];
  280.         }

  281.         // Potential derivatives
  282.         double dUda  = 0.;
  283.         double dUdk  = 0.;
  284.         double dUdh  = 0.;
  285.         double dUdAl = 0.;
  286.         double dUdBe = 0.;
  287.         double dUdGa = 0.;

  288.         for (int s = 0; s <= maxEccPow; s++) {
  289.             // Get the current Gs coefficient
  290.             final double gs = GsHs[0][s];

  291.             // Compute Gs partial derivatives from 3.1-(9)
  292.             double dGsdh  = 0.;
  293.             double dGsdk  = 0.;
  294.             double dGsdAl = 0.;
  295.             double dGsdBe = 0.;
  296.             if (s > 0) {
  297.                 // First get the G(s-1) and the H(s-1) coefficients
  298.                 final double sxGsm1 = s * GsHs[0][s - 1];
  299.                 final double sxHsm1 = s * GsHs[1][s - 1];
  300.                 // Then compute derivatives
  301.                 dGsdh  = beta  * sxGsm1 - alpha * sxHsm1;
  302.                 dGsdk  = alpha * sxGsm1 + beta  * sxHsm1;
  303.                 dGsdAl = k * sxGsm1 - h * sxHsm1;
  304.                 dGsdBe = h * sxGsm1 + k * sxHsm1;
  305.             }

  306.             // Kronecker symbol (2 - delta(0,s))
  307.             final double delta0s = (s == 0) ? 1. : 2.;

  308.             for (int n = FastMath.max(2, s); n <= maxAR3Pow; n++) {
  309.                 // (n - s) must be even
  310.                 if ((n - s) % 2 == 0) {
  311.                     // Extract data from previous computation :
  312.                     final double kns   = hansen.getValue(n, s);
  313.                     final double dkns  = hansen.getDerivative(n, s);
  314.                     final double vns   = Vns.get(new NSKey(n, s));
  315.                     final double coef0 = delta0s * aoR3Pow[n] * vns;
  316.                     final double coef1 = coef0 * Qns[n][s];
  317.                     final double coef2 = coef1 * kns;
  318.                     // dQns/dGamma = Q(n, s + 1) from Equation 3.1-(8)
  319.                     // for n = s, Q(n, n + 1) = 0. (Cefola & Broucke, 1975)
  320.                     final double dqns = (n == s) ? 0. : Qns[n][s + 1];

  321.                     // Compute dU / da :
  322.                     dUda += coef2 * n * gs;
  323.                     // Compute dU / dh
  324.                     dUdh += coef1 * (kns * dGsdh + h * XXX * gs * dkns);
  325.                     // Compute dU / dk
  326.                     dUdk += coef1 * (kns * dGsdk + k * XXX * gs * dkns);
  327.                     // Compute dU / dAlpha
  328.                     dUdAl += coef2 * dGsdAl;
  329.                     // Compute dU / dBeta
  330.                     dUdBe += coef2 * dGsdBe;
  331.                     // Compute dU / dGamma
  332.                     dUdGa += coef0 * kns * dqns * gs;
  333.                 }
  334.             }
  335.         }

  336.         // mu3 / R3
  337.         final double muoR3 = gm / R3;

  338.         return new double[] {
  339.             dUda  * muoR3 / a,
  340.             dUdk  * muoR3,
  341.             dUdh  * muoR3,
  342.             dUdAl * muoR3,
  343.             dUdBe * muoR3,
  344.             dUdGa * muoR3
  345.         };

  346.     }

  347.     /** Hansen coefficients for 3rd body force model.
  348.      *  <p>
  349.      *  Hansen coefficients are functions of the eccentricity.
  350.      *  For a given eccentricity, the computed elements are stored in a map.
  351.      *  </p>
  352.      */
  353.     private class HansenThirdBody {

  354.         /** Map to store every Hansen coefficient computed. */
  355.         private TreeMap<NSKey, Double> coefficients;

  356.         /** Map to store every Hansen coefficient derivative computed. */
  357.         private TreeMap<NSKey, Double> derivatives;

  358.         /** Simple constructor. */
  359.         public HansenThirdBody() {
  360.             coefficients = new TreeMap<CoefficientsFactory.NSKey, Double>();
  361.             derivatives  = new TreeMap<CoefficientsFactory.NSKey, Double>();
  362.             initialize();
  363.         }

  364.         /** Get the K<sub>0</sub><sup>n,s</sup> coefficient value.
  365.          *  @param n n value
  366.          *  @param s s value
  367.          *  @return K<sub>0</sub><sup>n,s</sup>
  368.          */
  369.         public double getValue(final int n, final int s) {
  370.             if (coefficients.containsKey(new NSKey(n, s))) {
  371.                 return coefficients.get(new NSKey(n, s));
  372.             } else {
  373.                 // Compute the K0(n,s) coefficients
  374.                 return computeValue(n, s);
  375.             }
  376.         }

  377.         /** Get the dK<sub>0</sub><sup>n,s</sup> / d&x; coefficient derivative.
  378.          *  @param n n value
  379.          *  @param s s value
  380.          *  @return dK<sub>j</sub><sup>n,s</sup> / d&x;
  381.          */
  382.         public double getDerivative(final int n, final int s) {
  383.             if (derivatives.containsKey(new NSKey(n, s))) {
  384.                 return derivatives.get(new NSKey(n, s));
  385.             } else {
  386.                 // Compute the dK0(n,s) / dX derivative
  387.                 return computeDerivative(n, s);
  388.             }
  389.         }

  390.         /** Initialization. */
  391.         private void initialize() {
  392.             final double ec2 = ecc * ecc;
  393.             final double oX3 = 1. / XXX;
  394.             coefficients.put(new NSKey(0, 0),  1.);
  395.             coefficients.put(new NSKey(0, 1), -1.);
  396.             coefficients.put(new NSKey(1, 0),  1. + 0.5 * ec2);
  397.             coefficients.put(new NSKey(1, 1), -1.5);
  398.             coefficients.put(new NSKey(2, 0),  1. + 1.5 * ec2);
  399.             coefficients.put(new NSKey(2, 1), -2. - 0.5 * ec2);
  400.             derivatives.put(new NSKey(0, 0),  0.);
  401.             derivatives.put(new NSKey(1, 0),  oX3);
  402.             derivatives.put(new NSKey(2, 0),  3. * oX3);
  403.             derivatives.put(new NSKey(2, 1), -oX3);
  404.         }

  405.         /** Compute K<sub>0</sub><sup>n,s</sup> from Equation 2.7.3-(7)(8).
  406.          *  @param n n value
  407.          *  @param s s value
  408.          *  @return K<sub>0</sub><sup>n,s</sup>
  409.          */
  410.         private double computeValue(final int n, final int s) {
  411.             // Initialize return value
  412.             double kns = 0.;

  413.             if (n == (s - 1)) {

  414.                 final NSKey key = new NSKey(s - 2, s - 1);
  415.                 if (coefficients.containsKey(key)) {
  416.                     kns = coefficients.get(key);
  417.                 } else {
  418.                     kns = computeValue(s - 2, s - 1);
  419.                 }

  420.                 kns *= -(2. * s - 1.) / s;

  421.             } else if (n == s) {

  422.                 final NSKey key = new NSKey(s - 1, s);
  423.                 if (coefficients.containsKey(key)) {
  424.                     kns = coefficients.get(key);
  425.                 } else {
  426.                     kns = computeValue(s - 1, s);
  427.                 }

  428.                 kns *= (2. * s + 1.) / (s + 1.);

  429.             } else if (n > s) {

  430.                 final NSKey key1 = new NSKey(n - 1, s);
  431.                 double knM1 = 0.;
  432.                 if (coefficients.containsKey(key1)) {
  433.                     knM1 = coefficients.get(key1);
  434.                 } else {
  435.                     knM1 = computeValue(n - 1, s);
  436.                 }

  437.                 final NSKey key2 = new NSKey(n - 2, s);
  438.                 double knM2 = 0.;
  439.                 if (coefficients.containsKey(key2)) {
  440.                     knM2 = coefficients.get(key2);
  441.                 } else {
  442.                     knM2 = computeValue(n - 2, s);
  443.                 }

  444.                 final double val1 = (2. * n + 1.) / (n + 1.);
  445.                 final double val2 = (n + s) * (n - s) / (n * (n + 1.) * XX);

  446.                 kns = val1 * knM1 - val2 * knM2;
  447.             }

  448.             coefficients.put(new NSKey(n, s), kns);
  449.             return kns;
  450.         }

  451.         /** Compute dK<sub>0</sub><sup>n,s</sup> / d&x; from Equation 3.2-(3).
  452.          *  @param n n value
  453.          *  @param s s value
  454.          *  @return dK<sub>0</sub><sup>n,s</sup> / d&x;
  455.          */
  456.         private double computeDerivative(final int n, final int s) {
  457.             // Initialize return value
  458.             double dknsdx = 0.;

  459.             if (n > s) {

  460.                 final NSKey keyNm1 = new NSKey(n - 1, s);
  461.                 double dKnM1 = 0.;
  462.                 if (derivatives.containsKey(keyNm1)) {
  463.                     dKnM1 = derivatives.get(keyNm1);
  464.                 } else {
  465.                     dKnM1 = computeDerivative(n - 1, s);
  466.                 }

  467.                 final NSKey keyNm2 = new NSKey(n - 2, s);
  468.                 double dKnM2 = 0.;
  469.                 if (derivatives.containsKey(keyNm2)) {
  470.                     dKnM2 = derivatives.get(keyNm2);
  471.                 } else {
  472.                     dKnM2 = computeDerivative(n - 2, s);
  473.                 }

  474.                 final double knM2 = getValue(n - 2, s);

  475.                 final double val1 = (2. * n + 1.) / (n + 1.);
  476.                 final double coef = (n + s) * (n - s) / (n * (n + 1.));
  477.                 final double val2 = coef / XX;
  478.                 final double val3 = 2. * coef / XXX;

  479.                 dknsdx = val1 * dKnM1 - val2 * dKnM2 + val3 * knM2;
  480.             }

  481.             derivatives.put(new NSKey(n, s), dknsdx);
  482.             return dknsdx;
  483.         }

  484.     }

  485. }