mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-12-28 03:37:59 +00:00
Merge branch 'feature-iso_distance-surface' into 'develop'
Feature iso distance surface See merge request Development/openfoam!407
This commit is contained in:
@ -28,7 +28,9 @@ surface/cutting/cuttingSurfaceCuts.C
|
||||
surface/cutting/cuttingSurfaceBase.C
|
||||
surface/cutting/cuttingSurfaceBaseSelection.C
|
||||
surface/distanceSurface/distanceSurface.C
|
||||
surface/distanceSurface/distanceSurfaceFilter.C
|
||||
surface/isoSurface/isoSurfaceBase.C
|
||||
surface/isoSurface/isoSurfaceBaseNew.C
|
||||
surface/isoSurface/isoSurfaceParams.C
|
||||
surface/isoSurface/isoSurfaceCell.C
|
||||
surface/isoSurface/isoSurfacePoint.C
|
||||
@ -42,6 +44,7 @@ sampledSurface/sampledPatchInternalField/sampledPatchInternalField.C
|
||||
sampledSurface/sampledPlane/sampledPlane.C
|
||||
sampledSurface/isoSurface/sampledIsoSurface.C
|
||||
sampledSurface/isoSurface/sampledIsoSurfaceCell.C
|
||||
sampledSurface/isoSurface/sampledIsoSurfacePoint.C
|
||||
sampledSurface/isoSurface/sampledIsoSurfaceTopo.C
|
||||
sampledSurface/distanceSurface/sampledDistanceSurface.C
|
||||
sampledSurface/sampledCuttingPlane/sampledCuttingPlane.C
|
||||
|
||||
@ -40,6 +40,9 @@ Usage
|
||||
surface1
|
||||
{
|
||||
type distanceSurface;
|
||||
surfaceType triSurfaceMesh;
|
||||
surfaceName something.obj;
|
||||
topology proximity;
|
||||
}
|
||||
}
|
||||
\endverbatim
|
||||
@ -48,18 +51,23 @@ Usage
|
||||
\table
|
||||
Property | Description | Required | Default
|
||||
type | distanceSurface | yes |
|
||||
distance | Distance from surface | yes |
|
||||
signed | Use sign when distance is positive | partly |
|
||||
isoMethod | Iso-algorithm (cell/topo/point) | no | topo
|
||||
regularise | Point snapping for iso-surface | no | true
|
||||
distance | distance from surface | no | 0
|
||||
signed | Use sign when distance is positive | no | true
|
||||
isoMethod | Iso-algorithm (cell/topo/point) | no | default
|
||||
regularise | Face simplification (enum or bool) | no | true
|
||||
average | Cell values from averaged point values | no | false
|
||||
bounds | Limit with bounding box | no |
|
||||
surfaceType | Type of surface | yes |
|
||||
surfaceName | Name of surface in \c triSurface/ | no | dict name
|
||||
topology | Topology filter (none/largestRegion/nearestPoints/proximity) | no | none
|
||||
nearestPoints | Points for point-based segmentation | no |
|
||||
maxDistance | Max search distance for nearestPoints | no | GREAT
|
||||
relProximity | Max limit of absolute vs normal distance | no | 1e3
|
||||
\endtable
|
||||
|
||||
SourceFiles
|
||||
sampledDistanceSurface.C
|
||||
sampledDistanceSurfaceTemplates.C
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
@ -28,9 +28,11 @@ License
|
||||
|
||||
#include "sampledIsoSurface.H"
|
||||
#include "dictionary.H"
|
||||
#include "fvMesh.H"
|
||||
#include "volFields.H"
|
||||
#include "volPointInterpolation.H"
|
||||
#include "addToRunTimeSelectionTable.H"
|
||||
#include "PtrList.H"
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
@ -44,13 +46,6 @@ namespace Foam
|
||||
word,
|
||||
isoSurface
|
||||
);
|
||||
addNamedToRunTimeSelectionTable
|
||||
(
|
||||
sampledSurface,
|
||||
sampledIsoSurface,
|
||||
word,
|
||||
isoSurfacePoint
|
||||
);
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
@ -310,6 +305,111 @@ void Foam::sampledIsoSurface::getIsoFields() const
|
||||
}
|
||||
|
||||
|
||||
void Foam::sampledIsoSurface::combineSurfaces
|
||||
(
|
||||
PtrList<isoSurfaceBase>& isoSurfPtrs
|
||||
)
|
||||
{
|
||||
isoSurfacePtr_.reset(nullptr);
|
||||
|
||||
// Already checked previously for ALGO_POINT, but do it again
|
||||
// - ALGO_POINT still needs fields (for interpolate)
|
||||
// The others can do straight transfer
|
||||
if
|
||||
(
|
||||
isoParams_.algorithm() == isoSurfaceParams::ALGO_POINT
|
||||
&& isoSurfPtrs.size() == 1
|
||||
)
|
||||
{
|
||||
// Shift from list to autoPtr
|
||||
isoSurfacePtr_.reset(isoSurfPtrs.release(0));
|
||||
}
|
||||
else if (isoSurfPtrs.size() == 1)
|
||||
{
|
||||
autoPtr<isoSurfaceBase> ptr(isoSurfPtrs.release(0));
|
||||
auto& surf = *ptr;
|
||||
|
||||
surface_.transfer(static_cast<meshedSurface&>(surf));
|
||||
meshCells_.transfer(surf.meshCells());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Combine faces with point offsets
|
||||
//
|
||||
// Note: use points().size() from surface, not nPoints()
|
||||
// since there may be uncompacted dangling nodes
|
||||
|
||||
label nFaces = 0, nPoints = 0;
|
||||
|
||||
for (const auto& surf : isoSurfPtrs)
|
||||
{
|
||||
nFaces += surf.size();
|
||||
nPoints += surf.points().size();
|
||||
}
|
||||
|
||||
faceList newFaces(nFaces);
|
||||
pointField newPoints(nPoints);
|
||||
meshCells_.resize(nFaces);
|
||||
|
||||
surfZoneList newZones(isoSurfPtrs.size());
|
||||
|
||||
nFaces = 0;
|
||||
nPoints = 0;
|
||||
forAll(isoSurfPtrs, surfi)
|
||||
{
|
||||
autoPtr<isoSurfaceBase> ptr(isoSurfPtrs.release(surfi));
|
||||
auto& surf = *ptr;
|
||||
|
||||
SubList<face> subFaces(newFaces, surf.size(), nFaces);
|
||||
SubList<point> subPoints(newPoints, surf.points().size(), nPoints);
|
||||
SubList<label> subCells(meshCells_, surf.size(), nFaces);
|
||||
|
||||
newZones[surfi] = surfZone
|
||||
(
|
||||
surfZoneIdentifier::defaultName(surfi),
|
||||
subFaces.size(), // size
|
||||
nFaces, // start
|
||||
surfi // index
|
||||
);
|
||||
|
||||
subFaces = surf.surfFaces();
|
||||
subPoints = surf.points();
|
||||
subCells = surf.meshCells();
|
||||
|
||||
if (nPoints)
|
||||
{
|
||||
for (face& f : subFaces)
|
||||
{
|
||||
for (label& pointi : f)
|
||||
{
|
||||
pointi += nPoints;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nFaces += subFaces.size();
|
||||
nPoints += subPoints.size();
|
||||
}
|
||||
|
||||
meshedSurface combined
|
||||
(
|
||||
std::move(newPoints),
|
||||
std::move(newFaces),
|
||||
newZones
|
||||
);
|
||||
|
||||
surface_.transfer(combined);
|
||||
}
|
||||
|
||||
// Addressing into the full mesh
|
||||
if (subMeshPtr_ && meshCells_.size())
|
||||
{
|
||||
meshCells_ =
|
||||
UIndirectList<label>(subMeshPtr_->cellMap(), meshCells_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Foam::sampledIsoSurface::updateGeometry() const
|
||||
{
|
||||
const fvMesh& fvm = static_cast<const fvMesh&>(mesh());
|
||||
@ -330,34 +430,76 @@ bool Foam::sampledIsoSurface::updateGeometry() const
|
||||
// Clear derived data
|
||||
sampledSurface::clearGeom();
|
||||
|
||||
const bool hasCellZones =
|
||||
(-1 != mesh().cellZones().findIndex(zoneNames_));
|
||||
|
||||
// Get sub-mesh if any
|
||||
// Geometry
|
||||
if
|
||||
(
|
||||
!subMeshPtr_
|
||||
&& (-1 != mesh().cellZones().findIndex(zoneNames_))
|
||||
simpleSubMesh_
|
||||
&& isoParams_.algorithm() != isoSurfaceParams::ALGO_POINT
|
||||
)
|
||||
{
|
||||
const label exposedPatchi =
|
||||
mesh().boundaryMesh().findPatchID(exposedPatchName_);
|
||||
subMeshPtr_.reset(nullptr);
|
||||
|
||||
DebugInfo
|
||||
<< "Allocating subset of size "
|
||||
<< mesh().cellZones().selection(zoneNames_).count()
|
||||
<< " with exposed faces into patch "
|
||||
<< exposedPatchi << endl;
|
||||
// Handle cell zones as inverse (blocked) selection
|
||||
if (!ignoreCellsPtr_)
|
||||
{
|
||||
ignoreCellsPtr_.reset(new bitSet);
|
||||
|
||||
subMeshPtr_.reset
|
||||
(
|
||||
new fvMeshSubset
|
||||
if (hasCellZones)
|
||||
{
|
||||
bitSet select(mesh().cellZones().selection(zoneNames_));
|
||||
|
||||
if (select.any() && !select.all())
|
||||
{
|
||||
// From selection to blocking
|
||||
select.flip();
|
||||
|
||||
*ignoreCellsPtr_ = std::move(select);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// A standard subMesh treatment
|
||||
|
||||
if (ignoreCellsPtr_)
|
||||
{
|
||||
ignoreCellsPtr_->clearStorage();
|
||||
}
|
||||
else
|
||||
{
|
||||
ignoreCellsPtr_.reset(new bitSet);
|
||||
}
|
||||
|
||||
// Get sub-mesh if any
|
||||
if (!subMeshPtr_ && hasCellZones)
|
||||
{
|
||||
const label exposedPatchi =
|
||||
mesh().boundaryMesh().findPatchID(exposedPatchName_);
|
||||
|
||||
DebugInfo
|
||||
<< "Allocating subset of size "
|
||||
<< mesh().cellZones().selection(zoneNames_).count()
|
||||
<< " with exposed faces into patch "
|
||||
<< exposedPatchi << endl;
|
||||
|
||||
subMeshPtr_.reset
|
||||
(
|
||||
fvm,
|
||||
mesh().cellZones().selection(zoneNames_),
|
||||
exposedPatchi
|
||||
)
|
||||
);
|
||||
new fvMeshSubset
|
||||
(
|
||||
fvm,
|
||||
mesh().cellZones().selection(zoneNames_),
|
||||
exposedPatchi
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The fields
|
||||
getIsoFields();
|
||||
|
||||
refPtr<volScalarField> tvolFld(*volFieldPtr_);
|
||||
@ -369,27 +511,57 @@ bool Foam::sampledIsoSurface::updateGeometry() const
|
||||
tpointFld.cref(*pointSubFieldPtr_);
|
||||
}
|
||||
|
||||
isoSurfacePtr_.reset
|
||||
(
|
||||
new isoSurfacePoint
|
||||
(
|
||||
tvolFld(),
|
||||
tpointFld(),
|
||||
isoVal_,
|
||||
isoParams_
|
||||
)
|
||||
);
|
||||
|
||||
// Create surfaces for each iso level
|
||||
|
||||
PtrList<isoSurfaceBase> isoSurfPtrs(isoValues_.size());
|
||||
|
||||
forAll(isoValues_, surfi)
|
||||
{
|
||||
isoSurfPtrs.set
|
||||
(
|
||||
surfi,
|
||||
isoSurfaceBase::New
|
||||
(
|
||||
isoParams_,
|
||||
tvolFld(),
|
||||
tpointFld().primitiveField(),
|
||||
isoValues_[surfi],
|
||||
*ignoreCellsPtr_
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// And flatten
|
||||
const_cast<sampledIsoSurface&>(*this)
|
||||
.combineSurfaces(isoSurfPtrs);
|
||||
|
||||
|
||||
// triangulate uses remapFaces()
|
||||
// - this is somewhat less efficient since it recopies the faces
|
||||
// that we just created, but we probably don't want to do this
|
||||
// too often anyhow.
|
||||
if
|
||||
(
|
||||
triangulate_
|
||||
&& surface_.size()
|
||||
&& (isoParams_.algorithm() == isoSurfaceParams::ALGO_TOPO)
|
||||
)
|
||||
{
|
||||
labelList faceMap;
|
||||
surface_.triangulate(faceMap);
|
||||
meshCells_ = UIndirectList<label>(meshCells_, faceMap)();
|
||||
}
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "isoSurfacePoint::updateGeometry() : constructed iso:"
|
||||
<< nl
|
||||
<< " isoField : " << isoField_ << nl
|
||||
<< " isoValue : " << isoVal_ << nl
|
||||
Pout<< "isoSurface::updateGeometry() : constructed iso:" << nl
|
||||
<< " field : " << isoField_ << nl
|
||||
<< " value : " << flatOutput(isoValues_) << nl
|
||||
<< " average : " << Switch(average_) << nl
|
||||
<< " filter : "
|
||||
<< Switch(bool(isoParams_.filter())) << nl;
|
||||
<< Switch(bool(isoParams_.filter())) << nl
|
||||
<< " bounds : " << isoParams_.getClipBounds() << nl;
|
||||
if (subMeshPtr_)
|
||||
{
|
||||
Pout<< " zone size : "
|
||||
@ -409,6 +581,7 @@ bool Foam::sampledIsoSurface::updateGeometry() const
|
||||
|
||||
Foam::sampledIsoSurface::sampledIsoSurface
|
||||
(
|
||||
const isoSurfaceParams& params,
|
||||
const word& name,
|
||||
const polyMesh& mesh,
|
||||
const dictionary& dict
|
||||
@ -416,32 +589,102 @@ Foam::sampledIsoSurface::sampledIsoSurface
|
||||
:
|
||||
sampledSurface(name, mesh, dict),
|
||||
isoField_(dict.get<word>("isoField")),
|
||||
isoVal_(dict.get<scalar>("isoValue")),
|
||||
isoParams_(dict),
|
||||
isoValues_(),
|
||||
isoParams_(dict, params),
|
||||
average_(dict.getOrDefault("average", false)),
|
||||
triangulate_(dict.getOrDefault("triangulate", false)),
|
||||
simpleSubMesh_(dict.getOrDefault("simpleSubMesh", false)),
|
||||
zoneNames_(),
|
||||
exposedPatchName_(),
|
||||
prevTimeIndex_(-1),
|
||||
|
||||
surface_(),
|
||||
meshCells_(),
|
||||
isoSurfacePtr_(nullptr),
|
||||
|
||||
subMeshPtr_(nullptr),
|
||||
ignoreCellsPtr_(nullptr),
|
||||
|
||||
storedVolFieldPtr_(nullptr),
|
||||
volFieldPtr_(nullptr),
|
||||
pointFieldPtr_(nullptr),
|
||||
subMeshPtr_(nullptr),
|
||||
|
||||
storedVolSubFieldPtr_(nullptr),
|
||||
volSubFieldPtr_(nullptr),
|
||||
pointSubFieldPtr_(nullptr)
|
||||
{
|
||||
isoParams_.algorithm(isoSurfaceParams::ALGO_POINT); // Force
|
||||
|
||||
if (!sampledSurface::interpolate())
|
||||
if (params.algorithm() != isoSurfaceParams::ALGO_DEFAULT)
|
||||
{
|
||||
FatalIOErrorInFunction(dict)
|
||||
<< "Non-interpolated iso surface not supported since triangles"
|
||||
<< " span across cells." << exit(FatalIOError);
|
||||
// Forced use of specified algorithm (ignore dictionary entry)
|
||||
isoParams_.algorithm(params.algorithm());
|
||||
}
|
||||
|
||||
// The isoValues or isoValue
|
||||
|
||||
if (!dict.readIfPresent("isoValues", isoValues_))
|
||||
{
|
||||
isoValues_.resize(1);
|
||||
dict.readEntry("isoValue", isoValues_.first());
|
||||
}
|
||||
|
||||
if (isoValues_.empty())
|
||||
{
|
||||
FatalIOErrorInFunction(dict)
|
||||
<< "No isoValue or isoValues specified." << nl
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
|
||||
if (isoValues_.size() > 1)
|
||||
{
|
||||
const label nOrig = isoValues_.size();
|
||||
|
||||
inplaceUniqueSort(isoValues_);
|
||||
|
||||
if (nOrig != isoValues_.size())
|
||||
{
|
||||
IOWarningInFunction(dict)
|
||||
<< "Removed non-unique isoValues" << nl;
|
||||
}
|
||||
}
|
||||
|
||||
if (isoParams_.algorithm() == isoSurfaceParams::ALGO_POINT)
|
||||
{
|
||||
// Not possible for ALGO_POINT
|
||||
simpleSubMesh_ = false;
|
||||
|
||||
if (!sampledSurface::interpolate())
|
||||
{
|
||||
FatalIOErrorInFunction(dict)
|
||||
<< "Non-interpolated iso-surface (point) not supported"
|
||||
<< " since triangles span across cells." << nl
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
|
||||
if (isoValues_.size() > 1)
|
||||
{
|
||||
FatalIOErrorInFunction(dict)
|
||||
<< "Multiple values on iso-surface (point) not supported"
|
||||
<< " since needs original interpolators." << nl
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
}
|
||||
|
||||
if (isoParams_.algorithm() == isoSurfaceParams::ALGO_TOPO)
|
||||
{
|
||||
if
|
||||
(
|
||||
triangulate_
|
||||
&& (isoParams_.filter() == isoSurfaceParams::filterType::NONE)
|
||||
)
|
||||
{
|
||||
FatalIOErrorInFunction(dict)
|
||||
<< "Cannot triangulate without a regularise filter" << nl
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Zones
|
||||
|
||||
if (!dict.readIfPresent("zones", zoneNames_) && dict.found("zone"))
|
||||
{
|
||||
@ -461,6 +704,17 @@ Foam::sampledIsoSurface::sampledIsoSurface
|
||||
}
|
||||
|
||||
|
||||
Foam::sampledIsoSurface::sampledIsoSurface
|
||||
(
|
||||
const word& name,
|
||||
const polyMesh& mesh,
|
||||
const dictionary& dict
|
||||
)
|
||||
:
|
||||
sampledIsoSurface(isoSurfaceParams(), name, mesh, dict)
|
||||
{}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::sampledIsoSurface::~sampledIsoSurface()
|
||||
@ -608,7 +862,7 @@ void Foam::sampledIsoSurface::print(Ostream& os) const
|
||||
{
|
||||
os << "isoSurfacePoint: " << name() << " :"
|
||||
<< " field :" << isoField_
|
||||
<< " value :" << isoVal_;
|
||||
<< " value :" << flatOutput(isoValues_);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -28,8 +28,7 @@ Class
|
||||
Foam::sampledIsoSurface
|
||||
|
||||
Description
|
||||
A sampledSurface defined by a surface of iso value using a
|
||||
\em point algorithm (always triangulated!).
|
||||
A sampledSurface defined by a surface of iso value.
|
||||
It only recalculates the iso-surface if time changes.
|
||||
To be used in sampleSurfaces / functionObjects.
|
||||
|
||||
@ -40,9 +39,10 @@ Usage
|
||||
{
|
||||
surface1
|
||||
{
|
||||
type isoSurfacePoint;
|
||||
type isoSurface;
|
||||
isoField T;
|
||||
isoValue 373;
|
||||
isoMethod topo;
|
||||
}
|
||||
}
|
||||
\endverbatim
|
||||
@ -50,18 +50,26 @@ Usage
|
||||
Where the sub-entries comprise:
|
||||
\table
|
||||
Property | Description | Required | Default
|
||||
type | isoSurfacePoint / isoSurface | yes |
|
||||
type | isoSurface | yes |
|
||||
isoField | field name for obtaining iso-surface | yes |
|
||||
isoValue | value of iso-surface | yes |
|
||||
isoValues| values for iso-surfaces | yes |
|
||||
isoMethod | Iso-algorithm (cell/topo/point) | no | topo
|
||||
average | cell values from averaged point values | no | false
|
||||
bounds | limit with bounding box | no |
|
||||
zone | limit to cell zone (name or regex) | no |
|
||||
zones | limit to cell zones (names, regexs) | no |
|
||||
simpleSubMesh | Simple sub-meshing in algorithm itself | no | false
|
||||
exposedPatchName | name for zone subset | optional |
|
||||
regularise | point snapping (bool or enum) | no | true
|
||||
triangulate | triangulate faces (if regularise) | no | false
|
||||
mergeTol | tolerance for merging points | no | 1e-6
|
||||
\endtable
|
||||
|
||||
Some options are limited to particular algorithms.
|
||||
- triangulate is topo-only
|
||||
- simpleSubMesh and multiple isoValues are not available for point.
|
||||
|
||||
SourceFiles
|
||||
sampledIsoSurface.C
|
||||
sampledIsoSurfaceTemplates.C
|
||||
@ -71,9 +79,9 @@ SourceFiles
|
||||
#ifndef sampledIsoSurface_H
|
||||
#define sampledIsoSurface_H
|
||||
|
||||
#include "isoSurfacePoint.H"
|
||||
#include "sampledSurface.H"
|
||||
#include "fvMeshSubset.H"
|
||||
#include "isoSurfaceBase.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
@ -93,8 +101,8 @@ class sampledIsoSurface
|
||||
//- Field to get isoSurface of
|
||||
const word isoField_;
|
||||
|
||||
//- Iso value
|
||||
const scalar isoVal_;
|
||||
//- The iso-value(s)
|
||||
List<scalar> isoValues_;
|
||||
|
||||
//- Parameters (filtering etc) for iso-surface
|
||||
isoSurfaceParams isoParams_;
|
||||
@ -102,6 +110,12 @@ class sampledIsoSurface
|
||||
//- Whether to recalculate cell values as average of point values
|
||||
bool average_;
|
||||
|
||||
//- Whether to triangulate ALGO_TOPO (after filtering)
|
||||
bool triangulate_;
|
||||
|
||||
//- Use simple sub-meshing in algorithm itself
|
||||
bool simpleSubMesh_;
|
||||
|
||||
//- The zone or zones for the iso-surface
|
||||
wordRes zoneNames_;
|
||||
|
||||
@ -121,7 +135,16 @@ class sampledIsoSurface
|
||||
mutable labelList meshCells_;
|
||||
|
||||
//- Extracted iso-surface, for interpolators
|
||||
mutable autoPtr<isoSurfacePoint> isoSurfacePtr_;
|
||||
mutable autoPtr<isoSurfaceBase> isoSurfacePtr_;
|
||||
|
||||
|
||||
// Mesh Subsetting
|
||||
|
||||
//- Cached subMesh for (pre-)subset of cell zones
|
||||
mutable autoPtr<fvMeshSubset> subMeshPtr_;
|
||||
|
||||
//- Cached ignore cells for (post-)subset of cell zones
|
||||
mutable autoPtr<bitSet> ignoreCellsPtr_;
|
||||
|
||||
|
||||
// Fields
|
||||
@ -133,10 +156,8 @@ class sampledIsoSurface
|
||||
//- Cached pointfield
|
||||
mutable const pointScalarField* pointFieldPtr_;
|
||||
|
||||
// And on subsetted mesh
|
||||
|
||||
//- Cached submesh
|
||||
mutable autoPtr<fvMeshSubset> subMeshPtr_;
|
||||
// And on (pre-)subsetted mesh
|
||||
|
||||
//- Cached volfield
|
||||
mutable autoPtr<volScalarField> storedVolSubFieldPtr_;
|
||||
@ -151,6 +172,9 @@ class sampledIsoSurface
|
||||
//- Get fields needed to recreate iso surface.
|
||||
void getIsoFields() const;
|
||||
|
||||
//- Collect iso-surfaces into a single surface (No point merging)
|
||||
void combineSurfaces(PtrList<isoSurfaceBase>& isoSurfPtrs);
|
||||
|
||||
//- Create iso surface (if time has changed)
|
||||
// Do nothing (and return false) if no update was needed
|
||||
bool updateGeometry() const;
|
||||
@ -196,6 +220,15 @@ public:
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct from dictionary
|
||||
sampledIsoSurface
|
||||
(
|
||||
const isoSurfaceParams& params,
|
||||
const word& name,
|
||||
const polyMesh& mesh,
|
||||
const dictionary& dict
|
||||
);
|
||||
|
||||
//- Construct from dictionary
|
||||
sampledIsoSurface
|
||||
(
|
||||
|
||||
@ -5,8 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||
Copyright (C) 2016-2020 OpenCFD Ltd.
|
||||
Copyright (C) 2020 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -27,19 +26,13 @@ License
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "sampledIsoSurfaceCell.H"
|
||||
#include "isoSurfaceCell.H"
|
||||
#include "dictionary.H"
|
||||
#include "fvMesh.H"
|
||||
#include "volFields.H"
|
||||
#include "volPointInterpolation.H"
|
||||
#include "addToRunTimeSelectionTable.H"
|
||||
#include "fvMesh.H"
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
defineTypeNameAndDebug(sampledIsoSurfaceCell, 0);
|
||||
defineTypeName(sampledIsoSurfaceCell);
|
||||
addNamedToRunTimeSelectionTable
|
||||
(
|
||||
sampledSurface,
|
||||
@ -49,161 +42,6 @@ namespace Foam
|
||||
);
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
bool Foam::sampledIsoSurfaceCell::updateGeometry() const
|
||||
{
|
||||
const fvMesh& fvm = static_cast<const fvMesh&>(mesh());
|
||||
|
||||
// No update needed
|
||||
if (fvm.time().timeIndex() == prevTimeIndex_)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
prevTimeIndex_ = fvm.time().timeIndex();
|
||||
|
||||
// Clear any previously stored topologies
|
||||
surface_.clear();
|
||||
meshCells_.clear();
|
||||
isoSurfacePtr_.reset(nullptr);
|
||||
|
||||
// Clear derived data
|
||||
sampledSurface::clearGeom();
|
||||
|
||||
|
||||
// Handle cell zones as inverse (blocked) selection
|
||||
if (!ignoreCellsPtr_)
|
||||
{
|
||||
ignoreCellsPtr_.reset(new bitSet);
|
||||
|
||||
if (-1 != mesh().cellZones().findIndex(zoneNames_))
|
||||
{
|
||||
bitSet select(mesh().cellZones().selection(zoneNames_));
|
||||
|
||||
if (select.any() && !select.all())
|
||||
{
|
||||
// From selection to blocking
|
||||
select.flip();
|
||||
|
||||
*ignoreCellsPtr_ = std::move(select);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Use field from database, or try to read it in
|
||||
const auto* cellFldPtr = fvm.findObject<volScalarField>(isoField_);
|
||||
|
||||
if (debug)
|
||||
{
|
||||
if (cellFldPtr)
|
||||
{
|
||||
InfoInFunction << "Lookup " << isoField_ << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
InfoInFunction
|
||||
<< "Reading " << isoField_
|
||||
<< " from time " << fvm.time().timeName()
|
||||
<< endl;
|
||||
}
|
||||
}
|
||||
|
||||
// For holding the volScalarField read in.
|
||||
autoPtr<volScalarField> fieldReadPtr;
|
||||
|
||||
if (!cellFldPtr)
|
||||
{
|
||||
// Bit of a hack. Read field and store.
|
||||
|
||||
fieldReadPtr = autoPtr<volScalarField>::New
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
isoField_,
|
||||
fvm.time().timeName(),
|
||||
fvm,
|
||||
IOobject::MUST_READ,
|
||||
IOobject::NO_WRITE,
|
||||
false
|
||||
),
|
||||
fvm
|
||||
);
|
||||
}
|
||||
|
||||
const volScalarField& cellFld =
|
||||
(fieldReadPtr ? *fieldReadPtr : *cellFldPtr);
|
||||
|
||||
auto tpointFld = volPointInterpolation::New(fvm).interpolate(cellFld);
|
||||
|
||||
// Field reference (assuming non-averaged)
|
||||
tmp<scalarField> tcellValues(cellFld.primitiveField());
|
||||
|
||||
if (average_)
|
||||
{
|
||||
// From point field and interpolated cell.
|
||||
tcellValues = tmp<scalarField>::New(fvm.nCells(), Zero);
|
||||
auto& cellAvg = tcellValues.ref();
|
||||
|
||||
labelField nPointCells(fvm.nCells(), Zero);
|
||||
|
||||
for (label pointi = 0; pointi < fvm.nPoints(); ++pointi)
|
||||
{
|
||||
const scalar& val = tpointFld().primitiveField()[pointi];
|
||||
const labelList& pCells = fvm.pointCells(pointi);
|
||||
|
||||
for (const label celli : pCells)
|
||||
{
|
||||
cellAvg[celli] += val;
|
||||
++nPointCells[celli];
|
||||
}
|
||||
}
|
||||
forAll(cellAvg, celli)
|
||||
{
|
||||
cellAvg[celli] /= nPointCells[celli];
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
isoSurfaceCell surf
|
||||
(
|
||||
fvm,
|
||||
tcellValues(), // A primitiveField
|
||||
tpointFld().primitiveField(),
|
||||
isoVal_,
|
||||
isoParams_,
|
||||
*ignoreCellsPtr_
|
||||
);
|
||||
|
||||
surface_.transfer(static_cast<meshedSurface&>(surf));
|
||||
meshCells_.transfer(surf.meshCells());
|
||||
}
|
||||
|
||||
// if (subMeshPtr_ && meshCells_.size())
|
||||
// {
|
||||
// // With the correct addressing into the full mesh
|
||||
// meshCells_ =
|
||||
// UIndirectList<label>(subMeshPtr_->cellMap(), meshCells_);
|
||||
// }
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "isoSurfaceCell::updateGeometry() : constructed iso:" << nl
|
||||
<< " isoField : " << isoField_ << nl
|
||||
<< " isoValue : " << isoVal_ << nl
|
||||
<< " average : " << Switch(average_) << nl
|
||||
<< " filter : "
|
||||
<< Switch(bool(isoParams_.filter())) << nl
|
||||
<< " bounds : " << isoParams_.getClipBounds() << nl
|
||||
<< " points : " << points().size() << nl
|
||||
<< " faces : " << surface().size() << nl
|
||||
<< " cut cells : " << meshCells().size() << endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
@ -214,185 +52,14 @@ Foam::sampledIsoSurfaceCell::sampledIsoSurfaceCell
|
||||
const dictionary& dict
|
||||
)
|
||||
:
|
||||
sampledSurface(name, mesh, dict),
|
||||
isoField_(dict.get<word>("isoField")),
|
||||
isoVal_(dict.get<scalar>("isoValue")),
|
||||
isoParams_(dict),
|
||||
average_(dict.getOrDefault("average", true)),
|
||||
zoneNames_(),
|
||||
prevTimeIndex_(-1),
|
||||
surface_(),
|
||||
meshCells_(),
|
||||
isoSurfacePtr_(nullptr)
|
||||
{
|
||||
isoParams_.algorithm(isoSurfaceParams::ALGO_CELL); // Force
|
||||
|
||||
if (!dict.readIfPresent("zones", zoneNames_) && dict.found("zone"))
|
||||
{
|
||||
zoneNames_.resize(1);
|
||||
dict.readEntry("zone", zoneNames_.first());
|
||||
}
|
||||
|
||||
if (-1 != mesh.cellZones().findIndex(zoneNames_))
|
||||
{
|
||||
DebugInfo
|
||||
<< "Restricting to cellZone(s) " << flatOutput(zoneNames_) << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::sampledIsoSurfaceCell::~sampledIsoSurfaceCell()
|
||||
sampledIsoSurface
|
||||
(
|
||||
isoSurfaceParams(isoSurfaceParams::ALGO_CELL),
|
||||
name,
|
||||
mesh,
|
||||
dict
|
||||
)
|
||||
{}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
bool Foam::sampledIsoSurfaceCell::needsUpdate() const
|
||||
{
|
||||
const fvMesh& fvm = static_cast<const fvMesh&>(mesh());
|
||||
|
||||
return fvm.time().timeIndex() != prevTimeIndex_;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::sampledIsoSurfaceCell::expire()
|
||||
{
|
||||
surface_.clear();
|
||||
meshCells_.clear();
|
||||
isoSurfacePtr_.reset(nullptr);
|
||||
|
||||
// Clear derived data
|
||||
sampledSurface::clearGeom();
|
||||
|
||||
ignoreCellsPtr_.reset(nullptr);
|
||||
|
||||
// Already marked as expired
|
||||
if (prevTimeIndex_ == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Force update
|
||||
prevTimeIndex_ = -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::sampledIsoSurfaceCell::update()
|
||||
{
|
||||
return updateGeometry();
|
||||
}
|
||||
|
||||
|
||||
Foam::tmp<Foam::scalarField>
|
||||
Foam::sampledIsoSurfaceCell::sample
|
||||
(
|
||||
const interpolation<scalar>& sampler
|
||||
) const
|
||||
{
|
||||
return sampleOnFaces(sampler);
|
||||
}
|
||||
|
||||
|
||||
Foam::tmp<Foam::vectorField>
|
||||
Foam::sampledIsoSurfaceCell::sample
|
||||
(
|
||||
const interpolation<vector>& sampler
|
||||
) const
|
||||
{
|
||||
return sampleOnFaces(sampler);
|
||||
}
|
||||
|
||||
|
||||
Foam::tmp<Foam::sphericalTensorField>
|
||||
Foam::sampledIsoSurfaceCell::sample
|
||||
(
|
||||
const interpolation<sphericalTensor>& sampler
|
||||
) const
|
||||
{
|
||||
return sampleOnFaces(sampler);
|
||||
}
|
||||
|
||||
|
||||
Foam::tmp<Foam::symmTensorField>
|
||||
Foam::sampledIsoSurfaceCell::sample
|
||||
(
|
||||
const interpolation<symmTensor>& sampler
|
||||
) const
|
||||
{
|
||||
return sampleOnFaces(sampler);
|
||||
}
|
||||
|
||||
|
||||
Foam::tmp<Foam::tensorField>
|
||||
Foam::sampledIsoSurfaceCell::sample
|
||||
(
|
||||
const interpolation<tensor>& sampler
|
||||
) const
|
||||
{
|
||||
return sampleOnFaces(sampler);
|
||||
}
|
||||
|
||||
|
||||
Foam::tmp<Foam::scalarField>
|
||||
Foam::sampledIsoSurfaceCell::interpolate
|
||||
(
|
||||
const interpolation<scalar>& interpolator
|
||||
) const
|
||||
{
|
||||
return sampleOnPoints(interpolator);
|
||||
}
|
||||
|
||||
|
||||
Foam::tmp<Foam::vectorField>
|
||||
Foam::sampledIsoSurfaceCell::interpolate
|
||||
(
|
||||
const interpolation<vector>& interpolator
|
||||
) const
|
||||
{
|
||||
return sampleOnPoints(interpolator);
|
||||
}
|
||||
|
||||
Foam::tmp<Foam::sphericalTensorField>
|
||||
Foam::sampledIsoSurfaceCell::interpolate
|
||||
(
|
||||
const interpolation<sphericalTensor>& interpolator
|
||||
) const
|
||||
{
|
||||
return sampleOnPoints(interpolator);
|
||||
}
|
||||
|
||||
|
||||
Foam::tmp<Foam::symmTensorField>
|
||||
Foam::sampledIsoSurfaceCell::interpolate
|
||||
(
|
||||
const interpolation<symmTensor>& interpolator
|
||||
) const
|
||||
{
|
||||
return sampleOnPoints(interpolator);
|
||||
}
|
||||
|
||||
|
||||
Foam::tmp<Foam::tensorField>
|
||||
Foam::sampledIsoSurfaceCell::interpolate
|
||||
(
|
||||
const interpolation<tensor>& interpolator
|
||||
) const
|
||||
{
|
||||
return sampleOnPoints(interpolator);
|
||||
}
|
||||
|
||||
|
||||
void Foam::sampledIsoSurfaceCell::print(Ostream& os) const
|
||||
{
|
||||
os << "isoSurfaceCell: " << name() << " :"
|
||||
<< " field:" << isoField_
|
||||
<< " value:" << isoVal_;
|
||||
//<< " faces:" << faces().size() // possibly no geom yet
|
||||
//<< " points:" << points().size();
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
@ -63,17 +63,13 @@ Usage
|
||||
|
||||
SourceFiles
|
||||
sampledIsoSurfaceCell.C
|
||||
sampledIsoSurfaceCellTemplates.C
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef sampledIsoSurfaceCell_H
|
||||
#define sampledIsoSurfaceCell_H
|
||||
|
||||
#include "sampledSurface.H"
|
||||
#include "MeshedSurface.H"
|
||||
#include "MeshedSurfacesFwd.H"
|
||||
#include "isoSurfaceCell.H"
|
||||
#include "sampledIsoSurface.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
@ -86,94 +82,12 @@ namespace Foam
|
||||
|
||||
class sampledIsoSurfaceCell
|
||||
:
|
||||
public sampledSurface
|
||||
public sampledIsoSurface
|
||||
{
|
||||
// Private typedefs for convenience
|
||||
typedef meshedSurface Mesh;
|
||||
|
||||
|
||||
// Private Data
|
||||
|
||||
//- Field to get isoSurface of
|
||||
const word isoField_;
|
||||
|
||||
//- Iso value
|
||||
const scalar isoVal_;
|
||||
|
||||
//- Parameters (filtering etc) for iso-surface
|
||||
isoSurfaceParams isoParams_;
|
||||
|
||||
//- Recalculate cell values as average of point values
|
||||
bool average_;
|
||||
|
||||
//- The zone or zones for the iso-surface
|
||||
wordRes zoneNames_;
|
||||
|
||||
|
||||
// Sampling geometry. Directly stored or via an iso-surface (ALGO_POINT)
|
||||
|
||||
//- Time at last call, also track if surface needs an update
|
||||
mutable label prevTimeIndex_;
|
||||
|
||||
//- The extracted surface (direct storage)
|
||||
mutable meshedSurface surface_;
|
||||
|
||||
//- For every face the original cell in mesh (direct storage)
|
||||
mutable labelList meshCells_;
|
||||
|
||||
//- Extracted iso-surface, for interpolators
|
||||
mutable autoPtr<isoSurfaceCell> isoSurfacePtr_;
|
||||
|
||||
|
||||
// Mesh subsetting
|
||||
|
||||
//- Cached ignore cells for sub-mesh (zoned)
|
||||
mutable autoPtr<bitSet> ignoreCellsPtr_;
|
||||
|
||||
|
||||
// Private Member Functions
|
||||
|
||||
//- Create iso surface (if time has changed)
|
||||
// Do nothing (and return false) if no update was needed
|
||||
bool updateGeometry() const;
|
||||
|
||||
//- Sample volume field onto surface faces
|
||||
template<class Type>
|
||||
tmp<Field<Type>> sampleOnFaces
|
||||
(
|
||||
const interpolation<Type>& sampler
|
||||
) const;
|
||||
|
||||
//- Interpolate volume field onto surface points
|
||||
template<class Type>
|
||||
tmp<Field<Type>> sampleOnPoints
|
||||
(
|
||||
const interpolation<Type>& interpolator
|
||||
) const;
|
||||
|
||||
//- Use isoSurfacePtr_ for point interpolation
|
||||
template<class Type>
|
||||
tmp<Field<Type>> sampleOnIsoSurfacePoints
|
||||
(
|
||||
const interpolation<Type>& interpolator
|
||||
) const;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// Protected Member Functions
|
||||
|
||||
//- Is currently backed by an isoSurfacePtr_
|
||||
bool hasIsoSurface() const
|
||||
{
|
||||
return bool(isoSurfacePtr_);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
//- Runtime type information
|
||||
TypeName("sampledIsoSurfaceCell");
|
||||
TypeNameNoDebug("sampledIsoSurfaceCell");
|
||||
|
||||
|
||||
// Constructors
|
||||
@ -188,147 +102,7 @@ public:
|
||||
|
||||
|
||||
//- Destructor
|
||||
virtual ~sampledIsoSurfaceCell();
|
||||
|
||||
|
||||
// Member Functions
|
||||
|
||||
//- Does the surface need an update?
|
||||
virtual bool needsUpdate() const;
|
||||
|
||||
//- Mark the surface as needing an update.
|
||||
// May also free up unneeded data.
|
||||
// Return false if surface was already marked as expired.
|
||||
virtual bool expire();
|
||||
|
||||
//- Update the surface as required.
|
||||
// Do nothing (and return false) if no update was needed
|
||||
virtual bool update();
|
||||
|
||||
//- The currently created surface geometry
|
||||
const meshedSurface& surface() const
|
||||
{
|
||||
if (isoSurfacePtr_)
|
||||
{
|
||||
return *isoSurfacePtr_;
|
||||
}
|
||||
return surface_;
|
||||
}
|
||||
|
||||
//- For each face, the original cell in mesh
|
||||
const labelList& meshCells() const
|
||||
{
|
||||
if (isoSurfacePtr_)
|
||||
{
|
||||
return isoSurfacePtr_->meshCells();
|
||||
}
|
||||
return meshCells_;
|
||||
}
|
||||
|
||||
//- Points of surface
|
||||
virtual const pointField& points() const
|
||||
{
|
||||
return surface().points();
|
||||
}
|
||||
|
||||
//- Faces of surface
|
||||
virtual const faceList& faces() const
|
||||
{
|
||||
return surface().surfFaces();
|
||||
}
|
||||
|
||||
//- Per-face zone/region information
|
||||
virtual const labelList& zoneIds() const
|
||||
{
|
||||
return labelList::null();
|
||||
}
|
||||
|
||||
//- Face area magnitudes
|
||||
virtual const vectorField& Sf() const
|
||||
{
|
||||
return surface().Sf();
|
||||
}
|
||||
|
||||
//- Face area magnitudes
|
||||
virtual const scalarField& magSf() const
|
||||
{
|
||||
return surface().magSf();
|
||||
}
|
||||
|
||||
//- Face centres
|
||||
virtual const vectorField& Cf() const
|
||||
{
|
||||
return surface().Cf();
|
||||
}
|
||||
|
||||
|
||||
// Sample
|
||||
|
||||
//- Sample volume field onto surface faces
|
||||
virtual tmp<scalarField> sample
|
||||
(
|
||||
const interpolation<scalar>& sampler
|
||||
) const;
|
||||
|
||||
//- Sample volume field onto surface faces
|
||||
virtual tmp<vectorField> sample
|
||||
(
|
||||
const interpolation<vector>& sampler
|
||||
) const;
|
||||
|
||||
//- Sample volume field onto surface faces
|
||||
virtual tmp<sphericalTensorField> sample
|
||||
(
|
||||
const interpolation<sphericalTensor>& sampler
|
||||
) const;
|
||||
|
||||
//- Sample volume field onto surface faces
|
||||
virtual tmp<symmTensorField> sample
|
||||
(
|
||||
const interpolation<symmTensor>& sampler
|
||||
) const;
|
||||
|
||||
//- Sample volume field onto surface faces
|
||||
virtual tmp<tensorField> sample
|
||||
(
|
||||
const interpolation<tensor>& sampler
|
||||
) const;
|
||||
|
||||
|
||||
// Interpolate
|
||||
|
||||
//- Interpolate volume field onto surface points
|
||||
virtual tmp<scalarField> interpolate
|
||||
(
|
||||
const interpolation<scalar>& interpolator
|
||||
) const;
|
||||
|
||||
//- Interpolate volume field onto surface points
|
||||
virtual tmp<vectorField> interpolate
|
||||
(
|
||||
const interpolation<vector>& interpolator
|
||||
) const;
|
||||
|
||||
//- Interpolate volume field onto surface points
|
||||
virtual tmp<sphericalTensorField> interpolate
|
||||
(
|
||||
const interpolation<sphericalTensor>& interpolator
|
||||
) const;
|
||||
|
||||
//- Interpolate volume field onto surface points
|
||||
virtual tmp<symmTensorField> interpolate
|
||||
(
|
||||
const interpolation<symmTensor>& interpolator
|
||||
) const;
|
||||
|
||||
//- Interpolate volume field onto surface points
|
||||
virtual tmp<tensorField> interpolate
|
||||
(
|
||||
const interpolation<tensor>& interpolator
|
||||
) const;
|
||||
|
||||
//- Write
|
||||
virtual void print(Ostream& os) const;
|
||||
virtual ~sampledIsoSurfaceCell() = default;
|
||||
};
|
||||
|
||||
|
||||
@ -338,12 +112,6 @@ public:
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#ifdef NoRepository
|
||||
#include "sampledIsoSurfaceCellTemplates.C"
|
||||
#endif
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#endif
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
@ -1,120 +1 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||
Copyright (C) 2018-2020 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 "sampledIsoSurfaceCell.H"
|
||||
#include "volFieldsFwd.H"
|
||||
#include "pointFields.H"
|
||||
#include "volPointInterpolation.H"
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
template<class Type>
|
||||
Foam::tmp<Foam::Field<Type>>
|
||||
Foam::sampledIsoSurfaceCell::sampleOnFaces
|
||||
(
|
||||
const interpolation<Type>& sampler
|
||||
) const
|
||||
{
|
||||
updateGeometry(); // Recreate geometry if time has changed
|
||||
|
||||
return sampledSurface::sampleOnFaces
|
||||
(
|
||||
sampler,
|
||||
meshCells(),
|
||||
surface(),
|
||||
points()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
template<class Type>
|
||||
Foam::tmp<Foam::Field<Type>>
|
||||
Foam::sampledIsoSurfaceCell::sampleOnPoints
|
||||
(
|
||||
const interpolation<Type>& interpolator
|
||||
) const
|
||||
{
|
||||
updateGeometry(); // Recreate geometry if time has changed
|
||||
|
||||
if (isoSurfacePtr_)
|
||||
{
|
||||
return this->sampleOnIsoSurfacePoints(interpolator);
|
||||
}
|
||||
|
||||
return sampledSurface::sampleOnPoints
|
||||
(
|
||||
interpolator,
|
||||
meshCells(),
|
||||
faces(),
|
||||
points()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
template<class Type>
|
||||
Foam::tmp<Foam::Field<Type>>
|
||||
Foam::sampledIsoSurfaceCell::sampleOnIsoSurfacePoints
|
||||
(
|
||||
const interpolation<Type>& interpolator
|
||||
) const
|
||||
{
|
||||
if (!isoSurfacePtr_)
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "cannot call without an iso-surface" << nl
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
// Assume volPointInterpolation for the point field!
|
||||
const auto& volFld = interpolator.psi();
|
||||
|
||||
tmp<GeometricField<Type, fvPatchField, volMesh>> tvolFld(volFld);
|
||||
tmp<GeometricField<Type, pointPatchField, pointMesh>> tpointFld;
|
||||
|
||||
// if (subMeshPtr_)
|
||||
// {
|
||||
// // Replace with subset
|
||||
// tvolFld.reset(subMeshPtr_->interpolate(volFld));
|
||||
// }
|
||||
|
||||
// Interpolated point field
|
||||
tpointFld.reset
|
||||
(
|
||||
volPointInterpolation::New(tvolFld().mesh()).interpolate(tvolFld())
|
||||
);
|
||||
|
||||
if (average_)
|
||||
{
|
||||
tvolFld.reset(pointAverage(tpointFld()));
|
||||
}
|
||||
|
||||
return isoSurfacePtr_->interpolate(tvolFld(), tpointFld());
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
#warning File removed - left for old dependency check only
|
||||
|
||||
@ -0,0 +1,64 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2020 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 "sampledIsoSurfacePoint.H"
|
||||
#include "addToRunTimeSelectionTable.H"
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
defineTypeName(sampledIsoSurfacePoint);
|
||||
addNamedToRunTimeSelectionTable
|
||||
(
|
||||
sampledSurface,
|
||||
sampledIsoSurfacePoint,
|
||||
word,
|
||||
isoSurfacePoint
|
||||
);
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::sampledIsoSurfacePoint::sampledIsoSurfacePoint
|
||||
(
|
||||
const word& name,
|
||||
const polyMesh& mesh,
|
||||
const dictionary& dict
|
||||
)
|
||||
:
|
||||
sampledIsoSurface
|
||||
(
|
||||
isoSurfaceParams(isoSurfaceParams::ALGO_POINT),
|
||||
name,
|
||||
mesh,
|
||||
dict
|
||||
)
|
||||
{}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
116
src/sampling/sampledSurface/isoSurface/sampledIsoSurfacePoint.H
Normal file
116
src/sampling/sampledSurface/isoSurface/sampledIsoSurfacePoint.H
Normal file
@ -0,0 +1,116 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2020 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::sampledIsoSurfacePoint
|
||||
|
||||
Description
|
||||
A sampledSurface defined by a surface of iso value using a
|
||||
\em point algorithm (always triangulated!).
|
||||
It only recalculates the iso-surface if time changes.
|
||||
To be used in sampleSurfaces / functionObjects.
|
||||
|
||||
Usage
|
||||
Example of function object partial specification:
|
||||
\verbatim
|
||||
surfaces
|
||||
{
|
||||
surface1
|
||||
{
|
||||
type isoSurfacePoint;
|
||||
isoField T;
|
||||
isoValue 373;
|
||||
}
|
||||
}
|
||||
\endverbatim
|
||||
|
||||
Where the sub-entries comprise:
|
||||
\table
|
||||
Property | Description | Required | Default
|
||||
type | isoSurfacePoint | yes |
|
||||
isoField | field name for obtaining iso-surface | yes |
|
||||
isoValue | value of iso-surface | yes |
|
||||
average | cell values from averaged point values | no | false
|
||||
bounds | limit with bounding box | no |
|
||||
zone | limit to cell zone (name or regex) | no |
|
||||
zones | limit to cell zones (names, regexs) | no |
|
||||
regularise | point snapping | yes |
|
||||
mergeTol | tolerance for merging points | no | 1e-6
|
||||
\endtable
|
||||
|
||||
SourceFiles
|
||||
sampledIsoSurfacePoint.C
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef sampledIsoSurfacePoint_H
|
||||
#define sampledIsoSurfacePoint_H
|
||||
|
||||
#include "sampledIsoSurface.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Class sampledIsoSurfacePoint Declaration
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
class sampledIsoSurfacePoint
|
||||
:
|
||||
public sampledIsoSurface
|
||||
{
|
||||
public:
|
||||
|
||||
//- Runtime type information
|
||||
TypeNameNoDebug("sampledIsoSurfacePoint");
|
||||
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct from dictionary
|
||||
sampledIsoSurfacePoint
|
||||
(
|
||||
const word& name,
|
||||
const polyMesh& mesh,
|
||||
const dictionary& dict
|
||||
);
|
||||
|
||||
|
||||
//- Destructor
|
||||
virtual ~sampledIsoSurfacePoint() = default;
|
||||
};
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#endif
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -5,8 +5,7 @@
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2018 OpenFOAM Foundation
|
||||
Copyright (C) 2018-2020 OpenCFD Ltd.
|
||||
Copyright (C) 2020 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -27,18 +26,13 @@ License
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "sampledIsoSurfaceTopo.H"
|
||||
#include "isoSurfaceTopo.H"
|
||||
#include "dictionary.H"
|
||||
#include "fvMesh.H"
|
||||
#include "volFields.H"
|
||||
#include "volPointInterpolation.H"
|
||||
#include "addToRunTimeSelectionTable.H"
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
defineTypeNameAndDebug(sampledIsoSurfaceTopo, 0);
|
||||
defineTypeName(sampledIsoSurfaceTopo);
|
||||
addNamedToRunTimeSelectionTable
|
||||
(
|
||||
sampledSurface,
|
||||
@ -48,174 +42,6 @@ namespace Foam
|
||||
);
|
||||
}
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
bool Foam::sampledIsoSurfaceTopo::updateGeometry() const
|
||||
{
|
||||
const fvMesh& fvm = static_cast<const fvMesh&>(mesh());
|
||||
|
||||
// No update needed
|
||||
if (fvm.time().timeIndex() == prevTimeIndex_)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
prevTimeIndex_ = fvm.time().timeIndex();
|
||||
|
||||
// Clear any previously stored topologies
|
||||
surface_.clear();
|
||||
meshCells_.clear();
|
||||
isoSurfacePtr_.reset(nullptr);
|
||||
|
||||
// Clear derived data
|
||||
sampledSurface::clearGeom();
|
||||
|
||||
|
||||
// Handle cell zones as inverse (blocked) selection
|
||||
if (!ignoreCellsPtr_)
|
||||
{
|
||||
ignoreCellsPtr_.reset(new bitSet);
|
||||
|
||||
if (-1 != mesh().cellZones().findIndex(zoneNames_))
|
||||
{
|
||||
bitSet select(mesh().cellZones().selection(zoneNames_));
|
||||
|
||||
if (select.any() && !select.all())
|
||||
{
|
||||
// From selection to blocking
|
||||
select.flip();
|
||||
|
||||
*ignoreCellsPtr_ = std::move(select);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Use field from database, or try to read it in
|
||||
const auto* cellFldPtr = fvm.findObject<volScalarField>(isoField_);
|
||||
|
||||
if (debug)
|
||||
{
|
||||
if (cellFldPtr)
|
||||
{
|
||||
InfoInFunction << "Lookup " << isoField_ << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
InfoInFunction
|
||||
<< "Reading " << isoField_
|
||||
<< " from time " << fvm.time().timeName()
|
||||
<< endl;
|
||||
}
|
||||
}
|
||||
|
||||
// For holding the volScalarField read in.
|
||||
autoPtr<volScalarField> fieldReadPtr;
|
||||
|
||||
if (!cellFldPtr)
|
||||
{
|
||||
// Bit of a hack. Read field and store.
|
||||
|
||||
fieldReadPtr = autoPtr<volScalarField>::New
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
isoField_,
|
||||
fvm.time().timeName(),
|
||||
fvm,
|
||||
IOobject::MUST_READ,
|
||||
IOobject::NO_WRITE,
|
||||
false
|
||||
),
|
||||
fvm
|
||||
);
|
||||
}
|
||||
|
||||
const volScalarField& cellFld =
|
||||
(fieldReadPtr ? *fieldReadPtr : *cellFldPtr);
|
||||
|
||||
auto tpointFld = volPointInterpolation::New(fvm).interpolate(cellFld);
|
||||
|
||||
// Field reference (assuming non-averaged)
|
||||
tmp<scalarField> tcellValues(cellFld.primitiveField());
|
||||
|
||||
if (average_)
|
||||
{
|
||||
// From point field and interpolated cell.
|
||||
tcellValues = tmp<scalarField>::New(fvm.nCells(), Zero);
|
||||
auto& cellAvg = tcellValues.ref();
|
||||
|
||||
labelField nPointCells(fvm.nCells(), Zero);
|
||||
|
||||
for (label pointi = 0; pointi < fvm.nPoints(); ++pointi)
|
||||
{
|
||||
const scalar& val = tpointFld().primitiveField()[pointi];
|
||||
const labelList& pCells = fvm.pointCells(pointi);
|
||||
|
||||
for (const label celli : pCells)
|
||||
{
|
||||
cellAvg[celli] += val;
|
||||
++nPointCells[celli];
|
||||
}
|
||||
}
|
||||
forAll(cellAvg, celli)
|
||||
{
|
||||
cellAvg[celli] /= nPointCells[celli];
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
isoSurfaceTopo surf
|
||||
(
|
||||
fvm,
|
||||
cellFld.primitiveField(),
|
||||
tpointFld().primitiveField(),
|
||||
isoVal_,
|
||||
isoParams_,
|
||||
*ignoreCellsPtr_
|
||||
);
|
||||
|
||||
surface_.transfer(static_cast<meshedSurface&>(surf));
|
||||
meshCells_ = std::move(surf.meshCells());
|
||||
}
|
||||
|
||||
// if (subMeshPtr_ && meshCells_.size())
|
||||
// {
|
||||
// // With the correct addressing into the full mesh
|
||||
// meshCells_ =
|
||||
// UIndirectList<label>(subMeshPtr_->cellMap(), meshCells_);
|
||||
// }
|
||||
|
||||
// triangulate uses remapFaces()
|
||||
// - this is somewhat less efficient since it recopies the faces
|
||||
// that we just created, but we probably don't want to do this
|
||||
// too often anyhow.
|
||||
if (triangulate_ && surface_.size())
|
||||
{
|
||||
labelList faceMap;
|
||||
surface_.triangulate(faceMap);
|
||||
meshCells_ = UIndirectList<label>(meshCells_, faceMap)();
|
||||
}
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "isoSurfaceTopo::updateGeometry() : constructed iso:" << nl
|
||||
<< " isoField : " << isoField_ << nl
|
||||
<< " isoValue : " << isoVal_ << nl
|
||||
<< " average : " << Switch(average_) << nl
|
||||
<< " filter : "
|
||||
<< isoSurfaceParams::filterNames[isoParams_.filter()] << nl
|
||||
<< " triangulate : " << Switch(triangulate_) << nl
|
||||
<< " bounds : " << isoParams_.getClipBounds() << nl
|
||||
<< " points : " << points().size() << nl
|
||||
<< " faces : " << surface().size() << nl
|
||||
<< " cut cells : " << meshCells().size() << endl;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::sampledIsoSurfaceTopo::sampledIsoSurfaceTopo
|
||||
@ -225,197 +51,14 @@ Foam::sampledIsoSurfaceTopo::sampledIsoSurfaceTopo
|
||||
const dictionary& dict
|
||||
)
|
||||
:
|
||||
sampledSurface(name, mesh, dict),
|
||||
isoField_(dict.get<word>("isoField")),
|
||||
isoVal_(dict.get<scalar>("isoValue")),
|
||||
isoParams_(dict),
|
||||
average_(dict.getOrDefault("average", false)),
|
||||
triangulate_(dict.getOrDefault("triangulate", false)),
|
||||
zoneNames_(),
|
||||
prevTimeIndex_(-1),
|
||||
surface_(),
|
||||
meshCells_(),
|
||||
isoSurfacePtr_(nullptr)
|
||||
{
|
||||
isoParams_.algorithm(isoSurfaceParams::ALGO_TOPO); // Force
|
||||
|
||||
if
|
||||
sampledIsoSurface
|
||||
(
|
||||
triangulate_
|
||||
&& (isoParams_.filter() == isoSurfaceParams::filterType::NONE)
|
||||
isoSurfaceParams(isoSurfaceParams::ALGO_TOPO),
|
||||
name,
|
||||
mesh,
|
||||
dict
|
||||
)
|
||||
{
|
||||
FatalIOErrorInFunction(dict)
|
||||
<< "Cannot triangulate without a regularise filter" << nl
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
|
||||
if (!dict.readIfPresent("zones", zoneNames_) && dict.found("zone"))
|
||||
{
|
||||
zoneNames_.resize(1);
|
||||
dict.readEntry("zone", zoneNames_.first());
|
||||
}
|
||||
|
||||
if (-1 != mesh.cellZones().findIndex(zoneNames_))
|
||||
{
|
||||
DebugInfo
|
||||
<< "Restricting to cellZone(s) " << flatOutput(zoneNames_) << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::sampledIsoSurfaceTopo::~sampledIsoSurfaceTopo()
|
||||
{}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
bool Foam::sampledIsoSurfaceTopo::needsUpdate() const
|
||||
{
|
||||
const fvMesh& fvm = static_cast<const fvMesh&>(mesh());
|
||||
|
||||
return fvm.time().timeIndex() != prevTimeIndex_;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::sampledIsoSurfaceTopo::expire()
|
||||
{
|
||||
surface_.clear();
|
||||
meshCells_.clear();
|
||||
isoSurfacePtr_.reset(nullptr);
|
||||
|
||||
// Clear derived data
|
||||
sampledSurface::clearGeom();
|
||||
|
||||
ignoreCellsPtr_.reset(nullptr);
|
||||
|
||||
// Already marked as expired
|
||||
if (prevTimeIndex_ == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Force update
|
||||
prevTimeIndex_ = -1;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool Foam::sampledIsoSurfaceTopo::update()
|
||||
{
|
||||
return updateGeometry();
|
||||
}
|
||||
|
||||
|
||||
Foam::tmp<Foam::scalarField>
|
||||
Foam::sampledIsoSurfaceTopo::sample
|
||||
(
|
||||
const interpolation<scalar>& sampler
|
||||
) const
|
||||
{
|
||||
return sampleOnFaces(sampler);
|
||||
}
|
||||
|
||||
|
||||
Foam::tmp<Foam::vectorField>
|
||||
Foam::sampledIsoSurfaceTopo::sample
|
||||
(
|
||||
const interpolation<vector>& sampler
|
||||
) const
|
||||
{
|
||||
return sampleOnFaces(sampler);
|
||||
}
|
||||
|
||||
|
||||
Foam::tmp<Foam::sphericalTensorField>
|
||||
Foam::sampledIsoSurfaceTopo::sample
|
||||
(
|
||||
const interpolation<sphericalTensor>& sampler
|
||||
) const
|
||||
{
|
||||
return sampleOnFaces(sampler);
|
||||
}
|
||||
|
||||
|
||||
Foam::tmp<Foam::symmTensorField>
|
||||
Foam::sampledIsoSurfaceTopo::sample
|
||||
(
|
||||
const interpolation<symmTensor>& sampler
|
||||
) const
|
||||
{
|
||||
return sampleOnFaces(sampler);
|
||||
}
|
||||
|
||||
|
||||
Foam::tmp<Foam::tensorField>
|
||||
Foam::sampledIsoSurfaceTopo::sample
|
||||
(
|
||||
const interpolation<tensor>& sampler
|
||||
) const
|
||||
{
|
||||
return sampleOnFaces(sampler);
|
||||
}
|
||||
|
||||
|
||||
Foam::tmp<Foam::scalarField>
|
||||
Foam::sampledIsoSurfaceTopo::interpolate
|
||||
(
|
||||
const interpolation<scalar>& interpolator
|
||||
) const
|
||||
{
|
||||
return sampleOnPoints(interpolator);
|
||||
}
|
||||
|
||||
|
||||
Foam::tmp<Foam::vectorField>
|
||||
Foam::sampledIsoSurfaceTopo::interpolate
|
||||
(
|
||||
const interpolation<vector>& interpolator
|
||||
) const
|
||||
{
|
||||
return sampleOnPoints(interpolator);
|
||||
}
|
||||
|
||||
Foam::tmp<Foam::sphericalTensorField>
|
||||
Foam::sampledIsoSurfaceTopo::interpolate
|
||||
(
|
||||
const interpolation<sphericalTensor>& interpolator
|
||||
) const
|
||||
{
|
||||
return sampleOnPoints(interpolator);
|
||||
}
|
||||
|
||||
|
||||
Foam::tmp<Foam::symmTensorField>
|
||||
Foam::sampledIsoSurfaceTopo::interpolate
|
||||
(
|
||||
const interpolation<symmTensor>& interpolator
|
||||
) const
|
||||
{
|
||||
return sampleOnPoints(interpolator);
|
||||
}
|
||||
|
||||
|
||||
Foam::tmp<Foam::tensorField>
|
||||
Foam::sampledIsoSurfaceTopo::interpolate
|
||||
(
|
||||
const interpolation<tensor>& interpolator
|
||||
) const
|
||||
{
|
||||
return sampleOnPoints(interpolator);
|
||||
}
|
||||
|
||||
|
||||
void Foam::sampledIsoSurfaceTopo::print(Ostream& os) const
|
||||
{
|
||||
os << "isoSurfaceTopo: " << name() << " :"
|
||||
<< " field:" << isoField_
|
||||
<< " value:" << isoVal_;
|
||||
//<< " faces:" << faces().size() // possibly no geom yet
|
||||
//<< " points:" << points().size();
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
@ -63,17 +63,13 @@ Usage
|
||||
|
||||
SourceFiles
|
||||
sampledIsoSurfaceTopo.C
|
||||
sampledIsoSurfaceTopoTemplates.C
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef sampledIsoSurfaceTopo_H
|
||||
#define sampledIsoSurfaceTopo_H
|
||||
|
||||
#include "sampledSurface.H"
|
||||
#include "MeshedSurface.H"
|
||||
#include "MeshedSurfacesFwd.H"
|
||||
#include "isoSurfaceTopo.H"
|
||||
#include "sampledIsoSurface.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
@ -86,97 +82,12 @@ namespace Foam
|
||||
|
||||
class sampledIsoSurfaceTopo
|
||||
:
|
||||
public sampledSurface
|
||||
public sampledIsoSurface
|
||||
{
|
||||
// Private typedefs for convenience
|
||||
typedef meshedSurface Mesh;
|
||||
|
||||
|
||||
// Private Data
|
||||
|
||||
//- Field to get isoSurface of
|
||||
const word isoField_;
|
||||
|
||||
//- Iso value
|
||||
const scalar isoVal_;
|
||||
|
||||
//- Parameters (filtering etc) for iso-surface
|
||||
isoSurfaceParams isoParams_;
|
||||
|
||||
//- Recalculate cell values as average of point values?
|
||||
bool average_;
|
||||
|
||||
//- Whether to triangulate (after filtering)
|
||||
bool triangulate_;
|
||||
|
||||
//- The zone or zones for the iso-surface
|
||||
wordRes zoneNames_;
|
||||
|
||||
|
||||
// Sampling geometry. Directly stored or via an iso-surface (ALGO_POINT)
|
||||
|
||||
//- Time at last call, also track it surface needs an update
|
||||
mutable label prevTimeIndex_;
|
||||
|
||||
//- The extracted surface (direct storage)
|
||||
mutable meshedSurface surface_;
|
||||
|
||||
//- For every face the original cell in mesh (direct storage)
|
||||
mutable labelList meshCells_;
|
||||
|
||||
//- Extracted iso-surface, for interpolators
|
||||
mutable autoPtr<isoSurfaceTopo> isoSurfacePtr_;
|
||||
|
||||
|
||||
// Mesh subsetting
|
||||
|
||||
//- Cached ignore cells for sub-mesh (zoned)
|
||||
mutable autoPtr<bitSet> ignoreCellsPtr_;
|
||||
|
||||
|
||||
// Private Member Functions
|
||||
|
||||
//- Create iso surface (if time has changed)
|
||||
// Do nothing (and return false) if no update was needed
|
||||
bool updateGeometry() const;
|
||||
|
||||
//- Sample volume field onto surface faces
|
||||
template<class Type>
|
||||
tmp<Field<Type>> sampleOnFaces
|
||||
(
|
||||
const interpolation<Type>& sampler
|
||||
) const;
|
||||
|
||||
//- Interpolate volume field onto surface points
|
||||
template<class Type>
|
||||
tmp<Field<Type>> sampleOnPoints
|
||||
(
|
||||
const interpolation<Type>& interpolator
|
||||
) const;
|
||||
|
||||
//- Use isoSurfacePtr_ for point interpolation
|
||||
template<class Type>
|
||||
tmp<Field<Type>> sampleOnIsoSurfacePoints
|
||||
(
|
||||
const interpolation<Type>& interpolator
|
||||
) const;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// Protected Member Functions
|
||||
|
||||
//- Is currently backed by an isoSurfacePtr_
|
||||
bool hasIsoSurface() const
|
||||
{
|
||||
return bool(isoSurfacePtr_);
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
|
||||
//- Runtime type information
|
||||
TypeName("sampledIsoSurfaceTopo");
|
||||
TypeNameNoDebug("sampledIsoSurfaceTopo");
|
||||
|
||||
|
||||
// Constructors
|
||||
@ -191,147 +102,7 @@ public:
|
||||
|
||||
|
||||
//- Destructor
|
||||
virtual ~sampledIsoSurfaceTopo();
|
||||
|
||||
|
||||
// Member Functions
|
||||
|
||||
//- Does the surface need an update?
|
||||
virtual bool needsUpdate() const;
|
||||
|
||||
//- Mark the surface as needing an update.
|
||||
// May also free up unneeded data.
|
||||
// Return false if surface was already marked as expired.
|
||||
virtual bool expire();
|
||||
|
||||
//- Update the surface as required.
|
||||
// Do nothing (and return false) if no update was needed
|
||||
virtual bool update();
|
||||
|
||||
//- The currently created surface geometry
|
||||
const meshedSurface& surface() const
|
||||
{
|
||||
if (isoSurfacePtr_)
|
||||
{
|
||||
return *isoSurfacePtr_;
|
||||
}
|
||||
return surface_;
|
||||
}
|
||||
|
||||
//- For each face, the original cell in mesh
|
||||
const labelList& meshCells() const
|
||||
{
|
||||
if (isoSurfacePtr_)
|
||||
{
|
||||
return isoSurfacePtr_->meshCells();
|
||||
}
|
||||
return meshCells_;
|
||||
}
|
||||
|
||||
//- Points of surface
|
||||
virtual const pointField& points() const
|
||||
{
|
||||
return surface().points();
|
||||
}
|
||||
|
||||
//- Faces of surface
|
||||
virtual const faceList& faces() const
|
||||
{
|
||||
return surface().surfFaces();
|
||||
}
|
||||
|
||||
//- Per-face zone/region information
|
||||
virtual const labelList& zoneIds() const
|
||||
{
|
||||
return labelList::null();
|
||||
}
|
||||
|
||||
//- Face area magnitudes
|
||||
virtual const vectorField& Sf() const
|
||||
{
|
||||
return surface().Sf();
|
||||
}
|
||||
|
||||
//- Face area magnitudes
|
||||
virtual const scalarField& magSf() const
|
||||
{
|
||||
return surface().magSf();
|
||||
}
|
||||
|
||||
//- Face centres
|
||||
virtual const vectorField& Cf() const
|
||||
{
|
||||
return surface().Cf();
|
||||
}
|
||||
|
||||
|
||||
// Sample
|
||||
|
||||
//- Sample volume field onto surface faces
|
||||
virtual tmp<scalarField> sample
|
||||
(
|
||||
const interpolation<scalar>& sampler
|
||||
) const;
|
||||
|
||||
//- Sample volume field onto surface faces
|
||||
virtual tmp<vectorField> sample
|
||||
(
|
||||
const interpolation<vector>& sampler
|
||||
) const;
|
||||
|
||||
//- Sample volume field onto surface faces
|
||||
virtual tmp<sphericalTensorField> sample
|
||||
(
|
||||
const interpolation<sphericalTensor>& sampler
|
||||
) const;
|
||||
|
||||
//- Sample volume field onto surface faces
|
||||
virtual tmp<symmTensorField> sample
|
||||
(
|
||||
const interpolation<symmTensor>& sampler
|
||||
) const;
|
||||
|
||||
//- Sample volume field onto surface faces
|
||||
virtual tmp<tensorField> sample
|
||||
(
|
||||
const interpolation<tensor>& sampler
|
||||
) const;
|
||||
|
||||
|
||||
// Interpolate
|
||||
|
||||
//- Interpolate volume field onto surface points
|
||||
virtual tmp<scalarField> interpolate
|
||||
(
|
||||
const interpolation<scalar>& interpolator
|
||||
) const;
|
||||
|
||||
//- Interpolate volume field onto surface points
|
||||
virtual tmp<vectorField> interpolate
|
||||
(
|
||||
const interpolation<vector>& interpolator
|
||||
) const;
|
||||
|
||||
//- Interpolate volume field onto surface points
|
||||
virtual tmp<sphericalTensorField> interpolate
|
||||
(
|
||||
const interpolation<sphericalTensor>& interpolator
|
||||
) const;
|
||||
|
||||
//- Interpolate volume field onto surface points
|
||||
virtual tmp<symmTensorField> interpolate
|
||||
(
|
||||
const interpolation<symmTensor>& interpolator
|
||||
) const;
|
||||
|
||||
//- Interpolate volume field onto surface points
|
||||
virtual tmp<tensorField> interpolate
|
||||
(
|
||||
const interpolation<tensor>& interpolator
|
||||
) const;
|
||||
|
||||
//- Write
|
||||
virtual void print(Ostream& os) const;
|
||||
virtual ~sampledIsoSurfaceTopo() = default;
|
||||
};
|
||||
|
||||
|
||||
@ -341,12 +112,6 @@ public:
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#ifdef NoRepository
|
||||
#include "sampledIsoSurfaceTopoTemplates.C"
|
||||
#endif
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#endif
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
@ -1,120 +1 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2018 OpenFOAM Foundation
|
||||
Copyright (C) 2018-2020 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 "sampledIsoSurfaceTopo.H"
|
||||
#include "volFieldsFwd.H"
|
||||
#include "pointFields.H"
|
||||
#include "volPointInterpolation.H"
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
template<class Type>
|
||||
Foam::tmp<Foam::Field<Type>>
|
||||
Foam::sampledIsoSurfaceTopo::sampleOnFaces
|
||||
(
|
||||
const interpolation<Type>& sampler
|
||||
) const
|
||||
{
|
||||
updateGeometry(); // Recreate geometry if time has changed
|
||||
|
||||
return sampledSurface::sampleOnFaces
|
||||
(
|
||||
sampler,
|
||||
meshCells(),
|
||||
faces(),
|
||||
points()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
template<class Type>
|
||||
Foam::tmp<Foam::Field<Type>>
|
||||
Foam::sampledIsoSurfaceTopo::sampleOnPoints
|
||||
(
|
||||
const interpolation<Type>& interpolator
|
||||
) const
|
||||
{
|
||||
updateGeometry(); // Recreate geometry if time has changed
|
||||
|
||||
if (isoSurfacePtr_)
|
||||
{
|
||||
return this->sampleOnIsoSurfacePoints(interpolator);
|
||||
}
|
||||
|
||||
return sampledSurface::sampleOnPoints
|
||||
(
|
||||
interpolator,
|
||||
meshCells(),
|
||||
faces(),
|
||||
points()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
template<class Type>
|
||||
Foam::tmp<Foam::Field<Type>>
|
||||
Foam::sampledIsoSurfaceTopo::sampleOnIsoSurfacePoints
|
||||
(
|
||||
const interpolation<Type>& interpolator
|
||||
) const
|
||||
{
|
||||
if (!isoSurfacePtr_)
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "cannot call without an iso-surface" << nl
|
||||
<< exit(FatalError);
|
||||
}
|
||||
|
||||
// Assume volPointInterpolation for the point field!
|
||||
const auto& volFld = interpolator.psi();
|
||||
|
||||
tmp<GeometricField<Type, fvPatchField, volMesh>> tvolFld(volFld);
|
||||
tmp<GeometricField<Type, pointPatchField, pointMesh>> tpointFld;
|
||||
|
||||
// if (subMeshPtr_)
|
||||
// {
|
||||
// // Replace with subset
|
||||
// tvolFld.reset(subMeshPtr_->interpolate(volFld));
|
||||
// }
|
||||
|
||||
// Interpolated point field
|
||||
tpointFld.reset
|
||||
(
|
||||
volPointInterpolation::New(tvolFld().mesh()).interpolate(tvolFld())
|
||||
);
|
||||
|
||||
if (average_)
|
||||
{
|
||||
tvolFld.reset(pointAverage(tpointFld()));
|
||||
}
|
||||
|
||||
return isoSurfacePtr_->interpolate(tvolFld(), tpointFld());
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
#warning File removed - left for old dependency check only
|
||||
|
||||
@ -28,13 +28,11 @@ License
|
||||
|
||||
#include "sampledCuttingPlane.H"
|
||||
#include "dictionary.H"
|
||||
#include "fvMesh.H"
|
||||
#include "volFields.H"
|
||||
#include "volPointInterpolation.H"
|
||||
#include "addToRunTimeSelectionTable.H"
|
||||
#include "fvMesh.H"
|
||||
#include "isoSurfaceCell.H"
|
||||
#include "isoSurfacePoint.H"
|
||||
#include "isoSurfaceTopo.H"
|
||||
#include "PtrList.H"
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
@ -189,6 +187,111 @@ void Foam::sampledCuttingPlane::setDistanceFields(const plane& pln)
|
||||
}
|
||||
|
||||
|
||||
void Foam::sampledCuttingPlane::combineSurfaces
|
||||
(
|
||||
PtrList<isoSurfaceBase>& isoSurfPtrs
|
||||
)
|
||||
{
|
||||
isoSurfacePtr_.reset(nullptr);
|
||||
|
||||
// Already checked previously for ALGO_POINT, but do it again
|
||||
// - ALGO_POINT still needs fields (for interpolate)
|
||||
// The others can do straight transfer
|
||||
if
|
||||
(
|
||||
isoParams_.algorithm() == isoSurfaceParams::ALGO_POINT
|
||||
&& isoSurfPtrs.size() == 1
|
||||
)
|
||||
{
|
||||
// Shift ownership from list to autoPtr
|
||||
isoSurfacePtr_.reset(isoSurfPtrs.release(0));
|
||||
}
|
||||
else if (isoSurfPtrs.size() == 1)
|
||||
{
|
||||
autoPtr<isoSurfaceBase> ptr(isoSurfPtrs.release(0));
|
||||
auto& surf = *ptr;
|
||||
|
||||
surface_.transfer(static_cast<meshedSurface&>(surf));
|
||||
meshCells_.transfer(surf.meshCells());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Combine faces with point offsets
|
||||
//
|
||||
// Note: use points().size() from surface, not nPoints()
|
||||
// since there may be uncompacted dangling nodes
|
||||
|
||||
label nFaces = 0, nPoints = 0;
|
||||
|
||||
for (const auto& surf : isoSurfPtrs)
|
||||
{
|
||||
nFaces += surf.size();
|
||||
nPoints += surf.points().size();
|
||||
}
|
||||
|
||||
faceList newFaces(nFaces);
|
||||
pointField newPoints(nPoints);
|
||||
meshCells_.resize(nFaces);
|
||||
|
||||
surfZoneList newZones(isoSurfPtrs.size());
|
||||
|
||||
nFaces = 0;
|
||||
nPoints = 0;
|
||||
forAll(isoSurfPtrs, surfi)
|
||||
{
|
||||
autoPtr<isoSurfaceBase> ptr(isoSurfPtrs.release(surfi));
|
||||
auto& surf = *ptr;
|
||||
|
||||
SubList<face> subFaces(newFaces, surf.size(), nFaces);
|
||||
SubList<point> subPoints(newPoints, surf.points().size(), nPoints);
|
||||
SubList<label> subCells(meshCells_, surf.size(), nFaces);
|
||||
|
||||
newZones[surfi] = surfZone
|
||||
(
|
||||
surfZoneIdentifier::defaultName(surfi),
|
||||
subFaces.size(), // size
|
||||
nFaces, // start
|
||||
surfi // index
|
||||
);
|
||||
|
||||
subFaces = surf.surfFaces();
|
||||
subPoints = surf.points();
|
||||
subCells = surf.meshCells();
|
||||
|
||||
if (nPoints)
|
||||
{
|
||||
for (face& f : subFaces)
|
||||
{
|
||||
for (label& pointi : f)
|
||||
{
|
||||
pointi += nPoints;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nFaces += subFaces.size();
|
||||
nPoints += subPoints.size();
|
||||
}
|
||||
|
||||
meshedSurface combined
|
||||
(
|
||||
std::move(newPoints),
|
||||
std::move(newFaces),
|
||||
newZones
|
||||
);
|
||||
|
||||
surface_.transfer(combined);
|
||||
}
|
||||
|
||||
// Addressing into the full mesh
|
||||
if (subMeshPtr_ && meshCells_.size())
|
||||
{
|
||||
meshCells_ =
|
||||
UIndirectList<label>(subMeshPtr_->cellMap(), meshCells_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Foam::sampledCuttingPlane::createGeometry()
|
||||
{
|
||||
if (debug)
|
||||
@ -198,62 +301,105 @@ void Foam::sampledCuttingPlane::createGeometry()
|
||||
}
|
||||
|
||||
// Clear any previously stored topologies
|
||||
isoSurfacePtr_.reset(nullptr);
|
||||
surface_.clear();
|
||||
meshCells_.clear();
|
||||
isoSurfacePtr_.reset(nullptr);
|
||||
|
||||
// Clear derived data
|
||||
sampledSurface::clearGeom();
|
||||
|
||||
// Clear any stored fields
|
||||
pointDistance_.clear();
|
||||
cellDistancePtr_.clear();
|
||||
|
||||
const bool hasCellZones =
|
||||
(-1 != mesh().cellZones().findIndex(zoneNames_));
|
||||
|
||||
const fvMesh& fvm = static_cast<const fvMesh&>(this->mesh());
|
||||
|
||||
// Get sub-mesh if any
|
||||
// Geometry
|
||||
if
|
||||
(
|
||||
!subMeshPtr_
|
||||
&& (-1 != mesh().cellZones().findIndex(zoneNames_))
|
||||
simpleSubMesh_
|
||||
&& isoParams_.algorithm() != isoSurfaceParams::ALGO_POINT
|
||||
)
|
||||
{
|
||||
const label exposedPatchi =
|
||||
mesh().boundaryMesh().findPatchID(exposedPatchName_);
|
||||
subMeshPtr_.reset(nullptr);
|
||||
|
||||
bitSet cellsToSelect(mesh().cellZones().selection(zoneNames_));
|
||||
|
||||
DebugInfo
|
||||
<< "Allocating subset of size "
|
||||
<< cellsToSelect.count()
|
||||
<< " with exposed faces into patch "
|
||||
<< exposedPatchi << endl;
|
||||
|
||||
|
||||
// If we will use a fvMeshSubset so can apply bounds as well to make
|
||||
// the initial selection smaller.
|
||||
|
||||
const boundBox& clipBb = isoParams_.getClipBounds();
|
||||
if (clipBb.valid() && cellsToSelect.any())
|
||||
// Handle cell zones as inverse (blocked) selection
|
||||
if (!ignoreCellsPtr_)
|
||||
{
|
||||
const auto& cellCentres = fvm.C();
|
||||
ignoreCellsPtr_.reset(new bitSet);
|
||||
|
||||
for (const label celli : cellsToSelect)
|
||||
if (hasCellZones)
|
||||
{
|
||||
const point& cc = cellCentres[celli];
|
||||
bitSet select(mesh().cellZones().selection(zoneNames_));
|
||||
|
||||
if (!clipBb.contains(cc))
|
||||
if (select.any() && !select.all())
|
||||
{
|
||||
cellsToSelect.unset(celli);
|
||||
// From selection to blocking
|
||||
select.flip();
|
||||
|
||||
*ignoreCellsPtr_ = std::move(select);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// A standard subMesh treatment
|
||||
|
||||
DebugInfo
|
||||
<< "Bounded subset of size "
|
||||
<< cellsToSelect.count() << endl;
|
||||
if (ignoreCellsPtr_)
|
||||
{
|
||||
ignoreCellsPtr_->clearStorage();
|
||||
}
|
||||
else
|
||||
{
|
||||
ignoreCellsPtr_.reset(new bitSet);
|
||||
}
|
||||
|
||||
subMeshPtr_.reset
|
||||
(
|
||||
new fvMeshSubset(fvm, cellsToSelect, exposedPatchi)
|
||||
);
|
||||
// Get sub-mesh if any
|
||||
if (!subMeshPtr_ && hasCellZones)
|
||||
{
|
||||
const label exposedPatchi =
|
||||
mesh().boundaryMesh().findPatchID(exposedPatchName_);
|
||||
|
||||
bitSet cellsToSelect(mesh().cellZones().selection(zoneNames_));
|
||||
|
||||
DebugInfo
|
||||
<< "Allocating subset of size "
|
||||
<< cellsToSelect.count() << " with exposed faces into patch "
|
||||
<< exposedPatchi << endl;
|
||||
|
||||
|
||||
// If we will use a fvMeshSubset so can apply bounds as well to make
|
||||
// the initial selection smaller.
|
||||
|
||||
const boundBox& clipBb = isoParams_.getClipBounds();
|
||||
if (clipBb.valid() && cellsToSelect.any())
|
||||
{
|
||||
const auto& cellCentres = fvm.C();
|
||||
|
||||
for (const label celli : cellsToSelect)
|
||||
{
|
||||
const point& cc = cellCentres[celli];
|
||||
|
||||
if (!clipBb.contains(cc))
|
||||
{
|
||||
cellsToSelect.unset(celli);
|
||||
}
|
||||
}
|
||||
|
||||
DebugInfo
|
||||
<< "Bounded subset of size "
|
||||
<< cellsToSelect.count() << endl;
|
||||
}
|
||||
|
||||
subMeshPtr_.reset
|
||||
(
|
||||
new fvMeshSubset(fvm, cellsToSelect, exposedPatchi)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -288,7 +434,6 @@ void Foam::sampledCuttingPlane::createGeometry()
|
||||
dimensionedScalar(dimLength, Zero)
|
||||
)
|
||||
);
|
||||
|
||||
const volScalarField& cellDistance = cellDistancePtr_();
|
||||
|
||||
setDistanceFields(plane_);
|
||||
@ -318,66 +463,37 @@ void Foam::sampledCuttingPlane::createGeometry()
|
||||
}
|
||||
|
||||
|
||||
// This will soon improve (reduced clutter)
|
||||
// Create surfaces for each offset
|
||||
|
||||
// Direct from cell field and point field.
|
||||
if (isoParams_.algorithm() == isoSurfaceParams::ALGO_POINT)
|
||||
PtrList<isoSurfaceBase> isoSurfPtrs(offsets_.size());
|
||||
|
||||
forAll(offsets_, surfi)
|
||||
{
|
||||
isoSurfacePtr_.reset
|
||||
isoSurfPtrs.set
|
||||
(
|
||||
new isoSurfacePoint
|
||||
surfi,
|
||||
isoSurfaceBase::New
|
||||
(
|
||||
isoParams_,
|
||||
cellDistance,
|
||||
pointDistance_,
|
||||
scalar(0), // distance
|
||||
isoParams_
|
||||
offsets_[surfi],
|
||||
*ignoreCellsPtr_
|
||||
)
|
||||
);
|
||||
}
|
||||
else if (isoParams_.algorithm() == isoSurfaceParams::ALGO_CELL)
|
||||
{
|
||||
isoSurfaceCell surf
|
||||
(
|
||||
fvm,
|
||||
cellDistance,
|
||||
pointDistance_,
|
||||
scalar(0), // distance
|
||||
isoParams_
|
||||
);
|
||||
|
||||
surface_.transfer(static_cast<meshedSurface&>(surf));
|
||||
meshCells_.transfer(surf.meshCells());
|
||||
}
|
||||
else
|
||||
{
|
||||
// ALGO_TOPO
|
||||
isoSurfaceTopo surf
|
||||
(
|
||||
fvm,
|
||||
cellDistance,
|
||||
pointDistance_,
|
||||
scalar(0), // distance
|
||||
isoParams_
|
||||
);
|
||||
// And flatten
|
||||
combineSurfaces(isoSurfPtrs);
|
||||
|
||||
surface_.transfer(static_cast<meshedSurface&>(surf));
|
||||
meshCells_.transfer(surf.meshCells());
|
||||
}
|
||||
|
||||
// Only retain for iso-surface
|
||||
// Discard fields if not required by an iso-surface
|
||||
if (!isoSurfacePtr_)
|
||||
{
|
||||
cellDistancePtr_.reset(nullptr);
|
||||
pointDistance_.clear();
|
||||
}
|
||||
|
||||
if (subMeshPtr_ && meshCells_.size())
|
||||
{
|
||||
// With the correct addressing into the full mesh
|
||||
meshCells_ =
|
||||
UIndirectList<label>(subMeshPtr_->cellMap(), meshCells_);
|
||||
}
|
||||
|
||||
if (debug)
|
||||
{
|
||||
print(Pout);
|
||||
@ -397,6 +513,7 @@ Foam::sampledCuttingPlane::sampledCuttingPlane
|
||||
:
|
||||
sampledSurface(name, mesh, dict),
|
||||
plane_(dict),
|
||||
offsets_(),
|
||||
isoParams_
|
||||
(
|
||||
dict,
|
||||
@ -404,15 +521,59 @@ Foam::sampledCuttingPlane::sampledCuttingPlane
|
||||
isoSurfaceParams::filterType::DIAGCELL
|
||||
),
|
||||
average_(dict.getOrDefault("average", false)),
|
||||
simpleSubMesh_(dict.getOrDefault("simpleSubMesh", false)),
|
||||
zoneNames_(),
|
||||
exposedPatchName_(),
|
||||
needsUpdate_(true),
|
||||
subMeshPtr_(nullptr),
|
||||
cellDistancePtr_(nullptr),
|
||||
|
||||
surface_(),
|
||||
meshCells_(),
|
||||
isoSurfacePtr_(nullptr)
|
||||
isoSurfacePtr_(nullptr),
|
||||
|
||||
subMeshPtr_(nullptr),
|
||||
ignoreCellsPtr_(nullptr),
|
||||
cellDistancePtr_(nullptr),
|
||||
pointDistance_()
|
||||
{
|
||||
dict.readIfPresent("offsets", offsets_);
|
||||
|
||||
if (offsets_.empty())
|
||||
{
|
||||
offsets_.resize(1);
|
||||
offsets_.first() = Zero;
|
||||
}
|
||||
|
||||
if (offsets_.size() > 1)
|
||||
{
|
||||
const label nOrig = offsets_.size();
|
||||
|
||||
inplaceUniqueSort(offsets_);
|
||||
|
||||
if (nOrig != offsets_.size())
|
||||
{
|
||||
IOWarningInFunction(dict)
|
||||
<< "Removed non-unique offsets" << nl;
|
||||
}
|
||||
}
|
||||
|
||||
if (isoParams_.algorithm() == isoSurfaceParams::ALGO_POINT)
|
||||
{
|
||||
// Not possible for ALGO_POINT
|
||||
simpleSubMesh_ = false;
|
||||
|
||||
// Not possible for ALGO_POINT
|
||||
if (offsets_.size() > 1)
|
||||
{
|
||||
FatalIOErrorInFunction(dict)
|
||||
<< "Multiple offsets with iso-surface (point) not supported"
|
||||
<< " since needs original interpolators." << nl
|
||||
<< exit(FatalIOError);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Zones
|
||||
|
||||
if (!dict.readIfPresent("zones", zoneNames_) && dict.found("zone"))
|
||||
{
|
||||
zoneNames_.resize(1);
|
||||
@ -589,6 +750,7 @@ void Foam::sampledCuttingPlane::print(Ostream& os) const
|
||||
{
|
||||
os << "sampledCuttingPlane: " << name() << " :"
|
||||
<< " plane:" << plane_
|
||||
<< " offsets:" << flatOutput(offsets_)
|
||||
<< " faces:" << faces().size()
|
||||
<< " points:" << points().size();
|
||||
}
|
||||
|
||||
@ -55,6 +55,7 @@ Usage
|
||||
Property | Description | Required | Default
|
||||
type | cuttingPlane | yes |
|
||||
planeType | plane description (pointAndNormal etc) | yes |
|
||||
offsets | Offsets of the origin in the normal direction | no | (0)
|
||||
isoMethod | Iso-algorithm (cell/topo/point) | no | topo
|
||||
bounds | limit with bounding box | no |
|
||||
zone | limit to cell zone (name or regex) | no |
|
||||
@ -81,7 +82,7 @@ SourceFiles
|
||||
#include "sampledSurface.H"
|
||||
#include "plane.H"
|
||||
#include "fvMeshSubset.H"
|
||||
#include "isoSurfacePoint.H"
|
||||
#include "isoSurfaceBase.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
@ -101,12 +102,18 @@ class sampledCuttingPlane
|
||||
//- Plane
|
||||
const plane plane_;
|
||||
|
||||
//- The offsets to the plane - defaults to (0).
|
||||
List<scalar> offsets_;
|
||||
|
||||
//- Parameters (filtering etc) for iso-surface
|
||||
isoSurfaceParams isoParams_;
|
||||
|
||||
//- Whether to recalculate cell values as average of point values
|
||||
bool average_;
|
||||
|
||||
//- Use simple sub-meshing in algorithm itself
|
||||
bool simpleSubMesh_;
|
||||
|
||||
//- The zone or zones in which cutting is to occur
|
||||
wordRes zoneNames_;
|
||||
|
||||
@ -117,16 +124,6 @@ class sampledCuttingPlane
|
||||
mutable bool needsUpdate_;
|
||||
|
||||
|
||||
//- Mesh subset (optional: only used with zones)
|
||||
autoPtr<fvMeshSubset> subMeshPtr_;
|
||||
|
||||
//- Distance to cell centres
|
||||
autoPtr<volScalarField> cellDistancePtr_;
|
||||
|
||||
//- Distance to points
|
||||
scalarField pointDistance_;
|
||||
|
||||
|
||||
// Sampling geometry. Directly stored or via an iso-surface (ALGO_POINT)
|
||||
|
||||
//- The extracted surface (direct storage)
|
||||
@ -136,7 +133,25 @@ class sampledCuttingPlane
|
||||
mutable labelList meshCells_;
|
||||
|
||||
//- Constructed iso-surface (ALGO_POINT), for interpolators
|
||||
autoPtr<isoSurfacePoint> isoSurfacePtr_;
|
||||
autoPtr<isoSurfaceBase> isoSurfacePtr_;
|
||||
|
||||
|
||||
// Mesh Subsetting
|
||||
|
||||
//- Cached subMesh for (pre-)subset of cell zones
|
||||
mutable autoPtr<fvMeshSubset> subMeshPtr_;
|
||||
|
||||
//- Cached ignore cells for (post-)subset of cell zones
|
||||
mutable autoPtr<bitSet> ignoreCellsPtr_;
|
||||
|
||||
|
||||
// Fields
|
||||
|
||||
//- Distance to cell centres
|
||||
autoPtr<volScalarField> cellDistancePtr_;
|
||||
|
||||
//- Distance to points
|
||||
scalarField pointDistance_;
|
||||
|
||||
|
||||
// Private Member Functions
|
||||
@ -151,6 +166,9 @@ class sampledCuttingPlane
|
||||
//- Fill cellDistance, pointDistance fields for the specified plane
|
||||
void setDistanceFields(const plane& pln);
|
||||
|
||||
//- Collect iso-surfaces into a single surface (No point merging)
|
||||
void combineSurfaces(PtrList<isoSurfaceBase>& isoSurfPtrs);
|
||||
|
||||
//- Create iso surface
|
||||
void createGeometry();
|
||||
|
||||
|
||||
@ -91,7 +91,6 @@ Foam::sampledCuttingPlane::sampleOnIsoSurfacePoints
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class Type>
|
||||
Foam::tmp<Foam::Field<Type>>
|
||||
Foam::sampledCuttingPlane::sampleOnPoints
|
||||
|
||||
@ -41,6 +41,205 @@ namespace Foam
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
const Foam::Enum
|
||||
<
|
||||
Foam::distanceSurface::topologyFilterType
|
||||
>
|
||||
Foam::distanceSurface::topoFilterNames_
|
||||
({
|
||||
{ topologyFilterType::NONE, "none" },
|
||||
{ topologyFilterType::LARGEST_REGION, "largestRegion" },
|
||||
{ topologyFilterType::NEAREST_POINTS, "nearestPoints" },
|
||||
{ topologyFilterType::PROXIMITY, "proximity" },
|
||||
});
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
// Check that all point hits are valid
|
||||
static inline void checkAllHits(const UList<pointIndexHit>& nearest)
|
||||
{
|
||||
label notHit = 0;
|
||||
for (const pointIndexHit& pHit : nearest)
|
||||
{
|
||||
if (!pHit.hit())
|
||||
{
|
||||
++notHit;
|
||||
}
|
||||
}
|
||||
|
||||
if (notHit)
|
||||
{
|
||||
FatalErrorInFunction
|
||||
<< "Had " << notHit << " from " << nearest.size()
|
||||
<< " without a point hit" << endl
|
||||
<< abort(FatalError);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Normal distance from surface hit point to a point in the mesh
|
||||
static inline scalar normalDistance_zero
|
||||
(
|
||||
const point& pt,
|
||||
const pointIndexHit& pHit,
|
||||
const vector& norm
|
||||
)
|
||||
{
|
||||
const vector diff(pt - pHit.point());
|
||||
|
||||
return (diff & norm);
|
||||
}
|
||||
|
||||
|
||||
// Signed distance from surface hit point to a point in the mesh,
|
||||
// the sign is dictated by the normal
|
||||
static inline scalar normalDistance_nonzero
|
||||
(
|
||||
const point& pt,
|
||||
const pointIndexHit& pHit,
|
||||
const vector& norm
|
||||
)
|
||||
{
|
||||
const vector diff(pt - pHit.point());
|
||||
const scalar normDist = (diff & norm);
|
||||
|
||||
return Foam::sign(normDist) * Foam::mag(diff);
|
||||
}
|
||||
|
||||
|
||||
// Normal distance from surface hit point to a point in the mesh
|
||||
static inline void calcNormalDistance_zero
|
||||
(
|
||||
scalarField& distance,
|
||||
const pointField& points,
|
||||
const List<pointIndexHit>& nearest,
|
||||
const vectorField& normals
|
||||
)
|
||||
{
|
||||
forAll(nearest, i)
|
||||
{
|
||||
distance[i] =
|
||||
normalDistance_zero(points[i], nearest[i], normals[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Signed distance from surface hit point -> point in the mesh,
|
||||
// the sign is dictated by the normal
|
||||
static inline void calcNormalDistance_nonzero
|
||||
(
|
||||
scalarField& distance,
|
||||
const pointField& points,
|
||||
const List<pointIndexHit>& nearest,
|
||||
const vectorField& normals
|
||||
)
|
||||
{
|
||||
forAll(nearest, i)
|
||||
{
|
||||
distance[i] =
|
||||
normalDistance_nonzero(points[i], nearest[i], normals[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Close to the surface: normal distance from surface hit point
|
||||
// Far from surface: distance from surface hit point
|
||||
//
|
||||
// Note
|
||||
// This switch may be helpful when working directly with
|
||||
// distance/gradient fields. Has low overhead otherwise.
|
||||
// May be replaced in the future (2020-11)
|
||||
static inline void calcNormalDistance_filtered
|
||||
(
|
||||
scalarField& distance,
|
||||
const bitSet& ignoreLocation,
|
||||
const pointField& points,
|
||||
const List<pointIndexHit>& nearest,
|
||||
const vectorField& normals
|
||||
)
|
||||
{
|
||||
forAll(nearest, i)
|
||||
{
|
||||
if (ignoreLocation.test(i))
|
||||
{
|
||||
distance[i] =
|
||||
normalDistance_nonzero(points[i], nearest[i], normals[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
distance[i] =
|
||||
normalDistance_zero(points[i], nearest[i], normals[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Flat surfaces (eg, a plane) have an extreme change in
|
||||
// the normal at the edge, which creates a zero-crossing
|
||||
// extending to infinity.
|
||||
//
|
||||
// Ad hoc treatment: require that the surface hit
|
||||
// point is within a somewhat generous bounding box
|
||||
// for the cell
|
||||
template<bool WantPointFilter = false>
|
||||
static bitSet simpleGeometricFilter
|
||||
(
|
||||
bitSet& ignoreCells,
|
||||
const List<pointIndexHit>& nearest,
|
||||
const polyMesh& mesh
|
||||
)
|
||||
{
|
||||
// A deny filter. Initially false (accept everything)
|
||||
ignoreCells.resize(mesh.nCells());
|
||||
|
||||
bitSet pointFilter;
|
||||
if (WantPointFilter)
|
||||
{
|
||||
// Create as accept filter. Initially false (deny everything)
|
||||
pointFilter.resize(mesh.nPoints());
|
||||
}
|
||||
|
||||
boundBox cellBb;
|
||||
|
||||
forAll(nearest, celli)
|
||||
{
|
||||
const point& pt = nearest[celli].point();
|
||||
|
||||
const labelList& cPoints = mesh.cellPoints(celli);
|
||||
|
||||
cellBb.clear();
|
||||
cellBb.add(mesh.points(), cPoints);
|
||||
|
||||
// Expand slightly to catch corners
|
||||
cellBb.inflate(0.1);
|
||||
|
||||
if (!cellBb.contains(pt))
|
||||
{
|
||||
ignoreCells.set(celli);
|
||||
}
|
||||
else if (WantPointFilter)
|
||||
{
|
||||
// Good cell candidate, accept its points
|
||||
pointFilter.set(cPoints);
|
||||
}
|
||||
}
|
||||
|
||||
// Flip from accept to deny filter
|
||||
pointFilter.flip();
|
||||
|
||||
return pointFilter;
|
||||
}
|
||||
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::distanceSurface::distanceSurface
|
||||
@ -51,7 +250,7 @@ Foam::distanceSurface::distanceSurface
|
||||
)
|
||||
:
|
||||
mesh_(mesh),
|
||||
surfPtr_
|
||||
geometryPtr_
|
||||
(
|
||||
searchableSurface::New
|
||||
(
|
||||
@ -68,19 +267,69 @@ Foam::distanceSurface::distanceSurface
|
||||
dict
|
||||
)
|
||||
),
|
||||
distance_(dict.get<scalar>("distance")),
|
||||
signed_
|
||||
distance_(dict.getOrDefault<scalar>("distance", 0)),
|
||||
withZeroDistance_(equal(distance_, 0)),
|
||||
withSignDistance_
|
||||
(
|
||||
distance_ < 0 || equal(distance_, Zero) || dict.get<bool>("signed")
|
||||
withZeroDistance_
|
||||
|| (distance_ < 0)
|
||||
|| dict.getOrDefault<bool>("signed", true)
|
||||
),
|
||||
isoParams_
|
||||
(
|
||||
dict,
|
||||
isoSurfaceBase::ALGO_TOPO
|
||||
isoSurfaceParams::ALGO_TOPO,
|
||||
isoSurfaceParams::filterType::DIAGCELL
|
||||
),
|
||||
topoFilter_
|
||||
(
|
||||
topoFilterNames_.getOrDefault
|
||||
(
|
||||
"topology",
|
||||
dict,
|
||||
topologyFilterType::NONE
|
||||
)
|
||||
),
|
||||
nearestPoints_(),
|
||||
maxDistanceSqr_(Foam::sqr(GREAT)),
|
||||
absProximity_(dict.getOrDefault<scalar>("absProximity", 1e-5)),
|
||||
cellDistancePtr_(nullptr),
|
||||
pointDistance_(),
|
||||
surface_(),
|
||||
meshCells_(),
|
||||
isoSurfacePtr_(nullptr)
|
||||
{
|
||||
if (topologyFilterType::NEAREST_POINTS == topoFilter_)
|
||||
{
|
||||
dict.readEntry("nearestPoints", nearestPoints_);
|
||||
}
|
||||
|
||||
if (dict.readIfPresent("maxDistance", maxDistanceSqr_))
|
||||
{
|
||||
maxDistanceSqr_ = Foam::sqr(maxDistanceSqr_);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Foam::distanceSurface::distanceSurface
|
||||
(
|
||||
const polyMesh& mesh,
|
||||
const word& surfaceType,
|
||||
const word& surfaceName,
|
||||
const isoSurfaceParams& params,
|
||||
const bool interpolate
|
||||
)
|
||||
:
|
||||
distanceSurface
|
||||
(
|
||||
mesh,
|
||||
interpolate,
|
||||
surfaceType,
|
||||
surfaceName,
|
||||
scalar(0),
|
||||
true, // redundant - must be signed
|
||||
params
|
||||
)
|
||||
{}
|
||||
|
||||
|
||||
@ -96,7 +345,7 @@ Foam::distanceSurface::distanceSurface
|
||||
)
|
||||
:
|
||||
mesh_(mesh),
|
||||
surfPtr_
|
||||
geometryPtr_
|
||||
(
|
||||
searchableSurface::New
|
||||
(
|
||||
@ -114,11 +363,20 @@ Foam::distanceSurface::distanceSurface
|
||||
)
|
||||
),
|
||||
distance_(distance),
|
||||
signed_
|
||||
withZeroDistance_(equal(distance_, 0)),
|
||||
withSignDistance_
|
||||
(
|
||||
useSignedDistance || distance_ < 0 || equal(distance_, Zero)
|
||||
withZeroDistance_
|
||||
|| (distance_ < 0)
|
||||
|| useSignedDistance
|
||||
),
|
||||
isoParams_(params),
|
||||
topoFilter_(topologyFilterType::NONE),
|
||||
nearestPoints_(),
|
||||
maxDistanceSqr_(Foam::sqr(GREAT)),
|
||||
absProximity_(1e-5),
|
||||
cellDistancePtr_(nullptr),
|
||||
pointDistance_(),
|
||||
surface_(),
|
||||
meshCells_(),
|
||||
isoSurfacePtr_(nullptr)
|
||||
@ -139,7 +397,10 @@ void Foam::distanceSurface::createGeometry()
|
||||
surface_.clear();
|
||||
meshCells_.clear();
|
||||
|
||||
const fvMesh& fvm = static_cast<const fvMesh&>(mesh_);
|
||||
// Doing searches on this surface
|
||||
const searchableSurface& geom = geometryPtr_();
|
||||
|
||||
const fvMesh& fvmesh = static_cast<const fvMesh&>(mesh_);
|
||||
|
||||
// Distance to cell centres
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
@ -151,132 +412,126 @@ void Foam::distanceSurface::createGeometry()
|
||||
IOobject
|
||||
(
|
||||
"distanceSurface.cellDistance",
|
||||
fvm.time().timeName(),
|
||||
fvm.time(),
|
||||
fvmesh.time().timeName(),
|
||||
fvmesh.time(),
|
||||
IOobject::NO_READ,
|
||||
IOobject::NO_WRITE,
|
||||
false
|
||||
),
|
||||
fvm,
|
||||
dimensionedScalar(dimLength, Zero)
|
||||
fvmesh,
|
||||
dimensionedScalar(dimLength, GREAT)
|
||||
)
|
||||
);
|
||||
volScalarField& cellDistance = *cellDistancePtr_;
|
||||
auto& cellDistance = *cellDistancePtr_;
|
||||
|
||||
// For distance = 0 (and isoSurfaceCell) we apply additional filtering
|
||||
|
||||
// For distance = 0 we apply additional geometric filtering
|
||||
// to limit the extent of open edges.
|
||||
//
|
||||
// Does not work with ALGO_POINT
|
||||
|
||||
bitSet ignoreCells, ignoreCellPoints;
|
||||
|
||||
const bool isZeroDist = equal(distance_, Zero);
|
||||
const bool filterCells =
|
||||
(
|
||||
isZeroDist
|
||||
withZeroDistance_
|
||||
&& isoParams_.algorithm() != isoSurfaceParams::ALGO_POINT
|
||||
);
|
||||
|
||||
bitSet ignoreCells;
|
||||
if (filterCells)
|
||||
{
|
||||
ignoreCells.resize(fvm.nCells());
|
||||
}
|
||||
|
||||
// Internal field
|
||||
{
|
||||
const pointField& cc = fvm.C();
|
||||
const pointField& cc = fvmesh.C();
|
||||
scalarField& fld = cellDistance.primitiveFieldRef();
|
||||
|
||||
List<pointIndexHit> nearest;
|
||||
surfPtr_().findNearest
|
||||
geom.findNearest
|
||||
(
|
||||
cc,
|
||||
scalarField(cc.size(), GREAT),
|
||||
// Use initialized field (GREAT) to limit search too
|
||||
fld,
|
||||
nearest
|
||||
);
|
||||
checkAllHits(nearest);
|
||||
|
||||
if (signed_ || isZeroDist)
|
||||
// Geometric pre-filtering when distance == 0
|
||||
if (filterCells)
|
||||
{
|
||||
ignoreCellPoints =
|
||||
simpleGeometricFilter<false>(ignoreCells, nearest, fvmesh);
|
||||
}
|
||||
|
||||
if (withSignDistance_)
|
||||
{
|
||||
vectorField norms;
|
||||
surfPtr_().getNormal(nearest, norms);
|
||||
geom.getNormal(nearest, norms);
|
||||
|
||||
boundBox cellBb;
|
||||
|
||||
forAll(norms, i)
|
||||
if (filterCells)
|
||||
{
|
||||
const point diff(cc[i] - nearest[i].hitPoint());
|
||||
|
||||
fld[i] =
|
||||
// With inside/outside switching (see note above)
|
||||
calcNormalDistance_filtered
|
||||
(
|
||||
isZeroDist // Use normal distance
|
||||
? (diff & norms[i])
|
||||
: Foam::sign(diff & norms[i]) * Foam::mag(diff)
|
||||
fld,
|
||||
ignoreCells,
|
||||
cc,
|
||||
nearest,
|
||||
norms
|
||||
);
|
||||
|
||||
if (filterCells)
|
||||
{
|
||||
cellBb.clear();
|
||||
cellBb.add(fvm.points(), fvm.cellPoints(i));
|
||||
|
||||
// Expand slightly to catch corners
|
||||
cellBb.inflate(0.1);
|
||||
|
||||
if (!cellBb.contains(nearest[i].hitPoint()))
|
||||
{
|
||||
ignoreCells.set(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (withZeroDistance_)
|
||||
{
|
||||
calcNormalDistance_zero(fld, cc, nearest, norms);
|
||||
}
|
||||
else
|
||||
{
|
||||
calcNormalDistance_nonzero(fld, cc, nearest, norms);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
forAll(nearest, i)
|
||||
{
|
||||
fld[i] = Foam::mag(cc[i] - nearest[i].hitPoint());
|
||||
|
||||
// No filtering for unsigned or distance != 0.
|
||||
}
|
||||
calcAbsoluteDistance(fld, cc, nearest);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Patch fields
|
||||
{
|
||||
volScalarField::Boundary& cellDistanceBf =
|
||||
cellDistance.boundaryFieldRef();
|
||||
|
||||
forAll(fvm.C().boundaryField(), patchi)
|
||||
forAll(fvmesh.C().boundaryField(), patchi)
|
||||
{
|
||||
const pointField& cc = fvm.C().boundaryField()[patchi];
|
||||
fvPatchScalarField& fld = cellDistanceBf[patchi];
|
||||
const pointField& cc = fvmesh.C().boundaryField()[patchi];
|
||||
scalarField& fld = cellDistance.boundaryFieldRef()[patchi];
|
||||
|
||||
List<pointIndexHit> nearest;
|
||||
surfPtr_().findNearest
|
||||
geom.findNearest
|
||||
(
|
||||
cc,
|
||||
scalarField(cc.size(), GREAT),
|
||||
nearest
|
||||
);
|
||||
checkAllHits(nearest);
|
||||
|
||||
if (signed_)
|
||||
if (withSignDistance_)
|
||||
{
|
||||
vectorField norms;
|
||||
surfPtr_().getNormal(nearest, norms);
|
||||
geom.getNormal(nearest, norms);
|
||||
|
||||
forAll(norms, i)
|
||||
if (withZeroDistance_)
|
||||
{
|
||||
const point diff(cc[i] - nearest[i].hitPoint());
|
||||
// Slight inconsistency in boundary vs interior when
|
||||
// cells are filtered, but the patch fields are only
|
||||
// used by isoSurfacePoint, and filtering is disabled
|
||||
// for that anyhow.
|
||||
|
||||
fld[i] =
|
||||
(
|
||||
isZeroDist // Use normal distance
|
||||
? (diff & norms[i])
|
||||
: Foam::sign(diff & norms[i]) * Foam::mag(diff)
|
||||
);
|
||||
calcNormalDistance_zero(fld, cc, nearest, norms);
|
||||
}
|
||||
else
|
||||
{
|
||||
calcNormalDistance_nonzero(fld, cc, nearest, norms);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
forAll(nearest, i)
|
||||
{
|
||||
fld[i] = Foam::mag(cc[i] - nearest[i].hitPoint());
|
||||
}
|
||||
calcAbsoluteDistance(fld, cc, nearest);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -287,45 +542,87 @@ void Foam::distanceSurface::createGeometry()
|
||||
|
||||
|
||||
// Distance to points
|
||||
pointDistance_.resize(fvm.nPoints());
|
||||
pointDistance_.resize(fvmesh.nPoints());
|
||||
pointDistance_ = GREAT;
|
||||
{
|
||||
const pointField& pts = fvm.points();
|
||||
const pointField& pts = fvmesh.points();
|
||||
scalarField& fld = pointDistance_;
|
||||
|
||||
List<pointIndexHit> nearest;
|
||||
surfPtr_().findNearest
|
||||
geom.findNearest
|
||||
(
|
||||
pts,
|
||||
scalarField(pts.size(), GREAT),
|
||||
// Use initialized field (GREAT) to limit search too
|
||||
pointDistance_,
|
||||
nearest
|
||||
);
|
||||
checkAllHits(nearest);
|
||||
|
||||
if (signed_)
|
||||
if (withSignDistance_)
|
||||
{
|
||||
vectorField norms;
|
||||
surfPtr_().getNormal(nearest, norms);
|
||||
geom.getNormal(nearest, norms);
|
||||
|
||||
forAll(norms, i)
|
||||
if (filterCells)
|
||||
{
|
||||
const point diff(pts[i] - nearest[i].hitPoint());
|
||||
|
||||
pointDistance_[i] =
|
||||
// With inside/outside switching (see note above)
|
||||
calcNormalDistance_filtered
|
||||
(
|
||||
isZeroDist // Use normal distance
|
||||
? (diff & norms[i])
|
||||
: Foam::sign(diff & norms[i]) * Foam::mag(diff)
|
||||
fld,
|
||||
ignoreCellPoints,
|
||||
pts,
|
||||
nearest,
|
||||
norms
|
||||
);
|
||||
}
|
||||
else if (withZeroDistance_)
|
||||
{
|
||||
calcNormalDistance_zero(fld, pts, nearest, norms);
|
||||
}
|
||||
else
|
||||
{
|
||||
calcNormalDistance_nonzero(fld, pts, nearest, norms);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
forAll(nearest, i)
|
||||
{
|
||||
pointDistance_[i] = Foam::mag(pts[i] - nearest[i].hitPoint());
|
||||
}
|
||||
calcAbsoluteDistance(fld, pts, nearest);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Don't need ignoreCells if there is nothing to ignore.
|
||||
if (ignoreCells.none())
|
||||
{
|
||||
ignoreCells.clearStorage();
|
||||
}
|
||||
else if (filterCells && topologyFilterType::NONE != topoFilter_)
|
||||
{
|
||||
// For refine blocked cells (eg, checking actual cells cut)
|
||||
isoSurfaceBase isoCutter
|
||||
(
|
||||
mesh_,
|
||||
cellDistance,
|
||||
pointDistance_,
|
||||
distance_
|
||||
);
|
||||
|
||||
if (topologyFilterType::LARGEST_REGION == topoFilter_)
|
||||
{
|
||||
refineBlockedCells(ignoreCells, isoCutter);
|
||||
filterKeepLargestRegion(ignoreCells);
|
||||
}
|
||||
else if (topologyFilterType::NEAREST_POINTS == topoFilter_)
|
||||
{
|
||||
refineBlockedCells(ignoreCells, isoCutter);
|
||||
filterKeepNearestRegions(ignoreCells);
|
||||
}
|
||||
}
|
||||
|
||||
// Don't need point filter beyond this point
|
||||
ignoreCellPoints.clearStorage();
|
||||
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "Writing cell distance:" << cellDistance.objectPath() << endl;
|
||||
@ -335,13 +632,13 @@ void Foam::distanceSurface::createGeometry()
|
||||
IOobject
|
||||
(
|
||||
"distanceSurface.pointDistance",
|
||||
fvm.time().timeName(),
|
||||
fvm.time(),
|
||||
fvmesh.time().timeName(),
|
||||
fvmesh.time(),
|
||||
IOobject::NO_READ,
|
||||
IOobject::NO_WRITE,
|
||||
false
|
||||
),
|
||||
pointMesh::New(fvm),
|
||||
pointMesh::New(fvmesh),
|
||||
dimensionedScalar(dimLength, Zero)
|
||||
);
|
||||
pDist.primitiveFieldRef() = pointDistance_;
|
||||
@ -350,60 +647,40 @@ void Foam::distanceSurface::createGeometry()
|
||||
pDist.write();
|
||||
}
|
||||
|
||||
// Don't need ignoreCells if there is nothing to ignore.
|
||||
if (!ignoreCells.any())
|
||||
{
|
||||
ignoreCells.clear();
|
||||
}
|
||||
|
||||
|
||||
// This will soon improve (reduced clutter)
|
||||
|
||||
// Direct from cell field and point field.
|
||||
if (isoParams_.algorithm() == isoSurfaceParams::ALGO_POINT)
|
||||
{
|
||||
isoSurfacePtr_.reset
|
||||
isoSurfacePtr_.reset
|
||||
(
|
||||
isoSurfaceBase::New
|
||||
(
|
||||
new isoSurfacePoint
|
||||
(
|
||||
cellDistance,
|
||||
pointDistance_,
|
||||
distance_,
|
||||
isoParams_,
|
||||
ignoreCells
|
||||
)
|
||||
);
|
||||
}
|
||||
else if (isoParams_.algorithm() == isoSurfaceParams::ALGO_CELL)
|
||||
{
|
||||
isoSurfaceCell surf
|
||||
(
|
||||
fvm,
|
||||
isoParams_,
|
||||
cellDistance,
|
||||
pointDistance_,
|
||||
distance_,
|
||||
isoParams_,
|
||||
ignoreCells
|
||||
);
|
||||
)
|
||||
);
|
||||
|
||||
surface_.transfer(static_cast<meshedSurface&>(surf));
|
||||
meshCells_.transfer(surf.meshCells());
|
||||
}
|
||||
else
|
||||
|
||||
// ALGO_POINT still needs cell, point fields (for interpolate)
|
||||
// The others can do straight transfer
|
||||
|
||||
// But also flatten into a straight transfer for proximity filtering
|
||||
if
|
||||
(
|
||||
isoParams_.algorithm() != isoSurfaceParams::ALGO_POINT
|
||||
|| topologyFilterType::PROXIMITY == topoFilter_
|
||||
)
|
||||
{
|
||||
// ALGO_TOPO
|
||||
isoSurfaceTopo surf
|
||||
(
|
||||
fvm,
|
||||
cellDistance,
|
||||
pointDistance_,
|
||||
distance_,
|
||||
isoParams_,
|
||||
ignoreCells
|
||||
);
|
||||
surface_.transfer(static_cast<meshedSurface&>(*isoSurfacePtr_));
|
||||
meshCells_.transfer(isoSurfacePtr_->meshCells());
|
||||
|
||||
surface_.transfer(static_cast<meshedSurface&>(surf));
|
||||
meshCells_.transfer(surf.meshCells());
|
||||
isoSurfacePtr_.reset(nullptr);
|
||||
cellDistancePtr_.reset(nullptr);
|
||||
pointDistance_.clear();
|
||||
}
|
||||
|
||||
if (topologyFilterType::PROXIMITY == topoFilter_)
|
||||
{
|
||||
filterByProximity();
|
||||
}
|
||||
|
||||
if (debug)
|
||||
|
||||
@ -32,27 +32,82 @@ Description
|
||||
Uses an iso-surface algorithm (cell, topo, point) for constructing the
|
||||
distance surface.
|
||||
|
||||
For a zero-distance surface, it performs additional checks and supports
|
||||
filtering to handle the surface boundaries.
|
||||
|
||||
Usage
|
||||
Example of function object partial specification:
|
||||
\verbatim
|
||||
surfaces
|
||||
{
|
||||
surface1
|
||||
{
|
||||
type distanceSurface;
|
||||
surfaceType triSurfaceMesh;
|
||||
surfaceName something.obj;
|
||||
topology proximity;
|
||||
}
|
||||
|
||||
surface2
|
||||
{
|
||||
type distanceSurface;
|
||||
surfaceType triSurfaceMesh;
|
||||
surfaceName other.obj;
|
||||
|
||||
topology nearestPoints;
|
||||
nearestPoints
|
||||
(
|
||||
(0 0 0)
|
||||
(10 10 0)
|
||||
);
|
||||
|
||||
// Max search distance for nearestPoints
|
||||
maxDistance 0.005;
|
||||
}
|
||||
}
|
||||
\endverbatim
|
||||
|
||||
Dictionary controls:
|
||||
\table
|
||||
Property | Description | Required | Default
|
||||
distance | distance from surface | yes |
|
||||
signed | Use sign when distance is positive | partly |
|
||||
isoMethod | Iso-algorithm (cell/topo/point) | no | topo
|
||||
distance | distance from surface | no | 0
|
||||
signed | Use sign when distance is positive | no | true
|
||||
isoMethod | Iso-algorithm (cell/topo/point) | no | default
|
||||
regularise | Face simplification (enum or bool) | no | true
|
||||
bounds | Limit with bounding box | no |
|
||||
surfaceType | Type of surface | yes |
|
||||
surfaceName | Name of surface in \c triSurface/ | no | dict name
|
||||
topology | Topology filter (none/largestRegion/nearestPoints/proximity) | no | none
|
||||
nearestPoints | Points for point-based segmentation | no |
|
||||
maxDistance | Max search distance for nearestPoints | no | GREAT
|
||||
absProximity | Max proximity of face centres | no | 1e-5
|
||||
\endtable
|
||||
|
||||
Filtering (for zero-distance only)
|
||||
|
||||
- \c largestRegion (pre-filter):
|
||||
The cut cells are checked for topological connectivity and the
|
||||
region with the most number of cut cells is retained.
|
||||
This handles the "ragged" edge problem.
|
||||
|
||||
- \c nearestPoints (pre-filter):
|
||||
The cut cells split into regions, the regions closest to the
|
||||
user-defined points are retained.
|
||||
Uses \c maxDistance for additional control.
|
||||
|
||||
- \c proximity (post-filter):
|
||||
Checks the resulting faces against the original search surface
|
||||
and rejects faces with a distance greater than \c absProximity.
|
||||
.
|
||||
|
||||
Note
|
||||
For distance = 0, some special adjustments.
|
||||
- Always signed (ignoring the input value).
|
||||
- Use normal distance from surface (for better treatment of open edges).
|
||||
- When the isoSurfaceCell algorithm is used, additional checks for open
|
||||
surfaces edges are used to limit the extend of resulting distance
|
||||
surface. The resulting surface elements will not, however, contain
|
||||
partial cell coverage.
|
||||
- Additional checks for open surfaces edges are used to limit the extend
|
||||
of resulting distance surface.
|
||||
The resulting surface elements will, however, contain partial cell
|
||||
coverage. NB: Not applicable if the \c point isoMethod is used.
|
||||
|
||||
The keyword \c cell (bool value) which was use in 1906 and earlier to switch
|
||||
between point/cell algorithms is now ignored (2020-12).
|
||||
@ -69,9 +124,8 @@ SourceFiles
|
||||
|
||||
#include "sampledSurface.H"
|
||||
#include "searchableSurface.H"
|
||||
#include "isoSurfaceCell.H"
|
||||
#include "isoSurfacePoint.H"
|
||||
#include "isoSurfaceTopo.H"
|
||||
#include "isoSurfaceBase.H"
|
||||
#include "pointIndexHit.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
@ -84,23 +138,53 @@ namespace Foam
|
||||
|
||||
class distanceSurface
|
||||
{
|
||||
// Data Types
|
||||
|
||||
//- The type of pre/post face-filtering
|
||||
enum class topologyFilterType : uint8_t
|
||||
{
|
||||
NONE, //!< No additional filtering
|
||||
LARGEST_REGION, //!< Retain largest region
|
||||
NEAREST_POINTS, //!< Retain regions nearest to the points
|
||||
PROXIMITY //!< Post-filter for surface proximity
|
||||
};
|
||||
|
||||
//- Names for the topology filter
|
||||
static const Enum<topologyFilterType> topoFilterNames_;
|
||||
|
||||
|
||||
// Private Data
|
||||
|
||||
//- Reference to mesh
|
||||
const polyMesh& mesh_;
|
||||
|
||||
//- Surface
|
||||
const autoPtr<searchableSurface> surfPtr_;
|
||||
//- Searchable surface
|
||||
const autoPtr<searchableSurface> geometryPtr_;
|
||||
|
||||
//- Distance value
|
||||
const scalar distance_;
|
||||
|
||||
//- Signed distance
|
||||
const bool signed_;
|
||||
//- Distance is zero. Implies signed and additional optimizations
|
||||
const bool withZeroDistance_;
|
||||
|
||||
//- Use signed distance
|
||||
const bool withSignDistance_;
|
||||
|
||||
//- Parameters for iso-surface (algorithm, filter, mergeTol, etc)
|
||||
isoSurfaceParams isoParams_;
|
||||
|
||||
//- Optional topology face-filtering
|
||||
topologyFilterType topoFilter_;
|
||||
|
||||
//- Points for nearest-points segmentation
|
||||
pointField nearestPoints_;
|
||||
|
||||
//- Max search distance squared (for nearestPoints)
|
||||
scalar maxDistanceSqr_;
|
||||
|
||||
//- Max distance for proximity check (post-filtering)
|
||||
scalar absProximity_;
|
||||
|
||||
//- Distance to cell centres
|
||||
autoPtr<volScalarField> cellDistancePtr_;
|
||||
|
||||
@ -117,7 +201,25 @@ class distanceSurface
|
||||
mutable labelList meshCells_;
|
||||
|
||||
//- Extracted iso-surface, for interpolators
|
||||
mutable autoPtr<isoSurfacePoint> isoSurfacePtr_;
|
||||
mutable autoPtr<isoSurfaceBase> isoSurfacePtr_;
|
||||
|
||||
|
||||
// Private Member Functions
|
||||
|
||||
//- Absolute distances from hit points
|
||||
// Hit/miss checks have been done elsewhere.
|
||||
static inline void calcAbsoluteDistance
|
||||
(
|
||||
scalarField& distance,
|
||||
const pointField& points,
|
||||
const List<pointIndexHit>& nearest
|
||||
)
|
||||
{
|
||||
forAll(nearest, i)
|
||||
{
|
||||
distance[i] = Foam::mag(points[i] - nearest[i].point());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
@ -147,6 +249,29 @@ protected:
|
||||
}
|
||||
|
||||
|
||||
// Private Member Functions
|
||||
|
||||
//- Re-filter the blocked cells based on the anticipated cuts
|
||||
// Uses a lightweight variant of cutting.
|
||||
bool refineBlockedCells
|
||||
(
|
||||
bitSet& ignoreCells,
|
||||
const isoSurfaceBase& isoContext
|
||||
) const;
|
||||
|
||||
//- Prepare blockedFaces for region split
|
||||
bitSet filterPrepareRegionSplit(const bitSet& ignoreCells) const;
|
||||
|
||||
//- Adjust extracted iso-surface to remove far faces
|
||||
void filterByProximity();
|
||||
|
||||
//- Keep region with the most cuts (after region split)
|
||||
void filterKeepLargestRegion(bitSet& ignoreCells) const;
|
||||
|
||||
//- Keep region(s) closest to the nearest points
|
||||
void filterKeepNearestRegions(bitSet& ignoreCells) const;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
//- Runtime type information
|
||||
@ -163,6 +288,16 @@ public:
|
||||
const dictionary& dict
|
||||
);
|
||||
|
||||
//- Construct from components with zero-distanced
|
||||
distanceSurface
|
||||
(
|
||||
const polyMesh& mesh,
|
||||
const word& surfaceType,
|
||||
const word& surfaceName,
|
||||
const isoSurfaceParams& params = isoSurfaceParams(),
|
||||
const bool interpolate = false
|
||||
);
|
||||
|
||||
//- Construct from components
|
||||
distanceSurface
|
||||
(
|
||||
@ -188,11 +323,11 @@ public:
|
||||
//- The name of the underlying searchableSurface
|
||||
const word& surfaceName() const
|
||||
{
|
||||
return surfPtr_->name();
|
||||
return geometryPtr_->name();
|
||||
}
|
||||
|
||||
//- The distance to the underlying searchableSurface
|
||||
scalar distance() const
|
||||
scalar distance() const noexcept
|
||||
{
|
||||
return distance_;
|
||||
}
|
||||
|
||||
421
src/sampling/surface/distanceSurface/distanceSurfaceFilter.C
Normal file
421
src/sampling/surface/distanceSurface/distanceSurfaceFilter.C
Normal file
@ -0,0 +1,421 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2020 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 "distanceSurface.H"
|
||||
#include "regionSplit.H"
|
||||
#include "syncTools.H"
|
||||
#include "vtkSurfaceWriter.H"
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
bool Foam::distanceSurface::refineBlockedCells
|
||||
(
|
||||
bitSet& ignoreCells,
|
||||
const isoSurfaceBase& isoCutter
|
||||
) const
|
||||
{
|
||||
// With the cell/point distance fields we can take a second pass at
|
||||
// pre-filtering.
|
||||
// This duplicates how cut detection is determined in the cell/topo
|
||||
// algorithms but is fairly inexpensive (creates no geometry)
|
||||
|
||||
bool changed = false;
|
||||
|
||||
for (label celli = 0; celli < mesh_.nCells(); ++celli)
|
||||
{
|
||||
if (ignoreCells.test(celli))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto cut = isoCutter.getCellCutType(celli);
|
||||
if (!(cut & isoSurfaceBase::ANYCUT))
|
||||
{
|
||||
ignoreCells.set(celli);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
|
||||
Foam::bitSet Foam::distanceSurface::filterPrepareRegionSplit
|
||||
(
|
||||
const bitSet& ignoreCells
|
||||
) const
|
||||
{
|
||||
// Prepare for region split
|
||||
|
||||
bitSet blockedFaces(mesh_.nFaces());
|
||||
|
||||
const labelList& faceOwn = mesh_.faceOwner();
|
||||
const labelList& faceNei = mesh_.faceNeighbour();
|
||||
|
||||
// Could be more efficient
|
||||
for (label facei = 0; facei < mesh_.nInternalFaces(); ++facei)
|
||||
{
|
||||
// If only one cell is blocked, the face corresponds
|
||||
// to an exposed subMesh face
|
||||
|
||||
if
|
||||
(
|
||||
ignoreCells.test(faceOwn[facei])
|
||||
!= ignoreCells.test(faceNei[facei])
|
||||
)
|
||||
{
|
||||
blockedFaces.set(facei);
|
||||
}
|
||||
}
|
||||
|
||||
for (const polyPatch& patch : mesh_.boundaryMesh())
|
||||
{
|
||||
if (!patch.coupled())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
forAll(patch, patchFacei)
|
||||
{
|
||||
const label facei = patch.start() + patchFacei;
|
||||
if (ignoreCells.test(faceOwn[facei]))
|
||||
{
|
||||
blockedFaces.set(facei);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
syncTools::syncFaceList(mesh_, blockedFaces, xorEqOp<unsigned int>());
|
||||
|
||||
return blockedFaces;
|
||||
}
|
||||
|
||||
|
||||
void Foam::distanceSurface::filterKeepLargestRegion
|
||||
(
|
||||
bitSet& ignoreCells
|
||||
) const
|
||||
{
|
||||
// For region split
|
||||
bitSet blockedFaces(filterPrepareRegionSplit(ignoreCells));
|
||||
|
||||
// Split region
|
||||
regionSplit rs(mesh_, blockedFaces);
|
||||
blockedFaces.clearStorage();
|
||||
|
||||
const labelList& regionColour = rs;
|
||||
|
||||
// Identical number of regions on all processors
|
||||
labelList nCutsPerRegion(rs.nRegions(), Zero);
|
||||
|
||||
// Count cut cells (ie, unblocked)
|
||||
forAll(regionColour, celli)
|
||||
{
|
||||
if (!ignoreCells.test(celli))
|
||||
{
|
||||
++nCutsPerRegion[regionColour[celli]];
|
||||
}
|
||||
}
|
||||
|
||||
// Sum totals from all processors
|
||||
Pstream::listCombineGather(nCutsPerRegion, plusEqOp<label>());
|
||||
|
||||
|
||||
// Define which regions to keep
|
||||
boolList keepRegion(rs.nRegions(), false);
|
||||
|
||||
if (Pstream::master())
|
||||
{
|
||||
const label largest = findMax(nCutsPerRegion);
|
||||
|
||||
if (largest == -1)
|
||||
{
|
||||
// Should not happen
|
||||
keepRegion = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
keepRegion[largest] = true;
|
||||
}
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Info<< "Had " << sum(nCutsPerRegion) << " cuts, in "
|
||||
<< nCutsPerRegion.size() << " regions, largest is "
|
||||
<< largest << ": " << flatOutput(nCutsPerRegion) << nl;
|
||||
}
|
||||
}
|
||||
|
||||
Pstream::scatter(keepRegion);
|
||||
|
||||
forAll(regionColour, celli)
|
||||
{
|
||||
if (!keepRegion.test(regionColour[celli]))
|
||||
{
|
||||
ignoreCells.set(celli);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Foam::distanceSurface::filterKeepNearestRegions
|
||||
(
|
||||
bitSet& ignoreCells
|
||||
) const
|
||||
{
|
||||
if (nearestPoints_.empty())
|
||||
{
|
||||
WarningInFunction
|
||||
<< "Ignoring nearestPoints - no points provided" << nl
|
||||
<< endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// For region split
|
||||
bitSet blockedFaces(filterPrepareRegionSplit(ignoreCells));
|
||||
|
||||
// Split region
|
||||
regionSplit rs(mesh_, blockedFaces);
|
||||
blockedFaces.clearStorage();
|
||||
|
||||
const labelList& regionColour = rs;
|
||||
|
||||
const pointField& cc = mesh_.cellCentres();
|
||||
const pointField& nearPts = nearestPoints_;
|
||||
|
||||
// The magSqr distance and region
|
||||
typedef Tuple2<scalar, label> nearInfo;
|
||||
List<nearInfo> nearest(nearPts.size(), nearInfo(GREAT, -1));
|
||||
|
||||
// Also collect cuts per region, may be useful for rejecting
|
||||
// small regions. Code as per filterKeepLargestRegion
|
||||
labelList nCutsPerRegion(rs.nRegions(), Zero);
|
||||
|
||||
forAll(cc, celli)
|
||||
{
|
||||
if (ignoreCells.test(celli))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const point& pt = cc[celli];
|
||||
const label regioni = regionColour[celli];
|
||||
|
||||
++nCutsPerRegion[regioni];
|
||||
|
||||
label pointi = 0;
|
||||
for (nearInfo& near : nearest)
|
||||
{
|
||||
const scalar distSqr = magSqr(nearPts[pointi] - pt);
|
||||
++pointi;
|
||||
|
||||
if (distSqr < near.first())
|
||||
{
|
||||
near.first() = distSqr;
|
||||
near.second() = regioni;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sum totals from all processors
|
||||
Pstream::listCombineGather(nCutsPerRegion, plusEqOp<label>());
|
||||
|
||||
// Get nearest
|
||||
Pstream::listCombineGather(nearest, minFirstEqOp<scalar>());
|
||||
|
||||
|
||||
// Define which regions to keep
|
||||
|
||||
boolList keepRegion(rs.nRegions(), false);
|
||||
|
||||
if (Pstream::master())
|
||||
{
|
||||
const label largest = findMax(nCutsPerRegion);
|
||||
|
||||
for (const nearInfo& near : nearest)
|
||||
{
|
||||
const scalar distSqr = near.first();
|
||||
const label regioni = near.second();
|
||||
|
||||
if (regioni != -1 && distSqr < maxDistanceSqr_)
|
||||
{
|
||||
keepRegion[regioni] = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Info<< "Had " << sum(nCutsPerRegion) << " cuts, in "
|
||||
<< nCutsPerRegion.size() << " regions, largest is "
|
||||
<< largest << ": " << flatOutput(nCutsPerRegion) << nl;
|
||||
|
||||
Info<< "nearestPoints (max distance = "
|
||||
<< sqrt(maxDistanceSqr_) << ")" << nl;
|
||||
|
||||
forAll(nearPts, pointi)
|
||||
{
|
||||
const scalar dist = sqrt(nearest[pointi].first());
|
||||
const label regioni = nearest[pointi].second();
|
||||
|
||||
Info<< " " << nearPts[pointi] << " region "
|
||||
<< regioni << " distance "
|
||||
<< dist;
|
||||
|
||||
if (!keepRegion.test(regioni))
|
||||
{
|
||||
Info<< " too far";
|
||||
}
|
||||
Info<< nl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Pstream::scatter(keepRegion);
|
||||
|
||||
forAll(regionColour, celli)
|
||||
{
|
||||
if (!keepRegion.test(regionColour[celli]))
|
||||
{
|
||||
ignoreCells.set(celli);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Foam::distanceSurface::filterByProximity()
|
||||
{
|
||||
const searchableSurface& geom = geometryPtr_();
|
||||
|
||||
// Filtering for faces
|
||||
const pointField& fc = surface_.faceCentres();
|
||||
|
||||
bitSet faceSelection(fc.size());
|
||||
label nTrimmed = 0;
|
||||
|
||||
|
||||
// For each face
|
||||
scalarField faceDistance(fc.size(), GREAT);
|
||||
scalarField faceNormalDistance; // Debugging only
|
||||
{
|
||||
List<pointIndexHit> nearest;
|
||||
geom.findNearest
|
||||
(
|
||||
fc,
|
||||
// Use initialized field (GREAT) to limit search too
|
||||
faceDistance,
|
||||
nearest
|
||||
);
|
||||
calcAbsoluteDistance(faceDistance, fc, nearest);
|
||||
|
||||
// Heavier debugging
|
||||
if (debug & 4)
|
||||
{
|
||||
vectorField norms;
|
||||
geom.getNormal(nearest, norms);
|
||||
|
||||
faceNormalDistance.resize(fc.size());
|
||||
|
||||
forAll(nearest, i)
|
||||
{
|
||||
const vector diff(fc[i] - nearest[i].point());
|
||||
|
||||
faceNormalDistance[i] = Foam::mag((diff & norms[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Note
|
||||
// Proximity checks using the face points (nearest hit) to establish
|
||||
// a length scale are too fragile. Can easily have stretched faces
|
||||
// where the centre is less than say 0.3-0.5 of the centre-point distance
|
||||
// but they are still outside.
|
||||
|
||||
// Using the absolute proximity of the face centres is more robust.
|
||||
|
||||
|
||||
// Consider the absolute proximity of the face centres
|
||||
forAll(faceDistance, facei)
|
||||
{
|
||||
if (faceDistance[facei] <= absProximity_)
|
||||
{
|
||||
faceSelection.set(facei);
|
||||
}
|
||||
else
|
||||
{
|
||||
++nTrimmed;
|
||||
|
||||
if (debug & 2)
|
||||
{
|
||||
Pout<< "trim reject: "
|
||||
<< faceDistance[facei] << nl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Heavier debugging
|
||||
if (debug & 4)
|
||||
{
|
||||
labelField faceFilterStatus(faceSelection.size(), Zero);
|
||||
|
||||
for (const label facei : faceSelection)
|
||||
{
|
||||
faceFilterStatus[facei] = 1;
|
||||
}
|
||||
|
||||
const fileName outputName(surfaceName() + "-proximity-filter");
|
||||
|
||||
Info<< "Writing debug surface: " << outputName << nl;
|
||||
|
||||
surfaceWriters::vtkWriter writer
|
||||
(
|
||||
surface_.points(),
|
||||
surface_, // faces
|
||||
outputName
|
||||
);
|
||||
|
||||
writer.write("absolute-distance", faceDistance);
|
||||
writer.write("normal-distance", faceNormalDistance);
|
||||
writer.write("filter-state", faceFilterStatus);
|
||||
}
|
||||
|
||||
|
||||
if (returnReduce(nTrimmed, sumOp<label>()) != 0)
|
||||
{
|
||||
labelList pointMap, faceMap;
|
||||
meshedSurface filtered
|
||||
(
|
||||
surface_.subsetMesh(faceSelection, pointMap, faceMap)
|
||||
);
|
||||
surface_.transfer(filtered);
|
||||
|
||||
meshCells_ = UIndirectList<label>(meshCells_, faceMap)();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -26,19 +26,292 @@ License
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "isoSurfaceBase.H"
|
||||
#include "polyMesh.H"
|
||||
#include "tetMatcher.H"
|
||||
#include "cyclicACMIPolyPatch.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#include "isoSurfaceBaseMethods.H"
|
||||
defineIsoSurfaceInterpolateMethods(Foam::isoSurfaceBase);
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
// Test face for edge cuts
|
||||
inline static bool isFaceCut
|
||||
(
|
||||
const scalar isoval,
|
||||
const scalarField& pointValues,
|
||||
const labelUList& indices
|
||||
)
|
||||
{
|
||||
auto iter = indices.cbegin();
|
||||
const auto last = indices.cend();
|
||||
|
||||
// if (iter == last) return false; // ie, indices.empty()
|
||||
|
||||
const bool aLower = (pointValues[*iter] < isoval);
|
||||
++iter;
|
||||
|
||||
while (iter != last)
|
||||
{
|
||||
if (aLower != (pointValues[*iter] < isoval))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::isoSurfaceBase::isoSurfaceBase
|
||||
(
|
||||
const polyMesh& mesh,
|
||||
const scalarField& cellValues,
|
||||
const scalarField& pointValues,
|
||||
const scalar iso,
|
||||
const isoSurfaceParams& params
|
||||
)
|
||||
:
|
||||
meshedSurface(),
|
||||
isoSurfaceParams(params),
|
||||
iso_(iso)
|
||||
mesh_(mesh),
|
||||
cVals_(cellValues),
|
||||
pVals_(pointValues),
|
||||
iso_(iso),
|
||||
ignoreBoundaryFaces_(),
|
||||
meshCells_()
|
||||
{}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
void Foam::isoSurfaceBase::ignoreCyclics()
|
||||
{
|
||||
// Determine boundary pyramids to ignore (originating from ACMI faces)
|
||||
// Maybe needs to be optional argument or more general detect colocated
|
||||
// faces.
|
||||
|
||||
for (const polyPatch& pp : mesh_.boundaryMesh())
|
||||
{
|
||||
if (isA<cyclicACMIPolyPatch>(pp))
|
||||
{
|
||||
ignoreBoundaryFaces_.set(labelRange(pp.offset(), pp.size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Foam::label Foam::isoSurfaceBase::countCutType
|
||||
(
|
||||
const UList<cutType>& cuts,
|
||||
const uint8_t maskValue
|
||||
)
|
||||
{
|
||||
label count = 0;
|
||||
|
||||
for (const cutType cut : cuts)
|
||||
{
|
||||
if (maskValue ? (cut & maskValue) != 0 : !cut)
|
||||
{
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
void Foam::isoSurfaceBase::resetCuts(UList<cutType>& cuts)
|
||||
{
|
||||
for (cutType& cut : cuts)
|
||||
{
|
||||
if (cut != cutType::BLOCKED)
|
||||
{
|
||||
cut = cutType::UNVISITED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Foam::label Foam::isoSurfaceBase::blockCells
|
||||
(
|
||||
UList<cutType>& cuts,
|
||||
const bitSet& ignoreCells
|
||||
) const
|
||||
{
|
||||
label count = 0;
|
||||
|
||||
for (const label celli : ignoreCells)
|
||||
{
|
||||
if (celli >= cuts.size())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
cuts[celli] = cutType::BLOCKED;
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
Foam::label Foam::isoSurfaceBase::blockCells
|
||||
(
|
||||
UList<cutType>& cuts,
|
||||
const boundBox& bb,
|
||||
const volumeType::type volType
|
||||
) const
|
||||
{
|
||||
label count = 0;
|
||||
|
||||
// Mark cells inside/outside bounding box as blocked
|
||||
const bool keepInside = (volType == volumeType::INSIDE);
|
||||
|
||||
if (!keepInside && volType != volumeType::OUTSIDE)
|
||||
{
|
||||
// Could warn about invalid...
|
||||
}
|
||||
else if (bb.valid())
|
||||
{
|
||||
const pointField& cc = mesh_.cellCentres();
|
||||
|
||||
forAll(cuts, celli)
|
||||
{
|
||||
if
|
||||
(
|
||||
cuts[celli] == cutType::UNVISITED
|
||||
&& (bb.contains(cc[celli]) ? keepInside : !keepInside)
|
||||
)
|
||||
{
|
||||
cuts[celli] = cutType::BLOCKED;
|
||||
++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
Foam::label Foam::isoSurfaceBase::calcCellCuts(List<cutType>& cuts) const
|
||||
{
|
||||
// Don't consider SPHERE cuts in the total number of cells cut
|
||||
constexpr uint8_t realCut(cutType::CUT | cutType::TETCUT);
|
||||
|
||||
cuts.resize(mesh_.nCells(), cutType::UNVISITED);
|
||||
|
||||
label nCuts = 0;
|
||||
forAll(cuts, celli)
|
||||
{
|
||||
if (cuts[celli] == cutType::UNVISITED)
|
||||
{
|
||||
cuts[celli] = getCellCutType(celli);
|
||||
|
||||
if ((cuts[celli] & realCut) != 0)
|
||||
{
|
||||
++nCuts;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nCuts;
|
||||
}
|
||||
|
||||
|
||||
Foam::isoSurfaceBase::cutType
|
||||
Foam::isoSurfaceBase::getFaceCutType(const label facei) const
|
||||
{
|
||||
return
|
||||
(
|
||||
(
|
||||
mesh_.isInternalFace(facei)
|
||||
|| !ignoreBoundaryFaces_.test(facei-mesh_.nInternalFaces())
|
||||
)
|
||||
&& isFaceCut(iso_, pVals_, mesh_.faces()[facei])
|
||||
) ? cutType::CUT : cutType::NOTCUT;
|
||||
}
|
||||
|
||||
|
||||
Foam::isoSurfaceBase::cutType
|
||||
Foam::isoSurfaceBase::getCellCutType(const label celli) const
|
||||
{
|
||||
// Tet version
|
||||
if (tetMatcher::test(mesh_, celli))
|
||||
{
|
||||
for (const label facei : mesh_.cells()[celli])
|
||||
{
|
||||
if
|
||||
(
|
||||
!mesh_.isInternalFace(facei)
|
||||
&& ignoreBoundaryFaces_.test(facei-mesh_.nInternalFaces())
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isFaceCut(iso_, pVals_, mesh_.faces()[facei]))
|
||||
{
|
||||
return cutType::TETCUT;
|
||||
}
|
||||
}
|
||||
|
||||
return cutType::NOTCUT;
|
||||
}
|
||||
|
||||
|
||||
// Regular cell
|
||||
label nPyrEdges = 0;
|
||||
label nPyrCuts = 0;
|
||||
|
||||
const bool cellLower = (cVals_[celli] < iso_);
|
||||
|
||||
for (const label facei : mesh_.cells()[celli])
|
||||
{
|
||||
if
|
||||
(
|
||||
!mesh_.isInternalFace(facei)
|
||||
&& ignoreBoundaryFaces_.test(facei-mesh_.nInternalFaces())
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const face& f = mesh_.faces()[facei];
|
||||
|
||||
// Count pyramid edges cut
|
||||
for (const label pointi : f)
|
||||
{
|
||||
++nPyrEdges;
|
||||
|
||||
if (cellLower != (pVals_[pointi] < iso_))
|
||||
{
|
||||
++nPyrCuts;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (nPyrCuts == 0)
|
||||
{
|
||||
return cutType::NOTCUT;
|
||||
}
|
||||
|
||||
// If all pyramid edges are cut (no outside faces),
|
||||
// it is a sphere cut
|
||||
|
||||
return (nPyrCuts == nPyrEdges) ? cutType::SPHERE : cutType::CUT;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
@ -29,15 +29,14 @@ Class
|
||||
Description
|
||||
Low-level components common to various iso-surface algorithms.
|
||||
|
||||
Some common dictionary properties:
|
||||
\table
|
||||
Property | Description | Required | Default
|
||||
isoAlgorithm | (cell/topo/point) | no | topo
|
||||
regularise | point snapping (bool or enum) | no | true
|
||||
\endtable
|
||||
Note
|
||||
The interpolation samplers currently require a volField for the cell
|
||||
values. This is largely a restriction imposed by the point algorithm
|
||||
and may be revised in the future.
|
||||
|
||||
SourceFiles
|
||||
isoSurfaceBase.C
|
||||
isoSurfaceBaseNew.C
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
@ -45,7 +44,10 @@ SourceFiles
|
||||
#define isoSurfaceBase_H
|
||||
|
||||
#include "isoSurfaceParams.H"
|
||||
#include "scalar.H"
|
||||
#include "bitSet.H"
|
||||
#include "scalarField.H"
|
||||
#include "volumeType.H"
|
||||
#include "volFieldsFwd.H"
|
||||
#include "MeshedSurface.H"
|
||||
#include "MeshedSurfacesFwd.H"
|
||||
|
||||
@ -55,6 +57,7 @@ namespace Foam
|
||||
{
|
||||
|
||||
// Forward Declarations
|
||||
class polyMesh;
|
||||
class tetCell;
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
@ -66,16 +69,58 @@ class isoSurfaceBase
|
||||
public meshedSurface,
|
||||
public isoSurfaceParams
|
||||
{
|
||||
public:
|
||||
|
||||
// Data Types
|
||||
|
||||
//- The type of cell/face cuts
|
||||
enum cutType : uint8_t
|
||||
{
|
||||
NOTCUT = 0, //!< Not cut
|
||||
CUT = 0x1, //!< Normal cut
|
||||
TETCUT = 0x2, //!< Cell cut is a tet
|
||||
SPHERE = 0x4, //!< All edges to cell centre cut
|
||||
ANYCUT = 0xF, //!< Any cut type (bitmask)
|
||||
|
||||
UNVISITED = 0x10, //!< Unvisited
|
||||
BLOCKED = 0x20, //!< Blocked (never cut)
|
||||
SPECIAL = 0xF0 //!< Bitmask for specials
|
||||
};
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// Protected typedefs for convenience
|
||||
typedef meshedSurface Mesh;
|
||||
|
||||
// Typedef for code transition
|
||||
typedef cutType cellCutType;
|
||||
|
||||
|
||||
// Protected Data
|
||||
|
||||
//- Reference to mesh
|
||||
const polyMesh& mesh_;
|
||||
|
||||
//- Cell values
|
||||
const scalarField& cVals_;
|
||||
|
||||
//- Point values
|
||||
const scalarField& pVals_;
|
||||
|
||||
//- Iso value
|
||||
const scalar iso_;
|
||||
|
||||
|
||||
// Controls, restrictions
|
||||
|
||||
//- Optional boundary faces to ignore.
|
||||
// Eg, Used to exclude cyclicACMI (since duplicate faces)
|
||||
bitSet ignoreBoundaryFaces_;
|
||||
|
||||
|
||||
// Sampling information
|
||||
|
||||
//- For every face, the original cell in mesh
|
||||
labelList meshCells_;
|
||||
|
||||
@ -102,21 +147,88 @@ protected:
|
||||
);
|
||||
}
|
||||
|
||||
//- Count the number of cuts matching the mask type
|
||||
// Checks as bitmask or as zero.
|
||||
static label countCutType
|
||||
(
|
||||
const UList<cutType>& cuts,
|
||||
const uint8_t maskValue
|
||||
);
|
||||
|
||||
//- Dummy templated interpolate method
|
||||
template<class Type>
|
||||
tmp<Field<Type>> interpolateTemplate
|
||||
(
|
||||
const GeometricField<Type, fvPatchField, volMesh>& cellValues,
|
||||
const Field<Type>& pointValues
|
||||
) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//- No copy construct
|
||||
isoSurfaceBase(const isoSurfaceBase&) = delete;
|
||||
|
||||
//- No copy assignment
|
||||
void operator=(const isoSurfaceBase&) = delete;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
// Typedefs for code transition
|
||||
using isoSurfaceParams::algorithmType;
|
||||
using isoSurfaceParams::filterType;
|
||||
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Create for specified algorithm type/filter and iso-value
|
||||
//- Construct with mesh, cell/point values and iso-value
|
||||
isoSurfaceBase
|
||||
(
|
||||
const polyMesh& mesh,
|
||||
const scalarField& cellValues,
|
||||
const scalarField& pointValues,
|
||||
const scalar iso,
|
||||
const isoSurfaceParams& params = isoSurfaceParams()
|
||||
);
|
||||
|
||||
|
||||
// Selector
|
||||
|
||||
//- Create for specified algorithm type
|
||||
// Currently uses hard-code lookups based in isoSurfaceParams
|
||||
static autoPtr<isoSurfaceBase> New
|
||||
(
|
||||
const isoSurfaceParams& params,
|
||||
const volScalarField& cellValues,
|
||||
const scalarField& pointValues,
|
||||
const scalar iso,
|
||||
const bitSet& ignoreCells = bitSet()
|
||||
);
|
||||
|
||||
|
||||
// Member Functions
|
||||
|
||||
// Access, Edit
|
||||
|
||||
//- The mesh for which the iso-surface is associated
|
||||
const polyMesh& mesh() const noexcept
|
||||
{
|
||||
return mesh_;
|
||||
}
|
||||
|
||||
//- The mesh cell values used for creating the iso-surface
|
||||
const scalarField& cellValues() const noexcept
|
||||
{
|
||||
return cVals_;
|
||||
}
|
||||
|
||||
//- The mesh point values used for creating the iso-surface
|
||||
const scalarField& pointValues() const noexcept
|
||||
{
|
||||
return pVals_;
|
||||
}
|
||||
|
||||
//- The iso-value associated with the surface
|
||||
scalar isoValue() const noexcept
|
||||
{
|
||||
@ -134,6 +246,63 @@ public:
|
||||
{
|
||||
return meshCells_;
|
||||
}
|
||||
|
||||
|
||||
// Helpers
|
||||
|
||||
//- Restore non-BLOCKED state to an UNVISITED state
|
||||
static void resetCuts(UList<cutType>& cuts);
|
||||
|
||||
//- Mark ignoreCells as BLOCKED
|
||||
label blockCells
|
||||
(
|
||||
UList<cutType>& cuts,
|
||||
const bitSet& ignoreCells
|
||||
) const;
|
||||
|
||||
//- Mark cells inside/outside a (valid) bound box as BLOCKED
|
||||
// The volType is INSIDE or OUTSIDE only
|
||||
label blockCells
|
||||
(
|
||||
UList<cutType>& cuts,
|
||||
const boundBox& bb,
|
||||
const volumeType::type volType
|
||||
) const;
|
||||
|
||||
|
||||
// Cutting
|
||||
|
||||
//- Set ignoreBoundaryFaces to ignore cyclics (cyclicACMI)
|
||||
void ignoreCyclics();
|
||||
|
||||
//- Populate a list of candidate cell cuts using getCellCutType()
|
||||
label calcCellCuts(List<cutType>& cuts) const;
|
||||
|
||||
//- Determine face cut for an individual face
|
||||
cutType getFaceCutType(const label facei) const;
|
||||
|
||||
//- Cell cut for an individual cell, with special handling
|
||||
//- for TETCUT and SPHERE cuts
|
||||
cutType getCellCutType(const label celli) const;
|
||||
|
||||
|
||||
// Sampling
|
||||
|
||||
#undef declareIsoSurfaceInterpolateMethod
|
||||
#define declareIsoSurfaceInterpolateMethod(Type) \
|
||||
/*! \brief interpolate Type cellValues, pointValues on iso-surface */ \
|
||||
virtual tmp<Field<Type>> \
|
||||
interpolate \
|
||||
( \
|
||||
const GeometricField<Type, fvPatchField, volMesh>& cellValues, \
|
||||
const Field<Type>& pointValues \
|
||||
) const;
|
||||
|
||||
declareIsoSurfaceInterpolateMethod(scalar);
|
||||
declareIsoSurfaceInterpolateMethod(vector);
|
||||
declareIsoSurfaceInterpolateMethod(sphericalTensor);
|
||||
declareIsoSurfaceInterpolateMethod(symmTensor);
|
||||
declareIsoSurfaceInterpolateMethod(tensor);
|
||||
};
|
||||
|
||||
|
||||
|
||||
66
src/sampling/surface/isoSurface/isoSurfaceBaseMethods.H
Normal file
66
src/sampling/surface/isoSurface/isoSurfaceBaseMethods.H
Normal file
@ -0,0 +1,66 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2020 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/>.
|
||||
|
||||
InClass
|
||||
Foam::isoSurfaceBaseMethods
|
||||
|
||||
Description
|
||||
Convenience macros for instantiating iso-surface interpolate methods.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef isoSurfaceBaseMethods_H
|
||||
#define isoSurfaceBaseMethods_H
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
// Instantiate templated method for standard types
|
||||
// See note in isoSurfaceBase explaining why these are volume fields
|
||||
|
||||
#undef defineIsoSurfaceInterpolateMethod
|
||||
#define defineIsoSurfaceInterpolateMethod(ThisClass, Type) \
|
||||
Foam::tmp<Foam::Field<Type>> ThisClass::interpolate \
|
||||
( \
|
||||
const GeometricField<Type, fvPatchField, volMesh>& cellValues, \
|
||||
const Field<Type>& pointValues \
|
||||
) const \
|
||||
{ \
|
||||
return interpolateTemplate(cellValues, pointValues); \
|
||||
}
|
||||
|
||||
|
||||
#define defineIsoSurfaceInterpolateMethods(ThisClass) \
|
||||
defineIsoSurfaceInterpolateMethod(ThisClass, Foam::scalar); \
|
||||
defineIsoSurfaceInterpolateMethod(ThisClass, Foam::vector); \
|
||||
defineIsoSurfaceInterpolateMethod(ThisClass, Foam::sphericalTensor); \
|
||||
defineIsoSurfaceInterpolateMethod(ThisClass, Foam::symmTensor); \
|
||||
defineIsoSurfaceInterpolateMethod(ThisClass, Foam::tensor)
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#endif
|
||||
|
||||
// ************************************************************************* //
|
||||
107
src/sampling/surface/isoSurface/isoSurfaceBaseNew.C
Normal file
107
src/sampling/surface/isoSurface/isoSurfaceBaseNew.C
Normal file
@ -0,0 +1,107 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | www.openfoam.com
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2020 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 "isoSurfaceBase.H"
|
||||
#include "isoSurfaceCell.H"
|
||||
#include "isoSurfacePoint.H"
|
||||
#include "isoSurfaceTopo.H"
|
||||
|
||||
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
|
||||
|
||||
Foam::autoPtr<Foam::isoSurfaceBase>
|
||||
Foam::isoSurfaceBase::New
|
||||
(
|
||||
const isoSurfaceParams& params,
|
||||
const volScalarField& cellValues,
|
||||
const scalarField& pointValues,
|
||||
const scalar iso,
|
||||
const bitSet& ignoreCells
|
||||
)
|
||||
{
|
||||
autoPtr<isoSurfaceBase> ptr;
|
||||
|
||||
if (params.algorithm() == isoSurfaceParams::ALGO_POINT)
|
||||
{
|
||||
ptr.reset
|
||||
(
|
||||
new isoSurfacePoint
|
||||
(
|
||||
/* fvMesh implicit from cellValues */
|
||||
cellValues,
|
||||
pointValues,
|
||||
iso,
|
||||
params,
|
||||
ignoreCells // unused
|
||||
)
|
||||
);
|
||||
}
|
||||
else if (params.algorithm() == isoSurfaceParams::ALGO_CELL)
|
||||
{
|
||||
ptr.reset
|
||||
(
|
||||
new isoSurfaceCell
|
||||
(
|
||||
cellValues.mesh(), // polyMesh
|
||||
cellValues.primitiveField(),
|
||||
pointValues,
|
||||
iso,
|
||||
params,
|
||||
ignoreCells
|
||||
)
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ALGO_TOPO, ALGO_DEFAULT
|
||||
ptr.reset
|
||||
(
|
||||
new isoSurfaceTopo
|
||||
(
|
||||
cellValues.mesh(), // polyMesh
|
||||
cellValues.primitiveField(),
|
||||
pointValues,
|
||||
iso,
|
||||
params,
|
||||
ignoreCells
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Cannot really fail (with current logic)
|
||||
// if (!ptr)
|
||||
// {
|
||||
// FatalErrorInFunction
|
||||
// << "Unknown iso-surface algorithm ("
|
||||
// << int(params.algorithm()) << ")\n"
|
||||
// << exit(FatalError);
|
||||
// }
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -38,6 +38,12 @@ License
|
||||
#include "Time.H"
|
||||
#include "triPoints.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#include "isoSurfaceBaseMethods.H"
|
||||
defineIsoSurfaceInterpolateMethods(Foam::isoSurfaceCell);
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
@ -46,29 +52,6 @@ namespace Foam
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
// Does any edge of triangle cross iso value?
|
||||
inline static bool isTriCut
|
||||
(
|
||||
const label a,
|
||||
const label b,
|
||||
const label c,
|
||||
const scalarField& pointValues,
|
||||
const scalar isoValue
|
||||
)
|
||||
{
|
||||
const bool aLower = (pointValues[a] < isoValue);
|
||||
const bool bLower = (pointValues[b] < isoValue);
|
||||
const bool cLower = (pointValues[c] < isoValue);
|
||||
|
||||
return !(aLower == bLower && aLower == cLower);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
Foam::scalar Foam::isoSurfaceCell::isoFraction
|
||||
@ -88,154 +71,6 @@ Foam::scalar Foam::isoSurfaceCell::isoFraction
|
||||
}
|
||||
|
||||
|
||||
Foam::isoSurfaceCell::cellCutType Foam::isoSurfaceCell::calcCutType
|
||||
(
|
||||
const bitSet& isTet,
|
||||
const scalarField& cellValues,
|
||||
const scalarField& pointValues,
|
||||
const label celli
|
||||
) const
|
||||
{
|
||||
if (ignoreCells_.test(celli))
|
||||
{
|
||||
return NOTCUT;
|
||||
}
|
||||
|
||||
const cell& cFaces = mesh_.cells()[celli];
|
||||
|
||||
if (isTet.test(celli))
|
||||
{
|
||||
for (const label facei : cFaces)
|
||||
{
|
||||
const face& f = mesh_.faces()[facei];
|
||||
|
||||
for (label fp = 1; fp < f.size() - 1; ++fp)
|
||||
{
|
||||
if (isTriCut(f[0], f[fp], f[f.fcIndex(fp)], pointValues, iso_))
|
||||
{
|
||||
return CUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NOTCUT;
|
||||
}
|
||||
|
||||
|
||||
const bool cellLower = (cellValues[celli] < iso_);
|
||||
|
||||
// First check if there is any cut in cell
|
||||
bool edgeCut = false;
|
||||
|
||||
for (const label facei : cFaces)
|
||||
{
|
||||
const face& f = mesh_.faces()[facei];
|
||||
|
||||
// Check pyramid edges (corner point to cell centre)
|
||||
for (const label pointi : f)
|
||||
{
|
||||
if (cellLower != (pointValues[pointi] < iso_))
|
||||
{
|
||||
edgeCut = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (edgeCut)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Check (triangulated) face edges
|
||||
// With fallback for problem decompositions
|
||||
const label fp0 =
|
||||
(mesh_.tetBasePtIs()[facei] < 0 ? 0 : mesh_.tetBasePtIs()[facei]);
|
||||
|
||||
label fp = f.fcIndex(fp0);
|
||||
for (label i = 2; i < f.size(); ++i)
|
||||
{
|
||||
const label nextFp = f.fcIndex(fp);
|
||||
|
||||
if (isTriCut(f[fp0], f[fp], f[nextFp], pointValues, iso_))
|
||||
{
|
||||
edgeCut = true;
|
||||
break;
|
||||
}
|
||||
|
||||
fp = nextFp;
|
||||
}
|
||||
|
||||
if (edgeCut)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (edgeCut)
|
||||
{
|
||||
// Count actual cuts (expensive since addressing needed)
|
||||
// Note: not needed if you don't want to preserve maxima/minima
|
||||
// centred around cellcentre. In that case just always return CUT
|
||||
|
||||
const labelList& cPoints = mesh_.cellPoints(celli);
|
||||
|
||||
label nPyrCuts = 0;
|
||||
|
||||
for (const label pointi : cPoints)
|
||||
{
|
||||
if ((pointValues[pointi] < iso_) != cellLower)
|
||||
{
|
||||
++nPyrCuts;
|
||||
}
|
||||
}
|
||||
|
||||
if (nPyrCuts == cPoints.size())
|
||||
{
|
||||
return SPHERE;
|
||||
}
|
||||
else if (nPyrCuts)
|
||||
{
|
||||
// There is a pyramid edge cut. E.g. lopping off a tet from a corner
|
||||
return CUT;
|
||||
}
|
||||
}
|
||||
|
||||
return NOTCUT;
|
||||
}
|
||||
|
||||
|
||||
void Foam::isoSurfaceCell::calcCutTypes
|
||||
(
|
||||
const bitSet& isTet,
|
||||
const scalarField& cVals,
|
||||
const scalarField& pVals
|
||||
)
|
||||
{
|
||||
cellCutType_.setSize(mesh_.nCells());
|
||||
nCutCells_ = 0;
|
||||
|
||||
// Some processor domains may require tetBasePtIs and others do not.
|
||||
// Do now to ensure things stay synchronized.
|
||||
(void)mesh_.tetBasePtIs();
|
||||
|
||||
forAll(cellCutType_, celli)
|
||||
{
|
||||
cellCutType_[celli] = calcCutType(isTet, cVals, pVals, celli);
|
||||
|
||||
if (cellCutType_[celli] == CUT)
|
||||
{
|
||||
++nCutCells_;
|
||||
}
|
||||
}
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "isoSurfaceCell : candidate cut cells "
|
||||
<< nCutCells_ << " / " << mesh_.nCells() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Foam::labelPair Foam::isoSurfaceCell::findCommonPoints
|
||||
(
|
||||
const labelledTri& tri0,
|
||||
@ -402,7 +237,7 @@ void Foam::isoSurfaceCell::calcSnappedCc
|
||||
|
||||
forAll(mesh_.cells(), celli)
|
||||
{
|
||||
if (cellCutType_[celli] == CUT && !isTet.test(celli))
|
||||
if (cellCutType_[celli] == cutType::CUT) // No tet cuts
|
||||
{
|
||||
const scalar cVal = cVals[celli];
|
||||
|
||||
@ -709,18 +544,21 @@ void Foam::isoSurfaceCell::calcSnappedPoint
|
||||
labelList& snappedPoint
|
||||
) const
|
||||
{
|
||||
const labelList& faceOwn = mesh_.faceOwner();
|
||||
const labelList& faceNei = mesh_.faceNeighbour();
|
||||
|
||||
// Determine if point is on boundary. Points on boundaries are never
|
||||
// snapped. Coupled boundaries are handled explicitly so not marked here.
|
||||
bitSet isBoundaryPoint(mesh_.nPoints());
|
||||
const polyBoundaryMesh& patches = mesh_.boundaryMesh();
|
||||
|
||||
for (const polyPatch& pp : patches)
|
||||
{
|
||||
if (!pp.coupled())
|
||||
{
|
||||
label facei = pp.start();
|
||||
forAll(pp, i)
|
||||
for (const label facei : pp.range())
|
||||
{
|
||||
const face& f = mesh_.faces()[facei++];
|
||||
const face& f = mesh_.faces()[facei];
|
||||
|
||||
isBoundaryPoint.set(f);
|
||||
}
|
||||
@ -739,6 +577,8 @@ void Foam::isoSurfaceCell::calcSnappedPoint
|
||||
|
||||
forAll(mesh_.pointFaces(), pointi)
|
||||
{
|
||||
constexpr uint8_t realCut(cutType::CUT | cutType::TETCUT);
|
||||
|
||||
if (isBoundaryPoint.test(pointi))
|
||||
{
|
||||
continue;
|
||||
@ -752,10 +592,10 @@ void Foam::isoSurfaceCell::calcSnappedPoint
|
||||
{
|
||||
if
|
||||
(
|
||||
cellCutType_[mesh_.faceOwner()[facei]] == CUT
|
||||
(cellCutType_[faceOwn[facei]] & realCut) != 0
|
||||
|| (
|
||||
mesh_.isInternalFace(facei)
|
||||
&& cellCutType_[mesh_.faceNeighbour()[facei]] == CUT
|
||||
&& (cellCutType_[faceNei[facei]] & realCut) != 0
|
||||
)
|
||||
)
|
||||
{
|
||||
@ -777,7 +617,7 @@ void Foam::isoSurfaceCell::calcSnappedPoint
|
||||
|
||||
for (const label facei : pFaces)
|
||||
{
|
||||
const label own = mesh_.faceOwner()[facei];
|
||||
const label own = faceOwn[facei];
|
||||
|
||||
if (isTet.test(own))
|
||||
{
|
||||
@ -803,7 +643,7 @@ void Foam::isoSurfaceCell::calcSnappedPoint
|
||||
|
||||
if (mesh_.isInternalFace(facei))
|
||||
{
|
||||
const label nei = mesh_.faceNeighbour()[facei];
|
||||
const label nei = faceNei[facei];
|
||||
|
||||
if (isTet.test(nei))
|
||||
{
|
||||
@ -1298,12 +1138,9 @@ Foam::isoSurfaceCell::isoSurfaceCell
|
||||
const bitSet& ignoreCells
|
||||
)
|
||||
:
|
||||
isoSurfaceBase(iso, params),
|
||||
mesh_(mesh),
|
||||
cVals_(cellValues),
|
||||
pVals_(pointValues),
|
||||
ignoreCells_(ignoreCells),
|
||||
mergeDistance_(params.mergeTol()*mesh.bounds().mag())
|
||||
isoSurfaceBase(mesh, cellValues, pointValues, iso, params),
|
||||
mergeDistance_(params.mergeTol()*mesh.bounds().mag()),
|
||||
cellCutType_(mesh.nCells(), cutType::UNVISITED)
|
||||
{
|
||||
const bool regularise = (params.filter() != filterType::NONE);
|
||||
|
||||
@ -1317,15 +1154,27 @@ Foam::isoSurfaceCell::isoSurfaceCell
|
||||
<< " mergeTol : " << params.mergeTol() << nl
|
||||
<< " mesh span : " << mesh.bounds().mag() << nl
|
||||
<< " mergeDistance : " << mergeDistance_ << nl
|
||||
<< " ignoreCells : " << ignoreCells_.count()
|
||||
<< " ignoreCells : " << ignoreCells.count()
|
||||
<< " / " << cVals_.size() << nl
|
||||
<< endl;
|
||||
}
|
||||
|
||||
// Determine if cell is tet
|
||||
|
||||
label nBlockedCells = 0;
|
||||
|
||||
// Mark ignoreCells as blocked
|
||||
nBlockedCells += blockCells(cellCutType_, ignoreCells);
|
||||
|
||||
|
||||
// Some processor domains may require tetBasePtIs and others do not.
|
||||
// Do now to ensure things stay synchronized.
|
||||
(void)mesh_.tetBasePtIs();
|
||||
|
||||
|
||||
// Calculate a tet/non-tet filter
|
||||
bitSet isTet(mesh_.nCells());
|
||||
{
|
||||
forAll(isTet, celli)
|
||||
for (label celli = 0; celli < mesh_.nCells(); ++celli)
|
||||
{
|
||||
if (tetMatcher::test(mesh_, celli))
|
||||
{
|
||||
@ -1334,26 +1183,33 @@ Foam::isoSurfaceCell::isoSurfaceCell
|
||||
}
|
||||
}
|
||||
|
||||
// Determine cell cuts
|
||||
nCutCells_ = calcCellCuts(cellCutType_);
|
||||
|
||||
// Determine if any cut through cell
|
||||
calcCutTypes(isTet, cellValues, pointValues);
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "isoSurfaceCell : candidate cells cut "
|
||||
<< nCutCells_
|
||||
<< " blocked " << nBlockedCells
|
||||
<< " total " << mesh_.nCells() << endl;
|
||||
}
|
||||
|
||||
if (debug && isA<fvMesh>(mesh))
|
||||
{
|
||||
const fvMesh& fvm = dynamicCast<const fvMesh&>(mesh);
|
||||
const fvMesh& fvmesh = dynamicCast<const fvMesh&>(mesh);
|
||||
|
||||
volScalarField debugField
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
"isoSurfaceCell.cutType",
|
||||
fvm.time().timeName(),
|
||||
fvm.time(),
|
||||
fvmesh.time().timeName(),
|
||||
fvmesh.time(),
|
||||
IOobject::NO_READ,
|
||||
IOobject::NO_WRITE,
|
||||
false
|
||||
),
|
||||
fvm,
|
||||
fvmesh,
|
||||
dimensionedScalar(dimless, Zero)
|
||||
);
|
||||
|
||||
@ -1614,4 +1470,5 @@ Foam::isoSurfaceCell::isoSurfaceCell
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
@ -50,7 +50,6 @@ SourceFiles
|
||||
|
||||
#include "labelPair.H"
|
||||
#include "pointIndexHit.H"
|
||||
#include "bitSet.H"
|
||||
#include "isoSurfaceBase.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
@ -59,8 +58,6 @@ namespace Foam
|
||||
{
|
||||
|
||||
// Forward Declarations
|
||||
|
||||
class polyMesh;
|
||||
class triSurface;
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
@ -71,38 +68,13 @@ class isoSurfaceCell
|
||||
:
|
||||
public isoSurfaceBase
|
||||
{
|
||||
// Private data
|
||||
|
||||
enum segmentCutType
|
||||
{
|
||||
NEARFIRST, //!< Intersection close to e.first()
|
||||
NEARSECOND, //!< Intersection close to e.second()
|
||||
NOTNEAR //!< No intersection
|
||||
};
|
||||
|
||||
enum cellCutType
|
||||
{
|
||||
NOTCUT, //!< Cell not cut
|
||||
SPHERE, //!< All edges to cell centre cut
|
||||
CUT //!< Normal cut
|
||||
};
|
||||
|
||||
|
||||
//- Reference to mesh
|
||||
const polyMesh& mesh_;
|
||||
|
||||
const scalarField& cVals_;
|
||||
|
||||
const scalarField& pVals_;
|
||||
|
||||
//- Optional cells to ignore
|
||||
const bitSet& ignoreCells_;
|
||||
// Private Data
|
||||
|
||||
//- When to merge points
|
||||
const scalar mergeDistance_;
|
||||
|
||||
//- Whether cell might be cut
|
||||
List<cellCutType> cellCutType_;
|
||||
//- The cell cut type
|
||||
List<cutType> cellCutType_;
|
||||
|
||||
//- Estimated number of cut cells
|
||||
label nCutCells_;
|
||||
@ -123,28 +95,7 @@ class isoSurfaceCell
|
||||
// Private Member Functions
|
||||
|
||||
//- Get location of iso value as fraction inbetween s0,s1
|
||||
scalar isoFraction
|
||||
(
|
||||
const scalar s0,
|
||||
const scalar s1
|
||||
) const;
|
||||
|
||||
|
||||
//- Determine whether cell is cut
|
||||
cellCutType calcCutType
|
||||
(
|
||||
const bitSet&,
|
||||
const scalarField& cellValues,
|
||||
const scalarField& pointValues,
|
||||
const label
|
||||
) const;
|
||||
|
||||
void calcCutTypes
|
||||
(
|
||||
const bitSet&,
|
||||
const scalarField& cellValues,
|
||||
const scalarField& pointValues
|
||||
);
|
||||
scalar isoFraction(const scalar s0, const scalar s1) const;
|
||||
|
||||
//- Return the two common points between two triangles
|
||||
static labelPair findCommonPoints
|
||||
@ -166,7 +117,7 @@ class isoSurfaceCell
|
||||
) const;
|
||||
|
||||
//- Determine per cc whether all near cuts can be snapped to single
|
||||
// point.
|
||||
//- point.
|
||||
void calcSnappedCc
|
||||
(
|
||||
const bitSet& isTet,
|
||||
@ -301,8 +252,17 @@ class isoSurfaceCell
|
||||
);
|
||||
|
||||
|
||||
public:
|
||||
// Sampling
|
||||
|
||||
//- Interpolates cCoords, pCoords.
|
||||
template<class Type>
|
||||
tmp<Field<Type>> interpolateTemplate
|
||||
(
|
||||
const Field<Type>& cCoords,
|
||||
const Field<Type>& pCoords
|
||||
) const;
|
||||
|
||||
public:
|
||||
|
||||
//- Runtime type information
|
||||
TypeName("isoSurfaceCell");
|
||||
@ -328,15 +288,17 @@ public:
|
||||
);
|
||||
|
||||
|
||||
// Member Functions
|
||||
//- Destructor
|
||||
virtual ~isoSurfaceCell() = default;
|
||||
|
||||
//- Interpolates cCoords, pCoords.
|
||||
template<class Type>
|
||||
tmp<Field<Type>> interpolate
|
||||
(
|
||||
const Field<Type>& cCoords,
|
||||
const Field<Type>& pCoords
|
||||
) const;
|
||||
|
||||
// Sampling
|
||||
|
||||
declareIsoSurfaceInterpolateMethod(scalar);
|
||||
declareIsoSurfaceInterpolateMethod(vector);
|
||||
declareIsoSurfaceInterpolateMethod(sphericalTensor);
|
||||
declareIsoSurfaceInterpolateMethod(symmTensor);
|
||||
declareIsoSurfaceInterpolateMethod(tensor);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -175,7 +175,7 @@ void Foam::isoSurfaceCell::generateTriPoints
|
||||
if (triIndex == 0x0C)
|
||||
{
|
||||
// Flip normals
|
||||
label sz = pts.size();
|
||||
const label sz = pts.size();
|
||||
Swap(pts[sz-5], pts[sz-4]);
|
||||
Swap(pts[sz-2], pts[sz-1]);
|
||||
}
|
||||
@ -285,7 +285,7 @@ void Foam::isoSurfaceCell::generateTriPoints
|
||||
|
||||
forAll(mesh_.cells(), celli)
|
||||
{
|
||||
if (cellCutType_[celli] != NOTCUT)
|
||||
if ((cellCutType_[celli] & cutType::ANYCUT) != 0)
|
||||
{
|
||||
label oldNPoints = triPoints.size();
|
||||
|
||||
@ -469,7 +469,7 @@ void Foam::isoSurfaceCell::generateTriPoints
|
||||
|
||||
template<class Type>
|
||||
Foam::tmp<Foam::Field<Type>>
|
||||
Foam::isoSurfaceCell::interpolate
|
||||
Foam::isoSurfaceCell::interpolateTemplate
|
||||
(
|
||||
const Field<Type>& cCoords,
|
||||
const Field<Type>& pCoords
|
||||
|
||||
@ -34,6 +34,12 @@ License
|
||||
#include "triSurface.H"
|
||||
#include "triPoints.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#include "isoSurfaceBaseMethods.H"
|
||||
defineIsoSurfaceInterpolateMethods(Foam::isoSurfacePoint);
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
@ -384,8 +390,8 @@ void Foam::isoSurfacePoint::calcCutTypes
|
||||
const labelList& own = mesh_.faceOwner();
|
||||
const labelList& nei = mesh_.faceNeighbour();
|
||||
|
||||
faceCutType_.setSize(mesh_.nFaces());
|
||||
faceCutType_ = NOTCUT;
|
||||
faceCutType_.resize(mesh_.nFaces());
|
||||
faceCutType_ = cutType::NOTCUT;
|
||||
|
||||
for (label facei = 0; facei < mesh_.nInternalFaces(); ++facei)
|
||||
{
|
||||
@ -409,7 +415,7 @@ void Foam::isoSurfacePoint::calcCutTypes
|
||||
|
||||
if (ownLower != neiLower)
|
||||
{
|
||||
faceCutType_[facei] = CUT;
|
||||
faceCutType_[facei] = cutType::CUT;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -419,7 +425,7 @@ void Foam::isoSurfacePoint::calcCutTypes
|
||||
|
||||
if (isEdgeOfFaceCut(pVals, f, ownLower, neiLower))
|
||||
{
|
||||
faceCutType_[facei] = CUT;
|
||||
faceCutType_[facei] = cutType::CUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -448,7 +454,7 @@ void Foam::isoSurfacePoint::calcCutTypes
|
||||
|
||||
if (ownLower != neiLower)
|
||||
{
|
||||
faceCutType_[facei] = CUT;
|
||||
faceCutType_[facei] = cutType::CUT;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -458,34 +464,34 @@ void Foam::isoSurfacePoint::calcCutTypes
|
||||
|
||||
if (isEdgeOfFaceCut(pVals, f, ownLower, neiLower))
|
||||
{
|
||||
faceCutType_[facei] = CUT;
|
||||
faceCutType_[facei] = cutType::CUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nCutCells_ = 0;
|
||||
cellCutType_.setSize(mesh_.nCells());
|
||||
cellCutType_ = NOTCUT;
|
||||
cellCutType_.resize(mesh_.nCells());
|
||||
cellCutType_ = cutType::NOTCUT;
|
||||
|
||||
|
||||
// Propagate internal face cuts into the cells.
|
||||
|
||||
for (label facei = 0; facei < mesh_.nInternalFaces(); ++facei)
|
||||
{
|
||||
if (faceCutType_[facei] == NOTCUT)
|
||||
if (faceCutType_[facei] == cutType::NOTCUT)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cellCutType_[own[facei]] == NOTCUT)
|
||||
if (cellCutType_[own[facei]] == cutType::NOTCUT)
|
||||
{
|
||||
cellCutType_[own[facei]] = CUT;
|
||||
cellCutType_[own[facei]] = cutType::CUT;
|
||||
++nCutCells_;
|
||||
}
|
||||
if (cellCutType_[nei[facei]] == NOTCUT)
|
||||
if (cellCutType_[nei[facei]] == cutType::NOTCUT)
|
||||
{
|
||||
cellCutType_[nei[facei]] = CUT;
|
||||
cellCutType_[nei[facei]] = cutType::CUT;
|
||||
++nCutCells_;
|
||||
}
|
||||
}
|
||||
@ -495,14 +501,14 @@ void Foam::isoSurfacePoint::calcCutTypes
|
||||
|
||||
for (label facei = mesh_.nInternalFaces(); facei < mesh_.nFaces(); ++facei)
|
||||
{
|
||||
if (faceCutType_[facei] == NOTCUT)
|
||||
if (faceCutType_[facei] == cutType::NOTCUT)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cellCutType_[own[facei]] == NOTCUT)
|
||||
if (cellCutType_[own[facei]] == cutType::NOTCUT)
|
||||
{
|
||||
cellCutType_[own[facei]] = CUT;
|
||||
cellCutType_[own[facei]] = cutType::CUT;
|
||||
++nCutCells_;
|
||||
}
|
||||
}
|
||||
@ -551,7 +557,7 @@ void Foam::isoSurfacePoint::calcSnappedCc
|
||||
|
||||
forAll(mesh_.cells(), celli)
|
||||
{
|
||||
if (cellCutType_[celli] == CUT)
|
||||
if (cellCutType_[celli] == cutType::CUT)
|
||||
{
|
||||
const scalar cVal = cVals[celli];
|
||||
|
||||
@ -722,7 +728,7 @@ void Foam::isoSurfacePoint::calcSnappedPoint
|
||||
|
||||
for (const label facei : pFaces)
|
||||
{
|
||||
if (faceCutType_[facei] == CUT)
|
||||
if (faceCutType_[facei] == cutType::CUT)
|
||||
{
|
||||
anyCut = true;
|
||||
break;
|
||||
@ -1335,19 +1341,25 @@ Foam::isoSurfacePoint::isoSurfacePoint
|
||||
const bitSet& /*unused*/
|
||||
)
|
||||
:
|
||||
isoSurfaceBase(iso, params),
|
||||
mesh_(cellValues.mesh()),
|
||||
pVals_(pointValues),
|
||||
isoSurfaceBase
|
||||
(
|
||||
cellValues.mesh(),
|
||||
cellValues.primitiveField(),
|
||||
pointValues,
|
||||
iso,
|
||||
params
|
||||
),
|
||||
cValsPtr_(nullptr),
|
||||
mergeDistance_(params.mergeTol()*mesh_.bounds().mag())
|
||||
{
|
||||
const bool regularise = (params.filter() != filterType::NONE);
|
||||
const fvMesh& fvmesh = cellValues.mesh();
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "isoSurfacePoint:" << nl
|
||||
<< " isoField : " << cellValues.name() << nl
|
||||
<< " cell min/max : "
|
||||
<< minMax(cellValues.primitiveField()) << nl
|
||||
<< " cell min/max : " << minMax(cVals_) << nl
|
||||
<< " point min/max : " << minMax(pVals_) << nl
|
||||
<< " isoValue : " << iso << nl
|
||||
<< " filter : " << Switch(regularise) << nl
|
||||
@ -1357,7 +1369,6 @@ Foam::isoSurfacePoint::isoSurfacePoint
|
||||
|
||||
const polyBoundaryMesh& patches = mesh_.boundaryMesh();
|
||||
|
||||
|
||||
// Rewrite input field
|
||||
// ~~~~~~~~~~~~~~~~~~~
|
||||
// Rewrite input volScalarField to have interpolated values
|
||||
@ -1376,17 +1387,17 @@ Foam::isoSurfacePoint::isoSurfacePoint
|
||||
IOobject
|
||||
(
|
||||
"C",
|
||||
mesh_.pointsInstance(),
|
||||
mesh_.meshSubDir,
|
||||
mesh_,
|
||||
fvmesh.pointsInstance(),
|
||||
fvmesh.meshSubDir,
|
||||
fvmesh,
|
||||
IOobject::NO_READ,
|
||||
IOobject::NO_WRITE,
|
||||
false
|
||||
),
|
||||
mesh_,
|
||||
fvmesh,
|
||||
dimLength,
|
||||
mesh_.cellCentres(),
|
||||
mesh_.faceCentres()
|
||||
fvmesh.cellCentres(),
|
||||
fvmesh.faceCentres()
|
||||
);
|
||||
forAll(patches, patchi)
|
||||
{
|
||||
@ -1429,7 +1440,7 @@ Foam::isoSurfacePoint::isoSurfacePoint
|
||||
patchi,
|
||||
new calculatedFvPatchField<vector>
|
||||
(
|
||||
mesh_.boundary()[patchi],
|
||||
fvmesh.boundary()[patchi],
|
||||
meshC
|
||||
)
|
||||
);
|
||||
@ -1454,20 +1465,18 @@ Foam::isoSurfacePoint::isoSurfacePoint
|
||||
|
||||
if (debug)
|
||||
{
|
||||
const fvMesh& fvm = mesh_;
|
||||
|
||||
volScalarField debugField
|
||||
(
|
||||
IOobject
|
||||
(
|
||||
"isoSurfacePoint.cutType",
|
||||
fvm.time().timeName(),
|
||||
fvm.time(),
|
||||
fvmesh.time().timeName(),
|
||||
fvmesh.time(),
|
||||
IOobject::NO_READ,
|
||||
IOobject::NO_WRITE,
|
||||
false
|
||||
),
|
||||
fvm,
|
||||
fvmesh,
|
||||
dimensionedScalar(dimless, Zero)
|
||||
);
|
||||
|
||||
|
||||
@ -76,9 +76,7 @@ SourceFiles
|
||||
namespace Foam
|
||||
{
|
||||
|
||||
// Forward declarations
|
||||
|
||||
class fvMesh;
|
||||
// Forward Declarations
|
||||
class plane;
|
||||
class treeBoundBox;
|
||||
class triSurface;
|
||||
@ -93,26 +91,7 @@ class isoSurfacePoint
|
||||
{
|
||||
// Private Data
|
||||
|
||||
enum segmentCutType
|
||||
{
|
||||
NEARFIRST, // intersection close to e.first()
|
||||
NEARSECOND, // ,, e.second()
|
||||
NOTNEAR // no intersection
|
||||
};
|
||||
|
||||
enum cellCutType
|
||||
{
|
||||
NOTCUT, // not cut
|
||||
SPHERE, // all edges to cell centre cut
|
||||
CUT // normal cut
|
||||
};
|
||||
|
||||
|
||||
//- Reference to mesh
|
||||
const fvMesh& mesh_;
|
||||
|
||||
const scalarField& pVals_;
|
||||
|
||||
//- Cell values.
|
||||
//- Input volScalarField with separated coupled patches rewritten
|
||||
autoPtr<slicedVolScalarField> cValsPtr_;
|
||||
|
||||
@ -120,10 +99,10 @@ class isoSurfacePoint
|
||||
const scalar mergeDistance_;
|
||||
|
||||
//- Whether face might be cut
|
||||
List<cellCutType> faceCutType_;
|
||||
List<cutType> faceCutType_;
|
||||
|
||||
//- Whether cell might be cut
|
||||
List<cellCutType> cellCutType_;
|
||||
List<cutType> cellCutType_;
|
||||
|
||||
//- Estimated number of cut cells
|
||||
label nCutCells_;
|
||||
@ -374,6 +353,18 @@ class isoSurfacePoint
|
||||
labelList& newToOldPoints
|
||||
);
|
||||
|
||||
|
||||
//- Interpolates cCoords, pCoords.
|
||||
// Uses the references to the original fields used to create the
|
||||
// iso surface.
|
||||
template<class Type>
|
||||
tmp<Field<Type>> interpolateTemplate
|
||||
(
|
||||
const GeometricField<Type, fvPatchField, volMesh>& cCoords,
|
||||
const Field<Type>& pCoords
|
||||
) const;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
//- Declare friendship to share some functionality
|
||||
@ -404,18 +395,19 @@ public:
|
||||
);
|
||||
|
||||
|
||||
//- Destructor
|
||||
virtual ~isoSurfacePoint() = default;
|
||||
|
||||
|
||||
// Member Functions
|
||||
|
||||
//- Interpolates cCoords, pCoords.
|
||||
// Uses the references to the original fields used to create the
|
||||
// iso surface.
|
||||
template<class Type>
|
||||
tmp<Field<Type>> interpolate
|
||||
(
|
||||
const GeometricField<Type, fvPatchField, volMesh>& cCoords,
|
||||
const Field<Type>& pCoords
|
||||
) const;
|
||||
// Sampling
|
||||
|
||||
declareIsoSurfaceInterpolateMethod(scalar);
|
||||
declareIsoSurfaceInterpolateMethod(vector);
|
||||
declareIsoSurfaceInterpolateMethod(sphericalTensor);
|
||||
declareIsoSurfaceInterpolateMethod(symmTensor);
|
||||
declareIsoSurfaceInterpolateMethod(tensor);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
Copyright (C) 2011-2016 OpenFOAM Foundation
|
||||
Copyright (C) 2018 OpenCFD Ltd.
|
||||
Copyright (C) 2018-2020 OpenCFD Ltd.
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
@ -407,7 +407,7 @@ void Foam::isoSurfacePoint::generateTriPoints
|
||||
if (triIndex == 0x09)
|
||||
{
|
||||
// Flip normals
|
||||
label sz = pts.size();
|
||||
const label sz = pts.size();
|
||||
Swap(pts[sz-5], pts[sz-4]);
|
||||
Swap(pts[sz-2], pts[sz-1]);
|
||||
}
|
||||
@ -433,7 +433,7 @@ void Foam::isoSurfacePoint::generateTriPoints
|
||||
if (triIndex == 0x07)
|
||||
{
|
||||
// Flip normals
|
||||
label sz = pts.size();
|
||||
const label sz = pts.size();
|
||||
Swap(pts[sz-2], pts[sz-1]);
|
||||
}
|
||||
}
|
||||
@ -465,7 +465,7 @@ Foam::label Foam::isoSurfacePoint::generateFaceTriPoints
|
||||
DynamicList<label>& triMeshCells
|
||||
) const
|
||||
{
|
||||
label own = mesh_.faceOwner()[facei];
|
||||
const label own = mesh_.faceOwner()[facei];
|
||||
|
||||
label oldNPoints = triPoints.size();
|
||||
|
||||
@ -577,7 +577,7 @@ void Foam::isoSurfacePoint::generateTriPoints
|
||||
|
||||
for (label facei = 0; facei < mesh_.nInternalFaces(); ++facei)
|
||||
{
|
||||
if (faceCutType_[facei] != NOTCUT)
|
||||
if ((faceCutType_[facei] & cutType::ANYCUT) != 0)
|
||||
{
|
||||
generateFaceTriPoints
|
||||
(
|
||||
@ -647,9 +647,9 @@ void Foam::isoSurfacePoint::generateTriPoints
|
||||
|
||||
forAll(isCollocated, i)
|
||||
{
|
||||
label facei = pp.start()+i;
|
||||
const label facei = pp.start()+i;
|
||||
|
||||
if (faceCutType_[facei] != NOTCUT)
|
||||
if ((faceCutType_[facei] & cutType::ANYCUT) != 0)
|
||||
{
|
||||
if (isCollocated[i])
|
||||
{
|
||||
@ -708,7 +708,7 @@ void Foam::isoSurfacePoint::generateTriPoints
|
||||
|
||||
forAll(pp, i)
|
||||
{
|
||||
if (faceCutType_[facei] != NOTCUT)
|
||||
if ((faceCutType_[facei] & cutType::ANYCUT) != 0)
|
||||
{
|
||||
generateFaceTriPoints
|
||||
(
|
||||
@ -807,7 +807,7 @@ Foam::isoSurfacePoint::interpolate
|
||||
|
||||
template<class Type>
|
||||
Foam::tmp<Foam::Field<Type>>
|
||||
Foam::isoSurfacePoint::interpolate
|
||||
Foam::isoSurfacePoint::interpolateTemplate
|
||||
(
|
||||
const GeometricField<Type, fvPatchField, volMesh>& cCoords,
|
||||
const Field<Type>& pCoords
|
||||
|
||||
@ -34,8 +34,14 @@ License
|
||||
#include "tetPointRef.H"
|
||||
#include "DynamicField.H"
|
||||
#include "syncTools.H"
|
||||
#include "uindirectPrimitivePatch.H"
|
||||
#include "polyMeshTetDecomposition.H"
|
||||
#include "cyclicACMIPolyPatch.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#include "isoSurfaceBaseMethods.H"
|
||||
defineIsoSurfaceInterpolateMethods(Foam::isoSurfaceTopo);
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
@ -45,206 +51,27 @@ namespace Foam
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
// Does any edge of triangle cross iso value?
|
||||
inline static bool isTriCut
|
||||
(
|
||||
const label a,
|
||||
const label b,
|
||||
const label c,
|
||||
const scalarField& pointValues,
|
||||
const scalar isoValue
|
||||
)
|
||||
{
|
||||
const bool aLower = (pointValues[a] < isoValue);
|
||||
const bool bLower = (pointValues[b] < isoValue);
|
||||
const bool cLower = (pointValues[c] < isoValue);
|
||||
|
||||
return !(aLower == bLower && aLower == cLower);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
Foam::isoSurfaceTopo::cellCutType Foam::isoSurfaceTopo::calcCutType
|
||||
(
|
||||
const label celli
|
||||
) const
|
||||
{
|
||||
if (ignoreCells_.test(celli))
|
||||
{
|
||||
return NOTCUT;
|
||||
}
|
||||
|
||||
const cell& cFaces = mesh_.cells()[celli];
|
||||
|
||||
if (tetMatcher::test(mesh_, celli))
|
||||
{
|
||||
for (const label facei : cFaces)
|
||||
{
|
||||
if
|
||||
(
|
||||
!mesh_.isInternalFace(facei)
|
||||
&& ignoreBoundaryFaces_.test(facei-mesh_.nInternalFaces())
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const face& f = mesh_.faces()[facei];
|
||||
|
||||
for (label fp = 1; fp < f.size() - 1; ++fp)
|
||||
{
|
||||
if (isTriCut(f[0], f[fp], f[f.fcIndex(fp)], pVals_, iso_))
|
||||
{
|
||||
return CUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NOTCUT;
|
||||
}
|
||||
|
||||
|
||||
const bool cellLower = (cVals_[celli] < iso_);
|
||||
|
||||
// First check if there is any cut in cell
|
||||
bool edgeCut = false;
|
||||
|
||||
for (const label facei : cFaces)
|
||||
{
|
||||
if
|
||||
(
|
||||
!mesh_.isInternalFace(facei)
|
||||
&& ignoreBoundaryFaces_.test(facei-mesh_.nInternalFaces())
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const face& f = mesh_.faces()[facei];
|
||||
|
||||
// Check pyramids cut
|
||||
for (const label pointi : f)
|
||||
{
|
||||
if ((pVals_[pointi] < iso_) != cellLower)
|
||||
{
|
||||
edgeCut = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (edgeCut)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Check (triangulated) face edges
|
||||
// With fallback for problem decompositions
|
||||
const label fp0 = (tetBasePtIs_[facei] < 0 ? 0 : tetBasePtIs_[facei]);
|
||||
|
||||
label fp = f.fcIndex(fp0);
|
||||
for (label i = 2; i < f.size(); ++i)
|
||||
{
|
||||
const label nextFp = f.fcIndex(fp);
|
||||
|
||||
if (isTriCut(f[fp0], f[fp], f[nextFp], pVals_, iso_))
|
||||
{
|
||||
edgeCut = true;
|
||||
break;
|
||||
}
|
||||
|
||||
fp = nextFp;
|
||||
}
|
||||
|
||||
if (edgeCut)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (edgeCut)
|
||||
{
|
||||
// Count actual cuts (expensive since addressing needed)
|
||||
// Note: not needed if you don't want to preserve maxima/minima
|
||||
// centred around cellcentre. In that case just always return CUT
|
||||
|
||||
const labelList& cPoints = mesh_.cellPoints(celli);
|
||||
|
||||
label nPyrCuts = 0;
|
||||
|
||||
for (const label pointi : cPoints)
|
||||
{
|
||||
if ((pVals_[pointi] < iso_) != cellLower)
|
||||
{
|
||||
++nPyrCuts;
|
||||
}
|
||||
}
|
||||
|
||||
if (nPyrCuts == cPoints.size())
|
||||
{
|
||||
return SPHERE;
|
||||
}
|
||||
else if (nPyrCuts)
|
||||
{
|
||||
return CUT;
|
||||
}
|
||||
}
|
||||
|
||||
return NOTCUT;
|
||||
}
|
||||
|
||||
|
||||
Foam::label Foam::isoSurfaceTopo::calcCutTypes
|
||||
(
|
||||
List<cellCutType>& cellCutTypes
|
||||
)
|
||||
{
|
||||
cellCutTypes.setSize(mesh_.nCells());
|
||||
|
||||
label nCutCells = 0;
|
||||
forAll(cellCutTypes, celli)
|
||||
{
|
||||
cellCutTypes[celli] = calcCutType(celli);
|
||||
|
||||
if (cellCutTypes[celli] == CUT)
|
||||
{
|
||||
++nCutCells;
|
||||
}
|
||||
}
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "isoSurfaceTopo : candidate cut cells "
|
||||
<< nCutCells << " / " << mesh_.nCells() << endl;
|
||||
}
|
||||
return nCutCells;
|
||||
}
|
||||
|
||||
|
||||
Foam::scalar Foam::isoSurfaceTopo::minTetQ
|
||||
(
|
||||
const label facei,
|
||||
const label faceBasePtI
|
||||
) const
|
||||
{
|
||||
scalar q = polyMeshTetDecomposition::minQuality
|
||||
(
|
||||
mesh_,
|
||||
mesh_.cellCentres()[mesh_.faceOwner()[facei]],
|
||||
facei,
|
||||
true,
|
||||
faceBasePtI
|
||||
);
|
||||
const scalar ownQuality =
|
||||
polyMeshTetDecomposition::minQuality
|
||||
(
|
||||
mesh_,
|
||||
mesh_.cellCentres()[mesh_.faceOwner()[facei]],
|
||||
facei,
|
||||
true,
|
||||
faceBasePtI
|
||||
);
|
||||
|
||||
if (mesh_.isInternalFace(facei))
|
||||
{
|
||||
q = min
|
||||
(
|
||||
q,
|
||||
const scalar neiQuality =
|
||||
polyMeshTetDecomposition::minQuality
|
||||
(
|
||||
mesh_,
|
||||
@ -252,10 +79,15 @@ Foam::scalar Foam::isoSurfaceTopo::minTetQ
|
||||
facei,
|
||||
false,
|
||||
faceBasePtI
|
||||
)
|
||||
);
|
||||
);
|
||||
|
||||
if (neiQuality < ownQuality)
|
||||
{
|
||||
return neiQuality;
|
||||
}
|
||||
}
|
||||
return q;
|
||||
|
||||
return ownQuality;
|
||||
}
|
||||
|
||||
|
||||
@ -264,8 +96,8 @@ void Foam::isoSurfaceTopo::fixTetBasePtIs()
|
||||
// Determine points used by two faces on the same cell
|
||||
const cellList& cells = mesh_.cells();
|
||||
const faceList& faces = mesh_.faces();
|
||||
const labelList& faceOwner = mesh_.faceOwner();
|
||||
const labelList& faceNeighbour = mesh_.faceNeighbour();
|
||||
const labelList& faceOwn = mesh_.faceOwner();
|
||||
const labelList& faceNei = mesh_.faceNeighbour();
|
||||
|
||||
|
||||
// Get face triangulation base point
|
||||
@ -279,11 +111,11 @@ void Foam::isoSurfaceTopo::fixTetBasePtIs()
|
||||
{
|
||||
if (tetBasePtIs_[facei] == -1)
|
||||
{
|
||||
problemCells.set(faceOwner[facei]);
|
||||
problemCells.set(faceOwn[facei]);
|
||||
|
||||
if (mesh_.isInternalFace(facei))
|
||||
{
|
||||
problemCells.set(faceNeighbour[facei]);
|
||||
problemCells.set(faceNei[facei]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -338,8 +170,8 @@ void Foam::isoSurfaceTopo::fixTetBasePtIs()
|
||||
{
|
||||
if
|
||||
(
|
||||
problemCells[faceOwner[facei]]
|
||||
|| (mesh_.isInternalFace(facei) && problemCells[faceNeighbour[facei]])
|
||||
problemCells.test(faceOwn[facei])
|
||||
|| (mesh_.isInternalFace(facei) && problemCells.test(faceNei[facei]))
|
||||
)
|
||||
{
|
||||
const face& f = faces[facei];
|
||||
@ -350,8 +182,8 @@ void Foam::isoSurfaceTopo::fixTetBasePtIs()
|
||||
|
||||
if
|
||||
(
|
||||
!problemPoints[f.rcValue(fp0)]
|
||||
&& !problemPoints[f.fcValue(fp0)]
|
||||
!problemPoints.test(f.rcValue(fp0))
|
||||
&& !problemPoints.test(f.fcValue(fp0))
|
||||
)
|
||||
{
|
||||
continue;
|
||||
@ -365,8 +197,8 @@ void Foam::isoSurfaceTopo::fixTetBasePtIs()
|
||||
{
|
||||
if
|
||||
(
|
||||
!problemPoints[f.rcValue(fp)]
|
||||
&& !problemPoints[f.fcValue(fp)]
|
||||
!problemPoints.test(f.rcValue(fp))
|
||||
&& !problemPoints.test(f.fcValue(fp))
|
||||
)
|
||||
{
|
||||
const scalar q = minTetQ(facei, fp);
|
||||
@ -832,7 +664,9 @@ void Foam::isoSurfaceTopo::generateTriPoints
|
||||
// For tets don't do cell-centre decomposition, just use the
|
||||
// tet points and values
|
||||
|
||||
label facei = cFaces[0];
|
||||
const label startTrii = verts.size();
|
||||
|
||||
const label facei = cFaces[0];
|
||||
const face& f0 = faces[facei];
|
||||
|
||||
// Get the other point from f1. Tbd: check if not duplicate face
|
||||
@ -848,7 +682,6 @@ void Foam::isoSurfaceTopo::generateTriPoints
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
label p0 = f0[0];
|
||||
label p1 = f0[1];
|
||||
label p2 = f0[2];
|
||||
@ -858,7 +691,6 @@ void Foam::isoSurfaceTopo::generateTriPoints
|
||||
Swap(p1, p2);
|
||||
}
|
||||
|
||||
label startTrii = verts.size();
|
||||
generateTriPoints
|
||||
(
|
||||
facei,
|
||||
@ -880,8 +712,7 @@ void Foam::isoSurfaceTopo::generateTriPoints
|
||||
verts // Every three verts is new triangle
|
||||
);
|
||||
|
||||
label nTris = (verts.size()-startTrii)/3;
|
||||
for (label i = 0; i < nTris; ++i)
|
||||
for (label nTris = (verts.size()-startTrii)/3; nTris; --nTris)
|
||||
{
|
||||
faceLabels.append(facei);
|
||||
}
|
||||
@ -899,12 +730,12 @@ void Foam::isoSurfaceTopo::generateTriPoints
|
||||
continue;
|
||||
}
|
||||
|
||||
const label startTrii = verts.size();
|
||||
|
||||
const face& f = faces[facei];
|
||||
|
||||
label fp0 = tetBasePtIs_[facei];
|
||||
|
||||
label startTrii = verts.size();
|
||||
|
||||
// Fallback
|
||||
if (fp0 < 0)
|
||||
{
|
||||
@ -957,8 +788,7 @@ void Foam::isoSurfaceTopo::generateTriPoints
|
||||
fp = nextFp;
|
||||
}
|
||||
|
||||
label nTris = (verts.size()-startTrii)/3;
|
||||
for (label i = 0; i < nTris; ++i)
|
||||
for (label nTris = (verts.size()-startTrii)/3; nTris; --nTris)
|
||||
{
|
||||
faceLabels.append(facei);
|
||||
}
|
||||
@ -967,6 +797,8 @@ void Foam::isoSurfaceTopo::generateTriPoints
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
|
||||
|
||||
void Foam::isoSurfaceTopo::triangulateOutside
|
||||
(
|
||||
const bool filterDiag,
|
||||
@ -978,7 +810,7 @@ void Foam::isoSurfaceTopo::triangulateOutside
|
||||
// outputs
|
||||
DynamicList<face>& compactFaces,
|
||||
DynamicList<label>& compactCellIDs
|
||||
) const
|
||||
)
|
||||
{
|
||||
// We can form pockets:
|
||||
// - 1. triangle on face
|
||||
@ -1000,10 +832,10 @@ void Foam::isoSurfaceTopo::triangulateOutside
|
||||
label fpi = 0;
|
||||
forAll(f, i)
|
||||
{
|
||||
label pointi = mp[loop[i]];
|
||||
const label pointi = mp[loop[i]];
|
||||
if (filterDiag && pointFromDiag[pointi])
|
||||
{
|
||||
label prevPointi = mp[loop[loop.fcIndex(i)]];
|
||||
const label prevPointi = mp[loop[loop.fcIndex(i)]];
|
||||
if
|
||||
(
|
||||
pointFromDiag[prevPointi]
|
||||
@ -1042,10 +874,10 @@ void Foam::isoSurfaceTopo::triangulateOutside
|
||||
}
|
||||
|
||||
|
||||
Foam::meshedSurface Foam::isoSurfaceTopo::removeInsidePoints
|
||||
void Foam::isoSurfaceTopo::removeInsidePoints
|
||||
(
|
||||
Mesh& s,
|
||||
const bool filterDiag,
|
||||
const Mesh& s,
|
||||
|
||||
// inputs
|
||||
const boolUList& pointFromDiag,
|
||||
@ -1055,13 +887,13 @@ Foam::meshedSurface Foam::isoSurfaceTopo::removeInsidePoints
|
||||
// outputs
|
||||
DynamicList<label>& pointCompactMap, // Per returned point the original
|
||||
DynamicList<label>& compactCellIDs // Per returned tri the cellID
|
||||
) const
|
||||
)
|
||||
{
|
||||
const pointField& points = s.points();
|
||||
|
||||
pointCompactMap.clear();
|
||||
compactCellIDs.clear();
|
||||
|
||||
const pointField& points = s.points();
|
||||
|
||||
DynamicList<face> compactFaces(s.size()/8);
|
||||
|
||||
for (label celli = 0; celli < start.size()-1; ++celli)
|
||||
@ -1119,14 +951,17 @@ Foam::meshedSurface Foam::isoSurfaceTopo::removeInsidePoints
|
||||
UIndirectList<point>(s.points(), pointCompactMap)
|
||||
);
|
||||
|
||||
Mesh cpSurface
|
||||
surfZoneList newZones(s.surfZones());
|
||||
|
||||
s.clear();
|
||||
Mesh updated
|
||||
(
|
||||
std::move(compactPoints),
|
||||
std::move(compactFaces),
|
||||
s.surfZones()
|
||||
);
|
||||
|
||||
return cpSurface;
|
||||
s.transfer(updated);
|
||||
}
|
||||
|
||||
|
||||
@ -1135,18 +970,15 @@ Foam::meshedSurface Foam::isoSurfaceTopo::removeInsidePoints
|
||||
Foam::isoSurfaceTopo::isoSurfaceTopo
|
||||
(
|
||||
const polyMesh& mesh,
|
||||
const scalarField& cVals,
|
||||
const scalarField& pVals,
|
||||
const scalarField& cellValues,
|
||||
const scalarField& pointValues,
|
||||
const scalar iso,
|
||||
const isoSurfaceParams& params,
|
||||
const bitSet& ignoreCells
|
||||
)
|
||||
:
|
||||
isoSurfaceBase(iso, params),
|
||||
mesh_(mesh),
|
||||
cVals_(cVals),
|
||||
pVals_(pVals),
|
||||
ignoreCells_(ignoreCells)
|
||||
isoSurfaceBase(mesh, cellValues, pointValues, iso, params),
|
||||
cellCutType_(mesh.nCells(), cutType::UNVISITED)
|
||||
{
|
||||
if (debug)
|
||||
{
|
||||
@ -1157,31 +989,35 @@ Foam::isoSurfaceTopo::isoSurfaceTopo
|
||||
<< " filter : "
|
||||
<< isoSurfaceParams::filterNames[params.filter()] << nl
|
||||
<< " mesh span : " << mesh.bounds().mag() << nl
|
||||
<< " ignoreCells : " << ignoreCells_.count()
|
||||
<< " ignoreCells : " << ignoreCells.count()
|
||||
<< " / " << cVals_.size() << nl
|
||||
<< endl;
|
||||
}
|
||||
|
||||
// Determine boundary pyramids to ignore (since originating from ACMI faces)
|
||||
// Maybe needs to be optional argument or more general detect colocated
|
||||
// faces.
|
||||
for (const polyPatch& pp : mesh_.boundaryMesh())
|
||||
{
|
||||
if (isA<cyclicACMIPolyPatch>(pp))
|
||||
{
|
||||
ignoreBoundaryFaces_.set
|
||||
(
|
||||
labelRange(pp.offset(), pp.size())
|
||||
);
|
||||
}
|
||||
}
|
||||
this->ignoreCyclics();
|
||||
|
||||
label nBlockedCells = 0;
|
||||
|
||||
// Mark ignoreCells as blocked
|
||||
nBlockedCells += blockCells(cellCutType_, ignoreCells);
|
||||
|
||||
// Mark cells outside bounding box as blocked
|
||||
nBlockedCells +=
|
||||
blockCells(cellCutType_, params.getClipBounds(), volumeType::OUTSIDE);
|
||||
|
||||
|
||||
fixTetBasePtIs();
|
||||
|
||||
// Determine if any cut through cell
|
||||
List<cellCutType> cellCutTypes;
|
||||
const label nCutCells = calcCutTypes(cellCutTypes);
|
||||
// Determine cell cuts
|
||||
const label nCutCells = calcCellCuts(cellCutType_);
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "isoSurfaceTopo : candidate cells cut "
|
||||
<< nCutCells
|
||||
<< " blocked " << nBlockedCells
|
||||
<< " total " << mesh_.nCells() << endl;
|
||||
}
|
||||
|
||||
if (debug && isA<fvMesh>(mesh))
|
||||
{
|
||||
@ -1204,9 +1040,9 @@ Foam::isoSurfaceTopo::isoSurfaceTopo
|
||||
|
||||
auto& debugFld = debugField.primitiveFieldRef();
|
||||
|
||||
forAll(cellCutTypes, celli)
|
||||
forAll(cellCutType_, celli)
|
||||
{
|
||||
debugFld[celli] = cellCutTypes[celli];
|
||||
debugFld[celli] = cellCutType_[celli];
|
||||
}
|
||||
|
||||
Pout<< "Writing cut types:"
|
||||
@ -1221,7 +1057,7 @@ Foam::isoSurfaceTopo::isoSurfaceTopo
|
||||
DynamicList<edge> pointToVerts(10*nCutCells);
|
||||
// - pointToFace : from generated iso point to originating mesh face
|
||||
DynamicList<label> pointToFace(10*nCutCells);
|
||||
// - pointToFace : from generated iso point whether is on face diagonal
|
||||
// - pointFromDiag : if generated iso point is on face diagonal
|
||||
DynamicList<bool> pointFromDiag(10*nCutCells);
|
||||
|
||||
// Per cell: number of intersected edges:
|
||||
@ -1239,12 +1075,14 @@ Foam::isoSurfaceTopo::isoSurfaceTopo
|
||||
for (label celli = 0; celli < mesh_.nCells(); ++celli)
|
||||
{
|
||||
startTri[celli] = faceLabels.size();
|
||||
if (cellCutTypes[celli] != NOTCUT)
|
||||
if ((cellCutType_[celli] & cutType::ANYCUT) != 0)
|
||||
{
|
||||
generateTriPoints
|
||||
(
|
||||
celli,
|
||||
tetMatcher::test(mesh_, celli),
|
||||
|
||||
// Same as tetMatcher::test(mesh_, celli),
|
||||
bool(cellCutType_[celli] & cutType::TETCUT), // isTet
|
||||
|
||||
pointToVerts,
|
||||
pointToFace,
|
||||
@ -1268,9 +1106,9 @@ Foam::isoSurfaceTopo::isoSurfaceTopo
|
||||
meshCells_.transfer(cellLabels);
|
||||
pointToFace_.transfer(pointToFace);
|
||||
|
||||
tmp<pointField> allPoints
|
||||
pointField allPoints
|
||||
(
|
||||
interpolate
|
||||
this->interpolateTemplate
|
||||
(
|
||||
mesh_.cellCentres(),
|
||||
mesh_.points()
|
||||
@ -1312,7 +1150,9 @@ Foam::isoSurfaceTopo::isoSurfaceTopo
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "isoSurfaceTopo : generated " << size() << " faces." << endl;
|
||||
Pout<< "isoSurfaceTopo : generated "
|
||||
<< Mesh::size() << " faces "
|
||||
<< Mesh::points().size() << " points" << endl;
|
||||
}
|
||||
|
||||
|
||||
@ -1322,159 +1162,190 @@ Foam::isoSurfaceTopo::isoSurfaceTopo
|
||||
// face diagonals)
|
||||
DynamicList<label> pointCompactMap(size()); // Back to original point
|
||||
DynamicList<label> compactCellIDs(size()); // Per tri the cell
|
||||
Mesh::operator=
|
||||
|
||||
removeInsidePoints
|
||||
(
|
||||
removeInsidePoints
|
||||
(
|
||||
(params.filter() == filterType::DIAGCELL ? true : false),
|
||||
*this,
|
||||
pointFromDiag,
|
||||
pointToFace_,
|
||||
startTri,
|
||||
pointCompactMap,
|
||||
compactCellIDs
|
||||
)
|
||||
*this,
|
||||
(params.filter() == filterType::DIAGCELL ? true : false),
|
||||
|
||||
pointFromDiag,
|
||||
pointToFace_,
|
||||
startTri,
|
||||
pointCompactMap,
|
||||
compactCellIDs
|
||||
);
|
||||
|
||||
pointToVerts_ = UIndirectList<edge>(pointToVerts_, pointCompactMap)();
|
||||
pointToFace_ = UIndirectList<label>(pointToFace_, pointCompactMap)();
|
||||
pointFromDiag = UIndirectList<bool>(pointFromDiag, pointCompactMap)();
|
||||
meshCells_.transfer(compactCellIDs);
|
||||
|
||||
pointCompactMap.clearStorage();
|
||||
compactCellIDs.clearStorage();
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "isoSurfaceTopo :"
|
||||
<< " after removing cell centre and face-diag triangles : "
|
||||
<< size() << endl;
|
||||
" after removing cell centre and face-diag triangles "
|
||||
<< Mesh::size() << " faces "
|
||||
<< Mesh::points().size() << " points"
|
||||
<< endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Not required after this stage
|
||||
pointFromDiag.clearStorage();
|
||||
|
||||
|
||||
if (params.filter() == filterType::DIAGCELL)
|
||||
{
|
||||
// We remove verts on face diagonals. This is in fact just
|
||||
// straightening the edges of the face through the cell. This can
|
||||
// close off 'pockets' of triangles and create open or
|
||||
// multiply-connected triangles
|
||||
|
||||
// Solved by eroding open-edges
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
// Mark points on mesh outside.
|
||||
bitSet isBoundaryPoint(mesh.nPoints());
|
||||
for
|
||||
(
|
||||
label facei = mesh.nInternalFaces();
|
||||
facei < mesh.nFaces();
|
||||
++facei
|
||||
)
|
||||
{
|
||||
isBoundaryPoint.set(mesh.faces()[facei]);
|
||||
}
|
||||
|
||||
|
||||
if (params.filter() == filterType::DIAGCELL)
|
||||
// Include faces that would be exposed from mesh subset
|
||||
if (nBlockedCells)
|
||||
{
|
||||
// We remove verts on face diagonals. This is in fact just
|
||||
// straightening the edges of the face through the cell. This can
|
||||
// close off 'pockets' of triangles and create open or
|
||||
// multiply-connected triangles
|
||||
const labelList& faceOwn = mesh_.faceOwner();
|
||||
const labelList& faceNei = mesh_.faceNeighbour();
|
||||
|
||||
// Solved by eroding open-edges
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
// Mark points on mesh outside.
|
||||
bitSet isBoundaryPoint(mesh.nPoints());
|
||||
for
|
||||
(
|
||||
label facei = mesh.nInternalFaces();
|
||||
facei < mesh.nFaces();
|
||||
++facei
|
||||
)
|
||||
for (label facei = 0; facei < mesh.nInternalFaces(); ++facei)
|
||||
{
|
||||
isBoundaryPoint.set(mesh.faces()[facei]);
|
||||
}
|
||||
|
||||
|
||||
// Include faces that would be exposed from mesh subset
|
||||
if (!ignoreCells_.empty())
|
||||
{
|
||||
const labelList& faceOwner = mesh_.faceOwner();
|
||||
const labelList& faceNeighbour = mesh_.faceNeighbour();
|
||||
|
||||
for
|
||||
// If only one cell is blocked, the face corresponds
|
||||
// to an exposed subMesh face
|
||||
if
|
||||
(
|
||||
label facei = 0;
|
||||
facei < mesh.nInternalFaces();
|
||||
++facei
|
||||
(cellCutType_[faceOwn[facei]] == cutType::BLOCKED)
|
||||
!= (cellCutType_[faceNei[facei]] == cutType::BLOCKED)
|
||||
)
|
||||
{
|
||||
// Only one of the cells is being ignored.
|
||||
// That means it is an exposed subMesh face.
|
||||
isBoundaryPoint.set(mesh.faces()[facei]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The list of surface faces that should be retained after erosion
|
||||
Mesh& surf = *this;
|
||||
labelList faceAddr(identity(surf.size()));
|
||||
|
||||
bitSet faceSelection;
|
||||
|
||||
while (true)
|
||||
{
|
||||
// Shadow the surface for the purposes of erosion
|
||||
uindirectPrimitivePatch erosion
|
||||
(
|
||||
UIndirectList<face>(surf, faceAddr),
|
||||
surf.points()
|
||||
);
|
||||
|
||||
faceSelection.clear();
|
||||
faceSelection.resize(erosion.size());
|
||||
|
||||
const labelList& mp = erosion.meshPoints();
|
||||
const edgeList& surfEdges = erosion.edges();
|
||||
const labelListList& edgeFaces = erosion.edgeFaces();
|
||||
|
||||
label nEdgeRemove = 0;
|
||||
|
||||
forAll(edgeFaces, edgei)
|
||||
{
|
||||
const labelList& eFaces = edgeFaces[edgei];
|
||||
if (eFaces.size() == 1)
|
||||
{
|
||||
// Open edge. Check that vertices do not originate
|
||||
// from a boundary face
|
||||
const edge& e = surfEdges[edgei];
|
||||
|
||||
const edge& verts0 = pointToVerts_[mp[e.first()]];
|
||||
const edge& verts1 = pointToVerts_[mp[e.second()]];
|
||||
|
||||
if
|
||||
(
|
||||
ignoreCells_.test(faceOwner[facei])
|
||||
!= ignoreCells_.test(faceNeighbour[facei])
|
||||
isBoundaryPoint.test(verts0.first())
|
||||
&& isBoundaryPoint.test(verts0.second())
|
||||
&& isBoundaryPoint.test(verts1.first())
|
||||
&& isBoundaryPoint.test(verts1.second())
|
||||
)
|
||||
{
|
||||
isBoundaryPoint.set(mesh.faces()[facei]);
|
||||
// Open edge on boundary face. Keep
|
||||
}
|
||||
else
|
||||
{
|
||||
// Open edge. Mark for erosion
|
||||
faceSelection.set(eFaces[0]);
|
||||
++nEdgeRemove;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bitSet faceSelection;
|
||||
|
||||
while (true)
|
||||
if (debug)
|
||||
{
|
||||
faceSelection.clear();
|
||||
faceSelection.resize(this->size());
|
||||
|
||||
const labelList& mp = meshPoints();
|
||||
|
||||
const labelListList& edgeFaces = Mesh::edgeFaces();
|
||||
|
||||
forAll(edgeFaces, edgei)
|
||||
{
|
||||
const labelList& eFaces = edgeFaces[edgei];
|
||||
if (eFaces.size() == 1)
|
||||
{
|
||||
// Open edge. Check that vertices do not originate
|
||||
// from a boundary face
|
||||
const edge& e = edges()[edgei];
|
||||
const edge& verts0 = pointToVerts_[mp[e[0]]];
|
||||
const edge& verts1 = pointToVerts_[mp[e[1]]];
|
||||
if
|
||||
(
|
||||
isBoundaryPoint.test(verts0[0])
|
||||
&& isBoundaryPoint.test(verts0[1])
|
||||
&& isBoundaryPoint.test(verts1[0])
|
||||
&& isBoundaryPoint.test(verts1[1])
|
||||
)
|
||||
{
|
||||
// Open edge on boundary face. Keep
|
||||
}
|
||||
else
|
||||
{
|
||||
// Open edge. Mark for erosion
|
||||
faceSelection.set(eFaces[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (debug)
|
||||
{
|
||||
Pout<< "isoSurfaceTopo :"
|
||||
<< " removing " << faceSelection.count()
|
||||
<< " faces on open edges" << endl;
|
||||
}
|
||||
|
||||
if (returnReduce(faceSelection.none(), andOp<bool>()))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// Flip from remove face -> keep face
|
||||
faceSelection.flip();
|
||||
|
||||
labelList pointMap;
|
||||
labelList faceMap;
|
||||
Mesh filteredSurf
|
||||
(
|
||||
Mesh::subsetMesh
|
||||
(
|
||||
faceSelection,
|
||||
pointMap,
|
||||
faceMap
|
||||
)
|
||||
);
|
||||
Mesh::transfer(filteredSurf);
|
||||
|
||||
pointToVerts_ = UIndirectList<edge>(pointToVerts_, pointMap)();
|
||||
pointToFace_ = UIndirectList<label>(pointToFace_, pointMap)();
|
||||
pointFromDiag = UIndirectList<bool>(pointFromDiag, pointMap)();
|
||||
meshCells_ = UIndirectList<label>(meshCells_, faceMap)();
|
||||
Pout<< "isoSurfaceTopo :"
|
||||
<< " removing " << faceSelection.count()
|
||||
<< " / " << faceSelection.size()
|
||||
<< " faces on " << nEdgeRemove << " open edges" << endl;
|
||||
}
|
||||
|
||||
if (returnReduce(faceSelection.none(), andOp<bool>()))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Remove the faces from the addressing
|
||||
inplaceSubset(faceSelection, faceAddr, true); // True = remove
|
||||
}
|
||||
|
||||
|
||||
// Finished erosion (if any)
|
||||
// - retain the faces listed in the updated addressing
|
||||
|
||||
if (surf.size() != faceAddr.size())
|
||||
{
|
||||
faceSelection.clear();
|
||||
faceSelection.resize(surf.size());
|
||||
faceSelection.set(faceAddr);
|
||||
|
||||
inplaceSubsetMesh(faceSelection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||
|
||||
void Foam::isoSurfaceTopo::inplaceSubsetMesh(const bitSet& include)
|
||||
{
|
||||
labelList pointMap;
|
||||
labelList faceMap;
|
||||
Mesh filtered
|
||||
(
|
||||
Mesh::subsetMesh(include, pointMap, faceMap)
|
||||
);
|
||||
Mesh::transfer(filtered);
|
||||
|
||||
meshCells_ = UIndirectList<label>(meshCells_, faceMap)();
|
||||
|
||||
pointToVerts_ = UIndirectList<edge>(pointToVerts_, pointMap)();
|
||||
pointToFace_ = UIndirectList<label>(pointToFace_, pointMap)();
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
@ -62,28 +62,6 @@ class isoSurfaceTopo
|
||||
{
|
||||
// Private Data
|
||||
|
||||
enum cellCutType
|
||||
{
|
||||
NOTCUT, //!< Not cut
|
||||
SPHERE, //!< All edges to cell centre cut
|
||||
CUT //!< Normal cut
|
||||
};
|
||||
|
||||
|
||||
//- Reference to mesh
|
||||
const polyMesh& mesh_;
|
||||
|
||||
const scalarField& cVals_;
|
||||
|
||||
const scalarField& pVals_;
|
||||
|
||||
//- Optional cells to ignore
|
||||
const bitSet& ignoreCells_;
|
||||
|
||||
//- Optional boundary faces to ignore. Used to exclude cyclicACMI
|
||||
// (since duplicate faces)
|
||||
bitSet ignoreBoundaryFaces_;
|
||||
|
||||
//- Corrected version of tetBasePtIs
|
||||
labelList tetBasePtIs_;
|
||||
|
||||
@ -93,6 +71,9 @@ class isoSurfaceTopo
|
||||
//- For every point the originating face in mesh
|
||||
labelList pointToFace_;
|
||||
|
||||
//- The cell cut type
|
||||
List<cutType> cellCutType_;
|
||||
|
||||
|
||||
// Private Member Functions
|
||||
|
||||
@ -104,13 +85,6 @@ class isoSurfaceTopo
|
||||
|
||||
void fixTetBasePtIs();
|
||||
|
||||
//- Determine whether cell is cut
|
||||
cellCutType calcCutType(const label celli) const;
|
||||
|
||||
//- Determine for all mesh whether cell is cut
|
||||
// \return number of cells cut
|
||||
label calcCutTypes(List<cellCutType>& cellCutTypes);
|
||||
|
||||
//- Generate single point on edge
|
||||
label generatePoint
|
||||
(
|
||||
@ -158,7 +132,7 @@ class isoSurfaceTopo
|
||||
|
||||
// Simplification
|
||||
|
||||
void triangulateOutside
|
||||
static void triangulateOutside
|
||||
(
|
||||
const bool filterDiag,
|
||||
const primitivePatch& pp,
|
||||
@ -169,12 +143,12 @@ class isoSurfaceTopo
|
||||
|
||||
DynamicList<face>& compactFaces,
|
||||
DynamicList<label>& compactCellIDs
|
||||
) const;
|
||||
);
|
||||
|
||||
Mesh removeInsidePoints
|
||||
static void removeInsidePoints
|
||||
(
|
||||
Mesh& s, // Modify inplace
|
||||
const bool filterDiag,
|
||||
const Mesh& s,
|
||||
|
||||
// Inputs
|
||||
const boolUList& pointFromDiag,
|
||||
@ -184,12 +158,31 @@ class isoSurfaceTopo
|
||||
// Outputs
|
||||
DynamicList<label>& pointCompactMap, // Per point the original
|
||||
DynamicList<label>& compactCellIDs // Per face the cellID
|
||||
) const;
|
||||
);
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// Editing
|
||||
|
||||
//- Subset the surface using the selected faces.
|
||||
//
|
||||
// \param[in] include the faces to select
|
||||
void inplaceSubsetMesh(const bitSet& include);
|
||||
|
||||
|
||||
// Sampling
|
||||
|
||||
//- Interpolates cCoords,pCoords.
|
||||
template<class Type>
|
||||
tmp<Field<Type>> interpolateTemplate
|
||||
(
|
||||
const Field<Type>& cCoords,
|
||||
const Field<Type>& pCoords
|
||||
) const;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
//- Runtime type information
|
||||
TypeName("isoSurfaceTopo");
|
||||
|
||||
@ -214,6 +207,10 @@ public:
|
||||
);
|
||||
|
||||
|
||||
//- Destructor
|
||||
virtual ~isoSurfaceTopo() = default;
|
||||
|
||||
|
||||
// Member Functions
|
||||
|
||||
//- For every point originating face (pyramid) in mesh
|
||||
@ -228,13 +225,14 @@ public:
|
||||
return pointToVerts_;
|
||||
}
|
||||
|
||||
//- Interpolates cCoords,pCoords.
|
||||
template<class Type>
|
||||
tmp<Field<Type>> interpolate
|
||||
(
|
||||
const Field<Type>& cCoords,
|
||||
const Field<Type>& pCoords
|
||||
) const;
|
||||
|
||||
// Sampling
|
||||
|
||||
declareIsoSurfaceInterpolateMethod(scalar);
|
||||
declareIsoSurfaceInterpolateMethod(vector);
|
||||
declareIsoSurfaceInterpolateMethod(sphericalTensor);
|
||||
declareIsoSurfaceInterpolateMethod(symmTensor);
|
||||
declareIsoSurfaceInterpolateMethod(tensor);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -30,7 +30,7 @@ License
|
||||
|
||||
template<class Type>
|
||||
Foam::tmp<Foam::Field<Type>>
|
||||
Foam::isoSurfaceTopo::interpolate
|
||||
Foam::isoSurfaceTopo::interpolateTemplate
|
||||
(
|
||||
const Field<Type>& cellCoords,
|
||||
const Field<Type>& pointCoords
|
||||
|
||||
Reference in New Issue
Block a user