1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.orekit.propagation.semianalytical.dsst.utilities;
18
19 import java.util.Map;
20 import java.util.SortedMap;
21 import java.util.TreeMap;
22
23 import org.hipparchus.CalculusFieldElement;
24 import org.hipparchus.Field;
25 import org.hipparchus.analysis.polynomials.PolynomialFunction;
26 import org.hipparchus.analysis.polynomials.PolynomialsUtils;
27 import org.hipparchus.complex.Complex;
28 import org.hipparchus.exception.NullArgumentException;
29 import org.hipparchus.random.MersenneTwister;
30 import org.hipparchus.util.CombinatoricsUtils;
31 import org.hipparchus.util.Binary64Field;
32 import org.hipparchus.util.FastMath;
33 import org.hipparchus.util.MathArrays;
34 import org.junit.jupiter.api.Assertions;
35 import org.junit.jupiter.api.Test;
36 import org.orekit.errors.OrekitException;
37 import org.orekit.propagation.semianalytical.dsst.utilities.CoefficientsFactory.NSKey;
38
39 public class CoefficientFactoryTest {
40
41 private static final double eps0 = 0.;
42 private static final double eps10 = 1e-10;
43 private static final double eps12 = 1e-12;
44
45
46 private static Map<NSKey, PolynomialFunction> QNS_MAP = new TreeMap<NSKey, PolynomialFunction>();
47
48 @Test
49 public void testVns() {
50 final int order = 100;
51 SortedMap<NSKey, Double> Vns = CoefficientsFactory.computeVns(order);
52
53
54 for (int i = 0; i < order; i++) {
55 for (int j = 0; j < i + 1; j++) {
56 if ((i - j) % 2 != 0) {
57 Assertions.assertEquals(0d, Vns.get(new NSKey(i, j)), eps0);
58 }
59 }
60 }
61
62
63 Assertions.assertEquals(1, Vns.get(new NSKey(0, 0)), eps0);
64 Assertions.assertEquals(0.5, Vns.get(new NSKey(1, 1)), eps0);
65 Assertions.assertEquals(-0.5, Vns.get(new NSKey(2, 0)), eps0);
66 Assertions.assertEquals(1 / 8d, Vns.get(new NSKey(2, 2)), eps0);
67 Assertions.assertEquals(-1 / 8d, Vns.get(new NSKey(3, 1)), eps0);
68 Assertions.assertEquals(1 / 48d, Vns.get(new NSKey(3, 3)), eps0);
69 Assertions.assertEquals(3 / 8d, Vns.get(new NSKey(4, 0)), eps0);
70 Assertions.assertEquals(-1 / 48d, Vns.get(new NSKey(4, 2)), eps0);
71 Assertions.assertEquals(1 / 384d, Vns.get(new NSKey(4, 4)), eps0);
72 Assertions.assertEquals(1 / 16d, Vns.get(new NSKey(5, 1)), eps0);
73 Assertions.assertEquals(-1 / 384d, Vns.get(new NSKey(5, 3)), eps0);
74 Assertions.assertEquals(1 / 3840d, Vns.get(new NSKey(5, 5)), eps0);
75 Assertions.assertEquals(Vns.lastKey().getN(), order - 1);
76 Assertions.assertEquals(Vns.lastKey().getS(), order - 1);
77 }
78
79
80
81
82
83 @Test
84 public void testVmns() {
85 Assertions.assertEquals(getVmns2(0, 0, 0), CoefficientsFactory.getVmns(0, 0, 0), eps0);
86 Assertions.assertEquals(getVmns2(0, 1, 1), CoefficientsFactory.getVmns(0, 1, 1), eps0);
87 Assertions.assertEquals(getVmns2(0, 2, 2), CoefficientsFactory.getVmns(0, 2, 2), eps0);
88 Assertions.assertEquals(getVmns2(0, 3, 1), CoefficientsFactory.getVmns(0, 3, 1), eps0);
89 Assertions.assertEquals(getVmns2(0, 3, 3), CoefficientsFactory.getVmns(0, 3, 3), eps0);
90 Assertions.assertEquals(getVmns2(2, 2, 2), CoefficientsFactory.getVmns(2, 2, 2), eps0);
91 final double vmnsp = getVmns2(12, 26, 20);
92 Assertions.assertEquals(vmnsp,
93 CoefficientsFactory.getVmns(12, 26, 20),
94 FastMath.abs(eps12 * vmnsp));
95 final double vmnsm = getVmns2(12, 27, -21);
96 Assertions.assertEquals(vmnsm,
97 CoefficientsFactory.getVmns(12, 27, -21),
98 Math.abs(eps12 * vmnsm));
99 }
100
101
102 @Test
103 public void testVmnsError() {
104 Assertions.assertThrows(OrekitException.class, () -> {
105
106 CoefficientsFactory.getVmns(3, 2, 1);
107 });
108 }
109
110 @Test
111 public void testKey() {
112
113 NSKey key21 = new NSKey(2, 1);
114 Assertions.assertEquals(key21, key21);
115 Assertions.assertEquals(key21, new NSKey(2, 1));
116 Assertions.assertNotEquals(key21, null);
117 Assertions.assertNotEquals(key21, new NSKey(2, 0));
118 Assertions.assertNotEquals(key21, new NSKey(3, 1));
119 Assertions.assertEquals(-1719365209, key21.hashCode());
120 Assertions.assertEquals(-1719365465, new NSKey(3, 1).hashCode());
121 }
122
123
124
125
126
127 @Test
128 public void testQns() {
129 Assertions.assertEquals(1., getQnsPolynomialValue(0, 0, 0), 0.);
130
131 final int nmax = 10;
132 final int smax = 10;
133 final MersenneTwister random = new MersenneTwister(123456789);
134 for (int g = 0; g < 1000; g++) {
135 final double gamma = random.nextDouble();
136 double[][] qns = CoefficientsFactory.computeQns(gamma, nmax, smax);
137 for (int n = 0; n <= nmax; n++) {
138 final int sdim = FastMath.min(smax + 2, n);
139 for (int s = 0; s <= sdim; s++) {
140 final double qp = getQnsPolynomialValue(gamma, n, s);
141 Assertions.assertEquals(qns[n][s], qp, FastMath.abs(eps10 * qns[n][s]));
142 }
143 }
144 }
145 }
146
147 @Test
148 public void testQnsField() {
149 doTestQnsField(Binary64Field.getInstance());
150 }
151
152
153
154
155
156 private <T extends CalculusFieldElement<T>> void doTestQnsField(Field<T> field) {
157 final T zero = field.getZero();
158 Assertions.assertEquals(1., getQnsPolynomialValue(0, 0, 0), 0.);
159
160 final int nmax = 10;
161 final int smax = 10;
162 final MersenneTwister random = new MersenneTwister(123456789);
163 for (int g = 0; g < 1000; g++) {
164 final T gamma = zero.add(random.nextDouble());
165 T[][] qns = CoefficientsFactory.computeQns(gamma, nmax, smax);
166 for (int n = 0; n <= nmax; n++) {
167 final int sdim = FastMath.min(smax + 2, n);
168 for (int s = 0; s <= sdim; s++) {
169 final T qp = getQnsPolynomialValue(gamma, n, s);
170 Assertions.assertEquals(qns[n][s].getReal(), qp.getReal(), FastMath.abs(qns[n][s].multiply(eps10)).getReal());
171 }
172 }
173 }
174 }
175
176
177
178
179 @Test
180 public void testGsHs() {
181 final int s = 50;
182 final MersenneTwister random = new MersenneTwister(123456789);
183 for (int i = 0; i < 10; i++) {
184 final double k = random.nextDouble();
185 final double h = random.nextDouble();
186 final double a = random.nextDouble();
187 final double b = random.nextDouble();
188 final double[][] GH = CoefficientsFactory.computeGsHs(k, h, a, b, s);
189 for (int j = 1; j < s; j++) {
190 final double[] GsHs = getGsHs(k, h, a, b, j);
191 Assertions.assertEquals(GsHs[0], GH[0][j], FastMath.abs(eps12 * GsHs[0]));
192 Assertions.assertEquals(GsHs[1], GH[1][j], FastMath.abs(eps12 * GsHs[1]));
193 }
194 }
195 }
196
197 @Test
198 public void testGsHsField() {
199 doTestGsHsField(Binary64Field.getInstance());
200 }
201
202
203
204
205 private <T extends CalculusFieldElement<T>> void doTestGsHsField(Field<T> field) {
206 final T zero = field.getZero();
207 final int s = 50;
208 final MersenneTwister random = new MersenneTwister(123456789);
209 for (int i = 0; i < 10; i++) {
210 final T k = zero.add(random.nextDouble());
211 final T h = zero.add(random.nextDouble());
212 final T a = zero.add(random.nextDouble());
213 final T b = zero.add(random.nextDouble());
214 final T[][] GH = CoefficientsFactory.computeGsHs(k, h, a, b, s, field);
215 for (int j = 1; j < s; j++) {
216 final T[] GsHs = getGsHs(k, h, a, b, j, field);
217 Assertions.assertEquals(GsHs[0].getReal(), GH[0][j].getReal(), FastMath.abs(GsHs[0].multiply(eps12)).getReal());
218 Assertions.assertEquals(GsHs[1].getReal(), GH[1][j].getReal(), FastMath.abs(GsHs[1].multiply(eps12)).getReal());
219 }
220 }
221 }
222
223
224
225
226 private static double getVmns2(final int m,
227 final int n,
228 final int s) {
229 double vmsn = 0d;
230 if ((n - s) % 2 == 0) {
231 final int coef = (s > 0 || s % 2 == 0) ? 1 : -1;
232 final int ss = (s > 0) ? s : -s;
233 final double num = FastMath.pow(-1, (n - ss) / 2) *
234 CombinatoricsUtils.factorialDouble(n + ss) *
235 CombinatoricsUtils.factorialDouble(n - ss);
236 final double den = FastMath.pow(2, n) *
237 CombinatoricsUtils.factorialDouble(n - m) *
238 CombinatoricsUtils.factorialDouble((n + ss) / 2) *
239 CombinatoricsUtils.factorialDouble((n - ss) / 2);
240 vmsn = coef * num / den;
241 }
242 return vmsn;
243 }
244
245
246
247
248
249
250
251
252
253
254
255 private static double getQnsPolynomialValue(final double gamma, final int n, final int s) {
256 PolynomialFunction derivative;
257 if (QNS_MAP.containsKey(new NSKey(n, s))) {
258 derivative = QNS_MAP.get(new NSKey(n, s));
259 } else {
260 final PolynomialFunction legendre = PolynomialsUtils.createLegendrePolynomial(n);
261 derivative = legendre;
262 for (int i = 0; i < s; i++) {
263 derivative = (PolynomialFunction) derivative.polynomialDerivative();
264 }
265 QNS_MAP.put(new NSKey(n, s), derivative);
266 }
267 return derivative.value(gamma);
268 }
269
270
271
272
273
274
275
276
277
278
279
280 private static <T extends CalculusFieldElement<T>> T getQnsPolynomialValue(final T gamma, final int n, final int s) {
281 PolynomialFunction derivative;
282 if (QNS_MAP.containsKey(new NSKey(n, s))) {
283 derivative = QNS_MAP.get(new NSKey(n, s));
284 } else {
285 final PolynomialFunction legendre = PolynomialsUtils.createLegendrePolynomial(n);
286 derivative = legendre;
287 for (int i = 0; i < s; i++) {
288 derivative = (PolynomialFunction) derivative.polynomialDerivative();
289 }
290 QNS_MAP.put(new NSKey(n, s), derivative);
291 }
292 return derivative.value(gamma);
293 }
294
295
296
297
298
299
300
301
302
303
304
305 private static double[] getGsHs(final double k, final double h,
306 final double a, final double b, final int s) {
307 final Complex as = new Complex(k, h).pow(s);
308 final Complex bs = new Complex(a, -b).pow(s);
309 final Complex asbs = as.multiply(bs);
310 return new double[] {asbs.getReal(), asbs.getImaginary()};
311 }
312
313
314
315
316
317
318
319
320
321
322
323 private static <T extends CalculusFieldElement<T>> T[] getGsHs(final T k, final T h,
324 final T a, final T b, final int s,
325 final Field<T> field) {
326 final FieldComplex<T> as = new FieldComplex<>(k, h).pow(s);
327 final FieldComplex<T> bs = new FieldComplex<>(a, b.negate()).pow(s);
328 final FieldComplex<T> asbs = as.multiply(bs);
329 final T[] values = MathArrays.buildArray(field, 2);
330 values[0] = asbs.getReal();
331 values[1] = asbs.getImaginary();
332 return values;
333 }
334
335 private static class FieldComplex <T extends CalculusFieldElement<T>> {
336
337
338 private final T imaginary;
339
340
341 private final T real;
342
343
344
345
346
347
348
349 FieldComplex(final T real, final T imaginary) {
350 this.real = real;
351 this.imaginary = imaginary;
352 }
353
354
355
356
357
358
359 public T getReal() {
360 return real;
361 }
362
363
364
365
366
367
368 public T getImaginary() {
369 return imaginary;
370 }
371
372
373
374
375
376
377
378
379
380
381 protected FieldComplex<T> createComplex(final T realPart, final T imaginaryPart) {
382 return new FieldComplex<>(realPart, imaginaryPart);
383 }
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400 public FieldComplex<T> multiply(final FieldComplex<T> factor) throws NullArgumentException {
401 return createComplex(real.multiply(factor.real).subtract(imaginary.multiply(factor.imaginary)),
402 real.multiply(factor.imaginary).add(imaginary.multiply(factor.real)));
403 }
404
405
406
407
408
409
410
411
412
413 public FieldComplex<T> multiply(final int factor) {
414 return createComplex(real.multiply(factor), imaginary.multiply(factor));
415 }
416
417
418
419
420
421
422
423
424 public FieldComplex<T> pow(int x) {
425 return this.log().multiply(x).exp();
426 }
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462 public FieldComplex<T> log() {
463 return createComplex(FastMath.log(abs()),
464 FastMath.atan2(imaginary, real));
465 }
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498 public FieldComplex<T> exp() {
499 T expReal = FastMath.exp(real);
500 return createComplex(expReal.multiply(FastMath.cos(imaginary)),
501 expReal.multiply(FastMath.sin(imaginary)));
502 }
503
504
505
506
507
508
509
510
511
512 public T abs() {
513 if (FastMath.abs(real).getReal() < FastMath.abs(imaginary).getReal()) {
514 if (imaginary.getReal() == 0.0) {
515 return FastMath.abs(real);
516 }
517 T q = real.divide(imaginary);
518 return FastMath.abs(imaginary).multiply(FastMath.sqrt(q.multiply(q).add(1.)));
519 } else {
520 if (real.getReal() == 0.0) {
521 return FastMath.abs(imaginary);
522 }
523 T q = imaginary.divide(real);
524 return FastMath.abs(real).multiply(FastMath.sqrt(q.multiply(q).add(1.)));
525 }
526 }
527
528 }
529 }