/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2023 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 "faceZone.H"
#include "addToRunTimeSelectionTable.H"
#include "faceZoneMesh.H"
#include "polyMesh.H"
#include "primitiveMesh.H"
#include "mapPolyMesh.H"
#include "syncTools.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(faceZone, 0);
defineRunTimeSelectionTable(faceZone, dictionary);
addToRunTimeSelectionTable(faceZone, faceZone, dictionary);
}
const char* const Foam::faceZone::labelsName = "faceLabels";
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::faceZone::setFlipMap(const bool val)
{
// Match size for flipMap
flipMap_.resize_nocopy(this->size());
flipMap_ = val;
}
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
void Foam::faceZone::calcFaceZonePatch() const
{
DebugInFunction << "Calculating primitive patch" << endl;
if (patchPtr_)
{
FatalErrorInFunction
<< "primitive face zone patch already calculated"
<< abort(FatalError);
}
patchPtr_.reset
(
new primitiveFacePatch
(
faceList(size()),
zoneMesh().mesh().points()
)
);
auto& patch = *patchPtr_;
const faceList& f = zoneMesh().mesh().faces();
const labelList& addr = *this;
const boolList& flips = flipMap();
forAll(addr, facei)
{
if (flips[facei])
{
patch[facei] = f[addr[facei]].reverseFace();
}
else
{
patch[facei] = f[addr[facei]];
}
}
DebugInfo << "Finished calculating primitive patch" << endl;
}
void Foam::faceZone::calcCellLayers() const
{
DebugInFunction << "Calculating cell layers" << endl;
if (frontCellsPtr_ || backCellsPtr_)
{
FatalErrorInFunction
<< "cell layers already calculated"
<< abort(FatalError);
}
else
{
// Go through all the faces in the zone.
// Choose the front/back cell based on the face flip
const labelList& own = zoneMesh().mesh().faceOwner();
const labelList& nei = zoneMesh().mesh().faceNeighbour();
const labelList& addr = *this;
const boolList& flips = flipMap();
frontCellsPtr_.reset(new labelList(addr.size()));
backCellsPtr_.reset(new labelList(addr.size()));
auto& fronts = *frontCellsPtr_;
auto& backs = *backCellsPtr_;
forAll(addr, facei)
{
const label ownCelli = own[addr[facei]];
const label neiCelli =
(
zoneMesh().mesh().isInternalFace(addr[facei])
? nei[addr[facei]]
: -1
);
if (flips[facei])
{
fronts[facei] = ownCelli;
backs[facei] = neiCelli;
}
else
{
fronts[facei] = neiCelli;
backs[facei] = ownCelli;
}
}
}
}
// Foam::label Foam::faceZone::getLayerCell
// (
// const side which,
// const label i
// ) const
// {
// const label facei = labelList::operator[](i);
// const bool flipped = flipMap_[i];
//
// if (which == side::FRONT ? flipped : !flipped)
// {
// return zoneMesh().mesh().faceOwner()[facei];
// }
// else if (zoneMesh().mesh().isInternalFace(facei))
// {
// return zoneMesh().mesh().faceNeighbour()[facei];
// }
// else
// {
// return -1;
// }
// }
//
//
// Foam::label Foam::faceZone::frontCell(const label i) const
// {
// return getLayerCell(side::FRONT, i);
// }
//
//
// Foam::label Foam::faceZone::backCell(const label i) const
// {
// return getLayerCell(side::BACK, i);
// }
void Foam::faceZone::checkAddressing() const
{
const labelList& addr = *this;
if (addr.size() != flipMap_.size())
{
FatalErrorInFunction
<< "Size of addressing: " << addr.size()
<< " size of flip map: " << flipMap_.size()
<< abort(FatalError);
}
// Note: nFaces, nCells might not be set yet on mesh so use owner size
const label nFaces = zoneMesh().mesh().faceOwner().size();
for (const label facei : addr)
{
if (facei < 0 || facei >= nFaces)
{
WarningInFunction
<< "Illegal face index " << facei
<< " outside range 0.." << nFaces-1 << endl;
break; // Only report once
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::faceZone::faceZone(const faceZoneMesh& zm)
:
faceZone(word::null, 0, zm)
{}
Foam::faceZone::faceZone
(
const word& name,
const label index,
const faceZoneMesh& zm
)
:
zone(name, index),
zoneMesh_(zm)
{}
Foam::faceZone::faceZone
(
const word& name,
const labelUList& addr,
const bool flipMapValue,
const label index,
const faceZoneMesh& zm
)
:
faceZone(name, index, zm)
{
labelList::operator=(addr);
flipMap_.resize(labelList::size(), flipMapValue);
checkAddressing();
}
Foam::faceZone::faceZone
(
const word& name,
labelList&& addr,
const bool flipMapValue,
const label index,
const faceZoneMesh& zm
)
:
faceZone(name, index, zm)
{
labelList::transfer(addr);
flipMap_.resize(labelList::size(), flipMapValue);
checkAddressing();
}
Foam::faceZone::faceZone
(
const word& name,
const labelUList& addr,
const boolUList& fm,
const label index,
const faceZoneMesh& zm
)
:
faceZone(name, index, zm)
{
labelList::operator=(addr);
flipMap_ = fm;
// TBD
// if (flipMap_.empty())
// {
// // An empty flipMap is treated like 'false' instead of as an error
// flipMap_.resize(labelList::size(), false);
// }
checkAddressing();
}
Foam::faceZone::faceZone
(
const word& name,
labelList&& addr,
boolList&& fm,
const label index,
const faceZoneMesh& zm
)
:
faceZone(name, index, zm)
{
labelList::transfer(addr);
flipMap_.transfer(fm);
// TBD
// if (flipMap_.empty())
// {
// // An empty flipMap is treated like 'false' instead of as an error
// flipMap_.resize(labelList::size(), false);
// }
checkAddressing();
}
Foam::faceZone::faceZone
(
const word& name,
const dictionary& dict,
const label index,
const faceZoneMesh& zm
)
:
zone(name, dict, this->labelsName, index),
flipMap_(dict.lookup("flipMap")), // OR: dict.get("flipMap")
zoneMesh_(zm)
{
checkAddressing();
}
Foam::faceZone::faceZone
(
const faceZone& originalZone,
const Foam::zero,
const faceZoneMesh& zm,
const label newIndex
)
:
zone(originalZone, labelList(), newIndex),
zoneMesh_(zm)
{}
Foam::faceZone::faceZone
(
const faceZone& originalZone,
const Foam::zero,
const label index,
const faceZoneMesh& zm
)
:
zone(originalZone, labelList(), index),
zoneMesh_(zm)
{}
Foam::faceZone::faceZone
(
const faceZone& originalZone,
const labelUList& addr,
const boolUList& fm,
const label index,
const faceZoneMesh& zm
)
:
faceZone(originalZone, Foam::zero{}, index, zm)
{
labelList::operator=(addr);
flipMap_ = fm;
checkAddressing();
}
Foam::faceZone::faceZone
(
const faceZone& originalZone,
labelList&& addr,
boolList&& fm,
const label index,
const faceZoneMesh& zm
)
:
faceZone(originalZone, Foam::zero{}, index, zm)
{
labelList::transfer(addr);
flipMap_.transfer(fm);
checkAddressing();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::label Foam::faceZone::whichFace(const label globalFaceID) const
{
return zone::localID(globalFaceID);
}
const Foam::primitiveFacePatch& Foam::faceZone::patch() const
{
if (!patchPtr_)
{
calcFaceZonePatch();
}
return *patchPtr_;
}
const Foam::labelList& Foam::faceZone::frontCells() const
{
if (!frontCellsPtr_)
{
calcCellLayers();
}
return *frontCellsPtr_;
}
const Foam::labelList& Foam::faceZone::backCells() const
{
if (!backCellsPtr_)
{
calcCellLayers();
}
return *backCellsPtr_;
}
const Foam::labelList& Foam::faceZone::meshEdges() const
{
if (!mePtr_)
{
mePtr_.reset
(
new labelList
(
this->patch().meshEdges
(
zoneMesh().mesh().edges(),
zoneMesh().mesh().pointEdges()
)
)
);
}
return *mePtr_;
}
void Foam::faceZone::clearGeom()
{
patchPtr_.reset(nullptr);
frontCellsPtr_.reset(nullptr);
backCellsPtr_.reset(nullptr);
mePtr_.reset(nullptr);
}
void Foam::faceZone::clearAddressing()
{
zone::clearAddressing();
clearGeom();
}
void Foam::faceZone::clearPrimitives()
{
zone::clearPrimitives();
flipMap_.clear();
}
void Foam::faceZone::resetAddressing(faceZone&& zn)
{
// TDB: clearGeom();
if (this == &zn)
{
return; // Self-assignment is a no-op
}
clearAddressing();
labelList::transfer(static_cast(zn));
flipMap_.transfer(zn.flipMap_);
zn.clearAddressing();
}
void Foam::faceZone::resetAddressing(const faceZone& zn)
{
// TDB: clearGeom();
if (this == &zn)
{
return; // Self-assignment is a no-op
}
clearAddressing();
labelList::operator=(static_cast(zn));
flipMap_ = zn.flipMap_;
}
void Foam::faceZone::resetAddressing
(
const labelUList& addr,
const bool flipMapValue
)
{
clearAddressing();
labelList::operator=(addr);
setFlipMap(flipMapValue);
}
void Foam::faceZone::resetAddressing
(
labelList&& addr,
const bool flipMapValue
)
{
clearAddressing();
labelList::transfer(addr);
setFlipMap(flipMapValue);
}
void Foam::faceZone::resetAddressing
(
const labelUList& addr,
const boolUList& flipMap
)
{
clearAddressing();
labelList::operator=(addr);
flipMap_ = flipMap;
}
void Foam::faceZone::updateMesh(const mapPolyMesh& mpm)
{
clearAddressing();
labelList newAddressing(size());
boolList newFlipMap(flipMap_.size());
label nFaces = 0;
const labelList& addr = *this;
const boolList& flips = flipMap();
const labelList& faceMap = mpm.reverseFaceMap();
forAll(addr, i)
{
const label facei = addr[i];
if (faceMap[facei] >= 0)
{
newAddressing[nFaces] = faceMap[facei];
newFlipMap[nFaces] = flips[i]; // Keep flip map
++nFaces;
}
}
newAddressing.resize(nFaces);
newFlipMap.resize(nFaces);
labelList::transfer(newAddressing);
flipMap_.transfer(newFlipMap);
}
bool Foam::faceZone::checkDefinition(const bool report) const
{
return zone::checkDefinition(zoneMesh().mesh().faces().size(), report);
}
bool Foam::faceZone::checkParallelSync(const bool report) const
{
const polyMesh& mesh = zoneMesh().mesh();
const polyBoundaryMesh& bm = mesh.boundaryMesh();
bool hasError = false;
// Check that zone faces are synced
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{
const labelList& addr = *this;
const boolList& flips = flipMap();
boolList neiZoneFace(mesh.nBoundaryFaces(), false);
boolList neiZoneFlip(mesh.nBoundaryFaces(), false);
forAll(addr, i)
{
const label facei = addr[i];
if (!mesh.isInternalFace(facei))
{
const label bFacei = facei-mesh.nInternalFaces();
neiZoneFace[bFacei] = true;
neiZoneFlip[bFacei] = flips[i];
}
}
boolList myZoneFace(neiZoneFace);
boolList myZoneFlip(neiZoneFlip);
syncTools::swapBoundaryFaceList(mesh, neiZoneFace);
syncTools::swapBoundaryFaceList(mesh, neiZoneFlip);
forAll(addr, i)
{
const label facei = addr[i];
const label patchi = bm.whichPatch(facei);
if (patchi != -1 && bm[patchi].coupled())
{
const label bFacei = facei-mesh.nInternalFaces();
// Check face in zone on both sides
if (myZoneFace[bFacei] != neiZoneFace[bFacei])
{
hasError = true;
if (report)
{
Pout<< " ***Problem with faceZone " << index()
<< " named " << name()
<< ". Face " << facei
<< " on coupled patch " << bm[patchi].name()
<< " is inconsistent with its coupled neighbour."
<< endl;
}
else
{
// w/o report - can stop checking now
break;
}
}
else if (myZoneFlip[bFacei] == neiZoneFlip[bFacei])
{
// Flip state should be opposite.
hasError = true;
if (report)
{
Pout<< " ***Problem with faceZone " << index()
<< " named " << name()
<< ". Face " << facei
<< " on coupled patch " << bm[patchi].name()
<< " has inconsistent flipMap across coupled faces."
<< endl;
}
else
{
// w/o report - can stop checking now
break;
}
}
}
}
}
return returnReduceOr(hasError);
}
void Foam::faceZone::movePoints(const pointField& pts)
{
if (patchPtr_)
{
patchPtr_->movePoints(pts);
}
}
void Foam::faceZone::write(Ostream& os) const
{
os << nl << name()
<< nl << static_cast(*this)
<< nl << flipMap();
}
void Foam::faceZone::writeDict(Ostream& os) const
{
os.beginBlock(name());
os.writeEntry("type", type());
zoneIdentifier::write(os);
writeEntry(this->labelsName, os);
flipMap().writeEntry("flipMap", os);
os.endBlock();
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
void Foam::faceZone::operator=(const faceZone& zn)
{
if (this == &zn)
{
return; // Self-assignment is a no-op
}
clearAddressing();
labelList::operator=(static_cast(zn));
flipMap_ = zn.flipMap_;
}
// * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * //
Foam::Ostream& Foam::operator<<(Ostream& os, const faceZone& zn)
{
zn.write(os);
os.check(FUNCTION_NAME);
return os;
}
// ************************************************************************* //