View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) 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 ASF 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  
18  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  
23  package org.hipparchus.geometry.euclidean.threed;
24  
25  import org.hipparchus.UnitTestUtils;
26  import org.hipparchus.analysis.differentiation.DSFactory;
27  import org.hipparchus.analysis.differentiation.DerivativeStructure;
28  import org.hipparchus.exception.MathIllegalArgumentException;
29  import org.hipparchus.util.FastMath;
30  import org.junit.Assert;
31  import org.junit.Test;
32  
33  public class SphericalCoordinatesTest {
34  
35      @Test
36      public void testCoordinatesStoC() throws MathIllegalArgumentException {
37          double piO2 = 0.5 * FastMath.PI;
38          SphericalCoordinates sc1 = new SphericalCoordinates(2.0, 0, piO2);
39          Assert.assertEquals(0, sc1.getCartesian().distance(new Vector3D(2, 0, 0)), 1.0e-10);
40          SphericalCoordinates sc2 = new SphericalCoordinates(2.0, piO2, piO2);
41          Assert.assertEquals(0, sc2.getCartesian().distance(new Vector3D(0, 2, 0)), 1.0e-10);
42          SphericalCoordinates sc3 = new SphericalCoordinates(2.0, FastMath.PI, piO2);
43          Assert.assertEquals(0, sc3.getCartesian().distance(new Vector3D(-2, 0, 0)), 1.0e-10);
44          SphericalCoordinates sc4 = new SphericalCoordinates(2.0, -piO2, piO2);
45          Assert.assertEquals(0, sc4.getCartesian().distance(new Vector3D(0, -2, 0)), 1.0e-10);
46          SphericalCoordinates sc5 = new SphericalCoordinates(2.0, 1.23456, 0);
47          Assert.assertEquals(0, sc5.getCartesian().distance(new Vector3D(0, 0, 2)), 1.0e-10);
48          SphericalCoordinates sc6 = new SphericalCoordinates(2.0, 6.54321, FastMath.PI);
49          Assert.assertEquals(0, sc6.getCartesian().distance(new Vector3D(0, 0, -2)), 1.0e-10);
50      }
51  
52      @Test
53      public void testCoordinatesCtoS() throws MathIllegalArgumentException {
54          double piO2 = 0.5 * FastMath.PI;
55          SphericalCoordinates sc1 = new SphericalCoordinates(new Vector3D(2, 0, 0));
56          Assert.assertEquals(2,           sc1.getR(),     1.0e-10);
57          Assert.assertEquals(0,           sc1.getTheta(), 1.0e-10);
58          Assert.assertEquals(piO2,        sc1.getPhi(),   1.0e-10);
59          SphericalCoordinates sc2 = new SphericalCoordinates(new Vector3D(0, 2, 0));
60          Assert.assertEquals(2,           sc2.getR(),     1.0e-10);
61          Assert.assertEquals(piO2,        sc2.getTheta(), 1.0e-10);
62          Assert.assertEquals(piO2,        sc2.getPhi(),   1.0e-10);
63          SphericalCoordinates sc3 = new SphericalCoordinates(new Vector3D(-2, 0, 0));
64          Assert.assertEquals(2,           sc3.getR(),     1.0e-10);
65          Assert.assertEquals(FastMath.PI, sc3.getTheta(), 1.0e-10);
66          Assert.assertEquals(piO2,        sc3.getPhi(),   1.0e-10);
67          SphericalCoordinates sc4 = new SphericalCoordinates(new Vector3D(0, -2, 0));
68          Assert.assertEquals(2,           sc4.getR(),     1.0e-10);
69          Assert.assertEquals(-piO2,       sc4.getTheta(), 1.0e-10);
70          Assert.assertEquals(piO2,        sc4.getPhi(),   1.0e-10);
71          SphericalCoordinates sc5 = new SphericalCoordinates(new Vector3D(0, 0, 2));
72          Assert.assertEquals(2,           sc5.getR(),     1.0e-10);
73          //  don't check theta on poles, as it is singular
74          Assert.assertEquals(0,           sc5.getPhi(),   1.0e-10);
75          SphericalCoordinates sc6 = new SphericalCoordinates(new Vector3D(0, 0, -2));
76          Assert.assertEquals(2,           sc6.getR(),     1.0e-10);
77          //  don't check theta on poles, as it is singular
78          Assert.assertEquals(FastMath.PI, sc6.getPhi(),   1.0e-10);
79      }
80  
81      @Test
82      public void testGradient() {
83          DSFactory factory = new DSFactory(3, 1);
84          for (double r = 0.2; r < 10; r += 0.5) {
85              for (double theta = 0; theta < 2 * FastMath.PI; theta += 0.1) {
86                  for (double phi = 0.1; phi < FastMath.PI; phi += 0.1) {
87                      SphericalCoordinates sc = new SphericalCoordinates(r, theta, phi);
88  
89                      DerivativeStructure svalue = valueSpherical(factory.variable(0, r),
90                                                                  factory.variable(1, theta),
91                                                                  factory.variable(2, phi));
92                      double[] sGradient = new double[] {
93                          svalue.getPartialDerivative(1, 0, 0),
94                          svalue.getPartialDerivative(0, 1, 0),
95                          svalue.getPartialDerivative(0, 0, 1),
96                      };
97  
98                      DerivativeStructure cvalue = valueCartesian(factory.variable(0, sc.getCartesian().getX()),
99                                                                  factory.variable(1, sc.getCartesian().getY()),
100                                                                 factory.variable(2, sc.getCartesian().getZ()));
101                     Vector3D refCGradient = new Vector3D(cvalue.getPartialDerivative(1, 0, 0),
102                                                          cvalue.getPartialDerivative(0, 1, 0),
103                                                          cvalue.getPartialDerivative(0, 0, 1));
104 
105                     Vector3D testCGradient = new Vector3D(sc.toCartesianGradient(sGradient));
106 
107                     Assert.assertEquals(0, testCGradient.distance(refCGradient) / refCGradient.getNorm(), 5.0e-14);
108 
109                 }
110             }
111         }
112     }
113 
114     @Test
115     public void testHessian() {
116         DSFactory factory = new DSFactory(3, 2);
117         for (double r = 0.2; r < 10; r += 0.5) {
118             for (double theta = 0; theta < 2 * FastMath.PI; theta += 0.2) {
119                 for (double phi = 0.1; phi < FastMath.PI; phi += 0.2) {
120                     SphericalCoordinates sc = new SphericalCoordinates(r, theta, phi);
121 
122                     DerivativeStructure svalue = valueSpherical(factory.variable(0, r),
123                                                                 factory.variable(1, theta),
124                                                                 factory.variable(2, phi));
125                     double[] sGradient = new double[] {
126                         svalue.getPartialDerivative(1, 0, 0),
127                         svalue.getPartialDerivative(0, 1, 0),
128                         svalue.getPartialDerivative(0, 0, 1),
129                     };
130                     double[][] sHessian = new double[3][3];
131                     sHessian[0][0] = svalue.getPartialDerivative(2, 0, 0); // d2F/dR2
132                     sHessian[1][0] = svalue.getPartialDerivative(1, 1, 0); // d2F/dRdTheta
133                     sHessian[2][0] = svalue.getPartialDerivative(1, 0, 1); // d2F/dRdPhi
134                     sHessian[0][1] = Double.NaN; // just to check upper-right part is not used
135                     sHessian[1][1] = svalue.getPartialDerivative(0, 2, 0); // d2F/dTheta2
136                     sHessian[2][1] = svalue.getPartialDerivative(0, 1, 1); // d2F/dThetadPhi
137                     sHessian[0][2] = Double.NaN; // just to check upper-right part is not used
138                     sHessian[1][2] = Double.NaN; // just to check upper-right part is not used
139                     sHessian[2][2] = svalue.getPartialDerivative(0, 0, 2); // d2F/dPhi2
140 
141                     DerivativeStructure cvalue = valueCartesian(factory.variable(0, sc.getCartesian().getX()),
142                                                                 factory.variable(1, sc.getCartesian().getY()),
143                                                                 factory.variable(2, sc.getCartesian().getZ()));
144                     double[][] refCHessian = new double[3][3];
145                     refCHessian[0][0] = cvalue.getPartialDerivative(2, 0, 0); // d2F/dX2
146                     refCHessian[1][0] = cvalue.getPartialDerivative(1, 1, 0); // d2F/dXdY
147                     refCHessian[2][0] = cvalue.getPartialDerivative(1, 0, 1); // d2F/dXdZ
148                     refCHessian[0][1] = refCHessian[1][0];
149                     refCHessian[1][1] = cvalue.getPartialDerivative(0, 2, 0); // d2F/dY2
150                     refCHessian[2][1] = cvalue.getPartialDerivative(0, 1, 1); // d2F/dYdZ
151                     refCHessian[0][2] = refCHessian[2][0];
152                     refCHessian[1][2] = refCHessian[2][1];
153                     refCHessian[2][2] = cvalue.getPartialDerivative(0, 0, 2); // d2F/dZ2
154                     double norm =  0;
155                     for (int i = 0; i < 3; ++i) {
156                         for (int j = 0; j < 3; ++j) {
157                             norm = FastMath.max(norm, FastMath.abs(refCHessian[i][j]));
158                         }
159                     }
160 
161                     double[][] testCHessian = sc.toCartesianHessian(sHessian, sGradient);
162                     for (int i = 0; i < 3; ++i) {
163                         for (int j = 0; j < 3; ++j) {
164                             Assert.assertEquals("" + FastMath.abs((refCHessian[i][j] - testCHessian[i][j]) / norm),
165                                                 refCHessian[i][j], testCHessian[i][j], 1.0e-14 * norm);
166                         }
167                     }
168 
169                 }
170             }
171         }
172     }
173 
174     public DerivativeStructure valueCartesian(DerivativeStructure x, DerivativeStructure y, DerivativeStructure z) {
175         return x.divide(y.multiply(5).add(10)).multiply(z.pow(3));
176     }
177 
178     public DerivativeStructure valueSpherical(DerivativeStructure r, DerivativeStructure theta, DerivativeStructure phi) {
179         return valueCartesian(r.multiply(theta.cos()).multiply(phi.sin()),
180                               r.multiply(theta.sin()).multiply(phi.sin()),
181                               r.multiply(phi.cos()));
182     }
183 
184     @Test
185     public void testSerialization() {
186         SphericalCoordinates a = new SphericalCoordinates(3, 2, 1);
187         SphericalCoordinates b = (SphericalCoordinates) UnitTestUtils.serializeAndRecover(a);
188         Assert.assertEquals(0, a.getCartesian().distance(b.getCartesian()), 1.0e-10);
189         Assert.assertEquals(a.getR(),     b.getR(),     1.0e-10);
190         Assert.assertEquals(a.getTheta(), b.getTheta(), 1.0e-10);
191         Assert.assertEquals(a.getPhi(),   b.getPhi(),   1.0e-10);
192     }
193 
194 }