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 -------------------------------------------------------------------------------
11 License
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 Application
28  orientFaceZone
29 
30 Group
31  grpMeshManipulationUtilities
32 
33 Description
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"
44 #include "patchFaceOrientation.H"
45 #include "PatchEdgeFaceWave.H"
46 #include "orientedSurface.H"
47 #include "globalIndex.H"
48 
49 using namespace Foam;
50 
51 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
52 
53 int 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.
125  allFaceInfo[facei] = orientedSurface::NOFLIP;
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,
157  plusEqOp<label>(),
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  {
199  if (allFaceInfo[facei] == orientedSurface::UNVISITED)
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,
295  allFaceInfo,
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 
306 
307  forAll(faceLabels, i)
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 
318  forAll(faceLabels, i)
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  {
335  allFaceInfo[i] = orientedSurface::FLIP;
336  }
337  else if (neiStatus[bFacei] == orientedSurface::FLIP)
338  {
339  allFaceInfo[i] = orientedSurface::NOFLIP;
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  {
358  if (allFaceInfo[facei] == orientedSurface::NOFLIP)
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.size() << " 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 // ************************************************************************* //
static void addNote(const string &note)
Add extra notes for the usage information.
Definition: argList.C:462
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.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
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
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:578
const labelListList & pointEdges() const
Wave propagation of information along patch. Every iteration information goes through one layer of fa...
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:49
bool empty() const noexcept
True if List is empty (ie, size() is zero)
Definition: UList.H:632
bool coupled(solutionDict.getOrDefault("coupledEnergyField", false))
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
virtual bool checkParallelSync(const bool report=false) const
Check whether all procs have faces synchronised.
Definition: faceZone.C:509
Transport of orientation for use in PatchEdgeFaceWave.
Required Variables.
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Can be negative if the process i...
Definition: UPstream.H:1029
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
A PrimitivePatch with an IndirectList for the faces, const reference for the point field...
labelList faceLabels(nFaceLabels)
T returnReduce(const T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Perform reduction on a copy, using specified binary operation.
bool isInternalFace(const label faceIndex) const noexcept
Return true if given face label is internal to the mesh.
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1073
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:414
A list of faces which address into the list of points.
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:62
bool returnReduceAnd(const bool value, const label comm=UPstream::worldComm)
Perform logical (and) MPI Allreduce on a copy. Uses UPstream::reduceAnd.
dynamicFvMesh & mesh
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition: polyMesh.H:584
A class for handling words, derived from Foam::string.
Definition: word.H:63
virtual bool write(const bool writeOnProc=true) const
Write using setting from DB.
void flip()
Reverse the orientation.
label nInternalFaces() const noexcept
Number of internal faces.
void append(const T &val)
Copy append an element to the end of this list.
Definition: DynamicList.H:570
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1098
label whichPatch(const label meshFacei) const
Return patch index for a given mesh face index. Uses binary search.
errorManip< error > abort(error &err)
Definition: errorManip.H:139
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO...
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
const faceZoneMesh & faceZones() const noexcept
Return face zone mesh.
Definition: polyMesh.H:646
const edgeList & edges() const
Return mesh edges. Uses calcEdges.
const vectorField & faceCentres() const
T get(const label index) const
Get a value from the argument at index.
Definition: argListI.H:271
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:59
const word & name() const noexcept
The zone name.
const std::string patch
OpenFOAM patch number as a std::string.
static void addArgument(const string &argName, const string &usage="")
Append a (mandatory) argument to validArgs.
Definition: argList.C:351
void reduce(const List< UPstream::commsStruct > &comms, T &value, const BinaryOp &bop, const int tag, const label comm)
Reduce inplace (cf. MPI Allreduce) using specified communication schedule.
const boolList & flipMap() const noexcept
Return face flip map.
Definition: faceZone.H:325
messageStream Info
Information stream (stdout output on master, null elsewhere)
constexpr label labelMax
Definition: label.H:55
A subset of mesh faces organised as a primitive patch.
Definition: faceZone.H:60
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.
label nBoundaryFaces() const noexcept
Number of boundary faces (== nFaces - nInternalFaces)
Foam::argList args(argc, argv)
A List with indirect addressing.
Definition: IndirectList.H:60
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
Namespace for OpenFOAM.
static void swapBoundaryFaceList(const polyMesh &mesh, UList< T > &faceValues)
Swap coupled boundary face values. Uses eqOp.
Definition: syncTools.H:485
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:133