diff --git a/src/shapes/src/SimplePore.cpp b/src/shapes/src/SimplePore.cpp index 7caade9759..ce3945c246 100644 --- a/src/shapes/src/SimplePore.cpp +++ b/src/shapes/src/SimplePore.cpp @@ -103,7 +103,7 @@ void SimplePore::calculate_dist(const Utils::Vector3d &pos, double &dist, } else { // smoothing area if (std::abs(z) >= c_z) { - auto const d_sq = Utils::sqr(r - c_r) + Utils::sqr(z - c_z); + auto const d_sq = Utils::sqr(r - c_r) + Utils::sqr(std::abs(z) - c_z); if (d_sq > Utils::sqr(m_smoothing_rad)) { side = 1; } diff --git a/src/shapes/unit_tests/CMakeLists.txt b/src/shapes/unit_tests/CMakeLists.txt index e4f8d9d160..52cb5cea61 100644 --- a/src/shapes/unit_tests/CMakeLists.txt +++ b/src/shapes/unit_tests/CMakeLists.txt @@ -26,5 +26,7 @@ espresso_unit_test(SRC Union_test.cpp DEPENDS espresso::shapes espresso::utils) espresso_unit_test(SRC Ellipsoid_test.cpp DEPENDS espresso::shapes espresso::utils) espresso_unit_test(SRC Sphere_test.cpp DEPENDS espresso::shapes espresso::utils) +espresso_unit_test(SRC SimplePore_test.cpp DEPENDS espresso::shapes + espresso::utils) espresso_unit_test(SRC NoWhere_test.cpp DEPENDS espresso::shapes espresso::utils) diff --git a/src/shapes/unit_tests/SimplePore_test.cpp b/src/shapes/unit_tests/SimplePore_test.cpp new file mode 100644 index 0000000000..30470669c1 --- /dev/null +++ b/src/shapes/unit_tests/SimplePore_test.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2010-2026 The ESPResSo project + * + * This file is part of ESPResSo. + * + * ESPResSo is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ESPResSo is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#define BOOST_TEST_MODULE simple_pore test +#define BOOST_TEST_DYN_LINK +#include + +#include +#include + +/* + * The pore has mirror symmetry in z about its center (the documented + * invariant in SimplePore::calculate_dist). Two probe points at the +z and + * -z mouths with identical r and |z| therefore MUST yield the same signed + * distance, and a point inside the solid wall material at either mouth must + * report a negative (inside) distance. + * + * Bug #13: the smoothing-area side test used the signed z in + * Utils::sqr(z - c_z) instead of Utils::sqr(std::abs(z) - c_z). At the + * negative-z mouth this forces side=+1 (outside) even for a point inside the + * solid, flipping the sign of the distance. + */ +BOOST_AUTO_TEST_CASE(mirror_symmetry_in_z) { + Shapes::SimplePore pore; + pore.set_axis({0., 0., 1.}); + pore.set_radius(3.); + pore.set_smoothing_radius(0.1); + pore.set_length(6.); + pore.center() = Utils::Vector3d{10., 10., 10.}; + /* derived: c_r = 3.1, c_z = 2.9 */ + + /* Probe r = 3.05 (x-offset), z = +/-2.95 relative to the center: inside the + solid wall material, inside the smoothing fillet at each mouth. r is + chosen slightly larger than m_rad so the smoothing branch is exercised. */ + Utils::Vector3d const center{10., 10., 10.}; + auto const pos_plus = center + Utils::Vector3d{3.05, 0., 2.95}; + auto const pos_minus = center + Utils::Vector3d{3.05, 0., -2.95}; + + double dist_plus, dist_minus; + Utils::Vector3d vec_plus, vec_minus; + pore.calculate_dist(pos_plus, dist_plus, vec_plus); + pore.calculate_dist(pos_minus, dist_minus, vec_minus); + + /* The signed scalar distance must be mirror-symmetric in z. */ + BOOST_TEST_INFO("dist(+z)=" << dist_plus << " dist(-z)=" << dist_minus); + BOOST_REQUIRE_CLOSE(dist_plus, dist_minus, 1e-9); + + /* The probe lies inside the solid wall material, so both mouths must + report a negative (inside) distance. */ + BOOST_REQUIRE_LT(dist_plus, 0.); + BOOST_REQUIRE_LT(dist_minus, 0.); +}