Enabled dynamic refinement in immersed boundary dynamic mesh

This commit is contained in:
Hrvoje Jasak 2018-05-16 15:10:47 +01:00
parent e90bc3a893
commit 4a16503359
6 changed files with 341 additions and 677 deletions

View file

@ -2,6 +2,9 @@ movingImmersedBoundary/movingImmersedBoundary.C
refineImmersedBoundaryMesh/refineImmersedBoundaryMesh.C
immersedBoundarySolidBodyMotionFvMesh/immersedBoundarySolidBodyMotionFvMesh.C
immersedBoundaryRefinement/immersedBoundaryRefinement.C
immersedBoundaryDynamicRefineSolidBodyMotionFvMesh/immersedBoundaryDynamicRefineSolidBodyMotionFvMesh.C
LIB = $(FOAM_LIBBIN)/libimmersedBoundaryDynamicMesh

View file

@ -6,6 +6,7 @@ EXE_INC = \
-I$(LIB_SRC)/sampling/lnInclude \
-I$(LIB_SRC)/dynamicMesh/dynamicMesh/lnInclude \
-I$(LIB_SRC)/dynamicMesh/dynamicFvMesh/lnInclude \
-I$(LIB_SRC)/dynamicMesh/topoChangerFvMesh/lnInclude \
-I$(LIB_SRC)/dynamicMesh/meshMotion/solidBodyMotion/lnInclude
LIB_LIBS = \
@ -16,4 +17,5 @@ LIB_LIBS = \
-lsampling \
-ldynamicMesh \
-ldynamicFvMesh \
-ltopoChangerFvMesh \
-lsolidBodyMotion

View file

@ -55,444 +55,13 @@ addToRunTimeSelectionTable
} // End namespace Foam
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::label Foam::immersedBoundaryDynamicRefineSolidBodyMotionFvMesh::count
(
const PackedBoolList& l,
const unsigned int val
)
{
label n = 0;
forAll (l, i)
{
if (l.get(i) == val)
{
n++;
}
// debug also serves to get-around Clang compiler trying to optimise
// out this forAll loop under O3 optimisation
if (debug)
{
Info<< "n=" << n << endl;
}
}
return n;
}
Foam::autoPtr<Foam::mapPolyMesh>
Foam::immersedBoundaryDynamicRefineSolidBodyMotionFvMesh::refine
(
const labelList& cellsToRefine
)
{
// Mesh changing engine.
directTopoChange meshMod(*this);
// Play refinement commands into mesh changer.
meshCutter_.setRefinement(cellsToRefine, meshMod);
// Create mesh (with inflation), return map from old to new mesh.
//autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, true);
autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, false);
Info<< "Refined from "
<< returnReduce(map().nOldCells(), sumOp<label>())
<< " to " << globalData().nTotalCells() << " cells." << endl;
if (debug)
{
// Check map.
for (label faceI = 0; faceI < nInternalFaces(); faceI++)
{
label oldFaceI = map().faceMap()[faceI];
if (oldFaceI >= nInternalFaces())
{
FatalErrorIn
(
"immersedBoundaryDynamicRefineSolidBodyMotionFvMesh::"
"refine(const labelList&)"
) << "New internal face:" << faceI
<< " fc:" << faceCentres()[faceI]
<< " originates from boundary oldFace:" << oldFaceI
<< abort(FatalError);
}
}
}
// Update fields
updateMesh(map);
// Update numbering of cells/vertices.
meshCutter_.updateMesh(map);
// Debug: Check refinement levels (across faces only)
meshCutter_.checkRefinementLevels(-1, labelList(0));
return map;
}
Foam::autoPtr<Foam::mapPolyMesh>
Foam::immersedBoundaryDynamicRefineSolidBodyMotionFvMesh::unrefine
(
const labelList& splitPoints
)
{
directTopoChange meshMod(*this);
// Play refinement commands into mesh changer.
meshCutter_.setUnrefinement(splitPoints, meshMod);
// Save information on faces that will be combined
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Find the faceMidPoints on cells to be combined.
// for each face resulting of split of face into four store the
// midpoint
Map<label> faceToSplitPoint(3*splitPoints.size());
{
forAll (splitPoints, i)
{
label pointI = splitPoints[i];
const labelList& pEdges = pointEdges()[pointI];
forAll (pEdges, j)
{
label otherPointI = edges()[pEdges[j]].otherVertex(pointI);
const labelList& pFaces = pointFaces()[otherPointI];
forAll (pFaces, pFaceI)
{
faceToSplitPoint.insert(pFaces[pFaceI], otherPointI);
}
}
}
}
// Change mesh and generate map.
autoPtr<mapPolyMesh> map = meshMod.changeMesh(*this, false);
Info<< "Unrefined from "
<< returnReduce(map().nOldCells(), sumOp<label>())
<< " to " << globalData().nTotalCells() << " cells."
<< endl;
// Update fields
updateMesh(map);
// Update numbering of cells/vertices.
meshCutter_.updateMesh(map);
// Debug: Check refinement levels (across faces only)
meshCutter_.checkRefinementLevels(-1, labelList(0));
return map;
}
Foam::labelList
Foam::immersedBoundaryDynamicRefineSolidBodyMotionFvMesh::
selectRefineCells
(
const label maxCells,
const label maxRefLevel,
const scalar refinementDistance,
PackedBoolList& candidateCell
) const
{
// Calculate distance to immersed boundary
// Note: minimum distance is inside (WET) and implies a live cell
scalarField cellDistance(nCells(), -GREAT);
const vector span(GREAT, GREAT, GREAT);
forAll (boundaryMesh(), patchI)
{
if (isA<immersedBoundaryPolyPatch>(boundaryMesh()[patchI]))
{
const immersedBoundaryPolyPatch& ibPatch =
refCast<const immersedBoundaryPolyPatch>
(
boundaryMesh()[patchI]
);
// Create a distance function
triSurfaceDistance tsd
(
ibPatch.triSurfSearch(),
span,
ibPatch.internalFlow(),
false // Do not iterate
);
// Calculate distance
cellDistance = Foam::max
(
cellDistance,
tsd.distance(cellCentres())
);
}
}
Info<< "Cell distance: " << min(cellDistance) << " " << max(cellDistance) << endl;
// Create a sorting criterion
forAll (cellDistance, cellI)
{
if
(
cellDistance[cellI] > -refinementDistance
&& cellDistance[cellI] < 0
)
{
// Found a refinement cell
candidateCell.set(cellI, 1);
}
}
// Note: Assuming predominantly hex mesh, i.e. every refined cell causes 7
// extra cells. This might lead to slight over shoot of maximum number of
// cells.
label nTotToRefine = (maxCells - globalData().nTotalCells())/7;
const labelList& cellLevel = meshCutter_.cellLevel();
// Count current selection
label nCandidates = returnReduce(count(candidateCell, 1), sumOp<label>());
// Collect all cells
dynamicLabelList candidates(nCells());
if (nCandidates < nTotToRefine)
{
// We won't exceed the maximum number of cells. Collect all candidate
// cells that have refinement level smaller than max level
forAll (candidateCell, cellI)
{
if
(
cellLevel[cellI] < maxRefLevel
&& candidateCell.get(cellI) == 1
)
{
candidates.append(cellI);
}
}
}
else
{
// We will exceed the maximum number of cells. Simply truncate the
// list. It is possible to prefer certain cells based on error field.
for (label level = 0; level < maxRefLevel; level++)
{
forAll (candidateCell, cellI)
{
if
(
cellLevel[cellI] == level
&& candidateCell.get(cellI) == 1
)
{
candidates.append(cellI);
}
}
if (returnReduce(candidates.size(), sumOp<label>()) > nTotToRefine)
{
break;
}
}
}
// Guarantee 2:1 refinement after refinement
labelList consistentSet
(
meshCutter_.consistentRefinement
(
candidates.shrink(),
true // Add to set to guarantee 2:1
)
);
Info<< "Selected " << returnReduce(consistentSet.size(), sumOp<label>())
<< " cells for refinement out of " << globalData().nTotalCells()
<< "." << endl;
return consistentSet;
}
Foam::labelList
Foam::immersedBoundaryDynamicRefineSolidBodyMotionFvMesh::selectUnrefinePoints
(
const scalar coarsenDistance,
const PackedBoolList& markedCell
) const
{
// All points that can be unrefined
const labelList splitPointLabels = meshCutter_.getSplitPoints();
// Get split points from all points
pointField splitPoints(points(), splitPointLabels);
// Calculate distance to immersed boundary
// Note: minimum distance is inside (WET) and implies a live cell
scalarField splitPointDistance(splitPoints.size(), -GREAT);
const vector span(GREAT, GREAT, GREAT);
forAll (boundaryMesh(), patchI)
{
if (isA<immersedBoundaryPolyPatch>(boundaryMesh()[patchI]))
{
const immersedBoundaryPolyPatch& ibPatch =
refCast<const immersedBoundaryPolyPatch>
(
boundaryMesh()[patchI]
);
// Create a distance function
triSurfaceDistance tsd
(
ibPatch.triSurfSearch(),
span,
ibPatch.internalFlow(),
false // Do not iterate
);
// Calculate distance
splitPointDistance = Foam::max
(
splitPointDistance,
tsd.distance(splitPoints)
);
}
}
Info<< "Split point distance: " << min(splitPointDistance) << " " << max(splitPointDistance) << endl;
dynamicLabelList newSplitPoints(splitPointLabels.size());
const labelListList& pc = pointCells();
// Only checking split points
forAll (splitPointLabels, pointI)
{
// Coarse live cells next to immersed boundary or dead cells
if
(
splitPointDistance[pointI] < -coarsenDistance
|| splitPointDistance[pointI] > SMALL
)
{
// Check that all cells are not marked
const labelList& pCells = pc[splitPointLabels[pointI]];
bool hasMarked = false;
forAll (pCells, pCellI)
{
if (markedCell.get(pCells[pCellI]) == 1)
{
hasMarked = true;
break;
}
}
if (!hasMarked)
{
newSplitPoints.append(splitPointLabels[pointI]);
}
}
}
newSplitPoints.shrink();
// Guarantee 2:1 refinement after unrefinement
labelList consistentSet
(
meshCutter_.consistentUnrefinement
(
newSplitPoints,
false
)
);
Info<< "Selected " << returnReduce(consistentSet.size(), sumOp<label>())
<< " split points out of a possible "
<< returnReduce(splitPointLabels.size(), sumOp<label>())
<< "." << endl;
return consistentSet;
}
void Foam::immersedBoundaryDynamicRefineSolidBodyMotionFvMesh::extendMarkedCells
(
PackedBoolList& markedCell
) const
{
// Mark faces using any marked cell
boolList markedFace(nFaces(), false);
forAll (markedCell, cellI)
{
if (markedCell.get(cellI) == 1)
{
const cell& cFaces = cells()[cellI];
forAll (cFaces, i)
{
markedFace[cFaces[i]] = true;
}
}
}
syncTools::syncFaceList(*this, markedFace, orEqOp<bool>(), false);
const labelList& own = faceOwner();
const labelList& nei = faceNeighbour();
// Update cells using any markedFace
for (label faceI = 0; faceI < nInternalFaces(); faceI++)
{
if (markedFace[faceI])
{
markedCell.set(own[faceI], 1);
markedCell.set(nei[faceI], 1);
}
}
for (label faceI = nInternalFaces(); faceI < nFaces(); faceI++)
{
if (markedFace[faceI])
{
markedCell.set(own[faceI], 1);
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::immersedBoundaryDynamicRefineSolidBodyMotionFvMesh::
immersedBoundaryDynamicRefineSolidBodyMotionFvMesh(const IOobject& io)
:
dynamicFvMesh(io),
ibMotions_(),
meshCutter_(*this),
curTimeIndex_(-1),
nRefinementIterations_(0)
dynamicPolyRefinementFvMesh(io),
ibMotions_()
{
// Read motion function for all regions
dictionary dynamicMeshCoeffs
@ -510,7 +79,7 @@ immersedBoundaryDynamicRefineSolidBodyMotionFvMesh(const IOobject& io)
).subDict(typeName + "Coeffs")
);
PtrList<entry> motionDicts(dynamicMeshCoeffs.lookup("motionFunctions"));
PtrList<entry> motionDicts(refinementDict().lookup("motionFunctions"));
ibMotions_.setSize(motionDicts.size());
@ -542,76 +111,16 @@ immersedBoundaryDynamicRefineSolidBodyMotionFvMesh::
bool immersedBoundaryDynamicRefineSolidBodyMotionFvMesh::update()
{
// Handling multiple calls in a single time step
if (curTimeIndex_ == this->time().timeIndex())
if (!firstUpdate())
{
// This is not the first call to update, simply return false
return false;
}
// Re-read dictionary. Choosen since usually -small so trivial amount
// of time compared to actual refinement. Also very useful to be able
// to modify on-the-fly.
dictionary refineDict
(
IOdictionary
(
IOobject
(
"dynamicMeshDict",
time().constant(),
*this,
IOobject::MUST_READ,
IOobject::NO_WRITE,
false
)
).subDict(typeName + "Coeffs")
);
label refineInterval = readLabel(refineDict.lookup("refineInterval"));
const label maxRefLevel = readLabel(refineDict.lookup("maxRefLevel"));
const label maxCells = readLabel(refineDict.lookup("maxCells"));
if (refineInterval < 0)
{
WarningIn
(
"immersedBoundaryDynamicRefineSolidBodyMotionFvMesh::update()"
) << "Illegal refineInterval " << refineInterval << nl
<< "The refineInterval setting in the dynamicMeshDict should"
<< " be >= 1." << nl
<< exit(FatalError);
}
if (maxCells <= 0)
{
WarningIn
(
"immersedBoundaryDynamicRefineSolidBodyMotionFvMesh::update()"
) << "Illegal maximum number of cells " << maxCells << nl
<< "The maxCells setting in the dynamicMeshDict should"
<< " be > 0." << nl
<< exit(FatalError);
}
if (maxRefLevel <= 0)
{
WarningIn
(
"immersedBoundaryDynamicRefineSolidBodyMotionFvMesh::update()"
) << "Illegal maximum refinement level " << maxRefLevel << nl
<< "The maxCells setting in the dynamicMeshDict should"
<< " be > 0." << nl
<< exit(FatalError);
}
// Move points based on new motion
if (curTimeIndex_ < this->time().timeIndex())
else
{
// Grab old volumes before moving the mesh
// This MUST be followed by mesh motion. HJ, 29/Dec/2017
setV0();
curTimeIndex_ = this->time().timeIndex();
}
forAll (ibMotions_, ibI)
@ -619,135 +128,7 @@ bool immersedBoundaryDynamicRefineSolidBodyMotionFvMesh::update()
ibMotions_[ibI].movePoints();
}
bool hasChanged = false;
if
(
time().timeIndex() > 0
&& refineInterval > 0
&& maxCells > 1
&& maxRefLevel > 0
&& time().timeIndex() % refineInterval == 0)
{
const scalar coarseningDistance =
readScalar(refineDict.lookup("coarseningDistance"));
const scalar refinementDistance =
readScalar(refineDict.lookup("refinementDistance"));
const label nBufferLayers =
readLabel(refineDict.lookup("nBufferLayers"));
// Note:
// Positive cell distance implies a dead cell: coarsen if possible
// Negative cell distance implies live cell
// For negative distance greater than -refinementDistance, refine
// For neegative distance smaller than -coarseningDistance, coarsen
// Cells marked for refinement or otherwise protected from unrefinement.
PackedBoolList refineCell(nCells());
if (globalData().nTotalCells() < maxCells)
{
// Determine candidates for refinement
labelList cellsToRefine =
selectRefineCells
(
maxCells,
maxRefLevel,
refinementDistance,
refineCell
);
label nCellsToRefine = returnReduce
(
cellsToRefine.size(),
sumOp<label>()
);
if (nCellsToRefine > 0)
{
// Refine/update mesh and map fields
autoPtr<mapPolyMesh> map = refine(cellsToRefine);
// Update refineCell. Note that some of the marked ones have
// not been refined due to constraints.
{
const labelList& cellMap = map().cellMap();
const labelList& reverseCellMap = map().reverseCellMap();
PackedBoolList newRefineCell(cellMap.size());
forAll (cellMap, cellI)
{
label oldCellI = cellMap[cellI];
if (oldCellI < 0)
{
newRefineCell.set(cellI, 1);
}
else if (reverseCellMap[oldCellI] != cellI)
{
newRefineCell.set(cellI, 1);
}
else
{
newRefineCell.set(cellI, refineCell.get(oldCellI));
}
}
refineCell.transfer(newRefineCell);
}
// Extend with a buffer layer to prevent neighbouring points
// being unrefined.
for (label i = 0; i < nBufferLayers; i++)
{
extendMarkedCells(refineCell);
}
hasChanged = true;
}
}
// Coarsening
{
// Select unrefineable points that are not marked in refineCell
labelList pointsToUnrefine =
selectUnrefinePoints
(
coarseningDistance,
refineCell
);
label nSplitPoints = returnReduce
(
pointsToUnrefine.size(),
sumOp<label>()
);
if (nSplitPoints > 0)
{
// Refine/update mesh
unrefine(pointsToUnrefine);
hasChanged = true;
}
}
if ((nRefinementIterations_ % 10) == 0)
{
// Compact refinement history occassionally (how often?).
// Unrefinement causes holes in the polyRefinementHistory.
const_cast<polyRefinementHistory&>
(
meshCutter().history()
).compact();
}
nRefinementIterations_++;
}
bool hasChanged = dynamicPolyRefinementFvMesh::update();
changing(hasChanged);

View file

@ -45,11 +45,8 @@ Notes
#ifndef immersedBoundaryDynamicRefineSolidBodyMotionFvMesh_H
#define immersedBoundaryDynamicRefineSolidBodyMotionFvMesh_H
#include "dynamicFvMesh.H"
#include "polyRef.H"
#include "PackedBoolList.H"
#include "dynamicPolyRefinementFvMesh.H"
#include "movingImmersedBoundary.H"
#include "triSurfaceDistance.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -62,7 +59,7 @@ namespace Foam
class immersedBoundaryDynamicRefineSolidBodyMotionFvMesh
:
public dynamicFvMesh
public dynamicPolyRefinementFvMesh
{
// Private data
@ -70,15 +67,6 @@ class immersedBoundaryDynamicRefineSolidBodyMotionFvMesh
//- Immersed boundary motion control function
PtrList<movingImmersedBoundary> ibMotions_;
//- Mesh cutting engine
polyRef meshCutter_;
//- Current mesh motion time index
label curTimeIndex_;
//- Number of refinement/unrefinement steps done so far.
label nRefinementIterations_;
// Private Member Functions
@ -95,38 +83,6 @@ class immersedBoundaryDynamicRefineSolidBodyMotionFvMesh
);
//- Count set/unset elements in packedlist.
static label count(const PackedBoolList&, const unsigned int);
//- Refine cells. Update mesh and fields.
autoPtr<mapPolyMesh> refine(const labelList&);
//- Unrefine cells. Gets passed in centre points of cells to combine.
autoPtr<mapPolyMesh> unrefine(const labelList&);
// Selection of cells to refine and coarsen
//- Subset candidate cells for refinement
labelList selectRefineCells
(
const label maxCells,
const label maxRefLevel,
const scalar refinementDistance,
PackedBoolList& candidateCell
) const;
//- Select points that can be unrefined
labelList selectUnrefinePoints
(
const scalar coarsenDistance,
const PackedBoolList& markedCell
) const;
//- Extend markedCell with cell-face-cell
void extendMarkedCells(PackedBoolList& markedCell) const;
public:
//- Runtime type information
@ -148,12 +104,6 @@ public:
// Member Functions
//- Direct access to the refinement engine
const polyRef& meshCutter() const
{
return meshCutter_;
}
//- Update the mesh for both mesh motion and topology change
virtual bool update();
};

View file

@ -0,0 +1,214 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright held by original author
\\/ 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 2 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, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Author
Hrvoje Jasak, Wikki Ltd. All rights reserved.
\*---------------------------------------------------------------------------*/
#include "immersedBoundaryRefinement.H"
#include "fvMesh.H"
#include "immersedBoundaryPolyPatch.H"
#include "triSurfaceDistance.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
defineTypeNameAndDebug(immersedBoundaryRefinement, 0);
addToRunTimeSelectionTable
(
refinementSelection,
immersedBoundaryRefinement,
dictionary
);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::immersedBoundaryRefinement::immersedBoundaryRefinement
(
const fvMesh& mesh,
const dictionary& dict
)
:
refinementSelection(mesh, dict),
refinementDistance_(readScalar(coeffDict().lookup("refinementDistance"))),
coarseningDistance_(readScalar(coeffDict().lookup("coarseningDistance")))
{}
// * * * * * * * * * * * * * * * * Destructor* * * * * * * * * * * * * * * * //
Foam::immersedBoundaryRefinement::~immersedBoundaryRefinement()
{}
// * * * * * * * * * * * * Public Member Functions * * * * * * * * * * * * * //
Foam::Xfer<Foam::labelList>
Foam::immersedBoundaryRefinement::refinementCellCandidates() const
{
// Calculate distance to immersed boundary
// Note: minimum distance is inside (WET) and implies a live cell
scalarField cellDistance(mesh().nCells(), -GREAT);
const polyBoundaryMesh& bMesh = mesh().boundaryMesh();
const vector span(GREAT, GREAT, GREAT);
forAll (bMesh, patchI)
{
if (isA<immersedBoundaryPolyPatch>(bMesh[patchI]))
{
const immersedBoundaryPolyPatch& ibPatch =
refCast<const immersedBoundaryPolyPatch>
(
bMesh[patchI]
);
// Create a distance function
triSurfaceDistance tsd
(
ibPatch.triSurfSearch(),
span,
ibPatch.internalFlow(),
false // Do not iterate
);
// Calculate distance
cellDistance = Foam::max
(
cellDistance,
tsd.distance(mesh().cellCentres())
);
}
}
Info<< "Cell distance (min, max): (" << min(cellDistance)
<< " " << max(cellDistance) << ")" << endl;
// Create storage for collection of cells. Assume that almost all of the
// cells will be marked to prevent excessive resizing.
dynamicLabelList refinementCandidates(mesh().nCells());
// Create a sorting criterion
forAll (cellDistance, cellI)
{
if
(
cellDistance[cellI] > -refinementDistance_
&& cellDistance[cellI] < 0
)
{
// Found a refinement cell
refinementCandidates.append(cellI);
}
}
// Print out some information
Info<< "Selection algorithm " << type() << " selected "
<< returnReduce(refinementCandidates.size(), sumOp<label>())
<< " cells as refinement candidates."
<< endl;
// Return the list in the Xfer container to prevent copying
return refinementCandidates.xfer();
}
Foam::Xfer<Foam::labelList>
Foam::immersedBoundaryRefinement::unrefinementPointCandidates() const
{
// Mark all points as unrefinement candidates since only split points may be
// considered for actual unrefinement and since this refinement criterion
// will be usually used in combination with others. VV, 15/Mar/2018.
// All points are unrefinement candidates
dynamicLabelList unrefinementCandidates(mesh().nPoints());
// Calculate distance to immersed boundary
// Note: minimum distance is inside (WET) and implies a live cell
scalarField pointDistance(mesh().nPoints(), -GREAT);
const polyBoundaryMesh& bMesh = mesh().boundaryMesh();
const vector span(GREAT, GREAT, GREAT);
forAll (bMesh, patchI)
{
if (isA<immersedBoundaryPolyPatch>(bMesh[patchI]))
{
const immersedBoundaryPolyPatch& ibPatch =
refCast<const immersedBoundaryPolyPatch>(bMesh[patchI]);
// Create a distance function
triSurfaceDistance tsd
(
ibPatch.triSurfSearch(),
span,
ibPatch.internalFlow(),
false // Do not iterate
);
// Calculate distance
pointDistance = Foam::max
(
pointDistance,
tsd.distance(mesh().points())
);
}
}
Info<< "Split point distance(min, max): (" << min(pointDistance)
<< " " << max(pointDistance) << ")" << endl;
forAll (pointDistance, pointI)
{
// Coarse live cells next to immersed boundary or dead cells
if
(
pointDistance[pointI] < -coarseningDistance_
|| pointDistance[pointI] > SMALL
)
{
unrefinementCandidates.append(pointI);
}
}
// Print out some information
Info<< "Selection algorithm " << type() << " selected "
<< returnReduce(unrefinementCandidates.size(), sumOp<label>())
<< " points as unrefinement candidates."
<< endl;
// Return the list in the Xfer container to prevent copying
return unrefinementCandidates.xfer();
}
// ************************************************************************* //

View file

@ -0,0 +1,114 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright held by original author
\\/ 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 2 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, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Class
Foam::immersedBoundaryRefinement
Description
Selection of refinement cells based on distance from immersed boundary
SourceFiles
immersedBoundaryRefinement.C
Author
Hrvoje Jasak, Wikki Ltd. All rights reserved.
\*---------------------------------------------------------------------------*/
#ifndef immersedBoundaryRefinement_H
#define immersedBoundaryRefinement_H
#include "refinementSelection.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class immersedBoundaryRefinement Declaration
\*---------------------------------------------------------------------------*/
class immersedBoundaryRefinement
:
public refinementSelection
{
// Private data
//- Refinement distance to immersed boundary
scalar refinementDistance_;
//- Coarsening distance to immersed boundary
scalar coarseningDistance_;
// Private Member Functions
//- Disallow default bitwise copy construct
immersedBoundaryRefinement(const immersedBoundaryRefinement&);
//- Disallow default bitwise assignment
void operator=(const immersedBoundaryRefinement&);
public:
//- Runtime type information
TypeName("immersedBoundaryRefinement");
// Constructors
//- Construct from components
immersedBoundaryRefinement
(
const fvMesh& mesh,
const dictionary& dict
);
//- Destructor
virtual ~immersedBoundaryRefinement();
// Member Functions
// Selection of refinement/unrefinement candidates
//- Return transferable list of cells to refine
virtual Xfer<labelList> refinementCellCandidates() const;
//- Return transferable list of split points to unrefine
virtual Xfer<labelList> unrefinementPointCandidates() const;
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //