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-2025 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
78inline Cell to_cell(signed_integral_vector auto const &xyz) {
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,
104 bool consider_ghost_layers) {
105 auto const &blocks = lattice.get_blocks();
106 auto n_ghost_layers = 0u;
107 if (consider_ghost_layers) {
108 n_ghost_layers = lattice.get_ghost_layers();
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
116 Cell local_cell;
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,
125 bool consider_ghost_layers) {
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]));
129 if (consider_ghost_layers and !block) {
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>
159 Utils::Vector3i const &lower_corner,
160 Utils::Vector3i const &upper_corner) {
161 auto const &cell_min = lower_corner;
162 auto const cell_max = upper_corner - Utils::Vector3i::broadcast(1);
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 =
170 get_min_corner(*upper_bc->block) - get_min_corner(*lower_bc->block);
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>
179 Utils::Vector3i const &lower_corner,
180 Utils::Vector3i const &upper_corner,
181 Utils::Vector3i const &block_offset, IBlock const &block) {
182 auto block_lower_corner = lattice.get_block_corner(block, true);
183 if (not(upper_corner > block_lower_corner)) {
184 return std::nullopt;
185 }
186 for (uint_t f = 0u; f < 3u; ++f) {
187 block_lower_corner[f] = std::max(block_lower_corner[f], lower_corner[f]);
188 }
189 auto block_upper_corner = lattice.get_block_corner(block, false);
190 if (not(block_upper_corner > lower_corner)) {
191 return std::nullopt;
192 }
193 for (uint_t f = 0u; f < 3u; ++f) {
194 block_upper_corner[f] = std::min(block_upper_corner[f], upper_corner[f]);
195 }
196 block_upper_corner -= Utils::Vector3i::broadcast(1);
197 auto const block_lower_cell = to_cell(block_lower_corner - block_offset);
198 auto const block_upper_cell = to_cell(block_upper_corner - block_offset);
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 */
216template <typename Kernel>
217void copy_block_buffer(CellInterval const &bci, CellInterval const &ci,
218 Utils::Vector3i const &block_offset,
219 Utils::Vector3i const &lower_corner, Kernel &&kernel) {
220 auto const local_grid = to_vector3i(ci.max() - ci.min() + Cell(1, 1, 1));
221 auto const block_grid = to_vector3i(bci.max() - bci.min() + Cell(1, 1, 1));
222 auto const lower_cell = bci.min();
223 auto const upper_cell = bci.max();
224 // In the loop, x,y,z are in block coordinates
225 // The field data given in the argument knows about BlockForest
226 // lattice indices from lower_corner to upper_corner. It is converted
227 // to block coordinates
228 for (auto x = lower_cell.x(), i = 0; x <= upper_cell.x(); ++x, ++i) {
229 for (auto y = lower_cell.y(), j = 0; y <= upper_cell.y(); ++y, ++j) {
230 for (auto z = lower_cell.z(), k = 0; z <= upper_cell.z(); ++z, ++k) {
231 auto const node = block_offset + Utils::Vector3i{{x, y, z}};
232 auto const local_index = Utils::get_linear_index(
233 node - lower_corner, local_grid, Utils::MemoryOrder::ROW_MAJOR);
234 auto const block_index = Utils::get_linear_index(
235 i, j, k, block_grid, Utils::MemoryOrder::ROW_MAJOR);
236 kernel(static_cast<unsigned>(block_index),
237 static_cast<unsigned>(local_index), node);
238 }
239 }
240 }
241}
242
243} // 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:132
static double * block(double *p, std::size_t index, std::size_t size)
Definition elc.cpp:176
Vector< T, 3 > Vector3
Definition Vector.hpp:181
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.
IBlock * get_block(::LatticeWalberla const &lattice, real_vector auto const &pos, bool consider_ghost_layers)
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)
void copy_block_buffer(CellInterval const &bci, CellInterval const &ci, Utils::Vector3i const &block_offset, Utils::Vector3i const &lower_corner, Kernel &&kernel)
Synchronize data between a sliced block and a container.
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.