1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.models.earth.troposphere.iturp834;
18
19 import org.hipparchus.CalculusFieldElement;
20 import org.hipparchus.util.FastMath;
21 import org.orekit.bodies.FieldGeodeticPoint;
22 import org.orekit.bodies.GeodeticPoint;
23 import org.orekit.models.earth.troposphere.TroposphericModelUtils;
24 import org.orekit.models.earth.weather.FieldPressureTemperatureHumidity;
25 import org.orekit.models.earth.weather.PressureTemperatureHumidity;
26 import org.orekit.models.earth.weather.PressureTemperatureHumidityProvider;
27 import org.orekit.time.AbsoluteDate;
28 import org.orekit.time.FieldAbsoluteDate;
29 import org.orekit.time.TimeScale;
30 import org.orekit.utils.Constants;
31 import org.orekit.utils.units.Unit;
32
33
34
35
36
37
38
39
40
41
42
43
44 public class ITURP834WeatherParametersProvider implements PressureTemperatureHumidityProvider {
45
46
47 private static final String AIR_TOTAL_PRESSURE_PREFIX = "pres";
48
49
50 private static final String WATER_VAPOUR_PARTIAL_PRESSURE_PREFIX = "vapr";
51
52
53 private static final String MEAN_TEMPERATURE_PREFIX = "tmpm";
54
55
56 private static final String VAPOUR_PRESSURE_DECREASE_FACTOR_PREFIX = "lamd";
57
58
59 private static final String LAPSE_RATE_MEAN_TEMPERATURE_WATER_VAPOUR_PREFIX = "alfm";
60
61
62 private static final String AVERAGE_SUFFIX = "_gd_a1.dat";
63
64
65 private static final String SEASONAL_SUFFIX = "_gd_a2.dat";
66
67
68 private static final String DAY_OF_MINIMUM_SUFFIX = "_gd_a3.dat";
69
70
71 private static final String AVERAGE_HEIGHT_REFERENCE_LEVEL_NAME = "hreflev.dat";
72
73
74 private static final double R = 8.314;
75
76
77 private static final double MD = Unit.GRAM.toSI(28.9644);
78
79
80 private static final double RD = R / MD;
81
82
83 private static final SeasonalGrid AIR_TOTAL_PRESSURE;
84
85
86 private static final SeasonalGrid WATER_VAPOUR_PARTIAL_PRESSURE;
87
88
89 private static final SeasonalGrid MEAN_TEMPERATURE;
90
91
92 private static final SeasonalGrid VAPOUR_PRESSURE_DECREASE_FACTOR;
93
94
95 private static final SeasonalGrid LAPSE_RATE_MEAN_TEMPERATURE_WATER_VAPOUR;
96
97
98 private static final ConstantGrid AVERAGE_HEIGHT_REFERENCE_LEVEL;
99
100
101 private final TimeScale utc;
102
103
104 static {
105
106
107 AIR_TOTAL_PRESSURE =
108 new SeasonalGrid(TroposphericModelUtils.HECTO_PASCAL,
109 AIR_TOTAL_PRESSURE_PREFIX + AVERAGE_SUFFIX,
110 AIR_TOTAL_PRESSURE_PREFIX + SEASONAL_SUFFIX,
111 AIR_TOTAL_PRESSURE_PREFIX + DAY_OF_MINIMUM_SUFFIX);
112 WATER_VAPOUR_PARTIAL_PRESSURE =
113 new SeasonalGrid(TroposphericModelUtils.HECTO_PASCAL,
114 WATER_VAPOUR_PARTIAL_PRESSURE_PREFIX + AVERAGE_SUFFIX,
115 WATER_VAPOUR_PARTIAL_PRESSURE_PREFIX + SEASONAL_SUFFIX,
116 WATER_VAPOUR_PARTIAL_PRESSURE_PREFIX + DAY_OF_MINIMUM_SUFFIX);
117 MEAN_TEMPERATURE =
118 new SeasonalGrid(Unit.NONE,
119 MEAN_TEMPERATURE_PREFIX + AVERAGE_SUFFIX,
120 MEAN_TEMPERATURE_PREFIX + SEASONAL_SUFFIX,
121 MEAN_TEMPERATURE_PREFIX + DAY_OF_MINIMUM_SUFFIX);
122 VAPOUR_PRESSURE_DECREASE_FACTOR =
123 new SeasonalGrid(Unit.NONE,
124 VAPOUR_PRESSURE_DECREASE_FACTOR_PREFIX + AVERAGE_SUFFIX,
125 VAPOUR_PRESSURE_DECREASE_FACTOR_PREFIX + SEASONAL_SUFFIX,
126 VAPOUR_PRESSURE_DECREASE_FACTOR_PREFIX + DAY_OF_MINIMUM_SUFFIX);
127 LAPSE_RATE_MEAN_TEMPERATURE_WATER_VAPOUR =
128 new SeasonalGrid(Unit.parse("km⁻¹"),
129 LAPSE_RATE_MEAN_TEMPERATURE_WATER_VAPOUR_PREFIX + AVERAGE_SUFFIX,
130 LAPSE_RATE_MEAN_TEMPERATURE_WATER_VAPOUR_PREFIX + SEASONAL_SUFFIX,
131 LAPSE_RATE_MEAN_TEMPERATURE_WATER_VAPOUR_PREFIX + DAY_OF_MINIMUM_SUFFIX);
132 AVERAGE_HEIGHT_REFERENCE_LEVEL = new ConstantGrid(Unit.METRE, AVERAGE_HEIGHT_REFERENCE_LEVEL_NAME);
133
134 }
135
136
137
138
139 public ITURP834WeatherParametersProvider(final TimeScale utc) {
140 this.utc = utc;
141 }
142
143
144 @Override
145 public PressureTemperatureHumidity getWeatherParameters(final GeodeticPoint location, final AbsoluteDate date) {
146
147
148 final double soy = date.getDayOfYear(utc) * Constants.JULIAN_DAY;
149 final GridCell pHRef = AIR_TOTAL_PRESSURE.getCell(location, soy);
150 final GridCell eHRef = WATER_VAPOUR_PARTIAL_PRESSURE.getCell(location, soy);
151 final GridCell tmHRef = MEAN_TEMPERATURE.getCell(location, soy);
152 final GridCell lambdaHRef = VAPOUR_PRESSURE_DECREASE_FACTOR.getCell(location, soy);
153 final GridCell alphaHRef = LAPSE_RATE_MEAN_TEMPERATURE_WATER_VAPOUR.getCell(location, soy);
154 final GridCell hRef = AVERAGE_HEIGHT_REFERENCE_LEVEL.getCell(location, soy);
155 final GridCell g = Gravity.getGravityAtSurface(location);
156
157
158 final GridCell tm = new GridCell((ct, ca, ch) -> ct - ca * (location.getAltitude() - ch),
159 tmHRef, alphaHRef, hRef);
160
161
162 final GridCell fraction = new GridCell((cl, cg) -> (cl + 1) * cg / RD,
163 lambdaHRef, g);
164 final GridCell alpha = new GridCell((cf, ca) -> 0.5 * (cf - FastMath.sqrt(cf * (cf - 4 * ca))),
165 fraction, alphaHRef);
166
167
168 final GridCell t = new GridCell((ct, ca, cf) -> ct / (1 - ca / cf),
169 tmHRef, alpha, fraction);
170
171
172 final GridCell p = new GridCell((cp, ca, ch, ct, cg) ->
173 cp * FastMath.pow(1 - ca * (location.getAltitude() - ch) / ct, cg / (ca * RD)),
174 pHRef, alpha, hRef, t, g);
175
176
177 final GridCell e = new GridCell((ce, cp, cpr, cl) ->
178 ce * FastMath.pow(cp / cpr, cl + 1),
179 eHRef, p, pHRef, lambdaHRef);
180
181
182
183
184
185
186
187
188
189
190
191 final GridCell gm = Gravity.getGravityAtAltitude(location);
192 final double gmInterp = gm.evaluate();
193 final double lambdaInterp = lambdaHRef.evaluate();
194 final double tmInterp = tm.evaluate();
195 final GridCell pOverG = new GridCell((cp, cg) -> cp / cg, p, gm);
196 final double compensatedPressure = pOverG.evaluate() * gmInterp;
197 final GridCell eOverGLT = new GridCell((ce, cg, cl, ctm) -> ce / (cg * (cl + 1) * ctm),
198 e, gm, lambdaHRef, tm);
199 final double compensatedWaterPressure = eOverGLT.evaluate() * gmInterp * (lambdaInterp + 1) * tmInterp;
200 return new PressureTemperatureHumidity(location.getAltitude(),
201 compensatedPressure,
202 t.evaluate(),
203 compensatedWaterPressure,
204 tmInterp,
205 lambdaInterp);
206
207 }
208
209
210 @Override
211 public <T extends CalculusFieldElement<T>> FieldPressureTemperatureHumidity<T>
212 getWeatherParameters(final FieldGeodeticPoint<T> location, final FieldAbsoluteDate<T> date) {
213
214
215 final T soy = date.getDayOfYear(utc).multiply(Constants.JULIAN_DAY);
216 final FieldGridCell<T> pHRef = AIR_TOTAL_PRESSURE.getCell(location, soy);
217 final FieldGridCell<T> eHRef = WATER_VAPOUR_PARTIAL_PRESSURE.getCell(location, soy);
218 final FieldGridCell<T> tmHRef = MEAN_TEMPERATURE.getCell(location, soy);
219 final FieldGridCell<T> lambdaHRef = VAPOUR_PRESSURE_DECREASE_FACTOR.getCell(location, soy);
220 final FieldGridCell<T> alphaHRef = LAPSE_RATE_MEAN_TEMPERATURE_WATER_VAPOUR.getCell(location, soy);
221 final FieldGridCell<T> hRef = AVERAGE_HEIGHT_REFERENCE_LEVEL.getCell(location, soy);
222 final FieldGridCell<T> g = Gravity.getGravityAtSurface(location);
223
224
225 final FieldGridCell<T> tm =
226 new FieldGridCell<>((ct, ca, ch) -> ct.subtract(ca.multiply(location.getAltitude().subtract(ch))),
227 tmHRef, alphaHRef, hRef);
228
229
230 final FieldGridCell<T> fraction =
231 new FieldGridCell<>((cl, cg) -> cl.add(1).multiply(cg).divide(RD),
232 lambdaHRef, g);
233 final FieldGridCell<T> alpha =
234 new FieldGridCell<>((cf, ca) -> cf.subtract(FastMath.sqrt(cf.multiply(cf.subtract(ca.multiply(4))))).multiply(0.5),
235 fraction, alphaHRef);
236
237
238 final FieldGridCell<T> t =
239 new FieldGridCell<>((ct, ca, cf) -> ct.divide(ca.divide(cf).subtract(1).negate()),
240 tmHRef, alpha, fraction);
241
242
243 final FieldGridCell<T> p =
244 new FieldGridCell<>((cp, ca, ch, ct, cg) ->
245 cp.multiply(FastMath.pow(ca.multiply(location.getAltitude().subtract(ch)).divide(ct).subtract(1).negate(),
246 cg.divide(ca.multiply(RD)))),
247 pHRef, alpha, hRef, t, g);
248
249
250 final FieldGridCell<T> e =
251 new FieldGridCell<>((ce, cp, cpr, cl) ->
252 ce.multiply(FastMath.pow(cp.divide(cpr), cl.add(1))),
253 eHRef, p, pHRef, lambdaHRef);
254
255
256
257
258
259
260
261
262
263
264
265 final FieldGridCell<T> gm = Gravity.getGravityAtAltitude(location);
266 final T gmInterp = gm.evaluate();
267 final T lambdaInterp = lambdaHRef.evaluate();
268 final T tmInterp = tm.evaluate();
269 final FieldGridCell<T> pOverG = new FieldGridCell<>(CalculusFieldElement::divide, p, gm);
270 final T compensatedPressure = pOverG.evaluate().multiply(gmInterp);
271 final FieldGridCell<T> eOverGLT = new FieldGridCell<>((ce, cg, cl, ctm) ->
272 ce.divide(cg.multiply(cl.add(1)).multiply(ctm)),
273 e, gm, lambdaHRef, tm);
274 final T compensatedWaterPressure = eOverGLT.evaluate().multiply(gmInterp).multiply(lambdaInterp.add(1)).multiply(tmInterp);
275 return new FieldPressureTemperatureHumidity<>(location.getAltitude(),
276 compensatedPressure,
277 t.evaluate(),
278 compensatedWaterPressure,
279 tmInterp,
280 lambdaInterp);
281
282 }
283
284 }