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