diff --git a/etc/caseDicts/annotated/runTimePostProcessingDict b/etc/caseDicts/annotated/runTimePostProcessingDict new file mode 100644 index 0000000000000000000000000000000000000000..cbe82ec81f0a0b74bdf9bb3f4cc0fca3433b7020 --- /dev/null +++ b/etc/caseDicts/annotated/runTimePostProcessingDict @@ -0,0 +1,281 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1812 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ +FoamFile +{ + version 2.0; + format ascii; + class dictionary; + object runTimePostProcessingDict; +} +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + + +// Type of functionObject +type runTimePostProcessing; + +// Where to load it from +libs ("librunTimePostProcessing.so"); + +// Function object enabled flag +enabled true; + +// When to output the average fields +writeControl writeTime; + +//- Optionally disable parallel VTK rendering, default = true +// parallel true; + +//- The output characteristics +output +{ + //- The name stem for output images + name image; + + //- The image dimensions + width 1400; + height 1050; +} + + +//- The camera settings +camera +{ + // If camera is moving, optionally provide start and end times + // startPosition 0.2; + // endPosition 0.75; + + // Total number of frames to generate + nFrameTotal 1; + + // Parallel projection flag + parallelProjection yes; + + // clipBox is optional + + position (385 -560 650); + focalPoint (160 90 60); + up (0.06 0.7 0.7); + + position ( -41.95 -247.55 426.87 ); + focalPoint ( 146 76 40 ); + up ( 0.3646 0.6194 0.6953 ); + + zoom 1.5; + // clipBox (-10 18 0)(280 160 76); + clipBox (-30 0 0)(300 200 80); +} + + +// Default colours +// - If select to colourBy colour, these values are used unless +// they are locally overridden +colours +{ + background (0.317647 0.341176 0.431373); + background2 (0.317647 0.341176 0.431373); + text (0.75 0.75 0.75); + edge (1 0 0); + surface (0.5 0.5 0.5); + line (1 0 0); + point (0.5 0.5 0.5); +} + + +// Line data +lines +{ + streamline + { + type functionObjectLine; + functionObject streamLines; + colourMap rainbow; + representation tube; + visible true; + tubeRadius 0.5; + colourBy field; + field U; + range (0 20); + opacity 1; + scalarBar + { + visible no; + } + } +} + + +// Surface data +surfaces +{ + geom + { + type geometry; + files ("<case>/myGeometry.vtp"); + renderMode phong; + representation surface; + edgeColour (0.5 0.5 0.5); + visible yes; + featureEdges none; + opacity 1.0; + } + + surf1 + { + type functionObjectSurface; + functionObject planes.plane0; + liveObject true; + colourMap coolToWarm; + + representation surface; + maxGlyphLength 0.1; + smooth true; + visible yes; + + featureEdges none; + colourBy field; + field U; + range (0 20); + opacity 1; + + scalarBar + { + visible no; + } + } + + patches + { + type patches; + patches ( buildings ground ); + nearCellValue true; + smooth true; + colourMap coolToWarm; + representation surface; + representation glyph; + + // maxGlyphLength 5; + maxGlyphLength 0; + visible yes; + featureEdges none; + colourBy field; + + field U; + range (0 20); + + opacity 1; + scalarBar + { + visible no; + position (0.8 0.1); + vertical yes; + fontSize 16; + titleSize 18; + title "velocity [m/s]"; + labelFormat "%6.2f"; + numberOfLabels 5; + + bold yes; + italic yes; + shadow yes; + } + } + + + cutting + { + type plane; + planeType pointAndNormal; + + pointAndNormalDict + { + point (100 100 50); + normal (1 0 0); + } + + offsets (0 100 200); + + smooth true; + colourMap coolToWarm; + representation surface; + + representation glyph; + + // maxGlyphLength 5; + maxGlyphLength 0; + visible yes; + featureEdges none; + + colourBy field; + colourField U; + field U; + range (0 20); + + opacity 1; + scalarBar + { + visible no; + } + } + + iso + { + type iso; + values (0 4 8); + + smooth true; + colourMap coolToWarm; + representation surface; + + representation glyph; + + // maxGlyphLength 5; + maxGlyphLength 0; + visible yes; + featureEdges none; + + colourBy field; + colourField U; + field U; + range (0 20); + + colourField k; + field k; + range (0 20); + + colourBy field; + colourField U; + field U; + range (0 20); + + opacity 1; + scalarBar + { + visible no; + } + } +} + +// Text data +text +{ + text1 + { + string "buildings"; + position (0.5 0.15); + halign centre; + size 18; + opacity 0.4; + bold yes; + italic yes; + shadow yes; + visible yes; + } +} + + +// ************************************************************************* // diff --git a/etc/caseDicts/postProcessing/visualization/runTimePostPro.cfg b/etc/caseDicts/postProcessing/visualization/runTimePostPro.cfg new file mode 100644 index 0000000000000000000000000000000000000000..cf5ab38a1cb54e889c98f1bcfea697d3f9bc0576 --- /dev/null +++ b/etc/caseDicts/postProcessing/visualization/runTimePostPro.cfg @@ -0,0 +1,107 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1812 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ + +type runTimePostProcessing; + +libs ("librunTimePostProcessing.so"); + +writeControl writeTime; + +// Output characteristics +output +{ + //- The name stem for output images + name image; + + //- The image dimensions + width 1400; + height 1050; +} + + +// Some convenient colour schemes +colourScheme +{ + black + { + background (0 0 0); + text (0.75 0.75 0.75); + edge (1 0 0); + surface (0.5 0.5 0.5); + line (1 0 0); + point (0.5 0.5 0.5); + } + + blueGradient + { + background (1 1 1); + background2 (0 0 1); + text (0 0 0); + edge (1 0 0); + surface (0.5 0.5 0.5); + line (1 0 0); + point (0.5 0.5 0.5); + } + + greyGradient + { + background (0.5 0.5 0.5); + background2 (0.7 0.7 0.7); + text (1 1 1); + edge (1 0 0); + surface (0.5 0.5 0.5); + line (1 0 0); + point (0.5 0.5 0.5); + } + + paraview + { + background (0.317647 0.341176 0.431373); + text (0.75 0.75 0.75); + edge (1 0 0); + surface (0.5 0.5 0.5); + line (1 0 0); + point (0.5 0.5 0.5); + } +} + + +// Some typical scalarBar settings +scalarBar +{ + right + { + visible true; + vertical true; + position (0.8 0.1); + size (0.1 0.75); + fontSize 16; + labelFormat "%f"; + numberOfLabels 5; + bold yes; + italic yes; + shadow yes; + } + + bottom + { + visible true; + vertical false; + position (0.2 0.1); + size (0.6 0.1); + fontSize 16; + labelFormat "%f"; + numberOfLabels 5; + bold yes; + italic yes; + shadow yes; + } +} + + +// ************************************************************************* // diff --git a/etc/controlDict b/etc/controlDict index f6a1120cfc879ec856f6af3eb48ae143db0d1453..3d6c94dd8003e42d21c61b21f81244a474c89b6d 100644 --- a/etc/controlDict +++ b/etc/controlDict @@ -820,6 +820,7 @@ DebugSwitches rotatedBoxToCell 0; rotatingPressureInletOutletVelocity 0; rotatingTotalPressure 0; + runTimePostPro::geometryBase 0; sampledPatch 0; sampledPlane 0; sampledSet 0; diff --git a/src/functionObjects/graphics/runTimePostProcessing/CMakeLists-Project.txt b/src/functionObjects/graphics/runTimePostProcessing/CMakeLists-Project.txt index d64168acbde2fd0de130c189bbef424ba4e72d64..3db266e911ed24d7465da6ace0e073b557c10479 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/CMakeLists-Project.txt +++ b/src/functionObjects/graphics/runTimePostProcessing/CMakeLists-Project.txt @@ -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} ) diff --git a/src/functionObjects/graphics/runTimePostProcessing/contourFilter.C b/src/functionObjects/graphics/runTimePostProcessing/contourFilter.C new file mode 100644 index 0000000000000000000000000000000000000000..2a6eb421a343e6fdd57bbe8b73a825927cfdb311 --- /dev/null +++ b/src/functionObjects/graphics/runTimePostProcessing/contourFilter.C @@ -0,0 +1,303 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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; +} + + +// ************************************************************************* // diff --git a/src/functionObjects/graphics/runTimePostProcessing/contourFilter.H b/src/functionObjects/graphics/runTimePostProcessing/contourFilter.H new file mode 100644 index 0000000000000000000000000000000000000000..403052d43dc0c4383fc7872c47b9306c4a4bfd61 --- /dev/null +++ b/src/functionObjects/graphics/runTimePostProcessing/contourFilter.H @@ -0,0 +1,140 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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 + +// ************************************************************************* // diff --git a/src/functionObjects/graphics/runTimePostProcessing/cuttingPlaneFilter.C b/src/functionObjects/graphics/runTimePostProcessing/cuttingPlaneFilter.C new file mode 100644 index 0000000000000000000000000000000000000000..929d5858acfef046db7dfe000849b08d78273579 --- /dev/null +++ b/src/functionObjects/graphics/runTimePostProcessing/cuttingPlaneFilter.C @@ -0,0 +1,292 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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: + // + // - 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(fieldName_, multiPiece); + fieldInfo.reduce(); + + + // Not rendered on this processor? + // This is where we stop, but could also have an MPI barrier + if (!renderer) + { + return true; + } + + + // Rendering + { + // OpenFOAM plane -> vtkPlane definition + + auto pln = vtkSmartPointer<vtkPlane>::New(); + + pln->SetNormal + ( + plane_.normal().x(), + plane_.normal().y(), + plane_.normal().z() + ); + pln->SetOrigin + ( + plane_.origin().x(), + plane_.origin().y(), + plane_.origin().z() + ); + + + // Plane cutting algorithm + + auto cutter = vtkSmartPointer<vtkCutter>::New(); + + cutter->SetInputData(multiPiece); + cutter->SetCutFunction(pln); + + cutter->SetNumberOfContours(values_.size()); + + forAll(values_, pointi) + { + cutter->SetValue(pointi, values_[pointi]); + } + + cutter->SetInputArrayToProcess + ( + (nCmpt == 3 ? 1 : 0), // index: scalars(0), vectors(1) + 0, // port + 0, // connection + vtkDataObject::FIELD_ASSOCIATION_CELLS, + fieldName_.c_str() + ); + + cutter->Modified(); + cutter->Update(); + + auto polyData = vtkSmartPointer<vtkCompositeDataGeometryFilter>::New(); + + polyData->SetInputConnection(cutter->GetOutputPort()); + polyData->Update(); + + auto mapper = vtkSmartPointer<vtkPolyDataMapper>::New(); + mapper->SetInputConnection(polyData->GetOutputPort()); + + if (representation_ == rtGlyph) + { + addGlyphs + ( + position, + fieldName_, fieldInfo, // scaling + fieldName_, fieldInfo, // colouring + maxGlyphLength_, + polyData->GetOutput(), + surfaceActor_, + renderer + ); + } + else + { + vtkSmartPointer<vtkCellDataToPointData> cellToPoint; + + // CellData - Need a cell->point filter + if (smooth_ && !fieldInfo.hasPointData()) + { + cellToPoint = vtkSmartPointer<vtkCellDataToPointData>::New(); + cellToPoint->SetInputConnection(cutter->GetOutputPort()); + + polyData->SetInputConnection(cellToPoint->GetOutputPort()); + polyData->Update(); + } + + setField + ( + position, + fieldName_, + ( + smooth_ + ? FieldAssociation::POINT_DATA + : FieldAssociation(fieldInfo.association_) + ), + mapper, + renderer + ); + + surfaceActor_->SetMapper(mapper); + + setRepresentation(surfaceActor_); + + renderer->AddActor(surfaceActor_); + } + } + + return true; +} + + +void Foam::functionObjects::runTimePostPro::cuttingPlaneFilter:: +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::cuttingPlaneFilter::clear() +{ + return true; +} + + +// ************************************************************************* // diff --git a/src/functionObjects/graphics/runTimePostProcessing/cuttingPlaneFilter.H b/src/functionObjects/graphics/runTimePostProcessing/cuttingPlaneFilter.H new file mode 100644 index 0000000000000000000000000000000000000000..1c89db28e00ad1e457a59fb83c407a0ce38da993 --- /dev/null +++ b/src/functionObjects/graphics/runTimePostProcessing/cuttingPlaneFilter.H @@ -0,0 +1,160 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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::cuttingPlaneFilter + +Description + Cutting planes of OpenFOAM volume fields. + + Example of text object specification: + \verbatim + planes + { + type plane; + planeType pointAndNormal; + + pointAndNormalDict + { + point (0 0 0); + normal (1 0 0); + } + + offsets (0 10 20); + + field T; + } + \endverbatim + + Dictionary controls + \table + Property | Description | Required | Default + type | The surface type: plane | yes | + planeType | Selector for plane description | yes | + offsets | Offets of the origin in the normal direction | no | (0) + field | The field to display | yes | + \endtable + +SourceFiles + cuttingPlaneFilter.C + +\*---------------------------------------------------------------------------*/ + +#ifndef functionObjects_runTimePostPro_cuttingPlaneFilter_H +#define functionObjects_runTimePostPro_cuttingPlaneFilter_H + +#include "plane.H" +#include "volumeFilter.H" +#include "fieldVisualisationBase.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ +namespace functionObjects +{ +namespace runTimePostPro +{ + +/*---------------------------------------------------------------------------*\ + Class cuttingPlaneFilter Declaration +\*---------------------------------------------------------------------------*/ + +class cuttingPlaneFilter +: + public volumeFilter, + public fieldVisualisationBase +{ +protected: + + // Protected Data + + //- The definition of the plane + plane plane_; + + //- The offsets to the plane - defaults to (0). + List<scalar> values_; + + + // Protected Member Functions + + //- No copy construct + cuttingPlaneFilter(const cuttingPlaneFilter&) = delete; + + //- No copy assignment + void operator=(const cuttingPlaneFilter&) = delete; + + +public: + + //- Run-time type information + TypeNameNoDebug("plane"); + + + // Constructors + + //- Construct from dictionary + cuttingPlaneFilter + ( + const runTimePostProcessing& parent, + const dictionary& dict, + const HashPtrTable<Function1<vector>>& colours + ); + + + //- Destructor + virtual ~cuttingPlaneFilter() = 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 + ); + + //- Cleanup files etc. + virtual bool clear(); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace runTimePostPro +} // End namespace functionObjects +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/functionObjects/graphics/runTimePostProcessing/fieldVisualisationBase.C b/src/functionObjects/graphics/runTimePostProcessing/fieldVisualisationBase.C index 5eba57decd9ae85b3f055653ebe1831de666838f..a8ee5dd4551f1675bcdd38ad68bc2e588bac1ae6 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/fieldVisualisationBase.C +++ b/src/functionObjects/graphics/runTimePostProcessing/fieldVisualisationBase.C @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2015-2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd. \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2015 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -29,25 +27,27 @@ License #include "fieldVisualisationBase.H" #include "runTimePostProcessing.H" +#include "doubleVector.H" +#include "foamVtkTools.H" + // VTK includes #include "vtkArrowSource.h" +#include "vtkCellDataToPointData.h" #include "vtkCellData.h" #include "vtkColorTransferFunction.h" -#include "vtkFloatArray.h" +#include "vtkCompositeDataSet.h" +#include "vtkDataObjectTreeIterator.h" +#include "vtkFieldData.h" #include "vtkGlyph3D.h" #include "vtkLookupTable.h" #include "vtkPointData.h" #include "vtkPolyData.h" #include "vtkPolyDataMapper.h" #include "vtkRenderer.h" -#include "vtkScalarBarActor.h" #include "vtkSmartPointer.h" #include "vtkSphereSource.h" -#include "vtkTextActor.h" -#include "vtkTextProperty.h" -#include "vtkCellDataToPointData.h" -// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // const Foam::Enum < @@ -69,13 +69,323 @@ const Foam::Enum Foam::functionObjects::runTimePostPro::fieldVisualisationBase:: colourMapTypeNames ({ - { colourMapType::cmRainbow, "rainbow" }, - { colourMapType::cmBlueWhiteRed, "blueWhiteRed" }, + { colourMapType::cmCoolToWarm, "coolToWarm" }, + { colourMapType::cmCoolToWarm, "blueWhiteRed" }, + { colourMapType::cmColdAndHot, "coldAndHot" }, { colourMapType::cmFire, "fire" }, + { colourMapType::cmRainbow, "rainbow" }, { colourMapType::cmGreyscale, "greyscale" }, + { colourMapType::cmGreyscale, "grayscale" }, + { colourMapType::cmXray, "xray" }, }); +// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // + +Foam::functionObjects::runTimePostPro::fieldVisualisationBase::fieldSummary +Foam::functionObjects::runTimePostPro::fieldVisualisationBase:: +queryFieldSummary +( + const word& fieldName, + vtkDataSet* dataset +) +{ + fieldSummary queried; + + if (dataset) + { + vtkDataArray* array; + + array = vtkDataArray::SafeDownCast + ( + dataset->GetCellData()->GetAbstractArray(fieldName.c_str()) + ); + + if (array) + { + queried.nComponents_ = array->GetNumberOfComponents(); + queried.association_ |= FieldAssociation::CELL_DATA; + queried.range_ += vtk::Tools::rangeOf(array); + } + + array = vtkDataArray::SafeDownCast + ( + dataset->GetPointData()->GetAbstractArray(fieldName.c_str()) + ); + + if (array) + { + queried.nComponents_ = array->GetNumberOfComponents(); + queried.association_ |= FieldAssociation::POINT_DATA; + queried.range_ += vtk::Tools::rangeOf(array); + } + } + + return queried; +} + + +Foam::functionObjects::runTimePostPro::fieldVisualisationBase::fieldSummary +Foam::functionObjects::runTimePostPro::fieldVisualisationBase:: +queryFieldSummary +( + const word& fieldName, + vtkCompositeDataSet* data +) +{ + fieldSummary queried; + + auto iter = vtkSmartPointer<vtkDataObjectTreeIterator>::New(); + + iter->SetDataSet(data); + iter->VisitOnlyLeavesOn(); + iter->SkipEmptyNodesOn(); + + for + ( + iter->InitTraversal(); + !iter->IsDoneWithTraversal(); + iter->GoToNextItem() + ) + { + vtkDataSet* dataset = vtkDataSet::SafeDownCast + ( + iter->GetCurrentDataObject() + ); + + if (dataset) + { + fieldSummary local(queryFieldSummary(fieldName, dataset)); + + if (!queried.nComponents_) + { + queried.nComponents_ = local.nComponents_; + } + + queried.association_ |= local.association_; + queried.range_ += local.range_; + } + } + + return queried; +} + + +Foam::functionObjects::runTimePostPro::fieldVisualisationBase::FieldAssociation +Foam::functionObjects::runTimePostPro::fieldVisualisationBase:: +queryFieldAssociation +( + const word& fieldName, + vtkDataSet* dataset +) +{ + unsigned where(FieldAssociation::NO_DATA); + + if (dataset) + { + if (dataset->GetCellData()->HasArray(fieldName.c_str())) + { + where |= FieldAssociation::CELL_DATA; + } + if (dataset->GetPointData()->HasArray(fieldName.c_str())) + { + where |= FieldAssociation::POINT_DATA; + } + } + + return FieldAssociation(where); +} + + +Foam::functionObjects::runTimePostPro::fieldVisualisationBase::FieldAssociation +Foam::functionObjects::runTimePostPro::fieldVisualisationBase:: +queryFieldAssociation +( + const word& fieldName, + vtkCompositeDataSet* data +) +{ + unsigned where(FieldAssociation::NO_DATA); + + auto iter = vtkSmartPointer<vtkDataObjectTreeIterator>::New(); + + iter->SetDataSet(data); + iter->VisitOnlyLeavesOn(); + iter->SkipEmptyNodesOn(); + + for + ( + iter->InitTraversal(); + !iter->IsDoneWithTraversal(); + iter->GoToNextItem() + ) + { + vtkDataSet* dataset = vtkDataSet::SafeDownCast + ( + iter->GetCurrentDataObject() + ); + + where |= queryFieldAssociation(fieldName, dataset); + } + + return FieldAssociation(where); +} + + +void Foam::functionObjects::runTimePostPro::fieldVisualisationBase::addMagField +( + const word& fieldName, + vtkFieldData* fieldData +) +{ + if (!fieldData) + { + return; + } + + vtkDataArray* input = vtkDataArray::SafeDownCast + ( + fieldData->GetAbstractArray(fieldName.c_str()) + ); + + if (!input) + { + return; + } + + const word magFieldName = "mag(" + fieldName + ")"; + + vtkDataArray* output = vtkDataArray::SafeDownCast + ( + fieldData->GetAbstractArray(magFieldName.c_str()) + ); + + if (output) + { + return; + } + + + // Simplfy and only handle scalar/vector input + + const int nCmpt = input->GetNumberOfComponents(); + const vtkIdType len = input->GetNumberOfTuples(); + + if (nCmpt == 1) + { + auto data = vtkSmartPointer<vtkFloatArray>::New(); + + data->SetName(magFieldName.c_str()); + data->SetNumberOfComponents(1); + data->SetNumberOfTuples(len); + + double scratch; + for (vtkIdType i=0; i < len; ++i) + { + input->GetTuple(i, &scratch); + + scratch = Foam::mag(scratch); + data->SetTuple(i, &scratch); + } + + fieldData->AddArray(data); + } + else if (nCmpt == 3) + { + auto data = vtkSmartPointer<vtkFloatArray>::New(); + + data->SetName(magFieldName.c_str()); + data->SetNumberOfComponents(1); + data->SetNumberOfTuples(len); + + doubleVector scratch; + for (vtkIdType i=0; i < len; ++i) + { + input->GetTuple(i, scratch.v_); + + scratch.x() = Foam::mag(scratch); + + data->SetTuple(i, scratch.v_); + } + + fieldData->AddArray(data); + } +} + + +void Foam::functionObjects::runTimePostPro::fieldVisualisationBase::addMagField +( + const word& fieldName, + vtkDataSet* dataset +) +{ + if (dataset) + { + addMagField(fieldName, dataset->GetCellData()); + addMagField(fieldName, dataset->GetPointData()); + } +} + + +void Foam::functionObjects::runTimePostPro::fieldVisualisationBase::addMagField +( + const word& fieldName, + vtkCompositeDataSet* data +) +{ + auto iter = vtkSmartPointer<vtkDataObjectTreeIterator>::New(); + + iter->SetDataSet(data); + iter->VisitOnlyLeavesOn(); + iter->SkipEmptyNodesOn(); + + for + ( + iter->InitTraversal(); + !iter->IsDoneWithTraversal(); + iter->GoToNextItem() + ) + { + vtkDataSet* dataset = vtkDataSet::SafeDownCast + ( + iter->GetCurrentDataObject() + ); + addMagField(fieldName, dataset); + } +} + + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +void Foam::functionObjects::runTimePostPro::fieldVisualisationBase:: +fieldSummary::reduce() +{ + if (Pstream::parRun()) + { + Foam::reduce(nComponents_, maxOp<int>()); + Foam::reduce(association_, bitOrOp<unsigned>()); + Foam::reduce(range_, minMaxOp<scalar>()); + } +} + + +Foam::Ostream& Foam::operator<< +( + Ostream& os, + const InfoProxy + < + functionObjects::runTimePostPro::fieldVisualisationBase::fieldSummary + >& proxy +) +{ + os << "nComponents:" << proxy.t_.nComponents_ + << " association:" << label(proxy.t_.association_) + << " min/max:" << proxy.t_.range_; + + return os; +} + + // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // void Foam::functionObjects::runTimePostPro::fieldVisualisationBase:: @@ -84,7 +394,7 @@ setColourMap vtkLookupTable* lut ) const { - label nColours = 256; + constexpr label nColours = 256; lut->SetNumberOfColors(nColours); @@ -92,47 +402,73 @@ setColourMap switch (colourMap_) { - case cmRainbow: - { - ctf->SetColorSpaceToHSV(); - ctf->AddRGBPoint(0, 0, 0, 1); - ctf->AddRGBPoint(0.5, 0, 1, 0); - ctf->AddRGBPoint(1, 1, 0, 0); - break; - } - case cmBlueWhiteRed: + case cmCoolToWarm: // ParaView: "Cool To Warm" { - // Values taken from ParaView settings ctf->SetColorSpaceToDiverging(); - ctf->AddRGBPoint(0.0, 0.231373, 0.298039, 0.752941); + ctf->AddRGBPoint(0.0, 0.231372, 0.298039, 0.752941); ctf->AddRGBPoint(0.5, 0.865003, 0.865003, 0.865003); ctf->AddRGBPoint(1.0, 0.705882, 0.0156863, 0.14902); + // ctf->SetNanColor(1, 1, 0); + break; + } + + case cmColdAndHot: // ParaView : "Cold and Hot" + { + ctf->SetColorSpaceToRGB(); + ctf->AddRGBPoint(0, 0, 1, 1); + ctf->AddRGBPoint(0.45, 0, 0, 1); + ctf->AddRGBPoint(0.5, 0, 0, 0.5019608); + ctf->AddRGBPoint(0.55, 1, 0, 0); + ctf->AddRGBPoint(1, 1, 1, 0); break; } - case cmFire: + + case cmFire: // ParaView: Black-Body Radiation { - // Values taken from ParaView settings ctf->SetColorSpaceToRGB(); ctf->AddRGBPoint(0, 0, 0, 0); ctf->AddRGBPoint(0.4, 0.901961, 0, 0); ctf->AddRGBPoint(0.8, 0.901961, 0.901961, 0); ctf->AddRGBPoint(1, 1, 1, 1); + // ctf->SetNanColor(0, 0.49804, 1); + break; + } + + case cmRainbow: + { + ctf->SetColorSpaceToHSV(); + ctf->AddRGBPoint(0, 0, 0, 1); + ctf->AddRGBPoint(0.5, 0, 1, 0); + ctf->AddRGBPoint(1, 1, 0, 0); + // ctf->SetNanColor(0.498039, 0.498039, 0.498039); break; } - case cmGreyscale: + + case cmGreyscale: // ParaView: grayscale { ctf->SetColorSpaceToRGB(); ctf->AddRGBPoint(0, 0, 0, 0); ctf->AddRGBPoint(1, 1, 1, 1); + // ctf->SetNanColor(1, 0, 0); + break; + } + + case cmXray: // ParaView: "X ray" + { + ctf->SetColorSpaceToRGB(); + ctf->AddRGBPoint(0, 1, 1, 1); + ctf->AddRGBPoint(1, 0, 0, 0); + // ctf->SetNanColor(1, 0, 0); break; } } - for (label i = 0; i < nColours; i++) + double rgba[4] = { 0, 0, 0, 1 }; + for (label i = 0; i < nColours; ++i) { - double* c = ctf->GetColor(scalar(i)/scalar(nColours)); - lut->SetTableValue(i, c[0], c[1], c[2], 1.0); + ctf->GetColor(scalar(i)/scalar(nColours), rgba); + lut->SetTableValue(i, rgba); } } @@ -145,105 +481,11 @@ addScalarBar vtkLookupTable* lut ) const { - // Add scalar bar legend - if (!scalarBar_.visible_) + // Add the scalar bar - only once! + if (renderer && Pstream::master()) { - return; + scalarBar_.add(colours_["text"]->value(position), renderer, lut); } - - auto sbar = vtkSmartPointer<vtkScalarBarActor>::New(); - sbar->SetLookupTable(lut); - sbar->SetNumberOfLabels(scalarBar_.numberOfLabels_); - - const vector textColour = colours_["text"]->value(position); - - // Work-around to supply our own scalarbar title - // - Default scalar bar title text is scales by the scalar bar box - // dimensions so if the title is a long string, the text is shrunk to fit - // Instead, suppress title and set the title using a vtkTextActor - auto titleActor = vtkSmartPointer<vtkTextActor>::New(); - sbar->SetTitle(" "); - titleActor->SetInput(scalarBar_.title_.c_str()); - titleActor->GetTextProperty()->SetFontFamilyToArial(); - titleActor->GetTextProperty()->SetFontSize(3*scalarBar_.fontSize_); - titleActor->GetTextProperty()->SetJustificationToCentered(); - titleActor->GetTextProperty()->SetVerticalJustificationToBottom(); - titleActor->GetTextProperty()->BoldOn(); - titleActor->GetTextProperty()->ItalicOff(); - titleActor->GetTextProperty()->SetColor - ( - textColour[0], - textColour[1], - textColour[2] - ); - titleActor->GetPositionCoordinate()-> - SetCoordinateSystemToNormalizedViewport(); - - // How to use the standard scalar bar text - // sbar->SetTitle(scalarBar_.title_.c_str()); - // sbar->GetTitleTextProperty()->SetColor - // ( - // textColour[0], - // textColour[1], - // textColour[2] - // ); - // sbar->GetTitleTextProperty()->SetFontSize(scalarBar_.fontSize_); - // sbar->GetTitleTextProperty()->ShadowOff(); - // sbar->GetTitleTextProperty()->BoldOn(); - // sbar->GetTitleTextProperty()->ItalicOff(); - - sbar->GetLabelTextProperty()->SetColor - ( - textColour[0], - textColour[1], - textColour[2] - ); - sbar->GetLabelTextProperty()->SetFontSize(scalarBar_.fontSize_); - sbar->GetLabelTextProperty()->ShadowOff(); - sbar->GetLabelTextProperty()->BoldOff(); - sbar->GetLabelTextProperty()->ItalicOff(); - sbar->SetLabelFormat(scalarBar_.labelFormat_.c_str()); - - sbar->GetPositionCoordinate()->SetCoordinateSystemToNormalizedViewport(); - sbar->GetPositionCoordinate()->SetValue - ( - scalarBar_.position_.first(), - scalarBar_.position_.second() - ); - if (scalarBar_.vertical_) - { - sbar->SetOrientationToVertical(); - sbar->SetWidth(0.1); - sbar->SetHeight(0.75); - sbar->SetTextPositionToSucceedScalarBar(); - } - else - { - sbar->SetOrientationToHorizontal(); - - // Adjustments since not using scalarbar title property - sbar->SetWidth(0.75); - sbar->SetHeight(0.07); - sbar->SetBarRatio(0.5); - // sbar->SetHeight(0.1); - // sbar->SetTitleRatio(0.01); - sbar->SetTextPositionToPrecedeScalarBar(); - } - - titleActor->GetPositionCoordinate()->SetValue - ( - scalarBar_.position_.first() + 0.5*sbar->GetWidth(), - scalarBar_.position_.second() + sbar->GetHeight() - ); - - // sbar->DrawFrameOn(); - // sbar->DrawBackgroundOn(); - // sbar->UseOpacityOff(); - // sbar->VisibilityOff(); - sbar->VisibilityOn(); - - renderer->AddActor(sbar); - renderer->AddActor2D(titleActor); } @@ -252,9 +494,9 @@ setField ( const scalar position, const word& colourFieldName, - vtkPolyDataMapper* mapper, - vtkRenderer* renderer, - vtkPolyData* pData + const FieldAssociation fieldAssociation, + vtkMapper* mapper, + vtkRenderer* renderer ) const { mapper->InterpolateScalarsBeforeMappingOn(); @@ -266,6 +508,7 @@ setField mapper->ScalarVisibilityOff(); break; } + case cbField: { // Create look-up table for colours @@ -277,15 +520,15 @@ setField const char* fieldName = colourFieldName.c_str(); mapper->SelectColorArray(fieldName); - // Set to use either point or cell data - // Note: if both point and cell data exists, preferentially - // choosing point data. This is often the case when using - // glyphs - if (pData->GetPointData()->HasArray(fieldName)) + // Use either point or cell data + // - if both point and cell data exists, preferentially choose + // point data. This is often the case when using glyphs. + + if (fieldAssociation & FieldAssociation::POINT_DATA) { mapper->SetScalarModeToUsePointFieldData(); } - else if (pData->GetCellData()->HasArray(fieldName)) + else if (fieldAssociation & FieldAssociation::CELL_DATA) { mapper->SetScalarModeToUseCellFieldData(); } @@ -301,7 +544,7 @@ setField mapper->SetLookupTable(lut); mapper->ScalarVisibilityOn(); - // Add the bar + // Add the scalar bar addScalarBar(position, renderer, lut); break; } @@ -316,43 +559,20 @@ addGlyphs ( const scalar position, const word& scaleFieldName, + const fieldSummary& scaleFieldInfo, const word& colourFieldName, + const fieldSummary& colourFieldInfo, const scalar maxGlyphLength, + vtkPolyData* data, vtkActor* actor, vtkRenderer* renderer ) const { - auto glyph = vtkSmartPointer<vtkGlyph3D>::New(); - auto glyphMapper = vtkSmartPointer<vtkPolyDataMapper>::New(); - glyphMapper->SetInputConnection(glyph->GetOutputPort()); - - glyph->SetInputData(data); - glyph->ScalingOn(); - - bool needPointData = false; + // Determine whether we have CellData/PointData and (scalar/vector) + // or if we need to a cell->point data filter. - // Determine whether we have scalar or vector data - // and if we need to convert CellData -> PointData - - label nComponents = -1; - const char* scaleFieldNameChar = scaleFieldName.c_str(); - if (data->GetPointData()->HasArray(scaleFieldNameChar)) - { - nComponents = - data->GetPointData()->GetArray(scaleFieldNameChar) - ->GetNumberOfComponents(); - } - else if (data->GetCellData()->HasArray(scaleFieldNameChar)) - { - // Need to convert CellData to PointData - needPointData = true; - - nComponents = - data->GetCellData()->GetArray(scaleFieldNameChar) - ->GetNumberOfComponents(); - } - else + if (!scaleFieldInfo.exists()) { WarningInFunction << "Cannot add glyphs. No such cell or point field: " @@ -360,30 +580,46 @@ addGlyphs return; } - - const bool ok = (nComponents == 1 || nComponents == 3); - - if (!ok) + if (!scaleFieldInfo.isScalar() && !scaleFieldInfo.isVector()) { WarningInFunction << "Glyphs can only be added to scalar or vector data. " << "Unable to process field " << scaleFieldName << endl; return; } - else if (needPointData) + + + // Setup glyphs + + // The min/max data range for the input data (cell or point), + // which will be slightly less after using a cell->point filter + // (since it averages), but is still essentially OK. + + + auto glyph = vtkSmartPointer<vtkGlyph3D>::New(); + glyph->ScalingOn(); + + auto glyphMapper = vtkSmartPointer<vtkPolyDataMapper>::New(); + glyphMapper->SetInputConnection(glyph->GetOutputPort()); + + vtkSmartPointer<vtkCellDataToPointData> cellToPoint; + + // The data source is filtered or original (PointData) + if (!scaleFieldInfo.hasPointData() || !colourFieldInfo.hasPointData()) { - auto cellToPoint = vtkSmartPointer<vtkCellDataToPointData>::New(); + // CellData - Need a cell->point filter + cellToPoint = vtkSmartPointer<vtkCellDataToPointData>::New(); cellToPoint->SetInputData(data); - cellToPoint->Update(); - vtkDataSet* pds = cellToPoint->GetOutput(); - vtkDataArray* pData = pds->GetPointData()->GetArray(scaleFieldNameChar); - // Store in main vtkPolyData - data->GetPointData()->AddArray(pData); + glyph->SetInputConnection(cellToPoint->GetOutputPort()); + } + else + { + glyph->SetInputData(data); } - if (nComponents == 1) + if (scaleFieldInfo.nComponents_ == 1) { auto sphere = vtkSmartPointer<vtkSphereSource>::New(); sphere->SetCenter(0, 0, 0); @@ -397,12 +633,12 @@ addGlyphs if (maxGlyphLength > 0) { - // Can get range from point data: - - // double range[2]; - // vtkDataArray* values = - // data->GetPointData()->GetScalars(scaleFieldNameChar); - // values->GetRange(range); + // Using range from the data: + // glyph->SetRange + // ( + // scaleFieldInfo.range_.first(), + // scaleFieldInfo.range_.second() + // ); // Set range according to user-supplied limits glyph->ClampingOn(); @@ -421,14 +657,14 @@ addGlyphs glyph->SetColorModeToColorByScalar(); glyph->SetInputArrayToProcess ( - 0, // scalars - 0, - 0, + 0, // index (0) = scalars + 0, // port + 0, // connection vtkDataObject::FIELD_ASSOCIATION_POINTS, - scaleFieldNameChar + scaleFieldName.c_str() ); } - else if (nComponents == 3) + else if (scaleFieldInfo.nComponents_ == 3) { auto arrow = vtkSmartPointer<vtkArrowSource>::New(); arrow->SetTipResolution(10); @@ -441,24 +677,13 @@ addGlyphs if (maxGlyphLength > 0) { - vtkDataArray* values = - data->GetPointData()->GetVectors(scaleFieldNameChar); - - double range[6]; - values->GetRange(range); - - // Attempt to set range for vectors... - // scalar x0 = sqrt(sqr(range_.first())/3.0); - // scalar x1 = sqrt(sqr(range_.second())/3.0); - // range[0] = x0; - // range[1] = x0; - // range[2] = x0; - // range[3] = x1; - // range[4] = x1; - // range[5] = x1; - + // Set range according data limits glyph->ClampingOn(); - glyph->SetRange(range); + glyph->SetRange + ( + scaleFieldInfo.range_.first(), + scaleFieldInfo.range_.second() + ); glyph->SetScaleFactor(maxGlyphLength); } else @@ -471,20 +696,30 @@ addGlyphs glyph->SetColorModeToColorByVector(); glyph->SetInputArrayToProcess ( - 1, // vectors - 0, - 0, + 1, // index (1) = vectors + 0, // port + 0, // connection vtkDataObject::FIELD_ASSOCIATION_POINTS, - scaleFieldNameChar + scaleFieldName.c_str() ); } - if (ok) + // Apply colouring etc. + // We already established PointData, which as either in the original, + // or generated with vtkCellDataToPointData filter. + { glyph->Update(); - setField(position, colourFieldName, glyphMapper, renderer, data); + setField + ( + position, + colourFieldName, + FieldAssociation::POINT_DATA, // Original or after filter + glyphMapper, + renderer + ); glyphMapper->Update(); @@ -506,9 +741,11 @@ fieldVisualisationBase : colours_(colours), fieldName_(dict.get<word>("field")), + smooth_(dict.lookupOrDefault("smooth", false)), colourBy_(cbColour), colourMap_(cmRainbow), - range_() + range_(), + scalarBar_() { colourByTypeNames.readEntry("colourBy", dict, colourBy_); @@ -516,26 +753,24 @@ fieldVisualisationBase { case cbColour: { - scalarBar_.visible_ = false; + scalarBar_.hide(); break; } + case cbField: { dict.readEntry("range", range_); - colourMapTypeNames.readIfPresent("colourMap", dict, colourMap_); - const dictionary& sbDict = dict.subDict("scalarBar"); - sbDict.readEntry("visible", scalarBar_.visible_); + const dictionary* sbar = dict.findDict("scalarBar"); - if (scalarBar_.visible_) + if (sbar) + { + scalarBar_.read(*sbar); + } + else { - sbDict.readEntry("vertical", scalarBar_.vertical_); - sbDict.readEntry("position", scalarBar_.position_); - sbDict.readEntry("title", scalarBar_.title_); - sbDict.readEntry("fontSize", scalarBar_.fontSize_); - sbDict.readEntry("labelFormat", scalarBar_.labelFormat_); - sbDict.readEntry("numberOfLabels", scalarBar_.numberOfLabels_); + scalarBar_.hide(); } break; } diff --git a/src/functionObjects/graphics/runTimePostProcessing/fieldVisualisationBase.H b/src/functionObjects/graphics/runTimePostProcessing/fieldVisualisationBase.H index 6120a90a027f6f628e919887b8d7044f331386cd..b1a56af9eee67069d28a499e0995423852fe6f2b 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/fieldVisualisationBase.H +++ b/src/functionObjects/graphics/runTimePostProcessing/fieldVisualisationBase.H @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2016-2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd. \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2015 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -29,6 +27,20 @@ Class Description Base class for scene objects + Dictionary controls - colour by field + \table + Property | Description | Required | Default + colourBy | Colouring type (color / field) | yes | + range | Lower/upper range to display | yes | + smooth | Request smoother output | no | false + colourMap | Colour map for rendering | no | rainbow + scalarBar | Scalar-bar sub-dictionary | yes | + \endtable + +Colour maps include "coolToWarm" ("blueWhiteRed"), "coldAndHot", +"fire", "rainbow", "greyscale" ("grayscale"), "xray". For historical +reasons, the default is still "rainbow". + SourceFiles fieldVisualisationBase.C @@ -41,27 +53,35 @@ SourceFiles #include "Tuple2.H" #include "Enum.H" #include "vector.H" +#include "MinMax.H" #include "HashPtrTable.H" +#include "scalarBar.H" #include "Function1.H" -// VTK includes #include "vtkSmartPointer.h" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -// Forward declarations +// Forward Declarations class vtkActor; +class vtkCompositeDataSet; +class vtkCompositeDataGeometryFilter; +class vtkCompositePolyDataMapper; +class vtkDataSet; +class vtkDataSetAlgorithm; +class vtkFieldData; class vtkLookupTable; class vtkMapper; class vtkPolyData; class vtkPolyDataMapper; class vtkRenderer; + namespace Foam { namespace functionObjects { -// Forward declarations +// Forward Declarations class runTimePostProcessing; namespace runTimePostPro @@ -75,48 +95,110 @@ class fieldVisualisationBase { public: - // Public enumerations + // Public Enumerations + //- Colouring type enum colourByType { - cbColour, - cbField + cbColour, //!< "colour" : Use specified colour + cbField //!< "field" : Use named field }; + //- Enumeration names for colourByType static const Enum<colourByType> colourByTypeNames; + //- Colour map enumerations enum colourMapType { - cmRainbow, - cmBlueWhiteRed, - cmFire, - cmGreyscale + cmCoolToWarm, //!< ParaView "Cool To Warm" blue-white-read + cmBlueWhiteRed = cmCoolToWarm, + cmColdAndHot, //!< ParaView "Cold and Hot" + cmFire, //!< ParaView "Black-Body Radiation" + cmRainbow, //!< "rainbow" + cmGreyscale, //!< ParaView "Grayscale" + cmXray //!< ParaView "X Ray" }; + //- Enumeration names for colourMapType static const Enum<colourMapType> colourMapTypeNames; -protected: + //- Enumeration of the data field associations + // These values are used internally and do NOT correspond to the + // vtkDataObject::FieldAssociations enumeration. + enum FieldAssociation + { + NO_DATA = 0, //!< No associated data + CELL_DATA = 0x1, //!< Associated with cells (faces) + POINT_DATA = 0x2, //!< Associated with points + CELL_POINT_DATA = 0x3 //!< Associated with cells and/or points + }; - // Protected Data - struct scalarBar + //- General field characteristics. + // For convenience, the interface is exposed but external use is + // highly discouraged. + struct fieldSummary { - bool visible_; - bool vertical_; - Tuple2<scalar, scalar> position_; - string title_; - label fontSize_; - string labelFormat_; - label numberOfLabels_; + int nComponents_; + unsigned association_; + scalarMinMax range_; + + //- Construct null + fieldSummary() + : + nComponents_(0), + association_(0u), + range_() + {} + + //- Parallel reduction. A no-op if Pstream::parRun() is false + void reduce(); + + //- True if nComponents_ == 1 + bool isScalar() const + { + return nComponents_ == 1; + } + + //- True if nComponents_ == 3 + bool isVector() const + { + return nComponents_ == 3; + } + + //- True if association_ is non-zero + bool exists() const + { + return association_; + } + + //- True if there is a POINT_DATA association + bool hasPointData() const + { + return (association_ & FieldAssociation::POINT_DATA); + } + + InfoProxy<fieldSummary> info() const + { + return InfoProxy<fieldSummary>(*this); + } }; + +protected: + + // Protected Data + //- Colours const HashPtrTable<Function1<vector>>& colours_; //- Field name word fieldName_; + //- Requested smoother fields (eg, interpolate cell -> point values) + bool smooth_; + //- Colour by type colourByType colourBy_; @@ -126,16 +208,67 @@ protected: //- Range of values Tuple2<scalar, scalar> range_; - //- Scalar bar + //- Scalar bar characteristics scalarBar scalarBar_; // Protected Member Functions + //- Query DataSet for field name and its field association + static fieldSummary queryFieldSummary + ( + const word& fieldName, + vtkDataSet* dataset + ); + + //- Query composite DataSet for field name and its FieldAssociation + static fieldSummary queryFieldSummary + ( + const word& fieldName, + vtkCompositeDataSet* data + ); + + //- Query DataSet for field name and its field association + static FieldAssociation queryFieldAssociation + ( + const word& fieldName, + vtkDataSet* dataset + ); + + //- Query composite DataSet for field name and its FieldAssociation + static FieldAssociation queryFieldAssociation + ( + const word& fieldName, + vtkCompositeDataSet* data + ); + + + //- Add "mag(..)" field for filters that only accept scalars + static void addMagField + ( + const word& fieldName, + vtkFieldData* fieldData + ); + + //- Add "mag(..)" field for filters that only accept scalars + static void addMagField + ( + const word& fieldName, + vtkDataSet* dataset + ); + + //- Add "mag(..)" field for filters that only accept scalars + static void addMagField + ( + const word& fieldName, + vtkCompositeDataSet* data + ); + + //- Set the colour map void setColourMap(vtkLookupTable* lut) const; - //- Add scalar bar to renderer + //- Add scalar bar (if visible) to renderer void addScalarBar ( const scalar position, @@ -148,9 +281,9 @@ protected: ( const scalar position, const word& colourFieldName, - vtkPolyDataMapper* mapper, - vtkRenderer* renderer, - vtkPolyData* pData + const FieldAssociation fieldAssociation, + vtkMapper* mapper, + vtkRenderer* renderer ) const; //- Add glyphs @@ -158,13 +291,17 @@ protected: ( const scalar position, const word& scaleFieldName, + const fieldSummary& scaleFieldInfo, const word& colourFieldName, + const fieldSummary& colourFieldInfo, const scalar maxGlyphLength, + vtkPolyData* data, vtkActor* actor, vtkRenderer* renderer ) const; + //- No copy construct fieldVisualisationBase(const fieldVisualisationBase&) = delete; @@ -204,6 +341,19 @@ public: } // End namespace runTimePostPro } // End namespace functionObjects + + +// Ostream +Ostream& operator<< +( + Ostream& os, + const InfoProxy + < + functionObjects::runTimePostPro::fieldVisualisationBase::fieldSummary + >& proxy +); + + } // End namespace Foam // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/functionObjects/graphics/runTimePostProcessing/functionObjectBase.C b/src/functionObjects/graphics/runTimePostProcessing/functionObjectBase.C index 28d4fbffb3f432803048e8af85d5a1adcb2438f4..c44fecc56fee28aa6148cdfe6b40bd42a13fad6a 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/functionObjectBase.C +++ b/src/functionObjects/graphics/runTimePostProcessing/functionObjectBase.C @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2016-2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd. \\/ M anipulation | ------------------------------------------------------------------------------- License @@ -25,20 +25,6 @@ License #include "functionObjectBase.H" -// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // - -namespace Foam -{ -namespace functionObjects -{ -namespace runTimePostPro -{ - defineTypeNameAndDebug(functionObjectBase, 0); -} -} -} - - // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // Foam::fileName @@ -69,7 +55,12 @@ bool Foam::functionObjects::runTimePostPro::functionObjectBase::removeFile { // Foam::rm() ignores empty names etc. - return Foam::rm(getFileName(keyword, subDictName)); + if (Pstream::master()) + { + return Foam::rm(getFileName(keyword, subDictName)); + } + + return false; } @@ -85,6 +76,7 @@ Foam::functionObjects::runTimePostPro::functionObjectBase::functionObjectBase fieldVisualisationBase(dict, colours), state_(state), functionObjectName_(dict.get<word>("functionObject")), + liveObject_(dict.lookupOrDefault("liveObject", true)), clearObjects_(dict.lookupOrDefault("clearObjects", false)) {} diff --git a/src/functionObjects/graphics/runTimePostProcessing/functionObjectBase.H b/src/functionObjects/graphics/runTimePostProcessing/functionObjectBase.H index 47647fc5e736b7393438cbfbb7046b03363d6659..abab1a26074c290d82de3cca9af2b062e1d44a2e 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/functionObjectBase.H +++ b/src/functionObjects/graphics/runTimePostProcessing/functionObjectBase.H @@ -2,7 +2,7 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2016-2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd. \\/ M anipulation | ------------------------------------------------------------------------------- License @@ -29,11 +29,15 @@ Description Dictionary controls \table - Property | Description | Required | Default - functionObject | The data source | yes | - clearObjects | Remove file after use | no | no + Property | Description | Required | Default + functionObject | The data source | yes | + clearObjects | Remove file after use | no | no + liveObject | Prefer simulation data source | no | true \endtable + The "live" keyword indiates that from within the simulation (in memory) + is preferred over data from disk (for example). + SourceFiles functionObjectBase.C @@ -64,14 +68,17 @@ class functionObjectBase { protected: - // Protected data + // Protected Data //- Reference to the state const stateFunctionObject& state_; - //- The function object name which provides the source data + //- The function object name that provides the source data word functionObjectName_; + //- Flag to indicate "live" (simulation) data source should be used + bool liveObject_; + //- Flag to indicate that source data should be cleared after use bool clearObjects_; @@ -109,6 +116,7 @@ protected: // \note does not change the stateFunctionObject bool removeFile(const word& keyword, const word& subDictName); + //- No copy construct functionObjectBase(const functionObjectBase&) = delete; @@ -118,10 +126,6 @@ protected: public: - //- Run-time type information - TypeName("functionObjectBase"); - - // Constructors //- Construct from dictionary diff --git a/src/functionObjects/graphics/runTimePostProcessing/functionObjectCloud.C b/src/functionObjects/graphics/runTimePostProcessing/functionObjectCloud.C index a429d7fffd3189ee60a3d56b412ee35273732d77..54e71f0444cff104e7945e1f76f54075532e8ca0 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/functionObjectCloud.C +++ b/src/functionObjects/graphics/runTimePostProcessing/functionObjectCloud.C @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2015-2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd. \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2015 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -33,11 +31,11 @@ License // VTK includes #include "vtkActor.h" -#include "vtkRenderer.h" -#include "vtkSmartPointer.h" #include "vtkPolyData.h" #include "vtkPolyDataMapper.h" #include "vtkProperty.h" +#include "vtkRenderer.h" +#include "vtkSmartPointer.h" // VTK Readers #include "vtkPolyDataReader.h" @@ -51,13 +49,42 @@ namespace functionObjects { namespace runTimePostPro { - defineTypeNameAndDebug(functionObjectCloud, 0); + defineTypeName(functionObjectCloud); addToRunTimeSelectionTable(pointData, functionObjectCloud, dictionary); } } } +// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * // + +namespace +{ + +static vtkSmartPointer<vtkPolyData> getPolyDataFile(const Foam::fileName& fName) +{ + // Very simple - we only support vtp files, which are expected to have + // the scaling and colouring fields. + + vtkSmartPointer<vtkPolyData> dataset; + + if (fName.ext() == "vtp") + { + auto reader = vtkSmartPointer<vtkXMLPolyDataReader>::New(); + + reader->SetFileName(fName.c_str()); + reader->Update(); + dataset = reader->GetOutput(); + + return dataset; + } + + return dataset; +} + +} // End anonymous namespace + + // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::functionObjects::runTimePostPro::functionObjectCloud::functionObjectCloud @@ -73,9 +100,7 @@ Foam::functionObjects::runTimePostPro::functionObjectCloud::functionObjectCloud inputFileName_(), colourFieldName_(dict.get<word>("colourField")), actor_() -{ - actor_ = vtkSmartPointer<vtkActor>::New(); -} +{} // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // @@ -87,8 +112,8 @@ Foam::functionObjects::runTimePostPro::functionObjectCloud:: // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // -void Foam::functionObjects::runTimePostPro::functionObjectCloud:: -addGeometryToScene +bool Foam::functionObjects::runTimePostPro::functionObjectCloud:: +addGeometryFromFile ( const scalar position, vtkRenderer* renderer @@ -96,72 +121,118 @@ addGeometryToScene { if (!visible_) { - return; + return false; } + vtkSmartPointer<vtkPolyData> polyData; + + bool good = true; + // The vtkCloud stores 'file' via the stateFunctionObject // (lookup by cloudName). // It only generates VTP format, which means there is a single file // containing all fields. - inputFileName_ = getFileName("file", cloudName_); + if (Pstream::master()) + { + inputFileName_ = getFileName("file", cloudName_); + + if (inputFileName_.size()) + { + polyData = getPolyDataFile(inputFileName_); + + if (!polyData || polyData->GetNumberOfPoints() == 0) + { + good = false; + + WarningInFunction + << "Could not read "<< inputFileName_ << nl + << "Only VTK (.vtp) files are supported" + << endl; + } + else + { + DebugInfo + << " Resolved cloud file " + << inputFileName_ << endl; + } + } + else + { + good = false; - if (inputFileName_.empty()) + WarningInFunction + << "Unable to find function object " << functionObjectName_ + << " output for field " << fieldName_ + << ". Cloud will not be processed" + << endl; + } + } + else { - WarningInFunction - << "Unable to find function object " << functionObjectName_ - << " output for field " << fieldName_ - << ". Cloud will not be processed" - << endl; - return; + inputFileName_.clear(); } + reduce(good, andOp<bool>()); - vtkSmartPointer<vtkPolyData> dataset; - - if (inputFileName_.hasExt("vtp")) + if (!good) { - auto reader = vtkSmartPointer<vtkXMLPolyDataReader>::New(); - reader->SetFileName(inputFileName_.c_str()); - reader->Update(); - - dataset = reader->GetOutput(); + return false; } - else + + // Only render on master + if (!renderer || !Pstream::master()) { - // Invalid name - ignore. - // Don't support VTK legacy format at all - it is too wasteful - // and cumbersome. + return true; + } - WarningInFunction - << "Could not read "<< inputFileName_ << nl - << "Only VTK (.vtp) files are supported" - << ". Cloud will not be processed" - << endl; - inputFileName_.clear(); - } + // Rendering + actor_ = vtkSmartPointer<vtkActor>::New(); - if (dataset) { + fieldSummary scaleFieldInfo = + queryFieldSummary(fieldName_, polyData); + + fieldSummary colourFieldInfo = + queryFieldSummary(colourFieldName_, polyData); + + // No reduction + auto mapper = vtkSmartPointer<vtkPolyDataMapper>::New(); actor_->SetMapper(mapper); + /// dataset->Print(std::cout); + addGlyphs ( position, - fieldName_, - colourFieldName_, + fieldName_, scaleFieldInfo, // scaling + colourFieldName_, colourFieldInfo, // colour maxGlyphLength_, - dataset, + polyData, actor_, renderer ); renderer->AddActor(actor_); } + + return true; +} + + +void Foam::functionObjects::runTimePostPro::functionObjectCloud:: +addGeometryToScene +( + const scalar position, + vtkRenderer* renderer +) +{ + // File source + addGeometryFromFile(position, renderer); } @@ -170,10 +241,16 @@ void Foam::functionObjects::runTimePostPro::functionObjectCloud::updateActors const scalar position ) { - actor_->GetProperty()->SetOpacity(opacity(position)); + if (actor_) + { + const vector colour = pointColour_->value(position); + + vtkProperty* prop = actor_->GetProperty(); - vector pc = pointColour_->value(position); - actor_->GetProperty()->SetColor(pc[0], pc[1], pc[2]); + prop->SetOpacity(opacity(position)); + + prop->SetColor(colour[0], colour[1], colour[2]); + } } diff --git a/src/functionObjects/graphics/runTimePostProcessing/functionObjectCloud.H b/src/functionObjects/graphics/runTimePostProcessing/functionObjectCloud.H index 9cf9e2dd6691a9921a9493453d4584943ed8f6cc..ba8d43a1689b30726bb033cea914ba136d000278 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/functionObjectCloud.H +++ b/src/functionObjects/graphics/runTimePostProcessing/functionObjectCloud.H @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2016-2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd. \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2015 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -27,7 +25,17 @@ Class Foam::functionObjects::runTimePostPro::functionObjectCloud Description - Visualisation of cloud data from function object output + Visualisation of cloud data from function object output (file-based only). + + Dictionary controls + \table + Property | Description | Required | Default + type | The point type: functionObjectCloud | yes | + functionObject | The data source | yes | + cloud | The cloud name | no | + field | The field for glyphs scaling | no | + colourField | The field to display | no | + \endtable SourceFiles functionObjectCloud.C @@ -87,7 +95,7 @@ protected: public: //- Run-time type information - TypeName("functionObjectCloud"); + TypeNameNoDebug("functionObjectCloud"); // Constructors @@ -107,7 +115,14 @@ public: // Member Functions - //- Add tube(s) to scene + //- Add cloud to scene (using file source) + bool addGeometryFromFile + ( + const scalar position, + vtkRenderer* renderer + ); + + //- Add cloud to scene virtual void addGeometryToScene ( const scalar position, diff --git a/src/functionObjects/graphics/runTimePostProcessing/functionObjectLine.C b/src/functionObjects/graphics/runTimePostProcessing/functionObjectLine.C index 3db0705aab98f9dcec9fed97ffbc0c702842c479..e27dabcc972c71887bcdd7e57a0934a321266c8a 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/functionObjectLine.C +++ b/src/functionObjects/graphics/runTimePostProcessing/functionObjectLine.C @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2015-2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd. \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2015 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -50,7 +48,7 @@ namespace functionObjects { namespace runTimePostPro { - defineTypeNameAndDebug(functionObjectLine, 0); + defineTypeName(functionObjectLine); addToRunTimeSelectionTable(pathline, functionObjectLine, dictionary); } } @@ -67,7 +65,7 @@ static vtkSmartPointer<vtkPolyData> getPolyDataFile(const Foam::fileName& fName) // Not extremely elegant... vtkSmartPointer<vtkPolyData> dataset; - if (fName.ext() == "vtk") + if ("vtk" == fName.ext()) { auto reader = vtkSmartPointer<vtkPolyDataReader>::New(); @@ -78,7 +76,7 @@ static vtkSmartPointer<vtkPolyData> getPolyDataFile(const Foam::fileName& fName) return dataset; } - if (fName.ext() == "vtp") + if ("vtp" == fName.ext()) { auto reader = vtkSmartPointer<vtkXMLPolyDataReader>::New(); @@ -127,7 +125,8 @@ addGeometryToScene vtkRenderer* renderer ) { - if (!visible_) + // Currently master-only + if (!visible_ || !renderer || !Pstream::master()) { return; } @@ -155,10 +154,19 @@ addGeometryToScene return; } + DebugInfo << " Resolved lines " << fName << endl; + auto mapper = vtkSmartPointer<vtkPolyDataMapper>::New(); - setField(position, fieldName_, mapper, renderer, polyData); + setField + ( + position, + fieldName_, + queryFieldAssociation(fieldName_, polyData), + mapper, + renderer + ); actor_->SetMapper(mapper); diff --git a/src/functionObjects/graphics/runTimePostProcessing/functionObjectLine.H b/src/functionObjects/graphics/runTimePostProcessing/functionObjectLine.H index f5b88bc9c6b1f98c7c902f27388419b6910c4806..63cc9619727fac28f6b342ba597409b4aab75194 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/functionObjectLine.H +++ b/src/functionObjects/graphics/runTimePostProcessing/functionObjectLine.H @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2016-2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd. \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2015 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -27,7 +25,13 @@ Class Foam::functionObjects::runTimePostPro::functionObjectLine Description - Visualisation of line data from function object output + Visualisation of line data from function object output (file-based only). + + Dictionary controls + \table + Property | Description | Required | Default + type | The line type: functionObjectLine | yes | + \endtable SourceFiles functionObjectLine.C @@ -78,7 +82,7 @@ protected: public: //- Run-time type information - TypeName("functionObjectLine"); + TypeNameNoDebug("functionObjectLine"); // Constructors diff --git a/src/functionObjects/graphics/runTimePostProcessing/functionObjectSurface.C b/src/functionObjects/graphics/runTimePostProcessing/functionObjectSurface.C index ce841148051de3fb9603a21da963067c96723bfa..801305f8c788f8e7fd86cbe55a8e70173ddfea3b 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/functionObjectSurface.C +++ b/src/functionObjects/graphics/runTimePostProcessing/functionObjectSurface.C @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2015-2016 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd. \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2015 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -32,6 +30,13 @@ License // VTK includes #include "vtkActor.h" +#include "vtkCellData.h" +#include "vtkCellDataToPointData.h" +#include "vtkCompositeDataGeometryFilter.h" +#include "vtkCompositeDataSet.h" +#include "vtkCompositePolyDataMapper.h" +#include "vtkMultiPieceDataSet.h" +#include "vtkPointData.h" #include "vtkPolyData.h" #include "vtkPolyDataMapper.h" #include "vtkProperty.h" @@ -50,7 +55,7 @@ namespace functionObjects { namespace runTimePostPro { - defineTypeNameAndDebug(functionObjectSurface, 0); + defineTypeName(functionObjectSurface); addToRunTimeSelectionTable(surface, functionObjectSurface, dictionary); } } @@ -67,7 +72,7 @@ static vtkSmartPointer<vtkPolyData> getPolyDataFile(const Foam::fileName& fName) // Not extremely elegant... vtkSmartPointer<vtkPolyData> dataset; - if (fName.ext() == "vtk") + if ("vtk" == fName.ext()) { auto reader = vtkSmartPointer<vtkPolyDataReader>::New(); @@ -78,7 +83,7 @@ static vtkSmartPointer<vtkPolyData> getPolyDataFile(const Foam::fileName& fName) return dataset; } - if (fName.ext() == "vtp") + if ("vtp" == fName.ext()) { auto reader = vtkSmartPointer<vtkXMLPolyDataReader>::New(); @@ -110,17 +115,10 @@ functionObjectSurface {} -// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // - -Foam::functionObjects::runTimePostPro::functionObjectSurface:: -~functionObjectSurface() -{} - - // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // -void Foam::functionObjects::runTimePostPro::functionObjectSurface:: -addGeometryToScene +bool Foam::functionObjects::runTimePostPro::functionObjectSurface:: +addGeometry ( const scalar position, vtkRenderer* renderer @@ -128,39 +126,291 @@ addGeometryToScene { if (!visible_) { - return; + return false; + } + + DebugInfo << " Resolve surface " << functionObjectName_ << endl; + + const polySurface* surf = + ( + geometryBase::parent_.storedObjects() + .cfindObject<polySurface>(functionObjectName_) + ); + + // Treat surface with no faces/points like a missing surface + surf = ((surf && surf->nPoints()) ? surf : nullptr); + + bool hasSurface = surf; + + + // Retrieve the field association (CELL, POINT) for the given field + + unsigned fieldAssociation(0u); + if (surf) + { + unsigned queried = surf->queryFieldAssociation(fieldName_); + + if (queried & polySurface::FACE_DATA) + { + fieldAssociation |= FieldAssociation::CELL_DATA; + } + if (queried & polySurface::POINT_DATA) + { + fieldAssociation |= FieldAssociation::POINT_DATA; + } + } + + // Reduce the information + if (Pstream::parRun()) + { + if (!hasSurface) + { + // No geometry - set all field association bits ON to ensure + // it does not affect bitwise reduction. + fieldAssociation = (~0u); + } + + reduce(hasSurface, orOp<bool>()); + reduce(fieldAssociation, bitAndOp<unsigned>()); } - fileName fName = getFileName("file", fieldName_); - if (fName.empty()) + if (!hasSurface) { WarningInFunction - << "Unable to read file name from function object " - << functionObjectName_ << " for field " << fieldName_ - << ". Surface will not be processed" + << "No functionObject surface, or has no faces: " + << functionObjectName_ << endl; - return; + + if (debug) + { + Info<< " Available surfaces:" << nl + << geometryBase::parent_.storedObjects() + .sortedNames<polySurface>() << endl; + } + return false; } + //// Pout<< "local surface = " << (surf ? surf->nFaces() : 0) << nl; + + + // Create a vtkMultiPieceDataSet with vtkPolyData on the leaves + vtkSmartPointer<vtkMultiPieceDataSet> multiPiece; - auto polyData = getPolyDataFile(fName); + // Requesting glyphs on the surface AND only have face data? + // - just use the faceCentres directly and attach fields as CellData + // (not PointData). - if (!polyData || polyData->GetNumberOfPoints() == 0) + if + ( + representation_ == rtGlyph + && (fieldAssociation == FieldAssociation::CELL_DATA) + ) { - WarningInFunction - << "Could not read "<< fName << nl - << "Only VTK (.vtp, .vtk) files are supported" - << endl; - return; + multiPiece = gatherFaceCentres(surf); } + else + { + multiPiece = gatherSurfacePieces(surf); + } + + + // Add the field (the information is consistent after last reduction). + + // Need field(s) for glyphs or colourByField: + + if (representation_ == rtGlyph || colourBy_ == cbField) + { + if (fieldAssociation == FieldAssociation::CELL_DATA) + { + addDimField<polySurfaceGeoMesh> + ( + multiPiece, + surf, + fieldName_ + ); + } + else if (fieldAssociation & FieldAssociation::POINT_DATA) + { + addDimField<polySurfacePointGeoMesh> + ( + multiPiece, + surf, + fieldName_ + ); + } + } + + + // Now have a multi-piece dataset that is one of the following: + // + // - one-piece per processor (OpenFOAM = parallel, VTK=parallel) + // - all pieces on master only (OpenFOAM = parallel, VTK=serial) + + // Re-query field information - we may have stored it differently + // than the original source. + + fieldSummary fieldInfo = queryFieldSummary(fieldName_, multiPiece); + fieldInfo.reduce(); + + + // Not rendered on this processor? + // This is where we stop, but could also have an MPI barrier + if (!renderer) + { + return true; + } + + + // Rendering + + { + auto polyData = vtkSmartPointer<vtkCompositeDataGeometryFilter>::New(); + + polyData->SetInputData(multiPiece); + polyData->Update(); + + if (representation_ == rtGlyph) + { + addGlyphs + ( + position, + fieldName_, fieldInfo, // scaling + fieldName_, fieldInfo, // colouring + maxGlyphLength_, + polyData->GetOutput(), + surfaceActor_, + renderer + ); + } + else + { + vtkSmartPointer<vtkCellDataToPointData> cellToPoint; + + // CellData - Need a cell->point filter + if (smooth_ && !fieldInfo.hasPointData()) + { + cellToPoint = vtkSmartPointer<vtkCellDataToPointData>::New(); + cellToPoint->SetInputData(multiPiece); + + polyData->SetInputConnection(cellToPoint->GetOutputPort()); + } + else + { + polyData->SetInputData(multiPiece); + } + polyData->Update(); + + + if (!smooth_) + { + addFeatureEdges(renderer, polyData); + } + + auto mapper = vtkSmartPointer<vtkPolyDataMapper>::New(); + mapper->SetInputConnection(polyData->GetOutputPort()); + + setField + ( + position, + fieldName_, + ( + smooth_ + ? FieldAssociation::POINT_DATA + : FieldAssociation(fieldInfo.association_) + ), + mapper, + renderer + ); + + surfaceActor_->SetMapper(mapper); + + setRepresentation(surfaceActor_); + + renderer->AddActor(surfaceActor_); + } + } + + return true; +} + + +bool Foam::functionObjects::runTimePostPro::functionObjectSurface:: +addGeometryFromFile +( + const scalar position, + vtkRenderer* renderer +) +{ + if (!visible_) + { + return false; + } + + vtkSmartPointer<vtkPolyData> polyData; + + bool good = true; + + // File reading is serial (master only) + if (Pstream::master()) + { + fileName fName = getFileName("file", fieldName_); + + if (fName.size()) + { + polyData = getPolyDataFile(fName); + + if (!polyData || polyData->GetNumberOfPoints() == 0) + { + good = false; + + WarningInFunction + << "Could not read "<< fName << nl + << "Only VTK (.vtp, .vtk) files are supported" + << endl; + } + else + { + DebugInfo << " Resolved surface " << fName << endl; + } + } + else + { + good = false; + + WarningInFunction + << "Unable to read file name from function object " + << functionObjectName_ << " for field " << fieldName_ + << ". Surface will not be processed" + << endl; + } + } + + reduce(good, andOp<bool>()); + + if (!good) + { + return false; + } + + // Only render on master + if (!renderer || !Pstream::master()) + { + return true; + } + + fieldSummary fieldInfo = queryFieldSummary(fieldName_, polyData); + // No reduction (serial) + + + // Render if (representation_ == rtGlyph) { addGlyphs ( position, - fieldName_, - fieldName_, + fieldName_, fieldInfo, // scaling + fieldName_, fieldInfo, // colouring maxGlyphLength_, polyData, surfaceActor_, @@ -174,7 +424,14 @@ addGeometryToScene auto mapper = vtkSmartPointer<vtkPolyDataMapper>::New(); mapper->SetInputData(polyData); - setField(position, fieldName_, mapper, renderer, polyData); + setField + ( + position, + fieldName_, + queryFieldAssociation(fieldName_, polyData), + mapper, + renderer + ); surfaceActor_->SetMapper(mapper); @@ -182,6 +439,44 @@ addGeometryToScene renderer->AddActor(surfaceActor_); } + + return true; +} + + +void Foam::functionObjects::runTimePostPro::functionObjectSurface:: +addGeometryToScene +( + const scalar position, + vtkRenderer* renderer +) +{ + if (!visible_) + { + return; + } + + if (liveObject_) + { + // Live source + if (addGeometry(position, renderer)) + { + return; + } + + WarningInFunction + << "No functionObject live source, or is empty: " + << functionObjectName_ + << " ... attempting with file source" + << endl; + } + else + { + DebugInfo << "Using file source only" << nl; + } + + // File source + addGeometryFromFile(position, renderer); } @@ -189,6 +484,8 @@ bool Foam::functionObjects::runTimePostPro::functionObjectSurface::clear() { if (functionObjectBase::clear()) { + // Even for a "live" data source we allow file cleanup + // (eg, from a previous run, etc) return removeFile("file", fieldName_); } diff --git a/src/functionObjects/graphics/runTimePostProcessing/functionObjectSurface.H b/src/functionObjects/graphics/runTimePostProcessing/functionObjectSurface.H index 719ba19e6b7de06f7b785cf5884335125bd87395..eb1288a624f753266841aca8ae398af32876b3fa 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/functionObjectSurface.H +++ b/src/functionObjects/graphics/runTimePostProcessing/functionObjectSurface.H @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2016-2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd. \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2015 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -27,7 +25,22 @@ Class Foam::functionObjects::runTimePostPro::functionObjectSurface Description - Visualisation of surface data from function object output + Visualisation of surface data from function object output, + typically the result of a prior sampled surfaces operation. + + Operates in a "live" mode, in which the previously sampled surfaces + are retrieved from the functionObject registry. + Or in the traditional file-based mode, in which the sampling is used + to generate a file and its name is retrieved from the functionObject + properties. + + File-based import is restricted to "vtk" and "vtp" formats. + + Dictionary controls + \table + Property | Description | Required | Default + type | The type: functionObjectSurface | yes | + \endtable SourceFiles functionObjectfunctionObjectSurface.C @@ -72,7 +85,7 @@ protected: public: //- Run-time type information - TypeName("functionObjectSurface"); + TypeNameNoDebug("functionObjectSurface"); // Constructors @@ -87,11 +100,25 @@ public: //- Destructor - virtual ~functionObjectSurface(); + virtual ~functionObjectSurface() = default; // Member Functions + //- Add functionObjectSurface to scene (using simulation source) + bool addGeometry + ( + const scalar position, + vtkRenderer* renderer + ); + + //- Add functionObjectSurface to scene (using file source) + bool addGeometryFromFile + ( + const scalar position, + vtkRenderer* renderer + ); + //- Add functionObjectSurface(s) to scene virtual void addGeometryToScene ( diff --git a/src/functionObjects/graphics/runTimePostProcessing/geometryBase.C b/src/functionObjects/graphics/runTimePostProcessing/geometryBase.C index c75179dbd93e8a9437737356d002f1c888454fb1..bac6e4fb06ec0ee7a7b93117d043068f89289e61 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/geometryBase.C +++ b/src/functionObjects/graphics/runTimePostProcessing/geometryBase.C @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2016-2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd. \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2015 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -35,6 +33,18 @@ License // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // +namespace Foam +{ +namespace functionObjects +{ +namespace runTimePostPro +{ + + defineDebugSwitchWithName(geometryBase, "runTimePostPro::geometryBase", 0); +} +} +} + const Foam::Enum < Foam::functionObjects::runTimePostPro::geometryBase::renderModeType @@ -89,7 +99,7 @@ Foam::functionObjects::runTimePostPro::geometryBase::geometryBase : parent_(parent), name_(dict.dictName()), - visible_(dict.get<bool>("visible")), + visible_(dict.lookupOrDefault("visible", true)), renderMode_ ( renderModeTypeNames.lookupOrDefault("renderMode", dict, rmGouraud) @@ -123,6 +133,13 @@ Foam::functionObjects::runTimePostPro::geometryBase::parent() const } +bool Foam::functionObjects::runTimePostPro::geometryBase:: +needsCollective() const +{ + return parent_.needsCollective(); +} + + const Foam::word& Foam::functionObjects::runTimePostPro::geometryBase::name() const { diff --git a/src/functionObjects/graphics/runTimePostProcessing/geometryBase.H b/src/functionObjects/graphics/runTimePostProcessing/geometryBase.H index 96f7cc99e57afcb01620e4e3a0d9904861037997..6fdb2c5ba5129ce7d55a46c23fde05c3c265acd0 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/geometryBase.H +++ b/src/functionObjects/graphics/runTimePostProcessing/geometryBase.H @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2016-2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd. \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2015 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -27,12 +25,12 @@ Class Foam::functionObjects::runTimePostPro::geometryBase Description - Base class for surface, text handling + Base class for surface, text handling etc. Dictionary controls \table Property | Description | Required | Default - visible | Display the object | yes | + visible | Display the object | no | yes renderMode | Shading (flat/gouraud/phong) | no | gouraud opacity | Object opacity | no | 1.0 \endtable @@ -53,7 +51,7 @@ SourceFiles // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -// Forward declarations +// Forward Declarations (VTK) class vtkRenderer; class vtkActor; @@ -62,7 +60,7 @@ namespace Foam namespace functionObjects { -// Forward declarations +// Forward Declarations class runTimePostProcessing; namespace runTimePostPro @@ -75,11 +73,11 @@ namespace runTimePostPro class geometryBase { - public: - // Public enumerations + // Public Enumerations + //- Surface shading types enum renderModeType { rmFlat, //!< Flat shading @@ -87,6 +85,7 @@ public: rmPhong //!< Phong shading }; + //- Names for surface shading types static const Enum<renderModeType> renderModeTypeNames; @@ -97,7 +96,7 @@ protected: //- Reference to the parent function object const runTimePostProcessing& parent_; - //- Name + //- The surface name word name_; //- Visible flag @@ -113,7 +112,7 @@ protected: const HashPtrTable<Function1<vector>>& colours_; - // Protected functions + // Protected Functions //- Initialise actor void initialiseActor(vtkActor* actor) const; @@ -127,6 +126,9 @@ protected: public: + //- Debug switch + static int debug; + // Constructors //- Construct from dictionary @@ -149,6 +151,10 @@ public: //- Return the reference to the parent function object const runTimePostProcessing& parent() const; + //- May need to gather geometry parts to render on single-processor + // True when OpenFOAM is running in parallel but VTK is not. + bool needsCollective() const; + //- Return the name const word& name() const; @@ -162,7 +168,7 @@ public: const HashPtrTable<Function1<vector>>& colours() const; - // Scene interaction + // Scene Interaction //- Add geometry to scene virtual void addGeometryToScene @@ -174,7 +180,7 @@ public: //- Update the actors virtual void updateActors(const scalar position) = 0; - //- Clear files used to create the object(s) + //- Clear any files used to create the object(s) virtual bool clear() = 0; }; diff --git a/src/functionObjects/graphics/runTimePostProcessing/geometryCloud.C b/src/functionObjects/graphics/runTimePostProcessing/geometryCloud.C new file mode 100644 index 0000000000000000000000000000000000000000..350c714f8bf5ac217048e866948dfacd2ab5918c --- /dev/null +++ b/src/functionObjects/graphics/runTimePostProcessing/geometryCloud.C @@ -0,0 +1,263 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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 "geometryCloud.H" +#include "cloud.H" +#include "fvMesh.H" +#include "runTimePostProcessing.H" +#include "addToRunTimeSelectionTable.H" + +// VTK includes +#include "vtkActor.h" +#include "vtkCompositeDataGeometryFilter.h" +#include "vtkCompositeDataSet.h" +#include "vtkCompositePolyDataMapper.h" +#include "vtkPolyData.h" +#include "vtkPolyDataMapper.h" +#include "vtkProperty.h" +#include "vtkRenderer.h" +#include "vtkSmartPointer.h" + +// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // + +namespace Foam +{ +namespace functionObjects +{ +namespace runTimePostPro +{ + defineTypeName(geometryCloud); + addToRunTimeSelectionTable(pointData, geometryCloud, dictionary); +} +} +} + + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +bool Foam::functionObjects::runTimePostPro::geometryCloud::addCloudField +( + vtkMultiPieceDataSet* multiPiece, + const objectRegistry& obrTmp, + const word& fieldName +) const +{ + const regIOobject* ioptr = obrTmp.cfindObject<regIOobject>(fieldName); + + return (multiPiece) && + ( + addCloudField<label> + ( + multiPiece, ioptr, fieldName + ) + || addCloudField<scalar> + ( + multiPiece, ioptr, fieldName + ) + || addCloudField<vector> + ( + multiPiece, ioptr, fieldName + ) + || addCloudField<sphericalTensor> + ( + multiPiece, ioptr, fieldName + ) + || addCloudField<symmTensor> + ( + multiPiece, ioptr, fieldName + ) + || addCloudField<tensor> + ( + multiPiece, ioptr, fieldName + ) + ); +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::functionObjects::runTimePostPro::geometryCloud::geometryCloud +( + const runTimePostProcessing& parent, + const dictionary& dict, + const HashPtrTable<Function1<vector>>& colours +) +: + pointData(parent, dict, colours), + fieldVisualisationBase(dict, colours), + cloudName_(dict.get<word>("cloud")), + colourFieldName_(dict.get<word>("colourField")), + actor_() +{} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::functionObjects::runTimePostPro::geometryCloud:: +~geometryCloud() +{} + + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // + +bool Foam::functionObjects::runTimePostPro::geometryCloud:: +addGeometry +( + const scalar position, + vtkRenderer* renderer +) +{ + if (!visible_) + { + return false; + } + + + // This is similar (almost identical) to vtkCloud + + const auto* objPtr = parent().mesh().cfindObject<cloud>(cloudName_); + if (!objPtr) + { + return false; + } + + objectRegistry obrTmp + ( + IOobject + ( + "runTimePostPro::cloud::" + cloudName_, + parent().mesh().time().constant(), + parent().mesh(), + IOobject::NO_READ, + IOobject::NO_WRITE, + false + ) + ); + + objPtr->writeObjects(obrTmp); + + const auto* pointsPtr = obrTmp.findObject<vectorField>("position"); + + if (!pointsPtr) + { + // This should be impossible + return false; + } + + + // Create a vtkMultiPieceDataSet with vtkPolyData on the leaves + auto multiPiece = gatherCloud(obrTmp); + + // Add in scaleField and colourField + addCloudField(multiPiece, obrTmp, fieldName_); + addCloudField(multiPiece, obrTmp, colourFieldName_); + + + // Not rendered on this processor? + // This is where we stop, but could also have an MPI barrier + if (!renderer) + { + return true; + } + + + // Rendering + + actor_ = vtkSmartPointer<vtkActor>::New(); + + { + fieldSummary scaleFieldInfo = + queryFieldSummary(fieldName_, multiPiece); + + fieldSummary colourFieldInfo = + queryFieldSummary(colourFieldName_, multiPiece); + + auto polyData = vtkSmartPointer<vtkCompositeDataGeometryFilter>::New(); + + polyData->SetInputData(multiPiece); + polyData->Update(); + + auto mapper = vtkSmartPointer<vtkPolyDataMapper>::New(); + + actor_->SetMapper(mapper); + + /// dataset->Print(std::cout); + + addGlyphs + ( + position, + fieldName_, scaleFieldInfo, // scaling + colourFieldName_, colourFieldInfo, // colour + maxGlyphLength_, + polyData->GetOutput(), + actor_, + renderer + ); + + renderer->AddActor(actor_); + } + + return true; +} + + +void Foam::functionObjects::runTimePostPro::geometryCloud:: +addGeometryToScene +( + const scalar position, + vtkRenderer* renderer +) +{ + // Live source + addGeometry(position, renderer); +} + + +void Foam::functionObjects::runTimePostPro::geometryCloud::updateActors +( + const scalar position +) +{ + if (actor_) + { + const vector colour = pointColour_->value(position); + + vtkProperty* prop = actor_->GetProperty(); + + prop->SetOpacity(opacity(position)); + + prop->SetColor(colour[0], colour[1], colour[2]); + } +} + + +bool Foam::functionObjects::runTimePostPro::geometryCloud::clear() +{ + return false; +} + + +// ************************************************************************* // diff --git a/src/functionObjects/graphics/runTimePostProcessing/geometryCloud.H b/src/functionObjects/graphics/runTimePostProcessing/geometryCloud.H new file mode 100644 index 0000000000000000000000000000000000000000..a420307fe3c1aa2c243622af9ad0591f12a0219b --- /dev/null +++ b/src/functionObjects/graphics/runTimePostProcessing/geometryCloud.H @@ -0,0 +1,201 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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::geometryCloud + +Description + Visualisation of cloud data from function object output (file-based only). + + Dictionary controls + \table + Property | Description | Required | Default + type | The point type: geometryCloud | yes | + cloud | The cloud name | no | + field | The field for glyphs scaling | no | + colourField | The field to display | no | + \endtable + +SourceFiles + geometryCloud.C + +\*---------------------------------------------------------------------------*/ + +#ifndef functionObjects_runTimePostPro_geometryCloud_H +#define functionObjects_runTimePostPro_geometryCloud_H + +#include "pointData.H" +#include "functionObjectBase.H" +#include "IOField.H" + +#include "vtkSmartPointer.h" +#include "vtkMultiPieceDataSet.h" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ +namespace functionObjects +{ +namespace runTimePostPro +{ + +/*---------------------------------------------------------------------------*\ + Class geometryCloud Declaration +\*---------------------------------------------------------------------------*/ + +class geometryCloud +: + public pointData, + public fieldVisualisationBase +{ +protected: + + // Protected Data + + //- Name of geometryCloud + word cloudName_; + + //- Name of field to colour by + word colourFieldName_; + + //- Actor + vtkSmartPointer<vtkActor> actor_; + + + // Protected Member Functions + + //- Gather and convert cloud positions with vtkPolyData for the leaves. + // If VTK is also running in parallel, each cloud is left + // as a processor-local piece. Otherwise all processor-local + // parts are gathered onto the master in their correponding + // slots. + vtkSmartPointer<vtkMultiPieceDataSet> + gatherCloud(const objectRegistry& obrTmp) const; + + + //- Add field + template<class Type> + bool addField + ( + vtkDataSet* piece, + const Field<Type>& fld, + const word& fieldName + ) const; + + //- Add field + template<class Type> + bool addCloudField + ( + vtkMultiPieceDataSet* multiPiece, + const IOField<Type>* fldptr, + const word& fieldName + ) const; + + //- Add field + template<class Type> + bool addCloudField + ( + vtkMultiPieceDataSet* multiPiece, + const regIOobject* fieldPtr, + const word& fieldName + ) const; + + //- Add field + bool addCloudField + ( + vtkMultiPieceDataSet* multiPiece, + const objectRegistry& obrTmp, + const word& fieldName + ) const; + + + //- No copy construct + geometryCloud(const geometryCloud&) = delete; + + //- No copy assignment + void operator=(const geometryCloud&) = delete; + + +public: + + //- Run-time type information + TypeNameNoDebug("geometryCloud"); + + + // Constructors + + //- Construct from dictionary + geometryCloud + ( + const runTimePostProcessing& parent, + const dictionary& dict, + const HashPtrTable<Function1<vector>>& colours + ); + + + //- Destructor + virtual ~geometryCloud(); + + + // Member Functions + + //- Add cloud to scene (from simulation) + bool addGeometry + ( + const scalar position, + vtkRenderer* renderer + ); + + //- Add cloud to scene + virtual void addGeometryToScene + ( + const scalar position, + vtkRenderer* renderer + ); + + //- Update actors + virtual void updateActors(const scalar position); + + //- No-op + virtual bool clear(); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace runTimePostPro +} // End namespace functionObjects +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#ifdef NoRepository + #include "geometryCloudTemplates.C" +#endif + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/functionObjects/graphics/runTimePostProcessing/geometryCloudGather.C b/src/functionObjects/graphics/runTimePostProcessing/geometryCloudGather.C new file mode 100644 index 0000000000000000000000000000000000000000..c8eb4e0d47530add3c6c5900e484ed59ecba47da --- /dev/null +++ b/src/functionObjects/graphics/runTimePostProcessing/geometryCloudGather.C @@ -0,0 +1,129 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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 "geometryCloud.H" +#include "cloud.H" +#include "runTimePostProcessing.H" + +#include "foamVtkTools.H" + +// VTK includes +#include "vtkMultiPieceDataSet.h" +#include "vtkPolyData.h" +#include "vtkSmartPointer.h" + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +vtkSmartPointer<vtkMultiPieceDataSet> +Foam::functionObjects::runTimePostPro::geometryCloud::gatherCloud +( + const objectRegistry& obrTmp +) const +{ + auto multiPiece = vtkSmartPointer<vtkMultiPieceDataSet>::New(); + multiPiece->SetNumberOfPieces(Pstream::nProcs()); + + const auto* pointsPtr = obrTmp.findObject<vectorField>("position"); + + if (!needsCollective()) + { + // Simple case (serial-serial, parallel-parallel) + + if (pointsPtr && pointsPtr->size()) + { + multiPiece->SetPiece + ( + Pstream::myProcNo(), + Foam::vtk::Tools::Vertices(*pointsPtr) + ); + } + } + else if (Pstream::master()) + { + // Gather pieces on master + + if (pointsPtr && pointsPtr->size()) + { + // Add myself + + multiPiece->SetPiece + ( + Pstream::myProcNo(), + Foam::vtk::Tools::Vertices(*pointsPtr) + ); + } + + // Receive points + pointField points; + + for + ( + int slave=Pstream::firstSlave(); + slave<=Pstream::lastSlave(); + ++slave + ) + { + IPstream fromSlave(Pstream::commsTypes::scheduled, slave); + + points.clear(); + + fromSlave >> points; + + if (points.size()) + { + multiPiece->SetPiece + ( + slave, + Foam::vtk::Tools::Vertices(points) + ); + } + } + } + else + { + // Slave - send points + + OPstream toMaster + ( + Pstream::commsTypes::scheduled, + Pstream::masterNo() + ); + + if (pointsPtr) + { + toMaster << *pointsPtr; + } + else + { + toMaster << pointField(); + } + } + + return multiPiece; +} + + +// ************************************************************************* // diff --git a/src/functionObjects/graphics/runTimePostProcessing/geometryCloudTemplates.C b/src/functionObjects/graphics/runTimePostProcessing/geometryCloudTemplates.C new file mode 100644 index 0000000000000000000000000000000000000000..b45cb40246df81adb328a9ed8dbcab1eadc3eea3 --- /dev/null +++ b/src/functionObjects/graphics/runTimePostProcessing/geometryCloudTemplates.C @@ -0,0 +1,168 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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/>. + +\*---------------------------------------------------------------------------*/ + +#include "foamVtkTools.H" + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +template<class Type> +bool Foam::functionObjects::runTimePostPro::geometryCloud::addField +( + vtkDataSet* piece, + const Field<Type>& fld, + const word& fieldName +) const +{ + if (!piece) return false; + + auto vtkfield = Foam::vtk::Tools::convertFieldToVTK<Type>(fieldName, fld); + + // Only has verts + piece->GetPointData()->AddArray(vtkfield); + + return true; +} + + +template<class Type> +bool Foam::functionObjects::runTimePostPro::geometryCloud::addCloudField +( + vtkMultiPieceDataSet* multiPiece, + const IOField<Type>* fldptr, + const word& fieldName +) const +{ + if (!multiPiece) + { + return false; + } + + if (!needsCollective()) + { + // Simple case (serial-serial, parallel-parallel) + + return fldptr && + addField<Type> + ( + multiPiece->GetPiece(Pstream::myProcNo()), + *fldptr, + fieldName + ); + } + + + // Gather fields + const bool ok = returnReduce((fldptr != nullptr), orOp<bool>()); + + if (!ok) + { + return false; + } + + if (Pstream::master()) + { + if (fldptr) + { + // My field data + addField<Type> + ( + multiPiece->GetPiece(Pstream::myProcNo()), + *fldptr, + fieldName + ); + } + + // Receive field data + Field<Type> recv; + + for + ( + int slave=Pstream::firstSlave(); + slave<=Pstream::lastSlave(); + ++slave + ) + { + IPstream fromSlave(Pstream::commsTypes::scheduled, slave); + + recv.clear(); + + fromSlave + >> recv; + + if (recv.size()) + { + addField<Type> + ( + multiPiece->GetPiece(slave), + recv, + fieldName + ); + } + } + } + else + { + // Slave - send field data + + OPstream toMaster + ( + Pstream::commsTypes::scheduled, + Pstream::masterNo() + ); + + if (fldptr) + { + toMaster + << *fldptr; + } + else + { + toMaster + << List<Type>(); + } + } + + return ok; +} + + +template<class Type> +bool Foam::functionObjects::runTimePostPro::geometryCloud::addCloudField +( + vtkMultiPieceDataSet* multiPiece, + const regIOobject* ioptr, + const word& fieldName +) const +{ + return addCloudField<Type> + ( + multiPiece, + dynamic_cast<const IOField<Type>*>(ioptr), + fieldName + ); +} + + +// ************************************************************************* // diff --git a/src/functionObjects/graphics/runTimePostProcessing/geometryPatches.C b/src/functionObjects/graphics/runTimePostProcessing/geometryPatches.C new file mode 100644 index 0000000000000000000000000000000000000000..c3e711b5afac86f7093d5fcc0e6ed1115723afa8 --- /dev/null +++ b/src/functionObjects/graphics/runTimePostProcessing/geometryPatches.C @@ -0,0 +1,315 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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 "geometryPatches.H" +#include "fvMesh.H" +#include "volFields.H" +#include "emptyPolyPatch.H" +#include "processorPolyPatch.H" +#include "foamVtkTools.H" +#include "runTimePostProcessing.H" +#include "addToRunTimeSelectionTable.H" + +// VTK includes +#include "vtkActor.h" +#include "vtkCellArray.h" +#include "vtkCellData.h" +#include "vtkCellDataToPointData.h" +#include "vtkCompositeDataGeometryFilter.h" +#include "vtkCompositeDataSet.h" +#include "vtkCompositePolyDataMapper.h" +#include "vtkMultiPieceDataSet.h" +#include "vtkPointData.h" +#include "vtkPolyData.h" +#include "vtkPolyDataMapper.h" +#include "vtkProperty.h" +#include "vtkRenderer.h" +#include "vtkSmartPointer.h" + + +// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // + +namespace Foam +{ +namespace functionObjects +{ +namespace runTimePostPro +{ + defineTypeName(geometryPatches); + addToRunTimeSelectionTable(surface, geometryPatches, dictionary); +} +} +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::functionObjects::runTimePostPro::geometryPatches::geometryPatches +( + const runTimePostProcessing& parent, + const dictionary& dict, + const HashPtrTable<Function1<vector>>& colours +) +: + geometrySurface(parent, dict, colours, List<fileName>()), + fieldVisualisationBase(dict, colours), + selectPatches_(), + nearCellValue_(dict.lookupOrDefault("nearCellValue", false)) +{ + dict.readEntry("patches", selectPatches_); +} + + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // + +void Foam::functionObjects::runTimePostPro::geometryPatches::addGeometryToScene +( + const scalar position, + vtkRenderer* renderer +) +{ + if (!visible_ || selectPatches_.empty()) + { + return; + } + + const polyBoundaryMesh& patches = parent().mesh().boundaryMesh(); + + bitSet selectedPatchIds(patches.size()); + + for (const polyPatch& pp : patches) + { + if (isType<emptyPolyPatch>(pp) || pp.empty()) + { + continue; + } + else if (isA<processorPolyPatch>(pp)) + { + break; // No processor patches + } + + if (selectPatches_.match(pp.name())) + { + selectedPatchIds.set(pp.index()); + } + } + + + labelListList patchIds(Pstream::nProcs()); + patchIds[Pstream::myProcNo()] = selectedPatchIds.sortedToc(); + + Pstream::gatherList(patchIds); + Pstream::scatterList(patchIds); + + label nPieces = 0; + for (const labelList& ids : patchIds) + { + nPieces += ids.size(); + } + + /// Pout<< "add patches: " << selectPatches_ << nl + /// << " = " << patchIds << " == " << nPieces << " total" << nl; + + if (!nPieces) + { + WarningInFunction + << "No patches selected: " << flatOutput(selectPatches_) + << endl; + return; + } + + DebugInfo << " Add geometry patches" << nl; + + + // Create a vtkMultiPieceDataSet with vtkPolyData on the leaves + + // When adding fields, only map scalar/vector fields. + // - this is easier and all we mostly ever need + + vtkSmartPointer<vtkMultiPieceDataSet> multiPiece; + + // Requesting glyphs on the surface - just use the faceCentres directly + // and attach fields as CellData (not PointData). + + if (representation_ == rtGlyph) + { + multiPiece = gatherPatchFaceCentres(patchIds); + } + else + { + multiPiece = gatherPatchPieces(patchIds); + } + + + // Add (scalar/vector) field. + // - Need field(s) for glyphs or colourByField: + + int nCmpt = 0; + if (representation_ == rtGlyph || colourBy_ == cbField) + { + if (!nCmpt) + { + nCmpt = addPatchField<scalar> + ( + multiPiece, + patchIds, + parent().mesh().cfindObject<volScalarField>(fieldName_), + fieldName_ + ); + } + if (!nCmpt) + { + nCmpt = addPatchField<vector> + ( + multiPiece, + patchIds, + parent().mesh().cfindObject<volVectorField>(fieldName_), + fieldName_ + ); + } + } + + // Now have a multi-piece dataset with + // one piece per patch and processor. + // + // For VTK=parallel, these pieces reside on their original processors. + // For VTK=serial, they are master only + + // Re-query actually field information, since we may have stored it + // somewhere slightly different than the original source. + + fieldSummary fieldInfo = queryFieldSummary(fieldName_, multiPiece); + fieldInfo.reduce(); + + + // Not rendering on this processor? + // This is where we stop, but could also have a MPI barrier + if (!renderer) + { + return; + } + + + // Rendering + + { + auto polyData = vtkSmartPointer<vtkCompositeDataGeometryFilter>::New(); + + polyData->SetInputData(multiPiece); + polyData->Update(); + + if (representation_ == rtGlyph) + { + addGlyphs + ( + position, + fieldName_, fieldInfo, // scaling + fieldName_, fieldInfo, // colouring + maxGlyphLength_, + polyData->GetOutput(), + surfaceActor_, + renderer + ); + } + else + { + vtkSmartPointer<vtkCellDataToPointData> cellToPoint; + + // CellData - Need a cell->point filter + if (smooth_ && !fieldInfo.hasPointData()) + { + cellToPoint = vtkSmartPointer<vtkCellDataToPointData>::New(); + cellToPoint->SetInputData(multiPiece); + + polyData->SetInputConnection(cellToPoint->GetOutputPort()); + } + else + { + polyData->SetInputData(multiPiece); + } + polyData->Update(); + + + if (!smooth_) + { + addFeatureEdges(renderer, polyData); + } + + auto mapper = vtkSmartPointer<vtkPolyDataMapper>::New(); + mapper->SetInputConnection(polyData->GetOutputPort()); + + setField + ( + position, + fieldName_, + ( + smooth_ + ? FieldAssociation::POINT_DATA + : FieldAssociation::CELL_DATA + ), + mapper, + renderer + ); + + surfaceActor_->SetMapper(mapper); + + setRepresentation(surfaceActor_); + + renderer->AddActor(surfaceActor_); + } + } +} + + +void Foam::functionObjects::runTimePostPro::geometryPatches::updateActors +( + const scalar position +) +{ + if (!visible_) + { + return; + } + + surface::updateActors(position); + + surfaceActor_->GetProperty()->SetOpacity(opacity(position)); + + vector sc = surfaceColour_->value(position); + surfaceActor_->GetProperty()->SetColor(sc[0], sc[1], sc[2]); + + vector ec = edgeColour_->value(position); + surfaceActor_->GetProperty()->SetEdgeColor(ec[0], ec[1], ec[2]); +} + + +bool Foam::functionObjects::runTimePostPro::geometryPatches::clear() +{ + return true; +} + + +// ************************************************************************* // diff --git a/src/functionObjects/graphics/runTimePostProcessing/geometryPatches.H b/src/functionObjects/graphics/runTimePostProcessing/geometryPatches.H new file mode 100644 index 0000000000000000000000000000000000000000..cb7a8de79c2c1f552d8a30e12bfcf35a0efc12ba --- /dev/null +++ b/src/functionObjects/graphics/runTimePostProcessing/geometryPatches.H @@ -0,0 +1,171 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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::geometryPatches + +Description + Visualisation of OpenFOAM patches and fields. + + \heading Basic Usage + \table + Property | Description | Required | Default + type | The surface type: patches | yes | + patches | Patches to display (wordRe list) | yes | + \endtable + +SourceFiles + geometryPatches.C + +\*---------------------------------------------------------------------------*/ + +#ifndef functionObjects_runTimePostPro_geometryPatches_H +#define functionObjects_runTimePostPro_geometryPatches_H + +#include "surface.H" +#include "geometrySurface.H" +#include "fieldVisualisationBase.H" +#include "volFieldsFwd.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +namespace Foam +{ +namespace functionObjects +{ +namespace runTimePostPro +{ + +/*---------------------------------------------------------------------------*\ + Class geometryPatches Declaration +\*---------------------------------------------------------------------------*/ + +class geometryPatches +: + public geometrySurface, + public fieldVisualisationBase +{ +protected: + + // Protected Data + + //- Requested names of patches to process + wordRes selectPatches_; + + //- Use cell value on patches instead of patch value itself + bool nearCellValue_; + + + // Protected Member Functions + + //- Gather and convert patches to multi-piece dataset with + //- vtkPolyData for each patch/processor. + // For serial, the pieces are gathered to the master. + vtkSmartPointer<vtkMultiPieceDataSet> + gatherPatchPieces(const labelListList& patchIds) const; + + //- Gather and convert patch face centres to multi-piece dataset with + //- vtkPolyData for each patch/processor. + // For serial, the pieces are gathered to the master. + vtkSmartPointer<vtkMultiPieceDataSet> + gatherPatchFaceCentres(const labelListList& patchIds) const; + + + // Adding Fields - multi-piece + + //- Add patch values. + // For nCells == nPoints (eg, only has face centres) add as PointData. + // \return 0 on failure to map and nCmpt (eg, 1=scalar, 3=vector) + // on success. + template<class Type> + int addPatchField + ( + vtkMultiPieceDataSet* multiPiece, + const labelListList& patchIds, + const GeometricField<Type, fvPatchField, volMesh>* fldptr, + const word& fieldName + ) const; + + + //- No copy construct + geometryPatches(const geometryPatches&) = delete; + + //- No copy assignment + void operator=(const geometryPatches&) = delete; + + +public: + + //- Run-time type information + TypeNameNoDebug("patches"); + + + // Constructors + + //- Construct from dictionary + geometryPatches + ( + const runTimePostProcessing& parent, + const dictionary& dict, + const HashPtrTable<Function1<vector>>& colours + ); + + + //- Destructor + virtual ~geometryPatches() = default; + + + // Member Functions + + //- Add geometry surface(s) to scene + virtual void addGeometryToScene + ( + const scalar position, + vtkRenderer* renderer + ); + + //- Update actors + virtual void updateActors(const scalar position); + + //- Clear files used to create the object(s) + virtual bool clear(); +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace runTimePostPro +} // End namespace functionObjects +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#ifdef NoRepository + #include "geometryPatchesTemplates.C" +#endif + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/functionObjects/graphics/runTimePostProcessing/geometryPatchesGather.C b/src/functionObjects/graphics/runTimePostProcessing/geometryPatchesGather.C new file mode 100644 index 0000000000000000000000000000000000000000..ce03fa02bbda36d5a40ff9eaf10323f5de08b0ad --- /dev/null +++ b/src/functionObjects/graphics/runTimePostProcessing/geometryPatchesGather.C @@ -0,0 +1,293 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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 "geometryPatches.H" +#include "fvMesh.H" +#include "volFields.H" +#include "emptyPolyPatch.H" +#include "processorPolyPatch.H" +#include "foamVtkTools.H" +#include "runTimePostProcessing.H" + +// VTK includes +#include "vtkCellArray.h" +#include "vtkCellData.h" +#include "vtkCompositeDataSet.h" +#include "vtkMultiPieceDataSet.h" +#include "vtkPointData.h" +#include "vtkPolyData.h" +#include "vtkSmartPointer.h" + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +vtkSmartPointer<vtkMultiPieceDataSet> +Foam::functionObjects::runTimePostPro::geometryPatches::gatherPatchPieces +( + const labelListList& patchIds +) const +{ + const polyBoundaryMesh& patches = parent().mesh().boundaryMesh(); + + label nPieces = 0; + for (const labelList& ids : patchIds) + { + nPieces += ids.size(); + } + + auto multiPiece = vtkSmartPointer<vtkMultiPieceDataSet>::New(); + multiPiece->SetNumberOfPieces(nPieces); + + label pieceId = 0; + + if (!needsCollective()) + { + // Simple case + + for (int proci=0; proci < Pstream::myProcNo(); ++proci) + { + pieceId += patchIds[proci].size(); + } + + for (const label patchId : patchIds[Pstream::myProcNo()]) + { + const polyPatch& pp = patches[patchId]; + + multiPiece->SetPiece + ( + pieceId, + Foam::vtk::Tools::Patch::mesh(pp) + ); + + ++pieceId; + } + } + else if (Pstream::master()) + { + // Gather pieces on master + + // Add myself + for (const label patchId : patchIds[Pstream::myProcNo()]) + { + const polyPatch& pp = patches[patchId]; + + multiPiece->SetPiece + ( + pieceId, + Foam::vtk::Tools::Patch::mesh(pp) + ); + + ++pieceId; + } + + // Receive surfaces + pointField points; + faceList faces; + + for + ( + int slave=Pstream::firstSlave(); + slave<=Pstream::lastSlave(); + ++slave + ) + { + const label nSlavePatches = patchIds[slave].size(); + + if (!nSlavePatches) + { + continue; + } + + IPstream fromSlave(Pstream::commsTypes::scheduled, slave); + + for (label recvi=0; recvi < nSlavePatches; ++recvi) + { + points.clear(); + faces.clear(); + + fromSlave + >> points >> faces; + + multiPiece->SetPiece + ( + pieceId, + Foam::vtk::Tools::Patch::mesh(points, faces) + ); + + ++pieceId; + } + } + } + else + { + // Slave - send surfaces + const labelList& slavePatchIds = patchIds[Pstream::myProcNo()]; + + if (slavePatchIds.size()) + { + OPstream toMaster + ( + Pstream::commsTypes::scheduled, + Pstream::masterNo() + ); + + for (const label patchId : patchIds[Pstream::myProcNo()]) + { + const polyPatch& pp = patches[patchId]; + + toMaster + << pp.localPoints() << pp.localFaces(); + } + } + } + + return multiPiece; +} + + +vtkSmartPointer<vtkMultiPieceDataSet> +Foam::functionObjects::runTimePostPro::geometryPatches::gatherPatchFaceCentres +( + const labelListList& patchIds +) const +{ + const polyBoundaryMesh& patches = parent().mesh().boundaryMesh(); + + label nPieces = 0; + for (const labelList& ids : patchIds) + { + nPieces += ids.size(); + } + + auto multiPiece = vtkSmartPointer<vtkMultiPieceDataSet>::New(); + multiPiece->SetNumberOfPieces(nPieces); + + label pieceId = 0; + + if (!needsCollective()) + { + // Simple case + + for (int proci=0; proci < Pstream::myProcNo(); ++proci) + { + pieceId += patchIds[proci].size(); + } + + for (const label patchId : patchIds[Pstream::myProcNo()]) + { + const polyPatch& pp = patches[patchId]; + + auto geom = vtkSmartPointer<vtkPolyData>::New(); + + geom->SetPoints(Foam::vtk::Tools::Patch::faceCentres(pp)); + geom->SetVerts(Foam::vtk::Tools::identityVertices(pp.size())); + + multiPiece->SetPiece(pieceId, geom); + + ++pieceId; + } + } + else if (Pstream::master()) + { + // Gather pieces (face centres) on master + + // Add myself + for (const label patchId : patchIds[Pstream::myProcNo()]) + { + const polyPatch& pp = patches[patchId]; + + auto geom = vtkSmartPointer<vtkPolyData>::New(); + + geom->SetPoints(Foam::vtk::Tools::Patch::faceCentres(pp)); + geom->SetVerts(Foam::vtk::Tools::identityVertices(pp.size())); + + multiPiece->SetPiece(pieceId, geom); + + ++pieceId; + } + + // Receive points + pointField points; + + for + ( + int slave=Pstream::firstSlave(); + slave<=Pstream::lastSlave(); + ++slave + ) + { + const label nSlavePatches = patchIds[slave].size(); + + if (!nSlavePatches) + { + continue; + } + + IPstream fromSlave(Pstream::commsTypes::scheduled, slave); + + for (label recvi=0; recvi < nSlavePatches; ++recvi) + { + points.clear(); + + fromSlave >> points; + + multiPiece->SetPiece + ( + pieceId, + Foam::vtk::Tools::Vertices(points) + ); + + ++pieceId; + } + } + } + else + { + // Slave - send face centres + + const labelList& slavePatchIds = patchIds[Pstream::myProcNo()]; + + if (slavePatchIds.size()) + { + OPstream toMaster + ( + Pstream::commsTypes::scheduled, + Pstream::masterNo() + ); + + for (const label patchId : patchIds[Pstream::myProcNo()]) + { + const polyPatch& pp = patches[patchId]; + + toMaster << pp.faceCentres(); + } + } + } + + return multiPiece; +} + + +// ************************************************************************* // diff --git a/src/functionObjects/graphics/runTimePostProcessing/geometryPatchesTemplates.C b/src/functionObjects/graphics/runTimePostProcessing/geometryPatchesTemplates.C new file mode 100644 index 0000000000000000000000000000000000000000..ec8edea73f085941bd68013c44634c2860b3a070 --- /dev/null +++ b/src/functionObjects/graphics/runTimePostProcessing/geometryPatchesTemplates.C @@ -0,0 +1,221 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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 "geometryPatches.H" +#include "fvMesh.H" +#include "volFields.H" +#include "foamVtkTools.H" + +// VTK includes +#include "vtkCellData.h" +#include "vtkMultiPieceDataSet.h" +#include "vtkPointData.h" + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +template<class Type> +int Foam::functionObjects::runTimePostPro::geometryPatches::addPatchField +( + vtkMultiPieceDataSet* multiPiece, + const labelListList& patchIds, + const GeometricField<Type, fvPatchField, volMesh>* fldptr, + const word& fieldName +) const +{ + if (!multiPiece || !fldptr) + { + return 0; + } + + const int nCmpt(pTraits<Type>::nComponents); + + const auto& bf = fldptr->boundaryField(); + + label pieceId = 0; + + if (!needsCollective()) + { + // Simple case (serial-serial, parallel-parallel) + + for (int proci=0; proci < Pstream::myProcNo(); ++proci) + { + pieceId += patchIds[proci].size(); + } + + for (const label patchId : patchIds[Pstream::myProcNo()]) + { + const auto& pf = bf[patchId]; + + auto vtkfield = + ( + nearCellValue_ + ? Foam::vtk::Tools::convertFieldToVTK<Type> + ( + fieldName, + pf.patchInternalField()() + ) + : Foam::vtk::Tools::convertFieldToVTK<Type> + ( + fieldName, + pf + ) + ); + + auto piece = multiPiece->GetPiece(pieceId); + + if (piece->GetNumberOfCells() == piece->GetNumberOfPoints()) + { + // Only has verts + piece->GetPointData()->AddArray(vtkfield); + } + else + { + piece->GetCellData()->AddArray(vtkfield); + } + + ++pieceId; + } + } + else if (Pstream::master()) + { + // Gather pieces on master + + // Add myself + for (const label patchId : patchIds[Pstream::myProcNo()]) + { + const auto& pf = bf[patchId]; + + auto vtkfield = + ( + nearCellValue_ + ? Foam::vtk::Tools::convertFieldToVTK<Type> + ( + fieldName, + pf.patchInternalField()() + ) + : Foam::vtk::Tools::convertFieldToVTK<Type> + ( + fieldName, + pf + ) + ); + + auto piece = multiPiece->GetPiece(pieceId); + + if (piece->GetNumberOfCells() == piece->GetNumberOfPoints()) + { + // Only has verts + piece->GetPointData()->AddArray(vtkfield); + } + else + { + piece->GetCellData()->AddArray(vtkfield); + } + + ++pieceId; + } + + // Receive field + Field<Type> recv; + + for + ( + int slave=Pstream::firstSlave(); + slave<=Pstream::lastSlave(); + ++slave + ) + { + const label nSlavePatches = patchIds[slave].size(); + + if (!nSlavePatches) + { + continue; + } + + IPstream fromSlave(Pstream::commsTypes::scheduled, slave); + + for (label recvi=0; recvi < nSlavePatches; ++recvi) + { + recv.clear(); + + fromSlave >> recv; + + auto vtkfield = Foam::vtk::Tools::convertFieldToVTK<Type> + ( + fieldName, + recv + ); + + auto piece = multiPiece->GetPiece(pieceId); + + if (piece->GetNumberOfCells() == piece->GetNumberOfPoints()) + { + // Only has verts + piece->GetPointData()->AddArray(vtkfield); + } + else + { + piece->GetCellData()->AddArray(vtkfield); + } + + ++pieceId; + } + } + } + else + { + // Slave - send fields + const labelList& slavePatchIds = patchIds[Pstream::myProcNo()]; + + if (slavePatchIds.size()) + { + OPstream toMaster + ( + Pstream::commsTypes::scheduled, + Pstream::masterNo() + ); + + for (const label patchId : patchIds[Pstream::myProcNo()]) + { + const auto& pf = bf[patchId]; + + if (nearCellValue_) + { + toMaster << pf.patchInternalField()(); + } + else + { + toMaster << pf; + } + } + } + } + + return nCmpt; +} + + +// ************************************************************************* // diff --git a/src/functionObjects/graphics/runTimePostProcessing/geometrySurface.C b/src/functionObjects/graphics/runTimePostProcessing/geometrySurface.C index f3af0ab14f6054530fd38cb88477f71a157cab0d..ee6fc254d0171207cd73c2c96c19b43bb5f2ae99 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/geometrySurface.C +++ b/src/functionObjects/graphics/runTimePostProcessing/geometrySurface.C @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2015-2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd. \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2015 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -77,7 +75,7 @@ static vtkSmartPointer<vtkPolyData> getPolyDataFile(const Foam::fileName& fName) // Not extremely elegant... vtkSmartPointer<vtkPolyData> dataset; - if (fName.ext() == "vtk") + if ("vtk" == fName.ext()) { auto reader = vtkSmartPointer<vtkPolyDataReader>::New(); @@ -88,7 +86,7 @@ static vtkSmartPointer<vtkPolyData> getPolyDataFile(const Foam::fileName& fName) return dataset; } - if (fName.ext() == "vtp") + if ("vtp" == fName.ext()) { auto reader = vtkSmartPointer<vtkXMLPolyDataReader>::New(); @@ -99,7 +97,7 @@ static vtkSmartPointer<vtkPolyData> getPolyDataFile(const Foam::fileName& fName) return dataset; } - if (fName.ext() == "obj") + if ("obj" == fName.ext()) { auto reader = vtkSmartPointer<vtkOBJReader>::New(); @@ -110,7 +108,7 @@ static vtkSmartPointer<vtkPolyData> getPolyDataFile(const Foam::fileName& fName) return dataset; } - if (fName.ext() == "stl" || fName.ext() == "stlb") + if ("stl" == fName.ext() || "stlb" == fName.ext()) { auto reader = vtkSmartPointer<vtkSTLReader>::New(); @@ -147,6 +145,12 @@ void Foam::functionObjects::runTimePostPro::geometrySurface::addGeometryToScene const fileName& fName ) const { + // Master-only, since that is where the files are. + if (!visible_ || !renderer || !Pstream::master()) + { + return; + } + if (representation_ == rtGlyph) { FatalErrorInFunction @@ -154,9 +158,11 @@ void Foam::functionObjects::runTimePostPro::geometrySurface::addGeometryToScene << " object" << exit(FatalError); } + DebugInfo << " Add geometry surface: " << fName << nl; + auto surf = getPolyDataFile(fName); - if (!surf || surf->GetNumberOfPoints() == 0) + if (!surf || !surf->GetNumberOfPoints()) { FatalErrorInFunction << "Could not read "<< fName << nl diff --git a/src/functionObjects/graphics/runTimePostProcessing/geometrySurface.H b/src/functionObjects/graphics/runTimePostProcessing/geometrySurface.H index 4e9e41e98195a4c0646c0111c527183fcb572185..65f5556790a4492da8428aab93defb81df7086ef 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/geometrySurface.H +++ b/src/functionObjects/graphics/runTimePostProcessing/geometrySurface.H @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2016 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd. \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2015 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -27,7 +25,18 @@ Class Foam::functionObjects::runTimePostPro::geometrySurface Description - Visualisation of surface geometry data + Read and visualize surface geometry files. + + Dictionary controls + \table + Property | Description | Required | Default + type | The type: geometry | yes | + files | The files to read | yes | + \endtable + + Standard file types (vtk, vtp, obj, stl, stlb) are read with the + VTK-native readers. Other file types use the OpenFOAM surfMesh + readers and convert to VTK. SourceFiles geometrySurface.C @@ -41,7 +50,7 @@ SourceFiles // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -// Forward declarations +// Forward Declarations class vtkPolyData; namespace Foam @@ -61,7 +70,7 @@ class geometrySurface { protected: - // Protected data + // Protected Data //- File names List<fileName> fileNames_; @@ -126,7 +135,7 @@ public: //- Update actors virtual void updateActors(const scalar position); - //- Clear files used to create the object(s) + //- Clear files used to create the object(s) - no-op virtual bool clear(); }; diff --git a/src/functionObjects/graphics/runTimePostProcessing/pathline.C b/src/functionObjects/graphics/runTimePostProcessing/pathline.C index 7ab781a99cfd74b2101e58c8672bdc6e10c9faa9..1642b4496b4e74bb38319825ccc0925e32345baa 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/pathline.C +++ b/src/functionObjects/graphics/runTimePostProcessing/pathline.C @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2015-2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd. \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2015 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -46,7 +44,7 @@ namespace functionObjects { namespace runTimePostPro { - defineTypeNameAndDebug(pathline, 0); + defineTypeName(pathline); defineRunTimeSelectionTable(pathline, dictionary); } } @@ -94,7 +92,6 @@ void Foam::functionObjects::runTimePostPro::pathline::addLines mapper->SetInputData(data); mapper->Update(); break; - } case rtTube: { @@ -107,9 +104,7 @@ void Foam::functionObjects::runTimePostPro::pathline::addLines mapper->SetInputConnection(tubes->GetOutputPort()); mapper->Update(); - break; - } case rtVector: { @@ -133,7 +128,7 @@ Foam::functionObjects::runTimePostPro::pathline::pathline ( representationTypeNames.get("representation", dict) ), - tubeRadius_(0.0), + tubeRadius_(0.001), lineColour_(nullptr) { if (dict.found("lineColour")) @@ -165,7 +160,6 @@ Foam::functionObjects::runTimePostPro::pathline::pathline break; } } - } @@ -180,10 +174,7 @@ Foam::functionObjects::runTimePostPro::pathline::New const word& pathlineType ) { - if (debug) - { - Info<< "Selecting pathline " << pathlineType << endl; - } + DebugInfo << "Selecting pathline " << pathlineType << endl; auto cstrIter = dictionaryConstructorTablePtr_->cfind(pathlineType); diff --git a/src/functionObjects/graphics/runTimePostProcessing/pathline.H b/src/functionObjects/graphics/runTimePostProcessing/pathline.H index a665eecf5ff5ff1b01e22c455257d3c48eae3bc8..44aca2e95c18483bc64dc610548001809df5a5c3 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/pathline.H +++ b/src/functionObjects/graphics/runTimePostProcessing/pathline.H @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2016-2018 OpenCFD Ltd + \\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2015 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -29,6 +27,14 @@ Class Description Visualisation of line data (eg, streamlines) + Dictionary controls + \table + Property | Description | Required | Default + representation| none/line/tube/vector | yes | + lineColour | Override line colour | no | + tubeRadius | Radius for tube representation | yes | + \endtable + SourceFiles pathline.C @@ -65,16 +71,18 @@ class pathline { public: - // Public enumerations + // Public Enumerations + //- Line representations enum representationType { - rtNone, - rtLine, - rtTube, - rtVector + rtNone, //!< "none" + rtLine, //!< "line" + rtTube, //!< "tube" + rtVector //!< "vector" }; + //- Names for line representations static const Enum<representationType> representationTypeNames; @@ -112,7 +120,7 @@ protected: public: //- Run-time type information - TypeName("pathline"); + TypeNameNoDebug("pathline"); // Declare run-time constructor selection table @@ -144,7 +152,7 @@ public: // Selectors - //- Return a reference to the selected RAS model + //- Return selected pathline static autoPtr<pathline> New ( const runTimePostProcessing& parent, diff --git a/src/functionObjects/graphics/runTimePostProcessing/pointData.C b/src/functionObjects/graphics/runTimePostProcessing/pointData.C index 0688c4252d23409cbcabb72a0ad970301f520856..577c6d6c5ce6fd1be0461dce8734f2789b9f9a84 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/pointData.C +++ b/src/functionObjects/graphics/runTimePostProcessing/pointData.C @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2004-2010, 2015-2018 OpenCFD Ltd. - \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2015 OpenFOAM Foundation + \\ / A nd | Copyright (C) 2004-2010, 2015-2019 OpenCFD Ltd. + \\/ M anipulation | ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -35,8 +33,6 @@ License #include "vtkProperty.h" #include "vtkRenderer.h" #include "vtkSmartPointer.h" -#include "vtkTubeFilter.h" -#include "vtkLookupTable.h" // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // @@ -46,7 +42,7 @@ namespace functionObjects { namespace runTimePostPro { - defineTypeNameAndDebug(pointData, 0); + defineTypeName(pointData); defineRunTimeSelectionTable(pointData, dictionary); } } @@ -141,10 +137,7 @@ Foam::functionObjects::runTimePostPro::pointData::New const word& pointDataType ) { - if (debug) - { - Info<< "Selecting pointData " << pointDataType << endl; - } + DebugInfo << "Selecting pointData " << pointDataType << endl; auto cstrIter = dictionaryConstructorTablePtr_->cfind(pointDataType); diff --git a/src/functionObjects/graphics/runTimePostProcessing/pointData.H b/src/functionObjects/graphics/runTimePostProcessing/pointData.H index 738f42897d46d5bc34087f2b0acf0c361166c9e5..f08ac5727d9492d601c08324a280172ce86c3cc4 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/pointData.H +++ b/src/functionObjects/graphics/runTimePostProcessing/pointData.H @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2004-2010, 2015-2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2004-2010, 2015-2019 OpenCFD Ltd. \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2015 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -29,6 +27,14 @@ Class Description Visualisation of point data + Dictionary controls + \table + Property | Description | Required | Default + representation| sphere/vector | yes | + pointColour | Override point colour | no | + maxGlyphLength | Limit for glyph representation | yes | + \endtable + SourceFiles pointData.C @@ -43,7 +49,7 @@ SourceFiles // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -// Forward declarations +// Forward Declarations class vtkActor; class vtkPolyData; class vtkPolyDataMapper; @@ -65,20 +71,22 @@ class pointData { public: - // Public enumerations + // Public Enumerations + //- Point representation types enum representationType { - rtSphere, //!< Sphere - rtVector //!< Vector + rtSphere, //!< "sphere" + rtVector //!< "vector" }; + //- Names for point representation types static const Enum<representationType> representationTypeNames; protected: - // Protected data + // Protected Data //- Representation type representationType representation_; @@ -111,7 +119,7 @@ protected: public: //- Run-time type information - TypeName("pointData"); + TypeNameNoDebug("pointData"); // Declare run-time constructor selection table @@ -143,7 +151,7 @@ public: // Selectors - //- Return a reference to the selected RAS model + //- Return selected pointData static autoPtr<pointData> New ( const runTimePostProcessing& parent, diff --git a/src/functionObjects/graphics/runTimePostProcessing/runTimePostProcessing.C b/src/functionObjects/graphics/runTimePostProcessing/runTimePostProcessing.C index d1bc3196b1891ed4e545fa2c8b0a73ec515487ef..f514b39b714ab220388aad3cb8fef649ec9fa2df 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/runTimePostProcessing.C +++ b/src/functionObjects/graphics/runTimePostProcessing/runTimePostProcessing.C @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2015-2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd. \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2015 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -34,6 +32,7 @@ License #include "text.H" #include "Time.H" #include "sigFpe.H" +#include "polySurfaceFields.H" #include "addToRunTimeSelectionTable.H" // VTK includes @@ -43,6 +42,16 @@ License #include "vtkSmartPointer.h" #include "vtkLight.h" +#ifdef FOAM_USING_VTK_MPI +# include "vtkMPICommunicator.h" +# include "vtkMPIController.h" +#endif +#include "vtkDummyController.h" + +#include "vtkSynchronizedRenderWindows.h" +#include "vtkCompositedSynchronizedRenderers.h" + + // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // namespace Foam @@ -103,6 +112,168 @@ static void cleanup(PtrList<Type>& objects) } // End namespace Foam +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +void Foam::functionObjects::runTimePostProcessing::render +( + vtkMultiProcessController* controller +) +{ + // Some feedback + if (controller) + { + Log << name() << " render (" << controller->GetNumberOfProcesses() + << " processes)" << endl; + } + else + { + Log << name() << " render" << endl; + } + + + // Normal rendering elements + vtkSmartPointer<vtkRenderer> renderer; + vtkSmartPointer<vtkRenderWindow> renderWindow; + + // Multi-process synchronization + vtkSmartPointer<vtkSynchronizedRenderWindows> syncWindows; + vtkSmartPointer<vtkCompositedSynchronizedRenderers> syncRenderers; + + + // Disable any floating point trapping + // (some low-level rendering functionality does not like it) + + sigFpe::ignore sigFpeHandling; //<- disable in local scope + + + // Initialise render window + if (controller || Pstream::master()) + { + renderWindow = vtkSmartPointer<vtkRenderWindow>::New(); + renderer = vtkSmartPointer<vtkRenderer>::New(); + + renderWindow->OffScreenRenderingOn(); + renderWindow->SetSize(output_.width_, output_.height_); + + // Legacy rendering - was deprecated for 8.1.0 + #if (VTK_MAJOR_VERSION < 8) || \ + ((VTK_MAJOR_VERSION == 8) && (VTK_MINOR_VERSION < 2)) + renderWindow->SetAAFrames(10); + #endif + renderWindow->SetAlphaBitPlanes(true); + renderWindow->SetMultiSamples(0); + // renderWindow->PolygonSmoothingOn(); + + renderWindow->AddRenderer(renderer); + } + + // Synchronization + if (controller) + { + syncWindows = + vtkSmartPointer<vtkSynchronizedRenderWindows>::New(); + + syncRenderers = + vtkSmartPointer<vtkCompositedSynchronizedRenderers>::New(); + + syncWindows->SetRenderWindow(renderWindow); + syncWindows->SetParallelController(controller); + syncWindows->SetIdentifier(1); + + // false = Call Render() manually on each process - don't use RMI + syncWindows->SetParallelRendering(true); + + syncRenderers->SetRenderer(renderer); + syncRenderers->SetParallelController(controller); + } + + // --------------------- + + scene_.initialise(renderer, output_.name_); + + addGeometryToScene(points_, 0, renderer); + addGeometryToScene(lines_, 0, renderer); + addGeometryToScene(surfaces_, 0, renderer); + addGeometryToScene(text_, 0, renderer); + + while (scene_.loop(renderer)) + { + const scalar position = scene_.position(); + + updateActors(text_, position); + updateActors(points_, position); + updateActors(lines_, position); + updateActors(surfaces_, position); + } + + // Cleanup + cleanup(text_); + cleanup(points_); + cleanup(lines_); + cleanup(surfaces_); + + + // Instead of relying on the destructor, manually restore the previous + // SIGFPE state. + // This is only to avoid compiler complaints about unused variables. + + sigFpeHandling.restore(); +} + + +void Foam::functionObjects::runTimePostProcessing::render +( + vtkMultiProcessController* controller, + void* processData +) +{ + reinterpret_cast<runTimePostProcessing*>(processData)->render(controller); +} + + +void Foam::functionObjects::runTimePostProcessing::render() +{ + #ifdef FOAM_USING_VTK_MPI + if (parallel_) + { + // Create vtkMPIController if MPI is configured, + // vtkThreadedController otherwise. + auto ctrl = vtkSmartPointer<vtkMPIController>::New(); + ctrl->Initialize(nullptr, nullptr, 1); + + ctrl->SetSingleMethod(runTimePostProcessing::render, this); + ctrl->SingleMethodExecute(); + + ctrl->Finalize(1); + } + else + #endif + { + // Normally we would have a fallback controller like this: + + // if (Pstream::master()) + // { + // auto ctrl = vtkSmartPointer<vtkDummyController>::New(); + // ctrl->Initialize(nullptr, nullptr, 1); + // + // ctrl->SetSingleMethod(runTimePostProcessing::render, this); + // ctrl->SingleMethodExecute(); + // + // ctrl->Finalize(1); + // } + + // However, this would prevent us from doing any of our own MPI + // since this would only be spawned the master. + + // Instead pass in nullptr for the controller and handling + // logic internally. + + vtkDummyController* dummy = nullptr; + render(dummy); + } +} + + // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::functionObjects::runTimePostProcessing::runTimePostProcessing @@ -113,6 +284,8 @@ Foam::functionObjects::runTimePostProcessing::runTimePostProcessing ) : fvMeshFunctionObject(name, runTime, dict), + output_(), + parallel_(false), scene_(runTime, name), points_(), lines_(), @@ -129,7 +302,20 @@ bool Foam::functionObjects::runTimePostProcessing::read(const dictionary& dict) { fvMeshFunctionObject::read(dict); - Info<< type() << " " << name() << ": reading post-processing data" << endl; + #ifdef FOAM_USING_VTK_MPI + parallel_ = (Pstream::parRun() && dict.lookupOrDefault("parallel", true)); + #else + parallel_ = false; + #endif + + Info<< type() << " " << name() << ": reading post-processing data (" + << (parallel_ ? "parallel" : "serial") << " rendering)" << endl; + + if (dict.lookupOrDefault("debug", false)) + { + runTimePostPro::geometryBase::debug = 1; + Info<< " debugging on" << endl; + } scene_.read(dict); @@ -179,68 +365,7 @@ bool Foam::functionObjects::runTimePostProcessing::execute() bool Foam::functionObjects::runTimePostProcessing::write() { - if (!Pstream::master()) - { - return true; - } - - Info<< type() << " " << name() << " output:" << nl - << " Constructing scene" << endl; - - - // Disable any floating point trapping - // (some low-level rendering functionality does not like it) - - sigFpe::ignore sigFpeHandling; //<- disable in local scope - - // Initialise render window - auto renderWindow = vtkSmartPointer<vtkRenderWindow>::New(); - renderWindow->OffScreenRenderingOn(); - renderWindow->SetSize(output_.width_, output_.height_); - - // Legacy rendering - was deprecated for 8.1.0 - #if (VTK_MAJOR_VERSION < 8) || \ - ((VTK_MAJOR_VERSION == 8) && (VTK_MINOR_VERSION < 2)) - renderWindow->SetAAFrames(10); - #endif - renderWindow->SetAlphaBitPlanes(true); - renderWindow->SetMultiSamples(0); -// renderWindow->PolygonSmoothingOn(); - - auto renderer = vtkSmartPointer<vtkRenderer>::New(); - scene_.initialise(renderer, output_.name_); - - renderWindow->AddRenderer(renderer); - - - addGeometryToScene(points_, 0, renderer); - addGeometryToScene(lines_, 0, renderer); - addGeometryToScene(surfaces_, 0, renderer); - addGeometryToScene(text_, 0, renderer); - - while (scene_.loop(renderer)) - { - const scalar position = scene_.position(); - - updateActors(text_, position); - updateActors(points_, position); - updateActors(lines_, position); - updateActors(surfaces_, position); - } - - // Cleanup - cleanup(text_); - cleanup(points_); - cleanup(lines_); - cleanup(surfaces_); - - - // Instead of relying on the destructor, manually restore the previous - // SIGFPE state. - // This is only to avoid compiler complaints about unused variables. - - sigFpeHandling.restore(); - + render(); return true; } diff --git a/src/functionObjects/graphics/runTimePostProcessing/runTimePostProcessing.H b/src/functionObjects/graphics/runTimePostProcessing/runTimePostProcessing.H index ef2d17708bf4f634f7ed627af7638a09029f906f..21ae24b147b7c70e7bf29a87d4b65184baf50a43 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/runTimePostProcessing.H +++ b/src/functionObjects/graphics/runTimePostProcessing/runTimePostProcessing.H @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2015-2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd. \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2015 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -56,9 +54,53 @@ Description - Selection of colour maps . - Scene configuration is performed using standard OpenFOAM dictionaries, using - the main headings of: output=, camera, colours, points, lines, - surfaces and text. + Mandatory entries: + \verbatim + output + { + name image; + width 800; + height 600; + } + + camera + { + ... + } + + colours + { + ... + } + + text + { + } + \endverbatim + + Optional entries: + \verbatim + points + { + } + + lines + { + ... + } + + surfaces + { + ... + } + \endverbatim + + Dictionary controls + \table + Property | Description | Required | Default + type | Type-name: runTimePostProcessing | yes | + debug | Additional debug information | no | false + \endtable SourceFiles runTimePostProcessing.C @@ -76,14 +118,20 @@ SourceFiles // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -// Forward declarations -class vtkRenderer; +// Forward Declarations +class vtkMultiPieceDataSet; +class vtkMultiProcessController; class vtkRenderWindow; +class vtkRenderer; +template<class T> class vtkSmartPointer; namespace Foam { namespace functionObjects { +// Forward declarations +class runTimePostProcessing; + namespace runTimePostPro { // Forward declarations @@ -101,11 +149,9 @@ class runTimePostProcessing : public fvMeshFunctionObject { -private: - - // Private data + // Private Data - // Output + //- Output information struct outputType { word name_; @@ -116,6 +162,9 @@ private: //- Output instance outputType output_; + //- Parallel rendering + bool parallel_; + //- Scene manager runTimePostPro::scene scene_; @@ -138,6 +187,15 @@ private: template<class Type> void readObjects(const dictionary& dict, PtrList<Type>& objects) const; + //- Construct controller and dispatch to render + void render(); + + //- Static function for SetSingleMethod binding + static void render(vtkMultiProcessController* ctrl, void* data); + + //- Render scene using given controller + void render(vtkMultiProcessController* ctrl); + public: @@ -162,11 +220,26 @@ public: // Member Functions + //- Parallel rendering + bool parallel() const + { + return parallel_; + } + + //- May need to gather parts to render on single-processor + // True when OpenFOAM is running in parallel but VTK is not. + bool needsCollective() const + { + return Pstream::parRun() && !parallel_; + } + + //- Reference to the underlying OpenFOAM mesh const fvMesh& mesh() const { return mesh_; } + //- Read the post-processing controls virtual bool read(const dictionary& dict); diff --git a/src/functionObjects/graphics/runTimePostProcessing/runTimePostProcessingTemplates.C b/src/functionObjects/graphics/runTimePostProcessing/runTimePostProcessingTemplates.C index 43574edf5e2d1a91b059c81f87a992f299f4ac69..e408f01a891ac9c78431cd8d0401860644d37db2 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/runTimePostProcessingTemplates.C +++ b/src/functionObjects/graphics/runTimePostProcessing/runTimePostProcessingTemplates.C @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2015-2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd. \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2015 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. diff --git a/src/functionObjects/graphics/runTimePostProcessing/scalarBar.C b/src/functionObjects/graphics/runTimePostProcessing/scalarBar.C new file mode 100644 index 0000000000000000000000000000000000000000..cfd24195301f42a56743ec57dbba79494235d5e8 --- /dev/null +++ b/src/functionObjects/graphics/runTimePostProcessing/scalarBar.C @@ -0,0 +1,250 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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 "scalarBar.H" + +// #include "doubleVector.H" +// #include "foamVtkTools.H" + +// VTK includes +#include "vtkCoordinate.h" +#include "vtkLookupTable.h" +#include "vtkRenderer.h" +#include "vtkScalarBarActor.h" +#include "vtkSmartPointer.h" +#include "vtkTextActor.h" +#include "vtkTextProperty.h" + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::functionObjects::runTimePostPro::scalarBar::scalarBar() +{ + clear(); +} + + +void Foam::functionObjects::runTimePostPro::scalarBar::clear() +{ + visible_ = true; + vertical_ = true; + bold_ = true; + shadow_ = false; + italic_ = false; + titleHack_ = true; + position_ = {0.8, 0.1}; + size_ = {0.1, 0.5}; + title_ = ""; + fontSize_ = 12; + titleSize_ = 0; // 0 == Auto-sizing (factor 3) + nLabels_ = 5; + labelFormat_ = "%f"; +} + + +void Foam::functionObjects::runTimePostPro::scalarBar::hide() +{ + visible_ = false; +} + + +void Foam::functionObjects::runTimePostPro::scalarBar::read +( + const dictionary& dict +) +{ + clear(); + + dict.readIfPresent("visible", visible_); + + if (visible_) + { + dict.readIfPresent("vertical", vertical_); + dict.readIfPresent("bold", bold_); + dict.readIfPresent("italic", italic_); + dict.readIfPresent("shadow", shadow_); + dict.readIfPresent("titleHack", titleHack_); + + if (vertical_) + { + size_ = { 0.1, 0.75 }; + } + else + { + size_ = { 0.75, 0.1 }; + } + + dict.readEntry("position", position_); + dict.readIfPresent("size", size_); + dict.readEntry("title", title_); + dict.readIfPresent("fontSize", fontSize_); + dict.readIfPresent("titleSize", titleSize_); + dict.readIfPresent("labelFormat", labelFormat_); + dict.readIfPresent("numberOfLabels", nLabels_); + } +} + + +bool Foam::functionObjects::runTimePostPro::scalarBar::add +( + const vector& textColour, + vtkRenderer* renderer, + vtkLookupTable* lut +) const +{ + // Add scalar bar legend + + if (!visible_ || !renderer) + { + return false; + } + + auto sbar = vtkSmartPointer<vtkScalarBarActor>::New(); + sbar->SetLookupTable(lut); + sbar->SetNumberOfLabels(nLabels_); + sbar->SetLabelFormat(labelFormat_.c_str()); + + /// const vector textColour = colours_["text"]->value(position); + + // Work-around to supply our own scalarbar title + // - Default scalar bar title text is scales by the scalar bar box + // dimensions so if the title is a long string, the text is shrunk to fit + // Instead, suppress title and set the title using a vtkTextActor + + vtkSmartPointer<vtkTextActor> titleActor; + vtkTextProperty* titleProp; + + if (titleHack_) + { + // Place the scalar bar title ourselves + titleActor = vtkSmartPointer<vtkTextActor>::New(); + titleActor->SetInput(title_.c_str()); + + titleProp = titleActor->GetTextProperty(); + titleProp->SetJustificationToCentered(); + } + else + { + // Use the standard scalar bar title + sbar->SetTitle(title_.c_str()); + titleProp = sbar->GetTitleTextProperty(); + } + + titleProp->SetFontFamilyToArial(); + + // Title size was supplied by user (absolute size) + // or use preset factor (3) of label font size + + if (titleSize_) + { + titleProp->SetFontSize(titleSize_); + } + else + { + // Auto = Factor 3 of fontSize + titleProp->SetFontSize(3*fontSize_); + + // Or this?? + // if (!titleHack_) titleProp->SetFontSize(fontSize_); + } + + titleProp->SetJustificationToCentered(); + titleProp->SetVerticalJustificationToBottom(); + titleProp->SetBold(bold_); + titleProp->SetItalic(italic_); + titleProp->SetShadow(shadow_); + + titleProp->SetColor(textColour[0], textColour[1], textColour[2]); + + + auto labProp = sbar->GetLabelTextProperty(); + + labProp->SetColor(textColour[0], textColour[1], textColour[2]); + + labProp->SetFontSize(fontSize_); + labProp->ShadowOff(); + labProp->BoldOff(); + labProp->ItalicOff(); + + // Positioning + { + vtkCoordinate* coord = sbar->GetPositionCoordinate(); + + coord->SetCoordinateSystemToNormalizedViewport(); + coord->SetValue(position_.first(), position_.second()); + } + + if (vertical_) + { + sbar->SetOrientationToVertical(); + sbar->SetTextPositionToSucceedScalarBar(); + sbar->SetWidth(size_.first()); + sbar->SetHeight(size_.second()); + // Standard is sbar->SetBarRatio(0.375); + } + else + { + sbar->SetOrientationToHorizontal(); + sbar->SetTextPositionToPrecedeScalarBar(); + + // Adjustments since not using scalarbar title property + sbar->SetWidth(size_.first()); + sbar->SetHeight(size_.second()); + // sbar->SetBarRatio(0.5); + // Standard is sbar->SetBarRatio(0.375); + // sbar->SetTitleRatio(0.01); + } + + if (titleActor) + { + vtkCoordinate* coord = titleActor->GetPositionCoordinate(); + + coord->SetCoordinateSystemToNormalizedViewport(); + + coord->SetValue + ( + position_.first() + (0.5 * sbar->GetWidth()), + position_.second() + (1.01 * sbar->GetHeight()) + ); + } + + // sbar->DrawFrameOn(); + // sbar->DrawBackgroundOn(); + // sbar->UseOpacityOff(); + // sbar->VisibilityOff(); + sbar->VisibilityOn(); + + renderer->AddActor(sbar); + + if (titleActor) + { + renderer->AddActor2D(titleActor); + } + + return true; +} + + +// ************************************************************************* // diff --git a/src/functionObjects/graphics/runTimePostProcessing/scalarBar.H b/src/functionObjects/graphics/runTimePostProcessing/scalarBar.H new file mode 100644 index 0000000000000000000000000000000000000000..ce3280e274592dcd2e9f9468d8d445bb4414e66f --- /dev/null +++ b/src/functionObjects/graphics/runTimePostProcessing/scalarBar.H @@ -0,0 +1,138 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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::scalarBar + +Description + Handling of scalar bar setup. + + Dictionary controls - scalar-bar entries (when \c visible is true) + \table + Property | Description | Required | Default + visible | Display scalar bar | no | true + title | The title for the scalar bar | yes | + position | Viewport position (x y) of scalar bar | yes | + vertical | Vertical scalar bar | no | true + size | Viewport size (x y) of scalar bar | no | auto + fontSize | Label size | no | 12 + titleSize | Title font size | no | 0 == auto + labelFormat | Label format string (eg, "%f") | no | "%f" + numberOfLabels | Total number of labels | no | 5 + bold | Title in bold | no | yes + italic | Title in italic font | no | no + shadow | Title with shadowont | no | no + titleHack | Alternative placement strategy | no | yes + \endtable + +SourceFiles + scalarBar.C + +\*---------------------------------------------------------------------------*/ + +#ifndef functionObjects_runTimePostPro_scalarBar_H +#define functionObjects_runTimePostPro_scalarBar_H + +#include "dictionary.H" +#include "Tuple2.H" +#include "vector.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +// Forward Declarations +class vtkLookupTable; +class vtkRenderer; + + +namespace Foam +{ +namespace functionObjects +{ +namespace runTimePostPro +{ + +/*---------------------------------------------------------------------------*\ + Class scalarBar Declaration +\*---------------------------------------------------------------------------*/ + +class scalarBar +{ + bool visible_; + bool vertical_; + bool bold_; + bool italic_; + bool shadow_; + bool titleHack_; + + Tuple2<scalar, scalar> position_; + + Tuple2<scalar, scalar> size_; + + string title_; + + label fontSize_; + + label titleSize_; + + label nLabels_; + + string labelFormat_; + + +public: + + //- Construct with sensible defaults + scalarBar(); + + //- Reset to sensible defaults + void clear(); + + //- Make non-visible + void hide(); + + //- Read dictionary settings + void read(const dictionary& dict); + + //- Add colour bar, when visible. + bool add + ( + const vector& textColour, + vtkRenderer* renderer, + vtkLookupTable* lut + ) const; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace runTimePostPro +} // End namespace functionObjects +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#endif + +// ************************************************************************* // diff --git a/src/functionObjects/graphics/runTimePostProcessing/scene.C b/src/functionObjects/graphics/runTimePostProcessing/scene.C index 2a1e7c337a95322b4de7c38deb43e54ea85a4815..edbb43c20681be3cbeb8c321e8cdbc0de8ba2624 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/scene.C +++ b/src/functionObjects/graphics/runTimePostProcessing/scene.C @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2015-2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd. \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2015 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -137,6 +135,8 @@ void Foam::functionObjects::runTimePostPro::scene::setActorVisibility const bool visible ) const { + if (!renderer) return; + vtkActorCollection *actors = renderer->GetActors(); for (int i = 0; i < actors->GetNumberOfItems(); ++i) { @@ -157,27 +157,30 @@ void Foam::functionObjects::runTimePostPro::scene::initialise outputName_ = outputName; + if (!renderer) return; + + // Set the background - const vector backgroundColour = colours_["background"]->value(position_); - renderer->SetBackground - ( - backgroundColour.x(), - backgroundColour.y(), - backgroundColour.z() - ); + const vector bgColour = colours_["background"]->value(position_); + + renderer->SetBackground(bgColour.x(), bgColour.y(), bgColour.z()); // Apply gradient background if "background2" defined if (colours_.found("background2")) { + const vector bg2Colour = colours_["background2"]->value(position_); + renderer->GradientBackgroundOn(); - vector backgroundColour2 = colours_["background2"]->value(position_); + renderer->SetBackground2(bg2Colour.x(), bg2Colour.y(), bg2Colour.z()); + } + else if (Pstream::parRun()) + { + // Oddly enough we seem a gradient background for parallel rendering, + // otherwise the colours look quite funny. + // Doesn't seem to matter if we use SetBackground2() though - renderer->SetBackground2 - ( - backgroundColour2.x(), - backgroundColour2.y(), - backgroundColour2.z() - ); + renderer->GradientBackgroundOn(); + renderer->SetBackground2(bgColour.x(), bgColour.y(), bgColour.z()); } // Depth peeling @@ -224,6 +227,8 @@ void Foam::functionObjects::runTimePostPro::scene::setCamera vtkRenderer* renderer ) const { + if (!renderer) return; + vtkCamera* camera = renderer->GetActiveCamera(); if (parallelProjection_) @@ -355,14 +360,18 @@ bool Foam::functionObjects::runTimePostPro::scene::loop(vtkRenderer* renderer) return true; } - // Ensure that all objects can be seen without clipping - // Note: can only be done after all objects have been added! - renderer->ResetCameraClippingRange(); + if (renderer) + { + + // Ensure that all objects can be seen without clipping + // Note: can only be done after all objects have been added! + renderer->ResetCameraClippingRange(); - // Save image from last iteration - saveImage(renderer->GetRenderWindow()); + // Save image from last iteration + saveImage(renderer->GetRenderWindow()); + } - currentFrameI_++; + ++currentFrameI_; position_ = startPosition_ + currentFrameI_*dPosition_; @@ -390,16 +399,15 @@ void Foam::functionObjects::runTimePostPro::scene::saveImage const Time& runTime = obr_.time(); - const fileName prefix + const fileName fName ( runTime.globalPath() / functionObject::outputPrefix / name_ / runTime.timeName() + / outputName_ + '.' + frameIndexStr() + ".png" ); - mkDir(prefix); - renderWindow->Render(); // Set up off-screen rendering @@ -415,15 +423,21 @@ void Foam::functionObjects::runTimePostPro::scene::saveImage windowToImageFilter->Update(); // Save the image - auto writer = vtkSmartPointer<vtkPNGWriter>::New(); - fileName fName(prefix/outputName_ + '.' + frameIndexStr() + ".png"); - writer->SetFileName(fName.c_str()); - writer->SetInputConnection(windowToImageFilter->GetOutputPort()); - Info<< " Generating image: " << fName << endl; + if (Pstream::master()) + { + mkDir(fName.path()); + + auto writer = vtkSmartPointer<vtkPNGWriter>::New(); + writer->SetFileName(fName.c_str()); + writer->SetInputConnection(windowToImageFilter->GetOutputPort()); + + Info<< " Generating image: " << runTime.relativePath(fName) << endl; - writer->Write(); + writer->Write(); + } } + // ************************************************************************* // diff --git a/src/functionObjects/graphics/runTimePostProcessing/scene.H b/src/functionObjects/graphics/runTimePostProcessing/scene.H index bcf440e6dbbcea954612ae1776739525cd852618..57c4f2b056e2f2fc8061869e2bfa6be3e9c13f35 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/scene.H +++ b/src/functionObjects/graphics/runTimePostProcessing/scene.H @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2016-2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd. \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2015 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -48,6 +46,10 @@ Usage viewAngle 20; zoom 1.1; } + + colours + { + } \endverbatim SourceFiles diff --git a/src/functionObjects/graphics/runTimePostProcessing/surface.C b/src/functionObjects/graphics/runTimePostProcessing/surface.C index 06c263f8a35bcd79137ff6d7af57f0802a6bbc9d..62f11d0e605828264677db842a86193e35d14561 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/surface.C +++ b/src/functionObjects/graphics/runTimePostProcessing/surface.C @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2015-2016 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd. \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2015 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -29,9 +27,15 @@ License #include "surface.H" #include "runTimePostProcessing.H" +#include "foamVtkTools.H" +#include "polySurfaceFields.H" +#include "polySurfacePointFields.H" + // VTK includes #include "vtkActor.h" +#include "vtkCompositeDataGeometryFilter.h" #include "vtkFeatureEdges.h" +#include "vtkMultiPieceDataSet.h" #include "vtkPolyData.h" #include "vtkPolyDataMapper.h" #include "vtkProperty.h" @@ -46,7 +50,7 @@ namespace functionObjects { namespace runTimePostPro { - defineTypeNameAndDebug(surface, 0); + defineTypeName(surface); defineRunTimeSelectionTable(surface, dictionary); } } @@ -60,13 +64,30 @@ const Foam::Enum Foam::functionObjects::runTimePostPro::surface::representationTypeNames ({ { representationType::rtNone, "none" }, + { representationType::rtGlyph, "glyph" }, { representationType::rtWireframe, "wireframe" }, { representationType::rtSurface, "surface" }, { representationType::rtSurfaceWithEdges, "surfaceWithEdges" }, - { representationType::rtGlyph, "glyph" }, }); +// * * * * * * * * * * * * * * * Specializations * * * * * * * * * * * * * * // + +// These need to shift elsewhere + +vtkCellData* Foam::vtk::Tools::GetCellData(vtkDataSet* dataset) +{ + if (dataset) return dataset->GetCellData(); + return nullptr; +} + +vtkPointData* Foam::vtk::Tools::GetPointData(vtkDataSet* dataset) +{ + if (dataset) return dataset->GetPointData(); + return nullptr; +} + + // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // void Foam::functionObjects::runTimePostPro::surface::setRepresentation @@ -85,7 +106,7 @@ void Foam::functionObjects::runTimePostPro::surface::setRepresentation } case rtWireframe: { - // note: colour is set using general SetColor, not SetEdgeColor + // Note: colour is set using general SetColor, not SetEdgeColor actor->GetProperty()->SetRepresentationToWireframe(); break; } @@ -108,21 +129,19 @@ void Foam::functionObjects::runTimePostPro::surface::setRepresentation void Foam::functionObjects::runTimePostPro::surface::addFeatureEdges ( vtkRenderer* renderer, - vtkPolyData* data + vtkFeatureEdges* featureEdges ) const { - if (!featureEdges_) + if (!featureEdges) { return; } - auto featureEdges = vtkSmartPointer<vtkFeatureEdges>::New(); - featureEdges->SetInputData(data); featureEdges->BoundaryEdgesOn(); featureEdges->FeatureEdgesOn(); featureEdges->ManifoldEdgesOff(); featureEdges->NonManifoldEdgesOff(); -// featureEdges->SetFeatureAngle(60); + /// featureEdges->SetFeatureAngle(60); featureEdges->ColoringOff(); featureEdges->Update(); @@ -139,6 +158,38 @@ void Foam::functionObjects::runTimePostPro::surface::addFeatureEdges } +void Foam::functionObjects::runTimePostPro::surface::addFeatureEdges +( + vtkRenderer* renderer, + vtkPolyData* data +) const +{ + if (featureEdges_) + { + auto featureEdges = vtkSmartPointer<vtkFeatureEdges>::New(); + featureEdges->SetInputData(data); + + addFeatureEdges(renderer, featureEdges); + } +} + + +void Foam::functionObjects::runTimePostPro::surface::addFeatureEdges +( + vtkRenderer* renderer, + vtkCompositeDataGeometryFilter* input +) const +{ + if (featureEdges_) + { + auto featureEdges = vtkSmartPointer<vtkFeatureEdges>::New(); + featureEdges->SetInputConnection(input->GetOutputPort()); + + addFeatureEdges(renderer, featureEdges); + } +} + + // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::functionObjects::runTimePostPro::surface::surface @@ -153,12 +204,12 @@ Foam::functionObjects::runTimePostPro::surface::surface ( representationTypeNames.get("representation", dict) ), - featureEdges_(false), + featureEdges_(dict.lookupOrDefault("featureEdges", false)), surfaceColour_(nullptr), edgeColour_(nullptr), surfaceActor_(), edgeActor_(), - maxGlyphLength_(0.0) + maxGlyphLength_(0) { surfaceActor_ = vtkSmartPointer<vtkActor>::New(); edgeActor_ = vtkSmartPointer<vtkActor>::New(); @@ -185,10 +236,6 @@ Foam::functionObjects::runTimePostPro::surface::surface { dict.readEntry("maxGlyphLength", maxGlyphLength_); } - else - { - dict.readEntry("featureEdges", featureEdges_); - } } @@ -203,10 +250,7 @@ Foam::functionObjects::runTimePostPro::surface::New const word& surfaceType ) { - if (debug) - { - Info<< "Selecting surface " << surfaceType << endl; - } + DebugInfo << "Selecting surface " << surfaceType << endl; auto cstrIter = dictionaryConstructorTablePtr_->cfind(surfaceType); @@ -242,22 +286,14 @@ void Foam::functionObjects::runTimePostPro::surface::updateActors return; } - edgeActor_->GetProperty()->SetLineWidth(2); - edgeActor_->GetProperty()->SetOpacity(opacity(position)); + vtkProperty* edgeProp = edgeActor_->GetProperty(); - const vector colour = edgeColour_->value(position); - edgeActor_->GetProperty()->SetColor - ( - colour[0], - colour[1], - colour[2] - ); - edgeActor_->GetProperty()->SetEdgeColor - ( - colour[0], - colour[1], - colour[2] - ); + edgeProp->SetLineWidth(2); + edgeProp->SetOpacity(opacity(position)); + + const vector ec = edgeColour_->value(position); + edgeProp->SetColor(ec[0], ec[1], ec[2]); + edgeProp->SetEdgeColor(ec[0], ec[1], ec[2]); } diff --git a/src/functionObjects/graphics/runTimePostProcessing/surface.H b/src/functionObjects/graphics/runTimePostProcessing/surface.H index 1de50dd5ee1272f3fa2742c438e34e7cc582991b..0725eb7e32d06fa8d42d644c67ba396ec70ead08 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/surface.H +++ b/src/functionObjects/graphics/runTimePostProcessing/surface.H @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2016-2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd. \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2015 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -27,10 +25,23 @@ Class Foam::functionObjects::runTimePostPro::surface Description - Visualisation of surface data + Visualisation of surface data with additional routines for handling + parallel distributed data. + + Dictionary controls + \table + Property | Description | Required | Default + representation| none/glyph/wireframe/surface/surfaceWithEdges | yes | + surfaceColour | Override surface colour | no | + edgeColour | Override edge colour | no | + featureEdges | Display surface feature edges | no | false + maxGlyphLength | Limit for glyph representation | yes | 0 + \endtable SourceFiles surface.C + surfaceGather.C + surfaceTemplates.C \*---------------------------------------------------------------------------*/ @@ -38,17 +49,80 @@ SourceFiles #define functionObjects_runTimePostPro_surface_H #include "geometryBase.H" +#include "DimensionedField.H" #include "Enum.H" #include "runTimeSelectionTables.H" + #include "vtkSmartPointer.h" +#include "vtkMultiPieceDataSet.h" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -// Forward declarations +// Forward Declarations class vtkActor; class vtkRenderer; +class vtkCellData; +class vtkCompositeDataGeometryFilter; +class vtkFeatureEdges; +class vtkPointData; class vtkPolyData; +namespace Foam +{ +// Forward Declarations +class polySurface; +class polySurfaceGeoMesh; +class polySurfacePointGeoMesh; +} + + +// These need to shift elsewhere + +namespace Foam +{ +namespace vtk +{ +namespace Tools +{ + +//- Functional call with null-pointer check +vtkCellData* GetCellData(vtkDataSet* dataset); + +//- Functional call with null-pointer check +vtkPointData* GetPointData(vtkDataSet* dataset); + + +//- Default field access is vtkCellData +template<class Type> +struct FieldAccess +{ + vtkCellData* operator()(vtkDataSet* dataset) const + { + return Tools::GetCellData(dataset); + } +}; + + +// Specializations on OpenFOAM type + +//- PointAccess for point fields (on polySurfacePointGeoMesh) +template<> +struct FieldAccess<::Foam::polySurfacePointGeoMesh> +{ + vtkPointData* operator()(vtkDataSet* dataset) const + { + return Tools::GetPointData(dataset); + } +}; + +} // End namespace Tools +} // End namespace vtk +} // End namespace Foam + + +// More + + namespace Foam { namespace functionObjects @@ -68,21 +142,23 @@ public: // Public enumerations + //- Surface representation types enum representationType { - rtNone, - rtWireframe, - rtSurface, - rtSurfaceWithEdges, - rtGlyph + rtNone, //!< "none" + rtGlyph, //!< "glyph" + rtWireframe, //!< "wireframe" + rtSurface, //!< "surface" + rtSurfaceWithEdges //!< "surfaceWithEdges" }; + //- Names for surface representation types static const Enum<representationType> representationTypeNames; protected: - // Protected data + // Protected Data //- Representation type representationType representation_; @@ -111,6 +187,13 @@ protected: //- Set the representation void setRepresentation(vtkActor* actor) const; + //- Add feature edges to scene + void addFeatureEdges + ( + vtkRenderer* renderer, + vtkFeatureEdges* featureEdges + ) const; + //- Add feature edges to scene void addFeatureEdges ( @@ -118,6 +201,110 @@ protected: vtkPolyData* data ) const; + //- Add feature edges to scene + void addFeatureEdges + ( + vtkRenderer* renderer, + vtkCompositeDataGeometryFilter* input + ) const; + + + //- Gather and convert polySurface to multi-piece dataset with + //- vtkPolyData for the leaves. + // If VTK is also running in parallel, each surface is left + // as a processor-local piece. Otherwise all processor-local + // surfaces are gathered onto the master in their correponding + // slots. + vtkSmartPointer<vtkMultiPieceDataSet> + gatherSurfacePieces(const polySurface* surf) const; + + //- Gather and convert polySurface to multi-piece dataset with + //- vtkPolyData for the leaves. + // If VTK is also running in parallel, each surface is left + // as a processor-local piece. Otherwise all processor-local + // surfaces are gathered onto the master in their correponding + // slots. + vtkSmartPointer<vtkMultiPieceDataSet> + gatherFaceCentres(const polySurface* surf) const; + + + // Adding Fields - single-piece + + //- Add field of Type to piece as VTK field data in GeoMeshType slot. + // GeoMeshType distinguishes between vtkCellData and vtkPointData + template<class Type, class GeoMeshType> + bool addField + ( + vtkDataSet* piece, //!< The VTK piece (null protected) + const Field<Type>& fld, //!< The field values to add + const word& fieldName //!< The field name to use + ) const; + + //- Attempt cast of regIOobject to DimensionedField\<Type\> and + //- add to piece as VTK field data in GeoMeshType slot. + // GeoMeshType distinguishes between vtkCellData and vtkPointData + template<class Type, class GeoMeshType> + bool addDimField + ( + vtkDataSet* piece, //!< The VTK piece (null protected) + const regIOobject* ioptr, //!< The field values to add + const word& fieldName //!< The field name to use + ) const; + + //- Attempt cast of regIOobject to standard DimensionedField types + //- and add to piece when possible + template<class GeoMeshType> + bool addDimField + ( + vtkDataSet* piece, //!< The VTK piece (null protected) + const regIOobject* ioptr, //!< The field values to add + const word& fieldName //!< The field name to use + ) const; + + + // Adding Fields - multi-piece + + //- Add DimensionedField of Type to multi-piece as VTK field data in + //- GeoMeshType slot (CELL | POINT). + template<class Type, class GeoMeshType> + bool addDimField + ( + vtkMultiPieceDataSet* multiPiece, + const DimensionedField<Type, GeoMeshType>* fldptr, + const word& fieldName + ) const; + + //- Attempt cast of regIOobject to DimensionedField\<Type\> and + //- add in multi-piece as VTK field data in + //- GeoMeshType slot (CELL | POINT). + template<class Type, class GeoMeshType> + bool addDimField + ( + vtkMultiPieceDataSet* multiPiece, //!< The VTK pieces + const regIOobject* ioptr, //!< The field values to add + const word& fieldName //!< The field name to use + ) const; + + //- Attempt cast of regIOobject to standard DimensionedField types + //- and add when possible in GeoMeshType slot (CELL | POINT). + template<class GeoMeshType> + bool addDimField + ( + vtkMultiPieceDataSet* multiPiece, //!< The VTK pieces + const regIOobject* ioptr, //!< The field values to add + const word& fieldName //!< The field name to use + ) const; + + //- Add using regIOobject information obtained from surface + template<class GeoMeshType> + bool addDimField + ( + vtkMultiPieceDataSet* multiPiece, + const polySurface* surf, + const word& fieldName + ) const; + + //- No copy construct surface(const surface&) = delete; @@ -128,7 +315,7 @@ protected: public: //- Run-time type information - TypeName("surface"); + TypeNameNoDebug("surface"); // Declare run-time constructor selection table @@ -160,7 +347,7 @@ public: // Selectors - //- Return a reference to the selected RAS model + //- Return selected surface static autoPtr<surface> New ( const runTimePostProcessing& parent, @@ -189,6 +376,12 @@ public: // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +#ifdef NoRepository + #include "surfaceTemplates.C" +#endif + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + #endif // ************************************************************************* // diff --git a/src/functionObjects/graphics/runTimePostProcessing/surfaceGather.C b/src/functionObjects/graphics/runTimePostProcessing/surfaceGather.C new file mode 100644 index 0000000000000000000000000000000000000000..218e3e13f3c257aeedd6ba9154f0a56a0f8248b5 --- /dev/null +++ b/src/functionObjects/graphics/runTimePostProcessing/surfaceGather.C @@ -0,0 +1,222 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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 "surface.H" +#include "runTimePostProcessing.H" + +#include "foamVtkTools.H" +#include "polySurface.H" + +// VTK includes +#include "vtkMultiPieceDataSet.h" +#include "vtkPolyData.h" +#include "vtkSmartPointer.h" + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +vtkSmartPointer<vtkMultiPieceDataSet> +Foam::functionObjects::runTimePostPro::surface::gatherSurfacePieces +( + const polySurface* surf +) const +{ + auto multiPiece = vtkSmartPointer<vtkMultiPieceDataSet>::New(); + multiPiece->SetNumberOfPieces(Pstream::nProcs()); + + if (!needsCollective()) + { + // Simple case (serial-serial, parallel-parallel) + + if (surf) + { + multiPiece->SetPiece + ( + Pstream::myProcNo(), + Foam::vtk::Tools::Patch::mesh(*surf) + ); + } + } + else if (Pstream::master()) + { + // Gather pieces on master + + if (surf) + { + // Add myself + + multiPiece->SetPiece + ( + Pstream::myProcNo(), + Foam::vtk::Tools::Patch::mesh(*surf) + ); + } + + // Receive surfaces + pointField points; + faceList faces; + + for + ( + int slave=Pstream::firstSlave(); + slave<=Pstream::lastSlave(); + ++slave + ) + { + IPstream fromSlave(Pstream::commsTypes::scheduled, slave); + + points.clear(); + faces.clear(); + + fromSlave >> points >> faces; + + if (points.size()) + { + multiPiece->SetPiece + ( + slave, + Foam::vtk::Tools::Patch::mesh(points, faces) + ); + } + } + } + else + { + // Slave - send surfaces + + OPstream toMaster + ( + Pstream::commsTypes::scheduled, + Pstream::masterNo() + ); + + if (surf) + { + toMaster + << surf->points() << surf->faces(); + } + else + { + toMaster + << pointField() << faceList(); + } + } + + return multiPiece; +} + + +vtkSmartPointer<vtkMultiPieceDataSet> +Foam::functionObjects::runTimePostPro::surface::gatherFaceCentres +( + const polySurface* surf +) const +{ + auto multiPiece = vtkSmartPointer<vtkMultiPieceDataSet>::New(); + multiPiece->SetNumberOfPieces(Pstream::nProcs()); + + if (!needsCollective()) + { + // Simple case + + if (surf) + { + auto dataset = vtkSmartPointer<vtkPolyData>::New(); + + auto geom = vtkSmartPointer<vtkPolyData>::New(); + + geom->SetPoints(Foam::vtk::Tools::Patch::faceCentres(*surf)); + geom->SetVerts(Foam::vtk::Tools::identityVertices(surf->nFaces())); + + multiPiece->SetPiece(Pstream::myProcNo(), geom); + } + } + else if (Pstream::master()) + { + // Gather pieces (face centres) on master + + if (surf) + { + // Add myself + + auto geom = vtkSmartPointer<vtkPolyData>::New(); + + geom->SetPoints(Foam::vtk::Tools::Patch::faceCentres(*surf)); + geom->SetVerts(Foam::vtk::Tools::identityVertices(surf->nFaces())); + + multiPiece->SetPiece(Pstream::myProcNo(), geom); + } + + // Receive points + pointField points; + + for + ( + int slave=Pstream::firstSlave(); + slave<=Pstream::lastSlave(); + ++slave + ) + { + IPstream fromSlave(Pstream::commsTypes::scheduled, slave); + + points.clear(); + + fromSlave >> points; + + if (points.size()) + { + multiPiece->SetPiece + ( + slave, + Foam::vtk::Tools::Vertices(points) + ); + } + } + } + else + { + // Slave - send face centres + + OPstream toMaster + ( + Pstream::commsTypes::scheduled, + Pstream::masterNo() + ); + + if (surf) + { + toMaster << surf->faceCentres(); + } + else + { + toMaster << pointField(); + } + } + + return multiPiece; +} + + +// ************************************************************************* // diff --git a/src/functionObjects/graphics/runTimePostProcessing/surfaceTemplates.C b/src/functionObjects/graphics/runTimePostProcessing/surfaceTemplates.C new file mode 100644 index 0000000000000000000000000000000000000000..eaf1498e8cbd4f858529782c85d6a32d66e344c2 --- /dev/null +++ b/src/functionObjects/graphics/runTimePostProcessing/surfaceTemplates.C @@ -0,0 +1,289 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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/>. + +\*---------------------------------------------------------------------------*/ + +#include "foamVtkTools.H" +#include "polySurfaceFields.H" +#include "polySurfacePointFields.H" + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +template<class Type, class GeoMeshType> +bool Foam::functionObjects::runTimePostPro::surface::addField +( + vtkDataSet* piece, + const Field<Type>& fld, + const word& fieldName +) const +{ + if (!piece) return false; + + auto vtkfield = Foam::vtk::Tools::convertFieldToVTK<Type>(fieldName, fld); + + if (piece->GetNumberOfCells() == piece->GetNumberOfPoints()) + { + // Only has verts + piece->GetPointData()->AddArray(vtkfield); + } + else + { + Foam::vtk::Tools::FieldAccess<GeoMeshType>()(piece)->AddArray(vtkfield); + } + + return true; +} + + +template<class Type, class GeoMeshType> +bool Foam::functionObjects::runTimePostPro::surface::addDimField +( + vtkDataSet* piece, + const regIOobject* ioptr, + const word& fieldName +) const +{ + const auto* fldptr = + dynamic_cast<const DimensionedField<Type, GeoMeshType>*>(ioptr); + + if (fldptr) + { + return addField<Type, GeoMeshType> + ( + piece, + fldptr->field(), + fieldName + ); + } + + return false; +} + + +template<class GeoMeshType> +bool Foam::functionObjects::runTimePostPro::surface::addDimField +( + vtkDataSet* piece, + const regIOobject* ioptr, + const word& fieldName +) const +{ + return (piece && ioptr) && + ( + addDimField<scalar, GeoMeshType> + ( + piece, ioptr, fieldName + ) + || addDimField<vector, GeoMeshType> + ( + piece, ioptr, fieldName + ) + || addDimField<sphericalTensor, GeoMeshType> + ( + piece, ioptr, fieldName + ) + || addDimField<symmTensor, GeoMeshType> + ( + piece, ioptr, fieldName + ) + || addDimField<tensor, GeoMeshType> + ( + piece, ioptr, fieldName + ) + ); +} + + +template<class Type, class GeoMeshType> +bool Foam::functionObjects::runTimePostPro::surface::addDimField +( + vtkMultiPieceDataSet* multiPiece, + const DimensionedField<Type, GeoMeshType>* fldptr, + const word& fieldName +) const +{ + if (!multiPiece) + { + return false; + } + + if (!needsCollective()) + { + // Simple case (serial-serial, parallel-parallel) + + return fldptr && + addField<Type, GeoMeshType> + ( + multiPiece->GetPiece(Pstream::myProcNo()), + fldptr->field(), + fieldName + ); + } + + + // Gather fields + const bool ok = returnReduce((fldptr != nullptr), orOp<bool>()); + + if (!ok) + { + return false; + } + + if (Pstream::master()) + { + if (fldptr) + { + // My field data + addField<Type, GeoMeshType> + ( + multiPiece->GetPiece(Pstream::myProcNo()), + fldptr->field(), + fieldName + ); + } + + // Receive field data + Field<Type> recv; + + for + ( + int slave=Pstream::firstSlave(); + slave<=Pstream::lastSlave(); + ++slave + ) + { + IPstream fromSlave(Pstream::commsTypes::scheduled, slave); + + recv.clear(); + + fromSlave + >> recv; + + if (recv.size()) + { + addField<Type, GeoMeshType> + ( + multiPiece->GetPiece(slave), + recv, + fieldName + ); + } + } + } + else + { + // Slave - send field data + + OPstream toMaster + ( + Pstream::commsTypes::scheduled, + Pstream::masterNo() + ); + + if (fldptr) + { + toMaster + << fldptr->field(); + } + else + { + toMaster + << List<Type>(); + } + } + + return ok; +} + + +template<class Type, class GeoMeshType> +bool Foam::functionObjects::runTimePostPro::surface::addDimField +( + vtkMultiPieceDataSet* multiPiece, + const regIOobject* ioptr, + const word& fieldName +) const +{ + return addDimField<Type, GeoMeshType> + ( + multiPiece, + dynamic_cast<const DimensionedField<Type, GeoMeshType>*>(ioptr), + fieldName + ); +} + + +template<class GeoMeshType> +bool Foam::functionObjects::runTimePostPro::surface::addDimField +( + vtkMultiPieceDataSet* multiPiece, + const regIOobject* ioptr, + const word& fieldName +) const +{ + return (multiPiece) && + ( + addDimField<scalar, GeoMeshType> + ( + multiPiece, ioptr, fieldName + ) + || addDimField<vector, GeoMeshType> + ( + multiPiece, ioptr, fieldName + ) + || addDimField<sphericalTensor, GeoMeshType> + ( + multiPiece, ioptr, fieldName + ) + || addDimField<symmTensor, GeoMeshType> + ( + multiPiece, ioptr, fieldName + ) + || addDimField<tensor, GeoMeshType> + ( + multiPiece, ioptr, fieldName + ) + ); +} + + +template<class GeoMeshType> +bool Foam::functionObjects::runTimePostPro::surface::addDimField +( + vtkMultiPieceDataSet* multiPiece, + const polySurface* surf, + const word& fieldName +) const +{ + const regIOobject* ioptr = + ( + surf + ? surf->findFieldObject<GeoMeshType>(fieldName) + : nullptr + ); + + return addDimField<GeoMeshType>(multiPiece, ioptr, fieldName); +} + + +// ************************************************************************* // diff --git a/src/functionObjects/graphics/runTimePostProcessing/text.C b/src/functionObjects/graphics/runTimePostProcessing/text.C index 09b622c565b24ebdb83c46143aa2007af62cfb3f..688e77486b207ac8eca21cf9b7d5f581c4ae5599 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/text.C +++ b/src/functionObjects/graphics/runTimePostProcessing/text.C @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2016-2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd. \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2015 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -27,10 +25,12 @@ License // OpenFOAM includes #include "text.H" +#include "stringOps.H" #include "fvMesh.H" #include "runTimePostProcessing.H" // VTK includes +#include "vtkCoordinate.h" #include "vtkRenderer.h" #include "vtkSmartPointer.h" #include "vtkTextActor.h" @@ -62,7 +62,7 @@ Foam::functionObjects::runTimePostPro::text::text : geometryBase(parent, dict, colours), string_(dict.get<string>("string")), - position_(), + positions_(), size_(dict.get<scalar>("size")), colour_(nullptr), halign_ @@ -74,7 +74,20 @@ Foam::functionObjects::runTimePostPro::text::text shadow_(dict.lookupOrDefault("shadow", false)), timeStamp_(dict.lookupOrDefault("timeStamp", false)) { - dict.readEntry("position", position_); + if (!dict.readIfPresent("positions", positions_)) + { + positions_.resize(1); + dict.readEntry("position", positions_.first()); + } + + // Additional safety + if (positions_.empty()) + { + positions_.resize(1); + positions_.first() = {0, 0}; + } + + stringOps::inplaceExpand(string_, dict, true, true); if (dict.found("colour")) { @@ -101,12 +114,13 @@ void Foam::functionObjects::runTimePostPro::text::addGeometryToScene vtkRenderer* renderer ) { - if (!visible_) + if (!visible_ || !renderer || !Pstream::master()) { + // Add text on master only! return; } - auto actor = vtkSmartPointer<vtkTextActor>::New(); + DebugInfo << " Add text: " << string_ << nl; // Concatenate string with timeStamp if true string str = string_; @@ -114,31 +128,40 @@ void Foam::functionObjects::runTimePostPro::text::addGeometryToScene { str += " " + geometryBase::parent_.mesh().time().timeName(); } - actor->SetInput(str.c_str()); - vtkTextProperty* prop = actor->GetTextProperty(); + const vector textColour = colour_->value(position); - prop->SetFontFamilyToArial(); - prop->SetFontSize(size_); - prop->SetJustification(int(halign_)); - prop->SetVerticalJustificationToBottom(); - prop->SetBold(bold_); - prop->SetItalic(italic_); - prop->SetShadow(shadow_); + const scalar textOpacity = opacity(position); - const vector colour = colour_->value(position); + for (const auto& textPosition : positions_) + { + auto actor = vtkSmartPointer<vtkTextActor>::New(); - prop->SetColor(colour[0], colour[1], colour[2]); - prop->SetOpacity(opacity(position)); + actor->SetInput(str.c_str()); - actor->GetPositionCoordinate()->SetCoordinateSystemToNormalizedViewport(); - actor->GetPositionCoordinate()->SetValue - ( - position_.first(), - position_.second() - ); + vtkTextProperty* prop = actor->GetTextProperty(); + + prop->SetFontFamilyToArial(); + prop->SetFontSize(size_); + prop->SetJustification(int(halign_)); + prop->SetVerticalJustificationToBottom(); + prop->SetBold(bold_); + prop->SetItalic(italic_); + prop->SetShadow(shadow_); + + prop->SetColor(textColour[0], textColour[1], textColour[2]); + prop->SetOpacity(textOpacity); - renderer->AddActor2D(actor); + // Positioning + { + vtkCoordinate* coord = actor->GetPositionCoordinate(); + + coord->SetCoordinateSystemToNormalizedViewport(); + coord->SetValue(textPosition.first(), textPosition.second()); + } + + renderer->AddActor2D(actor); + } } diff --git a/src/functionObjects/graphics/runTimePostProcessing/text.H b/src/functionObjects/graphics/runTimePostProcessing/text.H index 5eaf56c571553a799ebd0b902d7546b397e3476f..f298d4cff59518b0a646b18f1bba9cdef64d77ef 100644 --- a/src/functionObjects/graphics/runTimePostProcessing/text.H +++ b/src/functionObjects/graphics/runTimePostProcessing/text.H @@ -2,10 +2,8 @@ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | - \\ / A nd | Copyright (C) 2016-2018 OpenCFD Ltd. + \\ / A nd | Copyright (C) 2015-2019 OpenCFD Ltd. \\/ M anipulation | -------------------------------------------------------------------------------- - | Copyright (C) 2015 OpenFOAM Foundation ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -41,7 +39,6 @@ Description // Optional entry shadow false; - visible yes; // Optionally override default colour // colour (0 1 1); @@ -56,6 +53,7 @@ Description Property | Description | Required | Default string | Text to display | yes | position | The (x y) viewport position | yes | + positions | Multiple (x y) viewport positions | no | size | The font size in points | yes | halign | Text justification (left/centre/ right) | no | left bold | Use bold font | yes | @@ -68,10 +66,14 @@ Description Inherited controls \table Property | Description | Required | Default - visible | Display the object | yes | + visible | Display the object | no | true opacity | Object opacity | no | 1.0 \endtable +Note + The string text is expanded on input using stringOps::inplaceExpand() + to expand dictionary and environment variable entries. + SourceFiles text.C @@ -85,7 +87,7 @@ SourceFiles // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // -// Forward declarations +// Forward Declarations class vtkRenderer; namespace Foam @@ -96,7 +98,7 @@ namespace runTimePostPro { /*---------------------------------------------------------------------------*\ - Class text Declaration + Class text Declaration \*---------------------------------------------------------------------------*/ class text @@ -105,9 +107,9 @@ class text { public: - // Public enumerations + // Public Enumerations - //- Horizontal alignment type + //- Horizontal alignment type. Values to match VTK definitions enum halignType { LEFT = 0, //!< Left-justified text - default ("left") @@ -126,13 +128,13 @@ protected: //- Text string string_; - //- Position - Tuple2<scalar, scalar> position_; + //- Position(s) + List<Tuple2<scalar, scalar>> positions_; - //- Size + //- Font size scalar size_; - //- Colour + //- Text colour autoPtr<Function1<vector>> colour_; //- Horizontal alignment @@ -179,7 +181,7 @@ public: // Member Functions - //- Add surface(s) to scene + //- Add text to scene virtual void addGeometryToScene ( const scalar position, @@ -189,7 +191,7 @@ public: //- Update actors virtual void updateActors(const scalar position); - //- Clear files used to create the object(s) + //- Clear files used to create the object(s) - no-op virtual bool clear(); }; diff --git a/src/functionObjects/graphics/runTimePostProcessing/volumeFilter.C b/src/functionObjects/graphics/runTimePostProcessing/volumeFilter.C new file mode 100644 index 0000000000000000000000000000000000000000..9a3caf7f8b4fbfb60dfe7d64e0d274bf383debbc --- /dev/null +++ b/src/functionObjects/graphics/runTimePostProcessing/volumeFilter.C @@ -0,0 +1,144 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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 "volumeFilter.H" +#include "runTimePostProcessing.H" + +// VTK includes +#include "vtkCellData.h" +#include "vtkCellDataToPointData.h" +#include "vtkCompositeDataGeometryFilter.h" +#include "vtkCompositeDataSet.h" +#include "vtkCompositePolyDataMapper.h" +#include "vtkMultiPieceDataSet.h" +#include "vtkPointData.h" +#include "vtkPolyData.h" +#include "vtkPolyDataMapper.h" +#include "vtkSmartPointer.h" + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::functionObjects::runTimePostPro::volumeFilter::volumeFilter +( + const runTimePostProcessing& parent, + const dictionary& dict, + const HashPtrTable<Function1<vector>>& colours +) +: + surface(parent, dict, colours) +{} + + +// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // + +vtkSmartPointer<vtkMultiPieceDataSet> +Foam::functionObjects::runTimePostPro::volumeFilter::mesh +( + Foam::vtk::vtuAdaptor& adaptor +) const +{ + auto multiPiece = vtkSmartPointer<vtkMultiPieceDataSet>::New(); + + multiPiece->SetNumberOfPieces(Pstream::nProcs()); + multiPiece->SetPiece + ( + Pstream::myProcNo(), + adaptor.internal(parent().mesh()) + ); + + return multiPiece; +} + + +bool Foam::functionObjects::runTimePostPro::volumeFilter::addDimField +( + vtkDataSet* piece, + const vtk::vtuAdaptor& adaptor, + const regIOobject* ioptr, + const word& fieldName +) const +{ + return (piece && ioptr) && + ( + addDimField<scalar> + ( + piece, adaptor, ioptr, fieldName + ) + || addDimField<vector> + ( + piece, adaptor, ioptr, fieldName + ) + || addDimField<sphericalTensor> + ( + piece, adaptor, ioptr, fieldName + ) + || addDimField<symmTensor> + ( + piece, adaptor, ioptr, fieldName + ) + || addDimField<tensor> + ( + piece, adaptor, ioptr, fieldName + ) + ); +} + + +int Foam::functionObjects::runTimePostPro::volumeFilter::addDimField +( + vtkMultiPieceDataSet* piece, + const vtk::vtuAdaptor& adaptor, + const regIOobject* ioptr, + const word& fieldName +) const +{ + return (piece && ioptr) && + ( + addDimField<scalar> + ( + piece, adaptor, ioptr, fieldName + ) + || addDimField<vector> + ( + piece, adaptor, ioptr, fieldName + ) + || addDimField<sphericalTensor> + ( + piece, adaptor, ioptr, fieldName + ) + || addDimField<symmTensor> + ( + piece, adaptor, ioptr, fieldName + ) + || addDimField<tensor> + ( + piece, adaptor, ioptr, fieldName + ) + ); +} + + +// ************************************************************************* // diff --git a/src/functionObjects/graphics/runTimePostProcessing/volumeFilter.H b/src/functionObjects/graphics/runTimePostProcessing/volumeFilter.H new file mode 100644 index 0000000000000000000000000000000000000000..d75a1a7a51e8173e30d9d63c6fe6b48753ce7867 --- /dev/null +++ b/src/functionObjects/graphics/runTimePostProcessing/volumeFilter.H @@ -0,0 +1,162 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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::volumeFilter + +Description + Visualisation of OpenFOAM volume fields as surface data using + a VTK filter cascade. + +Note + Since this filter includes an OpenFOAM/VTK adaptor level, + it is ill-suited to mismatches in data parallelization. + If OpenFOAM is running in parallel but VTK is not, it would be rather + expensive to collect all the data on the master node for this filter. + That approach is acceptable for smaller amounts of data, but do not + allow for volume meshes. + +SourceFiles + volumeFilter.C + +\*---------------------------------------------------------------------------*/ + +#ifndef functionObjects_runTimePostPro_volumeFilter_H +#define functionObjects_runTimePostPro_volumeFilter_H + +#include "runTimePostProcessing.H" +#include "surface.H" +#include "foamVtkVtuAdaptor.H" + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +class vtkDataSet; +class vtkMultiPieceDataSet; +template<class T> class vtkSmartPointer; + +namespace Foam +{ +namespace vtk +{ +class vtuAdaptor; +} + +namespace functionObjects +{ +namespace runTimePostPro +{ + +/*---------------------------------------------------------------------------*\ + Class volumeFilter Declaration +\*---------------------------------------------------------------------------*/ + +class volumeFilter +: + public surface +{ +protected: + + // Protected Member Functions + + //- Return a vtu mesh with addressing information stored in adaptor + vtkSmartPointer<vtkMultiPieceDataSet> mesh + ( + Foam::vtk::vtuAdaptor& adaptor + ) const; + + + bool addDimField + ( + vtkDataSet* piece, + const vtk::vtuAdaptor& adaptor, + const regIOobject* ioptr, + const word& fieldName + ) const; + + int addDimField + ( + vtkMultiPieceDataSet* multiPiece, + const vtk::vtuAdaptor& adaptor, + const regIOobject* ioptr, + const word& fieldName + ) const; + + template<class Type> + bool addDimField + ( + vtkDataSet* piece, + const vtk::vtuAdaptor& adaptor, + const regIOobject* ioptr, + const word& fieldName + ) const; + + template<class Type> + int addDimField + ( + vtkMultiPieceDataSet* multiPiece, + const vtk::vtuAdaptor& adaptor, + const regIOobject* ioptr, + const word& fieldName + ) const; + + + //- No copy construct + volumeFilter(const volumeFilter&) = delete; + + //- No copy assignment + void operator=(const volumeFilter&) = delete; + + +public: + + // Constructors + + //- Construct from dictionary + volumeFilter + ( + const runTimePostProcessing& parent, + const dictionary& dict, + const HashPtrTable<Function1<vector>>& colours + ); + + + //- Destructor + virtual ~volumeFilter() = default; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +} // End namespace runTimePostPro +} // End namespace functionObjects +} // End namespace Foam + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +#ifdef NoRepository + #include "volumeFilterTemplates.C" +#endif + +#endif + +// ************************************************************************* // diff --git a/src/functionObjects/graphics/runTimePostProcessing/volumeFilterTemplates.C b/src/functionObjects/graphics/runTimePostProcessing/volumeFilterTemplates.C new file mode 100644 index 0000000000000000000000000000000000000000..5d5c6594c4d1cc7edca7fdbb3670174ff264f5ae --- /dev/null +++ b/src/functionObjects/graphics/runTimePostProcessing/volumeFilterTemplates.C @@ -0,0 +1,120 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / 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 "volumeFilter.H" +#include "fvMesh.H" +#include "volFields.H" +#include "foamVtkTools.H" + +// VTK includes +#include "vtkCellData.h" +#include "vtkMultiPieceDataSet.h" +#include "vtkPointData.h" + +// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * // + +template<class Type> +bool Foam::functionObjects::runTimePostPro::volumeFilter::addDimField +( + vtkDataSet* piece, + const vtk::vtuAdaptor& adaptor, + const regIOobject* ioptr, + const word& fieldName +) const +{ + vtkSmartPointer<vtkFloatArray> vtkdata; + + const auto* dimptr = + dynamic_cast<const DimensionedField<Type, volMesh>*>(ioptr); + + if (dimptr && !vtkdata) + { + vtkdata = adaptor.convertField(*dimptr); + } + + const auto* volptr = + dynamic_cast<const GeometricField<Type, fvPatchField, volMesh>*>(ioptr); + + if (volptr && !vtkdata) + { + vtkdata = adaptor.convertField(volptr->internalField()); + } + + if (vtkdata) + { + piece->GetCellData()->AddArray(vtkdata); + return true; + } + + return false; +} + + +template<class Type> +int Foam::functionObjects::runTimePostPro::volumeFilter::addDimField +( + vtkMultiPieceDataSet* multiPiece, + const vtk::vtuAdaptor& adaptor, + const regIOobject* ioptr, + const word& fieldName +) const +{ + if (!multiPiece) + { + return 0; + } + + const int nCmpt(pTraits<Type>::nComponents); + + if (!needsCollective()) + { + // Simple case (serial-serial, parallel-parallel) + + auto piece = multiPiece->GetPiece(Pstream::myProcNo()); + + if + ( + addDimField<Type> + ( + piece, + adaptor, + ioptr, + fieldName + ) + ) + { + return nCmpt; + } + } + else + { + } + + return 0; +} + + +// ************************************************************************* // diff --git a/tutorials/incompressible/pimpleFoam/RAS/ellipsekkLOmega/system/controlDict b/tutorials/incompressible/pimpleFoam/RAS/ellipsekkLOmega/system/controlDict index 2ca0331bc892109b37f4a5b9044e0dc2bbf87c35..f7779d15ceb72d14c8e9244bd2ae9ea41a6b8093 100644 --- a/tutorials/incompressible/pimpleFoam/RAS/ellipsekkLOmega/system/controlDict +++ b/tutorials/incompressible/pimpleFoam/RAS/ellipsekkLOmega/system/controlDict @@ -53,9 +53,8 @@ maxCo 0.2; functions { - #include "sampling" - #include "streamLines" - #include "runTimePostProcessing" + // Demonstrate runTimePostProcessing + #include "visualization" } // ************************************************************************* // diff --git a/tutorials/incompressible/pimpleFoam/RAS/ellipsekkLOmega/system/runTimePostProcessing b/tutorials/incompressible/pimpleFoam/RAS/ellipsekkLOmega/system/runTimePostProcessing index 3e9f362b168bd9290a5b37f79ae3c1f17893a67e..321960381f2153e7f7f15d033d403cd0bfe8e731 100644 --- a/tutorials/incompressible/pimpleFoam/RAS/ellipsekkLOmega/system/runTimePostProcessing +++ b/tutorials/incompressible/pimpleFoam/RAS/ellipsekkLOmega/system/runTimePostProcessing @@ -8,15 +8,21 @@ postPro1 { - type runTimePostProcessing; - libs ("librunTimePostProcessing.so"); - writeControl writeTime; + #includeEtc "caseDicts/postProcessing/visualization/runTimePostPro.cfg" + + // Time control etc + ${_visualization}; + + // debug true; + // parallel true; + output { name image; width 800; height 600; } + camera { // If camera is moving, optionally provide start and end times @@ -42,14 +48,10 @@ postPro1 // they are locally overridden colours { - background (0.317647 0.341176 0.431373); - background2 ${background}; - text (0.75 0.75 0.75); - edge (1 0 0); - surface (0.5 0.5 0.5); - line (1 0 0); + ${..colourScheme.paraview}; } + // Line data lines { streamline @@ -70,11 +72,11 @@ postPro1 } } - _plane + // Surface data + _surface { type functionObjectSurface; - functionObject cuttingPlane; - colourMap blueWhiteRed; + colourMap coolToWarm; representation glyph; maxGlyphLength 0.1; visible yes; @@ -83,13 +85,8 @@ postPro1 field U; range (0 10); opacity 1; - scalarBar - { - visible no; - } } - surfaces { geom @@ -102,26 +99,51 @@ postPro1 visible yes; featureEdges no; opacity 0.8; + visible false; } - plane0 + + patches { - ${_plane}; - functionObject plane0; + type patches; + patches (hole); + renderMode phong; + representation surface; + colourMap coolToWarm; + colourBy field; + field U; + range (0 10); + nearCellValue true; + smooth true; } - plane1 + + plane0 { - ${_plane}; - functionObject plane1; + ${_surface}; + functionObject planes.plane0; } - plane2 + plane1 { - ${_plane}; - functionObject plane2; + ${_surface}; + functionObject planes.plane1; } - plane3 + + cutting { - ${_plane}; - functionObject plane3; + // Same colours and scaling as surface + ${_surface}; + + type plane; + planeType pointAndNormal; + + pointAndNormalDict + { + point (0 0 0); + normal (1 0 0); + } + + offsets (0.1 0.2 0.3 0.4 0.5); + + colourMap coolToWarm; } } diff --git a/tutorials/incompressible/pimpleFoam/RAS/ellipsekkLOmega/system/sampling b/tutorials/incompressible/pimpleFoam/RAS/ellipsekkLOmega/system/sampling index cf6bc155bef10da90cf5221984af725fb34abca3..d54c13cda48554b92b71e7d70d67103ecc59c3b3 100644 --- a/tutorials/incompressible/pimpleFoam/RAS/ellipsekkLOmega/system/sampling +++ b/tutorials/incompressible/pimpleFoam/RAS/ellipsekkLOmega/system/sampling @@ -6,94 +6,58 @@ | \\/ M anipulation | | \*---------------------------------------------------------------------------*/ -plane0 +planes { type surfaces; libs ("libsampling.so"); - writeControl writeTime; - surfaceFormat vtk; + // Time control etc + ${_visualization}; + fields ( p U ); - interpolationScheme cellPoint; + // surfaceFormat vtk; + surfaceFormat none; - surfaces - ( - plane0 - { - type cuttingPlane; - planeType pointAndNormal; - interpolate true; - pointAndNormalDict - { - point (0 0 0); - normal (1 0 0); - } - } - ); -} + store true; + interpolationScheme cellPoint; -plane1 -{ - ${plane0} + _plane + { + type plane; //cuttingPlane; + planeType pointAndNormal; + interpolate false; - surfaces - ( - plane1 + pointAndNormalDict { - type cuttingPlane; - planeType pointAndNormal; - interpolate true; - pointAndNormalDict - { - point (0.1 0 0); - normal (1 0 0); - } + point (0 0 0); + normal (1 0 0); } - ); -} - - -plane2 -{ - ${plane0} + } surfaces - ( - plane2 + { + plane0 { - type cuttingPlane; - planeType pointAndNormal; - interpolate true; + ${_plane} pointAndNormalDict { - point (0.2 0 0); - normal (1 0 0); + point (0 0 0); } } - ); -} - - -plane3 -{ - ${plane0} - surfaces - ( - plane3 + plane1 { - type cuttingPlane; - planeType pointAndNormal; - interpolate true; + ${_plane} pointAndNormalDict { - point (0.3 0 0); - normal (1 0 0); + point (-0.1 0 0); } } - ); + } + + #remove _plane } diff --git a/tutorials/incompressible/pimpleFoam/RAS/ellipsekkLOmega/system/streamLines b/tutorials/incompressible/pimpleFoam/RAS/ellipsekkLOmega/system/streamLines index 86dd7663bf61be5a4acda8455c3c54b9c5ae56a3..3aeb39e409c2bbbdcbd3894946c84ae0c15a46a0 100644 --- a/tutorials/incompressible/pimpleFoam/RAS/ellipsekkLOmega/system/streamLines +++ b/tutorials/incompressible/pimpleFoam/RAS/ellipsekkLOmega/system/streamLines @@ -10,7 +10,8 @@ streamLines { type streamLine; - writeControl writeTime; + // Time control etc + ${_visualization}; setFormat vtk; diff --git a/tutorials/incompressible/pimpleFoam/RAS/ellipsekkLOmega/system/visualization b/tutorials/incompressible/pimpleFoam/RAS/ellipsekkLOmega/system/visualization new file mode 100644 index 0000000000000000000000000000000000000000..fb1739f4359a0ef512fe16b38b63bd25fb1d2792 --- /dev/null +++ b/tutorials/incompressible/pimpleFoam/RAS/ellipsekkLOmega/system/visualization @@ -0,0 +1,29 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1812 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ + +// Demonstrate runTimePostProcessing + +// Timing +_visualization +{ + writeControl writeTime; + + // enabled true; + + // Debug: writeControl timeStep; + // Debug: writeInterval 4; +} + + +#include "streamLines" +#include "sampling" +#include "runTimePostProcessing" + +#remove _visualization + +// ************************************************************************* // diff --git a/tutorials/incompressible/pisoFoam/LES/motorBike/motorBike/system/controlDict b/tutorials/incompressible/pisoFoam/LES/motorBike/motorBike/system/controlDict index e302d38c3333025524cf948da44605c0801ae99a..0d11850807f7da587405452ab9d4ce886597830a 100644 --- a/tutorials/incompressible/pisoFoam/LES/motorBike/motorBike/system/controlDict +++ b/tutorials/incompressible/pisoFoam/LES/motorBike/motorBike/system/controlDict @@ -49,10 +49,8 @@ runTimeModifiable true; functions { - // Demonstrate runtime postprocessing - #include "streamLines" - #include "cuttingPlane" - #include "runTimePostProcessing" + // Demonstrate runTimePostProcessing + #include "visualization" // Do some other functionObjects #include "forceCoeffs" diff --git a/tutorials/incompressible/pisoFoam/LES/motorBike/motorBike/system/runTimePostProcessing b/tutorials/incompressible/pisoFoam/LES/motorBike/motorBike/system/runTimePostProcessing index 7f4a0e9f96f0bad47f9ba0030ea338edb76e64cd..1f4f0cae237af30ca8cbc515edbaa9b9b887fae0 100644 --- a/tutorials/incompressible/pisoFoam/LES/motorBike/motorBike/system/runTimePostProcessing +++ b/tutorials/incompressible/pisoFoam/LES/motorBike/motorBike/system/runTimePostProcessing @@ -1,14 +1,34 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1812 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ + postPro1 { - type runTimePostProcessing; - libs ("librunTimePostProcessing.so"); - writeControl writeTime; + #includeEtc "caseDicts/postProcessing/visualization/runTimePostPro.cfg" + + // Time control etc + ${_visualization}; + + // debug true; + // parallel true; + output { name image; width 2000; height 1200; } + + // Default colours. Used for colourBy == colour unless locally overridden + colours + { + ${..colourScheme.blueGradient}; + } + camera { // If camera is moving, optionally provide start and end times @@ -19,27 +39,15 @@ postPro1 nFrameTotal 1; // Parallel projection flag - parallelProjection no; + parallelProjection off; clipBox (-0.2 -0.2 0)(1.65 0.2 1.25); // optional focalPoint (1.2 1.1 0.2); - up (0 0 1); position (3.6 5.1 -1.3); + up (0 0 1); } - // Default colours - // - If select to colourBy colour, these values are used unless - // they are locally overridden - colours - { - background (1 1 1); - background2 (0 0 1); - text (0 0 0); - edge (1 0 0); - surface (0.5 0.5 0.5); - line (1 0 0); - } // Line data lines { @@ -47,8 +55,9 @@ postPro1 { type functionObjectLine; functionObject streamLines; + colourMap rainbow; representation tube; - visible yes; + visible true; tubeRadius 0.01; colourBy field; field U; @@ -56,13 +65,17 @@ postPro1 opacity 1; scalarBar { - visible yes; + visible true; position (0.8 0.1); vertical yes; fontSize 16; - title "velocity / [m/s]"; + title "velocity [m/s]"; labelFormat "%6.2f"; numberOfLabels 5; + bold true; + italic true; + italic true; + colour (0.75 0.75 0.75); } } } @@ -77,27 +90,40 @@ postPro1 renderMode phong; representation surface; edgeColour (0 0 0); - visible yes; featureEdges yes; opacity 1; + visible false; } - cuttingPlane1 + + patches + { + type patches; + patches ("motorBike.*"); + renderMode phong; + representation surface; + colourMap coolToWarm; + colourBy field; + field U; + range (0 30); + nearCellValue true; + smooth true; + featureEdges yes; + edgeColour (0 0 0); + } + + plane1 { type functionObjectSurface; - functionObject cuttingPlane; - colourMap blueWhiteRed; + functionObject samples.yNormal; + colourMap coolToWarm; representation glyph; maxGlyphLength 0.1; - visible yes; + visible true; featureEdges no; colourBy field; field U; range (0 30); opacity 1; - scalarBar - { - visible no; - } } } @@ -106,11 +132,14 @@ postPro1 { text1 { - string "Motorbike"; - position (0.1 0.05); - size 72; - bold yes; - visible yes; + visible true; + string "Motorbike"; + position (0.1 0.05); + size 72; + bold true; + italic true; } } } + +// ************************************************************************* // diff --git a/tutorials/incompressible/pisoFoam/LES/motorBike/motorBike/system/cuttingPlane b/tutorials/incompressible/pisoFoam/LES/motorBike/motorBike/system/samples similarity index 85% rename from tutorials/incompressible/pisoFoam/LES/motorBike/motorBike/system/cuttingPlane rename to tutorials/incompressible/pisoFoam/LES/motorBike/motorBike/system/samples index dc4e254faf2b3048fc719eacb4bad67dd63d4b47..6731e79021aa84c5b00dcea77ede04ec52dee7a0 100644 --- a/tutorials/incompressible/pisoFoam/LES/motorBike/motorBike/system/cuttingPlane +++ b/tutorials/incompressible/pisoFoam/LES/motorBike/motorBike/system/samples @@ -6,31 +6,38 @@ | \\/ M anipulation | | \*---------------------------------------------------------------------------*/ -cuttingPlane +samples { type surfaces; libs ("libsampling.so"); - writeControl writeTime; - surfaceFormat vtk; + // Time control etc + ${_visualization}; + fields (p U); + // surfaceFormat vtk; + surfaceFormat none; + + verbose false; + interpolationScheme cellPoint; surfaces - ( + { yNormal { type cuttingPlane; planeType pointAndNormal; + interpolate true; + store true; pointAndNormalDict { point (0 0 0); normal (0 1 0); } - interpolate true; } - ); + } } diff --git a/tutorials/incompressible/pisoFoam/LES/motorBike/motorBike/system/stabilizationSchemes b/tutorials/incompressible/pisoFoam/LES/motorBike/motorBike/system/stabilizationSchemes index d8a71b89ef6514f34c5e674df33d3ecc23d1f921..6285f30aecedc1687e6124ed0540e31b9084d582 100644 --- a/tutorials/incompressible/pisoFoam/LES/motorBike/motorBike/system/stabilizationSchemes +++ b/tutorials/incompressible/pisoFoam/LES/motorBike/motorBike/system/stabilizationSchemes @@ -8,7 +8,7 @@ residuals { - type residuals; + type solverInfo; libs ("libutilityFunctionObjects.so"); writeFields true; writeControl outputTime; diff --git a/tutorials/incompressible/pisoFoam/LES/motorBike/motorBike/system/streamLines b/tutorials/incompressible/pisoFoam/LES/motorBike/motorBike/system/streamLines index 45983df17e78d861ed33b7ebc0ac2aa726d5defd..e87abf94a0df172b1ed9426cc0bef5f67afbaf2a 100644 --- a/tutorials/incompressible/pisoFoam/LES/motorBike/motorBike/system/streamLines +++ b/tutorials/incompressible/pisoFoam/LES/motorBike/motorBike/system/streamLines @@ -8,11 +8,10 @@ streamLines { - type streamLine; + type streamLine; - // Output every - writeControl writeTime; - // writeInterval 10; + // Time control etc + ${_visualization}; setFormat vtk; //gnuplot; //xmgr; //raw; //jplot; //csv; //ensight; diff --git a/tutorials/incompressible/pisoFoam/LES/motorBike/motorBike/system/visualization b/tutorials/incompressible/pisoFoam/LES/motorBike/motorBike/system/visualization new file mode 100644 index 0000000000000000000000000000000000000000..64ae524306fbad078eb9a14095d5c147fcd1f614 --- /dev/null +++ b/tutorials/incompressible/pisoFoam/LES/motorBike/motorBike/system/visualization @@ -0,0 +1,30 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1812 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ + +// Demonstrate runTimePostProcessing + +// Timing +_visualization +{ + writeControl writeTime; + + // enabled true; + + // Debug: writeControl timeStep; + // Debug: writeInterval 10; +} + + +#include "streamLines" +#include "samples" +#include "runTimePostProcessing" + +#remove _visualization + + +// ************************************************************************* // diff --git a/tutorials/incompressible/simpleFoam/windAroundBuildings/system/controlDict b/tutorials/incompressible/simpleFoam/windAroundBuildings/system/controlDict index 65bb7238b98345ba49ed0bb4587ba17af9bb8ae3..f97a4fa1d87920ca56a68ca0ff178192638bed8e 100644 --- a/tutorials/incompressible/simpleFoam/windAroundBuildings/system/controlDict +++ b/tutorials/incompressible/simpleFoam/windAroundBuildings/system/controlDict @@ -52,6 +52,9 @@ functions { #include "ensightWrite" #include "vtkWrite" + + // Demonstrate runTimePostProcessing + #include "visualization" } diff --git a/tutorials/incompressible/simpleFoam/windAroundBuildings/system/runTimePostProcessing b/tutorials/incompressible/simpleFoam/windAroundBuildings/system/runTimePostProcessing new file mode 100644 index 0000000000000000000000000000000000000000..4de8c7fb651475e29183e3b917af40a4859a42fb --- /dev/null +++ b/tutorials/incompressible/simpleFoam/windAroundBuildings/system/runTimePostProcessing @@ -0,0 +1,306 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1812 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ + +postPro1 +{ + #includeEtc "caseDicts/postProcessing/visualization/runTimePostPro.cfg" + + // Time control etc + ${_visualization}; + + // debug true; + // parallel true; + + showIsoSurface false; + + output + { + name image; + width 1280; + height 720; + } + + camera + { + // If camera is moving, optionally provide start and end times + // startPosition 0.2; + // endPosition 0.75; + + // Total number of frames to generate + nFrameTotal 1; + + // Parallel projection flag + parallelProjection yes; + + // clipBox is optional + + position (385 -560 650); + focalPoint (160 90 60); + up (0.06 0.7 0.7); + + position + ( + -41.95 + -247.55 + 426.87 + ); + focalPoint + ( + 146 + 76 + 40 + ); + up + ( + 0.3646 + 0.6194 + 0.6953 + ); + + zoom 1.5; + // clipBox (-10 18 0)(280 160 76); + clipBox (-30 0 0)(300 200 80); + } + + // Default colours + colours + { + ${..colourScheme.paraview}; + } + + // Line data + lines + { + streamline + { + type functionObjectLine; + functionObject streamLines; + colourMap rainbow; + representation tube; + visible yes; + tubeRadius 0.5; + colourBy field; + field U; + range (0 20); + opacity 1; + } + } + + _sampled + { + type functionObjectSurface; + colourMap coolToWarm; + representation glyph; + representation surface; + maxGlyphLength 0.1; + visible yes; + featureEdges no; + colourBy field; + field U; + range (0 20); + opacity 1; + } + + + _velocity_scalarBar + { + visible yes; + vertical false; + titleHack false; + position (0.8 0); + size (0.2 0.1); + + fontSize 8; + titleSize 24; + title "velocity [m/s]"; + labelFormat "%.0f"; + numberOfLabels 5; + + bold yes; + italic yes; + shadow yes; + } + + surfaces + { + /* + geom + { + type geometry; + files ("<case>/buildings.vtp"); + renderMode phong; + representation surface; + edgeColour (0.5 0.5 0.5); + visible yes; + featureEdges none; + opacity 1.0; + } + */ + + ground1 + { + type patches; + patches ( ground ); + nearCellValue true; + colourMap coolToWarm; + representation glyph; + + // maxGlyphLength 5; + maxGlyphLength 0; + colourBy field; + + field U; + range (0 20); + } + + ground2 + { + type patches; + patches ( ground ); + nearCellValue true; + smooth true; + colourMap coolToWarm; + representation wireframe; + + // maxGlyphLength 5; + maxGlyphLength 0; + visible yes; + colourBy field; + + field U; + range (0 20); + } + + buildings + { + type patches; + patches ( buildings ); + nearCellValue true; + smooth true; + colourMap coolToWarm; + representation surface; + renderMode phong; + + colourBy field; + field U; + range (0 20); + + scalarBar + { + ${_velocity_scalarBar}; + } + } + + // A cutting plane from sampled surfaces: + stored1 + { + ${_sampled}; + functionObject planes.plane2; + smooth true; + } + + // VTK cutting planes: + cutting + { + type plane; + planeType pointAndNormal; + + pointAndNormalDict + { + point (100 100 50); + normal (1 0 0); + } + + offsets (0 200); + + smooth true; + colourMap coolToWarm; + representation surface; + + // representation glyph; + + // maxGlyphLength 5; + maxGlyphLength 0; + visible yes; + featureEdges none; + + colourBy field; + colourField U; + field U; + range (0 20); + } + + // VTK iso surfaces of something + iso + { + visible ${showIsoSurface}; + type isoSurface; + + field U; + values (10); + + smooth true; + colourMap coolToWarm; + + representation surface; + + // maxGlyphLength 5; + maxGlyphLength 0; + featureEdges none; + + colourBy field; + colourField p; + range (-120 120); + } + } + + // Text data + text + { + title + { + string "Wind around buildings"; + position (0 0.95); + size 32; + bold yes; + italic yes; + shadow yes; + visible yes; + } + + version + { + ${title}; + string "OpenFOAM ${FOAM_API}"; + position (0 0); + size 24; + } + + watermark + { + string "www.openfoam.com"; + halign centre; + size 24; + opacity 0.3; + bold yes; + italic yes; + shadow yes; + + positions + ( + (0.50 0.05) (0.50 0.95) + (0.25 0.25) (0.75 0.25) + (0.25 0.50) (0.75 0.50) + (0.25 0.75) (0.75 0.75) + ); + } + } +} + + +// ************************************************************************* // diff --git a/tutorials/incompressible/simpleFoam/windAroundBuildings/system/sampling b/tutorials/incompressible/simpleFoam/windAroundBuildings/system/sampling new file mode 100644 index 0000000000000000000000000000000000000000..35b69cfcff21af0cd0c235afa25b071d9e7d1b9a --- /dev/null +++ b/tutorials/incompressible/simpleFoam/windAroundBuildings/system/sampling @@ -0,0 +1,71 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1812 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ + +planes +{ + type surfaces; + libs ("libsampling.so"); + + // Time control etc + ${_visualization}; + + fields ( p U ); + + // surfaceFormat vtk; + surfaceFormat none; + + store true; + + interpolationScheme cellPoint; + + _plane + { + type cuttingPlane; + planeType pointAndNormal; + interpolate false; + } + + surfaces + { + plane0 + { + ${_plane} + pointAndNormalDict + { + point (100 100 50); + normal (1 -1 0); + } + enabled false; + } + + plane1 + { + ${_plane} + pointAndNormalDict + { + point (100 100 50); + normal (1 1 0); + } + } + + plane2 + { + ${_plane} + pointAndNormalDict + { + point (200 100 50); + normal (1 0 0); + } + } + }; + + #remove _plane +} + + +// ************************************************************************* // diff --git a/tutorials/incompressible/simpleFoam/windAroundBuildings/system/streamLines b/tutorials/incompressible/simpleFoam/windAroundBuildings/system/streamLines new file mode 100644 index 0000000000000000000000000000000000000000..9b3a494454acc1e0067d440598ceeafb63080c65 --- /dev/null +++ b/tutorials/incompressible/simpleFoam/windAroundBuildings/system/streamLines @@ -0,0 +1,52 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1812 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ + +streamLines +{ + type streamLine; + + libs ("libfieldFunctionObjects.so"); + + // Time control etc + ${_visualization}; + + setFormat vtk; + + // Velocity field to use for tracking. + U U; + + // Tracked forwards (+U) or backwards (-U) + trackForward true; + + // Names of fields to sample. Should contain above velocity field! + fields (p U); + + // Steps particles can travel before being removed + lifeTime 10000; + + // Number of steps per cell (estimate). Set to 1 to disable subcycling. + nSubCycle 5; + + // Cloud name to use + cloud particleTracks; + + // Seeding method. + seedSampleSet + { + type uniform; + axis x; //distance; + + // Note: tracks slightly offset so as not to be on a face + start (0 -20 15); + end (0 150 15); + nPoints 40; + } +} + + +// ************************************************************************* // diff --git a/tutorials/incompressible/simpleFoam/windAroundBuildings/system/visualization b/tutorials/incompressible/simpleFoam/windAroundBuildings/system/visualization new file mode 100644 index 0000000000000000000000000000000000000000..ca867f071b84ccdcb9d16e3db7dc2a1014ced56e --- /dev/null +++ b/tutorials/incompressible/simpleFoam/windAroundBuildings/system/visualization @@ -0,0 +1,29 @@ +/*--------------------------------*- C++ -*----------------------------------*\ +| ========= | | +| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | +| \\ / O peration | Version: v1812 | +| \\ / A nd | Web: www.OpenFOAM.com | +| \\/ M anipulation | | +\*---------------------------------------------------------------------------*/ + +// Demonstrate runTimePostProcessing + +// Timing +_visualization +{ + writeControl writeTime; + + // enabled true; + + // Debug: writeControl timeStep; + // Debug: writeInterval 10; +} + + +#include "streamLines" +#include "sampling" +#include "runTimePostProcessing" + +#remove _visualization + +// ************************************************************************* // diff --git a/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/controlDict b/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/controlDict index e38412357f2201fb1b5094f8ad4ac052bcf77f74..bd195eb50f06ed9e32716013692f2659158f2e8e 100644 --- a/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/controlDict +++ b/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/controlDict @@ -53,8 +53,9 @@ maxDeltaT 1; functions { + #include "dataCloud" #include "vtkCloud" - // #include "dataCloud" + #include "runTimePostProcessing" } diff --git a/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/runTimePostProcessing b/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/runTimePostProcessing index 73d6b3533bb6a2ec069dcaf7569e69498e763cf6..9a4a0f382a5f1c6295562a27e92047e994ba6d48 100644 --- a/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/runTimePostProcessing +++ b/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/runTimePostProcessing @@ -2,9 +2,11 @@ postPro1 { - type runTimePostProcessing; - libs ("librunTimePostProcessing.so"); - writeControl writeTime; + #includeEtc "caseDicts/postProcessing/visualization/runTimePostPro.cfg" + + // parallel false; + // debug true; + output { name image; @@ -23,10 +25,10 @@ postPro1 parallelProjection yes; - focalPoint (0.251 0.415 0.05); - position (0.251 0.415 2.218); + focalPoint (0.25 0.42 0.05); + position (0.15 0.42 2.5); up (0 1 0); - zoom 1; + zoom 1.5; } // Default colours @@ -34,13 +36,7 @@ postPro1 // they are locally overridden colours { - background (0.5 0.5 0.5); - background2 (0.7 0.7 0.7); - text (1 1 1); - edge (1 0 0); - surface (0.5 0.5 0.5); - line (1 0 0); - point (0.5 0.5 0.5); + ${..colourScheme.greyGradient}; } // Points (cloud) data @@ -48,55 +44,69 @@ postPro1 { cloud1 { - type functionObjectCloud; - functionObject cloudWrite1; + type cloud; cloud coalCloud1; - colourMap blueWhiteRed; + colourMap coolToWarm; representation sphere; - maxGlyphLength 0.05; - visible yes; + maxGlyphLength 0.025; featureEdges no; colourBy field; colourField T; field T; range (290 410); opacity 1; + scalarBar { - visible yes; + visible true; vertical yes; position (0.8 0.1); fontSize 12; + titleSize 24; title "Temperature [K]"; labelFormat "%.0f"; - numberOfLabels 8; + numberOfLabels 9; + bold false; } } } -/* Future... + // Surface data surfaces { - container + patches { type patches; patches (".*"); renderMode phong; representation surface; - edgeColour (0 0 0); - visible yes; + colourBy colour; + field U; + range (0 40); featureEdges yes; - opacity 0.25; + edgeColour (0 0 0); + // Fails in parallel: opacity 0.25; + } + + k + { + type isoSurface; + renderMode phong; + representation surface; + field k; + values ( 100 ); + colourField T; + colourBy field; + range (290 410); + smooth true; } } -*/ // Text data text { text1 { - visible yes; string "simplifiedSiwek"; position (0.1 0.05); size 24;