Merge branch 'master' of ssh://git.code.sf.net/p/foam-extend/foam-extend-3.2
[foam-extend-3.2.git] / src / foam / meshes / polyMesh / polyPatches / constraint / processor / processorPolyPatch.C
blobf5b31ed70c9c6f64cf79cb484c7712b3d0adb067
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | foam-extend: Open Source CFD
4    \\    /   O peration     | Version:     3.2
5     \\  /    A nd           | Web:         http://www.foam-extend.org
6      \\/     M anipulation  | For copyright notice see file Copyright
7 -------------------------------------------------------------------------------
8 License
9     This file is part of foam-extend.
11     foam-extend is free software: you can redistribute it and/or modify it
12     under the terms of the GNU General Public License as published by the
13     Free Software Foundation, either version 3 of the License, or (at your
14     option) any later version.
16     foam-extend is distributed in the hope that it will be useful, but
17     WITHOUT ANY WARRANTY; without even the implied warranty of
18     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19     General Public License for more details.
21     You should have received a copy of the GNU General Public License
22     along with foam-extend.  If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "processorPolyPatch.H"
27 #include "addToRunTimeSelectionTable.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 "foamTime.H"
35 #include "transformList.H"
37 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
39 namespace Foam
41     defineTypeNameAndDebug(processorPolyPatch, 0);
42     addToRunTimeSelectionTable(polyPatch, processorPolyPatch, dictionary);
46 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
48 Foam::processorPolyPatch::processorPolyPatch
50     const word& name,
51     const label size,
52     const label start,
53     const label index,
54     const polyBoundaryMesh& bm,
55     const int myProcNo,
56     const int neighbProcNo
59     coupledPolyPatch(name, size, start, index, bm),
60     myProcNo_(myProcNo),
61     neighbProcNo_(neighbProcNo),
62     neighbFaceCentres_(),
63     neighbFaceAreas_(),
64     neighbFaceCellCentres_(),
65     neighbPointsPtr_(NULL),
66     neighbEdgesPtr_(NULL)
70 Foam::processorPolyPatch::processorPolyPatch
72     const word& name,
73     const dictionary& dict,
74     const label index,
75     const polyBoundaryMesh& bm
78     coupledPolyPatch(name, dict, index, bm),
79     myProcNo_(readLabel(dict.lookup("myProcNo"))),
80     neighbProcNo_(readLabel(dict.lookup("neighbProcNo"))),
81     neighbFaceCentres_(),
82     neighbFaceAreas_(),
83     neighbFaceCellCentres_(),
84     neighbPointsPtr_(NULL),
85     neighbEdgesPtr_(NULL)
89 Foam::processorPolyPatch::processorPolyPatch
91     const processorPolyPatch& pp,
92     const polyBoundaryMesh& bm
95     coupledPolyPatch(pp, bm),
96     myProcNo_(pp.myProcNo_),
97     neighbProcNo_(pp.neighbProcNo_),
98     neighbFaceCentres_(),
99     neighbFaceAreas_(),
100     neighbFaceCellCentres_(),
101     neighbPointsPtr_(NULL),
102     neighbEdgesPtr_(NULL)
106 Foam::processorPolyPatch::processorPolyPatch
108     const processorPolyPatch& pp,
109     const polyBoundaryMesh& bm,
110     const label index,
111     const label newSize,
112     const label newStart
115     coupledPolyPatch(pp, bm, index, newSize, newStart),
116     myProcNo_(pp.myProcNo_),
117     neighbProcNo_(pp.neighbProcNo_),
118     neighbFaceCentres_(),
119     neighbFaceAreas_(),
120     neighbFaceCellCentres_(),
121     neighbPointsPtr_(NULL),
122     neighbEdgesPtr_(NULL)
126 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
128 Foam::processorPolyPatch::~processorPolyPatch()
130     deleteDemandDrivenData(neighbPointsPtr_);
131     deleteDemandDrivenData(neighbEdgesPtr_);
135 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
137 void Foam::processorPolyPatch::initAddressing()
139     polyPatch::initAddressing();
143 void Foam::processorPolyPatch::calcAddressing()
145     polyPatch::calcAddressing();
149 void Foam::processorPolyPatch::initGeometry()
151     if (Pstream::parRun())
152     {
153         OPstream toNeighbProc
154         (
155             Pstream::blocking,
156             neighbProcNo(),
157             3*(sizeof(label) + size()*sizeof(vector) + sizeof(scalar))
158         );
160         toNeighbProc
161             << faceCentres()
162             << faceAreas()
163             << faceCellCentres();
164     }
168 void Foam::processorPolyPatch::calcGeometry()
170     if (Pstream::parRun())
171     {
172         {
173             IPstream fromNeighbProc
174             (
175                 Pstream::blocking,
176                 neighbProcNo(),
177                 3*(sizeof(label) + size()*sizeof(vector) + sizeof(scalar))
178             );
179             fromNeighbProc
180                 >> neighbFaceCentres_
181                 >> neighbFaceAreas_
182                 >> neighbFaceCellCentres_;
183         }
185         // My normals
186         vectorField faceNormals(size());
188         // Neighbour normals
189         vectorField nbrFaceNormals(neighbFaceAreas_.size());
191         // Calculate normals from areas and check
193         // Cache face areas
194         const vectorField::subField localFaceAreas = faceAreas();
196         forAll (faceNormals, facei)
197         {
198             scalar magSf = mag(localFaceAreas[facei]);
199             scalar nbrMagSf = mag(neighbFaceAreas_[facei]);
200             scalar avSf = (magSf + nbrMagSf)/2.0;
202             if (magSf < SMALL && nbrMagSf < SMALL)
203             {
204                 // Undetermined normal. Use dummy normal to force separation
205                 // check.
206                 // (note use of sqrt(VSMALL) since that is how mag scales)
207                 // HR, 11/12/2013: Found a face with area = 1e-21 before
208                 // topo deflation. Hence must use SMALL here.
209                 faceNormals[facei] = point(1, 0, 0);
210                 nbrFaceNormals[facei] = faceNormals[facei];
211             }
212             else if (mag(magSf - nbrMagSf)/avSf > polyPatch::matchTol_)
213             {
214                 FatalErrorIn
215                 (
216                     "processorPolyPatch::calcGeometry()"
217                 )   << "face " << facei << " area does not match neighbour by "
218                     << 100*mag(magSf - nbrMagSf)/avSf
219                     << "% -- possible face ordering problem." << endl
220                     << "patch: " << name()
221                     << " my area: " << magSf
222                     << " neighbour area: " << nbrMagSf
223                     << " matching tolerance: " << polyPatch::matchTol_
224                     << endl
225                     << "Mesh face: " << start()+facei
226                     << " vertices: "
227                     << UIndirectList<point>(points(), operator[](facei))()
228                     << endl
229                     << "Rerun with processor debug flag set for"
230                     << " more information." << exit(FatalError);
231             }
232             else
233             {
234                 faceNormals[facei] = localFaceAreas[facei]/magSf;
235                 nbrFaceNormals[facei] = neighbFaceAreas_[facei]/nbrMagSf;
236             }
237         }
239         calcTransformTensors
240         (
241             faceCentres(),
242             neighbFaceCentres_,
243             faceNormals,
244             nbrFaceNormals,
245             calcFaceTol(*this, points(), faceCentres())
246         );
247     }
251 void Foam::processorPolyPatch::initMovePoints(const pointField& p)
253     polyPatch::movePoints(p);
254     processorPolyPatch::initGeometry();
258 void Foam::processorPolyPatch::movePoints(const pointField&)
260     processorPolyPatch::calcGeometry();
264 void Foam::processorPolyPatch::initUpdateMesh()
266     polyPatch::initUpdateMesh();
268     deleteDemandDrivenData(neighbPointsPtr_);
269     deleteDemandDrivenData(neighbEdgesPtr_);
271     if (Pstream::parRun())
272     {
273         // Express all points as patch face and index in face.
274         labelList pointFace(nPoints());
275         labelList pointIndex(nPoints());
277         for (label patchPointI = 0; patchPointI < nPoints(); patchPointI++)
278         {
279             label faceI = pointFaces()[patchPointI][0];
281             pointFace[patchPointI] = faceI;
283             const face& f = localFaces()[faceI];
285             pointIndex[patchPointI] = findIndex(f, patchPointI);
286         }
288         // Express all edges as patch face and index in face.
289         labelList edgeFace(nEdges());
290         labelList edgeIndex(nEdges());
292         for (label patchEdgeI = 0; patchEdgeI < nEdges(); patchEdgeI++)
293         {
294             label faceI = edgeFaces()[patchEdgeI][0];
296             edgeFace[patchEdgeI] = faceI;
298             const labelList& fEdges = faceEdges()[faceI];
300             edgeIndex[patchEdgeI] = findIndex(fEdges, patchEdgeI);
301         }
303         OPstream toNeighbProc
304         (
305             Pstream::blocking,
306             neighbProcNo(),
307             8*sizeof(label)             // four headers of labelList
308           + 2*nPoints()*sizeof(label)   // two point-based labelLists
309           + 2*nEdges()*sizeof(label)    // two edge-based labelLists
310         );
312         toNeighbProc
313             << pointFace
314             << pointIndex
315             << edgeFace
316             << edgeIndex;
317     }
321 void Foam::processorPolyPatch::updateMesh()
323     // For completeness
324     polyPatch::updateMesh();
326     if (Pstream::parRun())
327     {
328         labelList nbrPointFace;
329         labelList nbrPointIndex;
330         labelList nbrEdgeFace;
331         labelList nbrEdgeIndex;
333         {
334             // Note cannot predict exact size since opposite nPoints might
335             // be different from one over here.
337             // Disagree: This needs to be sorted out, so that processor patches
338             // are simply internal faces and treat cyclics separately
339             // HJ, 10/Mar/2011
340             IPstream fromNeighbProc(Pstream::blocking, neighbProcNo());
342             fromNeighbProc
343                 >> nbrPointFace
344                 >> nbrPointIndex
345                 >> nbrEdgeFace
346                 >> nbrEdgeIndex;
347         }
349         // Convert neighbour faces and indices into face back into
350         // my edges and points.
352         // Convert points.
353         // ~~~~~~~~~~~~~~~
355         neighbPointsPtr_ = new labelList(nPoints(), -1);
356         labelList& neighbPoints = *neighbPointsPtr_;
358         forAll (nbrPointFace, nbrPointI)
359         {
360             // Find face and index in face on this side.
361             const face& f = localFaces()[nbrPointFace[nbrPointI]];
362             label index = (f.size() - nbrPointIndex[nbrPointI]) % f.size();
363             label patchPointI = f[index];
365             if (neighbPoints[patchPointI] == -1)
366             {
367                 // First reference of point
368                 neighbPoints[patchPointI] = nbrPointI;
369             }
370             else if (neighbPoints[patchPointI] >= 0)
371             {
372                 // Point already visited. Mark as duplicate.
373                 neighbPoints[patchPointI] = -2;
374             }
375         }
377         // Reset all duplicate entries to -1.
378         forAll (neighbPoints, patchPointI)
379         {
380             if (neighbPoints[patchPointI] == -2)
381             {
382                 neighbPoints[patchPointI] = -1;
383             }
384         }
386         // Convert edges.
387         // ~~~~~~~~~~~~~~
389         neighbEdgesPtr_ = new labelList(nEdges(), -1);
390         labelList& neighbEdges = *neighbEdgesPtr_;
392         forAll (nbrEdgeFace, nbrEdgeI)
393         {
394             // Find face and index in face on this side.
395             const labelList& f = faceEdges()[nbrEdgeFace[nbrEdgeI]];
396             label index = (f.size() - nbrEdgeIndex[nbrEdgeI] - 1) % f.size();
397             label patchEdgeI = f[index];
399             if (neighbEdges[patchEdgeI] == -1)
400             {
401                 // First reference of edge
402                 neighbEdges[patchEdgeI] = nbrEdgeI;
403             }
404             else if (neighbEdges[patchEdgeI] >= 0)
405             {
406                 // Edge already visited. Mark as duplicate.
407                 neighbEdges[patchEdgeI] = -2;
408             }
409         }
411         // Reset all duplicate entries to -1.
412         forAll (neighbEdges, patchEdgeI)
413         {
414             if (neighbEdges[patchEdgeI] == -2)
415             {
416                 neighbEdges[patchEdgeI] = -1;
417             }
418         }
420         // Remove any addressing used for shared points/edges calculation
421         primitivePatch::clearOut();
422     }
426 const Foam::labelList& Foam::processorPolyPatch::neighbPoints() const
428     if (!neighbPointsPtr_)
429     {
430         FatalErrorIn("processorPolyPatch::neighbPoints() const")
431             << "No extended addressing calculated for patch " << name()
432             << abort(FatalError);
433     }
435     return *neighbPointsPtr_;
439 const Foam::labelList& Foam::processorPolyPatch::neighbEdges() const
441     if (!neighbEdgesPtr_)
442     {
443         FatalErrorIn("processorPolyPatch::neighbEdges() const")
444             << "No extended addressing calculated for patch " << name()
445             << abort(FatalError);
446     }
448     return *neighbEdgesPtr_;
452 void Foam::processorPolyPatch::initOrder(const primitivePatch& pp) const
454     if (!Pstream::parRun())
455     {
456         return;
457     }
459     // Master side sends the data and slave side rotates the faces
460     // HJ, 10/Mar/2011
461     if (owner())
462     {
463         pointField ctrs(calcFaceCentres(pp, pp.points()));
465         // Anchor point is the start point of all faces.  HJ, 10/Mar/2011
466         pointField anchors(getAnchorPoints(pp, pp.points()));
468         // Now send all info over to the neighbour
469         OPstream toNeighbour(Pstream::blocking, neighbProcNo());
470         toNeighbour << ctrs << anchors;
471     }
475 // Return new ordering. Ordering is -faceMap: for every face index
476 // the new face -rotation:for every new face the clockwise shift
477 // of the original face. Return false if nothing changes (faceMap
478 // is identity, rotation is 0)
479 bool Foam::processorPolyPatch::order
481     const primitivePatch& pp,
482     labelList& faceMap,
483     labelList& rotation
484 ) const
486     if (!Pstream::parRun())
487     {
488         return false;
489     }
491     // Moved from initOrder to simplify communications
492     // HJ, 27/Nov/2009
493     if (debug)
494     {
495         fileName nm
496         (
497             boundaryMesh().mesh().time().path()
498            /name() + "_faces.obj"
499         );
500         Pout<< "processorPolyPatch::order : Writing my " << pp.size()
501             << " faces to OBJ file " << nm << endl;
502         writeOBJ(nm, pp, pp.points());
504         // Calculate my face centres
505         pointField ctrs(calcFaceCentres(pp, pp.points()));
507         OFstream localStr
508         (
509             boundaryMesh().mesh().time().path()
510            /name() + "_localFaceCentres.obj"
511         );
512         Pout<< "processorPolyPatch::order : "
513             << "Dumping " << ctrs.size()
514             << " local faceCentres to " << localStr.name() << endl;
516         forAll (ctrs, faceI)
517         {
518             writeOBJ(localStr, ctrs[faceI]);
519         }
520     }
522     faceMap.setSize(pp.size());
523     faceMap = -1;
525     rotation.setSize(pp.size());
526     rotation = 0;
528     if (owner())
529     {
530         // Do nothing (i.e. identical mapping, zero rotation).
531         // See comment at top.
532         forAll (faceMap, patchFaceI)
533         {
534             faceMap[patchFaceI] = patchFaceI;
535         }
537         return false;
538     }
539     else
540     {
541         // Slave side: receive points
542         vectorField masterCtrs;
543         vectorField masterAnchors;
545         // Receive data from neighbour
546         {
547             IPstream fromNeighbour(Pstream::blocking, neighbProcNo());
548             fromNeighbour >> masterCtrs >> masterAnchors;
549         }
551         // Calculate my face centres
552         pointField ctrs(calcFaceCentres(pp, pp.points()));
554         // Calculate typical distance from face centre
555         scalarField tols(calcFaceTol(pp, pp.points(), ctrs));
557         if (debug || masterCtrs.size() != pp.size())
558         {
559             {
560                 OFstream nbrStr
561                 (
562                     boundaryMesh().mesh().time().path()
563                    /name() + "_nbrFaceCentres.obj"
564                 );
566                 Pout<< "processorPolyPatch::order : "
567                     << "Dumping neighbour faceCentres to " << nbrStr.name()
568                     << endl;
570                 forAll (masterCtrs, faceI)
571                 {
572                     writeOBJ(nbrStr, masterCtrs[faceI]);
573                 }
574             }
576             if (masterCtrs.size() != pp.size())
577             {
578                 FatalErrorIn
579                 (
580                     "processorPolyPatch::order(const primitivePatch&"
581                     ", labelList&, labelList&) const"
582                 )   << "in patch:" << name() << " : "
583                     << "Local size of patch is " << pp.size() << " (faces)."
584                     << endl
585                     << "Received from neighbour " << masterCtrs.size()
586                     << " faceCentres!"
587                     << abort(FatalError);
588             }
589         }
591         // Geometric match of face centre vectors
592         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
594         // 1. Try existing ordering and transformation
595         bool matchedAll = false;
597         if
598         (
599             separated()
600          && (separation().size() == 1 || separation().size() == pp.size())
601         )
602         {
603             vectorField transformedCtrs;
605             const vectorField& v = separation();
607             if (v.size() == 1)
608             {
609                 transformedCtrs = masterCtrs - v[0];
610             }
611             else
612             {
613                 transformedCtrs = masterCtrs - v;
614             }
616             matchedAll = matchPoints
617             (
618                 ctrs,
619                 transformedCtrs,
620                 tols,
621                 true,
622                 faceMap
623             );
625             if (matchedAll)
626             {
627                 // Use transformed centers from now on
628                 masterCtrs = transformedCtrs;
630                 // Transform anchors
631                 if (v.size() == 1)
632                 {
633                     masterAnchors -= v[0];
634                 }
635                 else
636                 {
637                     masterAnchors -= v;
638                 }
639             }
640         }
641         else if
642         (
643            !parallel()
644          && (forwardT().size() == 1 || forwardT().size() == pp.size())
645         )
646         {
647             vectorField transformedCtrs = masterCtrs;
648             transformList(forwardT(), transformedCtrs);
650             matchedAll = matchPoints
651             (
652                 ctrs,
653                 transformedCtrs,
654                 tols,
655                 true,
656                 faceMap
657             );
659             if (matchedAll)
660             {
661                 // Use transformed centers from now on
662                 masterCtrs = transformedCtrs;
664                 // Transform anchors
665                 transformList(forwardT(), masterAnchors);
666             }
667         }
670         // 2. Try zero separation automatic matching
671         if (!matchedAll)
672         {
673             matchedAll = matchPoints(ctrs, masterCtrs, tols, true, faceMap);
674         }
676         if (!matchedAll || debug)
677         {
678             // Dump faces
679             fileName str
680             (
681                 boundaryMesh().mesh().time().path()
682                /name()/name() + "_faces.obj"
683             );
684             Pout<< "processorPolyPatch::order :"
685                 << " Writing faces to OBJ file " << str.name() << endl;
686             writeOBJ(str, pp, pp.points());
688             OFstream ccStr
689             (
690                 boundaryMesh().mesh().time().path()
691                /name() + "_faceCentresConnections.obj"
692             );
694             Pout<< "processorPolyPatch::order :"
695                 << " Dumping newly found match as lines between"
696                 << " corresponding face centres to OBJ file " << ccStr.name()
697                 << endl;
699             label vertI = 0;
701             forAll (ctrs, faceI)
702             {
703                 label masterFaceI = faceMap[faceI];
705                 if (masterFaceI != -1)
706                 {
707                     const point& c0 = masterCtrs[masterFaceI];
708                     const point& c1 = ctrs[faceI];
709                     writeOBJ(ccStr, c0, c1, vertI);
710                 }
711             }
712         }
714         if (!matchedAll)
715         {
716             FatalErrorIn
717 //             SeriousErrorIn
718             (
719                 "processorPolyPatch::order(const primitivePatch&"
720                 ", labelList&, labelList&) const"
721             )   << "in patch:" << name() << " : "
722                 << "Cannot match vectors to faces on both sides of patch"
723                 << endl
724                 << "    masterCtrs[0]:" << masterCtrs[0] << endl
725                 << "    ctrs[0]:" << ctrs[0] << endl
726                 << "    Please check your topology changes or maybe you have"
727                 << " multiple separated (from cyclics) processor patches"
728                 << endl
729                 << "    Continuing with incorrect face ordering from now on!"
730                 << abort(FatalError);
732             return false;
733         }
735         // Set rotation
736         forAll (faceMap, oldFaceI)
737         {
738             // The face f will be at newFaceI (after morphing) and we want its
739             // anchorPoint (= f[0]) to align with the anchorpoint for the
740             // corresponding face on the other side.
742             label newFaceI = faceMap[oldFaceI];
744             const point& wantedAnchor = masterAnchors[newFaceI];
746             rotation[newFaceI] = getRotation
747             (
748                 pp.points(),
749                 pp[oldFaceI],
750                 wantedAnchor,
751                 tols[oldFaceI]
752             );
754             if (rotation[newFaceI] == -1)
755             {
756                 FatalErrorIn
757 //                 SeriousErrorIn
758                 (
759                     "processorPolyPatch::order(const primitivePatch&"
760                     ", labelList&, labelList&) const"
761                 )   << "in patch " << name()
762                     << " : "
763                     << "Cannot find point on face " << pp[oldFaceI]
764                     << " with vertices "
765                     << UIndirectList<point>(pp.points(), pp[oldFaceI])()
766                     << " that matches point " << wantedAnchor
767                     << " when matching the halves of processor patch "
768                     << name()
769                     << "Continuing with incorrect face ordering from now on!"
770                     << abort(FatalError);
772                 return false;
773             }
774         }
776         forAll (faceMap, faceI)
777         {
778             if (faceMap[faceI] != faceI || rotation[faceI] != 0)
779             {
780                 return true;
781             }
782         }
784         return false;
785     }
789 void Foam::processorPolyPatch::syncOrder() const
791     if (!Pstream::parRun())
792     {
793         return;
794     }
796     // Read and discard info from owner side from the neighbour
797     if (neighbour())
798     {
799         vectorField masterCtrs;
800         vectorField masterAnchors;
802         // Receive data from neighbour
803         {
804             IPstream fromNeighbour(Pstream::blocking, neighbProcNo());
805             fromNeighbour >> masterCtrs >> masterAnchors;
806         }
807     }
811 void Foam::processorPolyPatch::write(Ostream& os) const
813     polyPatch::write(os);
814     os.writeKeyword("myProcNo") << myProcNo_
815         << token::END_STATEMENT << nl;
816     os.writeKeyword("neighbProcNo") << neighbProcNo_
817         << token::END_STATEMENT << nl;
821 // ************************************************************************* //