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 org.hipparchus.util.FastMath; 20 import org.orekit.errors.OrekitException; 21 import org.orekit.errors.OrekitMessages; 22 23 /** Utility for converting between (degree, order) indices and one-dimensional flatten index. 24 * <p> 25 * The outer loop in {@link org.orekit.forces.gravity.HolmesFeatherstoneAttractionModel} 26 * if in decreasing order and the inner loop is in increasing degree (starting 27 * from the diagonal). This utility converts (degree, order) indices into a flatten index 28 * in a one-dimensional array that increases as these loops are performed. 29 * This means the first element of the one-dimensional array corresponds to diagonal 30 * element at maximum order and the last element corresponds to order 0 and maximum degree. 31 * </p> 32 * @author Luc Maisonobe 33 * @since 11.1 34 */ 35 class Flattener { 36 37 /** Degree of the spherical harmonics. */ 38 private final int degree; 39 40 /** Order of the spherical harmonics. */ 41 private final int order; 42 43 /** Number of high order cells dropped in the triangular array. */ 44 private final int dropped; 45 46 /** Simple constructor. 47 * @param degree degree of the spherical harmonics 48 * @param order order of the spherical harmonics 49 */ 50 Flattener(final int degree, final int order) { 51 this.degree = degree; 52 this.order = order; 53 this.dropped = (degree - order + 1) * (degree - order) / 2; 54 } 55 56 /** Get the degree of the spherical harmonics. 57 * @return degree of the spherical harmonics 58 */ 59 public int getDegree() { 60 return degree; 61 } 62 63 /** Get the order of the spherical harmonics. 64 * @return order of the spherical harmonics 65 */ 66 public int getOrder() { 67 return order; 68 } 69 70 /** Convert (degree, order) indices to one-dimensional flatten index. 71 * <p> 72 * As the outer loop in {@link org.orekit.forces.gravity.HolmesFeatherstoneAttractionModel} 73 * if on decreasing order and the inner loop is in increasing degree (starting 74 * from the diagonal), the flatten index increases as these loops are performed. 75 * </p> 76 * @param n degree index (must be within range, otherwise an exception is thrown) 77 * @param m order index (must be within range, otherwise an exception is thrown) 78 * @return one-dimensional flatten index 79 * @see #withinRange(int, int) 80 */ 81 public int index(final int n, final int m) { 82 if (!withinRange(n, m)) { 83 throw new OrekitException(OrekitMessages.WRONG_DEGREE_OR_ORDER, n, m, degree, order); 84 } 85 final int dm = degree - m; 86 return dm * (dm + 1) / 2 + (n - m) - dropped; 87 } 88 89 /** Get the size of a flatten array sufficient to hold all coefficients. 90 * @return size of a flatten array sufficient to hold all coefficients 91 */ 92 public int arraySize() { 93 return index(degree, 0) + 1; 94 } 95 96 /** Check if indices are within range. 97 * @param n degree 98 * @param m order 99 * @return true if indices are within limits, false otherwise 100 */ 101 public boolean withinRange(final int n, final int m) { 102 return n >= 0 && n <= degree && m >= 0 && m <= FastMath.min(n, order); 103 } 104 105 /** Flatten a triangular array. 106 * @param triangular triangular array to flatten 107 * @return flatten array 108 */ 109 public double[] flatten(final double[][] triangular) { 110 final double[] flat = new double[arraySize()]; 111 for (int n = 0; n <= getDegree(); ++n) { 112 for (int m = 0; m <= FastMath.min(n, getOrder()); ++m) { 113 flat[index(n, m)] = triangular[n][m]; 114 } 115 } 116 return flat; 117 } 118 119 }