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