/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF 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.apache.commons.math4.geometry.euclidean.threed;
import org.apache.commons.math4.TestUtils;
import org.apache.commons.math4.analysis.differentiation.DerivativeStructure;
import org.apache.commons.math4.exception.DimensionMismatchException;
import org.apache.commons.math4.geometry.euclidean.threed.SphericalCoordinates;
import org.apache.commons.math4.geometry.euclidean.threed.Cartesian3D;
import org.apache.commons.math4.util.FastMath;
import org.junit.Assert;
import org.junit.Test;
public class SphericalCoordinatesTest {
@Test
public void testCoordinatesStoC() throws DimensionMismatchException {
double piO2 = 0.5 * FastMath.PI;
SphericalCoordinates sc1 = new SphericalCoordinates(2.0, 0, piO2);
Assert.assertEquals(0, sc1.getCartesian().distance(new Cartesian3D(2, 0, 0)), 1.0e-10);
SphericalCoordinates sc2 = new SphericalCoordinates(2.0, piO2, piO2);
Assert.assertEquals(0, sc2.getCartesian().distance(new Cartesian3D(0, 2, 0)), 1.0e-10);
SphericalCoordinates sc3 = new SphericalCoordinates(2.0, FastMath.PI, piO2);
Assert.assertEquals(0, sc3.getCartesian().distance(new Cartesian3D(-2, 0, 0)), 1.0e-10);
SphericalCoordinates sc4 = new SphericalCoordinates(2.0, -piO2, piO2);
Assert.assertEquals(0, sc4.getCartesian().distance(new Cartesian3D(0, -2, 0)), 1.0e-10);
SphericalCoordinates sc5 = new SphericalCoordinates(2.0, 1.23456, 0);
Assert.assertEquals(0, sc5.getCartesian().distance(new Cartesian3D(0, 0, 2)), 1.0e-10);
SphericalCoordinates sc6 = new SphericalCoordinates(2.0, 6.54321, FastMath.PI);
Assert.assertEquals(0, sc6.getCartesian().distance(new Cartesian3D(0, 0, -2)), 1.0e-10);
}
@Test
public void testCoordinatesCtoS() throws DimensionMismatchException {
double piO2 = 0.5 * FastMath.PI;
SphericalCoordinates sc1 = new SphericalCoordinates(new Cartesian3D(2, 0, 0));
Assert.assertEquals(2, sc1.getR(), 1.0e-10);
Assert.assertEquals(0, sc1.getTheta(), 1.0e-10);
Assert.assertEquals(piO2, sc1.getPhi(), 1.0e-10);
SphericalCoordinates sc2 = new SphericalCoordinates(new Cartesian3D(0, 2, 0));
Assert.assertEquals(2, sc2.getR(), 1.0e-10);
Assert.assertEquals(piO2, sc2.getTheta(), 1.0e-10);
Assert.assertEquals(piO2, sc2.getPhi(), 1.0e-10);
SphericalCoordinates sc3 = new SphericalCoordinates(new Cartesian3D(-2, 0, 0));
Assert.assertEquals(2, sc3.getR(), 1.0e-10);
Assert.assertEquals(FastMath.PI, sc3.getTheta(), 1.0e-10);
Assert.assertEquals(piO2, sc3.getPhi(), 1.0e-10);
SphericalCoordinates sc4 = new SphericalCoordinates(new Cartesian3D(0, -2, 0));
Assert.assertEquals(2, sc4.getR(), 1.0e-10);
Assert.assertEquals(-piO2, sc4.getTheta(), 1.0e-10);
Assert.assertEquals(piO2, sc4.getPhi(), 1.0e-10);
SphericalCoordinates sc5 = new SphericalCoordinates(new Cartesian3D(0, 0, 2));
Assert.assertEquals(2, sc5.getR(), 1.0e-10);
// don't check theta on poles, as it is singular
Assert.assertEquals(0, sc5.getPhi(), 1.0e-10);
SphericalCoordinates sc6 = new SphericalCoordinates(new Cartesian3D(0, 0, -2));
Assert.assertEquals(2, sc6.getR(), 1.0e-10);
// don't check theta on poles, as it is singular
Assert.assertEquals(FastMath.PI, sc6.getPhi(), 1.0e-10);
}
@Test
public void testGradient() {
for (double r = 0.2; r < 10; r += 0.5) {
for (double theta = 0; theta < 2 * FastMath.PI; theta += 0.1) {
for (double phi = 0.1; phi < FastMath.PI; phi += 0.1) {
SphericalCoordinates sc = new SphericalCoordinates(r, theta, phi);
DerivativeStructure svalue = valueSpherical(new DerivativeStructure(3, 1, 0, r),
new DerivativeStructure(3, 1, 1, theta),
new DerivativeStructure(3, 1, 2, phi));
double[] sGradient = new double[] {
svalue.getPartialDerivative(1, 0, 0),
svalue.getPartialDerivative(0, 1, 0),
svalue.getPartialDerivative(0, 0, 1),
};
DerivativeStructure cvalue = valueCartesian(new DerivativeStructure(3, 1, 0, sc.getCartesian().getX()),
new DerivativeStructure(3, 1, 1, sc.getCartesian().getY()),
new DerivativeStructure(3, 1, 2, sc.getCartesian().getZ()));
Cartesian3D refCGradient = new Cartesian3D(cvalue.getPartialDerivative(1, 0, 0),
cvalue.getPartialDerivative(0, 1, 0),
cvalue.getPartialDerivative(0, 0, 1));
Cartesian3D testCGradient = new Cartesian3D(sc.toCartesianGradient(sGradient));
Assert.assertEquals(0, testCGradient.distance(refCGradient) / refCGradient.getNorm(), 5.0e-14);
}
}
}
}
@Test
public void testHessian() {
for (double r = 0.2; r < 10; r += 0.5) {
for (double theta = 0; theta < 2 * FastMath.PI; theta += 0.2) {
for (double phi = 0.1; phi < FastMath.PI; phi += 0.2) {
SphericalCoordinates sc = new SphericalCoordinates(r, theta, phi);
DerivativeStructure svalue = valueSpherical(new DerivativeStructure(3, 2, 0, r),
new DerivativeStructure(3, 2, 1, theta),
new DerivativeStructure(3, 2, 2, phi));
double[] sGradient = new double[] {
svalue.getPartialDerivative(1, 0, 0),
svalue.getPartialDerivative(0, 1, 0),
svalue.getPartialDerivative(0, 0, 1),
};
double[][] sHessian = new double[3][3];
sHessian[0][0] = svalue.getPartialDerivative(2, 0, 0); // d2F/dR2
sHessian[1][0] = svalue.getPartialDerivative(1, 1, 0); // d2F/dRdTheta
sHessian[2][0] = svalue.getPartialDerivative(1, 0, 1); // d2F/dRdPhi
sHessian[0][1] = Double.NaN; // just to check upper-right part is not used
sHessian[1][1] = svalue.getPartialDerivative(0, 2, 0); // d2F/dTheta2
sHessian[2][1] = svalue.getPartialDerivative(0, 1, 1); // d2F/dThetadPhi
sHessian[0][2] = Double.NaN; // just to check upper-right part is not used
sHessian[1][2] = Double.NaN; // just to check upper-right part is not used
sHessian[2][2] = svalue.getPartialDerivative(0, 0, 2); // d2F/dPhi2
DerivativeStructure cvalue = valueCartesian(new DerivativeStructure(3, 2, 0, sc.getCartesian().getX()),
new DerivativeStructure(3, 2, 1, sc.getCartesian().getY()),
new DerivativeStructure(3, 2, 2, sc.getCartesian().getZ()));
double[][] refCHessian = new double[3][3];
refCHessian[0][0] = cvalue.getPartialDerivative(2, 0, 0); // d2F/dX2
refCHessian[1][0] = cvalue.getPartialDerivative(1, 1, 0); // d2F/dXdY
refCHessian[2][0] = cvalue.getPartialDerivative(1, 0, 1); // d2F/dXdZ
refCHessian[0][1] = refCHessian[1][0];
refCHessian[1][1] = cvalue.getPartialDerivative(0, 2, 0); // d2F/dY2
refCHessian[2][1] = cvalue.getPartialDerivative(0, 1, 1); // d2F/dYdZ
refCHessian[0][2] = refCHessian[2][0];
refCHessian[1][2] = refCHessian[2][1];
refCHessian[2][2] = cvalue.getPartialDerivative(0, 0, 2); // d2F/dZ2
double norm = 0;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
norm = FastMath.max(norm, FastMath.abs(refCHessian[i][j]));
}
}
double[][] testCHessian = sc.toCartesianHessian(sHessian, sGradient);
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
Assert.assertEquals("" + FastMath.abs((refCHessian[i][j] - testCHessian[i][j]) / norm),
refCHessian[i][j], testCHessian[i][j], 1.0e-14 * norm);
}
}
}
}
}
}
public DerivativeStructure valueCartesian(DerivativeStructure x, DerivativeStructure y, DerivativeStructure z) {
return x.divide(y.multiply(5).add(10)).multiply(z.pow(3));
}
public DerivativeStructure valueSpherical(DerivativeStructure r, DerivativeStructure theta, DerivativeStructure phi) {
return valueCartesian(r.multiply(theta.cos()).multiply(phi.sin()),
r.multiply(theta.sin()).multiply(phi.sin()),
r.multiply(phi.cos()));
}
@Test
public void testSerialization() {
SphericalCoordinates a = new SphericalCoordinates(3, 2, 1);
SphericalCoordinates b = (SphericalCoordinates) TestUtils.serializeAndRecover(a);
Assert.assertEquals(0, a.getCartesian().distance(b.getCartesian()), 1.0e-10);
Assert.assertEquals(a.getR(), b.getR(), 1.0e-10);
Assert.assertEquals(a.getTheta(), b.getTheta(), 1.0e-10);
Assert.assertEquals(a.getPhi(), b.getPhi(), 1.0e-10);
}
}