/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2017 OpenFOAM Foundation
\\/ 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 "cyclicAMIPolyPatch.H"
#include "OPstream.H"
#include "IPstream.H"
#include "PstreamReduceOps.H"
#include "debug.H"
#include "typeInfo.H"
#include "SubField.H"
#include "globalMeshData.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
template
const Foam::scalar Foam::FaceCellWave::geomTol_ = 1e-6;
template
Foam::scalar Foam::FaceCellWave::propagationTol_ = 0.01;
template
int Foam::FaceCellWave::dummyTrackData_ = 12345;
namespace Foam
{
template
class combine
{
//- Combine operator for AMIInterpolation
FaceCellWave& solver_;
const cyclicAMIPolyPatch& patch_;
public:
combine
(
FaceCellWave& solver,
const cyclicAMIPolyPatch& patch
)
:
solver_(solver),
patch_(patch)
{}
void operator()
(
Type& x,
const label facei,
const Type& y,
const scalar weight
) const
{
if (y.valid(solver_.data()))
{
label meshFacei = -1;
if (patch_.owner())
{
meshFacei = patch_.start() + facei;
}
else
{
meshFacei = patch_.neighbPatch().start() + facei;
}
x.updateFace
(
solver_.mesh(),
meshFacei,
y,
solver_.propagationTol(),
solver_.data()
);
}
}
};
}
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
template
bool Foam::FaceCellWave::updateCell
(
const label celli,
const label neighbourFacei,
const Type& neighbourInfo,
const scalar tol,
Type& cellInfo
)
{
// Update info for celli, at position pt, with information from
// neighbouring face/cell.
// Updates:
// - changedCell_, changedCells_
// - statistics: nEvals_, nUnvisitedCells_
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_.append(celli);
}
}
if (!wasValid && cellInfo.valid(td_))
{
--nUnvisitedCells_;
}
return propagate;
}
template
bool Foam::FaceCellWave::updateFace
(
const label facei,
const label neighbourCelli,
const Type& neighbourInfo,
const scalar tol,
Type& faceInfo
)
{
// Update info for facei, at position pt, with information from
// neighbouring face/cell.
// Updates:
// - changedFace_, changedFaces_,
// - statistics: nEvals_, nUnvisitedFaces_
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_.append(facei);
}
}
if (!wasValid && faceInfo.valid(td_))
{
--nUnvisitedFaces_;
}
return propagate;
}
template
bool Foam::FaceCellWave::updateFace
(
const label facei,
const Type& neighbourInfo,
const scalar tol,
Type& faceInfo
)
{
// Update info for facei, at position pt, with information from
// same face.
// Updates:
// - changedFace_, changedFaces_,
// - statistics: nEvals_, nUnvisitedFaces_
nEvals_++;
bool wasValid = faceInfo.valid(td_);
bool propagate =
faceInfo.updateFace
(
mesh_,
facei,
neighbourInfo,
tol,
td_
);
if (propagate)
{
if (!changedFace_[facei])
{
changedFace_[facei] = true;
changedFaces_.append(facei);
}
}
if (!wasValid && faceInfo.valid(td_))
{
--nUnvisitedFaces_;
}
return propagate;
}
template
void Foam::FaceCellWave::checkCyclic
(
const polyPatch& patch
) const
{
// For debugging: check status on both sides of cyclic
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_
)
)
{
FatalErrorInFunction
<< " faceInfo:" << allFaceInfo_[i1]
<< " otherfaceInfo:" << allFaceInfo_[i2]
<< abort(FatalError);
}
if (changedFace_[i1] != changedFace_[i2])
{
FatalErrorInFunction
<< " faceInfo:" << allFaceInfo_[i1]
<< " otherfaceInfo:" << allFaceInfo_[i2]
<< " changedFace:" << changedFace_[i1]
<< " otherchangedFace:" << changedFace_[i2]
<< abort(FatalError);
}
}
}
template
template
bool Foam::FaceCellWave::hasPatch() const
{
forAll(mesh_.boundaryMesh(), patchi)
{
if (isA(mesh_.boundaryMesh()[patchi]))
{
return true;
}
}
return false;
}
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_.append(facei);
}
}
template
void Foam::FaceCellWave::mergeFaceInfo
(
const polyPatch& patch,
const label nFaces,
const labelList& changedFaces,
const List& changedFacesInfo
)
{
// Merge face information into member data
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
);
}
}
}
template
Foam::label Foam::FaceCellWave::getChangedPatchFaces
(
const polyPatch& patch,
const label startFacei,
const label nFaces,
labelList& changedPatchFaces,
List& changedPatchFacesInfo
) const
{
// Construct compact patchFace change arrays for a (slice of a) single
// patch. changedPatchFaces in local patch numbering.
// Return length of arrays.
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;
}
template
void Foam::FaceCellWave::leaveDomain
(
const polyPatch& patch,
const label nFaces,
const labelList& faceLabels,
List& faceInfo
) const
{
// Handle leaving domain. Implementation referred to Type
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_);
}
}
template
void Foam::FaceCellWave::enterDomain
(
const polyPatch& patch,
const label nFaces,
const labelList& faceLabels,
List& faceInfo
) const
{
// Handle entering domain. Implementation referred to Type
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_);
}
}
template
void Foam::FaceCellWave::transform
(
const tensorField& rotTensor,
const label nFaces,
List& faceInfo
)
{
// Transform. Implementation referred to Type
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_);
}
}
}
template
void Foam::FaceCellWave::offset
(
const polyPatch&,
const label cycOffset,
const label nFaces,
labelList& faces
)
{
// Offset mesh face. Used for transferring from one cyclic half to the
// other.
for (label facei = 0; facei < nFaces; facei++)
{
faces[facei] += cycOffset;
}
}
template
void Foam::FaceCellWave::handleProcPatches()
{
// Tranfer all the information to/from neighbouring processors
const globalMeshData& pData = mesh_.globalData();
// Which patches are processor patches
const labelList& procPatches = pData.processorPatches();
// Send all
PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
forAll(procPatches, i)
{
label patchi = procPatches[i];
const processorPolyPatch& procPatch =
refCast(mesh_.boundaryMesh()[patchi]);
// Allocate buffers
label nSendFaces;
labelList sendFaces(procPatch.size());
List sendFacesInfo(procPatch.size());
// Determine which faces changed on current patch
nSendFaces = getChangedPatchFaces
(
procPatch,
0,
procPatch.size(),
sendFaces,
sendFacesInfo
);
// Adapt wallInfo for leaving domain
leaveDomain
(
procPatch,
nSendFaces,
sendFaces,
sendFacesInfo
);
if (debug & 2)
{
Pout<< " Processor patch " << patchi << ' ' << procPatch.name()
<< " communicating with " << procPatch.neighbProcNo()
<< " Sending:" << nSendFaces
<< endl;
}
UOPstream toNeighbour(procPatch.neighbProcNo(), pBufs);
//writeFaces(nSendFaces, sendFaces, sendFacesInfo, toNeighbour);
toNeighbour
<< SubList