46 constexpr unsigned Dim = Field::dim;
47 static_assert(
Dim == 3,
"mirrorField: only Dim == 3 is implemented");
49 assert(&src.getLayout() == &dst.getLayout()
50 &&
"mirrorField: src and dst must share a layout");
51 assert(src.getNghost() == dst.getNghost()
52 &&
"mirrorField: src and dst must have equal ghost counts");
54 using view_type =
typename Field::view_type;
55 using value_type =
typename view_type::value_type;
58 if (
static_cast<const void*
>(&src) ==
static_cast<const void*
>(&dst)) {
59 Field scratch = src.deepCopy();
64 const auto& layout = src.getLayout();
65 const auto& ldom_r = layout.getLocalNDIndex();
66 const auto& gdom = layout.getDomain();
67 const auto& hDomains = layout.getHostLocalDomains();
68 const int nghost = src.getNghost();
69 const int N_glob =
static_cast<int>(gdom[axis].length());
70 const int P = ippl::Comm->size();
71 const int r = ippl::Comm->rank();
73 auto srcView = src.getView();
74 auto dstView = dst.getView();
81 auto reflectOnAxis = [&](
const ippl::NDIndex<Dim>& ldom_p) {
82 ippl::NDIndex<Dim> out;
83 for (
unsigned d = 0; d <
Dim; ++d) {
85 const int k0_p = ldom_p[d].first();
86 const int k1_p = k0_p +
static_cast<int>(ldom_p[d].length());
87 out[d] = ippl::Index(N_glob - k1_p, N_glob - k0_p - 1);
95 std::vector<MPI_Request> requests;
96 ippl::detail::FieldBufferData<value_type> fd_send;
97 ippl::detail::FieldBufferData<value_type> fd_recv;
98 const int base_tag = ippl::mpi::tag::FIELD_MIRROR;
100 const bool flipX = (axis == 0);
101 const bool flipY = (axis == 1);
102 const bool flipZ = (axis == 2);
105 for (
int p = 0; p < P; ++p) {
109 ippl::NDIndex<Dim> ldom_p_mirror = reflectOnAxis(hDomains(p));
110 if (!ldom_r.touches(ldom_p_mirror)) {
113 ippl::NDIndex<Dim> intersect = ldom_r.intersect(ldom_p_mirror);
118 ippl::detail::solver_send_field(
119 base_tag, 0, p, intersect, ldom_r, nghost, srcView, fd_send, requests);
123 for (
int p = 0; p < P; ++p) {
127 ippl::NDIndex<Dim> ldom_p_mirror = reflectOnAxis(hDomains(p));
128 if (!ldom_r.touches(ldom_p_mirror)) {
131 ippl::NDIndex<Dim> intersect = ldom_r.intersect(ldom_p_mirror);
134 ippl::Vector<bool, Dim> coordBool =
false;
135 if constexpr (
Dim > 0) coordBool[0] = flipX;
136 if constexpr (
Dim > 1) coordBool[1] = flipY;
137 if constexpr (
Dim > 2) coordBool[2] = flipZ;
139 ippl::detail::solver_recv(
140 base_tag, 0, p, intersect, ldom_r, nghost, dstView, fd_recv, coordBool);
146 ippl::NDIndex<Dim> ldom_r_mirror = reflectOnAxis(ldom_r);
147 if (ldom_r.touches(ldom_r_mirror)) {
148 ippl::NDIndex<Dim> intersect = ldom_r.intersect(ldom_r_mirror);
150 const int first0 = intersect[0].first() + nghost - ldom_r[0].first();
151 const int first1 = intersect[1].first() + nghost - ldom_r[1].first();
152 const int first2 = intersect[2].first() + nghost - ldom_r[2].first();
153 const int last0 = intersect[0].last() + nghost - ldom_r[0].first() + 1;
154 const int last1 = intersect[1].last() + nghost - ldom_r[1].first() + 1;
155 const int last2 = intersect[2].last() + nghost - ldom_r[2].first() + 1;
163 const int k_shift = (N_glob - 1) + 2 * (nghost - ldom_r[axis].first());
164 const int axis_c =
static_cast<int>(axis);
166 using mdrange_type = Kokkos::MDRangePolicy<Kokkos::Rank<3>>;
167 Kokkos::parallel_for(
168 "opalx::mirrorField::self",
169 mdrange_type({first0, first1, first2}, {last0, last1, last2}),
170 KOKKOS_LAMBDA(
const size_t i,
const size_t j,
const size_t k) {
171 size_t idx[3] = {i, j, k};
172 idx[axis_c] =
static_cast<size_t>(k_shift) - idx[axis_c];
173 dstView(i, j, k) = srcView(idx[0], idx[1], idx[2]);
179 if (!requests.empty()) {
180 MPI_Waitall(requests.size(), requests.data(), MPI_STATUSES_IGNORE);
182 ippl::Comm->freeAllBuffers();