AstronomicalAmplitudeReader.java
/* Copyright 2002-2024 CS GROUP
* Licensed to CS GROUP (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.forces.gravity.potential;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.hipparchus.util.FastMath;
import org.orekit.data.DataLoader;
import org.orekit.errors.OrekitException;
import org.orekit.errors.OrekitMessages;
/**
* Parser for tides astronomical amplitude H<sub>f</sub>.
* @author Luc Maisonobe
* @since 6.1
*/
public class AstronomicalAmplitudeReader implements DataLoader {
/** Pattern for optional fields (either nothing or non-space characters). */
private static final String OPTIONAL_FIELD_PATTERN = "\\S*";
/** Pattern for fields with Doodson number. */
private static final String DOODSON_TYPE_PATTERN = "\\p{Digit}{2,3}[.,]\\p{Digit}{3}";
/** Pattern for fields with real type. */
private static final String REAL_TYPE_PATTERN =
"[-+]?(?:(?:\\p{Digit}+(?:\\.\\p{Digit}*)?)|(?:\\.\\p{Digit}+))(?:[eE][-+]?\\p{Digit}+)?";
/** Pattern for regular data. */
private static final Pattern PATTERN = Pattern.compile("[.,]");
/** Regular expression for supported files names. */
private final String supportedNames;
/** Pattern for regular data lines. */
private final Pattern regularLinePattern;
/** Doodson number column. */
private final int columnDoodson;
/** H<sub>f</sub> column. */
private final int columnHf;
/** Scaling factor for astronomical amplitude. */
private final double scale;
/** Amplitudes map. */
private final Map<Integer, Double> amplitudesMap;
/** Simple constructor.
* @param supportedNames regular expression for supported files names
* @param columns number of columns
* @param columnDoodson Doodson number column (counting from 1)
* @param columnHf H<sub>f</sub> column (counting from 1)
* @param scale scaling factor for astronomical amplitude
*/
public AstronomicalAmplitudeReader(final String supportedNames, final int columns,
final int columnDoodson, final int columnHf,
final double scale) {
// build the pattern for the regular data lines
final StringBuilder builder = new StringBuilder("^\\p{Space}*");
for (int i = 1; i <= columns; ++i) {
builder.append("(");
if (i == columnDoodson) {
builder.append(DOODSON_TYPE_PATTERN);
} else if (i == columnHf) {
builder.append(REAL_TYPE_PATTERN);
} else {
builder.append(OPTIONAL_FIELD_PATTERN);
}
builder.append(")");
builder.append(i < FastMath.max(columnDoodson, columnHf) ? "\\p{Space}+" : "\\p{Space}*");
}
builder.append('$');
this.regularLinePattern = Pattern.compile(builder.toString());
this.supportedNames = supportedNames;
this.columnDoodson = columnDoodson;
this.columnHf = columnHf;
this.scale = scale;
this.amplitudesMap = new HashMap<>();
}
/** Get the regular expression for supported files names.
* @return regular expression for supported files names
*/
public String getSupportedNames() {
return supportedNames;
}
/** {@inheritDoc} */
@Override
public boolean stillAcceptsData() {
return amplitudesMap.isEmpty();
}
/** {@inheritDoc} */
@Override
public void loadData(final InputStream input, final String name)
throws IOException {
int lineNumber = 0;
String line = null;
// parse the file
try (BufferedReader r = new BufferedReader(new InputStreamReader(input, StandardCharsets.UTF_8))) {
for (line = r.readLine(); line != null; line = r.readLine()) {
++lineNumber;
// replace unicode minus sign ('−') by regular hyphen ('-') for parsing
// such unicode characters occur in tables that are copy-pasted from PDF files
line = line.replace('\u2212', '-');
final Matcher regularMatcher = regularLinePattern.matcher(line);
if (regularMatcher.matches()) {
// we have found a regular data line
final int doodson = Integer.parseInt(PATTERN.matcher(regularMatcher.group(columnDoodson)).replaceAll(""));
final double hf = scale * Double.parseDouble(regularMatcher.group(columnHf));
amplitudesMap.put(doodson, hf);
}
}
} catch (NumberFormatException nfe) {
throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
lineNumber, name, line);
}
if (amplitudesMap.isEmpty()) {
throw new OrekitException(OrekitMessages.NOT_A_SUPPORTED_IERS_DATA_FILE, name);
}
}
/** Get astronomical amplitudes map.
* @return an unmodifiable map containing astronomical amplitudes H<sub>f</sub>
* from a Doodson number key
*/
public Map<Integer, Double> getAstronomicalAmplitudesMap() {
return Collections.unmodifiableMap(amplitudesMap);
}
}