Loading...
Searching...
No Matches
modifyMesh.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-2017 OpenFOAM Foundation
9 Copyright (C) 2016-2022 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
27Application
28 modifyMesh
29
30Group
31 grpMeshAdvancedUtilities
32
33Description
34 Manipulate mesh elements.
35
36 Actions are:
37 (boundary)points:
38 - move
39
40 (boundary)edges:
41 - split and move introduced point
42
43 (boundary)faces:
44 - split(triangulate) and move introduced point
45
46 edges:
47 - collapse
48
49 cells:
50 - split into polygonal base pyramids around newly introduced mid
51 point
52
53 Is a bit of a loose collection of mesh change drivers.
54
55\*---------------------------------------------------------------------------*/
56
57#include "argList.H"
58#include "Time.H"
59#include "polyMesh.H"
60#include "polyTopoChange.H"
61#include "mapPolyMesh.H"
62#include "boundaryCutter.H"
63#include "cellSplitter.H"
64#include "edgeCollapser.H"
65#include "meshTools.H"
66#include "Pair.H"
67#include "globalIndex.H"
68#include "topoSet.H"
69#include "processorMeshes.H"
70#include "IOdictionary.H"
71
72using namespace Foam;
73
74// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
75
76// Locate point on patch. Returns (mesh) point label.
77label findPoint(const primitivePatch& pp, const point& nearPoint)
78{
79 const pointField& points = pp.points();
80 const labelList& meshPoints = pp.meshPoints();
81
82 // Find nearest and next nearest
83 scalar minDistSqr = GREAT;
84 label minI = -1;
85
86 scalar almostMinDistSqr = GREAT;
87 label almostMinI = -1;
88
89 for (const label pointi : meshPoints)
90 {
91 scalar distSqr = nearPoint.distSqr(points[pointi]);
92
93 if (distSqr < minDistSqr)
94 {
95 almostMinDistSqr = minDistSqr;
96 almostMinI = minI;
97
98 minDistSqr = distSqr;
99 minI = pointi;
100 }
101 else if (distSqr < almostMinDistSqr)
102 {
103 almostMinDistSqr = distSqr;
104 almostMinI = pointi;
105 }
106 }
107
108
109 // Decide if nearPoint unique enough.
110 Info<< "Found to point " << nearPoint << nl
111 << " nearest point : " << minI
112 << " distance " << Foam::sqrt(minDistSqr)
113 << " at " << points[minI] << nl
114 << " next nearest point : " << almostMinI
115 << " distance " << Foam::sqrt(almostMinDistSqr)
116 << " at " << points[almostMinI] << endl;
117
118 if (almostMinDistSqr < 4*minDistSqr)
119 {
120 Info<< "Next nearest too close to nearest. Aborting" << endl;
121
122 return -1;
123 }
124 else
125 {
126 return minI;
127 }
128}
129
130
131// Locate edge on patch. Return mesh edge label.
132label findEdge
133(
134 const primitiveMesh& mesh,
135 const primitivePatch& pp,
136 const point& nearPoint
137)
138{
139 const pointField& localPoints = pp.localPoints();
140 const pointField& points = pp.points();
141 const labelList& meshPoints = pp.meshPoints();
142 const edgeList& edges = pp.edges();
143
144 // Find nearest and next nearest
145 scalar minDist = GREAT;
146 label minI = -1;
147
148 scalar almostMinDist = GREAT;
149 label almostMinI = -1;
150
151 for (const edge& e : edges)
152 {
153 pointHit pHit(e.line(localPoints).nearestDist(nearPoint));
154
155 if (pHit.hit())
156 {
157 if (pHit.distance() < minDist)
158 {
159 almostMinDist = minDist;
160 almostMinI = minI;
161
162 minDist = pHit.distance();
164 (
165 mesh,
166 meshPoints[e[0]],
167 meshPoints[e[1]]
168 );
169 }
170 else if (pHit.distance() < almostMinDist)
171 {
172 almostMinDist = pHit.distance();
173 almostMinI = meshTools::findEdge
174 (
175 mesh,
176 meshPoints[e[0]],
177 meshPoints[e[1]]
178 );
179 }
180 }
181 }
182
183 if (minI == -1)
184 {
185 Info<< "Did not find edge close to point " << nearPoint << endl;
186
187 return -1;
188 }
189
190
191 // Decide if nearPoint unique enough.
192 Info<< "Found to point " << nearPoint << nl
193 << " nearest edge : " << minI
194 << " distance " << minDist << " endpoints "
195 << mesh.edges()[minI].line(points) << nl
196 << " next nearest edge : " << almostMinI
197 << " distance " << almostMinDist << " endpoints "
198 << mesh.edges()[almostMinI].line(points) << nl
199 << endl;
200
201 if (almostMinDist < 2*minDist)
202 {
203 Info<< "Next nearest too close to nearest. Aborting" << endl;
204
205 return -1;
206 }
207 else
208 {
209 return minI;
210 }
211}
212
213
214// Find face on patch. Return mesh face label.
215label findFace
216(
217 const primitiveMesh& mesh,
218 const primitivePatch& pp,
219 const point& nearPoint
220)
221{
222 const pointField& points = pp.points();
223
224 // Find nearest and next nearest
225 scalar minDist = GREAT;
226 label minI = -1;
227
228 scalar almostMinDist = GREAT;
229 label almostMinI = -1;
230
231 forAll(pp, patchFacei)
232 {
233 pointHit pHit(pp[patchFacei].nearestPoint(nearPoint, points));
234
235 if (pHit.hit())
236 {
237 if (pHit.distance() < minDist)
238 {
239 almostMinDist = minDist;
240 almostMinI = minI;
241
242 minDist = pHit.distance();
243 minI = patchFacei + mesh.nInternalFaces();
244 }
245 else if (pHit.distance() < almostMinDist)
246 {
247 almostMinDist = pHit.distance();
248 almostMinI = patchFacei + mesh.nInternalFaces();
249 }
250 }
251 }
252
253 if (minI == -1)
254 {
255 Info<< "Did not find face close to point " << nearPoint << endl;
256
257 return -1;
258 }
259
260
261 // Decide if nearPoint unique enough.
262 Info<< "Found to point " << nearPoint << nl
263 << " nearest face : " << minI
264 << " distance " << minDist
265 << " to face centre " << mesh.faceCentres()[minI] << nl
266 << " next nearest face : " << almostMinI
267 << " distance " << almostMinDist
268 << " to face centre " << mesh.faceCentres()[almostMinI] << nl
269 << endl;
270
271 if (almostMinDist < 2*minDist)
272 {
273 Info<< "Next nearest too close to nearest. Aborting" << endl;
274
275 return -1;
276 }
277 else
278 {
279 return minI;
280 }
281}
282
283
284// Find cell with cell centre close to given point.
285label findCell(const primitiveMesh& mesh, const point& nearPoint)
286{
287 label celli = mesh.findCell(nearPoint);
288
289 if (celli != -1)
290 {
291 scalar distToCcSqr = nearPoint.distSqr(mesh.cellCentres()[celli]);
292
293 const labelList& cPoints = mesh.cellPoints()[celli];
294
295 label minI = -1;
296 scalar minDistSqr = GREAT;
297
298 for (const label pointi : cPoints)
299 {
300 scalar distSqr = nearPoint.distSqr(mesh.points()[pointi]);
301
302 if (distSqr < minDistSqr)
303 {
304 minDistSqr = distSqr;
305 minI = pointi;
306 }
307 }
308
309 // Decide if nearPoint unique enough.
310 Info<< "Found to point " << nearPoint << nl
311 << " nearest cell : " << celli
312 << " distance " << Foam::sqrt(distToCcSqr)
313 << " to cell centre " << mesh.cellCentres()[celli] << nl
314 << " nearest mesh point : " << minI
315 << " distance " << Foam::sqrt(minDistSqr)
316 << " to " << mesh.points()[minI] << nl
317 << endl;
318
319 if (minDistSqr < 4*distToCcSqr)
320 {
321 Info<< "Mesh point too close to nearest cell centre. Aborting"
322 << endl;
323
324 celli = -1;
325 }
326 }
327
328 return celli;
329}
330
331
332
333
334int main(int argc, char *argv[])
335{
337 (
338 "Manipulate mesh elements.\n"
339 "For example, moving points, splitting/collapsing edges etc."
340 );
341 #include "addOverwriteOption.H"
342 argList::addOption("dict", "file", "Alternative modifyMeshDict");
343
344 argList::noFunctionObjects(); // Never use function objects
345
346 #include "setRootCase.H"
347 #include "createTime.H"
348 #include "createPolyMesh.H"
349
350 const word oldInstance = mesh.pointsInstance();
351
352 const bool overwrite = args.found("overwrite");
353
354 Info<< "Reading modifyMeshDict\n" << endl;
355
356 // Read meshing dictionary
357 const word dictName("modifyMeshDict");
359 const IOdictionary dict(dictIO);
360
361 // Read all from the dictionary.
362 List<Pair<point>> pointsToMove(dict.lookup("pointsToMove"));
363 List<Pair<point>> edgesToSplit(dict.lookup("edgesToSplit"));
364 List<Pair<point>> facesToTriangulate
365 (
366 dict.lookup("facesToTriangulate")
367 );
368 // Optional
369 List<Pair<point>> facesToSplit;
370 dict.readIfPresent("facesToSplit", facesToSplit);
371
372 bool cutBoundary =
373 (
374 pointsToMove.size()
375 || edgesToSplit.size()
376 || facesToTriangulate.size()
377 || facesToSplit.size()
378 );
379
380 List<Pair<point>> edgesToCollapse(dict.lookup("edgesToCollapse"));
381
382 bool collapseEdge = edgesToCollapse.size();
383
384 List<Pair<point>> cellsToPyramidise(dict.lookup("cellsToSplit"));
385
386 bool cellsToSplit = cellsToPyramidise.size();
387
388 // List<Tuple2<pointField,point>>
389 // cellsToCreate(dict.lookup("cellsToCreate"));
390
391 Info<< "Read from " << dict.name() << nl
392 << " Boundary cutting module:" << nl
393 << " points to move :" << pointsToMove.size() << nl
394 << " edges to split :" << edgesToSplit.size() << nl
395 << " faces to split :" << facesToSplit.size() << nl
396 << " faces to triangulate:" << facesToTriangulate.size() << nl
397 << " Cell splitting module:" << nl
398 << " cells to split :" << cellsToPyramidise.size() << nl
399 << " Edge collapsing module:" << nl
400 << " edges to collapse :" << edgesToCollapse.size() << nl
401 //<< " cells to create :" << cellsToCreate.size() << nl
402 << endl;
403
404 if
405 (
406 (cutBoundary && collapseEdge)
407 || (cutBoundary && cellsToSplit)
408 || (collapseEdge && cellsToSplit)
409 )
410 {
412 << "Used more than one mesh modifying module "
413 << "(boundary cutting, cell splitting, edge collapsing)" << nl
414 << "Please do them in separate passes." << exit(FatalError);
415 }
416
417
418
419 // Get calculating engine for all of outside
420 primitivePatch allBoundary(mesh.boundaryMesh().faces(), mesh.points());
421
422
423 // Look up mesh labels and convert to input for boundaryCutter.
424
425 bool validInputs = true;
426
427
428 Info<< nl << "Looking up points to move ..." << nl << endl;
429 Map<point> pointToPos(pointsToMove.size());
430 for (const Pair<point>& pts : pointsToMove)
431 {
432 const label pointi = findPoint(allBoundary, pts.first());
433
434 if (pointi == -1 || !pointToPos.insert(pointi, pts.second()))
435 {
436 Info<< "Could not insert mesh point " << pointi
437 << " for input point " << pts.first() << nl
438 << "Perhaps the point is already marked for moving?" << endl;
439 validInputs = false;
440 }
441 }
442
443
444 Info<< nl << "Looking up edges to split ..." << nl << endl;
445 Map<List<point>> edgeToCuts(edgesToSplit.size());
446 for (const Pair<point>& pts : edgesToSplit)
447 {
448 label edgeI = findEdge(mesh, allBoundary, pts.first());
449
450 if
451 (
452 edgeI == -1
453 || !edgeToCuts.insert(edgeI, List<point>(1, pts.second()))
454 )
455 {
456 Info<< "Could not insert mesh edge " << edgeI
457 << " for input point " << pts.first() << nl
458 << "Perhaps the edge is already marked for cutting?" << endl;
459
460 validInputs = false;
461 }
462 }
463
464
465 Info<< nl << "Looking up faces to triangulate ..." << nl << endl;
466 Map<point> faceToDecompose(facesToTriangulate.size());
467 for (const Pair<point>& pts : facesToTriangulate)
468 {
469 label facei = findFace(mesh, allBoundary, pts.first());
470
471 if (facei == -1 || !faceToDecompose.insert(facei, pts.second()))
472 {
473 Info<< "Could not insert mesh face " << facei
474 << " for input point " << pts.first() << nl
475 << "Perhaps the face is already marked for splitting?" << endl;
476
477 validInputs = false;
478 }
479 }
480
481
482 Info<< nl << "Looking up faces to split ..." << nl << endl;
483 Map<labelPair> faceToSplit(facesToSplit.size());
484 for (const Pair<point>& pts : facesToSplit)
485 {
486 label facei = findFace(mesh, allBoundary, pts.first());
487 if (facei == -1)
488 {
489 Info<< "Could not insert mesh face " << facei
490 << " for input point " << pts.first() << nl
491 << "Perhaps the face is already marked for splitting?" << endl;
492
493 validInputs = false;
494 }
495 else
496 {
497 // Find nearest points on face
498 const primitivePatch pp
499 (
500 SubList<face>(mesh.faces(), 1, facei),
501 mesh.points()
502 );
503
504 const label p0 = findPoint(pp, pts.first());
505 const label p1 = findPoint(pp, pts.second());
506
507 const face& f = mesh.faces()[facei];
508
509 if
510 (
511 p0 != -1
512 && p1 != -1
513 && faceToSplit.insert(facei, labelPair(f.find(p0), f.find(p1)))
514 )
515 {}
516 else
517 {
518 Info<< "Could not insert mesh face " << facei
519 << " for input coordinates " << pts
520 << " with vertices " << p0 << " and " << p1 << nl
521 << "Perhaps the face is already marked for splitting?"
522 << endl;
523
524 }
525 }
526 }
527
528
529 Info<< nl << "Looking up cells to convert to pyramids around"
530 << " cell centre ..." << nl << endl;
531 Map<point> cellToPyrCentre(cellsToPyramidise.size());
532 for (const Pair<point>& pts : cellsToPyramidise)
533 {
534 label celli = findCell(mesh, pts.first());
535
536 if (celli == -1 || !cellToPyrCentre.insert(celli, pts.second()))
537 {
538 Info<< "Could not insert mesh cell " << celli
539 << " for input point " << pts.first() << nl
540 << "Perhaps the cell is already marked for splitting?" << endl;
541
542 validInputs = false;
543 }
544 }
545
546
547 Info<< nl << "Looking up edges to collapse ..." << nl << endl;
548 Map<point> edgeToPos(edgesToCollapse.size());
549 for (const Pair<point>& pts : edgesToCollapse)
550 {
551 label edgeI = findEdge(mesh, allBoundary, pts.first());
552
553 if (edgeI == -1 || !edgeToPos.insert(edgeI, pts.second()))
554 {
555 Info<< "Could not insert mesh edge " << edgeI
556 << " for input point " << pts.first() << nl
557 << "Perhaps the edge is already marked for collaping?" << endl;
558
559 validInputs = false;
560 }
561 }
562
563
564
565 if (!validInputs)
566 {
567 Info<< nl << "There was a problem in one of the inputs in the"
568 << " dictionary. Not modifying mesh." << endl;
569 }
570 else if (cellToPyrCentre.size())
571 {
572 Info<< nl << "All input cells located. Modifying mesh." << endl;
573
574 // Mesh change engine
575 cellSplitter cutter(mesh);
576
577 // Topo change container
578 polyTopoChange meshMod(mesh);
579
580 // Insert commands into meshMod
581 cutter.setRefinement(cellToPyrCentre, meshMod);
582
583 // Do changes
584 autoPtr<mapPolyMesh> morphMap = meshMod.changeMesh(mesh, false);
585
586 if (morphMap().hasMotionPoints())
587 {
588 mesh.movePoints(morphMap().preMotionPoints());
589 }
590
591 cutter.updateMesh(morphMap());
592
593 if (!overwrite)
594 {
595 ++runTime;
596 }
597 else
598 {
599 mesh.setInstance(oldInstance);
600 }
601
602 // Write resulting mesh
603 Info<< "Writing modified mesh to time " << runTime.timeName() << endl;
604 mesh.write();
607 }
608 else if (edgeToPos.size())
609 {
610 Info<< nl << "All input edges located. Modifying mesh." << endl;
611
612 // Mesh change engine
613 edgeCollapser cutter(mesh);
614
615 const edgeList& edges = mesh.edges();
616 const pointField& points = mesh.points();
617
618 pointField newPoints(points);
619
620 bitSet collapseEdge(mesh.nEdges());
621 Map<point> collapsePointToLocation(mesh.nPoints());
622
623 // Get new positions and construct collapse network
624 forAllConstIters(edgeToPos, iter)
625 {
626 label edgeI = iter.key();
627 const edge& e = edges[edgeI];
628
629 collapseEdge.set(edgeI);
630 collapsePointToLocation.set(e[1], points[e[0]]);
631
632 newPoints[e[0]] = iter.val();
633 }
634
635 // Move master point to destination.
636 mesh.movePoints(newPoints);
637
638 List<pointEdgeCollapse> allPointInfo;
639 const globalIndex globalPoints(mesh.nPoints());
640 labelList pointPriority(mesh.nPoints(), Zero);
641
642 cutter.consistentCollapse
643 (
645 pointPriority,
646 collapsePointToLocation,
648 allPointInfo
649 );
650
651 // Topo change container
652 polyTopoChange meshMod(mesh);
653
654 // Insert
655 cutter.setRefinement(allPointInfo, meshMod);
656
657 // Do changes
658 autoPtr<mapPolyMesh> morphMap = meshMod.changeMesh(mesh, false);
659
660 if (morphMap().hasMotionPoints())
661 {
662 mesh.movePoints(morphMap().preMotionPoints());
663 }
664
665 // Not implemented yet:
666 //cutter.updateMesh(morphMap());
667
668
669 if (!overwrite)
670 {
671 ++runTime;
672 }
673 else
674 {
675 mesh.setInstance(oldInstance);
676 }
677
678 // Write resulting mesh
679 Info<< "Writing modified mesh to time " << runTime.timeName() << endl;
680 mesh.write();
683 }
684 else
685 {
686 Info<< nl << "All input points located. Modifying mesh." << endl;
687
688 // Mesh change engine
689 boundaryCutter cutter(mesh);
690
691 // Topo change container
692 polyTopoChange meshMod(mesh);
693
694 // Insert commands into meshMod
695 cutter.setRefinement
696 (
697 pointToPos,
698 edgeToCuts,
699 faceToSplit, // Faces to split diagonally
700 faceToDecompose, // Faces to triangulate
701 meshMod
702 );
703
704 // Do changes
705 autoPtr<mapPolyMesh> morphMap = meshMod.changeMesh(mesh, false);
706
707 if (morphMap().hasMotionPoints())
708 {
709 mesh.movePoints(morphMap().preMotionPoints());
710 }
711
712 cutter.updateMesh(morphMap());
713
714 if (!overwrite)
715 {
716 ++runTime;
717 }
718 else
719 {
720 mesh.setInstance(oldInstance);
721 }
722
723 // Write resulting mesh
724 Info<< "Writing modified mesh to time " << runTime.timeName() << endl;
725 mesh.write();
728 }
729
730
731 Info<< "\nEnd\n" << endl;
732 return 0;
733}
734
735
736// ************************************************************************* //
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
static constexpr label size() noexcept
Return the number of elements in the FixedList.
Definition FixedList.H:619
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
A HashTable to objects of type <T> with a label key.
Definition Map.H:54
A non-owning sub-view of a List (allocated or unallocated storage).
Definition SubList.H:61
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
scalar distSqr(const Vector< Cmpt > &v2) const
The L2-norm distance squared from another vector. The magSqr() of the difference.
Definition VectorI.H:95
static void noFunctionObjects(bool addWithOption=false)
Remove '-noFunctionObjects' option and ignore any occurrences.
Definition argList.C:562
static void addOption(const word &optName, const string &param="", const string &usage="", bool advanced=false)
Add an option to validOptions with usage information.
Definition argList.C:400
static void addNote(const string &note)
Add extra notes for the usage information.
Definition argList.C:477
Pointer management similar to std::unique_ptr, with some additional methods and type checking.
Definition autoPtr.H:65
Does modifications to boundary faces.
Does pyramidal decomposition of selected cells. So all faces will become base of pyramid with as top ...
Does polyTopoChanges to remove edges. Can remove faces due to edge collapse but can not remove cells ...
An edge is a list of two vertex labels. This can correspond to a directed graph edge or an edge on a ...
Definition edge.H:62
A face is a list of labels corresponding to mesh vertices.
Definition face.H:71
Calculates a non-overlapping list of offsets based on an input size (eg, number of cells) from differ...
Definition globalIndex.H:77
Calculates points shared by more than two processor patches or cyclic patches.
Direct mesh changes based on v1.3 polyTopoChange syntax.
Cell-face mesh analysis engine.
static void removeFiles(const polyMesh &mesh)
Helper: remove all procAddressing files from mesh instance.
static void removeFiles(const polyMesh &)
Helper: remove all sets files from mesh instance.
Definition topoSet.C:693
A class for handling words, derived from Foam::string.
Definition word.H:66
label collapseEdge(triSurface &surf, const scalar minLen)
Keep collapsing all edges < minLen.
const volScalarField & p0
Definition EEqn.H:36
dynamicFvMesh & mesh
engineTime & runTime
Required Variables.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
const word dictName("faMeshDefinition")
const pointField & points
label findEdge(const edgeList &edges, const labelList &candidates, const label v0, const label v1)
Return edge among candidates that uses the two vertices.
Definition meshTools.C:352
Namespace for OpenFOAM.
List< edge > edgeList
List of edge.
Definition edgeList.H:32
Pair< label > labelPair
A pair of labels.
Definition Pair.H:54
PointHit< point > pointHit
A PointHit with a 3D point.
Definition pointHit.H:51
List< label > labelList
A List of labels.
Definition List.H:62
messageStream Info
Information stream (stdout output on master, null elsewhere).
PrimitivePatch< SubList< face >, const pointField & > primitivePatch
A PrimitivePatch with a SubList addressing for the faces, const reference for the point field.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
dimensionedScalar sqrt(const dimensionedScalar &ds)
vector point
Point is a vector.
Definition point.H:37
static constexpr const zero Zero
Global zero (0).
Definition zero.H:127
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
vectorField pointField
pointField is a vectorField.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition errorManip.H:125
constexpr char nl
The newline '\n' character (0x0a).
Definition Ostream.H:50
labelList f(nPoints)
dictionary dict
const pointField & pts
IOobject dictIO
Foam::argList args(argc, argv)
volScalarField & e
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299
#define forAllConstIters(container, iter)
Iterate across all elements of the container object with const access.
Definition stdFoam.H:235