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