24#ifndef BLOCK_COMMUNICATION_NEIGHBORHOOD_HH
25#define BLOCK_COMMUNICATION_NEIGHBORHOOD_HH
38template <
typename T,
unsigned D>
44#ifdef PARALLEL_MODE_MPI
48 _cuboidDecomposition(cuboidDecomposition)
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 const auto& cuboid = _cuboidDecomposition.get(_iC);
74 auto physR = _cuboidDecomposition.getPhysR(latticeR.
withPrefix(_iC));
75 if (
auto remoteLatticeR = _cuboidDecomposition.getLatticeR(physR)) {
76 _cellsInboundFrom[(*remoteLatticeR)[0]].emplace_back(paddedBlock.
getCellId(latticeR));
78 const auto& remoteCuboid = _cuboidDecomposition.get((*remoteLatticeR)[0]);
81 _cellsRequestedFrom[(*remoteLatticeR)[0]].emplace_back(
82 remotePaddedBlock.
getCellId(&(*remoteLatticeR)[1]));
85 throw std::logic_error(
"Requested cell is outside of available padding");
89template <
typename T,
unsigned D>
93 throw std::logic_error(
"Overlap requests must have width >= 1");
95 if (width > _padding) {
96 throw std::logic_error(
"Requested overlap exceeds available padding");
99 const auto& cuboid = _cuboidDecomposition.get(_iC);
102 overlapBlock.forSpatialLocations([&](
LatticeR<D> latticeR) {
103 if (overlapBlock.isPadding(latticeR)) {
104 requestCell(latticeR);
109template <
typename T,
unsigned D>
113 throw std::logic_error(
"Overlap requests must have width >= 1");
115 if (width > _padding) {
116 throw std::logic_error(
"Requested overlap exceeds available padding");
119 const auto& cuboid = _cuboidDecomposition.get(_iC);
120 BlockStructureD<D> overlapBlock(cuboid.getExtent(), width);
122 overlapBlock.forSpatialLocations([&](
LatticeR<D> latticeR) {
123 if (overlapBlock.isPadding(latticeR) && indicatorF(latticeR)) {
124 requestCell(latticeR);
129template <
typename T,
unsigned D>
132 _cellsInboundFrom.clear();
133 _cellsOutboundTo.clear();
134 _cellsRequestedFrom.clear();
137template <
typename T,
unsigned D>
140 auto iter = std::find(_fieldsRequested.begin(), _fieldsRequested.end(), field);
141 if (iter != _fieldsRequested.end()) {
142 _fieldsAvailable[iter - _fieldsRequested.begin()] = available;
146template <
typename T,
unsigned D>
147template <
typename BLOCK>
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);
160template <
typename T,
unsigned D>
163 for (
auto& [iC, _] : _cellsInboundFrom) {
164 auto& iCells = _cellsInboundFrom[iC];
165 auto& oCells = _cellsRequestedFrom[iC];
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]; });
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());
175 std::vector<CellID> buffer(p.size());
176 std::transform(p.begin(), p.end(), buffer.begin(), [&iCells](
auto i) { return iCells[i]; });
180 std::vector<CellID> buffer(p.size());
181 std::transform(p.begin(), p.end(), buffer.begin(), [&oCells](
auto i) { return oCells[i]; });
187#ifdef PARALLEL_MODE_MPI
189template <
typename T,
unsigned D>
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();
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();
205template <
typename T,
unsigned D>
208 forNeighbors([&](
int iC) {
209 std::unique_ptr<bool[]> fieldsAvailable(
new bool[_fieldsRequested.size()] { });
210 auto& fieldsCommonWith = _fieldsCommonWith[iC];
211 fieldsCommonWith.clear();
214 fieldsAvailable.get(), _fieldsRequested.size(),
215 _loadBalancer.rank(iC),
216 coordinator.
get(iC, _iC, 0),
219 for (
unsigned iField=0; iField < _fieldsRequested.size(); ++iField) {
220 if (fieldsAvailable[iField] && _fieldsAvailable[iField]) {
221 fieldsCommonWith.emplace_back(_fieldsRequested[iField]);
225 static_assert(
sizeof(
CellID) == 4 ||
sizeof(
CellID) == 8,
226 "CellID must be either 4 or 8 byte unsigned integer");
228 coordinator.
get(iC, _iC, 1),
230 _cellsOutboundTo[iC].resize(newOutboundCount);
233 _cellsOutboundTo[iC].data(),
234 _cellsOutboundTo[iC].size(),
235 _loadBalancer.rank(iC),
236 coordinator.
get(iC, _iC, 1),
241template <
typename T,
unsigned D>
244 forNeighbors([&](
int iC) {
245 _fieldRequests[iC]->wait();
246 _cellsRequests[iC]->wait();
252template <
typename T,
unsigned D>
253const std::vector<std::type_index>&
256 return _fieldsCommonWith.at(iC);
259template <
typename T,
unsigned D>
260const std::vector<CellID>&
263 return _cellsOutboundTo.at(iC);
266template <
typename T,
unsigned D>
267const std::vector<CellID>&
270 return _cellsInboundFrom.at(iC);
273template <
typename T,
unsigned D>
274const std::vector<CellID>&
277 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
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)
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.
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
Return new (prefix,this...) vector.
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, BlockIndicatorF2D< T >, BlockIndicatorF3D< T > > BlockIndicatorF
Vector< std::int32_t, D > LatticeR
Type for spatial block-local lattice coordinates.