1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
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 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
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"
31 #include "demandDrivenData.H"
32 #include "matchPoints.H"
36 #include "transformList.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_(),
66 neighbPointsPtr_(NULL),
71 Foam::processorPolyPatch::processorPolyPatch
74 const dictionary& dict,
76 const polyBoundaryMesh& bm
79 coupledPolyPatch(name, dict, index, bm),
80 myProcNo_(readLabel(dict.lookup("myProcNo"))),
81 neighbProcNo_(readLabel(dict.lookup("neighbProcNo"))),
84 neighbFaceCellCentres_(),
85 neighbPointsPtr_(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_),
101 neighbFaceCellCentres_(),
102 neighbPointsPtr_(NULL),
103 neighbEdgesPtr_(NULL)
107 Foam::processorPolyPatch::processorPolyPatch
109 const processorPolyPatch& pp,
110 const polyBoundaryMesh& bm,
116 coupledPolyPatch(pp, bm, index, newSize, newStart),
117 myProcNo_(pp.myProcNo_),
118 neighbProcNo_(pp.neighbProcNo_),
119 neighbFaceCentres_(),
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())
142 OPstream toNeighbProc
146 3*(sizeof(label) + size()*sizeof(vector) + sizeof(scalar))
152 << faceCellCentres();
157 void Foam::processorPolyPatch::calcGeometry()
159 if (Pstream::parRun())
162 IPstream fromNeighbProc
166 3*(sizeof(label) + size()*sizeof(vector) + sizeof(scalar))
169 >> neighbFaceCentres_
171 >> neighbFaceCellCentres_;
175 vectorField faceNormals(size());
178 vectorField nbrFaceNormals(neighbFaceAreas_.size());
180 // Calculate normals from areas and check
181 forAll(faceNormals, facei)
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)
189 // Undetermined normal. Use dummy normal to force separation
190 // check. (note use of sqrt(VSMALL) since that is how mag
192 faceNormals[facei] = point(1, 0, 0);
193 nbrFaceNormals[facei] = faceNormals[facei];
195 else if (mag(magSf - nbrMagSf)/avSf > coupledPolyPatch::matchTol)
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
208 << "Mesh face:" << start()+facei
210 << UIndirectList<point>(points(), operator[](facei))()
212 << "Rerun with processor debug flag set for"
213 << " more information." << exit(FatalError);
217 faceNormals[facei] = faceAreas()[facei]/magSf;
218 nbrFaceNormals[facei] = neighbFaceAreas_[facei]/nbrMagSf;
228 calcFaceTol(*this, points(), faceCentres())
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())
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++)
262 label faceI = pointFaces()[patchPointI][0];
264 pointFace[patchPointI] = faceI;
266 const face& f = localFaces()[faceI];
268 pointIndex[patchPointI] = findIndex(f, patchPointI);
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++)
277 label faceI = edgeFaces()[patchEdgeI][0];
279 edgeFace[patchEdgeI] = faceI;
281 const labelList& fEdges = faceEdges()[faceI];
283 edgeIndex[patchEdgeI] = findIndex(fEdges, patchEdgeI);
286 OPstream toNeighbProc
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
304 void Foam::processorPolyPatch::updateMesh()
307 polyPatch::updateMesh();
309 if (Pstream::parRun())
311 labelList nbrPointFace;
312 labelList nbrPointIndex;
313 labelList nbrEdgeFace;
314 labelList nbrEdgeIndex;
317 // Note cannot predict exact size since opposite nPoints might
318 // be different from one over here.
319 IPstream fromNeighbProc(Pstream::blocking, neighbProcNo());
328 // Convert neighbour faces and indices into face back into
329 // my edges and points.
334 neighbPointsPtr_ = new labelList(nPoints(), -1);
335 labelList& neighbPoints = *neighbPointsPtr_;
337 forAll(nbrPointFace, nbrPointI)
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)
346 // First reference of point
347 neighbPoints[patchPointI] = nbrPointI;
349 else if (neighbPoints[patchPointI] >= 0)
351 // Point already visited. Mark as duplicate.
352 neighbPoints[patchPointI] = -2;
356 // Reset all duplicate entries to -1.
357 forAll(neighbPoints, patchPointI)
359 if (neighbPoints[patchPointI] == -2)
361 neighbPoints[patchPointI] = -1;
368 neighbEdgesPtr_ = new labelList(nEdges(), -1);
369 labelList& neighbEdges = *neighbEdgesPtr_;
371 forAll(nbrEdgeFace, nbrEdgeI)
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)
380 // First reference of edge
381 neighbEdges[patchEdgeI] = nbrEdgeI;
383 else if (neighbEdges[patchEdgeI] >= 0)
385 // Edge already visited. Mark as duplicate.
386 neighbEdges[patchEdgeI] = -2;
390 // Reset all duplicate entries to -1.
391 forAll(neighbEdges, patchEdgeI)
393 if (neighbEdges[patchEdgeI] == -2)
395 neighbEdges[patchEdgeI] = -1;
399 // Remove any addressing used for shared points/edges calculation
400 primitivePatch::clearOut();
405 const Foam::labelList& Foam::processorPolyPatch::neighbPoints() const
407 if (!neighbPointsPtr_)
409 FatalErrorIn("processorPolyPatch::neighbPoints() const")
410 << "No extended addressing calculated for patch " << name()
411 << abort(FatalError);
413 return *neighbPointsPtr_;
417 const Foam::labelList& Foam::processorPolyPatch::neighbEdges() const
419 if (!neighbEdgesPtr_)
421 FatalErrorIn("processorPolyPatch::neighbEdges() const")
422 << "No extended addressing calculated for patch " << name()
423 << abort(FatalError);
425 return *neighbEdgesPtr_;
429 void Foam::processorPolyPatch::initOrder(const primitivePatch& pp) const
431 if (!Pstream::parRun())
440 boundaryMesh().mesh().time().path()
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()));
452 boundaryMesh().mesh().time().path()
453 /name() + "_localFaceCentres.obj"
455 Pout<< "processorPolyPatch::order : "
456 << "Dumping " << ctrs.size()
457 << " local faceCentres to " << localStr.name() << endl;
461 writeOBJ(localStr, ctrs[faceI]);
465 const bool isMaster = Pstream::myProcNo() < neighbProcNo();
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;
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,
491 if (!Pstream::parRun())
496 faceMap.setSize(pp.size());
499 rotation.setSize(pp.size());
502 const bool isMaster = Pstream::myProcNo() < neighbProcNo();
506 // Do nothing (i.e. identical mapping, zero rotation).
507 // See comment at top.
508 forAll(faceMap, patchFaceI)
510 faceMap[patchFaceI] = patchFaceI;
517 vectorField masterCtrs;
518 vectorField masterAnchors;
520 // Receive data from neighbour
522 IPstream fromNeighbour(Pstream::blocking, neighbProcNo());
523 fromNeighbour >> masterCtrs >> masterAnchors;
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())
537 boundaryMesh().mesh().time().path()
538 /name() + "_nbrFaceCentres.obj"
540 Pout<< "processorPolyPatch::order : "
541 << "Dumping neighbour faceCentres to " << nbrStr.name()
543 forAll(masterCtrs, faceI)
545 writeOBJ(nbrStr, masterCtrs[faceI]);
549 if (masterCtrs.size() != pp.size())
553 "processorPolyPatch::order(const primitivePatch&"
554 ", labelList&, labelList&) const"
555 ) << "in patch:" << name() << " : "
556 << "Local size of patch is " << pp.size() << " (faces)."
558 << "Received from neighbour " << masterCtrs.size()
560 << abort(FatalError);
564 // Geometric match of face centre vectors
565 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
567 // 1. Try existing ordering and transformation
568 bool matchedAll = false;
573 && (separation().size() == 1 || separation().size() == pp.size())
576 vectorField transformedCtrs;
578 const vectorField& v = separation();
582 transformedCtrs = masterCtrs-v[0];
586 transformedCtrs = masterCtrs-v;
588 matchedAll = matchPoints
599 // Use transformed centers from now on
600 masterCtrs = transformedCtrs;
605 masterAnchors -= v[0];
616 && (forwardT().size() == 1 || forwardT().size() == pp.size())
619 vectorField transformedCtrs = masterCtrs;
620 transformList(forwardT(), transformedCtrs);
621 matchedAll = matchPoints
632 // Use transformed centers from now on
633 masterCtrs = transformedCtrs;
636 transformList(forwardT(), masterAnchors);
641 // 2. Try zero separation automatic matching
644 matchedAll = matchPoints(ctrs, masterCtrs, tols, true, faceMap);
647 if (!matchedAll || debug)
652 boundaryMesh().mesh().time().path()
653 /name()/name()+"_faces.obj"
655 Pout<< "processorPolyPatch::order :"
656 << " Writing faces to OBJ file " << str.name() << endl;
657 writeOBJ(str, pp, pp.points());
661 boundaryMesh().mesh().time().path()
662 /name() + "_faceCentresConnections.obj"
665 Pout<< "processorPolyPatch::order :"
666 << " Dumping newly found match as lines between"
667 << " corresponding face centres to OBJ file " << ccStr.name()
674 label masterFaceI = faceMap[faceI];
676 if (masterFaceI != -1)
678 const point& c0 = masterCtrs[masterFaceI];
679 const point& c1 = ctrs[faceI];
680 writeOBJ(ccStr, c0, c1, vertI);
689 "processorPolyPatch::order(const primitivePatch&"
690 ", labelList&, labelList&) const"
691 ) << "in patch:" << name() << " : "
692 << "Cannot match vectors to faces on both sides of patch"
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"
699 << " Continuing with incorrect face ordering from now on!"
706 forAll(faceMap, oldFaceI)
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
724 if (rotation[newFaceI] == -1)
728 "processorPolyPatch::order(const primitivePatch&"
729 ", labelList&, labelList&) const"
730 ) << "in patch " << name()
732 << "Cannot find point on face " << pp[oldFaceI]
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!"
744 forAll(faceMap, faceI)
746 if (faceMap[faceI] != faceI || rotation[faceI] != 0)
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 // ************************************************************************* //