/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 1991-2009 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA \*----------------------------------------------------------------------------*/ #include "meshRefinement.H" #include "fvMesh.H" #include "syncTools.H" #include "Time.H" #include "refinementSurfaces.H" #include "pointSet.H" #include "faceSet.H" #include "indirectPrimitivePatch.H" #include "polyTopoChange.H" #include "meshTools.H" #include "polyModifyFace.H" #include "polyModifyCell.H" #include "polyAddFace.H" #include "polyRemoveFace.H" #include "polyAddPoint.H" #include "localPointRegion.H" #include "duplicatePoints.H" #include "OFstream.H" #include "regionSplit.H" #include "removeCells.H" // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // Repatches external face or creates baffle for internal face // with user specified patches (might be different for both sides). // Returns label of added face. Foam::label Foam::meshRefinement::createBaffle ( const label faceI, const label ownPatch, const label neiPatch, polyTopoChange& meshMod ) const { const face& f = mesh_.faces()[faceI]; label zoneID = mesh_.faceZones().whichZone(faceI); bool zoneFlip = false; if (zoneID >= 0) { const faceZone& fZone = mesh_.faceZones()[zoneID]; zoneFlip = fZone.flipMap()[fZone.whichFace(faceI)]; } meshMod.setAction ( polyModifyFace ( f, // modified face faceI, // label of face mesh_.faceOwner()[faceI], // owner -1, // neighbour false, // face flip ownPatch, // patch for face false, // remove from zone zoneID, // zone for face zoneFlip // face flip in zone ) ); label dupFaceI = -1; if (mesh_.isInternalFace(faceI)) { if (neiPatch == -1) { FatalErrorIn ( "meshRefinement::createBaffle" "(const label, const label, const label, polyTopoChange&)" ) << "No neighbour patch for internal face " << faceI << " fc:" << mesh_.faceCentres()[faceI] << " ownPatch:" << ownPatch << abort(FatalError); } bool reverseFlip = false; if (zoneID >= 0) { reverseFlip = !zoneFlip; } dupFaceI = meshMod.setAction ( polyAddFace ( f.reverseFace(), // modified face mesh_.faceNeighbour()[faceI],// owner -1, // neighbour -1, // masterPointID -1, // masterEdgeID faceI, // masterFaceID, true, // face flip neiPatch, // patch for face zoneID, // zone for face reverseFlip // face flip in zone ) ); } return dupFaceI; } // Get an estimate for the patch the internal face should get. Bit heuristic. Foam::label Foam::meshRefinement::getBafflePatch ( const labelList& facePatch, const label faceI ) const { const polyBoundaryMesh& patches = mesh_.boundaryMesh(); // Loop over face points // for each point check all faces patch IDs // as soon as an ID >= 0 is found, break and assign that ID // to the current face. // Check first for real patch (so proper surface intersection and then // in facePatch array for patches to block off faces forAll(mesh_.faces()[faceI], fp) { label pointI = mesh_.faces()[faceI][fp]; forAll(mesh_.pointFaces()[pointI], pf) { label pFaceI = mesh_.pointFaces()[pointI][pf]; label patchI = patches.whichPatch(pFaceI); if (patchI != -1 && !patches[patchI].coupled()) { return patchI; } else if (facePatch[pFaceI] != -1) { return facePatch[pFaceI]; } } } // Loop over owner and neighbour cells, looking for the first face with a // valid patch number const cell& ownFaces = mesh_.cells()[mesh_.faceOwner()[faceI]]; forAll(ownFaces, i) { label cFaceI = ownFaces[i]; label patchI = patches.whichPatch(cFaceI); if (patchI != -1 && !patches[patchI].coupled()) { return patchI; } else if (facePatch[cFaceI] != -1) { return facePatch[cFaceI]; } } if (mesh_.isInternalFace(faceI)) { const cell& neiFaces = mesh_.cells()[mesh_.faceNeighbour()[faceI]]; forAll(neiFaces, i) { label cFaceI = neiFaces[i]; label patchI = patches.whichPatch(cFaceI); if (patchI != -1 && !patches[patchI].coupled()) { return patchI; } else if (facePatch[cFaceI] != -1) { return facePatch[cFaceI]; } } } WarningIn ( "meshRefinement::getBafflePatch(const labelList&, const label)" ) << "Could not find boundary face neighbouring internal face " << faceI << " with face centre " << mesh_.faceCentres()[faceI] << nl << "Using arbitrary patch " << 0 << " instead." << endl; return 0; } // Determine patches for baffles. void Foam::meshRefinement::getBafflePatches ( const labelList& globalToPatch, const labelList& neiLevel, const pointField& neiCc, labelList& ownPatch, labelList& neiPatch ) const { autoPtr str; label vertI = 0; if (debug&OBJINTERSECTIONS) { str.reset ( new OFstream ( mesh_.time().path()/timeName()/"intersections.obj" ) ); Pout<< "getBafflePatches : Writing surface intersections to file " << str().name() << nl << endl; } const pointField& cellCentres = mesh_.cellCentres(); // Build list of surfaces that are not to be baffled. const wordList& cellZoneNames = surfaces_.cellZoneNames(); labelList surfacesToBaffle(cellZoneNames.size()); label baffleI = 0; forAll(cellZoneNames, surfI) { if (cellZoneNames[surfI].size()) { if (debug) { Pout<< "getBafflePatches : Not baffling surface " << surfaces_.names()[surfI] << endl; } } else { surfacesToBaffle[baffleI++] = surfI; } } surfacesToBaffle.setSize(baffleI); ownPatch.setSize(mesh_.nFaces()); ownPatch = -1; neiPatch.setSize(mesh_.nFaces()); neiPatch = -1; // Collect candidate faces // ~~~~~~~~~~~~~~~~~~~~~~~ labelList testFaces(intersectedFaces()); // Collect segments // ~~~~~~~~~~~~~~~~ pointField start(testFaces.size()); pointField end(testFaces.size()); forAll(testFaces, i) { label faceI = testFaces[i]; label own = mesh_.faceOwner()[faceI]; if (mesh_.isInternalFace(faceI)) { start[i] = cellCentres[own]; end[i] = cellCentres[mesh_.faceNeighbour()[faceI]]; } else { start[i] = cellCentres[own]; end[i] = neiCc[faceI-mesh_.nInternalFaces()]; } } // Do test for intersections // ~~~~~~~~~~~~~~~~~~~~~~~~~ labelList surface1; List hit1; labelList region1; labelList surface2; List hit2; labelList region2; surfaces_.findNearestIntersection ( surfacesToBaffle, start, end, surface1, hit1, region1, surface2, hit2, region2 ); forAll(testFaces, i) { label faceI = testFaces[i]; if (hit1[i].hit() && hit2[i].hit()) { if (str.valid()) { meshTools::writeOBJ(str(), start[i]); vertI++; meshTools::writeOBJ(str(), hit1[i].rawPoint()); vertI++; meshTools::writeOBJ(str(), hit2[i].rawPoint()); vertI++; meshTools::writeOBJ(str(), end[i]); vertI++; str()<< "l " << vertI-3 << ' ' << vertI-2 << nl; str()<< "l " << vertI-2 << ' ' << vertI-1 << nl; str()<< "l " << vertI-1 << ' ' << vertI << nl; } // Pick up the patches ownPatch[faceI] = globalToPatch [ surfaces_.globalRegion(surface1[i], region1[i]) ]; neiPatch[faceI] = globalToPatch [ surfaces_.globalRegion(surface2[i], region2[i]) ]; if (ownPatch[faceI] == -1 || neiPatch[faceI] == -1) { FatalErrorIn("getBafflePatches(..)") << "problem." << abort(FatalError); } } } // No need to parallel sync since intersection data (surfaceIndex_ etc.) // already guaranteed to be synced... // However: // - owncc and neicc are reversed on different procs so might pick // up different regions reversed? No problem. Neighbour on one processor // might not be owner on the other processor but the neighbour is // not used when creating baffles from proc faces. // - tolerances issues occasionally crop up. syncTools::syncFaceList(mesh_, ownPatch, maxEqOp