/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | Website: https://openfoam.org \\ / A nd | Copyright (C) 2011-2024 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 . Application PDRMesh Description Mesh and field preparation utility for PDR type simulations. Reads - cellSet giving blockedCells - faceSets giving blockedFaces and the patch they should go into NOTE: To avoid exposing wrong fields values faceSets should include faces contained in the blockedCells cellset. - coupledFaces reads coupledFacesSet to introduces mixe-coupled baffles Subsets out the blocked cells and splits the blockedFaces and updates fields. The face splitting is done by duplicating the faces. No duplication of points for now (so checkMesh will show a lot of 'duplicate face' messages) \*---------------------------------------------------------------------------*/ #include "fvMeshSubset.H" #include "argList.H" #include "cellSet.H" #include "IOobjectList.H" #include "volFields.H" #include "polyTopoChangeMap.H" #include "faceSet.H" #include "cellSet.H" #include "syncTools.H" #include "polyTopoChange.H" #include "regionSplit.H" #include "Tuple2.H" #include "cyclicFvPatch.H" using namespace Foam; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // void modifyOrAddFace ( polyTopoChange& meshMod, const face& f, const label facei, const label own, const bool flipFaceFlux, const label newPatchi, PackedBoolList& modifiedFace ) { if (!modifiedFace[facei]) { // First usage of face. Modify. meshMod.modifyFace ( f, // modified face facei, // label of face own, // owner -1, // neighbour flipFaceFlux, // face flip newPatchi // patch for face ); modifiedFace[facei] = 1; } else { // Second or more usage of face. Add. meshMod.addFace ( f, // modified face own, // owner -1, // neighbour facei, // master face flipFaceFlux, // face flip newPatchi // patch for face ); } } template void subsetVolFields ( const fvMeshSubset& subsetter, const IOobjectList& objectsList, const label patchi, const Type& exposedValue, const word GeomVolType, PtrList>& subFields ) { const fvMesh& baseMesh = subsetter.baseMesh(); label i = 0; forAllConstIter(IOobjectList , objectsList, iter) { if (iter()->headerClassName() == GeomVolType) { const word fieldName = iter()->name(); Info<< "Subsetting field " << fieldName << endl; VolField volField ( *iter(), baseMesh ); subFields.set(i, subsetter.interpolate(volField)); // Explicitly set exposed faces (in patchi) to exposedValue. if (patchi >= 0) { fvPatchField& fld = subFields[i++].boundaryFieldRef()[patchi]; label newStart = fld.patch().patch().start(); label oldPatchi = subsetter.patchMap()[patchi]; if (oldPatchi == -1) { // New patch. Reset whole value. fld = exposedValue; } else { // Reset those faces that originate from different patch // or internal faces. label oldSize = volField.boundaryField()[oldPatchi].size(); label oldStart = volField.boundaryField() [ oldPatchi ].patch().patch().start(); forAll(fld, j) { label oldFacei = subsetter.faceMap()[newStart+j]; if (oldFacei < oldStart || oldFacei >= oldStart+oldSize) { fld[j] = exposedValue; } } } } } } } template void subsetSurfaceFields ( const fvMeshSubset& subsetter, const IOobjectList& objectsList, const label patchi, const Type& exposedValue, const word GeomSurfType, PtrList>& subFields ) { const fvMesh& baseMesh = subsetter.baseMesh(); label i(0); forAllConstIter(IOobjectList , objectsList, iter) { if (iter()->headerClassName() == GeomSurfType) { const word& fieldName = iter.key(); Info<< "Subsetting field " << fieldName << endl; SurfaceField volField ( *iter(), baseMesh ); subFields.set(i, subsetter.interpolate(volField)); // Explicitly set exposed faces (in patchi) to exposedValue. if (patchi >= 0) { fvsPatchField& fld = subFields[i++].boundaryFieldRef()[patchi]; label newStart = fld.patch().patch().start(); label oldPatchi = subsetter.patchMap()[patchi]; if (oldPatchi == -1) { // New patch. Reset whole value. fld = exposedValue; } else { // Reset those faces that originate from different patch // or internal faces. label oldSize = volField.boundaryField()[oldPatchi].size(); label oldStart = volField.boundaryField() [ oldPatchi ].patch().patch().start(); forAll(fld, j) { label oldFacei = subsetter.faceMap()[newStart+j]; if (oldFacei < oldStart || oldFacei >= oldStart+oldSize) { fld[j] = exposedValue; } } } } } } } // Faces introduced into zero-sized patches don't get a value at all. // This is hack to set them to an initial value. template void initCreatedPatches ( const fvMesh& mesh, const polyTopoChangeMap& map, const typename GeoField::value_type initValue ) { HashTable fields ( mesh.objectRegistry::lookupClass() ); for ( typename HashTable:: iterator fieldIter = fields.begin(); fieldIter != fields.end(); ++fieldIter ) { GeoField& field = const_cast(*fieldIter()); typename GeoField::Boundary& fieldBf = field.boundaryFieldRef(); forAll(fieldBf, patchi) { if (map.oldPatchSizes()[patchi] == 0) { // Not mapped. fieldBf[patchi] = initValue; if (fieldBf[patchi].fixesValue()) { fieldBf[patchi] == initValue; } } } } } void createCoupledBaffles ( fvMesh& mesh, const labelList& coupledWantedPatch, polyTopoChange& meshMod, PackedBoolList& modifiedFace ) { forAll(coupledWantedPatch, facei) { if (coupledWantedPatch[facei] != -1) { const face& f = mesh.faces()[facei]; // Use owner side of face modifyOrAddFace ( meshMod, f, // modified face facei, // label of face mesh.faceOwner()[facei], // owner false, // face flip coupledWantedPatch[facei], // patch for face modifiedFace // modify or add status ); if (mesh.isInternalFace(facei)) { // Use neighbour side of face modifyOrAddFace ( meshMod, f.reverseFace(), // modified face facei, // label of face mesh.faceNeighbour()[facei],// owner false, // face flip coupledWantedPatch[facei], // patch for face modifiedFace // modify or add status ); } } } } void createCyclicCoupledBaffles ( fvMesh& mesh, const labelList& cyclicMasterPatch, const labelList& cyclicSlavePatch, polyTopoChange& meshMod, PackedBoolList& modifiedFace ) { forAll(cyclicMasterPatch, facei) { if (cyclicMasterPatch[facei] != -1) { const face& f = mesh.faces()[facei]; modifyOrAddFace ( meshMod, f.reverseFace(), // modified face facei, // label of face mesh.faceNeighbour()[facei], // owner false, // face flip cyclicMasterPatch[facei], // patch for face modifiedFace // modify or add ); } } forAll(cyclicSlavePatch, facei) { if (cyclicSlavePatch[facei] != -1) { const face& f = mesh.faces()[facei]; if (mesh.isInternalFace(facei)) { // Use owner side of face modifyOrAddFace ( meshMod, f, // modified face facei, // label of face mesh.faceOwner()[facei], // owner false, // face flip cyclicSlavePatch[facei], // patch for face modifiedFace // modify or add status ); } } } } void createBaffles ( fvMesh& mesh, const labelList& wantedPatch, polyTopoChange& meshMod ) { forAll(wantedPatch, facei) { if (wantedPatch[facei] != -1) { const face& f = mesh.faces()[facei]; meshMod.modifyFace ( f, // modified face facei, // label of face mesh.faceOwner()[facei], // owner -1, // neighbour false, // face flip wantedPatch[facei] // patch for face ); if (mesh.isInternalFace(facei)) { meshMod.addFace ( f.reverseFace(), // modified face mesh.faceNeighbour()[facei],// owner -1, // neighbour facei, // masterFaceID, false, // face flip wantedPatch[facei] // patch for face ); } } } } // Wrapper around find patch. Also makes sure same patch in parallel. label findPatch(const polyBoundaryMesh& patches, const word& patchName) { label patchi = patches.findIndex(patchName); if (patchi == -1) { FatalErrorInFunction << "Illegal patch " << patchName << nl << "Valid patches are " << patches.names() << exit(FatalError); } // Check same patch for all procs { label newPatch = patchi; reduce(newPatch, minOp