/*---------------------------------------------------------------------------*\ ========= | \\ / 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 . Description Extrude faceZones into separate mesh (as a different region). - used to e.g. extrude baffles (extrude internal faces) or create liquid film regions. - if extruding internal faces: - create baffles in original mesh with directMappedWall patches - if extruding boundary faces: - convert boundary faces to directMappedWall patches - extrude edges of faceZone as a _sidePatch - extrude edges inbetween different faceZones as a (nonuniformTransform)cyclic _ - extrudes into master direction (i.e. away from the owner cell if flipMap is false) - not parallel Internal face extrusion ----------------------- +-------------+ | | | | +---AAAAAAA---+ | | | | +-------------+ AAA=faceZone to extrude. For the case of no flipMap the extrusion starts at owner and extrudes into the space of the neighbour: +CCCCCCC+ | | <= extruded mesh +BBBBBBB+ +-------------+ | | | (neighbour) | |___CCCCCCC___| <= original mesh (with 'baffles' added) | BBBBBBB | |(owner side) | | | +-------------+ BBB=directMapped between owner on original mesh and new extrusion. (zero offset) CCC=directMapped between neighbour on original mesh and new extrusion (offset due to the thickness of the extruded mesh) For the case of flipMap the extrusion is the other way around: from the neighbour side into the owner side. Boundary face extrusion ----------------------- +--AAAAAAA--+ | | | | +-----------+ AAA=faceZone to extrude. E.g. slave side is owner side (no flipmap) becomes +CCCCCCC+ | | <= extruded mesh +BBBBBBB+ +--BBBBBBB--+ | | <= original mesh | | +-----------+ BBB=directMapped between original mesh and new extrusion CCC=polypatch Usage - extrudeToRegionMesh @param \ \n Name of mesh to create. @param \ \n List of faceZones to extrude @param \ \n Thickness of extruded mesh. \*---------------------------------------------------------------------------*/ #include "argList.H" #include "Time.H" #include "fvMesh.H" #include "polyTopoChange.H" #include "patchPointEdgeCirculator.H" #include "OFstream.H" #include "meshTools.H" #include "directMappedWallPolyPatch.H" #include "createShellMesh.H" #include "volFields.H" #include "surfaceFields.H" #include "syncTools.H" #include "cyclicPolyPatch.H" #include "nonuniformTransformCyclicPolyPatch.H" using namespace Foam; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // template void addPatchFields(fvMesh& mesh, const word& patchFieldType) { HashTable flds ( mesh.objectRegistry::lookupClass() ); forAllConstIter(typename HashTable, flds, iter) { const GeoField& fld = *iter(); typename GeoField::GeometricBoundaryField& bfld = const_cast ( fld.boundaryField() ); label sz = bfld.size(); bfld.setSize(sz+1); bfld.set ( sz, GeoField::PatchFieldType::New ( patchFieldType, mesh.boundary()[sz], fld.dimensionedInternalField() ) ); } } // Remove last patch field template void trimPatchFields(fvMesh& mesh, const label nPatches) { HashTable flds ( mesh.objectRegistry::lookupClass() ); forAllConstIter(typename HashTable, flds, iter) { const GeoField& fld = *iter(); const_cast ( fld.boundaryField() ).setSize(nPatches); } } // Reorder patch field template void reorderPatchFields(fvMesh& mesh, const labelList& oldToNew) { HashTable flds ( mesh.objectRegistry::lookupClass() ); forAllConstIter(typename HashTable, flds, iter) { const GeoField& fld = *iter(); typename GeoField::GeometricBoundaryField& bfld = const_cast ( fld.boundaryField() ); bfld.reorder(oldToNew); } } void addAllPatchFields(fvMesh& mesh, const label insertPatchI) { polyBoundaryMesh& polyPatches = const_cast(mesh.boundaryMesh()); fvBoundaryMesh& fvPatches = const_cast(mesh.boundary()); label sz = polyPatches.size(); addPatchFields ( mesh, calculatedFvPatchField::typeName ); addPatchFields ( mesh, calculatedFvPatchField::typeName ); addPatchFields ( mesh, calculatedFvPatchField::typeName ); addPatchFields ( mesh, calculatedFvPatchField::typeName ); addPatchFields ( mesh, calculatedFvPatchField::typeName ); // Surface fields addPatchFields ( mesh, calculatedFvPatchField::typeName ); addPatchFields ( mesh, calculatedFvPatchField::typeName ); addPatchFields ( mesh, calculatedFvPatchField::typeName ); addPatchFields ( mesh, calculatedFvPatchField::typeName ); addPatchFields ( mesh, calculatedFvPatchField::typeName ); // Create reordering list // patches before insert position stay as is labelList oldToNew(sz); for (label i = 0; i < insertPatchI; i++) { oldToNew[i] = i; } // patches after insert position move one up for (label i = insertPatchI; i < sz-1; i++) { oldToNew[i] = i+1; } // appended patch gets moved to insert position oldToNew[sz-1] = insertPatchI; // Shuffle into place polyPatches.reorder(oldToNew); fvPatches.reorder(oldToNew); reorderPatchFields(mesh, oldToNew); reorderPatchFields(mesh, oldToNew); reorderPatchFields(mesh, oldToNew); reorderPatchFields(mesh, oldToNew); reorderPatchFields(mesh, oldToNew); reorderPatchFields(mesh, oldToNew); reorderPatchFields(mesh, oldToNew); reorderPatchFields(mesh, oldToNew); reorderPatchFields(mesh, oldToNew); reorderPatchFields(mesh, oldToNew); } // Adds patch if not yet there. Returns patchID. template label addPatch(fvMesh& mesh, const word& patchName, const dictionary& dict) { polyBoundaryMesh& polyPatches = const_cast(mesh.boundaryMesh()); label patchI = polyPatches.findPatchID(patchName); if (patchI != -1) { if (isA(polyPatches[patchI])) { // Already there return patchI; } else { FatalErrorIn("addPatch(fvMesh&, const word&)") << "Already have patch " << patchName << " but of type " << PatchType::typeName << exit(FatalError); } } label insertPatchI = polyPatches.size(); label startFaceI = mesh.nFaces(); forAll(polyPatches, patchI) { const polyPatch& pp = polyPatches[patchI]; if (isA(pp)) { insertPatchI = patchI; startFaceI = pp.start(); break; } } dictionary patchDict(dict); patchDict.set("type", PatchType::typeName); patchDict.set("nFaces", 0); patchDict.set("startFace", startFaceI); // Below is all quite a hack. Feel free to change once there is a better // mechanism to insert and reorder patches. // Clear local fields and e.g. polyMesh parallelInfo. mesh.clearOut(); label sz = polyPatches.size(); fvBoundaryMesh& fvPatches = const_cast(mesh.boundary()); // Add polyPatch at the end polyPatches.setSize(sz+1); polyPatches.set ( sz, polyPatch::New ( patchName, patchDict, insertPatchI, polyPatches ) ); fvPatches.setSize(sz+1); fvPatches.set ( sz, fvPatch::New ( polyPatches[sz], // point to newly added polyPatch mesh.boundary() ) ); addAllPatchFields(mesh, insertPatchI); return insertPatchI; } template label addPatch(fvMesh& mesh, const word& patchName) { polyBoundaryMesh& polyPatches = const_cast(mesh.boundaryMesh()); label patchI = polyPatches.findPatchID(patchName); if (patchI != -1) { if (isA(polyPatches[patchI])) { // Already there return patchI; } else { FatalErrorIn("addPatch(fvMesh&, const word&)") << "Already have patch " << patchName << " but of type " << PatchType::typeName << exit(FatalError); } } label insertPatchI = polyPatches.size(); label startFaceI = mesh.nFaces(); forAll(polyPatches, patchI) { const polyPatch& pp = polyPatches[patchI]; if (isA(pp)) { insertPatchI = patchI; startFaceI = pp.start(); break; } } // Below is all quite a hack. Feel free to change once there is a better // mechanism to insert and reorder patches. // Clear local fields and e.g. polyMesh parallelInfo. mesh.clearOut(); label sz = polyPatches.size(); fvBoundaryMesh& fvPatches = const_cast(mesh.boundary()); // Add polyPatch at the end polyPatches.setSize(sz+1); polyPatches.set ( sz, polyPatch::New ( PatchType::typeName, patchName, 0, // size startFaceI, insertPatchI, polyPatches ) ); fvPatches.setSize(sz+1); fvPatches.set ( sz, fvPatch::New ( polyPatches[sz], // point to newly added polyPatch mesh.boundary() ) ); addAllPatchFields(mesh, insertPatchI); return insertPatchI; } // Reorder and delete patches. void reorderPatches ( fvMesh& mesh, const labelList& oldToNew, const label nNewPatches ) { polyBoundaryMesh& polyPatches = const_cast(mesh.boundaryMesh()); fvBoundaryMesh& fvPatches = const_cast(mesh.boundary()); // Shuffle into place polyPatches.reorder(oldToNew); fvPatches.reorder(oldToNew); reorderPatchFields(mesh, oldToNew); reorderPatchFields(mesh, oldToNew); reorderPatchFields(mesh, oldToNew); reorderPatchFields(mesh, oldToNew); reorderPatchFields(mesh, oldToNew); reorderPatchFields(mesh, oldToNew); reorderPatchFields(mesh, oldToNew); reorderPatchFields(mesh, oldToNew); reorderPatchFields(mesh, oldToNew); reorderPatchFields(mesh, oldToNew); // Remove last. polyPatches.setSize(nNewPatches); fvPatches.setSize(nNewPatches); trimPatchFields(mesh, nNewPatches); trimPatchFields(mesh, nNewPatches); trimPatchFields(mesh, nNewPatches); trimPatchFields(mesh, nNewPatches); trimPatchFields(mesh, nNewPatches); trimPatchFields(mesh, nNewPatches); trimPatchFields(mesh, nNewPatches); trimPatchFields(mesh, nNewPatches); trimPatchFields(mesh, nNewPatches); trimPatchFields(mesh, nNewPatches); } // Remove zero-sized patches void deleteEmptyPatches(fvMesh& mesh) { const polyBoundaryMesh& patches = mesh.boundaryMesh(); labelList oldToNew(patches.size()); label usedI = 0; label notUsedI = patches.size(); forAll(patches, patchI) { if (returnReduce(patches[patchI].size(), sumOp