You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by er...@apache.org on 2018/07/21 10:07:44 UTC
[commons-geometry] 06/15: GEOMETRY-7: adding previous spherical
gradient and Hessian convertion to new SphericalDerivativeConverter class;
removing old SphericalCoordinates class
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 <ma...@hotmail.com>
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);
+ }
+}