Canoe
Comprehensive Atmosphere N' Ocean Engine
implicit_solver.cpp
Go to the documentation of this file.
1 // C/C++
2 #include <algorithm>
3 #include <functional>
4 #include <string>
5 
6 // canoe
7 #include <configure.hpp>
8 #include <constants.hpp>
9 
10 // athena
11 #include <athena/bvals/bvals.hpp>
12 #include <athena/bvals/bvals_interfaces.hpp>
13 #include <athena/hydro/hydro.hpp>
14 #include <athena/mesh/mesh.hpp>
15 #include <athena/parameter_input.hpp>
16 
17 // application
18 #include <application/application.hpp>
19 #include <application/globals.hpp>
20 
21 // utils
22 #include <utils/ndarrays.hpp>
23 
24 // snap
25 #include "implicit_solver.hpp"
26 
27 // MPI headers
28 #ifdef MPI_PARALLEL
29 #include <mpi.h>
30 #endif
31 
32 #define MAX_DATA_SIZE 25
33 
34 ImplicitSolver::ImplicitSolver(MeshBlock *pmb, ParameterInput *pin)
35  : has_bot_neighbor(false),
36  has_top_neighbor(false),
37  first_block(true),
38  last_block(true),
39  periodic_boundary(false),
40  pole_at_bot(false),
41  pole_at_top(false),
42  pmy_block_(pmb) {
43  Application::Logger app("snap");
44  app->Log("Initialize ImplicitSolver");
45 
46  implicit_flag = pin->GetOrAddInteger("hydro", "implicit_flag", 0);
47  int nc1 = pmb->ncells1, nc2 = pmb->ncells2, nc3 = pmb->ncells3;
48  int n2max = nc2, n3max = nc3;
49  if (implicit_flag & 2) {
50  n2max = std::max(n2max, nc3);
51  n3max = std::max(n3max, nc1);
52  }
53  if (implicit_flag & 3) {
54  n2max = std::max(n2max, nc1);
55  n3max = std::max(n3max, nc2);
56  }
57 
58  du_.NewAthenaArray(NHYDRO, nc3, nc2, nc1);
59  coefficients_.NewAthenaArray(nc3, nc2, nc1, 4 * MAX_DATA_SIZE);
60  NewCArray(buffer_, n3max, n2max, 7 * MAX_DATA_SIZE);
61 
62 #ifdef MPI_PARALLEL
63  NewCArray(req_send_data1_, n3max, n2max);
64  NewCArray(req_send_data2_, n3max, n2max);
65  NewCArray(req_send_data6_, n3max, n2max);
66  NewCArray(req_send_data7_, n3max, n2max);
67 #endif
68 
69  int idn = 0, ivx = 1, ivy = 2, ivz = 3, ien = 4;
70  p2_.setZero();
71  p2_(idn, idn) = 1.;
72  p2_(ivx, ivy) = 1.;
73  p2_(ivy, ivz) = 1.;
74  p2_(ivz, ivx) = 1.;
75  p2_(ien, ien) = 1.;
76 
77  p3_.setZero();
78  p3_(idn, idn) = 1.;
79  p3_(ivx, ivz) = 1.;
80  p3_(ivy, ivx) = 1.;
81  p3_(ivz, ivy) = 1.;
82  p3_(ien, ien) = 1.;
83 }
84 
86  Application::Logger app("snap");
87  app->Log("Destroy ImplicitSolver");
88 
89  // delete[] usend_top_;
90  // delete[] urecv_bot_;
91  // delete[] usend_bot_;
92  // delete[] urecv_top_;
93 
95  // FreeCArray(coefficients_);
96  // FreeCArray(jacobian_);
97 
98 #ifdef MPI_PARALLEL
99  FreeCArray2(req_send_data1_);
100  FreeCArray2(req_send_data2_);
101  FreeCArray2(req_send_data6_);
102  FreeCArray2(req_send_data7_);
103 #endif
104 }
105 
106 void ImplicitSolver::SetDirection(CoordinateDirection dir) {
107  mydir_ = dir;
108  int nc1, nc2, nc3;
109  if (dir == X1DIR) {
110  nc1 = pmy_block_->ncells1, nc2 = pmy_block_->ncells2,
111  nc3 = pmy_block_->ncells3;
112  } else if (dir == X2DIR) {
113  nc1 = pmy_block_->ncells2, nc2 = pmy_block_->ncells3,
114  nc3 = pmy_block_->ncells1;
115  } else { // X3DIR
116  nc1 = pmy_block_->ncells3, nc2 = pmy_block_->ncells1,
117  nc3 = pmy_block_->ncells2;
118  }
119 
120  du_.SetDim1(nc1);
121  du_.SetDim2(nc2);
122  du_.SetDim3(nc3);
123 
124  coefficients_.SetDim2(nc1);
125  coefficients_.SetDim3(nc2);
126  coefficients_.SetDim4(nc3);
127 
128  if ((pmy_block_->pmy_mesh->mesh_bcs[2 * dir] == BoundaryFlag::periodic) &&
129  (pmy_block_->pmy_mesh->mesh_bcs[2 * dir + 1] == BoundaryFlag::periodic)) {
130  periodic_boundary = true;
131  } else {
132  periodic_boundary = false;
133  }
134 
135  if (pmy_block_->pbval->block_bcs[2 * dir] == BoundaryFlag::polar)
136  pole_at_bot = true;
137  else
138  pole_at_bot = false;
139 
140  if (pmy_block_->pbval->block_bcs[2 * dir + 1] == BoundaryFlag::polar)
141  pole_at_top = true;
142  else
143  pole_at_top = false;
144 }
145 
147  // find top and bot neighbor
148  has_top_neighbor = false;
149  has_bot_neighbor = false;
150  first_block = true;
151  last_block = true;
152 
153  for (int n = 0; n < pmy_block_->pbval->nneighbor; ++n) {
154  NeighborBlock &nb = pmy_block_->pbval->neighbor[n];
155  if (mydir_ == X1DIR) {
156  if ((nb.ni.ox1 == -1) && (nb.ni.ox2 == 0) && (nb.ni.ox3 == 0)) {
157  bblock = nb;
158  has_bot_neighbor = true;
159  }
160  if ((nb.ni.ox1 == 1) && (nb.ni.ox2 == 0) && (nb.ni.ox3 == 0)) {
161  tblock = nb;
162  has_top_neighbor = true;
163  }
164  } else if (mydir_ == X2DIR) {
165  if ((nb.ni.ox1 == 0) && (nb.ni.ox2 == -1) && (nb.ni.ox3 == 0)) {
166  bblock = nb;
167  has_bot_neighbor = true;
168  }
169  if ((nb.ni.ox1 == 0) && (nb.ni.ox2 == 1) && (nb.ni.ox3 == 0)) {
170  tblock = nb;
171  has_top_neighbor = true;
172  }
173  } else { // X3DIR
174  if ((nb.ni.ox1 == 0) && (nb.ni.ox2 == 0) && (nb.ni.ox3 == -1)) {
175  bblock = nb;
176  has_bot_neighbor = true;
177  }
178  if ((nb.ni.ox1 == 0) && (nb.ni.ox2 == 0) && (nb.ni.ox3 == 1)) {
179  tblock = nb;
180  has_top_neighbor = true;
181  }
182  }
183  }
184 
185  MeshBlock const *pmb = pmy_block_;
186  Mesh const *pmesh = pmb->pmy_mesh;
187 
188  if (mydir_ == X1DIR) {
189  if (pmb->block_size.x1min > pmesh->mesh_size.x1min) first_block = false;
190  if (pmb->block_size.x1max < pmesh->mesh_size.x1max) last_block = false;
191  } else if (mydir_ == X2DIR) {
192  if (pmb->block_size.x2min > pmesh->mesh_size.x2min) first_block = false;
193  if (pmb->block_size.x2max < pmesh->mesh_size.x2max) last_block = false;
194  } else { // X3DIR
195  if (pmb->block_size.x3min > pmesh->mesh_size.x3min) first_block = false;
196  if (pmb->block_size.x3max < pmesh->mesh_size.x3max) last_block = false;
197  }
198 
199  // if (first_block)
200  // has_bot_neighbor = false;
201 
202  // if (last_block)
203  // has_top_neighbor = false;
204 
205  // if (pmb->pbval->block_bcs[2*mydir_] == BoundaryFlag::polar)
206  // first_block = true;
207  // if (pmb->pbval->block_bcs[2*mydir_+1] == BoundaryFlag::polar)
208  // last_block = true;
209 
210  // std::cout << "dir = " << mydir_ << std::endl;
211  // std::cout << "I'm rank " << Globals::my_rank << std::endl;
212  // std::cout << "first_block " << first_block << std::endl;
213  // std::cout << "last_block " << last_block << std::endl;
214 }
215 
216 /*void ImplicitSolver::SynchronizeConserved(AthenaArray<Real> const& du,
217  int kl, int ku, int jl, int ju, int is, int ie) {
218  MeshBlock *pmb = pmy_hydro->pmy_block;
219 
220  if (has_bot_neighbor) {
221  int sbot = 0;
222  for (int k = kl; k <= ku; ++k)
223  for (int j = jl; j <= ju; ++j)
224  for (int n = 0; n < NHYDRO; ++n)
225  usend_bot_[sbot++] = du(n,k,j,is);
226  if (bblock.snb.rank != Globals::my_rank) { // MPI boundary
227 #ifdef MPI_PARALLEL
228  int tag = CreateMPITag(bblock.snb.gid, pmb->gid, "b");
229  MPI_Isend(usend_bot_, sbot, MPI_ATHENA_REAL, bblock.snb.rank, tag,
230 MPI_COMM_WORLD, &req_send_sync_bot_); if (pmb->pbval->block_bcs[2*mydir_] ==
231 BoundaryFlag::polar) tag = CreateMPITag(pmb->gid, bblock.snb.gid, "b"); else tag
232 = CreateMPITag(pmb->gid, bblock.snb.gid, "t"); MPI_Irecv(urecv_bot_, sbot,
233 MPI_ATHENA_REAL, bblock.snb.rank, tag, MPI_COMM_WORLD, &req_recv_sync_bot_);
234 #endif
235  } else { // local boundary
236  MeshBlock *pbl =
237 pmy_hydro->pmy_block->pmy_mesh->FindMeshBlock(bblock.snb.gid);
238  std::memcpy(pbl->phydro->pimp->urecv_top_, usend_bot_, sbot*sizeof(Real));
239  }
240  }
241 
242  if (has_top_neighbor) {
243  int stop = 0;
244  for (int k = kl; k <= ku; ++k)
245  for (int j = jl; j <= ju; ++j)
246  for (int n = 0; n < NHYDRO; ++n)
247  usend_top_[stop++] = du(n,k,j,ie);
248  if (tblock.snb.rank != Globals::my_rank) { // MPI boundary
249 #ifdef MPI_PARALLEL
250  int tag = CreateMPITag(tblock.snb.gid, pmb->gid, "t");
251  MPI_Isend(usend_top_, stop, MPI_ATHENA_REAL, tblock.snb.rank, tag,
252 MPI_COMM_WORLD, &req_send_sync_top_); if (pmb->pbval->block_bcs[2*mydir_+1] ==
253 BoundaryFlag::polar) tag = CreateMPITag(pmb->gid, tblock.snb.gid, "t"); else tag
254 = CreateMPITag(pmb->gid, tblock.snb.gid, "b"); MPI_Irecv(urecv_top_, stop,
255 MPI_ATHENA_REAL, tblock.snb.rank, tag, MPI_COMM_WORLD, &req_recv_sync_top_);
256 #endif
257  } else { // local boundary
258  MeshBlock *pbl =
259 pmy_hydro->pmy_block->pmy_mesh->FindMeshBlock(bblock.snb.gid);
260  std::memcpy(pbl->phydro->pimp->urecv_bot_, usend_top_, stop*sizeof(Real));
261  }
262  }
263 }
264 
265 void ImplicitSolver::WaitToFinishSync(int kl, int ku, int jl, int ju, int is,
266 int ie) { #ifdef MPI_PARALLEL MPI_Status status; if (has_bot_neighbor &&
267 (bblock.snb.rank != Globals::my_rank)) { MPI_Wait(&req_send_sync_bot_, &status);
268  MPI_Wait(&req_recv_sync_bot_, &status);
269  }
270 #endif
271 
272  if (has_bot_neighbor) {
273  int p = 0;
274  for (int k = kl; k <= ku; ++k)
275  for (int j = jl; j <= ju; ++j)
276  for (int n = 0; n < NHYDRO; ++n)
277  du_(n,k,j,is-1) = urecv_bot_[p++];
278  } else {
279  for (int k = kl; k <= ku; ++k)
280  for (int j = jl; j <= ju; ++j)
281  for (int n = 0; n < NHYDRO; ++n)
282  du_(n,k,j,is-1) = du_(n,k,j,is);
283  }
284 
285 #ifdef MPI_PARALLEL
286  if (has_top_neighbor && (tblock.snb.rank != Globals::my_rank)) {
287  MPI_Wait(&req_send_sync_top_, &status);
288  MPI_Wait(&req_recv_sync_top_, &status);
289  }
290 #endif
291 
292  if (has_top_neighbor) {
293  int p = 0;
294  for (int k = kl; k <= ku; ++k)
295  for (int j = jl; j <= ju; ++j)
296  for (int n = 0; n < NHYDRO; ++n)
297  du_(n,k,j,ie+1) = urecv_top_[p++];
298  } else {
299  for (int k = kl; k <= ku; ++k)
300  for (int j = jl; j <= ju; ++j)
301  for (int n = 0; n < NHYDRO; ++n)
302  du_(n,k,j,ie+1) = du_(n,k,j,ie);
303  }
304 }*/
305 
306 int ImplicitSolver::CreateMPITag(int recvid, int sendid, std::string phys) {
307  // return (lid<<17) | (bufid<<11) | phys;
308  std::string str = std::to_string(recvid);
309  str += "x";
310  str += std::to_string(sendid);
311  str += "x";
312  str += phys;
313  return std::hash<std::string>{}(str) % Globals::mpi_tag_ub;
314 }
315 
316 #undef MAX_DATA_SIZE
EIGEN_MAKE_ALIGNED_OPERATOR_NEW bool has_top_neighbor
int CreateMPITag(int lid, int bufid, std::string phy)
NeighborBlock bblock
EIGEN_MAKE_ALIGNED_OPERATOR_NEW bool has_bot_neighbor
NeighborBlock tblock
Eigen::Matrix< Real, 5, 5 > p3_
CoordinateDirection mydir_
AthenaArray< Real > coefficients_
void SetDirection(CoordinateDirection dir)
AthenaArray< Real > du_
Eigen::Matrix< Real, 5, 5 > p2_
MeshBlock const * pmy_block_
ImplicitSolver(MeshBlock *pmb, ParameterInput *pin)
double max(double x1, double x2, double x3)
Definition: core.h:19
#define MAX_DATA_SIZE
void FreeCArray(T **a)
Definition: ndarrays.hpp:13
void FreeCArray2(T **a)
Definition: ndarrays.hpp:19
void NewCArray(T **&a, int n1, int n2)
Definition: ndarrays.hpp:5