/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2011-2016 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() ); } } }; } // * * * * * * * * * * * * * Private 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::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