OceanTidesReader.java

  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. import java.util.ArrayList;
  19. import java.util.Arrays;
  20. import java.util.HashMap;
  21. import java.util.List;
  22. import java.util.Map;

  23. import org.hipparchus.util.FastMath;
  24. import org.orekit.data.DataLoader;
  25. import org.orekit.errors.OrekitException;
  26. import org.orekit.errors.OrekitMessages;

  27. /** Reader for ocean tides coefficients.
  28.  * @author Luc Maisonobe
  29.  * @see OceanTidesWave
  30.  * @since 6.1
  31.  */
  32. public abstract class OceanTidesReader implements DataLoader {

  33.     /** Regular expression for supported files names. */
  34.     private final String supportedNames;

  35.     /** Maximal degree to parse. */
  36.     private int maxParseDegree;

  37.     /** Maximal order to parse. */
  38.     private int maxParseOrder;

  39.     /** Loaded waves. */
  40.     private List<OceanTidesWave> waves;

  41.     /** Name name of the parsed file (or zip entry). */
  42.     private String name;

  43.     /** Triangular arrays to hold all coefficients. */
  44.     private Map<Integer, double[][][]> coefficients;

  45.     /** Max degree encountered up to now. */
  46.     private int maxDegree;

  47.     /** Max order encountered up to now. */
  48.     private int maxOrder;

  49.     /** Simple constructor.
  50.      * @param supportedNames regular expression for supported files names
  51.      */
  52.     public OceanTidesReader(final String supportedNames) {
  53.         this.supportedNames = supportedNames;
  54.         this.maxParseDegree = Integer.MAX_VALUE;
  55.         this.maxParseOrder  = Integer.MAX_VALUE;
  56.         this.waves          = new ArrayList<>();
  57.     }

  58.     /** Get the regular expression for supported files names.
  59.      * @return regular expression for supported files names
  60.      */
  61.     public String getSupportedNames() {
  62.         return supportedNames;
  63.     }

  64.     /** Set the degree limit for the next file parsing.
  65.      * @param maxParseDegree maximal degree to parse (may be safely
  66.      * set to {@link Integer#MAX_VALUE} to parse all available coefficients)
  67.      */
  68.     public void setMaxParseDegree(final int maxParseDegree) {
  69.         this.maxParseDegree = maxParseDegree;
  70.     }

  71.     /** Get the degree limit for the next file parsing.
  72.      * @return degree limit for the next file parsing
  73.      */
  74.     public int getMaxParseDegree() {
  75.         return maxParseDegree;
  76.     }

  77.     /** Set the order limit for the next file parsing.
  78.      * @param maxParseOrder maximal order to parse (may be safely
  79.      * set to {@link Integer#MAX_VALUE} to parse all available coefficients)
  80.      */
  81.     public void setMaxParseOrder(final int maxParseOrder) {
  82.         this.maxParseOrder = maxParseOrder;
  83.     }

  84.     /** Get the order limit for the next file parsing.
  85.      * @return order limit for the next file parsing
  86.      */
  87.     public int getMaxParseOrder() {
  88.         return maxParseOrder;
  89.     }

  90.     /** {@inheritDoc} */
  91.     @Override
  92.     public boolean stillAcceptsData() {
  93.         return !(getMaxAvailableDegree() == getMaxParseDegree() && getMaxAvailableOrder() == getMaxParseOrder());
  94.     }

  95.     /** Start parsing.
  96.      * <p>
  97.      * This method must be called by subclasses when they start parsing a file
  98.      * </p>
  99.      * @param fileName name of the file (or zip entry)
  100.      */
  101.     protected void startParse(final String fileName) {
  102.         this.waves        = new ArrayList<>();
  103.         this.name         = fileName;
  104.         this.coefficients = new HashMap<>();
  105.         this.maxDegree    = -1;
  106.         this.maxOrder     = -1;
  107.     }

  108.     /** Check if coefficients can be added.
  109.      * @param n degree of the coefficients
  110.      * @param m order of the coefficients
  111.      * @return true if coefficients can be added
  112.      */
  113.     public boolean canAdd(final int n, final int m) {
  114.         maxDegree = FastMath.max(maxDegree, n);
  115.         maxOrder  = FastMath.max(maxOrder,  m);
  116.         return n <= getMaxParseDegree() && m <= getMaxParseOrder();
  117.     }

  118.     /** Add parsed coefficients.
  119.      * @param doodson Doodson number of the current wave
  120.      * @param n degree of the coefficients
  121.      * @param m order of the coefficients
  122.      * @param cPlus  C+(n,m)
  123.      * @param sPlus  S+(n,m)
  124.      * @param cMinus C-(n,m)
  125.      * @param sMinus S-(n,m)
  126.      * @param lineNumber number of the parsed line
  127.      * @param line text of the line
  128.      */
  129.     protected void addWaveCoefficients(final int doodson, final int n, final int m,
  130.                                        final double cPlus, final double sPlus,
  131.                                        final double cMinus, final double sMinus,
  132.                                        final int lineNumber, final String line) {

  133.         if (!coefficients.containsKey(doodson)) {
  134.             // prepare the triangular array to hold coefficients
  135.             final double[][][] array = new double[getMaxParseDegree() + 1][][];
  136.             for (int i = 0; i <= getMaxParseDegree(); ++i) {
  137.                 array[i] = new double[FastMath.min(i, getMaxParseOrder()) + 1][4];
  138.                 for (double[] a : array[i]) {
  139.                     Arrays.fill(a, Double.NaN);
  140.                 }
  141.             }
  142.             coefficients.put(doodson, array);
  143.         }

  144.         // store the fields
  145.         final double[] cs = coefficients.get(doodson)[n][m];
  146.         cs[0] = cPlus;
  147.         cs[1] = sPlus;
  148.         cs[2] = cMinus;
  149.         cs[3] = sMinus;

  150.     }

  151.     /** End parsing.
  152.      * <p>
  153.      * This method must be called by subclasses when they end parsing a file
  154.      * </p>
  155.      */
  156.     protected void endParse() {

  157.         // check requested degree and order
  158.         if (maxDegree < getMaxParseDegree() || maxOrder < getMaxParseOrder()) {
  159.             throw new OrekitException(OrekitMessages.OCEAN_TIDE_DATA_DEGREE_ORDER_LIMITS,
  160.                                       name, maxDegree, maxOrder);
  161.         }

  162.         for (final Map.Entry<Integer, double[][][]> entry : coefficients.entrySet()) {

  163.             // check wave degree and order
  164.             int waveDegree = -1;
  165.             int waveOrder  = -1;
  166.             for (int i = 0; i < entry.getValue().length; ++i) {
  167.                 for (int j = 0; j < entry.getValue()[i].length; ++j) {
  168.                     if (!Double.isNaN(entry.getValue()[i][j][0])) {
  169.                         waveDegree = FastMath.max(waveDegree, i);
  170.                         waveOrder  = FastMath.max(waveOrder,  j);
  171.                     }
  172.                 }
  173.             }

  174.             // create wave
  175.             waves.add(new OceanTidesWave(entry.getKey(), waveDegree, waveOrder, entry.getValue()));

  176.         }

  177.     }

  178.     /** Get the loaded waves.
  179.      * @return loaded waves
  180.      */
  181.     public List<OceanTidesWave> getWaves() {
  182.         return waves;
  183.     }

  184.    /** Get the maximal degree available in the last file parsed.
  185.     * @return maximal degree available in the last file parsed
  186.     * @since 12.0.1
  187.     */
  188.     public int getMaxAvailableDegree() {
  189.         return waves.stream().map(OceanTidesWave::getMaxDegree).max(Integer::compareTo).orElse(-1);
  190.     }

  191.     /** Get the maximal order available in the last file parsed.
  192.      * @return maximal order available in the last file parsed
  193.      * @since 12.0.1
  194.      */
  195.     public int getMaxAvailableOrder() {
  196.         return waves.stream().map(OceanTidesWave::getMaxOrder).max(Integer::compareTo).orElse(-1);
  197.     }

  198. }