processorPolyPatch.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-2026 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 "processorPolyPatch.H"
28 #include "dictionary.H"
29 #include "SubField.H"
30 #include "demandDrivenData.H"
31 #include "matchPoints.H"
32 #include "OFstream.H"
33 #include "polyMesh.H"
34 #include "Time.H"
35 #include "PstreamBuffers.H"
36 #include "ConstCirculator.H"
37 
38 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
39 
40 namespace Foam
41 {
44 }
45 
46 
47 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
48 
50 (
51  const word& name,
52  const label size,
53  const label start,
54  const label index,
55  const polyBoundaryMesh& bm,
56  const int myProcNo,
57  const int neighbProcNo
58 )
59 :
60  coupledPolyPatch(name, size, start, index, bm),
61  myProcNo_(myProcNo),
62  neighbProcNo_(neighbProcNo),
63  neighbFaceCentres_(),
64  neighbFaceAreas_(),
65  neighbFaceCellCentres_()
66 {}
67 
68 
70 (
71  const label size,
72  const label start,
73  const label index,
74  const polyBoundaryMesh& bm,
75  const int myProcNo,
76  const int neighbProcNo
77 )
78 :
80  (
81  newName(myProcNo, neighbProcNo),
82  size,
83  start,
84  index,
85  bm
86  ),
87  myProcNo_(myProcNo),
88  neighbProcNo_(neighbProcNo),
89  neighbFaceCentres_(),
90  neighbFaceAreas_(),
91  neighbFaceCellCentres_()
92 {}
93 
94 
96 (
97  const word& name,
98  const dictionary& dict,
99  const label index,
100  const polyBoundaryMesh& bm
101 )
102 :
103  coupledPolyPatch(name, dict, index, bm),
104  myProcNo_(dict.lookup<label>("myProcNo")),
105  neighbProcNo_(dict.lookup<label>("neighbProcNo")),
106  neighbFaceCentres_(),
107  neighbFaceAreas_(),
108  neighbFaceCellCentres_()
109 {}
110 
111 
113 (
114  const processorPolyPatch& pp,
115  const polyBoundaryMesh& bm
116 )
117 :
118  coupledPolyPatch(pp, bm),
119  myProcNo_(pp.myProcNo_),
120  neighbProcNo_(pp.neighbProcNo_),
121  neighbFaceCentres_(),
122  neighbFaceAreas_(),
123  neighbFaceCellCentres_()
124 {}
125 
126 
128 (
129  const processorPolyPatch& pp,
130  const polyBoundaryMesh& bm,
131  const label index,
132  const label newSize,
133  const label newStart
134 )
135 :
136  coupledPolyPatch(pp, bm, index, newSize, newStart),
137  myProcNo_(pp.myProcNo_),
138  neighbProcNo_(pp.neighbProcNo_),
139  neighbFaceCentres_(),
140  neighbFaceAreas_(),
141  neighbFaceCellCentres_()
142 {}
143 
144 
145 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
146 
148 {
149  nbrPointsPtr_.clear();
150  nbrEdgesPtr_.clear();
151 }
152 
153 
154 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
155 
157 (
158  const label myProcNo,
159  const label neighbProcNo
160 )
161 {
162  return
163  "procBoundary"
164  + Foam::name(myProcNo)
165  + "to"
166  + Foam::name(neighbProcNo);
167 }
168 
169 
171 {
172  if (Pstream::parRun())
173  {
174  UOPstream toNeighbProc(neighbProcNo(), pBufs);
175 
176  toNeighbProc
177  << faceCentres()
178  << faceAreas()
179  << faceCellCentres();
180  }
181 }
182 
183 
185 {
186  if (Pstream::parRun())
187  {
188  {
189  UIPstream fromNeighbProc(neighbProcNo(), pBufs);
190 
191  fromNeighbProc
192  >> neighbFaceCentres_
193  >> neighbFaceAreas_
194  >> neighbFaceCellCentres_;
195  }
196 
197  // My normals
198  vectorField faceNormals(size());
199 
200  // Neighbour normals
201  vectorField nbrFaceNormals(neighbFaceAreas_.size());
202 
203  // Face match tolerances
204  scalarField tols = calcFaceTol(*this, points(), faceCentres());
205 
206  // Calculate normals from areas and check
207  forAll(faceNormals, facei)
208  {
209  scalar magSf = magFaceAreas()[facei];
210  scalar nbrMagSf = mag(neighbFaceAreas_[facei]);
211  scalar avSf = (magSf + nbrMagSf)/2.0;
212 
213  // For small face area calculation the results of the area
214  // calculation have been found to only be accurate to ~1e-20
215  if (magSf < small || nbrMagSf < small)
216  {
217  // Undetermined normal. Use dummy normal to force separation
218  // check.
219  faceNormals[facei] = point(1, 0, 0);
220  nbrFaceNormals[facei] = -faceNormals[facei];
221  tols[facei] = great;
222  }
223  else if (mag(magSf - nbrMagSf) > matchTolerance()*sqr(tols[facei]))
224  {
225  const fileName patchOBJName
226  (
227  mesh().time().path()/name() + "_faces.obj"
228  );
229 
230  Pout<< "processorPolyPatch::calcGeometry : Writing my "
231  << size() << " faces to " << patchOBJName << endl;
232 
233  writeOBJ(patchOBJName, *this);
234 
235  const fileName centresOBJName
236  (
237  mesh().time().path()/name()
238  + "_faceCentresConnections.obj"
239  );
240 
241  Pout<< "processorPolyPatch::calcGeometry :"
242  << " Dumping lines between corresponding face centres to "
243  << centresOBJName.name() << endl;
244 
245  writeOBJ(centresOBJName, neighbFaceCentres_, faceCentres());
246 
248  << "face " << facei << " area does not match neighbour by "
249  << 100*mag(magSf - nbrMagSf)/avSf
250  << "% -- possible face ordering problem." << endl
251  << "patch:" << name()
252  << " my area:" << magSf
253  << " neighbour area:" << nbrMagSf
254  << " matching tolerance:"
255  << matchTolerance()*sqr(tols[facei])
256  << endl
257  << "Mesh face:" << start()+facei
258  << " vertices:"
259  << UIndirectList<point>(points(), operator[](facei))()
260  << endl
261  << "If you are certain your matching is correct"
262  << " you can increase the 'matchTolerance' setting"
263  << " in the patch dictionary in the boundary file."
264  << endl
265  << "Rerun with processor debug flag set for"
266  << " more information." << exit(FatalError);
267  }
268  else
269  {
270  faceNormals[facei] = faceAreas()[facei]/magSf;
271  nbrFaceNormals[facei] = neighbFaceAreas_[facei]/nbrMagSf;
272  }
273  }
274  }
275 }
276 
277 
279 (
280  PstreamBuffers& pBufs,
281  const pointField& p
282 )
283 {
284  polyPatch::movePoints(pBufs, p);
286 }
287 
288 
290 (
291  PstreamBuffers& pBufs,
292  const pointField&
293 )
294 {
296 }
297 
298 
300 {
302 
303  if (Pstream::parRun())
304  {
305  // Express all points as patch face and index in face.
306  labelList pointFace(nPoints());
307  labelList pointIndex(nPoints());
308 
309  for (label patchPointi = 0; patchPointi < nPoints(); patchPointi++)
310  {
311  label facei = pointFaces()[patchPointi][0];
312 
313  pointFace[patchPointi] = facei;
314 
315  const face& f = localFaces()[facei];
316 
317  pointIndex[patchPointi] = findIndex(f, patchPointi);
318  }
319 
320  // Express all edges as patch face and index in face.
321  labelList edgeFace(nEdges());
322  labelList edgeIndex(nEdges());
323 
324  for (label patchEdgeI = 0; patchEdgeI < nEdges(); patchEdgeI++)
325  {
326  label facei = edgeFaces()[patchEdgeI][0];
327 
328  edgeFace[patchEdgeI] = facei;
329 
330  const labelList& fEdges = faceEdges()[facei];
331 
332  edgeIndex[patchEdgeI] = findIndex(fEdges, patchEdgeI);
333  }
334 
335  UOPstream toNeighbProc(neighbProcNo(), pBufs);
336 
337  toNeighbProc
338  << pointFace
339  << pointIndex
340  << edgeFace
341  << edgeIndex;
342  }
343 }
344 
345 
347 {
348  // For completeness
349  polyPatch::topoChange(pBufs);
350 
351  nbrPointsPtr_.clear();
352  nbrEdgesPtr_.clear();
353 
354  if (Pstream::parRun())
355  {
356  labelList nbrPointFace;
357  labelList nbrPointIndex;
358  labelList nbrEdgeFace;
359  labelList nbrEdgeIndex;
360 
361  {
362  // !Note: there is one situation where the opposite points and
363  // do not exactly match and that is while we are distributing
364  // meshes and multiple parts come together from different
365  // processors. This can temporarily create the situation that
366  // we have points which will be merged out later but we still
367  // need the face connectivity to be correct.
368  // So: cannot check here on same points and edges.
369 
370  UIPstream fromNeighbProc(neighbProcNo(), pBufs);
371 
372  fromNeighbProc
373  >> nbrPointFace
374  >> nbrPointIndex
375  >> nbrEdgeFace
376  >> nbrEdgeIndex;
377  }
378 
379  // Convert neighbour faces and indices into face back into
380  // my edges and points.
381 
382  // Convert points.
383  // ~~~~~~~~~~~~~~~
384 
385  nbrPointsPtr_.reset(new labelList(nPoints(), -1));
386  labelList& nbrPoints = nbrPointsPtr_();
387 
388  forAll(nbrPointFace, nbrPointi)
389  {
390  // Find face and index in face on this side.
391  const face& f = localFaces()[nbrPointFace[nbrPointi]];
392 
393  label index = (f.size() - nbrPointIndex[nbrPointi]) % f.size();
394  label patchPointi = f[index];
395 
396  if (nbrPoints[patchPointi] == -1)
397  {
398  // First reference of point
399  nbrPoints[patchPointi] = nbrPointi;
400  }
401  else if (nbrPoints[patchPointi] >= 0)
402  {
403  // Point already visited. Mark as duplicate.
404  nbrPoints[patchPointi] = -2;
405  }
406  }
407 
408  // Reset all duplicate entries to -1.
409  forAll(nbrPoints, patchPointi)
410  {
411  if (nbrPoints[patchPointi] == -2)
412  {
413  nbrPoints[patchPointi] = -1;
414  }
415  }
416 
417  // Convert edges.
418  // ~~~~~~~~~~~~~~
419 
420  nbrEdgesPtr_.reset(new labelList(nEdges(), -1));
421  labelList& nbrEdges = nbrEdgesPtr_();
422 
423  forAll(nbrEdgeFace, nbrEdgeI)
424  {
425  // Find face and index in face on this side.
426  const labelList& f = faceEdges()[nbrEdgeFace[nbrEdgeI]];
427  label index = (f.size() - nbrEdgeIndex[nbrEdgeI] - 1) % f.size();
428  label patchEdgeI = f[index];
429 
430  if (nbrEdges[patchEdgeI] == -1)
431  {
432  // First reference of edge
433  nbrEdges[patchEdgeI] = nbrEdgeI;
434  }
435  else if (nbrEdges[patchEdgeI] >= 0)
436  {
437  // Edge already visited. Mark as duplicate.
438  nbrEdges[patchEdgeI] = -2;
439  }
440  }
441 
442  // Reset all duplicate entries to -1.
443  forAll(nbrEdges, patchEdgeI)
444  {
445  if (nbrEdges[patchEdgeI] == -2)
446  {
447  nbrEdges[patchEdgeI] = -1;
448  }
449  }
450 
451  // Remove any addressing used for shared points/edges calculation
452  // since mostly not needed.
454  }
455 }
456 
457 
459 {
460  if (!nbrPointsPtr_.valid())
461  {
463  << "No extended addressing calculated for patch " << name()
464  << abort(FatalError);
465  }
466  return nbrPointsPtr_();
467 }
468 
469 
471 {
472  if (!nbrEdgesPtr_.valid())
473  {
475  << "No extended addressing calculated for patch " << name()
476  << abort(FatalError);
477  }
478  return nbrEdgesPtr_();
479 }
480 
481 
483 (
484  PstreamBuffers& pBufs,
485  const primitivePatch& pp
486 ) const
487 {
488  if (!Pstream::parRun())
489  {
490  return;
491  }
492 
493  if (owner())
494  {
495  ownToNbrOrderData ownToNbr;
496  autoPtr<ownToNbrDebugOrderData> ownToNbrDebugPtr
497  (
498  coupledPolyPatch::debug
499  ? new ownToNbrDebugOrderData()
500  : nullptr
501  );
502 
504  (
505  ownToNbr,
506  ownToNbrDebugPtr,
507  pp
508  );
509 
510  UOPstream toNeighbour(neighbProcNo(), pBufs);
511  toNeighbour << ownToNbr;
512  if (coupledPolyPatch::debug)
513  {
514  toNeighbour << ownToNbrDebugPtr();
515  }
516  }
517 }
518 
519 
521 (
522  PstreamBuffers& pBufs,
523  const primitivePatch& pp,
525  labelList& rotation
526 ) const
527 {
528  if (!Pstream::parRun())
529  {
530  return false;
531  }
532 
533  ownToNbrOrderData ownToNbr;
534  autoPtr<ownToNbrDebugOrderData> ownToNbrDebugPtr
535  (
536  coupledPolyPatch::debug
537  ? new ownToNbrDebugOrderData()
538  : nullptr
539  );
540 
541  if (!owner())
542  {
543  UIPstream fromOwner(neighbProcNo(), pBufs);
544  fromOwner >> ownToNbr;
545  ownToNbr.transform(transform());
546  if (coupledPolyPatch::debug)
547  {
548  fromOwner >> ownToNbrDebugPtr();
549  ownToNbrDebugPtr->transform(transform());
550  }
551  }
552 
553  return
555  (
556  ownToNbr,
557  ownToNbrDebugPtr,
558  pp,
559  faceMap,
560  rotation
561  );
562 }
563 
564 
566 {
568  writeEntry(os, "myProcNo", myProcNo_);
569  writeEntry(os, "neighbProcNo", neighbProcNo_);
570 }
571 
572 
573 // ************************************************************************* //
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
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
Buffers for inter-processor communications streams (UOPstream, UIPstream).
Input inter-processor communications stream operating on external buffer.
Definition: UIPstream.H:57
A List with indirect addressing.
Definition: UIndirectList.H:61
Output inter-processor communications stream operating on external buffer.
Definition: UOPstream.H:58
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:399
The coupledPolyPatch is an abstract base class for patches that couple regions of the computational d...
virtual void write(Ostream &) const
Write the polyPatch data as a dictionary.
virtual bool order(const ownToNbrOrderData &ownToNbr, const autoPtr< ownToNbrDebugOrderData > &ownToNbrDebugPtr, const primitivePatch &, labelList &faceMap, labelList &rotation) const
Return new ordering for the given primitivePatch.
virtual void initOrder(ownToNbrOrderData &ownToNbr, autoPtr< ownToNbrDebugOrderData > &ownToNbrDebugPtr, const primitivePatch &) const
Initialise ordering for the given primitivePatch. Fills the.
A list of keywords followed by any number of values (e.g. words and numbers) or sub-dictionaries.
Definition: dictionary.H:162
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:76
A class for handling file names.
Definition: fileName.H:82
word name() const
Return file name (part beyond last /)
Definition: fileName.C:195
Foam::polyBoundaryMesh.
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:71
virtual void movePoints(const pointField &p)
Correct patches after moving points.
Definition: polyPatch.C:56
virtual void initTopoChange(PstreamBuffers &)
Initialise the update of the patch topology.
Definition: polyPatch.H:116
virtual void topoChange(PstreamBuffers &)
Update of the patch topology.
Definition: polyPatch.C:68
Neighbour processor patch.
virtual void write(Ostream &) const
Write the polyPatch data as a dictionary.
void initMovePoints(PstreamBuffers &, const pointField &)
Initialise the patches for moving points.
virtual ~processorPolyPatch()
Destructor.
void calcGeometry(PstreamBuffers &)
Calculate the patch geometry.
virtual void initOrder(PstreamBuffers &, const primitivePatch &) const
Initialise ordering for primitivePatch. Does not.
void initCalcGeometry(PstreamBuffers &)
Initialise the calculation of the patch geometry.
const labelList & nbrPoints() const
Return neighbour point labels. WIP.
const labelList & nbrEdges() const
Return neighbour edge labels. WIP.
static word newName(const label myProcNo, const label neighbProcNo)
Return the name of a processorPolyPatch.
virtual bool order(PstreamBuffers &, const primitivePatch &, labelList &faceMap, labelList &rotation) const
Return new ordering for primitivePatch.
void movePoints(PstreamBuffers &, const pointField &)
Correct patches after moving points.
processorPolyPatch(const word &name, const label size, const label start, const label index, const polyBoundaryMesh &bm, const int myProcNo, const int neighbProcNo)
Construct from components with specified name.
virtual void initTopoChange(PstreamBuffers &)
Initialise the update of the patch topology.
virtual void topoChange(PstreamBuffers &)
Update of the patch topology.
A class for handling words, derived from string.
Definition: word.H:63
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
Template functions to aid in the implementation of demand driven data.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
const pointField & points
label nPoints
Determine correspondence between points. See below.
const dimensionSet time
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of point.
Definition: meshTools.C:203
const unitSet & lookup(const word &unitName)
Lookup and return the named unit from the table.
Definition: units.C:346
Namespace for OpenFOAM.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
List< label > labelList
A List of labels.
Definition: labelList.H:56
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)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
void transform(GeometricField< Type, GeoMesh > &rtf, const GeometricField< tensor, GeoMesh > &trf, const GeometricField< Type, GeoMesh > &tf)
errorManip< error > abort(error &err)
Definition: errorManip.H:131
vector point
Point is a vector.
Definition: point.H:41
tmp< DimensionedField< typename outerProduct< Type, Type >::type, GeoMesh, Field >> sqr(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
word name(const LagrangianState state)
Return a string representation of a Lagrangian state enumeration.
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
tmp< DimensionedField< scalar, GeoMesh, Field > > mag(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurrence of given element and return index,.
error FatalError
defineTypeNameAndDebug(atmosphericBoundaryLayer, 0)
void writeEntry(Ostream &os, const word &key, const DimensionedFieldFunction< DimensionedFieldType > &f)
labelList f(nPoints)
dictionary dict
volScalarField & p
Data to pass from owner.initOrder to nbr.order if debugging.
Data to pass from owner.initOrder to nbr.order.
void transform(const transformer &tr)