kahipDecomp.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2017-2023 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "kahipDecomp.H"
30 #include "Time.H"
32 #include <map>
33 #include <string>
34 #include <vector>
35 
36 // Probably not needed, but in case we pickup parhip_interface.h
37 #ifndef MPICH_SKIP_MPICXX
38 #define MPICH_SKIP_MPICXX
39 #endif
40 #ifndef OMPI_SKIP_MPICXX
41 #define OMPI_SKIP_MPICXX
42 #endif
43 
44 #include "kaHIP_interface.h"
45 
46 // Provide a clear error message if we have a severe size mismatch
47 // Allow widening, but not narrowing
48 
49 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
50 
51 namespace Foam
52 {
53  defineTypeNameAndDebug(kahipDecomp, 0);
55  (
56  decompositionMethod,
57  kahipDecomp,
59  );
60 }
61 
62 
63 const Foam::Enum
64 <
66 >
68 ({
69  { kahipDecomp::configs::FAST, "fast" },
70  { kahipDecomp::configs::ECO, "eco" },
71  { kahipDecomp::configs::STRONG, "strong" },
72  { kahipDecomp::configs::FASTSOCIAL, "fast-social" },
73  { kahipDecomp::configs::ECOSOCIAL, "eco-social" },
74  { kahipDecomp::configs::STRONGSOCIAL, "strong-social" },
75 });
76 
77 
78 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
79 
81 (
82  const labelList& adjncy,
83  const labelList& xadj,
84  const List<scalar>& cWeights,
85  labelList& decomp
86 ) const
87 {
88  // Default setup
89  enum configs kahipConfig = configs::FAST;
90  double imbalance = 0.01;
91  int seed = 0;
92  bool verbose = false;
93 
94  #if WM_LABEL_SIZE == 64
95  if (xadj.size()-1 > INT_MAX)
96  {
98  << "Cannot decompose " << (xadj.size()-1) << " cells," << nl
99  << "Exceeded integer limit of " << INT_MAX << nl
100  << exit(FatalError);
101  }
102  #endif
103 
104  int numCells = max(0, (xadj.size()-1));
105 
106  // Addressing
107  ConstPrecisionAdaptor<int, label, List> adjncy_param(adjncy);
108  ConstPrecisionAdaptor<int, label, List> xadj_param(xadj);
109 
110  // Output: cell -> processor addressing
111  decomp.resize_nocopy(numCells);
112  decomp = 0;
113  PrecisionAdaptor<int, label, List> decomp_param(decomp, false);
114 
115  // Avoid potential nullptr issues with zero-sized arrays
116  labelList adjncy_dummy, xadj_dummy, decomp_dummy;
117  if (!numCells)
118  {
119  adjncy_dummy.resize(1, 0);
120  adjncy_param.set(adjncy_dummy);
121 
122  xadj_dummy.resize(2, 0);
123  xadj_param.set(xadj_dummy);
124 
125  decomp_dummy.resize(1, 0);
126  decomp_param.clear(); // Avoid propagating spurious values
127  decomp_param.set(decomp_dummy);
128  }
129 
130 
131  // Graph
132  // ~~~~~
133 
134  // Check for externally provided cellweights and if so initialise weights
135 
136  bool hasWeights = !cWeights.empty();
137 
138  // Note: min, not gMin since routine runs on master only.
139  const scalar minWeights = hasWeights ? min(cWeights) : scalar(1);
140 
141  if (minWeights <= 0)
142  {
143  hasWeights = false;
145  << "Illegal minimum weight " << minWeights
146  << " ... ignoring"
147  << endl;
148  }
149  else if (hasWeights && (cWeights.size() != numCells))
150  {
152  << "Number of weights (" << cWeights.size()
153  << ") != number of cells (" << numCells << ")"
154  << exit(FatalError);
155  }
156 
157  // Cell weights (so on the vertices of the dual)
158  List<int> cellWeights;
159 
160  if (hasWeights)
161  {
162  // Convert to integers.
163  cellWeights.resize_nocopy(cWeights.size());
164  forAll(cellWeights, i)
165  {
166  cellWeights[i] = static_cast<int>
167  (
168  cWeights[i]/minWeights
169  );
170  }
171  }
172 
173  configNames.readIfPresent("config", coeffsDict_, kahipConfig);
174  coeffsDict_.readIfPresent("imbalance", imbalance);
175  coeffsDict_.readIfPresent("verbose", verbose);
176 
177  Info<< "kahipDecomp :"
178  << " config=" << configNames[kahipConfig]
179  << " imbalance=" << imbalance;
180 
181  if (coeffsDict_.readIfPresent("seed", seed))
182  {
183  Info<< " seed=" << seed;
184  }
185 
186  // Additional sizing parameters (testing only)
187  std::map<std::string, std::vector<int>> sizingParams;
188 
189  List<int> labels;
190  if
191  (
192  coeffsDict_.readIfPresent("hierarchy", labels)
193  && !labels.empty()
194  )
195  {
196  std::vector<int> vec;
197  vec.reserve(labels.size()+1);
198 
199  // Verify sizing
200 
201  int n = 1;
202  for (const auto val : labels)
203  {
204  n *= val;
205  vec.push_back(val);
206  }
207 
208  if (n != nDomains_)
209  {
210  // Size mismatch. Try to correct.
211 
212  if (nDomains_ % n)
213  {
215  << "Mismatch in number of processors and "
216  << "hierarchy specified" << flatOutput(labels) << endl;
217 
218  vec.clear();
219  }
220  else
221  {
222  // Evenly divisible, add extra hierarchy level
223  vec.push_back(nDomains_ / n);
224  }
225  }
226 
227  if (!vec.empty())
228  {
229  sizingParams["hierarchy"] = std::move(vec);
230  Info<< " hierarchy=" << flatOutput(labels);
231  }
232  }
233 
234  if
235  (
236  coeffsDict_.readIfPresent("distance", labels)
237  && !labels.empty()
238  )
239  {
240  std::vector<int> vec(labels.size());
241 
242  forAll(labels, i)
243  {
244  vec[i] = labels[i];
245  }
246 
247  sizingParams["distance"] = std::move(vec);
248  Info<< " distance=" << flatOutput(labels);
249  }
250 
251  Info<< endl;
252 
253 
254  // Number of partitions
255  int nParts = nDomains_;
256 
257  // Output: number of cut edges
258  int edgeCut = 0;
259 
260 
261 #if 0 // WIP: #ifdef KAFFPA_CPP_INTERFACE
262  kaffpa_cpp
263  (
264  &numCells, // num vertices in graph
265  (cellWeights.empty() ? nullptr : cellWeights.data()), // vertex wts
266  xadj_param.constCast().data(), // indexing into adjncy
267  nullptr, // edge wts
268  adjncy_param.constCast().data(), // neighbour info
269  &nParts, // nparts
270  &imbalance, // amount of imbalance allowed
271  !verbose, // suppress output
272  seed, // for random
273  int(kahipConfig),
274  &edgeCut, // [output]
275  decomp_param.ref().data(), // [output]
276  sizingParams
277  );
278 #else
279  kaffpa
280  (
281  &numCells, // num vertices in graph
282  (cellWeights.empty() ? nullptr : cellWeights.data()), // vertex wts
283  xadj_param.constCast().data(), // indexing into adjncy
284  nullptr, // edge wts
285  adjncy_param.constCast().data(), // neighbour info
286  &nParts, // nparts
287  &imbalance, // amount of imbalance allowed
288  !verbose, // suppress output
289  seed, // for random
290  int(kahipConfig),
291  &edgeCut, // [output]
292  decomp_param.ref().data() // [output]
293  );
294 #endif
296  return edgeCut;
297 }
298 
299 
300 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
301 
302 Foam::kahipDecomp::kahipDecomp(const label numDomains)
303 :
304  metisLikeDecomp(numDomains)
305 {}
306 
307 
309 (
310  const dictionary& decompDict,
311  const word& regionName
312 )
313 :
314  metisLikeDecomp(typeName, decompDict, regionName, selectionType::NULL_DICT)
315 {}
316 
317 
318 // ************************************************************************* //
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:160
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
label nDomains_
Number of domains for the decomposition.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
virtual label decomposeSerial(const labelList &adjncy, const labelList &xadj, const List< scalar > &cellWeights, labelList &decomp) const
Call kahip with options from dictionary.
Definition: kahipDecomp.C:74
bool readIfPresent(const word &key, const dictionary &dict, EnumType &val, const bool warnOnly=false) const
Find an entry if present, and assign to T val.
Definition: EnumI.H:111
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
const dictionary & coeffsDict_
Coefficients for all derived methods.
Macros for easy insertion into run-time selection tables.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
configs
The predefined KaHIP configuration types.
Definition: kahipDecomp.H:115
A class for handling words, derived from Foam::string.
Definition: word.H:63
static const Enum< configs > configNames
The selection names for predefined KaHIP configurations.
Definition: kahipDecomp.H:129
Domain decomposition using METIS-like data structures.
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
bool readIfPresent(const word &keyword, T &val, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry if present, and assign to T val. FatalIOError if it is found and the number of tokens i...
defineTypeNameAndDebug(combustionModel, 0)
#define WarningInFunction
Report a warning using Foam::Warning.
Enum is a wrapper around a list of names/values that represent particular enumeration (or int) values...
Definition: error.H:64
Foam::word regionName(args.getOrDefault< word >("region", Foam::polyMesh::defaultRegion))
kahipDecomp(const kahipDecomp &)=delete
No copy construct.
messageStream Info
Information stream (stdout output on master, null elsewhere)
label n
List< label > labelList
A List of labels.
Definition: List.H:62
Namespace for OpenFOAM.
addToRunTimeSelectionTable(functionObject, pointHistory, dictionary)
FlatOutput::OutputAdaptor< Container, Delimiters > flatOutput(const Container &obj, Delimiters delim)
Global flatOutput() function with specified output delimiters.
Definition: FlatOutput.H:225