OpenLB 1.8.1
Loading...
Searching...
No Matches
blockCommunicationNeighborhood.hh
Go to the documentation of this file.
1/* This file is part of the OpenLB library
2 *
3 * Copyright (C) 2020 Adrian Kummerlaender
4 * E-mail contact: info@openlb.net
5 * The most recent release of OpenLB can be downloaded at
6 * <http://www.openlb.net/>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this program; if not, write to the Free
20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22*/
23
24#ifndef BLOCK_COMMUNICATION_NEIGHBORHOOD_HH
25#define BLOCK_COMMUNICATION_NEIGHBORHOOD_HH
26
27#include <stdexcept>
28#include <algorithm>
29
31
32#include "utilities/aliases.h"
33
34namespace olb {
35
36// *INDENT-OFF*
37
38template <typename T, unsigned D>
40 CuboidDecomposition<T,D>& cuboidDecomposition
41 , LoadBalancer<T>& loadBalancer
42 , int iC
43 , int padding
44#ifdef PARALLEL_MODE_MPI
45 , MPI_Comm comm
46#endif
47):
48 _cuboidDecomposition(cuboidDecomposition)
49 , _loadBalancer(loadBalancer)
50 , _iC(iC)
51 , _padding(padding)
52#ifdef PARALLEL_MODE_MPI
53 , _neighborhoodComm(comm)
54#endif
55{
56 // Ensure that any neighboring cuboids are interacted with during request negotiation
58 for (auto& [_, cells] : _cellsInboundFrom) {
59 cells.clear();
60 }
61 for (auto& [_, cells] : _cellsRequestedFrom) {
62 cells.clear();
63 }
64}
65
66template <typename T, unsigned D>
68{
69 const auto& cuboid = _cuboidDecomposition.get(_iC);
70 BlockStructureD<D> paddedBlock(cuboid.getExtent(), _padding);
71 if (paddedBlock.isPadding(latticeR)) {
72 // Read physR using global cuboid geometry instead of local cuboid
73 // to resolve periodic boundaries
74 auto physR = _cuboidDecomposition.getPhysR(latticeR.withPrefix(_iC));
75 if (auto remoteLatticeR = _cuboidDecomposition.getLatticeR(physR)) {
76 _cellsInboundFrom[(*remoteLatticeR)[0]].emplace_back(paddedBlock.getCellId(latticeR));
77
78 const auto& remoteCuboid = _cuboidDecomposition.get((*remoteLatticeR)[0]);
79 BlockStructureD<D> remotePaddedBlock(remoteCuboid.getExtent(), _padding);
80
81 _cellsRequestedFrom[(*remoteLatticeR)[0]].emplace_back(
82 remotePaddedBlock.getCellId(&(*remoteLatticeR)[1]));
83 }
84 } else {
85 throw std::logic_error("Requested cell is outside of available padding");
86 }
87}
88
89template <typename T, unsigned D>
91{
92 if (width < 1) {
93 throw std::logic_error("Overlap requests must have width >= 1");
94 }
95 if (width > _padding) {
96 throw std::logic_error("Requested overlap exceeds available padding");
97 }
98
99 const auto& cuboid = _cuboidDecomposition.get(_iC);
100 BlockStructureD<D> overlapBlock(cuboid.getExtent(), width);
101
102 overlapBlock.forSpatialLocations([&](LatticeR<D> latticeR) {
103 if (overlapBlock.isPadding(latticeR)) {
104 requestCell(latticeR);
105 }
106 });
107}
109template <typename T, unsigned D>
112 if (width < 1) {
113 throw std::logic_error("Overlap requests must have width >= 1");
114 }
115 if (width > _padding) {
116 throw std::logic_error("Requested overlap exceeds available padding");
117 }
118
119 const auto& cuboid = _cuboidDecomposition.get(_iC);
120 BlockStructureD<D> overlapBlock(cuboid.getExtent(), width);
121
122 overlapBlock.forSpatialLocations([&](LatticeR<D> latticeR) {
123 if (overlapBlock.isPadding(latticeR) && indicatorF(latticeR)) {
124 requestCell(latticeR);
125 }
126 });
129template <typename T, unsigned D>
131{
132 _cellsInboundFrom.clear();
133 _cellsOutboundTo.clear();
134 _cellsRequestedFrom.clear();
135}
136
137template <typename T, unsigned D>
138void BlockCommunicationNeighborhood<T,D>::setFieldAvailability(std::type_index field, bool available)
139{
140 auto iter = std::find(_fieldsRequested.begin(), _fieldsRequested.end(), field);
141 if (iter != _fieldsRequested.end()) {
142 _fieldsAvailable[iter - _fieldsRequested.begin()] = available;
143 }
144}
145
146template <typename T, unsigned D>
147template <typename BLOCK>
149{
150 auto& fieldsCommonWith = _fieldsCommonWith[iC];
151 fieldsCommonWith.clear();
152 for (unsigned iField=0; iField < _fieldsRequested.size(); ++iField) {
153 auto field = _fieldsRequested[iField];
154 if (block.hasCommunicatable(field) && _fieldsAvailable[iField]) {
155 fieldsCommonWith.emplace_back(field);
156 }
157 }
158}
159
160template <typename T, unsigned D>
162{
163 for (auto& [iC, _] : _cellsInboundFrom) {
164 auto& iCells = _cellsInboundFrom[iC];
165 auto& oCells = _cellsRequestedFrom[iC];
166 // Compute sorted indices w.r.t. cell IDs in iCells
167 std::vector<std::ptrdiff_t> p(iCells.size());
168 std::iota(p.begin(), p.end(), 0);
169 std::sort(p.begin(), p.end(), [&iCells](auto i, auto j) { return iCells[i] < iCells[j]; });
170 // Reduce indices to only include unique values of iCells
171 auto pu = std::unique(p.begin(), p.end(), [&iCells](auto i, auto j) { return iCells[i] == iCells[j]; });
172 p.erase(pu, p.end());
173 // Copy cell IDs at computed indices to new in and out lists
174 {
175 std::vector<CellID> buffer(p.size());
176 std::transform(p.begin(), p.end(), buffer.begin(), [&iCells](auto i) { return iCells[i]; });
177 iCells = buffer;
178 }
179 {
180 std::vector<CellID> buffer(p.size());
181 std::transform(p.begin(), p.end(), buffer.begin(), [&oCells](auto i) { return oCells[i]; });
182 oCells = buffer;
183 }
184 }
185}
186
187#ifdef PARALLEL_MODE_MPI
188
189template <typename T, unsigned D>
191{
192 for (auto& [iC, cells] : _cellsRequestedFrom) {
193 _fieldRequests[iC] = std::make_unique<MpiSendRequest>(
194 _fieldsAvailable.data(), _fieldsRequested.size(),
195 _loadBalancer.rank(iC), coordinator.get(_iC, iC, 0), _neighborhoodComm);
196 _fieldRequests[iC]->start();
197
198 _cellsRequests[iC] = std::make_unique<MpiSendRequest>(
199 cells.data(), cells.size(),
200 _loadBalancer.rank(iC), coordinator.get(_iC, iC, 1), _neighborhoodComm);
201 _cellsRequests[iC]->start();
202 }
203}
204
205template <typename T, unsigned D>
207{
208 forNeighbors([&](int iC) {
209 std::unique_ptr<bool[]> fieldsAvailable(new bool[_fieldsRequested.size()] { });
210 auto& fieldsCommonWith = _fieldsCommonWith[iC];
211 fieldsCommonWith.clear();
212
214 fieldsAvailable.get(), _fieldsRequested.size(),
215 _loadBalancer.rank(iC),
216 coordinator.get(iC, _iC, 0),
217 _neighborhoodComm);
218
219 for (unsigned iField=0; iField < _fieldsRequested.size(); ++iField) {
220 if (fieldsAvailable[iField] && _fieldsAvailable[iField]) {
221 fieldsCommonWith.emplace_back(_fieldsRequested[iField]);
222 }
223 }
224
225 static_assert(sizeof(CellID) == 4 || sizeof(CellID) == 8,
226 "CellID must be either 4 or 8 byte unsigned integer");
227 std::size_t newOutboundCount = singleton::mpi().probeReceiveSize<CellID>(_loadBalancer.rank(iC),
228 coordinator.get(iC, _iC, 1),
229 _neighborhoodComm);
230 _cellsOutboundTo[iC].resize(newOutboundCount);
231
233 _cellsOutboundTo[iC].data(),
234 _cellsOutboundTo[iC].size(),
235 _loadBalancer.rank(iC),
236 coordinator.get(iC, _iC, 1),
237 _neighborhoodComm);
238 });
239}
240
241template <typename T, unsigned D>
243{
244 forNeighbors([&](int iC) {
245 _fieldRequests[iC]->wait();
246 _cellsRequests[iC]->wait();
247 });
248}
249
250#endif // PARALLEL_MODE_MPI
251
252template <typename T, unsigned D>
253const std::vector<std::type_index>&
255{
256 return _fieldsCommonWith.at(iC);
257}
258
259template <typename T, unsigned D>
260const std::vector<CellID>&
262{
263 return _cellsOutboundTo.at(iC);
264}
265
266template <typename T, unsigned D>
267const std::vector<CellID>&
269{
270 return _cellsInboundFrom.at(iC);
271}
272
273template <typename T, unsigned D>
274const std::vector<CellID>&
276{
277 return _cellsRequestedFrom.at(iC);
278}
279
280// *INDENT-ON*
281
282}
283
284#endif
void requestOverlap(int width)
Request all cells in overlap of size width for communication.
const std::vector< CellID > & getCellsRequestedFrom(int iC) const
const std::vector< CellID > & getCellsOutboundTo(int iC) const
const std::vector< std::type_index > & getFieldsCommonWith(int iC) const
const std::vector< CellID > & getCellsInboundFrom(int iC) const
void setFieldsAvailability(int iC, BLOCK &block)
Update outbound availabilities for locally available neighbor block.
void receive(SuperCommunicationTagCoordinator< T > &)
void clearRequestedCells()
Remove all requested cells.
void requestCell(LatticeR< D > latticeR)
Request individual cell for communication.
void send(SuperCommunicationTagCoordinator< T > &)
void setFieldAvailability(std::type_index field, bool available)
Update local availability of previously requested field.
BlockCommunicationNeighborhood(CuboidDecomposition< T, D > &cuboidDecomposition, LoadBalancer< T > &loadBalancer, int iC, int padding, MPI_Comm comm)
Base of a regular block.
bool isPadding(LatticeR< D > latticeR) const
Return whether location is valid.
CellID getCellId(LatticeR< D > latticeR) const
Get 1D cell ID.
Decomposition of a physical volume into a set of disjoint cuboids.
Base class for all LoadBalancer.
Definition vtiWriter.h:42
Communication-free negotation of unique tags for inter-cuboid communication.
int get(int iC, int jC, int iGroup=0)
Returns unique tag for communication between cuboids iC and jC.
Plain old scalar vector.
constexpr Vector< T, D+1 > withPrefix(T prefix) const any_platform
Return new (prefix,this...) vector.
Definition vector.h:198
std::size_t probeReceiveSize(int source, MPI_Datatype type, int tag=0, MPI_Comm comm=MPI_COMM_WORLD)
Probe size of incoming message.
void receive(T *buf, int count, int source, int tag=0, MPI_Comm comm=MPI_COMM_WORLD)
Receives data at *buf, blocking.
MpiManager & mpi()
Top level namespace for all of OpenLB.
std::uint32_t CellID
Type for sequential block-local cell indices.
std::conditional_t< D==2, BlockIndicatorF2D< T >, BlockIndicatorF3D< T > > BlockIndicatorF
Definition aliases.h:207
Vector< std::int32_t, D > LatticeR
Type for spatial block-local lattice coordinates.