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.util.FastMath;
24  import org.hipparchus.util.FieldSinCos;
25  import org.hipparchus.util.SinCos;
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 tropospheric delay model for radio techniques.
38   * @since 12.1
39   * @author Bryan Cazabonne
40   * @author Luc Maisonobe
41   */
42  public abstract class AbstractVienna implements TroposphericModel, TroposphereMappingFunction {
43  
44      /** C coefficient from Chen and Herring gradient mapping function.
45       * @see Modeling tropospheric delays for space geodetic techniques, Daniel Landskron, 2017, section 2.2
46       */
47      private static final double C = 0.0032;
48  
49      /** Provider for a<sub>h</sub> and a<sub>w</sub> coefficients. */
50      private final ViennaAProvider aProvider;
51  
52      /** Provider for {@link AzimuthalGradientCoefficients} and {@link FieldAzimuthalGradientCoefficients}. */
53      private final AzimuthalGradientProvider gProvider;
54  
55      /** Provider for zenith delays. */
56      private final TroposphericModel zenithDelayProvider;
57  
58      /** UTC time scale. */
59      private final TimeScale utc;
60  
61      /** Build a new instance.
62       * @param aProvider provider for a<sub>h</sub> and a<sub>w</sub> coefficients
63       * @param gProvider provider for {@link AzimuthalGradientCoefficients} and {@link FieldAzimuthalGradientCoefficients}
64       * @param zenithDelayProvider provider for zenith delays
65       * @param utc                 UTC time scale
66       */
67      protected AbstractVienna(final ViennaAProvider aProvider,
68                               final AzimuthalGradientProvider gProvider,
69                               final TroposphericModel zenithDelayProvider,
70                               final TimeScale utc) {
71          this.aProvider           = aProvider;
72          this.gProvider           = gProvider;
73          this.zenithDelayProvider = zenithDelayProvider;
74          this.utc                 = utc;
75      }
76  
77      /** {@inheritDoc} */
78      @Override
79      public TroposphericDelay pathDelay(final TrackingCoordinates trackingCoordinates,
80                                         final GeodeticPoint point,
81                                         final PressureTemperatureHumidity weather,
82                                         final double[] parameters, final AbsoluteDate date) {
83          // zenith delay
84          final TroposphericDelay delays =
85                          zenithDelayProvider.pathDelay(trackingCoordinates, point, weather, parameters, date);
86  
87          // mapping function
88          final double[] mappingFunction =
89                          mappingFactors(trackingCoordinates, point, weather, date);
90  
91          // horizontal gradient
92          final AzimuthalGradientCoefficients agc = gProvider.getGradientCoefficients(point, date);
93          final double gh;
94          final double gw;
95          if (agc != null) {
96  
97              // Chen and Herring gradient mapping function
98              final double sinE = FastMath.sin(trackingCoordinates.getElevation());
99              final double tanE = FastMath.tan(trackingCoordinates.getElevation());
100             final double mfh  = 1.0 / (sinE * tanE + C);
101 
102             final SinCos sc = FastMath.sinCos(trackingCoordinates.getAzimuth());
103             gh = mfh * (agc.getGnh() * sc.cos() + agc.getGeh() * sc.sin());
104             gw = mfh * (agc.getGnw() * sc.cos() + agc.getGew() * sc.sin());
105 
106         } else {
107             gh = 0;
108             gw = 0;
109         }
110 
111         // Tropospheric path delay
112         return new TroposphericDelay(delays.getZh(),
113                                      delays.getZw(),
114                                      delays.getZh() * mappingFunction[0] + gh,
115                                      delays.getZw() * mappingFunction[1] + gw);
116 
117     }
118 
119     /** {@inheritDoc} */
120     @Override
121     public <T extends CalculusFieldElement<T>> FieldTroposphericDelay<T> pathDelay(final FieldTrackingCoordinates<T> trackingCoordinates,
122                                                                                    final FieldGeodeticPoint<T> point,
123                                                                                    final FieldPressureTemperatureHumidity<T> weather,
124                                                                                    final T[] parameters, final FieldAbsoluteDate<T> date) {
125         // zenith delay
126         final FieldTroposphericDelay<T> delays =
127                         zenithDelayProvider.pathDelay(trackingCoordinates, point, weather, parameters, date);
128 
129         // mapping function
130         final T[] mappingFunction =
131                         mappingFactors(trackingCoordinates, point, weather, date);
132 
133         // horizontal gradient
134         final FieldAzimuthalGradientCoefficients<T> agc = gProvider.getGradientCoefficients(point, date);
135         final T gh;
136         final T gw;
137         if (agc != null) {
138 
139             // Chen and Herring gradient mapping function
140             final T sinE = FastMath.sin(trackingCoordinates.getElevation());
141             final T tanE = FastMath.tan(trackingCoordinates.getElevation());
142             final T mfh  = sinE.multiply(tanE).add(C).reciprocal();
143 
144             final FieldSinCos<T> sc = FastMath.sinCos(trackingCoordinates.getAzimuth());
145             gh = mfh.multiply(agc.getGnh().multiply(sc.cos()).add(agc.getGeh().multiply(sc.sin())));
146             gw = mfh.multiply(agc.getGnw().multiply(sc.cos()).add(agc.getGew().multiply(sc.sin())));
147 
148         } else {
149             gh = date.getField().getZero();
150             gw = date.getField().getZero();
151         }
152 
153         // Tropospheric path delay
154         return new FieldTroposphericDelay<>(delays.getZh(),
155                                             delays.getZw(),
156                                             delays.getZh().multiply(mappingFunction[0]).add(gh),
157                                             delays.getZw().multiply(mappingFunction[1]).add(gw));
158 
159     }
160 
161     /** {@inheritDoc} */
162     @Override
163     public List<ParameterDriver> getParametersDrivers() {
164         return Collections.emptyList();
165     }
166 
167     /** Get provider for Vienna a<sub>h</sub> and a<sub>w</sub> coefficients.
168      * @return provider for Vienna a<sub>h</sub> and a<sub>w</sub> coefficients
169      */
170     protected ViennaAProvider getAProvider() {
171         return aProvider;
172     }
173 
174     /** Get day of year.
175      * @param date date
176      * @return day of year
177      */
178     protected int getDayOfYear(final AbsoluteDate date) {
179         return date.getComponents(utc).getDate().getDayOfYear();
180     }
181 
182 }