1 /* Copyright 2002-2025 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.forces.gravity.potential;
18
19 import java.util.ArrayList;
20 import java.util.Arrays;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24
25 import org.hipparchus.util.FastMath;
26 import org.orekit.data.DataLoader;
27 import org.orekit.errors.OrekitException;
28 import org.orekit.errors.OrekitMessages;
29
30 /** Reader for ocean tides coefficients.
31 * @author Luc Maisonobe
32 * @see OceanTidesWave
33 * @since 6.1
34 */
35 public abstract class OceanTidesReader implements DataLoader {
36
37 /** Regular expression for supported files names. */
38 private final String supportedNames;
39
40 /** Maximal degree to parse. */
41 private int maxParseDegree;
42
43 /** Maximal order to parse. */
44 private int maxParseOrder;
45
46 /** Loaded waves. */
47 private List<OceanTidesWave> waves;
48
49 /** Name name of the parsed file (or zip entry). */
50 private String name;
51
52 /** Triangular arrays to hold all coefficients. */
53 private Map<Integer, double[][][]> coefficients;
54
55 /** Max degree encountered up to now. */
56 private int maxDegree;
57
58 /** Max order encountered up to now. */
59 private int maxOrder;
60
61 /** Simple constructor.
62 * @param supportedNames regular expression for supported files names
63 */
64 protected OceanTidesReader(final String supportedNames) {
65 this.supportedNames = supportedNames;
66 this.maxParseDegree = Integer.MAX_VALUE;
67 this.maxParseOrder = Integer.MAX_VALUE;
68 this.waves = new ArrayList<>();
69 }
70
71 /** Get the regular expression for supported files names.
72 * @return regular expression for supported files names
73 */
74 public String getSupportedNames() {
75 return supportedNames;
76 }
77
78 /** Set the degree limit for the next file parsing.
79 * @param maxParseDegree maximal degree to parse (may be safely
80 * set to {@link Integer#MAX_VALUE} to parse all available coefficients)
81 */
82 public void setMaxParseDegree(final int maxParseDegree) {
83 this.maxParseDegree = maxParseDegree;
84 }
85
86 /** Get the degree limit for the next file parsing.
87 * @return degree limit for the next file parsing
88 */
89 public int getMaxParseDegree() {
90 return maxParseDegree;
91 }
92
93 /** Set the order limit for the next file parsing.
94 * @param maxParseOrder maximal order to parse (may be safely
95 * set to {@link Integer#MAX_VALUE} to parse all available coefficients)
96 */
97 public void setMaxParseOrder(final int maxParseOrder) {
98 this.maxParseOrder = maxParseOrder;
99 }
100
101 /** Get the order limit for the next file parsing.
102 * @return order limit for the next file parsing
103 */
104 public int getMaxParseOrder() {
105 return maxParseOrder;
106 }
107
108 /** {@inheritDoc} */
109 @Override
110 public boolean stillAcceptsData() {
111 return !(getMaxAvailableDegree() == getMaxParseDegree() && getMaxAvailableOrder() == getMaxParseOrder());
112 }
113
114 /** Start parsing.
115 * <p>
116 * This method must be called by subclasses when they start parsing a file
117 * </p>
118 * @param fileName name of the file (or zip entry)
119 */
120 protected void startParse(final String fileName) {
121 this.waves = new ArrayList<>();
122 this.name = fileName;
123 this.coefficients = new HashMap<>();
124 this.maxDegree = -1;
125 this.maxOrder = -1;
126 }
127
128 /** Check if coefficients can be added.
129 * @param n degree of the coefficients
130 * @param m order of the coefficients
131 * @return true if coefficients can be added
132 */
133 public boolean canAdd(final int n, final int m) {
134 maxDegree = FastMath.max(maxDegree, n);
135 maxOrder = FastMath.max(maxOrder, m);
136 return n <= getMaxParseDegree() && m <= getMaxParseOrder();
137 }
138
139 /** Add parsed coefficients.
140 * @param doodson Doodson number of the current wave
141 * @param n degree of the coefficients
142 * @param m order of the coefficients
143 * @param cPlus C+(n,m)
144 * @param sPlus S+(n,m)
145 * @param cMinus C-(n,m)
146 * @param sMinus S-(n,m)
147 * @param lineNumber number of the parsed line
148 * @param line text of the line
149 */
150 protected void addWaveCoefficients(final int doodson, final int n, final int m,
151 final double cPlus, final double sPlus,
152 final double cMinus, final double sMinus,
153 final int lineNumber, final String line) {
154
155 if (!coefficients.containsKey(doodson)) {
156 // prepare the triangular array to hold coefficients
157 final double[][][] array = new double[getMaxParseDegree() + 1][][];
158 for (int i = 0; i <= getMaxParseDegree(); ++i) {
159 array[i] = new double[FastMath.min(i, getMaxParseOrder()) + 1][4];
160 for (double[] a : array[i]) {
161 Arrays.fill(a, Double.NaN);
162 }
163 }
164 coefficients.put(doodson, array);
165 }
166
167 // store the fields
168 final double[] cs = coefficients.get(doodson)[n][m];
169 cs[0] = cPlus;
170 cs[1] = sPlus;
171 cs[2] = cMinus;
172 cs[3] = sMinus;
173
174 }
175
176 /** End parsing.
177 * <p>
178 * This method must be called by subclasses when they end parsing a file
179 * </p>
180 */
181 protected void endParse() {
182
183 // check requested degree and order
184 if (maxDegree < getMaxParseDegree() || maxOrder < getMaxParseOrder()) {
185 throw new OrekitException(OrekitMessages.OCEAN_TIDE_DATA_DEGREE_ORDER_LIMITS,
186 name, maxDegree, maxOrder);
187 }
188
189 for (final Map.Entry<Integer, double[][][]> entry : coefficients.entrySet()) {
190
191 // check wave degree and order
192 int waveDegree = -1;
193 int waveOrder = -1;
194 for (int i = 0; i < entry.getValue().length; ++i) {
195 for (int j = 0; j < entry.getValue()[i].length; ++j) {
196 if (!Double.isNaN(entry.getValue()[i][j][0])) {
197 waveDegree = FastMath.max(waveDegree, i);
198 waveOrder = FastMath.max(waveOrder, j);
199 }
200 }
201 }
202
203 // create wave
204 waves.add(new OceanTidesWave(entry.getKey(), waveDegree, waveOrder, entry.getValue()));
205
206 }
207
208 }
209
210 /** Get the loaded waves.
211 * @return loaded waves
212 */
213 public List<OceanTidesWave> getWaves() {
214 return waves;
215 }
216
217 /** Get the maximal degree available in the last file parsed.
218 * @return maximal degree available in the last file parsed
219 * @since 12.0.1
220 */
221 public int getMaxAvailableDegree() {
222 return waves.stream().map(OceanTidesWave::getMaxDegree).max(Integer::compareTo).orElse(-1);
223 }
224
225 /** Get the maximal order available in the last file parsed.
226 * @return maximal order available in the last file parsed
227 * @since 12.0.1
228 */
229 public int getMaxAvailableOrder() {
230 return waves.stream().map(OceanTidesWave::getMaxOrder).max(Integer::compareTo).orElse(-1);
231 }
232
233 }