/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 1991-2010 OpenCFD Ltd.
\\/ M anipulation |
-------------------------------------------------------------------------------
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 "FaceCellWave.H"
#include "polyMesh.H"
#include "processorPolyPatch.H"
#include "cyclicPolyPatch.H"
#include "OPstream.H"
#include "IPstream.H"
#include "PstreamReduceOps.H"
#include "debug.H"
#include "typeInfo.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
template
const Foam::scalar
Foam::FaceCellWave::geomTol_ = 1e-6;
template
const Foam::scalar
Foam::FaceCellWave::propagationTol_ = 0.01;
template
Foam::label Foam::FaceCellWave::dummyTrackData_ = 12345;
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
// Update info for cellI, at position pt, with information from
// neighbouring face/cell.
// Updates:
// - changedCell_, changedCells_, nChangedCells_,
// - statistics: nEvals_, nUnvisitedCells_
template
bool Foam::FaceCellWave::updateCell
(
const label cellI,
const label neighbourFaceI,
const Type& neighbourInfo,
const scalar tol,
Type& cellInfo
)
{
nEvals_++;
bool wasValid = cellInfo.valid(td_);
bool propagate =
cellInfo.updateCell
(
mesh_,
cellI,
neighbourFaceI,
neighbourInfo,
tol,
td_
);
if (propagate)
{
if (!changedCell_[cellI])
{
changedCell_[cellI] = true;
changedCells_[nChangedCells_++] = cellI;
}
}
if (!wasValid && cellInfo.valid(td_))
{
--nUnvisitedCells_;
}
return propagate;
}
// Update info for faceI, at position pt, with information from
// neighbouring face/cell.
// Updates:
// - changedFace_, changedFaces_, nChangedFaces_,
// - statistics: nEvals_, nUnvisitedFaces_
template
bool Foam::FaceCellWave::updateFace
(
const label faceI,
const label neighbourCellI,
const Type& neighbourInfo,
const scalar tol,
Type& faceInfo
)
{
nEvals_++;
bool wasValid = faceInfo.valid(td_);
bool propagate =
faceInfo.updateFace
(
mesh_,
faceI,
neighbourCellI,
neighbourInfo,
tol,
td_
);
if (propagate)
{
if (!changedFace_[faceI])
{
changedFace_[faceI] = true;
changedFaces_[nChangedFaces_++] = faceI;
}
}
if (!wasValid && faceInfo.valid(td_))
{
--nUnvisitedFaces_;
}
return propagate;
}
// Update info for faceI, at position pt, with information from
// same face.
// Updates:
// - changedFace_, changedFaces_, nChangedFaces_,
// - statistics: nEvals_, nUnvisitedFaces_
template
bool Foam::FaceCellWave::updateFace
(
const label faceI,
const Type& neighbourInfo,
const scalar tol,
Type& faceInfo
)
{
nEvals_++;
bool wasValid = faceInfo.valid(td_);
bool propagate =
faceInfo.updateFace
(
mesh_,
faceI,
neighbourInfo,
tol,
td_
);
if (propagate)
{
if (!changedFace_[faceI])
{
changedFace_[faceI] = true;
changedFaces_[nChangedFaces_++] = faceI;
}
}
if (!wasValid && faceInfo.valid(td_))
{
--nUnvisitedFaces_;
}
return propagate;
}
// For debugging: check status on both sides of cyclic
template
void Foam::FaceCellWave::checkCyclic
(
const polyPatch& patch
) const
{
const cyclicPolyPatch& nbrPatch =
refCast(patch).neighbPatch();
forAll(patch, patchFaceI)
{
label i1 = patch.start() + patchFaceI;
label i2 = nbrPatch.start() + patchFaceI;
if
(
!allFaceInfo_[i1].sameGeometry
(
mesh_,
allFaceInfo_[i2],
geomTol_,
td_
)
)
{
FatalErrorIn
(
"FaceCellWave"
"::checkCyclic(const polyPatch&)"
) << "problem: i:" << i1 << " otheri:" << i2
<< " faceInfo:" << allFaceInfo_[i1]
<< " otherfaceInfo:" << allFaceInfo_[i2]
<< abort(FatalError);
}
if (changedFace_[i1] != changedFace_[i2])
{
FatalErrorIn
(
"FaceCellWave"
"::checkCyclic(const polyPatch&)"
) << " problem: i:" << i1 << " otheri:" << i2
<< " faceInfo:" << allFaceInfo_[i1]
<< " otherfaceInfo:" << allFaceInfo_[i2]
<< " changedFace:" << changedFace_[i1]
<< " otherchangedFace:" << changedFace_[i2]
<< abort(FatalError);
}
}
}
// Check if has cyclic patches
template
bool Foam::FaceCellWave::hasCyclicPatch() const
{
forAll(mesh_.boundaryMesh(), patchI)
{
if (isA(mesh_.boundaryMesh()[patchI]))
{
return true;
}
}
return false;
}
// Copy face information into member data
template
void Foam::FaceCellWave::setFaceInfo
(
const labelList& changedFaces,
const List& changedFacesInfo
)
{
forAll(changedFaces, changedFaceI)
{
label faceI = changedFaces[changedFaceI];
bool wasValid = allFaceInfo_[faceI].valid(td_);
// Copy info for faceI
allFaceInfo_[faceI] = changedFacesInfo[changedFaceI];
// Maintain count of unset faces
if (!wasValid && allFaceInfo_[faceI].valid(td_))
{
--nUnvisitedFaces_;
}
// Mark faceI as changed, both on list and on face itself.
changedFace_[faceI] = true;
changedFaces_[nChangedFaces_++] = faceI;
}
}
// Merge face information into member data
template
void Foam::FaceCellWave::mergeFaceInfo
(
const polyPatch& patch,
const label nFaces,
const labelList& changedFaces,
const List& changedFacesInfo
)
{
for (label changedFaceI = 0; changedFaceI < nFaces; changedFaceI++)
{
const Type& neighbourWallInfo = changedFacesInfo[changedFaceI];
label patchFaceI = changedFaces[changedFaceI];
label meshFaceI = patch.start() + patchFaceI;
Type& currentWallInfo = allFaceInfo_[meshFaceI];
if (!currentWallInfo.equal(neighbourWallInfo, td_))
{
updateFace
(
meshFaceI,
neighbourWallInfo,
propagationTol_,
currentWallInfo
);
}
}
}
// Construct compact patchFace change arrays for a (slice of a) single patch.
// changedPatchFaces in local patch numbering.
// Return length of arrays.
template
Foam::label Foam::FaceCellWave::getChangedPatchFaces
(
const polyPatch& patch,
const label startFaceI,
const label nFaces,
labelList& changedPatchFaces,
List& changedPatchFacesInfo
) const
{
label nChangedPatchFaces = 0;
for (label i = 0; i < nFaces; i++)
{
label patchFaceI = i + startFaceI;
label meshFaceI = patch.start() + patchFaceI;
if (changedFace_[meshFaceI])
{
changedPatchFaces[nChangedPatchFaces] = patchFaceI;
changedPatchFacesInfo[nChangedPatchFaces] = allFaceInfo_[meshFaceI];
nChangedPatchFaces++;
}
}
return nChangedPatchFaces;
}
// Handle leaving domain. Implementation referred to Type
template
void Foam::FaceCellWave::leaveDomain
(
const polyPatch& patch,
const label nFaces,
const labelList& faceLabels,
List& faceInfo
) const
{
const vectorField& fc = mesh_.faceCentres();
for (label i = 0; i < nFaces; i++)
{
label patchFaceI = faceLabels[i];
label meshFaceI = patch.start() + patchFaceI;
faceInfo[i].leaveDomain(mesh_, patch, patchFaceI, fc[meshFaceI], td_);
}
}
// Handle entering domain. Implementation referred to Type
template
void Foam::FaceCellWave::enterDomain
(
const polyPatch& patch,
const label nFaces,
const labelList& faceLabels,
List& faceInfo
) const
{
const vectorField& fc = mesh_.faceCentres();
for (label i = 0; i < nFaces; i++)
{
label patchFaceI = faceLabels[i];
label meshFaceI = patch.start() + patchFaceI;
faceInfo[i].enterDomain(mesh_, patch, patchFaceI, fc[meshFaceI], td_);
}
}
// Transform. Implementation referred to Type
template
void Foam::FaceCellWave::transform
(
const tensorField& rotTensor,
const label nFaces,
List& faceInfo
)
{
if (rotTensor.size() == 1)
{
const tensor& T = rotTensor[0];
for (label faceI = 0; faceI < nFaces; faceI++)
{
faceInfo[faceI].transform(mesh_, T, td_);
}
}
else
{
for (label faceI = 0; faceI < nFaces; faceI++)
{
faceInfo[faceI].transform(mesh_, rotTensor[faceI], td_);
}
}
}
// Offset mesh face. Used for transferring from one cyclic half to the other.
template
void Foam::FaceCellWave::offset
(
const polyPatch&,
const label cycOffset,
const label nFaces,
labelList& faces
)
{
for (label faceI = 0; faceI < nFaces; faceI++)
{
faces[faceI] += cycOffset;
}
}
// Tranfer all the information to/from neighbouring processors
template
void Foam::FaceCellWave::handleProcPatches()
{
// Send all
PstreamBuffers pBufs(Pstream::nonBlocking);
forAll(mesh_.boundaryMesh(), patchI)
{
const polyPatch& patch = mesh_.boundaryMesh()[patchI];
if (isA(patch))
{
// Allocate buffers
label nSendFaces;
labelList sendFaces(patch.size());
List sendFacesInfo(patch.size());
// Determine which faces changed on current patch
nSendFaces = getChangedPatchFaces
(
patch,
0,
patch.size(),
sendFaces,
sendFacesInfo
);
// Adapt wallInfo for leaving domain
leaveDomain
(
patch,
nSendFaces,
sendFaces,
sendFacesInfo
);
const processorPolyPatch& procPatch =
refCast(patch);
if (debug)
{
Pout<< " Processor patch " << patchI << ' ' << patch.name()
<< " communicating with " << procPatch.neighbProcNo()
<< " Sending:" << nSendFaces
<< endl;
}
UOPstream toNeighbour(procPatch.neighbProcNo(), pBufs);
//writeFaces(nSendFaces, sendFaces, sendFacesInfo, toNeighbour);
toNeighbour
<< SubList