DeepSDP4.java

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

  18. import org.hipparchus.util.FastMath;
  19. import org.hipparchus.util.MathUtils;
  20. import org.hipparchus.util.SinCos;
  21. import org.orekit.annotation.DefaultDataContext;
  22. import org.orekit.attitudes.AttitudeProvider;
  23. import org.orekit.data.DataContext;
  24. import org.orekit.frames.Frame;
  25. import org.orekit.time.DateTimeComponents;
  26. import org.orekit.utils.Constants;


  27. /** This class contains the methods that compute deep space perturbation terms.
  28.  * <p>
  29.  * The user should not bother in this class since it is handled internaly by the
  30.  * {@link TLEPropagator}.
  31.  * </p>
  32.  * <p>This implementation is largely inspired from the paper and source code <a
  33.  * href="https://www.celestrak.com/publications/AIAA/2006-6753/">Revisiting Spacetrack
  34.  * Report #3</a> and is fully compliant with its results and tests cases.</p>
  35.  * @author Felix R. Hoots, Ronald L. Roehrich, December 1980 (original fortran)
  36.  * @author David A. Vallado, Paul Crawford, Richard Hujsak, T.S. Kelso (C++ translation and improvements)
  37.  * @author Fabien Maussion (java translation)
  38.  */
  39. public class DeepSDP4 extends SDP4 {

  40.     // CHECKSTYLE: stop JavadocVariable check

  41.     // Internal constants
  42.     private static final double ZNS      = 1.19459E-5;
  43.     private static final double ZES      = 0.01675;
  44.     private static final double ZNL      = 1.5835218E-4;
  45.     private static final double ZEL      = 0.05490;
  46.     private static final double THDT     = 4.3752691E-3;
  47.     private static final double C1SS     =  2.9864797E-6;
  48.     private static final double C1L      = 4.7968065E-7;

  49.     private static final double ROOT22   = 1.7891679E-6;
  50.     private static final double ROOT32   = 3.7393792E-7;
  51.     private static final double ROOT44   = 7.3636953E-9;
  52.     private static final double ROOT52   = 1.1428639E-7;
  53.     private static final double ROOT54   = 2.1765803E-9;

  54.     private static final double Q22      =  1.7891679E-6;
  55.     private static final double Q31      =  2.1460748E-6;
  56.     private static final double Q33      =  2.2123015E-7;

  57.     private static final double C_FASX2  =  0.99139134268488593;
  58.     private static final double S_FASX2  =  0.13093206501640101;
  59.     private static final double C_2FASX4 =  0.87051638752972937;
  60.     private static final double S_2FASX4 = -0.49213943048915526;
  61.     private static final double C_3FASX6 =  0.43258117585763334;
  62.     private static final double S_3FASX6 =  0.90159499016666422;

  63.     private static final double C_G22    =  0.87051638752972937;
  64.     private static final double S_G22    = -0.49213943048915526;
  65.     private static final double C_G32    =  0.57972190187001149;
  66.     private static final double S_G32    =  0.81481440616389245;
  67.     private static final double C_G44    = -0.22866241528815548;
  68.     private static final double S_G44    =  0.97350577801807991;
  69.     private static final double C_G52    =  0.49684831179884198;
  70.     private static final double S_G52    =  0.86783740128127729;
  71.     private static final double C_G54    = -0.29695209575316894;
  72.     private static final double S_G54    = -0.95489237761529999;

  73.     /** Integration step (seconds). */
  74.     private static final double SECULAR_INTEGRATION_STEP  = 720.0;

  75.     /** Intermediate values. */
  76.     private double thgr;
  77.     private double xnq;
  78.     private double omegaq;
  79.     private double zcosil;
  80.     private double zsinil;
  81.     private double zsinhl;
  82.     private double zcoshl;
  83.     private double zmol;
  84.     private double zcosgl;
  85.     private double zsingl;
  86.     private double zmos;
  87.     private double savtsn;

  88.     private double ee2;
  89.     private double e3;
  90.     private double xi2;
  91.     private double xi3;
  92.     private double xl2;
  93.     private double xl3;
  94.     private double xl4;
  95.     private double xgh2;
  96.     private double xgh3;
  97.     private double xgh4;
  98.     private double xh2;
  99.     private double xh3;

  100.     private double d2201;
  101.     private double d2211;
  102.     private double d3210;
  103.     private double d3222;
  104.     private double d4410;
  105.     private double d4422;
  106.     private double d5220;
  107.     private double d5232;
  108.     private double d5421;
  109.     private double d5433;
  110.     private double xlamo;

  111.     private double sse;
  112.     private double ssi;
  113.     private double ssl;
  114.     private double ssh;
  115.     private double ssg;
  116.     private double se2;
  117.     private double si2;
  118.     private double sl2;
  119.     private double sgh2;
  120.     private double sh2;
  121.     private double se3;
  122.     private double si3;
  123.     private double sl3;
  124.     private double sgh3;
  125.     private double sh3;
  126.     private double sl4;
  127.     private double sgh4;

  128.     private double del1;
  129.     private double del2;
  130.     private double del3;
  131.     private double xfact;
  132.     private double xli;
  133.     private double xni;
  134.     private double atime;

  135.     private double pe;
  136.     private double pinc;
  137.     private double pl;
  138.     private double pgh;
  139.     private double ph;

  140.     private double[] derivs;

  141.     // CHECKSTYLE: resume JavadocVariable check

  142.     /** Flag for resonant orbits. */
  143.     private boolean resonant;

  144.     /** Flag for synchronous orbits. */
  145.     private boolean synchronous;

  146.     /** Flag for compliance with Dundee modifications. */
  147.     private boolean isDundeeCompliant = true;

  148.     /** Constructor for a unique initial TLE.
  149.      *
  150.      * <p>This constructor uses the {@link DataContext#getDefault() default data context}.
  151.      *
  152.      * @param initialTLE the TLE to propagate.
  153.      * @param attitudeProvider provider for attitude computation
  154.      * @param mass spacecraft mass (kg)
  155.      * @see #DeepSDP4(TLE, AttitudeProvider, double, Frame)
  156.      */
  157.     @DefaultDataContext
  158.     public DeepSDP4(final TLE initialTLE, final AttitudeProvider attitudeProvider,
  159.                     final double mass) {
  160.         this(initialTLE, attitudeProvider, mass,
  161.                 DataContext.getDefault().getFrames().getTEME());
  162.     }

  163.     /** Constructor for a unique initial TLE.
  164.      * @param initialTLE the TLE to propagate.
  165.      * @param attitudeProvider provider for attitude computation
  166.      * @param mass spacecraft mass (kg)
  167.      * @param teme the TEME frame to use for propagation.
  168.      * @since 10.1
  169.      */
  170.     public DeepSDP4(final TLE initialTLE,
  171.                     final AttitudeProvider attitudeProvider,
  172.                     final double mass,
  173.                     final Frame teme) {
  174.         super(initialTLE, attitudeProvider, mass, teme);
  175.     }

  176.     /** Computes luni - solar terms from initial coordinates and epoch.
  177.      */
  178.     protected void luniSolarTermsComputation() {

  179.         final SinCos scg  = FastMath.sinCos(tle.getPerigeeArgument());
  180.         final double sing = scg.sin();
  181.         final double cosg = scg.cos();

  182.         final SinCos scq  = FastMath.sinCos(tle.getRaan());
  183.         final double sinq = scq.sin();
  184.         final double cosq = scq.cos();
  185.         final double aqnv = 1.0 / a0dp;

  186.         // Compute julian days since 1900
  187.         final double daysSince1900 = (tle.getDate()
  188.                 .getComponents(utc)
  189.                 .offsetFrom(DateTimeComponents.JULIAN_EPOCH)) /
  190.                 Constants.JULIAN_DAY - 2415020;

  191.         double cc = C1SS;
  192.         double ze = ZES;
  193.         double zn = ZNS;
  194.         double zsinh = sinq;
  195.         double zcosh = cosq;

  196.         thgr = thetaG(tle.getDate());
  197.         xnq = xn0dp;
  198.         omegaq = tle.getPerigeeArgument();

  199.         final double xnodce = 4.5236020 - 9.2422029e-4 * daysSince1900;
  200.         final SinCos scTem  = FastMath.sinCos(xnodce);
  201.         final double stem   = scTem.sin();
  202.         final double ctem   = scTem.cos();
  203.         final double c_minus_gam = 0.228027132 * daysSince1900 - 1.1151842;
  204.         final double gam = 5.8351514 + 0.0019443680 * daysSince1900;

  205.         zcosil = 0.91375164 - 0.03568096 * ctem;
  206.         zsinil = FastMath.sqrt(1.0 - zcosil * zcosil);
  207.         zsinhl = 0.089683511 * stem / zsinil;
  208.         zcoshl = FastMath.sqrt(1.0 - zsinhl * zsinhl);
  209.         zmol = MathUtils.normalizeAngle(c_minus_gam, FastMath.PI);

  210.         double zx = 0.39785416 * stem / zsinil;
  211.         final double zy = zcoshl * ctem + 0.91744867 * zsinhl * stem;
  212.         zx = FastMath.atan2( zx, zy) + gam - xnodce;
  213.         final SinCos scZx = FastMath.sinCos(zx);
  214.         zcosgl = scZx.cos();
  215.         zsingl = scZx.sin();
  216.         zmos = MathUtils.normalizeAngle(6.2565837 + 0.017201977 * daysSince1900, FastMath.PI);

  217.         // Do solar terms
  218.         savtsn = 1e20;

  219.         double zcosi =  0.91744867;
  220.         double zsini =  0.39785416;
  221.         double zsing = -0.98088458;
  222.         double zcosg =  0.1945905;

  223.         double se = 0;
  224.         double sgh = 0;
  225.         double sh = 0;
  226.         double si = 0;
  227.         double sl = 0;

  228.         // There was previously some convoluted logic here, but it boils
  229.         // down to this:  we compute the solar terms,  then the lunar terms.
  230.         // On a second pass,  we recompute the solar terms, taking advantage
  231.         // of the improved data that resulted from computing lunar terms.
  232.         for (int iteration = 0; iteration < 2; ++iteration) {
  233.             final double a1 = zcosg * zcosh + zsing * zcosi * zsinh;
  234.             final double a3 = -zsing * zcosh + zcosg * zcosi * zsinh;
  235.             final double a7 = -zcosg * zsinh + zsing * zcosi * zcosh;
  236.             final double a8 = zsing * zsini;
  237.             final double a9 = zsing * zsinh + zcosg * zcosi * zcosh;
  238.             final double a10 = zcosg * zsini;
  239.             final double a2 = cosi0 * a7 + sini0 * a8;
  240.             final double a4 = cosi0 * a9 + sini0 * a10;
  241.             final double a5 = -sini0 * a7 + cosi0 * a8;
  242.             final double a6 = -sini0 * a9 + cosi0 * a10;
  243.             final double x1 = a1 * cosg + a2 * sing;
  244.             final double x2 = a3 * cosg + a4 * sing;
  245.             final double x3 = -a1 * sing + a2 * cosg;
  246.             final double x4 = -a3 * sing + a4 * cosg;
  247.             final double x5 = a5 * sing;
  248.             final double x6 = a6 * sing;
  249.             final double x7 = a5 * cosg;
  250.             final double x8 = a6 * cosg;
  251.             final double z31 = 12 * x1 * x1 - 3 * x3 * x3;
  252.             final double z32 = 24 * x1 * x2 - 6 * x3 * x4;
  253.             final double z33 = 12 * x2 * x2 - 3 * x4 * x4;
  254.             final double z11 = -6 * a1 * a5 + e0sq * (-24 * x1 * x7 - 6 * x3 * x5);
  255.             final double z12 = -6 * (a1 * a6 + a3 * a5) +
  256.                                e0sq * (-24 * (x2 * x7 + x1 * x8) - 6 * (x3 * x6 + x4 * x5));
  257.             final double z13 = -6 * a3 * a6 + e0sq * (-24 * x2 * x8 - 6 * x4 * x6);
  258.             final double z21 = 6 * a2 * a5 + e0sq * (24 * x1 * x5 - 6 * x3 * x7);
  259.             final double z22 = 6 * (a4 * a5 + a2 * a6) +
  260.                                e0sq * (24 * (x2 * x5 + x1 * x6) - 6 * (x4 * x7 + x3 * x8));
  261.             final double z23 = 6 * a4 * a6 + e0sq * (24 * x2 * x6 - 6 * x4 * x8);
  262.             final double s3 = cc / xnq;
  263.             final double s2 = -0.5 * s3 / beta0;
  264.             final double s4 = s3 * beta0;
  265.             final double s1 = -15 * tle.getE() * s4;
  266.             final double s5 = x1 * x3 + x2 * x4;
  267.             final double s6 = x2 * x3 + x1 * x4;
  268.             final double s7 = x2 * x4 - x1 * x3;
  269.             double z1 = 3 * (a1 * a1 + a2 * a2) + z31 * e0sq;
  270.             double z2 = 6 * (a1 * a3 + a2 * a4) + z32 * e0sq;
  271.             double z3 = 3 * (a3 * a3 + a4 * a4) + z33 * e0sq;

  272.             z1 = z1 + z1 + beta02 * z31;
  273.             z2 = z2 + z2 + beta02 * z32;
  274.             z3 = z3 + z3 + beta02 * z33;
  275.             se = s1 * zn * s5;
  276.             si = s2 * zn * (z11 + z13);
  277.             sl = -zn * s3 * (z1 + z3 - 14 - 6 * e0sq);
  278.             sgh = s4 * zn * (z31 + z33 - 6);
  279.             if (tle.getI() < (FastMath.PI / 60.0)) {
  280.                 // inclination smaller than 3 degrees
  281.                 sh = 0;
  282.             } else {
  283.                 sh = -zn * s2 * (z21 + z23);
  284.             }
  285.             ee2  =  2 * s1 * s6;
  286.             e3   =  2 * s1 * s7;
  287.             xi2  =  2 * s2 * z12;
  288.             xi3  =  2 * s2 * (z13 - z11);
  289.             xl2  = -2 * s3 * z2;
  290.             xl3  = -2 * s3 * (z3 - z1);
  291.             xl4  = -2 * s3 * (-21 - 9 * e0sq) * ze;
  292.             xgh2 =  2 * s4 * z32;
  293.             xgh3 =  2 * s4 * (z33 - z31);
  294.             xgh4 = -18 * s4 * ze;
  295.             xh2  = -2 * s2 * z22;
  296.             xh3  = -2 * s2 * (z23 - z21);

  297.             if (iteration == 0) { // we compute lunar terms only on the first pass:
  298.                 sse = se;
  299.                 ssi = si;
  300.                 ssl = sl;
  301.                 ssh = (tle.getI() < (FastMath.PI / 60.0)) ? 0 : sh / sini0;
  302.                 ssg = sgh - cosi0 * ssh;
  303.                 se2 = ee2;
  304.                 si2 = xi2;
  305.                 sl2 = xl2;
  306.                 sgh2 = xgh2;
  307.                 sh2 = xh2;
  308.                 se3 = e3;
  309.                 si3 = xi3;
  310.                 sl3 = xl3;
  311.                 sgh3 = xgh3;
  312.                 sh3 = xh3;
  313.                 sl4 = xl4;
  314.                 sgh4 = xgh4;
  315.                 zcosg = zcosgl;
  316.                 zsing = zsingl;
  317.                 zcosi = zcosil;
  318.                 zsini = zsinil;
  319.                 zcosh = zcoshl * cosq + zsinhl * sinq;
  320.                 zsinh = sinq * zcoshl - cosq * zsinhl;
  321.                 zn = ZNL;
  322.                 cc = C1L;
  323.                 ze = ZEL;
  324.             }
  325.         } // end of solar - lunar - solar terms computation

  326.         sse += se;
  327.         ssi += si;
  328.         ssl += sl;
  329.         ssg += sgh - ((tle.getI() < (FastMath.PI / 60.0)) ? 0 : (cosi0 / sini0 * sh));
  330.         ssh += (tle.getI() < (FastMath.PI / 60.0)) ? 0 : sh / sini0;



  331.         //        Start the resonant-synchronous tests and initialization

  332.         double bfact = 0;

  333.         // if mean motion is 1.893053 to 2.117652 revs/day, and eccentricity >= 0.5,
  334.         // start of the 12-hour orbit, e > 0.5 section
  335.         if ((xnq >= 0.00826) && (xnq <= 0.00924) && (tle.getE() >= 0.5)) {

  336.             final double g201 = -0.306 - (tle.getE() - 0.64) * 0.440;
  337.             final double eoc = tle.getE() * e0sq;
  338.             final double sini2 = sini0 * sini0;
  339.             final double f220 = 0.75 * (1 + 2 * cosi0 + theta2);
  340.             final double f221 = 1.5 * sini2;
  341.             final double f321 =  1.875 * sini0 * (1 - 2 * cosi0 - 3 * theta2);
  342.             final double f322 = -1.875 * sini0 * (1 + 2 * cosi0 - 3 * theta2);
  343.             final double f441 = 35 * sini2 * f220;
  344.             final double f442 = 39.3750 * sini2 * sini2;
  345.             final double f522 = 9.84375 * sini0 * (sini2 * (1 - 2 * cosi0 - 5 * theta2) +
  346.                                                    0.33333333 * (-2 + 4 * cosi0 + 6 * theta2));
  347.             final double f523 = sini0 * (4.92187512 * sini2 * (-2 - 4 * cosi0 + 10 * theta2) +
  348.                                          6.56250012 * (1 + 2 * cosi0 - 3 * theta2));
  349.             final double f542 = 29.53125 * sini0 * (2 - 8 * cosi0 + theta2 * (-12 + 8 * cosi0 + 10 * theta2));
  350.             final double f543 = 29.53125 * sini0 * (-2 - 8 * cosi0 + theta2 * (12 + 8 * cosi0 - 10 * theta2));
  351.             final double g211;
  352.             final double g310;
  353.             final double g322;
  354.             final double g410;
  355.             final double g422;
  356.             final double g520;

  357.             resonant = true;       // it is resonant...
  358.             synchronous = false;     // but it's not synchronous

  359.             // Geopotential resonance initialization for 12 hour orbits :
  360.             if (tle.getE() <= 0.65) {
  361.                 g211 =    3.616  -   13.247  * tle.getE() +   16.290  * e0sq;
  362.                 g310 =  -19.302  +  117.390  * tle.getE() -  228.419  * e0sq +  156.591  * eoc;
  363.                 g322 =  -18.9068 +  109.7927 * tle.getE() -  214.6334 * e0sq +  146.5816 * eoc;
  364.                 g410 =  -41.122  +  242.694  * tle.getE() -  471.094  * e0sq +  313.953  * eoc;
  365.                 g422 = -146.407  +  841.880  * tle.getE() - 1629.014  * e0sq + 1083.435  * eoc;
  366.                 g520 = -532.114  + 3017.977  * tle.getE() - 5740.032  * e0sq + 3708.276  * eoc;
  367.             } else  {
  368.                 g211 =   -72.099 +   331.819 * tle.getE() -   508.738 * e0sq +   266.724 * eoc;
  369.                 g310 =  -346.844 +  1582.851 * tle.getE() -  2415.925 * e0sq +  1246.113 * eoc;
  370.                 g322 =  -342.585 +  1554.908 * tle.getE() -  2366.899 * e0sq +  1215.972 * eoc;
  371.                 g410 = -1052.797 +  4758.686 * tle.getE() -  7193.992 * e0sq +  3651.957 * eoc;
  372.                 g422 = -3581.69  + 16178.11  * tle.getE() - 24462.77  * e0sq + 12422.52  * eoc;
  373.                 if (tle.getE() <= 0.715) {
  374.                     g520 = 1464.74 - 4664.75 * tle.getE() + 3763.64 * e0sq;
  375.                 } else {
  376.                     g520 = -5149.66 + 29936.92 * tle.getE() - 54087.36 * e0sq + 31324.56 * eoc;
  377.                 }
  378.             }

  379.             final double g533;
  380.             final double g521;
  381.             final double g532;
  382.             if (tle.getE() < 0.7) {
  383.                 g533 = -919.2277  + 4988.61   * tle.getE() - 9064.77   * e0sq + 5542.21  * eoc;
  384.                 g521 = -822.71072 + 4568.6173 * tle.getE() - 8491.4146 * e0sq + 5337.524 * eoc;
  385.                 g532 = -853.666   + 4690.25   * tle.getE() - 8624.77   * e0sq + 5341.4   * eoc;
  386.             } else {
  387.                 g533 = -37995.78  + 161616.52 * tle.getE() - 229838.2  * e0sq + 109377.94 * eoc;
  388.                 g521 = -51752.104 + 218913.95 * tle.getE() - 309468.16 * e0sq + 146349.42 * eoc;
  389.                 g532 = -40023.88  + 170470.89 * tle.getE() - 242699.48 * e0sq + 115605.82 * eoc;
  390.             }

  391.             double temp1 = 3 * xnq * xnq * aqnv * aqnv;
  392.             double temp = temp1 * ROOT22;
  393.             d2201 = temp * f220 * g201;
  394.             d2211 = temp * f221 * g211;
  395.             temp1 *= aqnv;
  396.             temp = temp1 * ROOT32;
  397.             d3210 = temp * f321 * g310;
  398.             d3222 = temp * f322 * g322;
  399.             temp1 *= aqnv;
  400.             temp = 2 * temp1 * ROOT44;
  401.             d4410 = temp * f441 * g410;
  402.             d4422 = temp * f442 * g422;
  403.             temp1 *= aqnv;
  404.             temp = temp1 * ROOT52;
  405.             d5220 = temp * f522 * g520;
  406.             d5232 = temp * f523 * g532;
  407.             temp = 2 * temp1 * ROOT54;
  408.             d5421 = temp * f542 * g521;
  409.             d5433 = temp * f543 * g533;
  410.             xlamo = tle.getMeanAnomaly() + tle.getRaan() + tle.getRaan() - thgr - thgr;
  411.             bfact = xmdot + xnodot + xnodot - THDT - THDT;
  412.             bfact += ssl + ssh + ssh;
  413.         } else if ((xnq < 0.0052359877) && (xnq > 0.0034906585)) {
  414.             // if mean motion is .8 to 1.2 revs/day : (geosynch)

  415.             final double cosio_plus_1 = 1.0 + cosi0;
  416.             final double g200 = 1 + e0sq * (-2.5 + 0.8125  * e0sq);
  417.             final double g300 = 1 + e0sq * (-6   + 6.60937 * e0sq);
  418.             final double f311 = 0.9375 * sini0 * sini0 * (1 + 3 * cosi0) - 0.75 * cosio_plus_1;
  419.             final double g310 = 1 + 2 * e0sq;
  420.             final double f220 = 0.75 * cosio_plus_1 * cosio_plus_1;
  421.             final double f330 = 2.5 * f220 * cosio_plus_1;

  422.             resonant = true;
  423.             synchronous = true;

  424.             // Synchronous resonance terms initialization
  425.             del1 = 3 * xnq * xnq * aqnv * aqnv;
  426.             del2 = 2 * del1 * f220 * g200 * Q22;
  427.             del3 = 3 * del1 * f330 * g300 * Q33 * aqnv;
  428.             del1 = del1 * f311 * g310 * Q31 * aqnv;
  429.             xlamo = tle.getMeanAnomaly() + tle.getRaan() + tle.getPerigeeArgument() - thgr;
  430.             bfact = xmdot + omgdot + xnodot - THDT;
  431.             bfact = bfact + ssl + ssg + ssh;
  432.         } else {
  433.             // it's neither a high-e 12-hours orbit nor a geosynchronous:
  434.             resonant = false;
  435.             synchronous = false;
  436.         }

  437.         if (resonant) {
  438.             xfact = bfact - xnq;

  439.             // Initialize integrator
  440.             xli   = xlamo;
  441.             xni   = xnq;
  442.             atime = 0;
  443.         }
  444.         derivs = new double[2];
  445.     }

  446.     /** Computes secular terms from current coordinates and epoch.
  447.      * @param t offset from initial epoch (minutes)
  448.      */
  449.     protected void deepSecularEffects(final double t)  {

  450.         xll    += ssl * t;
  451.         omgadf += ssg * t;
  452.         xnode  += ssh * t;
  453.         em      = tle.getE() + sse * t;
  454.         xinc    = tle.getI() + ssi * t;

  455.         if (resonant) {
  456.             // If we're closer to t = 0 than to the currently-stored data
  457.             // from the previous call to this function,  then we're
  458.             // better off "restarting",  going back to the initial data.
  459.             // The Dundee code rigs things up to _always_ take 720-minute
  460.             // steps from epoch to end time,  except for the final step.
  461.             // Easiest way to arrange similar behavior in this code is
  462.             // just to always do a restart,  if we're in Dundee-compliant
  463.             // mode.
  464.             if (FastMath.abs(t) < FastMath.abs(t - atime) || isDundeeCompliant)  {
  465.                 // Epoch restart
  466.                 atime = 0;
  467.                 xni = xnq;
  468.                 xli = xlamo;
  469.             }
  470.             boolean lastIntegrationStep = false;
  471.             // if |step|>|step max| then do one step at step max
  472.             while (!lastIntegrationStep) {
  473.                 double delt = t - atime;
  474.                 if (delt > SECULAR_INTEGRATION_STEP) {
  475.                     delt = SECULAR_INTEGRATION_STEP;
  476.                 } else if (delt < -SECULAR_INTEGRATION_STEP) {
  477.                     delt = -SECULAR_INTEGRATION_STEP;
  478.                 } else {
  479.                     lastIntegrationStep = true;
  480.                 }

  481.                 computeSecularDerivs();

  482.                 final double xldot = xni + xfact;

  483.                 double xlpow = 1.;
  484.                 xli += delt * xldot;
  485.                 xni += delt * derivs[0];
  486.                 double delt_factor = delt;
  487.                 xlpow *= xldot;
  488.                 derivs[1] *= xlpow;
  489.                 delt_factor *= delt / 2;
  490.                 xli += delt_factor * derivs[0];
  491.                 xni += delt_factor * derivs[1];
  492.                 atime += delt;
  493.             }
  494.             xn = xni;
  495.             final double temp = -xnode + thgr + t * THDT;
  496.             xll = xli + temp + (synchronous ? -omgadf : temp);
  497.         }
  498.     }

  499.     /** Computes periodic terms from current coordinates and epoch.
  500.      * @param t offset from initial epoch (min)
  501.      */
  502.     protected void deepPeriodicEffects(final double t)  {

  503.         // If the time didn't change by more than 30 minutes,
  504.         // there's no good reason to recompute the perturbations;
  505.         // they don't change enough over so short a time span.
  506.         // However,  the Dundee code _always_ recomputes,  so if
  507.         // we're attempting to replicate its results,  we've gotta
  508.         // recompute everything,  too.
  509.         if ((FastMath.abs(savtsn - t) >= 30.0) || isDundeeCompliant)  {

  510.             savtsn = t;

  511.             // Update solar perturbations for time T
  512.             double zm = zmos + ZNS * t;
  513.             double zf = zm + 2 * ZES * FastMath.sin(zm);
  514.             SinCos sczf = FastMath.sinCos(zf);
  515.             double sinzf = sczf.sin();
  516.             double f2 = 0.5 * sinzf * sinzf - 0.25;
  517.             double f3 = -0.5 * sinzf * sczf.cos();
  518.             final double ses = se2 * f2 + se3 * f3;
  519.             final double sis = si2 * f2 + si3 * f3;
  520.             final double sls = sl2 * f2 + sl3 * f3 + sl4 * sinzf;
  521.             final double sghs = sgh2 * f2 + sgh3 * f3 + sgh4 * sinzf;
  522.             final double shs = sh2 * f2 + sh3 * f3;

  523.             // Update lunar perturbations for time T
  524.             zm = zmol + ZNL * t;
  525.             zf = zm + 2 * ZEL * FastMath.sin(zm);
  526.             sczf = FastMath.sinCos(zf);
  527.             sinzf = sczf.sin();
  528.             f2 =  0.5 * sinzf * sinzf - 0.25;
  529.             f3 = -0.5 * sinzf * sczf.cos();
  530.             final double sel = ee2 * f2 + e3 * f3;
  531.             final double sil = xi2 * f2 + xi3 * f3;
  532.             final double sll = xl2 * f2 + xl3 * f3 + xl4 * sinzf;
  533.             final double sghl = xgh2 * f2 + xgh3 * f3 + xgh4 * sinzf;
  534.             final double sh1 = xh2 * f2 + xh3 * f3;

  535.             // Sum the solar and lunar contributions
  536.             pe   = ses  + sel;
  537.             pinc = sis  + sil;
  538.             pl   = sls  + sll;
  539.             pgh  = sghs + sghl;
  540.             ph   = shs  + sh1;
  541.         }

  542.         xinc += pinc;

  543.         final SinCos scis = FastMath.sinCos(xinc);
  544.         final double sinis = scis.sin();
  545.         final double cosis = scis.cos();

  546.         /* Add solar/lunar perturbation correction to eccentricity: */
  547.         em     += pe;
  548.         xll    += pl;
  549.         omgadf += pgh;
  550.         xinc    = MathUtils.normalizeAngle(xinc, 0);

  551.         if (FastMath.abs(xinc) >= 0.2) {
  552.             // Apply periodics directly
  553.             final double temp_val = ph / sinis;
  554.             omgadf -= cosis * temp_val;
  555.             xnode += temp_val;
  556.         } else {
  557.             // Apply periodics with Lyddane modification
  558.             final SinCos scok  = FastMath.sinCos(xnode);
  559.             final double sinok = scok.sin();
  560.             final double cosok = scok.cos();
  561.             final double alfdp =  ph * cosok + (pinc * cosis + sinis) * sinok;
  562.             final double betdp = -ph * sinok + (pinc * cosis + sinis) * cosok;
  563.             final double delta_xnode = MathUtils.normalizeAngle(FastMath.atan2(alfdp, betdp) - xnode, 0);
  564.             final double dls = -xnode * sinis * pinc;
  565.             omgadf += dls - cosis * delta_xnode;
  566.             xnode  += delta_xnode;
  567.         }
  568.     }

  569.     /** Computes internal secular derivs. */
  570.     private void computeSecularDerivs() {

  571.         final SinCos sc_li  = FastMath.sinCos(xli);
  572.         final double sin_li = sc_li.sin();
  573.         final double cos_li = sc_li.cos();
  574.         final double sin_2li = 2. * sin_li * cos_li;
  575.         final double cos_2li = 2. * cos_li * cos_li - 1.;

  576.         // Dot terms calculated :
  577.         if (synchronous)  {
  578.             final double sin_3li = sin_2li * cos_li + cos_2li * sin_li;
  579.             final double cos_3li = cos_2li * cos_li - sin_2li * sin_li;
  580.             final double term1a = del1 * (sin_li  * C_FASX2  - cos_li  * S_FASX2);
  581.             final double term2a = del2 * (sin_2li * C_2FASX4 - cos_2li * S_2FASX4);
  582.             final double term3a = del3 * (sin_3li * C_3FASX6 - cos_3li * S_3FASX6);
  583.             final double term1b = del1 * (cos_li  * C_FASX2  + sin_li  * S_FASX2);
  584.             final double term2b = 2.0 * del2 * (cos_2li * C_2FASX4 + sin_2li * S_2FASX4);
  585.             final double term3b = 3.0 * del3 * (cos_3li * C_3FASX6 + sin_3li * S_3FASX6);
  586.             derivs[0] = term1a + term2a + term3a;
  587.             derivs[1] = term1b + term2b + term3b;
  588.         } else {
  589.             // orbit is a 12-hour resonant one
  590.             final double xomi = omegaq + omgdot * atime;
  591.             final SinCos sc_omi  = FastMath.sinCos(xomi);
  592.             final double sin_omi = sc_omi.sin();
  593.             final double cos_omi = sc_omi.cos();
  594.             final double sin_li_m_omi = sin_li * cos_omi - sin_omi * cos_li;
  595.             final double sin_li_p_omi = sin_li * cos_omi + sin_omi * cos_li;
  596.             final double cos_li_m_omi = cos_li * cos_omi + sin_omi * sin_li;
  597.             final double cos_li_p_omi = cos_li * cos_omi - sin_omi * sin_li;
  598.             final double sin_2omi = 2. * sin_omi * cos_omi;
  599.             final double cos_2omi = 2. * cos_omi * cos_omi - 1.;
  600.             final double sin_2li_m_omi = sin_2li * cos_omi - sin_omi * cos_2li;
  601.             final double sin_2li_p_omi = sin_2li * cos_omi + sin_omi * cos_2li;
  602.             final double cos_2li_m_omi = cos_2li * cos_omi + sin_omi * sin_2li;
  603.             final double cos_2li_p_omi = cos_2li * cos_omi - sin_omi * sin_2li;
  604.             final double sin_2li_p_2omi = sin_2li * cos_2omi + sin_2omi * cos_2li;
  605.             final double cos_2li_p_2omi = cos_2li * cos_2omi - sin_2omi * sin_2li;
  606.             final double sin_2omi_p_li = sin_li * cos_2omi + sin_2omi * cos_li;
  607.             final double cos_2omi_p_li = cos_li * cos_2omi - sin_2omi * sin_li;
  608.             final double term1a = d2201 * (sin_2omi_p_li * C_G22 - cos_2omi_p_li * S_G22) +
  609.                                   d2211 * (sin_li * C_G22 - cos_li * S_G22) +
  610.                                   d3210 * (sin_li_p_omi * C_G32 - cos_li_p_omi * S_G32) +
  611.                                   d3222 * (sin_li_m_omi * C_G32 - cos_li_m_omi * S_G32) +
  612.                                   d5220 * (sin_li_p_omi * C_G52 - cos_li_p_omi * S_G52) +
  613.                                   d5232 * (sin_li_m_omi * C_G52 - cos_li_m_omi * S_G52);
  614.             final double term2a = d4410 * (sin_2li_p_2omi * C_G44 - cos_2li_p_2omi * S_G44) +
  615.                                   d4422 * (sin_2li * C_G44 - cos_2li * S_G44) +
  616.                                   d5421 * (sin_2li_p_omi * C_G54 - cos_2li_p_omi * S_G54) +
  617.                                   d5433 * (sin_2li_m_omi * C_G54 - cos_2li_m_omi * S_G54);
  618.             final double term1b = d2201 * (cos_2omi_p_li * C_G22 + sin_2omi_p_li * S_G22) +
  619.                                   d2211 * (cos_li * C_G22 + sin_li * S_G22) +
  620.                                   d3210 * (cos_li_p_omi * C_G32 + sin_li_p_omi * S_G32) +
  621.                                   d3222 * (cos_li_m_omi * C_G32 + sin_li_m_omi * S_G32) +
  622.                                   d5220 * (cos_li_p_omi * C_G52 + sin_li_p_omi * S_G52) +
  623.                                   d5232 * (cos_li_m_omi * C_G52 + sin_li_m_omi * S_G52);
  624.             final double term2b = 2.0 * (d4410 * (cos_2li_p_2omi * C_G44 + sin_2li_p_2omi * S_G44) +
  625.                                          d4422 * (cos_2li * C_G44 + sin_2li * S_G44) +
  626.                                          d5421 * (cos_2li_p_omi * C_G54 + sin_2li_p_omi * S_G54) +
  627.                                          d5433 * (cos_2li_m_omi * C_G54 + sin_2li_m_omi * S_G54));

  628.             derivs[0] = term1a + term2a;
  629.             derivs[1] = term1b + term2b;

  630.         }
  631.     }

  632. }