Commit 16709019 authored by Mark Olesen's avatar Mark Olesen

ENH: overhaul of channel handling. Various bug fixes. (issue #6)

- removed fvMesh sub-channels if favour of selector flags.
  To enable/disable portions of the geometry:

      internal    true/false
      boundary    true/false

  This replaces the previous method of sub-channels in which restrictions
  were propagated from the pipeline through.

  Before
  ======
      Function Object:

          input
          {
              fields    (U p);
          }

      Pipeline:
          input = coprocessor.CreateProducer(datadescription, 'input/patches')

  Now
  ===
      Function Object:

          input
          {
              internal  false;
              fields    (U p);
          }

      Pipeline:
          input = coprocessor.CreateProducer(datadescription, 'input')
parent 5afad06e
......@@ -47,7 +47,7 @@ namespace catalyst
area
);
}
}
} // End namespace Foam
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
......@@ -139,7 +139,7 @@ bool Foam::catalyst::faMeshInput::read(const dictionary& dict)
// Restrict to specified meshes
meshes_.filterKeys(selectAreas_);
dict.lookup("fields") >> selectFields_;
dict.read("fields", selectFields_);
return true;
}
......@@ -153,18 +153,18 @@ void Foam::catalyst::faMeshInput::update(polyMesh::readUpdateState state)
time_.lookupObject<objectRegistry>(regionName_);
// Be really paranoid and verify if the mesh actually exists
const wordList regionNames(backends_.toc());
const wordList areaNames(backends_.toc());
for (const word& regionName : regionNames)
for (const word& areaName : areaNames)
{
if (meshes_.found(regionName) && obr.found(regionName))
if (meshes_.found(areaName) && obr.found(areaName))
{
backends_[regionName]->updateState(state);
backends_[areaName]->updateState(state);
}
else
{
backends_.erase(regionName);
meshes_.erase(regionName);
backends_.erase(areaName);
meshes_.erase(areaName);
}
}
}
......@@ -186,7 +186,6 @@ Foam::label Foam::catalyst::faMeshInput::addChannels(dataQuery& dataq)
allFields += iter.object()->knownFields(selectFields_);
}
dataq.set(name(), allFields);
return 1;
......@@ -199,61 +198,41 @@ bool Foam::catalyst::faMeshInput::convert
outputChannels& outputs
)
{
const wordList regionNames(backends_.sortedToc());
const word channelName(name());
const wordList areaNames(backends_.sortedToc());
if (regionNames.empty())
if (areaNames.empty() || !dataq.found(channelName))
{
return false; // skip - not available
// Not available, or not requested
return false;
}
// Single channel only
label nChannels = 0;
if (dataq.found(name()))
{
++nChannels;
}
// A separate block for each area mesh
unsigned int blockNo = 0;
if (!nChannels)
for (const word& areaName : areaNames)
{
return false; // skip - not requested
}
auto dataset = backends_[areaName]->output(selectFields_);
// TODO: currently don't rely on the results from expecting much at all
// Existing or new
vtkSmartPointer<vtkMultiBlockDataSet> block =
outputs.lookup
(
channelName,
vtkSmartPointer<vtkMultiBlockDataSet>::New()
);
// Each region in a separate block
unsigned int blockNo = 0;
for (const word& regionName : regionNames)
{
auto dataset =
backends_[regionName]->output(selectFields_);
block->SetBlock(blockNo, dataset);
{
const fileName channel = name();
block->GetMetaData(blockNo)->Set
(
vtkCompositeDataSet::NAME(),
areaName // block name = area mesh name
);
if (dataq.found(channel))
{
// Get existing or new
vtkSmartPointer<vtkMultiBlockDataSet> block =
outputs.lookup
(
channel,
vtkSmartPointer<vtkMultiBlockDataSet>::New()
);
block->SetBlock(blockNo, dataset);
block->GetMetaData(blockNo)->Set
(
vtkCompositeDataSet::NAME(),
regionName
);
outputs.set(channel, block); // overwrites existing
}
}
outputs.set(channelName, block); // overwrites existing
++blockNo;
}
......
......@@ -25,15 +25,14 @@ Class
Foam::catalyst::faMeshInput
Description
A Paraview Catalyst source for OpenFOAM faMesh regions.
An input (source) for Paraview Catalyst from faMesh regions.
The source comprises a single internal "input" channel,
which is a multi-block dataset (one block per area mesh).
On output, the "input" sub-channel receives the name of the source.
Produces a multi-block dataset with one block per area mesh with pieces
from each processor.
Example specification:
\verbatim
myArea
someName
{
type area;
fields (U p);
......@@ -42,15 +41,29 @@ Description
Usage
\table
Property | Description | Required | Default
type | area | yes |
region | | no | region0
regions | wordRe list of regions | no |
fields | wordRe list of fields | yes |
Property | Description | Required | Default
type | input type: \c area | yes |
region | name for a single region | no | region0
area | select a single area | no |
areas | wordRe list of multiple areas | no |
fields | wordRe list of fields | yes |
\endtable
The output block structure:
\verbatim
|-- area0
| |-- piece0
| |-- ...
| \-- pieceN
|-- ...
\-- areaN
\-- ...
\endverbatim
Note
The channel name is that of the defining dictionary.
See also
Foam::catalyst::catalystInput
Foam::vtk::faMeshAdaptor
SourceFiles
......@@ -75,7 +88,7 @@ namespace catalyst
{
/*---------------------------------------------------------------------------*\
Class catalyst::faMeshInput Declaration
Class catalyst::faMeshInput Declaration
\*---------------------------------------------------------------------------*/
class faMeshInput
......
......@@ -44,7 +44,7 @@ namespace vtk
{
defineTypeNameAndDebug(faMeshAdaptor, 0);
}
}
} // End namespace Foam
const Foam::word Foam::vtk::faMeshAdaptor::internalName("internal");
......
......@@ -42,9 +42,6 @@ SourceFiles
#define foamVtkFaMeshAdaptor_H
#include "className.H"
#include "fileName.H"
#include "stringList.H"
#include "wordList.H"
#include "polyMesh.H"
#include "areaFieldsFwd.H"
#include "foamVtkTools.H"
......
......@@ -34,7 +34,7 @@ License
// Templates (only needed here)
#include "foamVtkFaMeshAdaptorFieldTemplates.C"
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
{
......@@ -53,8 +53,10 @@ static wordHashSet supportedTypes()
return types;
}
} // end of Foam
} // End namespace Foam
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::wordHashSet Foam::vtk::faMeshAdaptor::knownFields
(
......
......@@ -44,7 +44,7 @@ namespace catalyst
{
defineTypeNameAndDebug(coprocess, 0);
}
}
} // End namespace Foam
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
......@@ -53,7 +53,7 @@ template<class DataType>
bool Foam::catalyst::coprocess::processImpl
(
const dataQuery& dataq,
HashTable<vtkSmartPointer<DataType>, fileName>& outputs
HashTable<vtkSmartPointer<DataType>>& outputs
)
{
auto* descrip = dataq.description();
......@@ -63,7 +63,7 @@ bool Foam::catalyst::coprocess::processImpl
return false;
}
for (const fileName& channel : dataq.names())
for (const word& channel : dataq.names())
{
if (outputs.found(channel))
{
......
......@@ -68,7 +68,7 @@ private:
bool processImpl
(
const dataQuery& dataq,
HashTable<vtkSmartPointer<DataType>, fileName>& outputs
HashTable<vtkSmartPointer<DataType>>& outputs
);
public:
......
......@@ -11,9 +11,12 @@ catalyst
// ^^^^^
// #includeEtc "caseDicts/insitu/catalyst/catalyst.cfg"
// Optional directory creation command
// mkdir "<case>/someDir";
// Default output-directory
// outputDir "<case>/insitu";
scripts
(
// "<etc>/caseDicts/insitu/catalyst/printChannels.py"
......@@ -30,6 +33,12 @@ catalyst
// All regions
regions (".*");
// Emit boundary mesh/fields
boundary true;
// Emit internal mesh/fields
internal true;
// Selected fields (words or regex)
fields (T U p);
}
......
......@@ -192,7 +192,7 @@ bool Foam::functionObjects::catalystFunctionObject::read(const dictionary& dict)
Foam::mkDir(outputDir_);
}
dict.lookup("scripts") >> scripts_; // Python scripts
dict.read("scripts", scripts_); // Python scripts
expand(scripts_, dict); // Expand and check availability
......@@ -217,17 +217,18 @@ bool Foam::functionObjects::catalystFunctionObject::read(const dictionary& dict)
continue;
}
newList.set
(
nInputs,
auto input =
catalyst::catalystInput::New
(
word(iter().keyword()),
time_,
*subDictPtr
).ptr()
);
);
// We may wish to perform additional validity or sanity checks on
// the input before deciding to add it to the list.
newList.set(nInputs, input);
++nInputs;
}
......@@ -250,7 +251,7 @@ bool Foam::functionObjects::catalystFunctionObject::read(const dictionary& dict)
nInputs = 0;
for (const auto& inp : inputs_)
{
if (nInputs++) Info << nl;
if (nInputs++) Info<< nl;
inp.print(Info);
}
......@@ -263,8 +264,6 @@ bool Foam::functionObjects::catalystFunctionObject::read(const dictionary& dict)
bool Foam::functionObjects::catalystFunctionObject::execute()
{
// Enforce sanity for backends and adaptor
if (inputs_.empty())
{
return false;
......@@ -331,7 +330,7 @@ bool Foam::functionObjects::catalystFunctionObject::execute()
if (catalyst::coprocess::debug > 1)
{
Pout<< type() << ": sending data for" << outputs.size()
Pout<< type() << ": sending data for " << outputs.size()
<< " outputs" << nl;
}
......@@ -349,8 +348,10 @@ bool Foam::functionObjects::catalystFunctionObject::execute()
}
// Avoid compiler complaint about unused variable.
// - manually restore old SIGFPE state
// Instead of relying on the destructor, manually restore the previous
// SIGFPE state.
// This is only to avoid compiler complaints about unused variables.
sigFpeHandling.restore();
return true;
......
......@@ -28,10 +28,7 @@ Group
grpUtilitiesFunctionObjects
Description
A Paraview Catalyst adaptor for OpenFOAM fvMesh regions.
The output comprises up to three channels ("input", "mesh", "patches"),
each of which is a multi-block dataset.
A Paraview Catalyst adaptor for OpenFOAM.
Example of function object specification:
\verbatim
......@@ -39,30 +36,42 @@ Description
{
type catalyst;
libs ("libcatalystFoam.so");
scripts ( ... );
executeControl timeStep;
executeInterval 1;
scripts ( ... );
inputs
{
type default;
regions ( ".*Solid" )
fields (U p);
input1
{
type default;
regions (".*solid" );
fields (U p);
}
input2
{
type cloud;
cloud someCloud;
fields ( T U p rho );
}
}
}
\endverbatim
Usage
\table
Property | Description | Required | Default
type | catalyst | yes |
log | report extra information | no | false
mkdir | initial directory to create | no |
scripts | Python pipeline scripts | yes |
Property | Description | Required | Default
type | catalyst | yes |
log | report extra information | no | false
scripts | Python pipeline scripts | yes |
inputs | dictionary of catalyst inputs | yes |
outputDir | the output directory | no | "\<case\>/insitu"
mkdir | optional directory to create | no |
\endtable
Note
The execution frequency can be defined by the functionObject and
The execution frequency can be defined by both the functionObject and
by the Catalyst pipeline.
See also
......@@ -121,7 +130,7 @@ class catalystFunctionObject
//- The catalyst coprocess
autoPtr<catalyst::coprocess> adaptor_;
//- Pointers to the requested mesh regions
//- Pointers to the requested catalyst inputs
PtrList<catalyst::catalystInput> inputs_;
......@@ -133,6 +142,7 @@ class catalystFunctionObject
//- No copy assignment
void operator=(const catalystFunctionObject&) = delete;
public:
// Static Methods
......
......@@ -37,7 +37,7 @@ namespace catalyst
defineTypeNameAndDebug(catalystInput, 0);
defineRunTimeSelectionTable(catalystInput, dictionary);
}
}
} // End namespace Foam
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
......@@ -58,16 +58,15 @@ Foam::catalyst::catalystInput::New
const dictionary& dict
)
{
const word sourceType = dict.lookupOrDefault<word>("type", "default");
const word modelType(dict.lookupOrDefault<word>("type", "default"));
auto cstrIter = dictionaryConstructorTablePtr_->cfind(sourceType);
auto cstrIter = dictionaryConstructorTablePtr_->cfind(modelType);
if (!cstrIter.found())
{
FatalErrorInFunction
<< "Unknown catalystInput "
<< sourceType << nl << nl
<< "Valid sources : " << endl
<< "Unknown catalystInput " << modelType << nl << nl
<< "Valid inputs:" << endl
<< dictionaryConstructorTablePtr_->sortedToc()
<< exit(FatalError);
}
......
......@@ -22,10 +22,10 @@ License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::catalystInput
Foam::catalyst::catalystInput
Description
An OpenFOAM source for Paraview Catalyst.
An abstract input (source) for Paraview Catalyst.
See also
Foam::catalyst::coprocess
......@@ -42,8 +42,8 @@ SourceFiles
#include "className.H"
#include "polyMesh.H"
#include "runTimeSelectionTables.H"
#include "catalystTools.H"
#include "runTimeSelectionTables.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
......@@ -66,7 +66,7 @@ class catalystInput
{
// Private data
//- The name of the source
//- The Catalyst input channel name
word name_;
public:
......@@ -89,7 +89,7 @@ public:
// Selectors
//- Return a reference to the selected source
//- Return a reference to the selected input
static autoPtr<catalystInput> New
(
const word& name,
......@@ -104,7 +104,7 @@ public:
// Constructors
//- Construct with given channel name
//- Construct with given Catalyst input channel name
explicit catalystInput(const word& channel);
......@@ -114,7 +114,7 @@ public:
// Member Functions
//- The name of the source (channel)
//- The name of the Catalyst input channel
virtual const word& name() const
{
return name_;
......
......@@ -93,7 +93,7 @@ Foam::catalyst::dataQuery::~dataQuery()
void Foam::catalyst::dataQuery::set
(
const fileName& channel,
const word& channel,
const wordHashSet& fields
)
{
......@@ -134,23 +134,23 @@ Foam::label Foam::catalyst::dataQuery::query(vtkCPProcessor* coproc)
descrip->SetTimeData(dataq.timeValue, dataq.timeIndex);
descrip->SetForceOutput(dataq.forced);
const List<fileName> inputNames(dataq.names());
const wordList inputNames(dataq.names());
// Sort out which channels already exist, are new, or disappeared
// The currently defined channels
HashSet<fileName> currChannels;
wordHashSet currChannels;
const unsigned n = descrip->GetNumberOfInputDescriptions();
for (unsigned i=0; i < n; ++i)
{
currChannels.insert
(
fileName::validate(descrip->GetInputDescriptionName(i))
word::validate(descrip->GetInputDescriptionName(i))
);
}
HashSet<fileName> oldChannels(currChannels);
wordHashSet oldChannels(currChannels);
oldChannels.erase(inputNames);
if (oldChannels.size())
......@@ -165,7 +165,7 @@ Foam::label Foam::catalyst::dataQuery::query(vtkCPProcessor* coproc)
// Note: this misses updating field information for previously
// existing inputs.
for (const fileName& channel : inputNames)
for (const word& channel : inputNames)
{
if (currChannels.found(channel))
{
......@@ -173,8 +173,7 @@ Foam::label Foam::catalyst::dataQuery::query(vtkCPProcessor* coproc)
}
descrip->AddInput(channel.c_str());
auto* input =
descrip->GetInputDescriptionByName(channel.c_str());
auto* input = descrip->GetInputDescriptionByName(channel.c_str());
for (const word& fieldName : dataq.fields(channel))
{
......@@ -193,7 +192,7 @@ Foam::label Foam::catalyst::dataQuery::query(vtkCPProcessor* coproc)
return dataq.size();
}
for (const fileName& channel : inputNames)
for (const word& channel : inputNames)
{
auto* input = descrip->GetInputDescriptionByName(channel.c_str());
......
......@@ -25,7 +25,7 @@ Class
Foam::catalyst::timeQuery
Description
Low-level handling for time queries
Low-level handling for Catalyst time queries
SourceFiles
catalystTools.C
......@@ -36,7 +36,6 @@ SourceFiles
#define functionObjects_catalystTools_H
#include "wordList.H"
#include "stringList.H"
#include "DynamicList.H"
#include "HashSet.H"
......@@ -61,9 +60,7 @@ namespace catalyst
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//- Container holding VTK outputs per Catalyst channel name
typedef
HashTable<vtkSmartPointer<vtkMultiBlockDataSet>, fileName>
outputChannels;
typedef HashTable<vtkSmartPointer<vtkMultiBlockDataSet>> outputChannels;
//- Print information about data description
......@@ -74,7 +71,7 @@ void printInfo(Ostream& os, vtkCPDataDescription* descrip);
Class catalyst::timeQuery Declaration
\*---------------------------------------------------------------------------*/
//- Simple structure for time queries
//- Simple structure for Catalyst time queries
struct timeQuery
{
double timeValue;
......@@ -101,16 +98,16 @@ struct timeQuery
Class catalyst::dataQuery Declaration
\*---------------------------------------------------------------------------*/
//- Simple structure for data description queries
//- Simple structure for Catalyst data description queries
class dataQuery
:
public timeQuery