processorPolyPatch.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) 2011-2017 OpenFOAM Foundation
9  Copyright (C) 2015-2020 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 \*---------------------------------------------------------------------------*/
28 
29 #include "processorPolyPatch.H"
31 #include "dictionary.H"
32 #include "SubField.H"
33 #include "demandDrivenData.H"
34 #include "matchPoints.H"
35 #include "OFstream.H"
36 #include "polyMesh.H"
37 #include "Time.H"
38 #include "transformList.H"
39 #include "PstreamBuffers.H"
40 #include "ConstCirculator.H"
41 
42 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
43 
44 namespace Foam
45 {
46  defineTypeNameAndDebug(processorPolyPatch, 0);
47  addToRunTimeSelectionTable(polyPatch, processorPolyPatch, dictionary);
48 }
49 
50 
51 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
52 
54 (
55  const word& name,
56  const label size,
57  const label start,
58  const label index,
59  const polyBoundaryMesh& bm,
60  const int myProcNo,
61  const int neighbProcNo,
63  const word& patchType
64 )
65 :
66  coupledPolyPatch(name, size, start, index, bm, patchType, transform),
67  myProcNo_(myProcNo),
68  neighbProcNo_(neighbProcNo),
69  neighbFaceCentres_(),
70  neighbFaceAreas_(),
71  neighbFaceCellCentres_()
72 {}
73 
74 
76 (
77  const label size,
78  const label start,
79  const label index,
80  const polyBoundaryMesh& bm,
81  const int myProcNo,
82  const int neighbProcNo,
84  const word& patchType
85 )
86 :
88  (
89  newName(myProcNo, neighbProcNo),
90  size,
91  start,
92  index,
93  bm,
94  patchType,
95  transform
96  ),
97  myProcNo_(myProcNo),
98  neighbProcNo_(neighbProcNo),
99  neighbFaceCentres_(),
100  neighbFaceAreas_(),
101  neighbFaceCellCentres_()
102 {}
103 
104 
106 (
107  const word& name,
108  const dictionary& dict,
109  const label index,
110  const polyBoundaryMesh& bm,
111  const word& patchType
112 )
113 :
114  coupledPolyPatch(name, dict, index, bm, patchType),
115  myProcNo_(dict.get<label>("myProcNo")),
116  neighbProcNo_(dict.get<label>("neighbProcNo")),
117  neighbFaceCentres_(),
118  neighbFaceAreas_(),
119  neighbFaceCellCentres_()
120 {}
121 
122 
124 (
125  const processorPolyPatch& pp,
126  const polyBoundaryMesh& bm
127 )
128 :
129  coupledPolyPatch(pp, bm),
130  myProcNo_(pp.myProcNo_),
131  neighbProcNo_(pp.neighbProcNo_),
132  neighbFaceCentres_(),
133  neighbFaceAreas_(),
134  neighbFaceCellCentres_()
135 {}
136 
137 
139 (
140  const processorPolyPatch& pp,
141  const polyBoundaryMesh& bm,
142  const label index,
143  const label newSize,
144  const label newStart
145 )
146 :
147  coupledPolyPatch(pp, bm, index, newSize, newStart),
148  myProcNo_(pp.myProcNo_),
149  neighbProcNo_(pp.neighbProcNo_),
150  neighbFaceCentres_(),
151  neighbFaceAreas_(),
152  neighbFaceCellCentres_()
153 {}
154 
155 
157 (
158  const processorPolyPatch& pp,
159  const polyBoundaryMesh& bm,
160  const label index,
161  const labelUList& mapAddressing,
162  const label newStart
163 )
164 :
165  coupledPolyPatch(pp, bm, index, mapAddressing, newStart),
166  myProcNo_(pp.myProcNo_),
167  neighbProcNo_(pp.neighbProcNo_),
168  neighbFaceCentres_(),
169  neighbFaceAreas_(),
170  neighbFaceCellCentres_()
171 {}
172 
173 
174 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
175 
177 {
178  neighbPointsPtr_.clear();
179  neighbEdgesPtr_.clear();
180 }
181 
182 
183 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
184 
186 (
187  const label myProcNo,
188  const label neighbProcNo
189 )
190 {
191  return
192  "procBoundary"
193  + Foam::name(myProcNo)
194  + "to"
195  + Foam::name(neighbProcNo);
196 }
197 
198 
200 {
201  if (Pstream::parRun())
202  {
203  if (neighbProcNo() >= Pstream::nProcs(pBufs.comm()))
204  {
206  << "On patch " << name()
207  << " trying to access out of range neighbour processor "
208  << neighbProcNo() << ". This can happen if" << nl
209  << " trying to run on an incorrect number of processors"
210  << exit(FatalError);
211  }
212 
213  UOPstream toNeighbProc(neighbProcNo(), pBufs);
214 
215  toNeighbProc
216  << faceCentres()
217  << faceAreas()
218  << faceCellCentres();
219  }
220 }
221 
222 
224 {
225  if (Pstream::parRun())
226  {
227  {
228  UIPstream fromNeighbProc(neighbProcNo(), pBufs);
229 
230  fromNeighbProc
231  >> neighbFaceCentres_
232  >> neighbFaceAreas_
233  >> neighbFaceCellCentres_;
234  }
235 
236  // My normals
237  vectorField faceNormals(size());
238 
239  // Neighbour normals
240  vectorField nbrFaceNormals(neighbFaceAreas_.size());
241 
242  // Face match tolerances
243  scalarField tols = calcFaceTol(*this, points(), faceCentres());
244 
245  // Calculate normals from areas and check
246  forAll(faceNormals, facei)
247  {
248  scalar magSf = mag(faceAreas()[facei]);
249  scalar nbrMagSf = mag(neighbFaceAreas_[facei]);
250  scalar avSf = (magSf + nbrMagSf)/2.0;
251 
252  // For small face area calculation the results of the area
253  // calculation have been found to only be accurate to ~1e-20
254  if (magSf < SMALL || nbrMagSf < SMALL)
255  {
256  // Undetermined normal. Use dummy normal to force separation
257  // check.
258  faceNormals[facei] = point(1, 0, 0);
259  nbrFaceNormals[facei] = -faceNormals[facei];
260  tols[facei] = GREAT;
261  }
262  else if (mag(magSf - nbrMagSf) > matchTolerance()*sqr(tols[facei]))
263  {
264  fileName nm
265  (
266  boundaryMesh().mesh().time().path()
267  /name()+"_faces.obj"
268  );
269 
270  Pout<< "processorPolyPatch::calcGeometry : Writing my "
271  << size()
272  << " faces to OBJ file " << nm << endl;
273 
274  writeOBJ(nm, *this, points());
275 
276  OFstream ccStr
277  (
278  boundaryMesh().mesh().time().path()
279  /name() + "_faceCentresConnections.obj"
280  );
281 
282  Pout<< "processorPolyPatch::calcGeometry :"
283  << " Dumping cell centre lines between"
284  << " corresponding face centres to OBJ file" << ccStr.name()
285  << endl;
286 
287  label vertI = 0;
288 
289  forAll(faceCentres(), facej)
290  {
291  const point& c0 = neighbFaceCentres_[facej];
292  const point& c1 = faceCentres()[facej];
293 
294  writeOBJ(ccStr, c0, c1, vertI);
295  }
296 
298  << "face " << facei << " area does not match neighbour by "
299  << 100*mag(magSf - nbrMagSf)/avSf
300  << "% -- possible face ordering problem." << endl
301  << "patch:" << name()
302  << " my area:" << magSf
303  << " neighbour area:" << nbrMagSf
304  << " matching tolerance:"
305  << matchTolerance()*sqr(tols[facei])
306  << endl
307  << "Mesh face:" << start()+facei
308  << " vertices:"
309  << UIndirectList<point>(points(), operator[](facei))
310  << endl
311  << "If you are certain your matching is correct"
312  << " you can increase the 'matchTolerance' setting"
313  << " in the patch dictionary in the boundary file."
314  << endl
315  << "Rerun with processor debug flag set for"
316  << " more information." << exit(FatalError);
317  }
318  else
319  {
320  faceNormals[facei] = faceAreas()[facei]/magSf;
321  nbrFaceNormals[facei] = neighbFaceAreas_[facei]/nbrMagSf;
322  }
323  }
324 
325  calcTransformTensors
326  (
327  faceCentres(),
328  neighbFaceCentres_,
329  faceNormals,
330  nbrFaceNormals,
331  matchTolerance()*tols,
332  matchTolerance(),
333  transform()
334  );
335  }
336 }
337 
338 
340 (
341  PstreamBuffers& pBufs,
342  const pointField& p
343 )
344 {
345  polyPatch::movePoints(pBufs, p);
347 }
348 
349 
351 (
352  PstreamBuffers& pBufs,
353  const pointField&
354 )
355 {
357 }
358 
359 
361 {
363 
364  if (Pstream::parRun())
365  {
366  if (neighbProcNo() >= Pstream::nProcs(pBufs.comm()))
367  {
369  << "On patch " << name()
370  << " trying to access out of range neighbour processor "
371  << neighbProcNo() << ". This can happen if" << nl
372  << " trying to run on an incorrect number of processors"
373  << exit(FatalError);
374  }
375 
376  // Express all points as patch face and index in face.
377  labelList pointFace(nPoints());
378  labelList pointIndex(nPoints());
379 
380  for (label patchPointi = 0; patchPointi < nPoints(); patchPointi++)
381  {
382  label facei = pointFaces()[patchPointi][0];
383 
384  pointFace[patchPointi] = facei;
385 
386  const face& f = localFaces()[facei];
387 
388  pointIndex[patchPointi] = f.find(patchPointi);
389  }
390 
391  // Express all edges as patch face and index in face.
392  labelList edgeFace(nEdges());
393  labelList edgeIndex(nEdges());
394 
395  for (label patchEdgeI = 0; patchEdgeI < nEdges(); patchEdgeI++)
396  {
397  label facei = edgeFaces()[patchEdgeI][0];
398 
399  edgeFace[patchEdgeI] = facei;
400 
401  const labelList& fEdges = faceEdges()[facei];
402 
403  edgeIndex[patchEdgeI] = fEdges.find(patchEdgeI);
404  }
405 
406  UOPstream toNeighbProc(neighbProcNo(), pBufs);
407 
408  toNeighbProc
409  << pointFace
410  << pointIndex
411  << edgeFace
412  << edgeIndex;
413  }
414 }
415 
416 
418 {
419  // For completeness
420  polyPatch::updateMesh(pBufs);
421 
422  neighbPointsPtr_.clear();
423  neighbEdgesPtr_.clear();
424 
425  if (Pstream::parRun())
426  {
427  labelList nbrPointFace;
428  labelList nbrPointIndex;
429  labelList nbrEdgeFace;
430  labelList nbrEdgeIndex;
431 
432  {
433  // !Note: there is one situation where the opposite points and
434  // do not exactly match and that is while we are distributing
435  // meshes and multiple parts come together from different
436  // processors. This can temporarily create the situation that
437  // we have points which will be merged out later but we still
438  // need the face connectivity to be correct.
439  // So: cannot check here on same points and edges.
440 
441  UIPstream fromNeighbProc(neighbProcNo(), pBufs);
442 
443  fromNeighbProc
444  >> nbrPointFace
445  >> nbrPointIndex
446  >> nbrEdgeFace
447  >> nbrEdgeIndex;
448  }
449 
450  // Convert neighbour faces and indices into face back into
451  // my edges and points.
452 
453  // Convert points.
454  // ~~~~~~~~~~~~~~~
455 
456  neighbPointsPtr_.reset(new labelList(nPoints(), -1));
457  labelList& neighbPoints = neighbPointsPtr_();
458 
459  forAll(nbrPointFace, nbrPointi)
460  {
461  // Find face and index in face on this side.
462  const face& f = localFaces()[nbrPointFace[nbrPointi]];
463 
464  label index = (f.size() - nbrPointIndex[nbrPointi]) % f.size();
465  label patchPointi = f[index];
466 
467  if (neighbPoints[patchPointi] == -1)
468  {
469  // First reference of point
470  neighbPoints[patchPointi] = nbrPointi;
471  }
472  else if (neighbPoints[patchPointi] >= 0)
473  {
474  // Point already visited. Mark as duplicate.
475  neighbPoints[patchPointi] = -2;
476  }
477  }
478 
479  // Reset all duplicate entries to -1.
480  forAll(neighbPoints, patchPointi)
481  {
482  if (neighbPoints[patchPointi] == -2)
483  {
484  neighbPoints[patchPointi] = -1;
485  }
486  }
487 
488  // Convert edges.
489  // ~~~~~~~~~~~~~~
490 
491  neighbEdgesPtr_.reset(new labelList(nEdges(), -1));
492  labelList& neighbEdges = neighbEdgesPtr_();
493 
494  forAll(nbrEdgeFace, nbrEdgeI)
495  {
496  // Find face and index in face on this side.
497  const labelList& f = faceEdges()[nbrEdgeFace[nbrEdgeI]];
498  label index = (f.size() - nbrEdgeIndex[nbrEdgeI] - 1) % f.size();
499  label patchEdgeI = f[index];
500 
501  if (neighbEdges[patchEdgeI] == -1)
502  {
503  // First reference of edge
504  neighbEdges[patchEdgeI] = nbrEdgeI;
505  }
506  else if (neighbEdges[patchEdgeI] >= 0)
507  {
508  // Edge already visited. Mark as duplicate.
509  neighbEdges[patchEdgeI] = -2;
510  }
511  }
512 
513  // Reset all duplicate entries to -1.
514  forAll(neighbEdges, patchEdgeI)
515  {
516  if (neighbEdges[patchEdgeI] == -2)
517  {
518  neighbEdges[patchEdgeI] = -1;
519  }
520  }
521 
522  // Remove any addressing used for shared points/edges calculation
523  // since mostly not needed.
525  }
526 }
527 
528 
530 {
531  if (!neighbPointsPtr_)
532  {
534  << "No extended addressing calculated for patch " << name()
535  << abort(FatalError);
536  }
537  return *neighbPointsPtr_;
538 }
539 
540 
542 {
543  if (!neighbEdgesPtr_)
544  {
546  << "No extended addressing calculated for patch " << name()
547  << abort(FatalError);
548  }
549  return *neighbEdgesPtr_;
550 }
551 
552 
554 (
555  PstreamBuffers& pBufs,
556  const primitivePatch& pp
557 ) const
558 {
559  if
560  (
561  !Pstream::parRun()
562  || transform() == NOORDERING
563  )
564  {
565  return;
566  }
567 
568  if (debug)
569  {
570  fileName nm
571  (
572  boundaryMesh().mesh().time().path()
573  /name()+"_faces.obj"
574  );
575  Pout<< "processorPolyPatch::order : Writing my " << pp.size()
576  << " faces to OBJ file " << nm << endl;
577  writeOBJ(nm, pp, pp.points());
578 
579  // Calculate my face centres
580  const pointField& fc = pp.faceCentres();
581 
582  OFstream localStr
583  (
584  boundaryMesh().mesh().time().path()
585  /name() + "_localFaceCentres.obj"
586  );
587  Pout<< "processorPolyPatch::order : "
588  << "Dumping " << fc.size()
589  << " local faceCentres to " << localStr.name() << endl;
590 
591  forAll(fc, facei)
592  {
593  writeOBJ(localStr, fc[facei]);
594  }
595  }
596 
597  if (owner())
598  {
599  if (transform() == COINCIDENTFULLMATCH)
600  {
601  // Pass the patch points and faces across
602  UOPstream toNeighbour(neighbProcNo(), pBufs);
603  toNeighbour << pp.localPoints()
604  << pp.localFaces();
605  }
606  else
607  {
608  const pointField& ppPoints = pp.points();
609 
610  pointField anchors(getAnchorPoints(pp, ppPoints, transform()));
611 
612  // Get the average of the points of each face. This is needed in
613  // case the face centroid calculation is incorrect due to the face
614  // having a very high aspect ratio.
615  pointField facePointAverages(pp.size(), Zero);
616  forAll(pp, fI)
617  {
618  const labelList& facePoints = pp[fI];
619 
620  forAll(facePoints, pI)
621  {
622  facePointAverages[fI] += ppPoints[facePoints[pI]];
623  }
624 
625  facePointAverages[fI] /= facePoints.size();
626  }
627 
628  // Now send all info over to the neighbour
629  UOPstream toNeighbour(neighbProcNo(), pBufs);
630  toNeighbour << pp.faceCentres() << pp.faceNormals()
631  << anchors << facePointAverages;
632  }
633  }
634 }
635 
636 
638 (
639  const face& a,
640  const pointField& aPts,
641  const face& b,
642  const pointField& bPts,
643  const bool sameOrientation,
644  const scalar absTolSqr,
645  scalar& matchDistSqr
646 )
647 {
648  if (a.size() != b.size())
649  {
650  return -1;
651  }
652 
653  enum CirculatorBase::direction circulateDirection
655 
656  if (!sameOrientation)
657  {
658  circulateDirection = CirculatorBase::ANTICLOCKWISE;
659  }
660 
661  label matchFp = -1;
662 
663  scalar closestMatchDistSqr = sqr(GREAT);
664 
665  ConstCirculator<face> aCirc(a);
666  ConstCirculator<face> bCirc(b);
667 
668  do
669  {
670  const scalar diffSqr = magSqr(aPts[aCirc()] - bPts[bCirc()]);
671 
672  if (diffSqr < absTolSqr)
673  {
674  // Found a matching point. Set the fulcrum of b to the iterator
675  ConstCirculator<face> bCirc2 = bCirc;
676  ++aCirc;
677 
678  bCirc2.setFulcrumToIterator();
679 
680  if (!sameOrientation)
681  {
682  --bCirc2;
683  }
684  else
685  {
686  ++bCirc2;
687  }
688 
689  matchDistSqr = diffSqr;
690 
691  do
692  {
693  const scalar diffSqr2 = magSqr(aPts[aCirc()] - bPts[bCirc2()]);
694 
695  if (diffSqr2 > absTolSqr)
696  {
697  // No match.
698  break;
699  }
700 
701  matchDistSqr += diffSqr2;
702  }
703  while
704  (
706  bCirc2.circulate(circulateDirection)
707  );
708 
709  if (!aCirc.circulate())
710  {
711  if (matchDistSqr < closestMatchDistSqr)
712  {
713  closestMatchDistSqr = matchDistSqr;
714 
715  if (!sameOrientation)
716  {
717  matchFp = a.size() - bCirc.nRotations();
718  }
719  else
720  {
721  matchFp = bCirc.nRotations();
722  }
723 
724  if (closestMatchDistSqr == 0)
725  {
726  break;
727  }
728  }
729  }
730 
731  // Reset aCirc
732  aCirc.setIteratorToFulcrum();
733  }
734 
735  } while (bCirc.circulate(circulateDirection));
736 
737  matchDistSqr = closestMatchDistSqr;
738 
739  return matchFp;
740 }
741 
742 
744 (
745  PstreamBuffers& pBufs,
746  const primitivePatch& pp,
748  labelList& rotation
749 ) const
750 {
751  // Note: we only get the faces that originate from internal faces.
752 
753  if
754  (
755  !Pstream::parRun()
756  || transform() == NOORDERING
757  )
758  {
759  return false;
760  }
761 
762  faceMap.setSize(pp.size());
763  faceMap = -1;
764 
765  rotation.setSize(pp.size());
766  rotation = 0;
767 
768  bool change = false;
769 
770  if (owner())
771  {
772  // Do nothing (i.e. identical mapping, zero rotation).
773  // See comment at top.
774  forAll(faceMap, patchFacei)
775  {
776  faceMap[patchFacei] = patchFacei;
777  }
778 
779  if (transform() != COINCIDENTFULLMATCH)
780  {
781  const pointField& ppPoints = pp.points();
782 
783  pointField anchors(getAnchorPoints(pp, ppPoints, transform()));
784 
785  // Calculate typical distance from face centre
786  scalarField tols
787  (
788  matchTolerance()*calcFaceTol(pp, pp.points(), pp.faceCentres())
789  );
790 
791  forAll(faceMap, patchFacei)
792  {
793  const point& wantedAnchor = anchors[patchFacei];
794 
795  rotation[patchFacei] = getRotation
796  (
797  ppPoints,
798  pp[patchFacei],
799  wantedAnchor,
800  tols[patchFacei]
801  );
802 
803  if (rotation[patchFacei] > 0)
804  {
805  change = true;
806  }
807  }
808  }
809 
810  return change;
811  }
812  else
813  {
814  // Calculate the absolute matching tolerance
815  scalarField tols
816  (
817  matchTolerance()*calcFaceTol(pp, pp.points(), pp.faceCentres())
818  );
819 
820  if (transform() == COINCIDENTFULLMATCH)
821  {
822  vectorField masterPts;
823  faceList masterFaces;
824 
825  {
826  UIPstream fromNeighbour(neighbProcNo(), pBufs);
827  fromNeighbour >> masterPts >> masterFaces;
828  }
829 
830  const pointField& localPts = pp.localPoints();
831  const faceList& localFaces = pp.localFaces();
832 
833  label nMatches = 0;
834 
835  forAll(pp, lFacei)
836  {
837  const face& localFace = localFaces[lFacei];
838  label faceRotation = -1;
839 
840  const scalar absTolSqr = sqr(tols[lFacei]);
841 
842  scalar closestMatchDistSqr = sqr(GREAT);
843  scalar matchDistSqr = sqr(GREAT);
844  label closestFaceMatch = -1;
845  label closestFaceRotation = -1;
846 
847  forAll(masterFaces, mFacei)
848  {
849  const face& masterFace = masterFaces[mFacei];
850 
851  faceRotation = matchFace
852  (
853  localFace,
854  localPts,
855  masterFace,
856  masterPts,
857  false,
858  absTolSqr,
859  matchDistSqr
860  );
861 
862  if
863  (
864  faceRotation != -1
865  && matchDistSqr < closestMatchDistSqr
866  )
867  {
868  closestMatchDistSqr = matchDistSqr;
869  closestFaceMatch = mFacei;
870  closestFaceRotation = faceRotation;
871  }
872 
873  if (closestMatchDistSqr == 0)
874  {
875  break;
876  }
877  }
878 
879  if
880  (
881  closestFaceRotation != -1
882  && closestMatchDistSqr < absTolSqr
883  )
884  {
885  faceMap[lFacei] = closestFaceMatch;
886 
887  rotation[lFacei] = closestFaceRotation;
888 
889  if (lFacei != closestFaceMatch || closestFaceRotation > 0)
890  {
891  change = true;
892  }
893 
894  nMatches++;
895  }
896  else
897  {
898  Pout<< "Number of matches = " << nMatches << " / "
899  << pp.size() << endl;
900 
901  pointField pts(localFace.size());
902  forAll(localFace, pI)
903  {
904  const label localPtI = localFace[pI];
905  pts[pI] = localPts[localPtI];
906  }
907 
909  << "No match for face " << localFace << nl << pts
910  << abort(FatalError);
911  }
912  }
913 
914  return change;
915  }
916  else
917  {
918  vectorField masterCtrs;
919  vectorField masterNormals;
920  vectorField masterAnchors;
921  vectorField masterFacePointAverages;
922 
923  // Receive data from neighbour
924  {
925  UIPstream fromNeighbour(neighbProcNo(), pBufs);
926  fromNeighbour >> masterCtrs >> masterNormals
927  >> masterAnchors >> masterFacePointAverages;
928  }
929 
930  if (debug || masterCtrs.size() != pp.size())
931  {
932  {
933  OFstream nbrStr
934  (
935  boundaryMesh().mesh().time().path()
936  /name() + "_nbrFaceCentres.obj"
937  );
938  Pout<< "processorPolyPatch::order : "
939  << "Dumping neighbour faceCentres to " << nbrStr.name()
940  << endl;
941  forAll(masterCtrs, facei)
942  {
943  writeOBJ(nbrStr, masterCtrs[facei]);
944  }
945  }
946 
947  if (masterCtrs.size() != pp.size())
948  {
950  << "in patch:" << name() << " : "
951  << "Local size of patch is " << pp.size() << " (faces)."
952  << endl
953  << "Received from neighbour " << masterCtrs.size()
954  << " faceCentres!"
955  << abort(FatalError);
956  }
957  }
958 
959  // Geometric match of face centre vectors
960  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
961 
962  // 1. Try existing ordering and transformation
963  bool matchedAll = matchPoints
964  (
965  pp.faceCentres(),
966  masterCtrs,
967  pp.faceNormals(),
968  masterNormals,
969  tols,
970  false,
971  faceMap
972  );
973 
974  // Fallback: try using face point average for matching
975  if (!matchedAll)
976  {
977  const pointField& ppPoints = pp.points();
978 
979  pointField facePointAverages(pp.size(), Zero);
980  forAll(pp, fI)
981  {
982  const labelList& facePoints = pp[fI];
983 
984  forAll(facePoints, pI)
985  {
986  facePointAverages[fI] += ppPoints[facePoints[pI]];
987  }
988 
989  facePointAverages[fI] /= facePoints.size();
990  }
991 
992  scalarField tols2
993  (
994  matchTolerance()
995  *calcFaceTol(pp, pp.points(), facePointAverages)
996  );
997 
998  // Note that we do not use the faceNormals anymore for
999  // comparison. Since we're
1000  // having problems with the face centres (e.g. due to extreme
1001  // aspect ratios) we will probably also have problems with
1002  // reliable normals calculation
1003  labelList faceMap2(faceMap.size(), -1);
1004  matchPoints
1005  (
1006  facePointAverages,
1007  masterFacePointAverages,
1008  tols2,
1009  true,
1010  faceMap2
1011  );
1012 
1013  matchedAll = true;
1014 
1015  forAll(faceMap, oldFacei)
1016  {
1017  if (faceMap[oldFacei] == -1)
1018  {
1019  faceMap[oldFacei] = faceMap2[oldFacei];
1020 
1021  if (faceMap[oldFacei] == -1)
1022  {
1023  matchedAll = false;
1024  }
1025  }
1026  }
1027  }
1028 
1029  if (!matchedAll || debug)
1030  {
1031  // Dump faces
1032  fileName str
1033  (
1034  boundaryMesh().mesh().time().path()
1035  /name() + "_faces.obj"
1036  );
1037  Pout<< "processorPolyPatch::order :"
1038  << " Writing faces to OBJ file " << str.name() << endl;
1039  writeOBJ(str, pp, pp.points());
1040 
1041  OFstream ccStr
1042  (
1043  boundaryMesh().mesh().time().path()
1044  /name() + "_faceCentresConnections.obj"
1045  );
1046 
1047  Pout<< "processorPolyPatch::order :"
1048  << " Dumping newly found match as lines between"
1049  << " corresponding face centres to OBJ file "
1050  << ccStr.name()
1051  << endl;
1052 
1053  label vertI = 0;
1054 
1055  forAll(pp.faceCentres(), facei)
1056  {
1057  label masterFacei = faceMap[facei];
1058 
1059  if (masterFacei != -1)
1060  {
1061  const point& c0 = masterCtrs[masterFacei];
1062  const point& c1 = pp.faceCentres()[facei];
1063  writeOBJ(ccStr, c0, c1, vertI);
1064  }
1065  }
1066  }
1067 
1068  if (!matchedAll)
1069  {
1071  << "in patch:" << name() << " : "
1072  << "Cannot match vectors to faces on both sides of patch"
1073  << endl
1074  << " masterCtrs[0]:" << masterCtrs[0] << endl
1075  << " ctrs[0]:" << pp.faceCentres()[0] << endl
1076  << " Check your topology changes or maybe you have"
1077  << " multiple separated (from cyclics) processor patches"
1078  << endl
1079  << " Continuing with incorrect face ordering from now on"
1080  << endl;
1081 
1082  return false;
1083  }
1084 
1085  // Set rotation.
1086  forAll(faceMap, oldFacei)
1087  {
1088  // The face f will be at newFacei (after morphing) and we want
1089  // its anchorPoint (= f[0]) to align with the anchorpoint for
1090  // the corresponding face on the other side.
1091 
1092  label newFacei = faceMap[oldFacei];
1093 
1094  const point& wantedAnchor = masterAnchors[newFacei];
1095 
1096  rotation[newFacei] = getRotation
1097  (
1098  pp.points(),
1099  pp[oldFacei],
1100  wantedAnchor,
1101  tols[oldFacei]
1102  );
1103 
1104  if (rotation[newFacei] == -1)
1105  {
1107  << "in patch " << name()
1108  << " : "
1109  << "Cannot find point on face " << pp[oldFacei]
1110  << " with vertices "
1111  << UIndirectList<point>(pp.points(), pp[oldFacei])
1112  << " that matches point " << wantedAnchor
1113  << " when matching the halves of processor patch "
1114  << name()
1115  << "Continuing with incorrect face ordering from now on"
1116  << endl;
1117 
1118  return false;
1119  }
1120  }
1121 
1122  forAll(faceMap, facei)
1123  {
1124  if (faceMap[facei] != facei || rotation[facei] != 0)
1125  {
1126  return true;
1127  }
1128  }
1129 
1130  return false;
1131  }
1132  }
1133 }
1134 
1135 
1137 {
1139  os.writeEntry("myProcNo", myProcNo_);
1140  os.writeEntry("neighbProcNo", neighbProcNo_);
1141 }
1142 
1143 
1144 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::addToRunTimeSelectionTable
addToRunTimeSelectionTable(decompositionMethod, kahipDecomp, dictionary)
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:71
p
volScalarField & p
Definition: createFieldRefs.H:8
Foam::faceMap
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
Definition: blockMeshMergeTopological.C:94
Foam::word
A class for handling words, derived from Foam::string.
Definition: word.H:62
Foam::UOPstream
Output inter-processor communications stream operating on external buffer.
Definition: UOPstream.H:57
Foam::fileName
A class for handling file names.
Definition: fileName.H:69
SubField.H
Foam::polyPatch::movePoints
virtual void movePoints(PstreamBuffers &, const pointField &p)
Correct patches after moving points.
Definition: polyPatch.C:61
Foam::polyBoundaryMesh
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO.
Definition: polyBoundaryMesh.H:62
Foam::OFstream::name
virtual const fileName & name() const
Read/write access to the name of the stream.
Definition: OSstream.H:107
Foam::Zero
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
Foam::ConstCirculator
Walks over a container as if it were circular. The container must have the following members defined:
Definition: ConstCirculator.H:93
Foam::processorPolyPatch::initMovePoints
void initMovePoints(PstreamBuffers &, const pointField &)
Initialise the patches for moving points.
Definition: processorPolyPatch.C:340
Foam::meshTools::writeOBJ
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of a point.
Definition: meshTools.C:203
demandDrivenData.H
Template functions to aid in the implementation of demand driven data.
Foam::fileName::name
static std::string name(const std::string &str)
Return basename (part beyond last /), including its extension.
Definition: fileNameI.H:209
Foam::PstreamBuffers
Buffers for inter-processor communications streams (UOPstream, UIPstream).
Definition: PstreamBuffers.H:87
Foam::UPstream::parRun
static bool & parRun()
Test if this a parallel run, or allow modify access.
Definition: UPstream.H:434
ConstCirculator.H
Foam::ConstCirculator::setIteratorToFulcrum
void setIteratorToFulcrum()
Set the iterator to the current position of the fulcrum.
Definition: ConstCirculatorI.H:131
Foam::processorPolyPatch::neighbEdges
const labelList & neighbEdges() const
Return neighbour edge labels. WIP.
Definition: processorPolyPatch.C:541
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:350
Foam::coupledPolyPatch
The coupledPolyPatch is an abstract base class for patches that couple regions of the computational d...
Definition: coupledPolyPatch.H:53
Foam::Pout
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
Foam::transform
dimensionSet transform(const dimensionSet &ds)
Return the argument; transformations do not change the dimensions.
Definition: dimensionSet.C:519
polyMesh.H
Foam::polyPatch::updateMesh
virtual void updateMesh(PstreamBuffers &)
Update of the patch topology.
Definition: polyPatch.C:67
Foam::processorPolyPatch::calcGeometry
void calcGeometry(PstreamBuffers &)
Calculate the patch geometry.
Definition: processorPolyPatch.C:223
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
OFstream.H
Foam::magSqr
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
nPoints
label nPoints
Definition: gmvOutputHeader.H:2
Foam::processorPolyPatch::matchFace
static label matchFace(const face &localFace, const pointField &localPts, const face &masterFace, const pointField &masterPts, const bool sameOrientation, const scalar absTolSqr, scalar &matchDistSqr)
Returns rotation.
Definition: processorPolyPatch.C:638
matchPoints.H
Determine correspondence between points. See below.
Foam::polyPatch::initUpdateMesh
virtual void initUpdateMesh(PstreamBuffers &)
Initialise the update of the patch topology.
Definition: polyPatch.H:117
Foam::constant::physicoChemical::c1
const dimensionedScalar c1
First radiation constant: default SI units: [W/m2].
faceNormals
surfaceVectorField faceNormals(mesh.Sf()/mesh.magSf())
Foam::constant::physicoChemical::b
const dimensionedScalar b
Wien displacement law constant: default SI units: [m.K].
Definition: createFields.H:27
Foam::Field< vector >
Foam::name
word name(const complex &c)
Return string representation of complex.
Definition: complex.C:76
Foam::OSstream::name
virtual const fileName & name() const
Return the name of the stream.
Definition: OSstream.H:107
Foam::processorPolyPatch::initGeometry
void initGeometry(PstreamBuffers &)
Initialise the calculation of the patch geometry.
Definition: processorPolyPatch.C:199
SeriousErrorInFunction
#define SeriousErrorInFunction
Report an error message using Foam::SeriousError.
Definition: messageStream.H:281
Foam::processorPolyPatch
Neighbour processor patch.
Definition: processorPolyPatch.H:58
Foam::coupledPolyPatch::write
virtual void write(Ostream &) const
Write the polyPatch data as a dictionary.
Definition: coupledPolyPatch.C:567
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::FatalError
error FatalError
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:121
processorPolyPatch.H
Foam::PrimitivePatch::points
const Field< point_type > & points() const
Return reference to global points.
Definition: PrimitivePatch.H:305
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
addToRunTimeSelectionTable.H
Macros for easy insertion into run-time selection tables.
Foam::PrimitivePatch::localFaces
const List< face_type > & localFaces() const
Return patch faces addressing into local point list.
Definition: PrimitivePatch.C:297
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:144
Foam::ConstCirculator::nRotations
difference_type nRotations() const
Return the distance between the iterator and the fulcrum. This is.
Definition: ConstCirculatorI.H:139
Foam::processorPolyPatch::movePoints
void movePoints(PstreamBuffers &, const pointField &)
Correct patches after moving points.
Definition: processorPolyPatch.C:351
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::PrimitivePatch::localPoints
const Field< point_type > & localPoints() const
Return pointField of points in patch.
Definition: PrimitivePatch.C:339
Foam::OFstream
Output to file stream, using an OSstream.
Definition: OFstream.H:53
Foam::processorPolyPatch::initUpdateMesh
virtual void initUpdateMesh(PstreamBuffers &)
Initialise the update of the patch topology.
Definition: processorPolyPatch.C:360
Time.H
Foam::processorPolyPatch::processorPolyPatch
processorPolyPatch(const word &name, const label size, const label start, const label index, const polyBoundaryMesh &bm, const int myProcNo, const int neighbProcNo, const transformType transform=UNKNOWN, const word &patchType=typeName)
Construct from components with specified name.
Definition: processorPolyPatch.C:54
Foam::CirculatorBase::direction
direction
Direction type enumeration.
Definition: CirculatorBase.H:53
Foam::CirculatorBase::CLOCKWISE
Definition: CirculatorBase.H:56
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:381
Foam::processorPolyPatch::neighbPoints
const labelList & neighbPoints() const
Return neighbour point labels. WIP.
Definition: processorPolyPatch.C:529
Foam::sqr
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Definition: dimensionedSymmTensor.C:51
Foam::processorPolyPatch::write
virtual void write(Ostream &) const
Write the polyPatch data as a dictionary.
Definition: processorPolyPatch.C:1136
Foam::nl
constexpr char nl
Definition: Ostream.H:385
Foam::processorPolyPatch::initOrder
virtual void initOrder(PstreamBuffers &, const primitivePatch &) const
Initialize ordering for primitivePatch. Does not.
Definition: processorPolyPatch.C:554
f
labelList f(nPoints)
Foam::Vector< scalar >
Foam::List< label >
Foam::processorPolyPatch::newName
static word newName(const label myProcNo, const label neighbProcNo)
Return the name of a processorPolyPatch.
Definition: processorPolyPatch.C:186
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Foam::PrimitivePatch::clearOut
void clearOut()
Definition: PrimitivePatchClear.C:85
Foam::UList< label >
points
const pointField & points
Definition: gmvOutputHeader.H:1
dictionary.H
PstreamBuffers.H
path
fileName path(UMean.rootPath()/UMean.caseName()/"graphs"/UMean.instance())
Foam::Ostream::writeEntry
Ostream & writeEntry(const keyType &key, const T &value)
Write a keyword/value entry.
Definition: Ostream.H:232
Foam::PrimitivePatch::faceNormals
const Field< point_type > & faceNormals() const
Return face unit normals for patch.
Definition: PrimitivePatch.C:425
Foam::UIndirectList
A List with indirect addressing.
Definition: faMatrix.H:60
Foam::boundaryMesh
Addressing for all faces on surface of mesh. Can either be read from polyMesh or from triSurface....
Definition: boundaryMesh.H:62
Foam::face
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:72
Foam::ConstCirculator::setFulcrumToIterator
void setFulcrumToIterator()
Set the fulcrum to the current position of the iterator.
Definition: ConstCirculatorI.H:124
Foam::processorPolyPatch::updateMesh
virtual void updateMesh(PstreamBuffers &)
Update of the patch topology.
Definition: processorPolyPatch.C:417
Foam::Ostream
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:56
Foam::UIPstream
Input inter-processor communications stream operating on external buffer.
Definition: UIPstream.H:56
Foam::processorPolyPatch::~processorPolyPatch
virtual ~processorPolyPatch()
Destructor.
Definition: processorPolyPatch.C:176
Foam::point
vector point
Point is a vector.
Definition: point.H:43
Foam::coupledPolyPatch::transformType
transformType
Definition: coupledPolyPatch.H:59
transformList.H
Spatial transformation functions for list of values and primitive fields.
Foam::List::setSize
void setSize(const label newSize)
Alias for resize(const label)
Definition: ListI.H:146
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
Foam::CirculatorBase::ANTICLOCKWISE
Definition: CirculatorBase.H:57
Foam::ConstCirculator::circulate
bool circulate(const CirculatorBase::direction dir=NONE)
Circulate around the list in the given direction.
Definition: ConstCirculatorI.H:106
Foam::matchPoints
bool matchPoints(const UList< point > &pts0, const UList< point > &pts1, const UList< scalar > &matchDistance, const bool verbose, labelList &from0To1, const point &origin=point::zero)
Determine correspondence between pointFields. Gets passed.
Definition: matchPoints.C:36
Foam::PrimitivePatch::faceCentres
const Field< point_type > & faceCentres() const
Return face centres for patch.
Definition: PrimitivePatch.C:380
Foam::PstreamBuffers::comm
label comm() const
Definition: PstreamBuffers.H:147
Foam::UPstream::nProcs
static label nProcs(const label communicator=worldComm)
Number of processes in parallel run, and 1 for serial run.
Definition: UPstream.H:446
Foam::processorPolyPatch::order
virtual bool order(PstreamBuffers &, const primitivePatch &, labelList &faceMap, labelList &rotation) const
Return new ordering for primitivePatch.
Definition: processorPolyPatch.C:744
Foam::PrimitivePatch
A list of faces which address into the list of points.
Definition: PrimitivePatch.H:85