PredefinedIAUPoles.java

  1. /* Copyright 2002-2018 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.bodies;

  18. import org.hipparchus.RealFieldElement;
  19. import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
  20. import org.hipparchus.geometry.euclidean.threed.Vector3D;
  21. import org.hipparchus.util.FastMath;
  22. import org.orekit.time.AbsoluteDate;
  23. import org.orekit.time.FieldAbsoluteDate;
  24. import org.orekit.time.TimeScalesFactory;
  25. import org.orekit.utils.Constants;

  26. /** Enumerate for predefined IAU poles.
  27.  * <p>The pole models provided here come from the <a
  28.  * href="http://astropedia.astrogeology.usgs.gov/alfresco/d/d/workspace/SpacesStore/28fd9e81-1964-44d6-a58b-fbbf61e64e15/WGCCRE2009reprint.pdf">
  29.  * 2009 report</a> and the <a href="http://astropedia.astrogeology.usgs.gov/alfresco/d/d/workspace/SpacesStore/04d348b0-eb2b-46a2-abe9-6effacb37763/WGCCRE-Erratum-2011reprint.pdf">
  30.  * 2011 erratum</a> of the IAU/IAG Working Group on Cartographic Coordinates
  31.  * and Rotational Elements of the Planets and Satellites (WGCCRE). Note that these value
  32.  * differ from earliest reports (before 2005).
  33.  *</p>
  34.  * @author Luc Maisonobe
  35.  * @since 9.0
  36.  */
  37. enum PredefinedIAUPoles implements IAUPole {

  38.     /** IAU pole and prime meridian model for Sun. */
  39.     SUN {

  40.         /** Constant term of the prime meridian. */
  41.         private static final double W0 = 84.176;

  42.         /** Rate term of the prime meridian. */
  43.         private static final double W_DOT = 14.1844000;

  44.         /** Fixed pole. */
  45.         private final Vector3D pole = new Vector3D(FastMath.toRadians(286.13),
  46.                                                    FastMath.toRadians(63.87));

  47.         /** {@inheritDoc} */
  48.         public Vector3D getPole(final AbsoluteDate date) {
  49.             return pole;
  50.         }

  51.         /** {@inheritDoc} */
  52.         public <T extends RealFieldElement<T>> FieldVector3D<T> getPole(final FieldAbsoluteDate<T> date) {
  53.             return new FieldVector3D<>(date.getField(), pole);
  54.         }

  55.         /** {@inheritDoc} */
  56.         public double getPrimeMeridianAngle(final AbsoluteDate date) {
  57.             return FastMath.toRadians(d(date) * W_DOT + W0);
  58.         }

  59.         /** {@inheritDoc} */
  60.         public <T extends RealFieldElement<T>> T getPrimeMeridianAngle(final FieldAbsoluteDate<T> date) {
  61.             return toRadians(d(date).multiply(W_DOT).add(W0));
  62.         }

  63.     },

  64.     /** IAU pole and prime meridian model for Mercury. */
  65.     MERCURY {

  66.         /** Constant term of the right ascension of the pole. */
  67.         private static final double ALPHA_0 = 281.0097;

  68.         /** Rate term of the right ascension of the pole. */
  69.         private static final double ALPHA_DOT = -0.0328;

  70.         /** Constant term of the declination of the pole. */
  71.         private static final double DELTA_0 = 61.4143;

  72.         /** Rate term of the declination of the pole. */
  73.         private static final double DELTA_DOT = -0.0049;

  74.         /** Constant term of the prime meridian. */
  75.         private static final double W_0 = 329.5469;

  76.         /** Rate term of the prime meridian. */
  77.         private static final double W_DOT = 6.1385025;

  78.         /** M1 coefficient of the prime meridian. */
  79.         private static final double M1_COEFF = 0.00993822;

  80.         /** M2 coefficient of the prime meridian. */
  81.         private static final double M2_COEFF = -0.00104581;

  82.         /** M3 coefficient of the prime meridian. */
  83.         private static final double M3_COEFF = -0.00010280;

  84.         /** M4 coefficient of the prime meridian. */
  85.         private static final double M4_COEFF = -0.00002364;

  86.         /** M5 coefficient of the prime meridian. */
  87.         private static final double M5_COEFF = -0.00000532;

  88.         /** Constant term of the M1 angle. */
  89.         private static final double M1_0   = 174.791086;

  90.         /** Rate term of the M1 angle. */
  91.         private static final double M1_DOT = 4.092335;

  92.         /** Constant term of the M2 angle. */
  93.         private static final double M2_0   = 349.582171;

  94.         /** Rate term of the M1 angle. */
  95.         private static final double M2_DOT = 8.184670;

  96.         /** Constant term of the M3 angle. */
  97.         private static final double M3_0   = 164.373257;

  98.         /** Rate term of the M1 angle. */
  99.         private static final double M3_DOT = 12.277005;

  100.         /** Constant term of the M4 angle. */
  101.         private static final double M4_0   = 339.164343;

  102.         /** Rate term of the M1 angle. */
  103.         private static final double M4_DOT = 16.369340;

  104.         /** Constant term of the M5 angle. */
  105.         private static final double M5_0   = 153.955429;

  106.         /** Rate term of the M1 angle. */
  107.         private static final double M5_DOT = 20.461675;

  108.         /** {@inheritDoc} */
  109.         public Vector3D getPole(final AbsoluteDate date) {
  110.             final double t = t(date);
  111.             return new Vector3D(FastMath.toRadians(t * ALPHA_DOT + ALPHA_0),
  112.                                 FastMath.toRadians(t * DELTA_DOT + DELTA_0));
  113.         }

  114.         /** {@inheritDoc} */
  115.         public <T extends RealFieldElement<T>> FieldVector3D<T> getPole(final FieldAbsoluteDate<T> date) {
  116.             final T t = t(date);
  117.             return new FieldVector3D<>(toRadians(t.multiply(ALPHA_DOT).add(ALPHA_0)),
  118.                                        toRadians(t.multiply(DELTA_DOT).add(DELTA_0)));
  119.         }

  120.         /** {@inheritDoc} */
  121.         public double getPrimeMeridianAngle(final AbsoluteDate date) {
  122.             final double d = d(date);
  123.             return FastMath.toRadians(d(date) * W_DOT + W_0 +
  124.                                       FastMath.sin(FastMath.toRadians(d * M1_DOT + M1_0)) * M1_COEFF +
  125.                                       FastMath.sin(FastMath.toRadians(d * M2_DOT + M2_0)) * M2_COEFF +
  126.                                       FastMath.sin(FastMath.toRadians(d * M3_DOT + M3_0)) * M3_COEFF +
  127.                                       FastMath.sin(FastMath.toRadians(d * M4_DOT + M4_0)) * M4_COEFF +
  128.                                       FastMath.sin(FastMath.toRadians(d * M5_DOT + M5_0)) * M5_COEFF);
  129.         }

  130.         /** {@inheritDoc} */
  131.         public <T extends RealFieldElement<T>> T getPrimeMeridianAngle(final FieldAbsoluteDate<T> date) {
  132.             final T d = d(date);
  133.             return toRadians(d(date).multiply(W_DOT).add(W_0).
  134.                              add(toRadians(d.multiply(M1_DOT).add(M1_0)).sin().multiply(M1_COEFF)).
  135.                              add(toRadians(d.multiply(M2_DOT).add(M2_0)).sin().multiply(M2_COEFF)).
  136.                              add(toRadians(d.multiply(M3_DOT).add(M3_0)).sin().multiply(M3_COEFF)).
  137.                              add(toRadians(d.multiply(M4_DOT).add(M4_0)).sin().multiply(M4_COEFF)).
  138.                              add(toRadians(d.multiply(M5_DOT).add(M5_0)).sin().multiply(M5_COEFF)));
  139.         }

  140.     },

  141.     /** IAU pole and prime meridian model for Venus. */
  142.     VENUS {

  143.         /** Constant term of the prime meridian. */
  144.         private static final double W_0 = 160.20;

  145.         /** Rate term of the prime meridian. */
  146.         private static final double W_DOT = -1.4813688;

  147.         /** Fixed pole. */
  148.         private final Vector3D pole = new Vector3D(FastMath.toRadians(272.76),
  149.                                                    FastMath.toRadians(67.16));

  150.         /** {@inheritDoc} */
  151.         public Vector3D getPole(final AbsoluteDate date) {
  152.             return pole;
  153.         }

  154.         /** {@inheritDoc} */
  155.         public <T extends RealFieldElement<T>> FieldVector3D<T> getPole(final FieldAbsoluteDate<T> date) {
  156.             return new FieldVector3D<>(date.getField(), pole);
  157.         }

  158.         /** {@inheritDoc} */
  159.         public double getPrimeMeridianAngle(final AbsoluteDate date) {
  160.             return FastMath.toRadians(d(date) * W_DOT + W_0);
  161.         }

  162.         /** {@inheritDoc} */
  163.         public <T extends RealFieldElement<T>> T getPrimeMeridianAngle(final FieldAbsoluteDate<T> date) {
  164.             return toRadians(d(date).multiply(W_DOT).add(W_0));
  165.         }

  166.     },

  167.     /** IAU pole and prime meridian model for Earth. */
  168.     EARTH {

  169.         /** Constant term of the right ascension of the pole. */
  170.         private static final double ALPHA_0 =  0.00;

  171.         /** Rate term of the right ascension of the pole. */
  172.         private static final double ALPHA_DOT = -0.641;

  173.         /** Constant term of the declination of the pole. */
  174.         private static final double DELTA_0 = 90.00;

  175.         /** Rate term of the declination of the pole. */
  176.         private static final double DELTA_DOT = -0.557;

  177.         /** Constant term of the prime meridian. */
  178.         private static final double W_0 = 190.147;

  179.         /** Rate term of the prime meridian. */
  180.         private static final double W_DOT = 360.9856235;

  181.         /** {@inheritDoc} */
  182.         public Vector3D getPole(final AbsoluteDate date) {
  183.             final double t = t(date);
  184.             return new Vector3D(FastMath.toRadians(t * ALPHA_DOT + ALPHA_0),
  185.                                 FastMath.toRadians(t * DELTA_DOT + DELTA_0));
  186.         }

  187.         /** {@inheritDoc} */
  188.         public <T extends RealFieldElement<T>> FieldVector3D<T> getPole(final FieldAbsoluteDate<T> date) {
  189.             final T t = t(date);
  190.             return new FieldVector3D<>(toRadians(t.multiply(ALPHA_DOT).add(ALPHA_0)),
  191.                                        toRadians(t.multiply(DELTA_DOT).add(DELTA_0)));
  192.         }

  193.         /** {@inheritDoc} */
  194.         @Override
  195.         public Vector3D getNode(final AbsoluteDate date) {
  196.             final double t = t(date);
  197.             return new Vector3D(FastMath.toRadians(t * ALPHA_DOT + ALPHA_0 + 90.0),
  198.                                 0.0);
  199.         }

  200.         /** {@inheritDoc} */
  201.         @Override
  202.         public <T extends RealFieldElement<T>> FieldVector3D<T> getNode(final FieldAbsoluteDate<T> date) {
  203.             final T t = t(date);
  204.             return new FieldVector3D<>(toRadians(t.multiply(ALPHA_DOT).add(ALPHA_0 + 90.0)),
  205.                                        date.getField().getZero());
  206.         }

  207.         /** {@inheritDoc} */
  208.         public double getPrimeMeridianAngle(final AbsoluteDate date) {
  209.             return FastMath.toRadians(d(date) * W_DOT + W_0);
  210.         }

  211.         /** {@inheritDoc} */
  212.         public <T extends RealFieldElement<T>> T getPrimeMeridianAngle(final FieldAbsoluteDate<T> date) {
  213.             return toRadians(d(date).multiply(W_DOT).add(W_0));
  214.         }

  215.     },

  216.     /** IAU pole and prime meridian model for the Moon. */
  217.     MOON {

  218.         /** Constant term of the right ascension of the pole. */
  219.         private static final double ALPHA_0 = 269.9949;

  220.         /** Rate term of the right ascension of the pole. */
  221.         private static final double ALPHA_DOT = 0.0031;

  222.         /** Constant term of the declination of the pole. */
  223.         private static final double DELTA_0 = 66.5392;

  224.         /** Rate term of the declination of the pole. */
  225.         private static final double DELTA_DOT =  0.0130;

  226.         /** Constant term of the prime meridian. */
  227.         private static final double W_0 = 38.3213;

  228.         /** Rate term of the prime meridian. */
  229.         private static final double W_DOT = 13.17635815;

  230.         /** Rate term of the prime meridian. */
  231.         private static final double W_DOT_DOT = -1.4e-12;

  232.         /** Constant term of the E1 angle. */
  233.         private static final double E01_0    = 125.045;

  234.         /** Rate term of the E1 angle. */
  235.         private static final double E01_DOT  =  -0.0529921;

  236.         /** Sine coefficient of the E1 angle. */
  237.         private static final double E01_SIN  = -3.8787;

  238.         /** Cosine coefficient of the E1 angle. */
  239.         private static final double E01_COS  =  1.5419;

  240.         /** Sine coefficient of the E1 angle, for the prime meridian. */
  241.         private static final double E01_W_SIN =  3.5610;

  242.         /** Constant term of the E2 angle. */
  243.         private static final double E02_0    = 250.089;

  244.         /** Rate term of the E2 angle. */
  245.         private static final double E02_DOT  =  -0.1059842;

  246.         /** Sine coefficient of the E2 angle. */
  247.         private static final double E02_SIN  = -0.1204;

  248.         /** Cosine coefficient of the E2 angle. */
  249.         private static final double E02_COS  =  0.0239;

  250.         /** Sine coefficient of the E2 angle, for the prime meridian. */
  251.         private static final double E02_W_SIN =  0.1208;

  252.         /** Constant term of the E3 angle. */
  253.         private static final double E03_0    = 260.008;

  254.         /** Rate term of the E3 angle. */
  255.         private static final double E03_DOT  =  13.0120009;

  256.         /** Sine coefficient of the E3 angle. */
  257.         private static final double E03_SIN  =  0.0700;

  258.         /** Cosine coefficient of the E3 angle. */
  259.         private static final double E03_COS  = -0.0278;

  260.         /** Sine coefficient of the E3 angle, for the prime meridian. */
  261.         private static final double E03_W_SIN = -0.0642;

  262.         /** Constant term of the E4 angle. */
  263.         private static final double E04_0    = 176.625;

  264.         /** Rate term of the E4 angle. */
  265.         private static final double E04_DOT  =  13.3407154;

  266.         /** Sine coefficient of the E4 angle. */
  267.         private static final double E04_SIN  = -0.0172;

  268.         /** Cosine coefficient of the E4 angle. */
  269.         private static final double E04_COS  =  0.0068;

  270.         /** Sine coefficient of the E4 angle, for the prime meridian. */
  271.         private static final double E04_W_SIN =  0.0158;

  272.         /** Constant term of the E5 angle. */
  273.         private static final double E05_0    = 357.529;

  274.         /** Rate term of the E5 angle. */
  275.         private static final double E05_DOT  =   0.9856003;

  276.         /** Sine coefficient of the E5 angle, for the prime meridian. */
  277.         private static final double E05_W_SIN =  0.0252;

  278.         /** Constant term of the E6 angle. */
  279.         private static final double E06_0    = 311.589;

  280.         /** Rate term of the E6 angle. */
  281.         private static final double E06_DOT  =  26.4057084;

  282.         /** Sine coefficient of the E6 angle. */
  283.         private static final double E06_SIN  = 0.0072;

  284.         /** Cosine coefficient of the E6 angle. */
  285.         private static final double E06_COS  = -0.0029;

  286.         /** Sine coefficient of the E6 angle, for the prime meridian. */
  287.         private static final double E06_W_SIN = -0.0066;

  288.         /** Constant term of the E7 angle. */
  289.         private static final double E07_0    = 134.963;

  290.         /** Rate term of the E7 angle. */
  291.         private static final double E07_DOT  =  13.0649930;

  292.         /** Cosine coefficient of the E7 angle. */
  293.         private static final double E07_COS  =  0.0009;

  294.         /** Sine coefficient of the E7 angle, for the prime meridian. */
  295.         private static final double E07_W_SIN = -0.0047;

  296.         /** Constant term of the E8 angle. */
  297.         private static final double E08_0    = 276.617;

  298.         /** Rate term of the E8 angle. */
  299.         private static final double E08_DOT  =   0.3287146;

  300.         /** Sine coefficient of the E8 angle, for the prime meridian. */
  301.         private static final double E08_W_SIN = -0.0046;

  302.         /** Constant term of the E9 angle. */
  303.         private static final double E09_0    =  34.226;

  304.         /** Rate term of the E9 angle. */
  305.         private static final double E09_DOT  =   1.7484877;

  306.         /** Sine coefficient of the E9 angle, for the prime meridian. */
  307.         private static final double E09_W_SIN =  0.0028;

  308.         /** Constant term of the E10 angle. */
  309.         private static final double E10_0    =  15.134;

  310.         /** Rate term of the E10 angle. */
  311.         private static final double E10_DOT  =  -0.1589763;

  312.         /** Sine coefficient of the E10 angle. */
  313.         private static final double E10_SIN  = -0.0052;

  314.         /** Cosine coefficient of the E10 angle. */
  315.         private static final double E10_COS  = 0.0008;

  316.         /** Sine coefficient of the E10 angle, for the prime meridian. */
  317.         private static final double E10_W_SIN =  0.0052;

  318.         /** Constant term of the E11 angle. */
  319.         private static final double E11_0    = 119.743;

  320.         /** Rate term of the E11 angle. */
  321.         private static final double E11_DOT  =   0.0036096;

  322.         /** Sine coefficient of the E11 angle, for the prime meridian. */
  323.         private static final double E11_W_SIN =  0.0040;

  324.         /** Constant term of the E12 angle. */
  325.         private static final double E12_0    = 239.961;

  326.         /** Rate term of the E12 angle. */
  327.         private static final double E12_DOT  =   0.1643573;

  328.         /** Sine coefficient of the E12 angle, for the prime meridian. */
  329.         private static final double E12_W_SIN =  0.0019;

  330.         /** Constant term of the E13 angle. */
  331.         private static final double E13_0    =  25.053;

  332.         /** Rate term of the E13 angle. */
  333.         private static final double E13_DOT  =  12.9590088;

  334.         /** Sine coefficient of the E13 angle. */
  335.         private static final double E13_SIN  = 0.0043;

  336.         /** Cosine coefficient of the E13 angle. */
  337.         private static final double E13_COS  = -0.0009;

  338.         /** Sine coefficient of the E13 angle, for the prime meridian. */
  339.         private static final double E13_W_SIN = -0.0044;

  340.         /** {@inheritDoc} */
  341.         public Vector3D getPole(final AbsoluteDate date) {
  342.             final double d = d(date);
  343.             final double t = t(date);
  344.             return new Vector3D(FastMath.toRadians(t * ALPHA_DOT + ALPHA_0 +
  345.                                                    FastMath.sin(FastMath.toRadians(d * E01_DOT + E01_0)) * E01_SIN +
  346.                                                    FastMath.sin(FastMath.toRadians(d * E02_DOT + E02_0)) * E02_SIN +
  347.                                                    FastMath.sin(FastMath.toRadians(d * E03_DOT + E03_0)) * E03_SIN +
  348.                                                    FastMath.sin(FastMath.toRadians(d * E04_DOT + E04_0)) * E04_SIN +
  349.                                                    FastMath.sin(FastMath.toRadians(d * E06_DOT + E06_0)) * E06_SIN +
  350.                                                    FastMath.sin(FastMath.toRadians(d * E10_DOT + E10_0)) * E10_SIN +
  351.                                                    FastMath.sin(FastMath.toRadians(d * E13_DOT + E13_0)) * E13_SIN),
  352.                                 FastMath.toRadians(t * DELTA_DOT + DELTA_0 +
  353.                                                    FastMath.cos(FastMath.toRadians(d * E01_DOT + E01_0)) * E01_COS +
  354.                                                    FastMath.cos(FastMath.toRadians(d * E02_DOT + E02_0)) * E02_COS +
  355.                                                    FastMath.cos(FastMath.toRadians(d * E03_DOT + E03_0)) * E03_COS +
  356.                                                    FastMath.cos(FastMath.toRadians(d * E04_DOT + E04_0)) * E04_COS +
  357.                                                    FastMath.cos(FastMath.toRadians(d * E06_DOT + E06_0)) * E06_COS +
  358.                                                    FastMath.cos(FastMath.toRadians(d * E07_DOT + E07_0)) * E07_COS +
  359.                                                    FastMath.cos(FastMath.toRadians(d * E10_DOT + E10_0)) * E10_COS +
  360.                                                    FastMath.cos(FastMath.toRadians(d * E13_DOT + E13_0)) * E13_COS));
  361.         }

  362.         /** {@inheritDoc} */
  363.         public <T extends RealFieldElement<T>> FieldVector3D<T> getPole(final FieldAbsoluteDate<T> date) {
  364.             final T d = d(date);
  365.             final T t = t(date);
  366.             return new FieldVector3D<>(toRadians(t.multiply(ALPHA_DOT).add(ALPHA_0).
  367.                                                  add(toRadians(d.multiply(E01_DOT).add(E01_0)).sin().multiply(E01_SIN)).
  368.                                                  add(toRadians(d.multiply(E02_DOT).add(E02_0)).sin().multiply(E02_SIN)).
  369.                                                  add(toRadians(d.multiply(E03_DOT).add(E03_0)).sin().multiply(E03_SIN)).
  370.                                                  add(toRadians(d.multiply(E04_DOT).add(E04_0)).sin().multiply(E04_SIN)).
  371.                                                  add(toRadians(d.multiply(E06_DOT).add(E06_0)).sin().multiply(E06_SIN)).
  372.                                                  add(toRadians(d.multiply(E10_DOT).add(E10_0)).sin().multiply(E10_SIN)).
  373.                                                  add(toRadians(d.multiply(E13_DOT).add(E13_0)).sin().multiply(E13_SIN))),
  374.                                        toRadians(t.multiply(DELTA_DOT).add(DELTA_0).
  375.                                                  add(toRadians(d.multiply(E01_DOT).add(E01_0)).cos().multiply(E01_COS)).
  376.                                                  add(toRadians(d.multiply(E02_DOT).add(E02_0)).cos().multiply(E02_COS)).
  377.                                                  add(toRadians(d.multiply(E03_DOT).add(E03_0)).cos().multiply(E03_COS)).
  378.                                                  add(toRadians(d.multiply(E04_DOT).add(E04_0)).cos().multiply(E04_COS)).
  379.                                                  add(toRadians(d.multiply(E06_DOT).add(E06_0)).cos().multiply(E06_COS)).
  380.                                                  add(toRadians(d.multiply(E07_DOT).add(E07_0)).cos().multiply(E07_COS)).
  381.                                                  add(toRadians(d.multiply(E10_DOT).add(E10_0)).cos().multiply(E10_COS)).
  382.                                                  add(toRadians(d.multiply(E13_DOT).add(E13_0)).cos().multiply(E13_COS))));
  383.         }

  384.         /** {@inheritDoc} */
  385.         public double getPrimeMeridianAngle(final AbsoluteDate date) {
  386.             final double d = d(date);
  387.             return FastMath.toRadians(d * (d * W_DOT_DOT + W_DOT) + W_0 +
  388.                                       FastMath.sin(FastMath.toRadians(d * E01_DOT + E01_0)) * E01_W_SIN +
  389.                                       FastMath.sin(FastMath.toRadians(d * E02_DOT + E02_0)) * E02_W_SIN +
  390.                                       FastMath.sin(FastMath.toRadians(d * E03_DOT + E03_0)) * E03_W_SIN +
  391.                                       FastMath.sin(FastMath.toRadians(d * E04_DOT + E04_0)) * E04_W_SIN +
  392.                                       FastMath.sin(FastMath.toRadians(d * E05_DOT + E05_0)) * E05_W_SIN +
  393.                                       FastMath.sin(FastMath.toRadians(d * E06_DOT + E06_0)) * E06_W_SIN +
  394.                                       FastMath.sin(FastMath.toRadians(d * E07_DOT + E07_0)) * E07_W_SIN +
  395.                                       FastMath.sin(FastMath.toRadians(d * E08_DOT + E08_0)) * E08_W_SIN +
  396.                                       FastMath.sin(FastMath.toRadians(d * E09_DOT + E09_0)) * E09_W_SIN +
  397.                                       FastMath.sin(FastMath.toRadians(d * E10_DOT + E10_0)) * E10_W_SIN +
  398.                                       FastMath.sin(FastMath.toRadians(d * E11_DOT + E11_0)) * E11_W_SIN +
  399.                                       FastMath.sin(FastMath.toRadians(d * E12_DOT + E12_0)) * E12_W_SIN +
  400.                                       FastMath.sin(FastMath.toRadians(d * E13_DOT + E13_0)) * E13_W_SIN);
  401.         }

  402.         /** {@inheritDoc} */
  403.         public <T extends RealFieldElement<T>> T getPrimeMeridianAngle(final FieldAbsoluteDate<T> date) {
  404.             final T d = d(date);
  405.             return toRadians(d.multiply(d.multiply(W_DOT_DOT).add(W_DOT)).add(W_0).
  406.                              add(toRadians(d.multiply(E01_DOT).add(E01_0)).sin().multiply(E01_W_SIN)).
  407.                              add(toRadians(d.multiply(E02_DOT).add(E02_0)).sin().multiply(E02_W_SIN)).
  408.                              add(toRadians(d.multiply(E03_DOT).add(E03_0)).sin().multiply(E03_W_SIN)).
  409.                              add(toRadians(d.multiply(E04_DOT).add(E04_0)).sin().multiply(E04_W_SIN)).
  410.                              add(toRadians(d.multiply(E05_DOT).add(E05_0)).sin().multiply(E05_W_SIN)).
  411.                              add(toRadians(d.multiply(E06_DOT).add(E06_0)).sin().multiply(E06_W_SIN)).
  412.                              add(toRadians(d.multiply(E07_DOT).add(E07_0)).sin().multiply(E07_W_SIN)).
  413.                              add(toRadians(d.multiply(E08_DOT).add(E08_0)).sin().multiply(E08_W_SIN)).
  414.                              add(toRadians(d.multiply(E09_DOT).add(E09_0)).sin().multiply(E09_W_SIN)).
  415.                              add(toRadians(d.multiply(E10_DOT).add(E10_0)).sin().multiply(E10_W_SIN)).
  416.                              add(toRadians(d.multiply(E11_DOT).add(E11_0)).sin().multiply(E11_W_SIN)).
  417.                              add(toRadians(d.multiply(E12_DOT).add(E12_0)).sin().multiply(E12_W_SIN)).
  418.                              add(toRadians(d.multiply(E13_DOT).add(E13_0)).sin().multiply(E13_W_SIN)));
  419.         }

  420.     },

  421.     /** IAU pole and prime meridian model for Mars. */
  422.     MARS {

  423.         /** Constant term of the right ascension of the pole. */
  424.         private static final double ALPHA_0 = 317.68143;

  425.         /** Rate term of the right ascension of the pole. */
  426.         private static final double ALPHA_DOT = -0.1061;

  427.         /** Constant term of the declination of the pole. */
  428.         private static final double DELTA_0 =  52.88650;

  429.         /** Rate term of the declination of the pole. */
  430.         private static final double DELTA_DOT = -0.0609;

  431.         /** Constant term of the prime meridian. */
  432.         private static final double W_0 = 176.630;

  433.         /** Rate term of the prime meridian. */
  434.         private static final double W_DOT = 350.89198226;

  435.         /** {@inheritDoc} */
  436.         public Vector3D getPole(final AbsoluteDate date) {
  437.             final double t = t(date);
  438.             return new Vector3D(FastMath.toRadians(t * ALPHA_DOT + ALPHA_0),
  439.                                 FastMath.toRadians(t * DELTA_DOT + DELTA_0));
  440.         }

  441.         /** {@inheritDoc} */
  442.         public <T extends RealFieldElement<T>> FieldVector3D<T> getPole(final FieldAbsoluteDate<T> date) {
  443.             final T t = t(date);
  444.             return new FieldVector3D<>(toRadians(t.multiply(ALPHA_DOT).add(ALPHA_0)),
  445.                                        toRadians(t.multiply(DELTA_DOT).add(DELTA_0)));
  446.         }

  447.         /** {@inheritDoc} */
  448.         public double getPrimeMeridianAngle(final AbsoluteDate date) {
  449.             return FastMath.toRadians(d(date) * W_DOT + W_0);
  450.         }

  451.         /** {@inheritDoc} */
  452.         public <T extends RealFieldElement<T>> T getPrimeMeridianAngle(final FieldAbsoluteDate<T> date) {
  453.             return toRadians(d(date).multiply(W_DOT).add(W_0));
  454.         }

  455.     },

  456.     /** IAU pole and prime meridian model for Jupiter. */
  457.     JUPITER {

  458.         /** Constant term of the right ascension of the pole. */
  459.         private static final double ALPHA_0 = 268.056595;

  460.         /** Rate term of the right ascension of the pole. */
  461.         private static final double ALPHA_DOT = -0.006499;

  462.         /** Constant term of the declination of the pole. */
  463.         private static final double DELTA_0 = 64.495303;

  464.         /** Rate term of the declination of the pole. */
  465.         private static final double DELTA_DOT = 0.002413;

  466.         /** Constant term of the ja angle. */
  467.         private static final double JA_0 =  99.360714;

  468.         /** Rate term of the ja angle. */
  469.         private static final double JA_DOT = 4850.4046;

  470.         /** Sine coefficient of the ja angle. */
  471.         private static final double JA_SIN = 0.000117;

  472.         /** Cosine coefficient of the ja angle. */
  473.         private static final double JA_COS = 0.000050;

  474.         /** Constant term of the jb angle. */
  475.         private static final double JB_0 = 175.895369;

  476.         /** Rate term of the jb angle. */
  477.         private static final double JB_DOT = 1191.9605;

  478.         /** Sine coefficient of the jb angle. */
  479.         private static final double JB_SIN = 0.000938;

  480.         /** Cosine coefficient of the jb angle. */
  481.         private static final double JB_COS = 0.000404;

  482.         /** Constant term of the jc angle. */
  483.         private static final double JC_0 = 300.323162;

  484.         /** Rate term of the jc angle. */
  485.         private static final double JC_DOT = 262.5475;

  486.         /** Sine coefficient of the jc angle. */
  487.         private static final double JC_SIN = 0.001432;

  488.         /** Cosine coefficient of the jc angle. */
  489.         private static final double JC_COS = 0.000617;

  490.         /** Constant term of the jd angle. */
  491.         private static final double JD_0 = 114.012305;

  492.         /** Rate term of the jd angle. */
  493.         private static final double JD_DOT = 6070.2476;

  494.         /** Sine coefficient of the jd angle. */
  495.         private static final double JD_SIN = 0.000030;

  496.         /** Cosine coefficient of the jd angle. */
  497.         private static final double JD_COS = -0.000013;

  498.         /** Constant term of the je angle. */
  499.         private static final double JE_0 = 49.511251;

  500.         /** Rate term of the je angle. */
  501.         private static final double JE_DOT = 64.3000;

  502.         /** Sine coefficient of the je angle. */
  503.         private static final double JE_SIN = 0.002150;

  504.         /** Cosine coefficient of the je angle. */
  505.         private static final double JE_COS = 0.000926;

  506.         /** Constant term of the prime meridian. */
  507.         private static final double W_0 = 284.95;

  508.         /** Rate term of the prime meridian. */
  509.         private static final double W_DOT = 870.5360000;

  510.         /** {@inheritDoc} */
  511.         public Vector3D getPole(final AbsoluteDate date) {

  512.             final double t = t(date);
  513.             final double ja = FastMath.toRadians(t * JA_DOT + JA_0);
  514.             final double jb = FastMath.toRadians(t * JB_DOT + JB_0);
  515.             final double jc = FastMath.toRadians(t * JC_DOT + JC_0);
  516.             final double jd = FastMath.toRadians(t * JD_DOT + JD_0);
  517.             final double je = FastMath.toRadians(t * JE_DOT + JE_0);

  518.             return new Vector3D(FastMath.toRadians(t * ALPHA_DOT + ALPHA_0 +
  519.                                                    FastMath.sin(ja) * JA_SIN +
  520.                                                    FastMath.sin(jb) * JB_SIN +
  521.                                                    FastMath.sin(jc) * JC_SIN +
  522.                                                    FastMath.sin(jd) * JD_SIN +
  523.                                                    FastMath.sin(je) * JE_SIN),
  524.                                 FastMath.toRadians(t * DELTA_DOT + DELTA_0 +
  525.                                                    FastMath.cos(ja) * JA_COS +
  526.                                                    FastMath.cos(jb) * JB_COS +
  527.                                                    FastMath.cos(jc) * JC_COS +
  528.                                                    FastMath.cos(jd) * JD_COS +
  529.                                                    FastMath.cos(je) * JE_COS));
  530.         }

  531.         /** {@inheritDoc} */
  532.         public <T extends RealFieldElement<T>> FieldVector3D<T> getPole(final FieldAbsoluteDate<T> date) {

  533.             final T t = t(date);
  534.             final T ja = toRadians(t.multiply(JA_DOT).add(JA_0));
  535.             final T jb = toRadians(t.multiply(JB_DOT).add(JB_0));
  536.             final T jc = toRadians(t.multiply(JC_DOT).add(JC_0));
  537.             final T jd = toRadians(t.multiply(JD_DOT).add(JD_0));
  538.             final T je = toRadians(t.multiply(JE_DOT).add(JE_0));

  539.             return new FieldVector3D<>(toRadians(t.multiply(ALPHA_DOT).add(ALPHA_0).
  540.                                                  add(ja.sin().multiply(JA_SIN)).
  541.                                                  add(jb.sin().multiply(JB_SIN)).
  542.                                                  add(jc.sin().multiply(JC_SIN)).
  543.                                                  add(jd.sin().multiply(JD_SIN)).
  544.                                                  add(je.sin().multiply(JE_SIN))),
  545.                                        toRadians(t.multiply(DELTA_DOT).add(DELTA_0).
  546.                                                  add(ja.cos().multiply(JA_COS)).
  547.                                                  add(jb.cos().multiply(JB_COS)).
  548.                                                  add(jc.cos().multiply(JC_COS)).
  549.                                                  add(jd.cos().multiply(JD_COS)).
  550.                                                  add(je.cos().multiply(JE_COS))));

  551.         }

  552.         /** {@inheritDoc} */
  553.         public double getPrimeMeridianAngle(final AbsoluteDate date) {
  554.             return FastMath.toRadians(d(date) * W_DOT + W_0);
  555.         }

  556.         /** {@inheritDoc} */
  557.         public <T extends RealFieldElement<T>> T getPrimeMeridianAngle(final FieldAbsoluteDate<T> date) {
  558.             return toRadians(d(date).multiply(W_DOT).add(W_0));
  559.         }

  560.     },

  561.     /** IAU pole and prime meridian model for Saturn. */
  562.     SATURN {

  563.         /** Constant term of the right ascension of the pole. */
  564.         private static final double ALPHA_0 = 40.589;

  565.         /** Rate term of the right ascension of the pole. */
  566.         private static final double ALPHA_DOT = -0.036;

  567.         /** Constant term of the declination of the pole. */
  568.         private static final double DELTA_0 = 83.537;

  569.         /** Rate term of the declination of the pole. */
  570.         private static final double DELTA_DOT = -0.004;

  571.         /** Constant term of the prime meridian. */
  572.         private static final double W_0 = 38.90;

  573.         /** Rate term of the prime meridian. */
  574.         private static final double W_DOT = 810.7939024;

  575.         /** {@inheritDoc} */
  576.         public Vector3D getPole(final AbsoluteDate date) {
  577.             final double t = t(date);
  578.             return new Vector3D(FastMath.toRadians(t * ALPHA_DOT + ALPHA_0),
  579.                                 FastMath.toRadians(t * DELTA_DOT + DELTA_0));
  580.         }

  581.         /** {@inheritDoc} */
  582.         public <T extends RealFieldElement<T>> FieldVector3D<T> getPole(final FieldAbsoluteDate<T> date) {
  583.             final T t = t(date);
  584.             return new FieldVector3D<>(toRadians(t.multiply(ALPHA_DOT).add(ALPHA_0)),
  585.                                        toRadians(t.multiply(DELTA_DOT).add(DELTA_0)));
  586.         }

  587.         /** {@inheritDoc} */
  588.         public double getPrimeMeridianAngle(final AbsoluteDate date) {
  589.             return FastMath.toRadians(d(date) * W_DOT + W_0);
  590.         }

  591.         /** {@inheritDoc} */
  592.         public <T extends RealFieldElement<T>> T getPrimeMeridianAngle(final FieldAbsoluteDate<T> date) {
  593.             return toRadians(d(date).multiply(W_DOT).add(W_0));
  594.         }

  595.     },

  596.     /** IAU pole and prime meridian model for Uranus. */
  597.     URANUS {

  598.         /** Constant term of the prime meridian. */
  599.         private static final double W_0 = 203.81;

  600.         /** Rate term of the prime meridian. */
  601.         private static final double W_DOT = -501.1600928;

  602.         /** Fixed pole. */
  603.         private final Vector3D pole = new Vector3D(FastMath.toRadians(257.311),
  604.                                                    FastMath.toRadians(-15.175));

  605.         /** {@inheritDoc} */
  606.         public Vector3D getPole(final AbsoluteDate date) {
  607.             return pole;
  608.         }

  609.         /** {@inheritDoc} */
  610.         public <T extends RealFieldElement<T>> FieldVector3D<T> getPole(final FieldAbsoluteDate<T> date) {
  611.             return new FieldVector3D<>(date.getField(), pole);
  612.         }

  613.         /** {@inheritDoc} */
  614.         public double getPrimeMeridianAngle(final AbsoluteDate date) {
  615.             return FastMath.toRadians(d(date) * W_DOT + W_0);
  616.         }

  617.         /** {@inheritDoc} */
  618.         public <T extends RealFieldElement<T>> T getPrimeMeridianAngle(final FieldAbsoluteDate<T> date) {
  619.             return toRadians(d(date).multiply(W_DOT).add(W_0));
  620.         }

  621.     },

  622.     /** IAU pole and prime meridian model for Neptune. */
  623.     NEPTUNE {

  624.         /** Constant term of the right ascension of the pole. */
  625.         private static final double ALPHA_0 = 299.36;

  626.         /** Sine term of the right ascension of the pole. */
  627.         private static final double ALPHA_SIN = 0.70;

  628.         /** Constant term of the declination of the pole. */
  629.         private static final double DELTA_0 = 43.46;

  630.         /** Cosine term of the declination of the pole. */
  631.         private static final double DELTA_COS = -0.51;

  632.         /** Constant term of the prime meridian. */
  633.         private static final double W_0 = 253.18;

  634.         /** Rate term of the prime meridian. */
  635.         private static final double W_DOT = 536.3128492;

  636.         /** Sine term of the prime meridian. */
  637.         private static final double W_SIN = -0.48;

  638.         /** Constant term of the N angle. */
  639.         private static final double N_0   = 357.85;

  640.         /** Rate term of the M1 angle. */
  641.         private static final double N_DOT = 52.316;

  642.         /** {@inheritDoc} */
  643.         public Vector3D getPole(final AbsoluteDate date) {
  644.             final double n = FastMath.toRadians(t(date) * N_DOT + N_0);
  645.             return new Vector3D(FastMath.toRadians(FastMath.sin(n) * ALPHA_SIN + ALPHA_0),
  646.                                 FastMath.toRadians(FastMath.cos(n) * DELTA_COS + DELTA_0));
  647.         }

  648.         /** {@inheritDoc} */
  649.         public <T extends RealFieldElement<T>> FieldVector3D<T> getPole(final FieldAbsoluteDate<T> date) {
  650.             final T n = toRadians(t(date).multiply(N_DOT).add(N_0));
  651.             return new FieldVector3D<>(toRadians(n.sin().multiply(ALPHA_SIN).add(ALPHA_0)),
  652.                                        toRadians(n.cos().multiply(DELTA_COS).add(DELTA_0)));
  653.         }

  654.         /** {@inheritDoc} */
  655.         public double getPrimeMeridianAngle(final AbsoluteDate date) {
  656.             final double n = FastMath.toRadians(t(date) * N_DOT + N_0);
  657.             return FastMath.toRadians(d(date) * W_DOT + FastMath.sin(n) * W_SIN + W_0);
  658.         }

  659.         /** {@inheritDoc} */
  660.         public <T extends RealFieldElement<T>> T getPrimeMeridianAngle(final FieldAbsoluteDate<T> date) {
  661.             final T n = toRadians(t(date).multiply(N_DOT).add(N_0));
  662.             return toRadians(d(date).multiply(W_DOT).add(n.sin().multiply(W_SIN)).add(W_0));
  663.         }

  664.     },

  665.     /** IAU pole and prime meridian model for Pluto. */
  666.     PLUTO {

  667.         /** Constant term of the prime meridian. */
  668.         private static final double W_0 = 302.695;

  669.         /** Rate term of the prime meridian. */
  670.         private static final double W_DOT = 56.3625225;

  671.         /** Fixed pole. */
  672.         private final Vector3D pole = new Vector3D(FastMath.toRadians(132.993),
  673.                                                    FastMath.toRadians(-6.163));

  674.         /** {@inheritDoc} */
  675.         public Vector3D getPole(final AbsoluteDate date) {
  676.             return pole;
  677.         }

  678.         /** {@inheritDoc} */
  679.         public <T extends RealFieldElement<T>> FieldVector3D<T> getPole(final FieldAbsoluteDate<T> date) {
  680.             return new FieldVector3D<>(date.getField(), pole);
  681.         }

  682.         /** {@inheritDoc} */
  683.         public double getPrimeMeridianAngle(final AbsoluteDate date) {
  684.             return FastMath.toRadians(d(date) * W_DOT + W_0);
  685.         }

  686.         /** {@inheritDoc} */
  687.         public <T extends RealFieldElement<T>> T getPrimeMeridianAngle(final FieldAbsoluteDate<T> date) {
  688.             return toRadians(d(date).multiply(W_DOT).add(W_0));
  689.         }

  690.     },

  691.     /** Default IAUPole implementation for barycenters.
  692.      * <p>
  693.      * This implementation defines directions such that the inertially oriented and body
  694.      * oriented frames are identical and aligned with GCRF. It is used for example
  695.      * to define the ICRF.
  696.      * </p>
  697.      */
  698.     GCRF_ALIGNED {

  699.         /** {@inheritDoc} */
  700.         public Vector3D getPole(final AbsoluteDate date) {
  701.             return Vector3D.PLUS_K;
  702.         }

  703.         /** {@inheritDoc} */
  704.         public <T extends RealFieldElement<T>> FieldVector3D<T> getPole(final FieldAbsoluteDate<T> date) {
  705.             return FieldVector3D.getPlusK(date.getField());
  706.         }

  707.         /** {@inheritDoc} */
  708.         @Override
  709.         public Vector3D getNode(final AbsoluteDate date) {
  710.             return Vector3D.PLUS_I;
  711.         }

  712.         /** {@inheritDoc} */
  713.         @Override
  714.         public <T extends RealFieldElement<T>> FieldVector3D<T> getNode(final FieldAbsoluteDate<T> date) {
  715.             return FieldVector3D.getPlusI(date.getField());
  716.         }

  717.         /** {@inheritDoc} */
  718.         public double getPrimeMeridianAngle(final AbsoluteDate date) {
  719.             return 0;
  720.         }

  721.         /** {@inheritDoc} */
  722.         public <T extends RealFieldElement<T>> T getPrimeMeridianAngle(final FieldAbsoluteDate<T> date) {
  723.             return date.getField().getZero();
  724.         }

  725.     };


  726.     /** Get a predefined IAU pole.
  727.      * @param body body identifier
  728.      * @return predefined IAU pole
  729.      */
  730.     public static PredefinedIAUPoles getIAUPole(final JPLEphemeridesLoader.EphemerisType body) {
  731.         switch(body) {
  732.             case SUN :
  733.                 return SUN;
  734.             case MERCURY :
  735.                 return MERCURY;
  736.             case VENUS :
  737.                 return VENUS;
  738.             case EARTH :
  739.                 return EARTH;
  740.             case MOON :
  741.                 return MOON;
  742.             case MARS :
  743.                 return MARS;
  744.             case JUPITER :
  745.                 return JUPITER;
  746.             case SATURN :
  747.                 return SATURN;
  748.             case URANUS :
  749.                 return URANUS;
  750.             case NEPTUNE :
  751.                 return NEPTUNE;
  752.             case PLUTO :
  753.                 return PLUTO;
  754.             default :
  755.                 return GCRF_ALIGNED;
  756.         }
  757.     }

  758.     /** Compute the interval in julian centuries from standard epoch.
  759.      * @param date date
  760.      * @return interval between date and standard epoch in julian centuries
  761.      */
  762.     private static double t(final AbsoluteDate date) {
  763.         return date.offsetFrom(AbsoluteDate.J2000_EPOCH, TimeScalesFactory.getTDB()) / Constants.JULIAN_CENTURY;
  764.     }

  765.     /** Compute the interval in julian centuries from standard epoch.
  766.      * @param date date
  767.      * @param <T> type of the filed elements
  768.      * @return interval between date and standard epoch in julian centuries
  769.      */
  770.     private static <T extends RealFieldElement<T>> T t(final FieldAbsoluteDate<T> date) {
  771.         return date.offsetFrom(FieldAbsoluteDate.getJ2000Epoch(date.getField()), TimeScalesFactory.getTDB()).divide(Constants.JULIAN_CENTURY);
  772.     }

  773.     /** Compute the interval in julian days from standard epoch.
  774.      * @param date date
  775.      * @return interval between date and standard epoch in julian days
  776.      */
  777.     private static double d(final AbsoluteDate date) {
  778.         return date.offsetFrom(AbsoluteDate.J2000_EPOCH, TimeScalesFactory.getTDB()) / Constants.JULIAN_DAY;
  779.     }

  780.     /** Compute the interval in julian days from standard epoch.
  781.      * @param date date
  782.      * @param <T> type of the filed elements
  783.      * @return interval between date and standard epoch in julian days
  784.      */
  785.     private static <T extends RealFieldElement<T>> T d(final FieldAbsoluteDate<T> date) {
  786.         return date.offsetFrom(FieldAbsoluteDate.getJ2000Epoch(date.getField()), TimeScalesFactory.getTDB()).divide(Constants.JULIAN_DAY);
  787.     }

  788.     /** Convert an angle to radians.
  789.      * @param angleInDegrees angle in degrees
  790.      * @param <T> type of the filed elements
  791.      * @return angle in radians
  792.      */
  793.     private static <T extends RealFieldElement<T>> T toRadians(final T angleInDegrees) {
  794.         return angleInDegrees.multiply(FastMath.PI / 180);
  795.     }

  796. }