IPPL (Independent Parallel Particle Layer)
IPPL
Loading...
Searching...
No Matches
BcTypes.hpp
Go to the documentation of this file.
1// This file contains the abstract base class for
2// field boundary conditions and other child classes
3// which represent specific BCs. At the moment the
4// following field BCs are supported
5//
6// 1. Periodic BC
7// 2. Zero BC
8// 3. Specifying a constant BC
9// 4. No BC (default option)
10// 5. Constant extrapolation BC
11// Only cell-centered field BCs are implemented
12// at the moment.
13//
14
16
17#include "Field/HaloCells.h"
18
19namespace ippl {
20 namespace detail {
21
22 template <typename Field>
23 BCondBase<Field>::BCondBase(unsigned int face)
24 : face_m(face)
25 , changePhysical_m(false) {}
26
27 template <typename Field>
28 inline std::ostream& operator<<(std::ostream& os, const BCondBase<Field>& bc) {
29 bc.write(os);
30 return os;
31 }
32
33 } // namespace detail
34
35 template <typename Field>
37 // We only support constant extrapolation for the moment, other
38 // higher order extrapolation stuffs need to be added.
39
40 unsigned int face = this->face_m;
41 unsigned d = face / 2;
42 if (field.getCommunicator().size() > 1) {
43 const Layout_t& layout = field.getLayout();
44 const auto& lDomains = layout.getHostLocalDomains();
45 const auto& domain = layout.getDomain();
46 int myRank = field.getCommunicator().rank();
47
48 bool isBoundary = (lDomains[myRank][d].max() == domain[d].max())
49 || (lDomains[myRank][d].min() == domain[d].min());
50
51 if (!isBoundary) {
52 return;
53 }
54 }
55
56 // If we are here then it is a processor with the face on the physical
57 // boundary or it is the single core case. Then the following code is same
58 // irrespective of either it is a single core or multi-core case as the
59 // non-periodic BC is local to apply.
60 typename Field::view_type& view = field.getView();
61 const int nghost = field.getNghost();
62 int src, dest;
63
64 // It is not clear what it exactly means to do extrapolate
65 // BC for nghost >1
66 if (nghost > 1) {
67 throw IpplException("ExtrapolateFace::apply", "nghost > 1 not supported");
68 }
69
70 if (d >= Dim) {
71 throw IpplException("ExtrapolateFace::apply", "face number wrong");
72 }
73
74 // If face & 1 is true, then it is an upper BC
75 if (face & 1) {
76 src = view.extent(d) - 2;
77 dest = src + 1;
78 } else {
79 src = 1;
80 dest = src - 1;
81 }
82
83 using exec_space = typename Field::execution_space;
84 using index_type = typename RangePolicy<Dim, exec_space>::index_type;
85 Kokkos::Array<index_type, Dim> begin, end;
86 for (unsigned i = 0; i < Dim; i++) {
87 begin[i] = nghost;
88 end[i] = view.extent(i) - nghost;
89 }
90 begin[d] = src;
91 end[d] = src + 1;
92 using index_array_type = typename RangePolicy<Dim, exec_space>::index_array_type;
94 "Assign extrapolate BC", createRangePolicy<Dim, exec_space>(begin, end),
95 KOKKOS_CLASS_LAMBDA(index_array_type & args) {
96 // to avoid ambiguity with the member function
97 using ippl::apply;
98
99 T value = apply(view, args);
100
101 args[d] = dest;
102
103 apply(view, args) = slope_m * value + offset_m;
104 });
105 }
106
107 template <typename Field>
108 void ExtrapolateFace<Field>::write(std::ostream& out) const {
109 out << "Constant Extrapolation Face"
110 << ", Face = " << this->face_m;
111 }
112
113 template <typename Field>
114 void NoBcFace<Field>::write(std::ostream& out) const {
115 out << "NoBcFace"
116 << ", Face = " << this->face_m;
117 }
118
119 template <typename Field>
120 void ConstantFace<Field>::write(std::ostream& out) const {
121 out << "ConstantFace"
122 << ", Face = " << this->face_m << ", Constant = " << this->offset_m;
123 }
124
125 template <typename Field>
126 void ZeroFace<Field>::write(std::ostream& out) const {
127 out << "ZeroFace"
128 << ", Face = " << this->face_m;
129 }
130
131 template <typename Field>
132 void PeriodicFace<Field>::write(std::ostream& out) const {
133 out << "PeriodicFace"
134 << ", Face = " << this->face_m;
135 }
136
137 template <typename Field>
139 auto& comm = field.getCommunicator();
140 // For cell centering only face neighbors are needed
141 unsigned int face = this->face_m;
142 unsigned int d = face / 2;
143 const int nghost = field.getNghost();
144 int myRank = comm.rank();
145 const Layout_t& layout = field.getLayout();
146 const auto& lDomains = layout.getHostLocalDomains();
147 const auto& domain = layout.getDomain();
148
149 for (auto& neighbors : faceNeighbors_m) {
150 neighbors.clear();
151 }
152
153 if (lDomains[myRank][d].length() < domain[d].length()) {
154 // Only along this dimension we need communication.
155
156 bool isBoundary = (lDomains[myRank][d].max() == domain[d].max())
157 || (lDomains[myRank][d].min() == domain[d].min());
158
159 if (isBoundary) {
160 // this face is on mesh/physical boundary
161 // get my local box
162 auto& nd = lDomains[myRank];
163
164 // grow the box by nghost cells in dimension d of face
165 auto gnd = nd.grow(nghost, d);
166
167 int offset;
168 if (face & 1) {
169 // upper face
170 offset = -domain[d].length();
171 } else {
172 // lower face
173 offset = domain[d].length();
174 }
175 // shift by offset
176 gnd[d] = gnd[d] + offset;
177
178 // Now, we are ready to intersect
179 for (int rank = 0; rank < comm.size(); ++rank) {
180 if (rank == myRank) {
181 continue;
182 }
183
184 if (gnd.touches(lDomains[rank])) {
185 faceNeighbors_m[face].push_back(rank);
186 }
187 }
188 }
189 }
190 }
191
192 template <typename Field>
194 auto& comm = field.getCommunicator();
195 unsigned int face = this->face_m;
196 unsigned int d = face / 2;
197 typename Field::view_type& view = field.getView();
198 const Layout_t& layout = field.getLayout();
199 const int nghost = field.getNghost();
200 int myRank = comm.rank();
201 const auto& lDomains = layout.getHostLocalDomains();
202 const auto& domain = layout.getDomain();
203
204 // We have to put tag here so that the matchtag inside
205 // the if is proper.
206 int tag = comm.next_tag(mpi::tag::BC_PARALLEL_PERIODIC, mpi::tag::BC_CYCLE);
207
208 if (lDomains[myRank][d].length() < domain[d].length()) {
209 // Only along this dimension we need communication.
210
211 bool isBoundary = (lDomains[myRank][d].max() == domain[d].max())
212 || (lDomains[myRank][d].min() == domain[d].min());
213
214 if (isBoundary) {
215 // this face is on mesh/physical boundary
216 // get my local box
217 auto& nd = lDomains[myRank];
218
219 int offset, offsetRecv, matchtag;
220 if (face & 1) {
221 // upper face
222 offset = -domain[d].length();
223 offsetRecv = nghost;
224 matchtag = comm.preceding_tag(mpi::tag::BC_PARALLEL_PERIODIC);
225 } else {
226 // lower face
227 offset = domain[d].length();
228 offsetRecv = -nghost;
229 matchtag = comm.following_tag(mpi::tag::BC_PARALLEL_PERIODIC);
230 }
231
232 auto& neighbors = faceNeighbors_m[face];
233
234 using memory_space = typename Field::memory_space;
236 std::vector<MPI_Request> requests(neighbors.size());
237
238 using HaloCells_t = typename Field::halo_type;
239 using range_t = typename HaloCells_t::bound_type;
240 HaloCells_t& halo = field.getHalo();
241 std::vector<range_t> rangeNeighbors;
242
243 for (size_t i = 0; i < neighbors.size(); ++i) {
244 int rank = neighbors[i];
245
246 auto ndNeighbor = lDomains[rank];
247 ndNeighbor[d] = ndNeighbor[d] - offset;
248
249 NDIndex<Dim> gndNeighbor = ndNeighbor.grow(nghost, d);
250
251 NDIndex<Dim> overlap = gndNeighbor.intersect(nd);
252
253 range_t range;
254
255 for (size_t j = 0; j < Dim; ++j) {
256 range.lo[j] = overlap[j].first() - nd[j].first() + nghost;
257 range.hi[j] = overlap[j].last() - nd[j].first() + nghost + 1;
258 }
259
260 rangeNeighbors.push_back(range);
261
262 detail::size_type nSends;
263 halo.pack(range, view, haloData_m, nSends);
264
265 buffer_type buf = comm.template getBuffer<memory_space, T>(nSends);
266
267 comm.isend(rank, tag, haloData_m, *buf, requests[i], nSends);
268 buf->resetWritePos();
269 }
270
271 for (size_t i = 0; i < neighbors.size(); ++i) {
272 int rank = neighbors[i];
273
274 range_t range = rangeNeighbors[i];
275
276 range.lo[d] = range.lo[d] + offsetRecv;
277 range.hi[d] = range.hi[d] + offsetRecv;
278
279 detail::size_type nRecvs = range.size();
280
281 buffer_type buf = comm.template getBuffer<memory_space, T>(nRecvs);
282 comm.recv(rank, matchtag, haloData_m, *buf, nRecvs * sizeof(T), nRecvs);
283 buf->resetReadPos();
284
285 using assign_t = typename HaloCells_t::assign;
286 halo.template unpack<assign_t>(range, view, haloData_m);
287 }
288 if (!requests.empty()) {
289 MPI_Waitall(requests.size(), requests.data(), MPI_STATUSES_IGNORE);
290 }
291 comm.freeAllBuffers();
292 }
293 // For all other processors do nothing
294 } else {
295 if (d >= Dim) {
296 throw IpplException("PeriodicFace::apply", "face number wrong");
297 }
298
299 auto N = view.extent(d) - 1;
300
301 using exec_space = typename Field::execution_space;
302 using index_type = typename RangePolicy<Dim, exec_space>::index_type;
303 Kokkos::Array<index_type, Dim> begin, end;
304
305 // For the axis along which BCs are being applied, iterate
306 // through only the ghost cells. For all other axes, iterate
307 // through all internal cells.
308 for (size_t i = 0; i < Dim; ++i) {
309 end[i] = view.extent(i) - nghost;
310 begin[i] = nghost;
311 }
312 begin[d] = 0;
313 end[d] = nghost;
314
315 using index_array_type = typename RangePolicy<Dim, exec_space>::index_array_type;
317 "Assign periodic field BC", createRangePolicy<Dim, exec_space>(begin, end),
318 KOKKOS_CLASS_LAMBDA(index_array_type & coords) {
319 // The ghosts are filled starting from the inside of
320 // the domain proceeding outwards for both lower and
321 // upper faces.
322
323 // to avoid ambiguity with the member function
324 using ippl::apply;
325
326 // x -> nghost + x
327 coords[d] += nghost;
328 auto&& left = apply(view, coords);
329
330 // nghost + x -> N - (nghost + x) = N - nghost - x
331 coords[d] = N - coords[d];
332 auto&& right = apply(view, coords);
333
334 // N - nghost - x -> nghost - 1 - x
335 coords[d] += 2 * nghost - 1 - N;
336 apply(view, coords) = right;
337
338 // nghost - 1 - x -> N - (nghost - 1 - x)
339 // = N - (nghost - 1) + x
340 coords[d] = N - coords[d];
341 apply(view, coords) = left;
342 });
343 }
344 }
345
346 template <typename Field>
348 unsigned int face = this->face_m;
349 unsigned int d = face / 2;
350 typename Field::view_type& view = field.getView();
351 const Layout_t& layout = field.getLayout();
352 const int nghost = field.getNghost();
353 const auto& ldom = layout.getLocalNDIndex();
354 const auto& domain = layout.getDomain();
355
356 if (d >= Dim) {
357 throw IpplException("PeriodicFace::apply", "face number wrong");
358 }
359
360 bool upperFace = (face & 1);
361 bool isBoundary = ((ldom[d].max() == domain[d].max()) && upperFace)
362 || ((ldom[d].min() == domain[d].min()) && !(upperFace));
363
364 if (isBoundary) {
365
366 auto N = view.extent(d) - 1;
367
368 using exec_space = typename Field::execution_space;
369 using index_type = typename RangePolicy<Dim, exec_space>::index_type;
370 Kokkos::Array<index_type, Dim> begin, end;
371
372 // For the axis along which BCs are being applied, iterate
373 // through only the ghost cells. For all other axes, iterate
374 // through all internal cells.
375 bool isCorner = (d != 0);
376 for (size_t i = 0; i < Dim; ++i) {
377 bool upperFace_i = (ldom[i].max() == domain[i].max());
378 bool lowerFace_i = (ldom[i].min() == domain[i].min());
379 end[i] = view.extent(i) - nghost - (upperFace_i)*(isCorner);
380 begin[i] = nghost + (lowerFace_i)*(isCorner);
381 }
382 begin[d] = ((0 + nghost - 1) * (1 - upperFace)) + (N * upperFace);
383 end[d] = begin[d] + 1;
384
385 using index_array_type = typename RangePolicy<Dim, exec_space>::index_array_type;
387 "Assign periodic field BC", createRangePolicy<Dim, exec_space>(begin, end),
388 KOKKOS_CLASS_LAMBDA(index_array_type & coords) {
389 // we add the ghost cell values to the appropriate
390 // neighbouring physical boundary cell
391
392 // to avoid ambiguity with the member function
393 using ippl::apply;
394
395 // get the value at ghost cells
396 auto&& right = apply(view, coords);
397
398 // apply to the last physical cells (boundary)
399 int shift = 1 - (2 * upperFace);
400 coords[d] += shift;
401
402 apply(view, coords) += right;
403 });
404 }
405 }
406
407 template <typename Field>
409 unsigned int face = this->face_m;
410 unsigned int d = face / 2;
411 typename Field::view_type& view = field.getView();
412 const Layout_t& layout = field.getLayout();
413 const int nghost = field.getNghost();
414 const auto& ldom = layout.getLocalNDIndex();
415 const auto& domain = layout.getDomain();
416
417 if (d >= Dim) {
418 throw IpplException("ExtrapolateFace::apply", "face number wrong");
419 }
420
421 bool upperFace = (face & 1);
422 bool isBoundary = ((ldom[d].max() == domain[d].max()) && upperFace)
423 || ((ldom[d].min() == domain[d].min()) && !(upperFace));
424
425 if (isBoundary) {
426 auto N = view.extent(d) - 1;
427
428 using exec_space = typename Field::execution_space;
429 using index_type = typename RangePolicy<Dim, exec_space>::index_type;
430 Kokkos::Array<index_type, Dim> begin, end;
431
432 // For the axis along which BCs are being applied, iterate
433 // through only the ghost cells. For all other axes, iterate
434 // through all internal cells.
435 for (size_t i = 0; i < Dim; ++i) {
436 end[i] = view.extent(i) - nghost;
437 begin[i] = nghost;
438 }
439 begin[d] = ((0 + nghost - 1) * (1 - upperFace)) + (N * upperFace);
440 end[d] = begin[d] + 1;
441
442 using index_array_type = typename RangePolicy<Dim, exec_space>::index_array_type;
444 "Assign field BC", createRangePolicy<Dim, exec_space>(begin, end),
445 KOKKOS_CLASS_LAMBDA(index_array_type & coords) {
446 // we assign the ghost cell values to the appropriate
447 // neighbouring physical boundary cell
448
449 // to avoid ambiguity with the member function
450 using ippl::apply;
451
452 // get the value at ghost cells
453 auto&& right = apply(view, coords);
454
455 // apply to the last physical cells (boundary)
456 int shift = 1 - (2 * upperFace);
457
458 coords[d] += shift;
459
460 apply(view, coords) = right;
461 });
462 }
463 }
464} // namespace ippl
void unpack(const ippl::NDIndex< 3 > intersect, const Kokkos::View< Tf *** > &view, ippl::detail::FieldBufferData< Tb > &fd, int nghost, const ippl::NDIndex< 3 > ldom, bool x=false, bool y=false, bool z=false)
Definition Archive.h:20
KOKKOS_INLINE_FUNCTION constexpr decltype(auto) apply(const View &view, const Coords &coords)
RangePolicy< Dim, PolicyArgs... >::policy_type createRangePolicy(const Kokkos::Array< typename RangePolicy< Dim, PolicyArgs... >::index_type, Dim > &begin, const Kokkos::Array< typename RangePolicy< Dim, PolicyArgs... >::index_type, Dim > &end)
KOKKOS_INLINE_FUNCTION Vector< T, Dim > min(const Vector< T, Dim > &a, const Vector< T, Dim > &b)
Definition Vector.hpp:217
void parallel_for(const std::string &name, const ExecPolicy &policy, const FunctorType &functor)
std::size_t size_type
Definition IpplTypes.h:13
std::ostream & operator<<(std::ostream &, const BCondBase< Field > &)
Definition BcTypes.hpp:28
@ BC_PARALLEL_PERIODIC
Definition Tags.h:13
std::shared_ptr< archive_type< MemorySpace > > buffer_type
Layout_t & getLayout() const
Definition BareField.h:134
int getNghost() const
Definition BareField.h:125
view_type & getView()
Definition BareField.h:169
halo_type & getHalo()
Definition BareField.h:142
auto & getCommunicator() const
Definition BareField.h:131
unsigned int face_m
Definition BcTypes.h:72
BCondBase(unsigned int face)
Definition BcTypes.hpp:23
virtual void write(std::ostream &) const =0
typename detail::BCondBase< Field >::Layout_t Layout_t
Definition BcTypes.h:94
virtual void assignGhostToPhysical(Field &field)
Definition BcTypes.hpp:408
typename Field::value_type T
Definition BcTypes.h:86
virtual void write(std::ostream &out) const
Definition BcTypes.hpp:108
virtual void apply(Field &field)
Definition BcTypes.hpp:36
static constexpr unsigned Dim
Definition BcTypes.h:85
virtual void write(std::ostream &out) const
Definition BcTypes.hpp:114
virtual void write(std::ostream &out) const
Definition BcTypes.hpp:120
virtual void write(std::ostream &out) const
Definition BcTypes.hpp:126
virtual void findBCNeighbors(Field &field)
Definition BcTypes.hpp:138
face_neighbor_type faceNeighbors_m
Definition BcTypes.h:177
typename Field::value_type T
Definition BcTypes.h:159
virtual void write(std::ostream &out) const
Definition BcTypes.hpp:132
Field::halo_type::databuffer_type haloData_m
Definition BcTypes.h:178
virtual void apply(Field &field)
Definition BcTypes.hpp:193
typename detail::BCondBase< Field >::Layout_t Layout_t
Definition BcTypes.h:163
virtual void assignGhostToPhysical(Field &field)
Definition BcTypes.hpp:347
static constexpr unsigned Dim
Definition BcTypes.h:158
const host_mirror_type getHostLocalDomains() const
KOKKOS_INLINE_FUNCTION Vector< int, Dim > last() const
Definition NDIndex.hpp:178
KOKKOS_INLINE_FUNCTION Vector< int, Dim > first() const
Definition NDIndex.hpp:170
KOKKOS_INLINE_FUNCTION NDIndex< Dim > intersect(const NDIndex< Dim > &) const
Definition NDIndex.hpp:70
KOKKOS_INLINE_FUNCTION NDIndex< Dim > grow(int ncells) const
Definition NDIndex.hpp:79
::ippl::Vector< index_type, Dim > index_array_type
typename policy_type::array_index_type index_type