source: ThirdParty/vmg/src/units/particle/comm_mpi_particle.cpp

Candidate_v1.6.1
Last change on this file was 7faa5c, checked in by Frederik Heber <heber@…>, 8 years ago

Merge commit 'de061d9d851257a04e924d4472df4523d33bb08b' as 'ThirdParty/vmg'

  • Property mode set to 100644
File size: 10.8 KB
Line 
1/*
2 * vmg - a versatile multigrid solver
3 * Copyright (C) 2012 Institute for Numerical Simulation, University of Bonn
4 *
5 * vmg is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * vmg is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19/**
20 * @file comm_mpi_particle.cpp
21 * @author Julian Iseringhausen <isering@ins.uni-bonn.de>
22 * @date Tue May 8 15:27:06 2012
23 *
24 * @brief Class for MPI-based particle-related communication.
25 *
26 */
27
28#ifdef HAVE_CONFIG_H
29#include <libvmg_config.h>
30#endif
31
32#ifdef HAVE_MPI
33
34#include <mpi.h>
35#ifdef HAVE_MARMOT
36#include <enhancempicalls.h>
37#include <sourceinfompicalls.h>
38#endif
39
40#include "units/particle/comm_mpi_particle.hpp"
41#include "units/particle/linked_cell_list.hpp"
42#include "units/particle/particle.hpp"
43
44using namespace VMG;
45
46void Particle::CommMPI::CommParticles(const Grid& grid, std::list<Particle>& particles)
47{
48 Factory& factory = MG::GetFactory();
49
50 const vmg_int& num_particles_local = factory.GetObjectStorageVal<vmg_int>("PARTICLE_NUM_LOCAL");
51 vmg_float* x = factory.GetObjectStorageArray<vmg_float>("PARTICLE_POS_ARRAY");
52 vmg_float* q = factory.GetObjectStorageArray<vmg_float>("PARTICLE_CHARGE_ARRAY");
53
54 int rank, size;
55 MPI_Comm_rank(comm_global, &rank);
56 MPI_Comm_size(comm_global, &size);
57
58#ifndef VMG_ONE_SIDED
59 vmg_int* receiver;
60 if (!factory.TestObject("PARTICLE_RECEIVER_ARRAY"))
61 new ObjectStorageArray<vmg_int>("PARTICLE_RECEIVER_ARRAY", size);
62 receiver = factory.GetObjectStorageArray<vmg_int>("PARTICLE_RECEIVER_ARRAY");
63#endif
64
65 Index index;
66 std::vector<int> global_extent(6*size);
67 std::vector<int> send_sizes(size);
68 std::vector<int> recv_sizes(size);
69 std::vector<Index> begin_remote(size);
70 std::vector<Index> end_remote(size);
71 std::vector< std::vector<vmg_float> > send_buffer_x(size);
72 std::vector< std::vector<vmg_float> > send_buffer_q(size);
73 std::vector< std::vector<vmg_int> > send_buffer_ind(size);
74 std::vector< std::vector<vmg_float> > recv_buffer_x(size);
75 std::vector< std::vector<vmg_float> > recv_buffer_q(size);
76 std::vector< std::vector<vmg_int> > recv_buffer_ind(size);
77
78 std::memcpy(&global_extent[6*rank], grid.Global().LocalBegin().vec(), 3*sizeof(int));
79 std::memcpy(&global_extent[6*rank+3], grid.Global().LocalEnd().vec(), 3*sizeof(int));
80
81 MPI_Allgather(MPI_IN_PLACE, 6, MPI_INT, &global_extent.front(), 6, MPI_INT, comm_global);
82
83 for (int i=0; i<size; ++i) {
84 begin_remote[i] = static_cast<Index>(&global_extent[6*i]);
85 end_remote[i] = static_cast<Index>(&global_extent[6*i+3]);
86 }
87
88 for (int i=0; i<num_particles_local; ++i) {
89 index = grid.Global().GlobalBegin() + static_cast<Index>(((Vector(&x[3*i]) - grid.Extent().Begin()) / grid.Extent().MeshWidth()).Floor());
90 for (int j=0; j<size; ++j)
91 if (index.IsInBounds(begin_remote[j], end_remote[j])) {
92 send_buffer_x[j].push_back(x[3*i+0]);
93 send_buffer_x[j].push_back(x[3*i+1]);
94 send_buffer_x[j].push_back(x[3*i+2]);
95 send_buffer_q[j].push_back(q[i]);
96 send_buffer_ind[j].push_back(i);
97 break;
98 }
99 }
100
101 /*
102 * Communicate which process gets how many particles
103 */
104 for (int i=0; i<size; ++i)
105 send_sizes[i] = send_buffer_q[i].size();
106
107 MPI_Alltoall(&send_sizes.front(), 1, MPI_INT, &recv_sizes.front(), 1, MPI_INT, comm_global);
108
109 assert(RequestsPending() == 0);
110
111 /*
112 * Send particles
113 */
114 for (int i=0; i<size; ++i) {
115
116 if (!send_buffer_q[i].empty()) {
117 MPI_Isend(&send_buffer_x[i].front(), send_buffer_x[i].size(), MPI_DOUBLE, i, 0, comm_global, &Request());
118 MPI_Isend(&send_buffer_q[i].front(), send_buffer_q[i].size(), MPI_DOUBLE, i, 1, comm_global, &Request());
119 MPI_Isend(&send_buffer_ind[i].front(), send_buffer_ind[i].size(), MPI_INT, i, 2, comm_global, &Request());
120 }
121
122#ifndef VMG_ONE_SIDED
123 receiver[i] = send_buffer_q[i].size();
124#endif
125 }
126
127 /*
128 * Receive particles
129 */
130 for (int i=0; i<size; ++i) {
131
132 if (recv_sizes[i] > 0) {
133
134 recv_buffer_x[i].resize(3*recv_sizes[i]);
135 recv_buffer_q[i].resize(recv_sizes[i]);
136 recv_buffer_ind[i].resize(recv_sizes[i]);
137
138 MPI_Irecv(&recv_buffer_x[i].front(), 3*recv_sizes[i], MPI_DOUBLE, i, 0, comm_global, &Request());
139 MPI_Irecv(&recv_buffer_q[i].front(), recv_sizes[i], MPI_DOUBLE, i, 1, comm_global, &Request());
140 MPI_Irecv(&recv_buffer_ind[i].front(), recv_sizes[i], MPI_INT, i, 2, comm_global, &Request());
141
142 }
143
144 }
145
146 WaitAll();
147
148 particles.clear();
149
150 for (int i=0; i<size; ++i)
151 for (int j=0; j<recv_sizes[i]; ++j)
152 particles.push_back(Particle(&recv_buffer_x[i][3*j], recv_buffer_q[i][j], 0.0, 0.0, i, recv_buffer_ind[i][j]));
153}
154
155void Particle::CommMPI::CommParticlesBack(std::list<Particle>& particles)
156{
157 std::list<Particle>::iterator iter;
158
159#ifdef VMG_ONE_SIDED
160 if (!win_created) {
161 vmg_float* p = MG::GetFactory().GetObjectStorageArray<vmg_float>("PARTICLE_POTENTIAL_ARRAY");
162 const vmg_int& num_particles_local = MG::GetFactory().GetObjectStorageVal<vmg_int>("PARTICLE_NUM_LOCAL");
163 MPI_Win_create(p, num_particles_local*sizeof(vmg_float), sizeof(vmg_float), info, comm_global, &win);
164 win_created = true;
165 }
166
167 MPI_Win_fence(MPI_MODE_NOPRECEDE, win);
168
169 for (iter=particles.begin(); iter!=particles.end(); ++iter)
170 MPI_Put(&iter->Pot(), 1, MPI_DOUBLE, iter->Rank(), iter->Index(), 1, MPI_DOUBLE, win);
171
172 MPI_Win_fence(MPI_MODE_NOSTORE | MPI_MODE_NOSUCCEED, win);
173#else
174 int rank, size;
175 MPI_Comm_rank(comm_global, &rank);
176 MPI_Comm_size(comm_global, &size);
177
178 std::vector< std::vector<vmg_float> > send_buffer_float(size);
179 std::vector< std::vector<vmg_float> > recv_buffer_float(size);
180 std::vector< std::vector<vmg_int> > send_buffer_index(size);
181 std::vector< std::vector<vmg_int> > recv_buffer_index(size);
182
183 vmg_int* size_receive = MG::GetFactory().GetObjectStorageArray<vmg_int>("PARTICLE_RECEIVER_ARRAY");
184 vmg_float* p = MG::GetFactory().GetObjectStorageArray<vmg_float>("PARTICLE_POTENTIAL_ARRAY");
185 vmg_float* f = MG::GetFactory().GetObjectStorageArray<vmg_float>("PARTICLE_FIELD_ARRAY");
186
187 // Build send buffer
188 for (iter=particles.begin(); iter!=particles.end(); ++iter) {
189 send_buffer_float[iter->Rank()].push_back(iter->Pot());
190 send_buffer_float[iter->Rank()].push_back(iter->Field()[0]);
191 send_buffer_float[iter->Rank()].push_back(iter->Field()[1]);
192 send_buffer_float[iter->Rank()].push_back(iter->Field()[2]);
193 send_buffer_index[iter->Rank()].push_back(iter->Index());
194 }
195
196 // Send potentials
197 for (int i=0; i<size; ++i) {
198 if (!send_buffer_float[i].empty()) {
199 MPI_Isend(&send_buffer_float[i].front(), send_buffer_float[i].size(), MPI_DOUBLE, i, 699+rank, comm_global, &Request());
200 MPI_Isend(&send_buffer_index[i].front(), send_buffer_index[i].size(), MPI_INT, i, 32111+rank, comm_global, &Request());
201 }
202 }
203
204 //Receive potentials
205 for (int i=0; i<size; ++i) {
206 if (size_receive[i] > 0) {
207 recv_buffer_float[i].resize(4*size_receive[i]);
208 recv_buffer_index[i].resize(size_receive[i]);
209 MPI_Irecv(&recv_buffer_float[i].front(), 4*size_receive[i], MPI_DOUBLE, i, 699+i, comm_global, &Request());
210 MPI_Irecv(&recv_buffer_index[i].front(), size_receive[i], MPI_INT, i, 32111+i, comm_global, &Request());
211 }
212 }
213
214 WaitAll();
215
216 // Add potential values
217 for (int i=0; i<size; ++i)
218 for (vmg_int j=0; j<size_receive[i]; ++j) {
219 p[recv_buffer_index[i][j]] = recv_buffer_float[i][4*j];
220 std::memcpy(&f[3*recv_buffer_index[i][j]], &recv_buffer_float[i][4*j+1], 3*sizeof(vmg_float));
221 }
222#endif
223
224}
225
226void Particle::CommMPI::CommLCListToGhosts(LinkedCellList& lc)
227{
228 VMG::MPI::DatatypesLocal types(lc, comm_global, false);
229 std::vector<int> send_size(types.NB().size());
230 vmg_int recv_size;
231 std::list<Particle*>::iterator iter;
232 Index ind;
233 Vector offset;
234
235 const Vector halo_length = lc.Local().HaloSize1() * lc.Extent().MeshWidth();
236
237 lc.ClearHalo();
238
239 for (unsigned int i=0; i<types.NB().size(); ++i)
240 if (types.NB()[i].Feasible()) {
241
242 for (int j=0; j<3; ++j)
243 if ((types.Offset()[i][j] < 0 && lc.Global().LocalBegin()[j] == lc.Global().GlobalBegin()[j]) ||
244 (types.Offset()[i][j] > 0 && lc.Global().LocalEnd()[j] == lc.Global().GlobalEnd()[j]))
245 offset[j] = -1.0 * types.Offset()[i][j] * lc.Extent().Size()[j];
246 else
247 offset[j] = 0.0;
248
249 for (ind.X() = types.NB()[i].Starts().X(); ind.X() < types.NB()[i].Starts().X()+types.NB()[i].Subsizes().X(); ++ind.X())
250 for (ind.Y() = types.NB()[i].Starts().Y(); ind.Y() < types.NB()[i].Starts().Y()+types.NB()[i].Subsizes().Y(); ++ind.Y())
251 for (ind.Z() = types.NB()[i].Starts().Z(); ind.Z() < types.NB()[i].Starts().Z()+types.NB()[i].Subsizes().Z(); ++ind.Z())
252 for (iter=lc(ind).begin(); iter!=lc(ind).end(); ++iter) {
253
254 for (int j=0; j<3; ++j)
255 types.NB()[i].Buffer().push_back((*iter)->Pos()[j] + offset[j]);
256 types.NB()[i].Buffer().push_back((*iter)->Charge());
257
258 assert(lc.Extent().Begin().IsComponentwiseLessOrEqual((*iter)->Pos()));
259 assert(lc.Extent().End().IsComponentwiseGreaterOrEqual((*iter)->Pos()));
260 assert(lc.Extent().Begin().IsComponentwiseLessOrEqual((*iter)->Pos() + offset + halo_length));
261 assert(lc.Extent().End().IsComponentwiseGreaterOrEqual((*iter)->Pos() + offset - halo_length));
262 }
263
264 send_size[i] = types.NB()[i].Buffer().size();
265 MPI_Isend(&send_size[i], 1, MPI_INT, types.NB()[i].Rank(), 2048+types.NB()[i].TagSend(), comm_global, &Request());
266
267 if (send_size[i] > 0)
268 MPI_Isend(&types.NB()[i].Buffer().front(), send_size[i], MPI_DOUBLE,
269 types.NB()[i].Rank(), 4096+types.NB()[i].TagSend(),
270 comm_global, &Request());
271 }
272
273 for (unsigned int i=0; i<types.Halo().size(); ++i)
274 if (types.Halo()[i].Feasible()) {
275 MPI_Recv(&recv_size, 1, MPI_INT, types.Halo()[i].Rank(), 2048+types.Halo()[i].TagReceive(), comm_global, MPI_STATUS_IGNORE);
276 if (recv_size > 0) {
277 types.Halo()[i].Buffer().resize(recv_size);
278 MPI_Irecv(&types.Halo()[i].Buffer().front(), recv_size, MPI_DOUBLE,
279 types.Halo()[i].Rank(), 4096+types.Halo()[i].TagReceive(),
280 comm_global, &Request());
281 }
282 }
283
284 WaitAll();
285
286 for (unsigned int i=0; i<types.Halo().size(); ++i)
287 for (unsigned int j=0; j<types.Halo()[i].Buffer().size(); j+=4)
288 lc.AddParticleToHalo(&types.Halo()[i].Buffer()[j], types.Halo()[i].Buffer()[j+3]);
289}
290
291#endif /* HAVE_MPI */
Note: See TracBrowser for help on using the repository browser.