1   /* Copyright 2011-2012 Space Applications Services
2    * Licensed to CS Communication & Systèmes (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.analysis.interpolation.PiecewiseBicubicSplineInterpolatingFunction;
24  import org.hipparchus.analysis.interpolation.PiecewiseBicubicSplineInterpolator;
25  import org.hipparchus.util.FastMath;
26  import org.hipparchus.util.MathUtils;
27  import org.orekit.annotation.DefaultDataContext;
28  import org.orekit.bodies.FieldGeodeticPoint;
29  import org.orekit.bodies.GeodeticPoint;
30  import org.orekit.data.DataContext;
31  import org.orekit.data.DataProvidersManager;
32  import org.orekit.errors.OrekitException;
33  import org.orekit.errors.OrekitMessages;
34  import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity;
35  import org.orekit.models.earth.weather.PressureTemperatureHumidity;
36  import org.orekit.time.AbsoluteDate;
37  import org.orekit.time.FieldAbsoluteDate;
38  import org.orekit.utils.FieldTrackingCoordinates;
39  import org.orekit.utils.InterpolationTableLoader;
40  import org.orekit.utils.ParameterDriver;
41  import org.orekit.utils.TrackingCoordinates;
42  
43  /** A static tropospheric model that interpolates the actual tropospheric delay
44   * based on values read from a configuration file (tropospheric-delay.txt) via
45   * the {@link DataProvidersManager}.
46   * @author Thomas Neidhart
47   */
48  @SuppressWarnings("deprecation")
49  public class FixedTroposphericDelay implements DiscreteTroposphericModel, TroposphericModel {
50  
51      /** Singleton object for the default model. */
52      private static FixedTroposphericDelay defaultModel;
53  
54      /** Abscissa grid for the bi-variate interpolation function read from the file. */
55      private final double[] xArr;
56  
57      /** Ordinate grid for the bi-variate interpolation function read from the file. */
58      private final double[] yArr;
59  
60      /** Values samples for the bi-variate interpolation function read from the file. */
61      private final double[][] fArr;
62  
63      /** Interpolation function for the tropospheric delays. */
64      private PiecewiseBicubicSplineInterpolatingFunction delayFunction;
65  
66      /** Creates a new {@link FixedTroposphericDelay} instance.
67       * @param xArr abscissa grid for the interpolation function
68       * @param yArr ordinate grid for the interpolation function
69       * @param fArr values samples for the interpolation function
70       */
71      public FixedTroposphericDelay(final double[] xArr, final double[] yArr, final double[][] fArr) {
72          this.xArr = xArr.clone();
73          this.yArr = yArr.clone();
74          this.fArr = fArr.clone();
75          delayFunction = new PiecewiseBicubicSplineInterpolator().interpolate(xArr, yArr, fArr);
76      }
77  
78      /** Creates a new {@link FixedTroposphericDelay} instance, and loads the
79       * delay values from the given resource via the {@link DataContext#getDefault()
80       * default data context}.
81       *
82       * @param supportedName a regular expression for supported resource names
83       * @see #FixedTroposphericDelay(String, DataProvidersManager)
84       */
85      @DefaultDataContext
86      public FixedTroposphericDelay(final String supportedName) {
87          this(supportedName, DataContext.getDefault().getDataProvidersManager());
88      }
89  
90      /**
91       * Creates a new {@link FixedTroposphericDelay} instance, and loads the delay values
92       * from the given resource via the specified data manager.
93       *
94       * @param supportedName a regular expression for supported resource names
95       * @param dataProvidersManager provides access to auxiliary data.
96       * @since 10.1
97       */
98      public FixedTroposphericDelay(final String supportedName,
99                                    final DataProvidersManager dataProvidersManager) {
100 
101         final InterpolationTableLoader loader = new InterpolationTableLoader();
102         dataProvidersManager.feed(supportedName, loader);
103 
104         if (!loader.stillAcceptsData()) {
105             xArr = loader.getAbscissaGrid();
106             yArr = loader.getOrdinateGrid();
107             for (int i = 0; i < yArr.length; ++i) {
108                 yArr[i] = FastMath.toRadians(yArr[i]);
109             }
110             fArr = loader.getValuesSamples();
111             delayFunction = new PiecewiseBicubicSplineInterpolator().interpolate(xArr, yArr, fArr);
112         } else {
113             throw new OrekitException(OrekitMessages.UNABLE_TO_FIND_RESOURCE, supportedName);
114         }
115     }
116 
117     /** Returns the default model, loading delay values from the file
118      * "tropospheric-delay.txt" via the {@link DataContext#getDefault() default data
119      * context}.
120      *
121      * <p>This method uses the {@link DataContext#getDefault() default data context}.
122      *
123      * @return the default model
124      */
125     @DefaultDataContext
126     public static FixedTroposphericDelay getDefaultModel() {
127         synchronized (FixedTroposphericDelay.class) {
128             if (defaultModel == null) {
129                 defaultModel = new FixedTroposphericDelay("^tropospheric-delay\\.txt$");
130             }
131         }
132         return defaultModel;
133     }
134 
135     /** {@inheritDoc} */
136     @Override
137     @Deprecated
138     public double pathDelay(final double elevation, final GeodeticPoint point,
139                             final double[] parameters, final AbsoluteDate date) {
140         return pathDelay(new TrackingCoordinates(0.0, elevation, 0.0), point,
141                          TroposphericModelUtils.STANDARD_ATMOSPHERE, parameters, date).getDelay();
142     }
143 
144     /** {@inheritDoc}
145      * <p>
146      * All delays are affected to {@link TroposphericDelay#getZh() hydrostatic zenith}
147      * and {@link TroposphericDelay#getSh() hydrostatic slanted} delays, the wet delays
148      * are arbitrarily set to 0.
149      * </p>
150      */
151     @Override
152     public TroposphericDelay pathDelay(final TrackingCoordinates trackingCoordinates, final GeodeticPoint point,
153                                        final PressureTemperatureHumidity weather,
154                                        final double[] parameters, final AbsoluteDate date) {
155         // limit the height to 5000 m
156         final double h = FastMath.min(FastMath.max(0, point.getAltitude()), 5000);
157         // limit the elevation to 0 - π
158         final double ele = FastMath.min(FastMath.PI, FastMath.max(0d, trackingCoordinates.getElevation()));
159         // mirror elevation at the right angle of π/2
160         final double e = ele > 0.5 * FastMath.PI ? FastMath.PI - ele : ele;
161 
162         return new TroposphericDelay(delayFunction.value(h, MathUtils.SEMI_PI), 0.0,
163                                      delayFunction.value(h, e), 0.0);
164     }
165 
166     /** {@inheritDoc} */
167     @Override
168     @Deprecated
169     public <T extends CalculusFieldElement<T>> T pathDelay(final T elevation, final FieldGeodeticPoint<T> point,
170                                                            final T[] parameters, final FieldAbsoluteDate<T> date) {
171         return pathDelay(new FieldTrackingCoordinates<>(date.getField().getZero(), elevation, date.getField().getZero()),
172                          point,
173                          new FieldPressureTemperatureHumidity<>(date.getField(), TroposphericModelUtils.STANDARD_ATMOSPHERE),
174                          parameters, date).getDelay();
175     }
176 
177     /** {@inheritDoc}
178      * <p>
179      * All delays are affected to {@link FieldTroposphericDelay#getZh() hydrostatic zenith}
180      * and {@link FieldTroposphericDelay#getSh() hydrostatic slanted} delays, the wet delays
181      * are arbitrarily set to 0.
182      * </p>
183      */
184     @Override
185     public <T extends CalculusFieldElement<T>> FieldTroposphericDelay<T> pathDelay(final FieldTrackingCoordinates<T> trackingCoordinates,
186                                                                                    final FieldGeodeticPoint<T> point,
187                                                                                    final FieldPressureTemperatureHumidity<T> weather,
188                                                                                    final T[] parameters, final FieldAbsoluteDate<T> date) {
189         final T zero = date.getField().getZero();
190         final T pi   = zero.getPi();
191         // limit the height to 5000 m
192         final T h = FastMath.min(FastMath.max(zero, point.getAltitude()), zero.newInstance(5000));
193         // limit the elevation to 0 - π
194         final T ele = FastMath.min(pi, FastMath.max(zero, trackingCoordinates.getElevation()));
195         // mirror elevation at the right angle of π/2
196         final T e = ele.getReal() > pi.multiply(0.5).getReal() ? ele.negate().add(pi) : ele;
197 
198         return new FieldTroposphericDelay<>(delayFunction.value(h, date.getField().getZero().newInstance(MathUtils.SEMI_PI)),
199                                             date.getField().getZero(),
200                                             delayFunction.value(h, e),
201                                             date.getField().getZero());
202 
203     }
204 
205     /** {@inheritDoc} */
206     @Override
207     public List<ParameterDriver> getParametersDrivers() {
208         return Collections.emptyList();
209     }
210 
211 }