View Javadoc
1   /*
2    * Licensed to the Hipparchus project under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The Hipparchus project 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    *      https://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.hipparchus.special.elliptic.legendre;
18  
19  import org.hipparchus.CalculusFieldElement;
20  import org.hipparchus.Field;
21  import org.hipparchus.special.elliptic.carlson.CarlsonEllipticIntegral;
22  import org.hipparchus.util.Binary64Field;
23  import org.hipparchus.util.FastMath;
24  import org.hipparchus.util.MathUtils;
25  import org.junit.jupiter.api.Test;
26  
27  import static org.junit.jupiter.api.Assertions.assertEquals;
28  import static org.junit.jupiter.api.Assertions.assertTrue;
29  
30  public class FieldLegendreEllipticIntegralTest {
31  
32      @Test
33      void testNoConvergence() {
34          doTestNoConvergence(Binary64Field.getInstance());
35      }
36  
37      private <T extends CalculusFieldElement<T>> void doTestNoConvergence(final Field<T> field) {
38          assertTrue(LegendreEllipticIntegral.bigK(field.getZero().newInstance(Double.NaN)).isNaN());
39      }
40  
41      @Test
42      void testComplementary() {
43          doTestComplementary(Binary64Field.getInstance());
44      }
45  
46      private <T extends CalculusFieldElement<T>> void doTestComplementary(final Field<T> field) {
47          for (double m = 0.01; m < 1; m += 0.01) {
48              T k1 = LegendreEllipticIntegral.bigK(field.getZero().newInstance(m));
49              T k2 = LegendreEllipticIntegral.bigKPrime(field.getZero().newInstance(1 - m));
50              assertEquals(k1.getReal(), k2.getReal(), FastMath.ulp(k1).getReal());
51          }
52      }
53  
54      @Test
55      void testAbramowitzStegunExample3() {
56          doTestAbramowitzStegunExample3(Binary64Field.getInstance());
57      }
58  
59      private <T extends CalculusFieldElement<T>> void doTestAbramowitzStegunExample3(final Field<T> field) {
60          T k = LegendreEllipticIntegral.bigK(field.getZero().newInstance(80.0 / 81.0));
61          assertEquals(3.591545001, k.getReal(), 2.0e-9);
62      }
63  
64      public void testAbramowitzStegunExample4() {
65          doTestBigE(Binary64Field.getInstance(), 80.0 / 81.0, 1.019106060, 2.0e-8);
66      }
67  
68      @Test
69      void testAbramowitzStegunExample8() {
70          final double m    = 1.0 / 5.0;
71          doTestBigF(Binary64Field.getInstance(), FastMath.acos(FastMath.sqrt(2) / 3.0), m, 1.115921, 1.0e-6);
72          doTestBigF(Binary64Field.getInstance(), FastMath.acos(FastMath.sqrt(2) / 2.0), m, 0.800380, 1.0e-6);
73      }
74  
75      @Test
76      void testAbramowitzStegunExample9() {
77          final double m    = 1.0 / 2.0;
78          doTestBigF(Binary64Field.getInstance(), MathUtils.SEMI_PI, m, 1.854075, 1.0e-6);
79          doTestBigF(Binary64Field.getInstance(), FastMath.PI / 6.0, m, 0.535623, 1.0e-6);
80      }
81  
82      @Test
83      void testAbramowitzStegunExample10() {
84          final double m    = 4.0 / 5.0;
85          doTestBigF(Binary64Field.getInstance(), FastMath.PI / 6.0, m, 0.543604, 1.0e-6);
86      }
87  
88      @Test
89      void testAbramowitzStegunExample14() {
90          final double k    = 3.0 / 5.0;
91          doTestBigE(Binary64Field.getInstance(), FastMath.asin(FastMath.sqrt(5.0) / 3.0),          k * k, 0.80904, 1.0e-5);
92          doTestBigE(Binary64Field.getInstance(), FastMath.asin(5.0 / (3.0 * FastMath.sqrt(17.0))), k * k, 0.41192, 1.0e-5);
93      }
94  
95      @Test
96      void testAbramowitzStegunTable175() {
97          final double sinAlpha1 = FastMath.sin(FastMath.toRadians(32));
98          doTestBigF(Binary64Field.getInstance(), FastMath.toRadians(15), sinAlpha1 * sinAlpha1, 0.26263487, 1.0e-8);
99          final double sinAlpha2 = FastMath.sin(FastMath.toRadians(46));
100         doTestBigF(Binary64Field.getInstance(), FastMath.toRadians(80), sinAlpha2 * sinAlpha2, 1.61923762, 1.0e-8);
101     }
102 
103     @Test
104     void testAbramowitzStegunTable176() {
105         final double sinAlpha1 = FastMath.sin(FastMath.toRadians(64));
106         doTestBigE(Binary64Field.getInstance(), FastMath.toRadians(25), sinAlpha1 * sinAlpha1, 0.42531712, 1.0e-8);
107         final double sinAlpha2 = FastMath.sin(FastMath.toRadians(76));
108         doTestBigE(Binary64Field.getInstance(), FastMath.toRadians(70), sinAlpha2 * sinAlpha2, 0.96208074, 1.0e-8);
109     }
110 
111     @Test
112     void testAbramowitzStegunTable179() {
113         final double sinAlpha1 = FastMath.sin(FastMath.toRadians(15));
114         doTestBigPi(Binary64Field.getInstance(), FastMath.toRadians(75), 0.4, sinAlpha1 * sinAlpha1, 1.62298, 1.0e-5);
115         final double sinAlpha2 = FastMath.sin(FastMath.toRadians(60));
116         doTestBigPi(Binary64Field.getInstance(), FastMath.toRadians(45), 0.8, sinAlpha2 * sinAlpha2, 1.03076, 1.0e-5);
117         final double sinAlpha3 = FastMath.sin(FastMath.toRadians(15));
118         doTestBigPi(Binary64Field.getInstance(), FastMath.toRadians(75), 0.9, sinAlpha3 * sinAlpha3, 2.79990, 1.0e-5);
119     }
120 
121     @Test
122     void testCompleteVsIncompleteF() {
123         doTestCompleteVsIncompleteF(Binary64Field.getInstance());
124     }
125 
126     @Test
127     void testCompleteVsIncompleteE() {
128         doTestCompleteVsIncompleteE(Binary64Field.getInstance());
129     }
130 
131     @Test
132     void testCompleteVsIncompleteD() {
133         doTestCompleteVsIncompleteD(Binary64Field.getInstance());
134     }
135 
136     @Test
137     void testCompleteVsIncompletePi() {
138         doTestCompleteVsIncompletePi(Binary64Field.getInstance());
139     }
140 
141     @Test
142     void testNomeMediumParameter() {
143         doTestNomeMediumParameter(Binary64Field.getInstance());
144     }
145 
146     @Test
147     void testNomeSmallParameter() {
148         doTestNomeSmallParameter(Binary64Field.getInstance());
149     }
150 
151     @Test
152     void testPrecomputedDelta() {
153         doTestPrecomputedDelta(Binary64Field.getInstance());
154     }
155 
156     @Test
157     void testIntegralsSmallParameter() {
158         doTestIntegralsSmallParameter(Binary64Field.getInstance());
159     }
160 
161     private <T extends CalculusFieldElement<T>> void doTestBigE(final Field<T> field, final double m,
162                                                                 final double expected, final double tol) {
163         assertEquals(expected,
164                             LegendreEllipticIntegral.bigE(field.getZero().newInstance(m)).getReal(),
165                             tol);
166     }
167 
168     private <T extends CalculusFieldElement<T>> void doTestBigE(final Field<T> field,
169                                                                 final double phi, final double m,
170                                                                 final double expected, final double tol) {
171         assertEquals(expected,
172                             LegendreEllipticIntegral.bigE(field.getZero().newInstance(phi),
173                                                           field.getZero().newInstance(m)).getReal(),
174                             tol);
175     }
176 
177     private <T extends CalculusFieldElement<T>> void doTestBigF(final Field<T> field,
178                                                                 final double phi, final double m,
179                                                                 final double expected, final double tol) {
180         assertEquals(expected,
181                             LegendreEllipticIntegral.bigF(field.getZero().newInstance(phi),
182                                                           field.getZero().newInstance(m)).getReal(),
183                             tol);
184     }
185 
186     private <T extends CalculusFieldElement<T>> void doTestBigPi(final Field<T> field,
187                                                                  final double phi, final double alpha2, final double m,
188                                                                  final double expected, final double tol) {
189         assertEquals(expected,
190                             LegendreEllipticIntegral.bigPi(field.getZero().newInstance(alpha2),
191                                                            field.getZero().newInstance(phi),
192                                                            field.getZero().newInstance(m)).getReal(),
193                             tol);
194     }
195 
196     private <T extends CalculusFieldElement<T>> void doTestCompleteVsIncompleteF(final Field<T> field) {
197         for (double m = 0.01; m < 1; m += 0.01) {
198             double complete   = LegendreEllipticIntegral.bigK(field.getZero().newInstance(m)).getReal();
199             double incomplete = LegendreEllipticIntegral.bigF(field.getZero().newInstance(MathUtils.SEMI_PI),
200                                                               field.getZero().newInstance(m)).getReal();
201             assertEquals(complete, incomplete, FastMath.ulp(complete));
202         }
203     }
204 
205     private <T extends CalculusFieldElement<T>> void doTestCompleteVsIncompleteE(final Field<T> field) {
206         for (double m = 0.01; m < 1; m += 0.01) {
207             double complete   = LegendreEllipticIntegral.bigE(field.getZero().newInstance(m)).getReal();
208             double incomplete = LegendreEllipticIntegral.bigE(field.getZero().newInstance(MathUtils.SEMI_PI),
209                                                               field.getZero().newInstance(m)).getReal();
210             assertEquals(complete, incomplete, 4 * FastMath.ulp(complete));
211         }
212     }
213 
214     private <T extends CalculusFieldElement<T>> void doTestCompleteVsIncompleteD(final Field<T> field) {
215         for (double m = 0.01; m < 1; m += 0.01) {
216             double complete   = LegendreEllipticIntegral.bigD(field.getZero().newInstance(m)).getReal();
217             double incomplete = LegendreEllipticIntegral.bigD(field.getZero().newInstance(MathUtils.SEMI_PI),
218                                                               field.getZero().newInstance(m)).getReal();
219             assertEquals(complete, incomplete, FastMath.ulp(complete));
220         }
221     }
222 
223     private <T extends CalculusFieldElement<T>> void doTestCompleteVsIncompletePi(final Field<T> field) {
224         for (double alpha2 = 0.01; alpha2 < 1; alpha2 += 0.01) {
225             for (double m = 0.01; m < 1; m += 0.01) {
226                 double complete   = LegendreEllipticIntegral.bigPi(field.getZero().newInstance(alpha2),
227                                                                    field.getZero().newInstance(m)).getReal();
228                 double incomplete = LegendreEllipticIntegral.bigPi(field.getZero().newInstance(alpha2),
229                                                                    field.getZero().newInstance(MathUtils.SEMI_PI),
230                                                                    field.getZero().newInstance(m)).getReal();
231                 assertEquals(complete, incomplete, FastMath.ulp(complete));
232             }
233         }
234     }
235 
236     private <T extends CalculusFieldElement<T>> void doTestNomeMediumParameter(final Field<T> field) {
237         assertEquals(0.0857957337021947665168, LegendreEllipticIntegral.nome(field.getZero().newInstance(0.75)).getReal(), 1.0e-15);
238     }
239 
240     private <T extends CalculusFieldElement<T>> void doTestNomeSmallParameter(final Field<T> field) {
241         assertEquals(5.9375e-18, LegendreEllipticIntegral.nome(field.getZero().newInstance(0.95e-16)).getReal(), 1.0e-22);
242     }
243 
244     private <T extends CalculusFieldElement<T>> void doTestIntegralsSmallParameter(final Field<T> field) {
245         assertEquals(7.8539816428e-10,
246                             LegendreEllipticIntegral.bigK(field.getZero().newInstance(2.0e-9)).getReal() - MathUtils.SEMI_PI,
247                             1.0e-15);
248     }
249 
250     private <T extends CalculusFieldElement<T>> void doTestPrecomputedDelta(final Field<T> field) {
251 
252         T n   = field.getZero().newInstance(0.7);
253         T m   = field.getZero().newInstance(0.2);
254         T phi = field.getZero().newInstance(1.2);
255         T ref = field.getZero().newInstance(1.8264362537906997);
256         assertEquals(0.0, LegendreEllipticIntegral.bigPi(n, phi, m).subtract(ref).getReal(), 1.0e-15);
257 
258         // no argument reduction and no precomputed delta
259         final T csc     = phi.sin().reciprocal();
260         final T csc2    = csc.multiply(csc);
261         final T cM1     = csc2.subtract(1);
262         final T cMm     = csc2.subtract(m);
263         final T cMn     = csc2.subtract(n);
264         final T pinphim = CarlsonEllipticIntegral.rF(cM1, cMm, csc2).
265                           add(CarlsonEllipticIntegral.rJ(cM1, cMm, csc2, cMn).multiply(n).divide(3));
266         assertEquals(0.0, pinphim.subtract(ref).getReal(), 1.0e-15);
267 
268     }
269 
270 }