ENH: improvements for dataCloud function object (issue #1044)

- now supports a parcel selection mechanism like vtkCloud,
  giving the ability to select a subset of parcels.
  For example, a given stride, or removal of parcels with a small
  diameter.

  Eg,
      dataCloud output Time: 3.2
      Applying parcel filtering to 994 parcels
      - add stride 4
      - subtract field U : (less 0.2)
      After filtering using 214/994 parcels

- add output precision control for dataCloud
This commit is contained in:
Mark Olesen
2018-11-24 13:14:57 +01:00
parent 05353da5f4
commit 58dae2de43
12 changed files with 302 additions and 99 deletions

View File

@ -1,9 +1,9 @@
common/parcelSelectionDetail.C
dataCloud/dataCloud.C dataCloud/dataCloud.C
cloudInfo/cloudInfo.C cloudInfo/cloudInfo.C
icoUncoupledKinematicCloud/icoUncoupledKinematicCloud.C icoUncoupledKinematicCloud/icoUncoupledKinematicCloud.C
dsmcFields/dsmcFields.C dsmcFields/dsmcFields.C
vtkCloud/vtkCloud.C vtkCloud/vtkCloud.C
vtkCloud/parcelSelectionDetail.C
LIB = $(FOAM_LIBBIN)/liblagrangianFunctionObjects LIB = $(FOAM_LIBBIN)/liblagrangianFunctionObjects

View File

@ -78,12 +78,6 @@ Foam::functionObjects::cloudInfo::cloudInfo
} }
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::functionObjects::cloudInfo::~cloudInfo()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::functionObjects::cloudInfo::read(const dictionary& dict) bool Foam::functionObjects::cloudInfo::read(const dictionary& dict)
@ -96,10 +90,10 @@ bool Foam::functionObjects::cloudInfo::read(const dictionary& dict)
if (writeToFile() && names().size()) if (writeToFile() && names().size())
{ {
Info<< "applying to clouds:" << nl; Info<< "applying to clouds:" << nl;
forAll(names(), i) forAll(names(), cloudi)
{ {
Info<< " " << names()[i] << nl; Info<< " " << names()[cloudi] << nl;
writeFileHeader(files(i)); writeFileHeader(files(cloudi));
} }
Info<< endl; Info<< endl;
} }
@ -107,8 +101,6 @@ bool Foam::functionObjects::cloudInfo::read(const dictionary& dict)
{ {
Info<< "no clouds to be processed" << nl << endl; Info<< "no clouds to be processed" << nl << endl;
} }
return true;
} }
return true; return true;
@ -123,24 +115,26 @@ bool Foam::functionObjects::cloudInfo::execute()
bool Foam::functionObjects::cloudInfo::write() bool Foam::functionObjects::cloudInfo::write()
{ {
forAll(names(), i) forAll(names(), cloudi)
{ {
const word& cloudName = names()[i]; const word& cloudName = names()[cloudi];
const kinematicCloud& cloud = const kinematicCloud& cloud =
obr_.lookupObject<kinematicCloud>(cloudName); obr_.lookupObject<kinematicCloud>(cloudName);
label nParcels = returnReduce(cloud.nParcels(), sumOp<label>()); const label nTotParcels =
scalar massInSystem = returnReduce(cloud.nParcels(), sumOp<label>());
const scalar totMass =
returnReduce(cloud.massInSystem(), sumOp<scalar>()); returnReduce(cloud.massInSystem(), sumOp<scalar>());
scalar Dmax = cloud.Dmax(); const scalar Dmax = cloud.Dmax();
scalar D10 = cloud.Dij(1, 0); const scalar D10 = cloud.Dij(1, 0);
scalar D32 = cloud.Dij(3, 2); const scalar D32 = cloud.Dij(3, 2);
Log << type() << " " << name() << " write:" << nl Log << type() << " " << name() << " write:" << nl
<< " number of parcels : " << nParcels << nl << " number of parcels : " << nTotParcels << nl
<< " mass in system : " << massInSystem << nl << " mass in system : " << totMass << nl
<< " maximum diameter : " << Dmax << nl << " maximum diameter : " << Dmax << nl
<< " D10 diameter : " << D10 << nl << " D10 diameter : " << D10 << nl
<< " D32 diameter : " << D32 << nl << " D32 diameter : " << D32 << nl
@ -148,14 +142,15 @@ bool Foam::functionObjects::cloudInfo::write()
if (writeToFile()) if (writeToFile())
{ {
writeTime(files(i)); auto& os = files(cloudi);
files(i)
<< token::TAB writeTime(os);
<< nParcels << token::TAB os
<< massInSystem << token::TAB << token::TAB << nTotParcels
<< Dmax << token::TAB << token::TAB << totMass
<< D10 << token::TAB << token::TAB << Dmax
<< D32 << token::TAB << token::TAB << D10
<< token::TAB << D32
<< endl; << endl;
} }
} }

View File

@ -52,9 +52,9 @@ Usage
Where the entries comprise: Where the entries comprise:
\table \table
Property | Description | Required | Default value Property | Description | Required | Default
type | type name: cloudInfo | yes | type | type name: cloudInfo | yes |
clouds | list of clouds names to process |yes | clouds | list of clouds names to process | yes |
\endtable \endtable
The output data of each cloud is written to a file named \<cloudName\>.dat The output data of each cloud is written to a file named \<cloudName\>.dat
@ -108,10 +108,6 @@ protected:
virtual void writeFileHeader(Ostream& os) const; virtual void writeFileHeader(Ostream& os) const;
private:
// Private member functions
//- No copy construct //- No copy construct
cloudInfo(const cloudInfo&) = delete; cloudInfo(const cloudInfo&) = delete;
@ -137,13 +133,13 @@ public:
//- Destructor //- Destructor
virtual ~cloudInfo(); virtual ~cloudInfo() = default;
// Member Functions // Member Functions
//- Read the controls //- Read the controls
virtual bool read(const dictionary&); virtual bool read(const dictionary& dict);
//- Execute, currently does nothing //- Execute, currently does nothing
virtual bool execute(); virtual bool execute();

View File

@ -79,16 +79,29 @@ bool Foam::functionObjects::dataCloud::writeCloud
return false; 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 // Total number of parcels on all processes
label nTotParcels = pointsPtr->size(); const label nTotParcels = returnReduce(nParcels, sumOp<label>());
reduce(nTotParcels, sumOp<label>());
if (applyFilter_ && log)
{
// Report filtered/unfiltered count
Log << "After filtering using " << nTotParcels << '/'
<< (returnReduce(pointsPtr->size(), sumOp<label>()))
<< " parcels" << nl;
}
if (!nTotParcels) if (!nTotParcels)
{ {
return false; return false;
} }
if (Pstream::master()) if (Pstream::master())
{ {
mkDir(outputName.path()); mkDir(outputName.path());
@ -113,6 +126,9 @@ Foam::functionObjects::dataCloud::dataCloud
) )
: :
fvMeshFunctionObject(name, runTime, dict), fvMeshFunctionObject(name, runTime, dict),
printf_(),
precision_(IOstream::defaultPrecision()),
applyFilter_(false),
selectClouds_(), selectClouds_(),
fieldName_(), fieldName_(),
directory_() directory_()
@ -139,6 +155,9 @@ bool Foam::functionObjects::dataCloud::read(const dictionary& dict)
printf_ = "%0" + std::to_string(padWidth) + "d"; printf_ = "%0" + std::to_string(padWidth) + "d";
} }
precision_ =
dict.lookupOrDefault("precision", IOstream::defaultPrecision());
selectClouds_.clear(); selectClouds_.clear();
dict.readIfPresent("clouds", selectClouds_); dict.readIfPresent("clouds", selectClouds_);
@ -152,6 +171,9 @@ bool Foam::functionObjects::dataCloud::read(const dictionary& dict)
dict.readEntry("field", fieldName_); dict.readEntry("field", fieldName_);
// Actions to define selection
parcelSelect_ = dict.subOrEmptyDict("selection");
// Output directory // Output directory
directory_.clear(); directory_.clear();

View File

@ -43,19 +43,34 @@ Description
} }
\endverbatim \endverbatim
Usage \heading Basic Usage
\table \table
Property | Description | Required | Default Property | Description | Required | Default
type | Type name: dataCloud | yes | type | Type name: dataCloud | yes |
cloud | | no | defaultCloud clouds | List of clouds (name or regex) | no |
clouds | wordRe list of clouds | no | cloud | Cloud name | no | defaultCloud
field | Name of the field | yes | field | Name of the field | yes |
directory | The output directory name | no | postProcessing/NAME selection | Parcel selection control | no | empty-dict
width | Padding width for file name | no | 8
\endtable \endtable
\heading Output Options
\table
Property | Description | Required | Default
precision | The write precision | no | same as IOstream
directory | The output directory name | no | postProcessing/NAME
width | Padding width for file name | no | 8
writeControl | Output control | recommended | timeStep
\endtable
Note
See Foam::functionObjects::vtkCloud and Foam::Detail::parcelSelection
for more details about the parcel selection mechanism.
See also See also
Foam::Detail::parcelSelection
Foam::functionObjects::vtkCloud Foam::functionObjects::vtkCloud
Foam::functionObjects::fvMeshFunctionObject
Foam::functionObjects::timeControl
SourceFiles SourceFiles
dataCloud.C dataCloud.C
@ -67,6 +82,7 @@ SourceFiles
#define functionObjects_dataCloud_H #define functionObjects_dataCloud_H
#include "fvMeshFunctionObject.H" #include "fvMeshFunctionObject.H"
#include "parcelSelectionDetail.H"
#include "vectorField.H" #include "vectorField.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -82,13 +98,20 @@ namespace functionObjects
class dataCloud class dataCloud
: :
public fvMeshFunctionObject public fvMeshFunctionObject,
public Foam::Detail::parcelSelection
{ {
// Private data // Private data
//- The printf format for zero-padding names //- The printf format for zero-padding names
string printf_; string printf_;
//- The output precision
unsigned precision_;
//- Apply output filter (for the current cloud)
bool applyFilter_;
//- Requested names of clouds to process //- Requested names of clouds to process
wordRes selectClouds_; wordRes selectClouds_;
@ -101,12 +124,47 @@ class dataCloud
// Private Member Functions // Private Member Functions
//- Output (point,value) combination on a single line
template<class Type> template<class Type>
static void writeField static void writePointValue
(
Ostream& os,
const vector& pt,
const Type& val
);
template<class Type>
static void writeList
( (
Ostream& os, Ostream& os,
const vectorField& points, const vectorField& points,
const Field<Type>& field const List<Type>& field
);
template<class Type>
static void writeListParallel
(
Ostream& os,
const vectorField& points,
const List<Type>& field
);
template<class Type>
static void writeList
(
Ostream& os,
const vectorField& points,
const List<Type>& field,
const bitSet& selected
);
template<class Type>
static void writeListParallel
(
Ostream& os,
const vectorField& points,
const List<Type>& field,
const bitSet& selected
); );
//- Write to disk //- Write to disk

View File

@ -25,33 +25,141 @@ License
#include "IOField.H" #include "IOField.H"
#include "OFstream.H" #include "OFstream.H"
#include "ListOps.H"
#include "pointField.H" #include "pointField.H"
#include "vectorField.H" #include "vectorField.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class Type> template<class Type>
void Foam::functionObjects::dataCloud::writeField void Foam::functionObjects::dataCloud::writePointValue
(
Ostream& os,
const vector& pt,
const Type& val
)
{
os << pt.x() << ' ' << pt.y() << ' ' << pt.z();
for (direction cmpt=0; cmpt < pTraits<Type>::nComponents; ++cmpt)
{
os << ' ' << component(val, cmpt);
}
os << nl;
}
template<class Type>
void Foam::functionObjects::dataCloud::writeList
( (
Ostream& os, Ostream& os,
const vectorField& points, const vectorField& points,
const Field<Type>& field const List<Type>& field
) )
{ {
const label len = field.size(); const label len = field.size();
for (label pointi=0; pointi<len; ++pointi) for (label pointi=0; pointi<len; ++pointi)
{ {
const point& pt = points[pointi]; writePointValue(os, points[pointi], field[pointi]);
const Type& val = field[pointi]; }
}
os << pt.x() << ' ' << pt.y() << ' ' << pt.z();
for (direction cmpt=0; cmpt < pTraits<Type>::nComponents; ++cmpt) template<class Type>
void Foam::functionObjects::dataCloud::writeListParallel
(
Ostream& os,
const vectorField& points,
const List<Type>& field
)
{
if (Pstream::master())
{
writeList(os, points, field);
vectorField recvPoints;
Field<Type> recvField;
// Receive and write
for (int slave=1; slave<Pstream::nProcs(); ++slave)
{ {
os << ' ' << component(val, cmpt); IPstream fromSlave(Pstream::commsTypes::blocking, slave);
fromSlave >> recvPoints >> recvField;
writeList(os, recvPoints, recvField);
} }
os << nl; }
else
{
// Send to master
OPstream toMaster
(
Pstream::commsTypes::blocking,
Pstream::masterNo()
);
toMaster
<< points << field;
}
}
template<class Type>
void Foam::functionObjects::dataCloud::writeList
(
Ostream& os,
const vectorField& points,
const List<Type>& field,
const bitSet& selected
)
{
for (const label pointi : selected)
{
writePointValue(os, points[pointi], field[pointi]);
}
}
template<class Type>
void Foam::functionObjects::dataCloud::writeListParallel
(
Ostream& os,
const vectorField& points,
const List<Type>& field,
const bitSet& selected
)
{
if (Pstream::master())
{
writeList(os, points, field, selected);
vectorField recvPoints;
Field<Type> recvField;
// Receive and write
for (int slave=1; slave<Pstream::nProcs(); ++slave)
{
IPstream fromSlave(Pstream::commsTypes::blocking, slave);
fromSlave >> recvPoints >> recvField;
writeList(os, recvPoints, recvField);
}
}
else
{
// Send to master
OPstream toMaster
(
Pstream::commsTypes::blocking,
Pstream::masterNo()
);
toMaster
<< subset(selected, points)
<< subset(selected, field);
} }
} }
@ -63,16 +171,6 @@ bool Foam::functionObjects::dataCloud::writeField
const objectRegistry& obrTmp const objectRegistry& obrTmp
) const ) const
{ {
// Fields are not always on all processors (eg, multi-component parcels).
// Thus need to resolve between all processors.
const auto* fldPtr = obrTmp.findObject<IOField<Type>>(fieldName_);
if (!returnReduce((fldPtr != nullptr), orOp<bool>()))
{
return false;
}
const auto* pointsPtr = obrTmp.findObject<vectorField>("position"); const auto* pointsPtr = obrTmp.findObject<vectorField>("position");
if (!pointsPtr) if (!pointsPtr)
@ -81,46 +179,35 @@ bool Foam::functionObjects::dataCloud::writeField
return false; return false;
} }
// Fields are not always on all processors (eg, multi-component parcels).
// Thus need to resolve between all processors.
const List<Type>* fldPtr = obrTmp.findObject<IOField<Type>>(fieldName_);
const List<Type>& values = (fldPtr ? *fldPtr : List<Type>());
if (!returnReduce((fldPtr != nullptr), orOp<bool>()))
{
return false;
}
autoPtr<OFstream> osPtr;
if (Pstream::master()) if (Pstream::master())
{ {
OFstream os(outputName); osPtr.reset(new OFstream(outputName));
osPtr->precision(precision_);
os << "# x y z " << fieldName_ << nl; *(osPtr) << "# x y z " << fieldName_ << nl;
}
// Master
if (fldPtr)
{
writeField(os, *pointsPtr, *fldPtr);
}
// Slaves - recv if (applyFilter_)
for (int slave=1; slave<Pstream::nProcs(); ++slave) {
{ writeListParallel(osPtr.ref(), *pointsPtr, values, parcelAddr_);
IPstream fromSlave(Pstream::commsTypes::blocking, slave);
vectorField points(fromSlave);
Field<Type> fld(fromSlave);
writeField(os, points, fld);
}
} }
else else
{ {
// Slaves writeListParallel(osPtr.ref(), *pointsPtr, values);
OPstream toMaster(Pstream::commsTypes::blocking, Pstream::masterNo());
if (fldPtr)
{
toMaster
<< *pointsPtr
<< *fldPtr;
}
else
{
toMaster
<< vectorField()
<< Field<Type>();
}
} }
return true; return true;

View File

@ -1,5 +1,6 @@
// -*- C++ -*- // -*- C++ -*-
// Minimal example of using the dataCloud function object. // Minimal example of using the dataCloud function object.
dataCloud dataCloud
{ {
type dataCloud; type dataCloud;

View File

@ -53,6 +53,7 @@ maxDeltaT 1;
functions functions
{ {
#include "dataCloud"
#include "vtkCloud" #include "vtkCloud"
#include "vtkWrite" #include "vtkWrite"
} }

View File

@ -0,0 +1,42 @@
// -*- C++ -*-
dataCloud
{
type dataCloud;
libs ("liblagrangianFunctionObjects.so");
log true;
// Nothing happens before this anyhow
timeStart 0.5;
writeControl writeTime;
// cloud reactingCloud1;
clouds ( ".*" );
// Field to output
field d;
// Optional selection mechanism
selection
{
// Reduced number of output parcels
stride
{
action add;
source stride;
stride 4;
}
Umin
{
action subtract;
source field;
field U;
accept (less 0.2);
}
}
}
// ************************************************************************* //

View File

@ -28,6 +28,7 @@ cloudWrite
//- Output directory name - Default postProcessing //- Output directory name - Default postProcessing
// directory "VTK"; // directory "VTK";
// Optional selection mechanism
selection selection
{ {
all all