loadBalancer_fvMeshDistributor.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) 2021-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 
27 #include "decompositionMethod.H"
28 #include "cpuLoad.H"
29 #include "globalMeshData.H"
31 
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33 
34 namespace Foam
35 {
36 namespace fvMeshDistributors
37 {
40  (
43  fvMesh
44  );
45 }
46 }
47 
48 
49 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
50 
52 (
53  fvMesh& mesh,
54  const dictionary& dict
55 )
56 :
58  multiConstraint_(dict.lookupOrDefault<Switch>("multiConstraint", true))
59 {}
60 
61 
62 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
63 
65 {}
66 
67 
68 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
69 
71 {
72  const fvMesh& mesh = this->mesh();
73 
74  bool redistributed = false;
75 
76  if
77  (
78  Pstream::nProcs() > 1
79  && mesh.time().timeIndex() - mesh.time().startTimeIndex() > 1
80  && timeIndex_ != mesh.time().timeIndex()
81  )
82  {
83  timeIndex_ = mesh.time().timeIndex();
84 
85  // Get the CPU time fer this processor which includes waiting time
86  const scalar timeStepCpuTime = cpuTime_.cpuTimeIncrement();
87 
88  // CPU loads per cell
89  HashTable<cpuLoad*> cpuLoads(this->mesh().lookupClass<cpuLoad>());
90 
91  if (!cpuLoads.size())
92  {
94  << "No CPU loads have been allocated"
95  << exit(FatalError);
96  }
97 
98  if (mesh.time().timeIndex() % redistributionInterval_ == 0)
99  {
100  timeIndex_ = mesh.time().timeIndex();
101 
102  scalarList procCpuLoads(cpuLoads.size());
103 
104  label l = 0;
105  forAllConstIter(HashTable<cpuLoad*>, cpuLoads, iter)
106  {
107  procCpuLoads[l++] = sum(*iter());
108  }
109 
110  List<scalarList> allProcCpuLoads(Pstream::nProcs());
111  allProcCpuLoads[Pstream::myProcNo()] = procCpuLoads;
112  Pstream::gatherList(allProcCpuLoads);
113  Pstream::scatterList(allProcCpuLoads);
114 
115  scalarList sumProcCpuLoads(procCpuLoads.size(), scalar(0));
116  scalarList maxProcCpuLoads(procCpuLoads.size(), scalar(0));
117  forAll(maxProcCpuLoads, l)
118  {
119  forAll(allProcCpuLoads, proci)
120  {
121  sumProcCpuLoads[l] += allProcCpuLoads[proci][l];
122 
123  maxProcCpuLoads[l] =
124  max(maxProcCpuLoads[l], allProcCpuLoads[proci][l]);
125  }
126  }
127 
128  // Sum over loads of the maximum load CPU time per processor
129  const scalar sumMaxProcCpuLoad(sum(maxProcCpuLoads));
130 
131  // Maximum number of cells per processor
132  const label maxNcells = returnReduce(mesh.nCells(), maxOp<label>());
133 
134  // Maximum processor CPU time spent doing basic CFD
135  const scalar maxBaseCpuTime =
136  returnReduce(timeStepCpuTime, maxOp<scalar>())
137  - sumMaxProcCpuLoad;
138 
139  const scalar cellBaseCpuTime = maxBaseCpuTime/maxNcells;
140 
141  // Processor CPU time spent doing basic CFD, not waiting
142  const scalar baseCpuTime = mesh.nCells()*cellBaseCpuTime;
143 
144  // Maximum total CPU time
145  const scalar maxProcCpuTime = maxBaseCpuTime + sumMaxProcCpuLoad;
146 
147  // Total CPU time for this processor not waiting
148  const scalar procCpuTime = baseCpuTime + sum(procCpuLoads);
149 
150  // Average processor CPU time
151  const scalar averageProcessorCpuTime =
152  returnReduce(procCpuTime, sumOp<scalar>())/Pstream::nProcs();
153 
154  const scalar imbalance =
155  (maxProcCpuTime - averageProcessorCpuTime)
156  /averageProcessorCpuTime;
157 
158  Info<< nl << type() << nl;
159 
160  l = 0;
161  forAllConstIter(HashTable<cpuLoad*>, cpuLoads, iter)
162  {
163  Info<< " Imbalance of load " << iter()->name() << ": "
164  << (
165  maxProcCpuLoads[l]
166  - sumProcCpuLoads[l]/Pstream::nProcs()
167  )/averageProcessorCpuTime
168  << endl;
169  l++;
170  }
171 
172  Info<< " Imbalance of base load " << ": "
173  << (
174  maxBaseCpuTime
175  - mesh.globalData().nTotalCells()*cellBaseCpuTime
176  /Pstream::nProcs()
177  )/averageProcessorCpuTime
178  << endl;
179 
180  Info<< " Total imbalance " << imbalance << endl;
181 
182  if (imbalance > maxImbalance_)
183  {
184  Info<< " Redistributing mesh" << endl;
185 
186  scalarField weights;
187 
188  if (multiConstraint_)
189  {
190  const label nWeights = cpuLoads.size() + 1;
191 
192  weights.setSize(nWeights*mesh.nCells());
193 
194  for (label i=0; i<mesh.nCells(); i++)
195  {
196  weights[nWeights*i] = cellBaseCpuTime;
197  }
198 
199  label l = 1;
200  forAllConstIter(HashTable<cpuLoad*>, cpuLoads, iter)
201  {
202  const scalarField& cpuLoadField = *iter();
203 
204  forAll(cpuLoadField, i)
205  {
206  weights[nWeights*i + l] = cpuLoadField[i];
207  }
208 
209  iter()->checkOut();
210 
211  l++;
212  }
213  }
214  else
215  {
216  weights.setSize(mesh.nCells(), cellBaseCpuTime);
217 
218  forAllConstIter(HashTable<cpuLoad*>, cpuLoads, iter)
219  {
220  weights += *iter();
221  iter()->checkOut();
222  }
223  }
224 
225  // Create new decomposition distribution
226  const labelList distribution
227  (
228  distributor_->decompose(mesh, weights)
229  );
230 
231  distribute(distribution);
232 
233  redistributed = true;
234 
235  Info<< endl;
236  }
237  else
238  {
239  forAllIter(HashTable<cpuLoad*>, cpuLoads, iter)
240  {
241  iter()->checkOut();
242  }
243  }
244  }
245  else
246  {
247  forAllIter(HashTable<cpuLoad*>, cpuLoads, iter)
248  {
249  iter()->checkOut();
250  }
251  }
252  }
253 
254  return redistributed;
255 }
256 
257 
258 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:433
#define forAllIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:458
#define forAllConstIter(Container, container, iter)
Iterate across all elements in the container object of type.
Definition: UList.H:476
Macros for easy insertion into run-time selection tables.
An STL-conforming hash table.
Definition: HashTable.H:127
label size() const
Return number of elements in table.
Definition: HashTableI.H:65
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
static void scatterList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Scatter data. Reverse of gatherList.
static void gatherList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Gather data but keep individual values separate.
A simple wrapper around bool so that it can be read as a word: true/false, on/off,...
Definition: Switch.H:61
label timeIndex() const
Return current time index.
Definition: TimeStateI.H:28
virtual label startTimeIndex() const
Return start time index.
Definition: Time.C:774
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:411
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
Base class for statistical distributions.
Definition: distribution.H:76
Abstract base class for fvMesh movers.
Dynamic mesh redistribution using the distributor specified in decomposeParDict.
Dynamic mesh redistribution using the distributor specified in decomposeParDict.
loadBalancer(fvMesh &mesh, const dictionary &dict)
Construct from fvMesh and dictionary.
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:96
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:420
label nTotalCells() const
Return total number of cells in decomposed mesh.
const globalMeshData & globalData() const
Return parallel info.
Definition: polyMesh.C:1521
label nCells() const
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
addToRunTimeSelectionTable(fvMeshDistributor, none, fvMesh)
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
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
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:258
messageStream Info
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
error FatalError
static const char nl
Definition: Ostream.H:267
fileType type(const fileName &, const bool checkVariants=true, const bool followLink=true)
Return the file type: directory or file.
Definition: POSIX.C:488
dictionary dict