/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation Copyright (C) 2018-2022 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. OpenFOAM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenFOAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . \*---------------------------------------------------------------------------*/ #include "polyBoundaryMesh.H" #include "polyMesh.H" #include "primitiveMesh.H" #include "processorPolyPatch.H" #include "PstreamBuffers.H" #include "lduSchedule.H" #include "globalMeshData.H" #include "stringListOps.H" #include "DynamicList.H" #include "PtrListOps.H" #include "edgeHashes.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // namespace Foam { defineTypeNameAndDebug(polyBoundaryMesh, 0); } // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // bool Foam::polyBoundaryMesh::hasGroupIDs() const { if (groupIDsPtr_) { // Use existing cache return !groupIDsPtr_->empty(); } const polyPatchList& patches = *this; for (const polyPatch& p : patches) { if (!p.inGroups().empty()) { return true; } } return false; } void Foam::polyBoundaryMesh::calcGroupIDs() const { if (groupIDsPtr_) { return; // Or FatalError } groupIDsPtr_.reset(new HashTable(16)); auto& groupLookup = *groupIDsPtr_; const polyPatchList& patches = *this; forAll(patches, patchi) { const wordList& groups = patches[patchi].inGroups(); for (const word& groupName : groups) { groupLookup(groupName).append(patchi); } } // Remove groups that clash with patch names forAll(patches, patchi) { if (groupLookup.erase(patches[patchi].name())) { WarningInFunction << "Removed group '" << patches[patchi].name() << "' which clashes with patch " << patchi << " of the same name." << endl; } } } bool Foam::polyBoundaryMesh::readContents(const bool allowReadIfPresent) { if ( this->isReadRequired() || (allowReadIfPresent && this->isReadOptional() && this->headerOk()) ) { // Warn for MUST_READ_IF_MODIFIED warnNoRereading(); polyPatchList& patches = *this; // Read polyPatchList Istream& is = readStream(typeName); // Read patches as entries PtrList patchEntries(is); patches.resize(patchEntries.size()); // Transcribe forAll(patches, patchi) { patches.set ( patchi, polyPatch::New ( patchEntries[patchi].keyword(), patchEntries[patchi].dict(), patchi, *this ) ); } is.check(FUNCTION_NAME); close(); return true; } return false; } // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::polyBoundaryMesh::polyBoundaryMesh ( const IOobject& io, const polyMesh& mesh ) : polyPatchList(), regIOobject(io), mesh_(mesh) { readContents(false); // READ_IF_PRESENT allowed: False } Foam::polyBoundaryMesh::polyBoundaryMesh ( const IOobject& io, const polyMesh& pm, const label size ) : polyPatchList(size), regIOobject(io), mesh_(pm) {} Foam::polyBoundaryMesh::polyBoundaryMesh ( const IOobject& io, const polyMesh& pm, const polyPatchList& ppl ) : polyPatchList(), regIOobject(io), mesh_(pm) { if (!readContents(true)) // READ_IF_PRESENT allowed: True { polyPatchList& patches = *this; patches.resize(ppl.size()); forAll(patches, patchi) { patches.set(patchi, ppl[patchi].clone(*this)); } } } // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // void Foam::polyBoundaryMesh::clearGeom() { polyPatchList& patches = *this; for (polyPatch& p : patches) { p.clearGeom(); } } void Foam::polyBoundaryMesh::clearAddressing() { neighbourEdgesPtr_.clear(); patchIDPtr_.clear(); groupIDsPtr_.clear(); polyPatchList& patches = *this; for (polyPatch& p : patches) { p.clearAddressing(); } } // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // void Foam::polyBoundaryMesh::calcGeometry() { PstreamBuffers pBufs(Pstream::defaultCommsType); if ( pBufs.commsType() == Pstream::commsTypes::blocking || pBufs.commsType() == Pstream::commsTypes::nonBlocking ) { forAll(*this, patchi) { operator[](patchi).initGeometry(pBufs); } pBufs.finishedSends(); forAll(*this, patchi) { operator[](patchi).calcGeometry(pBufs); } } else if (pBufs.commsType() == Pstream::commsTypes::scheduled) { const lduSchedule& patchSchedule = mesh().globalData().patchSchedule(); // Dummy. pBufs.finishedSends(); for (const auto& schedEval : patchSchedule) { const label patchi = schedEval.patch; if (schedEval.init) { operator[](patchi).initGeometry(pBufs); } else { operator[](patchi).calcGeometry(pBufs); } } } } Foam::UPtrList Foam::polyBoundaryMesh::faceCells() const { const polyPatchList& patches = *this; UPtrList list(patches.size()); forAll(patches, patchi) { list.set(patchi, &patches[patchi].faceCells()); } return list; } const Foam::List& Foam::polyBoundaryMesh::neighbourEdges() const { if (Pstream::parRun()) { WarningInFunction << "Neighbour edge addressing not correct across parallel" << " boundaries." << endl; } if (!neighbourEdgesPtr_) { neighbourEdgesPtr_.reset(new List(size())); auto& neighbourEdges = *neighbourEdgesPtr_; // Initialize. label nEdgePairs = 0; forAll(*this, patchi) { const polyPatch& pp = operator[](patchi); neighbourEdges[patchi].setSize(pp.nEdges() - pp.nInternalEdges()); for (labelPair& edgeInfo : neighbourEdges[patchi]) { edgeInfo[0] = -1; edgeInfo[1] = -1; } nEdgePairs += pp.nEdges() - pp.nInternalEdges(); } // From mesh edge (expressed as a point pair so as not to construct // point addressing) to patch + relative edge index. EdgeMap pointsToEdge(nEdgePairs); forAll(*this, patchi) { const polyPatch& pp = operator[](patchi); const edgeList& edges = pp.edges(); for ( label edgei = pp.nInternalEdges(); edgei < edges.size(); edgei++ ) { // Edge in patch local points const edge& e = edges[edgei]; // Edge in mesh points. edge meshEdge(pp.meshPoints()[e[0]], pp.meshPoints()[e[1]]); auto fnd = pointsToEdge.find(meshEdge); if (!fnd.found()) { // First occurrence of mesh edge. Store patch and my // local index. pointsToEdge.insert ( meshEdge, labelPair ( patchi, edgei - pp.nInternalEdges() ) ); } else { // Second occurrence. Store. const labelPair& edgeInfo = fnd.val(); neighbourEdges[patchi][edgei - pp.nInternalEdges()] = edgeInfo; neighbourEdges[edgeInfo[0]][edgeInfo[1]] = labelPair(patchi, edgei - pp.nInternalEdges()); // Found all two occurrences of this edge so remove from // hash to save space. Note that this will give lots of // problems if the polyBoundaryMesh is multiply connected. pointsToEdge.erase(meshEdge); } } } if (pointsToEdge.size()) { FatalErrorInFunction << "Not all boundary edges of patches match up." << nl << "Is the outside of your mesh multiply connected?" << abort(FatalError); } forAll(*this, patchi) { const polyPatch& pp = operator[](patchi); const labelPairList& nbrEdges = neighbourEdges[patchi]; forAll(nbrEdges, i) { const labelPair& edgeInfo = nbrEdges[i]; if (edgeInfo[0] == -1 || edgeInfo[1] == -1) { const label edgei = pp.nInternalEdges() + i; const edge& e = pp.edges()[edgei]; FatalErrorInFunction << "Not all boundary edges of patches match up." << nl << "Edge " << edgei << " on patch " << pp.name() << " end points " << pp.localPoints()[e[0]] << ' ' << pp.localPoints()[e[1]] << " is not matched to an" << " edge on any other patch." << nl << "Is the outside of your mesh multiply connected?" << abort(FatalError); } } } } return *neighbourEdgesPtr_; } const Foam::labelList& Foam::polyBoundaryMesh::patchID() const { if (!patchIDPtr_) { patchIDPtr_.reset(new labelList(mesh_.nBoundaryFaces())); labelList& list = *patchIDPtr_; const polyPatchList& patches = *this; forAll(patches, patchi) { SubList