1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
7 -------------------------------------------------------------------------------
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
13 the Free Software Foundation, either version 3 of the License, or
14 (at your 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
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
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"
36 #include "PstreamBuffers.H"
38 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
42 defineTypeNameAndDebug(processorPolyPatch, 0);
43 addToRunTimeSelectionTable(polyPatch, processorPolyPatch, dictionary);
47 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
49 Foam::processorPolyPatch::processorPolyPatch
55 const polyBoundaryMesh& bm,
57 const int neighbProcNo
60 coupledPolyPatch(name, size, start, index, bm),
62 neighbProcNo_(neighbProcNo),
65 neighbFaceCellCentres_()
69 Foam::processorPolyPatch::processorPolyPatch
72 const dictionary& dict,
74 const polyBoundaryMesh& bm
77 coupledPolyPatch(name, dict, index, bm),
78 myProcNo_(readLabel(dict.lookup("myProcNo"))),
79 neighbProcNo_(readLabel(dict.lookup("neighbProcNo"))),
82 neighbFaceCellCentres_()
86 Foam::processorPolyPatch::processorPolyPatch
88 const processorPolyPatch& pp,
89 const polyBoundaryMesh& bm
92 coupledPolyPatch(pp, bm),
93 myProcNo_(pp.myProcNo_),
94 neighbProcNo_(pp.neighbProcNo_),
97 neighbFaceCellCentres_()
101 Foam::processorPolyPatch::processorPolyPatch
103 const processorPolyPatch& pp,
104 const polyBoundaryMesh& bm,
110 coupledPolyPatch(pp, bm, index, newSize, newStart),
111 myProcNo_(pp.myProcNo_),
112 neighbProcNo_(pp.neighbProcNo_),
113 neighbFaceCentres_(),
115 neighbFaceCellCentres_()
119 Foam::processorPolyPatch::processorPolyPatch
121 const processorPolyPatch& pp,
122 const polyBoundaryMesh& bm,
124 const labelUList& mapAddressing,
128 coupledPolyPatch(pp, bm, index, mapAddressing, newStart),
129 myProcNo_(pp.myProcNo_),
130 neighbProcNo_(pp.neighbProcNo_),
131 neighbFaceCentres_(),
133 neighbFaceCellCentres_()
137 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
139 Foam::processorPolyPatch::~processorPolyPatch()
141 neighbPointsPtr_.clear();
142 neighbEdgesPtr_.clear();
146 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
148 void Foam::processorPolyPatch::initGeometry(PstreamBuffers& pBufs)
150 if (Pstream::parRun())
152 UOPstream toNeighbProc(neighbProcNo(), pBufs);
157 << faceCellCentres();
162 void Foam::processorPolyPatch::calcGeometry(PstreamBuffers& pBufs)
164 if (Pstream::parRun())
167 UIPstream fromNeighbProc(neighbProcNo(), pBufs);
170 >> neighbFaceCentres_
172 >> neighbFaceCellCentres_;
177 vectorField faceNormals(size());
180 vectorField nbrFaceNormals(neighbFaceAreas_.size());
182 // Calculate normals from areas and check
183 forAll(faceNormals, facei)
185 scalar magSf = mag(faceAreas()[facei]);
186 scalar nbrMagSf = mag(neighbFaceAreas_[facei]);
187 scalar avSf = (magSf + nbrMagSf)/2.0;
189 if (magSf < ROOTVSMALL && nbrMagSf < ROOTVSMALL)
191 // Undetermined normal. Use dummy normal to force separation
192 // check. (note use of sqrt(VSMALL) since that is how mag
194 faceNormals[facei] = point(1, 0, 0);
195 nbrFaceNormals[facei] = faceNormals[facei];
197 else if (mag(magSf - nbrMagSf)/avSf > matchTolerance())
201 boundaryMesh().mesh().time().path()
204 Pout<< "processorPolyPatch::order : Writing my " << size()
205 << " faces to OBJ file " << nm << endl;
206 writeOBJ(nm, *this, points());
210 "processorPolyPatch::calcGeometry()"
211 ) << "face " << facei << " area does not match neighbour by "
212 << 100*mag(magSf - nbrMagSf)/avSf
213 << "% -- possible face ordering problem." << endl
214 << "patch:" << name()
215 << " my area:" << magSf
216 << " neighbour area:" << nbrMagSf
217 << " matching tolerance:" << matchTolerance()
219 << "Mesh face:" << start()+facei
221 << UIndirectList<point>(points(), operator[](facei))()
223 << "If you are certain your matching is correct"
224 << " you can increase the 'matchTolerance' setting"
225 << " in the patch dictionary in the boundary file."
227 << "Rerun with processor debug flag set for"
228 << " more information." << exit(FatalError);
232 faceNormals[facei] = faceAreas()[facei]/magSf;
233 nbrFaceNormals[facei] = neighbFaceAreas_[facei]/nbrMagSf;
243 calcFaceTol(matchTolerance(), *this, points(), faceCentres()),
250 void Foam::processorPolyPatch::initMovePoints
252 PstreamBuffers& pBufs,
256 polyPatch::movePoints(pBufs, p);
257 processorPolyPatch::initGeometry(pBufs);
261 void Foam::processorPolyPatch::movePoints
263 PstreamBuffers& pBufs,
267 processorPolyPatch::calcGeometry(pBufs);
271 void Foam::processorPolyPatch::initUpdateMesh(PstreamBuffers& pBufs)
273 polyPatch::initUpdateMesh(pBufs);
275 if (Pstream::parRun())
277 // Express all points as patch face and index in face.
278 labelList pointFace(nPoints());
279 labelList pointIndex(nPoints());
281 for (label patchPointI = 0; patchPointI < nPoints(); patchPointI++)
283 label faceI = pointFaces()[patchPointI][0];
285 pointFace[patchPointI] = faceI;
287 const face& f = localFaces()[faceI];
289 pointIndex[patchPointI] = findIndex(f, patchPointI);
292 // Express all edges as patch face and index in face.
293 labelList edgeFace(nEdges());
294 labelList edgeIndex(nEdges());
296 for (label patchEdgeI = 0; patchEdgeI < nEdges(); patchEdgeI++)
298 label faceI = edgeFaces()[patchEdgeI][0];
300 edgeFace[patchEdgeI] = faceI;
302 const labelList& fEdges = faceEdges()[faceI];
304 edgeIndex[patchEdgeI] = findIndex(fEdges, patchEdgeI);
307 UOPstream toNeighbProc(neighbProcNo(), pBufs);
318 void Foam::processorPolyPatch::updateMesh(PstreamBuffers& pBufs)
321 polyPatch::updateMesh(pBufs);
323 neighbPointsPtr_.clear();
324 neighbEdgesPtr_.clear();
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.
336 UIPstream fromNeighbProc(neighbProcNo(), pBufs);
345 // Convert neighbour faces and indices into face back into
346 // my edges and points.
351 neighbPointsPtr_.reset(new labelList(nPoints(), -1));
352 labelList& neighbPoints = neighbPointsPtr_();
354 forAll(nbrPointFace, nbrPointI)
356 // Find face and index in face on this side.
357 const face& f = localFaces()[nbrPointFace[nbrPointI]];
358 label index = (f.size() - nbrPointIndex[nbrPointI]) % f.size();
359 label patchPointI = f[index];
361 if (neighbPoints[patchPointI] == -1)
363 // First reference of point
364 neighbPoints[patchPointI] = nbrPointI;
366 else if (neighbPoints[patchPointI] >= 0)
368 // Point already visited. Mark as duplicate.
369 neighbPoints[patchPointI] = -2;
373 // Reset all duplicate entries to -1.
374 forAll(neighbPoints, patchPointI)
376 if (neighbPoints[patchPointI] == -2)
378 neighbPoints[patchPointI] = -1;
385 neighbEdgesPtr_.reset(new labelList(nEdges(), -1));
386 labelList& neighbEdges = neighbEdgesPtr_();
388 forAll(nbrEdgeFace, nbrEdgeI)
390 // Find face and index in face on this side.
391 const labelList& f = faceEdges()[nbrEdgeFace[nbrEdgeI]];
392 label index = (f.size() - nbrEdgeIndex[nbrEdgeI] - 1) % f.size();
393 label patchEdgeI = f[index];
395 if (neighbEdges[patchEdgeI] == -1)
397 // First reference of edge
398 neighbEdges[patchEdgeI] = nbrEdgeI;
400 else if (neighbEdges[patchEdgeI] >= 0)
402 // Edge already visited. Mark as duplicate.
403 neighbEdges[patchEdgeI] = -2;
407 // Reset all duplicate entries to -1.
408 forAll(neighbEdges, patchEdgeI)
410 if (neighbEdges[patchEdgeI] == -2)
412 neighbEdges[patchEdgeI] = -1;
416 // Remove any addressing used for shared points/edges calculation
417 // since mostly not needed.
418 primitivePatch::clearOut();
423 const Foam::labelList& Foam::processorPolyPatch::neighbPoints() const
425 if (!neighbPointsPtr_.valid())
427 FatalErrorIn("processorPolyPatch::neighbPoints() const")
428 << "No extended addressing calculated for patch " << name()
429 << abort(FatalError);
431 return neighbPointsPtr_();
435 const Foam::labelList& Foam::processorPolyPatch::neighbEdges() const
437 if (!neighbEdgesPtr_.valid())
439 FatalErrorIn("processorPolyPatch::neighbEdges() const")
440 << "No extended addressing calculated for patch " << name()
441 << abort(FatalError);
443 return neighbEdgesPtr_();
447 void Foam::processorPolyPatch::initOrder
449 PstreamBuffers& pBufs,
450 const primitivePatch& pp
453 if (!Pstream::parRun())
462 boundaryMesh().mesh().time().path()
465 Pout<< "processorPolyPatch::order : Writing my " << pp.size()
466 << " faces to OBJ file " << nm << endl;
467 writeOBJ(nm, pp, pp.points());
469 // Calculate my face centres
470 const pointField& fc = pp.faceCentres();
474 boundaryMesh().mesh().time().path()
475 /name() + "_localFaceCentres.obj"
477 Pout<< "processorPolyPatch::order : "
478 << "Dumping " << fc.size()
479 << " local faceCentres to " << localStr.name() << endl;
483 writeOBJ(localStr, fc[faceI]);
489 pointField anchors(getAnchorPoints(pp, pp.points()));
491 // Now send all info over to the neighbour
492 UOPstream toNeighbour(neighbProcNo(), pBufs);
493 toNeighbour << pp.faceCentres() << anchors;
498 // Return new ordering. Ordering is -faceMap: for every face index
499 // the new face -rotation:for every new face the clockwise shift
500 // of the original face. Return false if nothing changes (faceMap
501 // is identity, rotation is 0)
502 bool Foam::processorPolyPatch::order
504 PstreamBuffers& pBufs,
505 const primitivePatch& pp,
510 // Note: we only get the faces that originate from internal faces.
512 if (!Pstream::parRun())
517 faceMap.setSize(pp.size());
520 rotation.setSize(pp.size());
525 // Do nothing (i.e. identical mapping, zero rotation).
526 // See comment at top.
527 forAll(faceMap, patchFaceI)
529 faceMap[patchFaceI] = patchFaceI;
536 vectorField masterCtrs;
537 vectorField masterAnchors;
539 // Receive data from neighbour
541 UIPstream fromNeighbour(neighbProcNo(), pBufs);
542 fromNeighbour >> masterCtrs >> masterAnchors;
545 // Calculate typical distance from face centre
548 calcFaceTol(matchTolerance(), pp, pp.points(), pp.faceCentres())
551 if (debug || masterCtrs.size() != pp.size())
556 boundaryMesh().mesh().time().path()
557 /name() + "_nbrFaceCentres.obj"
559 Pout<< "processorPolyPatch::order : "
560 << "Dumping neighbour faceCentres to " << nbrStr.name()
562 forAll(masterCtrs, faceI)
564 writeOBJ(nbrStr, masterCtrs[faceI]);
568 if (masterCtrs.size() != pp.size())
572 "processorPolyPatch::order(const primitivePatch&"
573 ", labelList&, labelList&) const"
574 ) << "in patch:" << name() << " : "
575 << "Local size of patch is " << pp.size() << " (faces)."
577 << "Received from neighbour " << masterCtrs.size()
579 << abort(FatalError);
583 // Geometric match of face centre vectors
584 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
586 // 1. Try existing ordering and transformation
587 bool matchedAll = matchPoints
596 if (!matchedAll || debug)
601 boundaryMesh().mesh().time().path()
602 /name()/name()+"_faces.obj"
604 Pout<< "processorPolyPatch::order :"
605 << " Writing faces to OBJ file " << str.name() << endl;
606 writeOBJ(str, pp, pp.points());
610 boundaryMesh().mesh().time().path()
611 /name() + "_faceCentresConnections.obj"
614 Pout<< "processorPolyPatch::order :"
615 << " Dumping newly found match as lines between"
616 << " corresponding face centres to OBJ file " << ccStr.name()
621 forAll(pp.faceCentres(), faceI)
623 label masterFaceI = faceMap[faceI];
625 if (masterFaceI != -1)
627 const point& c0 = masterCtrs[masterFaceI];
628 const point& c1 = pp.faceCentres()[faceI];
629 writeOBJ(ccStr, c0, c1, vertI);
638 "processorPolyPatch::order(const primitivePatch&"
639 ", labelList&, labelList&) const"
640 ) << "in patch:" << name() << " : "
641 << "Cannot match vectors to faces on both sides of patch"
643 << " masterCtrs[0]:" << masterCtrs[0] << endl
644 << " ctrs[0]:" << pp.faceCentres()[0] << endl
645 << " Please check your topology changes or maybe you have"
646 << " multiple separated (from cyclics) processor patches"
648 << " Continuing with incorrect face ordering from now on!"
655 forAll(faceMap, oldFaceI)
657 // The face f will be at newFaceI (after morphing) and we want its
658 // anchorPoint (= f[0]) to align with the anchorpoint for the
659 // corresponding face on the other side.
661 label newFaceI = faceMap[oldFaceI];
663 const point& wantedAnchor = masterAnchors[newFaceI];
665 rotation[newFaceI] = getRotation
673 if (rotation[newFaceI] == -1)
677 "processorPolyPatch::order(const primitivePatch&"
678 ", labelList&, labelList&) const"
679 ) << "in patch " << name()
681 << "Cannot find point on face " << pp[oldFaceI]
683 << UIndirectList<point>(pp.points(), pp[oldFaceI])()
684 << " that matches point " << wantedAnchor
685 << " when matching the halves of processor patch " << name()
686 << "Continuing with incorrect face ordering from now on!"
693 forAll(faceMap, faceI)
695 if (faceMap[faceI] != faceI || rotation[faceI] != 0)
706 void Foam::processorPolyPatch::write(Ostream& os) const
708 coupledPolyPatch::write(os);
709 os.writeKeyword("myProcNo") << myProcNo_
710 << token::END_STATEMENT << nl;
711 os.writeKeyword("neighbProcNo") << neighbProcNo_
712 << token::END_STATEMENT << nl;
716 // ************************************************************************* //