Skip to content
Commits on Source (5)
  • Mark OLESEN's avatar
    STYLE: remove 'functions' dictionary scope from catalyst files · e8d1fe02
    Mark OLESEN authored
    - relocate to controlDict, since more than a single function object
      is often used.
    e8d1fe02
  • Mark OLESEN's avatar
    d8824950
  • Mark OLESEN's avatar
    ENH: disable SIGFPE handling in catalyst loop · 80667fc4
    Mark OLESEN authored
    - if sigFpe is enabled within OpenFOAM, any errors in the Catalyst
      pipeline will potentially kill the entire simulation.
    
    - use the new sigFpe::ignore helper class to manage a local disabling
      of SIGFPE handling.
    80667fc4
  • Mark OLESEN's avatar
    ENH: improve direct use of cmake (issue #5) · 5afad06e
    Mark OLESEN authored
    - allows cmake override of the default output library directory,
      which is normally $FOAM_LIBBIN
    
    ENH: additional debug verbosity
    
    - extra information (in parallel) when debug level > 1, which can help
      when isolating problems.
    5afad06e
  • Mark OLESEN's avatar
    ENH: overhaul of channel handling. Various bug fixes. (issue #6) · 16709019
    Mark OLESEN authored
    - 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')
    16709019
## What
## General Description
Library for [OpenFOAM] that provides a runtime-selectable
function object for embedding [ParaView Catalyst][Catalyst]
in-situ visualization into arbitrary OpenFOAM simulations.
Supports in-situ conversion of the following types:
- finite volume meshes and fields. Single or multi-region.
- finite area meshes and fields. Single region.
- lagrangian (clouds). Single or multiple clouds.
### Overset
For simulations with overset meshes, internal blanking is used to hide
the *holes* so that user visualization pipelines do not require any
thresholding workarounds. Note, however, that visualization artifices
may be present in multi-overlapping regions.
Library and function object for embedding ParaView Catalyst into OpenFOAM.
## Requirements
1. OpenFOAM.com development version (11-May-2018 or newer) or OpenFOAM-v1806.
2. ParaView or ParaView Catalyst 5.5 or newer, compiled with python support
(optionally with MPI support).
1. [OpenFOAM-v1806] or a recent [development version][OpenFOAM-git]
from [OpenFOAM.com][OpenFOAM].
2. [ParaView] or ParaView [Catalyst] 5.5 or newer,
compiled with python support (optionally with MPI support).
### Patching
It is **highly recommended** to patch the ParaView 5.5 sources to
include changes ([MR2433], [MR2436]) that will be part of the
ParaView 5.6 release.
These patches are necessary to ensure that the in-situ results are
placed in the correct output directory.
Without these patches, the results will always land in the current
working directory: not in the case-local `insitu` subdirectory
and ignoring the OpenFOAM `-case` parameter.
These [patches] will be automatically applied when the `makeParaView`
script from OpenFOAM ThirdParty is used.
## Building
It is highly recommended to patch the ParaView 5.5 sources (eg, using the
OpenFOAM ThirdParty makeParaView script) to ensure that they properly handle
outputting results in directories other than the main simulation directory:
Ensure that the OpenFOAM environment is active and that ParaView or Catalyst
can be found (Eg, the `ParaView_DIR` environment is properly set).
* [MR2433]
* [MR2436]
### With the OpenFOAM `wmake`
Simply use the supplied `Allwmake` script:
````
./Allwmake
````
This will install into `$FOAM_LIBBIN`
### With `cmake` directly
Without parameters, it installs to `$FOAM_LIBBIN` as the default output
location for the library.
````
mkdir build; cd build
cmake ../src/catalyst
````
which is identical to
````
mkdir build; cd build
cmake -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=default ../src/catalyst
````
To specifying an alternative library location, change the cmake parameter:
````
mkdir build; cd build
cmake -DCMAKE_LIBRARY_OUTPUT_DIRECTORY=/output/path/lib ../src/catalyst
````
The cmake configuration possibilities are functional, but still very
**rudimentary** at the moment.
## Authors
* Mark Olesen <Mark.Olesen@esi-group.com>
* Simone Bna <Simone.Bna@cineca.it>
- Mark Olesen | <Mark.Olesen@esi-group.com> | (ESI-OpenCFD)
- Simone Bna | <Simone.Bna@cineca.it> | (CINECA)
## License
Same terms as OpenFOAM.
Licensed under GNU General Public License <http://www.gnu.org/licenses/>.
Licensed under GNU General Public License <http://www.gnu.org/licenses/>
with the same terms as OpenFOAM itself.
----
[OpenFOAM]: https://www.openfoam.com
[OpenFOAM-v1806]: https://www.openfoam.com/releases/openfoam-v1806/
[OpenFOAM-git]: https://develop.openfoam.com/Development/OpenFOAM-plus
[patches]: https://develop.openfoam.com/Development/ThirdParty-plus/raw/develop/etc/patches/paraview-5.5.2
[ParaView]: https://www.paraview.org/
[Catalyst]: https://www.paraview.org/in-situ/
[MR2433]: https://gitlab.kitware.com/paraview/paraview/merge_requests/2433
[MR2436]: https://gitlab.kitware.com/paraview/paraview/merge_requests/2436
......@@ -56,12 +56,12 @@ else()
endif()
# Set output library destination to OpenFOAM library directory
set(LIBRARY_OUTPUT_PATH $ENV{FOAM_LIBBIN}
set(LIBRARY_OUTPUT_PATH ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
CACHE INTERNAL
""
)
file(GLOB SOURCE_FILES
catalystCoprocess.C
catalystTools.C
......@@ -85,12 +85,12 @@ file(GLOB SOURCE_FILES
set(OPENFOAM_LIBRARIES
OpenFOAM
Pstream
finiteArea
finiteVolume
fileFormats
conversion
Pstream
meshTools
conversion
lagrangian
overset
)
......
#------------------------------------------------------------------------------
cmake_minimum_required(VERSION 2.8)
# Fail immediately if not using an out-of-source build
if (CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
message(FATAL_ERROR
"In-source builds are not supported. Please create a build directory "
"separate from the source directory")
endif()
project(catalyst)
# Set policy for CMP0002 needed for cmake > 3
cmake_policy(SET CMP0002 OLD)
#------------------------------------------------------------------------------
# Simple sanity checks
if (NOT EXISTS "$ENV{WM_PROJECT_DIR}")
message(FATAL_ERROR "WM_PROJECT_DIR not set")
endif()
if (EXISTS "$ENV{ParaView_DIR}")
message("Building with Paraview from $ENV{ParaView_DIR}")
find_package(ParaView REQUIRED COMPONENTS vtkPVPythonCatalyst)
if (NOT PARAVIEW_USE_MPI)
message(WARNING "==== Recommended to build using ParaView Catalyst with MPI ====")
endif()
else()
message (FATAL_ERROR "ParaView_DIR not set")
message(FATAL_ERROR "ParaView_DIR not set")
endif()
include(CMakeLists-Common.txt)
#------------------------------------------------------------------------------
# Installation locations (not much)
# - default install into FOAM_LIBBIN
if ((NOT CMAKE_LIBRARY_OUTPUT_DIRECTORY) OR
("${CMAKE_LIBRARY_OUTPUT_DIRECTORY}" STREQUAL "default"))
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY $ENV{FOAM_LIBBIN})
endif()
#-----------------------------------------------------------------------------
# All messages
message("================")
message("Using OpenFOAM = $ENV{WM_PROJECT_DIR}")
message("Using ParaView = $ENV{ParaView_DIR}")
if (NOT PARAVIEW_USE_MPI)
message(WARNING "==== Recommended to build using ParaView Catalyst with MPI ====")
endif()
message("install libdir = ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}")
message("================")
#-----------------------------------------------------------------------------
include(CMakeLists-Common.txt)
#-----------------------------------------------------------------------------
......@@ -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:
......
// ParaView Catalyst function object for OpenFOAM (-*- C++ -*-)
functions
catalyst
{
catalyst
type catalyst;
libs ("libcatalystFoam.so");
executeControl timeStep;
writeControl none;
// ^^^^^
// #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"
"<etc>/caseDicts/insitu/catalyst/writeAll.py"
);
inputs
{
type catalyst;
libs ("libcatalystFoam.so");
executeControl timeStep;
writeControl none;
// fvMesh
region
{
type default;
// OR #includeEtc "caseDicts/insitu/catalyst/catalyst.cfg"
// All regions
regions (".*");
// mkdir "<case>/someDir";
// Emit boundary mesh/fields
boundary true;
scripts
(
// "<etc>/caseDicts/insitu/catalyst/printChannels.py"
"<etc>/caseDicts/insitu/catalyst/writeAll.py"
);
// Emit internal mesh/fields
internal true;
inputs
// Selected fields (words or regex)
fields (T U p);
}
// faMesh
area
{
// fvMesh
region
{
type default;
// All regions
regions (".*");
// Selected fields (words or regex)
fields (T U p);
}
// faMesh
area
{
type area;
// Selected fields (words or regex)
fields ( ".*" );
}
// lagrangian
cloud
{
type cloud;
// Selected clouds (words or regex)
clouds ( coalCloud1 limestoneCloud1 );
// Selected fields (words or regex)
fields ( T U p rho "Y.*" );
}
type area;
// Selected fields (words or regex)
fields ( ".*" );
}
// lagrangian
cloud
{
type cloud;
// Selected clouds (words or regex)
clouds ( coalCloud1 limestoneCloud1 );
// Selected fields (words or regex)
fields ( T U p rho "Y.*" );
}
}
}
......
......@@ -28,6 +28,7 @@ License
#include "stringOps.H"
#include "OSHA1stream.H"
#include "OSspecific.H"
#include "sigFpe.H"
#include "addToRunTimeSelectionTable.H"
#include <vtkCPDataDescription.h>
......@@ -79,6 +80,23 @@ Foam::label Foam::functionObjects::catalystFunctionObject::expand
}
}
const label nbad = (scripts.size() - nscript);
if (nbad)
{
Warning
<< nl
<< "Could not resolve " << nbad << " of " << scripts.size()
<< " catalyst scripts - check your input" << nl << nl;
}
if (!nscript)
{
Warning
<< nl
<< "No catalyst scripts resolved - check your input" << nl << nl;
}
scripts.resize(nscript);
return nscript;
......@@ -174,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
......@@ -199,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;
}
......@@ -232,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);
}
......@@ -245,13 +264,17 @@ bool Foam::functionObjects::catalystFunctionObject::read(const dictionary& dict)
bool Foam::functionObjects::catalystFunctionObject::execute()
{
// Enforce sanity for backends and adaptor
if (inputs_.empty())
{
return false;
}
// Disable any floating point trapping so that errors in
// Catalyst pipelines do not kill the simulation
// TODO: report that errors occurred?
sigFpe::ignore sigFpeHandling; //<- disable in local scope
if (!adaptor_.valid())
{
adaptor_.reset(new catalyst::coprocess());
......@@ -268,12 +291,24 @@ bool Foam::functionObjects::catalystFunctionObject::execute()
if (nChannels)
{
if (catalyst::coprocess::debug > 1)
{
Pout<< type() << ": query catalyst for " << nChannels
<< " channels" << nl;
}
nChannels = adaptor_().query(dataq);
}
if (catalyst::coprocess::debug)
if (catalyst::coprocess::debug > 1)
{
Info<< type() << ": expecting data for " << nChannels << nl;
Pout<< type() << ": query catalyst for " << nChannels
<< " channels" << nl;
}
else if (catalyst::coprocess::debug)
{
Info<< type() << ": expecting data for " << nChannels
<< " channels" << nl;
}
if (!nChannels)
......@@ -283,11 +318,22 @@ bool Foam::functionObjects::catalystFunctionObject::execute()
catalyst::outputChannels outputs;
if (catalyst::coprocess::debug > 1)
{
Pout<< type() << ": converting input" << nl;
}
for (auto& inp : inputs_)
{
inp.convert(dataq, outputs);
}
if (catalyst::coprocess::debug > 1)
{
Pout<< type() << ": sending data for " << outputs.size()
<< " outputs" << nl;
}
if (outputs.size())
{
Log << type() << ": send data" << nl;
......@@ -295,6 +341,19 @@ bool Foam::functionObjects::catalystFunctionObject::execute()
adaptor_().process(dataq, outputs);
}
if (catalyst::coprocess::debug > 1)
{
Pout<< type() << ": done step" << nl;
}
// 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
{
//- Catalyst channel names for query, in the order of addition
DynamicList<fileName> names_;
DynamicList<word> names_;
//- Fields per channel
HashTable<wordHashSet, fileName> fields_;
HashTable<wordHashSet> fields_;
//- Indices (into names_) of active channels
labelHashSet active_;
......@@ -156,22 +153,22 @@ public:
inline label size() const;
//- True if given channel exists (in fields or active)
inline bool found(const fileName& channel) const;
inline bool found(const word& channel) const;
//- The active channel numbers
inline List<label> active() const;
//- The channel names
inline List<fileName> names() const;
inline wordList names() const;
//- Fields for the given channel
inline const wordHashSet& fields(const fileName& channel) const;
inline const wordHashSet& fields(const word& channel) const;
//- Clear the specified channel
inline void clear(const fileName& channel);
inline void clear(const word& channel);
//- Set fields for the specified channel and make it active
void set(const fileName& channel, const wordHashSet& fields);
void set(const word& channel, const wordHashSet& fields);
//- Query coprocess, transform defined input channels to
//- known requests.
......@@ -186,11 +183,9 @@ public:
} // End namespace catalyst
// Ostream Operator
Ostream& operator<<(Ostream& os, const catalyst::timeQuery& when);
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
......
......@@ -51,10 +51,7 @@ inline Foam::label Foam::catalyst::dataQuery::size() const
}
inline bool Foam::catalyst::dataQuery::found
(
const fileName& channel
) const
inline bool Foam::catalyst::dataQuery::found(const word& channel) const
{
return fields_.found(channel);
}
......@@ -62,18 +59,20 @@ inline bool Foam::catalyst::dataQuery::found
inline Foam::List<Foam::label> Foam::catalyst::dataQuery::active() const
{
// The active indices
return active_.sortedToc();
}
inline Foam::List<Foam::fileName> Foam::catalyst::dataQuery::names() const
inline Foam::wordList Foam::catalyst::dataQuery::names() const
{
return List<fileName>(names_, active_.sortedToc());
// Subset of known names with the active indices
return wordList(names_, active_.sortedToc());
}
inline const Foam::wordHashSet&
Foam::catalyst::dataQuery::fields(const fileName& channel) const
Foam::catalyst::dataQuery::fields(const word& channel) const
{
const auto iter = fields_.cfind(channel);
if (iter.found())
......@@ -85,7 +84,7 @@ Foam::catalyst::dataQuery::fields(const fileName& channel) const
}
inline void Foam::catalyst::dataQuery::clear(const fileName& channel)
inline void Foam::catalyst::dataQuery::clear(const word& channel)
{
fields_.erase(channel);
active_.erase(names_.find(channel));
......
......@@ -47,7 +47,7 @@ namespace catalyst
cloud
);
}
}
} // End namespace Foam
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
......@@ -120,57 +120,43 @@ bool Foam::catalyst::cloudInput::convert
outputChannels& outputs
)
{
const fileName channelName(name());
const fvMesh& fvm = time_.lookupObject<fvMesh>(regionName_);
const wordList cloudNames(fvm.sortedNames<cloud>(selectClouds_));
if (cloudNames.empty())
if (cloudNames.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;
}
if (!nChannels)
{
return false; // skip - not requested
}
// Each cloud in a separate block.
// A separate block for each cloud
unsigned int blockNo = 0;
for (const word& cloudName : cloudNames)
{
auto dataset =
vtk::cloudAdaptor(fvm).getCloud(cloudName, selectFields_);
const fileName channel = 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
// Existing or new
vtkSmartPointer<vtkMultiBlockDataSet> block =
outputs.lookup
(
vtkCompositeDataSet::NAME(),
cloudName
channelName,
vtkSmartPointer<vtkMultiBlockDataSet>::New()
);
outputs.set(channel, block); // overwrites existing
}
block->SetBlock(blockNo, dataset);
block->GetMetaData(blockNo)->Set
(
vtkCompositeDataSet::NAME(),
cloudName // block name = cloud name
);
outputs.set(channelName, block); // overwrites existing
++blockNo;
}
......
......@@ -22,37 +22,49 @@ License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::catalystCloud
Foam::catalyst::cloudInput
Description
A Paraview Catalyst source for OpenFOAM clouds (lagrangian).
An input (source) for Paraview Catalyst from clouds (lagrangian).
The source comprises a single internal "cloud" channel,
which is a multi-block dataset (one block per cloud).
On output, the "cloud" sub-channel receives the name of the source.
Produces a multi-block dataset with one block per cloud with pieces
from each processor.
Example specification:
\verbatim
myCloud
someName
{
type cloud;
cloud NAME;
fields (U T rho);
type cloud;
cloud myCloud;
fields (U T rho);
}
\endverbatim
Usage
\table
Property | Description | Required | Default
type | cloud | yes |
region | | no | region0
cloud | | no | defaultCloud
clouds | wordRe list of clouds | no |
fields | wordRe list of fields | yes |
Property | Description | Required | Default
type | input type: \c cloud | yes |
region | name for a single region | no | region0
cloud | name for a single cloud | no | defaultCloud
clouds | wordRe list of clouds | no |
fields | wordRe list of fields | yes |
\endtable
The output block structure:
\verbatim
|-- cloud0
| |-- piece0
| |-- ...
| \-- pieceN
|-- ...
\-- cloudN
\-- ...
\endverbatim
Note
The channel name is that of the defining dictionary.
See also
Foam::catalyst::catalystInput
Foam::vtk::cloudAdaptor
SourceFiles
......