Commit ee4c3cb7 authored by Mark Olesen's avatar Mark Olesen

ENH: extended runTimePostProcessing (#1206)

- Extended runTimePostProcessing to include access to "live"
  simulation objects such a geometry patches and sampled surfaces
  stored on the "functionObjectObjects" registry.

- Add 'live' runTimePostProcessing of cloud data.
  Extracts position and fields from the cloud via its objectRegistry writer

- For the "live" simulation objects, there are two new volume filters
  that work directly with the OpenFOAM volume fields:
      * iso-surface
      * cutting planes
  Both use the VTK algorithms directly and support multiple values.
  Eg, can make multiple iso-levels or multiple planes parallel to each
  other.

- When VTK has been compiled with MPI-support, parallel rendering will
  be used.

- Additional title text properties (shadow, italic etc)

- Simplified handling of scalar-bar and visibility switches

- Support multiple text positions. Eg, for adding watermark text.
parent 90f2acec
......@@ -13,13 +13,40 @@ else()
message(FATAL_ERROR " VTK version is too old - requires VTK6 or newer")
endif()
#-----------------------------------------------------------------------------
# Test some characteristics
set(test_file ${CMAKE_CURRENT_BINARY_DIR}/check_mpi.cxx)
file(WRITE ${test_file}
"#include <vtkMPICommunicator.h>\n"
"int main() {\n"
" vtkMPICommunicator* p = vtkMPICommunicator::New();\n"
" p->Delete();\n"
" return 0;\n"
"}"
)
try_compile(FOAM_USING_VTK_MPI
${CMAKE_CURRENT_BINARY_DIR} ${test_file}
LINK_LIBRARIES vtkParallelMPI
CMAKE_FLAGS "-DINCLUDE_DIRECTORIES=${PARAVIEW_INCLUDE_DIRS}"
)
if (FOAM_USING_VTK_MPI)
add_definitions(-DFOAM_USING_VTK_MPI)
message("Building with VTK MPI")
include(vtkMPI)
else()
message(WARNING "==== Building without VTK MPI ====")
endif()
#-----------------------------------------------------------------------------
include_directories(
${LIB_SRC}/OpenFOAM/include
${LIB_SRC}/OpenFOAM/lnInclude
${LIB_SRC}/OSspecific/${WM_OSTYPE}/lnInclude
${LIB_SRC}/finiteVolume/lnInclude
${LIB_SRC}/surfMesh/lnInclude
${LIB_SRC}/fileFormats/lnInclude
${LIB_SRC}/conversion/lnInclude
${LIB_SRC}/surfMesh/lnInclude
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
)
......@@ -45,12 +72,16 @@ set(LIBRARY_OUTPUT_PATH $ENV{FOAM_LIBBIN}
file(GLOB SOURCE_FILES
fieldVisualisationBase.C
scalarBar.C
functionObjectBase.C
functionObjectCloud.C
functionObjectLine.C
functionObjectSurface.C
geometryBase.C
geometryCloud.C
geometryCloudGather.C
geometryPatches.C
geometryPatchesGather.C
geometrySurface.C
pathline.C
pointData.C
......@@ -58,16 +89,27 @@ file(GLOB SOURCE_FILES
runTimePostProcessingFunctionObject.C
scene.C
surface.C
surfaceGather.C
text.C
contourFilter.C
cuttingPlaneFilter.C
volumeFilter.C
)
set(OPENFOAM_LIBRARIES
OpenFOAM
finiteVolume
surfMesh
fileFormats
conversion
)
if (FOAM_USING_VTK_MPI)
set(LINK_LIBRARIES vtkParallelMPI)
else()
set(LINK_LIBRARIES)
endif()
add_library(
runTimePostProcessing
SHARED
......@@ -84,6 +126,7 @@ set_target_properties(
target_link_libraries(
runTimePostProcessing
${VTK_LIBRARIES}
${LINK_LIBRARIES}
${OPENFOAM_LIBRARIES}
)
......
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2019 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/>.
\*---------------------------------------------------------------------------*/
// OpenFOAM includes
#include "contourFilter.H"
#include "runTimePostProcessing.H"
#include "addToRunTimeSelectionTable.H"
// VTK includes
#include "vtkActor.h"
#include "vtkCellDataToPointData.h"
#include "vtkCompositeDataGeometryFilter.h"
#include "vtkCompositeDataSet.h"
#include "vtkCompositePolyDataMapper.h"
#include "vtkContourFilter.h"
#include "vtkMultiPieceDataSet.h"
#include "vtkPolyData.h"
#include "vtkPolyDataMapper.h"
#include "vtkRenderer.h"
#include "vtkSmartPointer.h"
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
namespace Foam
{
namespace functionObjects
{
namespace runTimePostPro
{
defineTypeName(contourFilter);
addToRunTimeSelectionTable(surface, contourFilter, dictionary);
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::functionObjects::runTimePostPro::contourFilter::contourFilter
(
const runTimePostProcessing& parent,
const dictionary& dict,
const HashPtrTable<Function1<vector>>& colours
)
:
volumeFilter(parent, dict, colours),
fieldVisualisationBase(dict, colours),
colourFieldName_(dict.get<word>("colourField")),
values_()
{
dict.readEntry("values", values_);
// Extra safety
if (values_.empty())
{
values_.resize(1);
values_.first() = Zero;
}
}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
bool Foam::functionObjects::runTimePostPro::contourFilter::
addGeometry
(
const scalar position,
vtkRenderer* renderer
)
{
if (!visible_)
{
return false;
}
if (needsCollective())
{
Info<< type() << " : Not available for collective operation" << endl;
return false;
}
DebugInfo << " Adding iso-surface" << endl;
// Bookkeeping for vtkUnstructuredGrid
vtk::vtuAdaptor adaptor;
vtkSmartPointer<vtkMultiPieceDataSet> multiPiece = mesh(adaptor);
// Add (scalar/vector) field.
// - always need field(s) for glyphs or colourByField:
int nCmpt = 0;
{
const auto* ioptr =
parent().mesh().cfindObject<regIOobject>(fieldName_);
if (!nCmpt)
{
nCmpt = addDimField<scalar>
(
multiPiece, adaptor, ioptr, fieldName_
);
}
if (!nCmpt)
{
nCmpt = addDimField<vector>
(
multiPiece, adaptor, ioptr, fieldName_
);
}
}
// If the input is vector, need magnitude
word magFieldName = fieldName_;
if (nCmpt == 3)
{
addMagField(fieldName_, multiPiece);
magFieldName = "mag(" + fieldName_ + ")";
}
// Colouring
nCmpt = 0;
if (colourBy_ == cbField && fieldName_ != colourFieldName_)
{
const auto* ioptr =
parent().mesh().cfindObject<regIOobject>(fieldName_);
if (!nCmpt)
{
nCmpt = addDimField<scalar>
(
multiPiece, adaptor, ioptr, colourFieldName_
);
}
if (!nCmpt)
{
nCmpt = addDimField<vector>
(
multiPiece, adaptor, ioptr, colourFieldName_
);
}
}
// Now have a multi-piece dataset that is one of the following:
//
// - one-piece per processor (OpenFOAM = parallel, VTK=parallel)
// Re-query field information - we may have stored it differently
// than the original source.
fieldSummary fieldInfo = queryFieldSummary(magFieldName, multiPiece);
fieldInfo.reduce();
fieldSummary colourFieldInfo =
queryFieldSummary(colourFieldName_, multiPiece);
colourFieldInfo.reduce();
// Not rendered on this processor?
// This is where we stop, but could also have an MPI barrier
if (!renderer)
{
return true;
}
// Rendering
{
auto contour = vtkSmartPointer<vtkContourFilter>::New();
vtkSmartPointer<vtkCellDataToPointData> cellToPoint;
// CellData - Need a cell->point filter
if (!fieldInfo.hasPointData() || !colourFieldInfo.hasPointData())
{
cellToPoint = vtkSmartPointer<vtkCellDataToPointData>::New();
cellToPoint->SetInputData(multiPiece);
contour->SetInputConnection(cellToPoint->GetOutputPort());
}
else
{
contour->SetInputData(multiPiece);
}
contour->SetNumberOfContours(values_.size());
forAll(values_, valuei)
{
contour->SetValue(valuei, values_[valuei]);
}
contour->SetInputArrayToProcess
(
0, // index: scalars(0)
0, // port
0, // connection
vtkDataObject::FIELD_ASSOCIATION_POINTS,
magFieldName.c_str()
);
contour->Modified();
contour->Update();
auto polyData = vtkSmartPointer<vtkCompositeDataGeometryFilter>::New();
polyData->SetInputConnection(contour->GetOutputPort());
polyData->Update();
auto mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(polyData->GetOutputPort());
if (representation_ == rtGlyph)
{
addGlyphs
(
position,
colourFieldName_, colourFieldInfo, // scaling
colourFieldName_, colourFieldInfo, // colouring
maxGlyphLength_,
polyData->GetOutput(),
surfaceActor_,
renderer
);
}
else
{
setField
(
position,
colourFieldName_,
FieldAssociation::POINT_DATA,
mapper,
renderer
);
surfaceActor_->SetMapper(mapper);
setRepresentation(surfaceActor_);
renderer->AddActor(surfaceActor_);
}
}
return true;
}
void Foam::functionObjects::runTimePostPro::contourFilter::
addGeometryToScene
(
const scalar position,
vtkRenderer* renderer
)
{
if (visible_)
{
// Live source
if (addGeometry(position, renderer))
{
return;
}
WarningInFunction
<< "Unsupported for OpenFOAM parallel and VTK serial"
<< endl;
}
}
bool Foam::functionObjects::runTimePostPro::contourFilter::clear()
{
return true;
}
// ************************************************************************* //
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2019 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::functionObjects::runTimePostPro::contourFilter
Description
Iso-surface contours of OpenFOAM volume fields.
Dictionary controls
\table
Property | Description | Required | Default
type | The surface type: isoSurface | yes |
field | The field defining the surface | yes |
colourField | The field to display on the surface | yes |
values | List of iso-values to define the surface(s) | yes |
\endtable
SourceFiles
contourFilter.C
\*---------------------------------------------------------------------------*/
#ifndef functionObjects_runTimePostPro_contourFilter_H
#define functionObjects_runTimePostPro_contourFilter_H
#include "volumeFilter.H"
#include "fieldVisualisationBase.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace functionObjects
{
namespace runTimePostPro
{
/*---------------------------------------------------------------------------*\
Class contourFilter Declaration
\*---------------------------------------------------------------------------*/
class contourFilter
:
public volumeFilter,
public fieldVisualisationBase
{
protected:
// Protected Data
//- Name of field to colour by
word colourFieldName_;
//- The iso values
List<scalar> values_;
// Protected Member Functions
//- No copy construct
contourFilter(const contourFilter&) = delete;
//- No copy assignment
void operator=(const contourFilter&) = delete;
public:
//- Run-time type information
TypeNameNoDebug("isoSurface");
// Constructors
//- Construct from dictionary
contourFilter
(
const runTimePostProcessing& parent,
const dictionary& dict,
const HashPtrTable<Function1<vector>>& colours
);
//- Destructor
virtual ~contourFilter() = default;
// Member Functions
//- Add cutting planes to scene (using simulation source)
bool addGeometry
(
const scalar position,
vtkRenderer* renderer
);
//- Add cutting planes to scene (using simulation source)
virtual void addGeometryToScene
(
const scalar position,
vtkRenderer* renderer
);
//- Add cutting planes to scene (using simulation source)
virtual bool clear();
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace runTimePostPro
} // End namespace functionObjects
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2019 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/>.
\*---------------------------------------------------------------------------*/
// OpenFOAM includes
#include "cuttingPlaneFilter.H"
#include "runTimePostProcessing.H"
#include "addToRunTimeSelectionTable.H"
// VTK includes
#include "vtkActor.h"
#include "vtkCellDataToPointData.h"
#include "vtkCompositeDataGeometryFilter.h"
#include "vtkCompositeDataSet.h"
#include "vtkCompositePolyDataMapper.h"
#include "vtkCutter.h"
#include "vtkMultiPieceDataSet.h"
#include "vtkPlane.h"
#include "vtkPolyData.h"
#include "vtkPolyDataMapper.h"
#include "vtkRenderer.h"
#include "vtkSmartPointer.h"
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
namespace Foam
{
namespace functionObjects
{
namespace runTimePostPro
{
defineTypeName(cuttingPlaneFilter);
addToRunTimeSelectionTable(surface, cuttingPlaneFilter, dictionary);
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::functionObjects::runTimePostPro::cuttingPlaneFilter::cuttingPlaneFilter
(
const runTimePostProcessing& parent,
const dictionary& dict,
const HashPtrTable<Function1<vector>>& colours
)
:
volumeFilter(parent, dict, colours),
fieldVisualisationBase(dict, colours),
plane_(dict),
values_()
{
dict.readIfPresent("offsets", values_);
if (values_.empty())
{
values_.resize(1);
values_.first() = Zero;
}
}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
bool Foam::functionObjects::runTimePostPro::cuttingPlaneFilter::
addGeometry
(
const scalar position,
vtkRenderer* renderer
)
{
if (!visible_)
{
return false;
}
if (needsCollective())
{
Info<< type() << " : Not available for collective operation" << endl;
return false;
}
DebugInfo << " Adding cutting plane" << endl;
// Bookkeeping for vtkUnstructuredGrid
vtk::vtuAdaptor adaptor;
vtkSmartPointer<vtkMultiPieceDataSet> multiPiece = mesh(adaptor);
// Add (scalar/vector) field.
// - Need field(s) for glyphs or colourByField:
int nCmpt = 0;
if (representation_ == rtGlyph || colourBy_ == cbField)
{
const auto* ioptr =
parent().mesh().cfindObject<regIOobject>(fieldName_);
if (!nCmpt)
{
nCmpt = addDimField<scalar>
(
multiPiece, adaptor, ioptr, fieldName_
);
}
if (!nCmpt)
{
nCmpt = addDimField<vector>
(
multiPiece, adaptor, ioptr, fieldName_
);
}
}
// Now have a multi-piece dataset that is one of the following: