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 "polyBoundaryMesh.H"
28 #include "primitiveMesh.H"
29 #include "processorPolyPatch.H"
30 #include "stringListOps.H"
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34 defineTypeNameAndDebug(Foam::polyBoundaryMesh, 0);
37 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
39 Foam::labelList Foam::polyBoundaryMesh::ident(const label len)
50 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
52 Foam::polyBoundaryMesh::polyBoundaryMesh
61 neighbourEdgesPtr_(NULL)
63 if (readOpt() == IOobject::MUST_READ)
65 polyPatchList& patches = *this;
68 Istream& is = readStream(typeName);
70 PtrList<entry> patchEntries(is);
71 patches.setSize(patchEntries.size());
73 forAll(patches, patchI)
80 patchEntries[patchI].keyword(),
81 patchEntries[patchI].dict(),
88 // Check state of IOstream
91 "polyBoundaryMesh::polyBoundaryMesh"
92 "(const IOobject&, const polyMesh&)"
100 Foam::polyBoundaryMesh::polyBoundaryMesh
110 neighbourEdgesPtr_(NULL)
114 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
116 Foam::polyBoundaryMesh::~polyBoundaryMesh()
118 deleteDemandDrivenData(neighbourEdgesPtr_);
122 void Foam::polyBoundaryMesh::clearGeom()
124 forAll (*this, patchi)
126 operator[](patchi).clearGeom();
131 void Foam::polyBoundaryMesh::clearAddressing()
133 deleteDemandDrivenData(neighbourEdgesPtr_);
135 forAll (*this, patchi)
137 operator[](patchi).clearAddressing();
142 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
144 void Foam::polyBoundaryMesh::calcGeometry()
146 // Calculation of addressing, with communication
148 forAll(*this, patchi)
150 operator[](patchi).initAddressing();
153 forAll(*this, patchi)
155 operator[](patchi).calcAddressing();
158 // Calculation of geometry with communications
159 forAll(*this, patchi)
161 operator[](patchi).initGeometry();
164 forAll(*this, patchi)
166 operator[](patchi).calcGeometry();
171 const Foam::labelPairListList&
172 Foam::polyBoundaryMesh::neighbourEdges() const
174 if (Pstream::parRun())
176 WarningIn("polyBoundaryMesh::neighbourEdges() const")
177 << "Neighbour edge addressing not correct across parallel"
178 << " boundaries." << endl;
181 if (!neighbourEdgesPtr_)
183 neighbourEdgesPtr_ = new labelPairListList(size());
184 labelPairListList& neighbourEdges = *neighbourEdgesPtr_;
187 label nEdgePairs = 0;
188 forAll(*this, patchi)
190 const polyPatch& pp = operator[](patchi);
192 neighbourEdges[patchi].setSize(pp.nEdges() - pp.nInternalEdges());
194 forAll(neighbourEdges[patchi], i)
196 labelPair& edgeInfo = neighbourEdges[patchi][i];
202 nEdgePairs += pp.nEdges() - pp.nInternalEdges();
205 // From mesh edge (expressed as a point pair so as not to construct
206 // point addressing) to patch + relative edge index.
207 HashTable<labelPair, edge, Hash<edge> > pointsToEdge(nEdgePairs);
209 forAll(*this, patchi)
211 const polyPatch& pp = operator[](patchi);
213 const edgeList& edges = pp.edges();
217 label edgei = pp.nInternalEdges();
218 edgei < edges.size();
222 // Edge in patch local points
223 const edge& e = edges[edgei];
225 // Edge in mesh points.
226 edge meshEdge(pp.meshPoints()[e[0]], pp.meshPoints()[e[1]]);
228 HashTable<labelPair, edge, Hash<edge> >::iterator fnd =
229 pointsToEdge.find(meshEdge);
231 if (fnd == pointsToEdge.end())
233 // First occurrence of mesh edge. Store patch and my
241 edgei - pp.nInternalEdges()
247 // Second occurrence. Store.
248 const labelPair& edgeInfo = fnd();
250 neighbourEdges[patchi][edgei - pp.nInternalEdges()] =
253 neighbourEdges[edgeInfo[0]][edgeInfo[1]]
254 = labelPair(patchi, edgei - pp.nInternalEdges());
256 // Found all two occurrences of this edge so remove from
257 // hash to save space. Note that this will give lots of
258 // problems if the polyBoundaryMesh is multiply connected.
259 pointsToEdge.erase(meshEdge);
264 if (pointsToEdge.size())
266 FatalErrorIn("polyBoundaryMesh::neighbourEdges() const")
267 << "Not all boundary edges of patches match up." << nl
268 << "Is the outside of your mesh multiply connected?"
269 << abort(FatalError);
272 forAll(*this, patchi)
274 const polyPatch& pp = operator[](patchi);
276 const labelPairList& nbrEdges = neighbourEdges[patchi];
280 const labelPair& edgeInfo = nbrEdges[i];
282 if (edgeInfo[0] == -1 || edgeInfo[1] == -1)
284 label edgeI = pp.nInternalEdges() + i;
285 const edge& e = pp.edges()[edgeI];
287 FatalErrorIn("polyBoundaryMesh::neighbourEdges() const")
288 << "Not all boundary edges of patches match up." << nl
289 << "Edge " << edgeI << " on patch " << pp.name()
290 << " end points " << pp.localPoints()[e[0]] << ' '
291 << pp.localPoints()[e[1]] << " is not matched to an"
292 << " edge on any other patch." << nl
293 << "Is the outside of your mesh multiply connected?"
294 << abort(FatalError);
300 return *neighbourEdgesPtr_;
304 Foam::wordList Foam::polyBoundaryMesh::names() const
306 const polyPatchList& patches = *this;
308 wordList t(patches.size());
310 forAll (patches, patchI)
312 t[patchI] = patches[patchI].name();
319 Foam::wordList Foam::polyBoundaryMesh::types() const
321 const polyPatchList& patches = *this;
323 wordList t(patches.size());
325 forAll (patches, patchI)
327 t[patchI] = patches[patchI].type();
334 Foam::wordList Foam::polyBoundaryMesh::physicalTypes() const
336 const polyPatchList& patches = *this;
338 wordList t(patches.size());
340 forAll (patches, patchI)
342 t[patchI] = patches[patchI].physicalType();
349 Foam::label Foam::polyBoundaryMesh::findPatchID(const word& patchName) const
351 const polyPatchList& patches = *this;
353 forAll (patches, patchI)
355 // Check only if pointer is set. HJ, 28/Jan/2011
356 if (patches.set(patchI))
358 if (patches[patchI].name() == patchName)
368 Pout<< "label polyBoundaryMesh::findPatchID(const word& "
369 << "patchName) const"
370 << "Patch named " << patchName << " not found. "
371 << "List of available patch names: " << names() << endl;
374 // Not found, return -1
379 Foam::label Foam::polyBoundaryMesh::whichPatch(const label faceIndex) const
381 // Find out which patch the current face belongs to by comparing label
382 // with patch start labels.
383 // If the face is internal, return -1;
384 // if it is off the end of the list, abort
385 if (faceIndex >= mesh().nFaces())
389 "polyBoundaryMesh::whichPatch(const label faceIndex) const"
390 ) << "given label greater than the number of geometric faces"
391 << abort(FatalError);
394 if (faceIndex < mesh().nInternalFaces())
399 forAll (*this, patchI)
401 const polyPatch& bp = operator[](patchI);
405 faceIndex >= bp.start()
406 && faceIndex < bp.start() + bp.size()
413 // If not in any of above, it is trouble!
416 "label polyBoundaryMesh::whichPatch(const label faceIndex) const"
417 ) << "Cannot find face " << faceIndex << " in any of the patches "
419 << "It seems your patches are not consistent with the mesh :"
420 << " internalFaces:" << mesh().nInternalFaces()
421 << " total number of faces:" << mesh().nFaces()
422 << abort(FatalError);
428 Foam::labelHashSet Foam::polyBoundaryMesh::patchSet
430 const wordList& patchNames
433 wordList allPatchNames = names();
434 labelHashSet ps(size());
436 forAll(patchNames, i)
438 // Treat the given patch names as wild-cards and search the set
439 // of all patch names for matches
440 labelList patchIDs = findStrings(patchNames[i], allPatchNames);
442 if (patchIDs.empty())
444 WarningIn("polyBoundaryMesh::patchSet(const wordList&)")
445 << "Cannot find any patch names matching " << patchNames[i]
451 ps.insert(patchIDs[j]);
459 bool Foam::polyBoundaryMesh::checkParallelSync(const bool report) const
461 if (!Pstream::parRun())
467 const polyBoundaryMesh& bm = *this;
469 bool boundaryError = false;
471 // Collect non-proc patches and check proc patches are last.
472 wordList names(bm.size());
473 wordList types(bm.size());
479 if (!isA<processorPolyPatch>(bm[patchI]))
481 if (nonProcI != patchI)
483 // There is processor patch inbetween normal patches.
484 boundaryError = true;
488 Pout<< " ***Problem with boundary patch " << patchI
489 << " named " << bm[patchI].name()
490 << " of type " << bm[patchI].type()
491 << ". The patch seems to be preceeded by processor"
492 << " patches. This is can give problems."
498 names[nonProcI] = bm[patchI].name();
499 types[nonProcI] = bm[patchI].type();
504 names.setSize(nonProcI);
505 types.setSize(nonProcI);
507 List<wordList> allNames(Pstream::nProcs());
508 allNames[Pstream::myProcNo()] = names;
509 Pstream::gatherList(allNames);
510 Pstream::scatterList(allNames);
512 List<wordList> allTypes(Pstream::nProcs());
513 allTypes[Pstream::myProcNo()] = types;
514 Pstream::gatherList(allTypes);
515 Pstream::scatterList(allTypes);
517 // Have every processor check but only master print error.
519 for (label procI = 1; procI < allNames.size(); procI++)
523 (allNames[procI] != allNames[0])
524 || (allTypes[procI] != allTypes[0])
527 boundaryError = true;
529 if (debug || (report && Pstream::master()))
531 Info<< " ***Inconsistent patches across processors, "
532 "processor 0 has patch names:" << allNames[0]
533 << " patch types:" << allTypes[0]
534 << " processor " << procI << " has patch names:"
536 << " patch types:" << allTypes[procI]
542 return boundaryError;
546 bool Foam::polyBoundaryMesh::checkDefinition(const bool report) const
548 label nextPatchStart = mesh().nInternalFaces();
549 const polyBoundaryMesh& bm = *this;
551 bool boundaryError = false;
555 if (bm[patchI].start() != nextPatchStart && !boundaryError)
557 boundaryError = true;
559 Info<< " ****Problem with boundary patch " << patchI
560 << " named " << bm[patchI].name()
561 << " of type " << bm[patchI].type()
562 << ". The patch should start on face no " << nextPatchStart
563 << " and the patch specifies " << bm[patchI].start()
565 << "Possibly consecutive patches have this same problem."
566 << " Suppressing future warnings." << endl;
569 nextPatchStart += bm[patchI].size();
572 reduce(boundaryError, orOp<bool>());
578 Pout << " ***Boundary definition is in error." << endl;
587 Info << " Boundary definition OK." << endl;
595 void Foam::polyBoundaryMesh::movePoints(const pointField& p)
597 polyPatchList& patches = *this;
599 forAll(patches, patchi)
601 patches[patchi].initMovePoints(p);
604 forAll(patches, patchi)
606 patches[patchi].movePoints(p);
611 void Foam::polyBoundaryMesh::updateMesh()
613 deleteDemandDrivenData(neighbourEdgesPtr_);
615 polyPatchList& patches = *this;
617 forAll(patches, patchi)
619 patches[patchi].initUpdateMesh();
622 forAll(patches, patchi)
624 patches[patchi].updateMesh();
627 // Calculation of addressing, with communication
629 forAll(*this, patchi)
631 operator[](patchi).initAddressing();
634 forAll(*this, patchi)
636 operator[](patchi).calcAddressing();
639 // Calculation of geometry with communications
640 forAll(*this, patchi)
642 operator[](patchi).initGeometry();
645 forAll(*this, patchi)
647 operator[](patchi).calcGeometry();
652 void Foam::polyBoundaryMesh::reorder(const UList<label>& oldToNew)
654 // Change order of patches
655 polyPatchList::reorder(oldToNew);
658 polyPatchList& patches = *this;
660 forAll(patches, patchi)
662 patches[patchi].index() = patchi;
669 bool Foam::polyBoundaryMesh::writeData(Ostream& os) const
671 const polyPatchList& patches = *this;
673 os << patches.size() << nl << token::BEGIN_LIST << incrIndent << nl;
675 forAll(patches, patchi)
677 os << indent << patches[patchi].name() << nl
678 << indent << token::BEGIN_BLOCK << nl
679 << incrIndent << patches[patchi] << decrIndent
680 << indent << token::END_BLOCK << endl;
683 os << decrIndent << token::END_LIST;
685 // Check state of IOstream
686 os.check("polyBoundaryMesh::writeData(Ostream& os) const");
692 bool Foam::polyBoundaryMesh::writeObject
694 IOstream::streamFormat fmt,
695 IOstream::versionNumber ver,
696 IOstream::compressionType cmp
699 return regIOobject::writeObject(fmt, ver, IOstream::UNCOMPRESSED);
702 // * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * * //
704 const Foam::polyPatch& Foam::polyBoundaryMesh::operator[]
706 const word& patchName
709 const label patchI = findPatchID(patchName);
715 "polyBoundaryMesh::operator[](const word&) const"
716 ) << "Patch named " << patchName << " not found." << nl
717 << "Available patch names: " << names() << endl
718 << abort(FatalError);
721 return operator[](patchI);
725 Foam::polyPatch& Foam::polyBoundaryMesh::operator[]
727 const word& patchName
730 const label patchI = findPatchID(patchName);
736 "polyBoundaryMesh::operator[](const word&)"
737 ) << "Patch named " << patchName << " not found." << nl
738 << "Available patch names: " << names() << endl
739 << abort(FatalError);
742 return operator[](patchI);
746 // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
748 Foam::Ostream& Foam::operator<<(Ostream& os, const polyBoundaryMesh& pbm)
755 // ************************************************************************* //