/*---------------------------------------------------------------------------*\
========= |
\\ / 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
Extrude faceZones (internal or boundary faces) or faceSets (boundary faces
only) into a 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 mappedWall patches
- if extruding boundary faces:
- convert boundary faces to mappedWall 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)
\verbatim
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=mapped between owner on original mesh and new extrusion.
(zero offset)
CCC=mapped 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=mapped between original mesh and new extrusion
CCC=polypatch
Notes:
- when extruding cyclics with only one cell inbetween it does not
detect this as a cyclic since the face is the same face. It will
only work if the coupled edge extrudes a different face so if there
are more than 1 cell inbetween.
\endverbatim
\*---------------------------------------------------------------------------*/
#include "argList.H"
#include "fvMesh.H"
#include "polyTopoChange.H"
#include "OFstream.H"
#include "meshTools.H"
#include "mappedWallPolyPatch.H"
#include "createShellMesh.H"
#include "syncTools.H"
#include "cyclicPolyPatch.H"
#include "wedgePolyPatch.H"
#include "nonuniformTransformCyclicPolyPatch.H"
#include "extrudeModel.H"
#include "globalIndex.H"
#include "faceSet.H"
#include "volFields.H"
#include "surfaceFields.H"
#include "pointFields.H"
//#include "ReadFields.H"
using namespace Foam;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//template
//void addPatchFields(const 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();
//
// for (label i = 0; i < sz; i++)
// {
// bfld.set
// (
// i,
// bfld.clone(GeoField::PatchFieldType::New
// (
// patchFieldType,
// fld.mesh().boundary()[sz],
// fld.dimensionedInternalField()
// )
// );
//
//
//
// Pout<< "fld:" << fld.name() << " had " << sz << " patches." << endl;
// Pout<< "fld before:" << fld << endl;
// Pout<< "adding on patch:" << fld.mesh().boundary()[sz].name() << endl;
//
// bfld.setSize(sz+1);
// bfld.set
// (
// sz,
// GeoField::PatchFieldType::New
// (
// patchFieldType,
// fld.mesh().boundary()[sz],
// fld.dimensionedInternalField()
// )
// );
//
// bfld[sz].operator=(pTraits::zero);
//
// Pout<< "fld:" << fld.name() << " now " << bfld.size() << " patches."
// << endl;
//
// const typename GeoField::PatchFieldType& pfld = bfld[sz];
// Pout<< "pfld:" << pfld << endl;
//
//
// Pout<< "fld value:" << fld << endl;
// }
//}
// 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 addCalculatedPatchFields(const fvMesh& mesh)
//{
// 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
// );
//
// // Point fields
//
// addPatchFields
// (
// mesh,
// calculatedFvPatchField::typeName
// );
// addPatchFields
// (
// mesh,
// calculatedFvPatchField::typeName
// );
//}
//
//
//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)
//{
//Pout<< "addPatch:" << patchName << endl;
//
// 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;
//}
label findPatchID(const List& newPatches, const word& name)
{
forAll(newPatches, i)
{
if (newPatches[i]->name() == name)
{
return i;
}
}
return -1;
}
template
label addPatch
(
const polyBoundaryMesh& patches,
const word& patchName,
DynamicList& newPatches
)
{
label patchI = findPatchID(newPatches, patchName);
if (patchI != -1)
{
if (isA(*newPatches[patchI]))
{
// Already there
return patchI;
}
else
{
FatalErrorIn
(
"addPatch(const polyBoundaryMesh&,"
" const word&, DynamicList)"
) << "Already have patch " << patchName
<< " but of type " << newPatches[patchI]->type()
<< exit(FatalError);
}
}
patchI = newPatches.size();
label startFaceI = 0;
if (patchI > 0)
{
const polyPatch& pp = *newPatches.last();
startFaceI = pp.start()+pp.size();
}
newPatches.append
(
polyPatch::New
(
PatchType::typeName,
patchName,
0, // size
startFaceI, // nFaces
patchI,
patches
).ptr()
);
return patchI;
}
template
label addPatch
(
const polyBoundaryMesh& patches,
const word& patchName,
const dictionary& dict,
DynamicList& newPatches
)
{
label patchI = findPatchID(newPatches, patchName);
if (patchI != -1)
{
if (isA(*newPatches[patchI]))
{
// Already there
return patchI;
}
else
{
FatalErrorIn
(
"addPatch(const polyBoundaryMesh&,"
" const word&, DynamicList)"
) << "Already have patch " << patchName
<< " but of type " << newPatches[patchI]->type()
<< exit(FatalError);
}
}
patchI = newPatches.size();
label startFaceI = 0;
if (patchI > 0)
{
const polyPatch& pp = *newPatches.last();
startFaceI = pp.start()+pp.size();
}
dictionary patchDict(dict);
patchDict.set("type", PatchType::typeName);
patchDict.set("nFaces", 0);
patchDict.set("startFace", startFaceI);
newPatches.append
(
polyPatch::New
(
patchName,
patchDict,
patchI,
patches
).ptr()
);
return patchI;
}
// 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);
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);
trimPatchFields(mesh, nNewPatches);
trimPatchFields(mesh, nNewPatches);
}
// Remove zero-sized patches
void deleteEmptyPatches(fvMesh& mesh)
{
const polyBoundaryMesh& patches = mesh.boundaryMesh();
wordList masterNames;
if (Pstream::master())
{
masterNames = patches.names();
}
Pstream::scatter(masterNames);
labelList oldToNew(patches.size(), -1);
label usedI = 0;
label notUsedI = patches.size();
// Add all the non-empty, non-processor patches
forAll(masterNames, masterI)
{
label patchI = patches.findPatchID(masterNames[masterI]);
if (patchI != -1)
{
if (isA(patches[patchI]))
{
// Similar named processor patch? Not 'possible'.
if (patches[patchI].size() == 0)
{
Pout<< "Deleting processor patch " << patchI
<< " name:" << patches[patchI].name()
<< endl;
oldToNew[patchI] = --notUsedI;
}
else
{
oldToNew[patchI] = usedI++;
}
}
else
{
// Common patch.
if (returnReduce(patches[patchI].size(), sumOp