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.Locale;
26 import java.util.regex.Pattern;
27
28 import org.hipparchus.util.FastMath;
29 import org.hipparchus.util.Precision;
30 import org.orekit.annotation.DefaultDataContext;
31 import org.orekit.data.DataContext;
32 import org.orekit.errors.OrekitException;
33 import org.orekit.errors.OrekitMessages;
34 import org.orekit.time.AbsoluteDate;
35 import org.orekit.time.DateComponents;
36 import org.orekit.time.TimeScale;
37 import org.orekit.utils.Constants;
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 public class SHMFormatReader extends PotentialCoefficientsReader {
54
55
56 private static final Pattern SEPARATOR = Pattern.compile("\\s+");
57
58
59 private static final String GRCOEF = "GRCOEF";
60
61
62 private static final String GRCOF2 = "GRCOF2";
63
64
65 private static final String GRDOTA = "GRDOTA";
66
67
68 private static final int EARTH = 0x1;
69
70
71 private static final int LIMITS = 0x2;
72
73
74 private static final int COEFFS = 0x4;
75
76
77 private AbsoluteDate referenceDate;
78
79
80 private Flattener dotFlattener;
81
82
83 private double[] cDot;
84
85
86 private double[] sDot;
87
88
89
90
91
92
93
94
95
96 @DefaultDataContext
97 public SHMFormatReader(final String supportedNames, final boolean missingCoefficientsAllowed) {
98 this(supportedNames, missingCoefficientsAllowed,
99 DataContext.getDefault().getTimeScales().getTT());
100 }
101
102
103
104
105
106
107
108 public SHMFormatReader(final String supportedNames,
109 final boolean missingCoefficientsAllowed,
110 final TimeScale timeScale) {
111 super(supportedNames, missingCoefficientsAllowed, timeScale);
112 reset();
113 }
114
115
116 public void loadData(final InputStream input, final String name)
117 throws IOException, ParseException, OrekitException {
118
119
120 reset();
121
122 boolean normalized = false;
123 TideSystem tideSystem = TideSystem.UNKNOWN;
124
125 Flattener flattener = null;
126 int dotDegree = -1;
127 int dotOrder = -1;
128 int flags = 0;
129 double[] c0 = null;
130 double[] s0 = null;
131 double[] c1 = null;
132 double[] s1 = null;
133 String line = null;
134 int lineNumber = 1;
135 try (BufferedReader r = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8))) {
136 line = r.readLine();
137 if (line != null &&
138 "FIRST ".equals(line.substring(0, 6)) &&
139 "SHM ".equals(line.substring(49, 56))) {
140 for (line = r.readLine(); line != null; line = r.readLine()) {
141 lineNumber++;
142 if (line.length() >= 6) {
143 final String[] tab = SEPARATOR.split(line);
144
145
146 if ("EARTH".equals(tab[0])) {
147 setMu(parseDouble(tab[1]));
148 setAe(parseDouble(tab[2]));
149 flags |= EARTH;
150 }
151
152
153 if ("SHM".equals(tab[0])) {
154
155 final int degree = FastMath.min(getMaxParseDegree(), Integer.parseInt(tab[1]));
156 final int order = FastMath.min(getMaxParseOrder(), degree);
157 flattener = new Flattener(degree, order);
158 c0 = buildFlatArray(flattener, missingCoefficientsAllowed() ? 0.0 : Double.NaN);
159 s0 = buildFlatArray(flattener, missingCoefficientsAllowed() ? 0.0 : Double.NaN);
160 c1 = buildFlatArray(flattener, 0.0);
161 s1 = buildFlatArray(flattener, 0.0);
162 final String lowerCaseLine = line.toLowerCase(Locale.US);
163 normalized = lowerCaseLine.contains("fully normalized");
164 if (lowerCaseLine.contains("exclusive permanent tide")) {
165 tideSystem = TideSystem.TIDE_FREE;
166 } else {
167 tideSystem = TideSystem.UNKNOWN;
168 }
169 flags |= LIMITS;
170 }
171
172
173 if (GRCOEF.equals(line.substring(0, 6)) || GRCOF2.equals(tab[0]) || GRDOTA.equals(tab[0])) {
174 final int i = Integer.parseInt(tab[1]);
175 final int j = Integer.parseInt(tab[2]);
176 if (flattener.withinRange(i, j)) {
177 if (GRDOTA.equals(tab[0])) {
178
179
180 parseCoefficient(tab[3], flattener, c1, i, j, "Cdot", name);
181 parseCoefficient(tab[4], flattener, s1, i, j, "Sdot", name);
182 dotDegree = FastMath.max(dotDegree, i);
183 dotOrder = FastMath.max(dotOrder, j);
184
185
186 final DateComponents localRef = new DateComponents(Integer.parseInt(tab[7].substring(0, 4)),
187 Integer.parseInt(tab[7].substring(4, 6)),
188 Integer.parseInt(tab[7].substring(6, 8)));
189 if (referenceDate == null) {
190
191 referenceDate = toDate(localRef);
192 } else if (!referenceDate.equals(toDate(localRef))) {
193 final AbsoluteDate localDate = toDate(localRef);
194 throw new OrekitException(OrekitMessages.SEVERAL_REFERENCE_DATES_IN_GRAVITY_FIELD,
195 referenceDate, localDate, name,
196 localDate.durationFrom(referenceDate));
197 }
198
199 } else {
200
201
202 parseCoefficient(tab[3], flattener, c0, i, j, "C", name);
203 parseCoefficient(tab[4], flattener, s0, i, j, "S", name);
204
205 }
206 }
207 flags |= COEFFS;
208 }
209
210 }
211 }
212 }
213 } catch (NumberFormatException nfe) {
214 throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
215 lineNumber, name, line);
216 }
217
218 if (flags != (EARTH | LIMITS | COEFFS)) {
219 String loaderName = getClass().getName();
220 loaderName = loaderName.substring(loaderName.lastIndexOf('.') + 1);
221 throw new OrekitException(OrekitMessages.UNEXPECTED_FILE_FORMAT_ERROR_FOR_LOADER,
222 name, loaderName);
223 }
224
225 if (missingCoefficientsAllowed()) {
226
227 if (Precision.equals(c0[flattener.index(0, 0)], 0.0, 0)) {
228 c0[flattener.index(0, 0)] = 1.0;
229 }
230 }
231
232
233 if (dotDegree >= 0) {
234 dotFlattener = new Flattener(dotDegree, dotOrder);
235 cDot = new double[dotFlattener.arraySize()];
236 sDot = new double[dotFlattener.arraySize()];
237 for (int n = 0; n <= dotDegree; ++n) {
238 for (int m = 0; m <= FastMath.min(n, dotOrder); ++m) {
239 cDot[dotFlattener.index(n, m)] = c1[flattener.index(n, m)];
240 sDot[dotFlattener.index(n, m)] = s1[flattener.index(n, m)];
241 }
242 }
243 }
244
245 setRawCoefficients(normalized, flattener, c0, s0, name);
246 setTideSystem(tideSystem);
247 setReadComplete(true);
248
249 }
250
251
252
253
254 private void reset() {
255 setReadComplete(false);
256 referenceDate = null;
257 dotFlattener = null;
258 cDot = null;
259 sDot = null;
260 }
261
262
263
264
265
266
267
268
269
270
271
272
273
274 public RawSphericalHarmonicsProvider getProvider(final boolean wantNormalized,
275 final int degree, final int order) {
276
277
278 RawSphericalHarmonicsProvider provider = getBaseProvider(wantNormalized, degree, order);
279
280 if (dotFlattener != null) {
281
282
283 final double scale = 1.0 / Constants.JULIAN_YEAR;
284 final Flattener rescaledFlattener = new Flattener(FastMath.min(degree, dotFlattener.getDegree()),
285 FastMath.min(order, dotFlattener.getOrder()));
286 provider = new SecularTrendSphericalHarmonics(provider, referenceDate, rescaledFlattener,
287 rescale(scale, wantNormalized, rescaledFlattener, dotFlattener, cDot),
288 rescale(scale, wantNormalized, rescaledFlattener, dotFlattener, sDot));
289
290 }
291
292 return provider;
293
294 }
295
296 }