119 {
123 const auto &grains =
data.d_particlesListTypeParticle;
124 const size_t n_grains = grains.size();
125
126 std::vector<double> local_c(4 * n_grains, 0.);
127 for (size_t g = 0; g < n_grains; ++g) {
128 const auto c = grains[g]->getXCenter();
129 local_c[4 * g + 0] = c.d_x;
130 local_c[4 * g + 1] = c.d_y;
131 local_c[4 * g + 2] = c.d_z;
132 local_c[4 * g + 3] = grains[g]->d_geom_p->boundingRadius();
133 }
134 std::vector<double> all_c(4 * n_grains * static_cast<size_t>(size), 0.);
135 MPI_Allgather(local_c.data(), static_cast<int>(local_c.size()), MPI_DOUBLE,
136 all_c.data(), static_cast<int>(local_c.size()), MPI_DOUBLE,
137 comm);
138
139 std::vector<util::Point> centers(n_grains);
140 std::vector<double> radii(n_grains);
141 for (size_t g = 0; g < n_grains; ++g) {
142 const int own = grains[g]->d_mpiOwner;
143 const size_t base = static_cast<size_t>(own) * 4 * n_grains + 4 * g;
144 centers[g] =
util::Point(all_c[base + 0], all_c[base + 1], all_c[base + 2]);
145 radii[g] = all_c[base + 3];
146 }
147
148 data.d_mpiIncludeInContactCloud.assign(
data.d_particlesListTypeAll.size(), 0);
149 for (
auto *p :
data.d_particlesListTypeAll) {
151 data.d_mpiIncludeInContactCloud[p->getId()] = 1;
152 }
153
154
155
156 const double extra =
157 std::max(0.25 *
data.d_maxContactR, std::max(
data.d_hMax, 1.0e-16));
158 const double search_r =
159 (
data.d_contNeighSearchRadius > 1.0e-16)
160 ?
data.d_contNeighSearchRadius
161 :
data.d_maxContactR;
162 const double cutoff = search_r + extra;
163
164 data.d_mpiGhostNeedFrom.assign(
static_cast<size_t>(size), {});
165 size_t n_ghost = 0;
166 auto add_ghost = [&](size_t g) {
167 auto *pj = grains[g];
169 return;
170 const int own = pj->d_mpiOwner;
171 if (own < 0 || own == rank)
172 return;
173 auto &vec =
data.d_mpiGhostNeedFrom[
static_cast<size_t>(own)];
174 const int gid = static_cast<int>(g);
175 if (std::find(vec.begin(), vec.end(), gid) != vec.end())
176 return;
177 vec.push_back(gid);
178 data.d_mpiIncludeInContactCloud[pj->getId()] = 1;
179 ++n_ghost;
180 };
181
182 for (size_t g = 0; g < n_grains; ++g) {
184 for (
size_t i = 0; i < n_grains && !
near; ++i) {
186 continue;
187 const double lim = radii[i] + radii[g] + cutoff;
188 if (centers[i].dist(centers[g]) < lim)
189 near = true;
190 }
191 if (near)
192 add_ghost(g);
193 }
194
195
196
197 for (
auto *w :
data.d_particlesListTypeWall) {
198 if (!w)
199 continue;
200 const auto wc = w->getXCenter();
201 const double wr = w->d_geom_p->boundingRadius();
202 for (size_t g = 0; g < n_grains; ++g) {
203 const double lim = wr + radii[g] + cutoff;
204 if (wc.dist(centers[g]) < lim)
205 add_ghost(g);
206 }
207 }
208
209 std::vector<int> req_sendcounts(static_cast<size_t>(size), 0);
210 std::vector<int> req_recvcounts(static_cast<size_t>(size), 0);
211 for (int r = 0; r < size; ++r)
212 req_sendcounts[static_cast<size_t>(r)] =
213 static_cast<int>(
data.d_mpiGhostNeedFrom[
static_cast<size_t>(r)].size());
214 MPI_Alltoall(req_sendcounts.data(), 1, MPI_INT, req_recvcounts.data(), 1,
215 MPI_INT, comm);
216
217 std::vector<int> req_sdispls(static_cast<size_t>(size), 0);
218 std::vector<int> req_rdispls(static_cast<size_t>(size), 0);
219 int req_send_total = 0;
220 int req_recv_total = 0;
221 for (int r = 0; r < size; ++r) {
222 req_sdispls[static_cast<size_t>(r)] = req_send_total;
223 req_rdispls[static_cast<size_t>(r)] = req_recv_total;
224 req_send_total += req_sendcounts[static_cast<size_t>(r)];
225 req_recv_total += req_recvcounts[static_cast<size_t>(r)];
226 }
227
228 std::vector<int> req_sendbuf(static_cast<size_t>(req_send_total));
229 for (int r = 0; r < size; ++r) {
230 const auto &v =
data.d_mpiGhostNeedFrom[
static_cast<size_t>(r)];
231 std::copy(v.begin(), v.end(),
232 req_sendbuf.begin() + req_sdispls[static_cast<size_t>(r)]);
233 }
234 std::vector<int> req_recvbuf(static_cast<size_t>(req_recv_total));
235 MPI_Alltoallv(req_sendbuf.data(), req_sendcounts.data(), req_sdispls.data(),
236 MPI_INT, req_recvbuf.data(), req_recvcounts.data(),
237 req_rdispls.data(), MPI_INT, comm);
238
239 data.d_mpiGhostServeTo.assign(
static_cast<size_t>(size), {});
240 for (int r = 0; r < size; ++r) {
241 const int off = req_rdispls[static_cast<size_t>(r)];
242 const int nreq = req_recvcounts[static_cast<size_t>(r)];
243 auto &dst =
data.d_mpiGhostServeTo[
static_cast<size_t>(r)];
244 dst.resize(static_cast<size_t>(nreq));
245 for (int k = 0; k < nreq; ++k) {
246 const int g = req_recvbuf[static_cast<size_t>(off + k)];
247 if (g < 0 || static_cast<size_t>(g) >= n_grains)
248 throw std::runtime_error("rebuildGhostPlan: bad grain id");
249 if (grains[static_cast<size_t>(g)]->d_mpiOwner != rank)
250 throw std::runtime_error(
251 "rebuildGhostPlan: requested grain not owned here");
252 dst[static_cast<size_t>(k)] = g;
253 }
254 }
255
256 data.d_mpiGhostPlanValid =
true;
257 data.d_mpiGhostStepsSinceRebuild = 0;
258 data.setKeyData(
"mpi_ghost_grain_count",
static_cast<double>(n_ghost));
259}
bool near(double a, double b, double tol=1.e-12)
bool isLocallyOwned(const BaseParticle &p)
True if this rank updates / assembles forces for the particle. Walls are replicated on every rank....
int mpiRank()
get rank (id) of this processor
A structure to represent 3d vectors.