Canoe
Comprehensive Atmosphere N' Ocean Engine
decomposition.cpp
Go to the documentation of this file.
1 // C/C++
2 #include <functional>
3 #include <iostream>
4 #include <sstream>
5 #include <string>
6 
7 // athena
8 #include <athena/bvals/bvals.hpp>
9 #include <athena/globals.hpp>
10 #include <athena/mesh/mesh.hpp>
11 #include <athena/stride_iterator.hpp>
12 
13 // application
14 #include <application/application.hpp>
15 #include <application/globals.hpp>
16 
17 // canoe
18 #include <constants.hpp>
19 #include <impl.hpp>
20 
21 // snap
22 #include "../thermodynamics/thermodynamics.hpp"
23 #include "decomposition.hpp"
24 
26  : pmy_block_(pmb), has_top_neighbor(false), has_bot_neighbor(false) {
27  Application::Logger app("snap");
28  app->Log("Initialize Decomposition");
29  int nc1 = pmb->ncells1, nc2 = pmb->ncells2, nc3 = pmb->ncells3;
30  // allocate hydrostatic and nonhydrostatic pressure
31  psf_.NewAthenaArray(nc3, nc2, nc1 + 1);
32  psv_.NewAthenaArray(nc3, nc2, nc1);
33  pres_.NewAthenaArray(nc3, nc2, nc1);
34  dens_.NewAthenaArray(nc3, nc2, nc1);
35 
36  buffer_ = new Real[3 * (NGHOST + 1) * nc3 * nc2];
37  send_buffer_ = new Real[2 * (NGHOST + 1) * nc3 * nc2];
38  wsend_top_ = new Real[2 * NGHOST * nc3 * nc2];
39  wrecv_top_ = new Real[2 * NGHOST * nc3 * nc2];
40  wsend_bot_ = new Real[2 * NGHOST * nc3 * nc2];
41  wrecv_bot_ = new Real[2 * NGHOST * nc3 * nc2];
42  brank_ = new int[Globals::nranks];
43  color_ = new int[Globals::nranks];
44 
45  // allocate polytropic index and pseudo entropy
46  entropy_.NewAthenaArray(2, nc3, nc2);
47  gamma_.NewAthenaArray(nc3, nc2, nc1);
48 }
49 
51  Application::Logger app("snap");
52  app->Log("Destroy Decomposition");
53 
54  delete[] buffer_;
55  delete[] send_buffer_;
56  delete[] wsend_top_;
57  delete[] wrecv_top_;
58  delete[] wsend_bot_;
59  delete[] wrecv_bot_;
60  delete[] brank_;
61  delete[] color_;
62 }
63 
64 int Decomposition::CreateMPITag(int recvid, int sendid, int phys) {
65  std::string str = std::to_string(recvid);
66  str += "x";
67  str += std::to_string(sendid);
68  str += "x";
69  str += std::to_string(phys);
70  return std::hash<std::string>{}(str) % Globals::mpi_tag_ub;
71  // return (recvid<<11) | (sendid<<5) | phys;
72 }
73 
75  MeshBlock *pmb = pmy_block_;
76  has_top_neighbor = false;
77  has_bot_neighbor = false;
78  for (int n = 0; n < pmb->pbval->nneighbor; ++n) {
79  NeighborBlock &nb = pmb->pbval->neighbor[n];
80  if ((nb.ni.ox1 == -1) && (nb.ni.ox2 == 0) && (nb.ni.ox3 == 0)) {
81  bblock = nb;
82  has_bot_neighbor = true;
83  }
84  if ((nb.ni.ox1 == 1) && (nb.ni.ox2 == 0) && (nb.ni.ox3 == 0)) {
85  tblock = nb;
86  has_top_neighbor = true;
87  }
88  }
89 
90  if (!has_bot_neighbor) {
91  bblock.snb.gid = -1;
92  bblock.snb.rank = -1;
93  }
94  if (!has_top_neighbor) {
95  tblock.snb.gid = -1;
96  tblock.snb.rank = -1;
97  }
98 
99 #ifdef MPI_PARALLEL
100  MPI_Allgather(&bblock.snb.rank, 1, MPI_INT, brank_, 1, MPI_INT,
101  MPI_COMM_WORLD);
102 #else
103  brank_[0] = -1;
104 #endif
105 }
106 
107 // FIXME: local boundary has not been implemented
108 // Ordering the meshblocks need to be worked out such that
109 // the upper boundary executes before the lower boundary
110 void Decomposition::RecvFromTop(AthenaArray<Real> &psf, int kl, int ku, int jl,
111  int ju) {
112  MeshBlock *pmb = pmy_block_;
113  int ssize = (ju - jl + 1) * (ku - kl + 1) * (NGHOST + 1);
114 
115  std::stringstream msg;
116 #ifdef MPI_PARALLEL
117  MPI_Status status;
118 #endif
119 
120  if (tblock.snb.rank != Globals::my_rank) { // MPI boundary
121 #ifdef MPI_PARALLEL
122  int tag = CreateMPITag(pmb->gid, tblock.snb.gid, 22);
123  MPI_Recv(buffer_, ssize, MPI_ATHENA_REAL, tblock.snb.rank, tag,
124  MPI_COMM_WORLD, &status);
125 #endif
126  } else { // local boundary
127  // need to wait for the top boundary to finish
128  msg << "### FATAL ERROR in Decompositin::RecvFromTop" << std::endl
129  << "Local boundary not yet implemented" << std::endl;
130  ATHENA_ERROR(msg);
131  }
132  int p = 0;
133  for (int k = kl; k <= ku; ++k)
134  for (int j = jl; j <= ju; ++j)
135  for (int i = 0; i <= NGHOST; ++i)
136  psf(k, j, pmb->ie + i + 1) = buffer_[p++];
137 }
138 
139 void Decomposition::SendToBottom(AthenaArray<Real> const &psf, int kl, int ku,
140  int jl, int ju) {
141  MeshBlock *pmb = pmy_block_;
142  int ssize = 0;
143  for (int k = kl; k <= ku; ++k)
144  for (int j = jl; j <= ju; ++j)
145  for (int i = 0; i <= NGHOST; ++i)
146  buffer_[ssize++] = psf(k, j, pmb->is + i);
147 
148  if (bblock.snb.rank != Globals::my_rank) { // MPI boundary
149 #ifdef MPI_PARALLEL
150  int tag = CreateMPITag(bblock.snb.gid, pmb->gid, 22);
151  MPI_Isend(buffer_, ssize, MPI_ATHENA_REAL, bblock.snb.rank, tag,
152  MPI_COMM_WORLD, &req_send_bot_);
153 #endif
154  } else { // local boundary
155  MeshBlock *pbl = pmy_block_->pmy_mesh->FindMeshBlock(bblock.snb.gid);
156  std::memcpy(pbl->pimpl->pdec->buffer_, buffer_, ssize * sizeof(Real));
157  }
158 }
159 
161  int jl, int ju) {
162  MeshBlock *pmb = pmy_block_;
163 
164  if (has_bot_neighbor) {
165  int sbot = 0;
166  for (int k = kl; k <= ku; ++k)
167  for (int j = jl; j <= ju; ++j)
168  for (int i = 0; i < NGHOST; ++i) {
169  wsend_bot_[sbot++] = w(IDN, k, j, pmb->is + i);
170  wsend_bot_[sbot++] = w(IPR, k, j, pmb->is + i);
171  }
172  if (bblock.snb.rank != Globals::my_rank) { // MPI boundary
173 #ifdef MPI_PARALLEL
174  int tag = CreateMPITag(bblock.snb.gid, pmb->gid, 17);
175  MPI_Isend(wsend_bot_, sbot, MPI_ATHENA_REAL, bblock.snb.rank, tag,
176  MPI_COMM_WORLD, &req_send_sync_bot_);
177  tag = CreateMPITag(pmb->gid, bblock.snb.gid, 19);
178  MPI_Irecv(wrecv_bot_, sbot, MPI_ATHENA_REAL, bblock.snb.rank, tag,
179  MPI_COMM_WORLD, &req_recv_sync_bot_);
180 #endif
181  } else { // local boundary
182  MeshBlock *pbl = pmy_block_->pmy_mesh->FindMeshBlock(bblock.snb.gid);
183  std::memcpy(pbl->pimpl->pdec->wrecv_top_, wsend_bot_,
184  sbot * sizeof(Real));
185  std::memcpy(wrecv_bot_, pbl->pimpl->pdec->wsend_top_,
186  sbot * sizeof(Real));
187  }
188  }
189 
190  if (has_top_neighbor) {
191  int stop = 0;
192  for (int k = kl; k <= ku; ++k)
193  for (int j = jl; j <= ju; ++j)
194  for (int i = 0; i < NGHOST; ++i) {
195  wsend_top_[stop++] = w(IDN, k, j, pmb->ie - i);
196  wsend_top_[stop++] = w(IPR, k, j, pmb->ie - i);
197  }
198  if (tblock.snb.rank != Globals::my_rank) { // MPI boundary
199 #ifdef MPI_PARALLEL
200  int tag = CreateMPITag(tblock.snb.gid, pmb->gid, 19);
201  MPI_Isend(wsend_top_, stop, MPI_ATHENA_REAL, tblock.snb.rank, tag,
202  MPI_COMM_WORLD, &req_send_sync_top_);
203  tag = CreateMPITag(pmb->gid, tblock.snb.gid, 17);
204  MPI_Irecv(wrecv_top_, stop, MPI_ATHENA_REAL, tblock.snb.rank, tag,
205  MPI_COMM_WORLD, &req_recv_sync_top_);
206 #endif
207  } else { // local boundary
208  MeshBlock *pbl = pmy_block_->pmy_mesh->FindMeshBlock(bblock.snb.gid);
209  std::memcpy(pbl->pimpl->pdec->wrecv_bot_, wsend_top_,
210  stop * sizeof(Real));
211  std::memcpy(wrecv_top_, pbl->pimpl->pdec->wsend_bot_,
212  stop * sizeof(Real));
213  }
214  }
215 }
216 
218 #ifdef MPI_PARALLEL
219  MPI_Status status;
220  if (has_bot_neighbor && (bblock.snb.rank != Globals::my_rank))
221  MPI_Wait(&req_send_bot_, &status);
222 
223  if (has_top_neighbor && (tblock.snb.rank != Globals::my_rank))
224  MPI_Wait(&req_send_top_, &status);
225 #endif
226 }
227 
229  int jl, int ju) {
230  MeshBlock *pmb = pmy_block_;
231 #ifdef MPI_PARALLEL
232  MPI_Status status;
233  if (has_bot_neighbor && (bblock.snb.rank != Globals::my_rank)) {
234  MPI_Wait(&req_send_sync_bot_, &status);
235  MPI_Wait(&req_recv_sync_bot_, &status);
236  }
237 #endif
238 
239  if (has_bot_neighbor) {
240  int p = 0;
241  for (int k = kl; k <= ku; ++k)
242  for (int j = jl; j <= ju; ++j)
243  for (int i = 1; i <= NGHOST; ++i) {
244  w(IDN, k, j, pmb->is - i) = wrecv_bot_[p++];
245  w(IPR, k, j, pmb->is - i) = wrecv_bot_[p++];
246  }
247  }
248 
249 #ifdef MPI_PARALLEL
250  if (has_top_neighbor && (tblock.snb.rank != Globals::my_rank)) {
251  MPI_Wait(&req_send_sync_top_, &status);
252  MPI_Wait(&req_recv_sync_top_, &status);
253  }
254 #endif
255 
256  if (has_top_neighbor) {
257  int p = 0;
258  for (int k = kl; k <= ku; ++k)
259  for (int j = jl; j <= ju; ++j)
260  for (int i = 1; i <= NGHOST; ++i) {
261  w(IDN, k, j, pmb->ie + i) = wrecv_top_[p++];
262  w(IPR, k, j, pmb->ie + i) = wrecv_top_[p++];
263  }
264  }
265 }
266 
267 // FIXME: local boundary has not been implemented
268 // Ordering the meshblocks need to be worked out such that
269 // the upper boundary executes before the lower boundary
270 void Decomposition::RecvBuffer(AthenaArray<Real> &psf, int kl, int ku, int jl,
271  int ju, int il, int iu, NeighborBlock nb) {
272  MeshBlock *pmb = pmy_block_;
273  int ssize = (iu - il + 1) * (ju - jl + 1) * (ku - kl + 1);
274 
275  std::stringstream msg;
276 #ifdef MPI_PARALLEL
277  MPI_Status status;
278 #endif
279 
280  if (nb.snb.rank != Globals::my_rank) { // MPI boundary
281 #ifdef MPI_PARALLEL
282  int tag = CreateMPITag(pmb->gid, nb.snb.gid, 22);
283  MPI_Recv(buffer_, ssize, MPI_ATHENA_REAL, nb.snb.rank, tag, MPI_COMM_WORLD,
284  &status);
285 #endif
286  } else { // local boundary
287  // need to wait for the top boundary to finish
288  msg << "### FATAL ERROR in Decompositin::RecvBuffer" << std::endl
289  << "Local boundary not yet implemented" << std::endl;
290  ATHENA_ERROR(msg);
291  }
292  int p = 0;
293  for (int k = kl; k <= ku; ++k)
294  for (int j = jl; j <= ju; ++j)
295  for (int i = il; i <= iu; ++i) psf(k, j, i) = buffer_[p++];
296 }
297 
298 void Decomposition::SendBuffer(AthenaArray<Real> const &psf, int kl, int ku,
299  int jl, int ju) {
300  MeshBlock *pmb = pmy_block_;
301  int s1 = 0;
302  for (int k = kl; k <= ku; ++k)
303  for (int j = jl; j <= ju; ++j)
304  for (int i = pmb->is; i <= pmb->is + NGHOST; ++i)
305  send_buffer_[s1++] = psf(k, j, i);
306 
307  int s2 = s1;
308  for (int k = kl; k <= ku; ++k)
309  for (int j = jl; j <= ju; ++j)
310  for (int i = pmb->ie - NGHOST + 1; i <= pmb->ie + 1; ++i)
311  send_buffer_[s2++] = psf(k, j, i);
312 
313  if (has_bot_neighbor) {
314  if (bblock.snb.rank != Globals::my_rank) { // MPI boundary
315  int tag = CreateMPITag(bblock.snb.gid, pmb->gid, 22);
316 #ifdef MPI_PARALLEL
317  MPI_Isend(send_buffer_, s1, MPI_ATHENA_REAL, bblock.snb.rank, tag,
318  MPI_COMM_WORLD, &req_send_bot_);
319 #endif
320  } else { // local boundary, place holder, may not work
321  MeshBlock *pbl = pmy_block_->pmy_mesh->FindMeshBlock(bblock.snb.gid);
322  std::memcpy(pbl->pimpl->pdec->buffer_, send_buffer_, s1 * sizeof(Real));
323  }
324  }
325 
326  if (has_top_neighbor) {
327  if (tblock.snb.rank != Globals::my_rank) {
328  int tag = CreateMPITag(tblock.snb.gid, pmb->gid, 22);
329 #ifdef MPI_PARALLEL
330  MPI_Isend(send_buffer_ + s1, s1, MPI_ATHENA_REAL, tblock.snb.rank, tag,
331  MPI_COMM_WORLD, &req_send_top_);
332 #endif
333  } else { // local boundary, place holder, may not work
334  MeshBlock *pbl = pmy_block_->pmy_mesh->FindMeshBlock(tblock.snb.gid);
335  std::memcpy(pbl->pimpl->pdec->buffer_, send_buffer_ + s1,
336  s1 * sizeof(Real));
337  }
338  }
339 }
340 
342  int ku, int jl, int ju) {
343  MeshBlock *pmb = pmy_block_;
344  int c = 0;
345  for (int i = 0; i < Globals::nranks; ++i) {
346  if (brank_[i] == -1)
347  color_[i] = c++;
348  else
349  color_[i] = color_[brank_[i]];
350  }
351 
352  int ssize = 2 * (ku - kl + 1) * (ju - jl + 1), p = 0;
353  auto pthermo = Thermodynamics::GetInstance();
354  if (!has_bot_neighbor) {
355  for (int k = kl; k <= ku; ++k)
356  for (int j = jl; j <= ju; ++j) {
357  Real gamma = pthermo->GetGamma(pmb, k, j, pmb->is);
358  buffer_[p++] = gamma;
359  buffer_[p++] =
360  log(w(IPR, k, j, pmb->is)) - gamma * log(w(IDN, k, j, pmb->is));
361  }
362  }
363 
364  /*if (Globals::my_rank == 0) {
365  for (int i = 0; i < Globals::nranks; ++i)
366  std::cout << brank_[i] << " ";
367  std::cout << std::endl;
368  for (int i = 0; i < Globals::nranks; ++i)
369  std::cout << color_[i] << " ";
370  std::cout << std::endl;
371  }*/
372 
373 #ifdef MPI_PARALLEL
374  MPI_Comm comm_col;
375  MPI_Comm_split(MPI_COMM_WORLD, color_[Globals::my_rank], Globals::my_rank,
376  &comm_col);
377  // assuming correct ordering
378  MPI_Bcast(buffer_, ssize, MPI_ATHENA_REAL, 0, comm_col);
379  MPI_Comm_free(&comm_col);
380 #endif
381 
382  p = 0;
383  for (int k = kl; k <= ku; ++k)
384  for (int j = jl; j <= ju; ++j) {
385  entropy_(0, k, j) = buffer_[p++];
386  entropy_(1, k, j) = buffer_[p++];
387  }
388 }
void RecvBuffer(AthenaArray< Real > &psf, int kl, int ku, int jl, int ju, int il, int iu, NeighborBlock nb)
AthenaArray< Real > psf_
AthenaArray< Real > gamma_
NeighborBlock tblock
MeshBlock * pmy_block_
AthenaArray< Real > pres_
AthenaArray< Real > dens_
void WaitToFinishSync(AthenaArray< Real > &w, int kl, int ku, int jl, int ju)
void RecvFromTop(AthenaArray< Real > &psf, int kl, int ku, int jl, int ju)
NeighborBlock bblock
int CreateMPITag(int lid, int bufid, int phy)
void SyncNewVariables(AthenaArray< Real > const &w, int kl, int ku, int jl, int ju)
AthenaArray< Real > psv_
Decomposition(MeshBlock *pmb)
void WaitToFinishSend()
void SendBuffer(AthenaArray< Real > const &psf, int kl, int ku, int jl, int ju)
AthenaArray< Real > entropy_
void FindNeighbors()
void SendToBottom(AthenaArray< Real > const &psf, int kl, int ku, int jl, int ju)
void PopulateBotEntropy(AthenaArray< Real > const &w, int kl, int ku, int jl, int ju)
static Thermodynamics const * GetInstance()
Return a pointer to the one and only instance of Thermodynamics.