metisLikeDecomp.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-2025 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 "metisLikeDecomp.H"
29 #include "Time.H"
30 #include "globalIndex.H"
31 #include "globalMeshData.H"
32 
33 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
34 
36 (
37  const labelList& adjncy,
38  const labelList& xadj,
39  const List<scalar>& cWeights,
40  labelList& decomp
41 ) const
42 {
43  if (!UPstream::parRun())
44  {
45  // Treat zero-sized weights as uniform weighting
46  return decomposeSerial
47  (
48  adjncy,
49  xadj,
50  cWeights,
51  decomp
52  );
53  }
54 
55  if (debug)
56  {
57  Info<< type() << "Decomp : running in parallel."
58  << " Decomposing all of graph on master processor." << endl;
59  }
60 
61  // Protect against zero-sized offset list
62  const label numCells = Foam::max(0, (xadj.size()-1));
63 
64  const globalIndex globalAdjncy(adjncy.size());
65  const globalIndex globalCells(numCells);
66 
67  List<label> allAdjncy(globalAdjncy.gather(adjncy));
68 
69  // Gathering xadj to master is similar to globalIndex gather()
70  // except for the following:
71  //
72  // - gathered list is size+1
73  // - apply local to global renumbering
74 
76  const label startOfRequests = UPstream::nRequests();
77 
78 
79  List<label> allXadj;
80  if (UPstream::master())
81  {
82  allXadj.resize(globalCells.totalSize()+1);
83  allXadj.back() = globalAdjncy.totalSize(); // Final end offset
84 
85  // My values - no renumbering required
86  SubList<label>(allXadj, globalCells.localSize(0)) =
87  SubList<label>(xadj, globalCells.localSize(0));
88 
89  for (const int proci : globalCells.subProcs())
90  {
91  SubList<label> procSlot(allXadj, globalCells.range(proci));
92 
93  if (procSlot.empty())
94  {
95  // Nothing to do
96  }
97  else
98  {
100  (
101  commsType,
102  proci,
103  procSlot,
106  );
107  }
108  }
109  }
110  else
111  {
112  // Send my part of the graph (local numbering)
113 
114  if (!numCells)
115  {
116  // Nothing to do
117  }
118  else
119  {
120  SubList<label> procSlot(xadj, numCells);
121 
123  (
124  commsType,
126  procSlot,
129  );
130  }
131  }
132 
133  // Wait for outstanding requests
134  if (commsType == UPstream::commsTypes::nonBlocking)
135  {
136  UPstream::waitRequests(startOfRequests);
137  }
138 
139  // Local to global renumbering
140  if (UPstream::master())
141  {
142  for (const int proci : globalCells.subProcs())
143  {
144  SubList<label> procSlot(allXadj, globalCells.range(proci));
145 
146  globalAdjncy.inplaceToGlobal(proci, procSlot);
147  }
148  }
149 
150  // Uniform weighting if weights are empty or poorly sized
151 
152  List<scalar> allWeights;
153  if (returnReduceAnd(cWeights.size() == globalCells.localSize()))
154  {
155  // ie, hasWeights
156  allWeights = globalCells.gather(cWeights);
157  }
158 
159 
160  // Global decomposition
161  labelList allDecomp;
162 
163  if (UPstream::master())
164  {
166  (
167  allAdjncy,
168  allXadj,
169  allWeights,
170  allDecomp
171  );
172 
173  allAdjncy.clear(); // Not needed anymore
174  allXadj.clear(); // ...
175  allWeights.clear(); // ...
176  }
177 
178  // The processor-local decomposition (output)
179  decomp.resize_nocopy(globalCells.localSize());
180  globalCells.scatter(allDecomp, decomp);
182  return 0;
183 }
184 
185 
186 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
187 
188 Foam::metisLikeDecomp::metisLikeDecomp(const label numDomains)
189 :
190  decompositionMethod(numDomains),
191  coeffsDict_(dictionary::null)
192 {}
193 
194 
196 (
197  const word& derivedType,
198  const dictionary& decompDict,
199  const word& regionName,
200  int select
201 )
202 :
203  decompositionMethod(decompDict, regionName),
204  coeffsDict_(findCoeffsDict(derivedType + "Coeffs", select))
205 {}
206 
207 
208 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
209 
211 (
212  const polyMesh& mesh,
213  const pointField& points,
214  const scalarField& pointWeights
215 ) const
216 {
217  if (!points.empty() && (points.size() != mesh.nCells()))
218  {
220  << "Number of cell centres (" << points.size()
221  << ") != number of cells (" << mesh.nCells() << ")"
222  << exit(FatalError);
223  }
224 
225  // Global mesh connectivity
226  CompactListList<label> cellCells;
227  globalMeshData::calcCellCells(mesh, cellCells, true);
228 
229  labelList decomp;
230  decomposeGeneral
231  (
232  cellCells.values(),
233  cellCells.offsets(),
234  pointWeights,
235  decomp
236  );
237 
238  return decomp;
239 }
240 
241 
243 (
244  const polyMesh& mesh,
245  const labelList& agglom,
246  const pointField& agglomPoints,
247  const scalarField& agglomWeights
248 ) const
249 {
250  if (agglom.size() != mesh.nCells())
251  {
253  << "Agglomeration size (" << agglom.size()
254  << ") != number of cells (" << mesh.nCells() << ")"
255  << exit(FatalError);
256  }
257 
258  // Make Metis CSR (Compressed Storage Format) storage
259  // adjncy : contains neighbours (= edges in graph)
260  // xadj(celli) : start of information in adjncy for celli
261 
262  CompactListList<label> cellCells;
264  (
265  mesh,
266  agglom,
267  agglomPoints.size(),
268  true, // Global mesh connectivity
269  cellCells
270  );
271 
272  labelList decomp;
273  decomposeGeneral
274  (
275  cellCells.values(),
276  cellCells.offsets(),
277  agglomWeights,
278  decomp
279  );
281  // From coarse back to fine for original mesh
282  return labelList(decomp, agglom);
283 }
284 
285 
287 (
288  const CompactListList<label>& globalCellCells,
289  const pointField& cellCentres,
290  const scalarField& cellWeights
291 ) const
292 {
293  if (!cellCentres.empty() && (cellCentres.size() != globalCellCells.size()))
294  {
296  << "Number of cell centres (" << cellCentres.size()
297  << ") != number of cells (" << globalCellCells.size() << ")"
298  << exit(FatalError);
299  }
300 
301  // CompactListList is already
302  // Metis CSR (Compressed Storage Format) storage
303  // adjncy : contains neighbours (= edges in graph)
304  // xadj(celli) : start of information in adjncy for celli
305 
306  labelList decomp;
307  decomposeGeneral
308  (
309  globalCellCells.values(),
310  globalCellCells.offsets(),
311  cellWeights,
312  decomp
313  );
314 
315  return decomp;
316 }
317 
318 
320 (
321  const labelListList& globalCellCells,
322  const pointField& cellCentres,
323  const scalarField& cellWeights
324 ) const
325 {
326  if (!cellCentres.empty() && (cellCentres.size() != globalCellCells.size()))
327  {
329  << "Number of cell centres (" << cellCentres.size()
330  << ") != number of cells (" << globalCellCells.size() << ")"
331  << exit(FatalError);
332  }
333 
334  // Make Metis CSR (Compressed Storage Format) storage
335  // adjncy : contains neighbours (= edges in graph)
336  // xadj(celli) : start of information in adjncy for celli
337 
338 
339  auto cellCells(CompactListList<label>::pack(globalCellCells));
340 
341  labelList decomp;
342  decomposeGeneral
343  (
344  cellCells.values(),
345  cellCells.offsets(),
346  cellWeights,
347  decomp
348  );
349 
350  return decomp;
351 }
352 
353 // ************************************************************************* //
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
const labelList & offsets() const noexcept
Return the offset table (= size()+1)
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
label size() const noexcept
The primary size (the number of rows/sublists)
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:150
commsTypes
Communications types.
Definition: UPstream.H:77
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
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:600
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
static label nRequests() noexcept
Number of outstanding requests (on the internal list of requests)
List< bool > select(const label n, const labelUList &locations)
Construct a selection list of bools (all false) with the given pre-size, subsequently add specified l...
Definition: BitOps.C:134
bool empty() const noexcept
True if List is empty (ie, size() is zero)
Definition: UList.H:697
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:529
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1586
void resize_nocopy(const label len)
Adjust allocated size of list without necessarily.
Definition: ListI.H:168
static int & msgType() noexcept
Message tag of standard messages.
Definition: UPstream.H:1787
static CompactListList< T > pack(const UList< SubListType > &lists, const bool checkOverflow=false)
Construct by packing together the list of lists.
static std::streamsize read(const UPstream::commsTypes commsType, const int fromProcNo, Type *buffer, std::streamsize count, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm, UPstream::Request *req=nullptr)
Receive buffer contents (contiguous types) from given processor.
static label worldComm
Communicator for all ranks. May differ from commGlobal() if local worlds are in use.
Definition: UPstream.H:987
static void waitRequests()
Wait for all requests to finish.
Definition: UPstream.H:2189
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: POSIX.C:801
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:61
A non-owning sub-view of a List (allocated or unallocated storage).
Definition: SubList.H:46
dynamicFvMesh & mesh
const pointField & points
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:130
A class for handling words, derived from Foam::string.
Definition: word.H:63
bool returnReduceAnd(const bool value, const int communicator=UPstream::worldComm)
Perform logical (and) MPI Allreduce on a copy. Uses UPstream::reduceAnd.
static constexpr int masterNo() noexcept
Relative rank for the master process - is always 0.
Definition: UPstream.H:1596
metisLikeDecomp(const metisLikeDecomp &)=delete
No copy construct.
static bool write(const UPstream::commsTypes commsType, const int toProcNo, const Type *buffer, std::streamsize count, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm, UPstream::Request *req=nullptr, const UPstream::sendModes sendMode=UPstream::sendModes::normal)
Write buffer contents (contiguous types only) to given processor.
Abstract base class for domain decomposition.
virtual labelList decompose(const polyMesh &mesh, const pointField &points=pointField::null(), const scalarField &pointWeights=scalarField::null()) const
Return for every coordinate the wanted processor number.
A packed storage of objects of type <T> using an offset table for access.
int debug
Static debugging option.
virtual label decomposeSerial(const labelList &adjncy, const labelList &xadj, const List< scalar > &cellWeights, labelList &decomp) const =0
Decomposition with metis-like parameters.
Foam::word regionName(args.getOrDefault< word >("region", Foam::polyMesh::defaultRegion))
label nCells() const noexcept
Number of mesh cells.
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1619
T & back()
Access last element of the list, position [size()-1].
Definition: UListI.H:244
"nonBlocking" (immediate) : (MPI_Isend, MPI_Irecv)
messageStream Info
Information stream (stdout output on master, null elsewhere)
const List< T > & values() const noexcept
Return the packed values.
virtual label decomposeGeneral(const labelList &adjncy, const labelList &xadj, const List< scalar > &cellWeights, labelList &decomp) const
Serial and/or collect/distribute for parallel operation.
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:75
static void calcCellCells(const polyMesh &mesh, const labelUList &agglom, const label nLocalCoarse, const bool parallel, CompactListList< label > &cellCells)
Determine (local or global) cellCells from mesh agglomeration.
List< label > labelList
A List of labels.
Definition: List.H:61