Loading...
Searching...
No Matches
orientFaceZone.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) 2013-2016 OpenFOAM Foundation
9 Copyright (C) 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 orientFaceZone
29
30Group
31 grpMeshManipulationUtilities
32
33Description
34 Corrects the orientation of faceZone.
35
36 - correct in parallel - excludes coupled faceZones from walk
37 - correct for non-manifold faceZones - restarts walk
38
39\*---------------------------------------------------------------------------*/
40
41#include "argList.H"
42#include "Time.H"
43#include "syncTools.H"
45#include "PatchEdgeFaceWave.H"
46#include "orientedSurface.H"
47#include "globalIndex.H"
48
49using namespace Foam;
50
51// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
52
53int main(int argc, char *argv[])
54{
56 (
57 "Corrects the orientation of faceZone"
58 );
59 #include "addRegionOption.H"
60 argList::addArgument("faceZone");
61 argList::addArgument("point", "A point outside of the mesh");
62
63 #include "setRootCase.H"
64 #include "createTime.H"
65 #include "createNamedPolyMesh.H"
66
67 const word zoneName = args[1];
68 const point outsidePoint = args.get<point>(2);
69
70 Info<< "Orienting faceZone " << zoneName
71 << " such that " << outsidePoint << " is outside"
72 << nl << endl;
73
74
75 const faceZone& fZone = mesh.faceZones()[zoneName];
76
77 if (fZone.checkParallelSync())
78 {
80 << "Face zone " << fZone.name()
81 << " is not parallel synchronised."
82 << " Any coupled face also needs its coupled version to be included"
83 << " and with opposite flipMap."
84 << exit(FatalError);
85 }
86
87 const labelList& faceLabels = fZone;
88
90 (
92 mesh.points()
93 );
94
95
96
97 const bitSet isMasterFace(syncTools::getMasterFaces(mesh));
98
99
100 // Data on all edges and faces
101 List<patchFaceOrientation> allEdgeInfo(patch.nEdges());
102 List<patchFaceOrientation> allFaceInfo(patch.size());
103
104 // Make sure we don't walk through
105 // - slaves of coupled faces
106 // - non-manifold edges
107 {
108 const polyBoundaryMesh& bm = mesh.boundaryMesh();
109
110 label nProtected = 0;
111
112 forAll(faceLabels, facei)
113 {
114 const label meshFacei = faceLabels[facei];
115 const label patchi = bm.whichPatch(meshFacei);
116
117 if
118 (
119 patchi != -1
120 && bm[patchi].coupled()
121 && !isMasterFace[meshFacei]
122 )
123 {
124 // Slave side. Mark so doesn't get visited.
126 nProtected++;
127 }
128 }
129
130 Info<< "Protected from visiting "
131 << returnReduce(nProtected, sumOp<label>())
132 << " slaves of coupled faces" << nl << endl;
133 }
134 {
135 // Number of (master)faces per edge
136 labelList nMasterFaces(patch.nEdges(), Zero);
137
138 forAll(faceLabels, facei)
139 {
140 const label meshFacei = faceLabels[facei];
141
142 if (isMasterFace[meshFacei])
143 {
144 const labelList& fEdges = patch.faceEdges()[facei];
145 forAll(fEdges, fEdgeI)
146 {
147 nMasterFaces[fEdges[fEdgeI]]++;
148 }
149 }
150 }
151
153 (
154 mesh,
155 patch.meshEdges(mesh.edges(), mesh.pointEdges()),
156 nMasterFaces,
158 label(0)
159 );
160
161
162 label nProtected = 0;
163
164 forAll(nMasterFaces, edgeI)
165 {
166 if (nMasterFaces[edgeI] > 2)
167 {
168 allEdgeInfo[edgeI] = orientedSurface::NOFLIP;
169 nProtected++;
170 }
171 }
172
173 Info<< "Protected from visiting "
174 << returnReduce(nProtected, sumOp<label>())
175 << " non-manifold edges" << nl << endl;
176 }
177
178
179
180 DynamicList<label> changedEdges;
182
183 const scalar tol = PatchEdgeFaceWave
184 <
187 >::propagationTol();
188
189 int dummyTrackData;
190
191 globalIndex globalFaces(patch.size());
192
193 while (true)
194 {
195 // Pick an unset face
196 label unsetFacei = labelMax;
197 forAll(allFaceInfo, facei)
198 {
200 {
201 unsetFacei = globalFaces.toGlobal(facei);
202 break;
203 }
204 }
205
206 reduce(unsetFacei, minOp<label>());
207
208 if (unsetFacei == labelMax)
209 {
210 break;
211 }
212
213 label proci = globalFaces.whichProcID(unsetFacei);
214 label seedFacei = globalFaces.toLocal(proci, unsetFacei);
215 Info<< "Seeding from processor " << proci
216 << " face " << seedFacei << endl;
217
218 if (proci == Pstream::myProcNo())
219 {
220 // Determine orientation of seedFace
221
222 vector d = outsidePoint-patch.faceCentres()[seedFacei];
223 const vector& fn = patch.faceNormals()[seedFacei];
224
225 // Set information to correct orientation
226 patchFaceOrientation& faceInfo = allFaceInfo[seedFacei];
227 faceInfo = orientedSurface::NOFLIP;
228
229 if ((fn&d) < 0)
230 {
231 faceInfo.flip();
232
233 Pout<< "Face " << seedFacei << " at "
234 << patch.faceCentres()[seedFacei]
235 << " with normal " << fn
236 << " needs to be flipped." << endl;
237 }
238 else
239 {
240 Pout<< "Face " << seedFacei << " at "
241 << patch.faceCentres()[seedFacei]
242 << " with normal " << fn
243 << " points in positive direction (cos = " << (fn&d)/mag(d)
244 << ")" << endl;
245 }
246
247
248 const labelList& fEdges = patch.faceEdges()[seedFacei];
249 forAll(fEdges, fEdgeI)
250 {
251 label edgeI = fEdges[fEdgeI];
252
253 patchFaceOrientation& edgeInfo = allEdgeInfo[edgeI];
254
255 if
256 (
257 edgeInfo.updateEdge<int>
258 (
259 mesh,
260 patch,
261 edgeI,
262 seedFacei,
263 faceInfo,
264 tol,
265 dummyTrackData
266 )
267 )
268 {
269 changedEdges.append(edgeI);
270 changedInfo.append(edgeInfo);
271 }
272 }
273 }
274
275
276 if (returnReduceAnd(changedEdges.empty()))
277 {
278 break;
279 }
280
281
282
283 // Walk
285 <
288 > calc
289 (
290 mesh,
291 patch,
292 changedEdges,
293 changedInfo,
294 allEdgeInfo,
296 returnReduce(patch.nEdges(), sumOp<label>())
297 );
298 }
299
300
301 // Push master zone info over to slave (since slave faces never visited)
302 {
303 const polyBoundaryMesh& bm = mesh.boundaryMesh();
304
305 labelList neiStatus(mesh.nBoundaryFaces(), orientedSurface::UNVISITED);
306
308 {
309 const label meshFacei = faceLabels[i];
310 if (!mesh.isInternalFace(meshFacei))
311 {
312 neiStatus[meshFacei-mesh.nInternalFaces()] =
313 allFaceInfo[i].flipStatus();
314 }
315 }
317
319 {
320 const label meshFacei = faceLabels[i];
321 const label patchi = bm.whichPatch(meshFacei);
322
323 if
324 (
325 patchi != -1
326 && bm[patchi].coupled()
327 && !isMasterFace[meshFacei]
328 )
329 {
330 // Slave side. Take flipped from neighbour
331 label bFacei = meshFacei-mesh.nInternalFaces();
332
333 if (neiStatus[bFacei] == orientedSurface::NOFLIP)
334 {
336 }
337 else if (neiStatus[bFacei] == orientedSurface::FLIP)
338 {
340 }
341 else
342 {
344 << "Incorrect status for face " << meshFacei
345 << abort(FatalError);
346 }
347 }
348 }
349 }
350
351
352 // Convert to flipmap and adapt faceZones
353
354 boolList newFlipMap(allFaceInfo.size(), false);
355 label nChanged = 0;
356 forAll(allFaceInfo, facei)
357 {
359 {
360 newFlipMap[facei] = false;
361 }
362 else if (allFaceInfo[facei] == orientedSurface::FLIP)
363 {
364 newFlipMap[facei] = true;
365 }
366 else
367 {
369 << "Problem : unvisited face " << facei
370 << " centre:" << mesh.faceCentres()[faceLabels[facei]]
371 << abort(FatalError);
372 }
373
374 if (fZone.flipMap()[facei] != newFlipMap[facei])
375 {
376 nChanged++;
377 }
378 }
379
380 reduce(nChanged, sumOp<label>());
381 if (nChanged > 0)
382 {
383 Info<< "Flipping " << nChanged << " out of "
384 << globalFaces.totalSize() << " faces." << nl << endl;
385
386 mesh.faceZones()[zoneName].resetAddressing(faceLabels, newFlipMap);
387 if (!mesh.faceZones().write())
388 {
390 << "Failed writing faceZones" << exit(FatalError);
391 }
392 }
393
394 Info<< "End\n" << endl;
395
396 return 0;
397}
398
399
400// ************************************************************************* //
Required Classes.
labelList faceLabels(nFaceLabels)
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition DynamicList.H:68
void append(const T &val)
Copy append an element to the end of this list.
A List with indirect addressing.
Wave propagation of information along patch. Every iteration information goes through one layer of fa...
bool empty() const noexcept
True if List is empty (ie, size() is zero).
Definition UList.H:701
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Negative if the process is not a...
Definition UPstream.H:1706
static void addArgument(const string &argName, const string &usage="")
Append a (mandatory) argument to validArgs.
Definition argList.C:366
static void addNote(const string &note)
Add extra notes for the usage information.
Definition argList.C:477
A subset of mesh faces organised as a primitive patch.
Definition faceZone.H:63
const boolList & flipMap() const noexcept
Return face flip map.
Definition faceZone.H:389
virtual bool checkParallelSync(const bool report=false) const
Check whether all procs have faces synchronised.
Definition faceZone.C:595
Calculates a non-overlapping list of offsets based on an input size (eg, number of cells) from differ...
Definition globalIndex.H:77
Transport of orientation for use in PatchEdgeFaceWave.
void flip()
Reverse the orientation.
bool updateEdge(const polyMesh &mesh, const indirectPrimitivePatch &patch, const label edgeI, const label facei, const patchFaceOrientation &faceInfo, const scalar tol, TrackingData &td)
Influence of face on edge.
A polyBoundaryMesh is a polyPatch list with registered IO, a reference to the associated polyMesh,...
label whichPatch(const label meshFacei) const
Return patch index for a given mesh face index. Uses binary search.
static bitSet getMasterFaces(const polyMesh &mesh)
Get per face whether it is uncoupled or a master of a coupled set of faces.
Definition syncTools.C:119
static void swapBoundaryFaceList(const polyMesh &mesh, UList< T > &faceValues, const bool parRun=UPstream::parRun())
Swap coupled boundary face values. Uses eqOp.
Definition syncTools.H:524
static void syncEdgeList(const polyMesh &mesh, List< T > &edgeValues, const CombineOp &cop, const T &nullValue, const TransformOp &top, const FlipOp &fop)
Synchronize values on all mesh edges.
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
A class for handling words, derived from Foam::string.
Definition word.H:66
const word & name() const noexcept
The zone name.
bool coupled
dynamicFvMesh & mesh
Required Classes.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
List< wallPoints > allFaceInfo(mesh_.nFaces())
return returnReduce(nRefine-oldNRefine, sumOp< label >())
const std::string patch
OpenFOAM patch number as a std::string.
Namespace for OpenFOAM.
List< label > labelList
A List of labels.
Definition List.H:62
messageStream Info
Information stream (stdout output on master, null elsewhere).
constexpr label labelMax
Definition label.H:55
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
void reduce(T &value, BinaryOp bop, const int tag=UPstream::msgType(), const int communicator=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce).
bool returnReduceAnd(const bool value, const int communicator=UPstream::worldComm)
Perform logical (and) MPI Allreduce on a copy. Uses UPstream::reduceAnd.
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
A PrimitivePatch with an IndirectList for the faces, const reference for the point field.
errorManip< error > abort(error &err)
Definition errorManip.H:139
vector point
Point is a vector.
Definition point.H:37
List< bool > boolList
A List of bools.
Definition List.H:60
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...
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
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
Foam::argList args(argc, argv)
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299