faMeshReconstructor.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) 2021-2022 OpenCFD Ltd.
9-------------------------------------------------------------------------------
10License
11 This file is part of OpenFOAM.
12
13 OpenFOAM is free software: you can redistribute it and/or modify it
14 under the terms of the GNU General Public License as published by
15 the Free Software Foundation, either version 3 of the License, or
16 (at your option) any later version.
17
18 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25
26\*---------------------------------------------------------------------------*/
27
28#include "faMeshReconstructor.H"
29#include "globalIndex.H"
30#include "globalMeshData.H"
31#include "edgeHashes.H"
32#include "Time.H"
33
34// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
35
37
38
39// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
40
41void Foam::faMeshReconstructor::calcAddressing
42(
43 const labelUList& fvFaceProcAddr
44)
45{
46 const globalIndex globalFaceNum(procMesh_.nFaces());
47
48 // ----------------------
49 // boundaryProcAddressing
50 //
51 // Trivial since non-processor boundary ordering is identical
52
53 const label nPatches = procMesh_.boundary().size();
54
55 faBoundaryProcAddr_ = identity(nPatches);
56
57 // Mark processor patches
58 for
59 (
60 label patchi = procMesh_.boundary().nNonProcessor();
61 patchi < nPatches;
62 ++patchi
63 )
64 {
65 faBoundaryProcAddr_[patchi] = -1;
66 }
67
68
69 // ------------------
70 // faceProcAddressing
71 //
72 // Transcribe/rewrite based on finiteVolume faceProcAddressing
73
74 faFaceProcAddr_ = procMesh_.faceLabels();
75
76 // From local faceLabels to proc values
77 for (label& facei : faFaceProcAddr_)
78 {
79 // Use finiteVolume info, ignoring face flips
80 facei = mag(fvFaceProcAddr[facei])-1;
81 }
82
83
84 // Make global consistent.
85 // Starting at '0', without gaps in numbering etc.
86 // - the sorted order is the obvious solution
87 {
88 globalFaceNum.gather(faFaceProcAddr_, singlePatchFaceLabels_);
89
90 const labelList globalOrder(Foam::sortedOrder(singlePatchFaceLabels_));
91
92 singlePatchFaceLabels_ =
93 labelList(singlePatchFaceLabels_, globalOrder);
94
95 // Set first face to be zero relative to the finiteArea patch
96 // ie, local-face numbering with the first being 0 on any given patch
97 {
98 label patchFirstMeshfacei
99 (
100 singlePatchFaceLabels_.empty()
101 ? 0
102 : singlePatchFaceLabels_.first()
103 );
104 Pstream::scatter(patchFirstMeshfacei);
105
106 for (label& facei : faFaceProcAddr_)
107 {
108 facei -= patchFirstMeshfacei;
109 }
110 }
111
112 PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
113
114 if (Pstream::master())
115 {
116 // Determine the respective local portions of the global ordering
117
118 labelList procTargets(globalFaceNum.totalSize());
119
120 for (const label proci : Pstream::allProcs())
121 {
123 (
124 globalFaceNum.range(proci),
125 procTargets
126 ) = proci;
127 }
128
129 labelList procStarts(globalFaceNum.offsets());
130 labelList procOrders(globalFaceNum.totalSize());
131
132 for (const label globali : globalOrder)
133 {
134 const label proci = procTargets[globali];
135
136 procOrders[procStarts[proci]++] =
137 (globali - globalFaceNum.localStart(proci));
138 }
139
140 // Send the local portions
141 for (const int proci : Pstream::subProcs())
142 {
143 SubList<label> localOrder
144 (
145 procOrders,
146 globalFaceNum.range(proci)
147 );
148
149 UOPstream toProc(proci, pBufs);
150 toProc << localOrder;
151 }
152
153 SubList<label> localOrder(procOrders, globalFaceNum.range(0));
154
155 faFaceProcAddr_ = labelList(faFaceProcAddr_, localOrder);
156 }
157
158 pBufs.finishedScatters();
159
160 if (!Pstream::master())
161 {
162 labelList localOrder;
163
164 UIPstream fromProc(Pstream::masterNo(), pBufs);
165 fromProc >> localOrder;
166
167 faFaceProcAddr_ = labelList(faFaceProcAddr_, localOrder);
168 }
169 }
170
171 // Broadcast the same information everywhere
172 Pstream::scatter(singlePatchFaceLabels_);
173
174
175 // ------------------
176 // edgeProcAddressing
177 //
178 // This is more complicated.
179
180 // Create a single (serial) patch of the finiteArea mesh without a
181 // corresponding volume mesh, otherwise it would be the same as
182 // reconstructPar on the volume mesh (big, slow, etc).
183 //
184 // Do manual point-merge and relabeling to avoid dependency on
185 // finiteVolume pointProcAddressing
186
187 faPointProcAddr_.clear(); // Final size == procMesh_.nPoints()
188
189 // 1.
190 // - Topological point merge of the area meshes
191 // - use the local patch faces and points
192
193 // 2.
194 // - build a single (serial) patch of the finiteArea mesh only
195 // without any point support from the volume mesh
196 // - it may be possible to skip this step, but not obvious how
197
198 // The collected faces are contiguous per processor, which gives us
199 // the possibility to easily identify their source by using the
200 // global face indexing (if needed).
201 // The ultimate face locations are handled with a separate ordering
202 // list.
203
204 const uindirectPrimitivePatch& procPatch = procMesh_.patch();
205
206
207 {
208 faceList singlePatchProcFaces; // [proc0faces, proc1faces ...]
209 labelList uniqueMeshPointLabels;
210
211 // Local face points to compact merged point index
212 labelList pointToGlobal;
213
214 autoPtr<globalIndex> globalPointsPtr =
215 procMesh_.mesh().globalData().mergePoints
216 (
217 procPatch.meshPoints(),
218 procPatch.meshPointMap(), // unused
219 pointToGlobal,
220 uniqueMeshPointLabels
221 );
222
223 // Gather faces, renumbered for the *merged* points
224 faceList tmpFaces(globalFaceNum.localSize());
225
226 forAll(tmpFaces, facei)
227 {
228 tmpFaces[facei] =
229 face(pointToGlobal, procPatch.localFaces()[facei]);
230 }
231
232 globalFaceNum.gather
233 (
234 tmpFaces,
235 singlePatchProcFaces,
238 );
239
240 globalPointsPtr().gather
241 (
242 UIndirectList<point>
243 (
244 procPatch.points(), // NB: mesh points (non-local)
245 uniqueMeshPointLabels
246 ),
247 singlePatchPoints_
248 );
249
250 // Transcribe into final assembled order
251 singlePatchFaces_.resize(singlePatchProcFaces.size());
252
253 // Target face ordering
254 labelList singlePatchProcAddr;
255 globalFaceNum.gather(faFaceProcAddr_, singlePatchProcAddr);
256
257 forAll(singlePatchProcAddr, facei)
258 {
259 const label targetFacei = singlePatchProcAddr[facei];
260 singlePatchFaces_[targetFacei] = singlePatchProcFaces[facei];
261 }
262
263 // Use initial equivalent "global" (serial) patch
264 // to establish the correct point and face walking order
265 //
266 // - only meaningful on master
267 const primitivePatch initialPatch
268 (
269 SubList<face>(singlePatchFaces_),
270 singlePatchPoints_
271 );
272
273 // Grab the faces/points in local point ordering
274 tmpFaces = initialPatch.localFaces();
275 pointField tmpPoints(initialPatch.localPoints());
276
277 // Equivalent to a flattened meshPointMap
278 labelList mpm(initialPatch.points().size(), -1);
279 {
280 const labelList& mp = initialPatch.meshPoints();
281 forAll(mp, i)
282 {
283 mpm[mp[i]] = i;
284 }
285 }
286 Pstream::scatter(mpm);
287
288 // Rewrite pointToGlobal according to the correct point order
289 for (label& pointi : pointToGlobal)
290 {
291 pointi = mpm[pointi];
292 }
293
294 // Finalize. overwrite
295 faPointProcAddr_ = std::move(pointToGlobal);
296
297 singlePatchFaces_ = std::move(tmpFaces);
298 singlePatchPoints_ = std::move(tmpPoints);
299 }
300
301 // Broadcast the same information everywhere
302 Pstream::scatter(singlePatchFaces_);
303 Pstream::scatter(singlePatchPoints_);
304
305 // Now have enough global information to determine global edge mappings
306
307 // Equivalent "global" (serial) patch
308 const primitivePatch onePatch
309 (
310 SubList<face>(singlePatchFaces_),
311 singlePatchPoints_
312 );
313
314 faEdgeProcAddr_.clear();
315 faEdgeProcAddr_.resize(procMesh_.nEdges(), -1);
316
317 {
318 EdgeMap<label> globalEdgeMapping(2*onePatch.nEdges());
319
320 // Pass 1: edge-hash lookup with edges in "natural" patch order
321
322 // Can use local edges() directly without remap via meshPoints()
323 // since the previous sorting means that we are already working
324 // with faces that are in the local point order and even
325 // the points themselves are also in the local point order
326 for (const edge& e : onePatch.edges())
327 {
328 globalEdgeMapping.insert(e, globalEdgeMapping.size());
329 }
330
331 // Lookup proc local edges (in natural order) to global equivalent
332 for (label edgei = 0; edgei < procPatch.nEdges(); ++edgei)
333 {
334 const edge globalEdge(faPointProcAddr_, procPatch.edges()[edgei]);
335
336 const auto fnd = globalEdgeMapping.cfind(globalEdge);
337
338 if (fnd.found())
339 {
340 faEdgeProcAddr_[edgei] = fnd.val();
341 }
342 else
343 {
345 << "Failed to find edge " << globalEdge
346 << " this indicates a programming error" << nl
347 << exit(FatalError);
348 }
349 }
350 }
351
352 // Now have consistent global edge
353 // This of course would all be too easy.
354 // The finiteArea edge lists have been defined as their own sorted
355 // order with sublists etc.
356
357 // Gather edge ids for nonProcessor boundaries.
358 // These will also be in the serial geometry
359
360 Map<label> remapGlobal(2*onePatch.nEdges());
361 for (label edgei = 0; edgei < onePatch.nInternalEdges(); ++edgei)
362 {
363 remapGlobal.insert(edgei, remapGlobal.size());
364 }
365
366 //
367 singlePatchEdgeLabels_.clear();
368 singlePatchEdgeLabels_.resize(procMesh_.boundary().nNonProcessor());
369
370 forAll(singlePatchEdgeLabels_, patchi)
371 {
372 const faPatch& fap = procMesh_.boundary()[patchi];
373
374 labelList& patchEdgeLabels = singlePatchEdgeLabels_[patchi];
375 patchEdgeLabels = fap.edgeLabels();
376
377 // Renumber from local edges to global edges (natural order)
378 for (label& edgeId : patchEdgeLabels)
379 {
380 edgeId = faEdgeProcAddr_[edgeId];
381 }
382
383 // OR patchEdgeLabels =
384 // UIndirectList<label>(faEdgeProcAddr_, fap.edgeLabels());
385
386
387 // Collect from all processors
389 (
390 patchEdgeLabels,
391 ListOps::appendEqOp<label>()
392 );
393
394 // Sorted order will be the original non-decomposed order
395 Foam::sort(patchEdgeLabels);
396
397 for (const label sortedEdgei : patchEdgeLabels)
398 {
399 remapGlobal.insert(sortedEdgei, remapGlobal.size());
400 }
401 }
402
403 {
404 // Use the map to rewrite the local faEdgeProcAddr_
405
406 labelList newEdgeProcAddr(faEdgeProcAddr_);
407
408 label edgei = procMesh_.nInternalEdges();
409
410 for (const faPatch& fap : procMesh_.boundary())
411 {
412 for (const label patchEdgei : fap.edgeLabels())
413 {
414 const label globalEdgei = faEdgeProcAddr_[patchEdgei];
415
416 const auto fnd = remapGlobal.cfind(globalEdgei);
417 if (fnd.found())
418 {
419 newEdgeProcAddr[edgei] = fnd.val();
420 ++edgei;
421 }
422 else
423 {
425 << "Failed to find edge " << globalEdgei
426 << " this indicates a programming error" << nl
427 << exit(FatalError);
428 }
429 }
430 }
431
432 faEdgeProcAddr_ = std::move(newEdgeProcAddr);
433 }
434}
435
436
437void Foam::faMeshReconstructor::initPatch() const
438{
439 serialPatchPtr_.reset
440 (
442 (
443 SubList<face>(singlePatchFaces_),
444 singlePatchPoints_
445 )
446 );
447}
448
449
450void Foam::faMeshReconstructor::createMesh()
451{
452 const Time& runTime = procMesh_.thisDb().time();
453
454 // Time for non-parallel case (w/o functionObjects or libs)
455 serialRunTime_ = Time::New(runTime.globalPath().toAbsolute());
456
457
458 // Trivial polyMesh only containing points and faces.
459 // This is valid, provided we don't use it for anything complicated.
460
461 serialVolMesh_.reset
462 (
463 new polyMesh
464 (
465 IOobject
466 (
467 procMesh_.mesh().name(), // Volume region name
468 procMesh_.mesh().facesInstance(),
469
470 *serialRunTime_,
471
474 false // not registered
475 ),
476 pointField(singlePatchPoints_), // copy
477 faceList(singlePatchFaces_), // copy
478 labelList(singlePatchFaces_.size(), Zero), // faceOwner
479 labelList(), // faceNeighbour
480 false // no syncPar!
481 )
482 );
483
484 // A simple area-mesh with one-to-one mapping of faceLabels
485 serialAreaMesh_.reset
486 (
487 new faMesh
488 (
489 *serialVolMesh_,
490 identity(singlePatchFaces_.size()) // faceLabels
491 )
492 );
493
494 auto& completeMesh = *serialAreaMesh_;
495
496 // Add in non-processor boundary patches
497 faPatchList completePatches(singlePatchEdgeLabels_.size());
498 forAll(completePatches, patchi)
499 {
500 const labelList& patchEdgeLabels = singlePatchEdgeLabels_[patchi];
501
502 const faPatch& fap = procMesh_.boundary()[patchi];
503
504 const label neiPolyPatchId = fap.ngbPolyPatchIndex();
505
506 completePatches.set
507 (
508 patchi,
509 fap.clone
510 (
511 completeMesh.boundary(),
512 patchEdgeLabels,
513 patchi, // index
514 neiPolyPatchId
515 )
516 );
517 }
518
519 // Serial mesh - no parallel communication
520
521 const bool oldParRun = Pstream::parRun(false);
522
523 completeMesh.addFaPatches(completePatches);
524
525 Pstream::parRun(oldParRun); // Restore parallel state
526}
527
528
529// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
530
532(
533 const faMesh& procMesh
534)
535:
536 procMesh_(procMesh)
537{
538 if (!Pstream::parRun())
539 {
541 << "Can only be called in parallel!!" << nl
542 << exit(FatalError);
543 }
544
545 // Require faceProcAddressing from finiteVolume decomposition
546 labelIOList fvFaceProcAddressing
547 (
549 (
550 "faceProcAddressing",
551 procMesh_.mesh().facesInstance(),
552
553 // Or search?
554 // procMesh_.time().findInstance
555 // (
556 // // Search for polyMesh face instance
557 // // mesh.facesInstance()
558 // procMesh_.mesh().meshDir(),
559 // "faceProcAddressing"
560 // ),
561
563 procMesh_.mesh(), // The polyMesh db
566 false // not registered
567 )
568 );
569
570 calcAddressing(fvFaceProcAddressing);
571}
572
573
575(
576 const faMesh& procMesh,
577 const labelUList& fvFaceProcAddressing
578)
579:
580 procMesh_(procMesh)
581{
582 if (!Pstream::parRun())
583 {
585 << "Can only be called in parallel!!" << nl
586 << exit(FatalError);
587 }
588
589 calcAddressing(fvFaceProcAddressing);
590}
591
592
593// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
594
596{}
597
598
599// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
600
602{
603 serialAreaMesh_.reset(nullptr);
604 serialVolMesh_.reset(nullptr);
605 serialRunTime_.reset(nullptr);
606}
607
608
610{
611 if (!serialPatchPtr_)
612 {
613 initPatch();
614 }
615
616 return *serialPatchPtr_;
617}
618
619
621{
622 if (!serialPatchPtr_)
623 {
624 initPatch();
625 }
626
627 return *serialPatchPtr_;
628}
629
630
632{
633 if (!serialAreaMesh_)
634 {
635 const_cast<faMeshReconstructor&>(*this).createMesh();
636 }
637
638 return *serialAreaMesh_;
639}
640
641
643{
644 writeAddressing(procMesh_.mesh().facesInstance());
645}
646
647
649{
650 // Write copies
651
652 IOobject ioAddr
653 (
654 "procAddressing",
655 timeName,
657 procMesh_.thisDb(),
660 false // not registered
661 );
662
663 // boundaryProcAddressing
664 ioAddr.rename("boundaryProcAddressing");
665 IOListRef<label>(ioAddr, faBoundaryProcAddr_).write();
666
667 // faceProcAddressing
668 ioAddr.rename("faceProcAddressing");
669 IOListRef<label>(ioAddr, faFaceProcAddr_).write();
670
671 // pointProcAddressing
672 ioAddr.rename("pointProcAddressing");
673 IOListRef<label>(ioAddr, faPointProcAddr_).write();
674
675 // edgeProcAddressing
676 ioAddr.rename("edgeProcAddressing");
677 IOListRef<label>(ioAddr, faEdgeProcAddr_).write();
678}
679
680
682{
683 writeMesh(procMesh_.mesh().facesInstance());
684}
685
686
688{
689 const faMesh& fullMesh = this->mesh();
690
691 const bool oldDistributed = fileHandler().distributed();
692 auto oldHandler = fileHandler(fileOperation::NewUncollated());
693 fileHandler().distributed(true);
694
695 if (Pstream::master())
696 {
697 const bool oldParRun = Pstream::parRun(false);
698
699 IOobject io(fullMesh.boundary());
700
701 io.rename("faceLabels");
702 IOListRef<label>(io, singlePatchFaceLabels_).write();
703
704 fullMesh.boundary().write();
705
706 Pstream::parRun(oldParRun);
707 }
708
709 // Restore old settings
710 if (oldHandler)
711 {
712 fileHandler(std::move(oldHandler));
713 }
714 fileHandler().distributed(oldDistributed);
715}
716
717
718// ************************************************************************* //
A IOList wrapper for writing external data.
Definition: IOList.H:123
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition: IOobject.H:170
virtual void rename(const word &newName)
Rename the object.
Definition: IOobject.H:497
std::enable_if< std::is_same< bool, TypeT >::value, bool >::type set(const label i, bool val=true)
A bitSet::set() method for a list of bool.
Definition: List.H:330
SubList< label > subList
Declare type of subList.
Definition: List.H:111
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:139
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:116
A list of faces which address into the list of points.
UPstream::rangeType allProcs() const noexcept
Range of ranks indices associated with PstreamBuffers.
UPstream::rangeType subProcs() const noexcept
Range of sub-processes indices associated with PstreamBuffers.
static void combineAllGather(const List< commsStruct > &comms, T &value, const CombineOp &cop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
static void scatter(const List< commsStruct > &comms, T &value, const int tag, const label comm)
Broadcast data: Distribute without modification.
fileName globalPath() const
Return global path for the case.
Definition: TimePathsI.H:80
static autoPtr< Time > New()
Construct (dummy) Time - no functionObjects or libraries.
Definition: Time.C:717
T & first()
Return the first element of the list.
Definition: UListI.H:202
bool empty() const noexcept
True if the UList is empty (ie, size() is zero)
Definition: UListI.H:427
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
@ nonBlocking
"nonBlocking"
static int & msgType() noexcept
Message tag of standard messages.
Definition: UPstream.H:556
static constexpr int masterNo() noexcept
Process index of the master (always 0)
Definition: UPstream.H:451
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:433
label size() const noexcept
The number of elements in the list.
Definition: UPtrListI.H:106
label nNonProcessor() const
The number of patches before the first processor patch.
A bare-bones reconstructor for finiteArea meshes when processor meshes are available (in parallel) bu...
const faMesh & mesh() const
Serial equivalent faMesh.
const primitivePatch & patch() const
Serial equivalent patch.
void writeMesh() const
Write equivalent mesh information at the polyMesh faceInstances time.
void writeAddressing() const
Write proc addressing at the polyMesh faceInstances time.
static int debug
Debug flag.
Finite area mesh (used for 2-D non-Euclidian finite area method) defined using a patch of faces on a ...
Definition: faMesh.H:100
const faBoundaryMesh & boundary() const noexcept
Return constant reference to boundary mesh.
Definition: faMeshI.H:38
label nEdges() const noexcept
Number of local mesh edges.
Definition: faMeshI.H:62
const polyMesh & mesh() const
Return access to polyMesh.
Definition: faMeshI.H:31
const uindirectPrimitivePatch & patch() const
Return constant reference to primitive patch.
Definition: faMeshI.H:128
label nInternalEdges() const noexcept
Number of internal faces.
Definition: faMeshI.H:68
label nFaces() const noexcept
Number of patch faces.
Definition: faMeshI.H:80
const labelList & faceLabels() const noexcept
Return the underlying polyMesh face labels.
Definition: faMeshI.H:122
static word meshSubDir
The mesh sub-directory name (usually "faMesh")
Definition: faMesh.H:504
fileName & toAbsolute()
Convert from relative to absolute.
Definition: fileName.C:377
bool distributed() const noexcept
Distributed roots (parallel run)
static autoPtr< fileOperation > NewUncollated()
Static construct the commonly used uncollatedFileOperation.
autoPtr< globalIndex > mergePoints(labelList &pointToGlobal, labelList &uniquePoints) const
Helper for merging (collocated!) mesh point data.
const Time & time() const noexcept
Return time registry.
const objectRegistry & thisDb() const noexcept
Return the object registry.
const fileName & facesInstance() const
Return the current instance directory for faces.
Definition: polyMesh.C:866
const globalMeshData & globalData() const
Return parallel info.
Definition: polyMesh.C:1310
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:324
virtual bool write(const bool valid=true) const
Write using setting from DB.
splitCell * master() const
Definition: splitCell.H:113
A class for handling words, derived from Foam::string.
Definition: word.H:68
dynamicFvMesh & mesh
engineTime & runTime
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
const label nPatches
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, false)
word timeName
Definition: getTimeIndex.H:3
const dimensionedScalar mp
Proton mass.
const fileOperation & fileHandler()
Get current file handler.
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i)
Definition: labelList.C:38
List< label > labelList
A List of labels.
Definition: List.H:66
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
PrimitivePatch< SubList< face >, const pointField & > primitivePatch
A PrimitivePatch with a SubList addressing for the faces, const reference for the point field.
PrimitivePatch< UIndirectList< face >, const pointField & > uindirectPrimitivePatch
A PrimitivePatch with UIndirectList for the faces, const reference for the point field.
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
labelList sortedOrder(const UList< T > &input)
Return the (stable) sort order for the list.
void sort(UList< T > &list)
Sort the list.
Definition: UList.C:342
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
error FatalError
PtrList< faPatch > faPatchList
Store lists of faPatch as a PtrList.
Definition: faPatch.H:66
List< face > faceList
A List of faces.
Definition: faceListFwd.H:47
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
volScalarField & e
Definition: createFields.H:11
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333