Commit 8d900264 authored by Mark Olesen's avatar Mark Olesen

ENH: paraview reader module with internal caching of the vtk geometries

- The reader module allows two levels of caching.
  The OpenFOAM fvMesh can be cached in memory, for faster loading of
  fields. Additionally, the translated VTK geometries are held in a
  local cache. The cached VTK geometries should incur no additional
  overhead since they use the VTK reference counting for their storage
  management.
parent cba5a97c
......@@ -27,6 +27,8 @@
</Documentation>
</DoubleVectorProperty>
<!-- General Controls -->
<!-- Refresh (push button) -->
<Property
name="Refresh"
......@@ -35,12 +37,10 @@
<Documentation>Rescan for updated times/fields.</Documentation>
</Property>
<!-- General Controls -->
<!-- Skip Zero Time (check-box) -->
<IntVectorProperty animateable="0"
name="ZeroTime"
label="Skip Zero Time"
label="Skip 0/ time"
command="SetSkipZeroTime"
default_values="1"
number_of_elements="1"
......@@ -54,26 +54,28 @@
<!-- Include Sets (check-box) -->
<IntVectorProperty animateable="0"
name="IncludeSets"
label="With Sets"
command="SetIncludeSets"
default_values="0"
number_of_elements="1"
panel_visibility="default">
<BooleanDomain name="bool"/>
<Documentation>
Search the polyMesh/sets/ directory
Search the polyMesh/sets/ directory for {cell,face,point} sets
</Documentation>
</IntVectorProperty>
<!-- Include Zones (check-box) -->
<IntVectorProperty animateable="0"
name="IncludeZones"
label="With Zones"
command="SetIncludeZones"
default_values="0"
number_of_elements="1"
panel_visibility="default">
<BooleanDomain name="bool"/>
<Documentation>
ZoneMesh information is used to find {cell,face,point}Zones.
ZoneMesh information is used to find {cell,face,point} zones.
The polyMesh/ directory is only checked on startup.
</Documentation>
</IntVectorProperty>
......@@ -88,7 +90,7 @@
panel_visibility="default">
<BooleanDomain name="bool"/>
<Documentation>
Show patchGroups only.
Display patchGroups only instead of individual patches.
</Documentation>
</IntVectorProperty>
......@@ -109,6 +111,7 @@
<!-- Interpolate Fields (check-box) -->
<IntVectorProperty animateable="0"
name="InterpolateFields"
label="cell-to-point"
command="SetInterpolateVolFields"
default_values="1"
number_of_elements="1"
......@@ -122,6 +125,7 @@
<!-- Extrapolate Patches (check-box) -->
<IntVectorProperty animateable="0"
name="ExtrapolatePatches"
label="field-to-patch"
command="SetExtrapolatePatches"
default_values="0"
number_of_elements="1"
......@@ -132,7 +136,7 @@
</Documentation>
</IntVectorProperty>
<!-- Force GUI update (check-box) -->
<!-- Force GUI update (push button) -->
<IntVectorProperty animateable="0"
name="UpdateGUI"
command="SetUpdateGUI"
......@@ -159,16 +163,22 @@
</Documentation>
</IntVectorProperty>
<!-- Cache Mesh (check-box) -->
<!-- Mesh Caching (combo-box) -->
<IntVectorProperty animateable="0"
name="CacheMesh"
command="SetCacheMesh"
default_values="1"
name="MeshCaching"
command="SetMeshCaching"
default_values="3"
number_of_elements="1"
panel_visibility="default">
<BooleanDomain name="bool"/>
<EnumerationDomain name="enum">
<Entry text="No caching" value="0" />
<Entry text="Cache fvMesh" value="1" />
<Entry text="Cache vtk,fvMesh" value="3" />
</EnumerationDomain>
<Documentation>
Cache the fvMesh in memory.
Mesh caching styles.
Caching the OpenFOAM fvMesh reduces disk access.
Caching the VTK mesh reduces transcription overhead.
</Documentation>
</IntVectorProperty>
......@@ -185,7 +195,7 @@
<Property name="ShowPatchNames"/>
<Property name="UpdateGUI"/>
<Property name="UseVTKPolyhedron"/>
<Property name="CacheMesh"/>
<Property name="MeshCaching"/>
</PropertyGroup>
<!-- Parts Selections -->
......
......@@ -26,6 +26,7 @@ License
#include "pqFoamReaderControls.h"
#include <QCheckBox>
#include <QComboBox>
#include <QFrame>
#include <QGridLayout>
#include <QPushButton>
......@@ -42,6 +43,17 @@ License
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
// file-scope
// Add horizontal divider to layout
static void addHline(QGridLayout* layout, int row, int nCols)
{
QFrame* hline = new QFrame(layout->parentWidget());
hline->setFrameStyle(QFrame::HLine | QFrame::Sunken);
layout->addWidget(hline, row, 0, 1, nCols);
}
// file-scope
// Widget properties
static QWidget* setWidgetProperties
......@@ -94,6 +106,66 @@ static QAbstractButton* setButtonProperties
}
// file-scope
// Fill combo-box from XML enumeration
static QComboBox* setComboBoxContent
(
QComboBox* b,
vtkSMIntVectorProperty* prop
)
{
vtkSMEnumerationDomain* propEnum =
vtkSMEnumerationDomain::SafeDownCast
(
prop->FindDomain("vtkSMEnumerationDomain")
);
if (propEnum)
{
unsigned int n = propEnum->GetNumberOfEntries();
for (unsigned int idx=0; idx < n; ++idx)
{
const int val = propEnum->GetEntryValue(idx);
const char* txt = propEnum->GetEntryText(idx);
b->insertItem(val, txt);
}
// Set default
const int val = prop->GetElement(0);
unsigned int idx = 0;
if (!propEnum->IsInDomain(val, idx))
{
idx = 0;
}
b->setCurrentIndex(idx);
}
return b;
}
// file-scope
// Translate a combo-box index to a lookup value
static int comboBoxValue(vtkSMIntVectorProperty* prop, int idx)
{
vtkSMEnumerationDomain* propEnum =
vtkSMEnumerationDomain::SafeDownCast
(
prop->FindDomain("vtkSMEnumerationDomain")
);
if (propEnum)
{
return propEnum->GetEntryValue(idx);
}
else
{
return idx;
}
}
static vtkSMIntVectorProperty* lookupIntProp
(
vtkSMPropertyGroup* group,
......@@ -154,9 +226,9 @@ void pqFoamReaderControls::refreshPressed()
}
void pqFoamReaderControls::cacheMesh(int val)
void pqFoamReaderControls::cacheMesh(int idx)
{
fireCommand(cacheMesh_, val);
fireCommand(meshCaching_, comboBoxValue(meshCaching_, idx));
}
......@@ -210,12 +282,14 @@ pqFoamReaderControls::pqFoamReaderControls
showGroupsOnly_(lookupIntProp(group, "ShowGroupsOnly")),
includeSets_(lookupIntProp(group, "IncludeSets")),
includeZones_(lookupIntProp(group, "IncludeZones")),
cacheMesh_(lookupIntProp(group, "CacheMesh"))
meshCaching_(lookupIntProp(group, "MeshCaching"))
{
typedef vtkSMIntVectorProperty intProp;
QGridLayout* form = new QGridLayout(this);
const int nCols = 3;
// ROW
// ~~~
int row = 0;
......@@ -243,13 +317,7 @@ pqFoamReaderControls::pqFoamReaderControls
}
// LINE
// ~~~~
++row;
{
QFrame* hline = new QFrame(this);
hline->setFrameStyle(QFrame::HLine | QFrame::Sunken);
form->addWidget(hline, row, 0, 1, 4);
}
addHline(form, ++row, nCols);
// ROW
// ~~~
......@@ -321,13 +389,7 @@ pqFoamReaderControls::pqFoamReaderControls
}
// LINE
// ~~~~
++row;
{
QFrame* hline = new QFrame(this);
hline->setFrameStyle(QFrame::HLine | QFrame::Sunken);
form->addWidget(hline, row, 0, 1, 4);
}
addHline(form, ++row, nCols);
// ROW
// ~~~
......@@ -360,13 +422,7 @@ pqFoamReaderControls::pqFoamReaderControls
}
// LINE
// ~~~~
++row;
{
QFrame* hline = new QFrame(this);
hline->setFrameStyle(QFrame::HLine | QFrame::Sunken);
form->addWidget(hline, row, 0, 1, 4);
}
addHline(form, ++row, nCols);
// ROW
// ~~~
......@@ -398,14 +454,22 @@ pqFoamReaderControls::pqFoamReaderControls
);
}
if (cacheMesh_)
if (meshCaching_)
{
QCheckBox* b = new QCheckBox(this);
setButtonProperties(b, cacheMesh_);
QComboBox* b = new QComboBox(this);
form->addWidget(b, row, 2, Qt::AlignLeft);
setWidgetProperties(b, meshCaching_);
setComboBoxContent(b, meshCaching_);
addPropertyLink
(
b, "indexChanged", SIGNAL(currentIndexChanged(int)), meshCaching_
);
connect
(
b, SIGNAL(toggled(bool)), this, SLOT(cacheMesh(bool))
b, SIGNAL(currentIndexChanged(int)), this, SLOT(cacheMesh(int))
);
}
}
......
......@@ -69,8 +69,8 @@ class pqFoamReaderControls
//- IncludeZones (bool property)
vtkSMIntVectorProperty* includeZones_;
//- CacheMesh (bool property)
vtkSMIntVectorProperty* cacheMesh_;
//- MeshCaching (enum property)
vtkSMIntVectorProperty* meshCaching_;
// Private Member Functions
......@@ -102,7 +102,7 @@ protected slots:
// Protected Member Functions
void refreshPressed();
void cacheMesh(bool checked);
void cacheMesh(int idx);
void showPatchNames(bool checked);
void showGroupsOnly(bool checked);
void includeSets(bool checked);
......
......@@ -69,8 +69,7 @@ vtkPVFoamReader::vtkPVFoamReader()
// Add second output for the Lagrangian
this->SetNumberOfOutputPorts(2);
vtkSmartPointer<vtkMultiBlockDataSet> lagrangian =
vtkSmartPointer<vtkMultiBlockDataSet>::New();
auto lagrangian = vtkSmartPointer<vtkMultiBlockDataSet>::New();
lagrangian->ReleaseData();
......@@ -80,7 +79,7 @@ vtkPVFoamReader::vtkPVFoamReader()
TimeStepRange[0] = 0;
TimeStepRange[1] = 0;
CacheMesh = true;
MeshCaching = 3; // fvMesh+vtk
SkipZeroTime = true;
ExtrapolatePatches = false;
......
......@@ -83,9 +83,9 @@ public:
virtual void PrintInfo();
// Description:
// OpenFOAM mesh caching control
vtkSetMacro(CacheMesh, bool);
vtkGetMacro(CacheMesh, bool);
// Mesh caching control (0:none,1:fvMesh,3:fvMesh+vtk)
vtkSetMacro(MeshCaching, int);
vtkGetMacro(MeshCaching, int);
// Description:
// OpenFOAM refresh times/fields
......@@ -232,7 +232,7 @@ private:
void updatePatchNamesView(const bool show);
int TimeStepRange[2];
bool CacheMesh;
int MeshCaching;
bool SkipZeroTime;
bool ExtrapolatePatches;
......
......@@ -136,12 +136,12 @@ bool Foam::vtkPVFoam::addOutputBlock
if (selectedPartIds_.found(partId))
{
const auto& longName = selectedPartIds_[partId];
const word shortName = getPartName(partId);
const word shortName = getFoamName(longName);
auto iter = cache.find(longName);
if (iter.found() && (*iter).vtkmesh)
if (iter.found() && iter.object().dataset)
{
auto dataset = (*iter).vtkmesh;
auto dataset = iter.object().dataset;
if (singleDataset)
{
......@@ -224,7 +224,6 @@ int Foam::vtkPVFoam::setTime(int nRequest, const double requestTimes[])
runTime.setTime(Times[nearestIndex], nearestIndex);
// When the changes, so do the fields
fieldsChanged_ = true;
meshState_ = meshPtr_ ? meshPtr_->readUpdate() : polyMesh::TOPO_CHANGE;
reader_->UpdateProgress(0.05);
......@@ -238,27 +237,13 @@ int Foam::vtkPVFoam::setTime(int nRequest, const double requestTimes[])
Info<< "<end> setTime() - selectedTime="
<< Times[nearestIndex].name() << " index=" << timeIndex_
<< "/" << Times.size()
<< " meshUpdateState=" << updateStateName(meshState_)
<< " fieldsChanged=" << Switch(fieldsChanged_) << endl;
<< " meshUpdateState=" << updateStateName(meshState_) << endl;
}
return nearestIndex;
}
Foam::word Foam::vtkPVFoam::getPartName(const int partId) const
{
if (selectedPartIds_.found(partId))
{
return getFoamName(selectedPartIds_[partId]);
}
else
{
return word::null;
}
}
Foam::word Foam::vtkPVFoam::getReaderPartName(const int partId) const
{
return getFoamName(reader_->GetPartArrayName(partId));
......@@ -279,8 +264,8 @@ Foam::vtkPVFoam::vtkPVFoam
meshRegion_(polyMesh::defaultRegion),
meshDir_(polyMesh::meshSubDir),
timeIndex_(-1),
decomposePoly_(false),
meshState_(polyMesh::TOPO_CHANGE),
fieldsChanged_(true),
rangeVolume_("unzoned"),
rangePatches_("patch"),
rangeLagrangian_("lagrangian"),
......@@ -414,16 +399,16 @@ void Foam::vtkPVFoam::updateInfo()
// time of the vtkDataArraySelection, but the qt/paraview proxy
// layer doesn't care about that anyhow.
HashSet<string> enabledEntries;
HashSet<string> enabled;
if (!partSelection->GetNumberOfArrays() && !meshPtr_)
{
// enable 'internalMesh' on the first call
enabledEntries = { "internalMesh" };
// Fake enable 'internalMesh' on the first call
enabled = { "internalMesh" };
}
else
{
// preserve the enabled selections
enabledEntries = getSelectedArrayEntries(partSelection);
enabled = getSelectedArraySet(partSelection);
}
// Clear current mesh parts list
......@@ -431,18 +416,13 @@ void Foam::vtkPVFoam::updateInfo()
// Update mesh parts list - add Lagrangian at the bottom
updateInfoInternalMesh(partSelection);
updateInfoPatches(partSelection, enabledEntries);
updateInfoPatches(partSelection, enabled);
updateInfoSets(partSelection);
updateInfoZones(partSelection);
updateInfoLagrangian(partSelection);
// Adjust/restore the enabled selections
setSelectedArrayEntries(partSelection, enabledEntries);
if (meshState_ != polyMesh::UNCHANGED)
{
fieldsChanged_ = true;
}
setSelectedArrayEntries(partSelection, enabled);
// Update volume, point and lagrangian fields
updateInfoFields<fvPatchField, volMesh>
......@@ -480,42 +460,28 @@ void Foam::vtkPVFoam::Update
}
reader_->UpdateProgress(0.1);
const int caching = reader_->GetMeshCaching();
const bool oldDecomp = decomposePoly_;
decomposePoly_ = !reader_->GetUseVTKPolyhedron();
// Set up mesh parts selection(s)
// Update cached, saved, unneed values.
{
vtkDataArraySelection* selection = reader_->GetPartSelection();
const int n = selection->GetNumberOfArrays();
// All previously selected (enabled) names
HashSet<string> original;
forAllConstIters(selectedPartIds_, iter)
{
original.insert(iter.object());
}
selectedPartIds_.clear();
HashSet<string> nowActive;
for (int id=0; id < n; ++id)
{
string str(selection->GetArrayName(id));
bool status = selection->GetArraySetting(id);
const string str(selection->GetArrayName(id));
const bool status = selection->GetArraySetting(id);
if (status)
{
selectedPartIds_.set(id, str); // id -> name
if (!original.erase(str))
{
// New part, or newly enabled
//? meshChanged_ = true;
}
}
else
{
if (original.erase(str))
{
// Part disappeared, or newly disabled
//? meshChanged_ = true;
}
nowActive.set(str);
}
if (debug > 1)
......@@ -524,6 +490,39 @@ void Foam::vtkPVFoam::Update
<< " : " << str << nl;
}
}
// Dispose of unneeded components
cachedVtp_.retain(nowActive);
cachedVtu_.retain(nowActive);
if
(
!caching
|| meshState_ == polyMesh::TOPO_CHANGE
|| meshState_ == polyMesh::TOPO_PATCH_CHANGE
)
{
// Eliminate cached values that would be unreliable
forAllIters(cachedVtp_, iter)
{
iter.object().clearGeom();
iter.object().clear();
}
forAllIters(cachedVtu_, iter)
{
iter.object().clearGeom();
iter.object().clear();
}
}
else if (oldDecomp != decomposePoly_)
{
// poly-decompose changed - dispose of cached values
forAllIters(cachedVtu_, iter)
{
iter.object().clearGeom();
iter.object().clear();
}
}
}
reader_->UpdateProgress(0.15);
......@@ -536,7 +535,7 @@ void Foam::vtkPVFoam::Update
printMemory();
}
if (!reader_->GetCacheMesh())
if (!caching)
{
delete meshPtr_;
meshPtr_ = nullptr;
......@@ -549,7 +548,6 @@ void Foam::vtkPVFoam::Update
{
Info<< "Creating OpenFOAM mesh for region " << meshRegion_
<< " at time=" << dbPtr_().timeName() << endl;
}
meshPtr_ = new fvMesh
......@@ -582,17 +580,6 @@ void Foam::vtkPVFoam::Update
reader_->UpdateProgress(0.4);
// Update cached, saved, unneed values:
HashSet<string> nowActive;
forAllConstIters(selectedPartIds_, iter)
{
nowActive.insert(iter.object());
}
// Dispose of unneeded components
cachedVtp_.retain(nowActive);
cachedVtu_.retain(nowActive);
convertMeshVolume();
convertMeshPatches();
reader_->UpdateProgress(0.6);
......@@ -645,18 +632,28 @@ void Foam::vtkPVFoam::Update
}
reader_->UpdateProgress(0.95);
fieldsChanged_ = false;
meshState_ = polyMesh::UNCHANGED;
// Standard memory cleanup
cachedVtp_.clear();
cachedVtu_.clear();
if (caching & 2)
{
// Suppress caching of Lagrangian since it normally always changes.
cachedVtp_.filterKeys
(
[](const word& k){ return k.startsWith("lagrangian/"); },
true // prune
);
}
else
{
cachedVtp_.clear();
cachedVtu_.clear();