meshOctreeParallelCommunication.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | cfMesh: A library for mesh generation
4  \\ / O peration |
5  \\ / A nd | Author: Franjo Juretic (franjo.juretic@c-fields.com)
6  \\/ M anipulation | Copyright (C) Creative Fields, Ltd.
7 -------------------------------------------------------------------------------
8 License
9  This file is part of cfMesh.
10 
11  cfMesh is free software; you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by the
13  Free Software Foundation; either version 3 of the License, or (at your
14  option) any later version.
15 
16  cfMesh is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with cfMesh. If not, see <http://www.gnu.org/licenses/>.
23 
24 Description
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "meshOctree.H"
29 #include "HashSet.H"
30 
31 //#define OCTREE_DEBUG
32 
33 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
34 
35 namespace Foam
36 {
37 
38 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
39 
41 (
42  const LongList<meshOctreeCubeCoordinates>& dataToSend,
44 ) const
45 {
46  if( !Pstream::parRun() || (neiProcs_.size() == 0) )
47  {
48  //- this is a serial run
49  return;
50  }
51 
53  (
54  neiProcs_.size(),
56  );
57  meshOctreeCubeCoordinates minCoord, maxCoord;
58  forAll(dataToSend, i)
59  {
60  dataToSend[i].neighbourRange(minCoord, maxCoord);
61 
62  # ifdef OCTREE_DEBUG
63  label counter(0);
64  # endif
65 
66  forAll(neiProcs_, procI)
67  {
68  if( maxCoord >= neiRange_[procI].first() )
69  {
70  if( minCoord <= neiRange_[procI].second() )
71  {
72  toProcs[procI].append(dataToSend[i]);
73 
74  # ifdef OCTREE_DEBUG
75  ++counter;
76  # endif
77  }
78  }
79  else
80  {
81  break;
82  }
83  }
84 
85  # ifdef OCTREE_DEBUG
86  if( !counter )
87  {
88  DynList<label> neighs;
89  this->findAllLeafNeighbours(dataToSend[i], neighs);
90  forAll(neighs, nI)
91  if( neighs[nI] == meshOctreeCubeBasic::OTHERPROC )
92  {
93  forAll(neiRange_, j)
94  {
95  if( minCoord <= neiRange_[j].second() )
96  Pout << "Min coord " << minCoord << " is smaller "
97  << "than " << neiRange_[j].first() << endl;
98  if( maxCoord >= neiRange_[j].first() )
99  Pout << "Max coord " << maxCoord << " is greater "
100  << "than " << neiRange_[j].second() << endl;
101  }
102 
103  FatalError << "Box " << dataToSend[i] << " is not sent"
104  << " minCoord " << minCoord
105  << " maxCoord " << maxCoord
106  << " neighbours " << neiProcs_
107  << " neiRange_ " << neiRange_
108  << abort(FatalError);
109  }
110  }
111  # endif
112  }
113 
114  //- send an receive the size of data chunk which will be exchanged
115  forAll(neiProcs_, neiProcI)
116  {
117  OPstream toOtherProc
118  (
120  neiProcs_[neiProcI],
121  sizeof(label)
122  );
123 
124  toOtherProc << toProcs[neiProcI].size();
125  }
126 
127  labelList sizeOfOtherProc(neiProcs_.size());
128  forAll(neiProcs_, neiProcI)
129  {
130  IPstream fromOtherProc
131  (
133  neiProcs_[neiProcI],
134  sizeof(label)
135  );
136 
137  fromOtherProc >> sizeOfOtherProc[neiProcI];
138  }
139 
140  //- exchange data between processors
141  //- upper-diagonal communication
142  forAll(neiProcs_, neiProcI)
143  {
144  if( sizeOfOtherProc[neiProcI] == 0 )
145  continue;
146  if( neiProcs_[neiProcI] >= Pstream::myProcNo() )
147  continue;
148 
149  //- receive data from other processor
150  IPstream fromOtherProc(Pstream::scheduled, neiProcs_[neiProcI]);
151  dataToReceive.appendFromStream(fromOtherProc);
152  }
153 
154  forAll(neiProcs_, neiProcI)
155  {
156  if( toProcs[neiProcI].size() == 0 )
157  continue;
158  if( neiProcs_[neiProcI] <= Pstream::myProcNo() )
159  continue;
160 
161  //- send data to other processor
162  OPstream toOtherProc(Pstream::scheduled, neiProcs_[neiProcI]);
163  toOtherProc << toProcs[neiProcI];
164  }
165 
166  //- lower-diagonal communication
167  forAllReverse(neiProcs_, neiProcI)
168  {
169  if( sizeOfOtherProc[neiProcI] == 0 )
170  continue;
171  if( neiProcs_[neiProcI] <= Pstream::myProcNo() )
172  continue;
173 
174  //- receive data from other processor
175  IPstream fromOtherProc(Pstream::scheduled, neiProcs_[neiProcI]);
176  dataToReceive.appendFromStream(fromOtherProc);
177  }
178 
179  forAllReverse(neiProcs_, neiProcI)
180  {
181  if( toProcs[neiProcI].size() == 0 )
182  continue;
183  if( neiProcs_[neiProcI] >= Pstream::myProcNo() )
184  continue;
185 
186  //- send data to other processor
187  OPstream toOtherProc(Pstream::scheduled, neiProcs_[neiProcI]);
188  toOtherProc << toProcs[neiProcI];
189  }
190 }
192 (
193  const LongList<meshOctreeCubeCoordinates>& dataToSend,
194  const LongList<scalar>& rangesToSend,
196  LongList<scalar>& receivedRanges
197 ) const
198 {
199  if( !Pstream::parRun() || (neiProcs_.size() == 0) )
200  {
201  //- this is a serial run
202  return;
203  }
204 
206  (
207  neiProcs_.size(),
209  );
210  List<LongList<scalar> > attributesToProcs
211  (
212  neiProcs_.size(),
214  );
215 
216  meshOctreeCubeCoordinates minCoord, maxCoord;
217  forAll(dataToSend, i)
218  {
219  dataToSend[i].neighbourRange(minCoord, maxCoord);
220 
221  const scalar size = dataToSend[i].size(rootBox_);
222  const label nLayers = ceil(rangesToSend[i] / size);
223 
224  minCoord =
226  (
227  minCoord.posX() - nLayers,
228  minCoord.posY() - nLayers,
229  minCoord.posZ() - nLayers,
230  minCoord.level()
231  );
232  maxCoord =
234  (
235  nLayers + maxCoord.posX(),
236  nLayers + maxCoord.posY(),
237  nLayers + maxCoord.posZ(),
238  maxCoord.level()
239  );
240 
241  # ifdef OCTREE_DEBUG
242  label counter(0);
243  # endif
244 
245  forAll(neiProcs_, procI)
246  {
247  if( maxCoord >= neiRange_[procI].first() )
248  {
249  if( minCoord <= neiRange_[procI].second() )
250  {
251  toProcs[procI].append(dataToSend[i]);
252  attributesToProcs[procI].append(rangesToSend[i]);
253 
254  # ifdef OCTREE_DEBUG
255  ++counter;
256  # endif
257  }
258  }
259  else
260  {
261  break;
262  }
263  }
264  }
265 
266  //- send an receive the size of data chunk which will be exchanged
267  forAll(neiProcs_, neiProcI)
268  {
269  OPstream toOtherProc
270  (
272  neiProcs_[neiProcI],
273  sizeof(label)
274  );
275 
276  toOtherProc << toProcs[neiProcI].size();
277  }
278 
279  labelList sizeOfOtherProc(neiProcs_.size());
280  forAll(neiProcs_, neiProcI)
281  {
282  IPstream fromOtherProc
283  (
285  neiProcs_[neiProcI],
286  sizeof(label)
287  );
288 
289  fromOtherProc >> sizeOfOtherProc[neiProcI];
290  }
291 
292  //- exchange data between processors
293  //- upper-diagonal communication
294  forAll(neiProcs_, neiProcI)
295  {
296  if( sizeOfOtherProc[neiProcI] == 0 )
297  continue;
298  if( neiProcs_[neiProcI] >= Pstream::myProcNo() )
299  continue;
300 
301  //- receive data from other processor
302  IPstream fromOtherProc(Pstream::scheduled, neiProcs_[neiProcI]);
303 
304  dataToReceive.appendFromStream(fromOtherProc);
305  }
306 
307  forAll(neiProcs_, neiProcI)
308  {
309  if( toProcs[neiProcI].size() == 0 )
310  continue;
311  if( neiProcs_[neiProcI] <= Pstream::myProcNo() )
312  continue;
313 
314  //- send data to other processor
315  OPstream toOtherProc(Pstream::scheduled, neiProcs_[neiProcI]);
316  toOtherProc << toProcs[neiProcI];
317  }
318 
319  //- lower-diagonal communication
320  forAllReverse(neiProcs_, neiProcI)
321  {
322  if( sizeOfOtherProc[neiProcI] == 0 )
323  continue;
324  if( neiProcs_[neiProcI] <= Pstream::myProcNo() )
325  continue;
326 
327  //- receive data from other processor
328  IPstream fromOtherProc(Pstream::scheduled, neiProcs_[neiProcI]);
329 
330  dataToReceive.appendFromStream(fromOtherProc);
331  }
332 
333  forAllReverse(neiProcs_, neiProcI)
334  {
335  if( toProcs[neiProcI].size() == 0 )
336  continue;
337  if( neiProcs_[neiProcI] >= Pstream::myProcNo() )
338  continue;
339 
340  //- send data to other processor
341  OPstream toOtherProc(Pstream::scheduled, neiProcs_[neiProcI]);
342  toOtherProc << toProcs[neiProcI];
343  }
344 
345  //- exchange attributes
346  //- exchange data between processors
347  //- upper-diagonal communication
348  forAll(neiProcs_, neiProcI)
349  {
350  if( sizeOfOtherProc[neiProcI] == 0 )
351  continue;
352  if( neiProcs_[neiProcI] >= Pstream::myProcNo() )
353  continue;
354 
355  //- receive data from other processor
356  IPstream fromOtherProc(Pstream::scheduled, neiProcs_[neiProcI]);
357 
358  receivedRanges.appendFromStream(fromOtherProc);
359  }
360 
361  forAll(neiProcs_, neiProcI)
362  {
363  if( toProcs[neiProcI].size() == 0 )
364  continue;
365  if( neiProcs_[neiProcI] <= Pstream::myProcNo() )
366  continue;
367 
368  //- send data to other processor
369  OPstream toOtherProc
370  (
372  neiProcs_[neiProcI],
373  attributesToProcs[neiProcI].byteSize()
374  );
375 
376  toOtherProc << attributesToProcs[neiProcI];
377  }
378 
379  //- lower-diagonal communication
380  forAllReverse(neiProcs_, neiProcI)
381  {
382  if( sizeOfOtherProc[neiProcI] == 0 )
383  continue;
384  if( neiProcs_[neiProcI] <= Pstream::myProcNo() )
385  continue;
386 
387  //- receive data from other processor
388  IPstream fromOtherProc(Pstream::scheduled, neiProcs_[neiProcI]);
389 
390  receivedRanges.appendFromStream(fromOtherProc);
391  }
392 
393  forAllReverse(neiProcs_, neiProcI)
394  {
395  if( toProcs[neiProcI].size() == 0 )
396  continue;
397  if( neiProcs_[neiProcI] >= Pstream::myProcNo() )
398  continue;
399 
400  //- send data to other processor
401  OPstream toOtherProc
402  (
404  neiProcs_[neiProcI],
405  attributesToProcs[neiProcI].byteSize()
406  );
407 
408  toOtherProc << attributesToProcs[neiProcI];
409  }
410 }
411 
412 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
413 
414 } // End namespace Foam
415 
416 // ************************************************************************* //
Foam::LongList::appendFromStream
void appendFromStream(Istream &)
Read from stream and append to the current content.
Definition: LongList.C:275
Foam::meshOctreeCubeCoordinates::posX
label posX() const
return x, y, z coordinates
Definition: meshOctreeCubeCoordinatesI.H:79
Foam::UPstream::scheduled
@ scheduled
Definition: UPstream.H:67
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:406
Foam::meshOctreeCubeCoordinates
Definition: meshOctreeCubeCoordinates.H:55
Foam::OPstream
Output inter-processor communications stream.
Definition: OPstream.H:50
Foam::UPstream::parRun
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:377
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
Foam::LongList::size
label size() const
Size of the active part of the list.
Definition: LongListI.H:203
meshOctree.H
Foam::LongList
Definition: LongList.H:55
Foam::UPstream::blocking
@ blocking
Definition: UPstream.H:66
Foam::label
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Foam::List::append
void append(const T &)
Append an element at the end of the list.
Foam::meshOctree::exchangeRequestsWithNeighbourProcessors
void exchangeRequestsWithNeighbourProcessors(const LongList< meshOctreeCubeCoordinates > &dataToSend, LongList< meshOctreeCubeCoordinates > &dataToReceive) const
exchange requests with other processors generating the octree
Definition: meshOctreeParallelCommunication.C:41
HashSet.H
Foam::FatalError
error FatalError
forAllReverse
#define forAllReverse(list, i)
Reverse loop across all elements in list.
Definition: UList.H:418
Foam
Namespace for OpenFOAM.
Definition: combustionModel.C:30
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:131
Foam::DynList< label >
Foam::UPstream::myProcNo
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:405
Foam::meshOctreeCubeBasic::OTHERPROC
@ OTHERPROC
Definition: meshOctreeCubeBasic.H:93
Foam::meshOctreeCubeCoordinates::level
direction level() const
return level
Definition: meshOctreeCubeCoordinatesI.H:74
Foam::Pout
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:59
Foam::IPstream
Input inter-processor communications stream.
Definition: IPstream.H:50
Foam::List::size
void size(const label)
Override size to be inconsistent with allocated storage.
Foam::meshOctreeCubeCoordinates::posZ
label posZ() const
Definition: meshOctreeCubeCoordinatesI.H:89
Foam::meshOctreeCubeCoordinates::posY
label posY() const
Definition: meshOctreeCubeCoordinatesI.H:84