Skip to content

Commit 0ec14ab

Browse files
19helloFei Yang
andauthored
Add MPI in neighbor_search (#7537)
* add mpi in neighbor_search * fix neighbor search build without mpi * make neighbor search initialization cxx11 compatible * add distributed neighbor decomposition * add mpi in neighbor_search2 * Add neighbor list shared type definitions * fix compile bug * Optimize MPI ghost atom exchange * Resolve Makefile object conflict markers * Guard MPI domain decomposition in serial builds * Align neighbor search Makefile objects * Link neighbor MPI benchmark external deps * Guard benchmark external deps target * Always build neighbor domain decomposition source * Link neighbor MPI benchmark math deps explicitly * fix cmakelists --------- Co-authored-by: Fei Yang <2501213217@stu.pku.edu.cn>
1 parent 8e5d457 commit 0ec14ab

19 files changed

Lines changed: 1789 additions & 886 deletions

source/Makefile.Objects

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,7 @@ OBJS_NEIGHBOR=sltk_atom.o\
415415

416416
OBJS_NEIGHBOR_SEARCH=neighbor_search.o\
417417
bin_manager.o\
418+
domain_decomposition.o\
418419
page_allocator.o\
419420
unitcell_lite.o\
420421

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
1-
add_library(
2-
neighbor_search
3-
OBJECT
1+
set(neighbor_search_sources
42
bin_manager.cpp
3+
domain_decomposition.cpp
54
neighbor_search.cpp
65
page_allocator.cpp
76
unitcell_lite.cpp
87
)
98

9+
add_library(
10+
neighbor_search
11+
OBJECT
12+
${neighbor_search_sources}
13+
)
14+
1015
if(ENABLE_COVERAGE)
1116
add_coverage(neighbor_search)
1217
endif()
@@ -15,4 +20,4 @@ if(BUILD_TESTING)
1520
if(ENABLE_MPI)
1621
add_subdirectory(test)
1722
endif()
18-
endif()
23+
endif()

source/source_cell/module_neighlist/bin_manager.cpp

Lines changed: 67 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,13 @@
22
#include <cmath>
33
#include <algorithm>
44
#include <cassert>
5+
#include <stdexcept>
56
#include "bin_manager.h"
67

78
// ========== Bin class implementation ==========
89

9-
int Bin::get_id_x() const {
10-
return id_x_;
11-
}
12-
13-
int Bin::get_id_y() const {
14-
return id_y_;
15-
}
16-
17-
int Bin::get_id_z() const {
18-
return id_z_;
19-
}
20-
21-
const std::vector<NeighborAtom>& Bin::get_atoms() const {
22-
return atoms_;
10+
const std::vector<ModuleNeighList::LocalAtomIndex>& Bin::get_atom_indices() const {
11+
return atom_indices_;
2312
}
2413

2514
void Bin::set_id(int ix, int iy, int iz) {
@@ -29,11 +18,11 @@ void Bin::set_id(int ix, int iy, int iz) {
2918
}
3019

3120
void Bin::clear_atoms() {
32-
atoms_.clear();
21+
atom_indices_.clear();
3322
}
3423

35-
void Bin::add_atom(const NeighborAtom& atom) {
36-
atoms_.push_back(atom);
24+
void Bin::add_atom_index(ModuleNeighList::LocalAtomIndex atom_index) {
25+
atom_indices_.push_back(atom_index);
3726
}
3827

3928
// ========== BinManager getter methods ==========
@@ -51,26 +40,30 @@ int BinManager::get_nbinz() const {
5140
}
5241

5342
int BinManager::get_total_bins() const {
54-
return static_cast<int>(bins_.size());
43+
return ModuleNeighList::checked_int_size(bins_.size(), "BinManager total bin count");
5544
}
5645

5746
int BinManager::get_bin_atom_count(int bin_index) const {
58-
if (bin_index < 0 || bin_index >= static_cast<int>(bins_.size())) {
47+
if (bin_index < 0 || static_cast<std::size_t>(bin_index) >= bins_.size()) {
5948
return 0;
6049
}
61-
return static_cast<int>(bins_[bin_index].get_atoms().size());
50+
return ModuleNeighList::checked_int_size(bins_[bin_index].get_atom_indices().size(),
51+
"Bin atom count");
6252
}
6353

6454
// ========== BinManager main methods ==========
6555

6656
void BinManager::init_bins(
6757
double sr,
68-
const std::vector<NeighborAtom>& inside_atoms,
69-
const std::vector<NeighborAtom>& ghost_atoms
58+
const std::vector<NeighborAtom>& all_atoms
7059
)
7160
{
7261
sradius_ = sr;
73-
if(inside_atoms.empty() && ghost_atoms.empty())
62+
if (!std::isfinite(sradius_) || sradius_ <= 0.0)
63+
{
64+
throw std::invalid_argument("BinManager search radius must be finite and positive.");
65+
}
66+
if(all_atoms.empty())
7467
{
7568
x_min_ = y_min_ = z_min_ = 0;
7669
x_max_ = y_max_ = z_max_ = 0;
@@ -98,20 +91,34 @@ void BinManager::init_bins(
9891
}
9992
};
10093

101-
update_bounds(inside_atoms);
102-
update_bounds(ghost_atoms);
94+
update_bounds(all_atoms);
10395

10496
bin_sizex_ = bin_sizey_ = bin_sizez_ = sradius_;
10597

106-
nbinx_ = std::ceil((x_max_ - x_min_) / bin_sizex_);
107-
nbiny_ = std::ceil((y_max_ - y_min_) / bin_sizey_);
108-
nbinz_ = std::ceil((z_max_ - z_min_) / bin_sizez_);
98+
const auto checked_bin_dimension = [](const double span, const double bin_size, const char* context) {
99+
const double count = std::ceil(span / bin_size);
100+
if (!std::isfinite(count) || count > static_cast<double>(std::numeric_limits<int>::max()))
101+
{
102+
throw std::overflow_error(std::string(context) + " exceeds int range.");
103+
}
104+
return static_cast<int>(count);
105+
};
106+
107+
nbinx_ = checked_bin_dimension(x_max_ - x_min_, bin_sizex_, "BinManager X bin count");
108+
nbiny_ = checked_bin_dimension(y_max_ - y_min_, bin_sizey_, "BinManager Y bin count");
109+
nbinz_ = checked_bin_dimension(z_max_ - z_min_, bin_sizez_, "BinManager Z bin count");
109110

110111
nbinx_ = std::max(1, nbinx_);
111112
nbiny_ = std::max(1, nbiny_);
112113
nbinz_ = std::max(1, nbinz_);
113114

114-
int nbins = nbinx_ * nbiny_ * nbinz_;
115+
const std::size_t nbins_xy = ModuleNeighList::checked_size_product(static_cast<std::size_t>(nbinx_),
116+
static_cast<std::size_t>(nbiny_),
117+
"BinManager bin count");
118+
const std::size_t nbins_size = ModuleNeighList::checked_size_product(nbins_xy,
119+
static_cast<std::size_t>(nbinz_),
120+
"BinManager bin count");
121+
const int nbins = ModuleNeighList::checked_int_size(nbins_size, "BinManager bin count");
115122

116123
bins_.clear();
117124
bins_.resize(nbins);
@@ -132,12 +139,17 @@ void BinManager::init_bins(
132139
}
133140

134141
void BinManager::do_binning(
135-
const std::vector<NeighborAtom>& inside_atoms,
136-
const std::vector<NeighborAtom>& ghost_atoms
142+
const std::vector<NeighborAtom>& atoms
137143
)
138144
{
139-
auto bin_atom = [&](const NeighborAtom& atom)
145+
if (atoms.size() > static_cast<std::size_t>(std::numeric_limits<ModuleNeighList::LocalAtomIndex>::max()))
140146
{
147+
throw std::overflow_error("BinManager binned atom count exceeds local atom index range.");
148+
}
149+
150+
for (std::size_t iatom = 0; iatom < atoms.size(); ++iatom)
151+
{
152+
const NeighborAtom& atom = atoms[iatom];
141153
int ix = std::min(
142154
std::max(int((atom.position_x - x_min_) / bin_sizex_), 0),
143155
nbinx_ - 1
@@ -155,11 +167,9 @@ void BinManager::do_binning(
155167

156168
int idx = bin_index(ix, iy, iz);
157169

158-
bins_[idx].add_atom(atom);
159-
};
160-
161-
for (const auto& atom : inside_atoms) bin_atom(atom);
162-
for (const auto& atom : ghost_atoms) bin_atom(atom);
170+
const ModuleNeighList::LocalAtomIndex atom_index = static_cast<ModuleNeighList::LocalAtomIndex>(iatom);
171+
bins_[idx].add_atom_index(atom_index);
172+
}
163173
}
164174

165175
int BinManager::bin_index(int ix, int iy, int iz) const {
@@ -168,7 +178,8 @@ int BinManager::bin_index(int ix, int iy, int iz) const {
168178

169179
void BinManager::build_atom_neighbors(
170180
NeighborList& neighbor_list,
171-
std::vector<NeighborAtom>& atoms
181+
const std::vector<NeighborAtom>& atoms,
182+
const std::vector<NeighborAtom>& binned_atoms
172183
)
173184
{
174185
assert(atoms.size() == static_cast<size_t>(neighbor_list.get_nlocal()));
@@ -179,22 +190,24 @@ void BinManager::build_atom_neighbors(
179190

180191
std::vector<int> neigh_tmp;
181192

182-
for (int i = 0; i < atoms.size(); i++)
193+
const int nlocal = neighbor_list.get_nlocal();
194+
for (int i = 0; i < nlocal; i++)
183195
{
184196
neigh_tmp.clear();
197+
const NeighborAtom& atom = atoms[i];
185198

186199
int ix = std::min(
187-
std::max(int((atoms[i].position_x - x_min_) / bin_sizex_), 0),
200+
std::max(int((atom.position_x - x_min_) / bin_sizex_), 0),
188201
nbinx_ - 1
189202
);
190203

191204
int iy = std::min(
192-
std::max(int((atoms[i].position_y - y_min_) / bin_sizey_), 0),
205+
std::max(int((atom.position_y - y_min_) / bin_sizey_), 0),
193206
nbiny_ - 1
194207
);
195208

196209
int iz = std::min(
197-
std::max(int((atoms[i].position_z - z_min_) / bin_sizez_), 0),
210+
std::max(int((atom.position_z - z_min_) / bin_sizez_), 0),
198211
nbinz_ - 1
199212
);
200213

@@ -215,15 +228,20 @@ void BinManager::build_atom_neighbors(
215228

216229
int nidx = bin_index(jx, jy, jz);
217230

218-
for (const NeighborAtom& natom : bins_[nidx].get_atoms())
231+
for (const ModuleNeighList::LocalAtomIndex binned_atom_index : bins_[nidx].get_atom_indices())
219232
{
220-
double dx = atoms[i].position_x - natom.position_x;
221-
double dy = atoms[i].position_y - natom.position_y;
222-
double dz = atoms[i].position_z - natom.position_z;
233+
const NeighborAtom& natom = binned_atoms[static_cast<std::size_t>(binned_atom_index)];
234+
double dx = atom.position_x - natom.position_x;
235+
double dy = atom.position_y - natom.position_y;
236+
double dz = atom.position_z - natom.position_z;
223237

224238
double dist2 = dx * dx + dy * dy + dz * dz;
225239

226-
if (dist2 <= sradius2 && dist2 != 0)
240+
if (natom.atom_id == atom.atom_id)
241+
{
242+
continue;
243+
}
244+
if (dist2 <= sradius2)
227245
{
228246
neigh_tmp.push_back(natom.atom_id);
229247
}
@@ -232,7 +250,7 @@ void BinManager::build_atom_neighbors(
232250
}
233251
}
234252

235-
int n = neigh_tmp.size();
253+
const int n = ModuleNeighList::checked_int_size(neigh_tmp.size(), "BinManager neighbor count");
236254

237255
int* ptr = neighbor_list.allocator_.allocate(n);
238256

@@ -255,4 +273,4 @@ void BinManager::clear()
255273
}
256274

257275
bins_.clear();
258-
}
276+
}

source/source_cell/module_neighlist/bin_manager.h

Lines changed: 17 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
#include <vector>
55
#include "source_cell/module_neighlist/neighbor_atom.h"
66
#include "source_cell/module_neighlist/neighbor_list.h"
7+
#include "source_cell/module_neighlist/neighbor_types.h"
78

89
/**
910
* @brief A single bin in the 3D binning grid for neighbor search.
1011
*
11-
* Each bin stores atoms that fall within its spatial region,
12+
* Each bin stores indices of atoms that fall within its spatial region,
1213
* along with its position indices in the 3D grid.
1314
*/
1415
class Bin
@@ -27,28 +28,10 @@ class Bin
2728
// ========== Getter methods ==========
2829

2930
/**
30-
* @brief Get the X index of this bin in the grid.
31-
* @return X index.
31+
* @brief Get the atom indices stored in this bin.
32+
* @return Const reference to the atom-index vector.
3233
*/
33-
int get_id_x() const;
34-
35-
/**
36-
* @brief Get the Y index of this bin in the grid.
37-
* @return Y index.
38-
*/
39-
int get_id_y() const;
40-
41-
/**
42-
* @brief Get the Z index of this bin in the grid.
43-
* @return Z index.
44-
*/
45-
int get_id_z() const;
46-
47-
/**
48-
* @brief Get the atoms stored in this bin.
49-
* @return Const reference to the atom vector.
50-
*/
51-
const std::vector<NeighborAtom>& get_atoms() const;
34+
const std::vector<ModuleNeighList::LocalAtomIndex>& get_atom_indices() const;
5235

5336
// ========== Setter methods (internal use) ==========
5437

@@ -66,10 +49,10 @@ class Bin
6649
void clear_atoms();
6750

6851
/**
69-
* @brief Add an atom to this bin.
70-
* @param atom The atom to add.
52+
* @brief Add an atom index to this bin.
53+
* @param atom_index Index of the atom in the vector passed to BinManager::do_binning().
7154
*/
72-
void add_atom(const NeighborAtom& atom);
55+
void add_atom_index(ModuleNeighList::LocalAtomIndex atom_index);
7356

7457
private:
7558
/// X index in the 3D bin grid
@@ -81,8 +64,8 @@ class Bin
8164
/// Z index in the 3D bin grid
8265
int id_z_ = 0;
8366

84-
/// Atoms contained in this bin
85-
std::vector<NeighborAtom> atoms_;
67+
/// Indices into the atom vector passed to BinManager::do_binning().
68+
std::vector<ModuleNeighList::LocalAtomIndex> atom_indices_;
8669
};
8770

8871
/**
@@ -113,8 +96,7 @@ class BinManager
11396
*/
11497
void init_bins(
11598
double sr,
116-
const std::vector<NeighborAtom>& inside_atoms,
117-
const std::vector<NeighborAtom>& ghost_atoms
99+
const std::vector<NeighborAtom>& all_atoms
118100
);
119101

120102
/**
@@ -123,13 +105,9 @@ class BinManager
123105
* Must be called after init_bins(). Each atom is placed into the
124106
* bin that contains its spatial position.
125107
*
126-
* @param inside_atoms Atoms inside the local MPI domain.
127-
* @param ghost_atoms Ghost atoms from neighboring domains.
108+
* @param atoms All atoms to assign to bins.
128109
*/
129-
void do_binning(
130-
const std::vector<NeighborAtom>& inside_atoms,
131-
const std::vector<NeighborAtom>& ghost_atoms
132-
);
110+
void do_binning(const std::vector<NeighborAtom>& atoms);
133111

134112
/**
135113
* @brief Build neighbor list by searching adjacent bins.
@@ -139,10 +117,12 @@ class BinManager
139117
*
140118
* @param neighbor_list Output neighbor list to populate.
141119
* @param atoms Atoms for which to build neighbors.
120+
* @param binned_atoms All atoms assigned to bins by do_binning().
142121
*/
143122
void build_atom_neighbors(
144123
NeighborList& neighbor_list,
145-
std::vector<NeighborAtom>& atoms
124+
const std::vector<NeighborAtom>& atoms,
125+
const std::vector<NeighborAtom>& binned_atoms
146126
);
147127

148128
/**
@@ -220,4 +200,4 @@ class BinManager
220200
int bin_index(int ix, int iy, int iz) const;
221201
};
222202

223-
#endif // BIN_MANAGER_H
203+
#endif // BIN_MANAGER_H

0 commit comments

Comments
 (0)