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.hipparchus.util.SinCos;
21  import org.orekit.time.AbsoluteDate;
22  import org.orekit.utils.TimeSpanMap;
23  
24  /** Piecewise gravity fields with time-dependent models in each interval.
25   * @author Luc Maisonobe
26   * @since 11.1
27   */
28  class PiecewiseSphericalHarmonics implements RawSphericalHarmonicsProvider {
29  
30      /** Constant part of the field. */
31      private final ConstantSphericalHarmonics constant;
32  
33      /** Reference dates. */
34      private final AbsoluteDate[] references;
35  
36      /** Pulsations (rad/s). */
37      private final double[] pulsations;
38  
39      /** Piecewise parts. */
40      private final TimeSpanMap<PiecewisePart> pieces;
41  
42      /** Maximum supported degree. */
43      private final int maxDegree;
44  
45      /** Maximum supported order. */
46      private final int maxOrder;
47  
48      /** Simple constructor.
49       * @param constant constant part of the field
50       * @param references references dates
51       * @param pulsations pulsations (rad/s)
52       * @param pieces piecewise parts
53       */
54      PiecewiseSphericalHarmonics(final ConstantSphericalHarmonics constant,
55                                  final AbsoluteDate[] references, final double[] pulsations,
56                                  final TimeSpanMap<PiecewisePart> pieces) {
57          this.constant   = constant;
58          this.references = references.clone();
59          this.pulsations = pulsations.clone();
60          this.pieces     = pieces;
61  
62          // get limits
63          int d = constant.getMaxDegree();
64          int o = constant.getMaxOrder();
65          for (TimeSpanMap.Span<PiecewisePart> span = pieces.getFirstSpan(); span != null; span = span.next()) {
66              final PiecewisePart piece = span.getData();
67              if (piece != null) {
68                  d = FastMath.max(d, piece.getMaxDegree());
69                  o = FastMath.max(o, piece.getMaxOrder());
70              }
71          }
72          this.maxDegree = d;
73          this.maxOrder  = o;
74  
75      }
76  
77      /** Get the constant part of the field.
78       * @return constant part of the field
79       */
80      public ConstantSphericalHarmonics getConstant() {
81          return constant;
82      }
83  
84      /** {@inheritDoc} */
85      public int getMaxDegree() {
86          return maxDegree;
87      }
88  
89      /** {@inheritDoc} */
90      public int getMaxOrder() {
91          return maxOrder;
92      }
93  
94      /** {@inheritDoc} */
95      public double getMu() {
96          return constant.getMu();
97      }
98  
99      /** {@inheritDoc} */
100     public double getAe() {
101         return constant.getAe();
102     }
103 
104     /** {@inheritDoc} */
105     public AbsoluteDate getReferenceDate() {
106         AbsoluteDate last = AbsoluteDate.PAST_INFINITY;
107         for (final AbsoluteDate date : references) {
108             if (date.isAfter(last)) {
109                 last = date;
110             }
111         }
112         return last;
113     }
114 
115     /** {@inheritDoc} */
116     @Deprecated
117     public double getOffset(final AbsoluteDate date) {
118         return date.durationFrom(references[0]);
119     }
120 
121     /** {@inheritDoc} */
122     public TideSystem getTideSystem() {
123         return constant.getTideSystem();
124     }
125 
126     /** Get the raw spherical harmonic coefficients on a specific date.
127      * @param date to evaluate the spherical harmonics
128      * @return the raw spherical harmonics on {@code date}.
129      */
130     public RawSphericalHarmonics onDate(final AbsoluteDate date) {
131 
132         // raw (constant) harmonics
133         final RawSphericalHarmonics raw = constant.onDate(date);
134 
135         // select part of the piecewise model that is active at specified date
136         final PiecewisePart piece = pieces.get(date);
137 
138         // pre-compute canonical functions
139         final double[]   offsets = new double[references.length];
140         final SinCos[][] sinCos  = new SinCos[references.length][pulsations.length];
141         for (int i = 0; i < references.length; ++i) {
142             final double offset = date.durationFrom(references[i]);
143             offsets[i] = offset;
144             for (int j = 0; j < pulsations.length; ++j) {
145                 sinCos[i][j] = FastMath.sinCos(offset * pulsations[j]);
146             }
147         }
148 
149         return new RawSphericalHarmonics() {
150 
151             @Override
152             public AbsoluteDate getDate() {
153                 return date;
154             }
155 
156             /** {@inheritDoc} */
157             public double getRawCnm(final int n, final int m) {
158                 return raw.getRawCnm(n, m) + piece.computeCnm(n, m, offsets, sinCos);
159             }
160 
161             /** {@inheritDoc} */
162             public double getRawSnm(final int n, final int m) {
163                 return raw.getRawSnm(n, m) + piece.computeSnm(n, m, offsets, sinCos);
164             }
165 
166         };
167 
168     }
169 
170 }