/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2012 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 .
Description
Makes internal faces into boundary faces. Does not duplicate points, unlike
mergeOrSplitBaffles.
Note: if any coupled patch face is selected for baffling the opposite
member has to be selected for baffling as well.
- if the patch already exists will not override it nor its fields
- if the patch does not exist it will be created together with 'calculated'
patchfields unless the field is mentioned in the patchFields section.
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "Time.H"
#include "polyTopoChange.H"
#include "polyModifyFace.H"
#include "polyAddFace.H"
#include "ReadFields.H"
#include "volFields.H"
#include "surfaceFields.H"
#include "fvMeshMapper.H"
#include "faceSelection.H"
#include "fvMeshTools.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
void modifyOrAddFace
(
polyTopoChange& meshMod,
const face& f,
const label faceI,
const label own,
const bool flipFaceFlux,
const label newPatchI,
const label zoneID,
const bool zoneFlip,
PackedBoolList& modifiedFace
)
{
if (!modifiedFace[faceI])
{
// First usage of face. Modify.
meshMod.setAction
(
polyModifyFace
(
f, // modified face
faceI, // label of face
own, // owner
-1, // neighbour
flipFaceFlux, // face flip
newPatchI, // patch for face
false, // remove from zone
zoneID, // zone for face
zoneFlip // face flip in zone
)
);
modifiedFace[faceI] = 1;
}
else
{
// Second or more usage of face. Add.
meshMod.setAction
(
polyAddFace
(
f, // modified face
own, // owner
-1, // neighbour
-1, // master point
-1, // master edge
faceI, // master face
flipFaceFlux, // face flip
newPatchI, // patch for face
zoneID, // zone for face
zoneFlip // face flip in zone
)
);
}
}
// Main program:
int main(int argc, char *argv[])
{
argList::addNote
(
"Makes internal faces into boundary faces.\n"
"Does not duplicate points."
);
#include "addOverwriteOption.H"
argList::addOption
(
"dict",
"file",
"specify alternative dictionary for the createBaffles description"
);
#include "addRegionOption.H"
#include "setRootCase.H"
#include "createTime.H"
runTime.functionObjects().off();
#include "createNamedMesh.H"
const bool overwrite = args.optionFound("overwrite");
const word oldInstance = mesh.pointsInstance();
const word dictName
(
args.optionLookupOrDefault
(
"dict",
"createBafflesDict"
)
);
Switch internalFacesOnly(false);
Switch noFields(false);
PtrList selectors;
{
Info<< "Reading baffle criteria from " << dictName << nl << endl;
IOdictionary dict
(
IOobject
(
dictName,
mesh.time().system(),
mesh,
IOobject::MUST_READ,
IOobject::NO_WRITE
)
);
dict.lookup("internalFacesOnly") >> internalFacesOnly;
noFields = dict.lookupOrDefault("noFields", false);
const dictionary& selectionsDict = dict.subDict("baffles");
label n = 0;
forAllConstIter(dictionary, selectionsDict, iter)
{
if (iter().isDict())
{
n++;
}
}
selectors.setSize(n);
n = 0;
forAllConstIter(dictionary, selectionsDict, iter)
{
if (iter().isDict())
{
selectors.set
(
n++,
faceSelection::New(iter().keyword(), mesh, iter().dict())
);
}
}
}
if (internalFacesOnly)
{
Info<< "Not converting faces on non-coupled patches." << nl << endl;
}
// Read objects in time directory
IOobjectList objects(mesh, runTime.timeName());
// Read vol fields.
Info<< "Reading geometric fields" << nl << endl;
PtrList vsFlds;
if (!noFields) ReadFields(mesh, objects, vsFlds);
PtrList vvFlds;
if (!noFields) ReadFields(mesh, objects, vvFlds);
PtrList vstFlds;
if (!noFields) ReadFields(mesh, objects, vstFlds);
PtrList vsymtFlds;
if (!noFields) ReadFields(mesh, objects, vsymtFlds);
PtrList vtFlds;
if (!noFields) ReadFields(mesh, objects, vtFlds);
// Read surface fields.
PtrList ssFlds;
if (!noFields) ReadFields(mesh, objects, ssFlds);
PtrList svFlds;
if (!noFields) ReadFields(mesh, objects, svFlds);
PtrList sstFlds;
if (!noFields) ReadFields(mesh, objects, sstFlds);
PtrList ssymtFlds;
if (!noFields) ReadFields(mesh, objects, ssymtFlds);
PtrList stFlds;
if (!noFields) ReadFields(mesh, objects, stFlds);
// Creating (if necessary) baffles
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
forAll(selectors, selectorI)
{
const word& name = selectors[selectorI].name();
if (mesh.faceZones().findZoneID(name) == -1)
{
mesh.faceZones().clearAddressing();
label sz = mesh.faceZones().size();
labelList addr(0);
boolList flip(0);
mesh.faceZones().setSize(sz+1);
mesh.faceZones().set
(
sz,
new faceZone(name, addr, flip, sz, mesh.faceZones())
);
}
}
// Select faces
// ~~~~~~~~~~~~
//- Per face zoneID it is in and flip status.
labelList faceToZoneID(mesh.nFaces(), -1);
boolList faceToFlip(mesh.nFaces(), false);
forAll(selectors, selectorI)
{
const word& name = selectors[selectorI].name();
label zoneID = mesh.faceZones().findZoneID(name);
selectors[selectorI].select(zoneID, faceToZoneID, faceToFlip);
}
// Add faces to faceZones
labelList nFaces(mesh.faceZones().size(), 0);
forAll(faceToZoneID, faceI)
{
label zoneID = faceToZoneID[faceI];
if (zoneID != -1)
{
nFaces[zoneID]++;
}
}
forAll(selectors, selectorI)
{
const word& name = selectors[selectorI].name();
label zoneID = mesh.faceZones().findZoneID(name);
label& n = nFaces[zoneID];
labelList addr(n);
boolList flip(n);
n = 0;
forAll(faceToZoneID, faceI)
{
label zone = faceToZoneID[faceI];
if (zone == zoneID)
{
addr[n] = faceI;
flip[n] = faceToFlip[faceI];
n++;
}
}
Info<< "Created zone " << name
<< " at index " << zoneID
<< " with " << n << " faces" << endl;
mesh.faceZones().set
(
zoneID,
new faceZone(name, addr, flip, zoneID, mesh.faceZones())
);
}
// Count patches to add
// ~~~~~~~~~~~~~~~~~~~~
HashSet bafflePatches;
{
forAll(selectors, selectorI)
{
const dictionary& patchSources
(
selectors[selectorI].dict().subDict("patches")
);
forAllConstIter(dictionary, patchSources, iter)
{
//const word& patchName = iter().keyword();
const word patchName(iter().dict()["name"]);
bafflePatches.insert(patchName);
}
}
}
// Create baffles
// ~~~~~~~~~~~~~~
// Is done in multiple steps
// - create patches with 'calculated' patchFields
// - move faces into these patches
// - change the patchFields to the wanted type
// This order is done so e.g. fixedJump works:
// - you cannot create patchfields at the same time as patches since
// they do an evaluate upon construction
// - you want to create the patchField only after you have faces
// so you don't get the 'create-from-nothing' mapping problem.
// Pass 1: add patches
// ~~~~~~~~~~~~~~~~~~~
//HashSet addedPatches;
{
const polyBoundaryMesh& pbm = mesh.boundaryMesh();
forAll(selectors, selectorI)
{
const dictionary& patchSources
(
selectors[selectorI].dict().subDict("patches")
);
forAllConstIter(dictionary, patchSources, iter)
{
//const word& patchName = iter().keyword();
const word patchName(iter().dict()["name"]);
label destPatchI = pbm.findPatchID(patchName);
if (destPatchI == -1)
{
dictionary patchDict = iter().dict();
patchDict.set("nFaces", 0);
patchDict.set("startFace", 0);
Info<< "Adding new patch " << patchName
<< " from " << patchDict << endl;
autoPtr ppPtr
(
polyPatch::New
(
patchName,
patchDict,
0,
pbm
)
);
// Add patch, create calculated everywhere
fvMeshTools::addPatch
(
mesh,
ppPtr(),
dictionary(), // do not set specialised patchFields
calculatedFvPatchField::typeName,
true // parallel sync'ed addition
);
//addedPatches.insert(patchName);
}
else
{
Info<< "Patch '" << patchName << "' already exists. Only "
<< "moving patch faces - type will remain the same"
<< endl;
}
}
}
}
// Make sure patches and zoneFaces are synchronised across couples
mesh.boundaryMesh().checkParallelSync(true);
mesh.faceZones().checkParallelSync(true);
// Mesh change container
polyTopoChange meshMod(mesh);
const polyBoundaryMesh& pbm = mesh.boundaryMesh();
// Do the actual changes. Note:
// - loop in incrementing face order (not necessary if faceZone ordered).
// Preserves any existing ordering on patch faces.
// - two passes, do non-flip faces first and flip faces second. This
// guarantees that when e.g. creating a cyclic all faces from one
// side come first and faces from the other side next.
// Whether first use of face (modify) or consecutive (add)
PackedBoolList modifiedFace(mesh.nFaces());
label nModified = 0;
forAll(selectors, selectorI)
{
const word& name = selectors[selectorI].name();
label zoneID = mesh.faceZones().findZoneID(name);
const faceZone& fZone = mesh.faceZones()[zoneID];
const dictionary& patchSources
(
selectors[selectorI].dict().subDict("patches")
);
DynamicList