7 #ifndef MPI_PARTICLE_DISTRIBUTE_H_ 8 #define MPI_PARTICLE_DISTRIBUTE_H_ 10 #ifdef PORTAGE_ENABLE_MPI 21 #include "wonton/support/Point.h" 38 class MPI_Particle_Distribute {
44 explicit MPI_Particle_Distribute(Wonton::MPIExecutor_type
const *mpiexecutor) {
46 comm_ = mpiexecutor->mpicomm;
53 ~MPI_Particle_Distribute() =
default;;
61 std::vector<int> source_num;
65 std::vector<int> send_counts;
67 std::vector<int> recv_counts;
87 template<
class SourceSwarm,
class SourceState,
class TargetSwarm,
class TargetState>
88 void distribute(SourceSwarm& source_swarm, SourceState& source_state,
89 TargetSwarm& target_swarm, TargetState& target_state,
95 Meshfree::WeightCenter center = Meshfree::WeightCenter::Gather) {
98 MPI_Comm_size(comm_, &nb_ranks);
99 MPI_Comm_rank(comm_, &rank);
101 assert(dim == source_swarm.space_dimension());
102 assert(dim == target_swarm.space_dimension());
104 int nb_target_points = target_swarm.num_particles(Wonton::PARALLEL_OWNED);
105 int nb_source_points = source_swarm.num_particles(Wonton::PARALLEL_OWNED);
108 if (center == Meshfree::WeightCenter::Gather) {
109 assert(smoothing_lengths.size() == unsigned(nb_target_points));
110 assert(target_extents.size() == unsigned(nb_target_points));
111 assert(kernel_types.size() == unsigned(nb_target_points));
112 assert(geom_types.size() == unsigned(nb_target_points));
113 }
else if (center == Meshfree::WeightCenter::Scatter) {
114 assert(smoothing_lengths.size() == unsigned(nb_source_points));
115 assert(source_extents.size() == unsigned(nb_source_points));
116 assert(kernel_types.size() == unsigned(nb_source_points));
117 assert(geom_types.size() == unsigned(nb_source_points));
127 std::vector<double> targetBoundingBoxes(2 * dim * nb_ranks);
129 for (
int i = 0; i < 2 * dim; i += 2) {
130 targetBoundingBoxes[2 * dim * rank + i + 0] = std::numeric_limits<double>::max();
131 targetBoundingBoxes[2 * dim * rank + i + 1] = -std::numeric_limits<double>::max();
134 for (
int c = 0; c < nb_target_points; ++c) {
135 Point<dim> coord = target_swarm.get_particle_coordinates(c);
137 if (center == Meshfree::WeightCenter::Gather) {
138 ext = target_extents[c];
140 for (
int k = 0; k < dim; ++k) {
141 double val0 = 0., val1 = 0.;
142 if (center == Meshfree::WeightCenter::Gather) {
143 val0 = coord[k] - ext[k];
144 val1 = coord[k] + ext[k];
145 }
else if (center == Meshfree::WeightCenter::Scatter) {
149 if (val0 < targetBoundingBoxes[2 * dim * rank + 2 * k])
150 targetBoundingBoxes[2 * dim * rank + 2 * k] = val0;
152 if (val1 > targetBoundingBoxes[2 * dim * rank + 2 * k + 1])
153 targetBoundingBoxes[2 * dim * rank + 2 * k + 1] = val1;
161 for (
int i = 0; i < nb_ranks; i++)
162 MPI_Bcast(&(targetBoundingBoxes[0]) + 2 * dim * i, 2 * dim, MPI_DOUBLE, i, comm_);
165 std::cout <<
"Target boxes: ";
166 for (
int i=0; i<2*dim*nb_ranks; i++) std::cout << targetBoundingBoxes[i] <<
" ";
167 std::cout << std::endl;
175 std::vector<bool> sendFlags(nb_ranks,
false);
176 std::vector<std::vector<int>> sourcePtsToSend(nb_ranks);
177 std::vector<int> sourcePtsToSendSize(nb_ranks);
179 for (
int i = 0; i < nb_ranks; ++i) {
183 double min[dim], max[dim];
185 for (
int k = 0; k < dim; ++k) {
186 min[k] = targetBoundingBoxes[2 * dim * i + 2 * k];
187 max[k] = targetBoundingBoxes[2 * dim * i + 2 * k + 1];
190 for (
int c = 0; c < nb_source_points; ++c) {
191 Point<dim> coord = source_swarm.get_particle_coordinates(c);
193 if (center == Meshfree::WeightCenter::Scatter) {
194 ext = source_extents[c];
197 for (
int k = 0; k < dim; ++k) {
198 double val0 = 0., val1 = 0.;
200 if (center == Meshfree::WeightCenter::Gather) {
203 }
else if (center == Meshfree::WeightCenter::Scatter) {
204 val0 = coord[k] - ext[k];
205 val1 = coord[k] + ext[k];
211 thisPt = thisPt && (val0 <= max[k] && val1 >= min[k]);
214 if (thisPt) sourcePtsToSend[i].push_back(c);
218 sourcePtsToSendSize[i] = sourcePtsToSend[i].size();
219 sendFlags[i] = not sourcePtsToSend[i].empty();
226 comm_info_t src_info;
227 setInfo(&src_info, nb_ranks, sendFlags, sourcePtsToSendSize);
229 std::vector<std::vector<double>> sourceSendCoords(nb_ranks);
230 for (
int i = 0; i < nb_ranks; ++i) {
231 if ((!sendFlags[i]) || (i == rank))
234 for (
int j = 0; j < sourcePtsToSendSize[i]; ++j) {
235 Point<dim> coord = source_swarm.get_particle_coordinates(sourcePtsToSend[i][j]);
236 for (
int d = 0; d < dim; ++d)
237 sourceSendCoords[i].push_back(coord[d]);
243 std::vector<double> sourceRecvCoords(src_info.new_num * dim);
244 moveField<double>(&src_info, rank, nb_ranks, MPI_DOUBLE, dim, sourceSendCoords, &sourceRecvCoords);
247 std::vector<Point<dim>> RecvCoords;
248 for (
int i = 0; i < src_info.new_num; ++i) {
250 for (
int d = 0; d < dim; ++d)
251 coord[d] = sourceRecvCoords[dim * i + d];
252 RecvCoords.push_back(coord);
254 source_swarm.extend_particle_list(RecvCoords);
261 if (center == Meshfree::WeightCenter::Scatter) {
263 std::vector<std::vector<double>> h0 = smoothing_lengths[0];
264 int smlen_dim = h0[0].size();
265 std::vector<int> smoothing_length_sizes(nb_source_points);
267 for (
int i = 0; i < nb_source_points; i++) {
268 std::vector<std::vector<double>> h = smoothing_lengths[i];
269 smoothing_length_sizes[i] = h.size();
270 max_slsize = std::max<int>(smoothing_length_sizes[i], max_slsize);
271 for (
int j = 0; j < smoothing_length_sizes[i]; j++)
272 assert(h[j].size() == unsigned(smlen_dim));
277 std::vector<std::vector<int>> sourceSendSmoothSizes(nb_ranks);
278 for (
int i = 0; i < nb_ranks; ++i) {
279 if ((!sendFlags[i]) || (i == rank))
282 for (
int j = 0; j < sourcePtsToSendSize[i]; ++j) {
283 int smlensize = smoothing_length_sizes[sourcePtsToSend[i][j]];
284 sourceSendSmoothSizes[i].push_back(smlensize);
289 std::vector<int> sourceRecvSmoothSizes(src_info.new_num);
290 moveField<int>(&src_info, rank, nb_ranks, MPI_INT, 1,
291 sourceSendSmoothSizes, &sourceRecvSmoothSizes);
294 for (
int i = 0; i < src_info.new_num; ++i) {
295 int smlensize = sourceRecvSmoothSizes[i];
296 smoothing_length_sizes.push_back(smlensize);
300 std::vector<int> recvSLSizeCum(src_info.new_num, 0);
301 for (
int i = 1; i < src_info.new_num; ++i) recvSLSizeCum[i] += recvSLSizeCum[i - 1];
306 std::vector<std::vector<double>> sourceSendSmoothLengths(nb_ranks);
307 for (
int i = 0; i < nb_ranks; ++i) {
308 if ((!sendFlags[i]) || (i == rank))
311 for (
int j = 0; j < sourcePtsToSendSize[i]; ++j) {
312 std::vector<std::vector<double>> smlen(max_slsize, std::vector<double>(smlen_dim, 0.));
313 std::vector<std::vector<double>> h = smoothing_lengths[sourcePtsToSend[i][j]];
314 std::copy(h.begin(), h.end(), smlen.begin());
315 for (
int k = 0; k < max_slsize; ++k)
316 for (
int d = 0; d < smlen_dim; d++)
317 sourceSendSmoothLengths[i].push_back(smlen[k][d]);
322 std::vector<double> sourceRecvSmoothLengths(src_info.new_num * max_slsize * smlen_dim);
323 moveField<double>(&src_info, rank, nb_ranks, MPI_DOUBLE, max_slsize * smlen_dim,
324 sourceSendSmoothLengths, &sourceRecvSmoothLengths);
327 for (
int i = 0; i < src_info.new_num; ++i) {
328 std::vector<std::vector<double>> smlen
329 (smoothing_length_sizes[nb_source_points + i], std::vector<double>(smlen_dim));
330 for (
int k = 0; k < smoothing_length_sizes[nb_source_points + i]; k++)
331 for (
int d = 0; d < smlen_dim; ++d)
332 smlen[k][d] = sourceRecvSmoothLengths[recvSLSizeCum[i] + k * smlen_dim + d];
334 smoothing_lengths.push_back(smlen);
339 if (center == Meshfree::WeightCenter::Scatter) {
340 std::vector<std::vector<double>> sourceSendExtents(nb_ranks);
341 for (
int i = 0; i < nb_ranks; ++i) {
342 if ((!sendFlags[i]) || (i == rank))
345 for (
int j = 0; j < sourcePtsToSendSize[i]; ++j) {
346 Point<dim> ext = source_extents[sourcePtsToSend[i][j]];
347 for (
int d = 0; d < dim; ++d)
348 sourceSendExtents[i].push_back(ext[d]);
353 std::vector<double> sourceRecvExtents(src_info.new_num * dim);
354 moveField<double>(&src_info, rank, nb_ranks, MPI_DOUBLE, dim,
355 sourceSendExtents, &sourceRecvExtents);
358 for (
int i = 0; i < src_info.new_num; ++i) {
360 for (
int d = 0; d < dim; ++d)
361 ext[d] = sourceRecvExtents[dim * i + d];
363 source_extents.push_back(ext);
369 std::vector<std::vector<int>> sourceSendKernels(nb_ranks);
370 for (
int i = 0; i < nb_ranks; ++i) {
371 if ((!sendFlags[i]) || (i == rank))
374 for (
int j = 0; j < sourcePtsToSendSize[i]; ++j) {
375 sourceSendKernels[i].push_back(kernel_types[sourcePtsToSend[i][j]]);
380 std::vector<int> sourceRecvKernels(src_info.new_num);
381 moveField<int>(&src_info, rank, nb_ranks, MPI_INT, 1,
382 sourceSendKernels, &sourceRecvKernels);
385 for (
int i = 0; i < src_info.new_num; ++i) {
386 kernel_types.push_back(static_cast<Meshfree::Weight::Kernel>(sourceRecvKernels[i]));
391 std::vector<std::vector<int>> sourceSendGeoms(nb_ranks);
392 for (
int i = 0; i < nb_ranks; ++i) {
393 if ((!sendFlags[i]) || (i == rank))
396 for (
int j = 0; j < sourcePtsToSendSize[i]; ++j) {
397 sourceSendGeoms[i].push_back(geom_types[sourcePtsToSend[i][j]]);
402 std::vector<int> sourceRecvGeoms(src_info.new_num);
403 moveField<int>(&src_info, rank, nb_ranks, MPI_INT, 1,
404 sourceSendGeoms, &sourceRecvGeoms);
407 for (
int i = 0; i < src_info.new_num; ++i) {
408 geom_types.push_back(static_cast<Meshfree::Weight::Geometry>(sourceRecvGeoms[i]));
415 auto int_field_names = source_state.template get_field_names<int>();
416 int const num_int_fields = int_field_names.size();
417 for (
int nvars = 0; nvars < num_int_fields; ++nvars) {
419 auto& srcdata = source_state.get_field_int(int_field_names[nvars]);
422 std::vector<std::vector<int>> sourceSendData(nb_ranks);
423 for (
int i = 0; i < nb_ranks; ++i) {
424 if ((!sendFlags[i]) || (i == rank))
427 for (
int j = 0; j < sourcePtsToSendSize[i]; ++j) {
428 int sid = sourcePtsToSend[i][j];
429 sourceSendData[i].push_back(srcdata[sid]);
435 std::vector<int> sourceRecvData(src_info.new_num);
436 moveField<int>(&src_info, rank, nb_ranks, MPI_INT, 1, sourceSendData, &sourceRecvData);
440 vector<int> recvtmp(sourceRecvData);
441 source_state.extend_field(int_field_names[nvars], recvtmp);
449 auto dbl_field_names = source_state.template get_field_names<double>();
450 int const num_dbl_fields = dbl_field_names.size();
451 for (
int nvars = 0; nvars < num_dbl_fields; ++nvars) {
453 auto& srcdata = source_state.get_field(dbl_field_names[nvars]);
456 std::vector<std::vector<double>> sourceSendData(nb_ranks);
457 for (
int i = 0; i < nb_ranks; ++i) {
458 if ((!sendFlags[i]) || (i == rank))
461 for (
int j = 0; j < sourcePtsToSendSize[i]; ++j) {
462 int sid = sourcePtsToSend[i][j];
463 sourceSendData[i].push_back(srcdata[sid]);
469 std::vector<double> sourceRecvData(src_info.new_num);
470 moveField<double>(&src_info, rank, nb_ranks, MPI_DOUBLE, 1, sourceSendData, &sourceRecvData);
474 vector<double> recvtmp(sourceRecvData);
475 source_state.extend_field(dbl_field_names[nvars], recvtmp);
484 MPI_Comm comm_ = MPI_COMM_NULL;
493 void setInfo(comm_info_t *info,
495 const std::vector<bool>& sendFlags,
496 const std::vector<int>& sourceNum) {
498 info->source_num.resize(nb_ranks);
501 info->send_counts.resize(nb_ranks);
502 info->recv_counts.resize(nb_ranks);
504 for (
int i = 0; i < nb_ranks; i++) {
505 info->source_num[i] = sourceNum[i];
506 info->send_counts[i] = sendFlags[i] ? info->source_num[i] : 0;
509 MPI_Alltoall(&(info->send_counts[0]), 1, MPI_INT,
510 &(info->recv_counts[0]), 1, MPI_INT, comm_);
513 for (
int i = 0; i < nb_ranks; i++)
514 info->new_num += info->recv_counts[i];
529 void moveField(comm_info_t *info,
530 int rank,
int nb_ranks,
531 const MPI_Datatype datatype,
const int nvals,
533 std::vector<T> *newData) {
537 std::vector<MPI_Request> requests;
539 for (
int i = 0; i < nb_ranks; i++) {
540 if ((i != rank) && (info->recv_counts[i] > 0)) {
542 MPI_Irecv((
void *) &((*newData)[writeOffset]),
543 info->recv_counts[i] * nvals, datatype, i,
544 MPI_ANY_TAG, comm_, &request);
545 requests.push_back(request);
547 writeOffset += info->recv_counts[i] * nvals;
549 assert(writeOffset == info->new_num * nvals);
552 for (
int i = 0; i < nb_ranks; i++) {
553 if ((i != rank) && (info->send_counts[i] > 0)) {
554 MPI_Send((
void *) &(sourceData[i][0]),
555 info->send_counts[i] * nvals, datatype, i, 0, comm_);
560 if (not requests.empty()) {
561 std::vector<MPI_Status> statuses(requests.size());
562 MPI_Waitall(requests.size(), &(requests[0]), &(statuses[0]));
571 #endif // PORTAGE_ENABLE_MPI 573 #endif // MPI_Particle_Distribute std::vector< T > vector
Definition: portage.h:238
Definition: coredriver.h:42