diff --git a/src/shapes/src/Sphere.cpp b/src/shapes/src/Sphere.cpp index 0f56f23cc83..081d99837d5 100644 --- a/src/shapes/src/Sphere.cpp +++ b/src/shapes/src/Sphere.cpp @@ -32,13 +32,23 @@ void Sphere::calculate_dist(const Utils::Vector3d &pos, double &dist, if (m_direction == -1) { /* apply force towards inside the sphere */ dist = m_rad - c_dist; - auto const fac = dist / c_dist; - vec *= fac; + if (c_dist == 0) { + // any vector of length `dist` is correct in this case + vec = Utils::Vector3d{dist, 0, 0}; + } else { + auto const fac = dist / c_dist; + vec *= fac; + } } else { /* apply force towards outside the sphere */ dist = c_dist - m_rad; - auto const fac = dist / c_dist; - vec *= -fac; + if (c_dist == 0) { + // any vector of length `dist` is correct in this case + vec = Utils::Vector3d{dist, 0, 0}; + } else { + auto const fac = dist / c_dist; + vec *= -fac; + } } } } // namespace Shapes diff --git a/src/shapes/unit_tests/CMakeLists.txt b/src/shapes/unit_tests/CMakeLists.txt index abe3d2805fd..5e176fd9f67 100644 --- a/src/shapes/unit_tests/CMakeLists.txt +++ b/src/shapes/unit_tests/CMakeLists.txt @@ -6,5 +6,7 @@ unit_test(NAME Union_test SRC Union_test.cpp DEPENDS EspressoShapes EspressoUtils) unit_test(NAME Ellipsoid_test SRC Ellipsoid_test.cpp DEPENDS EspressoShapes EspressoUtils) +unit_test(NAME Sphere_test SRC Sphere_test.cpp DEPENDS EspressoShapes + EspressoUtils) unit_test(NAME NoWhere_test SRC NoWhere_test.cpp DEPENDS EspressoShapes EspressoUtils) diff --git a/src/shapes/unit_tests/Sphere_test.cpp b/src/shapes/unit_tests/Sphere_test.cpp new file mode 100644 index 00000000000..f3e92d1710b --- /dev/null +++ b/src/shapes/unit_tests/Sphere_test.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2010-2021 The ESPResSo project + * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009,2010 + * Max-Planck-Institute for Polymer Research, Theory Group + * + * 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 . + */ + +#include +#define BOOST_TEST_MODULE sphere test +#define BOOST_TEST_DYN_LINK +#include + +#include +#include + +#include + +void check_distance_function(Shapes::Sphere &s) { + Utils::Vector3d pos; + Utils::Vector3d vec; + double dist; + // multiply by 100 because BOOST_REQUIRE_CLOSE takes a percentage tolerance + auto const tol = std::numeric_limits::epsilon() * 100; + + s.rad() = 1.0; + + pos = {0., 0., 0.}; + s.calculate_dist(pos, dist, vec); + double always_pos_dist = -s.direction() * dist; + BOOST_REQUIRE_GE(always_pos_dist, 0.0); + BOOST_REQUIRE_CLOSE(always_pos_dist, s.rad(), tol); + BOOST_REQUIRE_CLOSE(always_pos_dist, vec.norm(), tol); + + for (int i = 0; i < 3; ++i) { + pos[i] = 1.0; + s.calculate_dist(pos, dist, vec); + double always_pos_dist = -s.direction() * dist; + BOOST_REQUIRE_GE(always_pos_dist, 0.0); + BOOST_REQUIRE_CLOSE(dist, 0.0, tol); + BOOST_REQUIRE_CLOSE(always_pos_dist, vec.norm(), tol); + pos = {0., 0., 0.}; + } +} + +BOOST_AUTO_TEST_CASE(dist_function) { + Shapes::Sphere s_pos; + Shapes::Sphere s_neg; + s_pos.direction() = 1.0; + s_neg.direction() = -1.0; + + check_distance_function(s_pos); + check_distance_function(s_neg); +}