ESPResSo
Extensible Simulation Package for Research on Soft Matter Systems
Loading...
Searching...
No Matches
InterpolateAndShiftAtBoundary.hpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2021-2023 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
23
24#include <blockforest/StructuredBlockForest.h>
25#include <domain_decomposition/all.h>
26#include <stencil/D3Q19.h>
27
28#include <cmath>
29#include <functional>
30#include <memory>
31#include <stdexcept>
32#include <utility>
33
34namespace walberla {
35
36/**
37 * @brief Lees-Edwards sweep.
38 *
39 * @todo Currently is constrained by the blockforest domain decomposition.
40 * It only works if the structured block forest domain decomposition doesn't
41 * partition along the shear direction or the normal direction.
42 * The normal direction cannot be sliced, since we need full access to the
43 * sheared layer population on the opposite side of the box during the
44 * interpolation (we don't use the ghost populations).
45 * The shear direction cannot be sliced, because the ghost layer might not
46 * contain the data if the offset is larger than the ghost layer thickness.
47 *
48 * As a practical example, consider a simulation where the shear direction is
49 * the z-axis, it is possible to run on 2 MPI ranks with MPI Cartesian topology
50 * [2, 1, 1].
51 * At the moment, ESPResSo requires system.cell_system.node_grid to be in
52 * decreasing order, therefore parallelization requires a shear direction
53 * along the z-axis and a MPI node_grid of [x, y, 1] with x >= y.
54 */
55template <class FieldType, typename FloatType>
57public:
59 std::shared_ptr<StructuredBlockForest> blocks, BlockDataID field_id,
60 BlockDataID tmp_field_id, unsigned int n_ghost_layers,
61 unsigned int shear_direction, unsigned int shear_plane_normal,
62 std::function<double()> get_pos_offset,
63 std::function<double()> get_shift = []() { return 0.0; })
64 : m_blocks(std::move(blocks)), m_field_id(field_id),
65 m_tmp_field_id(tmp_field_id), m_n_ghost_layers(uint_c(n_ghost_layers)),
66 m_shear_direction(uint_c(shear_direction)),
67 m_shear_plane_normal(uint_c(shear_plane_normal)),
68 m_get_pos_offset(std::move(get_pos_offset)),
69 m_get_shift(std::move(get_shift)) {
70 if (m_n_ghost_layers != 1u) {
71 throw std::domain_error("The Lees-Edwards sweep is implemented "
72 "for a ghost layer of thickness 1");
73 }
74 if (m_shear_plane_normal == 0u) {
75 m_slab_min = stencil::W;
76 m_slab_max = stencil::E;
77 } else if (m_shear_plane_normal == 1u) {
78 m_slab_min = stencil::S;
79 m_slab_max = stencil::N;
80 } else if (m_shear_plane_normal == 2u) {
81 m_slab_min = stencil::B;
82 m_slab_max = stencil::T;
83 }
84 }
85
86 FloatType get_pos_offset() const {
87 return numeric_cast<FloatType>(m_get_pos_offset());
88 }
89
90 FloatType get_shift() const { return numeric_cast<FloatType>(m_get_shift()); }
91
92 void operator()(IBlock *block) {
93 kernel(block, m_slab_min);
94 kernel(block, m_slab_max);
95 }
96
97private:
98 void kernel(IBlock *block, stencil::Direction slab_dir) {
99 // setup lengths
100 assert(m_blocks->getNumberOfCells(*block, m_shear_plane_normal) >= 2u);
101 auto const dir = m_shear_direction;
102 auto const dim = cell_idx_c(m_blocks->getNumberOfCells(*block, dir));
103 auto const length = numeric_cast<FloatType>(dim);
104
105 // setup slab
106 auto field = block->template getData<FieldType>(m_field_id);
107 auto tmp_field = block->template getData<FieldType>(m_tmp_field_id);
108
109 CellInterval ci;
110 field->getGhostRegion(slab_dir, ci, cell_idx_t{1}, true);
111
112 // shift
113 auto const shift = get_shift();
114 // Note that the offset is applied to the interpolation source rather than
115 // the target
116 auto const prefactor =
117 ((slab_dir == m_slab_max) ? FloatType{-1} : FloatType{1});
118 auto const offset = static_cast<FloatType>(get_pos_offset()) * prefactor;
119 auto const folded_offset = modulo(offset, length);
120 // 0<=folded_offset<length
121 auto const weight1 = FloatType{1} - std::fmod(folded_offset, FloatType{1});
122 auto const weight2 = std::fmod(folded_offset, FloatType{1});
123 for (auto const &&cell : ci) {
124 Cell source1 = cell;
125 Cell source2 = cell;
126 auto const source_pos = static_cast<FloatType>(cell[dir]) + folded_offset;
127 auto const folded_source_pos = modulo(source_pos, length);
128 // 0 <= folded_source_pos < length
129 source1[dir] = cell_idx_c(std::floor(folded_source_pos));
130 // 0 <= source1[dir] < length, i.e. integer value up to length-1 inclusive
131 source2[dir] = cell_idx_c(modulo(FloatType(source1[dir] + 1), length));
132 // integer value between 0 and length -1 inclusive
133 for (uint_t q = 0u; q < FieldType::F_SIZE; ++q) {
134 tmp_field->get(cell, q) =
135 field->get(source1, q) * weight1 + field->get(source2, q) * weight2;
136 }
137 tmp_field->get(cell, m_shear_direction) -= prefactor * shift;
138 }
139
140 // swap
141 for (auto const &&cell : ci) {
142 for (uint_t f = 0; f < FieldType::F_SIZE; ++f) {
143 field->get(cell, f) = tmp_field->get(cell, f);
144 }
145 }
146 }
147
148 FloatType modulo(FloatType a, FloatType b) const {
149 auto const res = std::fmod(a, b);
150 return (res < FloatType{0}) ? res + b : res;
151 }
152
153private:
154 std::shared_ptr<StructuredBlockForest> m_blocks;
155 BlockDataID m_field_id;
156 BlockDataID m_tmp_field_id;
157 uint_t m_n_ghost_layers;
158 uint_t m_shear_direction;
159 uint_t m_shear_plane_normal;
160 std::function<double()> m_get_pos_offset;
161 std::function<double()> m_get_shift;
162 stencil::Direction m_slab_min;
163 stencil::Direction m_slab_max;
164};
165
166} // namespace walberla
Definition Cell.hpp:97
InterpolateAndShiftAtBoundary(std::shared_ptr< StructuredBlockForest > blocks, BlockDataID field_id, BlockDataID tmp_field_id, unsigned int n_ghost_layers, unsigned int shear_direction, unsigned int shear_plane_normal, std::function< double()> get_pos_offset, std::function< double()> get_shift=[]() { return 0.0;})
static double * block(double *p, std::size_t index, std::size_t size)
Definition elc.cpp:172
\file PackInfoPdfDoublePrecision.cpp \author pystencils