mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: cellDecomposer: functionObject to map fields.
Left out original files
This commit is contained in:
415
src/functionObjects/field/cellDecomposer/cellDecomposer.C
Normal file
415
src/functionObjects/field/cellDecomposer/cellDecomposer.C
Normal file
@ -0,0 +1,415 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | www.openfoam.com
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2024 OpenCFD Ltd.
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "cellDecomposer.H"
|
||||||
|
#include "addToRunTimeSelectionTable.H"
|
||||||
|
#include "polyTopoChange.H"
|
||||||
|
#include "mapPolyMesh.H"
|
||||||
|
#include "tetDecomposer.H"
|
||||||
|
#include "syncTools.H"
|
||||||
|
#include "dummyTransform.H"
|
||||||
|
#include "ReadFields.H"
|
||||||
|
#include "surfaceFields.H"
|
||||||
|
#include "PackedBoolList.H"
|
||||||
|
#include "fvMeshTools.H"
|
||||||
|
#include "cellSetOption.H"
|
||||||
|
#include "cellBitSet.H"
|
||||||
|
#include "cellSet.H"
|
||||||
|
#include "hexMatcher.H"
|
||||||
|
#include "prismMatcher.H"
|
||||||
|
#include "pyrMatcher.H"
|
||||||
|
#include "tetMatcher.H"
|
||||||
|
|
||||||
|
#include "OBJstream.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
namespace functionObjects
|
||||||
|
{
|
||||||
|
defineTypeNameAndDebug(cellDecomposer, 0);
|
||||||
|
addToRunTimeSelectionTable(functionObject, cellDecomposer, dictionary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||||
|
|
||||||
|
void Foam::functionObjects::cellDecomposer::makeMesh
|
||||||
|
(
|
||||||
|
const dictionary& dict,
|
||||||
|
const word& regionName
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Info<< name() << ':' << nl
|
||||||
|
<< " Decomposing cells to region " << regionName << endl;
|
||||||
|
|
||||||
|
Info<< incrIndent;
|
||||||
|
|
||||||
|
const fv::cellSetOption::selectionModeType selectionMode
|
||||||
|
(
|
||||||
|
fv::cellSetOption::selectionModeTypeNames_.get
|
||||||
|
(
|
||||||
|
"selectionMode",
|
||||||
|
dict
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// Start off from existing mesh
|
||||||
|
polyTopoChange meshMod(mesh_);
|
||||||
|
|
||||||
|
tetDecompPtr_.reset(new Foam::tetDecomposer(mesh_));
|
||||||
|
|
||||||
|
// Default values
|
||||||
|
bitSet decomposeCell(mesh_.nCells());
|
||||||
|
autoPtr<bitSet> decomposeFacePtr;
|
||||||
|
tetDecomposer::decompositionType decompType
|
||||||
|
(
|
||||||
|
tetDecomposer::FACE_CENTRE_TRIS
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
switch (selectionMode)
|
||||||
|
{
|
||||||
|
case fv::cellSetOption::smAll:
|
||||||
|
{
|
||||||
|
Info<< indent << "- selecting all cells" << endl;
|
||||||
|
|
||||||
|
decomposeCell = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case fv::cellSetOption::smGeometric:
|
||||||
|
{
|
||||||
|
Info<< indent << "- selecting cells geometrically" << endl;
|
||||||
|
|
||||||
|
decomposeCell =
|
||||||
|
cellBitSet::select(mesh_, dict.subDict("selection"), true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case fv::cellSetOption::smCellSet:
|
||||||
|
{
|
||||||
|
const word selectionName(dict.get<word>("cellSet"));
|
||||||
|
|
||||||
|
Info<< indent
|
||||||
|
<< "- selecting cells using cellSet "
|
||||||
|
<< selectionName << endl;
|
||||||
|
|
||||||
|
decomposeCell.set
|
||||||
|
(
|
||||||
|
cellSet(mesh_, selectionName, IOobject::MUST_READ).toc()
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case fv::cellSetOption::smCellZone:
|
||||||
|
{
|
||||||
|
wordRes selectionNames;
|
||||||
|
if
|
||||||
|
(
|
||||||
|
!dict.readIfPresent("cellZones", selectionNames)
|
||||||
|
|| selectionNames.empty()
|
||||||
|
)
|
||||||
|
{
|
||||||
|
selectionNames.resize(1);
|
||||||
|
dict.readEntry("cellZone", selectionNames.first());
|
||||||
|
}
|
||||||
|
|
||||||
|
Info<< indent
|
||||||
|
<< "- selecting cells using cellZones "
|
||||||
|
<< flatOutput(selectionNames) << nl;
|
||||||
|
|
||||||
|
const auto& zones = mesh_.cellZones();
|
||||||
|
|
||||||
|
// Also handles groups, multiple zones etc ...
|
||||||
|
labelList zoneIDs = zones.indices(selectionNames);
|
||||||
|
|
||||||
|
if (zoneIDs.empty())
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "No matching cellZones: "
|
||||||
|
<< flatOutput(selectionNames) << nl
|
||||||
|
<< "Valid zones : "
|
||||||
|
<< flatOutput(zones.names()) << nl
|
||||||
|
<< "Valid groups: "
|
||||||
|
<< flatOutput(zones.groupNames())
|
||||||
|
<< nl
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zoneIDs.size() == 1)
|
||||||
|
{
|
||||||
|
decomposeCell.set(zones[zoneIDs.first()]);
|
||||||
|
// TBD: Foam::sort(cells_);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
decomposeCell.set(zones.selection(zoneIDs).sortedToc());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "Unsupported selectionMode "
|
||||||
|
<< fv::cellSetOption::selectionModeTypeNames_[selectionMode]
|
||||||
|
<< ". Valid selectionMode types are "
|
||||||
|
<< fv::cellSetOption::selectionModeTypeNames_
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
word decompTypeName;
|
||||||
|
if (dict.readIfPresent("decomposeType", decompTypeName))
|
||||||
|
{
|
||||||
|
if (decompTypeName == "polyhedral")
|
||||||
|
{
|
||||||
|
// Automatic selection to generate hex/prism/tet only
|
||||||
|
// - subset decomposeCell to exclude hex/prism/tet
|
||||||
|
// - set faces to FACE_DIAG_QUADS
|
||||||
|
// Usually start with cellSetOption::smAll
|
||||||
|
decomposeFacePtr.reset(new bitSet(mesh_.nFaces()));
|
||||||
|
auto& decomposeFace = decomposeFacePtr();
|
||||||
|
|
||||||
|
decompType = tetDecomposer::FACE_DIAG_QUADS;
|
||||||
|
bitSet oldDecomposeCell(decomposeCell);
|
||||||
|
decomposeCell = false;
|
||||||
|
|
||||||
|
// Construct shape recognizers
|
||||||
|
prismMatcher prism;
|
||||||
|
|
||||||
|
for (const label celli : oldDecomposeCell)
|
||||||
|
{
|
||||||
|
if
|
||||||
|
(
|
||||||
|
!hexMatcher::test(mesh_, celli)
|
||||||
|
&& !tetMatcher::test(mesh_, celli)
|
||||||
|
&& !pyrMatcher::test(mesh_, celli)
|
||||||
|
&& !prism.isA(mesh_, celli)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
decomposeCell.set(celli);
|
||||||
|
decomposeFace.set(mesh_.cells()[celli]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sync boundary info
|
||||||
|
syncTools::syncFaceList
|
||||||
|
(
|
||||||
|
mesh_,
|
||||||
|
decomposeFace,
|
||||||
|
orEqOp<unsigned int>()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
decompType = tetDecomposer::decompositionTypeNames[decompTypeName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Insert all changes to create tets
|
||||||
|
if (decomposeFacePtr)
|
||||||
|
{
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
OBJstream os(mesh_.time().path()/"orig_faces.obj");
|
||||||
|
os.write
|
||||||
|
(
|
||||||
|
UIndirectList<face>
|
||||||
|
(
|
||||||
|
mesh_.faces(),
|
||||||
|
decomposeFacePtr().sortedToc()
|
||||||
|
)(),
|
||||||
|
mesh_.points(),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
Pout<< "Written " << meshMod.faces().size()
|
||||||
|
<< " faces to " << os.name() << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
tetDecompPtr_().setRefinement
|
||||||
|
(
|
||||||
|
decompType, //Foam::tetDecomposer::FACE_CENTRE_TRIS,
|
||||||
|
decomposeCell,
|
||||||
|
decomposeFacePtr(),
|
||||||
|
meshMod
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tetDecompPtr_().setRefinement
|
||||||
|
(
|
||||||
|
decompType, //Foam::tetDecomposer::FACE_CENTRE_TRIS,
|
||||||
|
decomposeCell,
|
||||||
|
meshMod
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
{
|
||||||
|
OBJstream os(mesh_.time().path()/"faces.obj");
|
||||||
|
os.write(meshMod.faces(), pointField(meshMod.points()), false);
|
||||||
|
Pout<< "Written " << meshMod.faces().size()
|
||||||
|
<< " faces to " << os.name() << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
autoPtr<fvMesh> tetMeshPtr;
|
||||||
|
|
||||||
|
mapPtr_ = meshMod.makeMesh
|
||||||
|
(
|
||||||
|
tetMeshPtr,
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
regionName,
|
||||||
|
mesh_.facesInstance(), // same instance as original mesh
|
||||||
|
mesh_.time(), //? why same database? TBD.
|
||||||
|
IOobject::READ_IF_PRESENT, // Read fv* if present
|
||||||
|
IOobject::AUTO_WRITE,
|
||||||
|
IOobject::REGISTER
|
||||||
|
),
|
||||||
|
mesh_
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
//- Update numbering on tet-decomposition engine
|
||||||
|
tetDecompPtr_().updateMesh(mapPtr_());
|
||||||
|
|
||||||
|
Info<< indent << "Writing decomposed mesh to "
|
||||||
|
<< tetMeshPtr().objectRegistry::objectRelPath()
|
||||||
|
<< endl;
|
||||||
|
tetMeshPtr().write();
|
||||||
|
|
||||||
|
fvMeshTools::createDummyFvMeshFiles(mesh_.time(), regionName, true);
|
||||||
|
|
||||||
|
// Store new mesh on object registry
|
||||||
|
tetMeshPtr.ptr()->polyMesh::store();
|
||||||
|
|
||||||
|
Info<< decrIndent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::functionObjects::cellDecomposer::cellDecomposer
|
||||||
|
(
|
||||||
|
const word& name,
|
||||||
|
const Time& runTime,
|
||||||
|
const dictionary& dict
|
||||||
|
)
|
||||||
|
:
|
||||||
|
fvMeshFunctionObject(name, runTime, dict)
|
||||||
|
{
|
||||||
|
read(dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
bool Foam::functionObjects::cellDecomposer::read(const dictionary& dict)
|
||||||
|
{
|
||||||
|
if (fvMeshFunctionObject::read(dict))
|
||||||
|
{
|
||||||
|
// Generate new tet equivalent mesh. TBD: why meshObject?
|
||||||
|
//meshObjects::tetDecomposition::New(mesh, dict);
|
||||||
|
|
||||||
|
dict_ = dict.optionalSubDict(typeName + "Coeffs");
|
||||||
|
dict_.readEntry("mapRegion", mapRegion_);
|
||||||
|
dict_.readEntry("fields", fieldNames_);
|
||||||
|
makeMesh(dict_, mapRegion_);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::functionObjects::cellDecomposer::execute()
|
||||||
|
{
|
||||||
|
Log << type() << " " << name() << " execute:" << nl;
|
||||||
|
|
||||||
|
bool ok = false;
|
||||||
|
|
||||||
|
if (mesh_.changing())
|
||||||
|
{
|
||||||
|
// Re-do mesh. Currently rebuilds whole mesh. Could move points only
|
||||||
|
// for mesh motion.
|
||||||
|
tetDecompPtr_.clear();
|
||||||
|
mapPtr_.clear();
|
||||||
|
const_cast<Time&>(this->mesh_.time()).erase(mapRegion_);
|
||||||
|
makeMesh(dict_, mapRegion_);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Look up
|
||||||
|
ok = mapFieldType<scalar>() || ok;
|
||||||
|
ok = mapFieldType<vector>() || ok;
|
||||||
|
ok = mapFieldType<sphericalTensor>() || ok;
|
||||||
|
ok = mapFieldType<symmTensor>() || ok;
|
||||||
|
ok = mapFieldType<tensor>() || ok;
|
||||||
|
|
||||||
|
if (log)
|
||||||
|
{
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
Info<< " none" << nl;
|
||||||
|
}
|
||||||
|
|
||||||
|
Info<< endl;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::functionObjects::cellDecomposer::write()
|
||||||
|
{
|
||||||
|
Log << type() << " " << name() << " write:" << nl;
|
||||||
|
|
||||||
|
bool ok = false;
|
||||||
|
|
||||||
|
ok = writeFieldType<scalar>() || ok;
|
||||||
|
ok = writeFieldType<vector>() || ok;
|
||||||
|
ok = writeFieldType<sphericalTensor>() || ok;
|
||||||
|
ok = writeFieldType<symmTensor>() || ok;
|
||||||
|
ok = writeFieldType<tensor>() || ok;
|
||||||
|
|
||||||
|
if (log)
|
||||||
|
{
|
||||||
|
if (!ok)
|
||||||
|
{
|
||||||
|
Info<< " none" << nl;
|
||||||
|
}
|
||||||
|
|
||||||
|
Info<< endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
226
src/functionObjects/field/cellDecomposer/cellDecomposer.H
Normal file
226
src/functionObjects/field/cellDecomposer/cellDecomposer.H
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | www.openfoam.com
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2024 OpenCFD Ltd.
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Class
|
||||||
|
Foam::functionObjects::cellDecomposer
|
||||||
|
|
||||||
|
Group
|
||||||
|
grpFieldFunctionObjects
|
||||||
|
|
||||||
|
Description
|
||||||
|
Maps input fields from local mesh to a secondary mesh at runtime.
|
||||||
|
|
||||||
|
The secondary mesh gets created on-the-fly by decomposing the current mesh.
|
||||||
|
|
||||||
|
|
||||||
|
Operands:
|
||||||
|
\table
|
||||||
|
Operand | Type | Location
|
||||||
|
input | {vol,surface}\<Type\>Field <!--
|
||||||
|
--> | $FOAM_CASE/\<time\>/\<inpField\>
|
||||||
|
output file | - | -
|
||||||
|
output field | {vol,surface}\<Type\>Field <!--
|
||||||
|
--> | $FOAM_CASE/\<time\>/\<outField\>
|
||||||
|
\endtable
|
||||||
|
|
||||||
|
where \c \<Type\>=Scalar/Vector/SphericalTensor/SymmTensor/Tensor.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
Minimal example by using \c system/controlDict.functions:
|
||||||
|
\verbatim
|
||||||
|
cellDecomposer1
|
||||||
|
{
|
||||||
|
// Mandatory entries (unmodifiable)
|
||||||
|
type cellDecomposer;
|
||||||
|
libs (fieldFunctionObjects);
|
||||||
|
|
||||||
|
// Mandatory (inherited) entries (runtime modifiable)
|
||||||
|
fields (<field1> <field2> ... <fieldN>);
|
||||||
|
mapRegion myTetMesh;
|
||||||
|
...
|
||||||
|
// Mandatory entries
|
||||||
|
// Decompose type:
|
||||||
|
decomposeType polyhedral;
|
||||||
|
// Cell set to decompose
|
||||||
|
selectionMode all;
|
||||||
|
}
|
||||||
|
\endverbatim
|
||||||
|
|
||||||
|
where the entries mean:
|
||||||
|
\table
|
||||||
|
Property | Description | Type | Req'd | Dflt
|
||||||
|
type | Type name: cellDecomposer | word | yes | -
|
||||||
|
libs | Library name: fieldFunctionObjects | word | yes | -
|
||||||
|
fields | Names of operand fields | wordList | yes | -
|
||||||
|
mapRegion | Name of region to map to | word | yes | -
|
||||||
|
decomposeType | How to decompose cells | word | yes | -
|
||||||
|
selectionMode | How to select cells (see fvOption)| word | yes | -
|
||||||
|
\endtable
|
||||||
|
|
||||||
|
decomposeType:
|
||||||
|
- faceCentre : decompose cells into tets using face centre and cell centre.
|
||||||
|
(hex becomes 6*4 tets)
|
||||||
|
- faceDiagonal : decompose cells into tets using face diagonal, similar
|
||||||
|
to implicit decomposition inside lagrangian tracking.
|
||||||
|
(hex becomes 6*2 tets)
|
||||||
|
- pyramid : keep faces intact but create (polygonal-base) pyramids using
|
||||||
|
cell centre (hex becomes 6 pyramids)
|
||||||
|
- faceDiagonalQuads : like faceDiagonal but split faces into quads and
|
||||||
|
triangles instead of just triangles
|
||||||
|
- polyhedral : like faceDiagonalQuads but only decompose non-hex/prism/tet
|
||||||
|
cells in selected set. Used to convert polyhedral mesh into
|
||||||
|
'simple' mesh.
|
||||||
|
|
||||||
|
The inherited entries are elaborated in:
|
||||||
|
- \link functionObject.H \endlink
|
||||||
|
|
||||||
|
See also
|
||||||
|
- Foam::functionObjects::mapFields
|
||||||
|
|
||||||
|
SourceFiles
|
||||||
|
cellDecomposer.C
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef functionObjects_cellDecomposer_H
|
||||||
|
#define functionObjects_cellDecomposer_H
|
||||||
|
|
||||||
|
#include "fvMeshFunctionObject.H"
|
||||||
|
#include "volFieldsFwd.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
|
||||||
|
class tetDecomposer;
|
||||||
|
class mapPolyMesh;
|
||||||
|
|
||||||
|
namespace functionObjects
|
||||||
|
{
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
Class cellDecomposer Declaration
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
class cellDecomposer
|
||||||
|
:
|
||||||
|
public fvMeshFunctionObject
|
||||||
|
{
|
||||||
|
// Private Data
|
||||||
|
|
||||||
|
//- Parameter dictionary
|
||||||
|
dictionary dict_;
|
||||||
|
|
||||||
|
//- Name of new mesh
|
||||||
|
word mapRegion_;
|
||||||
|
|
||||||
|
//- List of field names to interpolate
|
||||||
|
wordRes fieldNames_;
|
||||||
|
|
||||||
|
//- Tet decomposer
|
||||||
|
autoPtr<tetDecomposer> tetDecompPtr_;
|
||||||
|
|
||||||
|
//- Map from polyMesh to tet-mesh
|
||||||
|
autoPtr<mapPolyMesh> mapPtr_;
|
||||||
|
|
||||||
|
|
||||||
|
// Private Member Functions
|
||||||
|
|
||||||
|
//- Generate mesh
|
||||||
|
void makeMesh(const dictionary& dict, const word& name);
|
||||||
|
|
||||||
|
//- Helper function to map the \<Type\> fields
|
||||||
|
template<class Type>
|
||||||
|
bool mapFieldType() const;
|
||||||
|
|
||||||
|
//- Helper function to write the \<Type\> fields
|
||||||
|
template<class Type>
|
||||||
|
bool writeFieldType() const;
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
tmp<GeometricField<Type, fvPatchField, volMesh>>
|
||||||
|
interpolate
|
||||||
|
(
|
||||||
|
const GeometricField<Type, fvPatchField, volMesh>& vf,
|
||||||
|
const fvMesh& sMesh,
|
||||||
|
const labelUList& patchMap,
|
||||||
|
const labelUList& cellMap,
|
||||||
|
const labelUList& faceMap,
|
||||||
|
const bool allowUnmapped
|
||||||
|
) const;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
//- Runtime type information
|
||||||
|
TypeName("cellDecomposer");
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
|
||||||
|
//- Construct from Time and dictionary
|
||||||
|
cellDecomposer
|
||||||
|
(
|
||||||
|
const word& name,
|
||||||
|
const Time& runTime,
|
||||||
|
const dictionary& dict
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
//- Destructor
|
||||||
|
virtual ~cellDecomposer() = default;
|
||||||
|
|
||||||
|
|
||||||
|
// Member Functions
|
||||||
|
|
||||||
|
//- Read the cellDecomposer data
|
||||||
|
virtual bool read(const dictionary& dict);
|
||||||
|
|
||||||
|
//- Execute
|
||||||
|
virtual bool execute();
|
||||||
|
|
||||||
|
//- Write
|
||||||
|
virtual bool write();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
} // End namespace functionObjects
|
||||||
|
} // End namespace Foam
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
#ifdef NoRepository
|
||||||
|
#include "cellDecomposerTemplates.C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -0,0 +1,364 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | www.openfoam.com
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2024 OpenCFD Ltd.
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "fvMesh.H"
|
||||||
|
#include "emptyFvPatchFields.H"
|
||||||
|
#include "directFvPatchFieldMapper.H"
|
||||||
|
#include "mapPolyMesh.H"
|
||||||
|
//#include "polyPatch.H"
|
||||||
|
//#include "lduSchedule.H"
|
||||||
|
//#include "meshToMesh.H"
|
||||||
|
|
||||||
|
//template<class Type>
|
||||||
|
//void Foam::functionObjects::cellDecomposer::evaluateConstraintTypes
|
||||||
|
//(
|
||||||
|
// GeometricField<Type, fvPatchField, volMesh>& fld
|
||||||
|
//) const
|
||||||
|
//{
|
||||||
|
// auto& fldBf = fld.boundaryFieldRef();
|
||||||
|
//
|
||||||
|
// const UPstream::commsTypes commsType = UPstream::defaultCommsType;
|
||||||
|
// const label startOfRequests = UPstream::nRequests();
|
||||||
|
//
|
||||||
|
// if
|
||||||
|
// (
|
||||||
|
// commsType == UPstream::commsTypes::blocking
|
||||||
|
// || commsType == UPstream::commsTypes::nonBlocking
|
||||||
|
// )
|
||||||
|
// {
|
||||||
|
// forAll(fldBf, patchi)
|
||||||
|
// {
|
||||||
|
// fvPatchField<Type>& tgtField = fldBf[patchi];
|
||||||
|
//
|
||||||
|
// if
|
||||||
|
// (
|
||||||
|
// tgtField.type() == tgtField.patch().patch().type()
|
||||||
|
// && polyPatch::constraintType(tgtField.patch().patch().type())
|
||||||
|
// )
|
||||||
|
// {
|
||||||
|
// tgtField.initEvaluate(commsType);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // Wait for outstanding requests
|
||||||
|
// if (commsType == UPstream::commsTypes::nonBlocking)
|
||||||
|
// {
|
||||||
|
// UPstream::waitRequests(startOfRequests);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// forAll(fldBf, patchi)
|
||||||
|
// {
|
||||||
|
// fvPatchField<Type>& tgtField = fldBf[patchi];
|
||||||
|
//
|
||||||
|
// if
|
||||||
|
// (
|
||||||
|
// tgtField.type() == tgtField.patch().patch().type()
|
||||||
|
// && polyPatch::constraintType(tgtField.patch().patch().type())
|
||||||
|
// )
|
||||||
|
// {
|
||||||
|
// tgtField.evaluate(commsType);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else if (commsType == UPstream::commsTypes::scheduled)
|
||||||
|
// {
|
||||||
|
// const lduSchedule& patchSchedule =
|
||||||
|
// fld.mesh().globalData().patchSchedule();
|
||||||
|
//
|
||||||
|
// for (const auto& schedEval : patchSchedule)
|
||||||
|
// {
|
||||||
|
// const label patchi = schedEval.patch;
|
||||||
|
//
|
||||||
|
// fvPatchField<Type>& tgtField = fldBf[patchi];
|
||||||
|
//
|
||||||
|
// if
|
||||||
|
// (
|
||||||
|
// tgtField.type() == tgtField.patch().patch().type()
|
||||||
|
// && polyPatch::constraintType(tgtField.patch().patch().type())
|
||||||
|
// )
|
||||||
|
// {
|
||||||
|
// if (schedEval.init)
|
||||||
|
// {
|
||||||
|
// tgtField.initEvaluate(commsType);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// tgtField.evaluate(commsType);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
Foam::tmp
|
||||||
|
<
|
||||||
|
Foam::GeometricField<Type, Foam::fvPatchField, Foam::volMesh>
|
||||||
|
>
|
||||||
|
Foam::functionObjects::cellDecomposer::interpolate
|
||||||
|
(
|
||||||
|
const GeometricField<Type, fvPatchField, volMesh>& vf,
|
||||||
|
const fvMesh& sMesh,
|
||||||
|
const labelUList& patchMap,
|
||||||
|
const labelUList& cellMap,
|
||||||
|
const labelUList& faceMap,
|
||||||
|
const bool allowUnmapped
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
// 1. Create the complete field with dummy patch fields
|
||||||
|
PtrList<fvPatchField<Type>> patchFields(patchMap.size());
|
||||||
|
|
||||||
|
forAll(patchFields, patchi)
|
||||||
|
{
|
||||||
|
// Set the first one by hand as it corresponds to the
|
||||||
|
// exposed internal faces. Additional interpolation can be put here
|
||||||
|
// as necessary.
|
||||||
|
if (patchMap[patchi] == -1)
|
||||||
|
{
|
||||||
|
patchFields.set
|
||||||
|
(
|
||||||
|
patchi,
|
||||||
|
new emptyFvPatchField<Type>
|
||||||
|
(
|
||||||
|
sMesh.boundary()[patchi],
|
||||||
|
fvPatchField<Type>::Internal::null()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
patchFields.set
|
||||||
|
(
|
||||||
|
patchi,
|
||||||
|
fvPatchField<Type>::New
|
||||||
|
(
|
||||||
|
fvPatchFieldBase::calculatedType(),
|
||||||
|
sMesh.boundary()[patchi],
|
||||||
|
fvPatchField<Type>::Internal::null()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto tresult = tmp<GeometricField<Type, fvPatchField, volMesh>>::New
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
"subset"+vf.name(),
|
||||||
|
sMesh.time().timeName(),
|
||||||
|
sMesh,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::NO_WRITE
|
||||||
|
),
|
||||||
|
sMesh,
|
||||||
|
vf.dimensions(),
|
||||||
|
Field<Type>(vf.primitiveField(), cellMap),
|
||||||
|
patchFields
|
||||||
|
);
|
||||||
|
auto& result = tresult.ref();
|
||||||
|
result.oriented() = vf.oriented();
|
||||||
|
|
||||||
|
|
||||||
|
// 2. Change the fvPatchFields to the correct type using a mapper
|
||||||
|
// constructor (with reference to the now correct internal field)
|
||||||
|
|
||||||
|
auto& bf = result.boundaryFieldRef();
|
||||||
|
|
||||||
|
forAll(bf, patchi)
|
||||||
|
{
|
||||||
|
const label basePatchId = patchMap[patchi];
|
||||||
|
|
||||||
|
if (basePatchId != -1)
|
||||||
|
{
|
||||||
|
// Construct addressing
|
||||||
|
const fvPatch& subPatch = sMesh.boundary()[patchi];
|
||||||
|
const fvPatch& basePatch = vf.mesh().boundary()[basePatchId];
|
||||||
|
const label baseStart = basePatch.start();
|
||||||
|
const label baseSize = basePatch.size();
|
||||||
|
|
||||||
|
labelList directAddressing(subPatch.size());
|
||||||
|
|
||||||
|
forAll(directAddressing, i)
|
||||||
|
{
|
||||||
|
const label baseFacei = faceMap[subPatch.start()+i];
|
||||||
|
|
||||||
|
if (baseFacei >= baseStart && baseFacei < baseStart+baseSize)
|
||||||
|
{
|
||||||
|
directAddressing[i] = baseFacei-baseStart;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Mapped from internal face. Do what? Leave up to
|
||||||
|
// fvPatchField
|
||||||
|
directAddressing[i] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
directFvPatchFieldMapper mapper(directAddressing);
|
||||||
|
|
||||||
|
// allowUnmapped : special mode for if we do not want to be
|
||||||
|
// warned for unmapped faces (e.g. from fvMeshDistribute).
|
||||||
|
|
||||||
|
const bool hasUnmapped = mapper.hasUnmapped();
|
||||||
|
if (allowUnmapped)
|
||||||
|
{
|
||||||
|
mapper.hasUnmapped() = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bf.set
|
||||||
|
(
|
||||||
|
patchi,
|
||||||
|
fvPatchField<Type>::New
|
||||||
|
(
|
||||||
|
vf.boundaryField()[basePatchId],
|
||||||
|
subPatch,
|
||||||
|
result.internalField(),
|
||||||
|
mapper
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (allowUnmapped && hasUnmapped)
|
||||||
|
{
|
||||||
|
// Set unmapped values to zeroGradient. This is the default
|
||||||
|
// action for unmapped fvPatchFields. Note that this bypasses
|
||||||
|
// any special logic for handling unmapped fvPatchFields but
|
||||||
|
// since this is only used inside fvMeshDistribute ...
|
||||||
|
|
||||||
|
tmp<Field<Type>> tfld(bf[patchi].patchInternalField());
|
||||||
|
const Field<Type>& fld = tfld();
|
||||||
|
|
||||||
|
Field<Type> value(bf[patchi]);
|
||||||
|
forAll(directAddressing, i)
|
||||||
|
{
|
||||||
|
if (directAddressing[i] == -1)
|
||||||
|
{
|
||||||
|
value[i] = fld[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bf[patchi].fvPatchField<Type>::operator=(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tresult;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
bool Foam::functionObjects::cellDecomposer::mapFieldType() const
|
||||||
|
{
|
||||||
|
typedef GeometricField<Type, fvPatchField, volMesh> VolFieldType;
|
||||||
|
|
||||||
|
const fvMesh& mapRegion =
|
||||||
|
this->mesh_.time().lookupObject<fvMesh>(mapRegion_);
|
||||||
|
|
||||||
|
const labelList patchMap(identity(mapRegion.boundaryMesh().size()));
|
||||||
|
|
||||||
|
const wordList fieldNames
|
||||||
|
(
|
||||||
|
this->mesh_.sortedNames<VolFieldType>(fieldNames_)
|
||||||
|
);
|
||||||
|
|
||||||
|
const bool processed = !fieldNames.empty();
|
||||||
|
|
||||||
|
for (const word& fieldName : fieldNames)
|
||||||
|
{
|
||||||
|
const VolFieldType& field = lookupObject<VolFieldType>(fieldName);
|
||||||
|
|
||||||
|
auto* mapFieldPtr = mapRegion.getObjectPtr<VolFieldType>(fieldName);
|
||||||
|
|
||||||
|
if (!mapFieldPtr)
|
||||||
|
{
|
||||||
|
mapFieldPtr = new VolFieldType
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
fieldName,
|
||||||
|
time_.timeName(),
|
||||||
|
mapRegion,
|
||||||
|
IOobject::NO_READ,
|
||||||
|
IOobject::NO_WRITE,
|
||||||
|
IOobject::REGISTER
|
||||||
|
),
|
||||||
|
mapRegion,
|
||||||
|
dimensioned<Type>(field.dimensions(), Zero)
|
||||||
|
);
|
||||||
|
|
||||||
|
mapFieldPtr->store();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& mappedField = *mapFieldPtr;
|
||||||
|
|
||||||
|
mappedField = interpolate
|
||||||
|
(
|
||||||
|
field,
|
||||||
|
mapRegion,
|
||||||
|
patchMap,
|
||||||
|
mapPtr_().cellMap(),
|
||||||
|
mapPtr_().faceMap(),
|
||||||
|
false //allowUnmapped
|
||||||
|
);
|
||||||
|
Log << " " << fieldName << ": interpolated";
|
||||||
|
|
||||||
|
//evaluateConstraintTypes(mappedField);
|
||||||
|
}
|
||||||
|
|
||||||
|
return processed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class Type>
|
||||||
|
bool Foam::functionObjects::cellDecomposer::writeFieldType() const
|
||||||
|
{
|
||||||
|
typedef GeometricField<Type, fvPatchField, volMesh> VolFieldType;
|
||||||
|
|
||||||
|
const fvMesh& mapRegion =
|
||||||
|
this->mesh_.time().lookupObject<fvMesh>(mapRegion_);
|
||||||
|
|
||||||
|
const wordList fieldNames
|
||||||
|
(
|
||||||
|
this->mesh_.sortedNames<VolFieldType>(fieldNames_)
|
||||||
|
);
|
||||||
|
|
||||||
|
const bool processed = !fieldNames.empty();
|
||||||
|
|
||||||
|
for (const word& fieldName : fieldNames)
|
||||||
|
{
|
||||||
|
const VolFieldType& mappedField =
|
||||||
|
mapRegion.template lookupObject<VolFieldType>(fieldName);
|
||||||
|
|
||||||
|
mappedField.write();
|
||||||
|
|
||||||
|
Log << " " << fieldName << ": written";
|
||||||
|
}
|
||||||
|
|
||||||
|
return processed;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
Reference in New Issue
Block a user