/* Copyright 2002-2017 CS Systèmes d'Information
* Licensed to CS Systèmes d'Information (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.propagation.semianalytical.dsst.utilities;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.hipparchus.util.CombinatoricsUtils;
import org.hipparchus.util.FastMath;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
public class GammaMnsFunctionTest {
int nMax;
double[] fact;
@Test
public void testIndex()
throws NoSuchMethodException, SecurityException,
IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Method indexM = GammaMnsFunction.class.getDeclaredMethod("index",
Integer.TYPE, Integer.TYPE, Integer.TYPE);
indexM.setAccessible(true);
int i = 0;
for (int n = 0; n <= nMax; ++n) {
for (int m = 0; m <= n; ++m) {
for (int s = -n; s <= n; ++s) {
Assert.assertEquals(i++, indexM.invoke(null, m, n, s));
}
}
}
}
@Test
public void testPrecomputedRatios()
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
Field precomputedF = GammaMnsFunction.class.getDeclaredField("PRECOMPUTED_RATIOS");
precomputedF.setAccessible(true);
new GammaMnsFunction(nMax, 0.5, +1);
double[] precomputed = (double[]) precomputedF.get(null);
int i = 0;
for (int n = 0; n <= nMax; ++n) {
for (int m = 0; m <= n; ++m) {
for (int s = -n; s <= n; ++s) {
// compare against naive implementation
double r = naiveRatio(m, n, s);
Assert.assertEquals(r, precomputed[i++], 2.0e-14 * r);
}
}
}
}
@Test
public void testReallocate()
throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
Field precomputedF = GammaMnsFunction.class.getDeclaredField("PRECOMPUTED_RATIOS");
precomputedF.setAccessible(true);
precomputedF.set(null, new double[0]);
new GammaMnsFunction(nMax, 0.5, +1);
double[] orginalPrecomputed = (double[]) precomputedF.get(null);
Assert.assertEquals((nMax + 1) * (nMax + 2) * (4 * nMax + 3) / 6, orginalPrecomputed.length);
new GammaMnsFunction(nMax + 3, 0.5, +1);
double[] reallocatedPrecomputed = (double[]) precomputedF.get(null);
Assert.assertEquals((nMax + 4) * (nMax + 5) * (4 * nMax + 15) / 6, reallocatedPrecomputed.length);
for (int i = 0; i < orginalPrecomputed.length; ++i) {
Assert.assertEquals(orginalPrecomputed[i], reallocatedPrecomputed[i],
1.0e-15 * orginalPrecomputed[i]);
}
}
@Test
public void testValue() {
for (int bigI : new int[] { -1, +1 }) {
for (double gamma = 0; gamma <= 1; gamma += 1.0 / 64.0) {
GammaMnsFunction gammaMNS = new GammaMnsFunction(nMax, gamma, bigI);
for (int n = 0; n <= nMax; ++n) {
for (int m = 0; m <= n; ++m) {
for (int s = -n; s <= n; ++s) {
// compare against naive implementation
final double v = naiveValue(bigI, gamma, m, n, s);
final double g = gammaMNS.getValue(m, n, s);
if (Double.isInfinite(v)) {
Assert.assertTrue(Double.isInfinite(g));
Assert.assertTrue(v * g > 0);
} else {
Assert.assertEquals(v, g, 2.0e-14 * FastMath.abs(v));
}
}
}
}
}
}
}
private double naiveValue(final int bigI, final double gamma,
final int m, final int n, final int s) {
final double f = 1 + bigI * gamma;
if (s <= -m) {
return FastMath.pow(-1, m - s ) * FastMath.pow(2, s) * FastMath.pow(f, -bigI * m);
} else if (s < m) {
return FastMath.pow(-1, m - s ) * FastMath.pow(2, -m) * naiveRatio(m, n, s) * FastMath.pow(f, bigI * s);
} else {
return FastMath.pow(2, -s) * FastMath.pow(f, bigI * m);
}
}
private double naiveRatio(final int m, final int n, final int s) {
return (CombinatoricsUtils.factorialDouble(n + m) * CombinatoricsUtils.factorialDouble(n - m)) /
(CombinatoricsUtils.factorialDouble(n + s) * CombinatoricsUtils.factorialDouble(n - s));
}
@Before
public void setUp() {
nMax = 12;
fact = new double[2 * nMax + 1];
fact[0] = 1;
for (int i = 1; i < fact.length; ++i) {
fact[i] = i * fact[i - 1];
}
}
}