Canoe
Comprehensive Atmosphere N' Ocean Engine
particle_exchanger.cpp
Go to the documentation of this file.
1 
4 // C/C++ header
5 #include <iostream>
6 #include <sstream>
7 #include <stdexcept>
8 
9 // application
10 #include <application/exceptions.hpp>
11 
12 // Athena++ headers
13 #include <athena/bvals/bvals.hpp>
14 #include <athena/mesh/mesh.hpp>
15 
16 // n-body
17 #include "particle_data.hpp"
18 #include "particles.hpp"
19 
20 bool ParticleBase::UnpackData(MeshBlock const *pmb) {
21  bool success = true;
22  int test;
23 
24  auto pm = pmb->pmy_mesh;
25 
26  for (auto &nb : pmb->pbval->neighbor) {
27  if (status_flag_[nb.bufid] == BoundaryStatus::completed) continue;
28 
29 #ifdef MPI_PARALLEL
30  if (status_flag_[nb.bufid] == BoundaryStatus::waiting) {
31  MPI_Test(&req_mpi_recv_[nb.bufid], &test, MPI_STATUS_IGNORE);
32  if (test)
33  status_flag_[nb.bufid] = BoundaryStatus::arrived;
34  else {
35  success = false;
36  continue;
37  }
38  }
39 #endif
40 
41  if (status_flag_[nb.bufid] == BoundaryStatus::arrived) {
42  auto it = recv_buffer_[nb.bufid].begin();
43 
44  for (; it != recv_buffer_[nb.bufid].end(); ++it) {
45  // 0:INNER_X1, 1:OUTER_X1
46  if (pm->mesh_bcs[(nb.ni.ox1 + 1) >> 1] == BoundaryFlag::periodic) {
47  if (it->x1 >= pm->mesh_size.x1max)
48  it->x1 -= pm->mesh_size.x1max - pm->mesh_size.x1min;
49  if (it->x1 <= pm->mesh_size.x1min)
50  it->x1 += pm->mesh_size.x1max - pm->mesh_size.x1min;
51  }
52 
53  // 2:INNER_X2, 3:OUTER_X2
54  if (pm->mesh_bcs[2 + ((nb.ni.ox2 + 1) >> 1)] ==
55  BoundaryFlag::periodic) {
56  if (it->x2 >= pm->mesh_size.x2max)
57  it->x2 -= pm->mesh_size.x2max - pm->mesh_size.x2min;
58  if (it->x2 <= pm->mesh_size.x2min)
59  it->x2 += pm->mesh_size.x2max - pm->mesh_size.x2min;
60  }
61 
62  // 4:INNER_X3, 5:OUTER_X3
63  if (pm->mesh_bcs[4 + ((nb.ni.ox3 + 1) >> 1)] ==
64  BoundaryFlag::periodic) {
65  if (it->x3 >= pm->mesh_size.x3max)
66  it->x3 -= pm->mesh_size.x3max - pm->mesh_size.x3min;
67  if (it->x3 <= pm->mesh_size.x3min)
68  it->x3 += pm->mesh_size.x3max - pm->mesh_size.x3min;
69  }
70 
71  bool in_meshblock = ParticlesHelper::check_in_meshblock(*it, pmb);
72  if (!in_meshblock) {
73  throw RuntimeError("ParticleBase::AttachParticles",
74  "Particle moved out of MeshBlock limits");
75  } else {
76  pc.push_back(*it);
77  }
78  }
79 
80  SetBoundaryStatus(nb.bufid, BoundaryStatus::completed); // completed
81  }
82  }
83 
84  return success;
85 }
86 
87 // This subroutine will remove inactive particles (id < 0) and move particles to
88 // appropriate buffers if they moved out of the current domain
89 void ParticleBase::PackData(MeshBlock const *pmb) {
90  auto pm = pmb->pmy_mesh;
91 
92  Real x1min = pmb->block_size.x1min;
93  Real x1max = pmb->block_size.x1max;
94  Real x2min = pmb->block_size.x2min;
95  Real x2max = pmb->block_size.x2max;
96  Real x3min = pmb->block_size.x3min;
97  Real x3max = pmb->block_size.x3max;
98 
99  int ox1 = 0, ox2 = 0, ox3 = 0, fi1 = 0, fi2 = 0;
100  auto qi = pc.begin();
101  auto qj = pc.end();
102 
103  while (qi < qj) {
104  // if particle is inactive, swap the current one with the last one
105  if (qi->pid < 0) {
106  *qi = *(qj - 1);
107  qj--;
108  continue;
109  } // proceed to living particle
110  // take care of reflective boundary condition
111  if (pmb->pbval->block_bcs[inner_x1] == BoundaryFlag::reflect &&
112  qi->x1 < x1min) {
113  qi->x1 = 2 * x1min - qi->x1;
114  qi->v1 = -qi->v1;
115  }
116  if (pmb->pbval->block_bcs[outer_x1] == BoundaryFlag::reflect &&
117  qi->x1 > x1max) {
118  qi->x1 = 2 * x1max - qi->x1;
119  qi->v1 = -qi->v1;
120  }
121  ox1 = qi->x1 < x1min ? -1 : (qi->x1 > x1max ? 1 : 0);
122 
123  if (pm->f2) {
124  if (pmb->pbval->block_bcs[inner_x2] == BoundaryFlag::reflect &&
125  qi->x2 < x2min) {
126  qi->x2 = 2 * x2min - qi->x2;
127  qi->v2 = -qi->v2;
128  } else if (pmb->pbval->block_bcs[inner_x2] == BoundaryFlag::polar &&
129  qi->x2 < 0.) {
130  // \todo TODO: fix pole problem
131  }
132  if (pmb->pbval->block_bcs[outer_x2] == BoundaryFlag::reflect &&
133  qi->x2 > x2max) {
134  qi->x2 = 2 * x2max - qi->x2;
135  qi->v2 = -qi->v2;
136  } else if (pmb->pbval->block_bcs[outer_x2] == BoundaryFlag::polar &&
137  qi->x2 > 2. * M_PI) {
138  // \todo TODO: fix pole problem
139  }
140  ox2 = qi->x2 < x2min ? -1 : (qi->x2 > x2max ? 1 : 0);
141  }
142 
143  if (pm->f3) {
144  if (pmb->pbval->block_bcs[inner_x3] == BoundaryFlag::reflect &&
145  qi->x3 < x3min) {
146  qi->x3 = 2 * x3min - qi->x3;
147  qi->v3 = -qi->v3;
148  }
149  if (pmb->pbval->block_bcs[outer_x3] == BoundaryFlag::reflect &&
150  qi->x3 > x3max) {
151  qi->x3 = 2 * x3max - qi->x3;
152  qi->v3 = -qi->v3;
153  }
154  ox3 = qi->x3 < x3min ? -1 : (qi->x3 > x3max ? 1 : 0);
155  }
156 
157  if (pm->multilevel) {
158  // reserved implementation for multilevel, fi1, fi2
159  }
160 
161  int bid = BoundaryBase::FindBufferID(ox1, ox2, ox3, fi1, fi2);
162  if (bid == -1) { // particle inside domain
163  qi++;
164  } else { // particle moved out of the domain
165  // std::cout << "particle (" << qi->id << "," << qi->x2 << ") move to " <<
166  // bid << std::endl;; std::cout << "block range = (" << x1min << "," <<
167  // x1max << ")" << std::endl;
168  send_buffer_[bid].push_back(*qi);
169  // pmb->pdebug->msg << *qi;
170  *qi = *(qj - 1);
171  qj--;
172  }
173  }
174 
175  // particles beyond qi are inactive particles. Remove them from the list
176  pc.resize(qi - pc.begin());
177 }
void SetBoundaryStatus(int bid, BoundaryStatus status)
Set the boundary status.
Definition: exchanger.hpp:82
enum BoundaryStatus status_flag_[MessageTraits< T >::num_buffers]
Definition: exchanger.hpp:87
BufferType recv_buffer_[MessageTraits< ParticleBase >::num_buffers]
Definition: exchanger.hpp:89
BufferType send_buffer_[MessageTraits< ParticleBase >::num_buffers]
Definition: exchanger.hpp:88
void PackData(MeshBlock const *pmb) override
Pack data to send buffer.
ParticleContainer pc
Definition: particles.hpp:39
bool UnpackData(MeshBlock const *pmb) override
Unpack data from receive buffer.
bool check_in_meshblock(ParticleData const &pd, MeshBlock const *pmb)