/*---------------------------------------------------------------------------*\ ========= | \\ / 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