From d52bfbae6ba2eef98fb7ba6c1c153ed100572506 Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Fri, 9 Oct 2026 19:11:03 +0800 Subject: [PATCH 1/4] fix(esolver): sort DeePMD MD neighbors by distance --- source/source_esolver/esolver_dp.cpp | 43 ++++++++++++++++++- source/source_esolver/esolver_dp.h | 10 +++++ source/source_esolver/test/CMakeLists.txt | 1 + .../source_esolver/test/test_esolver_dp.cpp | 36 ++++++++++++++++ 4 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 source/source_esolver/test/test_esolver_dp.cpp diff --git a/source/source_esolver/esolver_dp.cpp b/source/source_esolver/esolver_dp.cpp index b5a84727b9c..2992043a790 100644 --- a/source/source_esolver/esolver_dp.cpp +++ b/source/source_esolver/esolver_dp.cpp @@ -31,9 +31,38 @@ #include #include #include +#include using namespace ModuleESolver; +std::vector ESolver_DP::sort_neighbor_indices_by_distance(const std::vector& coord, + const int central_atom, + const int* neighbor_indices, + const int neighbor_count) +{ + std::vector > distance_neighbors; + distance_neighbors.reserve(static_cast(neighbor_count)); + for (int ineighbor = 0; ineighbor < neighbor_count; ++ineighbor) + { + const int neighbor_atom = neighbor_indices[ineighbor]; + const double dx = coord[3 * central_atom] - coord[3 * neighbor_atom]; + const double dy = coord[3 * central_atom + 1] - coord[3 * neighbor_atom + 1]; + const double dz = coord[3 * central_atom + 2] - coord[3 * neighbor_atom + 2]; + const double distance2 = dx * dx + dy * dy + dz * dz; + distance_neighbors.push_back(std::make_pair(distance2, neighbor_atom)); + } + + std::sort(distance_neighbors.begin(), distance_neighbors.end()); + + std::vector sorted_neighbors; + sorted_neighbors.reserve(static_cast(neighbor_count)); + for (const std::pair& distance_neighbor : distance_neighbors) + { + sorted_neighbors.push_back(distance_neighbor.second); + } + return sorted_neighbors; +} + void ESolver_DP::before_all_runners(BaseCell& basecell, const Input_para& inp) { this->inp_ = &inp; @@ -131,11 +160,21 @@ void ESolver_DP::runner(BaseCell& basecell, const int istep) std::vector ilist(static_cast(nowned_atoms), 0); std::vector numneigh(static_cast(nowned_atoms), 0); std::vector firstneigh(static_cast(nowned_atoms), NULL); + std::vector > sorted_neighbors(static_cast(nowned_atoms)); for (int iat = 0; iat < nowned_atoms; ++iat) { ilist[static_cast(iat)] = iat; - numneigh[static_cast(iat)] = neighbor_list.get_numneigh(iat); - firstneigh[static_cast(iat)] = const_cast(neighbor_list.get_firstneigh(iat)); + sorted_neighbors[static_cast(iat)] = sort_neighbor_indices_by_distance( + coord, + iat, + neighbor_list.get_firstneigh(iat), + neighbor_list.get_numneigh(iat)); + numneigh[static_cast(iat)] + = static_cast(sorted_neighbors[static_cast(iat)].size()); + firstneigh[static_cast(iat)] + = sorted_neighbors[static_cast(iat)].empty() + ? NULL + : sorted_neighbors[static_cast(iat)].data(); } #ifdef __DPMDC deepmd::hpp::InputNlist nlist(nowned_atoms, diff --git a/source/source_esolver/esolver_dp.h b/source/source_esolver/esolver_dp.h index 8b8067552df..ac10abed7d7 100644 --- a/source/source_esolver/esolver_dp.h +++ b/source/source_esolver/esolver_dp.h @@ -2,6 +2,9 @@ #define ESOLVER_DP_H #include "esolver.h" + +class ESolverDPNeighborListTest; + #ifdef __DPMD #ifdef __DPMDC #include "deepmd/deepmd.hpp" @@ -107,6 +110,13 @@ class ESolver_DP : public ESolver } private: + friend class ::ESolverDPNeighborListTest; + + static std::vector sort_neighbor_indices_by_distance(const std::vector& coord, + int central_atom, + const int* neighbor_indices, + int neighbor_count); + /** * @brief determine the type map of DP model * diff --git a/source/source_esolver/test/CMakeLists.txt b/source/source_esolver/test/CMakeLists.txt index 80ca8f061b1..e9d7a9d75c5 100644 --- a/source/source_esolver/test/CMakeLists.txt +++ b/source/source_esolver/test/CMakeLists.txt @@ -21,6 +21,7 @@ AddTest( LIBS ${_esolver_dp_test_libs} SOURCES esolver_dp_test.cpp + test_esolver_dp.cpp ../esolver_dp.cpp ../../source_cell/basecell.cpp ../../source_cell/cif_io.cpp diff --git a/source/source_esolver/test/test_esolver_dp.cpp b/source/source_esolver/test/test_esolver_dp.cpp new file mode 100644 index 00000000000..afdb868585f --- /dev/null +++ b/source/source_esolver/test/test_esolver_dp.cpp @@ -0,0 +1,36 @@ +#include "gtest/gtest.h" + +#include "../esolver_dp.h" + +#include + +class ESolverDPNeighborListTest : public ::testing::Test +{ + public: + static std::vector sort_neighbors(const std::vector& coord, + int central_atom, + const int* neighbor_indices, + int neighbor_count) + { + return ModuleESolver::ESolver_DP::sort_neighbor_indices_by_distance(coord, + central_atom, + neighbor_indices, + neighbor_count); + } +}; + +TEST_F(ESolverDPNeighborListTest, SortsNeighborsByDistanceWithStableIndexTieBreak) +{ + const std::vector coord = { + 0.0, 0.0, 0.0, + 2.0, 0.0, 0.0, + 1.0, 0.0, 0.0, + 0.0, 3.0, 0.0, + -1.0, 0.0, 0.0}; + const int neighbors[] = {3, 1, 4, 2}; + + const std::vector sorted = ESolverDPNeighborListTest::sort_neighbors(coord, 0, neighbors, 4); + + const std::vector expected = {2, 1, 4, 3}; + EXPECT_EQ(sorted, expected); +} From 3a0bb7072b773f1ba1423f5c30564783975e2016 Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Fri, 9 Oct 2026 19:50:29 +0800 Subject: [PATCH 2/4] test(esolver): fix neighbor ordering expectation --- source/source_esolver/test/test_esolver_dp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/source_esolver/test/test_esolver_dp.cpp b/source/source_esolver/test/test_esolver_dp.cpp index afdb868585f..e00c0e91cda 100644 --- a/source/source_esolver/test/test_esolver_dp.cpp +++ b/source/source_esolver/test/test_esolver_dp.cpp @@ -31,6 +31,6 @@ TEST_F(ESolverDPNeighborListTest, SortsNeighborsByDistanceWithStableIndexTieBrea const std::vector sorted = ESolverDPNeighborListTest::sort_neighbors(coord, 0, neighbors, 4); - const std::vector expected = {2, 1, 4, 3}; + const std::vector expected = {2, 4, 1, 3}; EXPECT_EQ(sorted, expected); } From 8757b747875171e7ca9f3baf628d079f3950d39a Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Fri, 9 Oct 2026 21:01:48 +0800 Subject: [PATCH 3/4] refactor(neighbor): provide distance-sorted neighbor view --- .../module_neighlist/CMakeLists.txt | 1 + .../module_neighlist/neighbor_list.cpp | 31 ++++++++++++++++ .../module_neighlist/neighbor_list.h | 3 ++ .../module_neighlist/test/CMakeLists.txt | 1 + .../test/test_neighbor_list.cpp | 21 +++++++++++ source/source_esolver/esolver_dp.cpp | 37 +------------------ source/source_esolver/esolver_dp.h | 9 ----- source/source_esolver/test/CMakeLists.txt | 2 +- .../source_esolver/test/test_esolver_dp.cpp | 36 ------------------ 9 files changed, 60 insertions(+), 81 deletions(-) create mode 100644 source/source_cell/module_neighlist/neighbor_list.cpp delete mode 100644 source/source_esolver/test/test_esolver_dp.cpp diff --git a/source/source_cell/module_neighlist/CMakeLists.txt b/source/source_cell/module_neighlist/CMakeLists.txt index 119eba4dfd4..0c5d9bebffa 100644 --- a/source/source_cell/module_neighlist/CMakeLists.txt +++ b/source/source_cell/module_neighlist/CMakeLists.txt @@ -1,5 +1,6 @@ set(neighbor_search_sources bin_manager.cpp + neighbor_list.cpp neighbor_search.cpp page_allocator.cpp ) diff --git a/source/source_cell/module_neighlist/neighbor_list.cpp b/source/source_cell/module_neighlist/neighbor_list.cpp new file mode 100644 index 00000000000..920a32fa6d4 --- /dev/null +++ b/source/source_cell/module_neighlist/neighbor_list.cpp @@ -0,0 +1,31 @@ +#include "neighbor_list.h" + +#include +#include + +std::vector NeighborList::get_neighbors_sorted_by_distance(const int central_atom, + const std::vector& coordinates) const +{ + const int neighbor_count = get_numneigh(central_atom); + std::vector > distance_neighbors; + distance_neighbors.reserve(static_cast(neighbor_count)); + for (int ineighbor = 0; ineighbor < neighbor_count; ++ineighbor) + { + const int neighbor_atom = get_firstneigh(central_atom)[ineighbor]; + const double dx = coordinates[3 * central_atom] - coordinates[3 * neighbor_atom]; + const double dy = coordinates[3 * central_atom + 1] - coordinates[3 * neighbor_atom + 1]; + const double dz = coordinates[3 * central_atom + 2] - coordinates[3 * neighbor_atom + 2]; + const double distance2 = dx * dx + dy * dy + dz * dz; + distance_neighbors.push_back(std::make_pair(distance2, neighbor_atom)); + } + + std::sort(distance_neighbors.begin(), distance_neighbors.end()); + + std::vector sorted_neighbors; + sorted_neighbors.reserve(static_cast(neighbor_count)); + for (const std::pair& distance_neighbor : distance_neighbors) + { + sorted_neighbors.push_back(distance_neighbor.second); + } + return sorted_neighbors; +} diff --git a/source/source_cell/module_neighlist/neighbor_list.h b/source/source_cell/module_neighlist/neighbor_list.h index 017d23fb328..c460deb11c3 100644 --- a/source/source_cell/module_neighlist/neighbor_list.h +++ b/source/source_cell/module_neighlist/neighbor_list.h @@ -29,6 +29,9 @@ class NeighborList int get_numneigh(int i) const { return numneigh_[i]; } int* get_firstneigh(int i) { return firstneigh_[i]; } const int* get_firstneigh(int i) const { return firstneigh_[i]; } + /// Return a distance-sorted copy of one atom's neighbors without changing the stored order. + std::vector get_neighbors_sorted_by_distance(int central_atom, + const std::vector& coordinates) const; PageAllocator& get_allocator() { return allocator_; } const PageAllocator& get_allocator() const { return allocator_; } diff --git a/source/source_cell/module_neighlist/test/CMakeLists.txt b/source/source_cell/module_neighlist/test/CMakeLists.txt index 80270b213d3..d2f6c85845a 100644 --- a/source/source_cell/module_neighlist/test/CMakeLists.txt +++ b/source/source_cell/module_neighlist/test/CMakeLists.txt @@ -31,6 +31,7 @@ AddTest( LIBS parameter base device SOURCES test_neighbor_list.cpp + ../neighbor_list.cpp ../page_allocator.cpp ) diff --git a/source/source_cell/module_neighlist/test/test_neighbor_list.cpp b/source/source_cell/module_neighlist/test/test_neighbor_list.cpp index d40d5e03c21..2e949859296 100644 --- a/source/source_cell/module_neighlist/test/test_neighbor_list.cpp +++ b/source/source_cell/module_neighlist/test/test_neighbor_list.cpp @@ -76,3 +76,24 @@ TEST(NeighborList_Getters, Accessors) EXPECT_EQ(nl.get_numneigh(0), 0); EXPECT_EQ(nl.get_firstneigh(0), nullptr); } + +TEST(NeighborList_Sort, ByDistanceWithIndexTieBreak) +{ + NeighborList nl; + nl.initialize(1, 16); + const std::vector neighbors = {3, 1, 4, 2}; + nl.set_neighbors(0, neighbors); + + const std::vector coordinates = { + 0.0, 0.0, 0.0, + 2.0, 0.0, 0.0, + 1.0, 0.0, 0.0, + 0.0, 3.0, 0.0, + -1.0, 0.0, 0.0}; + + const std::vector sorted = nl.get_neighbors_sorted_by_distance(0, coordinates); + + const std::vector expected = {2, 4, 1, 3}; + EXPECT_EQ(sorted, expected); + EXPECT_EQ(nl.get_firstneigh(0)[0], 3); +} diff --git a/source/source_esolver/esolver_dp.cpp b/source/source_esolver/esolver_dp.cpp index 2992043a790..3de1522e053 100644 --- a/source/source_esolver/esolver_dp.cpp +++ b/source/source_esolver/esolver_dp.cpp @@ -26,43 +26,13 @@ #include "source_io/module_output/output_log.h" #include "source_io/module_parameter/parameter.h" -#include #include #include #include #include -#include using namespace ModuleESolver; -std::vector ESolver_DP::sort_neighbor_indices_by_distance(const std::vector& coord, - const int central_atom, - const int* neighbor_indices, - const int neighbor_count) -{ - std::vector > distance_neighbors; - distance_neighbors.reserve(static_cast(neighbor_count)); - for (int ineighbor = 0; ineighbor < neighbor_count; ++ineighbor) - { - const int neighbor_atom = neighbor_indices[ineighbor]; - const double dx = coord[3 * central_atom] - coord[3 * neighbor_atom]; - const double dy = coord[3 * central_atom + 1] - coord[3 * neighbor_atom + 1]; - const double dz = coord[3 * central_atom + 2] - coord[3 * neighbor_atom + 2]; - const double distance2 = dx * dx + dy * dy + dz * dz; - distance_neighbors.push_back(std::make_pair(distance2, neighbor_atom)); - } - - std::sort(distance_neighbors.begin(), distance_neighbors.end()); - - std::vector sorted_neighbors; - sorted_neighbors.reserve(static_cast(neighbor_count)); - for (const std::pair& distance_neighbor : distance_neighbors) - { - sorted_neighbors.push_back(distance_neighbor.second); - } - return sorted_neighbors; -} - void ESolver_DP::before_all_runners(BaseCell& basecell, const Input_para& inp) { this->inp_ = &inp; @@ -164,11 +134,8 @@ void ESolver_DP::runner(BaseCell& basecell, const int istep) for (int iat = 0; iat < nowned_atoms; ++iat) { ilist[static_cast(iat)] = iat; - sorted_neighbors[static_cast(iat)] = sort_neighbor_indices_by_distance( - coord, - iat, - neighbor_list.get_firstneigh(iat), - neighbor_list.get_numneigh(iat)); + sorted_neighbors[static_cast(iat)] + = neighbor_list.get_neighbors_sorted_by_distance(iat, coord); numneigh[static_cast(iat)] = static_cast(sorted_neighbors[static_cast(iat)].size()); firstneigh[static_cast(iat)] diff --git a/source/source_esolver/esolver_dp.h b/source/source_esolver/esolver_dp.h index ac10abed7d7..9edd2b9608c 100644 --- a/source/source_esolver/esolver_dp.h +++ b/source/source_esolver/esolver_dp.h @@ -3,8 +3,6 @@ #include "esolver.h" -class ESolverDPNeighborListTest; - #ifdef __DPMD #ifdef __DPMDC #include "deepmd/deepmd.hpp" @@ -110,13 +108,6 @@ class ESolver_DP : public ESolver } private: - friend class ::ESolverDPNeighborListTest; - - static std::vector sort_neighbor_indices_by_distance(const std::vector& coord, - int central_atom, - const int* neighbor_indices, - int neighbor_count); - /** * @brief determine the type map of DP model * diff --git a/source/source_esolver/test/CMakeLists.txt b/source/source_esolver/test/CMakeLists.txt index e9d7a9d75c5..2b7a04a122c 100644 --- a/source/source_esolver/test/CMakeLists.txt +++ b/source/source_esolver/test/CMakeLists.txt @@ -21,9 +21,9 @@ AddTest( LIBS ${_esolver_dp_test_libs} SOURCES esolver_dp_test.cpp - test_esolver_dp.cpp ../esolver_dp.cpp ../../source_cell/basecell.cpp ../../source_cell/cif_io.cpp + ../../source_cell/module_neighlist/neighbor_list.cpp ../../source_io/module_output/output_log.cpp ) diff --git a/source/source_esolver/test/test_esolver_dp.cpp b/source/source_esolver/test/test_esolver_dp.cpp deleted file mode 100644 index e00c0e91cda..00000000000 --- a/source/source_esolver/test/test_esolver_dp.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "gtest/gtest.h" - -#include "../esolver_dp.h" - -#include - -class ESolverDPNeighborListTest : public ::testing::Test -{ - public: - static std::vector sort_neighbors(const std::vector& coord, - int central_atom, - const int* neighbor_indices, - int neighbor_count) - { - return ModuleESolver::ESolver_DP::sort_neighbor_indices_by_distance(coord, - central_atom, - neighbor_indices, - neighbor_count); - } -}; - -TEST_F(ESolverDPNeighborListTest, SortsNeighborsByDistanceWithStableIndexTieBreak) -{ - const std::vector coord = { - 0.0, 0.0, 0.0, - 2.0, 0.0, 0.0, - 1.0, 0.0, 0.0, - 0.0, 3.0, 0.0, - -1.0, 0.0, 0.0}; - const int neighbors[] = {3, 1, 4, 2}; - - const std::vector sorted = ESolverDPNeighborListTest::sort_neighbors(coord, 0, neighbors, 4); - - const std::vector expected = {2, 4, 1, 3}; - EXPECT_EQ(sorted, expected); -} From f7ebfed657c32c50b5afe1fe30a7f7b55ce428f0 Mon Sep 17 00:00:00 2001 From: Fei Yang <2501213217@stu.pku.edu.cn> Date: Fri, 9 Oct 2026 21:03:23 +0800 Subject: [PATCH 4/4] style(esolver): remove extra header blank line --- source/source_esolver/esolver_dp.h | 1 - 1 file changed, 1 deletion(-) diff --git a/source/source_esolver/esolver_dp.h b/source/source_esolver/esolver_dp.h index 9edd2b9608c..8b8067552df 100644 --- a/source/source_esolver/esolver_dp.h +++ b/source/source_esolver/esolver_dp.h @@ -2,7 +2,6 @@ #define ESOLVER_DP_H #include "esolver.h" - #ifdef __DPMD #ifdef __DPMDC #include "deepmd/deepmd.hpp"