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