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.models.earth.weather;
18  
19  import org.hipparchus.util.FastMath;
20  import org.hipparchus.util.SinCos;
21  import org.orekit.annotation.DefaultDataContext;
22  import org.orekit.bodies.GeodeticPoint;
23  import org.orekit.data.DataContext;
24  import org.orekit.models.earth.Geoid;
25  import org.orekit.models.earth.troposphere.TroposphericModelUtils;
26  import org.orekit.time.AbsoluteDate;
27  import org.orekit.time.DateTimeComponents;
28  import org.orekit.time.TimeScale;
29  import org.orekit.utils.LegendrePolynomials;
30  
31  /** The Global Pressure and Temperature model.
32   * This model is an empirical model that provides the temperature and the pressure depending
33   * the latitude and the longitude of the station.
34   * <p>
35   * The Global Pressure and Temperature model is based on spherical harmonics up
36   * to degree and order of 9. The residual values ​​of this model can reach 20 hPa
37   * for pressure and 10 ° C for temperature. They are significant for higher latitudes and
38   * small near the equator (Böhm, 2007)
39   * </p>
40   *
41   * @see "J. Böhm, R. Heinkelmann, and H. Schuh (2007),
42   * Short Note: A global model of pressure and temperature for geodetic applications. J Geod,
43   * doi:10.1007/s00190-007-0135-3."
44   *
45   * @author Bryan Cazabonne
46   * @author Luc Maisonobe
47   * @since 12.1
48   */
49  public class GlobalPressureTemperature {
50  
51      /** Temperature gradient (°C/m). */
52      private static final double TEMPERATURE_GRADIENT = -6.5e-3;
53  
54      /** Spherical harmonics degree. */
55      private static final int DEGREE = 9;
56  
57      /** Spherical harmonics order. */
58      private static final int ORDER = 9;
59  
60      /** Geoid used to compute the undulations. */
61      private final Geoid geoid;
62  
63      /** UTC time scale. */
64      private final TimeScale utc;
65  
66      /** Build a new instance.
67       *
68       * <p>This method uses the {@link DataContext#getDefault() default data context}.
69       *
70       * @param geoid level surface of the gravity potential of a body
71       * @see #GlobalPressureTemperature(Geoid, TimeScale)
72       */
73      @DefaultDataContext
74      public GlobalPressureTemperature(final Geoid geoid) {
75          this(geoid, DataContext.getDefault().getTimeScales().getUTC());
76      }
77  
78      /** Build a new instance.
79       * @param geoid level surface of the gravity potential of a body
80       * @param utc UTC time scale.
81       */
82      public GlobalPressureTemperature(final Geoid geoid, final TimeScale utc) {
83          this.geoid = geoid;
84          this.utc   = utc;
85      }
86  
87      /** Provide weather parameters.
88       * @param location location at which parameters are requested
89       * @param date date at which parameters are requested
90       * @return weather parameters
91       */
92      public PressureTemperature getWeatherParameters(final GeodeticPoint location, final AbsoluteDate date) {
93  
94          // Day of year computation
95          final DateTimeComponents dtc = date.getComponents(utc);
96          final int dofyear = dtc.getDate().getDayOfYear();
97  
98          // Reference day: 28 January 1980 (Niell, 1996)
99          final int t0 = 28;
100         final double coef = ((dofyear + 1 - t0) / 365.25) * 2 * FastMath.PI;
101         final double cosCoef = FastMath.cos(coef);
102 
103         // Compute Legendre Polynomials Pnm(sin(phi))
104         final LegendrePolynomials p = new LegendrePolynomials(DEGREE, ORDER,
105                                                               FastMath.sin(location.getLatitude()));
106 
107         // Corrected height
108         final double correctedheight = FastMath.max(0.0,
109                                                     location.getAltitude() - geoid.getUndulation(location.getLatitude(),
110                                                                                                  location.getLongitude(),
111                                                                                                  date));
112 
113         // Eq. 4 (Ref)
114         double meanT0      = 0.0;
115         double amplitudeT0 = 0.0;
116         double meanP0      = 0.0;
117         double amplitudeP0 = 0.0;
118         final ABCoefficients abCoef = new ABCoefficients();
119         int j = 0;
120         for (int n = 0; n <= DEGREE; n++) {
121             for (int m = 0; m <= n; m++) {
122                 final SinCos sc = FastMath.sinCos(m * location.getLongitude());
123                 final double pCosmLambda = p.getPnm(n, m) * sc.cos();
124                 final double pSinmLambda = p.getPnm(n, m) * sc.sin();
125 
126                 meanT0      = meanT0 +
127                                 (abCoef.getAnmTemperatureMean(j) * pCosmLambda + abCoef.getBnmTemperatureMean(j) * pSinmLambda);
128                 amplitudeT0 = amplitudeT0 +
129                                 (abCoef.getAnmTemperatureAmpl(j) * pCosmLambda + abCoef.getBnmTemperatureAmpl(j) * pSinmLambda);
130                 meanP0      = meanP0 +
131                                 (abCoef.getAnmPressureMean(j) * pCosmLambda + abCoef.getBnmPressureMean(j) * pSinmLambda);
132                 amplitudeP0 = amplitudeP0 +
133                                 (abCoef.getAnmPressureAmpl(j) * pCosmLambda + abCoef.getBnmPressureAmpl(j) * pSinmLambda);
134 
135                 j = j + 1;
136             }
137         }
138 
139         // Eq. 3 (Ref)
140         final double temp0 = meanT0 + amplitudeT0 * cosCoef;
141         final double pres0 = meanP0 + amplitudeP0 * cosCoef;
142 
143         // Compute pressure and temperature Eq. 1 and 2 (Ref)
144         final double degrees = temp0 + TEMPERATURE_GRADIENT * correctedheight;
145         final double temperature = degrees + 273.15;
146         final double pressure    = pres0 * FastMath.pow(1.0 - correctedheight * 0.0000226, 5.225);
147 
148         return new PressureTemperature(location.getAltitude(),
149                                        TroposphericModelUtils.HECTO_PASCAL.toSI(pressure),
150                                        temperature);
151 
152     }
153 
154     private static class ABCoefficients {
155 
156         /** Mean A<sub>nm</sub> coefficients for the pressure. */
157         private static final double[] A_PRESSURE_MEAN = {
158             1.0108e+03,
159             8.4886e+00,
160             1.4799e+00,
161             -1.3897e+01,
162             3.7516e-03,
163             -1.4936e-01,
164             1.2232e+01,
165             -7.6615e-01,
166             -6.7699e-02,
167             8.1002e-03,
168             -1.5874e+01,
169             3.6614e-01,
170             -6.7807e-02,
171             -3.6309e-03,
172             5.9966e-04,
173             4.8163e+00,
174             -3.7363e-01,
175             -7.2071e-02,
176             1.9998e-03,
177             -6.2385e-04,
178             -3.7916e-04,
179             4.7609e+00,
180             -3.9534e-01,
181             8.6667e-03,
182             1.1569e-02,
183             1.1441e-03,
184             -1.4193e-04,
185             -8.5723e-05,
186             6.5008e-01,
187             -5.0889e-01,
188             -1.5754e-02,
189             -2.8305e-03,
190             5.7458e-04,
191             3.2577e-05,
192             -9.6052e-06,
193             -2.7974e-06,
194             1.3530e+00,
195             -2.7271e-01,
196             -3.0276e-04,
197             3.6286e-03,
198             -2.0398e-04,
199             1.5846e-05,
200             -7.7787e-06,
201             1.1210e-06,
202             9.9020e-08,
203             5.5046e-01,
204             -2.7312e-01,
205             3.2532e-03,
206             -2.4277e-03,
207             1.1596e-04,
208             2.6421e-07,
209             -1.3263e-06,
210             2.7322e-07,
211             1.4058e-07,
212             4.9414e-09
213         };
214 
215         /** Mean B<sub>nm</sub> coefficients for the pressure. */
216         private static final double[] B_PRESSURE_MEAN = {
217             0.0000e+00,
218             0.0000e+00,
219             -1.2878e+00,
220             0.0000e+00,
221             7.0444e-01,
222             3.3222e-01,
223             0.0000e+00,
224             -2.9636e-01,
225             7.2248e-03,
226             7.9655e-03,
227             0.0000e+00,
228             1.0854e+00,
229             1.1145e-02,
230             -3.6513e-02,
231             3.1527e-03,
232             0.0000e+00,
233             -4.8434e-01,
234             5.2023e-02,
235             -1.3091e-02,
236             1.8515e-03,
237             1.5422e-04,
238             0.0000e+00,
239             6.8298e-01,
240             2.5261e-03,
241             -9.9703e-04,
242             -1.0829e-03,
243             +1.7688e-04,
244             -3.1418e-05,
245             +0.0000e+00,
246             -3.7018e-01,
247             4.3234e-02,
248             7.2559e-03,
249             3.1516e-04,
250             2.0024e-05,
251             -8.0581e-06,
252             -2.3653e-06,
253             0.0000e+00,
254             1.0298e-01,
255             -1.5086e-02,
256             5.6186e-03,
257             3.2613e-05,
258             4.0567e-05,
259             -1.3925e-06,
260             -3.6219e-07,
261             -2.0176e-08,
262             0.0000e+00,
263             -1.8364e-01,
264             1.8508e-02,
265             7.5016e-04,
266             -9.6139e-05,
267             -3.1995e-06,
268             1.3868e-07,
269             -1.9486e-07,
270             3.0165e-10,
271             -6.4376e-10
272         };
273 
274         /** Amplitude A<sub>nm</sub> coefficients for the pressure. */
275         private static final double[] A_PRESSURE_AMPLITUDE = {
276             -1.0444e-01,
277             1.6618e-01,
278             -6.3974e-02,
279             1.0922e+00,
280             5.7472e-01,
281             -3.0277e-01,
282             -3.5087e+00,
283             7.1264e-03,
284             -1.4030e-01,
285             3.7050e-02,
286             4.0208e-01,
287             -3.0431e-01,
288             -1.3292e-01,
289             4.6746e-03,
290             -1.5902e-04,
291             2.8624e+00,
292             -3.9315e-01,
293             -6.4371e-02,
294             1.6444e-02,
295             -2.3403e-03,
296             4.2127e-05,
297             1.9945e+00,
298             -6.0907e-01,
299             -3.5386e-02,
300             -1.0910e-03,
301             -1.2799e-04,
302             4.0970e-05,
303             2.2131e-05,
304             -5.3292e-01,
305             -2.9765e-01,
306             -3.2877e-02,
307             1.7691e-03,
308             5.9692e-05,
309             3.1725e-05,
310             2.0741e-05,
311             -3.7622e-07,
312             2.6372e+00,
313             -3.1165e-01,
314             1.6439e-02,
315             2.1633e-04,
316             1.7485e-04,
317             2.1587e-05,
318             6.1064e-06,
319             -1.3755e-08,
320             -7.8748e-08,
321             -5.9152e-01,
322             -1.7676e-01,
323             8.1807e-03,
324             1.0445e-03,
325             2.3432e-04,
326             9.3421e-06,
327             2.8104e-06,
328             -1.5788e-07,
329             -3.0648e-08,
330             2.6421e-10
331         };
332 
333         /** Amplitude B<sub>nm</sub> coefficients for the pressure. */
334         private static final double[] B_PRESSURE_AMPLITUDE = {
335             0.0000e+00,
336             0.0000e+00,
337             9.3340e-01,
338             0.0000e+00,
339             8.2346e-01,
340             2.2082e-01,
341             0.0000e+00,
342             9.6177e-01,
343             -1.5650e-02,
344             1.2708e-03,
345             0.0000e+00,
346             -3.9913e-01,
347             2.8020e-02,
348             2.8334e-02,
349             8.5980e-04,
350             0.0000e+00,
351             3.0545e-01,
352             -2.1691e-02,
353             6.4067e-04,
354             -3.6528e-05,
355             -1.1166e-04,
356             0.0000e+00,
357             -7.6974e-02,
358             -1.8986e-02,
359             +5.6896e-03,
360             -2.4159e-04,
361             -2.3033e-04,
362             -9.6783e-06,
363             0.0000e+00,
364             -1.0218e-01,
365             -1.3916e-02,
366             -4.1025e-03,
367             -5.1340e-05,
368             -7.0114e-05,
369             -3.3152e-07,
370             1.6901e-06,
371             0.0000e+00,
372             -1.2422e-02,
373             +2.5072e-03,
374             +1.1205e-03,
375             -1.3034e-04,
376             -2.3971e-05,
377             -2.6622e-06,
378             5.7852e-07,
379             4.5847e-08,
380             0.0000e+00,
381             4.4777e-02,
382             -3.0421e-03,
383             2.6062e-05,
384             -7.2421e-05,
385             1.9119e-06,
386             3.9236e-07,
387             2.2390e-07,
388             2.9765e-09,
389             -4.6452e-09
390         };
391 
392         /** Mean A<sub>nm</sub> coefficients for the temperature. */
393         private static final double[] A_TEMPERATURE_MEAN = {
394             1.6257e+01,
395             2.1224e+00,
396             9.2569e-01,
397             -2.5974e+01,
398             1.4510e+00,
399             9.2468e-02,
400             -5.3192e-01,
401             2.1094e-01,
402             -6.9210e-02,
403             -3.4060e-02,
404             -4.6569e+00,
405             2.6385e-01,
406             -3.6093e-02,
407             1.0198e-02,
408             -1.8783e-03,
409             7.4983e-01,
410             1.1741e-01,
411             3.9940e-02,
412             5.1348e-03,
413             5.9111e-03,
414             8.6133e-06,
415             6.3057e-01,
416             1.5203e-01,
417             3.9702e-02,
418             4.6334e-03,
419             2.4406e-04,
420             1.5189e-04,
421             1.9581e-07,
422             5.4414e-01,
423             3.5722e-01,
424             5.2763e-02,
425             4.1147e-03,
426             -2.7239e-04,
427             -5.9957e-05,
428             1.6394e-06,
429             -7.3045e-07,
430             -2.9394e+00,
431             5.5579e-02,
432             1.8852e-02,
433             3.4272e-03,
434             -2.3193e-05,
435             -2.9349e-05,
436             3.6397e-07,
437             2.0490e-06,
438             -6.4719e-08,
439             -5.2225e-01,
440             2.0799e-01,
441             1.3477e-03,
442             3.1613e-04,
443             -2.2285e-04,
444             -1.8137e-05,
445             -1.5177e-07,
446             6.1343e-07,
447             7.8566e-08,
448             1.0749e-09
449         };
450 
451         /** Mean B<sub>nm</sub> coefficients for the temperature. */
452         private static final double[] B_TEMPERATURE_MEAN = {
453             0.0000e+00,
454             0.0000e+00,
455             1.0210e+00,
456             0.0000e+00,
457             6.0194e-01,
458             1.2292e-01,
459             0.0000e+00,
460             -4.2184e-01,
461             1.8230e-01,
462             4.2329e-02,
463             0.0000e+00,
464             9.3312e-02,
465             9.5346e-02,
466             -1.9724e-03,
467             5.8776e-03,
468             0.0000e+00,
469             -2.0940e-01,
470             3.4199e-02,
471             -5.7672e-03,
472             -2.1590e-03,
473             5.6815e-04,
474             0.0000e+00,
475             2.2858e-01,
476             1.2283e-02,
477             -9.3679e-03,
478             -1.4233e-03,
479             -1.5962e-04,
480             4.0160e-05,
481             0.0000e+00,
482             3.6353e-02,
483             -9.4263e-04,
484             -3.6762e-03,
485             5.8608e-05,
486             -2.6391e-05,
487             3.2095e-06,
488             -1.1605e-06,
489             0.0000e+00,
490             1.6306e-01,
491             1.3293e-02,
492             -1.1395e-03,
493             5.1097e-05,
494             3.3977e-05,
495             7.6449e-06,
496             -1.7602e-07,
497             -7.6558e-08,
498             0.0000e+00,
499             -4.5415e-02,
500             -1.8027e-02,
501             3.6561e-04,
502             -1.1274e-04,
503             1.3047e-05,
504             2.0001e-06,
505             -1.5152e-07,
506             -2.7807e-08,
507             7.7491e-09
508         };
509 
510         /** Amplitude A<sub>nm</sub> coefficients for the temperature. */
511         private static final double[] A_TEMPERATURE_AMPLITUDE = {
512             -1.8654e+00,
513             -9.0041e+00,
514             -1.2974e-01,
515             -3.6053e+00,
516             2.0284e-02,
517             2.1872e-01,
518             -1.3015e+00,
519             4.0355e-01,
520             2.2216e-01,
521             -4.0605e-03,
522             1.9623e+00,
523             4.2887e-01,
524             2.1437e-01,
525             -1.0061e-02,
526             -1.1368e-03,
527             -6.9235e-02,
528             5.6758e-01,
529             1.1917e-01,
530             -7.0765e-03,
531             3.0017e-04,
532             3.0601e-04,
533             1.6559e+00,
534             2.0722e-01,
535             6.0013e-02,
536             1.7023e-04,
537             -9.2424e-04,
538             1.1269e-05,
539             -6.9911e-06,
540             -2.0886e+00,
541             -6.7879e-02,
542             -8.5922e-04,
543             -1.6087e-03,
544             -4.5549e-05,
545             3.3178e-05,
546             -6.1715e-06,
547             -1.4446e-06,
548             -3.7210e-01,
549             1.5775e-01,
550             -1.7827e-03,
551             -4.4396e-04,
552             2.2844e-04,
553             -1.1215e-05,
554             -2.1120e-06,
555             -9.6421e-07,
556             -1.4170e-08,
557             7.8720e-01,
558             -4.4238e-02,
559             -1.5120e-03,
560             -9.4119e-04,
561             4.0645e-06,
562             -4.9253e-06,
563             -1.8656e-06,
564             -4.0736e-07,
565             -4.9594e-08,
566             1.6134e-09
567         };
568 
569         /** Amplitude B<sub>nm</sub> coefficients for the temperature. */
570         private static final double[] B_TEMPERATURE_AMPLITUDE = {
571             0.0000e+00,
572             0.0000e+00,
573             -8.9895e-01,
574             0.0000e+00,
575             -1.0790e+00,
576             -1.2699e-01,
577             0.0000e+00,
578             -5.9033e-01,
579             3.4865e-02,
580             -3.2614e-02,
581             0.0000e+00,
582             -2.4310e-02,
583             1.5607e-02,
584             -2.9833e-02,
585             -5.9048e-03,
586             0.0000e+00,
587             2.8383e-01,
588             4.0509e-02,
589             -1.8834e-02,
590             -1.2654e-03,
591             -1.3794e-04,
592             0.0000e+00,
593             1.3306e-01,
594             3.4960e-02,
595             -3.6799e-03,
596             -3.5626e-04,
597             1.4814e-04,
598             3.7932e-06,
599             0.0000e+00,
600             2.0801e-01,
601             6.5640e-03,
602             -3.4893e-03,
603             -2.7395e-04,
604             7.4296e-05,
605             -7.9927e-06,
606             -1.0277e-06,
607             0.0000e+00,
608             3.6515e-02,
609             -7.4319e-03,
610             -6.2873e-04,
611             8.2461e-05,
612             3.1095e-05,
613             -5.3860e-07,
614             -1.2055e-07,
615             -1.1517e-07,
616             0.0000e+00,
617             3.1404e-02,
618             1.5580e-02,
619             -1.1428e-03,
620             3.3529e-05,
621             1.0387e-05,
622             -1.9378e-06,
623             -2.7327e-07,
624             7.5833e-09,
625             -9.2323e-09
626         };
627 
628         /** Build a new instance. */
629         ABCoefficients() {
630 
631         }
632 
633         /** Get the value of the mean A<sub>nm</sub> pressure coefficient for the given index.
634          * @param index index
635          * @return the mean A<sub>nm</sub> pressure coefficient for the given index
636          */
637         public double getAnmPressureMean(final int index) {
638             return A_PRESSURE_MEAN[index];
639         }
640 
641         /** Get the value of the mean B<sub>nm</sub> pressure coefficient for the given index.
642          * @param index index
643          * @return the mean B<sub>nm</sub> pressure coefficient for the given index
644          */
645         public double getBnmPressureMean(final int index) {
646             return B_PRESSURE_MEAN[index];
647         }
648 
649         /** Get the value of the amplitude A<sub>nm</sub> pressure coefficient for the given index.
650          * @param index index
651          * @return the amplitude A<sub>nm</sub> pressure coefficient for the given index.
652          */
653         public double getAnmPressureAmpl(final int index) {
654             return A_PRESSURE_AMPLITUDE[index];
655         }
656 
657         /** Get the value of the amplitude B<sub>nm</sub> pressure coefficient for the given index.
658          * @param index index
659          * @return the amplitude B<sub>nm</sub> pressure coefficient for the given index
660          */
661         public double getBnmPressureAmpl(final int index) {
662             return B_PRESSURE_AMPLITUDE[index];
663         }
664 
665         /** Get the value of the mean A<sub>nm</sub> temperature coefficient for the given index.
666          * @param index index
667          * @return the mean A<sub>nm</sub> temperature coefficient for the given index
668          */
669         public double getAnmTemperatureMean(final int index) {
670             return A_TEMPERATURE_MEAN[index];
671         }
672 
673         /** Get the value of the mean B<sub>nm</sub> temperature coefficient for the given index.
674          * @param index index
675          * @return the mean B<sub>nm</sub> temperature coefficient for the given index
676          */
677         public double getBnmTemperatureMean(final int index) {
678             return B_TEMPERATURE_MEAN[index];
679         }
680 
681         /** Get the value of the amplitude A<sub>nm</sub> temperature coefficient for the given index.
682          * @param index index
683          * @return the amplitude A<sub>nm</sub> temperature coefficient for the given index.
684          */
685         public double getAnmTemperatureAmpl(final int index) {
686             return A_TEMPERATURE_AMPLITUDE[index];
687         }
688 
689         /** Get the value of the amplitude B<sub>nm</sub> temperature coefficient for the given index.
690          * @param index index
691          * @return the amplitude B<sub>nm</sub> temperature coefficient for the given index
692          */
693         public double getBnmTemperatureAmpl(final int index) {
694             return B_TEMPERATURE_AMPLITUDE[index];
695         }
696     }
697 
698 }