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 "Circulator.H"
40 
41 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
42 
43 namespace Foam
44 {
45  defineTypeNameAndDebug(processorPolyPatch, 0);
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,
61  const transformType transform,
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,
82  const transformType transform,
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() >= pBufs.nProcs())
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 
222 void Foam::processorPolyPatch::calcGeometry(PstreamBuffers& pBufs)
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  const scalar magSf = mag(faceAreas()[facei]);
248  const scalar nbrMagSf = mag(neighbFaceAreas_[facei]);
249 
250  // For small face area calculation the results of the area
251  // calculation have been found to only be accurate to ~1e-20
252  if (magSf < SMALL || nbrMagSf < SMALL)
253  {
254  // Undetermined normal. Use dummy normal to force separation
255  // check.
256  faceNormals[facei] = point(1, 0, 0);
257  nbrFaceNormals[facei] = -faceNormals[facei];
258  tols[facei] = GREAT;
259  }
260  else if (mag(magSf - nbrMagSf) > matchTolerance()*sqr(tols[facei]))
261  {
262  const scalar avgMagSf = 0.5*(magSf + nbrMagSf);
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)/avgMagSf
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(),
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() >= pBufs.nProcs())
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 
417 void Foam::processorPolyPatch::updateMesh(PstreamBuffers& pBufs)
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()
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  (
705  aCirc.circulate(CirculatorBase::CLOCKWISE),
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  }
1130  return false;
1131  }
1132  }
1133 }
1134 
1135 
1136 void Foam::processorPolyPatch::write(Ostream& os) const
1137 {
1139  os.writeEntry("myProcNo", myProcNo_);
1140  os.writeEntry("neighbProcNo", neighbProcNo_);
1141 }
1142 
1143 
1144 // ************************************************************************* //
List< ReturnType > get(const UPtrList< T > &list, const AccessOp &aop)
List of values generated by applying the access operation to each list item.
virtual const fileName & name() const
Get the name of the output serial stream. (eg, the name of the Fstream file name) ...
Definition: OSstream.H:128
const List< face_type > & localFaces() const
Return patch faces addressing into local point list.
dictionary dict
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
const labelList & neighbPoints() const
Return neighbour point labels. WIP.
virtual void write(Ostream &os) const
Write the polyPatch data as a dictionary.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
const Field< point_type > & localPoints() const
Return pointField of points in patch.
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:120
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:578
virtual void initUpdateMesh(PstreamBuffers &)
Initialise the update of the patch topology.
Definition: polyPatch.H:135
label find(const T &val, label pos=0) const
Find index of the first occurrence of the value.
Definition: UList.C:204
dimensionedSymmTensor sqr(const dimensionedVector &dv)
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:49
virtual void initOrder(PstreamBuffers &, const primitivePatch &) const
Initialize ordering for primitivePatch. Does not.
static word newName(const label myProcNo, const label neighbProcNo)
Return the name of a processorPolyPatch.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
void calcGeometry(PstreamBuffers &)
Calculate the patch geometry.
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1004
The coupledPolyPatch is an abstract base class for patches that couple regions of the computational d...
direction
Direction type enumeration.
Definition: Circulator.H:86
Ostream & writeEntry(const keyType &key, const T &value)
Write a keyword/value entry.
Definition: Ostream.H:312
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of a point.
Definition: meshTools.C:196
void movePoints(PstreamBuffers &, const pointField &)
Correct patches after moving points.
Determine correspondence between points. See below.
Macros for easy insertion into run-time selection tables.
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
virtual void movePoints(PstreamBuffers &, const pointField &p)
Correct patches after moving points.
Definition: polyPatch.C:54
#define SeriousErrorInFunction
Report an error message using Foam::SeriousError.
Neighbour processor patch.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:414
void initMovePoints(PstreamBuffers &, const pointField &)
Initialise the patches for moving points.
const Field< point_type > & faceNormals() const
Return face unit normals for patch.
List< face > faceList
List of faces.
Definition: faceListFwd.H:39
A list of faces which address into the list of points.
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:29
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
void setSize(const label n)
Alias for resize()
Definition: List.H:289
dynamicFvMesh & mesh
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:52
const pointField & points
const dimensionedScalar b
Wien displacement law constant: default SI units: [m.K].
Definition: createFields.H:27
virtual void initUpdateMesh(PstreamBuffers &)
Initialise the update of the patch topology.
A class for handling words, derived from Foam::string.
Definition: word.H:63
label nPoints
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
const Field< point_type > & faceCentres() const
Return face centres for patch.
virtual ~processorPolyPatch()
Destructor.
virtual void updateMesh(PstreamBuffers &)
Update of the patch topology.
Definition: polyPatch.C:60
const Field< point_type > & points() const noexcept
Return reference to global points.
errorManip< error > abort(error &err)
Definition: errorManip.H:139
void initGeometry(PstreamBuffers &)
Initialise the calculation of the patch geometry.
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO...
int debug
Static debugging option.
OBJstream os(runTime.globalPath()/outputName)
fileName path(UMean.rootPath()/UMean.caseName()/"graphs"/UMean.instance())
defineTypeNameAndDebug(combustionModel, 0)
virtual void updateMesh(PstreamBuffers &)
Update of the patch topology.
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.
labelList f(nPoints)
Buffers for inter-processor communications streams (UOPstream, UIPstream).
PrimitivePatch< SubList< face >, const pointField & > primitivePatch
A PrimitivePatch with a SubList addressing for the faces, const reference for the point field...
Spatial transformation functions for list of values and primitive fields.
addToRunTimeSelectionTable(decompositionMethod, kahipDecomp, dictionary)
vector point
Point is a vector.
Definition: point.H:37
const dimensionedScalar c1
First radiation constant: default SI units: [W/m2].
virtual void write(Ostream &) const
Write the polyPatch data as a dictionary.
Field< vector > vectorField
Specialisation of Field<T> for vector.
virtual bool order(PstreamBuffers &, const primitivePatch &, labelList &faceMap, labelList &rotation) const
Return new ordering for primitivePatch.
label nProcs() const noexcept
Number of ranks associated with PstreamBuffers.
List< label > labelList
A List of labels.
Definition: List.H:62
volScalarField & p
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:69
const labelList & neighbEdges() const
Return neighbour edge labels. WIP.
dimensionSet transform(const dimensionSet &ds)
Return the argument; transformations do not change the dimensions.
Definition: dimensionSet.C:521
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.
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
Namespace for OpenFOAM.
const pointField & pts
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:133