This is an automated email from the ASF dual-hosted git repository. erans pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-geometry.git
commit fefd035e263190d74aa02127fcd1ffcfdb3d227e Author: Matt Juntunen <[email protected]> AuthorDate: Sun Jul 1 00:09:07 2018 -0400 GEOMETRY-7: adding previous spherical gradient and Hessian convertion to new SphericalDerivativeConverter class; removing old SphericalCoordinates class --- ..._OLD.java => SphericalDerivativeConverter.java} | 253 +++++---------------- .../euclidean/threed/SphericalCoordinatesTest.java | 16 ++ .../threed/SphericalCoordinatesTest_OLD.java | 84 ------- .../threed/SphericalDerivativeConverterTest.java | 187 +++++++++++++++ 4 files changed, 254 insertions(+), 286 deletions(-) diff --git a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SphericalCoordinates_OLD.java b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SphericalDerivativeConverter.java similarity index 60% rename from commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SphericalCoordinates_OLD.java rename to commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SphericalDerivativeConverter.java index ac39a5e..45b8794 100644 --- a/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SphericalCoordinates_OLD.java +++ b/commons-geometry-euclidean/src/main/java/org/apache/commons/geometry/euclidean/threed/SphericalDerivativeConverter.java @@ -16,52 +16,16 @@ */ package org.apache.commons.geometry.euclidean.threed; - -import java.io.Serializable; - -/** This class provides conversions related to <a - * href="http://mathworld.wolfram.com/SphericalCoordinates.html">spherical coordinates</a>. - * <p> - * The conventions used here are the mathematical ones, i.e. spherical coordinates are - * related to Cartesian coordinates as follows: - * </p> - * <ul> - * <li>x = r cos(θ) sin(Φ)</li> - * <li>y = r sin(θ) sin(Φ)</li> - * <li>z = r cos(Φ)</li> - * </ul> - * <ul> - * <li>r = √(x<sup>2</sup>+y<sup>2</sup>+z<sup>2</sup>)</li> - * <li>θ = atan2(y, x)</li> - * <li>Φ = acos(z/r)</li> - * </ul> - * <p> - * r is the radius, θ is the azimuthal angle in the x-y plane and Φ is the polar - * (co-latitude) angle. These conventions are <em>different</em> from the conventions used - * in physics (and in particular in spherical harmonics) where the meanings of θ and - * Φ are reversed. - * </p> - * <p> - * This class provides conversion of coordinates and also of gradient and Hessian - * between spherical and Cartesian coordinates. - * </p> +/** Class containing methods for converting gradients and Hessian + * matrices from spherical to Cartesian coordinates. */ -public class SphericalCoordinates_OLD implements Serializable { - - /** Serializable UID. */ - private static final long serialVersionUID = 20130206L; - - /** Cartesian coordinates. */ - private final Vector3D v; +public class SphericalDerivativeConverter { - /** Radius. */ - private final double r; + /** Spherical coordinates. */ + private final SphericalCoordinates spherical; - /** Azimuthal angle in the x-y plane θ. */ - private final double theta; - - /** Polar angle (co-latitude) Φ. */ - private final double phi; + /** Cartesian vector equivalent to spherical coordinates. */ + private final Vector3D vector; /** Jacobian of (r, θ Φ). */ private double[][] jacobian; @@ -75,77 +39,26 @@ public class SphericalCoordinates_OLD implements Serializable { /** Hessian of polar (co-latitude) angle Φ. */ private double[][] phiHessian; - /** Build a spherical coordinates transformer from Cartesian coordinates. - * @param v Cartesian coordinates - */ - public SphericalCoordinates_OLD(final Vector3D v) { - - // Cartesian coordinates - this.v = v; - - // remaining spherical coordinates - this.r = v.getNorm(); - this.theta = 0.0; //v.getAlpha(); - this.phi = Math.acos(v.getZ() / r); - - } - - /** Build a spherical coordinates transformer from spherical coordinates. - * @param r radius - * @param theta azimuthal angle in x-y plane - * @param phi polar (co-latitude) angle - */ - public SphericalCoordinates_OLD(final double r, final double theta, final double phi) { - - final double cosTheta = Math.cos(theta); - final double sinTheta = Math.sin(theta); - final double cosPhi = Math.cos(phi); - final double sinPhi = Math.sin(phi); + public SphericalDerivativeConverter(SphericalCoordinates spherical) { + this.spherical = spherical; + this.vector = spherical.toVector(); - // spherical coordinates - this.r = r; - this.theta = theta; - this.phi = phi; - - // Cartesian coordinates - this.v = Vector3D.of(r * cosTheta * sinPhi, - r * sinTheta * sinPhi, - r * cosPhi); - - } - - /** Get the Cartesian coordinates. - * @return Cartesian coordinates - */ - public Vector3D getCartesian() { - return v; - } - - /** Get the radius. - * @return radius r - * @see #getTheta() - * @see #getPhi() - */ - public double getR() { - return r; + computeJacobian(); } - /** Get the azimuthal angle in x-y plane. - * @return azimuthal angle in x-y plane θ - * @see #getR() - * @see #getPhi() + /** Return the {@link SphericalCoordinates} for this instance. + * @return spherical coordinates for this instance */ - public double getTheta() { - return theta; + public SphericalCoordinates getSpherical() { + return spherical; } - /** Get the polar (co-latitude) angle. - * @return polar (co-latitude) angle Φ - * @see #getR() - * @see #getTheta() + /** Return the {@link Vector3D} for this instance. This vector is + * equivalent to the spherical coordinates. + * @return vector for this instance */ - public double getPhi() { - return phi; + public Vector3D getVector() { + return vector; } /** Convert a gradient with respect to spherical coordinates into a gradient @@ -156,10 +69,6 @@ public class SphericalCoordinates_OLD implements Serializable { * {df/dx, df/dy, df/dz} */ public double[] toCartesianGradient(final double[] sGradient) { - - // lazy evaluation of Jacobian - computeJacobian(); - // compose derivatives as gradient^T . J // the expressions have been simplified since we know jacobian[1][2] = dTheta/dZ = 0 return new double[] { @@ -167,7 +76,6 @@ public class SphericalCoordinates_OLD implements Serializable { sGradient[0] * jacobian[0][1] + sGradient[1] * jacobian[1][1] + sGradient[2] * jacobian[2][1], sGradient[0] * jacobian[0][2] + sGradient[2] * jacobian[2][2] }; - } /** Convert a Hessian with respect to spherical coordinates into a Hessian @@ -189,8 +97,6 @@ public class SphericalCoordinates_OLD implements Serializable { * {d<sup>2</sup>f/dxdz, d<sup>2</sup>f/dydz, d<sup>2</sup>f/dz<sup>2</sup>}} */ public double[][] toCartesianHessian(final double[][] sHessian, final double[] sGradient) { - - computeJacobian(); computeHessians(); // compose derivative as J^T . H_f . J + df/dr H_r + df/dtheta H_theta + df/dphi H_phi @@ -233,52 +139,47 @@ public class SphericalCoordinates_OLD implements Serializable { cHessian[1][2] = cHessian[2][1]; return cHessian; - } - /** Lazy evaluation of (r, θ, φ) Jacobian. - */ + /** Evaluates (r, θ, φ) Jacobian. */ private void computeJacobian() { - if (jacobian == null) { - // intermediate variables - final double x = v.getX(); - final double y = v.getY(); - final double z = v.getZ(); - final double rho2 = x * x + y * y; - final double rho = Math.sqrt(rho2); - final double r2 = rho2 + z * z; - - jacobian = new double[3][3]; - - // row representing the gradient of r - jacobian[0][0] = x / r; - jacobian[0][1] = y / r; - jacobian[0][2] = z / r; - - // row representing the gradient of theta - jacobian[1][0] = -y / rho2; - jacobian[1][1] = x / rho2; - // jacobian[1][2] is already set to 0 at allocation time - - // row representing the gradient of phi - jacobian[2][0] = x * z / (rho * r2); - jacobian[2][1] = y * z / (rho * r2); - jacobian[2][2] = -rho / r2; - - } + // intermediate variables + final double r = spherical.getRadius(); + final double x = vector.getX(); + final double y = vector.getY(); + final double z = vector.getZ(); + final double rho2 = x * x + y * y; + final double rho = Math.sqrt(rho2); + final double r2 = rho2 + z * z; + + jacobian = new double[3][3]; + + // row representing the gradient of r + jacobian[0][0] = x / r; + jacobian[0][1] = y / r; + jacobian[0][2] = z / r; + + // row representing the gradient of theta + jacobian[1][0] = -y / rho2; + jacobian[1][1] = x / rho2; + // jacobian[1][2] is already set to 0 at allocation time + + // row representing the gradient of phi + jacobian[2][0] = x * z / (rho * r2); + jacobian[2][1] = y * z / (rho * r2); + jacobian[2][2] = -rho / r2; } - /** Lazy evaluation of Hessians. - */ + /** Lazy evaluation of Hessians. */ private void computeHessians() { - if (rHessian == null) { // intermediate variables - final double x = v.getX(); - final double y = v.getY(); - final double z = v.getZ(); + final double r = spherical.getRadius(); + final double x = vector.getX(); + final double y = vector.getY(); + final double z = vector.getZ(); final double x2 = x * x; final double y2 = y * y; final double z2 = z * z; @@ -335,58 +236,6 @@ public class SphericalCoordinates_OLD implements Serializable { phiHessian[0][1] = phiHessian[1][0]; phiHessian[0][2] = phiHessian[2][0]; phiHessian[1][2] = phiHessian[2][1]; - } - - } - - /** - * Replace the instance with a data transfer object for serialization. - * @return data transfer object that will be serialized - */ - private Object writeReplace() { - return new DataTransferObject(v.getX(), v.getY(), v.getZ()); } - - /** Internal class used only for serialization. */ - private static class DataTransferObject implements Serializable { - - /** Serializable UID. */ - private static final long serialVersionUID = 20130206L; - - /** Abscissa. - * @serial - */ - private final double x; - - /** Ordinate. - * @serial - */ - private final double y; - - /** Height. - * @serial - */ - private final double z; - - /** Simple constructor. - * @param x abscissa - * @param y ordinate - * @param z height - */ - DataTransferObject(final double x, final double y, final double z) { - this.x = x; - this.y = y; - this.z = z; - } - - /** Replace the deserialized data transfer object with a {@link SphericalCoordinates_OLD}. - * @return replacement {@link SphericalCoordinates_OLD} - */ - private Object readResolve() { - return new SphericalCoordinates_OLD(Vector3D.of(x, y, z)); - } - - } - } diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SphericalCoordinatesTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SphericalCoordinatesTest.java index d1d9f01..37d381d 100644 --- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SphericalCoordinatesTest.java +++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SphericalCoordinatesTest.java @@ -1,3 +1,19 @@ +/* + * 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.geometry.euclidean.threed; import java.util.regex.Pattern; diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SphericalCoordinatesTest_OLD.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SphericalCoordinatesTest_OLD.java deleted file mode 100644 index 999111c..0000000 --- a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SphericalCoordinatesTest_OLD.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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.geometry.euclidean.threed; - -import org.apache.commons.geometry.euclidean.threed.SphericalCoordinates_OLD; -import org.apache.commons.geometry.euclidean.threed.Vector3D; -import org.apache.commons.geometry.core.GeometryTestUtils; -import org.junit.Assert; -import org.junit.Test; - -public class SphericalCoordinatesTest_OLD { - - @Test - public void testCoordinatesStoC() { - double piO2 = 0.5 * Math.PI; - SphericalCoordinates_OLD sc1 = new SphericalCoordinates_OLD(2.0, 0, piO2); - Assert.assertEquals(0, sc1.getCartesian().distance(Vector3D.of(2, 0, 0)), 1.0e-10); - SphericalCoordinates_OLD sc2 = new SphericalCoordinates_OLD(2.0, piO2, piO2); - Assert.assertEquals(0, sc2.getCartesian().distance(Vector3D.of(0, 2, 0)), 1.0e-10); - SphericalCoordinates_OLD sc3 = new SphericalCoordinates_OLD(2.0, Math.PI, piO2); - Assert.assertEquals(0, sc3.getCartesian().distance(Vector3D.of(-2, 0, 0)), 1.0e-10); - SphericalCoordinates_OLD sc4 = new SphericalCoordinates_OLD(2.0, -piO2, piO2); - Assert.assertEquals(0, sc4.getCartesian().distance(Vector3D.of(0, -2, 0)), 1.0e-10); - SphericalCoordinates_OLD sc5 = new SphericalCoordinates_OLD(2.0, 1.23456, 0); - Assert.assertEquals(0, sc5.getCartesian().distance(Vector3D.of(0, 0, 2)), 1.0e-10); - SphericalCoordinates_OLD sc6 = new SphericalCoordinates_OLD(2.0, 6.54321, Math.PI); - Assert.assertEquals(0, sc6.getCartesian().distance(Vector3D.of(0, 0, -2)), 1.0e-10); - } - - @Test - public void testCoordinatesCtoS() { - double piO2 = 0.5 * Math.PI; - SphericalCoordinates_OLD sc1 = new SphericalCoordinates_OLD(Vector3D.of(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_OLD sc2 = new SphericalCoordinates_OLD(Vector3D.of(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_OLD sc3 = new SphericalCoordinates_OLD(Vector3D.of(-2, 0, 0)); - Assert.assertEquals(2, sc3.getR(), 1.0e-10); - Assert.assertEquals(Math.PI, sc3.getTheta(), 1.0e-10); - Assert.assertEquals(piO2, sc3.getPhi(), 1.0e-10); - SphericalCoordinates_OLD sc4 = new SphericalCoordinates_OLD(Vector3D.of(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_OLD sc5 = new SphericalCoordinates_OLD(Vector3D.of(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_OLD sc6 = new SphericalCoordinates_OLD(Vector3D.of(0, 0, -2)); - Assert.assertEquals(2, sc6.getR(), 1.0e-10); - // don't check theta on poles, as it is singular - Assert.assertEquals(Math.PI, sc6.getPhi(), 1.0e-10); - } - - @Test - public void testSerialization() { - SphericalCoordinates_OLD a = new SphericalCoordinates_OLD(3, 2, 1); - SphericalCoordinates_OLD b = (SphericalCoordinates_OLD) GeometryTestUtils.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); - } - -} diff --git a/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SphericalDerivativeConverterTest.java b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SphericalDerivativeConverterTest.java new file mode 100644 index 0000000..4b9bcbd --- /dev/null +++ b/commons-geometry-euclidean/src/test/java/org/apache/commons/geometry/euclidean/threed/SphericalDerivativeConverterTest.java @@ -0,0 +1,187 @@ +/* + * 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.geometry.euclidean.threed; + +import org.apache.commons.geometry.core.Geometry; +import org.junit.Assert; +import org.junit.Test; + +public class SphericalDerivativeConverterTest { + + private static final double EPS = 1e-10; + + @Test + public void testConstructor() { + // arrange + SphericalCoordinates sc = SphericalCoordinates.of(2, Geometry.PI, Geometry.HALF_PI); + + // act + SphericalDerivativeConverter conv = new SphericalDerivativeConverter(sc); + + // assert + checkSpherical(conv.getSpherical(), 2, Geometry.PI, Geometry.HALF_PI); + checkVector(conv.getVector(), -2, 0, 0); + } + + @Test + public void testToCartesianGradient() { + // NOTE: The following set of test data is taken from the original test for this code in commons-math. + // The test in that project generated and checked the inputs on the fly using the commons-math differentiation + // classes. However, since we don't have the benefit of those here, we're using some selected data points + // from that test. + + // act/assert + checkToCartesianGradient( + SphericalCoordinates.of(0.2, 0.1, 0.1), + new double[] { 3.1274095413292105E-4, -1.724542757978006E-6, 1.5102449769881866E-4 }, + new double[] { 0.0007872851, -0.0000078127, 0.0002357921 }); + + checkToCartesianGradient( + SphericalCoordinates.of(0.2, 0.1, 1.6), + new double[] { -7.825830329191124E-8, 7.798528724837122E-10, -4.027286034178383E-7 }, + new double[] { -0.0000000197, 0.0000000019, 0.0000020151 }); + + checkToCartesianGradient( + SphericalCoordinates.of(0.2, 1.6, 0.1), + new double[] { -9.075903886546823E-6, -1.5573157416535893E-5, -4.352284221940998E-6 }, + new double[] { 0.0007802833, 0.0000002252, -0.000006858 }); + + checkToCartesianGradient( + SphericalCoordinates.of(0.2, 2.4, 2.4), + new double[] { 6.045188551967462E-4, 2.944844493772992E-5, 5.207279563401837E-5 }, + new double[] { -0.0003067696, -0.0000146129, -0.0006216347 }); + + checkToCartesianGradient( + SphericalCoordinates.of(9.2, 5.5, 2.4), + new double[] { 27.09285722408859, 327.829199283976, 422.53939642005736 }, + new double[] { 26.1884919572, 48.3685006936, -51.0009075025 }); + } + + private void checkToCartesianGradient(SphericalCoordinates spherical, double[] sGradient, double[] cGradient) { + SphericalDerivativeConverter conv = new SphericalDerivativeConverter(spherical); + + double[] result = conv.toCartesianGradient(sGradient); + + Assert.assertArrayEquals(cGradient, result, EPS); + } + + @Test + public void testToCartesianHessian() { + // NOTE: The following set of test data is taken from the original test for this code in commons-math. + // The test in that project generated and checked the inputs on the fly using the commons-math differentiation + // classes. However, since we don't have the benefit of those here, we're using some selected data points + // from that test. + // + // The NaN values in the input spherical Hessians are only present to ensure that the upper-right + // part of the matrix is not used in the calculation. + + // act/assert + checkToCartesianHessian( + SphericalCoordinates.of(0.2, 0.0, 0.1), + new double[] { 3.147028015595093E-4, -1.5708927954007288E-7, 1.5209020574753025E-4 }, + new double[][] { + { 0.004720542023392639, Double.NaN, Double.NaN }, + { -3.927231988501822E-6, -1.5732003526076452E-5, Double.NaN }, + { 0.0030418041149506037, -3.0840214797113795E-6, -1.56400962465978E-4 } + }, + new double[][] { + { 0.0, -3.940348984959686E-4, 0.011880399467047453 }, + { -3.940348984959686E-4, 7.867570038987733E-6, -1.1860608699245036E-4 }, + { 0.011880399467047453, -1.1860608699245036E-4, 0.002384031969540735 } + }); + + checkToCartesianHessian( + SphericalCoordinates.of(0.2, 0.2, 1.7), + new double[] { -6.492205616890373E-6, 9.721055406032577E-8, -7.490005649457144E-6 }, + new double[][] { + { -9.660140526063848E-5, Double.NaN, Double.NaN }, + { 2.087263937942704E-6, 3.0135301759512823E-7, Double.NaN }, + { -1.4908056742242714E-4, 2.228225255291761E-6, -1.1271700251178201E-4 } + }, + new double[][] { + { 0.0, 8.228328248729827E-7, 1.9536195257978514E-4 }, + { 8.228328248729827E-7, -1.568516517220037E-7, -1.862033454396115E-5 }, + { 1.9536195257978514E-4, -1.862033454396115E-5, -0.0029473017314775615 } + }); + + checkToCartesianHessian( + SphericalCoordinates.of(0.2, 1.6, 0.1), + new double[] { -9.075903886546686E-6, -1.5573157416535897E-5, -4.352284221940931E-6 }, + new double[][] { + { -1.3557892633841054E-4, Double.NaN, Double.NaN }, + { -3.106944464923055E-4, 4.4143436330613375E-7, Double.NaN }, + { -8.660889278565699E-5, -1.489922640116937E-4, 5.374400993902801E-6 } + }, + new double[][] { + { 0.0, -3.862868527078941E-4, 0.011763015339492582 }, + { -3.862868527078941E-4, -2.229868350965674E-7, 3.395142163599996E-6 }, + { 0.011763015339492582, 3.395142163599996E-6, -6.892478835391066E-5 } + }); + + checkToCartesianHessian( + SphericalCoordinates.of(0.2, 2.4, 2.5), + new double[] { 6.911538590806891E-4, 3.344602742543664E-5, 3.330643810411849E-5 }, + new double[][] { + { 0.010200457858547542, Double.NaN, Double.NaN }, + { 6.695363800209198E-4, -3.070347513695088E-5, Double.NaN }, + { 6.68380906286568E-4, 3.001744637007274E-5, -2.273032055462482E-4 } + }, + new double[][] { + { 0.0, 1.9000713243497378E-4, 0.007402721147059207 }, + { 1.9000713243497378E-4, 1.6118798431431763E-5, 3.139960286869248E-4 }, + { 0.007402721147059207, 3.139960286869248E-4, 0.008155571186075681 } + }); + + checkToCartesianHessian( + SphericalCoordinates.of(9.2, 5.6, 2.5), + new double[] { 41.42645719593436, 859.1407583470807, 939.7112322238082 }, + new double[][] { + { 11.642163255436742, Double.NaN, Double.NaN }, + { 54.8154280776715, 5286.1651942531325, Double.NaN }, + { 60.370567966140726, 4700.570567363823, 4929.996883244262 } + }, + new double[][] { + { 0.0, 36.772022140868714, -22.087375306566134 }, + { 36.772022140868714, 212.8111723550033, -63.91326828897971 }, + { -22.087375306566134, -63.91326828897971, 25.593304575600133 } + }); + } + + private void checkToCartesianHessian(SphericalCoordinates spherical, double[] sGradient, + double[][] sHessian, double[][] cHessian) { + SphericalDerivativeConverter conv = new SphericalDerivativeConverter(spherical); + + double[][] result = conv.toCartesianHessian(sHessian, sGradient); + + Assert.assertEquals(cHessian.length, result.length); + for (int i=0; i<cHessian.length; ++i) { + Assert.assertArrayEquals("Hessians differ at row " + i, cHessian[i], result[i], EPS); + } + } + + private void checkSpherical(SphericalCoordinates c, double radius, double azimuth, double polar) { + Assert.assertEquals(radius, c.getRadius(), EPS); + Assert.assertEquals(azimuth, c.getAzimuth(), EPS); + Assert.assertEquals(polar, c.getPolar(), EPS); + } + + private void checkVector(Vector3D v, double x, double y, double z) { + Assert.assertEquals(x, v.getX(), EPS); + Assert.assertEquals(y, v.getY(), EPS); + Assert.assertEquals(z, v.getZ(), EPS); + } +}
