simple.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2024 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM 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 OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "simple.H"
28 #include "SortableList.H"
29 #include "globalIndex.H"
30 #include "SubField.H"
31 
32 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
33 
34 namespace Foam
35 {
36 namespace decompositionMethods
37 {
39 
41  (
43  simple,
44  decomposer
45  );
46 
48  (
50  simple,
51  distributor
52  );
53 }
54 }
55 
56 
57 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
58 
59 // assignToProcessorGroup : given nCells cells and nProcGroup processor
60 // groups to share them, how do we share them out? Answer : each group
61 // gets nCells/nProcGroup cells, and the first few get one
62 // extra to make up the numbers. This should produce almost
63 // perfect load balancing
64 
65 void Foam::decompositionMethods::simple::assignToProcessorGroup
66 (
67  labelList& processorGroup,
68  const label nProcGroup
69 ) const
70 {
71  label jump = processorGroup.size()/nProcGroup;
72  label jumpb = jump + 1;
73  label fstProcessorGroup = processorGroup.size() - jump*nProcGroup;
74 
75  label ind = 0;
76  label j = 0;
77 
78  // assign cells to the first few processor groups (those with
79  // one extra cell each
80  for (j=0; j<fstProcessorGroup; j++)
81  {
82  for (label k=0; k<jumpb; k++)
83  {
84  processorGroup[ind++] = j;
85  }
86  }
87 
88  // and now to the `normal' processor groups
89  for (; j<nProcGroup; j++)
90  {
91  for (label k=0; k<jump; k++)
92  {
93  processorGroup[ind++] = j;
94  }
95  }
96 }
97 
98 
99 void Foam::decompositionMethods::simple::assignToProcessorGroup
100 (
101  labelList& processorGroup,
102  const label nProcGroup,
103  const labelList& indices,
104  const scalarField& weights,
105  const scalar summedWeights
106 ) const
107 {
108  // This routine gets the sorted points.
109  // Easiest to explain with an example.
110  // E.g. 400 points, sum of weights : 513.
111  // Now with number of divisions in this direction (nProcGroup) : 4
112  // gives the split at 513/4 = 128
113  // So summed weight from 0..128 goes into bin 0,
114  // ,, 128..256 goes into bin 1
115  // etc.
116  // Finally any remaining ones go into the last bin (3).
117 
118  const scalar jump = summedWeights/nProcGroup;
119  const label nProcGroupM1 = nProcGroup - 1;
120  scalar sumWeights = 0;
121  label ind = 0;
122  label j = 0;
123 
124  // assign cells to all except last group.
125  for (j=0; j<nProcGroupM1; j++)
126  {
127  const scalar limit = jump*scalar(j + 1);
128  while (sumWeights < limit)
129  {
130  sumWeights += weights[indices[ind]];
131  processorGroup[ind++] = j;
132  }
133  }
134  // Ensure last included.
135  while (ind < processorGroup.size())
136  {
137  processorGroup[ind++] = nProcGroupM1;
138  }
139 }
140 
141 
142 Foam::labelList Foam::decompositionMethods::simple::decomposeOneProc
143 (
144  const pointField& points
145 ) const
146 {
147  // construct a list for the final result
148  labelList finalDecomp(points.size());
149 
150  labelList processorGroups(points.size());
151 
152  labelList pointIndices(points.size());
153  forAll(pointIndices, i)
154  {
155  pointIndices[i] = i;
156  }
157 
158  const pointField rotatedPoints(rotDelta_ & points);
159 
160  // and one to take the processor group id's. For each direction.
161  // we assign the processors to groups of processors labelled
162  // 0..nX to give a banded structure on the mesh. Then we
163  // construct the actual processor number by treating this as
164  // the units part of the processor number.
165  sort
166  (
167  pointIndices,
168  UList<scalar>::less(rotatedPoints.component(vector::X))
169  );
170 
171  assignToProcessorGroup(processorGroups, n_.x());
172 
173  forAll(points, i)
174  {
175  finalDecomp[pointIndices[i]] = processorGroups[i];
176  }
177 
178 
179  // now do the same thing in the Y direction. These processor group
180  // numbers add multiples of nX to the proc. number (columns)
181  sort
182  (
183  pointIndices,
184  UList<scalar>::less(rotatedPoints.component(vector::Y))
185  );
186 
187  assignToProcessorGroup(processorGroups, n_.y());
188 
189  forAll(points, i)
190  {
191  finalDecomp[pointIndices[i]] += n_.x()*processorGroups[i];
192  }
193 
194 
195  // finally in the Z direction. Now we add multiples of nX*nY to give
196  // layers
197  sort
198  (
199  pointIndices,
200  UList<scalar>::less(rotatedPoints.component(vector::Z))
201  );
202 
203  assignToProcessorGroup(processorGroups, n_.z());
204 
205  forAll(points, i)
206  {
207  finalDecomp[pointIndices[i]] += n_.x()*n_.y()*processorGroups[i];
208  }
209 
210  return finalDecomp;
211 }
212 
213 
214 Foam::labelList Foam::decompositionMethods::simple::decomposeOneProc
215 (
216  const pointField& points,
217  const scalarField& weights
218 ) const
219 {
220  // construct a list for the final result
221  labelList finalDecomp(points.size());
222 
223  labelList processorGroups(points.size());
224 
225  labelList pointIndices(points.size());
226  forAll(pointIndices, i)
227  {
228  pointIndices[i] = i;
229  }
230 
231  const pointField rotatedPoints(rotDelta_ & points);
232 
233  // and one to take the processor group id's. For each direction.
234  // we assign the processors to groups of processors labelled
235  // 0..nX to give a banded structure on the mesh. Then we
236  // construct the actual processor number by treating this as
237  // the units part of the processor number.
238  sort
239  (
240  pointIndices,
241  UList<scalar>::less(rotatedPoints.component(vector::X))
242  );
243 
244  const scalar summedWeights = sum(weights);
245  assignToProcessorGroup
246  (
247  processorGroups,
248  n_.x(),
249  pointIndices,
250  weights,
251  summedWeights
252  );
253 
254  forAll(points, i)
255  {
256  finalDecomp[pointIndices[i]] = processorGroups[i];
257  }
258 
259 
260  // now do the same thing in the Y direction. These processor group
261  // numbers add multiples of nX to the proc. number (columns)
262  sort
263  (
264  pointIndices,
265  UList<scalar>::less(rotatedPoints.component(vector::Y))
266  );
267 
268  assignToProcessorGroup
269  (
270  processorGroups,
271  n_.y(),
272  pointIndices,
273  weights,
274  summedWeights
275  );
276 
277  forAll(points, i)
278  {
279  finalDecomp[pointIndices[i]] += n_.x()*processorGroups[i];
280  }
281 
282 
283  // finally in the Z direction. Now we add multiples of nX*nY to give
284  // layers
285  sort
286  (
287  pointIndices,
288  UList<scalar>::less(rotatedPoints.component(vector::Z))
289  );
290 
291  assignToProcessorGroup
292  (
293  processorGroups,
294  n_.z(),
295  pointIndices,
296  weights,
297  summedWeights
298  );
299 
300  forAll(points, i)
301  {
302  finalDecomp[pointIndices[i]] += n_.x()*n_.y()*processorGroups[i];
303  }
304 
305  return finalDecomp;
306 }
307 
308 
309 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
310 
312 (
313  const dictionary& decompositionDict,
314  const dictionary& methodDict
315 )
316 :
317  geometric(decompositionDict, methodDict)
318 {}
319 
320 
321 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
322 
324 (
325  const pointField& points
326 )
327 {
328  if (!Pstream::parRun())
329  {
330  return decomposeOneProc(points);
331  }
332  else
333  {
334  globalIndex globalNumbers(points.size());
335 
336  // Collect all points on master
337  if (Pstream::master())
338  {
339  pointField allPoints(globalNumbers.size());
340 
341  label nTotalPoints = 0;
342  // Master first
343  SubField<point>(allPoints, points.size()) = points;
344  nTotalPoints += points.size();
345 
346  // Add slaves
347  for (int slave=1; slave<Pstream::nProcs(); slave++)
348  {
349  IPstream fromSlave(Pstream::commsTypes::scheduled, slave);
350  pointField nbrPoints(fromSlave);
352  (
353  allPoints,
354  nbrPoints.size(),
355  nTotalPoints
356  ) = nbrPoints;
357  nTotalPoints += nbrPoints.size();
358  }
359 
360  // Decompose
361  labelList finalDecomp(decomposeOneProc(allPoints));
362 
363  // Send back
364  for (int slave=1; slave<Pstream::nProcs(); slave++)
365  {
367  toSlave << SubField<label>
368  (
369  finalDecomp,
370  globalNumbers.localSize(slave),
371  globalNumbers.offset(slave)
372  );
373  }
374  // Get my own part
375  finalDecomp.setSize(points.size());
376 
377  return finalDecomp;
378  }
379  else
380  {
381  // Send my points
382  {
383  OPstream toMaster
384  (
387  );
388  toMaster<< points;
389  }
390 
391  // Receive back decomposition
392  IPstream fromMaster
393  (
396  );
397  labelList finalDecomp(fromMaster);
398 
399  return finalDecomp;
400  }
401  }
402 }
403 
404 
406 (
407  const pointField& points,
408  const scalarField& weights
409 )
410 {
411  checkWeights(points, weights);
412 
413  if (!Pstream::parRun())
414  {
415  return decomposeOneProc(points, weights);
416  }
417  else
418  {
419  globalIndex globalNumbers(points.size());
420 
421  // Collect all points on master
422  if (Pstream::master())
423  {
424  pointField allPoints(globalNumbers.size());
425  scalarField allWeights(allPoints.size());
426 
427  label nTotalPoints = 0;
428  // Master first
429  SubField<point>(allPoints, points.size()) = points;
430  SubField<scalar>(allWeights, points.size()) = weights;
431  nTotalPoints += points.size();
432 
433  // Add slaves
434  for (int slave=1; slave<Pstream::nProcs(); slave++)
435  {
436  IPstream fromSlave(Pstream::commsTypes::scheduled, slave);
437  pointField nbrPoints(fromSlave);
438  scalarField nbrWeights(fromSlave);
440  (
441  allPoints,
442  nbrPoints.size(),
443  nTotalPoints
444  ) = nbrPoints;
446  (
447  allWeights,
448  nbrWeights.size(),
449  nTotalPoints
450  ) = nbrWeights;
451  nTotalPoints += nbrPoints.size();
452  }
453 
454  // Decompose
455  labelList finalDecomp(decomposeOneProc(allPoints, allWeights));
456 
457  // Send back
458  for (int slave=1; slave<Pstream::nProcs(); slave++)
459  {
461  toSlave << SubField<label>
462  (
463  finalDecomp,
464  globalNumbers.localSize(slave),
465  globalNumbers.offset(slave)
466  );
467  }
468  // Get my own part
469  finalDecomp.setSize(points.size());
470 
471  return finalDecomp;
472  }
473  else
474  {
475  // Send my points
476  {
477  OPstream toMaster
478  (
481  );
482  toMaster<< points << weights;
483  }
484 
485  // Receive back decomposition
486  IPstream fromMaster
487  (
490  );
491  labelList finalDecomp(fromMaster);
492 
493  return finalDecomp;
494  }
495  }
496 }
497 
498 
499 // ************************************************************************* //
label k
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:433
Macros for easy insertion into run-time selection tables.
Input inter-processor communications stream.
Definition: IPstream.H:54
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
void setSize(const label)
Reset size of List.
Definition: List.C:281
Output inter-processor communications stream.
Definition: OPstream.H:54
Pre-declare related SubField type.
Definition: SubField.H:63
static int masterNo()
Process index of the master.
Definition: UPstream.H:417
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:423
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:411
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:399
Abstract base class for decomposition.
Geometrical domain decomposition.
Definition: geometric.H:52
simple(const dictionary &decompositionDict, const dictionary &methodDict)
Construct given the decomposition dictionary.
Definition: simple.C:312
virtual labelList decompose(const pointField &)
Like decompose but with uniform weights on the points.
Definition: simple.C:324
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:64
label localSize() const
My local size.
Definition: globalIndexI.H:60
label size() const
Global sum of localSizes.
Definition: globalIndexI.H:66
label offset(const label proci) const
Start of proci data.
Definition: globalIndexI.H:48
const pointField & points
addToRunTimeSelectionTable(decompositionMethod, metis, decomposer)
Namespace for OpenFOAM.
List< label > labelList
A List of labels.
Definition: labelList.H:56
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
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
complex limit(const complex &, const complex &)
Definition: complexI.H:202
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
void sort(UList< T > &)
Definition: UList.C:115
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
static bool less(const vector &x, const vector &y)
To compare normals.