Commit 544941b9 authored by Mark Olesen's avatar Mark Olesen
Browse files

ENH: support zone and zones for sampled cutting planes, sampledIsoSurface

- rework to use bitSet for more flexibility
parent cf7bd82c
......@@ -108,7 +108,7 @@ void Foam::sampledIsoSurface::getIsoFields() const
fvm
)
);
volFieldPtr_ = storedVolFieldPtr_.operator->();
volFieldPtr_ = storedVolFieldPtr_.get();
}
else
{
......@@ -132,7 +132,7 @@ void Foam::sampledIsoSurface::getIsoFields() const
// (volPointInterpolation::interpolate with cache=false deletes any
// registered one or if mesh.changing())
if (!subMeshPtr_.valid())
if (subMeshPtr_.empty())
{
const word pointFldName =
"volPointInterpolate_"
......@@ -200,8 +200,8 @@ void Foam::sampledIsoSurface::getIsoFields() const
}
// If averaging redo the volField. Can only be done now since needs the
// point field.
// If averaging redo the volField.
// Can only be done now since needs the point field.
if (average_)
{
storedVolFieldPtr_.reset
......@@ -261,7 +261,7 @@ void Foam::sampledIsoSurface::getIsoFields() const
}
// Pointfield on submesh
// The point field on subMesh
const word pointFldName =
"volPointInterpolate_"
......@@ -360,30 +360,30 @@ bool Foam::sampledIsoSurface::updateGeometry() const
return false;
}
// Get any subMesh
if (zoneID_.index() != -1 && !subMeshPtr_.valid())
// Get sub-mesh if any
if
(
(-1 != mesh().cellZones().findIndex(zoneNames_))
&& subMeshPtr_.empty()
)
{
const polyBoundaryMesh& patches = mesh().boundaryMesh();
// Patch to put exposed internal faces into
const label exposedPatchi = patches.findPatchID(exposedPatchName_);
if (debug)
{
Info<< "Allocating subset of size "
<< mesh().cellZones()[zoneID_.index()].size()
DebugInfo
<< "Allocating subset of size "
<< mesh().cellZones().selection(zoneNames_).count()
<< " with exposed faces into patch "
<< patches[exposedPatchi].name() << endl;
}
// Remove old mesh if any
subMeshPtr_.clear();
subMeshPtr_.reset
(
new fvMeshSubset
(
fvm,
mesh().cellZones()[zoneID_.index()],
mesh().cellZones().selection(zoneNames_),
exposedPatchi
)
);
......@@ -474,8 +474,8 @@ Foam::sampledIsoSurface::sampledIsoSurface
mergeTol_(dict.lookupOrDefault("mergeTol", 1e-6)),
regularise_(dict.lookupOrDefault("regularise", true)),
average_(dict.lookupOrDefault("average", false)),
zoneID_(dict.lookupOrDefault("zone", word::null), mesh.cellZones()),
exposedPatchName_(word::null),
zoneNames_(),
exposedPatchName_(),
surfPtr_(nullptr),
prevTimeIndex_(-1),
storedVolFieldPtr_(nullptr),
......@@ -491,28 +491,31 @@ Foam::sampledIsoSurface::sampledIsoSurface
<< " span across cells." << exit(FatalIOError);
}
if (zoneID_.index() != -1)
if (!dict.readIfPresent("zones", zoneNames_) && dict.found("zone"))
{
zoneNames_.resize(1);
dict.readEntry("zone", zoneNames_.first());
}
if (-1 != mesh.cellZones().findIndex(zoneNames_))
{
dict.readEntry("exposedPatchName", exposedPatchName_);
if (mesh.boundaryMesh().findPatchID(exposedPatchName_) == -1)
{
FatalIOErrorInFunction
(
dict
) << "Cannot find patch " << exposedPatchName_
FatalIOErrorInFunction(dict)
<< "Cannot find patch " << exposedPatchName_
<< " in which to put exposed faces." << endl
<< "Valid patches are " << mesh.boundaryMesh().names()
<< exit(FatalIOError);
}
if (debug && zoneID_.index() != -1)
{
Info<< "Restricting to cellZone " << zoneID_.name()
DebugInfo
<< "Restricting to cellZone(s) " << flatOutput(zoneNames_)
<< " with exposed internal faces into patch "
<< exposedPatchName_ << endl;
}
}
}
......
......@@ -54,7 +54,8 @@ Usage
regularise | point snapping | yes |
average | cell values from averaged point values | no | false
bounds | limit with bounding box | no |
zone | limit to specified zone | no |
zone | limit to cell zone (name or regex) | no |
zones | limit to cell zones (names, regexs) | no |
exposedPatchName | name for zone subset | partly |
\endtable
......@@ -68,7 +69,6 @@ SourceFiles
#include "isoSurface.H"
#include "sampledSurface.H"
#include "ZoneIDs.H"
#include "fvMeshSubset.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
......@@ -104,8 +104,8 @@ class sampledIsoSurface
//- Whether to recalculate cell values as average of point values
const bool average_;
//- Zone name/index (if restricted to zones)
mutable cellZoneID zoneID_;
//- The zone or zones for the iso-surface
wordRes zoneNames_;
//- For zones: patch to put exposed faces into
mutable word exposedPatchName_;
......
......@@ -201,7 +201,6 @@ Foam::sampledIsoSurfaceCell::sampledIsoSurfaceCell
bounds_(dict.lookupOrDefault("bounds", boundBox::invertedBox)),
regularise_(dict.lookupOrDefault("regularise", true)),
average_(dict.lookupOrDefault("average", true)),
zoneKey_(keyType::null),
prevTimeIndex_(-1),
meshCells_()
{}
......
......@@ -56,6 +56,9 @@ Usage
bounds | limit with bounding box | no |
\endtable
Note
Does not currently support cell zones.
SourceFiles
sampledIsoSurfaceCell.C
......@@ -102,9 +105,6 @@ class sampledIsoSurfaceCell
//- Whether to recalculate cell values as average of point values
const bool average_;
//- If restricted to zones, name of this zone or a regular expression
keyType zoneKey_;
// Recreated for every isoSurface
......
......@@ -46,6 +46,51 @@ namespace Foam
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::sampledCuttingPlane::checkBoundsIntersection
(
const plane& pln,
const boundBox& meshBb
) const
{
// Verify specified bounding box
if (!bounds_.empty())
{
// Bounding box does not overlap with (global) mesh!
if (!bounds_.overlaps(meshBb))
{
WarningInFunction
<< nl
<< name() << " : "
<< "Bounds " << bounds_
<< " do not overlap the mesh bounding box " << meshBb
<< nl << endl;
}
// Plane does not intersect the bounding box
if (!bounds_.intersects(pln))
{
WarningInFunction
<< nl
<< name() << " : "
<< "Plane "<< pln << " does not intersect the bounds "
<< bounds_
<< nl << endl;
}
}
// Plane does not intersect the (global) mesh!
if (!meshBb.intersects(pln))
{
WarningInFunction
<< nl
<< name() << " : "
<< "Plane "<< pln << " does not intersect the mesh bounds "
<< meshBb
<< nl << endl;
}
}
void Foam::sampledCuttingPlane::createGeometry()
{
if (debug)
......@@ -62,29 +107,51 @@ void Foam::sampledCuttingPlane::createGeometry()
// Clear derived data
clearGeom();
// Get any subMesh
if (zoneID_.index() != -1 && !subMeshPtr_.valid())
const fvMesh& fvm = static_cast<const fvMesh&>(this->mesh());
// Get sub-mesh if any
if
(
(-1 != mesh().cellZones().findIndex(zoneNames_))
&& subMeshPtr_.empty()
)
{
const polyBoundaryMesh& patches = mesh().boundaryMesh();
// Patch to put exposed internal faces into
const label exposedPatchi = patches.findPatchID(exposedPatchName_);
bitSet cellsToSelect = mesh().cellZones().selection(zoneNames_);
DebugInfo
<< "Allocating subset of size "
<< mesh().cellZones()[zoneID_.index()].size()
<< cellsToSelect.count()
<< " with exposed faces into patch "
<< patches[exposedPatchi].name() << endl;
subMeshPtr_.reset
(
new fvMeshSubset
(
static_cast<const fvMesh&>(mesh()),
mesh().cellZones()[zoneID_.index()],
exposedPatchi
)
);
// If we will use a fvMeshSubset so can apply bounds as well to make
// the initial selection smaller.
if (!bounds_.empty() && cellsToSelect.any())
{
const auto& cellCentres = fvm.C();
for (const label celli : cellsToSelect)
{
const point& cc = cellCentres[celli];
if (!bounds_.contains(cc))
{
cellsToSelect.unset(celli);
}
}
DebugInfo
<< "Bounded subset of size "
<< cellsToSelect.count() << endl;
}
subMeshPtr_.reset(new fvMeshSubset(fvm, cellsToSelect, exposedPatchi));
}
......@@ -93,9 +160,11 @@ void Foam::sampledCuttingPlane::createGeometry()
(
subMeshPtr_.valid()
? subMeshPtr_().subMesh()
: static_cast<const fvMesh&>(this->mesh())
: fvm
);
checkBoundsIntersection(plane_, mesh.bounds());
// Distance to cell centres
// ~~~~~~~~~~~~~~~~~~~~~~~~
......@@ -121,7 +190,7 @@ void Foam::sampledCuttingPlane::createGeometry()
// Internal field
{
const pointField& cc = mesh.cellCentres();
const auto& cc = mesh.cellCentres();
scalarField& fld = cellDistance.primitiveFieldRef();
forAll(cc, i)
......@@ -167,6 +236,7 @@ void Foam::sampledCuttingPlane::createGeometry()
}
else
{
// Other side cell centres?
const pointField& cc = mesh.C().boundaryField()[patchi];
fvPatchScalarField& fld = cellDistanceBf[patchi];
......@@ -242,43 +312,6 @@ void Foam::sampledCuttingPlane::createGeometry()
//)
);
// Verify specified bounding box
if (!bounds_.empty())
{
// Bounding box does not overlap with (global) mesh!
if (!bounds_.overlaps(mesh.bounds()))
{
WarningInFunction
<< nl
<< name() << " : "
<< "Bounds " << bounds_
<< " do not overlap the mesh bounding box " << mesh.bounds()
<< nl << endl;
}
// Plane does not intersect the bounding box
if (!bounds_.intersects(plane_))
{
WarningInFunction
<< nl
<< name() << " : "
<< "Plane "<< plane_ << " does not intersect the bounds "
<< bounds_
<< nl << endl;
}
}
// Plane does not intersect the (global) mesh!
if (!mesh.bounds().intersects(plane_))
{
WarningInFunction
<< nl
<< name() << " : "
<< "Plane "<< plane_ << " does not intersect the mesh bounds "
<< mesh.bounds()
<< nl << endl;
}
if (debug)
{
print(Pout);
......@@ -302,33 +335,37 @@ Foam::sampledCuttingPlane::sampledCuttingPlane
mergeTol_(dict.lookupOrDefault("mergeTol", 1e-6)),
regularise_(dict.lookupOrDefault("regularise", true)),
average_(dict.lookupOrDefault("average", false)),
zoneID_(dict.lookupOrDefault("zone", word::null), mesh.cellZones()),
exposedPatchName_(word::null),
zoneNames_(),
exposedPatchName_(),
needsUpdate_(true),
subMeshPtr_(nullptr),
cellDistancePtr_(nullptr),
isoSurfPtr_(nullptr)
{
if (zoneID_.index() != -1)
if (!dict.readIfPresent("zones", zoneNames_) && dict.found("zone"))
{
zoneNames_.resize(1);
dict.readEntry("zone", zoneNames_.first());
}
if (-1 != mesh.cellZones().findIndex(zoneNames_))
{
dict.readEntry("exposedPatchName", exposedPatchName_);
if (mesh.boundaryMesh().findPatchID(exposedPatchName_) == -1)
if (-1 == mesh.boundaryMesh().findPatchID(exposedPatchName_))
{
FatalErrorInFunction
FatalIOErrorInFunction(dict)
<< "Cannot find patch " << exposedPatchName_
<< " in which to put exposed faces." << endl
<< "Valid patches are " << mesh.boundaryMesh().names()
<< exit(FatalError);
}
if (debug && zoneID_.index() != -1)
{
Info<< "Restricting to cellZone " << zoneID_.name()
DebugInfo
<< "Restricting to cellZone(s) " << flatOutput(zoneNames_)
<< " with exposed internal faces into patch "
<< exposedPatchName_ << endl;
}
}
}
......
......@@ -55,10 +55,14 @@ Usage
mergeTol | tolerance for merging points | no | 1e-6
regularise | point snapping | no | true
bounds | limit with bounding box | no |
zone | limit to specified zone | no |
zone | limit to cell zone (name or regex) | no |
zones | limit to cell zones (names, regexs) | no |
exposedPatchName | name for zone subset | partly |
\endtable
Note
The keyword \c zones has priority over \c zone.
SeeAlso
Foam::plane
......@@ -74,7 +78,6 @@ SourceFiles
#include "isoSurface.H"
//#include "isoSurfaceCell.H"
#include "plane.H"
#include "ZoneIDs.H"
#include "fvMeshSubset.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
......@@ -107,8 +110,8 @@ class sampledCuttingPlane
//- Whether to recalculate cell values as average of point values
const bool average_;
//- Zone name/index (if restricted to zones)
mutable cellZoneID zoneID_;
//- The zone or zones in which cutting is to occur
wordRes zoneNames_;
//- For zones: patch to put exposed faces into
mutable word exposedPatchName_;
......@@ -117,7 +120,7 @@ class sampledCuttingPlane
mutable bool needsUpdate_;
//- Optional subsetted mesh
//- Mesh subset (optional: only used with zones)
autoPtr<fvMeshSubset> subMeshPtr_;
//- Distance to cell centres
......@@ -133,6 +136,13 @@ class sampledCuttingPlane
// Private Member Functions
//- Check and warn if bounding box does not intersect mesh or plane
void checkBoundsIntersection
(
const plane& pln,
const boundBox& meshBb
) const;
//- Create iso surface
void createGeometry();
......
......@@ -44,6 +44,159 @@ namespace Foam
);
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::sampledPlane::checkBoundsIntersection
(
const plane& pln,
const boundBox& meshBb
) const
{
// Verify specified bounding box
if (!bounds_.empty())
{
// Bounding box does not overlap with (global) mesh!
if (!bounds_.overlaps(meshBb))
{
WarningInFunction
<< nl
<< name() << " : "
<< "Bounds " << bounds_
<< " do not overlap the mesh bounding box " << meshBb
<< nl << endl;
}
// Plane does not intersect the bounding box
if (!bounds_.intersects(pln))
{
WarningInFunction
<< nl
<< name() << " : "
<< "Plane "<< pln << " does not intersect the bounds "
<< bounds_
<< nl << endl;
}
}
// Plane does not intersect the (global) mesh!
if (!meshBb.intersects(pln))
{
WarningInFunction
<< nl
<< name() << " : "
<< "Plane "<< pln << " does not intersect the mesh bounds "
<< meshBb
<< nl << endl;
}
}
Foam::bitSet Foam::sampledPlane::cellSelection
(
const bool warnIntersect
) const
{
// Zones requested and in use?
const bool hasZones =
returnReduce
(
(-1 != mesh().cellZones().findIndex(zoneNames_)),
andOp<bool>()
);
bitSet cellsToSelect;
if (hasZones)
{
cellsToSelect = mesh().cellZones().selection(zoneNames_);
}
// Subset the zoned cells with the bounds_.
// For a full mesh, use the bounds to define the cell selection.
// If there are zones cells, use them to build the effective mesh
// bound box.
// Note that for convenience we use cell centres here instead of the
// cell points, since it will only be used for checking.
boundBox meshBb;
if (bounds_.empty())
{
// No bounds restriction, but will need the effective mesh boundBox
// for checking intersections
if (hasZones && warnIntersect)
{
const auto& cellCentres = static_cast<const fvMesh&>(mesh()).C();
for (const label celli : cellsToSelect)
{
const point& cc = cellCentres[celli];
meshBb.add(cc);
}
meshBb.reduce();
}
else
{
meshBb = mesh().bounds(); // use the regular mesh bounding box
}
}
else
{
const auto& cellCentres = static_cast<const fvMesh&>(mesh()).C();
// Only examine cells already set
if (hasZones)
{
for (const label celli : cellsToSelect)
{
const point& cc = cellCentres[celli];
meshBb.add(cc);
if (!bounds_.contains(cc))
{
cellsToSelect.unset(celli);
}
}