1 /* Copyright 2002-2021 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.ArrayList;
20 import java.util.List;
21 import java.util.NavigableSet;
22
23 import org.hipparchus.CalculusFieldElement;
24 import org.hipparchus.util.MathArrays;
25 import org.orekit.annotation.DefaultDataContext;
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.time.TimeScalesFactory;
32 import org.orekit.utils.ParameterDriver;
33 import org.orekit.utils.TimeSpanMap;
34 import org.orekit.utils.TimeSpanMap.Transition;
35
36 /**
37 * Time span estimated tropospheric model.
38 * <p>
39 * This class is closely related to {@link org.orekit.models.earth.troposphere EstimatedTroposphericModel} class.<br>
40 * The difference is that it has a {@link TimeSpanMap} of {@link EstimatedTroposphericModel} objects as attribute. <br>
41 * The idea behind this model is to allow the user to design a tropospheric model that can see its physical parameters
42 * (total zenith delay) change with time, at dates chosen by the user. <br>
43 * </p>
44 * @author Bryan Cazabonne
45 * @since 10.2
46 */
47 public class TimeSpanEstimatedTroposphericModel implements DiscreteTroposphericModel {
48
49 /** Prefix for dates before in the tropospheric parameter drivers' name. */
50 public static final String DATE_BEFORE = " - Before ";
51
52 /** Prefix for dates after in the tropospheric parameter drivers' name. */
53 public static final String DATE_AFTER = " - After ";
54
55 /** Time scale for transition dates. */
56 private final TimeScale timeScale;
57
58 /** It contains all the models use for the whole period of measurements. */
59 private final TimeSpanMap<EstimatedTroposphericModel> troposphericModelMap;
60
61 /**
62 * Constructor with default UTC time scale.
63 * @param model the initial model which going to be used for all the models initialization.
64 */
65 @DefaultDataContext
66 public TimeSpanEstimatedTroposphericModel(final EstimatedTroposphericModel model) {
67 this(model, TimeScalesFactory.getUTC());
68 }
69
70 /**
71 * Constructor with default UTC time scale.
72 * @param model the initial model which going to be used for all the models initialization.
73 * @param timeScale timeScale Time scale used for the default names of the tropospheric parameter drivers
74 */
75 public TimeSpanEstimatedTroposphericModel(final EstimatedTroposphericModel model,
76 final TimeScale timeScale) {
77 this.troposphericModelMap = new TimeSpanMap<>(model);
78 this.timeScale = timeScale;
79 }
80
81 /** {@inheritDoc}
82 * <p>
83 * All the parameter drivers of all Estimated models are returned in an array.
84 * Models are ordered chronologically.
85 * </p>
86 */
87 @Override
88 public List<ParameterDriver> getParametersDrivers() {
89
90 // Get all transitions from the TimeSpanMap
91 final List<ParameterDriver> listTroposphericParameterDrivers = new ArrayList<>();
92 final NavigableSet<Transition<EstimatedTroposphericModel>> troposphericModelTransitions = getTransitions();
93
94 // Loop on the transitions
95 for (Transition<EstimatedTroposphericModel> transition : troposphericModelTransitions) {
96 // Add all the "before" parameter drivers of each transition
97 for (ParameterDriver tropoDriver : transition.getBefore().getParametersDrivers()) {
98 // Add the driver only if the name does not exist already
99 if (!findByName(listTroposphericParameterDrivers, tropoDriver.getName())) {
100 listTroposphericParameterDrivers.add(tropoDriver);
101 }
102 }
103 }
104 // Finally, add the "after" parameter drivers of the last transition
105 for (ParameterDriver tropoDriver : troposphericModelTransitions.last().getAfter().getParametersDrivers()) {
106 // Adds only if the name does not exist already
107 if (!findByName(listTroposphericParameterDrivers, tropoDriver.getName())) {
108 listTroposphericParameterDrivers.add(tropoDriver);
109 }
110 }
111
112 // Return an array of parameter drivers with no duplicated name
113 return listTroposphericParameterDrivers;
114
115 }
116
117 /** Add an EstimatedTroposphericModel entry valid before a limit date.<br>
118 * Using <code>addTroposphericValidBefore(entry, t)</code> will make <code>entry</code>
119 * valid in ]-∞, t[ (note the open bracket).
120 * @param model EstimatedTroposphericModel entry
121 * @param latestValidityDate date before which the entry is valid
122 * (must be different from <b>all</b> dates already used for transitions)
123 */
124 public void addTroposphericModelValidBefore(final EstimatedTroposphericModel model, final AbsoluteDate latestValidityDate) {
125 troposphericModelMap.addValidBefore(changeTroposphericParameterDriversNames(model,
126 latestValidityDate,
127 DATE_BEFORE),
128 latestValidityDate);
129 }
130
131 /** Add a EstimatedTroposphericModel entry valid after a limit date.<br>
132 * Using <code>addTroposphericModelValidAfter(entry, t)</code> will make <code>entry</code>
133 * valid in [t, +∞[ (note the closed bracket).
134 * @param model EstimatedTroposphericModel entry
135 * @param earliestValidityDate date after which the entry is valid
136 * (must be different from <b>all</b> dates already used for transitions)
137 */
138 public void addTroposphericModelValidAfter(final EstimatedTroposphericModel model, final AbsoluteDate earliestValidityDate) {
139 troposphericModelMap.addValidAfter(changeTroposphericParameterDriversNames(model,
140 earliestValidityDate,
141 DATE_AFTER),
142 earliestValidityDate);
143 }
144
145 /** Get the {@link EstimatedTroposphericModel} model valid at a date.
146 * @param date the date of validity
147 * @return the EstimatedTroposphericModel model valid at date
148 */
149 public EstimatedTroposphericModel getTroposphericModel(final AbsoluteDate date) {
150 return troposphericModelMap.get(date);
151 }
152
153 /** Get the {@link Transition}s of the tropospheric model time span map.
154 * @return the {@link Transition}s for the tropospheric model time span map
155 */
156 public NavigableSet<Transition<EstimatedTroposphericModel>> getTransitions() {
157 return troposphericModelMap.getTransitions();
158 }
159
160 /** Extract the proper parameter drivers' values from the array in input of the
161 * {@link #pathDelay(double, GeodeticPoint, double[], AbsoluteDate) pathDelay} method.
162 * Parameters are filtered given an input date.
163 * @param parameters the input parameters array
164 * @param date the date
165 * @return the parameters given the date
166 */
167 public double[] extractParameters(final double[] parameters, final AbsoluteDate date) {
168
169 // Get the tropospheric parameter drivers of the date
170 final List<ParameterDriver> troposphericParameterDriver = getTroposphericModel(date).getParametersDrivers();
171
172 // Find out the indexes of the parameters in the whole array of parameters
173 final List<ParameterDriver> allTroposphericParameters = getParametersDrivers();
174 final double[] outParameters = new double[troposphericParameterDriver.size()];
175 int index = 0;
176 for (int i = 0; i < allTroposphericParameters.size(); i++) {
177 final String driverName = allTroposphericParameters.get(i).getName();
178 for (ParameterDriver tropoDriver : troposphericParameterDriver) {
179 if (tropoDriver.getName().equals(driverName)) {
180 outParameters[index++] = parameters[i];
181 }
182 }
183 }
184 return outParameters;
185 }
186
187 /** Extract the proper parameter drivers' values from the array in input of the
188 * {@link #pathDelay(double, GeodeticPoint, double[], AbsoluteDate) pathDelay} method.
189 * Parameters are filtered given an input date.
190 * @param parameters the input parameters array
191 * @param date the date
192 * @param <T> extends CalculusFieldElements
193 * @return the parameters given the date
194 */
195 public <T extends CalculusFieldElement<T>> T[] extractParameters(final T[] parameters,
196 final FieldAbsoluteDate<T> date) {
197
198 // Get the tropospheric parameter drivers of the date
199 final List<ParameterDriver> troposphericParameterDriver = getTroposphericModel(date.toAbsoluteDate()).getParametersDrivers();
200
201 // Find out the indexes of the parameters in the whole array of parameters
202 final List<ParameterDriver> allTroposphericParameters = getParametersDrivers();
203 final T[] outParameters = MathArrays.buildArray(date.getField(), troposphericParameterDriver.size());
204 int index = 0;
205 for (int i = 0; i < allTroposphericParameters.size(); i++) {
206 final String driverName = allTroposphericParameters.get(i).getName();
207 for (ParameterDriver tropoDriver : troposphericParameterDriver) {
208 if (tropoDriver.getName().equals(driverName)) {
209 outParameters[index++] = parameters[i];
210 }
211 }
212 }
213 return outParameters;
214 }
215
216 /** {@inheritDoc} */
217 @Override
218 public double pathDelay(final double elevation, final GeodeticPoint point,
219 final double[] parameters, final AbsoluteDate date) {
220 // Extract the proper parameters valid at date from the input array
221 final double[] extractedParameters = extractParameters(parameters, date);
222 // Compute and return the path delay
223 return getTroposphericModel(date).pathDelay(elevation, point,
224 extractedParameters, date);
225 }
226
227 /** {@inheritDoc} */
228 @Override
229 public <T extends CalculusFieldElement<T>> T pathDelay(final T elevation, final FieldGeodeticPoint<T> point,
230 final T[] parameters, final FieldAbsoluteDate<T> date) {
231 // Extract the proper parameters valid at date from the input array
232 final T[] extractedParameters = extractParameters(parameters, date);
233 // Compute and return the path delay
234 return getTroposphericModel(date.toAbsoluteDate()).pathDelay(elevation, point,
235 extractedParameters, date);
236 }
237
238 /** Find if a parameter driver with a given name already exists in a list of parameter drivers.
239 * @param driversList the list of parameter drivers
240 * @param name the parameter driver's name to filter with
241 * @return true if the name was found, false otherwise
242 */
243 private boolean findByName(final List<ParameterDriver> driversList, final String name) {
244 for (final ParameterDriver driver : driversList) {
245 if (driver.getName().equals(name)) {
246 return true;
247 }
248 }
249 return false;
250 }
251
252 /** Change the parameter drivers names of a {@link EstimatedTroposphericModel} model, if needed.
253 * <p>
254 * This is done to avoid that several parameter drivers have the same name.<br>
255 * It is done only if the user hasn't modify the EstimatedTroposphericModel parameter drivers default names.
256 * </p>
257 * @param troposphericModel the EstimatedTroposphericModel model
258 * @param date the date used in the parameter driver's name
259 * @param datePrefix the date prefix used in the parameter driver's name
260 * @return the EstimatedTroposphericModel with its drivers' names changed
261 */
262 private EstimatedTroposphericModel changeTroposphericParameterDriversNames(final EstimatedTroposphericModel troposphericModel,
263 final AbsoluteDate date,
264 final String datePrefix) {
265 // Loop on the parameter drivers of the EstimatedTroposphericModel model
266 for (ParameterDriver driver: troposphericModel.getParametersDrivers()) {
267 final String driverName = driver.getName();
268
269 // If the name is the default name for EstimatedTroposphericModel parameter drivers
270 // Modify the name to add the prefix and the date
271 if (driverName.equals(EstimatedTroposphericModel.TOTAL_ZENITH_DELAY)) {
272 driver.setName(driverName + datePrefix + date.toString(timeScale));
273 }
274 }
275 return troposphericModel;
276 }
277
278 }