1   /* Copyright 2002-2022 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  
19  import org.hipparchus.util.FastMath;
20  import org.orekit.time.AbsoluteDate;
21  
22  /** Simple implementation of {@link RawSphericalHarmonicsProvider} for gravity fields with secular trend.
23   * @author Luc Maisonobe
24   * @since 6.0
25   */
26  class SecularTrendSphericalHarmonics implements RawSphericalHarmonicsProvider {
27  
28      /** Non-secular part of the field. */
29      private final RawSphericalHarmonicsProvider provider;
30  
31      /** Reference date for the harmonics. */
32      private final AbsoluteDate referenceDate;
33  
34      /** Converter from triangular to flatten array.
35       * @since 11.1
36       */
37      private final Flattener flattener;
38  
39      /** Secular trend of the cosine coefficients. */
40      private final double[] cTrend;
41  
42      /** Secular trend of the sine coefficients. */
43      private final double[] sTrend;
44  
45      /** Simple constructor.
46       * @param provider underlying provider for the non secular part
47       * @param referenceDate reference date for the harmonics (considered to be at 12:00 TT)
48       * @param cTrend secular trend of the cosine coefficients (s<sup>-1</sup>)
49       * @param sTrend secular trend of the sine coefficients (s<sup>-1</sup>)
50       * @deprecated as of 11.1, replaced by {@link #SecularTrendSphericalHarmonics(RawSphericalHarmonicsProvider,
51       * AbsoluteDate, Flattener, double[], double[])
52       */
53      @Deprecated
54      SecularTrendSphericalHarmonics(final RawSphericalHarmonicsProvider provider,
55                                     final AbsoluteDate referenceDate,
56                                     final double[][] cTrend, final double[][] sTrend) {
57          this(provider, referenceDate, buildFlattener(cTrend),
58               buildFlattener(cTrend).flatten(cTrend), buildFlattener(sTrend).flatten(sTrend));
59      }
60  
61      /** Simple constructor.
62       * @param provider underlying provider for the non secular part
63       * @param referenceDate reference date for the harmonics (considered to be at 12:00 TT)
64       * @param flattener flattener from triangular to flatten array
65       * @param cTrend secular trend of the cosine coefficients (s<sup>-1</sup>)
66       * @param sTrend secular trend of the sine coefficients (s<sup>-1</sup>)
67       * @since 11.1
68       */
69      SecularTrendSphericalHarmonics(final RawSphericalHarmonicsProvider provider, final AbsoluteDate referenceDate,
70                                     final Flattener flattener, final double[] cTrend, final double[] sTrend) {
71          this.provider      = provider;
72          this.referenceDate = referenceDate;
73          this.flattener     = flattener;
74          this.cTrend        = cTrend.clone();
75          this.sTrend        = sTrend.clone();
76      }
77  
78      /** Get a flattener for a triangular array.
79       * @param triangular triangular array to flatten
80       * @return flattener suited for triangular array dimensions
81       * @since 11.1
82       */
83      private static Flattener buildFlattener(final double[][] triangular) {
84          return new Flattener(triangular.length - 1, triangular[triangular.length - 1].length - 1);
85      }
86  
87      /** {@inheritDoc} */
88      public int getMaxDegree() {
89          return FastMath.max(flattener.getDegree(), provider.getMaxDegree());
90      }
91  
92      /** {@inheritDoc} */
93      public int getMaxOrder() {
94          return FastMath.max(flattener.getOrder(), provider.getMaxOrder());
95      }
96  
97      /** {@inheritDoc} */
98      public double getMu() {
99          return provider.getMu();
100     }
101 
102     /** {@inheritDoc} */
103     public double getAe() {
104         return provider.getAe();
105     }
106 
107     /** {@inheritDoc} */
108     public AbsoluteDate getReferenceDate() {
109         return referenceDate;
110     }
111 
112     /** {@inheritDoc} */
113     @Deprecated
114     public double getOffset(final AbsoluteDate date) {
115         return date.durationFrom(referenceDate);
116     }
117 
118     /** {@inheritDoc} */
119     public TideSystem getTideSystem() {
120         return provider.getTideSystem();
121     }
122 
123     @Override
124     public RawSphericalHarmonics onDate(final AbsoluteDate date) {
125         final RawSphericalHarmonics harmonics = provider.onDate(date);
126         //compute date offset from reference
127         final double dateOffset = date.durationFrom(referenceDate);
128         return new RawSphericalHarmonics() {
129 
130             @Override
131             public AbsoluteDate getDate() {
132                 return date;
133             }
134 
135             /** {@inheritDoc} */
136             public double getRawCnm(final int n, final int m) {
137 
138                 // retrieve the constant part of the coefficient
139                 double cnm = harmonics.getRawCnm(n, m);
140 
141                 if (flattener.withinRange(n, m)) {
142                     // add secular trend
143                     cnm += dateOffset * cTrend[flattener.index(n, m)];
144                 }
145 
146                 return cnm;
147 
148             }
149 
150             /** {@inheritDoc} */
151             public double getRawSnm(final int n, final int m) {
152 
153                 // retrieve the constant part of the coefficient
154                 double snm = harmonics.getRawSnm(n, m);
155 
156                 if (flattener.withinRange(n, m)) {
157                     // add secular trend
158                     snm += dateOffset * sTrend[flattener.index(n, m)];
159                 }
160 
161                 return snm;
162 
163             }
164 
165         };
166     }
167 
168 }