ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
BoundaryPackInfo.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2024-2026 The ESPResSo project
3 *
4 * This file is part of ESPResSo.
5 *
6 * ESPResSo is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * ESPResSo is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#pragma once
21
22#include <core/debug/Debug.h>
23#include <core/mpi/RecvBuffer.h>
24#include <core/mpi/SendBuffer.h>
25#include <domain_decomposition/IBlock.h>
26#include <field/FlagUID.h>
27#include <field/communication/PackInfo.h>
28#include <stencil/Directions.h>
29
30#include <memory>
31#include <tuple>
32#include <utility>
33
34namespace walberla {
35namespace field {
36namespace communication {
37
38template <typename GhostLayerField_T>
39class BoundaryFlagPackInfo : public PackInfo<GhostLayerField_T> {
40
41public:
42 using PackInfo<GhostLayerField_T>::PackInfo;
43 using PackInfo<GhostLayerField_T>::numberOfGhostLayersToCommunicate;
44
45 ~BoundaryFlagPackInfo() override = default;
46
47 bool constantDataExchange() const override { return false; }
48 bool threadsafeReceiving() const override { return false; }
49};
50
51template <typename GhostLayerField_T, typename Boundary_T>
52class BoundaryPackInfo : public PackInfo<GhostLayerField_T> {
53protected:
54 using PackInfo<GhostLayerField_T>::bdId_;
55 /** Flag for domain cells, i.e. all cells. */
56 FlagUID const Domain_flag{"domain"};
57 /** Flag for boundary cells. */
58 FlagUID const Boundary_flag{"boundary"};
59
60public:
61 using PackInfo<GhostLayerField_T>::PackInfo;
62 using PackInfo<GhostLayerField_T>::numberOfGhostLayersToCommunicate;
63
64 ~BoundaryPackInfo() override = default;
65
66 void setup_boundary_handle(std::shared_ptr<LatticeWalberla> lattice,
67 std::shared_ptr<Boundary_T> boundary) {
68 m_lattice = std::move(lattice);
69 m_boundary = std::move(boundary);
70 }
71
72 bool constantDataExchange() const override { return false; }
73 bool threadsafeReceiving() const override { return false; }
74
75 void communicateLocal(IBlock const *sender, IBlock *receiver,
76 stencil::Direction dir) override {
77#pragma omp critical
78 {
79 mpi::SendBuffer sBuffer;
80 packDataImpl(sender, dir, sBuffer);
81 mpi::RecvBuffer rBuffer(sBuffer);
82 unpackData(receiver, stencil::inverseDir[dir], rBuffer);
83 }
84 }
85
86 void unpackData(IBlock *receiver, stencil::Direction dir,
87 mpi::RecvBuffer &buffer) override {
88
89 auto *flag_field = receiver->getData<GhostLayerField_T>(bdId_);
90 WALBERLA_ASSERT_NOT_NULLPTR(flag_field);
91 WALBERLA_ASSERT_NOT_NULLPTR(m_boundary);
92 WALBERLA_ASSERT_NOT_NULLPTR(m_lattice);
93
94 auto const boundary_flag = flag_field->getFlag(Boundary_flag);
95 auto const gl = numberOfGhostLayersToCommunicate(flag_field);
96 auto const begin = [gl, dir](auto const *field) {
97 return field->beginGhostLayerOnly(gl, dir);
98 };
99
100#ifndef NDEBUG
101 uint_t xSize, ySize, zSize, bSize;
102 buffer >> xSize >> ySize >> zSize >> bSize;
103 uint_t buf_size{0u};
104 for (auto it = begin(flag_field); it != flag_field->end(); ++it) {
105 if (isFlagSet(it, boundary_flag)) {
106 ++buf_size;
107 }
108 }
109 WALBERLA_ASSERT_EQUAL(xSize, flag_field->xSize());
110 WALBERLA_ASSERT_EQUAL(ySize, flag_field->ySize());
111 WALBERLA_ASSERT_EQUAL(zSize, flag_field->zSize());
112 WALBERLA_ASSERT_EQUAL(bSize, buf_size);
113#endif
114
115 auto const offset = m_lattice->get_block_corner(*receiver, true);
116 typename Boundary_T::value_type value;
117 for (auto it = begin(flag_field); it != flag_field->end(); ++it) {
118 if (isFlagSet(it, boundary_flag)) {
119 auto const node = offset + Utils::Vector3i{{it.x(), it.y(), it.z()}};
120 buffer >> value;
121 m_boundary->unpack_node(node, value);
122 }
123 }
124 }
125
126protected:
127 void packDataImpl(IBlock const *sender, stencil::Direction dir,
128 mpi::SendBuffer &buffer) const override {
129
130 auto const *flag_field = sender->getData<GhostLayerField_T>(bdId_);
131 WALBERLA_ASSERT_NOT_NULLPTR(flag_field);
132 WALBERLA_ASSERT_NOT_NULLPTR(m_boundary);
133 WALBERLA_ASSERT_NOT_NULLPTR(m_lattice);
134
135 auto const boundary_flag = flag_field->getFlag(Boundary_flag);
136 auto const gl = numberOfGhostLayersToCommunicate(flag_field);
137 auto const begin = [gl, dir](auto const *field) {
138 return field->beginSliceBeforeGhostLayer(dir, cell_idx_c(gl));
139 };
140
141#ifndef NDEBUG
142 uint_t buf_size{0u};
143 for (auto it = begin(flag_field); it != flag_field->end(); ++it) {
144 if (isFlagSet(it, boundary_flag)) {
145 ++buf_size;
146 }
147 }
148 buffer << flag_field->xSize() << flag_field->ySize() << flag_field->zSize()
149 << buf_size;
150#endif
151
152 auto const offset = m_lattice->get_block_corner(*sender, true);
153 for (auto it = begin(flag_field); it != flag_field->end(); ++it) {
154 if (isFlagSet(it, boundary_flag)) {
155 auto const node = offset + Utils::Vector3i{{it.x(), it.y(), it.z()}};
156 buffer << m_boundary->get_node_value_at_boundary(node);
157 }
158 }
159 }
160
161private:
162 std::shared_ptr<LatticeWalberla> m_lattice;
163 std::shared_ptr<Boundary_T> m_boundary;
164};
165
166} // namespace communication
167} // namespace field
168} // namespace walberla
void setup_boundary_handle(std::shared_ptr< LatticeWalberla > lattice, std::shared_ptr< Boundary_T > boundary)
void unpackData(IBlock *receiver, stencil::Direction dir, mpi::RecvBuffer &buffer) override
void packDataImpl(IBlock const *sender, stencil::Direction dir, mpi::SendBuffer &buffer) const override
void communicateLocal(IBlock const *sender, IBlock *receiver, stencil::Direction dir) override
FlagUID const Domain_flag
Flag for domain cells, i.e.
FlagUID const Boundary_flag
Flag for boundary cells.
\file PackInfoPdfDoublePrecision.cpp \author pystencils