ptscotchDecomp.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 | Copyright (C) 2011-2015 OpenFOAM Foundation
6  \\/ M anipulation | Copyright (C) 2015 OpenCFD Ltd.
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  From scotch forum:
25 
26  By: Francois PELLEGRINI RE: Graph mapping 'strategy' string [ reply ]
27  2008-08-22 10:09 Strategy handling in Scotch is a bit tricky. In order
28  not to be confused, you must have a clear view of how they are built.
29  Here are some rules:
30 
31  1- Strategies are made up of "methods" which are combined by means of
32  "operators".
33 
34  2- A method is of the form "m{param=value,param=value,...}", where "m"
35  is a single character (this is your first error: "f" is a method name,
36  not a parameter name).
37 
38  3- There exist different sort of strategies : bipartitioning strategies,
39  mapping strategies, ordering strategies, which cannot be mixed. For
40  instance, you cannot build a bipartitioning strategy and feed it to a
41  mapping method (this is your second error).
42 
43  To use the "mapCompute" routine, you must create a mapping strategy, not
44  a bipartitioning one, and so use stratGraphMap() and not
45  stratGraphBipart(). Your mapping strategy should however be based on the
46  "recursive bipartitioning" method ("b"). For instance, a simple (and
47  hence not very efficient) mapping strategy can be :
48 
49  "b{sep=f}"
50 
51  which computes mappings with the recursive bipartitioning method "b",
52  this latter using the Fiduccia-Mattheyses method "f" to compute its
53  separators.
54 
55  If you want an exact partition (see your previous post), try
56  "b{sep=fx}".
57 
58  However, these strategies are not the most efficient, as they do not
59  make use of the multi-level framework.
60 
61  To use the multi-level framework, try for instance:
62 
63  "b{sep=m{vert=100,low=h,asc=f}x}"
64 
65  The current default mapping strategy in Scotch can be seen by using the
66  "-vs" option of program dgpart. It is, to date:
67 
68  r
69  {
70  sep=m
71  {
72  asc=b
73  {
74  width=3,
75  bnd=(d{pass=40,dif=1,rem=0,type=b}|)
76  q{strat=f{move=80,pass=-1,bal=0.01,type=b}}
77  x{sbbt=5,bal=0.05},
78  org=q{strat=f{move=80,pass=-1,bal=0.01,type=b}}
79  x{sbbt=5,bal=0.05}
80  },
81  low=q
82  {
83  strat=
84  (
85  m
86  {
87  asc=b
88  {
89  bnd=(d{pass=40,type=b}|)
90  f{move=80,pass=-1,bal=0.05,type=b},
91  org=f{move=80,pass=-1,bal=0.05,type=b},
92  width=3
93  },
94  low=h{pass=10}
95  f{move=80,pass=-1,bal=0.05,type=b},
96  vert=80,
97  rat=0.8
98  }
99  |m
100  {
101  asc=b
102  {
103  bnd=(d{pass=40,type=b}|)
104  f{move=80,pass=-1,bal=0.05,type=b},
105  org=f{move=80,pass=-1,bal=0.05,type=b},
106  width=3
107  },
108  low=h{pass=10}
109  f{move=80,pass=-1,bal=0.05,type=b},
110  vert=80,
111  rat=0.8
112  }
113  )
114  },
115  seq=q
116  {
117  strat=
118  (
119  m
120  {
121  asc=b
122  {
123  bnd=(d{pass=40,type=b}|)
124  f{move=80,pass=-1,bal=0.05,type=b},
125  org=f{move=80,pass=-1,bal=0.05,type=b},
126  width=3
127  },
128  low=h{pass=10}
129  f{move=80,pass=-1,bal=0.05,type=b},
130  vert=80,
131  rat=0.8
132  }
133  |m
134  {
135  asc=b
136  {
137  bnd=(d{pass=40,type=b}|)
138  f{move=80,pass=-1,bal=0.05,type=b},
139  org=f{move=80,pass=-1,bal=0.05,type=b},
140  width=3
141  },
142  low=h{pass=10}
143  f{move=80,pass=-1,bal=0.05,type=b},
144  vert=80,
145  rat=0.8
146  }
147  )
148  },
149  pass=5,
150  vert=10000,
151  rat=0.8
152  },
153  seq=r
154  {
155  job=t,
156  bal=0.05,
157  map=t,
158  poli=S,
159  sep=
160  (
161  m
162  {
163  asc=b
164  {
165  bnd=(d{pass=40,type=b}|)
166  f{move=80,pass=-1,bal=0.05,type=b},
167  org=f{move=80,pass=-1,bal=0.05,type=b},
168  width=3
169  },
170  low=h{pass=10}
171  f{move=80,pass=-1,bal=0.05,type=b},
172  vert=80,
173  rat=0.8
174  }
175  |m
176  {
177  asc=b
178  {
179  bnd=(d{pass=40,type=b}|)
180  f{move=80,pass=-1,bal=0.05,type=b},
181  org=f{move=80,pass=-1,bal=0.05,type=b},
182  width=3
183  },
184  low=h{pass=10}
185  f{move=80,pass=-1,bal=0.05,type=b},
186  vert=80,
187  rat=0.8
188  }
189  )
190  },
191  bal=0.05
192  }
193 
194  Note: writeGraph=true : writes out .dgr files for debugging. Run with e.g.
195 
196  mpirun -np 4 dgpart 2 'region0_%r.dgr'
197 
198  - %r gets replaced by current processor rank
199  - decompose into 2 domains
200 
201 \*---------------------------------------------------------------------------*/
202 
203 #include "ptscotchDecomp.H"
205 #include "Time.H"
206 #include "OFstream.H"
207 #include "globalIndex.H"
208 #include "SubField.H"
209 
210 extern "C"
211 {
212  #include <stdio.h>
213  #include <mpi.h>
214  #include "ptscotch.h"
215 }
216 
217 
218 // Hack: scotch generates floating point errors so need to switch of error
219 // trapping!
220 #ifdef __GLIBC__
221 # ifndef _GNU_SOURCE
222 # define _GNU_SOURCE
223 # endif
224 # include <fenv.h>
225 #endif
226 
227 
228 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
229 
230 namespace Foam
231 {
232  defineTypeNameAndDebug(ptscotchDecomp, 0);
233 
234  addToRunTimeSelectionTable(decompositionMethod, ptscotchDecomp, dictionary);
235 }
236 
237 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
238 
239 void Foam::ptscotchDecomp::check(const int retVal, const char* str)
240 {
241  if (retVal)
242  {
244  << "Call to scotch routine " << str << " failed."
245  << exit(FatalError);
246  }
247 }
248 
249 
251 //Foam::label Foam::ptscotchDecomp::decomposeZeroDomains
252 //(
253 // const fileName& meshPath,
254 // const List<label>& initadjncy,
255 // const List<label>& initxadj,
256 // const scalarField& initcWeights,
257 //
258 // List<label>& finalDecomp
259 //) const
260 //{
261 // globalIndex globalCells(initxadj.size()-1);
262 //
263 // bool hasZeroDomain = false;
264 // for (label procI = 0; procI < Pstream::nProcs(); procI++)
265 // {
266 // if (globalCells.localSize(procI) == 0)
267 // {
268 // hasZeroDomain = true;
269 // break;
270 // }
271 // }
272 //
273 // if (!hasZeroDomain)
274 // {
275 // return decompose
276 // (
277 // meshPath,
278 // initadjncy,
279 // initxadj,
280 // initcWeights,
281 // finalDecomp
282 // );
283 // }
284 //
285 //
286 // if (debug)
287 // {
288 // Info<< "ptscotchDecomp : have graphs with locally 0 cells."
289 // << " trickling down." << endl;
290 // }
291 //
292 // // Make sure every domain has at least one cell
293 // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
294 // // (scotch does not like zero sized domains)
295 // // Trickle cells from processors that have them up to those that
296 // // don't.
297 //
298 //
299 // // Number of cells to send to the next processor
300 // // (is same as number of cells next processor has to receive)
301 // List<label> nSendCells(Pstream::nProcs(), 0);
302 //
303 // for (label procI = nSendCells.size()-1; procI >=1; procI--)
304 // {
305 // label nLocalCells = globalCells.localSize(procI);
306 // if (nLocalCells-nSendCells[procI] < 1)
307 // {
308 // nSendCells[procI-1] = nSendCells[procI]-nLocalCells+1;
309 // }
310 // }
311 //
312 // // First receive (so increasing the sizes of all arrays)
313 //
314 // Field<int> xadj(initxadj);
315 // Field<int> adjncy(initadjncy);
316 // scalarField cWeights(initcWeights);
317 //
318 // if (Pstream::myProcNo() >= 1 && nSendCells[Pstream::myProcNo()-1] > 0)
319 // {
320 // // Receive cells from previous processor
321 // IPstream fromPrevProc(Pstream::blocking, Pstream::myProcNo()-1);
322 //
323 // Field<int> prevXadj(fromPrevProc);
324 // Field<int> prevAdjncy(fromPrevProc);
325 // scalarField prevCellWeights(fromPrevProc);
326 //
327 // if (prevXadj.size() != nSendCells[Pstream::myProcNo()-1])
328 // {
329 // FatalErrorInFunction
330 // << "Expected from processor " << Pstream::myProcNo()-1
331 // << " connectivity for " << nSendCells[Pstream::myProcNo()-1]
332 // << " nCells but only received " << prevXadj.size()
333 // << abort(FatalError);
334 // }
335 //
336 // // Insert adjncy
337 // prepend(prevAdjncy, adjncy);
338 // // Adapt offsets and prepend xadj
339 // xadj += prevAdjncy.size();
340 // prepend(prevXadj, xadj);
341 // // Weights
342 // prepend(prevCellWeights, cWeights);
343 // }
344 //
345 //
346 // // Send to my next processor
347 //
348 // if (nSendCells[Pstream::myProcNo()] > 0)
349 // {
350 // // Send cells to next processor
351 // OPstream toNextProc(Pstream::blocking, Pstream::myProcNo()+1);
352 //
353 // label nCells = nSendCells[Pstream::myProcNo()];
354 // label startCell = xadj.size()-1 - nCells;
355 // label startFace = xadj[startCell];
356 // label nFaces = adjncy.size()-startFace;
357 //
358 // // Send for all cell data: last nCells elements
359 // // Send for all face data: last nFaces elements
360 // toNextProc
361 // << Field<int>::subField(xadj, nCells, startCell)-startFace
362 // << Field<int>::subField(adjncy, nFaces, startFace)
363 // <<
364 // (
365 // cWeights.size()
366 // ? static_cast<const scalarField&>
367 // (
368 // scalarField::subField(cWeights, nCells, startCell)
369 // )
370 // : scalarField(0)
371 // );
372 //
373 // // Remove data that has been sent
374 // if (cWeights.size())
375 // {
376 // cWeights.setSize(cWeights.size()-nCells);
377 // }
378 // adjncy.setSize(adjncy.size()-nFaces);
379 // xadj.setSize(xadj.size() - nCells);
380 // }
381 //
382 //
383 // // Do decomposition as normal. Sets finalDecomp.
384 // label result = decompose(meshPath, adjncy, xadj, cWeights, finalDecomp);
385 //
386 //
387 // if (debug)
388 // {
389 // Info<< "ptscotchDecomp : have graphs with locally 0 cells."
390 // << " trickling up." << endl;
391 // }
392 //
393 //
394 // // If we sent cells across make sure we undo it
395 // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
396 //
397 // // Receive back from next processor if I sent something
398 // if (nSendCells[Pstream::myProcNo()] > 0)
399 // {
400 // IPstream fromNextProc(Pstream::blocking, Pstream::myProcNo()+1);
401 //
402 // List<label> nextFinalDecomp(fromNextProc);
403 //
404 // if (nextFinalDecomp.size() != nSendCells[Pstream::myProcNo()])
405 // {
406 // FatalErrorInFunction
407 // << "Expected from processor " << Pstream::myProcNo()+1
408 // << " decomposition for " << nSendCells[Pstream::myProcNo()]
409 // << " nCells but only received " << nextFinalDecomp.size()
410 // << abort(FatalError);
411 // }
412 //
413 // append(nextFinalDecomp, finalDecomp);
414 // }
415 //
416 // // Send back to previous processor.
417 // if (Pstream::myProcNo() >= 1 && nSendCells[Pstream::myProcNo()-1] > 0)
418 // {
419 // OPstream toPrevProc(Pstream::blocking, Pstream::myProcNo()-1);
420 //
421 // label nToPrevious = nSendCells[Pstream::myProcNo()-1];
422 //
423 // toPrevProc <<
424 // SubList<label>
425 // (
426 // finalDecomp,
427 // nToPrevious,
428 // finalDecomp.size()-nToPrevious
429 // );
430 //
431 // // Remove locally what has been sent
432 // finalDecomp.setSize(finalDecomp.size()-nToPrevious);
433 // }
434 // return result;
435 //}
436 
437 
438 // Call scotch with options from dictionary.
440 (
441  const fileName& meshPath,
442  const List<label>& adjncy,
443  const List<label>& xadj,
444  const scalarField& cWeights,
445  List<label>& finalDecomp
446 ) const
447 {
448  List<label> dummyAdjncy(1);
449  List<label> dummyXadj(1);
450  dummyXadj[0] = 0;
451 
452  return decompose
453  (
454  meshPath,
455  adjncy.size(),
456  (adjncy.size() ? adjncy.begin() : dummyAdjncy.begin()),
457  xadj.size(),
458  (xadj.size() ? xadj.begin() : dummyXadj.begin()),
459  cWeights,
460  finalDecomp
461  );
462 }
463 
464 
465 // Call scotch with options from dictionary.
467 (
468  const fileName& meshPath,
469  const label adjncySize,
470  const label adjncy[],
471  const label xadjSize,
472  const label xadj[],
473  const scalarField& cWeights,
474 
475  List<label>& finalDecomp
476 ) const
477 {
478  if (debug)
479  {
480  Pout<< "ptscotchDecomp : entering with xadj:" << xadjSize << endl;
481  }
482 
483  // Dump graph
484  if (decompositionDict_.found("scotchCoeffs"))
485  {
486  const dictionary& scotchCoeffs =
487  decompositionDict_.subDict("scotchCoeffs");
488 
489  if (scotchCoeffs.lookupOrDefault("writeGraph", false))
490  {
491  OFstream str
492  (
493  meshPath + "_" + Foam::name(Pstream::myProcNo()) + ".dgr"
494  );
495 
496  Pout<< "Dumping Scotch graph file to " << str.name() << endl
497  << "Use this in combination with dgpart." << endl;
498 
499  globalIndex globalCells(xadjSize-1);
500 
501  // Distributed graph file (.grf)
502  label version = 2;
503  str << version << nl;
504  // Number of files (procglbnbr)
505  str << Pstream::nProcs();
506  // My file number (procloc)
507  str << ' ' << Pstream::myProcNo() << nl;
508 
509  // Total number of vertices (vertglbnbr)
510  str << globalCells.size();
511  // Total number of connections (edgeglbnbr)
512  str << ' ' << returnReduce(xadj[xadjSize-1], sumOp<label>())
513  << nl;
514  // Local number of vertices (vertlocnbr)
515  str << xadjSize-1;
516  // Local number of connections (edgelocnbr)
517  str << ' ' << xadj[xadjSize-1] << nl;
518  // Numbering starts from 0
519  label baseval = 0;
520  // 100*hasVertlabels+10*hasEdgeWeights+1*hasVertWeighs
521  str << baseval << ' ' << "000" << nl;
522  for (label cellI = 0; cellI < xadjSize-1; cellI++)
523  {
524  label start = xadj[cellI];
525  label end = xadj[cellI+1];
526  str << end-start;
527 
528  for (label i = start; i < end; i++)
529  {
530  str << ' ' << adjncy[i];
531  }
532  str << nl;
533  }
534  }
535  }
536 
537  // Strategy
538  // ~~~~~~~~
539 
540  // Default.
541  SCOTCH_Strat stradat;
542  check(SCOTCH_stratInit(&stradat), "SCOTCH_stratInit");
543 
544  if (decompositionDict_.found("scotchCoeffs"))
545  {
546  const dictionary& scotchCoeffs =
547  decompositionDict_.subDict("scotchCoeffs");
548 
549 
550  string strategy;
551  if (scotchCoeffs.readIfPresent("strategy", strategy))
552  {
553  if (debug)
554  {
555  Info<< "ptscotchDecomp : Using strategy " << strategy << endl;
556  }
557  SCOTCH_stratDgraphMap(&stradat, strategy.c_str());
558  //fprintf(stdout, "S\tStrat=");
559  //SCOTCH_stratSave(&stradat, stdout);
560  //fprintf(stdout, "\n");
561  }
562  }
563 
564 
565  // Graph
566  // ~~~~~
567 
568  List<label> velotab;
569 
570 
571  // Check for externally provided cellweights and if so initialise weights
572 
573  scalar minWeights = gMin(cWeights);
574  scalar maxWeights = gMax(cWeights);
575 
576  if (maxWeights > minWeights)
577  {
578  if (minWeights <= 0)
579  {
581  << "Illegal minimum weight " << minWeights
582  << endl;
583  }
584 
585  if (cWeights.size() != xadjSize-1)
586  {
588  << "Number of cell weights " << cWeights.size()
589  << " does not equal number of cells " << xadjSize-1
590  << exit(FatalError);
591  }
592  }
593 
594  scalar velotabSum = gSum(cWeights)/minWeights;
595 
596  scalar rangeScale(1.0);
597 
598  if (Pstream::master())
599  {
600  if (velotabSum > scalar(labelMax - 1))
601  {
602  // 0.9 factor of safety to avoid floating point round-off in
603  // rangeScale tipping the subsequent sum over the integer limit.
604  rangeScale = 0.9*scalar(labelMax - 1)/velotabSum;
605 
607  << "Sum of weights has overflowed integer: " << velotabSum
608  << ", compressing weight scale by a factor of " << rangeScale
609  << endl;
610  }
611  }
612 
613  Pstream::scatter(rangeScale);
614 
615  if (maxWeights > minWeights)
616  {
617  if (cWeights.size())
618  {
619  // Convert to integers.
620  velotab.setSize(cWeights.size());
621 
622  forAll(velotab, i)
623  {
624  velotab[i] = int((cWeights[i]/minWeights - 1)*rangeScale) + 1;
625  }
626  }
627  else
628  {
629  // Locally zero cells but not globally. Make sure we have
630  // some size so .begin() does not return null pointer. Data
631  // itself is never used.
632  velotab.setSize(1);
633  velotab[0] = 1;
634  }
635  }
636 
637 
638 
639  if (debug)
640  {
641  Pout<< "SCOTCH_dgraphInit" << endl;
642  }
643  SCOTCH_Dgraph grafdat;
644  check(SCOTCH_dgraphInit(&grafdat, MPI_COMM_WORLD), "SCOTCH_dgraphInit");
645 
646 
647  if (debug)
648  {
649  Pout<< "SCOTCH_dgraphBuild with:" << nl
650  << "xadjSize-1 : " << xadjSize-1 << nl
651  << "xadj : " << uintptr_t(xadj) << nl
652  << "velotab : " << uintptr_t(velotab.begin()) << nl
653  << "adjncySize : " << adjncySize << nl
654  << "adjncy : " << uintptr_t(adjncy) << nl
655  << endl;
656  }
657 
658  check
659  (
660  SCOTCH_dgraphBuild
661  (
662  &grafdat, // grafdat
663  0, // baseval, c-style numbering
664  xadjSize-1, // vertlocnbr, nCells
665  xadjSize-1, // vertlocmax
666  const_cast<SCOTCH_Num*>(xadj),
667  // vertloctab, start index per cell into
668  // adjncy
669  const_cast<SCOTCH_Num*>(xadj+1),// vendloctab, end index ,,
670 
671  const_cast<SCOTCH_Num*>(velotab.begin()),// veloloctab, vtx weights
672  NULL, // vlblloctab
673 
674  adjncySize, // edgelocnbr, number of arcs
675  adjncySize, // edgelocsiz
676  const_cast<SCOTCH_Num*>(adjncy), // edgeloctab
677  NULL, // edgegsttab
678  NULL // edlotab, edge weights
679  ),
680  "SCOTCH_dgraphBuild"
681  );
682 
683 
684  if (debug)
685  {
686  Pout<< "SCOTCH_dgraphCheck" << endl;
687  }
688  check(SCOTCH_dgraphCheck(&grafdat), "SCOTCH_dgraphCheck");
689 
690 
691  // Architecture
692  // ~~~~~~~~~~~~
693  // (fully connected network topology since using switch)
694 
695  if (debug)
696  {
697  Pout<< "SCOTCH_archInit" << endl;
698  }
699  SCOTCH_Arch archdat;
700  check(SCOTCH_archInit(&archdat), "SCOTCH_archInit");
701 
702  List<label> processorWeights;
703  if (decompositionDict_.found("scotchCoeffs"))
704  {
705  const dictionary& scotchCoeffs =
706  decompositionDict_.subDict("scotchCoeffs");
707 
708  scotchCoeffs.readIfPresent("processorWeights", processorWeights);
709  }
710  if (processorWeights.size())
711  {
712  if (debug)
713  {
714  Info<< "ptscotchDecomp : Using procesor weights "
715  << processorWeights
716  << endl;
717  }
718  check
719  (
720  SCOTCH_archCmpltw(&archdat, nProcessors_, processorWeights.begin()),
721  "SCOTCH_archCmpltw"
722  );
723  }
724  else
725  {
726  if (debug)
727  {
728  Pout<< "SCOTCH_archCmplt" << endl;
729  }
730  check
731  (
732  SCOTCH_archCmplt(&archdat, nProcessors_),
733  "SCOTCH_archCmplt"
734  );
735  }
736 
737 
738  // Hack:switch off fpu error trapping
739 # ifdef FE_NOMASK_ENV
740  int oldExcepts = fedisableexcept
741  (
742  FE_DIVBYZERO
743  | FE_INVALID
744  | FE_OVERFLOW
745  );
746 # endif
747 
748 
749  // Note: always provide allocated storage even if local size 0
750  finalDecomp.setSize(max(1, xadjSize-1));
751  finalDecomp = 0;
752 
753  if (debug)
754  {
755  Pout<< "SCOTCH_dgraphMap" << endl;
756  }
757  check
758  (
759  SCOTCH_dgraphMap
760  (
761  &grafdat,
762  &archdat,
763  &stradat, // const SCOTCH_Strat *
764  finalDecomp.begin() // parttab
765  ),
766  "SCOTCH_graphMap"
767  );
768 
769 # ifdef FE_NOMASK_ENV
770  feenableexcept(oldExcepts);
771 # endif
772 
773 
774 
775  //finalDecomp.setSize(xadjSize-1);
776  //check
777  //(
778  // SCOTCH_dgraphPart
779  // (
780  // &grafdat,
781  // nProcessors_, // partnbr
782  // &stradat, // const SCOTCH_Strat *
783  // finalDecomp.begin() // parttab
784  // ),
785  // "SCOTCH_graphPart"
786  //);
787 
788  if (debug)
789  {
790  Pout<< "SCOTCH_dgraphExit" << endl;
791  }
792  // Release storage for graph
793  SCOTCH_dgraphExit(&grafdat);
794  // Release storage for strategy
795  SCOTCH_stratExit(&stradat);
796  // Release storage for network topology
797  SCOTCH_archExit(&archdat);
798 
799  return 0;
800 }
801 
802 
803 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
804 
805 Foam::ptscotchDecomp::ptscotchDecomp(const dictionary& decompositionDict)
806 :
807  decompositionMethod(decompositionDict)
808 {}
809 
810 
811 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
812 
814 (
815  const polyMesh& mesh,
816  const pointField& points,
817  const scalarField& pointWeights
818 )
819 {
820  if (points.size() != mesh.nCells())
821  {
823  << "Can use this decomposition method only for the whole mesh"
824  << endl
825  << "and supply one coordinate (cellCentre) for every cell." << endl
826  << "The number of coordinates " << points.size() << endl
827  << "The number of cells in the mesh " << mesh.nCells()
828  << exit(FatalError);
829  }
830 
831 
832  // Make Metis CSR (Compressed Storage Format) storage
833  // adjncy : contains neighbours (= edges in graph)
834  // xadj(celli) : start of information in adjncy for celli
835 
836 
837  CompactListList<label> cellCells;
838  calcCellCells
839  (
840  mesh,
841  identity(mesh.nCells()),
842  mesh.nCells(),
843  true,
844  cellCells
845  );
846 
847  // Decompose using default weights
848  List<label> finalDecomp;
849  decompose
850  (
851  mesh.time().path()/mesh.name(),
852  cellCells.m(),
853  cellCells.offsets(),
854  pointWeights,
855  finalDecomp
856  );
857 
858  // Copy back to labelList
859  labelList decomp(points.size());
860  forAll(decomp, i)
861  {
862  decomp[i] = finalDecomp[i];
863  }
864  return decomp;
865 }
866 
867 
869 (
870  const polyMesh& mesh,
871  const labelList& agglom,
872  const pointField& agglomPoints,
873  const scalarField& pointWeights
874 )
875 {
876  if (agglom.size() != mesh.nCells())
877  {
879  << "Size of cell-to-coarse map " << agglom.size()
880  << " differs from number of cells in mesh " << mesh.nCells()
881  << exit(FatalError);
882  }
883 
884 
885  // Make Metis CSR (Compressed Storage Format) storage
886  // adjncy : contains neighbours (= edges in graph)
887  // xadj(celli) : start of information in adjncy for celli
888  CompactListList<label> cellCells;
889  calcCellCells
890  (
891  mesh,
892  agglom,
893  agglomPoints.size(),
894  true,
895  cellCells
896  );
897 
898  // Decompose using weights
899  List<label> finalDecomp;
900  decompose
901  (
902  mesh.time().path()/mesh.name(),
903  cellCells.m(),
904  cellCells.offsets(),
905  pointWeights,
906  finalDecomp
907  );
908 
909  // Rework back into decomposition for original mesh
910  labelList fineDistribution(agglom.size());
911 
912  forAll(fineDistribution, i)
913  {
914  fineDistribution[i] = finalDecomp[agglom[i]];
915  }
916 
917  return fineDistribution;
918 }
919 
920 
922 (
923  const labelListList& globalCellCells,
924  const pointField& cellCentres,
925  const scalarField& cWeights
926 )
927 {
928  if (cellCentres.size() != globalCellCells.size())
929  {
931  << "Inconsistent number of cells (" << globalCellCells.size()
932  << ") and number of cell centres (" << cellCentres.size()
933  << ")." << exit(FatalError);
934  }
935 
936 
937  // Make Metis CSR (Compressed Storage Format) storage
938  // adjncy : contains neighbours (= edges in graph)
939  // xadj(celli) : start of information in adjncy for celli
940 
941  CompactListList<label> cellCells(globalCellCells);
942 
943  // Decompose using weights
944  List<label> finalDecomp;
945  decompose
946  (
947  "ptscotch",
948  cellCells.m(),
949  cellCells.offsets(),
950  cWeights,
951  finalDecomp
952  );
953 
954  // Copy back to labelList
955  labelList decomp(cellCentres.size());
956  forAll(decomp, i)
957  {
958  decomp[i] = finalDecomp[i];
959  }
960  return decomp;
961 }
962 
963 
964 // ************************************************************************* //
Foam::pointField
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
Foam::scalarField
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Definition: primitiveFieldsFwd.H:48
SubField.H
Foam::labelList
List< label > labelList
A List of labels.
Definition: labelList.H:56
Foam::returnReduce
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
Definition: PstreamReduceOps.H:86
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:406
Foam::addToRunTimeSelectionTable
addToRunTimeSelectionTable(ensightPart, ensightPartCells, istream)
globalIndex.H
Foam::labelMax
static const label labelMax
Definition: label.H:62
Foam::UPstream::nProcs
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:387
Foam::Pstream::scatter
static void scatter(const List< commsStruct > &comms, T &Value, const int tag, const label comm)
Scatter data. Distribute without modification. Reverse of gather.
Definition: gatherScatter.C:147
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
Foam::gSum
Type gSum(const FieldField< Field, Type > &f)
Definition: FieldFieldFunctions.C:564
OFstream.H
Foam::primitiveMesh::nCells
label nCells() const
Definition: primitiveMeshI.H:64
List::size
int size() const
Definition: ListI.H:83
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::nl
static const char nl
Definition: Ostream.H:260
Foam::Info
messageStream Info
Foam::OSstream::name
virtual const fileName & name() const
Return the name of the stream.
Definition: OSstream.H:88
Foam::ptscotchDecomp::ptscotchDecomp
ptscotchDecomp(const ptscotchDecomp &)
Foam::identity
labelList identity(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
Foam::FatalError
error FatalError
Foam::HashTable::size
label size() const
Return number of elements in table.
Definition: HashTableI.H:65
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:18
addToRunTimeSelectionTable.H
Macros for easy insertion into run-time selection tables.
Foam
Namespace for OpenFOAM.
Definition: combustionModel.C:30
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
Foam::UPstream::myProcNo
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:405
Foam::UPstream::master
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:399
Foam::max
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
Foam::labelListList
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:57
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:318
Foam::Time::path
fileName path() const
Return path.
Definition: Time.H:281
Foam::Pout
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
Foam::ptscotchDecomp::decompose
label decompose(const fileName &meshPath, const List< label > &adjncy, const List< label > &xadj, const scalarField &cWeights, List< label > &finalDecomp) const
Decompose. Handles size 0 arrays.
Definition: dummyPtscotchDecomp.C:62
Foam::ptscotchDecomp::check
static void check(const int, const char *)
Check and print error message.
Definition: dummyPtscotchDecomp.C:57
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
points
const pointField & points
Definition: gmvOutputHeader.H:1
Foam::fvMesh::time
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:243
ptscotchDecomp.H
List
Definition: Test.C:19
Foam::gMin
Type gMin(const FieldField< Field, Type > &f)
Definition: FieldFieldFunctions.C:563
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:259
Foam::gMax
Type gMax(const FieldField< Field, Type > &f)
Definition: FieldFieldFunctions.C:562
Foam::name
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
Foam::fvMesh::name
const word & name() const
Return reference to name.
Definition: fvMesh.H:257