ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
BlockAndCell.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2020-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 <blockforest/StructuredBlockForest.h>
23#include <core/DataTypes.h>
24#include <core/cell/Cell.h>
25#include <domain_decomposition/IBlock.h>
26#include <utils/Vector.hpp>
27#include <utils/index.hpp>
28
29#include "../src/utils/types_conversion.hpp"
30#include "LatticeWalberla.hpp"
31
32#include <array>
33#include <cmath>
34#include <concepts>
35#include <memory>
36#include <optional>
37#include <type_traits>
38
39namespace detail {
40template <typename T> struct is_real_vector : std::false_type {};
41
42template <std::floating_point T>
43struct is_real_vector<std::array<T, 3>> : std::true_type {};
44
45template <std::floating_point T>
46struct is_real_vector<walberla::Vector3<T>> : std::true_type {};
47
48template <std::floating_point T>
49struct is_real_vector<Utils::Vector<T, 3>> : std::true_type {};
50} // namespace detail
51
52template <typename T>
53concept real_vector = detail::is_real_vector<T>::value;
54
55namespace detail {
56template <typename T> struct is_signed_integral_vector : std::false_type {};
57
58template <std::signed_integral T>
59struct is_signed_integral_vector<std::array<T, 3>> : std::true_type {};
60
61template <std::signed_integral T>
62struct is_signed_integral_vector<walberla::Vector3<T>> : std::true_type {};
63
64template <std::signed_integral T>
65struct is_signed_integral_vector<Utils::Vector<T, 3>> : std::true_type {};
66
67template <> struct is_signed_integral_vector<walberla::Cell> : std::true_type {
68 static_assert(std::integral<walberla::cell_idx_t> and
69 std::is_signed_v<walberla::cell_idx_t>);
70};
71} // namespace detail
72
73template <typename T>
74concept signed_integral_vector = detail::is_signed_integral_vector<T>::value;
75
76namespace walberla {
77
79 return {xyz[0], xyz[1], xyz[2]};
80}
81
83 IBlock *block;
85};
86
87IBlock *get_block_extended(LatticeWalberla const &lattice, auto const &pos,
88 unsigned int n_ghost_layers) {
89 auto const &cached_blocks = lattice.get_cached_blocks();
90 for (auto &block : cached_blocks) {
91 if (block->getAABB()
92 .getExtended(real_c(n_ghost_layers))
93 .contains(real_c(pos[0]), real_c(pos[1]), real_c(pos[2]))) {
94 return &(*block);
95 }
96 }
97 // Cell not in local blocks
98 return nullptr;
99}
100
101inline std::optional<BlockAndCell>
103 signed_integral_vector auto const &node,
105 auto const &blocks = lattice.get_blocks();
106 auto n_ghost_layers = 0u;
109 }
110
111 auto block = get_block_extended(lattice, node, n_ghost_layers);
112 if (!block)
113 return std::nullopt;
114
115 // Transform coords to block local
117
118 Cell global_cell = to_cell(node);
119 blocks->transformGlobalToBlockLocalCell(local_cell, *block, global_cell);
120 return {{block, local_cell}};
121}
122
123inline IBlock *get_block(::LatticeWalberla const &lattice,
124 real_vector auto const &pos,
126 // Get block
127 auto const blocks = lattice.get_blocks();
128 auto block = blocks->getBlock(real_c(pos[0]), real_c(pos[1]), real_c(pos[2]));
130 block = get_block_extended(lattice, pos, lattice.get_ghost_layers());
131 }
132 return block;
133}
134
135/**
136 * @brief Get the block-local coordinates of a block corner.
137 *
138 * This method leverages the fact that the grid spacing is unity in LB units,
139 * i.e. floating-point coordinates can be cast to integers indices.
140 */
141inline auto convert_cell_corner_to_coord(real_vector auto const &corner) {
142 return Utils::Vector3i{{static_cast<int>(std::round(corner[0])),
143 static_cast<int>(std::round(corner[1])),
144 static_cast<int>(std::round(corner[2]))}};
145}
146
147/** @brief Get the block-local coordinates of the lower corner of a block. */
148inline auto get_min_corner(IBlock const &block) {
149 return convert_cell_corner_to_coord(block.getAABB().minCorner());
150}
151
152/** @brief Get the block-local coordinates of the upper corner of a block. */
153inline auto get_max_corner(IBlock const &block) {
154 return convert_cell_corner_to_coord(block.getAABB().maxCorner());
155}
156
157[[nodiscard]] inline std::optional<walberla::cell::CellInterval>
161 auto const &cell_min = lower_corner;
163 auto const lower_bc = get_block_and_cell(lattice, cell_min, true);
164 auto const upper_bc = get_block_and_cell(lattice, cell_max, true);
165 if (not lower_bc or not upper_bc) {
166 return std::nullopt;
167 }
168
169 auto const block_extent =
171 auto const global_lower_cell = lower_bc->cell;
172 auto const global_upper_cell = upper_bc->cell + to_cell(block_extent);
173 return {CellInterval(global_lower_cell, global_upper_cell)};
174}
175
176// Interval within local block
177[[nodiscard]] inline std::optional<walberla::cell::CellInterval>
181 Utils::Vector3i const &block_offset, IBlock const &block) {
182 auto block_lower_corner = lattice.get_block_corner(block, true);
184 return std::nullopt;
185 }
186 for (uint_t f = 0u; f < 3u; ++f) {
188 }
189 auto block_upper_corner = lattice.get_block_corner(block, false);
191 return std::nullopt;
192 }
193 for (uint_t f = 0u; f < 3u; ++f) {
195 }
199 return {CellInterval(block_lower_cell, block_upper_cell)};
200}
201
202/**
203 * @brief Synchronize data between a sliced block and a container.
204 *
205 * Synchronize data between two data buffers representing sliced matrices
206 * with different memory layouts. The kernel takes as argument an index
207 * for the flattened data buffer containing the serialized block slice,
208 * an index for the flattened I/O buffer, and a block-local node position.
209 *
210 * @param bci Cell interval of the local block within a 3D slice
211 * @param ci Cell interval of the entire lattice within a 3D slice
212 * @param block_offset Origin of the local block
213 * @param lower_corner Lower corner of the 3D slice
214 * @param kernel Function to execute on the two data buffers
215 */
216void copy_block_buffer(CellInterval const &bci, CellInterval const &ci,
218 Utils::Vector3i const &lower_corner, auto &&kernel) {
219 auto const local_grid = to_vector3i(ci.max() - ci.min() + Cell(1, 1, 1));
220 auto const block_grid = to_vector3i(bci.max() - bci.min() + Cell(1, 1, 1));
221 auto const lower_cell = bci.min();
222 auto const upper_cell = bci.max();
223 // In the loop, x,y,z are in block coordinates
224 // The field data given in the argument knows about BlockForest
225 // lattice indices from lower_corner to upper_corner. It is converted
226 // to block coordinates
227 for (auto x = lower_cell.x(), i = 0; x <= upper_cell.x(); ++x, ++i) {
228 for (auto y = lower_cell.y(), j = 0; y <= upper_cell.y(); ++y, ++j) {
229 for (auto z = lower_cell.z(), k = 0; z <= upper_cell.z(); ++z, ++k) {
230 auto const node = block_offset + Utils::Vector3i{{x, y, z}};
235 kernel(static_cast<unsigned>(block_index),
236 static_cast<unsigned>(local_index), node);
237 }
238 }
239 }
240}
241
242/**
243 * @brief Iterate over all local blocks that overlap a given 3D slice,
244 * invoking a visitor for each such block.
245 *
246 * This encapsulates the common boilerplate shared by every
247 * @c get_slice_* / @c set_slice_* method in LB and EK.
248 *
249 * @param lattice The lattice
250 * @param lower_corner Lower corner of the 3D slice (inclusive)
251 * @param upper_corner Upper corner of the 3D slice (exclusive)
252 * @param visitor Callable with signature
253 * <tt>(IBlock &block, CellInterval const &bci,
254 * CellInterval const &ci, Utils::Vector3i const &block_offset)</tt>
255 */
259 auto &&visitor) {
260 if (auto const ci = get_interval(lattice, lower_corner, upper_corner)) {
261 for (auto &block : *lattice.get_blocks()) {
262 auto const block_offset = lattice.get_block_corner(block, true);
263 if (auto const bci = get_block_interval(
266 }
267 }
268 }
269}
270
271} // namespace walberla
Vector implementation and trait types for boost qvm interoperability.
Definition Cell.hpp:96
Class that runs and controls the BlockForest in waLBerla.
Utils::Vector3i get_block_corner(IBlock const &block, bool lower) const
static DEVICE_QUALIFIER constexpr Vector< T, N > broadcast(typename Base::value_type const &value) noexcept
Create a vector that has all entries set to the same value.
Definition Vector.hpp:131
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
Vector< T, 3 > Vector3
Definition Vector.hpp:180
int get_linear_index(int a, int b, int c, const Vector3i &adim)
Definition index.hpp:35
STL namespace.
\file PackInfoPdfDoublePrecision.cpp \author pystencils
IBlock * get_block_extended(LatticeWalberla const &lattice, auto const &pos, unsigned int n_ghost_layers)
auto convert_cell_corner_to_coord(real_vector auto const &corner)
Get the block-local coordinates of a block corner.
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.
IBlock * get_block(::LatticeWalberla const &lattice, real_vector auto const &pos, bool consider_ghost_layers)
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)
auto get_min_corner(IBlock const &block)
Get the block-local coordinates of the lower corner of a block.
Cell to_cell(signed_integral_vector auto const &xyz)
std::optional< walberla::cell::CellInterval > get_block_interval(::LatticeWalberla const &lattice, Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner, Utils::Vector3i const &block_offset, IBlock const &block)
Utils::Vector3i to_vector3i(Vector3< int > const &v) noexcept
std::optional< walberla::cell::CellInterval > get_interval(::LatticeWalberla const &lattice, Utils::Vector3i const &lower_corner, Utils::Vector3i const &upper_corner)
auto get_max_corner(IBlock const &block)
Get the block-local coordinates of the upper corner of a block.