1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2010 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
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 "polyBoundaryMesh.H"
27 #include <OpenFOAM/polyMesh.H>
28 #include <OpenFOAM/primitiveMesh.H>
29 #include <OpenFOAM/processorPolyPatch.H>
30 #include <OpenFOAM/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 forAll(*this, patchi)
148 operator[](patchi).initGeometry();
151 forAll(*this, patchi)
153 operator[](patchi).calcGeometry();
158 const Foam::List<Foam::labelPairList>&
159 Foam::polyBoundaryMesh::neighbourEdges() const
161 if (Pstream::parRun())
163 WarningIn("polyBoundaryMesh::neighbourEdges() const")
164 << "Neighbour edge addressing not correct across parallel"
165 << " boundaries." << endl;
168 if (!neighbourEdgesPtr_)
170 neighbourEdgesPtr_ = new List<labelPairList>(size());
171 List<labelPairList>& neighbourEdges = *neighbourEdgesPtr_;
174 label nEdgePairs = 0;
175 forAll(*this, patchi)
177 const polyPatch& pp = operator[](patchi);
179 neighbourEdges[patchi].setSize(pp.nEdges() - pp.nInternalEdges());
181 forAll(neighbourEdges[patchi], i)
183 labelPair& edgeInfo = neighbourEdges[patchi][i];
189 nEdgePairs += pp.nEdges() - pp.nInternalEdges();
192 // From mesh edge (expressed as a point pair so as not to construct
193 // point addressing) to patch + relative edge index.
194 HashTable<labelPair, edge, Hash<edge> > pointsToEdge(nEdgePairs);
196 forAll(*this, patchi)
198 const polyPatch& pp = operator[](patchi);
200 const edgeList& edges = pp.edges();
204 label edgei = pp.nInternalEdges();
205 edgei < edges.size();
209 // Edge in patch local points
210 const edge& e = edges[edgei];
212 // Edge in mesh points.
213 edge meshEdge(pp.meshPoints()[e[0]], pp.meshPoints()[e[1]]);
215 HashTable<labelPair, edge, Hash<edge> >::iterator fnd =
216 pointsToEdge.find(meshEdge);
218 if (fnd == pointsToEdge.end())
220 // First occurrence of mesh edge. Store patch and my
228 edgei - pp.nInternalEdges()
234 // Second occurrence. Store.
235 const labelPair& edgeInfo = fnd();
237 neighbourEdges[patchi][edgei - pp.nInternalEdges()] =
240 neighbourEdges[edgeInfo[0]][edgeInfo[1]]
241 = labelPair(patchi, edgei - pp.nInternalEdges());
243 // Found all two occurrences of this edge so remove from
244 // hash to save space. Note that this will give lots of
245 // problems if the polyBoundaryMesh is multiply connected.
246 pointsToEdge.erase(meshEdge);
251 if (pointsToEdge.size())
253 FatalErrorIn("polyBoundaryMesh::neighbourEdges() const")
254 << "Not all boundary edges of patches match up." << nl
255 << "Is the outside of your mesh multiply connected?"
256 << abort(FatalError);
259 forAll(*this, patchi)
261 const polyPatch& pp = operator[](patchi);
263 const labelPairList& nbrEdges = neighbourEdges[patchi];
267 const labelPair& edgeInfo = nbrEdges[i];
269 if (edgeInfo[0] == -1 || edgeInfo[1] == -1)
271 label edgeI = pp.nInternalEdges() + i;
272 const edge& e = pp.edges()[edgeI];
274 FatalErrorIn("polyBoundaryMesh::neighbourEdges() const")
275 << "Not all boundary edges of patches match up." << nl
276 << "Edge " << edgeI << " on patch " << pp.name()
277 << " end points " << pp.localPoints()[e[0]] << ' '
278 << pp.localPoints()[e[1]] << " is not matched to an"
279 << " edge on any other patch." << nl
280 << "Is the outside of your mesh multiply connected?"
281 << abort(FatalError);
287 return *neighbourEdgesPtr_;
291 Foam::wordList Foam::polyBoundaryMesh::names() const
293 const polyPatchList& patches = *this;
295 wordList t(patches.size());
297 forAll (patches, patchI)
299 t[patchI] = patches[patchI].name();
306 Foam::wordList Foam::polyBoundaryMesh::types() const
308 const polyPatchList& patches = *this;
310 wordList t(patches.size());
312 forAll (patches, patchI)
314 t[patchI] = patches[patchI].type();
321 Foam::wordList Foam::polyBoundaryMesh::physicalTypes() const
323 const polyPatchList& patches = *this;
325 wordList t(patches.size());
327 forAll (patches, patchI)
329 t[patchI] = patches[patchI].physicalType();
336 Foam::label Foam::polyBoundaryMesh::findPatchID(const word& patchName) const
338 const polyPatchList& patches = *this;
340 forAll (patches, patchI)
342 if (patches[patchI].name() == patchName)
351 Pout<< "label polyBoundaryMesh::findPatchID(const word& "
352 << "patchName) const"
353 << "Patch named " << patchName << " not found. "
354 << "List of available patch names: " << names() << endl;
357 // Not found, return -1
362 Foam::label Foam::polyBoundaryMesh::whichPatch(const label faceIndex) const
364 // Find out which patch the current face belongs to by comparing label
365 // with patch start labels.
366 // If the face is internal, return -1;
367 // if it is off the end of the list, abort
368 if (faceIndex >= mesh().nFaces())
372 "polyBoundaryMesh::whichPatch(const label faceIndex) const"
373 ) << "given label greater than the number of geometric faces"
374 << abort(FatalError);
377 if (faceIndex < mesh().nInternalFaces())
382 forAll (*this, patchI)
384 const polyPatch& bp = operator[](patchI);
388 faceIndex >= bp.start()
389 && faceIndex < bp.start() + bp.size()
396 // If not in any of above, it is trouble!
399 "label polyBoundaryMesh::whichPatch(const label faceIndex) const"
400 ) << "Cannot find face " << faceIndex << " in any of the patches "
402 << "It seems your patches are not consistent with the mesh :"
403 << " internalFaces:" << mesh().nInternalFaces()
404 << " total number of faces:" << mesh().nFaces()
405 << abort(FatalError);
411 Foam::labelHashSet Foam::polyBoundaryMesh::patchSet
413 const wordList& patchNames
416 wordList allPatchNames = names();
417 labelHashSet ps(size());
419 forAll(patchNames, i)
421 // Treat the given patch names as wild-cards and search the set
422 // of all patch names for matches
423 labelList patchIDs = findStrings(patchNames[i], allPatchNames);
425 if (patchIDs.empty())
427 WarningIn("polyBoundaryMesh::patchSet(const wordList&)")
428 << "Cannot find any patch names matching " << patchNames[i]
434 ps.insert(patchIDs[j]);
442 bool Foam::polyBoundaryMesh::checkParallelSync(const bool report) const
444 if (!Pstream::parRun())
450 const polyBoundaryMesh& bm = *this;
452 bool boundaryError = false;
454 // Collect non-proc patches and check proc patches are last.
455 wordList names(bm.size());
456 wordList types(bm.size());
462 if (!isA<processorPolyPatch>(bm[patchI]))
464 if (nonProcI != patchI)
466 // There is processor patch inbetween normal patches.
467 boundaryError = true;
471 Pout<< " ***Problem with boundary patch " << patchI
472 << " named " << bm[patchI].name()
473 << " of type " << bm[patchI].type()
474 << ". The patch seems to be preceded by processor"
475 << " patches. This is can give problems."
481 names[nonProcI] = bm[patchI].name();
482 types[nonProcI] = bm[patchI].type();
487 names.setSize(nonProcI);
488 types.setSize(nonProcI);
490 List<wordList> allNames(Pstream::nProcs());
491 allNames[Pstream::myProcNo()] = names;
492 Pstream::gatherList(allNames);
493 Pstream::scatterList(allNames);
495 List<wordList> allTypes(Pstream::nProcs());
496 allTypes[Pstream::myProcNo()] = types;
497 Pstream::gatherList(allTypes);
498 Pstream::scatterList(allTypes);
500 // Have every processor check but only master print error.
502 for (label procI = 1; procI < allNames.size(); procI++)
506 (allNames[procI] != allNames[0])
507 || (allTypes[procI] != allTypes[0])
510 boundaryError = true;
512 if (debug || (report && Pstream::master()))
514 Info<< " ***Inconsistent patches across processors, "
515 "processor 0 has patch names:" << allNames[0]
516 << " patch types:" << allTypes[0]
517 << " processor " << procI << " has patch names:"
519 << " patch types:" << allTypes[procI]
525 return boundaryError;
529 bool Foam::polyBoundaryMesh::checkDefinition(const bool report) const
531 label nextPatchStart = mesh().nInternalFaces();
532 const polyBoundaryMesh& bm = *this;
534 bool boundaryError = false;
538 if (bm[patchI].start() != nextPatchStart && !boundaryError)
540 boundaryError = true;
542 Info<< " ****Problem with boundary patch " << patchI
543 << " named " << bm[patchI].name()
544 << " of type " << bm[patchI].type()
545 << ". The patch should start on face no " << nextPatchStart
546 << " and the patch specifies " << bm[patchI].start()
548 << "Possibly consecutive patches have this same problem."
549 << " Suppressing future warnings." << endl;
552 nextPatchStart += bm[patchI].size();
555 reduce(boundaryError, orOp<bool>());
561 Pout << " ***Boundary definition is in error." << endl;
570 Info << " Boundary definition OK." << endl;
578 void Foam::polyBoundaryMesh::movePoints(const pointField& p)
580 polyPatchList& patches = *this;
582 forAll(patches, patchi)
584 patches[patchi].initMovePoints(p);
587 forAll(patches, patchi)
589 patches[patchi].movePoints(p);
594 void Foam::polyBoundaryMesh::updateMesh()
596 deleteDemandDrivenData(neighbourEdgesPtr_);
598 polyPatchList& patches = *this;
600 forAll(patches, patchi)
602 patches[patchi].initUpdateMesh();
605 forAll(patches, patchi)
607 patches[patchi].updateMesh();
612 void Foam::polyBoundaryMesh::reorder(const UList<label>& oldToNew)
614 // Change order of patches
615 polyPatchList::reorder(oldToNew);
618 polyPatchList& patches = *this;
620 forAll(patches, patchi)
622 patches[patchi].index() = patchi;
629 bool Foam::polyBoundaryMesh::writeData(Ostream& os) const
631 const polyPatchList& patches = *this;
633 os << patches.size() << nl << token::BEGIN_LIST << incrIndent << nl;
635 forAll(patches, patchi)
637 os << indent << patches[patchi].name() << nl
638 << indent << token::BEGIN_BLOCK << nl
639 << incrIndent << patches[patchi] << decrIndent
640 << indent << token::END_BLOCK << endl;
643 os << decrIndent << token::END_LIST;
645 // Check state of IOstream
646 os.check("polyBoundaryMesh::writeData(Ostream& os) const");
652 bool Foam::polyBoundaryMesh::writeObject
654 IOstream::streamFormat fmt,
655 IOstream::versionNumber ver,
656 IOstream::compressionType cmp
659 return regIOobject::writeObject(fmt, ver, IOstream::UNCOMPRESSED);
663 // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
665 Foam::Ostream& Foam::operator<<(Ostream& os, const polyBoundaryMesh& pbm)
672 // ************************ vim: set sw=4 sts=4 et: ************************ //