1   /* Copyright 2022-2025 Thales Alenia Space
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.models.earth.weather;
18  
19  import java.util.HashMap;
20  import java.util.Map;
21  
22  import org.hipparchus.CalculusFieldElement;
23  import org.hipparchus.util.FieldSinCos;
24  import org.hipparchus.util.MathUtils;
25  import org.hipparchus.util.SinCos;
26  
27  /** Grid entry in Global Pressure Temperature models.
28   * @author Luc Maisonobe
29   * @since 12.1
30   */
31  class GridEntry {
32  
33      /** Conversion factor from degrees to mill arcseconds. */
34      public static final int DEG_TO_MAS = 3600000;
35  
36      /** Latitude (radian). */
37      private final double latitude;
38  
39      /** Latitude key (mas). */
40      private final int latKey;
41  
42      /** Longitude (radian). */
43      private final double longitude;
44  
45      /** Longitude key (mas). */
46      private final int lonKey;
47  
48      /** Undulation. */
49      private final double undulation;
50  
51      /** Height correction. */
52      private final double hS;
53  
54      /** Seasonal models. */
55      private final Map<SeasonalModelType, SeasonalModel> models;
56  
57      /** Build an entry from its components.
58       * @param latitude latitude (radian)
59       * @param latKey latitude key (mas)
60       * @param longitude longitude (radian)
61       * @param lonKey longitude key (mas)
62       * @param undulation undulation (m)
63       * @param hS height correction
64       * @param models seasonal models
65       */
66      GridEntry(final double latitude, final int latKey, final double longitude, final int lonKey,
67                final double undulation, final double hS, final Map<SeasonalModelType, SeasonalModel> models) {
68  
69          this.latitude     = latitude;
70          this.latKey       = latKey;
71          this.longitude    = longitude;
72          this.lonKey       = lonKey;
73          this.undulation   = undulation;
74          this.hS           = hS;
75          this.models       = models;
76      }
77  
78      /** Build a new entry 360° to the East of instance.
79       * @return new wrapping entry (always same type as instance)
80       */
81      public GridEntry buildWrappedEntry() {
82          return new GridEntry(latitude, latKey,
83                               longitude + MathUtils.TWO_PI,
84                               lonKey + DEG_TO_MAS * 360,
85                               undulation, hS,
86                               models);
87      }
88  
89      /** Get latitude (radian).
90       * @return latitude (radian)
91       */
92      public double getLatitude() {
93          return latitude;
94      }
95  
96      /** Get latitude key (mas).
97       * @return latitude key (mas)
98       */
99      public int getLatKey() {
100         return latKey;
101     }
102 
103     /** Get longitude (radian).
104      * @return longitude (radian)
105      */
106     public double getLongitude() {
107         return longitude;
108     }
109 
110     /** Get longitude key (mas).
111      * @return longitude key (mas)
112      */
113     public int getLonKey() {
114         return lonKey;
115     }
116 
117     /** Get undulation.
118      * @return undulation
119      */
120     public double getUndulation() {
121         return undulation;
122     }
123 
124     /** Get height correction.
125      * @return height correction
126      */
127     public double getHs() {
128         return hS;
129     }
130 
131     /** Check if an entry has a model.
132      * @param type model type
133      * @return true if the entry has the model
134      * @since 13.0
135      */
136     public boolean hasModel(final SeasonalModelType type) {
137         return models.containsKey(type);
138     }
139 
140     /** Evaluate the entry at one date.
141      * @param sc1 sine and cosine of yearly harmonic term
142      * @param sc2 sine and cosine of bi-yearly harmonic term
143      * @param altitude altitude
144      * @return evaluated entry
145      */
146     public EvaluatedGridEntry evaluate(final SinCos sc1, final SinCos sc2, final double altitude) {
147 
148         // evaluate all models
149         final Map<SeasonalModelType, Double> evaluatedModels = new HashMap<>(models.size());
150         for (final Map.Entry<SeasonalModelType, SeasonalModel> entry : models.entrySet()) {
151             evaluatedModels.put(entry.getKey(), entry.getValue().evaluate(sc1, sc2));
152         }
153 
154         // build the evaluated grid entry
155         return new EvaluatedGridEntry(this, altitude, evaluatedModels);
156 
157     }
158 
159     /** Evaluate the entry at one date.
160      * @param <T> type of the field elements
161      * @param sc1 sine and cosine of yearly harmonic term
162      * @param sc2 sine and cosine of bi-yearly harmonic term
163      * @param altitude altitude
164      * @return evaluated entry
165      */
166     public <T extends CalculusFieldElement<T>> FieldEvaluatedGridEntry<T> evaluate(final FieldSinCos<T> sc1,
167                                                                                    final FieldSinCos<T> sc2,
168                                                                                    final T altitude) {
169 
170         // evaluate all models
171         final Map<SeasonalModelType, T> evaluatedModels = new HashMap<>(models.size());
172         for (final Map.Entry<SeasonalModelType, SeasonalModel> entry : models.entrySet()) {
173             evaluatedModels.put(entry.getKey(), entry.getValue().evaluate(sc1, sc2));
174         }
175 
176         // build the evaluated grid entry
177         return new FieldEvaluatedGridEntry<>(this, altitude, evaluatedModels);
178 
179     }
180 
181 }