Flattener.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 org.hipparchus.util.FastMath;
  19. import org.orekit.errors.OrekitException;
  20. import org.orekit.errors.OrekitMessages;

  21. /** Utility for converting between (degree, order) indices and one-dimensional flatten index.
  22.  * <p>
  23.  * The outer loop in {@link org.orekit.forces.gravity.HolmesFeatherstoneAttractionModel}
  24.  * if in decreasing order and the inner loop is in increasing degree (starting
  25.  * from the diagonal). This utility converts (degree, order) indices into a flatten index
  26.  * in a one-dimensional array that increases as these loops are performed.
  27.  * This means the first element of the one-dimensional array corresponds to diagonal
  28.  * element at maximum order and the last element corresponds to order 0 and maximum degree.
  29.  * </p>
  30.  * @author Luc Maisonobe
  31.  * @since 11.1
  32.  */
  33. class Flattener {

  34.     /** Degree of the spherical harmonics. */
  35.     private final int degree;

  36.     /** Order of the spherical harmonics. */
  37.     private final int order;

  38.     /** Number of high order cells dropped in the triangular array. */
  39.     private final int dropped;

  40.     /** Simple constructor.
  41.      * @param degree degree of the spherical harmonics
  42.      * @param order order of the spherical harmonics
  43.       */
  44.     Flattener(final int degree, final int order) {
  45.         this.degree  = degree;
  46.         this.order   = order;
  47.         this.dropped = (degree - order + 1) * (degree - order) / 2;
  48.     }

  49.     /** Get the degree of the spherical harmonics.
  50.      * @return degree of the spherical harmonics
  51.      */
  52.     public int getDegree() {
  53.         return degree;
  54.     }

  55.     /** Get the order of the spherical harmonics.
  56.      * @return order of the spherical harmonics
  57.      */
  58.     public int getOrder() {
  59.         return order;
  60.     }

  61.     /** Convert (degree, order) indices to one-dimensional flatten index.
  62.      * <p>
  63.      * As the outer loop in {@link org.orekit.forces.gravity.HolmesFeatherstoneAttractionModel}
  64.      * if on decreasing order and the inner loop is in increasing degree (starting
  65.      * from the diagonal), the flatten index increases as these loops are performed.
  66.      * </p>
  67.      * @param n degree index (must be within range, otherwise an exception is thrown)
  68.      * @param m order index (must be within range, otherwise an exception is thrown)
  69.      * @return one-dimensional flatten index
  70.      * @see #withinRange(int, int)
  71.      */
  72.     public int index(final int n, final int m) {
  73.         if (!withinRange(n, m)) {
  74.             throw new OrekitException(OrekitMessages.WRONG_DEGREE_OR_ORDER, n, m, degree, order);
  75.         }
  76.         final int dm = degree - m;
  77.         return dm * (dm + 1) / 2 + (n - m) - dropped;
  78.     }

  79.     /** Get the size of a flatten array sufficient to hold all coefficients.
  80.      * @return size of a flatten array sufficient to hold all coefficients
  81.      */
  82.     public int arraySize() {
  83.         return index(degree, 0) + 1;
  84.     }

  85.     /** Check if indices are within range.
  86.      * @param n degree
  87.      * @param m order
  88.      * @return true if indices are within limits, false otherwise
  89.      */
  90.     public boolean withinRange(final int n, final int m) {
  91.         return n >= 0 && n <= degree && m >= 0 && m <= FastMath.min(n, order);
  92.     }

  93.     /** Flatten a triangular array.
  94.      * @param triangular triangular array to flatten
  95.      * @return flatten array
  96.      */
  97.     public double[] flatten(final double[][] triangular) {
  98.         final double[] flat = new double[arraySize()];
  99.         for (int n = 0; n <= getDegree(); ++n) {
  100.             for (int m = 0; m <= FastMath.min(n, getOrder()); ++m) {
  101.                 flat[index(n, m)] = triangular[n][m];
  102.             }
  103.         }
  104.         return flat;
  105.     }

  106. }