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-2016 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 "ptscotchDecomp.H"
28 #include "Time.H"
29 #include "OFstream.H"
30 #include "globalIndex.H"
31 #include "SubField.H"
32 
33 extern "C"
34 {
35  #include <stdio.h>
36  #include <mpi.h>
37  #include "ptscotch.h"
38 }
39 
40 
41 // Hack: scotch generates floating point errors so need to switch of error
42 // trapping!
43 #ifdef __GLIBC__
44  #ifndef _GNU_SOURCE
45  #define _GNU_SOURCE
46  #endif
47  #include <fenv.h>
48 #endif
49 
50 
51 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
52 
53 namespace Foam
54 {
55  defineTypeNameAndDebug(ptscotchDecomp, 0);
56 
57  addToRunTimeSelectionTable(decompositionMethod, ptscotchDecomp, dictionary);
58 }
59 
60 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
61 
62 void Foam::ptscotchDecomp::check(const int retVal, const char* str)
63 {
64  if (retVal)
65  {
67  << "Call to scotch routine " << str << " failed."
68  << exit(FatalError);
69  }
70 }
71 
72 
74 //Foam::label Foam::ptscotchDecomp::decomposeZeroDomains
75 //(
76 // const fileName& meshPath,
77 // const List<label>& initadjncy,
78 // const List<label>& initxadj,
79 // const scalarField& initcWeights,
80 //
81 // List<label>& finalDecomp
82 //) const
83 //{
84 // globalIndex globalCells(initxadj.size()-1);
85 //
86 // bool hasZeroDomain = false;
87 // for (label proci = 0; proci < Pstream::nProcs(); proci++)
88 // {
89 // if (globalCells.localSize(proci) == 0)
90 // {
91 // hasZeroDomain = true;
92 // break;
93 // }
94 // }
95 //
96 // if (!hasZeroDomain)
97 // {
98 // return decompose
99 // (
100 // meshPath,
101 // initadjncy,
102 // initxadj,
103 // initcWeights,
104 // finalDecomp
105 // );
106 // }
107 //
108 //
109 // if (debug)
110 // {
111 // Info<< "ptscotchDecomp : have graphs with locally 0 cells."
112 // << " trickling down." << endl;
113 // }
114 //
115 // // Make sure every domain has at least one cell
116 // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
117 // // (scotch does not like zero sized domains)
118 // // Trickle cells from processors that have them up to those that
119 // // don't.
120 //
121 //
122 // // Number of cells to send to the next processor
123 // // (is same as number of cells next processor has to receive)
124 // List<label> nSendCells(Pstream::nProcs(), 0);
125 //
126 // for (label proci = nSendCells.size()-1; proci >=1; proci--)
127 // {
128 // label nLocalCells = globalCells.localSize(proci);
129 // if (nLocalCells-nSendCells[proci] < 1)
130 // {
131 // nSendCells[proci-1] = nSendCells[proci]-nLocalCells+1;
132 // }
133 // }
134 //
135 // // First receive (so increasing the sizes of all arrays)
136 //
137 // Field<int> xadj(initxadj);
138 // Field<int> adjncy(initadjncy);
139 // scalarField cWeights(initcWeights);
140 //
141 // if (Pstream::myProcNo() >= 1 && nSendCells[Pstream::myProcNo()-1] > 0)
142 // {
143 // // Receive cells from previous processor
144 // IPstream fromPrevProc(Pstream::blocking, Pstream::myProcNo()-1);
145 //
146 // Field<int> prevXadj(fromPrevProc);
147 // Field<int> prevAdjncy(fromPrevProc);
148 // scalarField prevCellWeights(fromPrevProc);
149 //
150 // if (prevXadj.size() != nSendCells[Pstream::myProcNo()-1])
151 // {
152 // FatalErrorInFunction
153 // << "Expected from processor " << Pstream::myProcNo()-1
154 // << " connectivity for " << nSendCells[Pstream::myProcNo()-1]
155 // << " nCells but only received " << prevXadj.size()
156 // << abort(FatalError);
157 // }
158 //
159 // // Insert adjncy
160 // prepend(prevAdjncy, adjncy);
161 // // Adapt offsets and prepend xadj
162 // xadj += prevAdjncy.size();
163 // prepend(prevXadj, xadj);
164 // // Weights
165 // prepend(prevCellWeights, cWeights);
166 // }
167 //
168 //
169 // // Send to my next processor
170 //
171 // if (nSendCells[Pstream::myProcNo()] > 0)
172 // {
173 // // Send cells to next processor
174 // OPstream toNextProc(Pstream::blocking, Pstream::myProcNo()+1);
175 //
176 // label nCells = nSendCells[Pstream::myProcNo()];
177 // label startCell = xadj.size()-1 - nCells;
178 // label startFace = xadj[startCell];
179 // label nFaces = adjncy.size()-startFace;
180 //
181 // // Send for all cell data: last nCells elements
182 // // Send for all face data: last nFaces elements
183 // toNextProc
184 // << Field<int>::subField(xadj, nCells, startCell)-startFace
185 // << Field<int>::subField(adjncy, nFaces, startFace)
186 // <<
187 // (
188 // cWeights.size()
189 // ? static_cast<const scalarField&>
190 // (
191 // scalarField::subField(cWeights, nCells, startCell)
192 // )
193 // : scalarField(0)
194 // );
195 //
196 // // Remove data that has been sent
197 // if (cWeights.size())
198 // {
199 // cWeights.setSize(cWeights.size()-nCells);
200 // }
201 // adjncy.setSize(adjncy.size()-nFaces);
202 // xadj.setSize(xadj.size() - nCells);
203 // }
204 //
205 //
206 // // Do decomposition as normal. Sets finalDecomp.
207 // label result = decompose(meshPath, adjncy, xadj, cWeights, finalDecomp);
208 //
209 //
210 // if (debug)
211 // {
212 // Info<< "ptscotchDecomp : have graphs with locally 0 cells."
213 // << " trickling up." << endl;
214 // }
215 //
216 //
217 // // If we sent cells across make sure we undo it
218 // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
219 //
220 // // Receive back from next processor if I sent something
221 // if (nSendCells[Pstream::myProcNo()] > 0)
222 // {
223 // IPstream fromNextProc(Pstream::blocking, Pstream::myProcNo()+1);
224 //
225 // List<label> nextFinalDecomp(fromNextProc);
226 //
227 // if (nextFinalDecomp.size() != nSendCells[Pstream::myProcNo()])
228 // {
229 // FatalErrorInFunction
230 // << "Expected from processor " << Pstream::myProcNo()+1
231 // << " decomposition for " << nSendCells[Pstream::myProcNo()]
232 // << " nCells but only received " << nextFinalDecomp.size()
233 // << abort(FatalError);
234 // }
235 //
236 // append(nextFinalDecomp, finalDecomp);
237 // }
238 //
239 // // Send back to previous processor.
240 // if (Pstream::myProcNo() >= 1 && nSendCells[Pstream::myProcNo()-1] > 0)
241 // {
242 // OPstream toPrevProc(Pstream::blocking, Pstream::myProcNo()-1);
243 //
244 // label nToPrevious = nSendCells[Pstream::myProcNo()-1];
245 //
246 // toPrevProc <<
247 // SubList<label>
248 // (
249 // finalDecomp,
250 // nToPrevious,
251 // finalDecomp.size()-nToPrevious
252 // );
253 //
254 // // Remove locally what has been sent
255 // finalDecomp.setSize(finalDecomp.size()-nToPrevious);
256 // }
257 // return result;
258 //}
259 
260 
261 // Call scotch with options from dictionary.
262 Foam::label Foam::ptscotchDecomp::decompose
263 (
264  const fileName& meshPath,
265  const List<label>& adjncy,
266  const List<label>& xadj,
267  const scalarField& cWeights,
268  List<label>& finalDecomp
269 ) const
270 {
271  List<label> dummyAdjncy(1);
272  List<label> dummyXadj(1);
273  dummyXadj[0] = 0;
274 
275  return decompose
276  (
277  meshPath,
278  adjncy.size(),
279  (adjncy.size() ? adjncy.begin() : dummyAdjncy.begin()),
280  xadj.size(),
281  (xadj.size() ? xadj.begin() : dummyXadj.begin()),
282  cWeights,
283  finalDecomp
284  );
285 }
286 
287 
288 // Call scotch with options from dictionary.
289 Foam::label Foam::ptscotchDecomp::decompose
290 (
291  const fileName& meshPath,
292  const label adjncySize,
293  const label adjncy[],
294  const label xadjSize,
295  const label xadj[],
296  const scalarField& cWeights,
297 
298  List<label>& finalDecomp
299 ) const
300 {
301  if (debug)
302  {
303  Pout<< "ptscotchDecomp : entering with xadj:" << xadjSize << endl;
304  }
305 
306  // Dump graph
307  if (decompositionDict_.found("scotchCoeffs"))
308  {
309  const dictionary& scotchCoeffs =
310  decompositionDict_.subDict("scotchCoeffs");
311 
312  if (scotchCoeffs.lookupOrDefault("writeGraph", false))
313  {
314  OFstream str
315  (
316  meshPath + "_" + Foam::name(Pstream::myProcNo()) + ".dgr"
317  );
318 
319  Pout<< "Dumping Scotch graph file to " << str.name() << endl
320  << "Use this in combination with dgpart." << endl;
321 
322  globalIndex globalCells(xadjSize-1);
323 
324  // Distributed graph file (.grf)
325  label version = 2;
326  str << version << nl;
327  // Number of files (procglbnbr)
328  str << Pstream::nProcs();
329  // My file number (procloc)
330  str << ' ' << Pstream::myProcNo() << nl;
331 
332  // Total number of vertices (vertglbnbr)
333  str << globalCells.size();
334  // Total number of connections (edgeglbnbr)
335  str << ' ' << returnReduce(xadj[xadjSize-1], sumOp<label>())
336  << nl;
337  // Local number of vertices (vertlocnbr)
338  str << xadjSize-1;
339  // Local number of connections (edgelocnbr)
340  str << ' ' << xadj[xadjSize-1] << nl;
341  // Numbering starts from 0
342  label baseval = 0;
343  // 100*hasVertlabels+10*hasEdgeWeights+1*hasVertWeighs
344  str << baseval << ' ' << "000" << nl;
345  for (label celli = 0; celli < xadjSize-1; celli++)
346  {
347  label start = xadj[celli];
348  label end = xadj[celli+1];
349  str << end-start;
350 
351  for (label i = start; i < end; i++)
352  {
353  str << ' ' << adjncy[i];
354  }
355  str << nl;
356  }
357  }
358  }
359 
360  // Strategy
361  // ~~~~~~~~
362 
363  // Default.
364  SCOTCH_Strat stradat;
365  check(SCOTCH_stratInit(&stradat), "SCOTCH_stratInit");
366 
367  if (decompositionDict_.found("scotchCoeffs"))
368  {
369  const dictionary& scotchCoeffs =
370  decompositionDict_.subDict("scotchCoeffs");
371 
372 
373  string strategy;
374  if (scotchCoeffs.readIfPresent("strategy", strategy))
375  {
376  if (debug)
377  {
378  Info<< "ptscotchDecomp : Using strategy " << strategy << endl;
379  }
380  SCOTCH_stratDgraphMap(&stradat, strategy.c_str());
381  //fprintf(stdout, "S\tStrat=");
382  //SCOTCH_stratSave(&stradat, stdout);
383  //fprintf(stdout, "\n");
384  }
385  }
386 
387 
388  // Graph
389  // ~~~~~
390 
391  List<label> velotab;
392 
393 
394  // Check for externally provided cellweights and if so initialise weights
395 
396  scalar minWeights = gMin(cWeights);
397  scalar maxWeights = gMax(cWeights);
398 
399  if (maxWeights > minWeights)
400  {
401  if (minWeights <= 0)
402  {
404  << "Illegal minimum weight " << minWeights
405  << endl;
406  }
407 
408  if (cWeights.size() != xadjSize-1)
409  {
411  << "Number of cell weights " << cWeights.size()
412  << " does not equal number of cells " << xadjSize-1
413  << exit(FatalError);
414  }
415  }
416 
417  scalar velotabSum = gSum(cWeights)/minWeights;
418 
419  scalar rangeScale(1.0);
420 
421  if (Pstream::master())
422  {
423  if (velotabSum > scalar(labelMax - 1))
424  {
425  // 0.9 factor of safety to avoid floating point round-off in
426  // rangeScale tipping the subsequent sum over the integer limit.
427  rangeScale = 0.9*scalar(labelMax - 1)/velotabSum;
428 
430  << "Sum of weights has overflowed integer: " << velotabSum
431  << ", compressing weight scale by a factor of " << rangeScale
432  << endl;
433  }
434  }
435 
436  Pstream::scatter(rangeScale);
437 
438  if (maxWeights > minWeights)
439  {
440  if (cWeights.size())
441  {
442  // Convert to integers.
443  velotab.setSize(cWeights.size());
444 
445  forAll(velotab, i)
446  {
447  velotab[i] = int((cWeights[i]/minWeights - 1)*rangeScale) + 1;
448  }
449  }
450  else
451  {
452  // Locally zero cells but not globally. Make sure we have
453  // some size so .begin() does not return null pointer. Data
454  // itself is never used.
455  velotab.setSize(1);
456  velotab[0] = 1;
457  }
458  }
459 
460 
461 
462  if (debug)
463  {
464  Pout<< "SCOTCH_dgraphInit" << endl;
465  }
466  SCOTCH_Dgraph grafdat;
467  check(SCOTCH_dgraphInit(&grafdat, MPI_COMM_WORLD), "SCOTCH_dgraphInit");
468 
469 
470  if (debug)
471  {
472  Pout<< "SCOTCH_dgraphBuild with:" << nl
473  << "xadjSize-1 : " << xadjSize-1 << nl
474  << "xadj : " << uintptr_t(xadj) << nl
475  << "velotab : " << uintptr_t(velotab.begin()) << nl
476  << "adjncySize : " << adjncySize << nl
477  << "adjncy : " << uintptr_t(adjncy) << nl
478  << endl;
479  }
480 
481  check
482  (
483  SCOTCH_dgraphBuild
484  (
485  &grafdat, // grafdat
486  0, // baseval, c-style numbering
487  xadjSize-1, // vertlocnbr, nCells
488  xadjSize-1, // vertlocmax
489  const_cast<SCOTCH_Num*>(xadj),
490  // vertloctab, start index per cell into
491  // adjncy
492  const_cast<SCOTCH_Num*>(xadj+1),// vendloctab, end index ,,
493 
494  const_cast<SCOTCH_Num*>(velotab.begin()),// veloloctab, vtx weights
495  NULL, // vlblloctab
496 
497  adjncySize, // edgelocnbr, number of arcs
498  adjncySize, // edgelocsiz
499  const_cast<SCOTCH_Num*>(adjncy), // edgeloctab
500  NULL, // edgegsttab
501  NULL // edlotab, edge weights
502  ),
503  "SCOTCH_dgraphBuild"
504  );
505 
506 
507  if (debug)
508  {
509  Pout<< "SCOTCH_dgraphCheck" << endl;
510  }
511  check(SCOTCH_dgraphCheck(&grafdat), "SCOTCH_dgraphCheck");
512 
513 
514  // Architecture
515  // ~~~~~~~~~~~~
516  // (fully connected network topology since using switch)
517 
518  if (debug)
519  {
520  Pout<< "SCOTCH_archInit" << endl;
521  }
522  SCOTCH_Arch archdat;
523  check(SCOTCH_archInit(&archdat), "SCOTCH_archInit");
524 
525  List<label> processorWeights;
526  if (decompositionDict_.found("scotchCoeffs"))
527  {
528  const dictionary& scotchCoeffs =
529  decompositionDict_.subDict("scotchCoeffs");
530 
531  scotchCoeffs.readIfPresent("processorWeights", processorWeights);
532  }
533  if (processorWeights.size())
534  {
535  if (debug)
536  {
537  Info<< "ptscotchDecomp : Using procesor weights "
538  << processorWeights
539  << endl;
540  }
541  check
542  (
543  SCOTCH_archCmpltw(&archdat, nProcessors_, processorWeights.begin()),
544  "SCOTCH_archCmpltw"
545  );
546  }
547  else
548  {
549  if (debug)
550  {
551  Pout<< "SCOTCH_archCmplt" << endl;
552  }
553  check
554  (
555  SCOTCH_archCmplt(&archdat, nProcessors_),
556  "SCOTCH_archCmplt"
557  );
558  }
559 
560 
561  // Hack:switch off fpu error trapping
562  #ifdef FE_NOMASK_ENV
563  int oldExcepts = fedisableexcept
564  (
565  FE_DIVBYZERO
566  | FE_INVALID
567  | FE_OVERFLOW
568  );
569  #endif
570 
571 
572  // Note: always provide allocated storage even if local size 0
573  finalDecomp.setSize(max(1, xadjSize-1));
574  finalDecomp = 0;
575 
576  if (debug)
577  {
578  Pout<< "SCOTCH_dgraphMap" << endl;
579  }
580  check
581  (
582  SCOTCH_dgraphMap
583  (
584  &grafdat,
585  &archdat,
586  &stradat, // const SCOTCH_Strat *
587  finalDecomp.begin() // parttab
588  ),
589  "SCOTCH_graphMap"
590  );
591 
592  #ifdef FE_NOMASK_ENV
593  feenableexcept(oldExcepts);
594  #endif
595 
596 
597 
598  //finalDecomp.setSize(xadjSize-1);
599  //check
600  //(
601  // SCOTCH_dgraphPart
602  // (
603  // &grafdat,
604  // nProcessors_, // partnbr
605  // &stradat, // const SCOTCH_Strat *
606  // finalDecomp.begin() // parttab
607  // ),
608  // "SCOTCH_graphPart"
609  //);
610 
611  if (debug)
612  {
613  Pout<< "SCOTCH_dgraphExit" << endl;
614  }
615  // Release storage for graph
616  SCOTCH_dgraphExit(&grafdat);
617  // Release storage for strategy
618  SCOTCH_stratExit(&stradat);
619  // Release storage for network topology
620  SCOTCH_archExit(&archdat);
621 
622  return 0;
623 }
624 
625 
626 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
627 
628 Foam::ptscotchDecomp::ptscotchDecomp(const dictionary& decompositionDict)
629 :
630  decompositionMethod(decompositionDict)
631 {}
632 
633 
634 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
635 
636 Foam::labelList Foam::ptscotchDecomp::decompose
637 (
638  const polyMesh& mesh,
639  const pointField& points,
640  const scalarField& pointWeights
641 )
642 {
643  if (points.size() != mesh.nCells())
644  {
646  << "Can use this decomposition method only for the whole mesh"
647  << endl
648  << "and supply one coordinate (cellCentre) for every cell." << endl
649  << "The number of coordinates " << points.size() << endl
650  << "The number of cells in the mesh " << mesh.nCells()
651  << exit(FatalError);
652  }
653 
654 
655  // Make Metis CSR (Compressed Storage Format) storage
656  // adjncy : contains neighbours (= edges in graph)
657  // xadj(celli) : start of information in adjncy for celli
658 
659 
660  CompactListList<label> cellCells;
662  (
663  mesh,
664  identity(mesh.nCells()),
665  mesh.nCells(),
666  true,
667  cellCells
668  );
669 
670  // Decompose using default weights
671  List<label> finalDecomp;
672  decompose
673  (
674  mesh.time().path()/mesh.name(),
675  cellCells.m(),
676  cellCells.offsets(),
677  pointWeights,
678  finalDecomp
679  );
680 
681  // Copy back to labelList
682  labelList decomp(points.size());
683  forAll(decomp, i)
684  {
685  decomp[i] = finalDecomp[i];
686  }
687  return decomp;
688 }
689 
690 
691 Foam::labelList Foam::ptscotchDecomp::decompose
692 (
693  const polyMesh& mesh,
694  const labelList& agglom,
695  const pointField& agglomPoints,
696  const scalarField& pointWeights
697 )
698 {
699  if (agglom.size() != mesh.nCells())
700  {
702  << "Size of cell-to-coarse map " << agglom.size()
703  << " differs from number of cells in mesh " << mesh.nCells()
704  << exit(FatalError);
705  }
706 
707 
708  // Make Metis CSR (Compressed Storage Format) storage
709  // adjncy : contains neighbours (= edges in graph)
710  // xadj(celli) : start of information in adjncy for celli
711  CompactListList<label> cellCells;
713  (
714  mesh,
715  agglom,
716  agglomPoints.size(),
717  true,
718  cellCells
719  );
720 
721  // Decompose using weights
722  List<label> finalDecomp;
723  decompose
724  (
725  mesh.time().path()/mesh.name(),
726  cellCells.m(),
727  cellCells.offsets(),
728  pointWeights,
729  finalDecomp
730  );
731 
732  // Rework back into decomposition for original mesh
733  labelList fineDistribution(agglom.size());
734 
735  forAll(fineDistribution, i)
736  {
737  fineDistribution[i] = finalDecomp[agglom[i]];
738  }
739 
740  return fineDistribution;
741 }
742 
743 
744 Foam::labelList Foam::ptscotchDecomp::decompose
745 (
746  const labelListList& globalCellCells,
747  const pointField& cellCentres,
748  const scalarField& cWeights
749 )
750 {
751  if (cellCentres.size() != globalCellCells.size())
752  {
754  << "Inconsistent number of cells (" << globalCellCells.size()
755  << ") and number of cell centres (" << cellCentres.size()
756  << ")." << exit(FatalError);
757  }
758 
759 
760  // Make Metis CSR (Compressed Storage Format) storage
761  // adjncy : contains neighbours (= edges in graph)
762  // xadj(celli) : start of information in adjncy for celli
763 
764  CompactListList<label> cellCells(globalCellCells);
765 
766  // Decompose using weights
767  List<label> finalDecomp;
768  decompose
769  (
770  "ptscotch",
771  cellCells.m(),
772  cellCells.offsets(),
773  cWeights,
774  finalDecomp
775  );
776 
777  // Copy back to labelList
778  labelList decomp(cellCentres.size());
779  forAll(decomp, i)
780  {
781  decomp[i] = finalDecomp[i];
782  }
783  return decomp;
784 }
785 
786 
787 // ************************************************************************* //
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:57
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:428
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
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
error FatalError
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
Type gMin(const FieldField< Field, Type > &f)
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:417
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:253
static bool master(const label communicator=0)
Am I the master process.
Definition: UPstream.H:411
labelList identity(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
Macros for easy insertion into run-time selection tables.
static void calcCellCells(const polyMesh &mesh, const labelList &agglom, const label nLocalCoarse, const bool global, CompactListList< label > &cellCells)
Helper: determine (local or global) cellCells from mesh.
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
Type gSum(const FieldField< Field, Type > &f)
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
virtual const fileName & name() const
Return the name of the stream.
Definition: OSstream.H:88
static const label labelMax
Definition: label.H:62
List< label > labelList
A List of labels.
Definition: labelList.H:56
static void scatter(const List< commsStruct > &comms, T &Value, const int tag, const label comm)
Scatter data. Distribute without modification. Reverse of gather.
prefixOSstream Pout(cout,"Pout")
Definition: IOstreams.H:53
addToRunTimeSelectionTable(ensightPart, ensightPartCells, istream)
static const char nl
Definition: Ostream.H:262
Type gMax(const FieldField< Field, Type > &f)
defineTypeNameAndDebug(combustionModel, 0)
word name(const complex &)
Return a string representation of a complex.
Definition: complex.C:47
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:399
#define WarningInFunction
Report a warning using Foam::Warning.
messageStream Info
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
Namespace for OpenFOAM.