wedgePolyPatch.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2024 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "wedgePolyPatch.H"
28 #include "polyMesh.H"
29 #include "polyBoundaryMesh.H"
30 #include "RemoteData.H"
31 #include "SubField.H"
32 #include "Tuple3.H"
33 #include "transform.H"
34 
35 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
36 
37 namespace Foam
38 {
40 
43 }
44 
45 
46 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
47 
48 bool Foam::wedgePolyPatch::isQuadFace(const label facei) const
49 {
50  const polyMesh& mesh = boundaryMesh().mesh();
51 
52  const face& f = mesh.faces()[facei];
53 
54  // Face must be of size 4
55  if (f.size() != 4) return false;
56 
57  // Face must not have any repeated points
58  forAll(f, fpi)
59  {
60  for (label fpj = fpi + 1; fpj < f.size(); ++ fpj)
61  {
62  if (f[fpi] == f[fpj]) return false;
63  }
64  }
65 
66  return true;
67 }
68 
69 
70 bool Foam::wedgePolyPatch::isWedgeFace(const label facei) const
71 {
72  return
73  facei >= boundaryMesh().mesh().nInternalFaces()
74  && isA<wedgePolyPatch>
75  (
76  boundaryMesh()
77  [
78  boundaryMesh().patchIndices()
79  [
80  facei - boundaryMesh().mesh().nInternalFaces()
81  ]
82  ]
83  );
84 }
85 
86 
87 Foam::label Foam::wedgePolyPatch::oppositeWedgeFace(const label thisFacei) const
88 {
89  const polyMesh& mesh = boundaryMesh().mesh();
90 
91  // Function to generate a generic error that the search for the opposite
92  // wedge face has failed
93  auto error = [&]()
94  {
96  << "Wedge face not found opposite face " << thisFacei;
97 
98  if (Pstream::parRun())
99  {
101  << " on processor " << Pstream::myProcNo();
102  }
103 
105  << " at " << mesh.faceCentres()[thisFacei]
106  << exit(FatalError);
107  };
108 
109  const face& thisF = mesh.faces()[thisFacei];
110 
111  const cell& c = mesh.cells()[mesh.faceOwner()[thisFacei]];
112 
113  // Look for a "mid" face. This is any a quad face in the cell that is not
114  // on a wedge patch and is edge-connected to this face.
115  label midFacei = -1, midThisFaceEdgei = -1;
116  for (label cfi = 0; cfi < c.size() && midFacei == -1; ++ cfi)
117  {
118  const label facei = c[cfi];
119  const face& f = mesh.faces()[facei];
120 
121  if
122  (
123  thisFacei == facei
124  || !isQuadFace(facei)
125  || isWedgeFace(facei)
126  ) continue;
127 
128  for
129  (
130  label thisFei = 0;
131  thisFei < thisF.size() && midFacei == -1;
132  ++ thisFei
133  )
134  {
135  const edge thisE = thisF.faceEdge(thisFei);
136 
137  for (label fei = 0; fei < f.size() && midFacei == -1; ++ fei)
138  {
139  const edge e = f.faceEdge(fei);
140 
141  if (edge::compare(thisE, e) != 0)
142  {
143  midFacei = facei;
144  midThisFaceEdgei = fei;
145  }
146  }
147  }
148  }
149 
150  if (midFacei == -1) error();
151 
152  // Get the edge on the opposite side of the "mid" face
153  const label midOppFaceEdgei = (midThisFaceEdgei + 2) % 4;
154  const edge midOppE = mesh.faces()[midFacei].faceEdge(midOppFaceEdgei);
155 
156  // Look for the opposite face. This is a face in the cell that is on a
157  // wedge patch and is edge connected to the edge of the "mid" face opposite
158  // the provided face.
159  label oppFacei = -1;
160  for (label cfi = 0; cfi < c.size() && oppFacei == -1; ++ cfi)
161  {
162  const label facei = c[cfi];
163  const face& f = mesh.faces()[facei];
164 
165  if
166  (
167  facei == thisFacei
168  || facei == midFacei
169  || !isWedgeFace(facei)
170  ) continue;
171 
172  for (label fei = 0; fei < f.size() && oppFacei == -1; ++ fei)
173  {
174  const edge e = f.faceEdge(fei);
175 
176  if (edge::compare(midOppE, e) != 0)
177  {
178  oppFacei = facei;
179  }
180  }
181  }
182 
183  if (oppFacei == -1) error();
184 
185  return oppFacei;
186 }
187 
188 
189 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
190 
192 {
193  if (axis_ != vector::rootMax)
194  {
195  return;
196  }
197 
198  if (!returnReduce(size(), sumOp<label>()))
199  {
200  return;
201  }
202 
204  const vectorField& nf(faceNormals());
205  n_ = gAverage(nf);
206 
207  if (debug)
208  {
209  Info<< "Patch " << name() << " calculated average normal "
210  << n_ << endl;
211  }
212 
213  // Get the largest variation from the average normal
215  if (size())
216  {
217  const scalarField deltaNSqr(magSqr(n_ - nf));
218  const label i = findMax(deltaNSqr);
219  maxDeltaN = {Pstream::myProcNo(), i, {deltaNSqr[i], cf[i], nf[i]}};
220  }
222  (
223  maxDeltaN,
224  RemoteData<Tuple3<scalar, vector, vector>>::greatestFirstEqOp()
225  );
226 
227  // Warn if the wedge is not planar
228  if (maxDeltaN.data.first() > small)
229  {
230  Ostream& wos =
232  << "Wedge patch '" << name()
233  << "' may not be sufficiently planar" << nl;
234 
235  wos << "At patch face #" << maxDeltaN.elementi;
236 
237  if (Pstream::parRun())
238  {
239  wos << " on processor #" << maxDeltaN.proci;
240  }
241 
242  wos << " with centre " << maxDeltaN.data.second()
243  << " the normal " << maxDeltaN.data.third()
244  << " differs from the average normal " << n_
245  << " by " << maxDeltaN.data.first() << nl << endl;
246  }
247 
248  centreNormal_ =
249  vector
250  (
251  sign(n_.x())*(max(mag(n_.x()), 0.5) - 0.5),
252  sign(n_.y())*(max(mag(n_.y()), 0.5) - 0.5),
253  sign(n_.z())*(max(mag(n_.z()), 0.5) - 0.5)
254  );
255  centreNormal_ /= mag(centreNormal_);
256 
257  cosAngle_ = centreNormal_ & n_;
258 
259  const scalar cnCmptSum =
260  centreNormal_.x() + centreNormal_.y() + centreNormal_.z();
261 
262  if (mag(cnCmptSum) < (1 - small))
263  {
265  << "wedge " << name()
266  << " centre plane does not align with a coordinate plane by "
267  << 1 - mag(cnCmptSum)
268  << exit(FatalError);
269  }
270 
271  axis_ = centreNormal_ ^ n_;
272  scalar magAxis = mag(axis_);
273 
274  if (magAxis < small)
275  {
277  << "wedge " << name()
278  << " plane aligns with a coordinate plane." << nl
279  << " The wedge plane should make a small angle (~2.5deg)"
280  " with the coordinate plane" << nl
281  << " and the pair of wedge planes should be symmetric"
282  << " about the coordinate plane." << nl
283  << " Normal of wedge plane is " << n_
284  << " , implied coordinate plane direction is " << centreNormal_
285  << exit(FatalError);
286  }
287 
288  axis_ /= magAxis;
289 
290  faceT_ = rotationTensor(centreNormal_, n_);
291  cellT_ = faceT_ & faceT_;
292 }
293 
294 
295 // * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * * * * * //
296 
298 (
299  const word& name,
300  const label size,
301  const label start,
302  const label index,
303  const polyBoundaryMesh& bm,
304  const word& patchType
305 )
306 :
307  polyPatch(name, size, start, index, bm, patchType),
308  axis_(vector::rootMax),
309  centreNormal_(vector::rootMax),
310  n_(vector::rootMax),
311  cosAngle_(0.0),
312  faceT_(Zero),
313  cellT_(Zero),
314  oppositePatchIndex_(-1)
315 {}
316 
317 
319 (
320  const word& name,
321  const dictionary& dict,
322  const label index,
323  const polyBoundaryMesh& bm,
324  const word& patchType
325 )
326 :
327  polyPatch(name, dict, index, bm, patchType),
328  axis_(vector::rootMax),
329  centreNormal_(vector::rootMax),
330  n_(vector::rootMax),
331  cosAngle_(0.0),
332  faceT_(Zero),
333  cellT_(Zero),
334  oppositePatchIndex_(-1)
335 {}
336 
337 
339 (
340  const wedgePolyPatch& pp,
341  const polyBoundaryMesh& bm
342 )
343 :
344  polyPatch(pp, bm),
345  axis_(pp.axis_),
346  centreNormal_(pp.centreNormal_),
347  n_(pp.n_),
348  cosAngle_(pp.cosAngle_),
349  faceT_(pp.faceT_),
350  cellT_(pp.cellT_),
351  oppositePatchIndex_(-1)
352 {}
353 
354 
356 (
357  const wedgePolyPatch& pp,
358  const polyBoundaryMesh& bm,
359  const label index,
360  const label newSize,
361  const label newStart
362 )
363 :
364  polyPatch(pp, bm, index, newSize, newStart),
365  axis_(pp.axis_),
366  centreNormal_(pp.centreNormal_),
367  n_(pp.n_),
368  cosAngle_(pp.cosAngle_),
369  faceT_(pp.faceT_),
370  cellT_(pp.cellT_),
371  oppositePatchIndex_(-1)
372 {}
373 
374 
375 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
376 
378 {
379  if (oppositePatchIndex_ == -1)
380  {
381  if (size())
382  {
383  oppositePatchIndex_ =
384  boundaryMesh().patchIndices()
385  [
386  oppositeWedgeFace(start())
387  - boundaryMesh().mesh().nInternalFaces()
388  ];
389  }
390 
391  reduce(oppositePatchIndex_, maxOp<label>());
392  }
393 
394  return oppositePatchIndex_;
395 }
396 
397 
399 {
400  const polyPatch& pp = boundaryMesh()[oppositePatchIndex()];
401  return refCast<const wedgePolyPatch>(pp);
402 }
403 
404 
405 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:433
Macros for easy insertion into run-time selection tables.
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:57
const Field< PointType > & faceCentres() const
Return face centres for patch.
Buffers for inter-processor communications streams (UOPstream, UIPstream).
Struct for keeping processor, element (cell, face, point) and a piece of data. Used for finding minim...
Definition: RemoteData.H:65
Type data
Data.
Definition: RemoteData.H:75
A 3-tuple for storing three objects of different types.
Definition: Tuple3.H:60
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:399
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
static const Form rootMax
Definition: VectorSpace.H:122
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
static int compare(const edge &, const edge &)
Compare edges.
Definition: edgeI.H:36
const polyMesh & mesh() const
Return reference to polyMesh.
Definition: fvMesh.H:443
Foam::polyBoundaryMesh.
const polyMesh & mesh() const
Return the mesh reference.
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1344
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1357
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:70
const polyBoundaryMesh & boundaryMesh() const
Return boundaryMesh reference.
Definition: polyPatch.C:270
const vectorField & faceCentres() const
const cellList & cells() const
label elementi
Element index.
Definition: remote.H:70
label proci
Processor index.
Definition: remote.H:67
Wedge front and back plane patch.
virtual void calcGeometry(PstreamBuffers &)
Calculate the patch geometry.
const wedgePolyPatch & oppositePatch() const
Return a reference to the opposite wedge patch.
wedgePolyPatch(const word &name, const label size, const label start, const label index, const polyBoundaryMesh &bm, const word &patchType)
Construct from components.
label oppositePatchIndex() const
Return the index of the opposite wedge patch.
A class for handling words, derived from string.
Definition: word.H:62
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
#define WarningInFunction
Report a warning using Foam::Warning.
const dimensionedScalar c
Speed of light in a vacuum.
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
static const zero Zero
Definition: zero.H:97
const doubleScalar e
Definition: doubleScalar.H:106
tensor rotationTensor(const vector &n1, const vector &n2)
Rotational transformation tensor from unit vector n1 to n2.
Definition: transform.H:47
dimensionedScalar sign(const dimensionedScalar &ds)
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
addToRunTimeSelectionTable(polyPatch, mergedCyclicPolyPatch, word)
label findMax(const ListType &, const label start=0)
Find index of max element (and larger than given element).
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:258
messageStream Info
void mag(LagrangianPatchField< scalar > &f, const LagrangianPatchField< Type > &f1)
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:49
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
defineTypeNameAndDebug(combustionModel, 0)
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
Type gAverage(const FieldField< Field, Type > &f)
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
error FatalError
void magSqr(LagrangianPatchField< scalar > &f, const LagrangianPatchField< Type > &f1)
static const char nl
Definition: Ostream.H:267
void combineReduce(const List< UPstream::commsStruct > &comms, T &Value, const CombineOp &cop, const int tag, const label comm)
labelList f(nPoints)
dictionary dict
3D tensor transformation operations.