1   /* Copyright 2002-2024 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.troposphere;
18  
19  import java.util.Collections;
20  import java.util.List;
21  
22  import org.hipparchus.CalculusFieldElement;
23  import org.hipparchus.Field;
24  import org.hipparchus.util.FastMath;
25  import org.hipparchus.util.MathArrays;
26  import org.orekit.bodies.FieldGeodeticPoint;
27  import org.orekit.bodies.GeodeticPoint;
28  import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity;
29  import org.orekit.models.earth.weather.PressureTemperatureHumidity;
30  import org.orekit.time.AbsoluteDate;
31  import org.orekit.time.FieldAbsoluteDate;
32  import org.orekit.time.TimeScale;
33  import org.orekit.utils.FieldTrackingCoordinates;
34  import org.orekit.utils.ParameterDriver;
35  import org.orekit.utils.TrackingCoordinates;
36  
37  /** The Vienna 1 tropospheric delay model for radio techniques.
38   * The Vienna model data are given with a time interval of 6 hours
39   * as well as on a global 2.5° * 2.0° grid.
40   *
41   * This version considered the height correction for the hydrostatic part
42   * developed by Niell, 1996.
43   *
44   * @see "Boehm, J., Werl, B., and Schuh, H., (2006),
45   *       Troposhere mapping functions for GPS and very long baseline
46   *       interferometry from European Centre for Medium-Range Weather
47   *       Forecasts operational analysis data, J. Geophy. Res., Vol. 111,
48   *       B02406, doi:10.1029/2005JB003629"
49   * @since 12.1
50   * @author Bryan Cazabonne
51   * @author Luc Maisonobe
52   */
53  public class ViennaOne extends AbstractVienna {
54  
55      /** Build a new instance.
56       * @param aProvider provider for a<sub>h</sub> and a<sub>w</sub> coefficients
57       * @param gProvider provider for {@link AzimuthalGradientCoefficients} and {@link FieldAzimuthalGradientCoefficients}
58       * @param zenithDelayProvider provider for zenith delays
59       * @param utc                 UTC time scale
60       */
61      public ViennaOne(final ViennaAProvider aProvider,
62                       final AzimuthalGradientProvider gProvider,
63                       final TroposphericModel zenithDelayProvider,
64                       final TimeScale utc) {
65          super(aProvider, gProvider, zenithDelayProvider, utc);
66      }
67  
68      /** {@inheritDoc} */
69      @Override
70      public double[] mappingFactors(final TrackingCoordinates trackingCoordinates,
71                                     final GeodeticPoint point,
72                                     final PressureTemperatureHumidity weather,
73                                     final AbsoluteDate date) {
74  
75          // a coefficients
76          final ViennaACoefficients a = getAProvider().getA(point, date);
77  
78          // Day of year computation
79          final int dofyear = getDayOfYear(date);
80  
81          // General constants | Hydrostatic part
82          final double bh  = 0.0029;
83          final double c0h = 0.062;
84          final double c10h;
85          final double c11h;
86          final double psi;
87  
88          // Latitude of the station
89          final double latitude = point.getLatitude();
90  
91          // sin(latitude) > 0 -> northern hemisphere
92          if (FastMath.sin(latitude) > 0) {
93              c10h = 0.001;
94              c11h = 0.005;
95              psi  = 0;
96          } else {
97              c10h = 0.002;
98              c11h = 0.007;
99              psi  = FastMath.PI;
100         }
101 
102         // Temporal factor
103         double t0 = 28;
104         if (latitude < 0) {
105             // southern hemisphere: t0 = 28 + an integer half of year
106             t0 += 183;
107         }
108         // Compute hydrostatique coefficient c
109         final double coef = ((dofyear - t0) / 365) * 2 * FastMath.PI + psi;
110         final double ch = c0h + ((FastMath.cos(coef) + 1) * (c11h / 2) + c10h) * (1 - FastMath.cos(latitude));
111 
112         // General constants | Wet part
113         final double bw = 0.00146;
114         final double cw = 0.04391;
115 
116         final double[] function = new double[2];
117         function[0] = TroposphericModelUtils.mappingFunction(a.getAh(), bh, ch,
118                                                              trackingCoordinates.getElevation());
119         function[1] = TroposphericModelUtils.mappingFunction(a.getAw(), bw, cw,
120                                                              trackingCoordinates.getElevation());
121 
122         // Apply height correction
123         final double correction = TroposphericModelUtils.computeHeightCorrection(trackingCoordinates.getElevation(),
124                                                                                  point.getAltitude());
125         function[0] = function[0] + correction;
126 
127         return function;
128     }
129 
130     /** {@inheritDoc} */
131     @Override
132     public <T extends CalculusFieldElement<T>> T[] mappingFactors(final FieldTrackingCoordinates<T> trackingCoordinates,
133                                                                   final FieldGeodeticPoint<T> point,
134                                                                   final FieldPressureTemperatureHumidity<T> weather,
135                                                                   final FieldAbsoluteDate<T> date) {
136 
137         final Field<T> field = date.getField();
138         final T zero = field.getZero();
139 
140         // a coefficients
141         final FieldViennaACoefficients<T> a = getAProvider().getA(point, date);
142 
143         // Day of year computation
144         final int dofyear = getDayOfYear(date.toAbsoluteDate());
145 
146         // General constants | Hydrostatic part
147         final T bh  = zero.newInstance(0.0029);
148         final T c0h = zero.newInstance(0.062);
149         final T c10h;
150         final T c11h;
151         final T psi;
152 
153         // Latitude and longitude of the station
154         final T latitude = point.getLatitude();
155 
156         // sin(latitude) > 0 -> northern hemisphere
157         if (FastMath.sin(latitude.getReal()) > 0) {
158             c10h = zero.newInstance(0.001);
159             c11h = zero.newInstance(0.005);
160             psi  = zero;
161         } else {
162             c10h = zero.newInstance(0.002);
163             c11h = zero.newInstance(0.007);
164             psi  = zero.getPi();
165         }
166 
167         // Compute hydrostatique coefficient c
168         // Temporal factor
169         double t0 = 28;
170         if (latitude.getReal() < 0) {
171             // southern hemisphere: t0 = 28 + an integer half of year
172             t0 += 183;
173         }
174         final T coef = psi.add(zero.getPi().multiply(2.0).multiply((dofyear - t0) / 365));
175         final T ch = c11h.divide(2.0).multiply(FastMath.cos(coef).add(1.0)).add(c10h).multiply(FastMath.cos(latitude).negate().add(1.)).add(c0h);
176 
177         // General constants | Wet part
178         final T bw = zero.newInstance(0.00146);
179         final T cw = zero.newInstance(0.04391);
180 
181         final T[] function = MathArrays.buildArray(field, 2);
182         function[0] = TroposphericModelUtils.mappingFunction(a.getAh(), bh, ch,
183                                                              trackingCoordinates.getElevation());
184         function[1] = TroposphericModelUtils.mappingFunction(a.getAw(), bw, cw,
185                                                              trackingCoordinates.getElevation());
186 
187         // Apply height correction
188         final T correction = TroposphericModelUtils.computeHeightCorrection(trackingCoordinates.getElevation(),
189                                                                             point.getAltitude(),
190                                                                             field);
191         function[0] = function[0].add(correction);
192 
193         return function;
194     }
195 
196     /** {@inheritDoc} */
197     @Override
198     public List<ParameterDriver> getParametersDrivers() {
199         return Collections.emptyList();
200     }
201 
202 }