OpenLB 1.7
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 CuboidGeometry<T,D>& cuboidGeometry
41 , LoadBalancer<T>& loadBalancer
42 , int iC
43 , int padding
44#ifdef PARALLEL_MODE_MPI
45 , MPI_Comm comm
46#endif
47):
48 _cuboidGeometry(cuboidGeometry)
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 auto& cuboid = _cuboidGeometry.get(_iC);
70 BlockStructureD<D> paddedBlock(cuboid.getExtent(), _padding);
71 if (paddedBlock.isPadding(latticeR)) {
72 T physR[D];
73 // Read physR using global cuboid geometry instead of local cuboid
74 // to resolve periodic boundaries
75 _cuboidGeometry.getPhysR(physR, latticeR.withPrefix(_iC));
76 int remoteLatticeR[D+1];
77 if (_cuboidGeometry.getLatticeR(remoteLatticeR, physR)) {
78 _cellsInboundFrom[remoteLatticeR[0]].emplace_back(paddedBlock.getCellId(latticeR));
79
80 Cuboid<T,D>& remoteCuboid = _cuboidGeometry.get(remoteLatticeR[0]);
81 BlockStructureD<D> remotePaddedBlock(remoteCuboid.getExtent(), _padding);
82
83 _cellsRequestedFrom[remoteLatticeR[0]].emplace_back(
84 remotePaddedBlock.getCellId(remoteLatticeR+1));
85 }
86 } else {
87 throw std::logic_error("Requested cell is outside of available padding");
88 }
89}
91template <typename T, unsigned D>
93{
94 if (width < 1) {
95 throw std::logic_error("Overlap requests must have width >= 1");
96 }
97 if (width > _padding) {
98 throw std::logic_error("Requested overlap exceeds available padding");
99 }
101 auto& cuboid = _cuboidGeometry.get(_iC);
102 BlockStructureD<D> overlapBlock(cuboid.getExtent(), width);
103
104 overlapBlock.forSpatialLocations([&](LatticeR<D> latticeR) {
105 if (overlapBlock.isPadding(latticeR)) {
106 requestCell(latticeR);
107 }
108 });
109}
110
111template <typename T, unsigned D>
114 if (width < 1) {
115 throw std::logic_error("Overlap requests must have width >= 1");
116 }
117 if (width > _padding) {
118 throw std::logic_error("Requested overlap exceeds available padding");
119 }
120
121 auto& cuboid = _cuboidGeometry.get(_iC);
122 BlockStructureD<D> overlapBlock(cuboid.getExtent(), width);
123
124 overlapBlock.forSpatialLocations([&](LatticeR<D> latticeR) {
125 if (overlapBlock.isPadding(latticeR) && indicatorF(latticeR)) {
126 requestCell(latticeR);
128 });
129}
130
131template <typename T, unsigned D>
133{
134 _cellsInboundFrom.clear();
135 _cellsOutboundTo.clear();
136 _cellsRequestedFrom.clear();
137}
138
139template <typename T, unsigned D>
140void BlockCommunicationNeighborhood<T,D>::setFieldAvailability(std::type_index field, bool available)
141{
142 auto iter = std::find(_fieldsRequested.begin(), _fieldsRequested.end(), field);
143 if (iter != _fieldsRequested.end()) {
144 _fieldsAvailable[iter - _fieldsRequested.begin()] = available;
145 }
146}
147
148template <typename T, unsigned D>
149template <typename BLOCK>
151{
152 auto& fieldsCommonWith = _fieldsCommonWith[iC];
153 fieldsCommonWith.clear();
154 for (unsigned iField=0; iField < _fieldsRequested.size(); ++iField) {
155 auto field = _fieldsRequested[iField];
156 if (block.hasCommunicatable(field) && _fieldsAvailable[iField]) {
157 fieldsCommonWith.emplace_back(field);
158 }
159 }
160}
161
162template <typename T, unsigned D>
164{
165 for (auto& [iC, _] : _cellsInboundFrom) {
166 auto& iCells = _cellsInboundFrom[iC];
167 auto& oCells = _cellsRequestedFrom[iC];
168 // Compute sorted indices w.r.t. cell IDs in iCells
169 std::vector<std::ptrdiff_t> p(iCells.size());
170 std::iota(p.begin(), p.end(), 0);
171 std::sort(p.begin(), p.end(), [&iCells](auto i, auto j) { return iCells[i] < iCells[j]; });
172 // Reduce indices to only include unique values of iCells
173 auto pu = std::unique(p.begin(), p.end(), [&iCells](auto i, auto j) { return iCells[i] == iCells[j]; });
174 p.erase(pu, p.end());
175 // Copy cell IDs at computed indices to new in and out lists
176 {
177 std::vector<CellID> buffer(p.size());
178 std::transform(p.begin(), p.end(), buffer.begin(), [&iCells](auto i) { return iCells[i]; });
179 iCells = buffer;
180 }
181 {
182 std::vector<CellID> buffer(p.size());
183 std::transform(p.begin(), p.end(), buffer.begin(), [&oCells](auto i) { return oCells[i]; });
184 oCells = buffer;
185 }
186 }
187}
188
189#ifdef PARALLEL_MODE_MPI
190
191template <typename T, unsigned D>
193{
194 for (auto& [iC, cells] : _cellsRequestedFrom) {
195 _fieldRequests[iC] = std::make_unique<MpiSendRequest>(
196 _fieldsAvailable.data(), _fieldsRequested.size(),
197 _loadBalancer.rank(iC), coordinator.get(_iC, iC, 0), _neighborhoodComm);
198 _fieldRequests[iC]->start();
199
200 _cellsRequests[iC] = std::make_unique<MpiSendRequest>(
201 cells.data(), cells.size(),
202 _loadBalancer.rank(iC), coordinator.get(_iC, iC, 1), _neighborhoodComm);
203 _cellsRequests[iC]->start();
204 }
205}
206
207template <typename T, unsigned D>
209{
210 forNeighbors([&](int iC) {
211 std::unique_ptr<bool[]> fieldsAvailable(new bool[_fieldsRequested.size()] { });
212 auto& fieldsCommonWith = _fieldsCommonWith[iC];
213 fieldsCommonWith.clear();
214
216 fieldsAvailable.get(), _fieldsRequested.size(),
217 _loadBalancer.rank(iC),
218 coordinator.get(iC, _iC, 0),
219 _neighborhoodComm);
220
221 for (unsigned iField=0; iField < _fieldsRequested.size(); ++iField) {
222 if (fieldsAvailable[iField] && _fieldsAvailable[iField]) {
223 fieldsCommonWith.emplace_back(_fieldsRequested[iField]);
224 }
225 }
226
227 static_assert(sizeof(CellID) == 4 || sizeof(CellID) == 8,
228 "CellID must be either 4 or 8 byte unsigned integer");
229 std::size_t newOutboundCount = singleton::mpi().probeReceiveSize<CellID>(_loadBalancer.rank(iC),
230 coordinator.get(iC, _iC, 1),
231 _neighborhoodComm);
232 _cellsOutboundTo[iC].resize(newOutboundCount);
233
235 _cellsOutboundTo[iC].data(),
236 _cellsOutboundTo[iC].size(),
237 _loadBalancer.rank(iC),
238 coordinator.get(iC, _iC, 1),
239 _neighborhoodComm);
240 });
241}
242
243template <typename T, unsigned D>
245{
246 forNeighbors([&](int iC) {
247 _fieldRequests[iC]->wait();
248 _cellsRequests[iC]->wait();
249 });
250}
251
252#endif // PARALLEL_MODE_MPI
253
254template <typename T, unsigned D>
255const std::vector<std::type_index>&
257{
258 return _fieldsCommonWith.at(iC);
259}
260
261template <typename T, unsigned D>
262const std::vector<CellID>&
264{
265 return _cellsOutboundTo.at(iC);
266}
267
268template <typename T, unsigned D>
269const std::vector<CellID>&
271{
272 return _cellsInboundFrom.at(iC);
273}
274
275template <typename T, unsigned D>
276const std::vector<CellID>&
278{
279 return _cellsRequestedFrom.at(iC);
280}
281
282// *INDENT-ON*
283
284}
285
286#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
BlockCommunicationNeighborhood(CuboidGeometry< T, D > &cuboidGeometry, LoadBalancer< T > &loadBalancer, int iC, int padding, MPI_Comm comm)
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.
Base of a regular block.
void forSpatialLocations(F f) const
bool isPadding(LatticeR< D > latticeR) const
Return whether location is valid.
CellID getCellId(LatticeR< D > latticeR) const
Get 1D cell ID.
Base class for all LoadBalancer.
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.
Definition vector.h:47
constexpr Vector< T, D+1 > withPrefix(T prefix) const any_platform
Definition vector.h:186
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, CuboidGeometry2D< T >, CuboidGeometry3D< T > > CuboidGeometry
Definition aliases.h:47
std::conditional_t< D==2, BlockIndicatorF2D< T >, BlockIndicatorF3D< T > > BlockIndicatorF
Definition aliases.h:218
std::conditional_t< D==2, Cuboid2D< T >, Cuboid3D< T > > Cuboid
Definition aliases.h:37