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