1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.forces.gravity.potential;
18
19 import java.io.BufferedReader;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.InputStreamReader;
23 import java.nio.charset.StandardCharsets;
24 import java.text.ParseException;
25 import java.util.ArrayList;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.regex.Pattern;
30
31 import org.hipparchus.util.FastMath;
32 import org.hipparchus.util.Precision;
33 import org.orekit.annotation.DefaultDataContext;
34 import org.orekit.data.DataContext;
35 import org.orekit.errors.OrekitException;
36 import org.orekit.errors.OrekitMessages;
37 import org.orekit.errors.OrekitParseException;
38 import org.orekit.time.AbsoluteDate;
39 import org.orekit.time.DateComponents;
40 import org.orekit.time.TimeScale;
41 import org.orekit.utils.Constants;
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91 public class ICGEMFormatReader extends PotentialCoefficientsReader {
92
93
94 private static final String PRODUCT_TYPE = "product_type";
95
96
97 private static final String GRAVITY_FIELD = "gravity_field";
98
99
100 private static final String GRAVITY_CONSTANT = "gravity_constant";
101
102
103 private static final String REFERENCE_RADIUS = "radius";
104
105
106 private static final String MAX_DEGREE = "max_degree";
107
108
109 private static final String TIDE_SYSTEM_INDICATOR = "tide_system";
110
111
112 private static final String ZERO_TIDE = "zero_tide";
113
114
115 private static final String TIDE_FREE = "tide_free";
116
117
118 private static final String TIDE_UNKNOWN = "unknown";
119
120
121 private static final String NORMALIZATION_INDICATOR = "norm";
122
123
124 private static final String NORMALIZED = "fully_normalized";
125
126
127 private static final String UNNORMALIZED = "unnormalized";
128
129
130 private static final String END_OF_HEADER = "end_of_head";
131
132
133 private static final String GFC = "gfc";
134
135
136 private static final String GFCT = "gfct";
137
138
139 private static final String DOT = "dot";
140
141
142 private static final String TRND = "trnd";
143
144
145 private static final String ASIN = "asin";
146
147
148 private static final String ACOS = "acos";
149
150
151 private static final Pattern SEPARATOR = Pattern.compile("\\s+");
152
153
154 private boolean normalized;
155
156
157 private AbsoluteDate referenceDate;
158
159
160 private final List<List<Double>> cTrend;
161
162
163 private final List<List<Double>> sTrend;
164
165
166 private final Map<Double, List<List<Double>>> cCos;
167
168
169 private final Map<Double, List<List<Double>>> cSin;
170
171
172 private final Map<Double, List<List<Double>>> sCos;
173
174
175 private final Map<Double, List<List<Double>>> sSin;
176
177
178
179
180
181
182
183
184
185 @DefaultDataContext
186 public ICGEMFormatReader(final String supportedNames, final boolean missingCoefficientsAllowed) {
187 this(supportedNames, missingCoefficientsAllowed,
188 DataContext.getDefault().getTimeScales().getTT());
189 }
190
191
192
193
194
195
196
197
198
199
200 public ICGEMFormatReader(final String supportedNames,
201 final boolean missingCoefficientsAllowed,
202 final TimeScale timeScale) {
203 super(supportedNames, missingCoefficientsAllowed, timeScale);
204 referenceDate = null;
205 cTrend = new ArrayList<>();
206 sTrend = new ArrayList<>();
207 cCos = new HashMap<>();
208 cSin = new HashMap<>();
209 sCos = new HashMap<>();
210 sSin = new HashMap<>();
211 }
212
213
214 public void loadData(final InputStream input, final String name)
215 throws IOException, ParseException, OrekitException {
216
217
218 setReadComplete(false);
219 referenceDate = null;
220 cTrend.clear();
221 sTrend.clear();
222 cCos.clear();
223 cSin.clear();
224 sCos.clear();
225 sSin.clear();
226
227
228
229 normalized = true;
230 TideSystem tideSystem = TideSystem.UNKNOWN;
231
232 boolean inHeader = true;
233 double[][] c = null;
234 double[][] s = null;
235 boolean okCoeffs = false;
236 int lineNumber = 0;
237 String line = null;
238 try (BufferedReader r = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8))) {
239 for (line = r.readLine(); line != null; line = r.readLine()) {
240 ++lineNumber;
241 line = line.trim();
242 if (line.length() == 0) {
243 continue;
244 }
245 final String[] tab = SEPARATOR.split(line);
246 if (inHeader) {
247 if (tab.length == 2 && PRODUCT_TYPE.equals(tab[0])) {
248 if (!GRAVITY_FIELD.equals(tab[1])) {
249 throw new OrekitParseException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
250 lineNumber, name, line);
251 }
252 } else if (tab.length == 2 && tab[0].endsWith(GRAVITY_CONSTANT)) {
253 setMu(parseDouble(tab[1]));
254 } else if (tab.length == 2 && REFERENCE_RADIUS.equals(tab[0])) {
255 setAe(parseDouble(tab[1]));
256 } else if (tab.length == 2 && MAX_DEGREE.equals(tab[0])) {
257
258 final int degree = FastMath.min(getMaxParseDegree(), Integer.parseInt(tab[1]));
259 final int order = FastMath.min(getMaxParseOrder(), degree);
260 c = buildTriangularArray(degree, order, missingCoefficientsAllowed() ? 0.0 : Double.NaN);
261 s = buildTriangularArray(degree, order, missingCoefficientsAllowed() ? 0.0 : Double.NaN);
262
263 } else if (tab.length == 2 && TIDE_SYSTEM_INDICATOR.equals(tab[0])) {
264 if (ZERO_TIDE.equals(tab[1])) {
265 tideSystem = TideSystem.ZERO_TIDE;
266 } else if (TIDE_FREE.equals(tab[1])) {
267 tideSystem = TideSystem.TIDE_FREE;
268 } else if (TIDE_UNKNOWN.equals(tab[1])) {
269 tideSystem = TideSystem.UNKNOWN;
270 } else {
271 throw new OrekitParseException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
272 lineNumber, name, line);
273 }
274 } else if (tab.length == 2 && NORMALIZATION_INDICATOR.equals(tab[0])) {
275 if (NORMALIZED.equals(tab[1])) {
276 normalized = true;
277 } else if (UNNORMALIZED.equals(tab[1])) {
278 normalized = false;
279 } else {
280 throw new OrekitParseException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
281 lineNumber, name, line);
282 }
283 } else if (tab.length == 2 && END_OF_HEADER.equals(tab[0])) {
284 inHeader = false;
285 }
286 } else {
287 if (tab.length == 7 && GFC.equals(tab[0]) || tab.length == 8 && GFCT.equals(tab[0])) {
288
289 final int i = Integer.parseInt(tab[1]);
290 final int j = Integer.parseInt(tab[2]);
291 if (i < c.length && j < c[i].length) {
292
293 parseCoefficient(tab[3], c, i, j, "C", name);
294 parseCoefficient(tab[4], s, i, j, "S", name);
295 okCoeffs = true;
296
297 if (tab.length == 8) {
298
299 final DateComponents localRef = new DateComponents(Integer.parseInt(tab[7].substring(0, 4)),
300 Integer.parseInt(tab[7].substring(4, 6)),
301 Integer.parseInt(tab[7].substring(6, 8)));
302 if (referenceDate == null) {
303
304 referenceDate = toDate(localRef);
305 } else if (!referenceDate.equals(toDate(localRef))) {
306 final AbsoluteDate localDate = toDate(localRef);
307 throw new OrekitException(OrekitMessages.SEVERAL_REFERENCE_DATES_IN_GRAVITY_FIELD,
308 referenceDate, localDate, name,
309 localDate.durationFrom(referenceDate));
310 }
311 }
312
313 }
314 } else if (tab.length == 7 && (DOT.equals(tab[0]) || TRND.equals(tab[0]))) {
315
316 final int i = Integer.parseInt(tab[1]);
317 final int j = Integer.parseInt(tab[2]);
318 if (i < c.length && j < c[i].length) {
319
320
321 extendListOfLists(cTrend, i, j, 0.0);
322 extendListOfLists(sTrend, i, j, 0.0);
323 parseCoefficient(tab[3], cTrend, i, j, "Ctrend", name);
324 parseCoefficient(tab[4], sTrend, i, j, "Strend", name);
325
326 }
327
328 } else if (tab.length == 8 && (ASIN.equals(tab[0]) || ACOS.equals(tab[0]))) {
329
330 final int i = Integer.parseInt(tab[1]);
331 final int j = Integer.parseInt(tab[2]);
332 if (i < c.length && j < c[i].length) {
333
334
335 final Double period = Double.valueOf(tab[7]);
336 if (!cCos.containsKey(period)) {
337 cCos.put(period, new ArrayList<>());
338 cSin.put(period, new ArrayList<>());
339 sCos.put(period, new ArrayList<>());
340 sSin.put(period, new ArrayList<>());
341 }
342 final List<List<Double>> cCosPeriod = cCos.get(period);
343 final List<List<Double>> cSinPeriod = cSin.get(period);
344 final List<List<Double>> sCosPeriod = sCos.get(period);
345 final List<List<Double>> sSinPeriod = sSin.get(period);
346
347
348 extendListOfLists(cCosPeriod, i, j, 0.0);
349 extendListOfLists(cSinPeriod, i, j, 0.0);
350 extendListOfLists(sCosPeriod, i, j, 0.0);
351 extendListOfLists(sSinPeriod, i, j, 0.0);
352 if (ACOS.equals(tab[0])) {
353 parseCoefficient(tab[3], cCosPeriod, i, j, "Ccos", name);
354 parseCoefficient(tab[4], sCosPeriod, i, j, "SCos", name);
355 } else {
356 parseCoefficient(tab[3], cSinPeriod, i, j, "Csin", name);
357 parseCoefficient(tab[4], sSinPeriod, i, j, "Ssin", name);
358 }
359
360 }
361
362 } else {
363 throw new OrekitParseException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
364 lineNumber, name, line);
365 }
366 }
367
368 }
369 } catch (NumberFormatException nfe) {
370 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
371 lineNumber, name, line);
372 }
373
374
375 if (missingCoefficientsAllowed() && c.length > 0 && c[0].length > 0) {
376
377 if (Precision.equals(c[0][0], 0.0, 0)) {
378 c[0][0] = 1.0;
379 }
380 }
381
382 if (Double.isNaN(getAe()) || Double.isNaN(getMu()) || !okCoeffs) {
383 String loaderName = getClass().getName();
384 loaderName = loaderName.substring(loaderName.lastIndexOf('.') + 1);
385 throw new OrekitException(OrekitMessages.UNEXPECTED_FILE_FORMAT_ERROR_FOR_LOADER,
386 name, loaderName);
387 }
388
389 setRawCoefficients(normalized, c, s, name);
390 setTideSystem(tideSystem);
391 setReadComplete(true);
392
393 }
394
395
396
397
398
399
400
401
402
403
404
405
406
407 public RawSphericalHarmonicsProvider getProvider(final boolean wantNormalized,
408 final int degree, final int order) {
409
410 RawSphericalHarmonicsProvider provider = getConstantProvider(wantNormalized, degree, order);
411 if (cTrend.isEmpty() && cCos.isEmpty()) {
412
413 return provider;
414 }
415
416 if (!cTrend.isEmpty()) {
417
418
419 final double[][] cArrayTrend = toArray(cTrend);
420 final double[][] sArrayTrend = toArray(sTrend);
421 rescale(1.0 / Constants.JULIAN_YEAR, normalized, cArrayTrend, sArrayTrend, wantNormalized, cArrayTrend, sArrayTrend);
422 provider = new SecularTrendSphericalHarmonics(provider, referenceDate, cArrayTrend, sArrayTrend);
423
424 }
425
426 for (final Map.Entry<Double, List<List<Double>>> entry : cCos.entrySet()) {
427
428 final double period = entry.getKey();
429
430
431 final double[][] cArrayCos = toArray(cCos.get(period));
432 final double[][] sArrayCos = toArray(sCos.get(period));
433 final double[][] cArraySin = toArray(cSin.get(period));
434 final double[][] sArraySin = toArray(sSin.get(period));
435 rescale(1.0, normalized, cArrayCos, sArrayCos, wantNormalized, cArrayCos, sArrayCos);
436 rescale(1.0, normalized, cArraySin, sArraySin, wantNormalized, cArraySin, sArraySin);
437 provider = new PulsatingSphericalHarmonics(provider, period * Constants.JULIAN_YEAR,
438 cArrayCos, cArraySin, sArrayCos, sArraySin);
439
440 }
441
442 return provider;
443
444 }
445
446 }