24#ifndef BLOCK_COMMUNICATION_NEIGHBORHOOD_HH
25#define BLOCK_COMMUNICATION_NEIGHBORHOOD_HH
38template <
typename T,
unsigned D>
44#ifdef PARALLEL_MODE_MPI
48 _cuboidGeometry(cuboidGeometry)
49 , _loadBalancer(loadBalancer)
52#ifdef PARALLEL_MODE_MPI
53 , _neighborhoodComm(comm)
58 for (
auto& [_, cells] : _cellsInboundFrom) {
61 for (
auto& [_, cells] : _cellsRequestedFrom) {
66template <
typename T,
unsigned D>
69 auto& cuboid = _cuboidGeometry.get(_iC);
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));
80 Cuboid<T,D>& remoteCuboid = _cuboidGeometry.get(remoteLatticeR[0]);
83 _cellsRequestedFrom[remoteLatticeR[0]].emplace_back(
84 remotePaddedBlock.
getCellId(remoteLatticeR+1));
87 throw std::logic_error(
"Requested cell is outside of available padding");
91template <
typename T,
unsigned D>
95 throw std::logic_error(
"Overlap requests must have width >= 1");
97 if (width > _padding) {
98 throw std::logic_error(
"Requested overlap exceeds available padding");
101 auto& cuboid = _cuboidGeometry.get(_iC);
104 overlapBlock.forSpatialLocations([&](
LatticeR<D> latticeR) {
105 if (overlapBlock.isPadding(latticeR)) {
106 requestCell(latticeR);
111template <
typename T,
unsigned D>
115 throw std::logic_error(
"Overlap requests must have width >= 1");
117 if (width > _padding) {
118 throw std::logic_error(
"Requested overlap exceeds available padding");
121 auto& cuboid = _cuboidGeometry.get(_iC);
125 if (overlapBlock.
isPadding(latticeR) && indicatorF(latticeR)) {
126 requestCell(latticeR);
131template <
typename T,
unsigned D>
134 _cellsInboundFrom.clear();
135 _cellsOutboundTo.clear();
136 _cellsRequestedFrom.clear();
139template <
typename T,
unsigned D>
142 auto iter = std::find(_fieldsRequested.begin(), _fieldsRequested.end(), field);
143 if (iter != _fieldsRequested.end()) {
144 _fieldsAvailable[iter - _fieldsRequested.begin()] = available;
148template <
typename T,
unsigned D>
149template <
typename BLOCK>
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);
162template <
typename T,
unsigned D>
165 for (
auto& [iC, _] : _cellsInboundFrom) {
166 auto& iCells = _cellsInboundFrom[iC];
167 auto& oCells = _cellsRequestedFrom[iC];
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]; });
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());
177 std::vector<CellID> buffer(p.size());
178 std::transform(p.begin(), p.end(), buffer.begin(), [&iCells](
auto i) { return iCells[i]; });
182 std::vector<CellID> buffer(p.size());
183 std::transform(p.begin(), p.end(), buffer.begin(), [&oCells](
auto i) { return oCells[i]; });
189#ifdef PARALLEL_MODE_MPI
191template <
typename T,
unsigned D>
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();
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();
207template <
typename T,
unsigned D>
210 forNeighbors([&](
int iC) {
211 std::unique_ptr<bool[]> fieldsAvailable(
new bool[_fieldsRequested.size()] { });
212 auto& fieldsCommonWith = _fieldsCommonWith[iC];
213 fieldsCommonWith.clear();
216 fieldsAvailable.get(), _fieldsRequested.size(),
217 _loadBalancer.rank(iC),
218 coordinator.
get(iC, _iC, 0),
221 for (
unsigned iField=0; iField < _fieldsRequested.size(); ++iField) {
222 if (fieldsAvailable[iField] && _fieldsAvailable[iField]) {
223 fieldsCommonWith.emplace_back(_fieldsRequested[iField]);
227 static_assert(
sizeof(
CellID) == 4 ||
sizeof(
CellID) == 8,
228 "CellID must be either 4 or 8 byte unsigned integer");
230 coordinator.
get(iC, _iC, 1),
232 _cellsOutboundTo[iC].resize(newOutboundCount);
235 _cellsOutboundTo[iC].data(),
236 _cellsOutboundTo[iC].size(),
237 _loadBalancer.rank(iC),
238 coordinator.
get(iC, _iC, 1),
243template <
typename T,
unsigned D>
246 forNeighbors([&](
int iC) {
247 _fieldRequests[iC]->wait();
248 _cellsRequests[iC]->wait();
254template <
typename T,
unsigned D>
255const std::vector<std::type_index>&
258 return _fieldsCommonWith.at(iC);
261template <
typename T,
unsigned D>
262const std::vector<CellID>&
265 return _cellsOutboundTo.at(iC);
268template <
typename T,
unsigned D>
269const std::vector<CellID>&
272 return _cellsInboundFrom.at(iC);
275template <
typename T,
unsigned D>
276const std::vector<CellID>&
279 return _cellsRequestedFrom.at(iC);
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.
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.
constexpr Vector< T, D+1 > withPrefix(T prefix) const any_platform
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.
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
std::conditional_t< D==2, BlockIndicatorF2D< T >, BlockIndicatorF3D< T > > BlockIndicatorF
std::conditional_t< D==2, Cuboid2D< T >, Cuboid3D< T > > Cuboid