initial commit for version 1.6.x patch release
[OpenFOAM-1.6.x.git] / src / OpenFOAM / meshes / polyMesh / polyPatches / constraint / processor / processorPolyPatch.C
blob70eafc70a88d8c4ed96982789ae03e8f916fc193
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
4    \\    /   O peration     |
5     \\  /    A nd           | Copyright (C) 1991-2009 OpenCFD Ltd.
6      \\/     M anipulation  |
7 -------------------------------------------------------------------------------
8 License
9     This file is part of OpenFOAM.
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 the
13     Free Software Foundation; either version 2 of the License, or (at your
14     option) any later version.
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.
21     You should have received a copy of the GNU General Public License
22     along with OpenFOAM; if not, write to the Free Software Foundation,
23     Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
27 #include "processorPolyPatch.H"
28 #include "addToRunTimeSelectionTable.H"
29 #include "dictionary.H"
30 #include "SubField.H"
31 #include "demandDrivenData.H"
32 #include "matchPoints.H"
33 #include "OFstream.H"
34 #include "polyMesh.H"
35 #include "Time.H"
36 #include "transformList.H"
38 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
40 namespace Foam
42     defineTypeNameAndDebug(processorPolyPatch, 0);
43     addToRunTimeSelectionTable(polyPatch, processorPolyPatch, dictionary);
47 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
49 Foam::processorPolyPatch::processorPolyPatch
51     const word& name,
52     const label size,
53     const label start,
54     const label index,
55     const polyBoundaryMesh& bm,
56     const int myProcNo,
57     const int neighbProcNo
60     coupledPolyPatch(name, size, start, index, bm),
61     myProcNo_(myProcNo),
62     neighbProcNo_(neighbProcNo),
63     neighbFaceCentres_(),
64     neighbFaceAreas_(),
65     neighbFaceCellCentres_(),
66     neighbPointsPtr_(NULL),
67     neighbEdgesPtr_(NULL)
71 Foam::processorPolyPatch::processorPolyPatch
73     const word& name,
74     const dictionary& dict,
75     const label index,
76     const polyBoundaryMesh& bm
79     coupledPolyPatch(name, dict, index, bm),
80     myProcNo_(readLabel(dict.lookup("myProcNo"))),
81     neighbProcNo_(readLabel(dict.lookup("neighbProcNo"))),
82     neighbFaceCentres_(),
83     neighbFaceAreas_(),
84     neighbFaceCellCentres_(),
85     neighbPointsPtr_(NULL),
86     neighbEdgesPtr_(NULL)
90 Foam::processorPolyPatch::processorPolyPatch
92     const processorPolyPatch& pp,
93     const polyBoundaryMesh& bm
96     coupledPolyPatch(pp, bm),
97     myProcNo_(pp.myProcNo_),
98     neighbProcNo_(pp.neighbProcNo_),
99     neighbFaceCentres_(),
100     neighbFaceAreas_(),
101     neighbFaceCellCentres_(),
102     neighbPointsPtr_(NULL),
103     neighbEdgesPtr_(NULL)
107 Foam::processorPolyPatch::processorPolyPatch
109     const processorPolyPatch& pp,
110     const polyBoundaryMesh& bm,
111     const label index,
112     const label newSize,
113     const label newStart
116     coupledPolyPatch(pp, bm, index, newSize, newStart),
117     myProcNo_(pp.myProcNo_),
118     neighbProcNo_(pp.neighbProcNo_),
119     neighbFaceCentres_(),
120     neighbFaceAreas_(),
121     neighbFaceCellCentres_(),
122     neighbPointsPtr_(NULL),
123     neighbEdgesPtr_(NULL)
127 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
129 Foam::processorPolyPatch::~processorPolyPatch()
131     deleteDemandDrivenData(neighbPointsPtr_);
132     deleteDemandDrivenData(neighbEdgesPtr_);
136 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
138 void Foam::processorPolyPatch::initGeometry()
140     if (Pstream::parRun())
141     {
142         OPstream toNeighbProc
143         (
144             Pstream::blocking,
145             neighbProcNo(),
146             3*(sizeof(label) + size()*sizeof(vector) + sizeof(scalar))
147         );
149         toNeighbProc
150             << faceCentres()
151             << faceAreas()
152             << faceCellCentres();
153     }
157 void Foam::processorPolyPatch::calcGeometry()
159     if (Pstream::parRun())
160     {
161         {
162             IPstream fromNeighbProc
163             (
164                 Pstream::blocking,
165                 neighbProcNo(),
166                 3*(sizeof(label) + size()*sizeof(vector) + sizeof(scalar))
167             );
168             fromNeighbProc
169                 >> neighbFaceCentres_
170                 >> neighbFaceAreas_
171                 >> neighbFaceCellCentres_;
172         }
174         // My normals
175         vectorField faceNormals(size());
177         // Neighbour normals
178         vectorField nbrFaceNormals(neighbFaceAreas_.size());
180         // Calculate normals from areas and check
181         forAll(faceNormals, facei)
182         {
183             scalar magSf = mag(faceAreas()[facei]);
184             scalar nbrMagSf = mag(neighbFaceAreas_[facei]);
185             scalar avSf = (magSf + nbrMagSf)/2.0;
187             if (magSf < ROOTVSMALL && nbrMagSf < ROOTVSMALL)
188             {
189                 // Undetermined normal. Use dummy normal to force separation
190                 // check. (note use of sqrt(VSMALL) since that is how mag
191                 // scales)
192                 faceNormals[facei] = point(1, 0, 0);
193                 nbrFaceNormals[facei] = faceNormals[facei];
194             }
195             else if (mag(magSf - nbrMagSf)/avSf > coupledPolyPatch::matchTol)
196             {
197                 FatalErrorIn
198                 (
199                     "processorPolyPatch::calcGeometry()"
200                 )   << "face " << facei << " area does not match neighbour by "
201                     << 100*mag(magSf - nbrMagSf)/avSf
202                     << "% -- possible face ordering problem." << endl
203                     << "patch:" << name()
204                     << " my area:" << magSf
205                     << " neighbour area:" << nbrMagSf
206                     << " matching tolerance:" << coupledPolyPatch::matchTol
207                     << endl
208                     << "Mesh face:" << start()+facei
209                     << " vertices:"
210                     << UIndirectList<point>(points(), operator[](facei))()
211                     << endl
212                     << "Rerun with processor debug flag set for"
213                     << " more information." << exit(FatalError);
214             }
215             else
216             {
217                 faceNormals[facei] = faceAreas()[facei]/magSf;
218                 nbrFaceNormals[facei] = neighbFaceAreas_[facei]/nbrMagSf;
219             }
220         }
222         calcTransformTensors
223         (
224             faceCentres(),
225             neighbFaceCentres_,
226             faceNormals,
227             nbrFaceNormals,
228             calcFaceTol(*this, points(), faceCentres())
229         );
230     }
234 void Foam::processorPolyPatch::initMovePoints(const pointField& p)
236     polyPatch::movePoints(p);
237     processorPolyPatch::initGeometry();
241 void Foam::processorPolyPatch::movePoints(const pointField&)
243     processorPolyPatch::calcGeometry();
247 void Foam::processorPolyPatch::initUpdateMesh()
249     polyPatch::initUpdateMesh();
251     deleteDemandDrivenData(neighbPointsPtr_);
252     deleteDemandDrivenData(neighbEdgesPtr_);
254     if (Pstream::parRun())
255     {
256         // Express all points as patch face and index in face.
257         labelList pointFace(nPoints());
258         labelList pointIndex(nPoints());
260         for (label patchPointI = 0; patchPointI < nPoints(); patchPointI++)
261         {
262             label faceI = pointFaces()[patchPointI][0];
264             pointFace[patchPointI] = faceI;
266             const face& f = localFaces()[faceI];
268             pointIndex[patchPointI] = findIndex(f, patchPointI);
269         }
271         // Express all edges as patch face and index in face.
272         labelList edgeFace(nEdges());
273         labelList edgeIndex(nEdges());
275         for (label patchEdgeI = 0; patchEdgeI < nEdges(); patchEdgeI++)
276         {
277             label faceI = edgeFaces()[patchEdgeI][0];
279             edgeFace[patchEdgeI] = faceI;
281             const labelList& fEdges = faceEdges()[faceI];
283             edgeIndex[patchEdgeI] = findIndex(fEdges, patchEdgeI);
284         }
286         OPstream toNeighbProc
287         (
288             Pstream::blocking,
289             neighbProcNo(),
290             8*sizeof(label)             // four headers of labelList
291           + 2*nPoints()*sizeof(label)   // two point-based labellists
292           + 2*nEdges()*sizeof(label)    // two edge-based labelLists
293         );
295         toNeighbProc
296             << pointFace
297             << pointIndex
298             << edgeFace
299             << edgeIndex;
300     }
304 void Foam::processorPolyPatch::updateMesh()
306     // For completeness
307     polyPatch::updateMesh();
309     if (Pstream::parRun())
310     {
311         labelList nbrPointFace;
312         labelList nbrPointIndex;
313         labelList nbrEdgeFace;
314         labelList nbrEdgeIndex;
316         {
317             // Note cannot predict exact size since opposite nPoints might
318             // be different from one over here.
319             IPstream fromNeighbProc(Pstream::blocking, neighbProcNo());
321             fromNeighbProc
322                 >> nbrPointFace
323                 >> nbrPointIndex
324                 >> nbrEdgeFace
325                 >> nbrEdgeIndex;
326         }
328         // Convert neighbour faces and indices into face back into
329         // my edges and points.
331         // Convert points.
332         // ~~~~~~~~~~~~~~~
334         neighbPointsPtr_ = new labelList(nPoints(), -1);
335         labelList& neighbPoints = *neighbPointsPtr_;
337         forAll(nbrPointFace, nbrPointI)
338         {
339             // Find face and index in face on this side.
340             const face& f = localFaces()[nbrPointFace[nbrPointI]];
341             label index = (f.size() - nbrPointIndex[nbrPointI]) % f.size();
342             label patchPointI = f[index];
344             if (neighbPoints[patchPointI] == -1)
345             {
346                 // First reference of point
347                 neighbPoints[patchPointI] = nbrPointI;
348             }
349             else if (neighbPoints[patchPointI] >= 0)
350             {
351                 // Point already visited. Mark as duplicate.
352                 neighbPoints[patchPointI] = -2;
353             }
354         }
356         // Reset all duplicate entries to -1.
357         forAll(neighbPoints, patchPointI)
358         {
359             if (neighbPoints[patchPointI] == -2)
360             {
361                 neighbPoints[patchPointI] = -1;
362             }
363         }
365         // Convert edges.
366         // ~~~~~~~~~~~~~~
368         neighbEdgesPtr_ = new labelList(nEdges(), -1);
369         labelList& neighbEdges = *neighbEdgesPtr_;
371         forAll(nbrEdgeFace, nbrEdgeI)
372         {
373             // Find face and index in face on this side.
374             const labelList& f = faceEdges()[nbrEdgeFace[nbrEdgeI]];
375             label index = (f.size() - nbrEdgeIndex[nbrEdgeI] - 1) % f.size();
376             label patchEdgeI = f[index];
378             if (neighbEdges[patchEdgeI] == -1)
379             {
380                 // First reference of edge
381                 neighbEdges[patchEdgeI] = nbrEdgeI;
382             }
383             else if (neighbEdges[patchEdgeI] >= 0)
384             {
385                 // Edge already visited. Mark as duplicate.
386                 neighbEdges[patchEdgeI] = -2;
387             }
388         }
390         // Reset all duplicate entries to -1.
391         forAll(neighbEdges, patchEdgeI)
392         {
393             if (neighbEdges[patchEdgeI] == -2)
394             {
395                 neighbEdges[patchEdgeI] = -1;
396             }
397         }
399         // Remove any addressing used for shared points/edges calculation
400         primitivePatch::clearOut();
401     }
405 const Foam::labelList& Foam::processorPolyPatch::neighbPoints() const
407     if (!neighbPointsPtr_)
408     {
409         FatalErrorIn("processorPolyPatch::neighbPoints() const")
410             << "No extended addressing calculated for patch " << name()
411             << abort(FatalError);
412     }
413     return *neighbPointsPtr_;
417 const Foam::labelList& Foam::processorPolyPatch::neighbEdges() const
419     if (!neighbEdgesPtr_)
420     {
421         FatalErrorIn("processorPolyPatch::neighbEdges() const")
422             << "No extended addressing calculated for patch " << name()
423             << abort(FatalError);
424     }
425     return *neighbEdgesPtr_;
429 void Foam::processorPolyPatch::initOrder(const primitivePatch& pp) const
431     if (!Pstream::parRun())
432     {
433         return;
434     }
436     if (debug)
437     {
438         fileName nm
439         (
440             boundaryMesh().mesh().time().path()
441            /name()+"_faces.obj"
442         );
443         Pout<< "processorPolyPatch::order : Writing my " << pp.size()
444             << " faces to OBJ file " << nm << endl;
445         writeOBJ(nm, pp, pp.points());
447         // Calculate my face centres
448         pointField ctrs(calcFaceCentres(pp, pp.points()));
450         OFstream localStr
451         (
452             boundaryMesh().mesh().time().path()
453            /name() + "_localFaceCentres.obj"
454         );
455         Pout<< "processorPolyPatch::order : "
456             << "Dumping " << ctrs.size()
457             << " local faceCentres to " << localStr.name() << endl;
459         forAll(ctrs, faceI)
460         {
461             writeOBJ(localStr, ctrs[faceI]);
462         }
463     }
465     const bool isMaster = Pstream::myProcNo() < neighbProcNo();
467     if (isMaster)
468     {
469         pointField ctrs(calcFaceCentres(pp, pp.points()));
471         pointField anchors(getAnchorPoints(pp, pp.points()));
473         // Now send all info over to the neighbour
474         OPstream toNeighbour(Pstream::blocking, neighbProcNo());
475         toNeighbour << ctrs << anchors;
476     }
480 // Return new ordering. Ordering is -faceMap: for every face index
481 // the new face -rotation:for every new face the clockwise shift
482 // of the original face. Return false if nothing changes (faceMap
483 // is identity, rotation is 0)
484 bool Foam::processorPolyPatch::order
486     const primitivePatch& pp,
487     labelList& faceMap,
488     labelList& rotation
489 ) const
491     if (!Pstream::parRun())
492     {
493         return false;
494     }
496     faceMap.setSize(pp.size());
497     faceMap = -1;
499     rotation.setSize(pp.size());
500     rotation = 0;
502     const bool isMaster = Pstream::myProcNo() < neighbProcNo();
504     if (isMaster)
505     {
506         // Do nothing (i.e. identical mapping, zero rotation).
507         // See comment at top.
508         forAll(faceMap, patchFaceI)
509         {
510             faceMap[patchFaceI] = patchFaceI;
511         }
513         return false;
514     }
515     else
516     {
517         vectorField masterCtrs;
518         vectorField masterAnchors;
520         // Receive data from neighbour
521         {
522             IPstream fromNeighbour(Pstream::blocking, neighbProcNo());
523             fromNeighbour >> masterCtrs >> masterAnchors;
524         }
526         // Calculate my face centres
527         pointField ctrs(calcFaceCentres(pp, pp.points()));
529         // Calculate typical distance from face centre
530         scalarField tols(calcFaceTol(pp, pp.points(), ctrs));
532         if (debug || masterCtrs.size() != pp.size())
533         {
534             {
535                 OFstream nbrStr
536                 (
537                     boundaryMesh().mesh().time().path()
538                    /name() + "_nbrFaceCentres.obj"
539                 );
540                 Pout<< "processorPolyPatch::order : "
541                     << "Dumping neighbour faceCentres to " << nbrStr.name()
542                     << endl;
543                 forAll(masterCtrs, faceI)
544                 {
545                     writeOBJ(nbrStr, masterCtrs[faceI]);
546                 }
547             }
549             if (masterCtrs.size() != pp.size())
550             {
551                 FatalErrorIn
552                 (
553                     "processorPolyPatch::order(const primitivePatch&"
554                     ", labelList&, labelList&) const"
555                 )   << "in patch:" << name() << " : "
556                     << "Local size of patch is " << pp.size() << " (faces)."
557                     << endl
558                     << "Received from neighbour " << masterCtrs.size()
559                     << " faceCentres!"
560                     << abort(FatalError);
561             }
562         }
564         // Geometric match of face centre vectors
565         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
567         // 1. Try existing ordering and transformation
568         bool matchedAll = false;
570         if
571         (
572             separated()
573          && (separation().size() == 1 || separation().size() == pp.size())
574         )
575         {
576             vectorField transformedCtrs;
578             const vectorField& v = separation();
580             if (v.size() == 1)
581             {
582                 transformedCtrs = masterCtrs-v[0];
583             }
584             else
585             {
586                 transformedCtrs = masterCtrs-v;
587             }
588             matchedAll = matchPoints
589             (
590                 ctrs,
591                 transformedCtrs,
592                 tols,
593                 true,
594                 faceMap
595             );
597             if (matchedAll)
598             {
599                 // Use transformed centers from now on
600                 masterCtrs = transformedCtrs;
602                 // Transform anchors
603                 if (v.size() == 1)
604                 {
605                     masterAnchors -= v[0];
606                 }
607                 else
608                 {
609                     masterAnchors -= v;
610                 }
611             }
612         }
613         else if
614         (
615            !parallel()
616          && (forwardT().size() == 1 || forwardT().size() == pp.size())
617         )
618         {
619             vectorField transformedCtrs = masterCtrs;
620             transformList(forwardT(), transformedCtrs);
621             matchedAll = matchPoints
622             (
623                 ctrs,
624                 transformedCtrs,
625                 tols,
626                 true,
627                 faceMap
628             );
630             if (matchedAll)
631             {
632                 // Use transformed centers from now on
633                 masterCtrs = transformedCtrs;
635                 // Transform anchors
636                 transformList(forwardT(), masterAnchors);
637             }
638         }
641         // 2. Try zero separation automatic matching
642         if (!matchedAll)
643         {
644             matchedAll = matchPoints(ctrs, masterCtrs, tols, true, faceMap);
645         }
647         if (!matchedAll || debug)
648         {
649             // Dump faces
650             fileName str
651             (
652                 boundaryMesh().mesh().time().path()
653                /name()/name()+"_faces.obj"
654             );
655             Pout<< "processorPolyPatch::order :"
656                 << " Writing faces to OBJ file " << str.name() << endl;
657             writeOBJ(str, pp, pp.points());
659             OFstream ccStr
660             (
661                 boundaryMesh().mesh().time().path()
662                /name() + "_faceCentresConnections.obj"
663             );
665             Pout<< "processorPolyPatch::order :"
666                 << " Dumping newly found match as lines between"
667                 << " corresponding face centres to OBJ file " << ccStr.name()
668                 << endl;
670             label vertI = 0;
672             forAll(ctrs, faceI)
673             {
674                 label masterFaceI = faceMap[faceI];
676                 if (masterFaceI != -1)
677                 {
678                     const point& c0 = masterCtrs[masterFaceI];
679                     const point& c1 = ctrs[faceI];
680                     writeOBJ(ccStr, c0, c1, vertI);
681                 }
682             }
683         }
685         if (!matchedAll)
686         {
687             SeriousErrorIn
688             (
689                 "processorPolyPatch::order(const primitivePatch&"
690                 ", labelList&, labelList&) const"
691             )   << "in patch:" << name() << " : "
692                 << "Cannot match vectors to faces on both sides of patch"
693                 << endl
694                 << "    masterCtrs[0]:" << masterCtrs[0] << endl
695                 << "    ctrs[0]:" << ctrs[0] << endl
696                 << "    Please check your topology changes or maybe you have"
697                 << " multiple separated (from cyclics) processor patches"
698                 << endl
699                 << "    Continuing with incorrect face ordering from now on!"
700                 << endl;
702             return false;
703         }
705         // Set rotation.
706         forAll(faceMap, oldFaceI)
707         {
708             // The face f will be at newFaceI (after morphing) and we want its
709             // anchorPoint (= f[0]) to align with the anchorpoint for the
710             // corresponding face on the other side.
712             label newFaceI = faceMap[oldFaceI];
714             const point& wantedAnchor = masterAnchors[newFaceI];
716             rotation[newFaceI] = getRotation
717             (
718                 pp.points(),
719                 pp[oldFaceI],
720                 wantedAnchor,
721                 tols[oldFaceI]
722             );
724             if (rotation[newFaceI] == -1)
725             {
726                 SeriousErrorIn
727                 (
728                     "processorPolyPatch::order(const primitivePatch&"
729                     ", labelList&, labelList&) const"
730                 )   << "in patch " << name()
731                     << " : "
732                     << "Cannot find point on face " << pp[oldFaceI]
733                     << " with vertices "
734                     << UIndirectList<point>(pp.points(), pp[oldFaceI])()
735                     << " that matches point " << wantedAnchor
736                     << " when matching the halves of processor patch " << name()
737                     << "Continuing with incorrect face ordering from now on!"
738                     << endl;
740                 return false;
741             }
742         }
744         forAll(faceMap, faceI)
745         {
746             if (faceMap[faceI] != faceI || rotation[faceI] != 0)
747             {
748                 return true;
749             }
750         }
752         return false;
753     }
757 void Foam::processorPolyPatch::write(Ostream& os) const
759     polyPatch::write(os);
760     os.writeKeyword("myProcNo") << myProcNo_
761         << token::END_STATEMENT << nl;
762     os.writeKeyword("neighbProcNo") << neighbProcNo_
763         << token::END_STATEMENT << nl;
767 // ************************************************************************* //