mirror of
https://develop.openfoam.com/Development/openfoam.git
synced 2025-11-28 03:28:01 +00:00
ENH: output filtering of vtkCloud by user selection (#1056)
- can filter by stride or field information.
For example,
selection
{
stride
{
// every 10th parcelId
action add;
source stride;
stride 10;
}
Umin
{
// Remove slow parcels
action subtract;
source field;
field U;
accept (less 1e-3);
}
diam
{
// Only particular diameter ranges
action subset;
source field;
field d;
accept (greater 1e-3) and (less 1e-3);
}
}
This commit is contained in:
@ -4,5 +4,6 @@ icoUncoupledKinematicCloud/icoUncoupledKinematicCloud.C
|
||||
dsmcFields/dsmcFields.C
|
||||
|
||||
vtkCloud/vtkCloud.C
|
||||
vtkCloud/parcelSelectionDetail.C
|
||||
|
||||
LIB = $(FOAM_LIBBIN)/liblagrangianFunctionObjects
|
||||
|
||||
416
src/functionObjects/lagrangian/vtkCloud/parcelSelectionDetail.C
Normal file
416
src/functionObjects/lagrangian/vtkCloud/parcelSelectionDetail.C
Normal file
@ -0,0 +1,416 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2018 OpenCFD Ltd.
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "parcelSelectionDetail.H"
|
||||
#include "scalarPredicates.H"
|
||||
#include "labelField.H"
|
||||
#include "scalarField.H"
|
||||
#include "pointField.H"
|
||||
#include "ListListOps.H"
|
||||
|
||||
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||
|
||||
const Foam::Enum
|
||||
<
|
||||
Foam::Detail::parcelSelection::actionType
|
||||
>
|
||||
Foam::Detail::parcelSelection::actionNames
|
||||
({
|
||||
{ actionType::ALL, "all" },
|
||||
{ actionType::CLEAR, "clear" },
|
||||
{ actionType::INVERT, "invert" },
|
||||
{ actionType::ADD, "add" },
|
||||
{ actionType::SUBTRACT, "subtract" },
|
||||
{ actionType::SUBSET, "subset" },
|
||||
{ actionType::IGNORE, "ignore" },
|
||||
});
|
||||
|
||||
|
||||
const Foam::Enum
|
||||
<
|
||||
Foam::Detail::parcelSelection::sourceType
|
||||
>
|
||||
Foam::Detail::parcelSelection::sourceNames
|
||||
({
|
||||
{ sourceType::FIELD, "field" },
|
||||
{ sourceType::STRIDE, "stride" },
|
||||
});
|
||||
|
||||
|
||||
const Foam::Enum
|
||||
<
|
||||
Foam::Detail::parcelSelection::logicType
|
||||
> Foam::Detail::parcelSelection::logicNames
|
||||
({
|
||||
{ logicType::AND, "and" },
|
||||
{ logicType::OR, "or" },
|
||||
});
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
template<class Type, class Predicate, class AccessOp>
|
||||
static void apply
|
||||
(
|
||||
bitSet& selection,
|
||||
const Detail::parcelSelection::actionType action,
|
||||
const Predicate& accept,
|
||||
const UList<Type>& list,
|
||||
const AccessOp& aop
|
||||
)
|
||||
{
|
||||
using actionType = Detail::parcelSelection::actionType;
|
||||
|
||||
const label len = selection.size();
|
||||
|
||||
switch (action)
|
||||
{
|
||||
case actionType::ADD:
|
||||
{
|
||||
for (label parceli = 0; parceli < len; ++parceli)
|
||||
{
|
||||
if (accept(aop(list[parceli])))
|
||||
{
|
||||
selection.set(parceli);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case actionType::SUBTRACT:
|
||||
{
|
||||
for (label parceli = 0; parceli < len; ++parceli)
|
||||
{
|
||||
if (accept(aop(list[parceli])))
|
||||
{
|
||||
selection.unset(parceli);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case actionType::SUBSET:
|
||||
{
|
||||
for (const label parceli : selection)
|
||||
{
|
||||
if (!accept(aop(list[parceli])))
|
||||
{
|
||||
selection.unset(parceli);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // End namespace Foam
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||
|
||||
Foam::Detail::parcelSelection::parcelSelection()
|
||||
:
|
||||
parcelSelect_(),
|
||||
parcelAddr_()
|
||||
{}
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||
|
||||
bool Foam::Detail::parcelSelection::calculateFilter
|
||||
(
|
||||
const objectRegistry& obrTmp,
|
||||
const bool log
|
||||
)
|
||||
{
|
||||
if (parcelSelect_.empty())
|
||||
{
|
||||
parcelAddr_.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Start with all parcels unselected
|
||||
|
||||
// Number of parcels (locally)
|
||||
const auto* pointsPtr = obrTmp.findObject<vectorField>("position");
|
||||
label nParcels = pointsPtr->size();
|
||||
|
||||
parcelAddr_.reset();
|
||||
parcelAddr_.resize(nParcels);
|
||||
|
||||
reduce(nParcels, sumOp<label>());
|
||||
|
||||
Log << "Applying parcel filtering to " << nParcels << " parcels" << nl;
|
||||
|
||||
if (!nParcels)
|
||||
{
|
||||
parcelAddr_.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
// The unary function type(s) for testing a scalar.
|
||||
// Allocate 3 slots.
|
||||
// 0 is the test
|
||||
// 1,2 are for storage of composite tests (eg, and/or logic)
|
||||
predicates::scalars tests(3);
|
||||
|
||||
for (const entry& dEntry : parcelSelect_)
|
||||
{
|
||||
if (!dEntry.isDict())
|
||||
{
|
||||
WarningInFunction
|
||||
<< "Ignoring non-dictionary entry "
|
||||
<< dEntry << endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
const dictionary& dict = dEntry.dict();
|
||||
|
||||
// A very limited number of sources (stride, field)
|
||||
// and actions (all add subtract subset) so handle manually
|
||||
|
||||
auto action = actionNames.get("action", dict);
|
||||
|
||||
// These ones we do directly
|
||||
switch (action)
|
||||
{
|
||||
case actionType::ALL:
|
||||
Log << "- select all" << nl;
|
||||
parcelAddr_ = true;
|
||||
continue;
|
||||
break;
|
||||
|
||||
case actionType::CLEAR:
|
||||
Log << "- clear" << nl;
|
||||
parcelAddr_ = false;
|
||||
continue;
|
||||
break;
|
||||
|
||||
case actionType::INVERT:
|
||||
Log << "- invert" << nl;
|
||||
parcelAddr_.flip();
|
||||
continue;
|
||||
break;
|
||||
|
||||
case actionType::IGNORE:
|
||||
continue;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// The others need a source
|
||||
// Need a source
|
||||
const auto source = sourceNames.get("source", dict);
|
||||
|
||||
switch (source)
|
||||
{
|
||||
case sourceType::STRIDE:
|
||||
{
|
||||
const label stride = dict.get<label>("stride");
|
||||
|
||||
const labelField& ids =
|
||||
obrTmp.lookupObject<labelField>("origId");
|
||||
|
||||
Log << "- " << actionNames[action]
|
||||
<< " stride " << stride << nl;
|
||||
|
||||
if (stride <= 0)
|
||||
{
|
||||
WarningInFunction
|
||||
<< nl
|
||||
<< "Ignoring bad value for stride=" << stride << nl
|
||||
<< endl;
|
||||
}
|
||||
else if (stride == 1)
|
||||
{
|
||||
// More efficient handling of stride 1, but should
|
||||
// not really be using stride == 1.
|
||||
switch (action)
|
||||
{
|
||||
case actionType::ADD:
|
||||
parcelAddr_ = true;
|
||||
break;
|
||||
|
||||
case actionType::SUBTRACT:
|
||||
parcelAddr_ = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Using stride > 1
|
||||
apply
|
||||
(
|
||||
parcelAddr_,
|
||||
action,
|
||||
[=](const label id) -> bool { return !(id % stride); },
|
||||
ids,
|
||||
accessOp<label>() // pass-through
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case sourceType::FIELD:
|
||||
{
|
||||
const word fieldName(dict.get<word>("field"));
|
||||
|
||||
const auto* labelFld =
|
||||
obrTmp.findObject<labelField>(fieldName);
|
||||
|
||||
const auto* scalarFld =
|
||||
obrTmp.findObject<scalarField>(fieldName);
|
||||
|
||||
const auto* vectorFld =
|
||||
obrTmp.findObject<vectorField>(fieldName);
|
||||
|
||||
|
||||
Log << "- " << actionNames[action] << " field " << fieldName;
|
||||
|
||||
if (!labelFld && !scalarFld && !vectorFld)
|
||||
{
|
||||
WarningInFunction
|
||||
<< nl
|
||||
<< "No scalar/vector parcel field: " << fieldName
|
||||
<< " ignoring selection" << nl
|
||||
<< endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
const entry& e = dict.lookupEntry("accept", keyType::LITERAL);
|
||||
|
||||
ITstream& is = e.stream();
|
||||
|
||||
if (4 == is.size())
|
||||
{
|
||||
// 4 tokens:
|
||||
// -> (op val)
|
||||
|
||||
Tuple2<word,scalar> expr1(is);
|
||||
e.checkITstream(is);
|
||||
|
||||
tests.first() = predicates::scalars::operation(expr1);
|
||||
|
||||
Log << " : " << expr1;
|
||||
}
|
||||
else if (9 == is.size())
|
||||
{
|
||||
// 9 tokens:
|
||||
// -> (op val) and (op val)
|
||||
// -> (op val) or (op val)
|
||||
|
||||
Tuple2<word,scalar> expr1(is);
|
||||
word logicName(is);
|
||||
Tuple2<word,scalar> expr2(is);
|
||||
e.checkITstream(is);
|
||||
|
||||
logicType logic = logicNames[logicName];
|
||||
tests[1] = predicates::scalars::operation(expr1);
|
||||
tests[2] = predicates::scalars::operation(expr2);
|
||||
|
||||
switch (logic)
|
||||
{
|
||||
case logicType::AND:
|
||||
tests.first() =
|
||||
predicates::scalars::andOp(tests[1], tests[2]);
|
||||
break;
|
||||
|
||||
case logicType::OR:
|
||||
tests.first() =
|
||||
predicates::scalars::orOp(tests[1], tests[2]);
|
||||
break;
|
||||
}
|
||||
|
||||
Log << " : " << expr1 << ' ' << logicName << ' ' << expr2;
|
||||
}
|
||||
else
|
||||
{
|
||||
action = actionType::IGNORE;
|
||||
|
||||
// Use the following to always provoke an error.
|
||||
e.checkITstream(is);
|
||||
}
|
||||
|
||||
if (labelFld)
|
||||
{
|
||||
apply
|
||||
(
|
||||
parcelAddr_,
|
||||
action,
|
||||
tests.first(),
|
||||
*labelFld,
|
||||
accessOp<label>() // pass-through
|
||||
);
|
||||
}
|
||||
else if (scalarFld)
|
||||
{
|
||||
apply
|
||||
(
|
||||
parcelAddr_,
|
||||
action,
|
||||
tests.first(),
|
||||
*scalarFld,
|
||||
accessOp<scalar>() // pass-through
|
||||
);
|
||||
}
|
||||
else if (vectorFld)
|
||||
{
|
||||
apply
|
||||
(
|
||||
parcelAddr_,
|
||||
action,
|
||||
tests.first(),
|
||||
*vectorFld,
|
||||
[](const vector& val) -> scalar
|
||||
{
|
||||
return Foam::mag(val);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
Log << endl;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
221
src/functionObjects/lagrangian/vtkCloud/parcelSelectionDetail.H
Normal file
221
src/functionObjects/lagrangian/vtkCloud/parcelSelectionDetail.H
Normal file
@ -0,0 +1,221 @@
|
||||
/*---------------------------------------------------------------------------*\
|
||||
========= |
|
||||
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||
\\ / O peration |
|
||||
\\ / A nd | Copyright (C) 2018 OpenCFD Ltd.
|
||||
\\/ M anipulation |
|
||||
-------------------------------------------------------------------------------
|
||||
License
|
||||
This file is part of OpenFOAM.
|
||||
|
||||
OpenFOAM is free software: you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Class
|
||||
Foam::Detail::parcelSelection
|
||||
|
||||
Description
|
||||
Selection of parcels based on their objectRegistry entries.
|
||||
Normally accessed via a dictionary entry.
|
||||
|
||||
Example sub-dictionary entry
|
||||
\verbatim
|
||||
selection
|
||||
{
|
||||
stride
|
||||
{
|
||||
// every 10th parcelId
|
||||
action add;
|
||||
source stride;
|
||||
stride 10;
|
||||
}
|
||||
injector
|
||||
{
|
||||
// Only output from injectorID == 1
|
||||
action subset;
|
||||
source field;
|
||||
field typeId;
|
||||
accept (equal 1);
|
||||
}
|
||||
Umin
|
||||
{
|
||||
// Remove slow parcels
|
||||
action subtract;
|
||||
source field;
|
||||
field U;
|
||||
accept (less 1e-3);
|
||||
}
|
||||
diam
|
||||
{
|
||||
// Only particular diameter ranges
|
||||
action subset;
|
||||
source field;
|
||||
field d;
|
||||
accept (greater 1e-3) and (less 1e-3);
|
||||
}
|
||||
}
|
||||
\endverbatim
|
||||
|
||||
\heading Entry type
|
||||
\table
|
||||
Property | Description | Required | Default
|
||||
action | all/clear/invert add/subtract/subset/ignore | yes |
|
||||
source | field/stride | mostly |
|
||||
\endtable
|
||||
|
||||
\heading Stride source
|
||||
\table
|
||||
Property | Description | Required | Default
|
||||
stride | The stride for the parcel id | yes |
|
||||
\endtable
|
||||
|
||||
\heading Field source
|
||||
\table
|
||||
Property | Description | Required | Default
|
||||
field | The label/scalar/vector field name | yes |
|
||||
accept | Acceptance or test criterion | yes |
|
||||
\endtable
|
||||
|
||||
The \c accept criterion has two forms:
|
||||
-# single expression
|
||||
- (expr)
|
||||
-# composite expression
|
||||
- (expr) or (expr)
|
||||
- (expr) and (expr)
|
||||
|
||||
The expressions are a (op scalar) pair that form a unary scalar
|
||||
predicate. The \a op is one of the following:
|
||||
- lt, less
|
||||
- le, lessEq
|
||||
- gt, greater
|
||||
- ge, greaterEq
|
||||
- eq, equal
|
||||
- neq, notEqual
|
||||
|
||||
For example,
|
||||
\verbatim
|
||||
accept (less 10);
|
||||
accept (less 10) or (greater 100);
|
||||
accept (ge 10) and (le 20);
|
||||
\endverbatim
|
||||
|
||||
See also
|
||||
Foam::predicates::scalars
|
||||
Foam::functionObjects::vtkCloud
|
||||
|
||||
SourceFiles
|
||||
parcelSelectionDetail.C
|
||||
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef parcelSelectionDetail_H
|
||||
#define parcelSelectionDetail_H
|
||||
|
||||
#include "bitSet.H"
|
||||
#include "Enum.H"
|
||||
#include "objectRegistry.H"
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
namespace Foam
|
||||
{
|
||||
namespace Detail
|
||||
{
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
Class Detail::parcelSelection Declaration
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
class parcelSelection
|
||||
{
|
||||
public:
|
||||
|
||||
//- Enumeration defining the valid selection actions
|
||||
enum actionType
|
||||
{
|
||||
ALL, //!< "all" - select all parcels
|
||||
CLEAR, //!< "clear" - clear the selection
|
||||
INVERT, //!< "invert" - invert the selection
|
||||
ADD, //!< "add" - parcel selection
|
||||
SUBTRACT, //!< "subtract" - remove parcel selection
|
||||
SUBSET, //!< "subset" - subset parcel selection
|
||||
IGNORE, //!< "ignore" - dummy no-op
|
||||
};
|
||||
|
||||
//- Names for the actionType
|
||||
static const Enum<actionType> actionNames;
|
||||
|
||||
|
||||
//- Enumeration defining the valid sources
|
||||
enum sourceType
|
||||
{
|
||||
FIELD, //!< "field" - select based on field value
|
||||
STRIDE //!< "stride" - select based on stride (parcel id)
|
||||
};
|
||||
|
||||
//- Names for the sourceType
|
||||
static const Enum<sourceType> sourceNames;
|
||||
|
||||
|
||||
//- Enumeration defining and/or logic
|
||||
enum logicType { AND, OR };
|
||||
|
||||
//- Names for the logicType
|
||||
static const Enum<logicType> logicNames;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
// Protected data
|
||||
|
||||
//- The filtered parcel addressing. Eg, for the current cloud.
|
||||
dictionary parcelSelect_;
|
||||
|
||||
//- The filtered parcel addressing. Eg, for the current cloud.
|
||||
bitSet parcelAddr_;
|
||||
|
||||
|
||||
// Protected Member Functions
|
||||
|
||||
//- Calculate parcel selection filter.
|
||||
// \return True if the filter is applicable
|
||||
bool calculateFilter
|
||||
(
|
||||
const objectRegistry& obrTmp,
|
||||
const bool log = true
|
||||
);
|
||||
|
||||
public:
|
||||
|
||||
// Constructors
|
||||
|
||||
//- Construct null
|
||||
parcelSelection();
|
||||
|
||||
|
||||
//- Destructor
|
||||
virtual ~parcelSelection() = default;
|
||||
|
||||
};
|
||||
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
} // End namespace Detail
|
||||
} // End namespace Foam
|
||||
|
||||
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||
|
||||
#endif
|
||||
|
||||
// ************************************************************************* //
|
||||
@ -132,9 +132,23 @@ bool Foam::functionObjects::vtkCloud::writeCloud
|
||||
return false;
|
||||
}
|
||||
|
||||
applyFilter_ = calculateFilter(obrTmp, log);
|
||||
reduce(applyFilter_, orOp<bool>());
|
||||
|
||||
|
||||
// Number of parcels (locally)
|
||||
label nParcels = (applyFilter_ ? parcelAddr_.count() : pointsPtr->size());
|
||||
|
||||
// Total number of parcels on all processes
|
||||
const label nTotParcels =
|
||||
returnReduce(pointsPtr->size(), sumOp<label>());
|
||||
const label nTotParcels = returnReduce(nParcels, sumOp<label>());
|
||||
|
||||
if (applyFilter_ && log)
|
||||
{
|
||||
// Report filtered/unfiltered count
|
||||
Log << "After filtering using " << nTotParcels << '/'
|
||||
<< (returnReduce(pointsPtr->size(), sumOp<label>()))
|
||||
<< " parcels" << nl;
|
||||
}
|
||||
|
||||
if (pruneEmpty_ && !nTotParcels)
|
||||
{
|
||||
@ -216,7 +230,14 @@ bool Foam::functionObjects::vtkCloud::writeCloud
|
||||
}
|
||||
|
||||
|
||||
if (applyFilter_)
|
||||
{
|
||||
vtk::writeListParallel(format.ref(), *pointsPtr, parcelAddr_);
|
||||
}
|
||||
else
|
||||
{
|
||||
vtk::writeListParallel(format.ref(), *pointsPtr);
|
||||
}
|
||||
|
||||
|
||||
if (Pstream::master())
|
||||
@ -333,6 +354,7 @@ Foam::functionObjects::vtkCloud::vtkCloud
|
||||
printf_(),
|
||||
useVerts_(false),
|
||||
pruneEmpty_(false),
|
||||
applyFilter_(false),
|
||||
selectClouds_(),
|
||||
selectFields_(),
|
||||
directory_(),
|
||||
@ -404,7 +426,6 @@ bool Foam::functionObjects::vtkCloud::read(const dictionary& dict)
|
||||
useVerts_ = dict.lookupOrDefault<bool>("cellData", false);
|
||||
pruneEmpty_ = dict.lookupOrDefault<bool>("prune", false);
|
||||
|
||||
|
||||
selectClouds_.clear();
|
||||
dict.readIfPresent("clouds", selectClouds_);
|
||||
|
||||
@ -417,7 +438,10 @@ bool Foam::functionObjects::vtkCloud::read(const dictionary& dict)
|
||||
|
||||
selectFields_.clear();
|
||||
dict.readIfPresent("fields", selectFields_);
|
||||
selectFields_.uniq();
|
||||
|
||||
// Actions to define selection
|
||||
parcelSelect_ = dict.subOrEmptyDict("selection");
|
||||
|
||||
// Output directory
|
||||
|
||||
|
||||
@ -44,23 +44,56 @@ Description
|
||||
cloud myCloud;
|
||||
fields (T U rho);
|
||||
width 4; // file-padding
|
||||
|
||||
selection
|
||||
{
|
||||
stride
|
||||
{
|
||||
// every 10th parcelId
|
||||
action add;
|
||||
source stride;
|
||||
stride 10;
|
||||
}
|
||||
Umin
|
||||
{
|
||||
// Remove slow parcels
|
||||
action subtract;
|
||||
source field;
|
||||
field U;
|
||||
accept (less 1e-3);
|
||||
}
|
||||
diam
|
||||
{
|
||||
// Only particular diameter ranges
|
||||
action subset;
|
||||
source field;
|
||||
field d;
|
||||
accept (greater 1e-3) and (less 1e-3);
|
||||
}
|
||||
}
|
||||
}
|
||||
\endverbatim
|
||||
|
||||
Usage
|
||||
\heading Basic Usage
|
||||
\table
|
||||
Property | Description | Required | Default
|
||||
type | Type name: vtkCloud | yes |
|
||||
writeControl | Output control | recommended | timeStep
|
||||
cloud | | no | defaultCloud
|
||||
clouds | wordRe list of clouds | no |
|
||||
fields | wordRe list of fields | no |
|
||||
prune | Suppress writing of empty clouds | no | false
|
||||
cellData | Emit cellData instead of pointData | no | false
|
||||
directory | The output directory name | no | postProcessing/NAME
|
||||
width | Padding width for file name | no | 8
|
||||
clouds | List of clouds (name or regex) | no |
|
||||
cloud | Cloud name | no | defaultCloud
|
||||
fields | List of fields (name or regex) | no |
|
||||
selection | Parcel selection control | no | empty-dict
|
||||
\endtable
|
||||
|
||||
\heading Output Options
|
||||
\table
|
||||
Property | Description | Required | Default
|
||||
format | Format as ascii or binary | no | binary
|
||||
precision | Write precision in ascii | no | same as IOstream
|
||||
directory | The output directory name | no | postProcessing/NAME
|
||||
width | Padding width for file name | no | 8
|
||||
cellData | Emit cellData instead of pointData | no | false
|
||||
prune | Suppress writing of empty clouds | no | false
|
||||
writeControl | Output control | recommended | timeStep
|
||||
\endtable
|
||||
|
||||
The output filename and fields are added to the functionObjectProperties
|
||||
@ -77,7 +110,17 @@ Usage
|
||||
}
|
||||
\endverbatim
|
||||
|
||||
Note
|
||||
The selection dictionary can be used for finer control of the parcel
|
||||
output. It contains a set of (add,subtract,subset,clear,invert)
|
||||
selection actions and sources.
|
||||
Omitting the selection dictionary is the same as specifying the
|
||||
conversion of all parcels (in the selected clouds).
|
||||
More syntax details are to be found in the corresponding
|
||||
Foam::Detail::parcelSelection class.
|
||||
|
||||
See also
|
||||
Foam::Detail::parcelSelection
|
||||
Foam::functionObjects::ensightWrite
|
||||
Foam::functionObjects::vtkWrite
|
||||
Foam::functionObjects::fvMeshFunctionObject
|
||||
@ -93,6 +136,7 @@ SourceFiles
|
||||
#define functionObjects_vtkCloud_H
|
||||
|
||||
#include "fvMeshFunctionObject.H"
|
||||
#include "parcelSelectionDetail.H"
|
||||
#include "foamVtkOutputOptions.H"
|
||||
#include "foamVtkSeriesWriter.H"
|
||||
#include "wordRes.H"
|
||||
@ -111,7 +155,8 @@ namespace functionObjects
|
||||
|
||||
class vtkCloud
|
||||
:
|
||||
public fvMeshFunctionObject
|
||||
public fvMeshFunctionObject,
|
||||
public Foam::Detail::parcelSelection
|
||||
{
|
||||
// Private data
|
||||
|
||||
@ -127,6 +172,9 @@ class vtkCloud
|
||||
//- Suppress writing of empty clouds
|
||||
bool pruneEmpty_;
|
||||
|
||||
//- Apply output filter (for the current cloud)
|
||||
bool applyFilter_;
|
||||
|
||||
//- Requested names of clouds to process
|
||||
wordRes selectClouds_;
|
||||
|
||||
|
||||
@ -88,7 +88,14 @@ Foam::wordList Foam::functionObjects::vtkCloud::writeFields
|
||||
}
|
||||
}
|
||||
|
||||
if (applyFilter_)
|
||||
{
|
||||
vtk::writeListParallel(format.ref(), values, parcelAddr_);
|
||||
}
|
||||
else
|
||||
{
|
||||
vtk::writeListParallel(format.ref(), values);
|
||||
}
|
||||
|
||||
if (Pstream::master())
|
||||
{
|
||||
|
||||
@ -54,6 +54,7 @@ maxDeltaT 1;
|
||||
functions
|
||||
{
|
||||
#include "vtkCloud"
|
||||
#include "vtkWrite"
|
||||
}
|
||||
|
||||
// ************************************************************************* //
|
||||
|
||||
@ -6,6 +6,9 @@ cloudWrite
|
||||
libs ("liblagrangianFunctionObjects.so");
|
||||
log true;
|
||||
|
||||
// Nothing happens before this anyhow
|
||||
timeStart 0.5;
|
||||
|
||||
writeControl writeTime;
|
||||
|
||||
// cloud reactingCloud1;
|
||||
@ -15,16 +18,68 @@ cloudWrite
|
||||
fields ( U T d "Y.*" );
|
||||
|
||||
//- Output format (ascii | binary) - default = binary
|
||||
// format binary;
|
||||
|
||||
// format ascii;
|
||||
// writePrecision 12;
|
||||
|
||||
//- Suppress writing of empty clouds - default = false
|
||||
// prune true;
|
||||
// precision 12;
|
||||
|
||||
//- Output directory name - default = "VTK"
|
||||
// Suppress writing of empty clouds - default = false
|
||||
prune true;
|
||||
|
||||
//- Output directory name - Default postProcessing
|
||||
// directory "VTK";
|
||||
|
||||
selection
|
||||
{
|
||||
all
|
||||
{
|
||||
action all;
|
||||
}
|
||||
|
||||
none
|
||||
{
|
||||
action clear;
|
||||
}
|
||||
|
||||
// Reduced number of output parcels
|
||||
stride
|
||||
{
|
||||
action add;
|
||||
source stride;
|
||||
stride 4;
|
||||
}
|
||||
|
||||
T
|
||||
{
|
||||
action subset;
|
||||
source field;
|
||||
field T;
|
||||
accept (greater 280) and (less 300);
|
||||
}
|
||||
|
||||
YH2O
|
||||
{
|
||||
action subset;
|
||||
source field;
|
||||
field YH2O(l);
|
||||
accept (greater 0.5);
|
||||
}
|
||||
|
||||
diameter
|
||||
{
|
||||
action subset;
|
||||
source field;
|
||||
field d;
|
||||
accept (greater 1e-10);
|
||||
}
|
||||
|
||||
Umin
|
||||
{
|
||||
action subtract;
|
||||
source field;
|
||||
field U;
|
||||
accept (less 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,35 @@
|
||||
// -*- C++ -*-
|
||||
// Minimal example of using the vtkWrite function object.
|
||||
vtkWrite
|
||||
{
|
||||
type vtkWrite;
|
||||
libs ("libutilityFunctionObjects.so");
|
||||
log true;
|
||||
|
||||
// Nothing happens before this anyhow
|
||||
timeStart 0.4;
|
||||
writeControl writeTime;
|
||||
|
||||
boundary false;
|
||||
|
||||
interpolate true;
|
||||
|
||||
fields (U);
|
||||
// format ascii;
|
||||
|
||||
// Region of interest
|
||||
selection
|
||||
{
|
||||
inletRegion
|
||||
{
|
||||
action add;
|
||||
source zone;
|
||||
zones (leftFluid);
|
||||
}
|
||||
}
|
||||
|
||||
// Write cell ids as field - Default=true
|
||||
writeIds false;
|
||||
}
|
||||
|
||||
// ************************************************************************* //
|
||||
Reference in New Issue
Block a user