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