postProcessing: Replaced 'foamCalc' and the 'postCalc' utilities

with the more general and flexible 'postProcess' utility and '-postProcess' solver option

Rationale
---------

Both the 'postProcess' utility and '-postProcess' solver option use the
same extensive set of functionObjects available for data-processing
during the run avoiding the substantial code duplication necessary for
the 'foamCalc' and 'postCalc' utilities and simplifying maintenance.
Additionally consistency is guaranteed between solver data processing
and post-processing.

The functionObjects have been substantially re-written and generalized
to simplify development and encourage contribution.

Configuration
-------------

An extensive set of simple functionObject configuration files are
provided in

OpenFOAM-dev/etc/caseDicts/postProcessing

and more will be added in the future.  These can either be copied into
'<case>/system' directory and included into the 'controlDict.functions'
sub-dictionary or included directly from 'etc/caseDicts/postProcessing'
using the '#includeEtc' directive or the new and more convenient
'#includeFunc' directive which searches the
'<etc>/caseDicts/postProcessing' directories for the selected
functionObject, e.g.

functions
{
    #includeFunc Q
    #includeFunc Lambda2
}

'#includeFunc' first searches the '<case>/system' directory in case
there is a local configuration.

Description of #includeFunc
---------------------------

    Specify a functionObject dictionary file to include, expects the
    functionObject name to follow (without quotes).

    Search for functionObject dictionary file in
    user/group/shipped directories.
    The search scheme allows for version-specific and
    version-independent files using the following hierarchy:
    - \b user settings:
      - ~/.OpenFOAM/\<VERSION\>/caseDicts/postProcessing
      - ~/.OpenFOAM/caseDicts/postProcessing
    - \b group (site) settings (when $WM_PROJECT_SITE is set):
      - $WM_PROJECT_SITE/\<VERSION\>/caseDicts/postProcessing
      - $WM_PROJECT_SITE/caseDicts/postProcessing
    - \b group (site) settings (when $WM_PROJECT_SITE is not set):
      - $WM_PROJECT_INST_DIR/site/\<VERSION\>/caseDicts/postProcessing
      - $WM_PROJECT_INST_DIR/site/caseDicts/postProcessing
    - \b other (shipped) settings:
      - $WM_PROJECT_DIR/etc/caseDicts/postProcessing

    An example of the \c \#includeFunc directive:
    \verbatim
        #includeFunc <funcName>
    \endverbatim

postProcess
-----------

The 'postProcess' utility and '-postProcess' solver option provide the
same set of controls to execute functionObjects after the run either by
reading a specified set of fields to process in the case of
'postProcess' or by reading all fields and models required to start the
run in the case of '-postProcess' for each selected time:

postProcess -help

Usage: postProcess [OPTIONS]
options:
  -case <dir>       specify alternate case directory, default is the cwd
  -constant         include the 'constant/' dir in the times list
  -dict <file>      read control dictionary from specified location
  -field <name>     specify the name of the field to be processed, e.g. U
  -fields <list>    specify a list of fields to be processed, e.g. '(U T p)' -
                    regular expressions not currently supported
  -func <name>      specify the name of the functionObject to execute, e.g. Q
  -funcs <list>     specify the names of the functionObjects to execute, e.g.
                    '(Q div(U))'
  -latestTime       select the latest time
  -newTimes         select the new times
  -noFunctionObjects
                    do not execute functionObjects
  -noZero           exclude the '0/' dir from the times list, has precedence
                    over the -withZero option
  -parallel         run in parallel
  -region <name>    specify alternative mesh region
  -roots <(dir1 .. dirN)>
                    slave root directories for distributed running
  -time <ranges>    comma-separated time ranges - eg, ':10,20,40:70,1000:'
  -srcDoc           display source code in browser
  -doc              display application documentation in browser
  -help             print the usage

 pimpleFoam -postProcess -help

Usage: pimpleFoam [OPTIONS]
options:
  -case <dir>       specify alternate case directory, default is the cwd
  -constant         include the 'constant/' dir in the times list
  -dict <file>      read control dictionary from specified location
  -field <name>     specify the name of the field to be processed, e.g. U
  -fields <list>    specify a list of fields to be processed, e.g. '(U T p)' -
                    regular expressions not currently supported
  -func <name>      specify the name of the functionObject to execute, e.g. Q
  -funcs <list>     specify the names of the functionObjects to execute, e.g.
                    '(Q div(U))'
  -latestTime       select the latest time
  -newTimes         select the new times
  -noFunctionObjects
                    do not execute functionObjects
  -noZero           exclude the '0/' dir from the times list, has precedence
                    over the -withZero option
  -parallel         run in parallel
  -postProcess      Execute functionObjects only
  -region <name>    specify alternative mesh region
  -roots <(dir1 .. dirN)>
                    slave root directories for distributed running
  -time <ranges>    comma-separated time ranges - eg, ':10,20,40:70,1000:'
  -srcDoc           display source code in browser
  -doc              display application documentation in browser
  -help             print the usage

The functionObjects to execute may be specified on the command-line
using the '-func' option for a single functionObject or '-funcs' for a
list, e.g.

postProcess -func Q
postProcess -funcs '(div(U) div(phi))'

In the case of 'Q' the default field to process is 'U' which is
specified in and read from the configuration file but this may be
overridden thus:

postProcess -func 'Q(Ua)'

as is done in the example above to calculate the two forms of the divergence of
the velocity field.  Additional fields which the functionObjects may depend on
can be specified using the '-field' or '-fields' options.

The 'postProcess' utility can only be used to execute functionObjects which
process fields present in the time directories.  However, functionObjects which
depend on fields obtained from models, e.g. properties derived from turbulence
models can be executed using the '-postProcess' of the appropriate solver, e.g.

pisoFoam -postProcess -func PecletNo

or

sonicFoam -postProcess -func MachNo

In this case all required fields will have already been read so the '-field' or
'-fields' options are not be needed.

Henry G. Weller
CFD Direct Ltd.
This commit is contained in:
Henry Weller
2016-05-28 18:58:48 +01:00
parent 6f9573bb12
commit e4dc50dcb0
394 changed files with 1450 additions and 5384 deletions

View File

@ -0,0 +1,103 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: dev |
| \\ / A nd | Web: www.OpenFOAM.org |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object controlDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
application icoFoam;
startFrom startTime;
startTime 0;
stopAt endTime;
endTime 0.5;
deltaT 0.005;
writeControl timeStep;
writeInterval 20;
purgeWrite 0;
writeFormat ascii;
writePrecision 6;
writeCompression off;
timeFormat general;
timePrecision 6;
runTimeModifiable true;
functions
{
streamLines
{
type streamLine;
// Where to load it from (if not already in solver)
libs ("libfieldFunctionObjects.so");
// Output every
writeControl writeTime;
// writeInterval 10;
setFormat vtk; //gnuplot, raw etc. See sampleDict.
// Interpolation method. Default is cellPoint. See sampleDict.
//interpolationScheme pointMVC;
// Tracked forwards (+U) or backwards (-U)
trackForward true;
// Names of fields to sample. Should contain above velocity field!
fields (p U);
// Steps particles can travel before being removed
lifeTime 10000;
//- Specify either absolute length of steps (trackLength) or a number
// of subcycling steps per cell (nSubCycle)
// Size of single track segment [m]
//trackLength 1e-3;
// Number of steps per cell (estimate). Set to 1 to disable
// subcycling.
nSubCycle 5;
// Cloud name to use
cloudName particleTracks;
// Seeding method. See the sampleSets in sampleDict.
seedSampleSet uniform; //cloud;//triSurfaceMeshPointSet;
uniformCoeffs
{
type uniform;
axis x; //distance;
start (-0.0205 0.0001 0.00001);
end (-0.0205 0.0005 0.00001);
nPoints 100;
}
}
}
// ************************************************************************* //

View File

@ -0,0 +1,698 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ 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 "Pstream.H"
#include "functionObjectList.H"
#include "streamLine.H"
#include "fvMesh.H"
#include "streamLineParticleCloud.H"
#include "ReadFields.H"
#include "meshSearch.H"
#include "sampledSet.H"
#include "globalIndex.H"
#include "mapDistribute.H"
#include "interpolationCellPoint.H"
#include "PatchTools.H"
#include "mapPolyMesh.H"
#include "addToRunTimeSelectionTable.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
namespace functionObjects
{
defineTypeNameAndDebug(streamLine, 0);
addToRunTimeSelectionTable(functionObject, streamLine, dictionary);
}
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::autoPtr<Foam::indirectPrimitivePatch>
Foam::functionObjects::streamLine::wallPatch() const
{
const fvMesh& mesh = dynamic_cast<const fvMesh&>(obr_);
const polyBoundaryMesh& patches = mesh.boundaryMesh();
label nFaces = 0;
forAll(patches, patchi)
{
if (isA<wallPolyPatch>(patches[patchi]))
{
nFaces += patches[patchi].size();
}
}
labelList addressing(nFaces);
nFaces = 0;
forAll(patches, patchi)
{
if (isA<wallPolyPatch>(patches[patchi]))
{
const polyPatch& pp = patches[patchi];
forAll(pp, i)
{
addressing[nFaces++] = pp.start()+i;
}
}
}
return autoPtr<indirectPrimitivePatch>
(
new indirectPrimitivePatch
(
IndirectList<face>
(
mesh.faces(),
addressing
),
mesh.points()
)
);
}
void Foam::functionObjects::streamLine::track()
{
const fvMesh& mesh = dynamic_cast<const fvMesh&>(obr_);
IDLList<streamLineParticle> initialParticles;
streamLineParticleCloud particles
(
mesh,
cloudName_,
initialParticles
);
const sampledSet& seedPoints = sampledSetPtr_();
forAll(seedPoints, i)
{
particles.addParticle
(
new streamLineParticle
(
mesh,
seedPoints[i],
seedPoints.cells()[i],
lifeTime_
)
);
}
label nSeeds = returnReduce(particles.size(), sumOp<label>());
Info << " seeded " << nSeeds << " particles" << endl;
// Read or lookup fields
PtrList<volScalarField> vsFlds;
PtrList<interpolation<scalar>> vsInterp;
PtrList<volVectorField> vvFlds;
PtrList<interpolation<vector>> vvInterp;
label UIndex = -1;
label nScalar = 0;
label nVector = 0;
forAll(fields_, i)
{
if (mesh.foundObject<volScalarField>(fields_[i]))
{
nScalar++;
}
else if (mesh.foundObject<volVectorField>(fields_[i]))
{
nVector++;
}
else
{
FatalErrorInFunction
<< "Cannot find field " << fields_[i] << nl
<< "Valid scalar fields are:"
<< mesh.names(volScalarField::typeName) << nl
<< "Valid vector fields are:"
<< mesh.names(volVectorField::typeName)
<< exit(FatalError);
}
}
vsInterp.setSize(nScalar);
nScalar = 0;
vvInterp.setSize(nVector);
nVector = 0;
forAll(fields_, i)
{
if (mesh.foundObject<volScalarField>(fields_[i]))
{
const volScalarField& f = mesh.lookupObject<volScalarField>
(
fields_[i]
);
vsInterp.set
(
nScalar++,
interpolation<scalar>::New
(
interpolationScheme_,
f
)
);
}
else if (mesh.foundObject<volVectorField>(fields_[i]))
{
const volVectorField& f = mesh.lookupObject<volVectorField>
(
fields_[i]
);
if (f.name() == UName_)
{
UIndex = nVector;
}
vvInterp.set
(
nVector++,
interpolation<vector>::New
(
interpolationScheme_,
f
)
);
}
}
// Store the names
scalarNames_.setSize(vsInterp.size());
forAll(vsInterp, i)
{
scalarNames_[i] = vsInterp[i].psi().name();
}
vectorNames_.setSize(vvInterp.size());
forAll(vvInterp, i)
{
vectorNames_[i] = vvInterp[i].psi().name();
}
// Check that we know the index of U in the interpolators.
if (UIndex == -1)
{
FatalErrorInFunction
<< "Cannot find field to move particles with : " << UName_ << nl
<< "This field has to be present in the sampled fields " << fields_
<< " and in the objectRegistry."
<< exit(FatalError);
}
// Sampled data
// ~~~~~~~~~~~~
// Size to maximum expected sizes.
allTracks_.clear();
allTracks_.setCapacity(nSeeds);
allScalars_.setSize(vsInterp.size());
forAll(allScalars_, i)
{
allScalars_[i].clear();
allScalars_[i].setCapacity(nSeeds);
}
allVectors_.setSize(vvInterp.size());
forAll(allVectors_, i)
{
allVectors_[i].clear();
allVectors_[i].setCapacity(nSeeds);
}
// Additional particle info
streamLineParticle::trackingData td
(
particles,
vsInterp,
vvInterp,
UIndex, // index of U in vvInterp
trackForward_, // track in +u direction?
nSubCycle_, // automatic track control:step through cells in steps?
trackLength_, // fixed track length
allTracks_,
allScalars_,
allVectors_
);
// Set very large dt. Note: cannot use GREAT since 1/GREAT is SMALL
// which is a trigger value for the tracking...
const scalar trackTime = Foam::sqrt(GREAT);
// Track
particles.move(td, trackTime);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::functionObjects::streamLine::streamLine
(
const word& name,
const Time& runTime,
const dictionary& dict
)
:
functionObject(name),
obr_
(
runTime.lookupObject<objectRegistry>
(
dict.lookupOrDefault("region", polyMesh::defaultRegion)
)
),
dict_(dict),
nSubCycle_(0)
{
if (!isA<fvMesh>(obr_))
{
FatalErrorInFunction
<< "objectRegistry is not an fvMesh" << exit(FatalError);
}
read(dict_);
}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
Foam::functionObjects::streamLine::~streamLine()
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::functionObjects::streamLine::read(const dictionary& dict)
{
Info<< type() << " " << name() << ":" << nl;
dict.lookup("fields") >> fields_;
if (dict.found("U"))
{
dict.lookup("U") >> UName_;
}
else
{
UName_ = "U";
if (dict.found("U"))
{
IOWarningInFunction(dict)
<< "Using deprecated entry \"U\"."
<< " Please use \"UName\" instead."
<< endl;
dict.lookup("U") >> UName_;
}
}
if (findIndex(fields_, UName_) == -1)
{
FatalIOErrorInFunction(dict)
<< "Velocity field for tracking " << UName_
<< " should be present in the list of fields " << fields_
<< exit(FatalIOError);
}
dict.lookup("trackForward") >> trackForward_;
dict.lookup("lifeTime") >> lifeTime_;
if (lifeTime_ < 1)
{
FatalErrorInFunction
<< "Illegal value " << lifeTime_ << " for lifeTime"
<< exit(FatalError);
}
bool subCycling = dict.found("nSubCycle");
bool fixedLength = dict.found("trackLength");
if (subCycling && fixedLength)
{
FatalIOErrorInFunction(dict)
<< "Cannot both specify automatic time stepping (through '"
<< "nSubCycle' specification) and fixed track length (through '"
<< "trackLength')"
<< exit(FatalIOError);
}
nSubCycle_ = 1;
if (dict.readIfPresent("nSubCycle", nSubCycle_))
{
trackLength_ = VGREAT;
if (nSubCycle_ < 1)
{
nSubCycle_ = 1;
}
Info<< " automatic track length specified through"
<< " number of sub cycles : " << nSubCycle_ << nl << endl;
}
else
{
dict.lookup("trackLength") >> trackLength_;
Info<< " fixed track length specified : "
<< trackLength_ << nl << endl;
}
interpolationScheme_ = dict.lookupOrDefault
(
"interpolationScheme",
interpolationCellPoint<scalar>::typeName
);
cloudName_ = dict.lookupOrDefault<word>("cloudName", "streamLine");
dict.lookup("seedSampleSet") >> seedSet_;
const fvMesh& mesh = dynamic_cast<const fvMesh&>(obr_);
meshSearchPtr_.reset(new meshSearch(mesh));
const dictionary& coeffsDict = dict.subDict(seedSet_ + "Coeffs");
sampledSetPtr_ = sampledSet::New
(
seedSet_,
mesh,
meshSearchPtr_(),
coeffsDict
);
coeffsDict.lookup("axis") >> sampledSetAxis_;
scalarFormatterPtr_ = writer<scalar>::New(dict.lookup("setFormat"));
vectorFormatterPtr_ = writer<vector>::New(dict.lookup("setFormat"));
return true;
}
bool Foam::functionObjects::streamLine::execute(const bool postProcess)
{
return true;
}
bool Foam::functionObjects::streamLine::write(const bool postProcess)
{
Info<< type() << " " << name() << " output:" << nl;
const Time& runTime = obr_.time();
const fvMesh& mesh = dynamic_cast<const fvMesh&>(obr_);
// Do all injection and tracking
track();
if (Pstream::parRun())
{
// Append slave tracks to master ones
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
globalIndex globalTrackIDs(allTracks_.size());
// Construct a distribution map to pull all to the master.
labelListList sendMap(Pstream::nProcs());
labelListList recvMap(Pstream::nProcs());
if (Pstream::master())
{
// Master: receive all. My own first, then consecutive
// processors.
label trackI = 0;
forAll(recvMap, proci)
{
labelList& fromProc = recvMap[proci];
fromProc.setSize(globalTrackIDs.localSize(proci));
forAll(fromProc, i)
{
fromProc[i] = trackI++;
}
}
}
labelList& toMaster = sendMap[0];
toMaster.setSize(globalTrackIDs.localSize());
forAll(toMaster, i)
{
toMaster[i] = i;
}
const mapDistribute distMap
(
globalTrackIDs.size(),
sendMap.xfer(),
recvMap.xfer()
);
// Distribute the track positions. Note: use scheduled comms
// to prevent buffering.
mapDistributeBase::distribute
(
Pstream::scheduled,
distMap.schedule(),
distMap.constructSize(),
distMap.subMap(),
false,
distMap.constructMap(),
false,
allTracks_,
flipOp()
);
// Distribute the scalars
forAll(allScalars_, scalarI)
{
allScalars_[scalarI].shrink();
mapDistributeBase::distribute
(
Pstream::scheduled,
distMap.schedule(),
distMap.constructSize(),
distMap.subMap(),
false,
distMap.constructMap(),
false,
allScalars_[scalarI],
flipOp()
);
allScalars_[scalarI].setCapacity(allScalars_[scalarI].size());
}
// Distribute the vectors
forAll(allVectors_, vectorI)
{
allVectors_[vectorI].shrink();
mapDistributeBase::distribute
(
Pstream::scheduled,
distMap.schedule(),
distMap.constructSize(),
distMap.subMap(),
false,
distMap.constructMap(),
false,
allVectors_[vectorI],
flipOp()
);
allVectors_[vectorI].setCapacity(allVectors_[vectorI].size());
}
}
label n = 0;
forAll(allTracks_, trackI)
{
n += allTracks_[trackI].size();
}
Info<< " Tracks:" << allTracks_.size() << nl
<< " Total samples:" << n
<< endl;
// Massage into form suitable for writers
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
if (Pstream::master() && allTracks_.size())
{
// Make output directory
fileName vtkPath
(
Pstream::parRun()
? runTime.path()/".."/"postProcessing"/"sets"/name()
: runTime.path()/"postProcessing"/"sets"/name()
);
if (mesh.name() != fvMesh::defaultRegion)
{
vtkPath = vtkPath/mesh.name();
}
vtkPath = vtkPath/mesh.time().timeName();
mkDir(vtkPath);
// Convert track positions
PtrList<coordSet> tracks(allTracks_.size());
forAll(allTracks_, trackI)
{
tracks.set
(
trackI,
new coordSet
(
"track" + Foam::name(trackI),
sampledSetAxis_ //"xyz"
)
);
tracks[trackI].transfer(allTracks_[trackI]);
}
// Convert scalar values
if (allScalars_.size() > 0)
{
List<List<scalarField>> scalarValues(allScalars_.size());
forAll(allScalars_, scalarI)
{
DynamicList<scalarList>& allTrackVals =
allScalars_[scalarI];
scalarValues[scalarI].setSize(allTrackVals.size());
forAll(allTrackVals, trackI)
{
scalarList& trackVals = allTrackVals[trackI];
scalarValues[scalarI][trackI].transfer(trackVals);
}
}
fileName vtkFile
(
vtkPath
/ scalarFormatterPtr_().getFileName
(
tracks[0],
scalarNames_
)
);
Info<< " Writing data to " << vtkFile.path() << endl;
scalarFormatterPtr_().write
(
true, // writeTracks
tracks,
scalarNames_,
scalarValues,
OFstream(vtkFile)()
);
}
// Convert vector values
if (allVectors_.size() > 0)
{
List<List<vectorField>> vectorValues(allVectors_.size());
forAll(allVectors_, vectorI)
{
DynamicList<vectorList>& allTrackVals =
allVectors_[vectorI];
vectorValues[vectorI].setSize(allTrackVals.size());
forAll(allTrackVals, trackI)
{
vectorList& trackVals = allTrackVals[trackI];
vectorValues[vectorI][trackI].transfer(trackVals);
}
}
fileName vtkFile
(
vtkPath
/ vectorFormatterPtr_().getFileName
(
tracks[0],
vectorNames_
)
);
vectorFormatterPtr_().write
(
true, // writeTracks
tracks,
vectorNames_,
vectorValues,
OFstream(vtkFile)()
);
}
}
return true;
}
void Foam::functionObjects::streamLine::updateMesh(const mapPolyMesh& mpm)
{
const fvMesh& mesh_ = dynamic_cast<const fvMesh&>(obr_);
if (&mpm.mesh() == &mesh_)
{
read(dict_);
}
}
void Foam::functionObjects::streamLine::movePoints(const polyMesh& mesh)
{
const fvMesh& mesh_ = dynamic_cast<const fvMesh&>(obr_);
if (&mesh == &mesh_)
{
// Moving mesh affects the search tree
read(dict_);
}
}
// ************************************************************************* //

View File

@ -0,0 +1,268 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ 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::functionObjects::streamLine
Group
grpFieldFunctionObjects
Description
This function object generates streamline data by sampling a set of
user-specified fields along a particle track, transported by a
user-specified velocity field.
Example of function object specification:
\verbatim
streamLine1
{
type streamLine;
libs ("libfieldFunctionObjects.so");
...
setFormat vtk;
trackForward yes;
fields
(
U
p
);
lifeTime 10000;
trackLength 1e-3;
nSubCycle 5;
cloudName particleTracks;
seedSampleSet uniform;
uniformCoeffs
{
type uniform;
axis x; //distance;
start (-0.0205 0.0001 0.00001);
end (-0.0205 0.0005 0.00001);
nPoints 100;
}
}
\endverbatim
\heading Function object usage
\table
Property | Description | Required | Default value
type | Type name: streamLine | yes |
setFormat | Output data type | yes |
U | Tracking velocity field name | yes |
fields | Fields to sample | yes |
lifetime | Maximum number of particle tracking steps | yes |
trackLength | Tracking segment length | no |
nSubCycle | Number of tracking steps per cell | no|
cloudName | Cloud name to use | yes |
seedSampleSet| Seeding method (see below)| yes |
\endtable
\linebreak
Where \c seedSampleSet is typically one of
\plaintable
uniform | uniform particle seeding
cloud | cloud of points
triSurfaceMeshPointSet | points according to a tri-surface mesh
\endplaintable
Note
When specifying the track resolution, the \c trackLength OR \c nSubCycle
option should be used
SeeAlso
Foam::functionObject
Foam::functionObjects::timeControl
Foam::sampledSet
Foam::wallBoundedStreamLine
SourceFiles
streamLine.C
\*---------------------------------------------------------------------------*/
#ifndef functionObjects_streamLine_H
#define functionObjects_streamLine_H
#include "functionObject.H"
#include "volFieldsFwd.H"
#include "DynamicList.H"
#include "scalarList.H"
#include "vectorList.H"
#include "writer.H"
#include "indirectPrimitivePatch.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
// Forward declaration of classes
class objectRegistry;
class meshSearch;
class sampledSet;
namespace functionObjects
{
/*---------------------------------------------------------------------------*\
Class streamLine Declaration
\*---------------------------------------------------------------------------*/
class streamLine
:
public functionObject
{
// Private data
//- Database this class is registered to
const objectRegistry& obr_;
//- Input dictionary
dictionary dict_;
//- List of fields to sample
wordList fields_;
//- Field to transport particle with
word UName_;
//- Interpolation scheme to use
word interpolationScheme_;
//- Whether to use +u or -u
bool trackForward_;
//- Maximum lifetime (= number of cells) of particle
label lifeTime_;
//- Number of subcycling steps
label nSubCycle_;
//- Track length
scalar trackLength_;
//- Optional specified name of particles
word cloudName_;
//- Type of seed
word seedSet_;
//- Names of scalar fields
wordList scalarNames_;
//- Names of vector fields
wordList vectorNames_;
// Demand driven
//- Mesh searching enigne
autoPtr<meshSearch> meshSearchPtr_;
//- Seed set engine
autoPtr<sampledSet> sampledSetPtr_;
//- Axis of the sampled points to output
word sampledSetAxis_;
//- File writer for scalar data
autoPtr<writer<scalar>> scalarFormatterPtr_;
//- File writer for vector data
autoPtr<writer<vector>> vectorFormatterPtr_;
// Generated data
//- All tracks. Per particle the points it passed through
DynamicList<List<point>> allTracks_;
//- Per scalarField, per particle, the sampled value.
List<DynamicList<scalarList>> allScalars_;
//- Per scalarField, per particle, the sampled value.
List<DynamicList<vectorList>> allVectors_;
//- Construct patch out of all wall patch faces
autoPtr<indirectPrimitivePatch> wallPatch() const;
//- Do all seeding and tracking
void track();
//- Disallow default bitwise copy construct
streamLine(const streamLine&);
//- Disallow default bitwise assignment
void operator=(const streamLine&);
public:
//- Runtime type information
TypeName("streamLine");
// Constructors
//- Construct from Time and dictionary
streamLine
(
const word& name,
const Time& runTime,
const dictionary& dict
);
//- Destructor
virtual ~streamLine();
// Member Functions
//- Read the field average data
virtual bool read(const dictionary&);
//- Do nothing
virtual bool execute(const bool postProcess = false);
//- Calculate and write the steamlines
virtual bool write(const bool postProcess = false);
//- Update for changes of mesh
virtual void updateMesh(const mapPolyMesh&);
//- Update for mesh point-motion
virtual void movePoints(const polyMesh&);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace functionObjects
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,507 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ 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 "streamLineParticle.H"
#include "vectorFieldIOField.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
// defineParticleTypeNameAndDebug(streamLineParticle, 0);
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
Foam::scalar Foam::streamLineParticle::calcSubCycleDeltaT
(
trackingData& td,
const scalar dt,
const vector& U
) const
{
particle testParticle(*this);
bool oldKeepParticle = td.keepParticle;
bool oldSwitchProcessor = td.switchProcessor;
scalar fraction = testParticle.trackToFace(position()+dt*U, td);
td.keepParticle = oldKeepParticle;
td.switchProcessor = oldSwitchProcessor;
// Adapt the dt to subdivide the trajectory into substeps.
return dt*fraction/td.nSubCycle_;
}
Foam::vector Foam::streamLineParticle::interpolateFields
(
const trackingData& td,
const point& position,
const label celli,
const label facei
)
{
if (celli == -1)
{
FatalErrorInFunction
<< "Cell:" << celli << abort(FatalError);
}
sampledScalars_.setSize(td.vsInterp_.size());
forAll(td.vsInterp_, scalarI)
{
sampledScalars_[scalarI].append
(
td.vsInterp_[scalarI].interpolate
(
position,
celli,
facei
)
);
}
sampledVectors_.setSize(td.vvInterp_.size());
forAll(td.vvInterp_, vectorI)
{
sampledVectors_[vectorI].append
(
td.vvInterp_[vectorI].interpolate
(
position,
celli,
facei
)
);
}
const DynamicList<vector>& U = sampledVectors_[td.UIndex_];
return U.last();
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::streamLineParticle::streamLineParticle
(
const polyMesh& mesh,
const vector& position,
const label celli,
const label lifeTime
)
:
particle(mesh, position, celli),
lifeTime_(lifeTime)
{}
Foam::streamLineParticle::streamLineParticle
(
const polyMesh& mesh,
Istream& is,
bool readFields
)
:
particle(mesh, is, readFields)
{
if (readFields)
{
//if (is.format() == IOstream::ASCII)
List<scalarList> sampledScalars;
List<vectorList> sampledVectors;
is >> lifeTime_ >> sampledPositions_ >> sampledScalars
>> sampledVectors;
sampledScalars_.setSize(sampledScalars.size());
forAll(sampledScalars, i)
{
sampledScalars_[i].transfer(sampledScalars[i]);
}
sampledVectors_.setSize(sampledVectors.size());
forAll(sampledVectors, i)
{
sampledVectors_[i].transfer(sampledVectors[i]);
}
}
// Check state of Istream
is.check
(
"streamLineParticle::streamLineParticle"
"(const Cloud<streamLineParticle>&, Istream&, bool)"
);
}
Foam::streamLineParticle::streamLineParticle
(
const streamLineParticle& p
)
:
particle(p),
lifeTime_(p.lifeTime_),
sampledPositions_(p.sampledPositions_),
sampledScalars_(p.sampledScalars_)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
bool Foam::streamLineParticle::move
(
trackingData& td,
const scalar trackTime
)
{
streamLineParticle& p = static_cast<streamLineParticle&>(*this);
td.switchProcessor = false;
td.keepParticle = true;
scalar tEnd = (1.0 - stepFraction())*trackTime;
scalar maxDt = mesh_.bounds().mag();
while
(
td.keepParticle
&& !td.switchProcessor
&& lifeTime_ > 0
)
{
// set the lagrangian time-step
scalar dt = maxDt;
// Cross cell in steps:
// - at subiter 0 calculate dt to cross cell in nSubCycle steps
// - at the last subiter do all of the remaining track
for (label subIter = 0; subIter < td.nSubCycle_; subIter++)
{
--lifeTime_;
// Store current position and sampled velocity.
sampledPositions_.append(position());
vector U = interpolateFields(td, position(), cell(), face());
if (!td.trackForward_)
{
U = -U;
}
scalar magU = mag(U);
if (magU < SMALL)
{
// Stagnant particle. Might as well stop
lifeTime_ = 0;
break;
}
U /= magU;
if (td.trackLength_ < GREAT)
{
dt = td.trackLength_;
//Pout<< " subiteration " << subIter
// << " : fixed length: updated dt:" << dt << endl;
}
else if (subIter == 0 && td.nSubCycle_ > 1)
{
// Adapt dt to cross cell in a few steps
dt = calcSubCycleDeltaT(td, dt, U);
}
else if (subIter == td.nSubCycle_ - 1)
{
// Do full step on last subcycle
dt = maxDt;
}
scalar fraction = trackToFace(position() + dt*U, td);
dt *= fraction;
tEnd -= dt;
stepFraction() = 1.0 - tEnd/trackTime;
if (tEnd <= ROOTVSMALL)
{
// Force removal
lifeTime_ = 0;
}
if
(
face() != -1
|| !td.keepParticle
|| td.switchProcessor
|| lifeTime_ == 0
)
{
break;
}
}
}
if (!td.keepParticle || lifeTime_ == 0)
{
if (lifeTime_ == 0)
{
if (debug)
{
Pout<< "streamLineParticle : Removing stagnant particle:"
<< p.position()
<< " sampled positions:" << sampledPositions_.size()
<< endl;
}
td.keepParticle = false;
}
else
{
// Normal exit. Store last position and fields
sampledPositions_.append(position());
interpolateFields(td, position(), cell(), face());
if (debug)
{
Pout<< "streamLineParticle : Removing particle:"
<< p.position()
<< " sampled positions:" << sampledPositions_.size()
<< endl;
}
}
// Transfer particle data into trackingData.
//td.allPositions_.append(sampledPositions_);
td.allPositions_.append(vectorList());
vectorList& top = td.allPositions_.last();
top.transfer(sampledPositions_);
forAll(sampledScalars_, i)
{
//td.allScalars_[i].append(sampledScalars_[i]);
td.allScalars_[i].append(scalarList());
scalarList& top = td.allScalars_[i].last();
top.transfer(sampledScalars_[i]);
}
forAll(sampledVectors_, i)
{
//td.allVectors_[i].append(sampledVectors_[i]);
td.allVectors_[i].append(vectorList());
vectorList& top = td.allVectors_[i].last();
top.transfer(sampledVectors_[i]);
}
}
return td.keepParticle;
}
bool Foam::streamLineParticle::hitPatch
(
const polyPatch&,
trackingData& td,
const label patchi,
const scalar trackFraction,
const tetIndices& tetIs
)
{
// Disable generic patch interaction
return false;
}
void Foam::streamLineParticle::hitWedgePatch
(
const wedgePolyPatch& pp,
trackingData& td
)
{
// Remove particle
td.keepParticle = false;
}
void Foam::streamLineParticle::hitSymmetryPlanePatch
(
const symmetryPlanePolyPatch& pp,
trackingData& td
)
{
// Remove particle
td.keepParticle = false;
}
void Foam::streamLineParticle::hitSymmetryPatch
(
const symmetryPolyPatch& pp,
trackingData& td
)
{
// Remove particle
td.keepParticle = false;
}
void Foam::streamLineParticle::hitCyclicPatch
(
const cyclicPolyPatch& pp,
trackingData& td
)
{
// Remove particle
td.keepParticle = false;
}
void Foam::streamLineParticle::hitProcessorPatch
(
const processorPolyPatch&,
trackingData& td
)
{
// Switch particle
td.switchProcessor = true;
}
void Foam::streamLineParticle::hitWallPatch
(
const wallPolyPatch& wpp,
trackingData& td,
const tetIndices&
)
{
// Remove particle
td.keepParticle = false;
}
void Foam::streamLineParticle::hitPatch
(
const polyPatch& wpp,
trackingData& td
)
{
// Remove particle
td.keepParticle = false;
}
void Foam::streamLineParticle::readFields(Cloud<streamLineParticle>& c)
{
if (!c.size())
{
return;
}
particle::readFields(c);
IOField<label> lifeTime
(
c.fieldIOobject("lifeTime", IOobject::MUST_READ)
);
c.checkFieldIOobject(c, lifeTime);
vectorFieldIOField sampledPositions
(
c.fieldIOobject("sampledPositions", IOobject::MUST_READ)
);
c.checkFieldIOobject(c, sampledPositions);
// vectorFieldIOField sampleVelocity
// (
// c.fieldIOobject("sampleVelocity", IOobject::MUST_READ)
// );
// c.checkFieldIOobject(c, sampleVelocity);
label i = 0;
forAllIter(Cloud<streamLineParticle>, c, iter)
{
iter().lifeTime_ = lifeTime[i];
iter().sampledPositions_.transfer(sampledPositions[i]);
// iter().sampleVelocity_.transfer(sampleVelocity[i]);
i++;
}
}
void Foam::streamLineParticle::writeFields(const Cloud<streamLineParticle>& c)
{
particle::writeFields(c);
label np = c.size();
IOField<label> lifeTime
(
c.fieldIOobject("lifeTime", IOobject::NO_READ),
np
);
vectorFieldIOField sampledPositions
(
c.fieldIOobject("sampledPositions", IOobject::NO_READ),
np
);
// vectorFieldIOField sampleVelocity
// (
// c.fieldIOobject("sampleVelocity", IOobject::NO_READ),
// np
// );
label i = 0;
forAllConstIter(Cloud<streamLineParticle>, c, iter)
{
lifeTime[i] = iter().lifeTime_;
sampledPositions[i] = iter().sampledPositions_;
// sampleVelocity[i] = iter().sampleVelocity_;
i++;
}
lifeTime.write();
sampledPositions.write();
// sampleVelocity.write();
}
// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
Foam::Ostream& Foam::operator<<(Ostream& os, const streamLineParticle& p)
{
os << static_cast<const particle&>(p)
<< token::SPACE << p.lifeTime_
<< token::SPACE << p.sampledPositions_
<< token::SPACE << p.sampledScalars_
<< token::SPACE << p.sampledVectors_;
// Check state of Ostream
os.check("Ostream& operator<<(Ostream&, const streamLineParticle&)");
return os;
}
// ************************************************************************* //

View File

@ -0,0 +1,309 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ 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::streamLineParticle
Description
Particle class that samples fields as it passes through. Used in streamline
calculation.
SourceFiles
streamLineParticle.C
\*---------------------------------------------------------------------------*/
#ifndef streamLineParticle_H
#define streamLineParticle_H
#include "particle.H"
#include "autoPtr.H"
#include "interpolation.H"
#include "vectorList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
class streamLineParticleCloud;
/*---------------------------------------------------------------------------*\
Class streamLineParticle Declaration
\*---------------------------------------------------------------------------*/
class streamLineParticle
:
public particle
{
public:
//- Class used to pass tracking data to the trackToFace function
class trackingData
:
public particle::TrackingData<Cloud<streamLineParticle>>
{
public:
const PtrList<interpolation<scalar>>& vsInterp_;
const PtrList<interpolation<vector>>& vvInterp_;
const label UIndex_;
const bool trackForward_;
const label nSubCycle_;
const scalar trackLength_;
DynamicList<vectorList>& allPositions_;
List<DynamicList<scalarList>>& allScalars_;
List<DynamicList<vectorList>>& allVectors_;
// Constructors
trackingData
(
Cloud<streamLineParticle>& cloud,
const PtrList<interpolation<scalar>>& vsInterp,
const PtrList<interpolation<vector>>& vvInterp,
const label UIndex,
const bool trackForward,
const label nSubCycle,
const scalar trackLength,
DynamicList<List<point>>& allPositions,
List<DynamicList<scalarList>>& allScalars,
List<DynamicList<vectorList>>& allVectors
)
:
particle::TrackingData<Cloud<streamLineParticle>>(cloud),
vsInterp_(vsInterp),
vvInterp_(vvInterp),
UIndex_(UIndex),
trackForward_(trackForward),
nSubCycle_(nSubCycle),
trackLength_(trackLength),
allPositions_(allPositions),
allScalars_(allScalars),
allVectors_(allVectors)
{}
};
private:
// Private data
//- Lifetime of particle. Particle dies when reaches 0.
label lifeTime_;
//- Sampled positions
DynamicList<point> sampledPositions_;
//- Sampled scalars
List<DynamicList<scalar>> sampledScalars_;
//- Sampled vectors
List<DynamicList<vector>> sampledVectors_;
// Private Member Functions
//- Estimate dt to cross from current face to next one in nSubCycle
// steps.
scalar calcSubCycleDeltaT
(
trackingData& td,
const scalar dt,
const vector& U
) const;
void constrainVelocity
(
trackingData& td,
const scalar dt,
vector& U
);
//- Interpolate all quantities; return interpolated velocity.
vector interpolateFields
(
const trackingData&,
const point&,
const label celli,
const label facei
);
public:
// Constructors
//- Construct from components
streamLineParticle
(
const polyMesh& c,
const vector& position,
const label celli,
const label lifeTime
);
//- Construct from Istream
streamLineParticle
(
const polyMesh& c,
Istream& is,
bool readFields = true
);
//- Construct copy
streamLineParticle(const streamLineParticle& p);
//- Construct and return a clone
autoPtr<particle> clone() const
{
return autoPtr<particle>(new streamLineParticle(*this));
}
//- Factory class to read-construct particles used for
// parallel transfer
class iNew
{
const polyMesh& mesh_;
public:
iNew(const polyMesh& mesh)
:
mesh_(mesh)
{}
autoPtr<streamLineParticle> operator()(Istream& is) const
{
return autoPtr<streamLineParticle>
(
new streamLineParticle(mesh_, is, true)
);
}
};
// Member Functions
// Tracking
//- Track all particles to their end point
bool move(trackingData&, const scalar trackTime);
//- Overridable function to handle the particle hitting a patch
// Executed before other patch-hitting functions
bool hitPatch
(
const polyPatch&,
trackingData& td,
const label patchi,
const scalar trackFraction,
const tetIndices& tetIs
);
//- Overridable function to handle the particle hitting a wedge
void hitWedgePatch
(
const wedgePolyPatch&,
trackingData& td
);
//- Overridable function to handle the particle hitting a
// symmetry plane
void hitSymmetryPlanePatch
(
const symmetryPlanePolyPatch&,
trackingData& td
);
//- Overridable function to handle the particle hitting a
// symmetry patch
void hitSymmetryPatch
(
const symmetryPolyPatch&,
trackingData& td
);
//- Overridable function to handle the particle hitting a cyclic
void hitCyclicPatch
(
const cyclicPolyPatch&,
trackingData& td
);
//- Overridable function to handle the particle hitting a
//- processorPatch
void hitProcessorPatch
(
const processorPolyPatch&,
trackingData& td
);
//- Overridable function to handle the particle hitting a wallPatch
void hitWallPatch
(
const wallPolyPatch&,
trackingData& td,
const tetIndices&
);
//- Overridable function to handle the particle hitting a polyPatch
void hitPatch
(
const polyPatch&,
trackingData& td
);
// I-O
//- Read
static void readFields(Cloud<streamLineParticle>&);
//- Write
static void writeFields(const Cloud<streamLineParticle>&);
// Ostream Operator
friend Ostream& operator<<(Ostream&, const streamLineParticle&);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -0,0 +1,64 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ 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 "streamLineParticleCloud.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
namespace Foam
{
defineTemplateTypeNameAndDebug(Cloud<streamLineParticle>, 0);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::streamLineParticleCloud::streamLineParticleCloud
(
const polyMesh& mesh,
const word& cloudName,
bool readFields
)
:
Cloud<streamLineParticle>(mesh, cloudName, false)
{
if (readFields)
{
streamLineParticle::readFields(*this);
}
}
Foam::streamLineParticleCloud::streamLineParticleCloud
(
const polyMesh& mesh,
const word& cloudName,
const IDLList<streamLineParticle>& particles
)
:
Cloud<streamLineParticle>(mesh, cloudName, particles)
{}
// ************************************************************************* //

View File

@ -0,0 +1,96 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\/ 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::streamLineParticleCloud
Description
A Cloud of streamLine particles
SourceFiles
streamLineCloud.C
\*---------------------------------------------------------------------------*/
#ifndef streamLineCloud_H
#define streamLineCloud_H
#include "Cloud.H"
#include "streamLineParticle.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class streamLineCloud Declaration
\*---------------------------------------------------------------------------*/
class streamLineParticleCloud
:
public Cloud<streamLineParticle>
{
// Private Member Functions
//- Disallow default bitwise copy construct
streamLineParticleCloud(const streamLineParticleCloud&);
//- Disallow default bitwise assignment
void operator=(const streamLineParticleCloud&);
public:
//- Type of parcel the cloud was instantiated for
typedef streamLineParticle parcelType;
// Constructors
//- Construct given mesh
streamLineParticleCloud
(
const polyMesh&,
const word& cloudName = "defaultCloud",
bool readFields = true
);
//- Construct from mesh, cloud name, and a list of particles
streamLineParticleCloud
(
const polyMesh& mesh,
const word& cloudName,
const IDLList<streamLineParticle>& particles
);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //