GAMGAgglomeration.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) 2011-2016 OpenFOAM Foundation
9 Copyright (C) 2019-2021 OpenCFD Ltd.
10-------------------------------------------------------------------------------
11License
12 This file is part of OpenFOAM.
13
14 OpenFOAM is free software: you can redistribute it and/or modify it
15 under the terms of the GNU General Public License as published by
16 the Free Software Foundation, either version 3 of the License, or
17 (at your option) any later version.
18
19 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26
27\*---------------------------------------------------------------------------*/
28
29#include "GAMGAgglomeration.H"
30#include "lduMesh.H"
31#include "lduMatrix.H"
32#include "Time.H"
33#include "GAMGInterface.H"
36#include "IOmanip.H"
37
38// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
39
40namespace Foam
41{
46}
47
48
49// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
50
51void Foam::GAMGAgglomeration::compactLevels(const label nCreatedLevels)
52{
53 nCells_.setSize(nCreatedLevels);
54 restrictAddressing_.setSize(nCreatedLevels);
55 nFaces_.setSize(nCreatedLevels);
56 faceRestrictAddressing_.setSize(nCreatedLevels);
57 faceFlipMap_.setSize(nCreatedLevels);
58 nPatchFaces_.setSize(nCreatedLevels);
59 patchFaceRestrictAddressing_.setSize(nCreatedLevels);
60 meshLevels_.setSize(nCreatedLevels);
61
62 // Have procCommunicator_ always, even if not procAgglomerating
63 procCommunicator_.setSize(nCreatedLevels + 1);
65 {
66 procAgglomMap_.setSize(nCreatedLevels);
67 agglomProcIDs_.setSize(nCreatedLevels);
68 procCellOffsets_.setSize(nCreatedLevels);
69 procFaceMap_.setSize(nCreatedLevels);
70 procBoundaryMap_.setSize(nCreatedLevels);
71 procBoundaryFaceMap_.setSize(nCreatedLevels);
72
73 procAgglomeratorPtr_().agglomerate();
74
75
76 }
77
78 // Print a bit
79 if (debug)
80 {
81 Info<< "GAMGAgglomeration:" << nl
82 << " local agglomerator : " << type() << nl;
84 {
85 Info<< " processor agglomerator : "
86 << procAgglomeratorPtr_().type() << nl
87 << nl;
88 }
89
90 Info<< setw(36) << "nCells"
91 << setw(20) << "nFaces/nCells"
92 << setw(20) << "nInterfaces"
93 << setw(20) << "nIntFaces/nCells"
94 << setw(12) << "profile"
95 << nl
96 << setw(8) << "Level"
97 << setw(8) << "nProcs"
98 << " "
99 << setw(8) << "avg"
100 << setw(8) << "max"
101 << " "
102 << setw(8) << "avg"
103 << setw(8) << "max"
104 << " "
105 << setw(8) << "avg"
106 << setw(8) << "max"
107 << " "
108 << setw(8) << "avg"
109 << setw(8) << "max"
110 //<< " "
111 << setw(12) << "avg"
112 << nl
113 << setw(8) << "-----"
114 << setw(8) << "------"
115 << " "
116 << setw(8) << "---"
117 << setw(8) << "---"
118 << " "
119 << setw(8) << "---"
120 << setw(8) << "---"
121 << " "
122 << setw(8) << "---"
123 << setw(8) << "---"
124 << " "
125 << setw(8) << "---"
126 << setw(8) << "---"
127 //<< " "
128 << setw(12) << "---"
129 //<< " "
130 << nl;
131
132 for (label levelI = 0; levelI <= size(); levelI++)
133 {
134 label nProcs = 0;
135 label nCells = 0;
136 scalar faceCellRatio = 0;
137 label nInterfaces = 0;
138 label nIntFaces = 0;
139 scalar ratio = 0.0;
140 scalar profile = 0.0;
141
142 if (hasMeshLevel(levelI))
143 {
144 nProcs = 1;
145
146 const lduMesh& fineMesh = meshLevel(levelI);
147 nCells = fineMesh.lduAddr().size();
148 faceCellRatio =
149 scalar(fineMesh.lduAddr().lowerAddr().size())/nCells;
150
151 const lduInterfacePtrsList interfaces =
152 fineMesh.interfaces();
153 forAll(interfaces, i)
154 {
155 if (interfaces.set(i))
156 {
157 nInterfaces++;
158 nIntFaces += interfaces[i].faceCells().size();
159 }
160 }
161 ratio = scalar(nIntFaces)/nCells;
162
163 profile = fineMesh.lduAddr().band().second();
164 }
165
166 label totNprocs = returnReduce(nProcs, sumOp<label>());
167
168 label maxNCells = returnReduce(nCells, maxOp<label>());
169 label totNCells = returnReduce(nCells, sumOp<label>());
170
171 scalar maxFaceCellRatio =
172 returnReduce(faceCellRatio, maxOp<scalar>());
173 scalar totFaceCellRatio =
174 returnReduce(faceCellRatio, sumOp<scalar>());
175
176 label maxNInt = returnReduce(nInterfaces, maxOp<label>());
177 label totNInt = returnReduce(nInterfaces, sumOp<label>());
178
179 scalar maxRatio = returnReduce(ratio, maxOp<scalar>());
180 scalar totRatio = returnReduce(ratio, sumOp<scalar>());
181
182 scalar totProfile = returnReduce(profile, sumOp<scalar>());
183
184 const int oldPrecision = Info.stream().precision(4);
185
186 Info<< setw(8) << levelI
187 << setw(8) << totNprocs
188 << " "
189 << setw(8) << totNCells/totNprocs
190 << setw(8) << maxNCells
191 << " "
192 << setw(8) << totFaceCellRatio/totNprocs
193 << setw(8) << maxFaceCellRatio
194 << " "
195 << setw(8) << scalar(totNInt)/totNprocs
196 << setw(8) << maxNInt
197 << " "
198 << setw(8) << totRatio/totNprocs
199 << setw(8) << maxRatio
200 << setw(12) << totProfile/totNprocs
201 << nl;
202
203 Info.stream().precision(oldPrecision);
204 }
205 Info<< endl;
206 }
207}
208
209
211(
212 const label nFineCells,
213 const label nCoarseCells
214) const
215{
216 const label nTotalCoarseCells = returnReduce(nCoarseCells, sumOp<label>());
217 if (nTotalCoarseCells < Pstream::nProcs()*nCellsInCoarsestLevel_)
218 {
219 return false;
220 }
221 else
222 {
223 const label nTotalFineCells = returnReduce(nFineCells, sumOp<label>());
224 return nTotalCoarseCells < nTotalFineCells;
225 }
226}
227
228
229// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
230
232(
233 const lduMesh& mesh,
235)
236:
238
239 maxLevels_(50),
240
241 nCellsInCoarsestLevel_
242 (
243 controlDict.getOrDefault<label>("nCellsInCoarsestLevel", 10)
244 ),
245 meshInterfaces_(mesh.interfaces()),
246 procAgglomeratorPtr_
247 (
248 (
249 (UPstream::nProcs(mesh.comm()) > 1)
250 && controlDict.found("processorAgglomerator")
251 )
253 (
254 controlDict.get<word>("processorAgglomerator"),
255 *this,
257 )
259 ),
260
261 nCells_(maxLevels_),
262 restrictAddressing_(maxLevels_),
263 nFaces_(maxLevels_),
264 faceRestrictAddressing_(maxLevels_),
265 faceFlipMap_(maxLevels_),
266 nPatchFaces_(maxLevels_),
267 patchFaceRestrictAddressing_(maxLevels_),
268
269 meshLevels_(maxLevels_)
270{
271 // Limit the cells in the coarsest level based on the local number of
272 // cells. Note: 2 for pair-wise
275
276 // Ensure all procs see the same nCellsInCoarsestLevel_
278
281 {
282 procAgglomMap_.setSize(maxLevels_);
283 agglomProcIDs_.setSize(maxLevels_);
285 procFaceMap_.setSize(maxLevels_);
288 }
289}
290
291
293(
294 const lduMesh& mesh,
296)
297{
298 const GAMGAgglomeration* agglomPtr =
300 (
302 );
303
304 if (agglomPtr)
305 {
306 return *agglomPtr;
307 }
308
309 {
310 const word agglomeratorType
311 (
312 controlDict.getOrDefault<word>("agglomerator", "faceAreaPair")
313 );
314
315 mesh.thisDb().time().libs().open
316 (
318 "geometricGAMGAgglomerationLibs",
319 lduMeshConstructorTablePtr_
320 );
321
322 auto* ctorPtr = lduMeshConstructorTable(agglomeratorType);
323
324 if (!ctorPtr)
325 {
327 << "Unknown GAMGAgglomeration type "
328 << agglomeratorType << ".\n"
329 << "Valid matrix GAMGAgglomeration types :"
330 << lduMatrixConstructorTablePtr_->sortedToc() << endl
331 << "Valid geometric GAMGAgglomeration types :"
332 << lduMeshConstructorTablePtr_->sortedToc()
333 << exit(FatalError);
334 }
335
336 return store(ctorPtr(mesh, controlDict).ptr());
337 }
338}
339
340
342(
343 const lduMatrix& matrix,
345)
346{
347 const lduMesh& mesh = matrix.mesh();
348
349 const GAMGAgglomeration* agglomPtr =
351 (
353 );
354
355 if (agglomPtr)
356 {
357 return *agglomPtr;
358 }
359
360 {
361 const word agglomeratorType
362 (
363 controlDict.getOrDefault<word>("agglomerator", "faceAreaPair")
364 );
365
366 mesh.thisDb().time().libs().open
367 (
369 "algebraicGAMGAgglomerationLibs",
370 lduMatrixConstructorTablePtr_
371 );
372
373 auto* ctorPtr = lduMatrixConstructorTable(agglomeratorType);
374
375 if (!ctorPtr)
376 {
377 return New(mesh, controlDict);
378 }
379 else
380 {
381 return store(ctorPtr(matrix, controlDict).ptr());
382 }
383 }
384}
385
386
388(
389 const lduMesh& mesh,
390 const scalarField& cellVolumes,
391 const vectorField& faceAreas,
393)
394{
395
396 const GAMGAgglomeration* agglomPtr =
398 (
400 );
401
402 if (agglomPtr)
403 {
404 return *agglomPtr;
405 }
406
407 {
408 const word agglomeratorType
409 (
410 controlDict.lookupOrDefault<word>("agglomerator", "faceAreaPair")
411 );
412
413 const_cast<Time&>(mesh.thisDb().time()).libs().open
414 (
416 "geometricGAMGAgglomerationLibs",
417 geometryConstructorTablePtr_
418 );
419
420 auto* ctorPtr = geometryConstructorTable(agglomeratorType);
421
422 if (!ctorPtr)
423 {
425 << "Unknown GAMGAgglomeration type "
426 << agglomeratorType << ".\n"
427 << "Valid geometric GAMGAgglomeration types :"
428 << geometryConstructorTablePtr_->sortedToc()
429 << exit(FatalError);
430 }
431
432 return store
433 (
434 ctorPtr
435 (
436 mesh,
437 cellVolumes,
438 faceAreas,
440 ).ptr()
441 );
442 }
443}
444
445
446// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
447
449{}
450
451
452// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
453
455(
456 const label i
457) const
458{
459 if (i == 0)
460 {
461 return mesh_;
462 }
463 else
464 {
465 return meshLevels_[i - 1];
466 }
467}
468
469
471{
472 if (i == 0)
473 {
474 return true;
475 }
476 else
477 {
478 return meshLevels_.set(i - 1);
479 }
480}
481
482
484(
485 const label i
486) const
487{
488 if (i == 0)
489 {
490 return meshInterfaces_;
491 }
492 else
493 {
494 return meshLevels_[i - 1].rawInterfaces();
495 }
496}
497
498
500{
501 if (hasMeshLevel(i))
502 {
503 meshLevels_.set(i - 1, nullptr);
504
505 if (i < nCells_.size())
506 {
507 nCells_[i] = -555;
508 restrictAddressing_.set(i, nullptr);
509 nFaces_[i] = -666;
510 faceRestrictAddressing_.set(i, nullptr);
511 faceFlipMap_.set(i, nullptr);
512 nPatchFaces_.set(i, nullptr);
513 patchFaceRestrictAddressing_.set(i, nullptr);
514 }
515 }
516}
517
518
520(
521 const label leveli
522) const
523{
524 return procAgglomMap_[leveli];
525}
526
527
529(
530 const label leveli
531) const
532{
533 return agglomProcIDs_[leveli];
534}
535
536
537bool Foam::GAMGAgglomeration::hasProcMesh(const label leveli) const
538{
539 return procCommunicator_[leveli] != -1;
540}
541
542
543Foam::label Foam::GAMGAgglomeration::procCommunicator(const label leveli) const
544{
545 return procCommunicator_[leveli];
546}
547
548
550(
551 const label leveli
552) const
553{
554 return procCellOffsets_[leveli];
555}
556
557
559(
560 const label leveli
561) const
562{
563 return procFaceMap_[leveli];
564}
565
566
568(
569 const label leveli
570) const
571{
572 return procBoundaryMap_[leveli];
573}
574
575
577(
578 const label leveli
579) const
580{
581 return procBoundaryFaceMap_[leveli];
582}
583
584
586(
587 labelList& newRestrict,
588 label& nNewCoarse,
589 const lduAddressing& fineAddressing,
590 const labelUList& restriction,
591 const label nCoarse
592)
593{
594 if (fineAddressing.size() != restriction.size())
595 {
597 << "nCells:" << fineAddressing.size()
598 << " agglom:" << restriction.size()
599 << abort(FatalError);
600 }
601
602 // Seed (master) for every region
603 labelList master(identity(fineAddressing.size()));
604
605 // Now loop and transport master through region
606 const labelUList& lower = fineAddressing.lowerAddr();
607 const labelUList& upper = fineAddressing.upperAddr();
608
609 while (true)
610 {
611 label nChanged = 0;
612
613 forAll(lower, facei)
614 {
615 const label own = lower[facei];
616 const label nei = upper[facei];
617
618 if (restriction[own] == restriction[nei])
619 {
620 // coarse-mesh-internal face
621
622 if (master[own] < master[nei])
623 {
624 master[nei] = master[own];
625 nChanged++;
626 }
627 else if (master[own] > master[nei])
628 {
629 master[own] = master[nei];
630 nChanged++;
631 }
632 }
633 }
634
635 reduce(nChanged, sumOp<label>());
636
637 if (nChanged == 0)
638 {
639 break;
640 }
641 }
642
643
644 // Count number of regions/masters per coarse cell
645 labelListList coarseToMasters(nCoarse);
646 nNewCoarse = 0;
647 forAll(restriction, celli)
648 {
649 labelList& masters = coarseToMasters[restriction[celli]];
650
651 if (!masters.found(master[celli]))
652 {
653 masters.append(master[celli]);
654 nNewCoarse++;
655 }
656 }
657
658 if (nNewCoarse > nCoarse)
659 {
660 //WarningInFunction
661 // << "Have " << nCoarse
662 // << " agglomerated cells but " << nNewCoarse
663 // << " disconnected regions" << endl;
664
665 // Keep coarseToMasters[0] the original coarse, allocate new ones
666 // for the others
667 labelListList coarseToNewCoarse(coarseToMasters.size());
668
669 nNewCoarse = nCoarse;
670
671 forAll(coarseToMasters, coarseI)
672 {
673 const labelList& masters = coarseToMasters[coarseI];
674
675 labelList& newCoarse = coarseToNewCoarse[coarseI];
676 newCoarse.setSize(masters.size());
677 newCoarse[0] = coarseI;
678 for (label i=1; i<newCoarse.size(); i++)
679 {
680 newCoarse[i] = nNewCoarse++;
681 }
682 }
683
684 newRestrict.setSize(fineAddressing.size());
685 forAll(restriction, celli)
686 {
687 const label coarseI = restriction[celli];
688
689 const label index = coarseToMasters[coarseI].find(master[celli]);
690 newRestrict[celli] = coarseToNewCoarse[coarseI][index];
691 }
692
693 return false;
694 }
695
696 return true;
697}
698
699
700// ************************************************************************* //
Istream and Ostream manipulators taking arguments.
bool found
Geometric agglomerated algebraic multigrid agglomeration class.
bool processorAgglomerate() const
Whether to agglomerate across processors.
void clearLevel(const label leveli)
const labelListListList & boundaryFaceMap(const label fineLeveli) const
Mapping from processor to procMesh boundary face.
PtrList< labelListList > patchFaceRestrictAddressing_
Patch-local face restriction addressing array.
PtrList< boolList > faceFlipMap_
Face flip: for faces mapped to internal faces stores whether.
PtrList< labelList > nPatchFaces_
The number of (coarse) patch faces in each level.
const label maxLevels_
Max number of levels.
static bool checkRestriction(labelList &newRestrict, label &nNewCoarse, const lduAddressing &fineAddressing, const labelUList &restriction, const label nCoarse)
Given restriction determines if coarse cells are connected.
label nCellsInCoarsestLevel_
Number of cells in coarsest level.
const labelList & procAgglomMap(const label fineLeveli) const
autoPtr< GAMGProcAgglomeration > procAgglomeratorPtr_
void compactLevels(const label nCreatedLevels)
Shrink the number of levels to that specified.
labelList nFaces_
The number of (coarse) faces in each level.
PtrList< lduPrimitiveMesh > meshLevels_
Hierarchy of mesh addressing.
bool continueAgglomerating(const label nCells, const label nCoarseCells) const
Check the need for further agglomeration.
labelList nCells_
The number of cells in each level.
bool hasProcMesh(const label fineLeveli) const
Check that level has combined mesh.
labelList procCommunicator_
Communicator for given level.
PtrList< labelList > agglomProcIDs_
Per level the set of processors to agglomerate. Element 0 is.
PtrList< labelList > procAgglomMap_
Per level, per processor the processor it agglomerates into.
PtrList< labelListList > procBoundaryMap_
Mapping from processor to procMeshLevel boundary.
const labelList & agglomProcIDs(const label fineLeveli) const
PtrList< labelList > procCellOffsets_
Mapping from processor to procMeshLevel cells.
PtrList< labelField > restrictAddressing_
Cell restriction addressing array.
PtrList< labelListList > procFaceMap_
Mapping from processor to procMeshLevel face.
PtrList< labelList > faceRestrictAddressing_
Face restriction addressing array.
const lduInterfacePtrsList & interfaceLevel(const label leveli) const
Return LDU interface addressing of given level.
bool hasMeshLevel(const label leveli) const
Do we have mesh for given level?
label nCells(const label leveli) const
Return number of coarse cells (before processor agglomeration)
label procCommunicator(const label fineLeveli) const
Communicator for current level or -1.
const lduMesh & meshLevel(const label leveli) const
Return LDU mesh of given level.
PtrList< labelListListList > procBoundaryFaceMap_
Mapping from processor to procMeshLevel boundary face.
Processor agglomeration of GAMGAgglomerations.
void setSize(const label n)
Alias for resize()
Definition: List.H:218
void append(const T &val)
Append an element at the end of the list.
Definition: ListI.H:175
Templated abstract base-class for optional mesh objects used to automate their allocation to the mesh...
Definition: MeshObject.H:91
virtual int precision() const
Get precision of output field.
Definition: OSstream.C:326
label nProcs() const noexcept
Number of ranks associated with PstreamBuffers.
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:80
static autoPtr< Time > New()
Construct (dummy) Time - no functionObjects or libraries.
Definition: Time.C:717
dlLibraryTable & libs() const
Mutable access to the loaded dynamic libraries.
Definition: Time.H:510
const T2 & second() const noexcept
Return second.
Definition: Tuple2.H:130
bool found(const T &val, label pos=0) const
True if the value if found in the list.
Definition: UListI.H:265
label find(const T &val, label pos=0) const
Find index of the first occurrence of the value.
Definition: UList.C:212
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
Inter-processor communications stream.
Definition: UPstream.H:59
const T * set(const label i) const
Definition: UPtrList.H:248
label size() const noexcept
The number of elements in the list.
Definition: UPtrListI.H:106
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition: autoPtr.H:66
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
bool open(bool verbose=true)
const faBoundaryMeshMapper & boundaryMap() const
Return boundary mapper.
Definition: faMeshMapper.H:205
virtual const objectRegistry & thisDb() const
Return the object registry - resolve conflict polyMesh/lduMesh.
Definition: fvMesh.H:302
The class contains the addressing required by the lduMatrix: upper, lower and losort.
Tuple2< label, scalar > band() const
Calculate bandwidth and profile of addressing.
virtual const labelUList & upperAddr() const =0
Return upper addressing.
label size() const
Return number of equations.
virtual const labelUList & lowerAddr() const =0
Return lower addressing.
lduMatrix is a general matrix class in which the coefficients are stored as three arrays,...
Definition: lduMatrix.H:84
const lduMesh & mesh() const
Return the LDU mesh from which the addressing is obtained.
Definition: lduMatrix.H:566
Abstract base class for meshes which provide LDU addressing for the construction of lduMatrix and LDU...
Definition: lduMesh.H:63
virtual const lduAddressing & lduAddr() const =0
Return ldu addressing.
virtual lduInterfacePtrsList interfaces() const =0
const labelList & cellOffsets() const
Return cellOffsets.
OSstream & stream(OSstream *alternative=nullptr)
Definition: messageStream.C:71
const Time & time() const noexcept
Return time registry.
const Type * cfindObject(const word &name, const bool recursive=false) const
Return const pointer to the object of the given Type.
const labelList & faceMap() const noexcept
A class for handling words, derived from Foam::string.
Definition: word.H:68
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition: className.H:121
runTime controlDict().readEntry("adjustTimeStep"
dynamicFvMesh & mesh
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
Namespace for OpenFOAM.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i)
Definition: labelList.C:38
messageStream Info
Information stream (stdout output on master, null elsewhere)
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: MSwindows.C:598
Omanip< int > setw(const int i)
Definition: IOmanip.H:199
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
void reduce(const List< UPstream::commsStruct > &comms, T &value, const BinaryOp &bop, const int tag, const label comm)
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:33
errorManip< error > abort(error &err)
Definition: errorManip.H:144
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh > > &tdf1, const word &name, const dimensionSet &dimensions)
Global function forwards to reuseTmpDimensionedField::New.
error FatalError
T returnReduce(const T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce (copy) and return value.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
#define defineRunTimeSelectionTable(baseType, argNames)
Define run-time selection table.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333
static const char *const typeName
The type name used in ensight case files.