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.propagation.semianalytical.dsst.utilities;
18
19 import org.hipparchus.CalculusFieldElement;
20 import org.hipparchus.Field;
21 import org.hipparchus.complex.Complex;
22 import org.hipparchus.exception.NullArgumentException;
23
24 import java.util.ArrayList;
25 import java.util.List;
26
27 /** Compute the S<sub>j</sub>(k, h) and the C<sub>j</sub>(k, h) series
28 * and their partial derivatives with respect to k and h.
29 * <p>
30 * Those series are given in Danielson paper by expression 2.5.3-(5):
31 *
32 * <p> C<sub>j</sub>(k, h) + i S<sub>j</sub>(k, h) = (k+ih)<sup>j</sup>
33 *
34 * <p>
35 * The C<sub>j</sub>(k, h) and the S<sub>j</sub>(k, h) elements are store as an
36 * {@link ArrayList} of {@link Complex} number, the C<sub>j</sub>(k, h) being
37 * represented by the real and the S<sub>j</sub>(k, h) by the imaginary part.
38 * @param <T> type of the field elements
39 */
40 public class FieldCjSjCoefficient <T extends CalculusFieldElement<T>> {
41
42 /** Zero for initialization. /*/
43 private final T zero;
44
45 /** Last computed order j. */
46 private int jLast;
47
48 /** Complex base (k + ih) of the C<sub>j</sub>, S<sub>j</sub> series. */
49 private final FieldComplex<T> kih;
50
51 /** List of computed elements. */
52 private final List<FieldComplex<T>> cjsj;
53
54 /** C<sub>j</sub>(k, h) and S<sub>j</sub>(k, h) constructor.
55 * @param k k value
56 * @param h h value
57 * @param field field for fieldElements
58 */
59 public FieldCjSjCoefficient(final T k, final T h, final Field<T> field) {
60 zero = field.getZero();
61 kih = new FieldComplex<>(k, h);
62 cjsj = new ArrayList<>();
63 cjsj.add(new FieldComplex<>(zero.newInstance(1.), zero));
64 cjsj.add(kih);
65 jLast = 1;
66 }
67
68 /** Get the C<sub>j</sub> coefficient.
69 * @param j order
70 * @return C<sub>j</sub>
71 */
72 public T getCj(final int j) {
73 if (j > jLast) {
74 // Update to order j
75 updateCjSj(j);
76 }
77 return cjsj.get(j).getReal();
78 }
79
80 /** Get the S<sub>j</sub> coefficient.
81 * @param j order
82 * @return S<sub>j</sub>
83 */
84 public T getSj(final int j) {
85 if (j > jLast) {
86 // Update to order j
87 updateCjSj(j);
88 }
89 return cjsj.get(j).getImaginary();
90 }
91
92 /** Get the dC<sub>j</sub> / dk coefficient.
93 * @param j order
94 * @return dC<sub>j</sub> / d<sub>k</sub>
95 */
96 public T getDcjDk(final int j) {
97 return j == 0 ? zero : getCj(j - 1).multiply(j);
98 }
99
100 /** Get the dS<sub>j</sub> / dk coefficient.
101 * @param j order
102 * @return dS<sub>j</sub> / d<sub>k</sub>
103 */
104 public T getDsjDk(final int j) {
105 return j == 0 ? zero : getSj(j - 1).multiply(j);
106 }
107
108 /** Get the dC<sub>j</sub> / dh coefficient.
109 * @param j order
110 * @return dC<sub>i</sub> / d<sub>k</sub>
111 */
112 public T getDcjDh(final int j) {
113 return j == 0 ? zero : getSj(j - 1).multiply(-j);
114 }
115
116 /** Get the dS<sub>j</sub> / dh coefficient.
117 * @param j order
118 * @return dS<sub>j</sub> / d<sub>h</sub>
119 */
120 public T getDsjDh(final int j) {
121 return j == 0 ? zero : getCj(j - 1).multiply(j);
122 }
123
124 /** Update the cjsj up to order j.
125 * @param j order
126 */
127 private void updateCjSj(final int j) {
128 FieldComplex<T> last = cjsj.get(cjsj.size() - 1);
129 for (int i = jLast; i < j; i++) {
130 final FieldComplex<T> next = last.multiply(kih);
131 cjsj.add(next);
132 last = next;
133 }
134 jLast = j;
135 }
136
137 private static class FieldComplex <T extends CalculusFieldElement<T>> {
138
139 /** The imaginary part. */
140 private final T imaginary;
141
142 /** The real part. */
143 private final T real;
144
145 /**
146 * Create a complex number given the real and imaginary parts.
147 *
148 * @param real Real part.
149 * @param imaginary Imaginary part.
150 */
151 FieldComplex(final T real, final T imaginary) {
152 this.real = real;
153 this.imaginary = imaginary;
154 }
155
156 /**
157 * Access the real part.
158 *
159 * @return the real part.
160 */
161 public T getReal() {
162 return real;
163 }
164
165 /**
166 * Access the imaginary part.
167 *
168 * @return the imaginary part.
169 */
170 public T getImaginary() {
171 return imaginary;
172 }
173
174 /**
175 * Create a complex number given the real and imaginary parts.
176 *
177 * @param realPart Real part.
178 * @param imaginaryPart Imaginary part.
179 * @return a new complex number instance.
180 *
181 */
182 protected FieldComplex<T> createComplex(final T realPart, final T imaginaryPart) {
183 return new FieldComplex<>(realPart, imaginaryPart);
184 }
185
186 /**
187 * Returns a {@code Complex} whose value is {@code this * factor}.
188 * Implements preliminary checks for {@code NaN} and infinity followed by
189 * the definitional formula:
190 * <p>
191 * {@code (a + bi)(c + di) = (ac - bd) + (ad + bc)i}
192 * </p>
193 * <p>
194 * Returns finite values in components of the result per the definitional
195 * formula in all remaining cases.</p>
196 *
197 * @param factor value to be multiplied by this {@code Complex}.
198 * @return {@code this * factor}.
199 * @throws NullArgumentException if {@code factor} is {@code null}.
200 */
201 public FieldComplex<T> multiply(final FieldComplex<T> factor) throws NullArgumentException {
202 return createComplex(real.multiply(factor.real).subtract(imaginary.multiply(factor.imaginary)),
203 real.multiply(factor.imaginary).add(imaginary.multiply(factor.real)));
204 }
205 }
206 }