ENH: extended runTimePostProcessing (#1206)
- Extended runTimePostProcessing to include access to "live"
simulation objects such a geometry patches and sampled surfaces
stored on the "functionObjectObjects" registry.
- Add 'live' runTimePostProcessing of cloud data.
Extracts position and fields from the cloud via its objectRegistry writer
- For the "live" simulation objects, there are two new volume filters
that work directly with the OpenFOAM volume fields:
* iso-surface
* cutting planes
Both use the VTK algorithms directly and support multiple values.
Eg, can make multiple iso-levels or multiple planes parallel to each
other.
- When VTK has been compiled with MPI-support, parallel rendering will
be used.
- Additional title text properties (shadow, italic etc)
- Simplified handling of scalar-bar and visibility switches
- Support multiple text positions. Eg, for adding watermark text.
This commit is contained in:
committed by
Andrew Heather
parent
03e6aa1a6d
commit
42fbf6d38c
@ -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;
|
||||
}
|
||||
|
||||
|
||||
// ************************************************************************* //
|
||||
Reference in New Issue
Block a user