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