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 * Lees-Edwards sweep.
38 * @todo Currently only works for 1 MPI rank! It should work in parallel if the
39 * MPI domain decomposition for the structured block forest doesn't partition
40 * along the shear direction. For example if the shear direction goes along
41 * the z-axis, it should be possible to run on 4 MPI ranks with [2, 2, 1].
42 * At the moment, ESPResSo requires system.cell_system.node_grid to be in
43 * decreasing order, therefore parallelization requires a shear direction
44 * along the z-axis and a MPI node_grid of [x, y, 1] with x >= y. This
45 * restriction on the ordering of the node_grid may be lifted in the
46 * distant future, when our FFT algorithm is replaced by a new one.
47 */
48template <class FieldType, typename FloatType>
50public:
52 std::shared_ptr<StructuredBlockForest> blocks, BlockDataID field_id,
53 BlockDataID tmp_field_id, unsigned int n_ghost_layers,
54 unsigned int shear_direction, unsigned int shear_plane_normal,
55 std::function<double()> get_pos_offset,
56 std::function<double()> get_shift = []() { return 0.0; })
57 : m_blocks(std::move(blocks)), m_field_id(field_id),
58 m_tmp_field_id(tmp_field_id), m_n_ghost_layers(uint_c(n_ghost_layers)),
59 m_shear_direction(uint_c(shear_direction)),
60 m_shear_plane_normal(uint_c(shear_plane_normal)),
61 m_get_pos_offset(std::move(get_pos_offset)),
62 m_get_shift(std::move(get_shift)) {
63 if (m_n_ghost_layers != 1u) {
64 throw std::domain_error("The Lees-Edwards sweep is implemented "
65 "for a ghost layer of thickness 1");
66 }
67 if (m_shear_plane_normal == 0u) {
68 m_slab_min = stencil::W;
69 m_slab_max = stencil::E;
70 } else if (m_shear_plane_normal == 1u) {
71 m_slab_min = stencil::S;
72 m_slab_max = stencil::N;
73 } else if (m_shear_plane_normal == 2u) {
74 m_slab_min = stencil::B;
75 m_slab_max = stencil::T;
76 }
77 }
78
79 FloatType get_pos_offset() const {
80 return numeric_cast<FloatType>(m_get_pos_offset());
81 }
82
83 FloatType get_shift() const { return numeric_cast<FloatType>(m_get_shift()); }
84
85 void operator()(IBlock *block) {
86 kernel(block, m_slab_min);
87 kernel(block, m_slab_max);
88 }
89
90private:
91 void kernel(IBlock *block, stencil::Direction slab_dir) {
92 // setup lengths
93 assert(m_blocks->getNumberOfCells(*block, m_shear_plane_normal) >= 2u);
94 auto const dir = m_shear_direction;
95 auto const dim = cell_idx_c(m_blocks->getNumberOfCells(*block, dir));
96 auto const length = numeric_cast<FloatType>(dim);
97
98 // setup slab
99 auto field = block->template getData<FieldType>(m_field_id);
100 auto tmp_field = block->template getData<FieldType>(m_tmp_field_id);
101
102 CellInterval ci;
103 field->getGhostRegion(slab_dir, ci, cell_idx_t{1}, true);
104
105 // shift
106 auto const shift = get_shift();
107 // Note that the offset is applied to the interpolation source rather than
108 // the target
109 auto const prefactor =
110 ((slab_dir == m_slab_max) ? FloatType{-1} : FloatType{1});
111 auto const offset = static_cast<FloatType>(get_pos_offset()) * prefactor;
112 auto const folded_offset = modulo(offset, length);
113 // 0<=folded_offset<length
114 auto const weight1 = FloatType{1} - std::fmod(folded_offset, FloatType{1});
115 auto const weight2 = std::fmod(folded_offset, FloatType{1});
116 for (auto const &&cell : ci) {
117 Cell source1 = cell;
118 Cell source2 = cell;
119 auto const source_pos = static_cast<FloatType>(cell[dir]) + folded_offset;
120 auto const folded_source_pos = modulo(source_pos, length);
121 // 0 <= folded_source_pos < length
122 source1[dir] = cell_idx_c(std::floor(folded_source_pos));
123 // 0 <= source1[dir] < length, i.e. integer value up to length-1 inclusive
124 source2[dir] = cell_idx_c(modulo(FloatType(source1[dir] + 1), length));
125 // integer value between 0 and length -1 inclusive
126 for (uint_t q = 0u; q < FieldType::F_SIZE; ++q) {
127 tmp_field->get(cell, q) =
128 field->get(source1, q) * weight1 + field->get(source2, q) * weight2;
129 }
130 tmp_field->get(cell, m_shear_direction) -= prefactor * shift;
131 }
132
133 // swap
134 for (auto const &&cell : ci) {
135 for (uint_t f = 0; f < FieldType::F_SIZE; ++f) {
136 field->get(cell, f) = tmp_field->get(cell, f);
137 }
138 }
139 }
140
141 FloatType modulo(FloatType a, FloatType b) const {
142 auto const res = std::fmod(a, b);
143 return (res < FloatType{0}) ? res + b : res;
144 }
145
146private:
147 std::shared_ptr<StructuredBlockForest> m_blocks;
148 BlockDataID m_field_id;
149 BlockDataID m_tmp_field_id;
150 uint_t m_n_ghost_layers;
151 uint_t m_shear_direction;
152 uint_t m_shear_plane_normal;
153 std::function<double()> m_get_pos_offset;
154 std::function<double()> m_get_shift;
155 stencil::Direction m_slab_min;
156 stencil::Direction m_slab_max;
157};
158
159} // 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