TimeDependentHarmonic.java

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

  18. import org.hipparchus.util.SinCos;

  19. /** Time-dependent part of a single component of spherical harmonics.
  20.  * @author Luc Maisonobe
  21.  * @since 11.1
  22.  */
  23. class TimeDependentHarmonic {

  24.     /** Index of the trend reference in the gravity field. */
  25.     private final int trendReferenceIndex;

  26.     /** Base of the cosine coefficient. */
  27.     private final double cBase;

  28.     /** Base of the sine coefficient. */
  29.     private final double sBase;

  30.     /** Secular trend of the cosine coefficient. */
  31.     private double cTrend;

  32.     /** Secular trend of the sine coefficient. */
  33.     private double sTrend;

  34.     /** Indices of the reference dates in the gravity field. */
  35.     private int[] cosReferenceIndices;

  36.     /** Indices of the harmonic pulsations in the gravity field. */
  37.     private int[] cosPulsationIndices;

  38.     /** Cosine component of the cosine coefficient. */
  39.     private double[] cosC;

  40.     /** Cosine component of the sine coefficient. */
  41.     private double[] cosS;

  42.     /** Indices of the reference dates in the gravity field. */
  43.     private int[] sinReferenceIndices;

  44.     /** Indices of the harmonic pulsations in the gravity field. */
  45.     private int[] sinPulsationIndices;

  46.     /** Sine component of the cosine coefficient. */
  47.     private double[] sinC;

  48.     /** Sine component of the sine coefficient. */
  49.     private double[] sinS;

  50.     /** Build a part with only base.
  51.      * @param trendReferenceIndex index of the trend reference in the gravity field
  52.      * @param cBase base of the cosine coefficient
  53.      * @param sBase base of the sine coefficient
  54.      */
  55.     TimeDependentHarmonic(final int trendReferenceIndex, final double cBase, final double sBase) {
  56.         this(trendReferenceIndex, cBase, sBase, 0, 0);
  57.     }

  58.     /** Build a rescaled component.
  59.      * @param scale scaling factor to apply to all coefficients elements
  60.      * @param original original component
  61.      */
  62.     TimeDependentHarmonic(final double scale, final TimeDependentHarmonic original) {

  63.         // rescale base
  64.         this(original.trendReferenceIndex, scale * original.cBase, scale * original.sBase,
  65.              original.cosReferenceIndices.length, original.sinReferenceIndices.length);

  66.         // rescale trend
  67.         cTrend = scale * original.cTrend;
  68.         sTrend = scale * original.sTrend;

  69.         // rescale cosine
  70.         for (int i = 0; i < cosReferenceIndices.length; ++i) {
  71.             cosReferenceIndices[i] = original.cosReferenceIndices[i];
  72.             cosPulsationIndices[i] = original.cosPulsationIndices[i];
  73.             cosC[i]                = scale * original.cosC[i];
  74.             cosS[i]                = scale * original.cosS[i];
  75.         }

  76.         // rescale sine
  77.         for (int i = 0; i < sinReferenceIndices.length; ++i) {
  78.             sinReferenceIndices[i] = original.sinReferenceIndices[i];
  79.             sinPulsationIndices[i] = original.sinPulsationIndices[i];
  80.             sinC[i]                = scale * original.sinC[i];
  81.             sinS[i]                = scale * original.sinS[i];
  82.         }

  83.     }

  84.     /** Build a part with only base.
  85.      * @param trendReferenceIndex index of the trend reference in the gravity field
  86.      * @param cBase base of the cosine coefficient
  87.      * @param sBase base of the sine coefficient
  88.      * @param cSize initial size of the cosine arrays
  89.      * @param sSize initial size of the sine arrays
  90.      */
  91.     private TimeDependentHarmonic(final int trendReferenceIndex, final double cBase, final double sBase,
  92.                                   final int cSize, final int sSize) {

  93.         // linear part
  94.         this.trendReferenceIndex = trendReferenceIndex;
  95.         this.cBase               = cBase;
  96.         this.sBase               = sBase;
  97.         this.cTrend              = 0.0;
  98.         this.sTrend              = 0.0;

  99.         // cosine component
  100.         this.cosReferenceIndices = new int[cSize];
  101.         this.cosPulsationIndices = new int[cSize];
  102.         this.cosC                = new double[cSize];
  103.         this.cosS                = new double[cSize];

  104.         // sine component
  105.         this.sinReferenceIndices = new int[sSize];
  106.         this.sinPulsationIndices = new int[sSize];
  107.         this.sinC                = new double[sSize];
  108.         this.sinS                = new double[sSize];

  109.     }

  110.     /** Set the trend part.
  111.      * @param cDot secular trend of the cosine coefficient (s⁻¹)
  112.      * @param sDot secular trend of the sine coefficient (s⁻¹)
  113.      */
  114.     public void setTrend(final double cDot, final double sDot) {
  115.         this.cTrend = cDot;
  116.         this.sTrend = sDot;
  117.     }

  118.     /** Add a cosine component.
  119.      * @param cosReferenceIndex index of the reference date in the gravity field
  120.      * (if negative, use the trend reference index)
  121.      * @param cosPulsationIndex index of the harmonic pulsation in the gravity field
  122.      * @param cosineC cosine component of the cosine coefficient
  123.      * @param cosineS cosine component of the sine coefficient
  124.      */
  125.     public void addCosine(final int cosReferenceIndex, final int cosPulsationIndex,
  126.                           final double cosineC, final double cosineS) {
  127.         final int refIndex = cosReferenceIndex < 0 ? trendReferenceIndex : cosReferenceIndex;
  128.         this.cosReferenceIndices = addInt(refIndex, this.cosReferenceIndices);
  129.         this.cosPulsationIndices = addInt(cosPulsationIndex, this.cosPulsationIndices);
  130.         this.cosC                = addDouble(cosineC,     this.cosC);
  131.         this.cosS                = addDouble(cosineS,     this.cosS);
  132.     }

  133.     /** Add a sine component.
  134.      * @param sinReferenceIndex index of the reference date in the gravity field
  135.      * (if negative, use the trend reference index)
  136.      * @param sinPulsationIndex index of the harmonic pulsation in the gravity field
  137.      * @param sineC sine component of the cosine coefficient
  138.      * @param sineS sine component of the sine coefficient
  139.      */
  140.     public void addSine(final int sinReferenceIndex, final int sinPulsationIndex,
  141.                         final double sineC, final double sineS) {
  142.         final int refIndex = sinReferenceIndex < 0 ? trendReferenceIndex : sinReferenceIndex;
  143.         this.sinReferenceIndices = addInt(refIndex, this.sinReferenceIndices);
  144.         this.sinPulsationIndices = addInt(sinPulsationIndex, this.sinPulsationIndices);
  145.         this.sinC                = addDouble(sineC,       this.sinC);
  146.         this.sinS                = addDouble(sineS,       this.sinS);
  147.     }

  148.     /** Add an integer to an array.
  149.      * <p>
  150.      * Expanding the array one element at a time may seem a waste of time,
  151.      * but we expect the array to be 0, 1 or 2 elements long only, and this
  152.      * if performed only when reading gravity field, so its is worth doing
  153.      * it this way.
  154.      * </p>
  155.      * @param n integer to add
  156.      * @param array array where to add the integer
  157.      * @return new array
  158.      */
  159.     private static int[] addInt(final int n, final int[] array) {
  160.         final int[] newArray = new int[array.length + 1];
  161.         System.arraycopy(array, 0, newArray, 0, array.length);
  162.         newArray[array.length] = n;
  163.         return newArray;
  164.     }

  165.     /** Add a double number to an array.
  166.      * <p>
  167.      * Expanding the array one element at a time may seem a waste of time,
  168.      * but we expect the array to be 0, 1 or 2 elements long only, and this
  169.      * if performed only when reading gravity field, so its is worth doing
  170.      * it this way.
  171.      * </p>
  172.      * @param d double number to add
  173.      * @param array array where to add the double number
  174.      * @return new array
  175.      */
  176.     private static double[] addDouble(final double d, final double[] array) {
  177.         final double[] newArray = new double[array.length + 1];
  178.         System.arraycopy(array, 0, newArray, 0, array.length);
  179.         newArray[array.length] = d;
  180.         return newArray;
  181.     }

  182.     /** Compute the time-dependent part of a spherical harmonic cosine coefficient.
  183.      * @param offsets offsets to reference dates in the gravity field
  184.      * @param pulsations angular pulsations in the gravity field
  185.      * @return raw coefficient Cnm
  186.      */
  187.     public double computeCnm(final double[] offsets, final SinCos[][] pulsations) {

  188.         // trend effect
  189.         double cnm = cBase + offsets[trendReferenceIndex] * cTrend;

  190.         for (int i = 0; i < cosPulsationIndices.length; ++i) {
  191.             // cosine effect
  192.             cnm += cosC[i] * pulsations[cosReferenceIndices[i]][cosPulsationIndices[i]].cos();
  193.         }

  194.         for (int i = 0; i < sinPulsationIndices.length; ++i) {
  195.             // sine effect
  196.             cnm += sinC[i] * pulsations[sinReferenceIndices[i]][sinPulsationIndices[i]].sin();
  197.         }

  198.         return cnm;

  199.     }

  200.     /** Compute the time-dependent part of a spherical harmonic sine coefficient.
  201.      * @param offsets offsets to reference dates in the gravity field
  202.      * @param pulsations angular pulsations in the gravity field
  203.      * @return raw coefficient Snm
  204.      */
  205.     public double computeSnm(final double[] offsets, final SinCos[][] pulsations) {

  206.         // trend effect
  207.         double snm = sBase + offsets[trendReferenceIndex] * sTrend;

  208.         for (int i = 0; i < cosPulsationIndices.length; ++i) {
  209.             // cosine effect
  210.             snm += cosS[i] * pulsations[cosReferenceIndices[i]][cosPulsationIndices[i]].cos();
  211.         }

  212.         for (int i = 0; i < sinPulsationIndices.length; ++i) {
  213.             // sine effect
  214.             snm += sinS[i] * pulsations[sinReferenceIndices[i]][sinPulsationIndices[i]].sin();
  215.         }

  216.         return snm;

  217.     }

  218. }