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 }