30 return data.d_pdDofMpi;
36 std::sort(v.begin(), v.end());
37 v.erase(std::unique(v.begin(), v.end()), v.end());
44 const size_t n_nodes =
data.d_pdNodePartition.size();
46 std::vector<std::vector<int>> need_from(
static_cast<size_t>(size));
47 for (
size_t i = 0; i < n_nodes; ++i) {
48 if (
static_cast<int>(
data.d_pdNodePartition[i]) != rank)
50 for (
size_t j :
data.d_neighPd[i]) {
51 const int own =
static_cast<int>(
data.d_pdNodePartition[j]);
53 need_from[
static_cast<size_t>(own)].push_back(
static_cast<int>(j));
56 for (
auto &v : need_from)
59 std::vector<int> sendcounts(
static_cast<size_t>(size), 0);
60 std::vector<int> recvcounts(
static_cast<size_t>(size), 0);
61 for (
int r = 0; r < size; ++r)
62 sendcounts[
static_cast<size_t>(r)] =
63 static_cast<int>(need_from[
static_cast<size_t>(r)].size());
64 MPI_Alltoall(sendcounts.data(), 1, MPI_INT, recvcounts.data(), 1, MPI_INT,
67 std::vector<int> sdispls(
static_cast<size_t>(size), 0);
68 std::vector<int> rdispls(
static_cast<size_t>(size), 0);
71 for (
int r = 0; r < size; ++r) {
72 sdispls[
static_cast<size_t>(r)] = send_total;
73 rdispls[
static_cast<size_t>(r)] = recv_total;
74 send_total += sendcounts[
static_cast<size_t>(r)];
75 recv_total += recvcounts[
static_cast<size_t>(r)];
78 std::vector<int> sendbuf(
static_cast<size_t>(send_total));
79 for (
int r = 0; r < size; ++r) {
80 const auto &v = need_from[
static_cast<size_t>(r)];
81 std::copy(v.begin(), v.end(),
82 sendbuf.begin() + sdispls[
static_cast<size_t>(r)]);
84 std::vector<int> recvbuf(
static_cast<size_t>(recv_total));
85 MPI_Alltoallv(sendbuf.data(), sendcounts.data(), sdispls.data(), MPI_INT,
86 recvbuf.data(), recvcounts.data(), rdispls.data(), MPI_INT,
89 data.d_pdGhostNeedFrom = std::move(need_from);
90 data.d_pdGhostServeTo.assign(
static_cast<size_t>(size), {});
91 for (
int r = 0; r < size; ++r) {
92 auto &dst =
data.d_pdGhostServeTo[
static_cast<size_t>(r)];
93 dst.resize(
static_cast<size_t>(recvcounts[
static_cast<size_t>(r)]));
94 for (
int k = 0; k < recvcounts[static_cast<size_t>(r)]; ++k) {
95 const int g = recvbuf[
static_cast<size_t>(rdispls[
static_cast<size_t>(r)] + k)];
96 if (g < 0 ||
static_cast<size_t>(g) >= n_nodes)
97 throw std::runtime_error(
"pdMpi: bad node id in ghost plan");
98 if (
static_cast<int>(
data.d_pdNodePartition[
static_cast<size_t>(g)]) !=
100 throw std::runtime_error(
"pdMpi: serve node not owned here");
101 dst[
static_cast<size_t>(k)] = g;
106 for (
const auto &v :
data.d_pdGhostNeedFrom)
108 data.setKeyData(
"pd_mpi_ghost_nodes",
static_cast<double>(n_ghost));
115 const size_t n = field.size();
116 std::vector<double> buf(3 * n, 0.);
117 for (
size_t i = 0; i < n; ++i) {
118 if (
static_cast<int>(
data.d_pdNodePartition[i]) != rank)
120 buf[3 * i + 0] = field[i].d_x;
121 buf[3 * i + 1] = field[i].d_y;
122 buf[3 * i + 2] = field[i].d_z;
124 MPI_Allreduce(MPI_IN_PLACE, buf.data(),
static_cast<int>(3 * n), MPI_DOUBLE,
126 for (
size_t i = 0; i < n; ++i)
127 field[i] =
util::Point(buf[3 * i], buf[3 * i + 1], buf[3 * i + 2]);
134 std::vector<std::vector<double>> send(
static_cast<size_t>(size));
135 for (
int r = 0; r < size; ++r) {
136 for (
int id :
data.d_pdGhostServeTo[
static_cast<size_t>(r)]) {
137 const auto &p = field[
static_cast<size_t>(id)];
138 send[
static_cast<size_t>(r)].push_back(p.d_x);
139 send[
static_cast<size_t>(r)].push_back(p.d_y);
140 send[
static_cast<size_t>(r)].push_back(p.d_z);
144 std::vector<int> sendcounts(
static_cast<size_t>(size), 0);
145 std::vector<int> recvcounts(
static_cast<size_t>(size), 0);
146 for (
int r = 0; r < size; ++r)
147 sendcounts[
static_cast<size_t>(r)] =
148 static_cast<int>(send[
static_cast<size_t>(r)].size());
149 MPI_Alltoall(sendcounts.data(), 1, MPI_INT, recvcounts.data(), 1, MPI_INT,
152 std::vector<int> sdispls(
static_cast<size_t>(size), 0);
153 std::vector<int> rdispls(
static_cast<size_t>(size), 0);
156 for (
int r = 0; r < size; ++r) {
157 sdispls[
static_cast<size_t>(r)] = send_total;
158 rdispls[
static_cast<size_t>(r)] = recv_total;
159 send_total += sendcounts[
static_cast<size_t>(r)];
160 recv_total += recvcounts[
static_cast<size_t>(r)];
163 std::vector<double> sendbuf(
static_cast<size_t>(send_total));
164 for (
int r = 0; r < size; ++r) {
165 const auto &v = send[
static_cast<size_t>(r)];
166 std::copy(v.begin(), v.end(),
167 sendbuf.begin() + sdispls[
static_cast<size_t>(r)]);
169 std::vector<double> recvbuf(
static_cast<size_t>(recv_total));
170 MPI_Alltoallv(sendbuf.data(), sendcounts.data(), sdispls.data(), MPI_DOUBLE,
171 recvbuf.data(), recvcounts.data(), rdispls.data(), MPI_DOUBLE,
174 for (
int r = 0; r < size; ++r) {
175 size_t off =
static_cast<size_t>(rdispls[
static_cast<size_t>(r)]);
176 for (
int id :
data.d_pdGhostNeedFrom[
static_cast<size_t>(r)]) {
177 field[
static_cast<size_t>(id)] =
178 util::Point(recvbuf[off], recvbuf[off + 1], recvbuf[off + 2]);
188 std::vector<std::vector<double>> send(
static_cast<size_t>(size));
189 for (
int r = 0; r < size; ++r) {
190 for (
int id :
data.d_pdGhostServeTo[
static_cast<size_t>(r)])
191 send[
static_cast<size_t>(r)].push_back(field[
static_cast<size_t>(
id)]);
194 std::vector<int> sendcounts(
static_cast<size_t>(size), 0);
195 std::vector<int> recvcounts(
static_cast<size_t>(size), 0);
196 for (
int r = 0; r < size; ++r)
197 sendcounts[
static_cast<size_t>(r)] =
198 static_cast<int>(send[
static_cast<size_t>(r)].size());
199 MPI_Alltoall(sendcounts.data(), 1, MPI_INT, recvcounts.data(), 1, MPI_INT,
202 std::vector<int> sdispls(
static_cast<size_t>(size), 0);
203 std::vector<int> rdispls(
static_cast<size_t>(size), 0);
206 for (
int r = 0; r < size; ++r) {
207 sdispls[
static_cast<size_t>(r)] = send_total;
208 rdispls[
static_cast<size_t>(r)] = recv_total;
209 send_total += sendcounts[
static_cast<size_t>(r)];
210 recv_total += recvcounts[
static_cast<size_t>(r)];
213 std::vector<double> sendbuf(
static_cast<size_t>(send_total));
214 for (
int r = 0; r < size; ++r) {
215 const auto &v = send[
static_cast<size_t>(r)];
216 std::copy(v.begin(), v.end(),
217 sendbuf.begin() + sdispls[
static_cast<size_t>(r)]);
219 std::vector<double> recvbuf(
static_cast<size_t>(recv_total));
220 MPI_Alltoallv(sendbuf.data(), sendcounts.data(), sdispls.data(), MPI_DOUBLE,
221 recvbuf.data(), recvcounts.data(), rdispls.data(), MPI_DOUBLE,
224 for (
int r = 0; r < size; ++r) {
225 size_t off =
static_cast<size_t>(rdispls[
static_cast<size_t>(r)]);
226 for (
int id :
data.d_pdGhostNeedFrom[
static_cast<size_t>(r)])
227 field[
static_cast<size_t>(id)] = recvbuf[off++];
234 data.d_pdDofMpi =
false;
235 data.d_pdGrainAligned =
false;
236 data.d_pdNodePartition.clear();
237 data.d_pdGhostNeedFrom.clear();
238 data.d_pdGhostServeTo.clear();
243 if (strategy !=
"dof")
248 if (
data.d_neighPd.empty() ||
data.d_neighPd.size() !=
data.d_x.size())
251 data.d_pdDofMpi =
true;
252 data.d_pdGrainAligned =
false;
254 const size_t n_nodes =
data.d_x.size();
260 data.d_pdNodePartition,
261 static_cast<size_t>(size));
263 data.d_pdNodePartition.assign(n_nodes, 0);
265 MPI_Bcast(
data.d_pdNodePartition.data(),
static_cast<int>(n_nodes),
269 for (
size_t i = 0; i < n_nodes; ++i)
270 if (
static_cast<int>(
data.d_pdNodePartition[i]) == rank)
276 "DOF-MPI: rank {}/{} owns {}/{} nodes\n", rank, size, n_owned, n_nodes));
280 if (
data.d_vMag.size() !=
data.d_v.size())
281 data.d_vMag.resize(
data.d_v.size(), 0.);
282 for (
size_t i = 0; i <
data.d_v.size(); ++i)
283 data.d_vMag[i] =
data.d_v[i].length();
287 if (!
data.d_pdDofMpi)
289 using clock = std::chrono::steady_clock;
290 const auto t0 = clock::now();
297 if (
data.d_input_p &&
data.d_input_p->isMultiParticle()) {
300 for (
size_t i = 0; i <
data.d_x.size(); ++i)
307 for (
int id :
data.d_pdGhostNeedFrom[
static_cast<size_t>(r)]) {
308 const size_t i =
static_cast<size_t>(id);
313 data.appendKeyData(
"pd_mpi_disp_exchange_time",
318 if (!
data.d_pdDofMpi)
320 if (
data.d_thetaX.empty())
322 using clock = std::chrono::steady_clock;
323 const auto t0 = clock::now();
324 if (
data.d_input_p &&
data.d_input_p->isMultiParticle()) {
326 const size_t n =
data.d_thetaX.size();
327 std::vector<double> buf(n, 0.);
328 for (
size_t i = 0; i < n; ++i) {
329 if (
static_cast<int>(
data.d_pdNodePartition[i]) == rank)
330 buf[i] =
data.d_thetaX[i];
332 MPI_Allreduce(MPI_IN_PLACE, buf.data(),
static_cast<int>(n), MPI_DOUBLE,
334 data.d_thetaX.swap(buf);
338 data.appendKeyData(
"pd_mpi_theta_exchange_time",
A class to store model data.
void buildGhostPlan(data::ModelData &data)
void exchangePoints(data::ModelData &data, std::vector< util::Point > &field)
void exchangeDoubles(data::ModelData &data, std::vector< double > &field)
void syncAllOwnedPoints(data::ModelData &data, std::vector< util::Point > &field)
void uniqueSorted(std::vector< int > &v)
void metisGraphPartition(std::string partitionMethod, const std::vector< std::vector< size_t > > &nodeNeighs, std::vector< size_t > &nodePartition, size_t nPartitions)
Partitions the nodes based on node neighborlist supplied. Function first creates a graph with nodes a...
std::string resolvedMpiStrategy(const data::ModelData &data)
Resolved MPI strategy: none|particle|dof (auto expanded).
bool dofMpiEnabled(const data::ModelData &data)
True when nodal DOF MPI is active (mpiSize > 1, MPI_Strategy=dof).
void setupDofPartition(data::ModelData &data)
Metis-partition nodes on the PD neighbor graph and build ghost plans. Call after d_neighPd is ready a...
void exchangeGhostTheta(data::ModelData &data)
Halo-exchange state-based dilatation d_thetaX for PD ghosts.
void exchangeGhostDisplacement(data::ModelData &data)
Halo-exchange nodal displacements (and current x) for PD ghosts.
void print(const T &msg, int nt=print_default_tab, int printMpiRank=print_default_mpi_rank)
Prints formatted information.
float timeDiff(std::chrono::steady_clock::time_point begin, std::chrono::steady_clock::time_point end, std::string unit="microseconds")
Returns difference between two times.
bool isMpiEnabled()
Function to check if MPI is enabled.
int mpiSize()
Get size (number) of processors.
int mpiRank()
get rank (id) of this processor
MPI_Comm mpiComm()
Get MPI comm.
static void refreshVMagFromV(data::ModelData &data)
A structure to represent 3d vectors.