meshOctreeModifierLoadDistribution.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 "meshOctreeModifier.H"
29 
30 #include <map>
31 
32 # ifdef USE_OMP
33 #include <omp.h>
34 # endif
35 
36 //#define OCTREETiming
37 //#define DEBUGBalancing
38 
39 # ifdef DEBUGBalancing
40 #include <sstream>
41 # endif
42 
43 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
44 
45 namespace Foam
46 {
47 
48 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
49 // Private member functions
50 
52 {
53  if( octree_.neiProcs().size() == 0 )
54  return;
55 
56  # ifdef OCTREETiming
58  const scalar startTime = omp_get_wtime();
59 
61  const scalar t1 = omp_get_wtime();
62  Info << "Creation of list of leaves lasted " << t1-startTime << endl;
63  # endif
64 
66 
67  label localNumWeighs(0);
68  labelList globalLeafWeight(leaves.size());
69 
70  if( usedType )
71  {
72  forAll(leaves, leafI)
73  {
74  if( leaves[leafI]->cubeType() & usedType )
75  {
76  globalLeafWeight[leafI] = localNumWeighs;
77  ++localNumWeighs;
78  }
79  else
80  {
81  globalLeafWeight[leafI] = -1;
82  }
83  }
84  }
85  else
86  {
87  forAll(leaves, leafI)
88  {
89  globalLeafWeight[leafI] = localNumWeighs;
90  ++localNumWeighs;
91  }
92  }
93 
94  # ifdef OCTREETiming
96  const scalar t2 = omp_get_wtime();
97  Info << "Creation of global leaf weights lasted " << t2-t1 << endl;
98  # endif
99 
100  const label totalNumWeights = returnReduce(localNumWeighs, sumOp<label>());
101  const label nWeightsPerProcessor = totalNumWeights / Pstream::nProcs();
102 
103  //- check if balancing should be performed
104  //- the tolerance is set to 5% difference in the number of boxes
105  //- from the ideal one
106  label doBalancing(0);
107  if(
108  mag
109  (
110  scalar(localNumWeighs - nWeightsPerProcessor) /
111  nWeightsPerProcessor
112  ) > 0.05
113  )
114  doBalancing = 1;
115 
116  reduce(doBalancing, maxOp<label>());
117 
118  if( doBalancing == 0 )
119  return;
120 
121  Info << "Distributing load between processors" << endl;
122 
123  //- start calculating new partitions
124  //- find global labels of the leaf boxes
125  doBalancing = 0;
126 
127  labelList procWeights(Pstream::nProcs());
128  procWeights[Pstream::myProcNo()] = localNumWeighs;
129  Pstream::gatherList(procWeights);
130  Pstream::scatterList(procWeights);
131 
132  for(label procI=0;procI<Pstream::myProcNo();++procI)
133  doBalancing += procWeights[procI];
134 
135  forAll(globalLeafWeight, lI)
136  {
137  if( globalLeafWeight[lI] != -1 )
138  globalLeafWeight[lI] += doBalancing;
139  }
140 
141  //- leaf boxes which are not in the range for the current processor
142  //- shall be migrated to other processors
143  std::map<label, labelLongList> leavesToSend;
144 
145  bool oneRemainingBox(false);
146  forAll(globalLeafWeight, leafI)
147  {
148  if( globalLeafWeight[leafI] == -1 )
149  continue;
150  if( !oneRemainingBox && (leafI == leaves.size() -1) )
151  continue;
152 
153  const label newProc =
154  Foam::min
155  (
156  globalLeafWeight[leafI] / nWeightsPerProcessor,
157  Pstream::nProcs()-1
158  );
159 
160  if( newProc != Pstream::myProcNo() )
161  {
162  leavesToSend[newProc].append(leafI);
163  leaves[leafI]->setProcNo(newProc);
164 
165  # ifdef DEBUGBalancing
166  if( leaves[leafI]->hasContainedElements() )
167  Serr << Pstream::myProcNo() << "Deleting a DATA cube "
168  << leaves[leafI]->coordinates() << " data is "
169  << leaves[leafI]->containedElements() << endl;
170  # endif
171  }
172  else
173  {
174  oneRemainingBox = true;
175  }
176  }
177 
178  # ifdef OCTREETiming
180  const scalar t3 = omp_get_wtime();
181  Info << "Completed assignment of leaves to processors in " << t3-t2 << endl;
182  # endif
183 
184  //- send the information to other processors
185  //- all processors shall received a list containing the same information
186  //- each processor informs which other processors shall receive data from
187  //- that processor
188  labelListList sendToProcesssors(Pstream::nProcs());
189  sendToProcesssors[Pstream::myProcNo()].setSize(leavesToSend.size());
190  label counter(0);
191  for
192  (
193  std::map<label, labelLongList>::const_iterator it=leavesToSend.begin();
194  it!=leavesToSend.end();
195  ++it
196  )
197  sendToProcesssors[Pstream::myProcNo()][counter++] = it->first;
198 
199  Pstream::gatherList(sendToProcesssors);
200  Pstream::scatterList(sendToProcesssors);
201 
202  labelHashSet receiveFrom;
203  forAll(sendToProcesssors, procI)
204  forAll(sendToProcesssors[procI], neiI)
205  if( sendToProcesssors[procI][neiI] == Pstream::myProcNo() )
206  receiveFrom.insert(procI);
207 
208  //- receive coordinates from processors with lower labels
209  LongList<meshOctreeCubeBasic> migratedCubes;
210  forAllConstIter(labelHashSet, receiveFrom, iter)
211  {
212  if( iter.key() >= Pstream::myProcNo() )
213  continue;
214 
216 
217  IPstream fromOtherProc(Pstream::blocking, iter.key());
218 
219  fromOtherProc >> mc;
220 
221  label currSize = migratedCubes.size();
222  migratedCubes.setSize(currSize+mc.size());
223  forAll(mc, mcI)
224  {
225  migratedCubes[currSize] = mc[mcI];
226  ++currSize;
227  }
228  }
229 
230  //- send the coordinates of the boxes to processors with greater label
231  const labelList& sendToProcs = sendToProcesssors[Pstream::myProcNo()];
232  forAll(sendToProcs, i)
233  {
234  const label procI = sendToProcs[i];
235 
236  if( procI <= Pstream::myProcNo() )
237  continue;
238 
239  List<meshOctreeCubeBasic> sendCoordinates
240  (
241  leavesToSend[procI].size()
242  );
243 
244  forAll(leavesToSend[procI], lI)
245  {
246  const meshOctreeCube& oc = *leaves[leavesToSend[procI][lI]];
247  sendCoordinates[lI] =
249  (
250  oc.coordinates(),
251  oc.cubeType()
252  );
253  }
254 
255  OPstream toOtherProc
256  (
258  procI,
259  sendCoordinates.byteSize()
260  );
261 
262  toOtherProc << sendCoordinates;
263  }
264 
265  //- receive data sent from processors with greater label
266  forAllConstIter(labelHashSet, receiveFrom, iter)
267  {
268  if( iter.key() <= Pstream::myProcNo() )
269  continue;
270 
272 
273  IPstream fromOtherProc(Pstream::blocking, iter.key());
274 
275  fromOtherProc >> mc;
276 
277  label currSize = migratedCubes.size();
278  migratedCubes.setSize(currSize+mc.size());
279  forAll(mc, mcI)
280  {
281  migratedCubes[currSize] = mc[mcI];
282  ++currSize;
283  }
284  }
285 
286  //- send the coordinates of the boxes to processors with lower label
287  forAll(sendToProcs, i)
288  {
289  const label procI = sendToProcs[i];
290 
291  if( procI >= Pstream::myProcNo() )
292  continue;
293 
294  List<meshOctreeCubeBasic> sendCoordinates
295  (
296  leavesToSend[procI].size()
297  );
298 
299  forAll(leavesToSend[procI], lI)
300  {
301  const meshOctreeCube& oc = *leaves[leavesToSend[procI][lI]];
302  sendCoordinates[lI] =
304  (
305  oc.coordinates(),
306  oc.cubeType()
307  );
308  }
309 
310  OPstream toOtherProc
311  (
313  procI,
314  sendCoordinates.byteSize()
315  );
316 
317  toOtherProc << sendCoordinates;
318  }
319 
320  # ifdef OCTREETiming
322  const scalar t4 = omp_get_wtime();
323  Info << "Data exchange lasted " << t4-t3 << endl;
324  # endif
325 
326  //- delete cubes which have been moved to other processors
328 
329  # ifdef OCTREETiming
331  const scalar t5 = omp_get_wtime();
332  Info << "Purging lasted " << t5-t4 << endl;
333  # endif
334 
335  //- create boxes from the received coordinates
336  forAll(migratedCubes, mcI)
337  {
339  (
340  migratedCubes[mcI].coordinates(),
342  migratedCubes[mcI].cubeType()
343  );
344  }
345 
347 
348  # ifdef OCTREETiming
350  const scalar t6 = omp_get_wtime();
351  Info << "Tree refinement lasted " << t6-t5 << endl;
352  # endif
353 
354  //- update the communication pattern
356 
357  # ifdef OCTREETiming
359  const scalar endTime = omp_get_wtime();
360  Info << "Updating of communication pattern lasted " << endTime-t6 << endl;
361  Info << "Time for load balancing is " << endTime-startTime << endl;
362  # endif
363 
364  Info << "Finished distributing load between processors" << endl;
365 }
366 
367 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
368 
369 } // End namespace Foam
370 
371 // ************************************************************************* //
Foam::maxOp
Definition: ops.H:172
Foam::returnReduce
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
Definition: PstreamReduceOps.H:86
Foam::meshOctreeModifier::refineTreeForCoordinates
void refineTreeForCoordinates(const meshOctreeCubeCoordinates &, const short procNo=Pstream::myProcNo(), const direction cubeType=meshOctreeCubeBasic::UNKNOWN)
refine the tree to add cubes transferred from other processors
Definition: meshOctreeModifierParallelRefinement.C:44
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:406
Foam::OPstream
Output inter-processor communications stream.
Definition: OPstream.H:50
Foam::Pstream::scatterList
static void scatterList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Scatter data. Reverse of gatherList.
Definition: gatherScatterList.C:205
Foam::UPstream::nProcs
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:387
Foam::meshOctree::neiProcs
const labelList & neiProcs() const
neighbour processors of the current one
Definition: meshOctreeI.H:152
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
Foam::meshOctreeCubeBasic::cubeType
direction cubeType() const
return type
Definition: meshOctreeCubeBasicI.H:75
Foam::LongList::size
label size() const
Size of the active part of the list.
Definition: LongListI.H:203
Foam::mag
dimensioned< scalar > mag(const dimensioned< Type > &)
Foam::HashSet< label, Hash< label > >
Foam::meshOctreeCubeBasic::coordinates
const meshOctreeCubeCoordinates & coordinates() const
return coordinates in the octree
Definition: meshOctreeCubeBasicI.H:90
meshOctreeModifier.H
forAllConstIter
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:39
Foam::LongList::setSize
void setSize(const label)
Reset size of List.
Definition: LongListI.H:223
Foam::LongList
Definition: LongList.H:55
Foam::UPstream::blocking
@ blocking
Definition: UPstream.H:66
Foam::reduce
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
Definition: PstreamReduceOps.H:43
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::meshOctreeModifier::loadDistribution
void loadDistribution(const direction usedType=0)
move octree cubes from one processor to another
Definition: meshOctreeModifierLoadDistribution.C:51
Foam::Info
messageStream Info
Foam::Serr
OSstream Serr(cerr, "Serr")
Definition: IOstreams.H:52
coordinates
PtrList< coordinateSystem > coordinates(solidRegions.size())
Foam::meshOctree::leaves_
LongList< meshOctreeCube * > leaves_
list of cubes which are leaves of the octree
Definition: meshOctree.H:89
Foam::meshOctreeCube::purgeProcessorCubes
bool purgeProcessorCubes(const short procNo)
delete boxes which are not local to the given processor
Definition: meshOctreeCubeRecursiveFunctions.C:247
Foam
Namespace for OpenFOAM.
Definition: combustionModel.C:30
Foam::meshOctreeModifier::updateCommunicationPattern
void updateCommunicationPattern()
Definition: meshOctreeModifierUpdateCommunicationPattern.C:45
Foam::UPstream::myProcNo
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:405
Foam::List::setSize
void setSize(const label)
Reset size of List.
Foam::Pstream::gatherList
static void gatherList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Gather data but keep individual values separate.
Definition: gatherScatterList.C:49
Foam::sumOp
Definition: ops.H:162
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::meshOctreeCube
Definition: meshOctreeCube.H:56
Foam::HashSet::insert
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:116
Foam::direction
unsigned char direction
Definition: direction.H:43
Foam::IPstream
Input inter-processor communications stream.
Definition: IPstream.H:50
startTime
Foam::label startTime
Definition: checkTimeOptions.H:5
Foam::meshOctree::initialCubePtr_
meshOctreeCube * initialCubePtr_
Root cube of the octree structure.
Definition: meshOctree.H:71
Foam::List::size
void size(const label)
Override size to be inconsistent with allocated storage.
Foam::min
dimensioned< Type > min(const dimensioned< Type > &, const dimensioned< Type > &)
Foam::meshOctreeCubeBasic
Definition: meshOctreeCubeBasic.H:49
Foam::meshOctreeModifier::createListOfLeaves
void createListOfLeaves()
create leaves
Definition: meshOctreeModifierI.H:100
Foam::meshOctreeModifier::octree_
meshOctree & octree_
Reference to the octree.
Definition: meshOctreeModifier.H:52