diff --git a/README b/README deleted file mode 100644 index 0e8a7211e1eb317758e52d65a7cb9db00ebdaff3..0000000000000000000000000000000000000000 --- a/README +++ /dev/null @@ -1,22 +0,0 @@ -What: - - Library and function object for embedding the ParaView Catalyst - into OpenFOAM. - -Requirements: - - OpenFOAM.com development version (April-2018 or newer) or OpenFOAM-v1806. - - ParaView or ParaView Catalyst 5.4 or newer, compiled with mpi and - python support. - -Authors: - - Mark Olesen <Mark.Olesen@esi-group.com> - Simone Bna <Simone.Bna@cineca.it> - -License: - - Same terms as OpenFOAM. - Licensed under GNU General Public License <http://www.gnu.org/licenses/>. - diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..7b8b247110b33f97dd591c1f1ce36b255ef10799 --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ +## What + +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 mpi and +python support. + +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: + +* [MR2433] +* [MR2436] + + +## Authors + +* Mark Olesen <Mark.Olesen@esi-group.com> +* Simone Bna <Simone.Bna@cineca.it> + + +## License + +Same terms as OpenFOAM. +Licensed under GNU General Public License <http://www.gnu.org/licenses/>. + + +[MR2433]: https://gitlab.kitware.com/paraview/paraview/merge_requests/2433 +[MR2436]: https://gitlab.kitware.com/paraview/paraview/merge_requests/2436 + diff --git a/etc/allinputsgridwriter.py b/etc/allinputsgridwriter.py index fcd0c77826cb0365547fd59f5b842ac3d42bc9d6..46354d9aff453b4d807529d71f13919dc324de49 100644 --- a/etc/allinputsgridwriter.py +++ b/etc/allinputsgridwriter.py @@ -10,7 +10,6 @@ def CreateCoProcessor(): def _CreatePipeline(coprocessor, datadescription): class Pipeline: for i in range(datadescription.GetNumberOfInputDescriptions()): - inputdescription = datadescription.GetInputDescription(i) name = datadescription.GetInputDescriptionName(i) adaptorinput = coprocessor.CreateProducer(datadescription, name) grid = adaptorinput.GetClientSideObject().GetOutputDataObject(0) diff --git a/etc/area.cfg b/etc/area.cfg deleted file mode 100644 index 2f6850f99531553441118e215c8bd3eca5c86142..0000000000000000000000000000000000000000 --- a/etc/area.cfg +++ /dev/null @@ -1,16 +0,0 @@ -/*--------------------------------*- C++ -*----------------------------------*\ -| ========= | | -| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | -| \\ / O peration | Version: plus | -| \\ / A nd | Web: www.OpenFOAM.com | -| \\/ M anipulation | | -\*---------------------------------------------------------------------------*/ -// Insitu processing of finiteArea fields with ParaView Catalyst - -type catalyst::area; -libs ("libcatalystFoam.so"); - -executeControl timeStep; -writeControl none; - -// ************************************************************************* // diff --git a/etc/cloud.cfg b/etc/cloud.cfg deleted file mode 100644 index d860e901a9003aa5716b796653b2c0e9ae1e19f1..0000000000000000000000000000000000000000 --- a/etc/cloud.cfg +++ /dev/null @@ -1,16 +0,0 @@ -/*--------------------------------*- C++ -*----------------------------------*\ -| ========= | | -| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | -| \\ / O peration | Version: plus | -| \\ / A nd | Web: www.OpenFOAM.com | -| \\/ M anipulation | | -\*---------------------------------------------------------------------------*/ -// Insitu processing of lagrangian clouds with ParaView Catalyst - -type catalyst::cloud; -libs ("libcatalystFoam.so"); - -executeControl timeStep; -writeControl none; - -// ************************************************************************* // diff --git a/etc/default.cfg b/etc/default.cfg deleted file mode 100644 index e9ace6b706c1c55b456b01faf4a564c82d13bce9..0000000000000000000000000000000000000000 --- a/etc/default.cfg +++ /dev/null @@ -1,16 +0,0 @@ -/*--------------------------------*- C++ -*----------------------------------*\ -| ========= | | -| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | -| \\ / O peration | Version: plus | -| \\ / A nd | Web: www.OpenFOAM.com | -| \\/ M anipulation | | -\*---------------------------------------------------------------------------*/ -// Insitu processing of finiteVolume fields with ParaView Catalyst - -type catalyst; -libs ("libcatalystFoam.so"); - -executeControl timeStep; -writeControl none; - -// ************************************************************************* // diff --git a/etc/printChannels.py b/etc/printChannels.py deleted file mode 100644 index 8fcb4472e7cf15c9e3db16f474c7a6fea2a80892..0000000000000000000000000000000000000000 --- a/etc/printChannels.py +++ /dev/null @@ -1,66 +0,0 @@ -from paraview.simple import * -from paraview import coprocessing - -# The frequency to output everything -outputfrequency = 1 - -# ----------------------- CoProcessor definition ----------------------- - -def CreateCoProcessor(): - def _CreatePipeline(coprocessor, datadescription): - class Pipeline: - for i in range(datadescription.GetNumberOfInputDescriptions()): - name = datadescription.GetInputDescriptionName(i) - adaptorinput = coprocessor.CreateProducer(datadescription, name) - grid = adaptorinput.GetClientSideObject().GetOutputDataObject(0) - print "Channel <" + name + "> is a ", grid.GetClassName() - - return Pipeline() - - class CoProcessor(coprocessing.CoProcessor): - def CreatePipeline(self, datadescription): - self.Pipeline = _CreatePipeline(self, datadescription) - - return CoProcessor() - -#-------------------------------------------------------------- -# Global variables that will hold the pipeline for each timestep -# Creating the CoProcessor object, doesn't actually create the ParaView pipeline. -# It will be automatically setup when coprocessor.UpdateProducers() is called the -# first time. -coprocessor = CreateCoProcessor() - -#-------------------------------------------------------------- -# Enable Live-Visualizaton with ParaView -coprocessor.EnableLiveVisualization(False) - - -# ---------------------- Data Selection method ---------------------- - -def RequestDataDescription(datadescription): - "Callback to populate the request for current timestep" - global coprocessor - if datadescription.GetForceOutput() == True or datadescription.GetTimeStep() % outputfrequency == 0: - # We are just going to request all fields and meshes from the simulation - # code/adaptor. - for i in range(datadescription.GetNumberOfInputDescriptions()): - datadescription.GetInputDescription(i).AllFieldsOn() - datadescription.GetInputDescription(i).GenerateMeshOn() - return - - # setup requests for all inputs based on the requirements of the - # pipeline. - coprocessor.LoadRequestedData(datadescription) - -# ------------------------ Processing method ------------------------ - -def DoCoProcessing(datadescription): - "Callback to do co-processing for current timestep" - global coprocessor - - # Update the coprocessor by providing it the newly generated simulation data. - # If the pipeline hasn't been setup yet, this will setup the pipeline. - coprocessor.UpdateProducers(datadescription) - - # Write output data, if appropriate. - coprocessor.WriteData(datadescription); diff --git a/etc/writeArea.py b/etc/writeArea.py deleted file mode 100644 index 1911a9da9fc2d9cd404cbe5cb0fdb9cff5290295..0000000000000000000000000000000000000000 --- a/etc/writeArea.py +++ /dev/null @@ -1,70 +0,0 @@ -from paraview.simple import * -from paraview import coprocessing - -# ----------------------- CoProcessor definition ----------------------- - -def CreateCoProcessor(): - def _CreatePipeline(coprocessor, datadescription): - class Pipeline: - input1 = coprocessor.CreateProducer(datadescription, 'input') - writer1 = servermanager.writers.XMLMultiBlockDataWriter(Input=input1) - - coprocessor.RegisterWriter(writer1, filename='area_%t.vtm', freq=2) - - return Pipeline() - - class CoProcessor(coprocessing.CoProcessor): - def CreatePipeline(self, datadescription): - self.Pipeline = _CreatePipeline(self, datadescription) - - coprocessor = CoProcessor() - freqs = {'input': [10]} - coprocessor.SetUpdateFrequencies(freqs) - return coprocessor - -#-------------------------------------------------------------- -# Global variables that will hold the pipeline for each timestep -# Creating the CoProcessor object, doesn't actually create the ParaView pipeline. -# It will be automatically setup when coprocessor.UpdateProducers() is called the -# first time. -coprocessor = CreateCoProcessor() - -#-------------------------------------------------------------- -# Enable Live-Visualizaton with ParaView -coprocessor.EnableLiveVisualization(True) - -# ---------------------- Data Selection method ---------------------- - -def RequestDataDescription(datadescription): - 'Callback to populate the request for current timestep' - global coprocessor - if datadescription.GetForceOutput() == True: - # We are just going to request all fields and meshes from the simulation - # code/adaptor. - for i in range(datadescription.GetNumberOfInputDescriptions()): - datadescription.GetInputDescription(i).AllFieldsOn() - datadescription.GetInputDescription(i).GenerateMeshOn() - return - - # setup requests for all inputs based on the requirements of the - # pipeline. - coprocessor.LoadRequestedData(datadescription) - -# ------------------------ Processing method ------------------------ - -def DoCoProcessing(datadescription): - 'Callback to do co-processing for current timestep' - global coprocessor - - # Update the coprocessor by providing it the newly generated simulation data. - # If the pipeline hasn't been setup yet, this will setup the pipeline. - coprocessor.UpdateProducers(datadescription) - - # Write output data, if appropriate. - coprocessor.WriteData(datadescription); - - # Write image capture (Last arg: rescale lookup table), if appropriate. - coprocessor.WriteImages(datadescription, rescale_lookuptable=False) - - # Live Visualization, if enabled. - coprocessor.DoLiveVisualization(datadescription, 'localhost', 22222) diff --git a/etc/writeCloud.py b/etc/writeCloud.py deleted file mode 100644 index db348ea49c18683d31f030958c1237c52921fdb6..0000000000000000000000000000000000000000 --- a/etc/writeCloud.py +++ /dev/null @@ -1,72 +0,0 @@ -from paraview.simple import * -from paraview import coprocessing - -# ----------------------- CoProcessor definition ----------------------- - -def CreateCoProcessor(): - def _CreatePipeline(coprocessor, datadescription): - class Pipeline: - input1 = coprocessor.CreateProducer(datadescription, 'cloud') - writer1 = servermanager.writers.XMLMultiBlockDataWriter(Input=input1) - - # register writer with coprocessor, with filename + output freq - coprocessor.RegisterWriter(writer1, filename='cloud_%t.vtm', freq=10) - - return Pipeline() - - class CoProcessor(coprocessing.CoProcessor): - def CreatePipeline(self, datadescription): - self.Pipeline = _CreatePipeline(self, datadescription) - - coprocessor = CoProcessor() - freqs = {'cloud': [10]} - coprocessor.SetUpdateFrequencies(freqs) - return coprocessor - -#-------------------------------------------------------------- -# Global variables that will hold the pipeline for each timestep -# Creating the CoProcessor object, doesn't actually create the ParaView pipeline. -# It will be automatically setup when coprocessor.UpdateProducers() is called the -# first time. -coprocessor = CreateCoProcessor() - -#-------------------------------------------------------------- -# Enable Live-Visualizaton with ParaView -coprocessor.EnableLiveVisualization(True) - - -# ---------------------- Data Selection method ---------------------- - -def RequestDataDescription(datadescription): - 'Callback to populate the request for current timestep' - global coprocessor - if datadescription.GetForceOutput() == True: - # We are just going to request all fields and meshes from the simulation - # code/adaptor. - for i in range(datadescription.GetNumberOfInputDescriptions()): - datadescription.GetInputDescription(i).AllFieldsOn() - datadescription.GetInputDescription(i).GenerateMeshOn() - return - - # setup requests for all inputs based on the requirements of the - # pipeline. - coprocessor.LoadRequestedData(datadescription) - -# ------------------------ Processing method ------------------------ - -def DoCoProcessing(datadescription): - 'Callback to do co-processing for current timestep' - global coprocessor - - # Update the coprocessor by providing it the newly generated simulation data. - # If the pipeline hasn't been setup yet, this will setup the pipeline. - coprocessor.UpdateProducers(datadescription) - - # Write output data, if appropriate. - coprocessor.WriteData(datadescription); - - # Write image capture (Last arg: rescale lookup table), if appropriate. - coprocessor.WriteImages(datadescription, rescale_lookuptable=False) - - # Live Visualization, if enabled. - coprocessor.DoLiveVisualization(datadescription, 'localhost', 22222) diff --git a/src/catalyst/CMakeLists-Common.txt b/src/catalyst/CMakeLists-Common.txt index 4ee2eef7b5cddfed78ff1d5ff72dd70635385bbb..341fed060b61bb8b3b132d95aa48bd5a13467f7c 100644 --- a/src/catalyst/CMakeLists-Common.txt +++ b/src/catalyst/CMakeLists-Common.txt @@ -63,6 +63,9 @@ set(LIBRARY_OUTPUT_PATH $ENV{FOAM_LIBBIN} file(GLOB SOURCE_FILES catalystCoprocess.C + catalystTools.C + catalystInput.C + catalystFunctionObject.C cloud/catalystCloud.C cloud/foamVtkCloudAdaptor.C diff --git a/src/catalyst/areaMesh/catalystFaMesh.C b/src/catalyst/areaMesh/catalystFaMesh.C index 02f8760df165f137627db3a38afa504b6b464ad7..94406f2a78455fe17fe8af2af7caa6b1d86cfb69 100644 --- a/src/catalyst/areaMesh/catalystFaMesh.C +++ b/src/catalyst/areaMesh/catalystFaMesh.C @@ -24,12 +24,10 @@ License \*---------------------------------------------------------------------------*/ #include "catalystFaMesh.H" -#include "catalystCoprocess.H" #include "addToRunTimeSelectionTable.H" #include "faMesh.H" #include "fvMesh.H" -#include <vtkNew.h> #include <vtkCPDataDescription.h> #include <vtkMultiBlockDataSet.h> #include <vtkInformation.h> @@ -38,76 +36,39 @@ License namespace Foam { -namespace functionObjects +namespace catalyst { - defineTypeNameAndDebug(catalystFaMesh, 0); - addToRunTimeSelectionTable(functionObject, catalystFaMesh, dictionary); + defineTypeNameAndDebug(faMeshInput, 0); + addNamedToRunTimeSelectionTable + ( + catalystInput, + faMeshInput, + dictionary, + area + ); } } // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // -bool Foam::functionObjects::catalystFaMesh::readBasics(const dictionary& dict) +void Foam::catalyst::faMeshInput::update() { - int debugLevel = 0; - if (dict.readIfPresent("debug", debugLevel)) - { - catalystCoprocess::debug = debugLevel; - } + // Backend requires a corresponding mesh + backends_.filterKeys + ( + [this](const word& k){ return meshes_.found(k); } + ); - if (Pstream::master()) + forAllConstIters(meshes_, iter) { - fileName dir; - if (dict.readIfPresent("mkdir", dir)) + if (!backends_.found(iter.key())) { - dir.expand(); - dir.clean(); - } - Foam::mkDir(dir); - } - - dict.readIfPresent("outputDir", outputDir_); - outputDir_.expand(); - outputDir_.clean(); - if (Pstream::master()) - { - Foam::mkDir(outputDir_); - } - - dict.lookup("scripts") >> scripts_; // Python scripts - catalystCoprocess::expand(scripts_, dict); // Expand and check availability - - if (adaptor_.valid()) - { - // Run-time modification of pipeline - adaptor_().reset(outputDir_, scripts_); - } - - return true; -} - - -void Foam::functionObjects::catalystFaMesh::updateState -( - polyMesh::readUpdateState state -) -{ - // Trigger change of state - - // Be really paranoid and verify if the mesh actually exists - const wordList regionNames(backends_.toc()); - - for (const word& regionName : regionNames) - { - if (meshes_.found(regionName) && time_.found(regionName)) - { - backends_[regionName]->updateState(state); - } - else - { - backends_.erase(regionName); - meshes_.erase(regionName); + backends_.insert + ( + iter.key(), + new Foam::vtk::faMeshAdaptor(*(iter.object())) + ); } } } @@ -115,61 +76,52 @@ void Foam::functionObjects::catalystFaMesh::updateState // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // -Foam::functionObjects::catalystFaMesh::catalystFaMesh +Foam::catalyst::faMeshInput::faMeshInput ( const word& name, const Time& runTime, const dictionary& dict ) : - fvMeshFunctionObject(name, runTime, dict), - outputDir_("<case>/insitu"), - scripts_(), - adaptor_(), + catalystInput(name), + time_(runTime), + regionName_(), selectAreas_(), selectFields_(), meshes_(), backends_() { - if (postProcess) - { - // Disable for post-process mode. - // Emit as FatalError for the try/catch in the caller. - FatalError - << type() << " disabled in post-process mode" - << exit(FatalError); - } read(dict); } -// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // - -Foam::functionObjects::catalystFaMesh::~catalystFaMesh() -{} - - // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -bool Foam::functionObjects::catalystFaMesh::read(const dictionary& dict) +bool Foam::catalyst::faMeshInput::read(const dictionary& dict) { - fvMeshFunctionObject::read(dict); + catalystInput::read(dict); - readBasics(dict); + selectAreas_.clear(); + selectFields_.clear(); + backends_.clear(); - // All possible meshes - meshes_ = mesh_.lookupClass<faMesh>(); + regionName_ = + dict.lookupOrDefault<word>("region", polyMesh::defaultRegion); + + const objectRegistry& obr = + time_.lookupObject<objectRegistry>(regionName_); + + // All possible meshes for the given region + meshes_ = obr.lookupClass<faMesh>(); - selectAreas_.clear(); dict.readIfPresent("areas", selectAreas_); if (selectAreas_.empty()) { word areaName; - if (!dict.readIfPresent("area", areaName)) { - wordList available = mesh_.sortedNames<faMesh>(); + wordList available = obr.sortedNames<faMesh>(); if (available.size()) { @@ -185,59 +137,49 @@ bool Foam::functionObjects::catalystFaMesh::read(const dictionary& dict) } // Restrict to specified meshes - meshes_.filterKeys(wordRes(selectAreas_)); + meshes_.filterKeys(selectAreas_); dict.lookup("fields") >> selectFields_; - Info<< type() << " " << name() << ":" << nl - <<" areas " << flatOutput(selectAreas_) << nl - <<" meshes " << flatOutput(meshes_.sortedToc()) << nl - <<" fields " << flatOutput(selectFields_) << nl - <<" scripts " << scripts_ << nl; - - - // Ensure consistency - only retain backends with corresponding mesh region - backends_.retain(meshes_); - return true; } -bool Foam::functionObjects::catalystFaMesh::execute() +void Foam::catalyst::faMeshInput::update(polyMesh::readUpdateState state) { - const wordList regionNames(meshes_.sortedToc()); + // Trigger change of state - if (regionNames.empty()) - { - return false; - } + const objectRegistry& obr = + time_.lookupObject<objectRegistry>(regionName_); + + // Be really paranoid and verify if the mesh actually exists + const wordList regionNames(backends_.toc()); - // Enforce sanity for backends and adaptor + for (const word& regionName : regionNames) { - bool updateAdaptor = false; - forAllConstIters(meshes_, iter) + if (meshes_.found(regionName) && obr.found(regionName)) { - if (!backends_.found(iter.key())) - { - backends_.insert - ( - iter.key(), - new Foam::vtk::faMeshAdaptor(*(iter.object())) - ); - updateAdaptor = true; - } + backends_[regionName]->updateState(state); } - - if (updateAdaptor && !adaptor_.valid()) + else { - adaptor_.reset(new catalystCoprocess()); - adaptor_().reset(outputDir_, scripts_); + backends_.erase(regionName); + meshes_.erase(regionName); } } +} - // Gather all fields that we know how to convert +Foam::label Foam::catalyst::faMeshInput::addChannels(dataQuery& dataq) +{ + update(); // Enforce sanity for backends and adaptor + + if (backends_.empty()) + { + return 0; + } + // Gather all fields that we know how to convert wordHashSet allFields; forAllConstIters(backends_, iter) { @@ -245,96 +187,89 @@ bool Foam::functionObjects::catalystFaMesh::execute() } - // Data description for co-processing - vtkNew<vtkCPDataDescription> descrip; + dataq.set(name(), allFields); - // Form data query for catalyst - catalystCoprocess::dataQuery dataq - ( - vtk::faMeshAdaptor::channelNames.names(), - time_, // timeQuery - descrip.Get() - ); + return 1; +} - // Query catalyst - const HashTable<wordHashSet> expecting(adaptor_().query(dataq, allFields)); - if (catalystCoprocess::debug) +bool Foam::catalyst::faMeshInput::convert +( + dataQuery& dataq, + outputChannels& outputs +) +{ + const wordList regionNames(backends_.sortedToc()); + + if (regionNames.empty()) { - if (expecting.empty()) - { - Info<< type() << ": expecting no data" << nl; - } - else - { - Info<< type() << ": expecting data " << expecting << nl; - } + return false; // skip - not available } - if (expecting.empty()) + // Single channel only + + label nChannels = 0; + + if (dataq.found(name())) + { + ++nChannels; + } + + if (!nChannels) { - return true; + return false; // skip - not requested } - auto output = vtkSmartPointer<vtkMultiBlockDataSet>::New(); // TODO: currently don't rely on the results from expecting much at all // Each region in a separate block - unsigned int regionNo = 0; + unsigned int blockNo = 0; for (const word& regionName : regionNames) { - auto pieces = backends_[regionName]->output(selectFields_); - - output->SetBlock(regionNo, pieces); - - output->GetMetaData(regionNo)->Set - ( - vtkCompositeDataSet::NAME(), - regionName - ); - ++regionNo; - } + auto dataset = + backends_[regionName]->output(selectFields_); - if (regionNo) - { - Log << type() << ": send data" << nl; - - adaptor_().process(dataq, output); - } + { + const fileName channel = name(); - return true; -} + if (dataq.found(channel)) + { + // Get existing or new + vtkSmartPointer<vtkMultiBlockDataSet> block = + outputs.lookup + ( + channel, + vtkSmartPointer<vtkMultiBlockDataSet>::New() + ); + block->SetBlock(blockNo, dataset); -bool Foam::functionObjects::catalystFaMesh::write() -{ - return true; -} + block->GetMetaData(blockNo)->Set + ( + vtkCompositeDataSet::NAME(), + regionName + ); + outputs.set(channel, block); // overwrites existing + } + } -bool Foam::functionObjects::catalystFaMesh::end() -{ - // Only here for extra feedback - if (log && adaptor_.valid()) - { - Info<< type() << ": Disconnecting ParaView Catalyst..." << nl; + ++blockNo; } - adaptor_.clear(); return true; } -void Foam::functionObjects::catalystFaMesh::updateMesh(const mapPolyMesh&) +Foam::Ostream& Foam::catalyst::faMeshInput::print(Ostream& os) const { - updateState(polyMesh::TOPO_CHANGE); -} - + os << name() << nl + <<" areas " << flatOutput(selectAreas_) << nl + <<" meshes " << flatOutput(meshes_.sortedToc()) << nl + <<" fields " << flatOutput(selectFields_) << nl; -void Foam::functionObjects::catalystFaMesh::movePoints(const polyMesh&) -{ - updateState(polyMesh::POINTS_MOVED); + return os; } diff --git a/src/catalyst/areaMesh/catalystFaMesh.H b/src/catalyst/areaMesh/catalystFaMesh.H index 17dc3f3eac4f5b7a66f95dde48d57989ad019999..275ab601bcd95a8fe13f8e715025240426bff50e 100644 --- a/src/catalyst/areaMesh/catalystFaMesh.H +++ b/src/catalyst/areaMesh/catalystFaMesh.H @@ -22,51 +22,35 @@ License along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. Class - Foam::functionObjects::catalystFaMesh - -Group - grpUtilitiesFunctionObjects + Foam::catalyst::faMeshInput Description - A Paraview Catalyst adaptor for OpenFOAM faMesh regions. + A Paraview Catalyst source for OpenFOAM faMesh regions. - The output comprises a single "input" channel, which is a multi-block - dataset (one block per area mesh). + 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. - Example of function object specification: + Example specification: \verbatim - catalyst + myArea { - type catalyst::area; - libs ("libcatalystFoam.so"); + type area; fields (U p); - scripts ( ... ); - executeControl timeStep; - executeInterval 1; } \endverbatim Usage \table Property | Description | Required | Default - type | catalyst::area | yes | - log | report extra information | no | false - mkdir | initial directory to create | no | + type | area | yes | region | | no | region0 regions | wordRe list of regions | no | fields | wordRe list of fields | yes | - scripts | Python pipeline scripts | yes | \endtable -Note - The execution frequency can be defined by the functionObject and - by the Catalyst pipeline. - See also - Foam::functionObjects::functionObject - Foam::functionObjects::fvMeshFunctionObject - Foam::functionObjects::timeControl - Foam::catalystCoprocess + Foam::catalyst::catalystInput Foam::vtk::faMeshAdaptor SourceFiles @@ -75,47 +59,38 @@ SourceFiles \*---------------------------------------------------------------------------*/ -#ifndef functionObjects_catalystFaMesh_H -#define functionObjects_catalystFaMesh_H +#ifndef catalyst_faMeshInput_H +#define catalyst_faMeshInput_H -#include "fvMeshFunctionObject.H" -#include "foamVtkFaMeshAdaptor.H" #include "wordRes.H" #include "HashPtrTable.H" +#include "catalystInput.H" +#include "foamVtkFaMeshAdaptor.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // namespace Foam { - -// Forward declarations - -class catalystCoprocess; - -namespace functionObjects +namespace catalyst { /*---------------------------------------------------------------------------*\ - Class catalystFaMesh Declaration + Class catalyst::faMeshInput Declaration \*---------------------------------------------------------------------------*/ -class catalystFaMesh +class faMeshInput : - public fvMeshFunctionObject + public catalystInput { protected: // Protected data - //- The output directory - fileName outputDir_; - - //- Python scripts for the catalyst pipeline - stringList scripts_; - - //- The catalyst coprocess - autoPtr<catalystCoprocess> adaptor_; + //- Reference to the time database + const Time& time_; + //- The region name for the area meshes + word regionName_; //- Requested names of areas to process wordRes selectAreas_; @@ -132,29 +107,25 @@ protected: // Protected Member Functions - //- Common boilerplate settings - bool readBasics(const dictionary& dict); - - //- On movement - void updateState(polyMesh::readUpdateState state); - + //- Update/synchronize internals with catalyst backends + void update(); //- No copy construct - catalystFaMesh(const catalystFaMesh&) = delete; + faMeshInput(const faMeshInput&) = delete; //- No copy assignment - void operator=(const catalystFaMesh&) = delete; + void operator=(const faMeshInput&) = delete; public: //- Runtime type information - TypeName("catalyst::area"); + ClassName("catalyst::faMesh"); // Constructors //- Construct from Time and dictionary - catalystFaMesh + faMeshInput ( const word& name, const Time& runTime, @@ -163,7 +134,7 @@ public: //- Destructor - virtual ~catalystFaMesh(); + virtual ~faMeshInput() = default; // Member Functions @@ -171,27 +142,23 @@ public: //- Read the specification virtual bool read(const dictionary& dict); - //- Execute catalyst pipelines - virtual bool execute(); - - //- Write - does nothing - virtual bool write(); - - //- On end - provide feedback about disconnecting from catatyst. - virtual bool end(); + //- Update for changes of mesh or mesh point-motion + virtual void update(polyMesh::readUpdateState state); - //- Update for changes of mesh - virtual void updateMesh(const mapPolyMesh& mpm); + //- Add available channels (with fields) to data query + virtual label addChannels(dataQuery& dataq); - //- Update for mesh point-motion - virtual void movePoints(const polyMesh& mesh); + //- Convert channels to vtkMultiBlockDataSet outputs + virtual bool convert(dataQuery& dataq, outputChannels& outputs); + //- Print information + virtual Ostream& print(Ostream& os) const; }; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -} // End namespace functionObjects +} // End namespace catalyst } // End namespace Foam // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/catalyst/areaMesh/foamVtkFaMeshAdaptor.C b/src/catalyst/areaMesh/foamVtkFaMeshAdaptor.C index a19f41c947ebef02b8d2bb077a22292d0d967649..47a89cf8f0f3d49ed30f3351d2ce872b29c8776a 100644 --- a/src/catalyst/areaMesh/foamVtkFaMeshAdaptor.C +++ b/src/catalyst/areaMesh/foamVtkFaMeshAdaptor.C @@ -46,16 +46,6 @@ namespace vtk } } -const Foam::Enum -< - Foam::vtk::faMeshAdaptor::channel -> -Foam::vtk::faMeshAdaptor::channelNames -{ - { channel::INPUT, "input" }, -}; - - const Foam::word Foam::vtk::faMeshAdaptor::internalName("internal"); diff --git a/src/catalyst/areaMesh/foamVtkFaMeshAdaptor.H b/src/catalyst/areaMesh/foamVtkFaMeshAdaptor.H index 5b37ccb36c1b58dffb18eaf62d356aa9ad3ef1b5..129d780dc41e0e3228684b44f82e1f436f4a1225 100644 --- a/src/catalyst/areaMesh/foamVtkFaMeshAdaptor.H +++ b/src/catalyst/areaMesh/foamVtkFaMeshAdaptor.H @@ -45,7 +45,6 @@ SourceFiles #include "fileName.H" #include "stringList.H" #include "wordList.H" -#include "Enum.H" #include "polyMesh.H" #include "areaFieldsFwd.H" #include "foamVtkTools.H" @@ -89,14 +88,6 @@ public: //- Public Data Members - //- The Catalyst output channels - enum channel - { - INPUT = 0x3 - }; - - static const Enum<channel> channelNames; - //- Name for internal mesh ("internal") static const word internalName; diff --git a/src/catalyst/areaMesh/foamVtkFaMeshAdaptorFieldTemplates.C b/src/catalyst/areaMesh/foamVtkFaMeshAdaptorFieldTemplates.C index e682a2bd2c45066ad30cfc6729d0cfc24ae2c9d1..6b2f6adad1a5c17b349dd4da165feb08520b7bb9 100644 --- a/src/catalyst/areaMesh/foamVtkFaMeshAdaptorFieldTemplates.C +++ b/src/catalyst/areaMesh/foamVtkFaMeshAdaptorFieldTemplates.C @@ -28,11 +28,6 @@ License // OpenFOAM includes #include "error.H" -#include "emptyFvPatchField.H" -#include "wallPolyPatch.H" -#include "volPointInterpolation.H" -#include "zeroGradientFvPatchField.H" -#include "interpolatePointToCell.H" // vtk includes #include "vtkFloatArray.h" diff --git a/src/catalyst/catalystCoprocess.C b/src/catalyst/catalystCoprocess.C index 967fdfb1c06361f0bf0006577df08300f4ad4691..12e4d59c51093fa048bcb2989af3c3e151eb2f1a 100644 --- a/src/catalyst/catalystCoprocess.C +++ b/src/catalyst/catalystCoprocess.C @@ -24,8 +24,6 @@ License #include "catalystCoprocess.H" #include "Time.H" -#include "stringOps.H" -#include "OSspecific.H" // VTK includes #include <vtkNew.h> @@ -42,135 +40,38 @@ License namespace Foam { - defineTypeNameAndDebug(catalystCoprocess, 0); -} - - -// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * // - -namespace Foam -{ -namespace -{ - -#if 0 -static void printInfo(vtkCPDataDescription* descrip) +namespace catalyst { - if (!descrip) - { - return; - } - - const unsigned nItems = descrip->GetNumberOfInputDescriptions(); - - for (unsigned itemi = 0; itemi < nItems; ++itemi) - { - vtkCPInputDataDescription* input = descrip->GetInputDescription(itemi); - if (!input) continue; // should not happen - - Info<<"input: " << descrip->GetInputDescriptionName(itemi) << nl; - - const unsigned nFields = input->GetNumberOfFields(); - for (unsigned fieldi = 0; fieldi < nFields; ++fieldi) - { - Info<< " field: " << input->GetFieldName(fieldi) << nl; - } - if (!nFields) Info<<" no fields requested" << nl; - } + defineTypeNameAndDebug(coprocess, 0); } -#endif - -} // End anonymous namespace -} // End namespace Foam - - -// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // - -Foam::label Foam::catalystCoprocess::expand -( - List<string>& scripts, - const dictionary& dict -) -{ - label nscript = 0; - - forAll(scripts, scripti) - { - string& s = scripts[scripti]; - - stringOps::inplaceExpand(s, dict, true, true); - fileName::clean(s); // Remove trailing, repeated slashes etc. - - if (isFile(s)) - { - if (nscript != scripti) - { - scripts[nscript] = std::move(s); - } - ++nscript; - } - } - - scripts.resize(nscript); - - return nscript; } // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // template<class DataType> -bool Foam::catalystCoprocess::processImpl -( - const dataQuery& dataq, - vtkSmartPointer<DataType>& output -) -{ - vtkCPDataDescription* descrip = dataq.get(); - - if (!coproc_->RequestDataDescription(descrip)) - { - return false; - } - - for (const word& chanName : dataq.channels()) - { - auto* input = descrip->GetInputDescriptionByName(chanName.c_str()); - - if (input && input->GetIfGridIsNecessary()) - { - input->SetGrid(output); - } - } - - coproc_->CoProcess(descrip); - return true; -} - - -template<class DataType> -bool Foam::catalystCoprocess::processImpl +bool Foam::catalyst::coprocess::processImpl ( const dataQuery& dataq, - HashTable<vtkSmartPointer<DataType>>& outputs + HashTable<vtkSmartPointer<DataType>, fileName>& outputs ) { - vtkCPDataDescription* descrip = dataq.get(); + auto* descrip = dataq.description(); if (!coproc_->RequestDataDescription(descrip)) { return false; } - for (const word& chanName : dataq.channels()) + for (const fileName& channel : dataq.names()) { - if (outputs.found(chanName)) + if (outputs.found(channel)) { - auto* input = descrip->GetInputDescriptionByName(chanName.c_str()); + auto* input = descrip->GetInputDescriptionByName(channel.c_str()); if (input && input->GetIfGridIsNecessary()) { - input->SetGrid(outputs[chanName]); + input->SetGrid(outputs[channel]); } } } @@ -180,21 +81,11 @@ bool Foam::catalystCoprocess::processImpl } -// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // - -Foam::catalystCoprocess::timeQuery::timeQuery(const Foam::Time& t) -: - timeValue(t.timeOutputValue()), - timeIndex(t.timeIndex()), - forced(t.timeOutputValue() >= t.endTime().value()) -{} - - // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // -Foam::catalystCoprocess::~catalystCoprocess() +Foam::catalyst::coprocess::~coprocess() { - // stop(), but without output + // As per stop(), but without output if (coproc_) { coproc_->Delete(); @@ -205,13 +96,13 @@ Foam::catalystCoprocess::~catalystCoprocess() // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -bool Foam::catalystCoprocess::good() const +bool Foam::catalyst::coprocess::good() const { return coproc_; } -void Foam::catalystCoprocess::stop() +void Foam::catalyst::coprocess::stop() { if (coproc_) { @@ -222,7 +113,7 @@ void Foam::catalystCoprocess::stop() } -void Foam::catalystCoprocess::reset(const fileName& outputDir) +void Foam::catalyst::coprocess::reset(const fileName& outputDir) { #ifdef USE_CATALYST_WORKING_DIRECTORY if (coproc_ == nullptr) @@ -253,6 +144,7 @@ void Foam::catalystCoprocess::reset(const fileName& outputDir) { coproc_ = vtkCPProcessor::New(); coproc_->Initialize(); + Info<< "Connecting ParaView Catalyst..." << endl; } else { @@ -265,7 +157,7 @@ void Foam::catalystCoprocess::reset(const fileName& outputDir) } -void Foam::catalystCoprocess::reset +void Foam::catalyst::coprocess::reset ( const fileName& outputDir, const UList<string>& scripts @@ -288,139 +180,20 @@ void Foam::catalystCoprocess::reset } -Foam::HashTable<Foam::wordHashSet> -Foam::catalystCoprocess::query -( - dataQuery& dataq, - const wordHashSet& allFields -) +Foam::label Foam::catalyst::coprocess::query(dataQuery& dataq) { - // Desirable to also know which fields have been requested - HashTable<wordHashSet> requests; - - if (!good()) - { - Info<< "No ParaView Catalyst initialized" << endl; - return requests; - } - - if (dataq.channels().empty()) - { - // No channels names have been published by the simulation - return requests; - } - - vtkCPDataDescription* descrip = dataq.get(); - - descrip->SetTimeData(dataq.timeValue, dataq.timeIndex); - descrip->SetForceOutput(dataq.forced); - - // Sort out which channels already exist, are new, or disappeared - { - // The currently defined channels - wordHashSet currChannels; - - const unsigned n = descrip->GetNumberOfInputDescriptions(); - for (unsigned i=0; i < n; ++i) - { - currChannels.insert - ( - word::validate(descrip->GetInputDescriptionName(i)) - ); - } - - wordHashSet newChannels(dataq.channels()); - wordHashSet oldChannels(currChannels); - oldChannels.erase(newChannels); - - if (oldChannels.size()) - { - descrip->ResetAll(); - } - else - { - newChannels.erase(currChannels); - } - - // Add channels - for (const word& chanName : newChannels) - { - descrip->AddInput(chanName.c_str()); - auto* input = descrip->GetInputDescriptionByName(chanName.c_str()); - - for (const word& fieldName : allFields) - { - input->AddPointField(fieldName.c_str()); - input->AddCellField(fieldName.c_str()); - } - } - - // Note: this misses updating field information for previously - // existing inputs. - } - - if - ( - !coproc_->RequestDataDescription(descrip) - || !descrip->GetIfAnyGridNecessary() - ) - { - return requests; - } - - for (const word& chanName : dataq.channels()) - { - auto* input = descrip->GetInputDescriptionByName(chanName.c_str()); - - if (input && input->GetIfGridIsNecessary()) - { - wordHashSet& fields = requests(chanName); // auto-vivify - - for (const word& fieldName : allFields) - { - if (input->IsFieldNeeded(fieldName.c_str())) - { - fields.insert(fieldName); - } - } - } - } - - return requests; + return dataq.query(coproc_); } -bool Foam::catalystCoprocess::process +bool Foam::catalyst::coprocess::process ( const dataQuery& dataq, - vtkSmartPointer<vtkMultiBlockDataSet>& output -) -{ - return processImpl(dataq, output); -} - - -bool Foam::catalystCoprocess::process -( - const dataQuery& dataq, - HashTable<vtkSmartPointer<vtkMultiBlockDataSet>>& outputs + outputChannels& outputs ) { return processImpl(dataq, outputs); } -// * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * // - -Foam::Ostream& Foam::operator<< -( - Ostream& os, - const catalystCoprocess::timeQuery& when -) -{ - os << "Time = " << when.timeValue << ", index: " << when.timeIndex; - return os; -} - - // ************************************************************************* // diff --git a/src/catalyst/catalystCoprocess.H b/src/catalyst/catalystCoprocess.H index 3366a4c8d2b6f71db2f123dfcaf29c5c0c74002b..bd7b1827c8267454ad1fff7197ef8e6f3692b22b 100644 --- a/src/catalyst/catalystCoprocess.H +++ b/src/catalyst/catalystCoprocess.H @@ -22,136 +22,37 @@ License along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. Class - Foam::catalystCoprocess + Foam::catalyst::coprocess Description Low-level interface between OpenFOAM and ParaView Catalyst. - \code - ... initialize catalyst - - ... define a data query for catalyst - - // Data description for co-processing - vtkNew<vtkCPDataDescription> descrip; - - // Form data query for catalyst - catalystCoprocess::dataQuery dataq(channelNames, runTime, descrip.Get()); - - // Query catalyst - HashTable<wordHashSet> expecting = adaptor_().query(dataq, fields); - - \endcode - SourceFiles catalystCoprocess.C \*---------------------------------------------------------------------------*/ -#ifndef functionObjects_catalystCoprocess_H -#define functionObjects_catalystCoprocess_H +#ifndef catalyst_coprocess_H +#define catalyst_coprocess_H #include "className.H" #include "wordList.H" #include "stringList.H" -#include "HashSet.H" +#include "catalystTools.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -// Forward Declarations -class vtkCPProcessor; -class vtkCPDataDescription; -class vtkMultiBlockDataSet; -template<class T> class vtkSmartPointer; - namespace Foam { - -// Forward Declarations -class dictionary; -class Time; -class Ostream; -class catalystCoprocess; +namespace catalyst +{ /*---------------------------------------------------------------------------*\ - Class catalystCoprocess Declaration + Class catalyst::coprocess Declaration \*---------------------------------------------------------------------------*/ -class catalystCoprocess +class coprocess { -public: - - //- Simple structure for time queries - struct timeQuery - { - double timeValue; - long timeIndex; - bool forced; - - constexpr timeQuery - ( - double val, - long index, - bool forcedOutput=false - ) noexcept - : - timeValue(val), - timeIndex(index), - forced(forcedOutput) - {} - - timeQuery(const Foam::Time& currTime); - }; - - - //- Simple structure for data description queries - // The storage for the description is held outside this class - class dataQuery - : - public timeQuery - { - //- Catalyst channel names to query - List<word> channels_; - mutable vtkCPDataDescription* descrip_; - - public: - - dataQuery - ( - const UList<word>& channelNames, - const timeQuery& when, - vtkCPDataDescription* description - ) - : - timeQuery(when), - channels_(channelNames), - descrip_(description) - {} - - dataQuery - ( - const UList<word>& channelNames, - const Foam::Time& when, - vtkCPDataDescription* description - ) - : - dataQuery(channelNames, timeQuery(when), description) - {} - - //- The declared output channels - const UList<word>& channels() const - { - return channels_; - } - - //- Pointer to coprocess data description - vtkCPDataDescription* get() const - { - return this->descrip_; - } - }; - - private: // Private Data @@ -162,30 +63,16 @@ private: // Private Member Functions - //- Process single output channel - template<class DataType> - bool processImpl - ( - const dataQuery& query, - vtkSmartPointer<DataType>& outputs - ); - //- Process multiple output channels template<class DataType> bool processImpl ( - const dataQuery& query, - HashTable<vtkSmartPointer<DataType>>& outputs + const dataQuery& dataq, + HashTable<vtkSmartPointer<DataType>, fileName>& outputs ); public: - // Static Methods - - //- Expand strings as filenames, retaining only those that exist - static label expand(List<string>& scripts, const dictionary& dict); - - //- Define class name and debug ClassName("catalyst"); @@ -193,14 +80,14 @@ public: // Constructors //- Construct null. Does not initialize catalyst. - constexpr catalystCoprocess() noexcept + constexpr coprocess() noexcept : coproc_(nullptr) {} //- Destructor. Shutdown process. - ~catalystCoprocess(); + ~coprocess(); // Member Functions @@ -225,35 +112,17 @@ public: //- iteration and possibly which fields they require. // // \param[in,out] dataq the data query for catalyst. - // On input it contains the published channel names, the current - // simulation time (index, value) and allocation for the coprocess - // data description. - // On output the data description will be filled with the field - // names added per channel. - // \param[in] allFields the fields that can be published from the - // simulation. + // On input it contains the published channel names with their + // published fields, as well as the current simulation time + // (index, value). + // On output the data description part of dataq will be filled + // with the requested field names added per channel. // - // \return HashTable with fields requested (what Catalyst expects) - // on a per-channel basis. - HashTable<wordHashSet> query - ( - dataQuery& dataq, - const wordHashSet& allFields - ); - - //- Single-channel source (eg, "input" or "cloud", ...) - bool process - ( - const dataQuery& dataq, - vtkSmartPointer<vtkMultiBlockDataSet>& output - ); + // \return number of channels request at this time + label query(dataQuery& dataq); - //- Multi-channel source (eg, "input", "mesh", "patches") - bool process - ( - const dataQuery& dataq, - HashTable<vtkSmartPointer<vtkMultiBlockDataSet>>& outputs - ); + //- Process the output channels + bool process(const dataQuery& dataq, outputChannels& outputs); //- Finalize void stop(); @@ -261,10 +130,9 @@ public: }; -// Ostream Operator -Ostream& operator<<(Ostream& os, const catalystCoprocess::timeQuery& when); - +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +} // End namespace catalyst } // End namespace Foam // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/catalyst/catalystDict b/src/catalyst/catalystDict new file mode 100644 index 0000000000000000000000000000000000000000..ff7bd1f9f8b60fbc0ff99070f6abb851d78fcf50 --- /dev/null +++ b/src/catalyst/catalystDict @@ -0,0 +1,61 @@ +// ParaView Catalyst function object for OpenFOAM (-*- C++ -*-) + +functions +{ + catalyst + { + type catalyst; + libs ("libcatalystFoam.so"); + executeControl timeStep; + writeControl none; + + // OR #includeEtc "caseDicts/insitu/catalyst/catalyst.cfg" + + // mkdir "<case>/someDir"; + + scripts + ( + // "<etc>/caseDicts/insitu/catalyst/printChannels.py" + "<etc>/caseDicts/insitu/catalyst/writeAll.py" + ); + + inputs + { + // 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.*" ); + } + } + } +} + + +// ************************************************************************* // diff --git a/src/catalyst/catalystFunctionObject.C b/src/catalyst/catalystFunctionObject.C new file mode 100644 index 0000000000000000000000000000000000000000..58d3bfb9a6e949b2d912d465742320a95fb8dd09 --- /dev/null +++ b/src/catalyst/catalystFunctionObject.C @@ -0,0 +1,344 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2018 OpenCFD Ltd. + \\/ M anipulation | Copyright (C) 2018 CINECA +------------------------------------------------------------------------------- +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 "catalystFunctionObject.H" +#include "catalystCoprocess.H" +#include "stringOps.H" +#include "OSHA1stream.H" +#include "OSspecific.H" +#include "addToRunTimeSelectionTable.H" + +#include <vtkCPDataDescription.h> +#include <vtkMultiBlockDataSet.h> +#include <vtkInformation.h> +#include <vtkSmartPointer.h> + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ +namespace functionObjects +{ + defineTypeNameAndDebug(catalystFunctionObject, 0); + addToRunTimeSelectionTable + ( + functionObject, + catalystFunctionObject, + dictionary + ); +} // End namespace functionObjects +} // End namespace Foam + + +// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // + +Foam::label Foam::functionObjects::catalystFunctionObject::expand +( + List<string>& scripts, + const dictionary& dict +) +{ + label nscript = 0; + + forAll(scripts, scripti) + { + string& s = scripts[scripti]; + + stringOps::inplaceExpand(s, dict, true, true); + fileName::clean(s); // Remove trailing, repeated slashes etc. + + if (isFile(s)) + { + if (nscript != scripti) + { + scripts[nscript] = std::move(s); + } + ++nscript; + } + } + + scripts.resize(nscript); + + return nscript; +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::functionObjects::catalystFunctionObject::catalystFunctionObject +( + const word& name, + const Time& runTime, + const dictionary& dict +) +: + functionObject(name), + time_(runTime), + outputDir_("<case>/insitu"), + scripts_(), + adaptor_(), + inputs_() +{ + if (postProcess) + { + // Disable for post-process mode. + // Emit as FatalError for the try/catch in the caller. + FatalError + << type() << " disabled in post-process mode" + << exit(FatalError); + } + + if (!read(dict)) + { + FatalError + << type() << " with errors" + << exit(FatalError); + } +} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::functionObjects::catalystFunctionObject::~catalystFunctionObject() +{} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +bool Foam::functionObjects::catalystFunctionObject::read(const dictionary& dict) +{ + functionObject::read(dict); + + const dictionary* inputDictPtr = dict.subDictPtr("inputs"); + + if (!inputDictPtr || inputDictPtr->empty()) + { + inputs_.clear(); + + WarningInFunction + << type() << " missing inputs" << endl; + + return false; + } + + int debugLevel = 0; + if (dict.readIfPresent("debug", debugLevel)) + { + catalyst::coprocess::debug = debugLevel; + } + + if (Pstream::master()) + { + fileName dir; + if (dict.readIfPresent("mkdir", dir)) + { + dir.expand(); + dir.clean(); + Foam::mkDir(dir); + } + } + + + // Track changes in outputDir and/or scripts + OSHA1stream osha1; + osha1 << outputDir_ << scripts_; + const SHA1Digest oldDigest(osha1.digest()); + + dict.readIfPresent("outputDir", outputDir_); + outputDir_.expand(); + outputDir_.clean(); + if (Pstream::master()) + { + Foam::mkDir(outputDir_); + } + + dict.lookup("scripts") >> scripts_; // Python scripts + expand(scripts_, dict); // Expand and check availability + + + // Any changes detected + osha1.reset(); + osha1 << outputDir_ osha1 << scripts_; + + if (adaptor_.valid() && oldDigest != osha1.digest()) + { + adaptor_().reset(outputDir_, scripts_); + } + + + PtrList<catalyst::catalystInput> newList(inputDictPtr->size()); + + label nInputs = 0; + forAllConstIters(*inputDictPtr, iter) + { + const dictionary* subDictPtr = iter().dictPtr(); + if (iter().keyword().isPattern() || !subDictPtr) + { + continue; + } + + newList.set + ( + nInputs, + catalyst::catalystInput::New + ( + word(iter().keyword()), + time_, + *subDictPtr + ).ptr() + ); + + ++nInputs; + } + + newList.resize(nInputs); + inputs_.transfer(newList); + + if (inputs_.empty()) + { + WarningInFunction + << type() << " missing inputs" << endl; + } + else + { + Info<< type() << " " << name() << ":" << nl + << " scripts " << scripts_ << nl + << " inputs:" << nl + << "(" << nl; + + nInputs = 0; + for (const auto& inp : inputs_) + { + if (nInputs++) Info << nl; + inp.print(Info); + } + + Info<< ")" << nl; + } + + return true; +} + + +bool Foam::functionObjects::catalystFunctionObject::execute() +{ + // Enforce sanity for backends and adaptor + + if (inputs_.empty()) + { + return false; + } + + if (!adaptor_.valid()) + { + adaptor_.reset(new catalyst::coprocess()); + adaptor_().reset(outputDir_, scripts_); + } + + catalyst::dataQuery dataq(time_); + + label nChannels = 0; + for (auto& inp : inputs_) + { + nChannels += inp.addChannels(dataq); + } + + if (nChannels) + { + nChannels = adaptor_().query(dataq); + } + + if (catalyst::coprocess::debug) + { + Info<< type() << ": expecting data for " << nChannels << nl; + } + + if (!nChannels) + { + return true; + } + + catalyst::outputChannels outputs; + + for (auto& inp : inputs_) + { + inp.convert(dataq, outputs); + } + + if (outputs.size()) + { + Log << type() << ": send data" << nl; + + adaptor_().process(dataq, outputs); + } + + return true; +} + + +bool Foam::functionObjects::catalystFunctionObject::write() +{ + return true; +} + + +bool Foam::functionObjects::catalystFunctionObject::end() +{ + // Only here for extra feedback + if (log && adaptor_.valid()) + { + Info<< type() << ": Disconnecting ParaView Catalyst..." << nl; + } + + adaptor_.clear(); + return true; +} + + +void Foam::functionObjects::catalystFunctionObject::updateMesh +( + const mapPolyMesh& +) +{ + for (auto& inp : inputs_) + { + inp.update(polyMesh::TOPO_CHANGE); + } +} + + +void Foam::functionObjects::catalystFunctionObject::movePoints +( + const polyMesh& +) +{ + for (auto& inp : inputs_) + { + inp.update(polyMesh::POINTS_MOVED); + } +} + + +// ************************************************************************* // diff --git a/src/catalyst/catalystFunctionObject.H b/src/catalyst/catalystFunctionObject.H new file mode 100644 index 0000000000000000000000000000000000000000..13bd9cfcbb8020c06accbf317d31fdd9fcac3ac6 --- /dev/null +++ b/src/catalyst/catalystFunctionObject.H @@ -0,0 +1,195 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2018 OpenCFD Ltd. + \\/ M anipulation | Copyright (C) 2018 CINECA +------------------------------------------------------------------------------- +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::catalystFunctionObject + +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. + + Example of function object specification: + \verbatim + catalyst + { + type catalyst; + libs ("libcatalystFoam.so"); + scripts ( ... ); + executeControl timeStep; + executeInterval 1; + + inputs + { + type default; + regions ( ".*Solid" ) + fields (U p); + } + } + \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 | + \endtable + +Note + The execution frequency can be defined by the functionObject and + by the Catalyst pipeline. + +See also + Foam::functionObjects::functionObject + Foam::functionObjects::fvMeshFunctionObject + Foam::functionObjects::timeControl + Foam::catalyst::coprocess + Foam::catalyst::cloudInput + Foam::catalyst::faMeshInput + Foam::catalyst::fvMeshInput + +SourceFiles + catalystFunctionObject.C + catalystFunctionObjectTemplates.C + +\*---------------------------------------------------------------------------*/ + +#ifndef functionObjects_catalystFunctionObject_H +#define functionObjects_catalystFunctionObject_H + +#include "className.H" +#include "wordList.H" +#include "stringList.H" +#include "polyMesh.H" +#include "PtrList.H" +#include "functionObject.H" +#include "catalystCoprocess.H" +#include "catalystInput.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ +namespace functionObjects +{ + +/*---------------------------------------------------------------------------*\ + Class catalystFunctionObject Declaration +\*---------------------------------------------------------------------------*/ + +class catalystFunctionObject +: + public functionObject +{ + // Private data + + //- Reference to the time database + const Time& time_; + + //- The output directory + fileName outputDir_; + + //- Python scripts for the catalyst pipeline + stringList scripts_; + + //- The catalyst coprocess + autoPtr<catalyst::coprocess> adaptor_; + + //- Pointers to the requested mesh regions + PtrList<catalyst::catalystInput> inputs_; + + + // Private Member Functions + + //- No copy construct + catalystFunctionObject(const catalystFunctionObject&) = delete; + + //- No copy assignment + void operator=(const catalystFunctionObject&) = delete; + +public: + + // Static Methods + + //- Expand strings as filenames, retaining only those that exist + static label expand(List<string>& scripts, const dictionary& dict); + + + //- Runtime type information + TypeName("catalyst"); + + + // Constructors + + //- Construct from Time and dictionary + catalystFunctionObject + ( + const word& name, + const Time& runTime, + const dictionary& dict + ); + + + //- Destructor + virtual ~catalystFunctionObject(); + + + // Member Functions + + //- Read the specification + virtual bool read(const dictionary& dict); + + //- Execute catalyst pipelines + virtual bool execute(); + + //- Write - does nothing + virtual bool write(); + + //- On end - provide feedback about disconnecting from catatyst. + virtual bool end(); + + //- Update for changes of mesh + virtual void updateMesh(const mapPolyMesh& mpm); + + //- Update for mesh point-motion + virtual void movePoints(const polyMesh& mesh); + +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace functionObjects +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/catalyst/catalystInput.C b/src/catalyst/catalystInput.C new file mode 100644 index 0000000000000000000000000000000000000000..4b1645d454d901ed6e888269eccf962ff8234e61 --- /dev/null +++ b/src/catalyst/catalystInput.C @@ -0,0 +1,95 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2018 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +#include "catalystInput.H" +#include "dictionary.H" +#include "Time.H" +#include "addToRunTimeSelectionTable.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ +namespace catalyst +{ + defineTypeNameAndDebug(catalystInput, 0); + defineRunTimeSelectionTable(catalystInput, dictionary); +} +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::catalyst::catalystInput::catalystInput(const word& channel) +: + name_(channel) +{} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +Foam::autoPtr<Foam::catalyst::catalystInput> +Foam::catalyst::catalystInput::New +( + const word& name, + const Time& runTime, + const dictionary& dict +) +{ + const word sourceType = dict.lookupOrDefault<word>("type", "default"); + + auto cstrIter = dictionaryConstructorTablePtr_->cfind(sourceType); + + if (!cstrIter.found()) + { + FatalErrorInFunction + << "Unknown catalystInput " + << sourceType << nl << nl + << "Valid sources : " << endl + << dictionaryConstructorTablePtr_->sortedToc() + << exit(FatalError); + } + + return autoPtr<catalystInput>(cstrIter()(name, runTime, dict)); +} + + +bool Foam::catalyst::catalystInput::read(const dictionary&) +{ + return true; +} + + +void Foam::catalyst::catalystInput::update(polyMesh::readUpdateState state) +{} + + +Foam::Ostream& Foam::catalyst::catalystInput::print(Ostream& os) const +{ + return os; +} + + +// ************************************************************************* // diff --git a/src/catalyst/catalystInput.H b/src/catalyst/catalystInput.H new file mode 100644 index 0000000000000000000000000000000000000000..f709f0035648ef94bf88b331ebb9a896045ff78b --- /dev/null +++ b/src/catalyst/catalystInput.H @@ -0,0 +1,150 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2018 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::catalystInput + +Description + An OpenFOAM source for Paraview Catalyst. + +See also + Foam::catalyst::coprocess + Foam::catalyst::dataQuery + Foam::catalyst::timeQuery + +SourceFiles + catalystInput.C + +\*---------------------------------------------------------------------------*/ + +#ifndef catalyst_catalystInput_H +#define catalyst_catalystInput_H + +#include "className.H" +#include "polyMesh.H" +#include "runTimeSelectionTables.H" +#include "catalystTools.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ + +// Forward declarations +class dictionary; +class mapPolyMesh; +class Time; + +namespace catalyst +{ + +/*---------------------------------------------------------------------------*\ + Class catalyst::catalystInput Declaration +\*---------------------------------------------------------------------------*/ + +class catalystInput +{ + // Private data + + //- The name of the source + word name_; + +public: + + // Declare run-time constructor selection table + + declareRunTimeSelectionTable + ( + autoPtr, + catalystInput, + dictionary, + ( + const word& name, + const Time& runTime, + const dictionary& dict + ), + (name, runTime, dict) + ); + + + // Selectors + + //- Return a reference to the selected source + static autoPtr<catalystInput> New + ( + const word& name, + const Time& runTime, + const dictionary& dict + ); + + + //- Runtime type information + ClassName("catalyst::input"); + + + // Constructors + + //- Construct with given channel name + explicit catalystInput(const word& channel); + + + //- Destructor + virtual ~catalystInput() = default; + + + // Member Functions + + //- The name of the source (channel) + virtual const word& name() const + { + return name_; + } + + //- Read the specification + virtual bool read(const dictionary& dict); + + //- Update for changes of mesh or mesh point-motion + virtual void update(polyMesh::readUpdateState state); + + //- Add channels (with fields) to data query + virtual label addChannels(dataQuery& dataq) = 0; + + //- Convert channels to vtkMultiBlockDataSet outputs + virtual bool convert(dataQuery& dataq, outputChannels& outputs) = 0; + + + //- Print information + virtual Ostream& print(Ostream& os) const; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace catalyst +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/catalyst/catalystTools.C b/src/catalyst/catalystTools.C new file mode 100644 index 0000000000000000000000000000000000000000..9ab35b7ba19247f8c61bed97ab60e8b19fff0b67 --- /dev/null +++ b/src/catalyst/catalystTools.C @@ -0,0 +1,233 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2018 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. +\*---------------------------------------------------------------------------*/ + +#include "catalystTools.H" +#include "Time.H" + +#include <vtkCPDataDescription.h> +#include <vtkCPInputDataDescription.h> +#include <vtkCPProcessor.h> + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +const Foam::wordHashSet Foam::catalyst::dataQuery::emptyWordHash_; + +// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * // + +void Foam::catalyst::printInfo(Ostream& os, vtkCPDataDescription* descrip) +{ + if (!descrip) + { + return; + } + + const unsigned nItems = descrip->GetNumberOfInputDescriptions(); + + for (unsigned itemi = 0; itemi < nItems; ++itemi) + { + vtkCPInputDataDescription* input = descrip->GetInputDescription(itemi); + if (!input) continue; // should not happen + + os <<"input: " << descrip->GetInputDescriptionName(itemi) << nl; + + const unsigned nFields = input->GetNumberOfFields(); + for (unsigned fieldi = 0; fieldi < nFields; ++fieldi) + { + os << " field: " << input->GetFieldName(fieldi) << nl; + } + if (!nFields) os <<" no fields requested" << nl; + } +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::catalyst::timeQuery::timeQuery(const Foam::Time& when) +: + timeValue(when.timeOutputValue()), + timeIndex(when.timeIndex()), + forced(when.timeOutputValue() >= when.endTime().value()) +{} + + +Foam::catalyst::dataQuery::dataQuery(const Foam::Time& when) +: + timeQuery(when), + names_(), + fields_(), + active_(), + descrip_(vtkCPDataDescription::New()) +{} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::catalyst::dataQuery::~dataQuery() +{ + descrip_->Delete(); +} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +void Foam::catalyst::dataQuery::set +( + const fileName& channel, + const wordHashSet& fields +) +{ + auto iter = fields_.find(channel); + + if (iter.found()) + { + *iter = fields; + } + else + { + active_.insert(names_.size()); + fields_.insert(channel, fields); + names_.append(channel); + } +} + + +Foam::label Foam::catalyst::dataQuery::query(vtkCPProcessor* coproc) +{ + dataQuery& dataq = *this; + + if (!coproc) + { + Info<< "No ParaView Catalyst initialized" << endl; + dataq.clear(); + return dataq.size(); + } + + if (dataq.empty()) + { + // No channels names have been published by the simulation + return dataq.size(); + } + + vtkCPDataDescription* descrip = dataq.description(); + + descrip->SetTimeData(dataq.timeValue, dataq.timeIndex); + descrip->SetForceOutput(dataq.forced); + + const List<fileName> inputNames(dataq.names()); + + // Sort out which channels already exist, are new, or disappeared + + // The currently defined channels + HashSet<fileName> currChannels; + + const unsigned n = descrip->GetNumberOfInputDescriptions(); + for (unsigned i=0; i < n; ++i) + { + currChannels.insert + ( + fileName::validate(descrip->GetInputDescriptionName(i)) + ); + } + + HashSet<fileName> oldChannels(currChannels); + oldChannels.eraseMany(inputNames); + + if (oldChannels.size()) + { + // Some channels disappear - remove and redo everything + descrip->ResetAll(); + currChannels.clear(); + } + + // Add channels. + + // Note: this misses updating field information for previously + // existing inputs. + + for (const fileName& channel : inputNames) + { + if (currChannels.found(channel)) + { + continue; + } + + descrip->AddInput(channel.c_str()); + auto* input = + descrip->GetInputDescriptionByName(channel.c_str()); + + for (const word& fieldName : dataq.fields(channel)) + { + input->AddPointField(fieldName.c_str()); + input->AddCellField(fieldName.c_str()); + } + } + + if + ( + !coproc->RequestDataDescription(descrip) + || !descrip->GetIfAnyGridNecessary() + ) + { + dataq.clear(); + return dataq.size(); + } + + for (const fileName& channel : inputNames) + { + auto* input = descrip->GetInputDescriptionByName(channel.c_str()); + + if (input && input->GetIfGridIsNecessary()) + { + wordHashSet requestedFields; + + for (const word& fieldName : dataq.fields(channel)) + { + if (input->IsFieldNeeded(fieldName.c_str())) + { + requestedFields.insert(fieldName); + } + } + + dataq.set(channel, requestedFields); + } + else + { + dataq.clear(channel); + } + } + + return dataq.size(); +} + + +// * * * * * * * * * * * * * * * Ostream Operator * * * * * * * * * * * * * // + +Foam::Ostream& Foam::operator<<(Ostream& os, const catalyst::timeQuery& when) +{ + os << "Time = " << when.timeValue << ", index: " << when.timeIndex; + return os; +} + + +// ************************************************************************* // diff --git a/src/catalyst/catalystTools.H b/src/catalyst/catalystTools.H new file mode 100644 index 0000000000000000000000000000000000000000..a47fedc6c4041d82e1aa73b86ed198ae549dd82b --- /dev/null +++ b/src/catalyst/catalystTools.H @@ -0,0 +1,204 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2018 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Class + Foam::catalyst::timeQuery + +Description + Low-level handling for time queries + +SourceFiles + catalystTools.C + +\*---------------------------------------------------------------------------*/ + +#ifndef functionObjects_catalystTools_H +#define functionObjects_catalystTools_H + +#include "wordList.H" +#include "stringList.H" +#include "DynamicList.H" +#include "HashSet.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +// Forward declarations +class vtkCPDataDescription; +class vtkCPProcessor; +class vtkMultiBlockDataSet; +template<class T> class vtkSmartPointer; + +namespace Foam +{ + +// Forward declarations +class Ostream; +class Time; + +namespace catalyst +{ + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +//- Container holding VTK outputs per Catalyst channel name +typedef + HashTable<vtkSmartPointer<vtkMultiBlockDataSet>, fileName> + outputChannels; + + +//- Print information about data description +void printInfo(Ostream& os, vtkCPDataDescription* descrip); + + +/*---------------------------------------------------------------------------*\ + Class catalyst::timeQuery Declaration +\*---------------------------------------------------------------------------*/ + +//- Simple structure for time queries +struct timeQuery +{ + double timeValue; + long timeIndex; + bool forced; + + constexpr timeQuery + ( + double val, + long index, + bool forcedOutput=false + ) noexcept + : + timeValue(val), + timeIndex(index), + forced(forcedOutput) + {} + + timeQuery(const Foam::Time& currTime); +}; + + +/*---------------------------------------------------------------------------*\ + Class catalyst::dataQuery Declaration +\*---------------------------------------------------------------------------*/ + +//- Simple structure for data description queries +class dataQuery +: + public timeQuery +{ + //- Catalyst channel names for query, in the order of addition + DynamicList<fileName> names_; + + //- Fields per channel + HashTable<wordHashSet, fileName> fields_; + + //- Indices (into names_) of active channels + labelHashSet active_; + + //- The data description + vtkCPDataDescription* descrip_; + + //- Empty dummy hash of field names + static const wordHashSet emptyWordHash_; + + + //- No copy construct + dataQuery(const dataQuery&) = delete; + + //- No copy assignment + void operator=(const dataQuery&) = delete; + + +public: + + // Constructors + + //- Construct query for given time. Add channels later + dataQuery(const Foam::Time& when); + + + //- Destructor + ~dataQuery(); + + + // Member Functions + + //- Pointer to coprocess data description + inline vtkCPDataDescription* description() const; + + //- Clear the channel information + inline void clear(); + + //- Empty if there are no active channels + inline bool empty() const; + + //- The number of active channels + inline label size() const; + + //- True if given channel exists (in fields or active) + inline bool found(const fileName& channel) const; + + //- The active channel numbers + inline List<label> active() const; + + //- The channel names + inline List<fileName> names() const; + + //- Fields for the given channel + inline const wordHashSet& fields(const fileName& channel) const; + + //- Clear the specified channel + inline void clear(const fileName& channel); + + //- Set fields for the specified channel and make it active + void set(const fileName& channel, const wordHashSet& fields); + + //- Query coprocess, transform defined input channels to + //- known requests. + // On input the dataQuery contains the channel names and their + // associated published fields. + // On output, retains the requested channels only. + label query(vtkCPProcessor* coproc); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace catalyst + + +// Ostream Operator +Ostream& operator<<(Ostream& os, const catalyst::timeQuery& when); + + +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#include "catalystToolsI.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/catalyst/catalystToolsI.H b/src/catalyst/catalystToolsI.H new file mode 100644 index 0000000000000000000000000000000000000000..3997b7d429344669f4172abffb7d231447d916ae --- /dev/null +++ b/src/catalyst/catalystToolsI.H @@ -0,0 +1,95 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2018 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. +\*---------------------------------------------------------------------------*/ + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +inline vtkCPDataDescription* +Foam::catalyst::dataQuery::description() const +{ + return descrip_; +} + + +inline void Foam::catalyst::dataQuery::clear() +{ + names_.clear(); + fields_.clear(); + active_.clear(); +} + + +inline bool Foam::catalyst::dataQuery::empty() const +{ + return active_.empty(); +} + + +inline Foam::label Foam::catalyst::dataQuery::size() const +{ + return active_.size(); +} + + +inline bool Foam::catalyst::dataQuery::found +( + const fileName& channel +) const +{ + return fields_.found(channel); +} + + +inline Foam::List<Foam::label> Foam::catalyst::dataQuery::active() const +{ + return active_.sortedToc(); +} + + +inline Foam::List<Foam::fileName> Foam::catalyst::dataQuery::names() const +{ + return List<fileName>(names_, active_.sortedToc()); +} + + +inline const Foam::wordHashSet& +Foam::catalyst::dataQuery::fields(const fileName& channel) const +{ + const auto iter = fields_.cfind(channel); + if (iter.found()) + { + return *iter; + } + + return emptyWordHash_; +} + + +inline void Foam::catalyst::dataQuery::clear(const fileName& channel) +{ + fields_.erase(channel); + active_.erase(names_.find(channel)); +} + + +// ************************************************************************* // diff --git a/src/catalyst/cloud/catalystCloud.C b/src/catalyst/cloud/catalystCloud.C index 206e769cabad8a85eb0bc138592eaf0e849c5b7a..58e8faec6a7b9507ec852a8d597ef84a253c61e3 100644 --- a/src/catalyst/cloud/catalystCloud.C +++ b/src/catalyst/cloud/catalystCloud.C @@ -24,12 +24,10 @@ License \*---------------------------------------------------------------------------*/ #include "catalystCloud.H" -#include "catalystCoprocess.H" #include "cloud.H" #include "foamVtkCloudAdaptor.H" #include "addToRunTimeSelectionTable.H" -#include <vtkNew.h> #include <vtkCPDataDescription.h> #include <vtkMultiBlockDataSet.h> #include <vtkInformation.h> @@ -38,97 +36,47 @@ License namespace Foam { -namespace functionObjects +namespace catalyst { - defineTypeNameAndDebug(catalystCloud, 0); - addToRunTimeSelectionTable(functionObject, catalystCloud, dictionary); + defineTypeNameAndDebug(cloudInput, 0); + addNamedToRunTimeSelectionTable + ( + catalystInput, + cloudInput, + dictionary, + cloud + ); } } -// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // - -bool Foam::functionObjects::catalystCloud::readBasics(const dictionary& dict) -{ - int debugLevel = 0; - if (dict.readIfPresent("debug", debugLevel)) - { - catalystCoprocess::debug = debugLevel; - } - - if (Pstream::master()) - { - fileName dir; - if (dict.readIfPresent("mkdir", dir)) - { - dir.expand(); - dir.clean(); - } - Foam::mkDir(dir); - } - - dict.readIfPresent("outputDir", outputDir_); - outputDir_.expand(); - outputDir_.clean(); - if (Pstream::master()) - { - Foam::mkDir(outputDir_); - } - - dict.lookup("scripts") >> scripts_; // Python scripts - catalystCoprocess::expand(scripts_, dict); // Expand and check availability - - if (adaptor_.valid()) - { - // Run-time modification of pipeline - adaptor_().reset(outputDir_, scripts_); - } - - return true; -} - - // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // -Foam::functionObjects::catalystCloud::catalystCloud +Foam::catalyst::cloudInput::cloudInput ( const word& name, const Time& runTime, const dictionary& dict ) : - fvMeshFunctionObject(name, runTime, dict), - outputDir_("<case>/insitu"), - scripts_(), - adaptor_(), + catalystInput(name), + time_(runTime), + regionName_(), selectClouds_(), selectFields_() { - if (postProcess) - { - // Disable for post-process mode. - // Emit as FatalError for the try/catch in the caller. - FatalError - << type() << " disabled in post-process mode" - << exit(FatalError); - } read(dict); } -// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // - -Foam::functionObjects::catalystCloud::~catalystCloud() -{} - - // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -bool Foam::functionObjects::catalystCloud::read(const dictionary& dict) +bool Foam::catalyst::cloudInput::read(const dictionary& dict) { - fvMeshFunctionObject::read(dict); + catalystInput::read(dict); - readBasics(dict); + regionName_ = + dict.lookupOrDefault<word>("region", polyMesh::defaultRegion); selectClouds_.clear(); dict.readIfPresent("clouds", selectClouds_); @@ -143,116 +91,101 @@ bool Foam::functionObjects::catalystCloud::read(const dictionary& dict) selectFields_.clear(); dict.readIfPresent("fields", selectFields_); - Info<< type() << " " << name() << ":" << nl - <<" clouds " << flatOutput(selectClouds_) << nl - <<" fields " << flatOutput(selectFields_) << nl - <<" scripts " << scripts_ << nl; - return true; } -bool Foam::functionObjects::catalystCloud::execute() +Foam::label Foam::catalyst::cloudInput::addChannels(dataQuery& dataq) { - const wordList cloudNames(mesh_.sortedNames<cloud>(selectClouds_)); - - if (cloudNames.empty()) - { - return true; - } + const fvMesh& fvm = time_.lookupObject<fvMesh>(regionName_); - // Enforce sanity for backends and adaptor + if (fvm.names<cloud>(selectClouds_).empty()) { - if (!adaptor_.valid()) - { - adaptor_.reset(new catalystCoprocess()); - adaptor_().reset(outputDir_, scripts_); - } + return 0; } - // Difficult to get the names of the fields from particles // ... need to skip for now wordHashSet allFields; + dataq.set(name(), allFields); - // Data description for co-processing - vtkNew<vtkCPDataDescription> descrip; + return 1; +} - // Form data query for catalyst - catalystCoprocess::dataQuery dataq - ( - vtk::cloudAdaptor::channelNames.names(), - time_, // timeQuery - descrip.Get() - ); - // Query catalyst - const HashTable<wordHashSet> expecting(adaptor_().query(dataq, allFields)); +bool Foam::catalyst::cloudInput::convert +( + dataQuery& dataq, + outputChannels& outputs +) +{ + const fvMesh& fvm = time_.lookupObject<fvMesh>(regionName_); + const wordList cloudNames(fvm.sortedNames<cloud>(selectClouds_)); - if (catalystCoprocess::debug) + if (cloudNames.empty()) { - if (expecting.empty()) - { - Info<< type() << ": expecting no data" << nl; - } - else - { - Info<< type() << ": expecting data " << expecting << nl; - } + return false; // skip - not available } - if (expecting.empty()) + // Single channel only + + label nChannels = 0; + + if (dataq.found(name())) { - return true; + ++nChannels; } - auto output = vtkSmartPointer<vtkMultiBlockDataSet>::New(); + if (!nChannels) + { + return false; // skip - not requested + } // Each cloud in a separate block. - unsigned int cloudNo = 0; + unsigned int blockNo = 0; for (const word& cloudName : cloudNames) { - auto pieces = - vtk::cloudAdaptor(mesh_).getCloud(cloudName, selectFields_); + auto dataset = + vtk::cloudAdaptor(fvm).getCloud(cloudName, selectFields_); - output->SetBlock(cloudNo, pieces); - output->GetMetaData(cloudNo)->Set - ( - vtkCompositeDataSet::NAME(), - cloudName - ); - - ++cloudNo; - } + const fileName channel = name(); - if (cloudNo) - { - Log << type() << ": send data" << nl; + 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(), + cloudName + ); + + outputs.set(channel, block); // overwrites existing + } - adaptor_().process(dataq, output); + ++blockNo; } return true; } -bool Foam::functionObjects::catalystCloud::write() -{ - return true; -} - - -bool Foam::functionObjects::catalystCloud::end() +Foam::Ostream& Foam::catalyst::cloudInput::print(Ostream& os) const { - // Only here for extra feedback - if (log && adaptor_.valid()) - { - Info<< type() << ": Disconnecting ParaView Catalyst..." << nl; - } + os << name() << nl + <<" clouds " << flatOutput(selectClouds_) << nl + <<" fields " << flatOutput(selectFields_) << nl; - adaptor_.clear(); - return true; + return os; } diff --git a/src/catalyst/cloud/catalystCloud.H b/src/catalyst/cloud/catalystCloud.H index 1f81166bbdb43983524878ec66a511806ea7b3cc..ef18d71bf7ef3df3e66485aa0a40daeef7fb1580 100644 --- a/src/catalyst/cloud/catalystCloud.H +++ b/src/catalyst/cloud/catalystCloud.H @@ -22,54 +22,37 @@ License along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. Class - Foam::functionObjects::catalystCloud - -Group - grpUtilitiesFunctionObjects + Foam::catalystCloud Description - A Paraview Catalyst adaptor for a single OpenFOAM cloud (lagrangian). + A Paraview Catalyst source for OpenFOAM clouds (lagrangian). - The output comprises a single "cloud" channel, which is a multi-block - dataset (one block per cloud). + 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. - Example of function object specification: + Example specification: \verbatim - catalystCloud1 + myCloud { - type catalyst::cloud; - libs ("libcatalystFoam.so"); + type cloud; cloud NAME; fields (U T rho); - scripts ( ... ); - executeControl timeStep; - executeInterval 1; } \endverbatim Usage \table - Property | Description | Required | Default value - type | catalyst::cloud | yes | - log | report extra information | no | false - mkdir | initial directory to create | no | + Property | Description | Required | Default + type | cloud | yes | + region | | no | region0 cloud | | no | defaultCloud clouds | wordRe list of clouds | no | - region | | no | region0 - regions | wordRe list of regions | no | fields | wordRe list of fields | yes | - scripts | Python pipeline scripts | yes | \endtable -Note - The execution frequency can be defined by the functionObject and - by the Catalyst pipeline. - See also - Foam::functionObjects::functionObject - Foam::functionObjects::fvMeshFunctionObject - Foam::functionObjects::timeControl - Foam::catalystCoprocess + Foam::catalyst::catalystInput Foam::vtk::cloudAdaptor SourceFiles @@ -78,45 +61,36 @@ SourceFiles \*---------------------------------------------------------------------------*/ -#ifndef functionObjects_catalystCloud_H -#define functionObjects_catalystCloud_H +#ifndef catalyst_cloudInput_H +#define catalyst_cloudInput_H -#include "fvMeshFunctionObject.H" #include "wordRes.H" +#include "catalystInput.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // namespace Foam { - -// Forward declarations - -class catalystCoprocess; - -namespace functionObjects +namespace catalyst { /*---------------------------------------------------------------------------*\ - Class catalystCloud Declaration + Class catalyst::cloudInput Declaration \*---------------------------------------------------------------------------*/ -class catalystCloud +class cloudInput : - public fvMeshFunctionObject + public catalystInput { protected: // Protected data - //- The output directory - fileName outputDir_; - - //- Python scripts for the catalyst pipeline - stringList scripts_; - - //- The catalyst coprocess - autoPtr<catalystCoprocess> adaptor_; + //- Reference to the time database + const Time& time_; + //- The region name for the clouds + word regionName_; //- Requested names of clouds to process wordRes selectClouds_; @@ -127,26 +101,22 @@ protected: // Protected Member Functions - //- Common boilerplate settings - bool readBasics(const dictionary& dict); - - //- No copy construct - catalystCloud(const catalystCloud&) = delete; + cloudInput(const cloudInput&) = delete; //- No copy assignment - void operator=(const catalystCloud&) = delete; + void operator=(const cloudInput&) = delete; public: //- Runtime type information - TypeName("catalyst::cloud"); + ClassName("catalyst::cloud"); // Constructors //- Construct from Time and dictionary - catalystCloud + cloudInput ( const word& name, const Time& runTime, @@ -155,7 +125,7 @@ public: //- Destructor - virtual ~catalystCloud(); + virtual ~cloudInput() = default; // Member Functions @@ -163,20 +133,20 @@ public: //- Read the specification virtual bool read(const dictionary& dict); - //- Execute catalyst pipelines - virtual bool execute(); + //- Add available channels (with fields) to data query + virtual label addChannels(dataQuery& dataq); - //- Write - does nothing - virtual bool write(); + //- Convert channels to vtkMultiBlockDataSet outputs + virtual bool convert(dataQuery& dataq, outputChannels& outputs); - //- On end - provide feedback about disconnecting from catatyst. - virtual bool end(); + //- Print information + virtual Ostream& print(Ostream& os) const; }; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -} // End namespace functionObjects +} // End namespace catalyst } // End namespace Foam // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/catalyst/cloud/foamVtkCloudAdaptor.C b/src/catalyst/cloud/foamVtkCloudAdaptor.C index 184196f9f0259a74122376b50a60f605db37c5c5..e9b8b5e76ea3acd36c75a3da6be8b9d300b43880 100644 --- a/src/catalyst/cloud/foamVtkCloudAdaptor.C +++ b/src/catalyst/cloud/foamVtkCloudAdaptor.C @@ -37,14 +37,13 @@ License // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // -const Foam::Enum -< - Foam::vtk::cloudAdaptor::channel -> -Foam::vtk::cloudAdaptor::channelNames +namespace Foam { - { channel::CLOUD, "cloud" }, -}; +namespace vtk +{ + defineTypeNameAndDebug(cloudAdaptor, 0); +} +} // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // diff --git a/src/catalyst/cloud/foamVtkCloudAdaptor.H b/src/catalyst/cloud/foamVtkCloudAdaptor.H index d8c6de02bfeed4835990fdbb76eabca54016965d..72374e9943a06917db1a43c98b7206dd25ba95b8 100644 --- a/src/catalyst/cloud/foamVtkCloudAdaptor.H +++ b/src/catalyst/cloud/foamVtkCloudAdaptor.H @@ -42,8 +42,8 @@ SourceFiles #ifndef foamVtkCloudAdaptor_H #define foamVtkCloudAdaptor_H +#include "className.H" #include "fvMesh.H" -#include "Enum.H" #include "foamVtkTools.H" #include <vtkPolyData.h> @@ -63,22 +63,7 @@ namespace vtk class cloudAdaptor { -public: - - //- Public Data - - //- The Catalyst output channels - enum class channel - { - CLOUD - }; - - static const Enum<channel> channelNames; - - -private: - - // Private Data + // Private data const fvMesh& mesh_; @@ -120,6 +105,11 @@ private: public: + //- Static Data Members + + ClassName("vtk::cloudAdaptor"); + + // Constructors //- Construct for a particular mesh region diff --git a/src/catalyst/volMesh/catalystFvMesh.C b/src/catalyst/volMesh/catalystFvMesh.C index 22e86889c784882a0728a5289f3f9f70c91e04ec..bb7fcb95c436efa5b4ac1d2c838f91373ac44e33 100644 --- a/src/catalyst/volMesh/catalystFvMesh.C +++ b/src/catalyst/volMesh/catalystFvMesh.C @@ -24,10 +24,9 @@ License \*---------------------------------------------------------------------------*/ #include "catalystFvMesh.H" -#include "catalystCoprocess.H" #include "addToRunTimeSelectionTable.H" +#include "fileNameList.H" -#include <vtkNew.h> #include <vtkCPDataDescription.h> #include <vtkMultiBlockDataSet.h> #include <vtkInformation.h> @@ -36,76 +35,50 @@ License namespace Foam { -namespace functionObjects +namespace catalyst { - defineTypeNameAndDebug(catalystFvMesh, 0); - addToRunTimeSelectionTable(functionObject, catalystFvMesh, dictionary); + defineTypeNameAndDebug(fvMeshInput, 0); + addNamedToRunTimeSelectionTable + ( + catalystInput, + fvMeshInput, + dictionary, + default + ); } } // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // -bool Foam::functionObjects::catalystFvMesh::readBasics(const dictionary& dict) +Foam::fileName Foam::catalyst::fvMeshInput::channelName(channelEnum chan) const { - int debugLevel = 0; - if (dict.readIfPresent("debug", debugLevel)) - { - catalystCoprocess::debug = debugLevel; - } - - if (Pstream::master()) + if (chan == channelEnum::INPUT) { - fileName dir; - if (dict.readIfPresent("mkdir", dir)) - { - dir.expand(); - dir.clean(); - } - Foam::mkDir(dir); + return name(); } - dict.readIfPresent("outputDir", outputDir_); - outputDir_.expand(); - outputDir_.clean(); - if (Pstream::master()) - { - Foam::mkDir(outputDir_); - } - - dict.lookup("scripts") >> scripts_; // Python scripts - catalystCoprocess::expand(scripts_, dict); // Expand and check availability - - if (adaptor_.valid()) - { - // Run-time modification of pipeline - adaptor_().reset(outputDir_, scripts_); - } - - return true; + return name()/vtk::fvMeshAdaptor::channelNames[chan]; } -void Foam::functionObjects::catalystFvMesh::updateState -( - polyMesh::readUpdateState state -) +void Foam::catalyst::fvMeshInput::update() { - // Trigger change of state - - // Be really paranoid and verify if the mesh actually exists - const wordList regionNames(backends_.toc()); + // Backend requires a corresponding mesh + backends_.filterKeys + ( + [this](const word& k){ return meshes_.found(k); } + ); - for (const word& regionName : regionNames) + forAllConstIters(meshes_, iter) { - if (meshes_.found(regionName) && time_.found(regionName)) - { - backends_[regionName]->updateState(state); - } - else + if (!backends_.found(iter.key())) { - backends_.erase(regionName); - meshes_.erase(regionName); + backends_.insert + ( + iter.key(), + new Foam::vtk::fvMeshAdaptor(*(iter.object()), decompose_) + ); } } } @@ -113,52 +86,39 @@ void Foam::functionObjects::catalystFvMesh::updateState // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // -Foam::functionObjects::catalystFvMesh::catalystFvMesh +Foam::catalyst::fvMeshInput::fvMeshInput ( const word& name, const Time& runTime, const dictionary& dict ) : - functionObject(name), + catalystInput(name), time_(runTime), - outputDir_("<case>/insitu"), - scripts_(), - adaptor_(), selectRegions_(), selectFields_(), + decompose_(false), meshes_(), backends_() { - if (postProcess) - { - // Disable for post-process mode. - // Emit as FatalError for the try/catch in the caller. - FatalError - << type() << " disabled in post-process mode" - << exit(FatalError); - } read(dict); } -// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // - -Foam::functionObjects::catalystFvMesh::~catalystFvMesh() -{} - - // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // -bool Foam::functionObjects::catalystFvMesh::read(const dictionary& dict) +bool Foam::catalyst::fvMeshInput::read(const dictionary& dict) { - functionObject::read(dict); - readBasics(dict); + catalystInput::read(dict); + + backends_.clear(); + selectFields_.clear(); + selectRegions_.clear(); + decompose_ = dict.lookupOrDefault("decompose", false); // All possible meshes meshes_ = time_.lookupClass<fvMesh>(); - selectRegions_.clear(); dict.readIfPresent("regions", selectRegions_); if (selectRegions_.empty()) @@ -169,58 +129,46 @@ bool Foam::functionObjects::catalystFvMesh::read(const dictionary& dict) } // Restrict to specified meshes - meshes_.filterKeys(wordRes(selectRegions_)); + meshes_.filterKeys(selectRegions_); dict.lookup("fields") >> selectFields_; - Info<< type() << " " << name() << ":" << nl - <<" regions " << flatOutput(selectRegions_) << nl - <<" meshes " << flatOutput(meshes_.sortedToc()) << nl - <<" fields " << flatOutput(selectFields_) << nl - <<" scripts " << scripts_ << nl; - - // Ensure consistency - only retain backends with corresponding mesh region - backends_.retain(meshes_); - return true; } -bool Foam::functionObjects::catalystFvMesh::execute() +void Foam::catalyst::fvMeshInput::update(polyMesh::readUpdateState state) { - const wordList regionNames(meshes_.sortedToc()); + // Trigger change of state - if (regionNames.empty()) - { - return false; - } + // Be really paranoid and verify if the mesh actually exists + const wordList regionNames(backends_.toc()); - // Enforce sanity for backends and adaptor + for (const word& regionName : regionNames) { - bool updateAdaptor = false; - forAllConstIters(meshes_, iter) + if (meshes_.found(regionName) && time_.found(regionName)) { - if (!backends_.found(iter.key())) - { - backends_.insert - ( - iter.key(), - new Foam::vtk::fvMeshAdaptor(*(iter.object())) - ); - updateAdaptor = true; - } + backends_[regionName]->updateState(state); } - - if (updateAdaptor && !adaptor_.valid()) + else { - adaptor_.reset(new catalystCoprocess()); - adaptor_().reset(outputDir_, scripts_); + backends_.erase(regionName); + meshes_.erase(regionName); } } +} - // Gather all fields that we know how to convert +Foam::label Foam::catalyst::fvMeshInput::addChannels(dataQuery& dataq) +{ + update(); // Enforce sanity for backends and adaptor + + if (backends_.empty()) + { + return 0; + } + // Gather all fields that we know how to convert wordHashSet allFields; forAllConstIters(backends_, iter) { @@ -228,178 +176,168 @@ bool Foam::functionObjects::catalystFvMesh::execute() } - // Data description for co-processing - vtkNew<vtkCPDataDescription> descrip; + // This solution may be a temporary measure... - // Form data query for catalyst - catalystCoprocess::dataQuery dataq - ( - vtk::fvMeshAdaptor::channelNames.names(), - time_, // timeQuery - descrip.Get() - ); + dataq.set(name(), allFields); // channel::INPUT + dataq.set(channelName(channelEnum::MESH), allFields); + dataq.set(channelName(channelEnum::PATCHES), allFields); - // Query catalyst - const HashTable<wordHashSet> expecting(adaptor_().query(dataq, allFields)); + return 3; +} - if (catalystCoprocess::debug) + +bool Foam::catalyst::fvMeshInput::convert +( + dataQuery& dataq, + outputChannels& outputs +) +{ + const wordList regionNames(backends_.sortedToc()); + + if (regionNames.empty()) { - if (expecting.empty()) - { - Info<< type() << ": expecting no data" << nl; - } - else - { - Info<< type() << ": expecting data " << expecting << nl; - } + return false; // skip - not available } - if (expecting.empty()) + // Multi-channel + + // This solution may be a temporary measure... + + unsigned whichChannels = channelEnum::NONE; + + // channel::INPUT + if (dataq.found(name())) { - return true; + whichChannels |= channelEnum::INPUT; + } + + // channel::MESH + if (dataq.found(channelName(channelEnum::MESH))) + { + whichChannels |= channelEnum::MESH; + } + + // channel::PATCHES + if (dataq.found(channelName(channelEnum::PATCHES))) + { + whichChannels |= channelEnum::PATCHES; + } + + if (channelEnum::NONE == whichChannels) + { + return false; // skip - not requested } - HashTable<vtkSmartPointer<vtkMultiBlockDataSet>> outputs; // TODO: currently don't rely on the results from expecting much at all - // Each region in a separate block. - unsigned int regionNo = 0; + // Each region goes into a separate block. + unsigned int blockNo = 0; for (const word& regionName : regionNames) { - // (re)define output channels - backends_[regionName]->channels(expecting.toc()); + // define/redefine output channels + backends_[regionName]->channels(whichChannels); vtkSmartPointer<vtkMultiBlockDataSet> dataset = backends_[regionName]->output(selectFields_); + // MESH = block 0 { - const unsigned int channelNo = 0; // MESH + const unsigned int channelNo = 0; - const word& channelName = - vtk::fvMeshAdaptor::channelNames - [vtk::fvMeshAdaptor::channel::MESH]; + const fileName channel(channelName(channelEnum::MESH)); - if (expecting.found(channelName)) + if (dataq.found(channel)) { // Get existing or new vtkSmartPointer<vtkMultiBlockDataSet> block = outputs.lookup ( - channelName, + channel, vtkSmartPointer<vtkMultiBlockDataSet>::New() ); - block->SetBlock(regionNo, dataset->GetBlock(channelNo)); + block->SetBlock(blockNo, dataset->GetBlock(channelNo)); - block->GetMetaData(regionNo)->Set + block->GetMetaData(blockNo)->Set ( vtkCompositeDataSet::NAME(), regionName ); - outputs.set(channelName, block); // overwrite existing + outputs.set(channel, block); // overwrites existing } } + // PATCHES = block 1 { - const unsigned int channelNo = 1; // PATCHES + const unsigned int channelNo = 1; - const word& channelName = - vtk::fvMeshAdaptor::channelNames - [vtk::fvMeshAdaptor::channel::PATCHES]; + const fileName channel(channelName(channelEnum::PATCHES)); - if (expecting.found(channelName)) + if (dataq.found(channel)) { // Get existing or new vtkSmartPointer<vtkMultiBlockDataSet> block = outputs.lookup ( - channelName, + channel, vtkSmartPointer<vtkMultiBlockDataSet>::New() ); - block->SetBlock(regionNo, dataset->GetBlock(channelNo)); + block->SetBlock(blockNo, dataset->GetBlock(channelNo)); - block->GetMetaData(regionNo)->Set + block->GetMetaData(blockNo)->Set ( vtkCompositeDataSet::NAME(), regionName ); - outputs.set(channelName, block); // overwrite existing + outputs.set(channel, block); // overwrites existing } } + // INPUT { - const word& channelName = - vtk::fvMeshAdaptor::channelNames - [vtk::fvMeshAdaptor::channel::INPUT]; + const fileName channel = name(); - if (expecting.found(channelName)) + if (dataq.found(channel)) { // Get existing or new vtkSmartPointer<vtkMultiBlockDataSet> block = outputs.lookup ( - channelName, + channel, vtkSmartPointer<vtkMultiBlockDataSet>::New() ); - block->SetBlock(regionNo, dataset); + block->SetBlock(blockNo, dataset); - block->GetMetaData(regionNo)->Set + block->GetMetaData(blockNo)->Set ( vtkCompositeDataSet::NAME(), regionName ); - outputs.set(channelName, block); // overwrite existing + outputs.set(channel, block); // overwrites existing } } - ++regionNo; - } - - if (regionNo) - { - Log << type() << ": send data" << nl; - - adaptor_().process(dataq, outputs); - } - - return true; -} - - -bool Foam::functionObjects::catalystFvMesh::write() -{ - return true; -} - - -bool Foam::functionObjects::catalystFvMesh::end() -{ - // Only here for extra feedback - if (log && adaptor_.valid()) - { - Info<< type() << ": Disconnecting ParaView Catalyst..." << nl; + ++blockNo; } - adaptor_.clear(); return true; } -void Foam::functionObjects::catalystFvMesh::updateMesh(const mapPolyMesh&) +Foam::Ostream& Foam::catalyst::fvMeshInput::print(Ostream& os) const { - updateState(polyMesh::TOPO_CHANGE); -} - + os << name() << nl + <<" regions " << flatOutput(selectRegions_) << nl + <<" meshes " << flatOutput(meshes_.sortedToc()) << nl + <<" fields " << flatOutput(selectFields_) << nl; -void Foam::functionObjects::catalystFvMesh::movePoints(const polyMesh&) -{ - updateState(polyMesh::POINTS_MOVED); + return os; } diff --git a/src/catalyst/volMesh/catalystFvMesh.H b/src/catalyst/volMesh/catalystFvMesh.H index 3a59ef7e9ef635b7480110d991550e56209bbc53..82d4fcf1dc53b47258aaca0840b57c4d4c78591d 100644 --- a/src/catalyst/volMesh/catalystFvMesh.H +++ b/src/catalyst/volMesh/catalystFvMesh.H @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2017-2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2018 OpenCFD Ltd. \\/ M anipulation | Copyright (C) 2018 CINECA ------------------------------------------------------------------------------- License @@ -22,52 +22,42 @@ License along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. Class - Foam::functionObjects::catalystFvMesh - -Group - grpUtilitiesFunctionObjects + Foam::catalyst::fvMeshInput Description - A Paraview Catalyst adaptor for OpenFOAM fvMesh regions. + A Paraview Catalyst source for OpenFOAM fvMesh regions. - The output comprises up to three channels ("input", "mesh", "patches"), - each of which is a multi-block dataset. + The source comprises up to three internal channels + ("input", "mesh", "patches"), each of which is a multi-block dataset. + On output, the "input" sub-channel receives the name of the source, + while the "mesh" and "patches" sub-channels are prefixed with the + name of the source. - Example of function object specification: + Example specification: \verbatim - catalyst + myName { - type catalyst; - libs ("libcatalystFoam.so"); + type default; regions ( ".*Solid" ) fields (U p); - scripts ( ... ); - executeControl timeStep; - executeInterval 1; } \endverbatim + Resulting in three output channels: + "myName", "myName/mesh", "myName/patches" + Usage \table - Property | Description | Required | Default - type | catalyst | yes | - log | report extra information | no | false - mkdir | initial directory to create | no | - region | | no | region0 - regions | wordRe list of regions | no | - fields | wordRe list of fields | yes | - scripts | Python pipeline scripts | yes | + Property | Description | Required | Default + type | default | no | default + region | | no | region0 + regions | wordRe list of regions | no | + fields | wordRe list of fields | yes | + decompose | decompose polyhedra | no | false \endtable -Note - The execution frequency can be defined by the functionObject and - by the Catalyst pipeline. - See also - Foam::functionObjects::functionObject - Foam::functionObjects::fvMeshFunctionObject - Foam::functionObjects::timeControl - Foam::catalystCoprocess + Foam::catalyst::catalystInput Foam::vtk::fvMeshAdaptor SourceFiles @@ -76,33 +66,28 @@ SourceFiles \*---------------------------------------------------------------------------*/ -#ifndef functionObjects_catalystFvMesh_H -#define functionObjects_catalystFvMesh_H +#ifndef catalyst_fvMeshInput_H +#define catalyst_fvMeshInput_H -#include "functionObject.H" -#include "foamVtkFvMeshAdaptor.H" #include "wordRes.H" #include "HashPtrTable.H" +#include "catalystInput.H" +#include "foamVtkFvMeshAdaptor.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // namespace Foam { - -// Forward declarations - -class catalystCoprocess; - -namespace functionObjects +namespace catalyst { /*---------------------------------------------------------------------------*\ - Class catalystFvMesh Declaration + Class catalyst::fvMeshInput Declaration \*---------------------------------------------------------------------------*/ -class catalystFvMesh +class fvMeshInput : - public functionObject + public catalystInput { protected: @@ -111,54 +96,49 @@ protected: //- Reference to the time database const Time& time_; - //- The output directory - fileName outputDir_; - - //- Python scripts for the catalyst pipeline - stringList scripts_; - - //- The catalyst coprocess - autoPtr<catalystCoprocess> adaptor_; - - //- Requested names of regions to process wordRes selectRegions_; //- Names of fields to process wordRes selectFields_; + //- Decompose polyhedra + bool decompose_; + //- Pointers to the requested mesh regions HashTable<const fvMesh*> meshes_; //- Backends for OpenFOAM to VTK translation (with internal caching) HashPtrTable<vtk::fvMeshAdaptor> backends_; + //- Use channel enumeration from vtk::fvMeshAdaptor + using channelEnum = vtk::fvMeshAdaptor::channel; - // Protected Member Functions - //- Common boilerplate settings - bool readBasics(const dictionary& dict); + // Protected Member Functions - //- On movement - void updateState(polyMesh::readUpdateState state); + //- Return full channel name + fileName channelName(channelEnum chan) const; + //- Update/synchronize internals with catalyst backends + void update(); //- No copy construct - catalystFvMesh(const catalystFvMesh&) = delete; + fvMeshInput(const fvMeshInput&) = delete; //- No copy assignment - void operator=(const catalystFvMesh&) = delete; + void operator=(const fvMeshInput&) = delete; public: //- Runtime type information - TypeName("catalyst"); + ClassName("catalyst::fvMesh"); // Constructors //- Construct from Time and dictionary - catalystFvMesh + fvMeshInput ( const word& name, const Time& runTime, @@ -167,7 +147,7 @@ public: //- Destructor - virtual ~catalystFvMesh(); + virtual ~fvMeshInput() = default; // Member Functions @@ -175,27 +155,23 @@ public: //- Read the specification virtual bool read(const dictionary& dict); - //- Execute catalyst pipelines - virtual bool execute(); - - //- Write - does nothing - virtual bool write(); - - //- On end - provide feedback about disconnecting from catatyst. - virtual bool end(); + //- Update for changes of mesh or mesh point-motion + virtual void update(polyMesh::readUpdateState state); - //- Update for changes of mesh - virtual void updateMesh(const mapPolyMesh& mpm); + //- Add available channels (with fields) to data query + virtual label addChannels(dataQuery& dataq); - //- Update for mesh point-motion - virtual void movePoints(const polyMesh& mesh); + //- Convert channels to vtkMultiBlockDataSet outputs + virtual bool convert(dataQuery& dataq, outputChannels& outputs); + //- Print information + virtual Ostream& print(Ostream& os) const; }; // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -} // End namespace functionObjects +} // End namespace catalyst } // End namespace Foam // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/catalyst/volMesh/foamVtkFvMeshAdaptor.C b/src/catalyst/volMesh/foamVtkFvMeshAdaptor.C index 180bacd2883f06d19f7ebd575baec22e3258a55f..56f5e1a946e995524974097a075cd986bb89b617 100644 --- a/src/catalyst/volMesh/foamVtkFvMeshAdaptor.C +++ b/src/catalyst/volMesh/foamVtkFvMeshAdaptor.C @@ -64,12 +64,13 @@ const Foam::word Foam::vtk::fvMeshAdaptor::internalName("internal"); Foam::vtk::fvMeshAdaptor::fvMeshAdaptor ( - const fvMesh& mesh + const fvMesh& mesh, + const bool decompose ) : mesh_(mesh), channels_(INPUT), - decomposePoly_(false), + decomposePoly_(decompose), meshState_(polyMesh::TOPO_CHANGE) {} @@ -146,9 +147,6 @@ void Foam::vtk::fvMeshAdaptor::updateContent(const wordRes& selectFields) { const bool oldDecomp = decomposePoly_; - // TODO from dictionary - //decomposePoly_ = !reader_->GetUseVTKPolyhedron(); - // Update cached, saved, unneed values. HashSet<string> nowActive; diff --git a/src/catalyst/volMesh/foamVtkFvMeshAdaptor.H b/src/catalyst/volMesh/foamVtkFvMeshAdaptor.H index ab21352382fef553c02d76d980268705bfdc6b06..025f14aefbf4dde5171be8bbc5867fcdb081599a 100644 --- a/src/catalyst/volMesh/foamVtkFvMeshAdaptor.H +++ b/src/catalyst/volMesh/foamVtkFvMeshAdaptor.H @@ -45,8 +45,8 @@ SourceFiles \*---------------------------------------------------------------------------*/ -#ifndef foamVtkFvMeshAdaptor_H -#define foamVtkFvMeshAdaptor_H +#ifndef foamvtk_fvMeshAdaptor_H +#define foamvtk_fvMeshAdaptor_H #include "className.H" #include "fileName.H" @@ -99,6 +99,7 @@ public: //- The Catalyst output channels enum channel { + NONE = 0, MESH = 0x1, PATCHES = 0x2, INPUT = 0x3 @@ -267,7 +268,7 @@ public: // Constructors //- Construct from components - fvMeshAdaptor(const fvMesh& mesh); + fvMeshAdaptor(const fvMesh& mesh, const bool decompose=false); //- Destructor diff --git a/tutorials/finiteArea/sphereSurfactantFoam/sphereTransport/system/catalystArea b/tutorials/finiteArea/sphereSurfactantFoam/sphereTransport/system/catalyst similarity index 53% rename from tutorials/finiteArea/sphereSurfactantFoam/sphereTransport/system/catalystArea rename to tutorials/finiteArea/sphereSurfactantFoam/sphereTransport/system/catalyst index ead19c9e96294f926ed352fcc5f5fd8389faf535..66b2730ddde0157737f3844fe3d427ee705c6963 100644 --- a/tutorials/finiteArea/sphereSurfactantFoam/sphereTransport/system/catalystArea +++ b/tutorials/finiteArea/sphereSurfactantFoam/sphereTransport/system/catalyst @@ -2,20 +2,23 @@ functions { - catalystArea + catalyst { - #includeEtc "caseDicts/postProcessing/catalyst/area.cfg" - - // Selected fields (words or regex) - fields ( ".*" ); - - // Output directory - //mkdir "<case>/images"; - + #includeEtc "caseDicts/insitu/catalyst/catalyst.cfg" scripts ( "<system>/scripts/writeArea.py" ); + + inputs + { + area + { + type area; + + fields ( ".*" ); + } + } } } diff --git a/tutorials/finiteArea/sphereSurfactantFoam/sphereTransport/system/controlDict b/tutorials/finiteArea/sphereSurfactantFoam/sphereTransport/system/controlDict index 338911e4c2ddf4dd97a2b74c9a0f6b89df489bab..2887b91158bad70195b4fd02d5675f7e8c9264d2 100644 --- a/tutorials/finiteArea/sphereSurfactantFoam/sphereTransport/system/controlDict +++ b/tutorials/finiteArea/sphereSurfactantFoam/sphereTransport/system/controlDict @@ -43,6 +43,6 @@ timePrecision 6; runTimeModifiable yes; -#include "catalystArea" +#include "catalyst" // ************************************************************************* // diff --git a/tutorials/finiteArea/sphereSurfactantFoam/sphereTransport/system/scripts/writeArea.py b/tutorials/finiteArea/sphereSurfactantFoam/sphereTransport/system/scripts/writeArea.py index 1911a9da9fc2d9cd404cbe5cb0fdb9cff5290295..93500d1078de369c6279708f763e8584dcfc386e 100644 --- a/tutorials/finiteArea/sphereSurfactantFoam/sphereTransport/system/scripts/writeArea.py +++ b/tutorials/finiteArea/sphereSurfactantFoam/sphereTransport/system/scripts/writeArea.py @@ -6,7 +6,7 @@ from paraview import coprocessing def CreateCoProcessor(): def _CreatePipeline(coprocessor, datadescription): class Pipeline: - input1 = coprocessor.CreateProducer(datadescription, 'input') + input1 = coprocessor.CreateProducer(datadescription, 'area') writer1 = servermanager.writers.XMLMultiBlockDataWriter(Input=input1) coprocessor.RegisterWriter(writer1, filename='area_%t.vtm', freq=2) @@ -18,7 +18,7 @@ def CreateCoProcessor(): self.Pipeline = _CreatePipeline(self, datadescription) coprocessor = CoProcessor() - freqs = {'input': [10]} + freqs = {'area': [10]} coprocessor.SetUpdateFrequencies(freqs) return coprocessor diff --git a/tutorials/heatTransfer/chtMultiRegionFoam/multiRegionHeater/system/catalyst b/tutorials/heatTransfer/chtMultiRegionFoam/multiRegionHeater/system/catalyst index ab49f45b0937627a60c4826359389a55eb4eb364..c8a1e6a71f4019f14e0c59728254dcca1b4b2bb7 100644 --- a/tutorials/heatTransfer/chtMultiRegionFoam/multiRegionHeater/system/catalyst +++ b/tutorials/heatTransfer/chtMultiRegionFoam/multiRegionHeater/system/catalyst @@ -4,19 +4,27 @@ functions { catalyst { - #includeEtc "caseDicts/postProcessing/catalyst/default.cfg" - - // All regions - regions (".*"); - - // Selected fields (words or regex) - fields (T U p); + #includeEtc "<etc>/caseDicts/insitu/catalyst/catalyst.cfg" scripts ( "<system>/scripts/slice1.py" "<system>/scripts/writePatches.py" + // "<etc>/caseDicts/insitu/catalyst/printChannels.py" + // "<etc>/caseDicts/insitu/catalyst/writeAll.py" ); + + inputs + { + region + { + // All regions + regions (".*"); + + // Selected fields (words or regex) + fields (T U p); + } + } } } diff --git a/tutorials/heatTransfer/chtMultiRegionFoam/multiRegionHeater/system/scripts/slice1.py b/tutorials/heatTransfer/chtMultiRegionFoam/multiRegionHeater/system/scripts/slice1.py index 864dba02aebfea515fb6ae4114a70134cc31f386..c3c0feb014ae1ef123bf0ff0a58c19edf64f9f5d 100644 --- a/tutorials/heatTransfer/chtMultiRegionFoam/multiRegionHeater/system/scripts/slice1.py +++ b/tutorials/heatTransfer/chtMultiRegionFoam/multiRegionHeater/system/scripts/slice1.py @@ -6,7 +6,7 @@ from paraview import coprocessing def CreateCoProcessor(): def _CreatePipeline(coprocessor, datadescription): class Pipeline: - mesh = coprocessor.CreateProducer(datadescription, "mesh") + mesh = coprocessor.CreateProducer(datadescription, 'region/mesh') slice1 = Slice(Input=mesh, guiName="Slice1", SliceOffsetValues=[0.0], Triangulatetheslice=1, SliceType="Plane") slice1.SliceType.Offset = 0.0 @@ -34,7 +34,7 @@ def CreateCoProcessor(): self.Pipeline = _CreatePipeline(self, datadescription) coprocessor = CoProcessor() - freqs = {'mesh': [10, 100]} + freqs = {'region/mesh': [10, 100]} coprocessor.SetUpdateFrequencies(freqs) return coprocessor diff --git a/tutorials/heatTransfer/chtMultiRegionFoam/multiRegionHeater/system/scripts/writeMesh.py b/tutorials/heatTransfer/chtMultiRegionFoam/multiRegionHeater/system/scripts/writeMesh.py index c40f022235937f83e1d9cf8adcf010c245bfe3e3..6b8fdd8d236d7e472e042deff20487251b9129a5 100644 --- a/tutorials/heatTransfer/chtMultiRegionFoam/multiRegionHeater/system/scripts/writeMesh.py +++ b/tutorials/heatTransfer/chtMultiRegionFoam/multiRegionHeater/system/scripts/writeMesh.py @@ -6,7 +6,7 @@ from paraview import coprocessing def CreateCoProcessor(): def _CreatePipeline(coprocessor, datadescription): class Pipeline: - input1 = coprocessor.CreateProducer(datadescription, 'mesh') + input1 = coprocessor.CreateProducer(datadescription, 'region/mesh') writer1 = servermanager.writers.XMLMultiBlockDataWriter(Input=input1) coprocessor.RegisterWriter(writer1, filename='mesh_%t.vtm', freq=2) @@ -18,7 +18,7 @@ def CreateCoProcessor(): self.Pipeline = _CreatePipeline(self, datadescription) coprocessor = CoProcessor() - freqs = {'mesh': [10]} + freqs = {'region/mesh': [10]} coprocessor.SetUpdateFrequencies(freqs) return coprocessor diff --git a/tutorials/heatTransfer/chtMultiRegionFoam/multiRegionHeater/system/scripts/writePatches.py b/tutorials/heatTransfer/chtMultiRegionFoam/multiRegionHeater/system/scripts/writePatches.py index 067e41d6d12993ffcc68e1e7946d4a3159366e33..de9def18c5405f87f9bef27bb3f5de15977e73a2 100644 --- a/tutorials/heatTransfer/chtMultiRegionFoam/multiRegionHeater/system/scripts/writePatches.py +++ b/tutorials/heatTransfer/chtMultiRegionFoam/multiRegionHeater/system/scripts/writePatches.py @@ -6,7 +6,7 @@ from paraview import coprocessing def CreateCoProcessor(): def _CreatePipeline(coprocessor, datadescription): class Pipeline: - input1 = coprocessor.CreateProducer(datadescription, 'patches') + input1 = coprocessor.CreateProducer(datadescription, 'region/patches') writer1 = servermanager.writers.XMLMultiBlockDataWriter(Input=input1) coprocessor.RegisterWriter(writer1, filename='patches_%t.vtm', freq=2) @@ -18,7 +18,7 @@ def CreateCoProcessor(): self.Pipeline = _CreatePipeline(self, datadescription) coprocessor = CoProcessor() - freqs = {'patches': [10]} + freqs = {'region/patches': [10]} coprocessor.SetUpdateFrequencies(freqs) return coprocessor diff --git a/tutorials/incompressible/icoFoam/cavity/system/catalyst b/tutorials/incompressible/icoFoam/cavity/system/catalyst index 4d40d140e5d9a17c467391027f57aa8cfb2f5075..ebb77626e199ee2e2373474f22b72ce311efd1e9 100644 --- a/tutorials/incompressible/icoFoam/cavity/system/catalyst +++ b/tutorials/incompressible/icoFoam/cavity/system/catalyst @@ -4,13 +4,7 @@ functions { catalyst { - #includeEtc "caseDicts/postProcessing/catalyst/default.cfg" - - // Regions - // regions ( ); - - // Selected fields (words or regex) - fields (U p); + #includeEtc "caseDicts/insitu/catalyst/catalyst.cfg" scripts ( @@ -24,6 +18,15 @@ functions // For testing: force endTime of catalyst and simulation // timeEnd 0.1; // "/endTime" 0.15; + + inputs + { + region + { + // Selected fields (words or regex) + fields (U p); + } + } } } diff --git a/tutorials/incompressible/icoFoam/cavity/system/scripts/slice1.py b/tutorials/incompressible/icoFoam/cavity/system/scripts/slice1.py index 39d7d28f6bd40ed6b441fd8db2322349b48c9951..7ded1ab34367dbd92b809aa85b2befa17580ab34 100644 --- a/tutorials/incompressible/icoFoam/cavity/system/scripts/slice1.py +++ b/tutorials/incompressible/icoFoam/cavity/system/scripts/slice1.py @@ -6,7 +6,7 @@ from paraview import coprocessing def CreateCoProcessor(): def _CreatePipeline(coprocessor, datadescription): class Pipeline: - input1 = coprocessor.CreateProducer(datadescription, "input") + input1 = coprocessor.CreateProducer(datadescription, 'region') slice1 = Slice(Input=input1, guiName="Slice1", Crinkleslice=0, SliceOffsetValues=[0.0], Triangulatetheslice=1, SliceType="Plane") slice1.SliceType.Offset = 0.0 @@ -26,7 +26,7 @@ def CreateCoProcessor(): # register the writer with coprocessor # and provide it with information such as the filename to use, # how frequently to write the data, etc. - coprocessor.RegisterWriter(meshWriter, filename='fullgrid_%t.vtm', freq=10) + coprocessor.RegisterWriter(meshWriter, filename='region_%t.vtm', freq=10) return Pipeline() @@ -35,7 +35,7 @@ def CreateCoProcessor(): self.Pipeline = _CreatePipeline(self, datadescription) coprocessor = CoProcessor() - freqs = {'input': [10, 100]} + freqs = {'region': [10, 100]} coprocessor.SetUpdateFrequencies(freqs) return coprocessor diff --git a/tutorials/incompressible/icoFoam/cavity/system/scripts/writeMesh.py b/tutorials/incompressible/icoFoam/cavity/system/scripts/writeMesh.py index 576083955b3e07afc416ebc62e7a2d1f653ce11d..443bf24133778f200d0c804de3fec3ea06a1e358 100644 --- a/tutorials/incompressible/icoFoam/cavity/system/scripts/writeMesh.py +++ b/tutorials/incompressible/icoFoam/cavity/system/scripts/writeMesh.py @@ -6,7 +6,7 @@ from paraview import coprocessing def CreateCoProcessor(): def _CreatePipeline(coprocessor, datadescription): class Pipeline: - input1 = coprocessor.CreateProducer(datadescription, "mesh") + input1 = coprocessor.CreateProducer(datadescription, 'region/mesh') writer1 = servermanager.writers.XMLMultiBlockDataWriter(Input=input1) # Register with filename to use, output frequency coprocessor.RegisterWriter(writer1, filename='mesh_%t.vtm', freq=2) @@ -22,7 +22,7 @@ def CreateCoProcessor(): self.Pipeline = _CreatePipeline(self, datadescription) coprocessor = CoProcessor() - freqs = {"mesh": [2]} + freqs = {'region/mesh': [2]} coprocessor.SetUpdateFrequencies(freqs) return coprocessor diff --git a/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/catalyst b/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/catalyst new file mode 100644 index 0000000000000000000000000000000000000000..3a3aba32b637f2ede6ebfd3ee117d35114df15f2 --- /dev/null +++ b/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/catalyst @@ -0,0 +1,39 @@ +// ParaView Catalyst function object for OpenFOAM (-*- C++ -*-) + +functions +{ + catalyst + { + #includeEtc "caseDicts/insitu/catalyst/catalyst.cfg" + + scripts + ( + "<system>/scripts/writeCloud.py" + "<system>/scripts/writePatches.py" + ); + + inputs + { + region + { + type default; + + // Selected fields (words or regex) + fields ( T U p rho ); + } + + cloud + { + type cloud; + + // Selected clouds (words or regex) + clouds ( coalCloud1 limestoneCloud1 ); + + // Selected fields (words or regex) + fields ( T U p rho "Y.*" ); + } + } + } +} + +// ************************************************************************* // diff --git a/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/catalystCloud b/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/catalystCloud deleted file mode 100644 index e9b7336918330cdbbe428c582b9809e27b8e1404..0000000000000000000000000000000000000000 --- a/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/catalystCloud +++ /dev/null @@ -1,22 +0,0 @@ -// ParaView Catalyst function object for OpenFOAM (-*- C++ -*-) - -functions -{ - catalystCloud1 - { - #includeEtc "caseDicts/postProcessing/catalyst/cloud.cfg" - - // Selected clouds (words or regex) - clouds ( coalCloud1 limestoneCloud1 ); - - // Selected fields (words or regex) - fields ( T U p rho "Y.*" ); - - scripts - ( - "<system>/scripts/writeCloud.py" - ); - } -} - -// ************************************************************************* // diff --git a/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/controlDict b/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/controlDict index d1bc650d884f34a5492c7796614a01c9a4afce74..224ef164a53d1dbb7f4b5f5c6f0899feadd5bca4 100644 --- a/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/controlDict +++ b/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/controlDict @@ -51,6 +51,6 @@ maxCo 1.0; maxDeltaT 1; -#include "catalystCloud" +#include "catalyst" // ************************************************************************* // diff --git a/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/scripts/writeCloud.py b/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/scripts/writeCloud.py index db348ea49c18683d31f030958c1237c52921fdb6..e6a98c64ea8262b168d0144817ee5f6a2d5aa56a 100644 --- a/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/scripts/writeCloud.py +++ b/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/scripts/writeCloud.py @@ -6,11 +6,12 @@ from paraview import coprocessing def CreateCoProcessor(): def _CreatePipeline(coprocessor, datadescription): class Pipeline: - input1 = coprocessor.CreateProducer(datadescription, 'cloud') + name1 = 'cloud' + input1 = coprocessor.CreateProducer(datadescription, name1) writer1 = servermanager.writers.XMLMultiBlockDataWriter(Input=input1) # register writer with coprocessor, with filename + output freq - coprocessor.RegisterWriter(writer1, filename='cloud_%t.vtm', freq=10) + coprocessor.RegisterWriter(writer1, filename=name1+'_%t.vtm', freq=10) return Pipeline() diff --git a/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/scripts/writeMesh.py b/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/scripts/writeMesh.py deleted file mode 100644 index c40f022235937f83e1d9cf8adcf010c245bfe3e3..0000000000000000000000000000000000000000 --- a/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/scripts/writeMesh.py +++ /dev/null @@ -1,70 +0,0 @@ -from paraview.simple import * -from paraview import coprocessing - -# ----------------------- CoProcessor definition ----------------------- - -def CreateCoProcessor(): - def _CreatePipeline(coprocessor, datadescription): - class Pipeline: - input1 = coprocessor.CreateProducer(datadescription, 'mesh') - writer1 = servermanager.writers.XMLMultiBlockDataWriter(Input=input1) - - coprocessor.RegisterWriter(writer1, filename='mesh_%t.vtm', freq=2) - - return Pipeline() - - class CoProcessor(coprocessing.CoProcessor): - def CreatePipeline(self, datadescription): - self.Pipeline = _CreatePipeline(self, datadescription) - - coprocessor = CoProcessor() - freqs = {'mesh': [10]} - coprocessor.SetUpdateFrequencies(freqs) - return coprocessor - -#-------------------------------------------------------------- -# Global variables that will hold the pipeline for each timestep -# Creating the CoProcessor object, doesn't actually create the ParaView pipeline. -# It will be automatically setup when coprocessor.UpdateProducers() is called the -# first time. -coprocessor = CreateCoProcessor() - -#-------------------------------------------------------------- -# Enable Live-Visualizaton with ParaView -coprocessor.EnableLiveVisualization(True) - -# ---------------------- Data Selection method ---------------------- - -def RequestDataDescription(datadescription): - 'Callback to populate the request for current timestep' - global coprocessor - if datadescription.GetForceOutput() == True: - # We are just going to request all fields and meshes from the simulation - # code/adaptor. - for i in range(datadescription.GetNumberOfInputDescriptions()): - datadescription.GetInputDescription(i).AllFieldsOn() - datadescription.GetInputDescription(i).GenerateMeshOn() - return - - # setup requests for all inputs based on the requirements of the - # pipeline. - coprocessor.LoadRequestedData(datadescription) - -# ------------------------ Processing method ------------------------ - -def DoCoProcessing(datadescription): - 'Callback to do co-processing for current timestep' - global coprocessor - - # Update the coprocessor by providing it the newly generated simulation data. - # If the pipeline hasn't been setup yet, this will setup the pipeline. - coprocessor.UpdateProducers(datadescription) - - # Write output data, if appropriate. - coprocessor.WriteData(datadescription); - - # Write image capture (Last arg: rescale lookup table), if appropriate. - coprocessor.WriteImages(datadescription, rescale_lookuptable=False) - - # Live Visualization, if enabled. - coprocessor.DoLiveVisualization(datadescription, 'localhost', 22222) diff --git a/etc/writePatches.py b/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/scripts/writePatches.py similarity index 92% rename from etc/writePatches.py rename to tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/scripts/writePatches.py index 067e41d6d12993ffcc68e1e7946d4a3159366e33..fd5f1eeaaa735da64f62a2a4d8b02d6aef08fc9c 100644 --- a/etc/writePatches.py +++ b/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/scripts/writePatches.py @@ -6,10 +6,11 @@ from paraview import coprocessing def CreateCoProcessor(): def _CreatePipeline(coprocessor, datadescription): class Pipeline: - input1 = coprocessor.CreateProducer(datadescription, 'patches') + name1 = 'region/patches' + input1 = coprocessor.CreateProducer(datadescription, name1) writer1 = servermanager.writers.XMLMultiBlockDataWriter(Input=input1) - coprocessor.RegisterWriter(writer1, filename='patches_%t.vtm', freq=2) + coprocessor.RegisterWriter(writer1, filename=name1+'_%t.vtm', freq=2) return Pipeline() @@ -18,7 +19,7 @@ def CreateCoProcessor(): self.Pipeline = _CreatePipeline(self, datadescription) coprocessor = CoProcessor() - freqs = {'patches': [10]} + freqs = {'region/patches': [10]} coprocessor.SetUpdateFrequencies(freqs) return coprocessor