ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
LBBoundaryAccess.impl.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2019-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/**
23 * @file
24 * Out-of-class boundary access definitions for
25 * @ref walberla::LBWalberlaImpl.
26 */
27
28#include <utils/Vector.hpp>
29
30#include <optional>
31#include <vector>
32
33namespace walberla {
34
35template <typename FloatType, lbmpy::Arch Architecture>
36std::optional<Utils::Vector3d>
38 Utils::Vector3i const &node, bool consider_ghosts) const {
39 assert(not(consider_ghosts and m_pending_ghost_comm.test(GhostComm::UBB)));
40 auto const bc = get_block_and_cell(get_lattice(), node, consider_ghosts);
41 if (!bc or !m_boundary->node_is_boundary(node))
42 return std::nullopt;
43
44 return {to_vector3d(m_boundary->get_node_value_at_boundary(node))};
45}
46
47template <typename FloatType, lbmpy::Arch Architecture>
49 Utils::Vector3i const &node, Utils::Vector3d const &velocity) {
50 on_boundary_add();
51 m_pending_ghost_comm.set(GhostComm::UBB);
52 auto bc = get_block_and_cell(get_lattice(), node, false);
53 if (!bc) {
54 bc = get_block_and_cell(get_lattice(), node, true);
55 }
56 if (bc) {
57 m_boundary->set_node_value_at_boundary(
59 }
60 return bc.has_value();
61}
62
63template <typename FloatType, lbmpy::Arch Architecture>
64std::vector<std::optional<Utils::Vector3d>>
67 Utils::Vector3i const &upper_corner) const {
68 std::vector<std::optional<Utils::Vector3d>> out;
70 get_lattice(), lower_corner, upper_corner,
71 [&](auto const &, auto const &bci, auto const &ci,
72 auto const &block_offset) {
73 if (out.empty())
74 out.resize(ci.numCells());
75
76 auto kernel = [&out, this](unsigned const, unsigned const local_index,
77 Utils::Vector3i const &node) {
78 if (m_boundary->node_is_boundary(node)) {
80 to_vector3d(m_boundary->get_node_value_at_boundary(node));
81 } else {
82 out[local_index] = std::nullopt;
83 }
84 };
85
87 });
88 return out;
89}
90
91template <typename FloatType, lbmpy::Arch Architecture>
94 std::vector<std::optional<Utils::Vector3d>> const &velocity) {
95 on_boundary_add();
96 m_pending_ghost_comm.set(GhostComm::UBB);
97 auto const &lattice = get_lattice();
99 lattice, lower_corner, upper_corner,
100 [&](auto &block, auto const &bci, auto const &ci,
101 auto const &block_offset) {
102 assert(velocity.size() == ci.numCells());
103
104 auto kernel = [&, this](unsigned const, unsigned const local_index,
105 Utils::Vector3i const &node) {
106 auto const bc = get_block_and_cell(lattice, node, false);
107 assert(bc->block->getAABB() == block.getAABB());
108 auto const &opt = velocity[local_index];
109 if (opt) {
110 m_boundary->set_node_value_at_boundary(
111 node, to_vector3<FloatType>(*opt), *bc);
112 } else {
113 m_boundary->remove_node_from_boundary(node, *bc);
114 }
115 };
116
118 });
119}
120
121template <typename FloatType, lbmpy::Arch Architecture>
122std::optional<Utils::Vector3d>
124 Utils::Vector3i const &node) const {
125 auto const bc = get_block_and_cell(get_lattice(), node, true);
126 if (!bc or !m_boundary->node_is_boundary(node))
127 return std::nullopt;
128
129 return get_node_last_applied_force(node, true);
130}
131
132template <typename FloatType, lbmpy::Arch Architecture>
134 Utils::Vector3i const &node) {
135 auto bc = get_block_and_cell(get_lattice(), node, false);
136 if (!bc) {
137 bc = get_block_and_cell(get_lattice(), node, true);
138 }
139 if (bc) {
140 m_boundary->remove_node_from_boundary(node, *bc);
141 }
142 return bc.has_value();
143}
144
145template <typename FloatType, lbmpy::Arch Architecture>
146std::optional<bool>
148 Utils::Vector3i const &node, bool consider_ghosts) const {
149 assert(not(consider_ghosts and m_pending_ghost_comm.test(GhostComm::UBB)));
150 auto const bc = get_block_and_cell(get_lattice(), node, consider_ghosts);
151 if (!bc)
152 return std::nullopt;
153
154 return {m_boundary->node_is_boundary(node)};
155}
156
157template <typename FloatType, lbmpy::Arch Architecture>
158std::vector<bool>
161 Utils::Vector3i const &upper_corner) const {
162 std::vector<bool> out;
164 get_lattice(), lower_corner, upper_corner,
165 [&](auto const &, auto const &bci, auto const &ci,
166 auto const &block_offset) {
167 if (out.empty())
168 out.resize(ci.numCells());
169
170 auto kernel = [&out, this](unsigned const, unsigned const local_index,
171 Utils::Vector3i const &node) {
172 out[local_index] = m_boundary->node_is_boundary(node);
173 };
174
176 });
177 return out;
178}
179
180template <typename FloatType, lbmpy::Arch Architecture>
182 m_boundary->boundary_update();
183}
184
185/**
186 * @brief Lazily enable boundary mode on first boundary addition.
187 * Switches the streaming communicator to the generic pack info,
188 * which correctly handles boundary-adjacent cells.
189 */
190template <typename FloatType, lbmpy::Arch Architecture>
192 if (not m_has_boundaries) {
193 m_has_boundaries = true;
194 setup_streaming_communicator();
195 }
196 m_has_boundaries = true;
197}
198
199template <typename FloatType, lbmpy::Arch Architecture>
201 reset_boundary_handling(get_lattice().get_blocks());
202 m_pending_ghost_comm.set(GhostComm::UBB);
203 ghost_communication();
204 m_has_boundaries = false;
205 setup_streaming_communicator();
206}
207
208/**
209 * @brief Set boundary conditions from a rasterized shape.
210 * @param raster_flat Flattened 3D mask (non-zero = boundary node).
211 * @param data_flat Flattened 3D array of slip velocities (3 components
212 * per node, same ordering as @p raster_flat).
213 */
214template <typename FloatType, lbmpy::Arch Architecture>
216 std::vector<int> const &raster_flat, std::vector<double> const &data_flat) {
217 on_boundary_add();
218 m_pending_ghost_comm.set(GhostComm::UBB);
219 auto const &grid_size = get_lattice().get_grid_dimensions();
221 set_boundary_from_grid(*m_boundary, get_lattice(), raster_flat, data);
222 ghost_communication();
223 reallocate_ubb_field();
224}
225
226/** @brief Convert a flat (row-major) index to a 3D grid coordinate. */
227template <typename FloatType, lbmpy::Arch Architecture>
230 Utils::Vector3i node({0, 0, 0});
231 auto const &grid_size = get_lattice().get_grid_dimensions();
232 node[2] = index % grid_size[2];
233 int tmp = index / grid_size[2];
234 node[1] = tmp % grid_size[1];
235 node[0] = tmp / grid_size[1];
236 return node;
237}
238
239/**
240 * @brief Get the fluid neighbor of a boundary node along stencil direction
241 * @p dir, with periodic wrapping.
242 */
243template <typename FloatType, lbmpy::Arch Architecture>
244Utils::Vector3i LBWalberlaImpl<FloatType, Architecture>::get_neighbor_node(
245 Utils::Vector3i const &node, int dir) const {
246 Utils::Vector3i neighbor({0, 0, 0});
247 auto const &grid_size = get_lattice().get_grid_dimensions();
248 auto constexpr neighbor_offset = Kernels::DynamicUBB::neighborOffset;
249 for (int i = 0; i < neighbor.size(); i++) {
250 neighbor[i] =
251 (node[i] - neighbor_offset[i][dir] + grid_size[i]) % grid_size[i];
252 }
253 return neighbor;
254}
255
256/**
257 * @brief Total force exerted by the fluid on a subset of boundary nodes.
258 * Only boundary nodes where @p raster_flat is non-zero are included.
259 * The force is accumulated from the UBB index/force vectors by matching
260 * each boundary node's stencil neighbors against the index field.
261 */
262template <typename FloatType, lbmpy::Arch Architecture>
265 std::vector<int> const &raster_flat) const {
266 Utils::Vector3d force({0, 0, 0});
267 auto const &grid_size = get_lattice().get_grid_dimensions();
268 for (auto &block : *get_lattice().get_blocks()) {
269 auto const offset = get_lattice().get_block_corner(block, true);
270 auto const &force_field = m_boundary->get_force_vector(&block);
271 auto const &index_field = m_boundary->get_index_vector(&block);
272 for (int i = 0; i < raster_flat.size(); i++) {
273 if (raster_flat[i] != 0) {
274 auto node = flat_index_to_node(i);
275 if (get_lattice().node_in_local_halo(node)) {
276 // shift node to local frame
277 node = (node - offset + grid_size) % grid_size;
278 for (int j = 0; j < index_field.size(); j++) {
279 auto neighbor_node = get_neighbor_node(node, index_field[j].dir);
280 if (index_field[j].x == neighbor_node[0] &&
281 index_field[j].y == neighbor_node[1] &&
282 index_field[j].z == neighbor_node[2]) {
283 force[0] += force_field[j].F_0;
284 force[1] += force_field[j].F_1;
285 force[2] += force_field[j].F_2;
286 }
287 }
288 }
289 }
290 }
291 }
292 return zero_centered_to_md(force);
293}
294
295template <typename FloatType, lbmpy::Arch Architecture>
298 Vector3<double> force(0.);
299 for (auto &block : *get_lattice().get_blocks()) {
300 force += m_boundary->get_total_force(&block);
301 }
302 return zero_centered_to_md(to_vector3d(force));
303}
304
305} // namespace walberla
Vector implementation and trait types for boost qvm interoperability.
DEVICE_QUALIFIER constexpr size_type size() const noexcept
Definition Array.hpp:166
Class that runs and controls the LB on waLBerla.
std::vector< std::optional< Utils::Vector3d > > get_slice_velocity_at_boundary(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner) const override
std::optional< Utils::Vector3d > get_node_velocity_at_boundary(Utils::Vector3i const &node, bool consider_ghosts=false) const override
Utils::Vector3d get_boundary_force_from_shape(std::vector< int > const &raster_flat) const override
Total force exerted by the fluid on a subset of boundary nodes.
bool remove_node_from_boundary(Utils::Vector3i const &node) override
std::optional< Utils::Vector3d > get_node_boundary_force(Utils::Vector3i const &node) const override
void set_slice_velocity_at_boundary(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner, std::vector< std::optional< Utils::Vector3d > > const &velocity) override
Utils::Vector3d get_boundary_force() const override
std::vector< bool > get_slice_is_boundary(Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner) const override
void update_boundary_from_shape(std::vector< int > const &raster_flat, std::vector< double > const &data_flat) override
Set boundary conditions from a rasterized shape.
std::optional< bool > get_node_is_boundary(Utils::Vector3i const &node, bool consider_ghosts=false) const override
void on_boundary_add()
Lazily enable boundary mode on first boundary addition.
bool set_node_velocity_at_boundary(Utils::Vector3i const &node, Utils::Vector3d const &velocity) override
cudaStream_t stream[1]
CUDA streams for parallel computing on CPU and GPU.
static double * block(double *p, std::size_t index, std::size_t size)
Definition elc.cpp:177
\file PackInfoPdfDoublePrecision.cpp \author pystencils
auto to_vector3d(Vector3< T > const &v) noexcept
void set_boundary_from_grid(BoundaryModel &boundary, LatticeWalberla const &lattice, std::vector< int > const &raster_flat, std::vector< DataType > const &data_flat)
Definition boundary.hpp:81
void copy_block_buffer(CellInterval const &bci, CellInterval const &ci, Utils::Vector3i const &block_offset, Utils::Vector3i const &lower_corner, auto &&kernel)
Synchronize data between a sliced block and a container.
void for_each_block_in_slice(::LatticeWalberla const &lattice, Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner, auto &&visitor)
Iterate over all local blocks that overlap a given 3D slice, invoking a visitor for each such block.
std::optional< BlockAndCell > get_block_and_cell(::LatticeWalberla const &lattice, signed_integral_vector auto const &node, bool consider_ghost_layers)
std::vector< Utils::Vector3d > fill_3D_vector_array(std::vector< double > const &vec_flat, Utils::Vector3i const &grid_size)
Definition boundary.hpp:36
static Utils::Vector3d velocity(Particle const &p_ref, Particle const &p_vs)
Velocity of the virtual site.
Definition relative.cpp:64