1 /*---------------------------------------------------------------------------*\
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 -------------------------------------------------------------------------------
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"
30 #include "demandDrivenData.H"
31 #include "matchPoints.H"
35 #include "transformList.H"
37 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
41 defineTypeNameAndDebug(processorPolyPatch, 0);
42 addToRunTimeSelectionTable(polyPatch, processorPolyPatch, dictionary);
46 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
48 Foam::processorPolyPatch::processorPolyPatch
54 const polyBoundaryMesh& bm,
56 const int neighbProcNo
59 coupledPolyPatch(name, size, start, index, bm),
61 neighbProcNo_(neighbProcNo),
64 neighbFaceCellCentres_(),
65 neighbPointsPtr_(NULL),
70 Foam::processorPolyPatch::processorPolyPatch
73 const dictionary& dict,
75 const polyBoundaryMesh& bm
78 coupledPolyPatch(name, dict, index, bm),
79 myProcNo_(readLabel(dict.lookup("myProcNo"))),
80 neighbProcNo_(readLabel(dict.lookup("neighbProcNo"))),
83 neighbFaceCellCentres_(),
84 neighbPointsPtr_(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_),
100 neighbFaceCellCentres_(),
101 neighbPointsPtr_(NULL),
102 neighbEdgesPtr_(NULL)
106 Foam::processorPolyPatch::processorPolyPatch
108 const processorPolyPatch& pp,
109 const polyBoundaryMesh& bm,
115 coupledPolyPatch(pp, bm, index, newSize, newStart),
116 myProcNo_(pp.myProcNo_),
117 neighbProcNo_(pp.neighbProcNo_),
118 neighbFaceCentres_(),
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())
153 OPstream toNeighbProc
157 3*(sizeof(label) + size()*sizeof(vector) + sizeof(scalar))
163 << faceCellCentres();
168 void Foam::processorPolyPatch::calcGeometry()
170 if (Pstream::parRun())
173 IPstream fromNeighbProc
177 3*(sizeof(label) + size()*sizeof(vector) + sizeof(scalar))
180 >> neighbFaceCentres_
182 >> neighbFaceCellCentres_;
186 vectorField faceNormals(size());
189 vectorField nbrFaceNormals(neighbFaceAreas_.size());
191 // Calculate normals from areas and check
194 const vectorField::subField localFaceAreas = faceAreas();
196 forAll (faceNormals, facei)
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)
204 // Undetermined normal. Use dummy normal to force separation
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];
212 else if (mag(magSf - nbrMagSf)/avSf > polyPatch::matchTol_)
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_
225 << "Mesh face: " << start()+facei
227 << UIndirectList<point>(points(), operator[](facei))()
229 << "Rerun with processor debug flag set for"
230 << " more information." << exit(FatalError);
234 faceNormals[facei] = localFaceAreas[facei]/magSf;
235 nbrFaceNormals[facei] = neighbFaceAreas_[facei]/nbrMagSf;
245 calcFaceTol(*this, points(), faceCentres())
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())
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++)
279 label faceI = pointFaces()[patchPointI][0];
281 pointFace[patchPointI] = faceI;
283 const face& f = localFaces()[faceI];
285 pointIndex[patchPointI] = findIndex(f, patchPointI);
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++)
294 label faceI = edgeFaces()[patchEdgeI][0];
296 edgeFace[patchEdgeI] = faceI;
298 const labelList& fEdges = faceEdges()[faceI];
300 edgeIndex[patchEdgeI] = findIndex(fEdges, patchEdgeI);
303 OPstream toNeighbProc
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
321 void Foam::processorPolyPatch::updateMesh()
324 polyPatch::updateMesh();
326 if (Pstream::parRun())
328 labelList nbrPointFace;
329 labelList nbrPointIndex;
330 labelList nbrEdgeFace;
331 labelList nbrEdgeIndex;
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
340 IPstream fromNeighbProc(Pstream::blocking, neighbProcNo());
349 // Convert neighbour faces and indices into face back into
350 // my edges and points.
355 neighbPointsPtr_ = new labelList(nPoints(), -1);
356 labelList& neighbPoints = *neighbPointsPtr_;
358 forAll (nbrPointFace, nbrPointI)
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)
367 // First reference of point
368 neighbPoints[patchPointI] = nbrPointI;
370 else if (neighbPoints[patchPointI] >= 0)
372 // Point already visited. Mark as duplicate.
373 neighbPoints[patchPointI] = -2;
377 // Reset all duplicate entries to -1.
378 forAll (neighbPoints, patchPointI)
380 if (neighbPoints[patchPointI] == -2)
382 neighbPoints[patchPointI] = -1;
389 neighbEdgesPtr_ = new labelList(nEdges(), -1);
390 labelList& neighbEdges = *neighbEdgesPtr_;
392 forAll (nbrEdgeFace, nbrEdgeI)
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)
401 // First reference of edge
402 neighbEdges[patchEdgeI] = nbrEdgeI;
404 else if (neighbEdges[patchEdgeI] >= 0)
406 // Edge already visited. Mark as duplicate.
407 neighbEdges[patchEdgeI] = -2;
411 // Reset all duplicate entries to -1.
412 forAll (neighbEdges, patchEdgeI)
414 if (neighbEdges[patchEdgeI] == -2)
416 neighbEdges[patchEdgeI] = -1;
420 // Remove any addressing used for shared points/edges calculation
421 primitivePatch::clearOut();
426 const Foam::labelList& Foam::processorPolyPatch::neighbPoints() const
428 if (!neighbPointsPtr_)
430 FatalErrorIn("processorPolyPatch::neighbPoints() const")
431 << "No extended addressing calculated for patch " << name()
432 << abort(FatalError);
435 return *neighbPointsPtr_;
439 const Foam::labelList& Foam::processorPolyPatch::neighbEdges() const
441 if (!neighbEdgesPtr_)
443 FatalErrorIn("processorPolyPatch::neighbEdges() const")
444 << "No extended addressing calculated for patch " << name()
445 << abort(FatalError);
448 return *neighbEdgesPtr_;
452 void Foam::processorPolyPatch::initOrder(const primitivePatch& pp) const
454 if (!Pstream::parRun())
459 // Master side sends the data and slave side rotates the faces
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;
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,
486 if (!Pstream::parRun())
491 // Moved from initOrder to simplify communications
497 boundaryMesh().mesh().time().path()
498 /name() + "_faces.obj"
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()));
509 boundaryMesh().mesh().time().path()
510 /name() + "_localFaceCentres.obj"
512 Pout<< "processorPolyPatch::order : "
513 << "Dumping " << ctrs.size()
514 << " local faceCentres to " << localStr.name() << endl;
518 writeOBJ(localStr, ctrs[faceI]);
522 faceMap.setSize(pp.size());
525 rotation.setSize(pp.size());
530 // Do nothing (i.e. identical mapping, zero rotation).
531 // See comment at top.
532 forAll (faceMap, patchFaceI)
534 faceMap[patchFaceI] = patchFaceI;
541 // Slave side: receive points
542 vectorField masterCtrs;
543 vectorField masterAnchors;
545 // Receive data from neighbour
547 IPstream fromNeighbour(Pstream::blocking, neighbProcNo());
548 fromNeighbour >> masterCtrs >> masterAnchors;
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())
562 boundaryMesh().mesh().time().path()
563 /name() + "_nbrFaceCentres.obj"
566 Pout<< "processorPolyPatch::order : "
567 << "Dumping neighbour faceCentres to " << nbrStr.name()
570 forAll (masterCtrs, faceI)
572 writeOBJ(nbrStr, masterCtrs[faceI]);
576 if (masterCtrs.size() != pp.size())
580 "processorPolyPatch::order(const primitivePatch&"
581 ", labelList&, labelList&) const"
582 ) << "in patch:" << name() << " : "
583 << "Local size of patch is " << pp.size() << " (faces)."
585 << "Received from neighbour " << masterCtrs.size()
587 << abort(FatalError);
591 // Geometric match of face centre vectors
592 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
594 // 1. Try existing ordering and transformation
595 bool matchedAll = false;
600 && (separation().size() == 1 || separation().size() == pp.size())
603 vectorField transformedCtrs;
605 const vectorField& v = separation();
609 transformedCtrs = masterCtrs - v[0];
613 transformedCtrs = masterCtrs - v;
616 matchedAll = matchPoints
627 // Use transformed centers from now on
628 masterCtrs = transformedCtrs;
633 masterAnchors -= v[0];
644 && (forwardT().size() == 1 || forwardT().size() == pp.size())
647 vectorField transformedCtrs = masterCtrs;
648 transformList(forwardT(), transformedCtrs);
650 matchedAll = matchPoints
661 // Use transformed centers from now on
662 masterCtrs = transformedCtrs;
665 transformList(forwardT(), masterAnchors);
670 // 2. Try zero separation automatic matching
673 matchedAll = matchPoints(ctrs, masterCtrs, tols, true, faceMap);
676 if (!matchedAll || debug)
681 boundaryMesh().mesh().time().path()
682 /name()/name() + "_faces.obj"
684 Pout<< "processorPolyPatch::order :"
685 << " Writing faces to OBJ file " << str.name() << endl;
686 writeOBJ(str, pp, pp.points());
690 boundaryMesh().mesh().time().path()
691 /name() + "_faceCentresConnections.obj"
694 Pout<< "processorPolyPatch::order :"
695 << " Dumping newly found match as lines between"
696 << " corresponding face centres to OBJ file " << ccStr.name()
703 label masterFaceI = faceMap[faceI];
705 if (masterFaceI != -1)
707 const point& c0 = masterCtrs[masterFaceI];
708 const point& c1 = ctrs[faceI];
709 writeOBJ(ccStr, c0, c1, vertI);
719 "processorPolyPatch::order(const primitivePatch&"
720 ", labelList&, labelList&) const"
721 ) << "in patch:" << name() << " : "
722 << "Cannot match vectors to faces on both sides of patch"
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"
729 << " Continuing with incorrect face ordering from now on!"
730 << abort(FatalError);
736 forAll (faceMap, oldFaceI)
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
754 if (rotation[newFaceI] == -1)
759 "processorPolyPatch::order(const primitivePatch&"
760 ", labelList&, labelList&) const"
761 ) << "in patch " << name()
763 << "Cannot find point on face " << pp[oldFaceI]
765 << UIndirectList<point>(pp.points(), pp[oldFaceI])()
766 << " that matches point " << wantedAnchor
767 << " when matching the halves of processor patch "
769 << "Continuing with incorrect face ordering from now on!"
770 << abort(FatalError);
776 forAll (faceMap, faceI)
778 if (faceMap[faceI] != faceI || rotation[faceI] != 0)
789 void Foam::processorPolyPatch::syncOrder() const
791 if (!Pstream::parRun())
796 // Read and discard info from owner side from the neighbour
799 vectorField masterCtrs;
800 vectorField masterAnchors;
802 // Receive data from neighbour
804 IPstream fromNeighbour(Pstream::blocking, neighbProcNo());
805 fromNeighbour >> masterCtrs >> masterAnchors;
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 // ************************************************************************* //