diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/Allwclean b/applications/utilities/postProcessing/graphics/PV398Readers/Allwclean
new file mode 100755
index 0000000000000000000000000000000000000000..ba4eb0a015041229c45b07b61f9968fd5974032f
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/Allwclean
@@ -0,0 +1,9 @@
+#!/bin/sh
+cd ${0%/*} || exit 1    # run from this directory
+set -x
+
+wclean libso vtkPV398Readers
+PV398blockMeshReader/Allwclean
+PV398FoamReader/Allwclean
+
+# ----------------------------------------------------------------- end-of-file
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/Allwmake b/applications/utilities/postProcessing/graphics/PV398Readers/Allwmake
new file mode 100755
index 0000000000000000000000000000000000000000..33d6bd18dd866fc70eae29df18d7075cdc307206
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/Allwmake
@@ -0,0 +1,22 @@
+#!/bin/sh
+cd ${0%/*} || exit 1    # run from this directory
+#set -x
+
+if [ -d "$ParaView_DIR" -a -r "$ParaView_DIR" ]
+then
+    [ -n "$PV_PLUGIN_PATH" ] || {
+        echo "$0 : PV_PLUGIN_PATH not valid - it is unset"
+        exit 1
+    }
+
+    # ensure CMake gets the correct C++ compiler
+    [ -n "$WM_CXX" ] && export CXX="$WM_CXX"
+
+    wmake libso vtkPV398Readers
+    PV398blockMeshReader/Allwmake
+    PV398FoamReader/Allwmake
+else
+    echo "ERROR: ParaView not found in $ParaView_DIR"
+fi
+
+# ----------------------------------------------------------------- end-of-file
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/Allwclean b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/Allwclean
new file mode 100755
index 0000000000000000000000000000000000000000..eda9ee566b20b05b59fbfb451656f5478d672e98
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/Allwclean
@@ -0,0 +1,11 @@
+#!/bin/sh
+cd ${0%/*} || exit 1    # run from this directory
+set -x
+
+# deal with client/server vs combined plugins
+rm -f $FOAM_LIBBIN/libPV398FoamReader* 2>/dev/null
+
+rm -rf PV398FoamReader/Make
+wclean libso vtkPV398Foam
+
+# ----------------------------------------------------------------- end-of-file
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/Allwmake b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/Allwmake
new file mode 100755
index 0000000000000000000000000000000000000000..77786eb58e8e28da13ba352d2a319ed91b68b901
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/Allwmake
@@ -0,0 +1,17 @@
+#!/bin/sh
+cd ${0%/*} || exit 1    # run from this directory
+set -x
+
+if [ -d "$ParaView_DIR" -a -r "$ParaView_DIR" ]
+then
+    wmake libso vtkPV398Foam
+    (
+        cd PV398FoamReader
+        mkdir -p Make/$WM_OPTIONS > /dev/null 2>&1
+        cd Make/$WM_OPTIONS
+        cmake ../..
+        make
+    )
+fi
+
+# ----------------------------------------------------------------- end-of-file
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/PV398FoamReader/CMakeLists.txt b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/PV398FoamReader/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..be5c2185b5bdd304bbc3ffcbdd6f1a7295913523
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/PV398FoamReader/CMakeLists.txt
@@ -0,0 +1,85 @@
+# create a plugin that adds a reader to the ParaView GUI
+# it is added in the file dialog when doing opens/saves.
+
+# The qrc file is processed by Qt's resource compiler (rcc)
+# the qrc file must have a resource prefix of "/ParaViewResources"
+# and ParaView will read anything contained under that prefix
+# the pqReader.xml file contains xml defining readers with their
+# file extensions and descriptions.
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
+
+FIND_PACKAGE(ParaView REQUIRED)
+INCLUDE(${PARAVIEW_USE_FILE})
+
+LINK_DIRECTORIES(
+    $ENV{FOAM_LIBBIN}
+    $ENV{FOAM_EXT_LIBBIN}
+)
+
+INCLUDE_DIRECTORIES(
+    $ENV{WM_PROJECT_DIR}/src/OpenFOAM/lnInclude
+    $ENV{WM_PROJECT_DIR}/src/OSspecific/$ENV{WM_OSTYPE}/lnInclude
+    $ENV{WM_PROJECT_DIR}/src/finiteVolume/lnInclude
+    ${PROJECT_SOURCE_DIR}/../vtkPV398Foam
+)
+
+ADD_DEFINITIONS(
+    -DWM_$ENV{WM_PRECISION_OPTION}
+)
+
+# Set output library destination to plugin folder
+SET(
+    LIBRARY_OUTPUT_PATH $ENV{PV_PLUGIN_PATH}
+    CACHE INTERNAL
+    "Single output directory for building all libraries."
+)
+
+
+#
+# Defined combined plugin
+#
+
+# Extend the auto-generated panel
+QT4_WRAP_CPP(MOC_SRCS pqPV398FoamReaderPanel.h)
+
+ADD_PARAVIEW_OBJECT_PANEL(IFACES IFACE_SRCS
+  CLASS_NAME pqPV398FoamReaderPanel
+  XML_NAME  PV398FoamReader  # name of SourceProxy in *SM.xml
+  XML_GROUP sources
+)
+
+ADD_PARAVIEW_PLUGIN(
+    PV398FoamReader_SM "1.0"
+    SERVER_MANAGER_XML PV398FoamReader_SM.xml
+    SERVER_MANAGER_SOURCES vtkPV398FoamReader.cxx
+    GUI_INTERFACES ${IFACES}
+    GUI_SOURCES pqPV398FoamReaderPanel.cxx
+        ${MOC_SRCS} ${UI_SRCS} ${IFACE_SRCS}
+    GUI_RESOURCE_FILES PV398FoamReader.xml
+)
+
+# #
+# # Define the server-side portion of the reader plugin
+# #
+# ADD_PARAVIEW_PLUGIN(
+#     PV398FoamReader_SM "1.0"
+#     SERVER_MANAGER_XML PV398FoamReader_SM.xml
+#     SERVER_MANAGER_SOURCES vtkPV398FoamReader.cxx
+# )
+# #
+# # Define the client-side portion of the reader plugin
+# #
+# ADD_PARAVIEW_PLUGIN(
+#     PV398FoamReader "1.0"
+#     GUI_RESOURCES PV3FoamReader.qrc
+# )
+#
+
+TARGET_LINK_LIBRARIES(
+    PV398FoamReader_SM
+    OpenFOAM
+    finiteVolume
+    vtkPV398Foam
+)
+#-----------------------------------------------------------------------------
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/PV398FoamReader/PV398FoamReader.qrc b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/PV398FoamReader/PV398FoamReader.qrc
new file mode 100644
index 0000000000000000000000000000000000000000..8f22c858df31ab062f0c16dba27a0f514ea59032
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/PV398FoamReader/PV398FoamReader.qrc
@@ -0,0 +1,5 @@
+<RCC>
+    <qresource prefix="/ParaViewResources" >
+        <file>PV398FoamReader.xml</file>
+    </qresource>
+</RCC>
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/PV398FoamReader/PV398FoamReader.xml b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/PV398FoamReader/PV398FoamReader.xml
new file mode 100644
index 0000000000000000000000000000000000000000..866ef557b2bcda6f572b64f18b0579f042a87b02
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/PV398FoamReader/PV398FoamReader.xml
@@ -0,0 +1,6 @@
+<ParaViewReaders>
+  <Reader name="PV398FoamReader"
+          extensions="OpenFOAM"
+          file_description="OpenFOAM Reader">
+  </Reader>
+</ParaViewReaders>
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/PV398FoamReader/PV398FoamReader_SM.xml b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/PV398FoamReader/PV398FoamReader_SM.xml
new file mode 100644
index 0000000000000000000000000000000000000000..73849a78c9e0bd01b65af7da122e05f392ac9ba5
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/PV398FoamReader/PV398FoamReader_SM.xml
@@ -0,0 +1,306 @@
+<ServerManagerConfiguration>
+  <ProxyGroup name="sources">
+  <SourceProxy
+    name="PV398FoamReader"
+    class="vtkPV398FoamReader">
+
+    <!-- File name - compulsory -->
+    <StringVectorProperty
+      name="FileName"
+      command="SetFileName"
+      number_of_elements="1"
+      animateable="0">
+      <FileListDomain name="files"/>
+      <Documentation>
+        Specifies the filename for the OpenFOAM Reader.
+      </Documentation>
+    </StringVectorProperty>
+
+    <!-- Send discrete time info to the animation panel -->
+    <DoubleVectorProperty
+      name="TimestepValues"
+      repeatable="1"
+      information_only="1">
+      <TimeStepsInformationHelper/>
+      <Documentation>
+        Available timestep values.
+      </Documentation>
+    </DoubleVectorProperty>
+
+    <!-- Cache Mesh check-box -->
+    <IntVectorProperty
+      name="UiCacheMesh"
+      command="SetCacheMesh"
+      number_of_elements="1"
+      is_internal="1"
+      default_values="1"
+      animateable="0">
+      <BooleanDomain name="bool"/>
+      <Documentation>
+        Cache the fvMesh in memory.
+      </Documentation>
+    </IntVectorProperty>
+
+    <!-- Refresh button -->
+    <IntVectorProperty
+      name="UiRefresh"
+      command="SetRefresh"
+      number_of_elements="1"
+      is_internal="0"
+      default_values="0"
+      animateable="0">
+      <BooleanDomain name="bool"/>
+      <Documentation>
+        Rescan for updated timesteps/fields.
+      </Documentation>
+    </IntVectorProperty>
+
+    <!-- Skip Zero Time check-box -->
+    <IntVectorProperty
+      name="UiZeroTime"
+      command="SetSkipZeroTime"
+      number_of_elements="1"
+      is_internal="1"
+      default_values="0"
+      animateable="0">
+      <BooleanDomain name="bool"/>
+      <Documentation>
+        Skip including the 0/ time directory
+      </Documentation>
+    </IntVectorProperty>
+
+    <!-- Interpolate Fields check-box -->
+    <IntVectorProperty
+      name="UiInterpolateVolFields"
+      command="SetInterpolateVolFields"
+      number_of_elements="1"
+      is_internal="1"
+      default_values="1"
+      animateable="0">
+      <BooleanDomain name="bool"/>
+      <Documentation>
+        Interpolate volume fields into point fields
+      </Documentation>
+    </IntVectorProperty>
+
+    <!-- Extrapolate Patches check-box -->
+    <IntVectorProperty
+      name="UiExtrapolatePatches"
+      command="SetExtrapolatePatches"
+      number_of_elements="1"
+      is_internal="1"
+      default_values="0"
+      animateable="0">
+      <BooleanDomain name="bool"/>
+      <Documentation>
+        Extrapolate internalField to non-constraint patches
+      </Documentation>
+    </IntVectorProperty>
+
+    <!-- Use VTK Polyhedron check-box -->
+    <IntVectorProperty
+      name="UseVTKPolyhedron"
+      command="SetUseVTKPolyhedron"
+      number_of_elements="1"
+      default_values="0"
+      animateable="0">
+      <BooleanDomain name="bool"/>
+      <Documentation>
+        Use vtkPolyhedron instead of decomposing polyhedra.
+      </Documentation>
+    </IntVectorProperty>
+
+    <!-- Include Sets check-box -->
+    <IntVectorProperty
+      name="UiIncludeSets"
+      command="SetIncludeSets"
+      number_of_elements="1"
+      is_internal="1"
+      default_values="0"
+      animateable="0">
+      <Documentation>
+        Search the polyMesh/sets/ directory
+      </Documentation>
+      <BooleanDomain name="bool"/>
+    </IntVectorProperty>
+
+    <!-- Include Zones check-box -->
+    <IntVectorProperty
+      name="UiIncludeZones"
+      command="SetIncludeZones"
+      number_of_elements="1"
+      is_internal="1"
+      default_values="0"
+      animateable="0">
+      <Documentation>
+        ZoneMesh information is used to find {cell,face,point}Zones.
+        The polyMesh/ directory is only checked on startup.
+      </Documentation>
+      <BooleanDomain name="bool"/>
+    </IntVectorProperty>
+
+    <!-- Show Patch Names check-box -->
+    <IntVectorProperty
+      name="UiShowPatchNames"
+      command="SetShowPatchNames"
+      number_of_elements="1"
+      default_values="0"
+      is_internal="1"
+      animateable="0">
+      <BooleanDomain name="bool"/>
+      <Documentation>
+        Show patch names in render window
+      </Documentation>
+    </IntVectorProperty>
+
+    <!-- Show Groups Only check-box -->
+    <IntVectorProperty
+      name="UiShowGroupsOnly"
+      command="SetShowGroupsOnly"
+      number_of_elements="1"
+      default_values="0"
+      is_internal="1"
+      animateable="0">
+      <BooleanDomain name="bool"/>
+      <Documentation>
+        Show groups only
+      </Documentation>
+    </IntVectorProperty>
+
+    <!-- Force GUI update check box -->
+    <IntVectorProperty
+      name="UpdateGUI"
+      command="SetUpdateGUI"
+      number_of_elements="1"
+      default_values="0"
+      animateable="0">
+      <BooleanDomain name="bool"/>
+      <Documentation>
+        A simple way to cause a reader GUI modification.
+      </Documentation>
+    </IntVectorProperty>
+
+    <!--
+       | Selections
+       -->
+
+    <!-- Available Parts (volume, patches, lagrangian) array -->
+    <StringVectorProperty
+      name="PartArrayStatus"
+      information_only="1">
+      <ArraySelectionInformationHelper attribute_name="Part"/>
+    </StringVectorProperty>
+    <StringVectorProperty
+      name="PartStatus"
+      label="Mesh Parts"
+      command="SetPartArrayStatus"
+      number_of_elements="0"
+      repeat_command="1"
+      number_of_elements_per_command="2"
+      element_types="2 0"
+      information_property="PartArrayStatus"
+      animateable="0">
+      <ArraySelectionDomain name="array_list">
+        <RequiredProperties>
+          <Property name="PartArrayStatus" function="ArrayList"/>
+        </RequiredProperties>
+      </ArraySelectionDomain>
+      <Documentation>
+        This property contains a list of the mesh parts
+        (patches, groups, sets, zones).
+      </Documentation>
+    </StringVectorProperty>
+
+    <!-- Available volFields array -->
+    <StringVectorProperty
+      name="VolFieldArrayStatus"
+      information_only="1">
+      <ArraySelectionInformationHelper attribute_name="VolField"/>
+    </StringVectorProperty>
+    <StringVectorProperty
+      name="VolFieldStatus"
+      label="Volume Fields"
+      command="SetVolFieldArrayStatus"
+      number_of_elements="0"
+      repeat_command="1"
+      number_of_elements_per_command="2"
+      element_types="2 0"
+      information_property="VolFieldArrayStatus"
+      animateable="0">
+      <ArraySelectionDomain name="array_list">
+        <RequiredProperties>
+          <Property name="VolFieldArrayStatus" function="ArrayList"/>
+        </RequiredProperties>
+      </ArraySelectionDomain>
+      <Documentation>
+        This property contains a list of the volume fields
+      </Documentation>
+    </StringVectorProperty>
+
+    <!-- Available Lagrangian fields array -->
+    <StringVectorProperty
+      name="LagrangianFieldArrayStatus"
+      information_only="1">
+      <ArraySelectionInformationHelper attribute_name="LagrangianField"/>
+    </StringVectorProperty>
+    <StringVectorProperty
+      name="LagrangianFieldStatus"
+      label="Lagrangian Fields"
+      command="SetLagrangianFieldArrayStatus"
+      number_of_elements="0"
+      repeat_command="1"
+      number_of_elements_per_command="2"
+      element_types="2 0"
+      information_property="LagrangianFieldArrayStatus"
+      animateable="0">
+      <ArraySelectionDomain name="array_list">
+        <RequiredProperties>
+          <Property name="LagrangianFieldArrayStatus" function="ArrayList"/>
+        </RequiredProperties>
+      </ArraySelectionDomain>
+      <Documentation>
+        This property contains a list of the lagrangian fields
+      </Documentation>
+    </StringVectorProperty>
+
+    <!-- Available pointFields array -->
+    <StringVectorProperty
+      name="PointFieldArrayStatus"
+      information_only="1">
+      <ArraySelectionInformationHelper attribute_name="PointField"/>
+    </StringVectorProperty>
+    <StringVectorProperty
+      name="PointFieldStatus"
+      label="Point Fields"
+      command="SetPointFieldArrayStatus"
+      number_of_elements="0"
+      repeat_command="1"
+      number_of_elements_per_command="2"
+      element_types="2 0"
+      information_property="PointFieldArrayStatus"
+      animateable="0">
+      <ArraySelectionDomain name="array_list">
+        <RequiredProperties>
+          <Property name="PointFieldArrayStatus" function="ArrayList"/>
+        </RequiredProperties>
+      </ArraySelectionDomain>
+      <Documentation>
+        This property contains a list of the point fields
+      </Documentation>
+    </StringVectorProperty>
+
+  <Hints>
+    <Property name="FileName" show="0"/>
+    <Property name="UiCacheMesh" show="0"/>
+    <Property name="UiZeroTime" show="0"/>
+    <Property name="UiRefresh" show="0"/>
+    <Property name="UiShowPatchNames" show="0"/>
+    <Property name="UiShowGroupsOnly" show="0"/>
+    <Property name="UiIncludeSets" show="0"/>
+    <Property name="UiIncludeZones" show="0"/>
+  </Hints>
+
+
+  </SourceProxy>
+  </ProxyGroup>
+</ServerManagerConfiguration>
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/PV398FoamReader/pqPV398FoamReaderPanel.cxx b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/PV398FoamReader/pqPV398FoamReaderPanel.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..758360192a00301c7c6e79bf5928553dc0e810cd
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/PV398FoamReader/pqPV398FoamReaderPanel.cxx
@@ -0,0 +1,468 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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 "pqPV398FoamReaderPanel.h"
+
+// QT
+#include <QGridLayout>
+#include <QCheckBox>
+#include <QLabel>
+#include <QLayout>
+#include <QString>
+#include <QPushButton>
+#include <QtDebug>
+
+// Paraview <-> QT UI
+#include "pqAnimationScene.h"
+#include "pqApplicationCore.h"
+#include "pqPipelineRepresentation.h"
+#include "pqServerManagerModel.h"
+#include "pqView.h"
+
+// Paraview Server Manager
+#include "vtkSMDoubleVectorProperty.h"
+#include "vtkSMIntVectorProperty.h"
+#include "vtkSMProperty.h"
+#include "vtkSMSourceProxy.h"
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+pqPV398FoamReaderPanel::pqPV398FoamReaderPanel
+(
+    pqProxy *proxy,
+    QWidget *p
+)
+:
+    pqAutoGeneratedObjectPanel(proxy, p)
+{
+    // create first sublayout (at top of the panel)
+    QGridLayout* form = new QGridLayout();
+    this->PanelLayout->addLayout(form, 0, 0, 1, -1);
+
+    // ROW 0
+    // ~~~~~
+
+    vtkSMProperty* prop = 0;
+
+    // refresh button for updating times/fields
+    if ((prop = this->proxy()->GetProperty("UiRefresh")) != 0)
+    {
+        prop->SetImmediateUpdate(1);
+        QPushButton *refresh = new QPushButton("Refresh Times");
+        refresh->setToolTip("Rescan for updated times/fields.");
+
+        form->addWidget(refresh, 0, 0, Qt::AlignLeft);
+        QObject::connect
+        (
+            refresh,
+            SIGNAL(clicked()),
+            this,
+            SLOT(RefreshPressed())
+        );
+    }
+
+    // checkbox for skip zeroTime
+    if ((prop = this->proxy()->GetProperty("UiZeroTime")) != 0)
+    {
+        // immediate update on the Server Manager side
+        prop->SetImmediateUpdate(true);
+
+        ZeroTime_ = new QCheckBox("Skip Zero Time");
+        ZeroTime_->setChecked
+        (
+            vtkSMIntVectorProperty::SafeDownCast(prop)->GetElement(0)
+        );
+        ZeroTime_->setToolTip
+        (
+            "Skip including the 0/ time directory."
+        );
+
+        form->addWidget(ZeroTime_, 0, 1, Qt::AlignLeft);
+        connect
+        (
+            ZeroTime_,
+            SIGNAL(stateChanged(int)),
+            this,
+            SLOT(ZeroTimeToggled())
+        );
+    }
+
+    // ROW 1
+    // ~~~~~
+
+    QFrame* hline1 = new QFrame(this);
+    hline1->setFrameStyle(QFrame::HLine | QFrame::Sunken);
+    form->addWidget(hline1, 1, 0, 1, 3);
+
+    // ROW 2
+    // ~~~~~
+
+    // checkbox for caching mesh
+    if ((prop = this->proxy()->GetProperty("UiCacheMesh")) != 0)
+    {
+        // immediate update on the Server Manager side
+        prop->SetImmediateUpdate(true);
+
+        CacheMesh_ = new QCheckBox("Cache Mesh");
+        CacheMesh_->setChecked
+        (
+            vtkSMIntVectorProperty::SafeDownCast(prop)->GetElement(0)
+        );
+        CacheMesh_->setToolTip
+        (
+            "Cache the fvMesh in memory."
+        );
+
+        form->addWidget(CacheMesh_, 2, 0, Qt::AlignLeft);
+        connect
+        (
+            CacheMesh_,
+            SIGNAL(stateChanged(int)),
+            this,
+            SLOT(CacheMeshToggled())
+        );
+    }
+
+    // cell 2,1 empty
+
+    // ROW 3
+    // ~~~~~
+
+    // checkbox for include sets
+    if ((prop = this->proxy()->GetProperty("UiIncludeSets")) != 0)
+    {
+        // immediate update on the Server Manager side
+        prop->SetImmediateUpdate(true);
+
+        IncludeSets_ = new QCheckBox("Include Sets");
+        IncludeSets_->setChecked
+        (
+            vtkSMIntVectorProperty::SafeDownCast(prop)->GetElement(0)
+        );
+        IncludeSets_->setToolTip
+        (
+            "Search the polyMesh/sets/ directory."
+        );
+
+        // row/col 1,0
+        form->addWidget(IncludeSets_, 3, 0, Qt::AlignLeft);
+        connect
+        (
+            IncludeSets_,
+            SIGNAL(stateChanged(int)),
+            this,
+            SLOT(IncludeSetsToggled())
+        );
+    }
+
+    // checkbox for Groups Only
+    if ((prop = this->proxy()->GetProperty("UiShowGroupsOnly")) != 0)
+    {
+        // immediate update on the Server Manager side
+        prop->SetImmediateUpdate(true);
+
+        ShowGroupsOnly_ = new QCheckBox("Groups Only");
+        ShowGroupsOnly_->setChecked
+        (
+            vtkSMIntVectorProperty::SafeDownCast(prop)->GetElement(0)
+        );
+        ShowGroupsOnly_->setToolTip
+        (
+            "Show patchGroups only."
+        );
+
+        // row/col 2, 2
+        form->addWidget(ShowGroupsOnly_, 3, 1, Qt::AlignLeft);
+        connect
+        (
+            ShowGroupsOnly_,
+            SIGNAL(stateChanged(int)),
+            this,
+            SLOT(ShowGroupsOnlyToggled())
+        );
+    }
+
+
+    // ROW 4
+    // ~~~~~
+
+    // checkbox for include zones
+    if ((prop = this->proxy()->GetProperty("UiIncludeZones")) != 0)
+    {
+        // immediate update on the Server Manager side
+        prop->SetImmediateUpdate(true);
+
+        IncludeZones_ = new QCheckBox("Include Zones");
+        IncludeZones_->setChecked
+        (
+            vtkSMIntVectorProperty::SafeDownCast(prop)->GetElement(0)
+        );
+        IncludeZones_->setToolTip
+        (
+            "ZoneMesh information is used to find {cell,face,point}Zones. "
+            "The polyMesh/ directory is only checked on startup."
+        );
+
+        // row/col 1,1
+        form->addWidget(IncludeZones_, 4, 0, Qt::AlignLeft);
+        connect
+        (
+            IncludeZones_,
+            SIGNAL(stateChanged(int)),
+            this,
+            SLOT(IncludeZonesToggled())
+        );
+    }
+
+    // checkbox for patch names
+    if ((prop = this->proxy()->GetProperty("UiShowPatchNames")) != 0)
+    {
+        // immediate update on the Server Manager side
+        prop->SetImmediateUpdate(true);
+
+        ShowPatchNames_ = new QCheckBox("Patch Names");
+        ShowPatchNames_->setChecked
+        (
+            vtkSMIntVectorProperty::SafeDownCast(prop)->GetElement(0)
+        );
+        ShowPatchNames_->setToolTip
+        (
+            "Show patch names in render window."
+        );
+
+        // row/col 0,1
+        form->addWidget(ShowPatchNames_, 4, 1, Qt::AlignLeft);
+        connect
+        (
+            ShowPatchNames_,
+            SIGNAL(stateChanged(int)),
+            this,
+            SLOT(ShowPatchNamesToggled())
+        );
+    }
+
+    // ROW 5
+    // ~~~~~
+
+    QFrame* hline2 = new QFrame(this);
+    hline2->setFrameStyle(QFrame::HLine | QFrame::Sunken);
+    form->addWidget(hline2, 5, 0, 1, 3);
+
+    // ROW 6
+    // ~~~~~
+
+    // checkbox for vol field interpolation
+    if ((prop = this->proxy()->GetProperty("UiInterpolateVolFields")) != 0)
+    {
+        // immediate update on the Server Manager side
+        prop->SetImmediateUpdate(true);
+
+        InterpolateVolFields_ = new QCheckBox("Interpolate volFields");
+        InterpolateVolFields_->setChecked
+        (
+            vtkSMIntVectorProperty::SafeDownCast(prop)->GetElement(0)
+        );
+        InterpolateVolFields_->setToolTip
+        (
+            "Interpolate volFields into pointFields"
+        );
+
+        // row/col 1,1
+        form->addWidget(InterpolateVolFields_, 6, 0, Qt::AlignLeft);
+        connect
+        (
+            InterpolateVolFields_,
+            SIGNAL(stateChanged(int)),
+            this,
+            SLOT(InterpolateVolFieldsToggled())
+        );
+    }
+
+    // checkbox for extrapolate patches
+    if ((prop = this->proxy()->GetProperty("UiExtrapolatePatches")) != 0)
+    {
+        // immediate update on the Server Manager side
+        prop->SetImmediateUpdate(true);
+
+        ExtrapolatePatches_ = new QCheckBox("Extrapolate Patches");
+        ExtrapolatePatches_->setChecked
+        (
+            vtkSMIntVectorProperty::SafeDownCast(prop)->GetElement(0)
+        );
+        ExtrapolatePatches_->setToolTip
+        (
+            "Extrapolate internalField to non-constraint patches"
+        );
+
+        // row/col 1,1
+        form->addWidget(ExtrapolatePatches_, 6, 1, Qt::AlignLeft);
+        connect
+        (
+            ExtrapolatePatches_,
+            SIGNAL(stateChanged(int)),
+            this,
+            SLOT(ExtrapolatePatchesToggled())
+        );
+    }
+
+    // ROW 7
+    // ~~~~~
+
+    QFrame* hline3 = new QFrame(this);
+    hline3->setFrameStyle(QFrame::HLine | QFrame::Sunken);
+    form->addWidget(hline3, 7, 0, 1, 3);
+}
+
+
+// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
+
+void pqPV398FoamReaderPanel::CacheMeshToggled()
+{
+    vtkSMIntVectorProperty::SafeDownCast
+    (
+        this->proxy()->GetProperty("UiCacheMesh")
+    )->SetElement(0, CacheMesh_->isChecked());
+}
+
+
+void pqPV398FoamReaderPanel::RefreshPressed()
+{
+    // update everything
+    vtkSMIntVectorProperty::SafeDownCast
+    (
+        this->proxy()->GetProperty("UiRefresh")
+    )->Modified();
+
+    vtkSMSourceProxy::SafeDownCast(this->proxy())->UpdatePipeline();
+
+    // render all views
+    pqApplicationCore::instance()->render();
+}
+
+
+void pqPV398FoamReaderPanel::ZeroTimeToggled()
+{
+    vtkSMIntVectorProperty::SafeDownCast
+    (
+        this->proxy()->GetProperty("UiZeroTime")
+    )->SetElement(0, ZeroTime_->isChecked());
+
+    this->setModified();
+}
+
+
+void pqPV398FoamReaderPanel::ShowPatchNamesToggled()
+{
+    vtkSMIntVectorProperty::SafeDownCast
+    (
+        this->proxy()->GetProperty("UiShowPatchNames")
+    )->SetElement(0, ShowPatchNames_->isChecked());
+
+    // update the active view
+    if (this->view())
+    {
+        this->view()->render();
+    }
+    // OR: update all views
+    // pqApplicationCore::instance()->render();
+}
+
+
+void pqPV398FoamReaderPanel::ShowGroupsOnlyToggled()
+{
+    vtkSMProperty* prop;
+
+    vtkSMIntVectorProperty::SafeDownCast
+    (
+        this->proxy()->GetProperty("UiShowGroupsOnly")
+    )->SetElement(0, ShowGroupsOnly_->isChecked());
+
+    if ((prop = this->proxy()->GetProperty("PartArrayStatus")) != 0)
+    {
+        this->proxy()->UpdatePropertyInformation(prop);
+    }
+}
+
+
+void pqPV398FoamReaderPanel::IncludeSetsToggled()
+{
+    vtkSMProperty* prop;
+
+    vtkSMIntVectorProperty::SafeDownCast
+    (
+        this->proxy()->GetProperty("UiIncludeSets")
+    )->SetElement(0, IncludeSets_->isChecked());
+
+    if ((prop = this->proxy()->GetProperty("PartArrayStatus")) != 0)
+    {
+        this->proxy()->UpdatePropertyInformation(prop);
+    }
+}
+
+
+void pqPV398FoamReaderPanel::IncludeZonesToggled()
+{
+    vtkSMProperty* prop;
+
+    vtkSMIntVectorProperty::SafeDownCast
+    (
+        this->proxy()->GetProperty("UiIncludeZones")
+    )->SetElement(0, IncludeZones_->isChecked());
+
+    if ((prop = this->proxy()->GetProperty("PartArrayStatus")) != 0)
+    {
+        this->proxy()->UpdatePropertyInformation(prop);
+    }
+}
+
+
+void pqPV398FoamReaderPanel::ExtrapolatePatchesToggled()
+{
+    vtkSMProperty* prop;
+
+    vtkSMIntVectorProperty::SafeDownCast
+    (
+        this->proxy()->GetProperty("UiExtrapolatePatches")
+    )->SetElement(0, ExtrapolatePatches_->isChecked());
+
+    this->setModified();
+}
+
+
+void pqPV398FoamReaderPanel::InterpolateVolFieldsToggled()
+{
+    vtkSMProperty* prop;
+
+    vtkSMIntVectorProperty::SafeDownCast
+    (
+        this->proxy()->GetProperty("UiInterpolateVolFields")
+    )->SetElement(0, InterpolateVolFields_->isChecked());
+
+    this->setModified();
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/PV398FoamReader/pqPV398FoamReaderPanel.h b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/PV398FoamReader/pqPV398FoamReaderPanel.h
new file mode 100644
index 0000000000000000000000000000000000000000..17c1b88893ca94974022884297ddbc61fbf94262
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/PV398FoamReader/pqPV398FoamReaderPanel.h
@@ -0,0 +1,120 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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
+    pqPV398FoamReaderPanel
+
+Description
+    GUI modifications for the ParaView reader panel
+
+    A custom panel for the PV398FoamReader.
+
+SourceFiles
+    pqPV398FoamReaderPanel.cxx
+
+\*---------------------------------------------------------------------------*/
+#ifndef pqPV398FoamReaderPanel_h
+#define pqPV398FoamReaderPanel_h
+
+
+#include "pqAutoGeneratedObjectPanel.h"
+
+// Forward declaration of QT classes
+
+class QCheckBox;
+class QLineEdit;
+class QTimer;
+class QToolButton;
+
+// Forward declaration of ParaView classes
+class vtkSMSourceProxy;
+
+
+/*---------------------------------------------------------------------------*\
+                  Class pqPV398FoamReaderPanel Declaration
+\*---------------------------------------------------------------------------*/
+
+class pqPV398FoamReaderPanel
+:
+    public pqAutoGeneratedObjectPanel
+{
+    // Private data
+    Q_OBJECT;
+    typedef pqAutoGeneratedObjectPanel Superclass;
+
+    //- ZeroTime checkbox
+    QCheckBox* ZeroTime_;
+
+    //- CacheMesh checkbox
+    QCheckBox* CacheMesh_;
+
+    //- Show Patch Names checkbox
+    QCheckBox* ShowPatchNames_;
+
+    //- Show Groups Only checkbox
+    QCheckBox* ShowGroupsOnly_;
+
+    //- IncludeSets checkbox
+    QCheckBox* IncludeSets_;
+
+    //- IncludeZones checkbox
+    QCheckBox* IncludeZones_;
+
+    //- InterpolateVolFields checkbox
+    QCheckBox* InterpolateVolFields_;
+
+    //- ExtrapolatePatches checkbox
+    QCheckBox* ExtrapolatePatches_;
+
+
+protected slots:
+
+    void CacheMeshToggled();
+    void ZeroTimeToggled();
+    void RefreshPressed();
+    void ShowPatchNamesToggled();
+    void ShowGroupsOnlyToggled();
+    void IncludeSetsToggled();
+    void IncludeZonesToggled();
+    void InterpolateVolFieldsToggled();
+    void ExtrapolatePatchesToggled();
+
+
+public:
+
+    // Constructors
+
+        //- Construct from components
+        pqPV398FoamReaderPanel(pqProxy*, QWidget*);
+
+
+    //- Destructor
+    // virtual ~pqPV398FoamReaderPanel();
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/PV398FoamReader/vtkPV398FoamReader.cxx b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/PV398FoamReader/vtkPV398FoamReader.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..435e5d51275c371745ed610e4aebb822a6d92124
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/PV398FoamReader/vtkPV398FoamReader.cxx
@@ -0,0 +1,752 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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 "vtkPV398FoamReader.h"
+
+#include "pqApplicationCore.h"
+#include "pqRenderView.h"
+#include "pqServerManagerModel.h"
+
+// VTK includes
+#include "vtkCallbackCommand.h"
+#include "vtkDataArraySelection.h"
+#include "vtkInformation.h"
+#include "vtkInformationVector.h"
+#include "vtkMultiBlockDataSet.h"
+#include "vtkObjectFactory.h"
+#include "vtkSMRenderViewProxy.h"
+#include "vtkStreamingDemandDrivenPipeline.h"
+#include "vtkStringArray.h"
+
+// OpenFOAM includes
+#include "vtkPV398Foam.H"
+
+#undef EXPERIMENTAL_TIME_CACHING
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+vtkStandardNewMacro(vtkPV398FoamReader);
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+vtkPV398FoamReader::vtkPV398FoamReader()
+{
+    Debug = 0;
+    vtkDebugMacro(<<"Constructor");
+
+    SetNumberOfInputPorts(0);
+
+    FileName  = NULL;
+    foamData_ = NULL;
+
+    output0_  = NULL;
+
+#ifdef VTKPV398FOAM_DUALPORT
+    // Add second output for the Lagrangian
+    this->SetNumberOfOutputPorts(2);
+    vtkMultiBlockDataSet *lagrangian = vtkMultiBlockDataSet::New();
+    lagrangian->ReleaseData();
+
+    this->GetExecutive()->SetOutputData(1, lagrangian);
+    lagrangian->Delete();
+#endif
+
+    TimeStepRange[0] = 0;
+    TimeStepRange[1] = 0;
+
+    CacheMesh = 1;
+    Refresh = 0;
+
+    SkipZeroTime = 0;
+    ExtrapolatePatches = 0;
+    UseVTKPolyhedron = 0;
+    IncludeSets = 0;
+    IncludeZones = 0;
+    ShowPatchNames = 0;
+    ShowGroupsOnly = 0;
+    InterpolateVolFields = 1;
+
+    UpdateGUI = 0;
+
+    PartSelection = vtkDataArraySelection::New();
+    VolFieldSelection = vtkDataArraySelection::New();
+    PointFieldSelection = vtkDataArraySelection::New();
+    LagrangianFieldSelection = vtkDataArraySelection::New();
+
+    // Setup the selection callback to modify this object when an array
+    // selection is changed.
+    SelectionObserver = vtkCallbackCommand::New();
+    SelectionObserver->SetCallback
+    (
+        &vtkPV398FoamReader::SelectionModifiedCallback
+    );
+    SelectionObserver->SetClientData(this);
+
+    PartSelection->AddObserver
+    (
+        vtkCommand::ModifiedEvent,
+        this->SelectionObserver
+    );
+    VolFieldSelection->AddObserver
+    (
+        vtkCommand::ModifiedEvent,
+        this->SelectionObserver
+    );
+    PointFieldSelection->AddObserver
+    (
+        vtkCommand::ModifiedEvent,
+        this->SelectionObserver
+    );
+    LagrangianFieldSelection->AddObserver
+    (
+        vtkCommand::ModifiedEvent,
+        this->SelectionObserver
+    );
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+vtkPV398FoamReader::~vtkPV398FoamReader()
+{
+    vtkDebugMacro(<<"Deconstructor");
+
+    if (foamData_)
+    {
+        // remove patch names
+        updatePatchNamesView(false);
+        delete foamData_;
+    }
+
+    if (FileName)
+    {
+        delete [] FileName;
+    }
+
+    if (output0_)
+    {
+        output0_->Delete();
+    }
+
+
+    PartSelection->RemoveObserver(this->SelectionObserver);
+    VolFieldSelection->RemoveObserver(this->SelectionObserver);
+    PointFieldSelection->RemoveObserver(this->SelectionObserver);
+    LagrangianFieldSelection->RemoveObserver(this->SelectionObserver);
+
+    SelectionObserver->Delete();
+
+    PartSelection->Delete();
+    VolFieldSelection->Delete();
+    PointFieldSelection->Delete();
+    LagrangianFieldSelection->Delete();
+}
+
+
+// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
+
+// Do everything except set the output info
+int vtkPV398FoamReader::RequestInformation
+(
+    vtkInformation* vtkNotUsed(request),
+    vtkInformationVector** vtkNotUsed(inputVector),
+    vtkInformationVector* outputVector
+)
+{
+    vtkDebugMacro(<<"RequestInformation");
+
+    if (Foam::vtkPV398Foam::debug)
+    {
+        cout<<"REQUEST_INFORMATION\n";
+    }
+
+    if (!FileName)
+    {
+        vtkErrorMacro("FileName has to be specified!");
+        return 0;
+    }
+
+    int nInfo = outputVector->GetNumberOfInformationObjects();
+
+    if (Foam::vtkPV398Foam::debug)
+    {
+        cout<<"RequestInformation with " << nInfo << " item(s)\n";
+        for (int infoI = 0; infoI < nInfo; ++infoI)
+        {
+            outputVector->GetInformationObject(infoI)->Print(cout);
+        }
+    }
+
+    if (!foamData_)
+    {
+        foamData_ = new Foam::vtkPV398Foam(FileName, this);
+    }
+    else
+    {
+        foamData_->updateInfo();
+    }
+
+    int nTimeSteps = 0;
+    double* timeSteps = foamData_->findTimes(nTimeSteps);
+
+    if (!nTimeSteps)
+    {
+        vtkErrorMacro("could not find valid OpenFOAM mesh");
+
+        // delete foamData and flag it as fatal error
+        delete foamData_;
+        foamData_ = NULL;
+        return 0;
+    }
+
+    // set identical time steps for all ports
+    for (int infoI = 0; infoI < nInfo; ++infoI)
+    {
+        outputVector->GetInformationObject(infoI)->Set
+        (
+            vtkStreamingDemandDrivenPipeline::TIME_STEPS(),
+            timeSteps,
+            nTimeSteps
+        );
+    }
+
+    if (nTimeSteps)
+    {
+        double timeRange[2];
+        timeRange[0] = timeSteps[0];
+        timeRange[1] = timeSteps[nTimeSteps-1];
+
+        if (Foam::vtkPV398Foam::debug > 1)
+        {
+            cout<<"nTimeSteps " << nTimeSteps << "\n"
+                <<"timeRange " << timeRange[0] << " to " << timeRange[1]
+                << "\n";
+
+            for (int timeI = 0; timeI < nTimeSteps; ++timeI)
+            {
+                cout<< "step[" << timeI << "] = " << timeSteps[timeI] << "\n";
+            }
+        }
+
+        for (int infoI = 0; infoI < nInfo; ++infoI)
+        {
+            outputVector->GetInformationObject(infoI)->Set
+            (
+                vtkStreamingDemandDrivenPipeline::TIME_RANGE(),
+                timeRange,
+                2
+            );
+        }
+    }
+
+    delete timeSteps;
+
+    return 1;
+}
+
+
+// Set the output info
+int vtkPV398FoamReader::RequestData
+(
+    vtkInformation* vtkNotUsed(request),
+    vtkInformationVector** vtkNotUsed(inputVector),
+    vtkInformationVector* outputVector
+)
+{
+    vtkDebugMacro(<<"RequestData");
+
+    if (!FileName)
+    {
+        vtkErrorMacro("FileName has to be specified!");
+        return 0;
+    }
+
+    // catch previous error
+    if (!foamData_)
+    {
+        vtkErrorMacro("Reader failed - perhaps no mesh?");
+        return 0;
+    }
+
+    int nInfo = outputVector->GetNumberOfInformationObjects();
+
+    if (Foam::vtkPV398Foam::debug)
+    {
+        cout<<"RequestData with " << nInfo << " item(s)\n";
+        for (int infoI = 0; infoI < nInfo; ++infoI)
+        {
+            outputVector->GetInformationObject(infoI)->Print(cout);
+        }
+    }
+
+    // Get the requested time step.
+    // We only support requests for a single time step
+
+    int nRequestTime = 0;
+    double requestTime[nInfo];
+
+    // taking port0 as the lead for other outputs would be nice, but fails when
+    // a filter is added - we need to check everything
+    // but since PREVIOUS_UPDATE_TIME_STEPS() is protected, relay the logic
+    // to the vtkPV398Foam::setTime() method
+    for (int infoI = 0; infoI < nInfo; ++infoI)
+    {
+        vtkInformation *outInfo = outputVector->GetInformationObject(infoI);
+
+        if
+        (
+            outInfo->Has(vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP())
+         && outInfo->Length(vtkStreamingDemandDrivenPipeline::TIME_STEPS()) > 0
+        )
+        {
+            requestTime[nRequestTime++] =
+                outInfo->Get
+                (
+                    vtkStreamingDemandDrivenPipeline::UPDATE_TIME_STEP()
+                );
+        }
+    }
+
+    if (nRequestTime)
+    {
+        foamData_->setTime(nRequestTime, requestTime);
+    }
+
+    vtkMultiBlockDataSet* output = vtkMultiBlockDataSet::SafeDownCast
+    (
+        outputVector->GetInformationObject(0)->Get
+        (
+            vtkMultiBlockDataSet::DATA_OBJECT()
+        )
+    );
+
+    if (Foam::vtkPV398Foam::debug)
+    {
+        cout<< "update output with "
+            << output->GetNumberOfBlocks() << " blocks\n";
+    }
+
+
+#ifdef EXPERIMENTAL_TIME_CACHING
+    bool needsUpdate = false;
+
+    if (!output0_)
+    {
+        output0_ = vtkMultiBlockDataSet::New();
+        needsUpdate = true;
+    }
+
+    // This experimental bit of code seems to work for the geometry,
+    // but trashes the fields and still triggers the GeometryFilter
+    if (needsUpdate)
+    {
+        foamData_->Update(output);
+        output0_->ShallowCopy(output);
+    }
+    else
+    {
+        output->ShallowCopy(output0_);
+    }
+
+    if (Foam::vtkPV398Foam::debug)
+    {
+        if (needsUpdate)
+        {
+            cout<< "full UPDATE ---------\n";
+        }
+        else
+        {
+            cout<< "cached UPDATE ---------\n";
+        }
+
+        cout<< "UPDATED output: ";
+        output->Print(cout);
+
+        cout<< "UPDATED output0_: ";
+        output0_->Print(cout);
+    }
+
+#else
+
+#ifdef VTKPV398FOAM_DUALPORT
+    foamData_->Update
+    (
+        output,
+        vtkMultiBlockDataSet::SafeDownCast
+        (
+            outputVector->GetInformationObject(1)->Get
+            (
+                vtkMultiBlockDataSet::DATA_OBJECT()
+            )
+        );
+    );
+#else
+    foamData_->Update(output, output);
+#endif
+
+    updatePatchNamesView(ShowPatchNames);
+
+#endif
+
+    // Do any cleanup on the OpenFOAM side
+    foamData_->CleanUp();
+
+    return 1;
+}
+
+
+void vtkPV398FoamReader::SetRefresh(int val)
+{
+    Modified();
+}
+
+
+void vtkPV398FoamReader::SetIncludeSets(int val)
+{
+    if (IncludeSets != val)
+    {
+        IncludeSets = val;
+        if (foamData_)
+        {
+            foamData_->updateInfo();
+        }
+    }
+}
+
+
+void vtkPV398FoamReader::SetIncludeZones(int val)
+{
+    if (IncludeZones != val)
+    {
+        IncludeZones = val;
+        if (foamData_)
+        {
+            foamData_->updateInfo();
+        }
+    }
+}
+
+
+void vtkPV398FoamReader::SetShowPatchNames(int val)
+{
+    if (ShowPatchNames != val)
+    {
+        ShowPatchNames = val;
+        updatePatchNamesView(ShowPatchNames);
+    }
+}
+
+
+void vtkPV398FoamReader::SetShowGroupsOnly(int val)
+{
+    if (ShowGroupsOnly != val)
+    {
+        ShowGroupsOnly = val;
+        if (foamData_)
+        {
+            foamData_->updateInfo();
+        }
+    }
+}
+
+
+void vtkPV398FoamReader::updatePatchNamesView(const bool show)
+{
+    pqApplicationCore* appCore = pqApplicationCore::instance();
+
+    // need to check this, since our destructor calls this
+    if (!appCore)
+    {
+        return;
+    }
+
+    // Server manager model for querying items in the server manager
+    pqServerManagerModel* smModel = appCore->getServerManagerModel();
+
+    if (!smModel || !foamData_)
+    {
+        return;
+    }
+
+    // Get all the pqRenderView instances
+    QList<pqRenderView*> renderViews = smModel->findItems<pqRenderView*>();
+
+    for (int viewI=0; viewI < renderViews.size(); ++viewI)
+    {
+        foamData_->renderPatchNames
+        (
+            renderViews[viewI]->getRenderViewProxy()->GetRenderer(),
+            show
+        );
+    }
+
+    // use refresh here?
+}
+
+
+void vtkPV398FoamReader::PrintSelf(ostream& os, vtkIndent indent)
+{
+    vtkDebugMacro(<<"PrintSelf");
+
+    this->Superclass::PrintSelf(os,indent);
+    os  << indent << "File name: "
+        << (this->FileName ? this->FileName : "(none)") << "\n";
+
+    foamData_->PrintSelf(os, indent);
+
+    os  << indent << "Time step range: "
+        << this->TimeStepRange[0] << " - " << this->TimeStepRange[1] << "\n"
+        << indent << "Time step: " << this->GetTimeStep() << endl;
+}
+
+
+int vtkPV398FoamReader::GetTimeStep()
+{
+    return foamData_ ? foamData_->timeIndex() : -1;
+}
+
+
+// ----------------------------------------------------------------------
+// Parts selection list control
+
+vtkDataArraySelection* vtkPV398FoamReader::GetPartSelection()
+{
+    vtkDebugMacro(<<"GetPartSelection");
+    return PartSelection;
+}
+
+
+int vtkPV398FoamReader::GetNumberOfPartArrays()
+{
+    vtkDebugMacro(<<"GetNumberOfPartArrays");
+    return PartSelection->GetNumberOfArrays();
+}
+
+
+const char* vtkPV398FoamReader::GetPartArrayName(int index)
+{
+    vtkDebugMacro(<<"GetPartArrayName");
+    return PartSelection->GetArrayName(index);
+}
+
+
+int vtkPV398FoamReader::GetPartArrayStatus(const char* name)
+{
+    vtkDebugMacro(<<"GetPartArrayStatus");
+    return PartSelection->ArrayIsEnabled(name);
+}
+
+
+void vtkPV398FoamReader::SetPartArrayStatus(const char* name, int status)
+{
+    vtkDebugMacro("Set mesh part \"" << name << "\" status to: " << status);
+
+    if (status)
+    {
+        PartSelection->EnableArray(name);
+    }
+    else
+    {
+        PartSelection->DisableArray(name);
+    }
+}
+
+
+// ----------------------------------------------------------------------
+// volField selection list control
+
+vtkDataArraySelection* vtkPV398FoamReader::GetVolFieldSelection()
+{
+    vtkDebugMacro(<<"GetVolFieldSelection");
+    return VolFieldSelection;
+}
+
+
+int vtkPV398FoamReader::GetNumberOfVolFieldArrays()
+{
+    vtkDebugMacro(<<"GetNumberOfVolFieldArrays");
+    return VolFieldSelection->GetNumberOfArrays();
+}
+
+
+const char* vtkPV398FoamReader::GetVolFieldArrayName(int index)
+{
+    vtkDebugMacro(<<"GetVolFieldArrayName");
+    return VolFieldSelection->GetArrayName(index);
+}
+
+
+int vtkPV398FoamReader::GetVolFieldArrayStatus(const char* name)
+{
+    vtkDebugMacro(<<"GetVolFieldArrayStatus");
+    return VolFieldSelection->ArrayIsEnabled(name);
+}
+
+
+void vtkPV398FoamReader::SetVolFieldArrayStatus(const char* name, int status)
+{
+    vtkDebugMacro(<<"SetVolFieldArrayStatus");
+    if (status)
+    {
+        VolFieldSelection->EnableArray(name);
+    }
+    else
+    {
+        VolFieldSelection->DisableArray(name);
+    }
+}
+
+
+// ----------------------------------------------------------------------
+// pointField selection list control
+
+vtkDataArraySelection* vtkPV398FoamReader::GetPointFieldSelection()
+{
+    vtkDebugMacro(<<"GetPointFieldSelection");
+    return PointFieldSelection;
+}
+
+
+int vtkPV398FoamReader::GetNumberOfPointFieldArrays()
+{
+    vtkDebugMacro(<<"GetNumberOfPointFieldArrays");
+    return PointFieldSelection->GetNumberOfArrays();
+}
+
+
+const char* vtkPV398FoamReader::GetPointFieldArrayName(int index)
+{
+    vtkDebugMacro(<<"GetPointFieldArrayName");
+    return PointFieldSelection->GetArrayName(index);
+}
+
+
+int vtkPV398FoamReader::GetPointFieldArrayStatus(const char* name)
+{
+    vtkDebugMacro(<<"GetPointFieldArrayStatus");
+    return PointFieldSelection->ArrayIsEnabled(name);
+}
+
+
+void vtkPV398FoamReader::SetPointFieldArrayStatus(const char* name, int status)
+{
+    vtkDebugMacro(<<"SetPointFieldArrayStatus");
+    if (status)
+    {
+        PointFieldSelection->EnableArray(name);
+    }
+    else
+    {
+        PointFieldSelection->DisableArray(name);
+    }
+}
+
+
+// ----------------------------------------------------------------------
+// lagrangianField selection list control
+
+vtkDataArraySelection* vtkPV398FoamReader::GetLagrangianFieldSelection()
+{
+    vtkDebugMacro(<<"GetLagrangianFieldSelection");
+    return LagrangianFieldSelection;
+}
+
+
+int vtkPV398FoamReader::GetNumberOfLagrangianFieldArrays()
+{
+    vtkDebugMacro(<<"GetNumberOfLagrangianFieldArrays");
+    return LagrangianFieldSelection->GetNumberOfArrays();
+}
+
+
+const char* vtkPV398FoamReader::GetLagrangianFieldArrayName(int index)
+{
+    vtkDebugMacro(<<"GetLagrangianFieldArrayName");
+    return LagrangianFieldSelection->GetArrayName(index);
+}
+
+
+int vtkPV398FoamReader::GetLagrangianFieldArrayStatus(const char* name)
+{
+    vtkDebugMacro(<<"GetLagrangianFieldArrayStatus");
+    return LagrangianFieldSelection->ArrayIsEnabled(name);
+}
+
+
+void vtkPV398FoamReader::SetLagrangianFieldArrayStatus
+(
+    const char* name,
+    int status
+)
+{
+    vtkDebugMacro(<<"SetLagrangianFieldArrayStatus");
+    if (status)
+    {
+        LagrangianFieldSelection->EnableArray(name);
+    }
+    else
+    {
+        LagrangianFieldSelection->DisableArray(name);
+    }
+}
+
+
+// ----------------------------------------------------------------------
+
+void vtkPV398FoamReader::SelectionModifiedCallback
+(
+    vtkObject*,
+    unsigned long,
+    void* clientdata,
+    void*
+)
+{
+    static_cast<vtkPV398FoamReader*>(clientdata)->SelectionModified();
+}
+
+
+void vtkPV398FoamReader::SelectionModified()
+{
+    vtkDebugMacro(<<"SelectionModified");
+    Modified();
+}
+
+
+int vtkPV398FoamReader::FillOutputPortInformation
+(
+    int port,
+    vtkInformation* info
+)
+{
+    if (port == 0)
+    {
+        return this->Superclass::FillOutputPortInformation(port, info);
+    }
+    info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkMultiBlockDataSet");
+    return 1;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/PV398FoamReader/vtkPV398FoamReader.h b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/PV398FoamReader/vtkPV398FoamReader.h
new file mode 100644
index 0000000000000000000000000000000000000000..21415bc44083ffd6d01f5ea935ae0b190cfa6617
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/PV398FoamReader/vtkPV398FoamReader.h
@@ -0,0 +1,262 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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
+    vtkPV398FoamReader
+
+Description
+    reads a dataset in OpenFOAM format
+
+    vtkPV398blockMeshReader creates an multiblock dataset.
+    It uses the OpenFOAM infrastructure (fvMesh, etc) to handle mesh and
+    field data.
+
+SourceFiles
+    vtkPV398blockMeshReader.cxx
+
+\*---------------------------------------------------------------------------*/
+#ifndef vtkPV398FoamReader_h
+#define vtkPV398FoamReader_h
+
+// VTK includes
+#include "vtkMultiBlockDataSetAlgorithm.h"
+
+// * * * * * * * * * * * * * Forward Declarations  * * * * * * * * * * * * * //
+
+// VTK forward declarations
+class vtkDataArraySelection;
+class vtkCallbackCommand;
+
+// OpenFOAM forward declarations
+namespace Foam
+{
+    class vtkPV398Foam;
+}
+
+
+/*---------------------------------------------------------------------------*\
+                     Class vtkPV398FoamReader Declaration
+\*---------------------------------------------------------------------------*/
+
+class vtkPV398FoamReader
+:
+    public vtkMultiBlockDataSetAlgorithm
+{
+public:
+    vtkTypeMacro(vtkPV398FoamReader, vtkMultiBlockDataSetAlgorithm);
+    void PrintSelf(ostream&, vtkIndent);
+
+    static vtkPV398FoamReader* New();
+
+    // Description:
+    // Get the current timestep and the timestep range.
+    vtkGetVector2Macro(TimeStepRange, int);
+
+    // Description:
+    // Set/Get the filename.
+    vtkSetStringMacro(FileName);
+    vtkGetStringMacro(FileName);
+
+    // Description:
+    // OpenFOAM mesh caching control
+    vtkSetMacro(CacheMesh, int);
+    vtkGetMacro(CacheMesh, int);
+
+    // Description:
+    // OpenFOAM refresh times/fields
+    virtual void SetRefresh(int);
+
+    // Description:
+    // OpenFOAM skip/include the 0/ time directory
+    vtkSetMacro(SkipZeroTime, int);
+    vtkGetMacro(SkipZeroTime, int);
+
+    // Description:
+    // GUI update control
+    vtkSetMacro(UpdateGUI, int);
+    vtkGetMacro(UpdateGUI, int);
+
+    // Description:
+    // OpenFOAM extrapolate internal values onto the patches
+    vtkSetMacro(ExtrapolatePatches, int);
+    vtkGetMacro(ExtrapolatePatches, int);
+
+    // Description:
+    // OpenFOAM use vtkPolyhedron instead of decomposing polyhedra
+    vtkSetMacro(UseVTKPolyhedron, int);
+    vtkGetMacro(UseVTKPolyhedron, int);
+
+    // Description:
+    // OpenFOAM read sets control
+    virtual void SetIncludeSets(int);
+    vtkGetMacro(IncludeSets, int);
+
+    // Description:
+    // OpenFOAM read zones control
+    virtual void SetIncludeZones(int);
+    vtkGetMacro(IncludeZones, int);
+
+    // Description:
+    // OpenFOAM display patch names control
+    virtual void SetShowPatchNames(int);
+    vtkGetMacro(ShowPatchNames, int);
+
+    // Description:
+    // OpenFOAM display patchGroups
+    virtual void SetShowGroupsOnly(int);
+    vtkGetMacro(ShowGroupsOnly, int);
+
+    // Description:
+    // OpenFOAM volField interpolation
+    vtkSetMacro(InterpolateVolFields, int);
+    vtkGetMacro(InterpolateVolFields, int);
+
+    // Description:
+    // Get the current timestep
+    int  GetTimeStep();
+
+    // Description:
+    // Parts selection list control
+    virtual vtkDataArraySelection* GetPartSelection();
+    int  GetNumberOfPartArrays();
+    int  GetPartArrayStatus(const char* name);
+    void SetPartArrayStatus(const char* name, int status);
+    const char* GetPartArrayName(int index);
+
+    // Description:
+    // volField selection list control
+    virtual vtkDataArraySelection* GetVolFieldSelection();
+    int  GetNumberOfVolFieldArrays();
+    int  GetVolFieldArrayStatus(const char* name);
+    void SetVolFieldArrayStatus(const char* name, int status);
+    const char* GetVolFieldArrayName(int index);
+
+    // Description:
+    // pointField selection list control
+    virtual vtkDataArraySelection* GetPointFieldSelection();
+    int  GetNumberOfPointFieldArrays();
+    int  GetPointFieldArrayStatus(const char* name);
+    void SetPointFieldArrayStatus(const char* name, int status);
+    const char* GetPointFieldArrayName(int index);
+
+    // Description:
+    // lagrangianField selection list control
+    virtual vtkDataArraySelection* GetLagrangianFieldSelection();
+    int  GetNumberOfLagrangianFieldArrays();
+    int  GetLagrangianFieldArrayStatus(const char* name);
+    void SetLagrangianFieldArrayStatus(const char* name, int status);
+    const char* GetLagrangianFieldArrayName(int index);
+
+    // Description:
+    // Callback registered with the SelectionObserver
+    // for all the selection lists
+    static void SelectionModifiedCallback
+    (
+        vtkObject* caller,
+        unsigned long eid,
+        void* clientdata,
+        void* calldata
+    );
+
+    void SelectionModified();
+
+
+protected:
+
+    //- Construct null
+    vtkPV398FoamReader();
+
+    //- Destructor
+    ~vtkPV398FoamReader();
+
+    //- Return information about mesh, times, etc without loading anything
+    virtual int RequestInformation
+    (
+        vtkInformation*,
+        vtkInformationVector**,
+        vtkInformationVector*
+    );
+
+    //- Get the mesh/fields for a particular time
+    virtual int RequestData
+    (
+        vtkInformation*,
+        vtkInformationVector**,
+        vtkInformationVector*
+    );
+
+    //- Fill in additional port information
+    virtual int FillOutputPortInformation(int, vtkInformation*);
+
+    //- The observer to modify this object when array selections are modified
+    vtkCallbackCommand* SelectionObserver;
+
+    //- The file name for this case
+    char* FileName;
+
+
+private:
+
+    //- Disallow default bitwise copy construct
+    vtkPV398FoamReader(const vtkPV398FoamReader&);
+
+    //- Disallow default bitwise assignment
+    void operator=(const vtkPV398FoamReader&);
+
+    //- Add/remove patch names to/from the view
+    void updatePatchNamesView(const bool show);
+
+    int TimeStepRange[2];
+    int Refresh;
+    int CacheMesh;
+    int SkipZeroTime;
+
+    int ExtrapolatePatches;
+    int UseVTKPolyhedron;
+    int IncludeSets;
+    int IncludeZones;
+    int ShowPatchNames;
+    int ShowGroupsOnly;
+    int InterpolateVolFields;
+
+    //- Dummy variable/switch to invoke a reader update
+    int UpdateGUI;
+
+    vtkDataArraySelection* PartSelection;
+    vtkDataArraySelection* VolFieldSelection;
+    vtkDataArraySelection* PointFieldSelection;
+    vtkDataArraySelection* LagrangianFieldSelection;
+
+    //- Cached data for output port0 (experimental!)
+    vtkMultiBlockDataSet* output0_;
+
+    //BTX
+    Foam::vtkPV398Foam* foamData_;
+    //ETX
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/Make/files b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..df6c4a0d23ce65c0f7540248df8501e8634e038e
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/Make/files
@@ -0,0 +1,11 @@
+vtkPV398Foam.C
+vtkPV398FoamFields.C
+vtkPV398FoamMesh.C
+vtkPV398FoamMeshLagrangian.C
+vtkPV398FoamMeshSet.C
+vtkPV398FoamMeshVolume.C
+vtkPV398FoamMeshZone.C
+vtkPV398FoamUpdateInfo.C
+vtkPV398FoamUtils.C
+
+LIB = $(FOAM_LIBBIN)/libvtkPV398Foam
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/Make/options b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..3b0bb17b3b68a52690ef0765b0d3b8648ba1ab8b
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/Make/options
@@ -0,0 +1,21 @@
+/* Note: enable vtkPolyhedron when available */
+
+EXE_INC = \
+    -I$(LIB_SRC)/meshTools/lnInclude \
+    -I$(LIB_SRC)/finiteVolume/lnInclude \
+    -I$(LIB_SRC)/lagrangian/basic/lnInclude \
+    -I../../vtkPV398Readers/lnInclude \
+    -I../PV398FoamReader \
+    -I$(ParaView_INCLUDE_DIR) \
+    $(shell \
+        test -f $(ParaView_INCLUDE_DIR)/vtkPolyhedron.h && \
+        echo "-DHAS_VTK_POLYHEDRON" || echo "-UHAS_VTK_POLYHEDRON" \
+    )
+
+LIB_LIBS = \
+    -lmeshTools \
+    -lfiniteVolume \
+    -lgenericPatchFields \
+    -llagrangian \
+    -L$(FOAM_LIBBIN) -lvtkPV398Readers \
+    $(GLIBS)
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkDataArrayTemplateImplicit.txx b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkDataArrayTemplateImplicit.txx
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkOpenFOAMPoints.H b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkOpenFOAMPoints.H
new file mode 100644
index 0000000000000000000000000000000000000000..aa0391408e686635a30ef47644bb68f060b39950
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkOpenFOAMPoints.H
@@ -0,0 +1,79 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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/>.
+
+InClass
+    vtkPV398Foam
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef vtkOpenFOAMPoints_H
+#define vtkOpenFOAMPoints_H
+
+// VTK includes
+#include "vtkPoints.h"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+inline void vtkInsertNextOpenFOAMPoint
+(
+    vtkPoints *points,
+    const Foam::point& p
+)
+{
+    points->InsertNextPoint(p.x(), p.y(), p.z());
+}
+
+#if 0
+// this should be faster, but didn't get it working ...
+inline void vtkSetOpenFOAMPoint
+(
+    vtkPoints *points,
+    const Foam::label id,
+    const Foam::point& p
+)
+{
+    points->SetPoint(id, p.x(), p.y(), p.z());
+}
+
+
+// Convert OpenFOAM mesh vertices to VTK
+inline vtkPoints* vtkSetOpenFOAMPoints(const Foam::pointField& points)
+{
+    vtkPoints *vtkpoints = vtkPoints::New();
+    vtkpoints->SetNumberOfPoints(points.size());
+    forAll(points, i)
+    {
+        const Foam::point& p = points[i];
+        vtkpoints->SetPoint(i, p.x(), p.y(), p.z());
+    }
+
+    return vtkpoints;
+}
+
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkOpenFOAMTupleRemap.H b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkOpenFOAMTupleRemap.H
new file mode 100644
index 0000000000000000000000000000000000000000..f5057359e690fd9bcbd563accc6db0d5a3d8ec39
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkOpenFOAMTupleRemap.H
@@ -0,0 +1,71 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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/>.
+
+InClass
+    vtkPV398Foam
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef vtkOpenFOAMTupleRemap_H
+#define vtkOpenFOAMTupleRemap_H
+
+// OpenFOAM includes
+#include "StaticAssert.H"
+#include "Swap.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+template<class Type>
+inline void vtkOpenFOAMTupleRemap(float vec[]);
+
+
+// a symmTensor specialization to remap OpenFOAM -> ParaView naming order
+// Qt/Core/pqScalarBarRepresentation.cxx defines this order
+//     { "XX", "YY", "ZZ", "XY", "YZ", "XZ" }
+// in pqScalarBarRepresentation::getDefaultComponentLabel()
+// whereas OpenFOAM uses this order
+//     { XX, XY, XZ, YY, YZ, ZZ }
+//
+// for extra safety, assert that symmTensor indeed has 6 components
+StaticAssert(Foam::symmTensor::nComponents == 6);
+
+
+// Template specialization for symmTensor
+template<>
+inline void vtkOpenFOAMTupleRemap<Foam::symmTensor>(float vec[])
+{
+    Foam::Swap(vec[1], vec[3]);   // swap XY <-> YY
+    Foam::Swap(vec[2], vec[5]);   // swap XZ <-> ZZ
+}
+
+
+template<class Type>
+inline void vtkOpenFOAMTupleRemap(float vec[])
+{}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398Foam.C b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398Foam.C
new file mode 100644
index 0000000000000000000000000000000000000000..54848ccc263b16eaf0d2976ea86b128214b233a0
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398Foam.C
@@ -0,0 +1,837 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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 "vtkPV398Foam.H"
+#include "vtkPV398FoamReader.h"
+
+// OpenFOAM includes
+#include "fvMesh.H"
+#include "Time.H"
+#include "patchZones.H"
+
+// VTK includes
+#include "vtkDataArraySelection.h"
+#include "vtkMultiBlockDataSet.h"
+#include "vtkRenderer.h"
+#include "vtkTextActor.h"
+#include "vtkTextProperty.h"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+defineTypeNameAndDebug(vtkPV398Foam, 0);
+}
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+#include "vtkPV398FoamAddToSelection.H"
+#include "vtkPV398FoamUpdateInfoFields.H"
+
+void Foam::vtkPV398Foam::resetCounters()
+{
+    // Reset array range information (ids and sizes)
+    arrayRangeVolume_.reset();
+    arrayRangePatches_.reset();
+    arrayRangeLagrangian_.reset();
+    arrayRangeCellZones_.reset();
+    arrayRangeFaceZones_.reset();
+    arrayRangePointZones_.reset();
+    arrayRangeCellSets_.reset();
+    arrayRangeFaceSets_.reset();
+    arrayRangePointSets_.reset();
+}
+
+
+void Foam::vtkPV398Foam::reduceMemory()
+{
+    forAll(regionPolyDecomp_, i)
+    {
+        regionPolyDecomp_[i].clear();
+    }
+
+    forAll(zonePolyDecomp_, i)
+    {
+        zonePolyDecomp_[i].clear();
+    }
+
+    forAll(csetPolyDecomp_, i)
+    {
+        csetPolyDecomp_[i].clear();
+    }
+
+    if (!reader_->GetCacheMesh())
+    {
+        delete meshPtr_;
+        meshPtr_ = NULL;
+    }
+}
+
+
+int Foam::vtkPV398Foam::setTime(int nRequest, const double requestTimes[])
+{
+    Time& runTime = dbPtr_();
+
+    // Get times list
+    instantList Times = runTime.times();
+
+    int nearestIndex = timeIndex_;
+    for (int requestI = 0; requestI < nRequest; ++requestI)
+    {
+        int index = Time::findClosestTimeIndex(Times, requestTimes[requestI]);
+        if (index >= 0 && index != timeIndex_)
+        {
+            nearestIndex = index;
+            break;
+        }
+    }
+
+    if (nearestIndex < 0)
+    {
+        nearestIndex = 0;
+    }
+
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::setTime(";
+        for (int requestI = 0; requestI < nRequest; ++requestI)
+        {
+            if (requestI)
+            {
+                Info<< ", ";
+            }
+
+            Info<< requestTimes[requestI];
+        }
+        Info<< ") - previousIndex = " << timeIndex_
+            << ", nearestIndex = " << nearestIndex << endl;
+    }
+
+
+    // see what has changed
+    if (timeIndex_ != nearestIndex)
+    {
+        timeIndex_ = nearestIndex;
+        runTime.setTime(Times[nearestIndex], nearestIndex);
+
+        // the fields change each time
+        fieldsChanged_ = true;
+
+        if (meshPtr_)
+        {
+            if (meshPtr_->readUpdate() != polyMesh::UNCHANGED)
+            {
+                meshChanged_ = true;
+            }
+        }
+        else
+        {
+            meshChanged_ = true;
+        }
+
+        reader_->UpdateProgress(0.05);
+
+        // this seems to be needed for catching Lagrangian fields
+        updateInfo();
+    }
+
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398Foam::setTime() - selectedTime="
+            << Times[nearestIndex].name() << " index=" << timeIndex_
+            << "/" << Times.size()
+            << " meshChanged=" << Switch(meshChanged_)
+            << " fieldsChanged=" << Switch(fieldsChanged_) << endl;
+    }
+
+    return nearestIndex;
+}
+
+
+void Foam::vtkPV398Foam::updateMeshPartsStatus()
+{
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::updateMeshPartsStatus" << endl;
+    }
+
+    vtkDataArraySelection* selection = reader_->GetPartSelection();
+    label nElem = selection->GetNumberOfArrays();
+
+    if (partStatus_.size() != nElem)
+    {
+        partStatus_.setSize(nElem);
+        partStatus_ = false;
+        meshChanged_ = true;
+    }
+
+    // this needs fixing if we wish to re-use the datasets
+    partDataset_.setSize(nElem);
+    partDataset_ = -1;
+
+    // Read the selected mesh parts (zones, patches ...) and add to list
+    forAll(partStatus_, partId)
+    {
+        const int setting = selection->GetArraySetting(partId);
+
+        if (partStatus_[partId] != setting)
+        {
+            partStatus_[partId] = setting;
+            meshChanged_ = true;
+        }
+
+        if (debug)
+        {
+            Info<< "  part[" << partId << "] = "
+                << partStatus_[partId]
+                << " : " << selection->GetArrayName(partId) << endl;
+        }
+    }
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398Foam::updateMeshPartsStatus" << endl;
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::vtkPV398Foam::vtkPV398Foam
+(
+    const char* const FileName,
+    vtkPV398FoamReader* reader
+)
+:
+    reader_(reader),
+    dbPtr_(NULL),
+    meshPtr_(NULL),
+    meshRegion_(polyMesh::defaultRegion),
+    meshDir_(polyMesh::meshSubDir),
+    timeIndex_(-1),
+    meshChanged_(true),
+    fieldsChanged_(true),
+    arrayRangeVolume_("unzoned"),
+    arrayRangePatches_("patches"),
+    arrayRangeLagrangian_("lagrangian"),
+    arrayRangeCellZones_("cellZone"),
+    arrayRangeFaceZones_("faceZone"),
+    arrayRangePointZones_("pointZone"),
+    arrayRangeCellSets_("cellSet"),
+    arrayRangeFaceSets_("faceSet"),
+    arrayRangePointSets_("pointSet")
+{
+    if (debug)
+    {
+        Info<< "Foam::vtkPV398Foam::vtkPV398Foam - " << FileName << endl;
+        printMemory();
+    }
+
+    // avoid argList and get rootPath/caseName directly from the file
+    fileName fullCasePath(fileName(FileName).path());
+
+    if (!isDir(fullCasePath))
+    {
+        return;
+    }
+    if (fullCasePath == ".")
+    {
+        fullCasePath = cwd();
+    }
+
+    // Set the case as an environment variable - some BCs might use this
+    if (fullCasePath.name().find("processor", 0) == 0)
+    {
+        const fileName globalCase = fullCasePath.path();
+
+        setEnv("FOAM_CASE", globalCase, true);
+        setEnv("FOAM_CASENAME", globalCase.name(), true);
+    }
+    else
+    {
+        setEnv("FOAM_CASE", fullCasePath, true);
+        setEnv("FOAM_CASENAME", fullCasePath.name(), true);
+    }
+
+    // look for 'case{region}.OpenFOAM'
+    // could be stringent and insist the prefix match the directory name...
+    // Note: cannot use fileName::name() due to the embedded '{}'
+    string caseName(fileName(FileName).lessExt());
+    string::size_type beg = caseName.find_last_of("/{");
+    string::size_type end = caseName.find('}', beg);
+
+    if
+    (
+        beg != string::npos && caseName[beg] == '{'
+     && end != string::npos && end == caseName.size()-1
+    )
+    {
+        meshRegion_ = caseName.substr(beg+1, end-beg-1);
+
+        // some safety
+        if (meshRegion_.empty())
+        {
+            meshRegion_ = polyMesh::defaultRegion;
+        }
+
+        if (meshRegion_ != polyMesh::defaultRegion)
+        {
+            meshDir_ = meshRegion_/polyMesh::meshSubDir;
+        }
+    }
+
+    if (debug)
+    {
+        Info<< "fullCasePath=" << fullCasePath << nl
+            << "FOAM_CASE=" << getEnv("FOAM_CASE") << nl
+            << "FOAM_CASENAME=" << getEnv("FOAM_CASENAME") << nl
+            << "region=" << meshRegion_ << endl;
+    }
+
+    // Create time object
+    dbPtr_.reset
+    (
+        new Time
+        (
+            Time::controlDictName,
+            fileName(fullCasePath.path()),
+            fileName(fullCasePath.name())
+        )
+    );
+
+    dbPtr_().functionObjects().off();
+
+    updateInfo();
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::vtkPV398Foam::~vtkPV398Foam()
+{
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398Foam::~vtkPV398Foam" << endl;
+    }
+
+    delete meshPtr_;
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::vtkPV398Foam::updateInfo()
+{
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::updateInfo"
+            << " [meshPtr=" << (meshPtr_ ? "set" : "NULL") << "] timeIndex="
+            << timeIndex_ << endl;
+    }
+
+    resetCounters();
+
+    vtkDataArraySelection* partSelection = reader_->GetPartSelection();
+
+    // there are two ways to ensure we have the correct list of parts:
+    // 1. remove everything and then set particular entries 'on'
+    // 2. build a 'char **' list and call SetArraysWithDefault()
+    //
+    // Nr. 2 has the potential advantage of not touching the modification
+    // time of the vtkDataArraySelection, but the qt/paraview proxy
+    // layer doesn't care about that anyhow.
+
+    // enable 'internalMesh' on the first call
+    // or preserve the enabled selections
+    stringList enabledEntries;
+    if (!partSelection->GetNumberOfArrays() && !meshPtr_)
+    {
+        enabledEntries.setSize(1);
+        enabledEntries[0] = "internalMesh";
+    }
+    else
+    {
+        enabledEntries = getSelectedArrayEntries(partSelection);
+    }
+
+    // Clear current mesh parts list
+    partSelection->RemoveAllArrays();
+
+    // Update mesh parts list - add Lagrangian at the bottom
+    updateInfoInternalMesh(partSelection);
+    updateInfoPatches(partSelection, enabledEntries);
+    updateInfoSets(partSelection);
+    updateInfoZones(partSelection);
+    updateInfoLagrangian(partSelection);
+
+    // restore the enabled selections
+    setSelectedArrayEntries(partSelection, enabledEntries);
+
+    if (meshChanged_)
+    {
+        fieldsChanged_ = true;
+    }
+
+    // Update volume, point and lagrangian fields
+    updateInfoFields<fvPatchField, volMesh>
+    (
+        reader_->GetVolFieldSelection()
+    );
+    updateInfoFields<pointPatchField, pointMesh>
+    (
+        reader_->GetPointFieldSelection()
+    );
+    updateInfoLagrangianFields();
+
+    if (debug)
+    {
+        // just for debug info
+        getSelectedArrayEntries(partSelection);
+        Info<< "<end> Foam::vtkPV398Foam::updateInfo" << endl;
+    }
+
+}
+
+
+void Foam::vtkPV398Foam::updateFoamMesh()
+{
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::updateFoamMesh" << endl;
+        printMemory();
+    }
+
+    if (!reader_->GetCacheMesh())
+    {
+        delete meshPtr_;
+        meshPtr_ = NULL;
+    }
+
+    // Check to see if the OpenFOAM mesh has been created
+    if (!meshPtr_)
+    {
+        if (debug)
+        {
+            Info<< "Creating OpenFOAM mesh for region " << meshRegion_
+                << " at time=" << dbPtr_().timeName()
+                << endl;
+
+        }
+
+        meshPtr_ = new fvMesh
+        (
+            IOobject
+            (
+                meshRegion_,
+                dbPtr_().timeName(),
+                dbPtr_(),
+                IOobject::MUST_READ
+            )
+        );
+
+        meshChanged_ = true;
+    }
+    else
+    {
+        if (debug)
+        {
+            Info<< "Using existing OpenFOAM mesh" << endl;
+        }
+    }
+
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398Foam::updateFoamMesh" << endl;
+        printMemory();
+    }
+}
+
+
+void Foam::vtkPV398Foam::Update
+(
+    vtkMultiBlockDataSet* output,
+    vtkMultiBlockDataSet* lagrangianOutput
+)
+{
+    if (debug)
+    {
+        cout<< "<beg> Foam::vtkPV398Foam::Update - output with "
+            << output->GetNumberOfBlocks() << " and "
+            << lagrangianOutput->GetNumberOfBlocks() << " blocks\n";
+        output->Print(cout);
+        lagrangianOutput->Print(cout);
+        printMemory();
+    }
+    reader_->UpdateProgress(0.1);
+
+    // Set up mesh parts selection(s)
+    updateMeshPartsStatus();
+
+    reader_->UpdateProgress(0.15);
+
+    // Update the OpenFOAM mesh
+    updateFoamMesh();
+    reader_->UpdateProgress(0.4);
+
+    // Convert meshes - start port0 at block=0
+    int blockNo = 0;
+
+    convertMeshVolume(output, blockNo);
+    convertMeshPatches(output, blockNo);
+    reader_->UpdateProgress(0.6);
+
+    if (reader_->GetIncludeZones())
+    {
+        convertMeshCellZones(output, blockNo);
+        convertMeshFaceZones(output, blockNo);
+        convertMeshPointZones(output, blockNo);
+        reader_->UpdateProgress(0.65);
+    }
+
+    if (reader_->GetIncludeSets())
+    {
+        convertMeshCellSets(output, blockNo);
+        convertMeshFaceSets(output, blockNo);
+        convertMeshPointSets(output, blockNo);
+        reader_->UpdateProgress(0.7);
+    }
+
+#ifdef VTKPV398FOAM_DUALPORT
+    // restart port1 at block=0
+    blockNo = 0;
+#endif
+    convertMeshLagrangian(lagrangianOutput, blockNo);
+
+    reader_->UpdateProgress(0.8);
+
+    // Update fields
+    convertVolFields(output);
+    convertPointFields(output);
+    convertLagrangianFields(lagrangianOutput);
+    if (debug)
+    {
+        Info<< "done reader part" << endl;
+    }
+    reader_->UpdateProgress(0.95);
+
+    meshChanged_ = fieldsChanged_ = false;
+}
+
+
+void Foam::vtkPV398Foam::CleanUp()
+{
+    // reclaim some memory
+    reduceMemory();
+    reader_->UpdateProgress(1.0);
+}
+
+
+double* Foam::vtkPV398Foam::findTimes(int& nTimeSteps)
+{
+    int nTimes = 0;
+    double* tsteps = NULL;
+
+    if (dbPtr_.valid())
+    {
+        Time& runTime = dbPtr_();
+        instantList timeLst = runTime.times();
+
+        // find the first time for which this mesh appears to exist
+        label timeI = 0;
+        for (; timeI < timeLst.size(); ++timeI)
+        {
+            const word& timeName = timeLst[timeI].name();
+
+            if
+            (
+                isFile(runTime.path()/timeName/meshDir_/"points")
+             && IOobject("points", timeName, meshDir_, runTime).headerOk()
+            )
+            {
+                break;
+            }
+        }
+
+        nTimes = timeLst.size() - timeI;
+
+        // skip "constant" time whenever possible
+        if (timeI == 0 && nTimes > 1)
+        {
+            if (timeLst[timeI].name() == runTime.constant())
+            {
+                ++timeI;
+                --nTimes;
+            }
+        }
+
+
+        // skip "0/" time if requested and possible
+        if (nTimes > 1 && reader_->GetSkipZeroTime())
+        {
+            if (mag(timeLst[timeI].value()) < SMALL)
+            {
+                ++timeI;
+                --nTimes;
+            }
+        }
+
+        if (nTimes)
+        {
+            tsteps = new double[nTimes];
+            for (label stepI = 0; stepI < nTimes; ++stepI, ++timeI)
+            {
+                tsteps[stepI] = timeLst[timeI].value();
+            }
+        }
+    }
+    else
+    {
+        if (debug)
+        {
+            cout<< "no valid dbPtr:\n";
+        }
+    }
+
+    // vector length returned via the parameter
+    nTimeSteps = nTimes;
+
+    return tsteps;
+}
+
+
+void Foam::vtkPV398Foam::renderPatchNames
+(
+    vtkRenderer* renderer,
+    const bool show
+)
+{
+    if (!meshPtr_)
+    {
+        return;
+    }
+
+    // always remove old actors first
+
+    forAll(patchTextActorsPtrs_, patchI)
+    {
+        renderer->RemoveViewProp(patchTextActorsPtrs_[patchI]);
+        patchTextActorsPtrs_[patchI]->Delete();
+    }
+    patchTextActorsPtrs_.clear();
+
+    if (show)
+    {
+        // get the display patches, strip off any suffix
+        wordHashSet selectedPatches = getSelected
+        (
+            reader_->GetPartSelection(),
+            arrayRangePatches_
+        );
+
+        if (selectedPatches.empty())
+        {
+            return;
+        }
+
+        const polyBoundaryMesh& pbMesh = meshPtr_->boundaryMesh();
+
+        // Find the total number of zones
+        // Each zone will take the patch name
+        // Number of zones per patch ... zero zones should be skipped
+        labelList nZones(pbMesh.size(), 0);
+
+        // Per global zone number the average face centre position
+        List<DynamicList<point> > zoneCentre(pbMesh.size());
+
+
+        // Loop through all patches to determine zones, and centre of each zone
+        forAll(pbMesh, patchI)
+        {
+            const polyPatch& pp = pbMesh[patchI];
+
+            // Only include the patch if it is selected
+            if (!selectedPatches.found(pp.name()))
+            {
+                continue;
+            }
+
+            const labelListList& edgeFaces = pp.edgeFaces();
+            const vectorField& n = pp.faceNormals();
+
+            boolList featEdge(pp.nEdges(), false);
+
+            forAll(edgeFaces, edgeI)
+            {
+                const labelList& eFaces = edgeFaces[edgeI];
+
+                if (eFaces.size() == 1)
+                {
+                    // Note: could also do ones with > 2 faces but this gives
+                    // too many zones for baffles
+                    featEdge[edgeI] = true;
+                }
+                else if (mag(n[eFaces[0]] & n[eFaces[1]]) < 0.5)
+                {
+                    featEdge[edgeI] = true;
+                }
+            }
+
+            // Do topological analysis of patch, find disconnected regions
+            patchZones pZones(pp, featEdge);
+
+            nZones[patchI] = pZones.nZones();
+
+            labelList zoneNFaces(pZones.nZones(), 0);
+
+            // Create storage for additional zone centres
+            forAll(zoneNFaces, zoneI)
+            {
+                zoneCentre[patchI].append(vector::zero);
+            }
+
+            // Do averaging per individual zone
+            forAll(pp, faceI)
+            {
+                label zoneI = pZones[faceI];
+                zoneCentre[patchI][zoneI] += pp[faceI].centre(pp.points());
+                zoneNFaces[zoneI]++;
+            }
+
+            forAll(zoneCentre[patchI], zoneI)
+            {
+                zoneCentre[patchI][zoneI] /= zoneNFaces[zoneI];
+            }
+        }
+
+        // Count number of zones we're actually going to display.
+        // This is truncated to a max per patch
+
+        const label MAXPATCHZONES = 20;
+
+        label displayZoneI = 0;
+
+        forAll(pbMesh, patchI)
+        {
+            displayZoneI += min(MAXPATCHZONES, nZones[patchI]);
+        }
+
+        if (debug)
+        {
+            Info<< "displayed zone centres = " << displayZoneI << nl
+                << "zones per patch = " << nZones << endl;
+        }
+
+        // Set the size of the patch labels to max number of zones
+        patchTextActorsPtrs_.setSize(displayZoneI);
+
+        if (debug)
+        {
+            Info<< "constructing patch labels" << endl;
+        }
+
+        // Actor index
+        displayZoneI = 0;
+
+        forAll(pbMesh, patchI)
+        {
+            const polyPatch& pp = pbMesh[patchI];
+
+            label globalZoneI = 0;
+
+            // Only selected patches will have a non-zero number of zones
+            label nDisplayZones = min(MAXPATCHZONES, nZones[patchI]);
+            label increment = 1;
+            if (nZones[patchI] >= MAXPATCHZONES)
+            {
+                increment = nZones[patchI]/MAXPATCHZONES;
+            }
+
+            for (label i = 0; i < nDisplayZones; i++)
+            {
+                if (debug)
+                {
+                    Info<< "patch name = " << pp.name() << nl
+                        << "anchor = " << zoneCentre[patchI][globalZoneI] << nl
+                        << "globalZoneI = " << globalZoneI << endl;
+                }
+
+                vtkTextActor* txt = vtkTextActor::New();
+
+                txt->SetInput(pp.name().c_str());
+
+                // Set text properties
+                vtkTextProperty* tprop = txt->GetTextProperty();
+                tprop->SetFontFamilyToArial();
+                tprop->BoldOff();
+                tprop->ShadowOff();
+                tprop->SetLineSpacing(1.0);
+                tprop->SetFontSize(12);
+                tprop->SetColor(1.0, 0.0, 0.0);
+                tprop->SetJustificationToCentered();
+
+                // Set text to use 3-D world co-ordinates
+                txt->GetPositionCoordinate()->SetCoordinateSystemToWorld();
+
+                txt->GetPositionCoordinate()->SetValue
+                (
+                    zoneCentre[patchI][globalZoneI].x(),
+                    zoneCentre[patchI][globalZoneI].y(),
+                    zoneCentre[patchI][globalZoneI].z()
+                );
+
+                // Add text to each renderer
+                renderer->AddViewProp(txt);
+
+                // Maintain a list of text labels added so that they can be
+                // removed later
+                patchTextActorsPtrs_[displayZoneI] = txt;
+
+                globalZoneI += increment;
+                displayZoneI++;
+            }
+        }
+
+        // Resize the patch names list to the actual number of patch names added
+        patchTextActorsPtrs_.setSize(displayZoneI);
+    }
+}
+
+
+void Foam::vtkPV398Foam::PrintSelf(ostream& os, vtkIndent indent) const
+{
+    os  << indent << "Number of nodes: "
+        << (meshPtr_ ? meshPtr_->nPoints() : 0) << "\n";
+
+    os  << indent << "Number of cells: "
+        << (meshPtr_ ? meshPtr_->nCells() : 0) << "\n";
+
+    os  << indent << "Number of available time steps: "
+        << (dbPtr_.valid() ? dbPtr_().times().size() : 0) << "\n";
+
+    os  << indent << "mesh region: " << meshRegion_ << "\n";
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398Foam.H b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398Foam.H
new file mode 100644
index 0000000000000000000000000000000000000000..e692fda6dfe628ccced28fdf361e9cd8f77d65d8
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398Foam.H
@@ -0,0 +1,741 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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::vtkPV398Foam
+
+Description
+    Provides a reader interface for OpenFOAM to VTK interaction.
+
+SourceFiles
+    vtkPV398Foam.C
+    vtkPV398Foam.H
+    vtkPV398FoamFields.C
+    vtkPV398FoamMesh.C
+    vtkPV398FoamMeshLagrangian.C
+    vtkPV398FoamTemplates.C
+    vtkPV398FoamMeshSet.C
+    vtkPV398FoamMeshVolume.C
+    vtkPV398FoamMeshZone.C
+    vtkPV398FoamFaceField.H
+    vtkPV398FoamLagrangianFields.H
+    vtkPV398FoamPatchField.H
+    vtkPV398FoamPointFields.H
+    vtkPV398FoamPoints.H
+    vtkPV398FoamUpdateInfo.C
+    vtkPV398FoamUpdateInfoFields.H
+    vtkPV398FoamUtils.C
+    vtkPV398FoamVolFields.H
+    vtkPV398FoamAddToSelection.H
+
+    // Needed by VTK:
+    vtkDataArrayTemplateImplicit.txx
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef vtkPV398Foam_H
+#define vtkPV398Foam_H
+
+// do not include legacy strstream headers
+#ifndef  VTK_EXCLUDE_STRSTREAM_HEADERS
+# define VTK_EXCLUDE_STRSTREAM_HEADERS
+#endif
+
+#include "className.H"
+#include "fileName.H"
+#include "stringList.H"
+#include "wordList.H"
+#include "primitivePatch.H"
+#include "PrimitivePatchInterpolation.H"
+#include "volPointInterpolation.H"
+
+#undef VTKPV398FOAM_DUALPORT
+
+// * * * * * * * * * * * * * Forward Declarations  * * * * * * * * * * * * * //
+
+class vtkDataArraySelection;
+class vtkDataSet;
+class vtkPoints;
+class vtkPV398FoamReader;
+class vtkRenderer;
+class vtkTextActor;
+class vtkMultiBlockDataSet;
+class vtkPolyData;
+class vtkUnstructuredGrid;
+class vtkIndent;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// OpenFOAM class forward declarations
+class argList;
+class Time;
+class fvMesh;
+class IOobjectList;
+class polyPatch;
+class faceSet;
+class pointSet;
+
+template<class Type> class IOField;
+template<class Type> class List;
+
+/*---------------------------------------------------------------------------*\
+                        Class vtkPV398Foam Declaration
+\*---------------------------------------------------------------------------*/
+
+class vtkPV398Foam
+{
+    // Private classes
+
+        //- Bookkeeping for GUI checklists and the multi-block organization
+        class arrayRange
+        {
+            const char *name_;
+            int block_;
+            int start_;
+            int size_;
+
+        public:
+
+            arrayRange(const char *name, const int blockNo=0)
+            :
+                name_(name),
+                block_(blockNo),
+                start_(0),
+                size_(0)
+            {}
+
+            //- Return the block holding these datasets
+            int block() const
+            {
+                return block_;
+            }
+
+            //- Assign block number, return previous value
+            int block(int blockNo)
+            {
+                int prev = block_;
+                block_ = blockNo;
+                return prev;
+            }
+
+            //- Return block name
+            const char* name() const
+            {
+                return name_;
+            }
+
+            //- Return array start index
+            int start() const
+            {
+                return start_;
+            }
+
+            //- Return array end index
+            int end() const
+            {
+                return start_ + size_;
+            }
+
+            //- Return sublist size
+            int size() const
+            {
+                return size_;
+            }
+
+            bool empty() const
+            {
+                return !size_;
+            }
+
+            //- Reset the size to zero and optionally assign a new start
+            void reset(const int startAt = 0)
+            {
+                start_ = startAt;
+                size_ = 0;
+            }
+
+            //- Increment the size
+            void operator+=(const int n)
+            {
+                size_ += n;
+            }
+        };
+
+        //- bookkeeping for polyhedral cell decomposition
+        //  hide in extra pointMap (cellSet/cellZone) for now
+        class polyDecomp
+        {
+            labelList superCells_;
+            labelList addPointCellLabels_;
+            labelList pointMap_;
+
+        public:
+
+            polyDecomp()
+            {}
+
+            //- Label of original cell for decomposed cells
+            labelList& superCells()
+            {
+                return superCells_;
+            }
+
+            //- Label of original cell for decomposed cells
+            const labelList& superCells() const
+            {
+                return superCells_;
+            }
+
+            //- Cell-centre labels for additional points of decomposed cells
+            labelList& addPointCellLabels()
+            {
+                return addPointCellLabels_;
+            }
+
+            //- Cell-centre labels for additional points of decomposed cells
+            const labelList& addPointCellLabels() const
+            {
+                return addPointCellLabels_;
+            }
+
+            //- Point labels for subsetted meshes
+            labelList& pointMap()
+            {
+                return pointMap_;
+            }
+
+            //- Point labels for subsetted meshes
+            const labelList& pointMap() const
+            {
+                return pointMap_;
+            }
+
+
+            //- Clear
+            void clear()
+            {
+                superCells_.clear();
+                addPointCellLabels_.clear();
+                pointMap_.clear();
+            }
+        };
+
+
+    // Private Data
+
+        //- Access to the controlling vtkPV398FoamReader
+        vtkPV398FoamReader* reader_;
+
+        //- OpenFOAM time control
+        autoPtr<Time> dbPtr_;
+
+        //- OpenFOAM mesh
+        fvMesh* meshPtr_;
+
+        //- The mesh region
+        word meshRegion_;
+
+        //- The mesh directory for the region
+        fileName meshDir_;
+
+        //- The time index
+        int timeIndex_;
+
+        //- Track changes in mesh geometry
+        bool meshChanged_;
+
+        //- Track changes in fields
+        bool fieldsChanged_;
+
+        //- Selected geometrical parts (internalMesh, patches, ...)
+        boolList partStatus_;
+
+        //- Datasets corresponding to selected geometrical pieces
+        //  a negative number indicates that no vtkmesh exists for this piece
+        labelList partDataset_;
+
+        //- First instance and size of various mesh parts
+        //  used to index into partStatus_ and partDataset_
+        arrayRange arrayRangeVolume_;
+        arrayRange arrayRangePatches_;
+        arrayRange arrayRangeLagrangian_;
+        arrayRange arrayRangeCellZones_;
+        arrayRange arrayRangeFaceZones_;
+        arrayRange arrayRangePointZones_;
+        arrayRange arrayRangeCellSets_;
+        arrayRange arrayRangeFaceSets_;
+        arrayRange arrayRangePointSets_;
+
+        //- Decomposed cells information (mesh regions)
+        //  TODO: regions
+        List<polyDecomp> regionPolyDecomp_;
+
+        //- Decomposed cells information (cellZone meshes)
+        List<polyDecomp> zonePolyDecomp_;
+
+        //- Decomposed cells information (cellSet meshes)
+        List<polyDecomp> csetPolyDecomp_;
+
+        //- List of patch names for rendering to window
+        List<vtkTextActor*> patchTextActorsPtrs_;
+
+    // Private Member Functions
+
+        // Convenience method use to convert the readers from VTK 5
+        // multiblock API to the current composite data infrastructure
+        static void AddToBlock
+        (
+            vtkMultiBlockDataSet* output,
+            vtkDataSet* dataset,
+            const arrayRange&,
+            const label datasetNo,
+            const std::string& datasetName
+        );
+
+        // Convenience method use to convert the readers from VTK 5
+        // multiblock API to the current composite data infrastructure
+        static vtkDataSet* GetDataSetFromBlock
+        (
+            vtkMultiBlockDataSet* output,
+            const arrayRange&,
+            const label datasetNo
+        );
+
+        // Convenience method use to convert the readers from VTK 5
+        // multiblock API to the current composite data infrastructure
+        static label GetNumberOfDataSets
+        (
+            vtkMultiBlockDataSet* output,
+            const arrayRange&
+        );
+
+        //- Reset data counters
+        void resetCounters();
+
+        // Update information helper functions
+
+            //- Update the mesh parts selected in the GUI
+            void updateMeshPartsStatus();
+
+            //- Internal mesh info
+            void updateInfoInternalMesh(vtkDataArraySelection*);
+
+            //- Lagrangian info
+            void updateInfoLagrangian(vtkDataArraySelection*);
+
+            //- Patch info
+            void updateInfoPatches(vtkDataArraySelection*, stringList&);
+
+            //- Set info
+            void updateInfoSets(vtkDataArraySelection*);
+
+            //- Zone info
+            void updateInfoZones(vtkDataArraySelection*);
+
+            //- Get non-empty zone names for zoneType from file
+            wordList getZoneNames(const word& zoneType) const;
+
+            //- Get non-empty zone names from mesh info
+            template<class ZoneType>
+            wordList getZoneNames
+            (
+                const ZoneMesh<ZoneType, polyMesh>&
+            ) const;
+
+            //- Add objects of Type to paraview array selection
+            template<class Type>
+            label addToSelection
+            (
+                vtkDataArraySelection*,
+                const IOobjectList&,
+                const string& suffix=string::null
+            );
+
+            //- Field info
+            template<template<class> class patchType, class meshType>
+            void updateInfoFields(vtkDataArraySelection*);
+
+            //- Lagrangian field info
+            void updateInfoLagrangianFields();
+
+
+        // Update helper functions
+
+            //- OpenFOAM mesh
+            void updateFoamMesh();
+
+            //- Reduce memory footprint after conversion
+            void reduceMemory();
+
+            //- Volume fields
+            void updateVolFields(vtkMultiBlockDataSet*);
+
+            //- Point fields
+            void updatePointFields(vtkMultiBlockDataSet*);
+
+            //- Lagrangian fields
+            void updateLagrangianFields(vtkMultiBlockDataSet*);
+
+
+        // Mesh conversion functions
+
+            //- Volume mesh
+            void convertMeshVolume(vtkMultiBlockDataSet*, int& blockNo);
+
+            //- Lagrangian mesh
+            void convertMeshLagrangian(vtkMultiBlockDataSet*, int& blockNo);
+
+            //- Patch meshes
+            void convertMeshPatches(vtkMultiBlockDataSet*, int& blockNo);
+
+            //- Cell zone meshes
+            void convertMeshCellZones(vtkMultiBlockDataSet*, int& blockNo);
+
+            //- Face zone meshes
+            void convertMeshFaceZones(vtkMultiBlockDataSet*, int& blockNo);
+
+            //- Point zone meshes
+            void convertMeshPointZones(vtkMultiBlockDataSet*, int& blockNo);
+
+            //- Cell set meshes
+            void convertMeshCellSets(vtkMultiBlockDataSet*, int& blockNo);
+
+            //- Face set meshes
+            void convertMeshFaceSets(vtkMultiBlockDataSet*, int& blockNo);
+
+            //- Point set meshes
+            void convertMeshPointSets(vtkMultiBlockDataSet*, int& blockNo);
+
+
+        // Add mesh functions
+
+            //- Add internal mesh/cell set meshes
+            vtkUnstructuredGrid* volumeVTKMesh(const fvMesh&, polyDecomp&);
+
+            //- Add Lagrangian mesh
+            vtkPolyData* lagrangianVTKMesh
+            (
+                const fvMesh&,
+                const word& cloudName
+            );
+
+            //- Add patch mesh
+            template<class PatchType>
+            vtkPolyData* patchVTKMesh(const word& name, const PatchType&);
+
+            //- Add point zone
+            vtkPolyData* pointZoneVTKMesh
+            (
+                const fvMesh&,
+                const labelList& pointLabels
+            );
+
+            //- Add face set mesh
+            vtkPolyData* faceSetVTKMesh
+            (
+                const fvMesh&,
+                const faceSet&
+            );
+
+            //- Add point mesh
+            vtkPolyData* pointSetVTKMesh
+            (
+                const fvMesh&,
+                const pointSet&
+            );
+
+        // Field conversion functions
+
+            //- Convert volume fields
+            void convertVolFields(vtkMultiBlockDataSet*);
+
+            //- Convert point fields
+            void convertPointFields(vtkMultiBlockDataSet*);
+
+            //- Convert Lagrangian fields
+            void convertLagrangianFields(vtkMultiBlockDataSet*);
+
+
+        //- Add the fields in the selected time directory to the selection
+        //  lists
+        template<class GeoField>
+        label addObjectsToSelection
+        (
+            vtkDataArraySelection*,
+            const IOobjectList&,
+            const string& suffix=string::null
+        );
+
+
+        // Convert OpenFOAM fields
+
+            //- Volume fields - all types
+            template<class Type>
+            void convertVolFields
+            (
+                const fvMesh&,
+                const PtrList<PrimitivePatchInterpolation<primitivePatch> >&,
+                const IOobjectList&,
+                const bool interpFields,
+                vtkMultiBlockDataSet* output
+            );
+
+            //- Volume field - all selected parts
+            template<class Type>
+            void convertVolFieldBlock
+            (
+                const GeometricField<Type, fvPatchField, volMesh>&,
+                autoPtr<GeometricField<Type, pointPatchField, pointMesh> >&,
+                vtkMultiBlockDataSet* output,
+                const arrayRange&,
+                const List<polyDecomp>& decompLst
+            );
+
+            //- Volume field
+            template<class Type>
+            void convertVolField
+            (
+                const GeometricField<Type, fvPatchField, volMesh>&,
+                vtkMultiBlockDataSet* output,
+                const arrayRange&,
+                const label datasetNo,
+                const polyDecomp&
+            );
+
+            //- Patch field
+            template<class Type>
+            void convertPatchField
+            (
+                const word& name,
+                const Field<Type>&,
+                vtkMultiBlockDataSet* output,
+                const arrayRange&,
+                const label datasetNo
+            );
+
+            //- face set/zone field
+            template<class Type>
+            void convertFaceField
+            (
+                const GeometricField<Type, fvPatchField, volMesh>&,
+                vtkMultiBlockDataSet* output,
+                const arrayRange&,
+                const label datasetNo,
+                const fvMesh&,
+                const labelList& faceLabels
+            );
+
+            //- Lagrangian fields - all types
+            template<class Type>
+            void convertLagrangianFields
+            (
+                const IOobjectList&,
+                vtkMultiBlockDataSet* output,
+                const label datasetNo
+            );
+
+            //- Lagrangian field
+            template<class Type>
+            void convertLagrangianField
+            (
+                const IOField<Type>&,
+                vtkMultiBlockDataSet* output,
+                const arrayRange&,
+                const label datasetNo
+            );
+
+            //- Point fields - all types
+            template<class Type>
+            void convertPointFields
+            (
+                const fvMesh&,
+                const pointMesh&,
+                const IOobjectList&,
+                vtkMultiBlockDataSet* output
+            );
+
+            //- Point field - all selected parts
+            template<class Type>
+            void convertPointFieldBlock
+            (
+                const GeometricField<Type, pointPatchField, pointMesh>&,
+                vtkMultiBlockDataSet* output,
+                const arrayRange&,
+                const List<polyDecomp>&
+            );
+
+            //- Point fields
+            template<class Type>
+            void convertPointField
+            (
+                const GeometricField<Type, pointPatchField, pointMesh>&,
+                const GeometricField<Type, fvPatchField, volMesh>&,
+                vtkMultiBlockDataSet* output,
+                const arrayRange&,
+                const label datasetNo,
+                const polyDecomp&
+            );
+
+            //- Patch point field
+            template<class Type>
+            void convertPatchPointField
+            (
+                const word& name,
+                const Field<Type>&,
+                vtkMultiBlockDataSet* output,
+                const arrayRange&,
+                const label datasetNo
+            );
+
+
+       // GUI selection helper functions
+
+            //- Only keep what is listed in hashSet
+            static void pruneObjectList
+            (
+                IOobjectList&,
+                const wordHashSet&
+            );
+
+            //- Retrieve the current selections
+            static wordHashSet getSelected(vtkDataArraySelection*);
+
+            //- Retrieve a sub-list of the current selections
+            static wordHashSet getSelected
+            (
+                vtkDataArraySelection*,
+                const arrayRange&
+            );
+
+            //- Retrieve the current selections
+            static stringList getSelectedArrayEntries(vtkDataArraySelection*);
+
+            //- Retrieve a sub-list of the current selections
+            static stringList getSelectedArrayEntries
+            (
+                vtkDataArraySelection*,
+                const arrayRange&
+            );
+
+            //- Set selection(s)
+            static void setSelectedArrayEntries
+            (
+                vtkDataArraySelection*,
+                const stringList&
+            );
+
+            //- Get the first word from the mesh parts selection
+            word getPartName(const int);
+
+
+        //- Disallow default bitwise copy construct
+        vtkPV398Foam(const vtkPV398Foam&);
+
+        //- Disallow default bitwise assignment
+        void operator=(const vtkPV398Foam&);
+
+
+public:
+
+    //- Static data members
+
+        ClassName("vtkPV398Foam");
+
+
+    // Constructors
+
+        //- Construct from components
+        vtkPV398Foam
+        (
+            const char* const FileName,
+            vtkPV398FoamReader* reader
+        );
+
+
+    //- Destructor
+    ~vtkPV398Foam();
+
+
+    // Member Functions
+
+        //- Update
+        void updateInfo();
+
+        void Update
+        (
+            vtkMultiBlockDataSet* output,
+            vtkMultiBlockDataSet* lagrangianOutput
+        );
+
+        //- Clean any storage
+        void CleanUp();
+
+        //- Allocate and return a list of selected times
+        //  returns the count via the parameter
+        double* findTimes(int& nTimeSteps);
+
+        //- Add/remove patch names to/from the view
+        void renderPatchNames(vtkRenderer*, const bool show);
+
+        //- set the runTime to the first plausible request time,
+        //  returns the timeIndex
+        //  sets to "constant" on error
+        int setTime(int count, const double requestTimes[]);
+
+
+        //- The current time index
+        int timeIndex() const
+        {
+           return timeIndex_;
+        }
+
+
+     // Access
+
+        //- Debug information
+        void PrintSelf(ostream&, vtkIndent) const;
+
+        //- Simple memory used debugging information
+        static void printMemory();
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+#   include "vtkPV398FoamTemplates.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamAddToSelection.H b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamAddToSelection.H
new file mode 100644
index 0000000000000000000000000000000000000000..f69ed8c8cb768d0685cc86f02f18e0eb0e0492be
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamAddToSelection.H
@@ -0,0 +1,74 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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/>.
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef vtkPV398FoamAddToSelection_H
+#define vtkPV398FoamAddToSelection_H
+
+// OpenFOAM includes
+#include "IOobjectList.H"
+#include "SortableList.H"
+
+// VTK includes
+#include "vtkDataArraySelection.h"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+template<class Type>
+Foam::label Foam::vtkPV398Foam::addToSelection
+(
+    vtkDataArraySelection *select,
+    const IOobjectList& objectLst,
+    const string& suffix
+)
+{
+    SortableList<word> names(objectLst.names(Type::typeName));
+
+    forAll(names, nameI)
+    {
+        if (suffix.size())
+        {
+            select->AddArray
+            (
+                (names[nameI] + suffix).c_str()
+            );
+        }
+        else
+        {
+            select->AddArray
+            (
+                (names[nameI]).c_str()
+            );
+        }
+    }
+
+    return names.size();
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamFaceField.H b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamFaceField.H
new file mode 100644
index 0000000000000000000000000000000000000000..95721216d52ad05de2a518bf460373f9be00349d
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamFaceField.H
@@ -0,0 +1,117 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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/>.
+
+InClass
+    vtkPV398Foam
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef vtkPV398FoamFaceField_H
+#define vtkPV398FoamFaceField_H
+
+// VTK includes
+#include "vtkCellData.h"
+#include "vtkFloatArray.h"
+#include "vtkMultiBlockDataSet.h"
+#include "vtkPolyData.h"
+
+#include "vtkOpenFOAMTupleRemap.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+template<class Type>
+void Foam::vtkPV398Foam::convertFaceField
+(
+    const GeometricField<Type, fvPatchField, volMesh>& tf,
+    vtkMultiBlockDataSet* output,
+    const arrayRange& range,
+    const label datasetNo,
+    const fvMesh& mesh,
+    const labelList& faceLabels
+)
+{
+    const label nComp = pTraits<Type>::nComponents;
+    const label nInternalFaces = mesh.nInternalFaces();
+    const labelList& faceOwner = mesh.faceOwner();
+    const labelList& faceNeigh = mesh.faceNeighbour();
+
+    vtkFloatArray* cellData = vtkFloatArray::New();
+    cellData->SetNumberOfTuples(faceLabels.size());
+    cellData->SetNumberOfComponents(nComp);
+    cellData->Allocate(nComp*faceLabels.size());
+    cellData->SetName(tf.name().c_str());
+
+    if (debug)
+    {
+        Info<< "convert convertFaceField: "
+            << tf.name()
+            << " size = " << tf.size()
+            << " nComp=" << nComp
+            << " nTuples = " << faceLabels.size() <<  endl;
+    }
+
+    float vec[nComp];
+
+    // for interior faces: average owner/neighbour
+    // for boundary faces: owner
+    forAll(faceLabels, faceI)
+    {
+        const label faceNo = faceLabels[faceI];
+        if (faceNo < nInternalFaces)
+        {
+            Type t = 0.5*(tf[faceOwner[faceNo]] + tf[faceNeigh[faceNo]]);
+
+            for (direction d=0; d<nComp; ++d)
+            {
+                vec[d] = component(t, d);
+            }
+        }
+        else
+        {
+            const Type& t = tf[faceOwner[faceNo]];
+            for (direction d=0; d<nComp; ++d)
+            {
+                vec[d] = component(t, d);
+            }
+        }
+        vtkOpenFOAMTupleRemap<Type>(vec);
+
+        cellData->InsertTuple(faceI, vec);
+    }
+
+
+    vtkPolyData::SafeDownCast
+    (
+        GetDataSetFromBlock(output, range, datasetNo)
+    )   ->GetCellData()
+        ->AddArray(cellData);
+
+    cellData->Delete();
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamFields.C b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamFields.C
new file mode 100644
index 0000000000000000000000000000000000000000..c4b2df11d4ddac4f7f8162d9d44428931829ecc0
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamFields.C
@@ -0,0 +1,325 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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 "vtkPV398Foam.H"
+
+// OpenFOAM includes
+#include "IOobjectList.H"
+#include "vtkPV398FoamReader.h"
+
+// VTK includes
+#include "vtkDataArraySelection.h"
+#include "vtkPolyData.h"
+#include "vtkUnstructuredGrid.h"
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+#include "vtkPV398FoamVolFields.H"
+#include "vtkPV398FoamPointFields.H"
+#include "vtkPV398FoamLagrangianFields.H"
+
+
+void Foam::vtkPV398Foam::pruneObjectList
+(
+    IOobjectList& objects,
+    const wordHashSet& selected
+)
+{
+    // hash all the selected field names
+    if (selected.empty())
+    {
+        objects.clear();
+    }
+
+    // only keep selected fields
+    forAllIter(IOobjectList, objects, iter)
+    {
+        if (!selected.found(iter()->name()))
+        {
+            objects.erase(iter);
+        }
+    }
+}
+
+
+void Foam::vtkPV398Foam::convertVolFields
+(
+    vtkMultiBlockDataSet* output
+)
+{
+    const fvMesh& mesh = *meshPtr_;
+
+    wordHashSet selectedFields = getSelected
+    (
+        reader_->GetVolFieldSelection()
+    );
+
+    if (selectedFields.empty())
+    {
+        return;
+    }
+
+    // Get objects (fields) for this time - only keep selected fields
+    // the region name is already in the mesh db
+    IOobjectList objects(mesh, dbPtr_().timeName());
+    pruneObjectList(objects, selectedFields);
+
+    if (objects.empty())
+    {
+        return;
+    }
+
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::convertVolFields" << nl
+            << "converting OpenFOAM volume fields" << endl;
+        forAllConstIter(IOobjectList, objects, iter)
+        {
+            Info<< "  " << iter()->name()
+                << " == " << iter()->objectPath() << nl;
+        }
+        printMemory();
+    }
+
+
+    PtrList<PrimitivePatchInterpolation<primitivePatch> >
+        ppInterpList(mesh.boundaryMesh().size());
+
+    forAll(ppInterpList, i)
+    {
+        ppInterpList.set
+        (
+            i,
+            new PrimitivePatchInterpolation<primitivePatch>
+            (
+                mesh.boundaryMesh()[i]
+            )
+        );
+    }
+
+
+    bool interpFields = reader_->GetInterpolateVolFields();
+
+    convertVolFields<scalar>
+    (
+        mesh, ppInterpList, objects, interpFields, output
+    );
+    convertVolFields<vector>
+    (
+        mesh, ppInterpList, objects, interpFields, output
+    );
+    convertVolFields<sphericalTensor>
+    (
+        mesh, ppInterpList, objects, interpFields, output
+    );
+    convertVolFields<symmTensor>
+    (
+        mesh, ppInterpList, objects, interpFields, output
+    );
+    convertVolFields<tensor>
+    (
+        mesh, ppInterpList, objects, interpFields, output
+    );
+
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398Foam::convertVolFields" << endl;
+        printMemory();
+    }
+}
+
+
+void Foam::vtkPV398Foam::convertPointFields
+(
+    vtkMultiBlockDataSet* output
+)
+{
+    const fvMesh& mesh = *meshPtr_;
+
+    wordHashSet selectedFields = getSelected
+    (
+        reader_->GetPointFieldSelection()
+    );
+
+    if (selectedFields.empty())
+    {
+        if (debug)
+        {
+            Info<< "no point fields selected" << endl;
+        }
+        return;
+    }
+
+    // Get objects (fields) for this time - only keep selected fields
+    // the region name is already in the mesh db
+    IOobjectList objects(mesh, dbPtr_().timeName());
+    pruneObjectList(objects, selectedFields);
+
+    if (objects.empty())
+    {
+        return;
+    }
+
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::convertPointFields" << nl
+            << "converting OpenFOAM volume fields -> point fields" << endl;
+        forAllConstIter(IOobjectList, objects, iter)
+        {
+            Info<< "  " << iter()->name()
+                << " == " << iter()->objectPath() << nl;
+        }
+        printMemory();
+    }
+
+    // Construct interpolation on the raw mesh
+    const pointMesh& pMesh = pointMesh::New(mesh);
+
+
+    convertPointFields<scalar>
+    (
+        mesh, pMesh, objects, output
+    );
+    convertPointFields<vector>
+    (
+        mesh, pMesh, objects, output
+    );
+    convertPointFields<sphericalTensor>
+    (
+        mesh, pMesh, objects, output
+    );
+    convertPointFields<symmTensor>
+    (
+        mesh, pMesh, objects, output
+    );
+    convertPointFields<tensor>
+    (
+        mesh, pMesh, objects, output
+    );
+
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398Foam::convertPointFields" << endl;
+        printMemory();
+    }
+}
+
+
+void Foam::vtkPV398Foam::convertLagrangianFields
+(
+    vtkMultiBlockDataSet* output
+)
+{
+    arrayRange& range = arrayRangeLagrangian_;
+    const fvMesh& mesh = *meshPtr_;
+
+    wordHashSet selectedFields = getSelected
+    (
+        reader_->GetLagrangianFieldSelection()
+    );
+
+    if (selectedFields.empty())
+    {
+        return;
+    }
+
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::convertLagrangianFields" << endl;
+        printMemory();
+    }
+
+    for (int partId = range.start(); partId < range.end(); ++partId)
+    {
+        const word  cloudName = getPartName(partId);
+        const label datasetNo = partDataset_[partId];
+
+        if (!partStatus_[partId] || datasetNo < 0)
+        {
+            continue;
+        }
+
+
+        // Get the Lagrangian fields for this time and this cloud
+        // but only keep selected fields
+        // the region name is already in the mesh db
+        IOobjectList objects
+        (
+            mesh,
+            dbPtr_().timeName(),
+            cloud::prefix/cloudName
+        );
+        pruneObjectList(objects, selectedFields);
+
+        if (objects.empty())
+        {
+            continue;
+        }
+
+        if (debug)
+        {
+            Info<< "converting OpenFOAM lagrangian fields" << nl;
+            forAllConstIter(IOobjectList, objects, iter)
+            {
+                Info<< "  " << iter()->name()
+                    << " == " << iter()->objectPath() << nl;
+            }
+        }
+
+        convertLagrangianFields<label>
+        (
+            objects, output, datasetNo
+        );
+        convertLagrangianFields<scalar>
+        (
+            objects, output, datasetNo
+        );
+        convertLagrangianFields<vector>
+        (
+            objects, output, datasetNo
+        );
+        convertLagrangianFields<sphericalTensor>
+        (
+            objects, output, datasetNo
+        );
+        convertLagrangianFields<symmTensor>
+        (
+            objects, output, datasetNo
+        );
+        convertLagrangianFields<tensor>
+        (
+            objects, output, datasetNo
+        );
+    }
+
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398Foam::convertLagrangianFields" << endl;
+        printMemory();
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamLagrangianFields.H b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamLagrangianFields.H
new file mode 100644
index 0000000000000000000000000000000000000000..8f6e4ea351646dbeef0f721da0eb5dcd2fcc75ef
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamLagrangianFields.H
@@ -0,0 +1,113 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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/>.
+
+InClass
+    vtkPV398Foam
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef vtkPV398FoamLagrangianFields_H
+#define vtkPV398FoamLagrangianFields_H
+
+#include "Cloud.H"
+
+#include "vtkOpenFOAMTupleRemap.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+template<class Type>
+void Foam::vtkPV398Foam::convertLagrangianFields
+(
+    const IOobjectList& objects,
+    vtkMultiBlockDataSet* output,
+    const label datasetNo
+)
+{
+    const arrayRange& range = arrayRangeLagrangian_;
+
+    forAllConstIter(IOobjectList, objects, iter)
+    {
+        // restrict to this IOField<Type>
+        if (iter()->headerClassName() == IOField<Type>::typeName)
+        {
+            IOField<Type> tf(*iter());
+            convertLagrangianField(tf, output, range, datasetNo);
+        }
+    }
+}
+
+
+template<class Type>
+void Foam::vtkPV398Foam::convertLagrangianField
+(
+    const IOField<Type>& tf,
+    vtkMultiBlockDataSet* output,
+    const arrayRange& range,
+    const label datasetNo
+)
+{
+    const label nComp = pTraits<Type>::nComponents;
+
+    vtkFloatArray* pointData = vtkFloatArray::New();
+    pointData->SetNumberOfTuples(tf.size());
+    pointData->SetNumberOfComponents(nComp);
+    pointData->Allocate(nComp*tf.size());
+    pointData->SetName(tf.name().c_str());
+
+    if (debug)
+    {
+        Info<< "convert LagrangianField: "
+            << tf.name()
+            << " size = " << tf.size()
+            << " nComp=" << nComp
+            << " nTuples = " << tf.size() <<  endl;
+    }
+
+    float vec[nComp];
+    forAll(tf, i)
+    {
+        const Type& t = tf[i];
+        for (direction d=0; d<nComp; ++d)
+        {
+            vec[d] = component(t, d);
+        }
+        vtkOpenFOAMTupleRemap<Type>(vec);
+
+        pointData->InsertTuple(i, vec);
+    }
+
+
+    vtkPolyData::SafeDownCast
+    (
+        GetDataSetFromBlock(output, range, datasetNo)
+    )   ->GetPointData()
+        ->AddArray(pointData);
+
+    pointData->Delete();
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamMesh.C b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamMesh.C
new file mode 100644
index 0000000000000000000000000000000000000000..b4fc7858b22302ad4cb4ebf5a64b99a5ed1369a4
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamMesh.C
@@ -0,0 +1,648 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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 "vtkPV398Foam.H"
+
+// OpenFOAM includes
+#include "cellSet.H"
+#include "faceSet.H"
+#include "pointSet.H"
+#include "fvMeshSubset.H"
+#include "vtkPV398FoamReader.h"
+#include "uindirectPrimitivePatch.H"
+
+// VTK includes
+#include "vtkDataArraySelection.h"
+#include "vtkMultiBlockDataSet.h"
+#include "vtkPolyData.h"
+#include "vtkUnstructuredGrid.h"
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::vtkPV398Foam::convertMeshVolume
+(
+    vtkMultiBlockDataSet* output,
+    int& blockNo
+)
+{
+    arrayRange& range = arrayRangeVolume_;
+    range.block(blockNo);      // set output block
+    label datasetNo = 0;       // restart at dataset 0
+    const fvMesh& mesh = *meshPtr_;
+
+    // resize for decomposed polyhedra
+    regionPolyDecomp_.setSize(range.size());
+
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::convertMeshVolume" << endl;
+        printMemory();
+    }
+
+    // Convert the internalMesh
+    // this looks like more than one part, but it isn't
+    for (int partId = range.start(); partId < range.end(); ++partId)
+    {
+        const word partName = "internalMesh";
+
+        if (!partStatus_[partId])
+        {
+            continue;
+        }
+
+        vtkUnstructuredGrid* vtkmesh = volumeVTKMesh
+        (
+            mesh,
+            regionPolyDecomp_[datasetNo]
+        );
+
+        if (vtkmesh)
+        {
+            AddToBlock(output, vtkmesh, range, datasetNo, partName);
+            vtkmesh->Delete();
+
+            partDataset_[partId] = datasetNo++;
+        }
+    }
+
+    // anything added?
+    if (datasetNo)
+    {
+        ++blockNo;
+    }
+
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398Foam::convertMeshVolume" << endl;
+        printMemory();
+    }
+}
+
+
+void Foam::vtkPV398Foam::convertMeshLagrangian
+(
+    vtkMultiBlockDataSet* output,
+    int& blockNo
+)
+{
+    arrayRange& range = arrayRangeLagrangian_;
+    range.block(blockNo);      // set output block
+    label datasetNo = 0;       // restart at dataset 0
+    const fvMesh& mesh = *meshPtr_;
+
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::convertMeshLagrangian" << endl;
+        printMemory();
+    }
+
+    for (int partId = range.start(); partId < range.end(); ++partId)
+    {
+        const word cloudName = getPartName(partId);
+
+        if (!partStatus_[partId])
+        {
+            continue;
+        }
+
+        vtkPolyData* vtkmesh = lagrangianVTKMesh(mesh, cloudName);
+
+        if (vtkmesh)
+        {
+            AddToBlock(output, vtkmesh, range, datasetNo, cloudName);
+            vtkmesh->Delete();
+
+            partDataset_[partId] = datasetNo++;
+        }
+    }
+
+    // anything added?
+    if (datasetNo)
+    {
+        ++blockNo;
+    }
+
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398Foam::convertMeshLagrangian" << endl;
+        printMemory();
+    }
+}
+
+
+void Foam::vtkPV398Foam::convertMeshPatches
+(
+    vtkMultiBlockDataSet* output,
+    int& blockNo
+)
+{
+    arrayRange& range = arrayRangePatches_;
+    range.block(blockNo);      // set output block
+    label datasetNo = 0;       // restart at dataset 0
+    const fvMesh& mesh = *meshPtr_;
+    const polyBoundaryMesh& patches = mesh.boundaryMesh();
+
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::convertMeshPatches" << endl;
+        printMemory();
+    }
+
+    for (int partId = range.start(); partId < range.end(); ++partId)
+    {
+        if (!partStatus_[partId])
+        {
+            continue;
+        }
+
+        const word patchName = getPartName(partId);
+
+        labelHashSet patchIds(patches.patchSet(List<wordRe>(1, patchName)));
+
+        if (debug)
+        {
+            Info<< "Creating VTK mesh for patches [" << patchIds <<"] "
+                << patchName  << endl;
+        }
+
+        vtkPolyData* vtkmesh = NULL;
+        if (patchIds.size() == 1)
+        {
+            vtkmesh = patchVTKMesh(patchName, patches[patchIds.begin().key()]);
+        }
+        else
+        {
+            // Patch group. Collect patch faces.
+            label sz = 0;
+            forAllConstIter(labelHashSet, patchIds, iter)
+            {
+                sz += patches[iter.key()].size();
+            }
+            labelList meshFaceLabels(sz);
+            sz = 0;
+            forAllConstIter(labelHashSet, patchIds, iter)
+            {
+                const polyPatch& pp = patches[iter.key()];
+                forAll(pp, i)
+                {
+                    meshFaceLabels[sz++] = pp.start()+i;
+                }
+            }
+            UIndirectList<face> fcs(mesh.faces(), meshFaceLabels);
+            uindirectPrimitivePatch pp(fcs, mesh.points());
+
+            vtkmesh = patchVTKMesh(patchName, pp);
+        }
+
+
+        if (vtkmesh)
+        {
+            AddToBlock(output, vtkmesh, range, datasetNo, patchName);
+            vtkmesh->Delete();
+
+            partDataset_[partId] = datasetNo++;
+        }
+    }
+
+    // anything added?
+    if (datasetNo)
+    {
+        ++blockNo;
+    }
+
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398Foam::convertMeshPatches" << endl;
+        printMemory();
+    }
+}
+
+
+void Foam::vtkPV398Foam::convertMeshCellZones
+(
+    vtkMultiBlockDataSet* output,
+    int& blockNo
+)
+{
+    arrayRange& range = arrayRangeCellZones_;
+    range.block(blockNo);      // set output block
+    label datasetNo = 0;       // restart at dataset 0
+    const fvMesh& mesh = *meshPtr_;
+
+    // resize for decomposed polyhedra
+    zonePolyDecomp_.setSize(range.size());
+
+    if (range.empty())
+    {
+        return;
+    }
+
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::convertMeshCellZones" << endl;
+        printMemory();
+    }
+
+    const cellZoneMesh& zMesh = mesh.cellZones();
+    for (int partId = range.start(); partId < range.end(); ++partId)
+    {
+        const word zoneName = getPartName(partId);
+        const label  zoneId = zMesh.findZoneID(zoneName);
+
+        if (!partStatus_[partId] || zoneId < 0)
+        {
+            continue;
+        }
+
+        if (debug)
+        {
+            Info<< "Creating VTK mesh for cellZone[" << zoneId << "] "
+                << zoneName << endl;
+        }
+
+        fvMeshSubset subsetter(mesh);
+        subsetter.setLargeCellSubset(zMesh[zoneId]);
+
+        vtkUnstructuredGrid* vtkmesh = volumeVTKMesh
+        (
+            subsetter.subMesh(),
+            zonePolyDecomp_[datasetNo]
+        );
+
+        if (vtkmesh)
+        {
+            // superCells + addPointCellLabels must contain global cell ids
+            inplaceRenumber
+            (
+                subsetter.cellMap(),
+                zonePolyDecomp_[datasetNo].superCells()
+            );
+            inplaceRenumber
+            (
+                subsetter.cellMap(),
+                zonePolyDecomp_[datasetNo].addPointCellLabels()
+            );
+
+            // copy pointMap as well, otherwise pointFields fail
+            zonePolyDecomp_[datasetNo].pointMap() = subsetter.pointMap();
+
+            AddToBlock(output, vtkmesh, range, datasetNo, zoneName);
+            vtkmesh->Delete();
+
+            partDataset_[partId] = datasetNo++;
+        }
+    }
+
+    // anything added?
+    if (datasetNo)
+    {
+        ++blockNo;
+    }
+
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398Foam::convertMeshCellZones" << endl;
+        printMemory();
+    }
+}
+
+
+void Foam::vtkPV398Foam::convertMeshCellSets
+(
+    vtkMultiBlockDataSet* output,
+    int& blockNo
+)
+{
+    arrayRange& range = arrayRangeCellSets_;
+    range.block(blockNo);      // set output block
+    label datasetNo = 0;       // restart at dataset 0
+    const fvMesh& mesh = *meshPtr_;
+
+    // resize for decomposed polyhedra
+    csetPolyDecomp_.setSize(range.size());
+
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::convertMeshCellSets" << endl;
+        printMemory();
+    }
+
+    for (int partId = range.start(); partId < range.end(); ++partId)
+    {
+        const word partName = getPartName(partId);
+
+        if (!partStatus_[partId])
+        {
+            continue;
+        }
+
+        if (debug)
+        {
+            Info<< "Creating VTK mesh for cellSet=" << partName << endl;
+        }
+
+        const cellSet cSet(mesh, partName);
+        fvMeshSubset subsetter(mesh);
+        subsetter.setLargeCellSubset(cSet);
+
+        vtkUnstructuredGrid* vtkmesh = volumeVTKMesh
+        (
+            subsetter.subMesh(),
+            csetPolyDecomp_[datasetNo]
+        );
+
+        if (vtkmesh)
+        {
+            // superCells + addPointCellLabels must contain global cell ids
+            inplaceRenumber
+            (
+                subsetter.cellMap(),
+                csetPolyDecomp_[datasetNo].superCells()
+            );
+            inplaceRenumber
+            (
+                subsetter.cellMap(),
+                csetPolyDecomp_[datasetNo].addPointCellLabels()
+            );
+
+            // copy pointMap as well, otherwise pointFields fail
+            csetPolyDecomp_[datasetNo].pointMap() = subsetter.pointMap();
+
+            AddToBlock(output, vtkmesh, range, datasetNo, partName);
+            vtkmesh->Delete();
+
+            partDataset_[partId] = datasetNo++;
+        }
+    }
+
+    // anything added?
+    if (datasetNo)
+    {
+        ++blockNo;
+    }
+
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398Foam::convertMeshCellSets" << endl;
+        printMemory();
+    }
+}
+
+
+void Foam::vtkPV398Foam::convertMeshFaceZones
+(
+    vtkMultiBlockDataSet* output,
+    int& blockNo
+)
+{
+    arrayRange& range = arrayRangeFaceZones_;
+    range.block(blockNo);      // set output block
+    label datasetNo = 0;       // restart at dataset 0
+    const fvMesh& mesh = *meshPtr_;
+
+    if (range.empty())
+    {
+        return;
+    }
+
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::convertMeshFaceZones" << endl;
+        printMemory();
+    }
+
+    const faceZoneMesh& zMesh = mesh.faceZones();
+    for (int partId = range.start(); partId < range.end(); ++partId)
+    {
+        const word zoneName = getPartName(partId);
+        const label  zoneId = zMesh.findZoneID(zoneName);
+
+        if (!partStatus_[partId] || zoneId < 0)
+        {
+            continue;
+        }
+
+        if (debug)
+        {
+            Info<< "Creating VTKmesh for faceZone[" << zoneId << "] "
+                << zoneName << endl;
+        }
+
+        vtkPolyData* vtkmesh = patchVTKMesh(zoneName, zMesh[zoneId]());
+
+        if (vtkmesh)
+        {
+            AddToBlock(output, vtkmesh, range, datasetNo, zoneName);
+            vtkmesh->Delete();
+
+            partDataset_[partId] = datasetNo++;
+        }
+    }
+
+    // anything added?
+    if (datasetNo)
+    {
+        ++blockNo;
+    }
+
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398Foam::convertMeshFaceZones" << endl;
+        printMemory();
+    }
+}
+
+
+void Foam::vtkPV398Foam::convertMeshFaceSets
+(
+    vtkMultiBlockDataSet* output,
+    int& blockNo
+)
+{
+    arrayRange& range = arrayRangeFaceSets_;
+    range.block(blockNo);      // set output block
+    label datasetNo = 0;       // restart at dataset 0
+    const fvMesh& mesh = *meshPtr_;
+
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::convertMeshFaceSets" << endl;
+        printMemory();
+    }
+
+    for (int partId = range.start(); partId < range.end(); ++partId)
+    {
+        const word partName = getPartName(partId);
+
+        if (!partStatus_[partId])
+        {
+            continue;
+        }
+
+        if (debug)
+        {
+            Info<< "Creating VTK mesh for faceSet=" << partName << endl;
+        }
+
+        const faceSet fSet(mesh, partName);
+
+        vtkPolyData* vtkmesh = faceSetVTKMesh(mesh, fSet);
+        if (vtkmesh)
+        {
+            AddToBlock(output, vtkmesh, range, datasetNo, partName);
+            vtkmesh->Delete();
+
+            partDataset_[partId] = datasetNo++;
+        }
+    }
+
+    // anything added?
+    if (datasetNo)
+    {
+        ++blockNo;
+    }
+
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398Foam::convertMeshFaceSets" << endl;
+        printMemory();
+    }
+}
+
+
+void Foam::vtkPV398Foam::convertMeshPointZones
+(
+    vtkMultiBlockDataSet* output,
+    int& blockNo
+)
+{
+    arrayRange& range = arrayRangePointZones_;
+    range.block(blockNo);      // set output block
+    label datasetNo = 0;       // restart at dataset 0
+    const fvMesh& mesh = *meshPtr_;
+
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::convertMeshPointZones" << endl;
+        printMemory();
+    }
+
+    if (range.size())
+    {
+        const pointZoneMesh& zMesh = mesh.pointZones();
+        for (int partId = range.start(); partId < range.end(); ++partId)
+        {
+            word zoneName = getPartName(partId);
+            label zoneId = zMesh.findZoneID(zoneName);
+
+            if (!partStatus_[partId] || zoneId < 0)
+            {
+                continue;
+            }
+
+            vtkPolyData* vtkmesh = pointZoneVTKMesh(mesh, zMesh[zoneId]);
+            if (vtkmesh)
+            {
+                AddToBlock(output, vtkmesh, range, datasetNo, zoneName);
+                vtkmesh->Delete();
+
+                partDataset_[partId] = datasetNo++;
+            }
+        }
+    }
+
+    // anything added?
+    if (datasetNo)
+    {
+        ++blockNo;
+    }
+
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398Foam::convertMeshPointZones" << endl;
+        printMemory();
+    }
+}
+
+
+
+void Foam::vtkPV398Foam::convertMeshPointSets
+(
+    vtkMultiBlockDataSet* output,
+    int& blockNo
+)
+{
+    arrayRange& range = arrayRangePointSets_;
+    range.block(blockNo);      // set output block
+    label datasetNo = 0;       // restart at dataset 0
+    const fvMesh& mesh = *meshPtr_;
+
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::convertMeshPointSets" << endl;
+        printMemory();
+    }
+
+    for (int partId = range.start(); partId < range.end(); ++partId)
+    {
+        word partName = getPartName(partId);
+
+        if (!partStatus_[partId])
+        {
+            continue;
+        }
+
+        if (debug)
+        {
+            Info<< "Creating VTK mesh for pointSet=" << partName << endl;
+        }
+
+        const pointSet pSet(mesh, partName);
+
+        vtkPolyData* vtkmesh = pointSetVTKMesh(mesh, pSet);
+        if (vtkmesh)
+        {
+            AddToBlock(output, vtkmesh, range, datasetNo, partName);
+            vtkmesh->Delete();
+
+            partDataset_[partId] = datasetNo++;
+        }
+    }
+
+    // anything added?
+    if (datasetNo)
+    {
+        ++blockNo;
+    }
+
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398Foam::convertMeshPointSets" << endl;
+        printMemory();
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamMeshLagrangian.C b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamMeshLagrangian.C
new file mode 100644
index 0000000000000000000000000000000000000000..7c4aa8f680a3cce8ee26e19a1dcf073fc4420362
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamMeshLagrangian.C
@@ -0,0 +1,109 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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 "vtkPV398Foam.H"
+
+// OpenFOAM includes
+#include "Cloud.H"
+#include "fvMesh.H"
+#include "IOobjectList.H"
+#include "passiveParticle.H"
+#include "vtkOpenFOAMPoints.H"
+
+// VTK includes
+#include "vtkCellArray.h"
+#include "vtkPoints.h"
+#include "vtkPolyData.h"
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+vtkPolyData* Foam::vtkPV398Foam::lagrangianVTKMesh
+(
+    const fvMesh& mesh,
+    const word& cloudName
+)
+{
+    vtkPolyData* vtkmesh = NULL;
+
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::lagrangianVTKMesh - timePath "
+            << mesh.time().timePath()/cloud::prefix/cloudName << endl;
+        printMemory();
+    }
+
+
+    // the region name is already in the mesh db
+    IOobjectList sprayObjs
+    (
+        mesh,
+        mesh.time().timeName(),
+        cloud::prefix/cloudName
+    );
+
+    IOobject* positionsPtr = sprayObjs.lookup("positions");
+    if (positionsPtr)
+    {
+        Cloud<passiveParticle> parcels(mesh, cloudName, false);
+
+        if (debug)
+        {
+            Info<< "cloud with " << parcels.size() << " parcels" << endl;
+        }
+
+        vtkmesh = vtkPolyData::New();
+        vtkPoints* vtkpoints = vtkPoints::New();
+        vtkCellArray* vtkcells = vtkCellArray::New();
+
+        vtkpoints->Allocate(parcels.size());
+        vtkcells->Allocate(parcels.size());
+
+        vtkIdType particleId = 0;
+        forAllConstIter(Cloud<passiveParticle>, parcels, iter)
+        {
+            vtkInsertNextOpenFOAMPoint(vtkpoints, iter().position());
+
+            vtkcells->InsertNextCell(1, &particleId);
+            particleId++;
+        }
+
+        vtkmesh->SetPoints(vtkpoints);
+        vtkpoints->Delete();
+
+        vtkmesh->SetVerts(vtkcells);
+        vtkcells->Delete();
+    }
+
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398Foam::lagrangianVTKMesh" << endl;
+        printMemory();
+    }
+
+    return vtkmesh;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamMeshSet.C b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamMeshSet.C
new file mode 100644
index 0000000000000000000000000000000000000000..a93e68d5c7118985be4c6d714904d535b0e9f394
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamMeshSet.C
@@ -0,0 +1,148 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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 "vtkPV398Foam.H"
+
+// OpenFOAM includes
+#include "faceSet.H"
+#include "pointSet.H"
+#include "vtkOpenFOAMPoints.H"
+
+// VTK includes
+#include "vtkPoints.h"
+#include "vtkPolyData.h"
+#include "vtkCellArray.h"
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+vtkPolyData* Foam::vtkPV398Foam::faceSetVTKMesh
+(
+    const fvMesh& mesh,
+    const faceSet& fSet
+)
+{
+    vtkPolyData* vtkmesh = vtkPolyData::New();
+
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::faceSetVTKMesh" << endl;
+        printMemory();
+    }
+
+    // Construct primitivePatch of faces in fSet.
+
+    const faceList& meshFaces = mesh.faces();
+    faceList patchFaces(fSet.size());
+    label faceI = 0;
+    forAllConstIter(faceSet, fSet, iter)
+    {
+        patchFaces[faceI++] = meshFaces[iter.key()];
+    }
+    primitiveFacePatch p(patchFaces, mesh.points());
+
+
+    // The balance of this routine should be identical to patchVTKMesh
+
+    // Convert OpenFOAM mesh vertices to VTK
+    const pointField& points = p.localPoints();
+
+    vtkPoints* vtkpoints = vtkPoints::New();
+    vtkpoints->Allocate(points.size());
+    forAll(points, i)
+    {
+        vtkInsertNextOpenFOAMPoint(vtkpoints, points[i]);
+    }
+    vtkmesh->SetPoints(vtkpoints);
+    vtkpoints->Delete();
+
+    // Add faces as polygons
+    const faceList& faces = p.localFaces();
+
+    vtkCellArray* vtkcells = vtkCellArray::New();
+    vtkcells->Allocate(faces.size());
+
+    forAll(faces, faceI)
+    {
+        const face& f = faces[faceI];
+        vtkIdType nodeIds[f.size()];
+
+        forAll(f, fp)
+        {
+            nodeIds[fp] = f[fp];
+        }
+        vtkcells->InsertNextCell(f.size(), nodeIds);
+    }
+
+    vtkmesh->SetPolys(vtkcells);
+    vtkcells->Delete();
+
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398Foam::faceSetVTKMesh" << endl;
+        printMemory();
+    }
+
+    return vtkmesh;
+}
+
+
+vtkPolyData* Foam::vtkPV398Foam::pointSetVTKMesh
+(
+    const fvMesh& mesh,
+    const pointSet& pSet
+)
+{
+    vtkPolyData* vtkmesh = vtkPolyData::New();
+
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::pointSetVTKMesh" << endl;
+        printMemory();
+    }
+
+    const pointField& meshPoints = mesh.points();
+
+    vtkPoints* vtkpoints = vtkPoints::New();
+    vtkpoints->Allocate(pSet.size());
+
+    forAllConstIter(pointSet, pSet, iter)
+    {
+        vtkInsertNextOpenFOAMPoint(vtkpoints, meshPoints[iter.key()]);
+    }
+
+    vtkmesh->SetPoints(vtkpoints);
+    vtkpoints->Delete();
+
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398Foam::pointSetVTKMesh" << endl;
+        printMemory();
+    }
+
+    return vtkmesh;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamMeshVolume.C b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamMeshVolume.C
new file mode 100644
index 0000000000000000000000000000000000000000..bfd56242f2361b5d8a3355f45f85c143ad538634
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamMeshVolume.C
@@ -0,0 +1,481 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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 "vtkPV398Foam.H"
+#include "vtkPV398FoamReader.h"
+
+// OpenFOAM includes
+#include "fvMesh.H"
+#include "cellModeller.H"
+#include "vtkOpenFOAMPoints.H"
+#include "Swap.H"
+#include "longLong.H"
+
+// VTK includes
+#include "vtkCellArray.h"
+#include "vtkIdTypeArray.h"
+#include "vtkUnstructuredGrid.h"
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+vtkUnstructuredGrid* Foam::vtkPV398Foam::volumeVTKMesh
+(
+    const fvMesh& mesh,
+    polyDecomp& decompInfo
+)
+{
+    const cellModel& tet = *(cellModeller::lookup("tet"));
+    const cellModel& pyr = *(cellModeller::lookup("pyr"));
+    const cellModel& prism = *(cellModeller::lookup("prism"));
+    const cellModel& wedge = *(cellModeller::lookup("wedge"));
+    const cellModel& tetWedge = *(cellModeller::lookup("tetWedge"));
+    const cellModel& hex = *(cellModeller::lookup("hex"));
+
+    vtkUnstructuredGrid* vtkmesh = vtkUnstructuredGrid::New();
+
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::volumeVTKMesh" << endl;
+        printMemory();
+    }
+
+    const cellShapeList& cellShapes = mesh.cellShapes();
+
+    // Number of additional points needed by the decomposition of polyhedra
+    label nAddPoints = 0;
+
+    // Number of additional cells generated by the decomposition of polyhedra
+    label nAddCells = 0;
+
+    // face owner is needed to determine the face orientation
+    const labelList& owner = mesh.faceOwner();
+
+    labelList& superCells = decompInfo.superCells();
+    labelList& addPointCellLabels = decompInfo.addPointCellLabels();
+
+    // Scan for cells which need to be decomposed and count additional points
+    // and cells
+    if (!reader_->GetUseVTKPolyhedron())
+    {
+        if (debug)
+        {
+            Info<< "... scanning for polyhedra" << endl;
+        }
+
+        forAll(cellShapes, cellI)
+        {
+            const cellModel& model = cellShapes[cellI].model();
+
+            if
+            (
+                model != hex
+             && model != wedge
+             && model != prism
+             && model != pyr
+             && model != tet
+             && model != tetWedge
+            )
+            {
+                const cell& cFaces = mesh.cells()[cellI];
+
+                forAll(cFaces, cFaceI)
+                {
+                    const face& f = mesh.faces()[cFaces[cFaceI]];
+
+                    label nQuads = 0;
+                    label nTris = 0;
+                    f.nTrianglesQuads(mesh.points(), nTris, nQuads);
+
+                    nAddCells += nQuads + nTris;
+                }
+
+                nAddCells--;
+                nAddPoints++;
+            }
+        }
+    }
+
+    // Set size of additional point addressing array
+    // (from added point to original cell)
+    addPointCellLabels.setSize(nAddPoints);
+
+    // Set size of additional cells mapping array
+    // (from added cell to original cell)
+
+    if (debug)
+    {
+        Info<<" mesh nCells     = " << mesh.nCells() << nl
+            <<"      nPoints    = " << mesh.nPoints() << nl
+            <<"      nAddCells  = " << nAddCells << nl
+            <<"      nAddPoints = " << nAddPoints << endl;
+    }
+
+    superCells.setSize(mesh.nCells() + nAddCells);
+
+    if (debug)
+    {
+        Info<< "... converting points" << endl;
+    }
+
+    // Convert OpenFOAM mesh vertices to VTK
+    vtkPoints* vtkpoints = vtkPoints::New();
+    vtkpoints->Allocate(mesh.nPoints() + nAddPoints);
+
+    const Foam::pointField& points = mesh.points();
+
+    forAll(points, i)
+    {
+        vtkInsertNextOpenFOAMPoint(vtkpoints, points[i]);
+    }
+
+
+    if (debug)
+    {
+        Info<< "... converting cells" << endl;
+    }
+
+    vtkmesh->Allocate(mesh.nCells() + nAddCells);
+
+    // Set counters for additional points and additional cells
+    label addPointI = 0, addCellI = 0;
+
+    // Create storage for points - needed for mapping from OpenFOAM to VTK
+    // data types - max 'order' = hex = 8 points
+    vtkIdType nodeIds[8];
+
+    // face-stream for a polyhedral cell
+    // [numFace0Pts, id1, id2, id3, numFace1Pts, id1, id2, id3, ...]
+    DynamicList<vtkIdType> faceStream(256);
+
+    forAll(cellShapes, cellI)
+    {
+        const cellShape& cellShape = cellShapes[cellI];
+        const cellModel& cellModel = cellShape.model();
+
+        superCells[addCellI++] = cellI;
+
+        if (cellModel == tet)
+        {
+            for (int j = 0; j < 4; j++)
+            {
+                nodeIds[j] = cellShape[j];
+            }
+            vtkmesh->InsertNextCell
+            (
+                VTK_TETRA,
+                4,
+                nodeIds
+            );
+        }
+        else if (cellModel == pyr)
+        {
+            for (int j = 0; j < 5; j++)
+            {
+                nodeIds[j] = cellShape[j];
+            }
+            vtkmesh->InsertNextCell
+            (
+                VTK_PYRAMID,
+                5,
+                nodeIds
+            );
+        }
+        else if (cellModel == prism)
+        {
+            // VTK has a different node order for VTK_WEDGE
+            // their triangles point outwards!
+            nodeIds[0] = cellShape[0];
+            nodeIds[1] = cellShape[2];
+            nodeIds[2] = cellShape[1];
+            nodeIds[3] = cellShape[3];
+            nodeIds[4] = cellShape[5];
+            nodeIds[5] = cellShape[4];
+
+            vtkmesh->InsertNextCell
+            (
+                VTK_WEDGE,
+                6,
+                nodeIds
+            );
+        }
+        else if (cellModel == tetWedge)
+        {
+            // Treat as squeezed prism
+
+            nodeIds[0] = cellShape[0];
+            nodeIds[1] = cellShape[2];
+            nodeIds[2] = cellShape[1];
+            nodeIds[3] = cellShape[3];
+            nodeIds[4] = cellShape[4];
+            nodeIds[5] = cellShape[4];
+
+            vtkmesh->InsertNextCell
+            (
+                VTK_WEDGE,
+                6,
+                nodeIds
+            );
+        }
+        else if (cellModel == wedge)
+        {
+            // Treat as squeezed hex
+
+            nodeIds[0] = cellShape[0];
+            nodeIds[1] = cellShape[1];
+            nodeIds[2] = cellShape[2];
+            nodeIds[3] = cellShape[2];
+            nodeIds[4] = cellShape[3];
+            nodeIds[5] = cellShape[4];
+            nodeIds[6] = cellShape[5];
+            nodeIds[7] = cellShape[6];
+
+            vtkmesh->InsertNextCell
+            (
+                VTK_HEXAHEDRON,
+                8,
+                nodeIds
+            );
+        }
+        else if (cellModel == hex)
+        {
+            for (int j = 0; j < 8; j++)
+            {
+                nodeIds[j] = cellShape[j];
+            }
+            vtkmesh->InsertNextCell
+            (
+                VTK_HEXAHEDRON,
+                8,
+                nodeIds
+            );
+        }
+        else if (reader_->GetUseVTKPolyhedron())
+        {
+            // Polyhedral cell - use VTK_POLYHEDRON
+            const labelList& cFaces = mesh.cells()[cellI];
+
+#ifdef HAS_VTK_POLYHEDRON
+            vtkIdType nFaces = cFaces.size();
+            vtkIdType nLabels = nFaces;
+
+            // count size for face stream
+            forAll(cFaces, cFaceI)
+            {
+                const face& f = mesh.faces()[cFaces[cFaceI]];
+                nLabels += f.size();
+            }
+
+            // build face-stream
+            // [numFace0Pts, id1, id2, id3, numFace1Pts, id1, id2, id3, ...]
+            // point Ids are global
+            faceStream.clear();
+            faceStream.reserve(nLabels + nFaces);
+
+            forAll(cFaces, cFaceI)
+            {
+                const face& f = mesh.faces()[cFaces[cFaceI]];
+                const bool isOwner = (owner[cFaces[cFaceI]] == cellI);
+                const label nFacePoints = f.size();
+
+                // number of labels for this face
+                faceStream.append(nFacePoints);
+
+                if (isOwner)
+                {
+                    forAll(f, fp)
+                    {
+                        faceStream.append(f[fp]);
+                    }
+                }
+                else
+                {
+                    // fairly immaterial if we reverse the list
+                    // or use face::reverseFace()
+                    forAllReverse(f, fp)
+                    {
+                        faceStream.append(f[fp]);
+                    }
+                }
+            }
+
+            vtkmesh->InsertNextCell(VTK_POLYHEDRON, nFaces, faceStream.data());
+#else
+            // this is a horrible substitute
+            // but avoids crashes when there is no vtkPolyhedron support
+
+            // establish unique node ids used
+            HashSet<vtkIdType, Hash<label> > hashUniqId(2*256);
+
+            forAll(cFaces, cFaceI)
+            {
+                const face& f = mesh.faces()[cFaces[cFaceI]];
+
+                forAll(f, fp)
+                {
+                    hashUniqId.insert(f[fp]);
+                }
+            }
+
+            // use face stream to store unique node ids:
+            faceStream = hashUniqId.sortedToc();
+
+            vtkmesh->InsertNextCell
+            (
+                VTK_CONVEX_POINT_SET,
+                vtkIdType(faceStream.size()),
+                faceStream.data()
+            );
+#endif
+        }
+        else
+        {
+            // Polyhedral cell. Decompose into tets + prisms.
+
+            // Mapping from additional point to cell
+            addPointCellLabels[addPointI] = cellI;
+
+            // The new vertex from the cell-centre
+            const label newVertexLabel = mesh.nPoints() + addPointI;
+            vtkInsertNextOpenFOAMPoint(vtkpoints, mesh.C()[cellI]);
+
+            // Whether to insert cell in place of original or not.
+            bool substituteCell = true;
+
+            const labelList& cFaces = mesh.cells()[cellI];
+            forAll(cFaces, cFaceI)
+            {
+                const face& f = mesh.faces()[cFaces[cFaceI]];
+                const bool isOwner = (owner[cFaces[cFaceI]] == cellI);
+
+                // Number of triangles and quads in decomposition
+                label nTris = 0;
+                label nQuads = 0;
+                f.nTrianglesQuads(mesh.points(), nTris, nQuads);
+
+                // Do actual decomposition into triFcs and quadFcs.
+                faceList triFcs(nTris);
+                faceList quadFcs(nQuads);
+                label trii = 0;
+                label quadi = 0;
+                f.trianglesQuads(mesh.points(), trii, quadi, triFcs, quadFcs);
+
+                forAll(quadFcs, quadI)
+                {
+                    if (substituteCell)
+                    {
+                        substituteCell = false;
+                    }
+                    else
+                    {
+                        superCells[addCellI++] = cellI;
+                    }
+
+                    const face& quad = quadFcs[quadI];
+
+                    // Ensure we have the correct orientation for the
+                    // base of the primitive cell shape.
+                    // If the cell is face owner, the orientation needs to be
+                    // flipped.
+                    // At the moment, VTK doesn't actually seem to care if
+                    // negative cells are defined, but we'll do it anyhow
+                    // (for safety).
+                    if (isOwner)
+                    {
+                        nodeIds[0] = quad[3];
+                        nodeIds[1] = quad[2];
+                        nodeIds[2] = quad[1];
+                        nodeIds[3] = quad[0];
+                    }
+                    else
+                    {
+                        nodeIds[0] = quad[0];
+                        nodeIds[1] = quad[1];
+                        nodeIds[2] = quad[2];
+                        nodeIds[3] = quad[3];
+                    }
+                    nodeIds[4] = newVertexLabel;
+                    vtkmesh->InsertNextCell
+                    (
+                        VTK_PYRAMID,
+                        5,
+                        nodeIds
+                    );
+                }
+
+                forAll(triFcs, triI)
+                {
+                    if (substituteCell)
+                    {
+                        substituteCell = false;
+                    }
+                    else
+                    {
+                        superCells[addCellI++] = cellI;
+                    }
+
+                    const face& tri = triFcs[triI];
+
+                    // See note above about the orientation.
+                    if (isOwner)
+                    {
+                        nodeIds[0] = tri[2];
+                        nodeIds[1] = tri[1];
+                        nodeIds[2] = tri[0];
+                    }
+                    else
+                    {
+                        nodeIds[0] = tri[0];
+                        nodeIds[1] = tri[1];
+                        nodeIds[2] = tri[2];
+                    }
+                    nodeIds[3] = newVertexLabel;
+
+                    vtkmesh->InsertNextCell
+                    (
+                        VTK_TETRA,
+                        4,
+                        nodeIds
+                    );
+                }
+            }
+
+            addPointI++;
+        }
+    }
+
+    vtkmesh->SetPoints(vtkpoints);
+    vtkpoints->Delete();
+
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398Foam::volumeVTKMesh" << endl;
+        printMemory();
+    }
+
+    return vtkmesh;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamMeshZone.C b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamMeshZone.C
new file mode 100644
index 0000000000000000000000000000000000000000..8c59fd2a6c3b25a3ff4c258f32d638fe76a67793
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamMeshZone.C
@@ -0,0 +1,75 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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 "vtkPV398Foam.H"
+
+// OpenFOAM includes
+#include "vtkOpenFOAMPoints.H"
+
+// VTK includes
+#include "vtkPoints.h"
+#include "vtkPolyData.h"
+#include "vtkCellArray.h"
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+vtkPolyData* Foam::vtkPV398Foam::pointZoneVTKMesh
+(
+    const fvMesh& mesh,
+    const labelList& pointLabels
+)
+{
+    vtkPolyData* vtkmesh = vtkPolyData::New();
+
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::pointZoneVTKMesh" << endl;
+        printMemory();
+    }
+
+    const pointField& meshPoints = mesh.points();
+
+    vtkPoints* vtkpoints = vtkPoints::New();
+    vtkpoints->Allocate(pointLabels.size());
+
+    forAll(pointLabels, pointI)
+    {
+        vtkInsertNextOpenFOAMPoint(vtkpoints, meshPoints[pointLabels[pointI]]);
+    }
+
+    vtkmesh->SetPoints(vtkpoints);
+    vtkpoints->Delete();
+
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::pointZoneVTKMesh" << endl;
+        printMemory();
+    }
+
+    return vtkmesh;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamPatchField.H b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamPatchField.H
new file mode 100644
index 0000000000000000000000000000000000000000..6223166dc8c8e9205bbd3f9e7df8cf7143af8036
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamPatchField.H
@@ -0,0 +1,129 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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/>.
+
+InClass
+    vtkPV398Foam
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef vtkPV398FoamPatchField_H
+#define vtkPV398FoamPatchField_H
+
+// VTK includes
+#include "vtkCellData.h"
+#include "vtkFloatArray.h"
+#include "vtkMultiBlockDataSet.h"
+#include "vtkPointData.h"
+#include "vtkPolyData.h"
+
+#include "vtkOpenFOAMTupleRemap.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+template<class Type>
+void Foam::vtkPV398Foam::convertPatchField
+(
+    const word& name,
+    const Field<Type>& ptf,
+    vtkMultiBlockDataSet* output,
+    const arrayRange& range,
+    const label datasetNo
+)
+{
+    const label nComp = pTraits<Type>::nComponents;
+
+    vtkFloatArray* cellData = vtkFloatArray::New();
+    cellData->SetNumberOfTuples(ptf.size());
+    cellData->SetNumberOfComponents(nComp);
+    cellData->Allocate(nComp*ptf.size());
+    cellData->SetName(name.c_str());
+
+    float vec[nComp];
+    forAll(ptf, i)
+    {
+        const Type& t = ptf[i];
+        for (direction d=0; d<nComp; ++d)
+        {
+            vec[d] = component(t, d);
+        }
+        vtkOpenFOAMTupleRemap<Type>(vec);
+
+        cellData->InsertTuple(i, vec);
+    }
+
+    vtkPolyData::SafeDownCast
+    (
+        GetDataSetFromBlock(output, range, datasetNo)
+    )   ->GetCellData()
+        ->AddArray(cellData);
+
+    cellData->Delete();
+}
+
+
+// as above, but with PointData()
+template<class Type>
+void Foam::vtkPV398Foam::convertPatchPointField
+(
+    const word& name,
+    const Field<Type>& pptf,
+    vtkMultiBlockDataSet* output,
+    const arrayRange& range,
+    const label datasetNo
+)
+{
+    const label nComp = pTraits<Type>::nComponents;
+
+    vtkFloatArray* pointData = vtkFloatArray::New();
+    pointData->SetNumberOfTuples(pptf.size());
+    pointData->SetNumberOfComponents(nComp);
+    pointData->Allocate(nComp*pptf.size());
+    pointData->SetName(name.c_str());
+
+    float vec[nComp];
+    forAll(pptf, i)
+    {
+        const Type& t = pptf[i];
+        for (direction d=0; d<nComp; ++d)
+        {
+            vec[d] = component(t, d);
+        }
+        vtkOpenFOAMTupleRemap<Type>(vec);
+
+        pointData->InsertTuple(i, vec);
+    }
+
+    vtkPolyData::SafeDownCast
+    (
+        GetDataSetFromBlock(output, range, datasetNo)
+    )   ->GetPointData()
+        ->AddArray(pointData);
+
+    pointData->Delete();
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamPointFields.H b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamPointFields.H
new file mode 100644
index 0000000000000000000000000000000000000000..9cc93349e1d759631fb184cb0676711a86485012
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamPointFields.H
@@ -0,0 +1,331 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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/>.
+
+InClass
+    vtkPV398Foam
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef vtkPV398FoamPointFields_H
+#define vtkPV398FoamPointFields_H
+
+// OpenFOAM includes
+#include "interpolatePointToCell.H"
+
+#include "vtkOpenFOAMTupleRemap.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+template<class Type>
+void Foam::vtkPV398Foam::convertPointFields
+(
+    const fvMesh& mesh,
+    const pointMesh& pMesh,
+    const IOobjectList& objects,
+    vtkMultiBlockDataSet* output
+)
+{
+    const polyBoundaryMesh& patches = mesh.boundaryMesh();
+
+    forAllConstIter(IOobjectList, objects, iter)
+    {
+        const word& fieldName = iter()->name();
+        // restrict to this GeometricField<Type, ...>
+        if
+        (
+            iter()->headerClassName()
+         != GeometricField<Type, pointPatchField, pointMesh>::typeName
+        )
+        {
+            continue;
+        }
+
+        if (debug)
+        {
+            Info<< "Foam::vtkPV398Foam::convertPointFields : "
+                << fieldName << endl;
+        }
+
+        GeometricField<Type, pointPatchField, pointMesh> ptf
+        (
+            *iter(),
+            pMesh
+        );
+
+
+        // Convert activated internalMesh regions
+        convertPointFieldBlock
+        (
+            ptf,
+            output,
+            arrayRangeVolume_,
+            regionPolyDecomp_
+        );
+
+        // Convert activated cellZones
+        convertPointFieldBlock
+        (
+            ptf,
+            output,
+            arrayRangeCellZones_,
+            zonePolyDecomp_
+        );
+
+        // Convert activated cellSets
+        convertPointFieldBlock
+        (
+            ptf,
+            output,
+            arrayRangeCellSets_,
+            csetPolyDecomp_
+        );
+
+
+        //
+        // Convert patches - if activated
+        //
+        for
+        (
+            int partId = arrayRangePatches_.start();
+            partId < arrayRangePatches_.end();
+            ++partId
+        )
+        {
+            const word patchName = getPartName(partId);
+            const label datasetNo = partDataset_[partId];
+            const label patchId = patches.findPatchID(patchName);
+
+            if (!partStatus_[partId] || datasetNo < 0 || patchId < 0)
+            {
+                continue;
+            }
+
+            convertPatchPointField
+            (
+                fieldName,
+                ptf.boundaryField()[patchId].patchInternalField()(),
+                output,
+                arrayRangePatches_,
+                datasetNo
+            );
+        }
+
+        //
+        // Convert faceZones - if activated
+        //
+        for
+        (
+            int partId = arrayRangeFaceZones_.start();
+            partId < arrayRangeFaceZones_.end();
+            ++partId
+        )
+        {
+            const word zoneName = getPartName(partId);
+            const label datasetNo = partDataset_[partId];
+            const label zoneId = mesh.faceZones().findZoneID(zoneName);
+
+            if (!partStatus_[partId] || datasetNo < 0 || zoneId < 0)
+            {
+                continue;
+            }
+
+            // Extract the field on the zone
+            Field<Type> fld
+            (
+                ptf.internalField(),
+                mesh.faceZones()[zoneId]().meshPoints()
+            );
+
+            convertPatchPointField
+            (
+                fieldName,
+                fld,
+                output,
+                arrayRangeFaceZones_,
+                datasetNo
+            );
+        }
+    }
+}
+
+
+template<class Type>
+void Foam::vtkPV398Foam::convertPointFieldBlock
+(
+    const GeometricField<Type, pointPatchField, pointMesh>& ptf,
+    vtkMultiBlockDataSet* output,
+    const arrayRange& range,
+    const List<polyDecomp>& decompLst
+)
+{
+   for (int partId = range.start(); partId < range.end(); ++partId)
+   {
+       const label datasetNo = partDataset_[partId];
+
+       if (datasetNo >= 0 && partStatus_[partId])
+       {
+           convertPointField
+           (
+               ptf,
+               GeometricField<Type, fvPatchField, volMesh>::null(),
+               output,
+               range,
+               datasetNo,
+               decompLst[datasetNo]
+           );
+       }
+   }
+}
+
+
+template<class Type>
+void Foam::vtkPV398Foam::convertPointField
+(
+    const GeometricField<Type, pointPatchField, pointMesh>& ptf,
+    const GeometricField<Type, fvPatchField, volMesh>& tf,
+    vtkMultiBlockDataSet* output,
+    const arrayRange& range,
+    const label datasetNo,
+    const polyDecomp& decomp
+)
+{
+    const label nComp = pTraits<Type>::nComponents;
+    const labelList& addPointCellLabels = decomp.addPointCellLabels();
+    const labelList& pointMap = decomp.pointMap();
+
+    // use a pointMap or address directly into mesh
+    label nPoints;
+    if (pointMap.size())
+    {
+        nPoints = pointMap.size();
+    }
+    else
+    {
+        nPoints = ptf.size();
+    }
+
+    vtkFloatArray* pointData = vtkFloatArray::New();
+    pointData->SetNumberOfTuples(nPoints + addPointCellLabels.size());
+    pointData->SetNumberOfComponents(nComp);
+    pointData->Allocate(nComp*(nPoints + addPointCellLabels.size()));
+
+    // Note: using the name of the original volField
+    // not the name generated by the interpolation "volPointInterpolate(<name>)"
+
+    if (&tf != &GeometricField<Type, fvPatchField, volMesh>::null())
+    {
+        pointData->SetName(tf.name().c_str());
+    }
+    else
+    {
+        pointData->SetName(ptf.name().c_str());
+    }
+
+    if (debug)
+    {
+        Info<< "convert convertPointField: "
+            << ptf.name()
+            << " size = " << nPoints
+            << " nComp=" << nComp
+            << " nTuples = " << (nPoints + addPointCellLabels.size())
+            <<  endl;
+    }
+
+    float vec[nComp];
+
+    if (pointMap.size())
+    {
+        forAll(pointMap, i)
+        {
+            const Type& t = ptf[pointMap[i]];
+            for (direction d=0; d<nComp; ++d)
+            {
+                vec[d] = component(t, d);
+            }
+            vtkOpenFOAMTupleRemap<Type>(vec);
+
+            pointData->InsertTuple(i, vec);
+        }
+    }
+    else
+    {
+        forAll(ptf, i)
+        {
+            const Type& t = ptf[i];
+            for (direction d=0; d<nComp; ++d)
+            {
+                vec[d] = component(t, d);
+            }
+            vtkOpenFOAMTupleRemap<Type>(vec);
+
+            pointData->InsertTuple(i, vec);
+        }
+    }
+
+    // continue insertion from here
+    label i = nPoints;
+
+    if (&tf != &GeometricField<Type, fvPatchField, volMesh>::null())
+    {
+        forAll(addPointCellLabels, apI)
+        {
+            const Type& t = tf[addPointCellLabels[apI]];
+            for (direction d=0; d<nComp; ++d)
+            {
+                vec[d] = component(t, d);
+            }
+            vtkOpenFOAMTupleRemap<Type>(vec);
+
+            pointData->InsertTuple(i++, vec);
+        }
+    }
+    else
+    {
+        forAll(addPointCellLabels, apI)
+        {
+            Type t = interpolatePointToCell(ptf, addPointCellLabels[apI]);
+            for (direction d=0; d<nComp; ++d)
+            {
+                vec[d] = component(t, d);
+            }
+            vtkOpenFOAMTupleRemap<Type>(vec);
+
+            pointData->InsertTuple(i++, vec);
+        }
+    }
+
+    vtkUnstructuredGrid::SafeDownCast
+    (
+        GetDataSetFromBlock(output, range, datasetNo)
+    )   ->GetPointData()
+        ->AddArray(pointData);
+
+    pointData->Delete();
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamTemplates.C b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamTemplates.C
new file mode 100644
index 0000000000000000000000000000000000000000..450a2e5b000e8b394c231e6f0eb9441d2fb85b04
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamTemplates.C
@@ -0,0 +1,99 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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 "vtkPV398Foam.H"
+
+// OpenFOAM includes
+#include "polyPatch.H"
+#include "primitivePatch.H"
+#include "vtkOpenFOAMPoints.H"
+
+// VTK includes
+#include "vtkCellArray.h"
+#include "vtkPoints.h"
+#include "vtkPolyData.h"
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+template<class PatchType>
+vtkPolyData* Foam::vtkPV398Foam::patchVTKMesh
+(
+    const word& name,
+    const PatchType& p
+)
+{
+    vtkPolyData* vtkmesh = vtkPolyData::New();
+
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::patchVTKMesh - " << name << endl;
+        printMemory();
+    }
+
+    // Convert OpenFOAM mesh vertices to VTK
+    const Foam::pointField& points = p.localPoints();
+
+    vtkPoints* vtkpoints = vtkPoints::New();
+    vtkpoints->Allocate(points.size());
+    forAll(points, i)
+    {
+        vtkInsertNextOpenFOAMPoint(vtkpoints, points[i]);
+    }
+
+    vtkmesh->SetPoints(vtkpoints);
+    vtkpoints->Delete();
+
+
+    // Add faces as polygons
+    const faceList& faces = p.localFaces();
+
+    vtkCellArray* vtkcells = vtkCellArray::New();
+    vtkcells->Allocate(faces.size());
+    forAll(faces, faceI)
+    {
+        const face& f = faces[faceI];
+        vtkIdType nodeIds[f.size()];
+
+        forAll(f, fp)
+        {
+            nodeIds[fp] = f[fp];
+        }
+        vtkcells->InsertNextCell(f.size(), nodeIds);
+    }
+
+    vtkmesh->SetPolys(vtkcells);
+    vtkcells->Delete();
+
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398Foam::patchVTKMesh - " << name << endl;
+        printMemory();
+    }
+
+    return vtkmesh;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamUpdateInfo.C b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamUpdateInfo.C
new file mode 100644
index 0000000000000000000000000000000000000000..fb155dc49e81eef94f469475338fe21eeb590ae6
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamUpdateInfo.C
@@ -0,0 +1,724 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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 "vtkPV398Foam.H"
+
+// OpenFOAM includes
+#include "cellSet.H"
+#include "faceSet.H"
+#include "pointSet.H"
+#include "IOobjectList.H"
+#include "IOPtrList.H"
+#include "polyBoundaryMeshEntries.H"
+#include "entry.H"
+#include "Cloud.H"
+#include "vtkPV398FoamReader.h"
+
+// local headers
+#include "vtkPV398FoamAddToSelection.H"
+#include "vtkPV398FoamUpdateInfoFields.H"
+
+// VTK includes
+#include "vtkDataArraySelection.h"
+
+
+// * * * * * * * * * * * * * * * Private Classes * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+//- A class for reading zone information without requiring a mesh
+class zonesEntries
+:
+    public regIOobject,
+    public PtrList<entry>
+{
+
+public:
+
+    // Constructors
+
+        explicit zonesEntries(const IOobject& io)
+        :
+            regIOobject(io),
+            PtrList<entry>(readStream("regIOobject"))
+        {
+            close();
+        }
+
+   // Member functions
+
+        bool writeData(Ostream&) const
+        {
+            notImplemented("zonesEntries::writeData(Ostream&) const");
+            return false;
+        }
+};
+
+}
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+template<class ZoneType>
+Foam::wordList Foam::vtkPV398Foam::getZoneNames
+(
+    const ZoneMesh<ZoneType, polyMesh>& zmesh
+) const
+{
+    wordList names(zmesh.size());
+    label nZone = 0;
+
+    forAll(zmesh, zoneI)
+    {
+        if (zmesh[zoneI].size())
+        {
+            names[nZone++] = zmesh[zoneI].name();
+        }
+    }
+    names.setSize(nZone);
+
+    return names;
+}
+
+
+Foam::wordList Foam::vtkPV398Foam::getZoneNames(const word& zoneType) const
+{
+    wordList names;
+
+    // mesh not loaded - read from file
+    IOobject ioObj
+    (
+        zoneType,
+        dbPtr_().findInstance
+        (
+            meshDir_,
+            zoneType,
+            IOobject::READ_IF_PRESENT
+        ),
+        meshDir_,
+        dbPtr_(),
+        IOobject::READ_IF_PRESENT,
+        IOobject::NO_WRITE,
+        false
+    );
+
+    if (ioObj.headerOk())
+    {
+        zonesEntries zones(ioObj);
+
+        names.setSize(zones.size());
+        forAll(zones, zoneI)
+        {
+            names[zoneI] = zones[zoneI].keyword();
+        }
+    }
+
+    return names;
+}
+
+
+void Foam::vtkPV398Foam::updateInfoInternalMesh
+(
+    vtkDataArraySelection* arraySelection
+)
+{
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::updateInfoInternalMesh" << endl;
+    }
+
+    // Determine mesh parts (internalMesh, patches...)
+    //- Add internal mesh as first entry
+    arrayRangeVolume_.reset(arraySelection->GetNumberOfArrays());
+    arraySelection->AddArray
+    (
+        "internalMesh"
+    );
+    arrayRangeVolume_ += 1;
+
+    if (debug)
+    {
+        // just for debug info
+        getSelectedArrayEntries(arraySelection);
+
+        Info<< "<end> Foam::vtkPV398Foam::updateInfoInternalMesh" << endl;
+    }
+}
+
+
+void Foam::vtkPV398Foam::updateInfoLagrangian
+(
+    vtkDataArraySelection* arraySelection
+)
+{
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::updateInfoLagrangian" << nl
+            << "    " << dbPtr_->timePath()/cloud::prefix << endl;
+    }
+
+
+    // use the db directly since this might be called without a mesh,
+    // but the region must get added back in
+    fileName lagrangianPrefix(cloud::prefix);
+    if (meshRegion_ != polyMesh::defaultRegion)
+    {
+        lagrangianPrefix = meshRegion_/cloud::prefix;
+    }
+
+    // Search for list of lagrangian objects for this time
+    fileNameList cloudDirs
+    (
+        readDir(dbPtr_->timePath()/lagrangianPrefix, fileName::DIRECTORY)
+    );
+
+    arrayRangeLagrangian_.reset(arraySelection->GetNumberOfArrays());
+
+    int nClouds = 0;
+    forAll(cloudDirs, cloudI)
+    {
+        // Add cloud to GUI list
+        arraySelection->AddArray
+        (
+            (cloudDirs[cloudI] + " - lagrangian").c_str()
+        );
+
+        ++nClouds;
+    }
+    arrayRangeLagrangian_ += nClouds;
+
+    if (debug)
+    {
+        // just for debug info
+        getSelectedArrayEntries(arraySelection);
+
+        Info<< "<end> Foam::vtkPV398Foam::updateInfoLagrangian" << endl;
+    }
+}
+
+
+void Foam::vtkPV398Foam::updateInfoPatches
+(
+    vtkDataArraySelection* arraySelection,
+    stringList& enabledEntries
+)
+{
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::updateInfoPatches"
+            << " [meshPtr=" << (meshPtr_ ? "set" : "NULL") << "]" << endl;
+    }
+
+
+    HashSet<string> enabledEntriesSet(enabledEntries);
+
+    arrayRangePatches_.reset(arraySelection->GetNumberOfArrays());
+
+    int nPatches = 0;
+    if (meshPtr_)
+    {
+        const polyBoundaryMesh& patches = meshPtr_->boundaryMesh();
+        const HashTable<labelList, word>& groups = patches.groupPatchIDs();
+        const wordList allPatchNames = patches.names();
+
+        // Add patch groups
+        // ~~~~~~~~~~~~~~~~
+
+        for
+        (
+            HashTable<labelList, word>::const_iterator iter = groups.begin();
+            iter != groups.end();
+            ++iter
+        )
+        {
+            const word& groupName = iter.key();
+            const labelList& patchIDs = iter();
+
+            label nFaces = 0;
+            forAll(patchIDs, i)
+            {
+                nFaces += patches[patchIDs[i]].size();
+            }
+
+            // Valid patch if nFace > 0 - add patch to GUI list
+            if (nFaces)
+            {
+                string vtkGrpName = groupName + " - group";
+                arraySelection->AddArray(vtkGrpName.c_str());
+
+                ++nPatches;
+
+                if (enabledEntriesSet.found(vtkGrpName))
+                {
+                    if (!reader_->GetShowGroupsOnly())
+                    {
+                        enabledEntriesSet.erase(vtkGrpName);
+                        forAll(patchIDs, i)
+                        {
+                            const polyPatch& pp = patches[patchIDs[i]];
+                            if (pp.size())
+                            {
+                                string vtkPatchName = pp.name() + " - patch";
+                                enabledEntriesSet.insert(vtkPatchName);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+
+        // Add patches
+        // ~~~~~~~~~~~
+
+        if (!reader_->GetShowGroupsOnly())
+        {
+            forAll(patches, patchI)
+            {
+                const polyPatch& pp = patches[patchI];
+
+                if (pp.size())
+                {
+                    // Add patch to GUI list
+                    arraySelection->AddArray
+                    (
+                        (pp.name() + " - patch").c_str()
+                    );
+
+                    ++nPatches;
+                }
+            }
+        }
+    }
+    else
+    {
+        // mesh not loaded - read from file
+        // but this could fail if we've supplied a bad region name
+        IOobject ioObj
+        (
+            "boundary",
+            dbPtr_().findInstance
+            (
+                meshDir_,
+                "boundary",
+                IOobject::READ_IF_PRESENT
+            ),
+            meshDir_,
+            dbPtr_(),
+            IOobject::READ_IF_PRESENT,
+            IOobject::NO_WRITE,
+            false
+        );
+
+        // this should only ever fail if the mesh region doesn't exist
+        if (ioObj.headerOk())
+        {
+            polyBoundaryMeshEntries patchEntries(ioObj);
+
+
+            // Read patches and determine sizes
+            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+            wordList names(patchEntries.size());
+            labelList sizes(patchEntries.size());
+
+            forAll(patchEntries, patchI)
+            {
+                const dictionary& patchDict = patchEntries[patchI].dict();
+
+                sizes[patchI] = readLabel(patchDict.lookup("nFaces"));
+                names[patchI] = patchEntries[patchI].keyword();
+            }
+
+
+            // Add (non-zero) patch groups to the list of mesh parts
+            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+            HashTable<labelList, word> groups(patchEntries.size());
+
+            forAll(patchEntries, patchI)
+            {
+                const dictionary& patchDict = patchEntries[patchI].dict();
+
+                wordList groupNames;
+                patchDict.readIfPresent("inGroups", groupNames);
+
+                forAll(groupNames, groupI)
+                {
+                    HashTable<labelList, word>::iterator iter = groups.find
+                    (
+                        groupNames[groupI]
+                    );
+                    if (iter != groups.end())
+                    {
+                        iter().append(patchI);
+                    }
+                    else
+                    {
+                        groups.insert(groupNames[groupI], labelList(1, patchI));
+                    }
+                }
+            }
+
+            for
+            (
+                HashTable<labelList, word>::const_iterator iter =
+                    groups.begin();
+                iter != groups.end();
+                ++iter
+            )
+            {
+                const word& groupName = iter.key();
+                const labelList& patchIDs = iter();
+
+                label nFaces = 0;
+                forAll(patchIDs, i)
+                {
+                    nFaces += sizes[patchIDs[i]];
+                }
+
+                // Valid patch if nFace > 0 - add patch to GUI list
+                if (nFaces)
+                {
+                    string vtkGrpName = groupName + " - group";
+                    arraySelection->AddArray(vtkGrpName.c_str());
+
+                    ++nPatches;
+
+                    if (enabledEntriesSet.found(vtkGrpName))
+                    {
+                        if (!reader_->GetShowGroupsOnly())
+                        {
+                            enabledEntriesSet.erase(vtkGrpName);
+                            forAll(patchIDs, i)
+                            {
+                                if (sizes[patchIDs[i]])
+                                {
+                                    string vtkPatchName =
+                                        names[patchIDs[i]] + " - patch";
+                                    enabledEntriesSet.insert(vtkPatchName);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+
+            // Add (non-zero) patches to the list of mesh parts
+            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+            if (!reader_->GetShowGroupsOnly())
+            {
+                forAll(names, patchI)
+                {
+                    // Valid patch if nFace > 0 - add patch to GUI list
+                    if (sizes[patchI])
+                    {
+                        arraySelection->AddArray
+                        (
+                            (names[patchI] + " - patch").c_str()
+                        );
+
+                        ++nPatches;
+                    }
+                }
+            }
+        }
+    }
+    arrayRangePatches_ += nPatches;
+
+    // Update enabled entries in case of group selection
+    enabledEntries = enabledEntriesSet.toc();
+
+    if (debug)
+    {
+        // just for debug info
+        getSelectedArrayEntries(arraySelection);
+
+        Info<< "<end> Foam::vtkPV398Foam::updateInfoPatches" << endl;
+    }
+}
+
+
+void Foam::vtkPV398Foam::updateInfoZones
+(
+    vtkDataArraySelection* arraySelection
+)
+{
+    if (!reader_->GetIncludeZones())
+    {
+        return;
+    }
+
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::updateInfoZones"
+            << " [meshPtr=" << (meshPtr_ ? "set" : "NULL") << "]" << endl;
+    }
+
+    wordList namesLst;
+
+    //
+    // cellZones information
+    // ~~~~~~~~~~~~~~~~~~~~~
+    if (meshPtr_)
+    {
+        namesLst = getZoneNames(meshPtr_->cellZones());
+    }
+    else
+    {
+        namesLst = getZoneNames("cellZones");
+    }
+
+    arrayRangeCellZones_.reset(arraySelection->GetNumberOfArrays());
+    forAll(namesLst, elemI)
+    {
+        arraySelection->AddArray
+        (
+            (namesLst[elemI] + " - cellZone").c_str()
+        );
+    }
+    arrayRangeCellZones_ += namesLst.size();
+
+
+    //
+    // faceZones information
+    // ~~~~~~~~~~~~~~~~~~~~~
+    if (meshPtr_)
+    {
+        namesLst = getZoneNames(meshPtr_->faceZones());
+    }
+    else
+    {
+        namesLst = getZoneNames("faceZones");
+    }
+
+    arrayRangeFaceZones_.reset(arraySelection->GetNumberOfArrays());
+    forAll(namesLst, elemI)
+    {
+        arraySelection->AddArray
+        (
+            (namesLst[elemI] + " - faceZone").c_str()
+        );
+    }
+    arrayRangeFaceZones_ += namesLst.size();
+
+
+    //
+    // pointZones information
+    // ~~~~~~~~~~~~~~~~~~~~~~
+    if (meshPtr_)
+    {
+        namesLst = getZoneNames(meshPtr_->pointZones());
+    }
+    else
+    {
+        namesLst = getZoneNames("pointZones");
+    }
+
+    arrayRangePointZones_.reset(arraySelection->GetNumberOfArrays());
+    forAll(namesLst, elemI)
+    {
+        arraySelection->AddArray
+        (
+            (namesLst[elemI] + " - pointZone").c_str()
+        );
+    }
+    arrayRangePointZones_ += namesLst.size();
+
+    if (debug)
+    {
+        // just for debug info
+        getSelectedArrayEntries(arraySelection);
+
+        Info<< "<end> Foam::vtkPV398Foam::updateInfoZones" << endl;
+    }
+}
+
+
+void Foam::vtkPV398Foam::updateInfoSets
+(
+    vtkDataArraySelection* arraySelection
+)
+{
+    if (!reader_->GetIncludeSets())
+    {
+        return;
+    }
+
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::updateInfoSets" << endl;
+    }
+
+    // Add names of sets. Search for last time directory with a sets
+    // subdirectory. Take care not to search beyond the last mesh.
+
+    word facesInstance = dbPtr_().findInstance
+    (
+        meshDir_,
+        "faces",
+        IOobject::READ_IF_PRESENT
+    );
+
+    word setsInstance = dbPtr_().findInstance
+    (
+        meshDir_/"sets",
+        word::null,
+        IOobject::READ_IF_PRESENT,
+        facesInstance
+    );
+
+    IOobjectList objects(dbPtr_(), setsInstance, meshDir_/"sets");
+
+    if (debug)
+    {
+        Info<< "     Foam::vtkPV398Foam::updateInfoSets read "
+            << objects.names() << " from " << setsInstance << endl;
+    }
+
+
+    arrayRangeCellSets_.reset(arraySelection->GetNumberOfArrays());
+    arrayRangeCellSets_ += addToSelection<cellSet>
+    (
+        arraySelection,
+        objects,
+        " - cellSet"
+    );
+
+    arrayRangeFaceSets_.reset(arraySelection->GetNumberOfArrays());
+    arrayRangeFaceSets_ += addToSelection<faceSet>
+    (
+        arraySelection,
+        objects,
+        " - faceSet"
+    );
+
+    arrayRangePointSets_.reset(arraySelection->GetNumberOfArrays());
+    arrayRangePointSets_ += addToSelection<pointSet>
+    (
+        arraySelection,
+        objects,
+        " - pointSet"
+    );
+
+    if (debug)
+    {
+        // just for debug info
+        getSelectedArrayEntries(arraySelection);
+
+        Info<< "<end> Foam::vtkPV398Foam::updateInfoSets" << endl;
+    }
+}
+
+
+void Foam::vtkPV398Foam::updateInfoLagrangianFields()
+{
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::updateInfoLagrangianFields"
+            << endl;
+    }
+
+    vtkDataArraySelection* fieldSelection =
+        reader_->GetLagrangianFieldSelection();
+
+    // preserve the enabled selections
+    stringList enabledEntries = getSelectedArrayEntries(fieldSelection);
+    fieldSelection->RemoveAllArrays();
+
+    // TODO - currently only get fields from ONE cloud
+    // have to decide if the second set of fields get mixed in
+    // or dealt with separately
+
+    const arrayRange& range = arrayRangeLagrangian_;
+    if (range.empty())
+    {
+        return;
+    }
+
+    int partId = range.start();
+    word cloudName = getPartName(partId);
+
+    // use the db directly since this might be called without a mesh,
+    // but the region must get added back in
+    fileName lagrangianPrefix(cloud::prefix);
+    if (meshRegion_ != polyMesh::defaultRegion)
+    {
+        lagrangianPrefix = meshRegion_/cloud::prefix;
+    }
+
+    IOobjectList objects
+    (
+        dbPtr_(),
+        dbPtr_().timeName(),
+        lagrangianPrefix/cloudName
+    );
+
+    addToSelection<IOField<label> >
+    (
+        fieldSelection,
+        objects
+    );
+    addToSelection<IOField<scalar> >
+    (
+        fieldSelection,
+        objects
+    );
+    addToSelection<IOField<vector> >
+    (
+        fieldSelection,
+        objects
+    );
+    addToSelection<IOField<sphericalTensor> >
+    (
+        fieldSelection,
+
+        objects
+    );
+    addToSelection<IOField<symmTensor> >
+    (
+        fieldSelection,
+        objects
+    );
+    addToSelection<IOField<tensor> >
+    (
+        fieldSelection,
+        objects
+    );
+
+    // restore the enabled selections
+    setSelectedArrayEntries(fieldSelection, enabledEntries);
+
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398Foam::updateInfoLagrangianFields - "
+            << "lagrangian objects.size() = " << objects.size() << endl;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamUpdateInfoFields.H b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamUpdateInfoFields.H
new file mode 100644
index 0000000000000000000000000000000000000000..0d864002c79b1096ca98f1834d2029b935e397c8
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamUpdateInfoFields.H
@@ -0,0 +1,115 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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/>.
+
+InClass
+    vtkPV398Foam
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef vtkPV398FoamUpdateInfoFields_H
+#define vtkPV398FoamUpdateInfoFields_H
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+template<template<class> class patchType, class meshType>
+void Foam::vtkPV398Foam::updateInfoFields
+(
+    vtkDataArraySelection* select
+)
+{
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398Foam::updateInfoFields <"
+            << meshType::Mesh::typeName
+            << "> [meshPtr=" << (meshPtr_ ? "set" : "NULL") << "]"
+            << endl;
+    }
+
+    stringList enabledEntries;
+    // enable 'p' and 'U' on the first call
+    if (select->GetNumberOfArrays() == 0 && !meshPtr_)
+    {
+        enabledEntries.setSize(2);
+        enabledEntries[0] = "p";
+        enabledEntries[1] = "U";
+    }
+    else
+    {
+        // preserve the enabled selections
+        enabledEntries = getSelectedArrayEntries(select);
+    }
+
+    select->RemoveAllArrays();
+
+    // use the db directly since this might be called without a mesh,
+    // but the region must get added back in
+    word regionPrefix;
+    if (meshRegion_ != polyMesh::defaultRegion)
+    {
+        regionPrefix = meshRegion_;
+    }
+
+    // Search for list of objects for this time and mesh region
+    IOobjectList objects(dbPtr_(), dbPtr_().timeName(), regionPrefix);
+
+    //- Add volume fields to GUI
+    addToSelection<GeometricField<scalar, patchType, meshType> >
+    (
+        select,
+        objects
+    );
+    addToSelection<GeometricField<vector, patchType, meshType> >
+    (
+        select,
+        objects
+    );
+    addToSelection<GeometricField<sphericalTensor, patchType, meshType> >
+    (
+        select,
+        objects
+    );
+    addToSelection<GeometricField<symmTensor, patchType, meshType> >
+    (
+        select,
+        objects
+    );
+    addToSelection<GeometricField<tensor, patchType, meshType> >
+    (
+        select,
+        objects
+    );
+
+    // restore the enabled selections
+    setSelectedArrayEntries(select, enabledEntries);
+
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398Foam::updateInfoFields" << endl;
+    }
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamUtils.C b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamUtils.C
new file mode 100644
index 0000000000000000000000000000000000000000..0ca381b0d5acf6e71aae74462ce0c5f5ed0c403b
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamUtils.C
@@ -0,0 +1,340 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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/>.
+
+Description
+    Misc helper methods and utilities
+
+\*---------------------------------------------------------------------------*/
+
+#include "vtkPV398Foam.H"
+#include "vtkPV398FoamReader.h"
+
+// OpenFOAM includes
+#include "fvMesh.H"
+#include "Time.H"
+#include "IFstream.H"
+#include "memInfo.H"
+
+// VTK includes
+#include "vtkDataArraySelection.h"
+#include "vtkDataSet.h"
+#include "vtkMultiBlockDataSet.h"
+#include "vtkInformation.h"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    //! \cond fileScope
+    //  Extract up to the first non-word characters
+    inline word getFirstWord(const char* str)
+    {
+        if (str)
+        {
+            label n = 0;
+            while (str[n] && word::valid(str[n]))
+            {
+                ++n;
+            }
+            return word(str, n, true);
+        }
+        else
+        {
+            return word::null;
+        }
+
+    }
+    //! \endcond
+
+} // End namespace Foam
+
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+void Foam::vtkPV398Foam::AddToBlock
+(
+    vtkMultiBlockDataSet* output,
+    vtkDataSet* dataset,
+    const arrayRange& range,
+    const label datasetNo,
+    const std::string& datasetName
+)
+{
+    const int blockNo = range.block();
+
+    vtkDataObject* blockDO = output->GetBlock(blockNo);
+    vtkMultiBlockDataSet* block = vtkMultiBlockDataSet::SafeDownCast(blockDO);
+
+    if (!block)
+    {
+        if (blockDO)
+        {
+            FatalErrorIn("Foam::vtkPV398Foam::AddToBlock")
+                << "Block already has a vtkDataSet assigned to it"
+                << endl;
+            return;
+        }
+
+        block = vtkMultiBlockDataSet::New();
+        output->SetBlock(blockNo, block);
+        block->Delete();
+    }
+
+    if (debug)
+    {
+        Info<< "block[" << blockNo << "] has "
+            << block->GetNumberOfBlocks()
+            <<  " datasets prior to adding set " << datasetNo
+            <<  " with name: " << datasetName << endl;
+    }
+
+    block->SetBlock(datasetNo, dataset);
+
+    // name the block when assigning dataset 0
+    if (datasetNo == 0)
+    {
+        output->GetMetaData(blockNo)->Set
+        (
+            vtkCompositeDataSet::NAME(),
+            range.name()
+        );
+    }
+
+    if (datasetName.size())
+    {
+        block->GetMetaData(datasetNo)->Set
+        (
+            vtkCompositeDataSet::NAME(),
+            datasetName.c_str()
+        );
+    }
+}
+
+
+vtkDataSet* Foam::vtkPV398Foam::GetDataSetFromBlock
+(
+    vtkMultiBlockDataSet* output,
+    const arrayRange& range,
+    const label datasetNo
+)
+{
+    const int blockNo = range.block();
+
+    vtkDataObject* blockDO = output->GetBlock(blockNo);
+    vtkMultiBlockDataSet* block = vtkMultiBlockDataSet::SafeDownCast(blockDO);
+
+    if (block)
+    {
+        return vtkDataSet::SafeDownCast(block->GetBlock(datasetNo));
+    }
+
+    return 0;
+}
+
+
+// ununsed at the moment
+Foam::label Foam::vtkPV398Foam::GetNumberOfDataSets
+(
+    vtkMultiBlockDataSet* output,
+    const arrayRange& range
+)
+{
+    const int blockNo = range.block();
+
+    vtkDataObject* blockDO = output->GetBlock(blockNo);
+    vtkMultiBlockDataSet* block = vtkMultiBlockDataSet::SafeDownCast(blockDO);
+    if (block)
+    {
+        return block->GetNumberOfBlocks();
+    }
+
+    return 0;
+}
+
+
+Foam::word Foam::vtkPV398Foam::getPartName(const int partId)
+{
+    return getFirstWord(reader_->GetPartArrayName(partId));
+}
+
+
+Foam::wordHashSet Foam::vtkPV398Foam::getSelected
+(
+    vtkDataArraySelection* select
+)
+{
+    int nElem = select->GetNumberOfArrays();
+    wordHashSet selections(2*nElem);
+
+    for (int elemI=0; elemI < nElem; ++elemI)
+    {
+        if (select->GetArraySetting(elemI))
+        {
+            selections.insert(getFirstWord(select->GetArrayName(elemI)));
+        }
+    }
+
+    return selections;
+}
+
+
+Foam::wordHashSet Foam::vtkPV398Foam::getSelected
+(
+    vtkDataArraySelection* select,
+    const arrayRange& range
+)
+{
+    int nElem = select->GetNumberOfArrays();
+    wordHashSet selections(2*nElem);
+
+    for (int elemI = range.start(); elemI < range.end(); ++elemI)
+    {
+        if (select->GetArraySetting(elemI))
+        {
+            selections.insert(getFirstWord(select->GetArrayName(elemI)));
+        }
+    }
+
+    return selections;
+}
+
+
+Foam::stringList Foam::vtkPV398Foam::getSelectedArrayEntries
+(
+    vtkDataArraySelection* select
+)
+{
+    stringList selections(select->GetNumberOfArrays());
+    label nElem = 0;
+
+    forAll(selections, elemI)
+    {
+        if (select->GetArraySetting(elemI))
+        {
+            selections[nElem++] = select->GetArrayName(elemI);
+        }
+    }
+    selections.setSize(nElem);
+
+
+    if (debug)
+    {
+        label nElem = select->GetNumberOfArrays();
+        Info<< "available(";
+        for (int elemI = 0; elemI < nElem; ++elemI)
+        {
+            Info<< " \"" << select->GetArrayName(elemI) << "\"";
+        }
+        Info<< " )\nselected(";
+
+        forAll(selections, elemI)
+        {
+            Info<< " " << selections[elemI];
+        }
+        Info<< " )\n";
+    }
+
+    return selections;
+}
+
+
+Foam::stringList Foam::vtkPV398Foam::getSelectedArrayEntries
+(
+    vtkDataArraySelection* select,
+    const arrayRange& range
+)
+{
+    stringList selections(range.size());
+    label nElem = 0;
+
+    for (int elemI = range.start(); elemI < range.end(); ++elemI)
+    {
+        if (select->GetArraySetting(elemI))
+        {
+            selections[nElem++] = select->GetArrayName(elemI);
+        }
+    }
+    selections.setSize(nElem);
+
+
+    if (debug)
+    {
+        Info<< "available(";
+        for (int elemI = range.start(); elemI < range.end(); ++elemI)
+        {
+            Info<< " \"" << select->GetArrayName(elemI) << "\"";
+        }
+        Info<< " )\nselected(";
+
+        forAll(selections, elemI)
+        {
+            Info<< " " << selections[elemI];
+        }
+        Info<< " )\n";
+    }
+
+    return selections;
+}
+
+
+void Foam::vtkPV398Foam::setSelectedArrayEntries
+(
+    vtkDataArraySelection* select,
+    const stringList& selections
+)
+{
+    const int nElem = select->GetNumberOfArrays();
+    select->DisableAllArrays();
+
+    // Loop through entries, setting values from selectedEntries
+    for (int elemI=0; elemI < nElem; ++elemI)
+    {
+        string arrayName(select->GetArrayName(elemI));
+
+        forAll(selections, elemI)
+        {
+            if (selections[elemI] == arrayName)
+            {
+                select->EnableArray(arrayName.c_str());
+                break;
+            }
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::vtkPV398Foam::printMemory()
+{
+    memInfo mem;
+
+    if (mem.valid())
+    {
+        Info<< "mem peak/size/rss: " << mem << "\n";
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamVolFields.H b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamVolFields.H
new file mode 100644
index 0000000000000000000000000000000000000000..b1b92c0c72df8c8f2717767c76503cdeec7bb707
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398FoamReader/vtkPV398Foam/vtkPV398FoamVolFields.H
@@ -0,0 +1,380 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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/>.
+
+InClass
+    vtkPV398Foam
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef vtkPV398FoamVolFields_H
+#define vtkPV398FoamVolFields_H
+
+// OpenFOAM includes
+#include "emptyFvPatchField.H"
+#include "wallPolyPatch.H"
+#include "faceSet.H"
+#include "volPointInterpolation.H"
+
+#include "vtkPV398FoamFaceField.H"
+#include "vtkPV398FoamPatchField.H"
+
+#include "vtkOpenFOAMTupleRemap.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+template<class Type>
+void Foam::vtkPV398Foam::convertVolFields
+(
+    const fvMesh& mesh,
+    const PtrList<PrimitivePatchInterpolation<primitivePatch> >& ppInterpList,
+    const IOobjectList& objects,
+    const bool interpFields,
+    vtkMultiBlockDataSet* output
+)
+{
+    const polyBoundaryMesh& patches = mesh.boundaryMesh();
+
+    forAllConstIter(IOobjectList, objects, iter)
+    {
+        // restrict to GeometricField<Type, ...>
+        if
+        (
+            iter()->headerClassName()
+         != GeometricField<Type, fvPatchField, volMesh>::typeName
+        )
+        {
+            continue;
+        }
+
+        // Load field
+        GeometricField<Type, fvPatchField, volMesh> tf
+        (
+            *iter(),
+            mesh
+        );
+
+        // Interpolated field (demand driven)
+        autoPtr<GeometricField<Type, pointPatchField, pointMesh> > ptfPtr;
+        if (interpFields)
+        {
+            if (debug)
+            {
+                Info<< "convertVolFieldBlock interpolating:" << tf.name()
+                    << endl;
+            }
+
+            ptfPtr.reset
+            (
+                volPointInterpolation::New(tf.mesh()).interpolate(tf).ptr()
+            );
+        }
+
+
+        // Convert activated internalMesh regions
+        convertVolFieldBlock
+        (
+            tf,
+            ptfPtr,
+            output,
+            arrayRangeVolume_,
+            regionPolyDecomp_
+        );
+
+        // Convert activated cellZones
+        convertVolFieldBlock
+        (
+            tf,
+            ptfPtr,
+            output,
+            arrayRangeCellZones_,
+            zonePolyDecomp_
+        );
+
+        // Convert activated cellSets
+        convertVolFieldBlock
+        (
+            tf,
+            ptfPtr,
+            output,
+            arrayRangeCellSets_,
+            csetPolyDecomp_
+        );
+
+
+        //
+        // Convert patches - if activated
+        //
+        for
+        (
+            int partId = arrayRangePatches_.start();
+            partId < arrayRangePatches_.end();
+            ++partId
+        )
+        {
+            const word patchName = getPartName(partId);
+            const label datasetNo = partDataset_[partId];
+            const label patchId = patches.findPatchID(patchName);
+
+            if (!partStatus_[partId] || datasetNo < 0 || patchId < 0)
+            {
+                continue;
+            }
+
+            const fvPatchField<Type>& ptf = tf.boundaryField()[patchId];
+
+            if
+            (
+                isType<emptyFvPatchField<Type> >(ptf)
+             ||
+                (
+                    reader_->GetExtrapolatePatches()
+                && !polyPatch::constraintType(patches[patchId].type())
+                )
+            )
+            {
+                fvPatch p(ptf.patch().patch(), tf.mesh().boundary());
+
+                tmp<Field<Type> > tpptf
+                (
+                    fvPatchField<Type>(p, tf).patchInternalField()
+                );
+
+                convertPatchField
+                (
+                    tf.name(),
+                    tpptf(),
+                    output,
+                    arrayRangePatches_,
+                    datasetNo
+                );
+
+                if (interpFields)
+                {
+                    convertPatchPointField
+                    (
+                        tf.name(),
+                        ppInterpList[patchId].faceToPointInterpolate(tpptf)(),
+                        output,
+                        arrayRangePatches_,
+                        datasetNo
+                    );
+                }
+            }
+            else
+            {
+                convertPatchField
+                (
+                    tf.name(),
+                    ptf,
+                    output,
+                    arrayRangePatches_,
+                    datasetNo
+                );
+
+                if (interpFields)
+                {
+                    convertPatchPointField
+                    (
+                        tf.name(),
+                        ppInterpList[patchId].faceToPointInterpolate(ptf)(),
+                        output,
+                        arrayRangePatches_,
+                        datasetNo
+                    );
+                }
+            }
+        }
+
+        //
+        // Convert face zones - if activated
+        //
+        for
+        (
+            int partId = arrayRangeFaceZones_.start();
+            partId < arrayRangeFaceZones_.end();
+            ++partId
+        )
+        {
+            const word zoneName = getPartName(partId);
+            const label datasetNo = partDataset_[partId];
+
+            if (!partStatus_[partId] || datasetNo < 0)
+            {
+                continue;
+            }
+
+            const faceZoneMesh& zMesh = mesh.faceZones();
+            const label zoneId = zMesh.findZoneID(zoneName);
+
+            if (zoneId < 0)
+            {
+                continue;
+            }
+
+            convertFaceField
+            (
+                tf,
+                output,
+                arrayRangeFaceZones_,
+                datasetNo,
+                mesh,
+                zMesh[zoneId]
+            );
+
+            // TODO: points
+        }
+
+        //
+        // Convert face sets - if activated
+        //
+        for
+        (
+            int partId = arrayRangeFaceSets_.start();
+            partId < arrayRangeFaceSets_.end();
+            ++partId
+        )
+        {
+            const word selectName = getPartName(partId);
+            const label datasetNo = partDataset_[partId];
+
+            if (!partStatus_[partId] || datasetNo < 0)
+            {
+                continue;
+            }
+
+            const faceSet fSet(mesh, selectName);
+
+            convertFaceField
+            (
+                tf,
+                output,
+                arrayRangeFaceSets_,
+                datasetNo,
+                mesh,
+                fSet.toc()
+            );
+
+            // TODO: points
+        }
+    }
+}
+
+
+template<class Type>
+void Foam::vtkPV398Foam::convertVolFieldBlock
+(
+    const GeometricField<Type, fvPatchField, volMesh>& tf,
+    autoPtr<GeometricField<Type, pointPatchField, pointMesh> >& ptfPtr,
+    vtkMultiBlockDataSet* output,
+    const arrayRange& range,
+    const List<polyDecomp>& decompLst
+)
+{
+    for (int partId = range.start(); partId < range.end(); ++partId)
+    {
+        const label datasetNo = partDataset_[partId];
+
+        if (datasetNo >= 0 && partStatus_[partId])
+        {
+            convertVolField
+            (
+                tf,
+                output,
+                range,
+                datasetNo,
+                decompLst[datasetNo]
+            );
+
+            if (ptfPtr.valid())
+            {
+                convertPointField
+                (
+                    ptfPtr(),
+                    tf,
+                    output,
+                    range,
+                    datasetNo,
+                    decompLst[datasetNo]
+                );
+            }
+        }
+    }
+}
+
+
+template<class Type>
+void Foam::vtkPV398Foam::convertVolField
+(
+    const GeometricField<Type, fvPatchField, volMesh>& tf,
+    vtkMultiBlockDataSet* output,
+    const arrayRange& range,
+    const label datasetNo,
+    const polyDecomp& decompInfo
+)
+{
+    const label nComp = pTraits<Type>::nComponents;
+    const labelList& superCells = decompInfo.superCells();
+
+    vtkFloatArray* celldata = vtkFloatArray::New();
+    celldata->SetNumberOfTuples(superCells.size());
+    celldata->SetNumberOfComponents(nComp);
+    celldata->Allocate(nComp*superCells.size());
+    celldata->SetName(tf.name().c_str());
+
+    if (debug)
+    {
+        Info<< "convert volField: "
+            << tf.name()
+            << " size = " << tf.size()
+            << " nComp=" << nComp
+            << " nTuples = " << superCells.size() <<  endl;
+    }
+
+    float vec[nComp];
+    forAll(superCells, i)
+    {
+        const Type& t = tf[superCells[i]];
+        for (direction d=0; d<nComp; ++d)
+        {
+            vec[d] = component(t, d);
+        }
+        vtkOpenFOAMTupleRemap<Type>(vec);
+
+        celldata->InsertTuple(i, vec);
+    }
+
+    vtkUnstructuredGrid::SafeDownCast
+    (
+        GetDataSetFromBlock(output, range, datasetNo)
+    )   ->GetCellData()
+        ->AddArray(celldata);
+
+    celldata->Delete();
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/Allwclean b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/Allwclean
new file mode 100755
index 0000000000000000000000000000000000000000..7b2b10c51bb4af79108e45f92e9375f1b33a1033
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/Allwclean
@@ -0,0 +1,11 @@
+#!/bin/sh
+cd ${0%/*} || exit 1    # run from this directory
+set -x
+
+# deal with client/server vs combined plugins
+rm -f $FOAM_LIBBIN/libPV398blockMeshReader*  2>/dev/null
+
+rm -rf PV398blockMeshReader/Make
+wclean libso vtkPV398blockMesh
+
+# ----------------------------------------------------------------- end-of-file
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/Allwmake b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/Allwmake
new file mode 100755
index 0000000000000000000000000000000000000000..59d6ed048c48ebbeb80f9a84f622111cd6d60bed
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/Allwmake
@@ -0,0 +1,17 @@
+#!/bin/sh
+cd ${0%/*} || exit 1    # run from this directory
+set -x
+
+if [ -d "$ParaView_DIR" -a -r "$ParaView_DIR" ]
+then
+    wmake libso vtkPV398blockMesh
+    (
+        cd PV398blockMeshReader
+        mkdir -p Make/$WM_OPTIONS > /dev/null 2>&1
+        cd Make/$WM_OPTIONS
+        cmake ../..
+        make
+    )
+fi
+
+# ----------------------------------------------------------------- end-of-file
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/PV398blockMeshReader/CMakeLists.txt b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/PV398blockMeshReader/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c03aa2bb0f8b83162adb9c8be4516ec3081ab16b
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/PV398blockMeshReader/CMakeLists.txt
@@ -0,0 +1,86 @@
+# create a plugin that adds a reader to the ParaView GUI
+# it is added in the file dialog when doing opens/saves.
+
+# The qrc file is processed by Qt's resource compiler (rcc)
+# the qrc file must have a resource prefix of "/ParaViewResources"
+# and ParaView will read anything contained under that prefix
+# the pqReader.xml file contains xml defining readers with their
+# file extensions and descriptions.
+
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+
+FIND_PACKAGE(ParaView REQUIRED)
+INCLUDE(${PARAVIEW_USE_FILE})
+
+LINK_DIRECTORIES(
+    $ENV{FOAM_LIBBIN}
+    $ENV{FOAM_EXT_LIBBIN}
+)
+
+INCLUDE_DIRECTORIES(
+    $ENV{WM_PROJECT_DIR}/src/OpenFOAM/lnInclude
+    $ENV{WM_PROJECT_DIR}/src/OSspecific/$ENV{WM_OSTYPE}/lnInclude
+    $ENV{WM_PROJECT_DIR}/src/meshing/blockMesh/lnInclude
+    ${PROJECT_SOURCE_DIR}/../vtkPV398blockMesh
+)
+
+ADD_DEFINITIONS(
+    -DWM_$ENV{WM_PRECISION_OPTION}
+)
+
+# Set output library destination to plugin folder
+SET(
+    LIBRARY_OUTPUT_PATH $ENV{PV_PLUGIN_PATH}
+    CACHE INTERNAL
+    "Single output directory for building all libraries."
+)
+
+#
+# Define combined plugin
+#
+
+# Extend the auto-generated panel
+QT4_WRAP_CPP(MOC_SRCS pqPV398blockMeshReaderPanel.h)
+
+ADD_PARAVIEW_OBJECT_PANEL(IFACES IFACE_SRCS
+  CLASS_NAME pqPV398blockMeshReaderPanel
+  XML_NAME  PV398blockMeshReader # name of SourceProxy in *SM.xml
+  XML_GROUP sources
+)
+
+ADD_PARAVIEW_PLUGIN(
+    PV398blockMeshReader_SM "1.0"
+    SERVER_MANAGER_XML PV398blockMeshReader_SM.xml
+    SERVER_MANAGER_SOURCES  vtkPV398blockMeshReader.cxx
+    GUI_INTERFACES ${IFACES}
+    GUI_SOURCES pqPV398blockMeshReaderPanel.cxx
+        ${MOC_SRCS} ${UI_SRCS} ${IFACE_SRCS}
+    GUI_RESOURCE_FILES PV398blockMeshReader.xml
+)
+
+
+# #
+# # Define the server-side portion of the reader plugin
+# #
+# ADD_PARAVIEW_PLUGIN(PV398blockMeshReader_SM "1.0"
+#   SERVER_MANAGER_XML PV398blockMeshReader_SM.xml
+#   SERVER_MANAGER_SOURCES vtkPV398blockMeshReader.cxx
+# )
+# #
+# # Define the client-side portion of the reader plugin
+# #
+# ADD_PARAVIEW_PLUGIN(
+#     PV398blockMeshReader "1.0"
+#     GUI_RESOURCES PV398blockMeshReader.qrc
+# )
+
+
+# Build the client-side plugin
+
+TARGET_LINK_LIBRARIES(
+    PV398blockMeshReader_SM
+    OpenFOAM
+    blockMesh
+    vtkPV398blockMesh
+)
+#-----------------------------------------------------------------------------
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/PV398blockMeshReader/PV398blockMeshReader.qrc b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/PV398blockMeshReader/PV398blockMeshReader.qrc
new file mode 100644
index 0000000000000000000000000000000000000000..5c0c189c5e8c4804790f59245d7fbf834667a1f9
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/PV398blockMeshReader/PV398blockMeshReader.qrc
@@ -0,0 +1,5 @@
+<RCC>
+  <qresource prefix="/ParaViewResources" >
+      <file>PV398blockMeshReader.xml</file>
+  </qresource>
+</RCC>
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/PV398blockMeshReader/PV398blockMeshReader.xml b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/PV398blockMeshReader/PV398blockMeshReader.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e9153d5d6d9f5a0a04c603dcfff6f0e6bfd9ffca
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/PV398blockMeshReader/PV398blockMeshReader.xml
@@ -0,0 +1,6 @@
+<ParaViewReaders>
+  <Reader name="PV398blockMeshReader"
+      extensions="blockMesh"
+      file_description="OpenFOAM blockMesh reader">
+  </Reader>
+</ParaViewReaders>
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/PV398blockMeshReader/PV398blockMeshReader_SM.xml b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/PV398blockMeshReader/PV398blockMeshReader_SM.xml
new file mode 100644
index 0000000000000000000000000000000000000000..4ac661c96e448a8b6c4dd916dff7ecf808b73cd4
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/PV398blockMeshReader/PV398blockMeshReader_SM.xml
@@ -0,0 +1,110 @@
+<ServerManagerConfiguration>
+  <ProxyGroup name="sources">
+  <SourceProxy
+    name="PV398blockMeshReader"
+    class="vtkPV398blockMeshReader">
+
+    <!-- File name - compulsory -->
+    <StringVectorProperty
+      name="FileName"
+      command="SetFileName"
+      number_of_elements="1"
+      animateable="0">
+      <FileListDomain name="files"/>
+      <Documentation>
+        Specifies the filename for the OpenFOAM blockMesh Reader.
+      </Documentation>
+    </StringVectorProperty>
+
+    <!-- Show Point Numbers check-box -->
+    <IntVectorProperty
+      name="UiShowPointNumbers"
+      command="SetShowPointNumbers"
+      number_of_elements="1"
+      default_values="1"
+      is_internal="1"
+      animateable="0">
+      <BooleanDomain name="bool"/>
+      <Documentation>
+        Show point numbers in render window.
+      </Documentation>
+    </IntVectorProperty>
+
+    <!-- Update GUI check box -->
+    <IntVectorProperty
+      name="UpdateGUI"
+      command="SetUpdateGUI"
+      number_of_elements="1"
+      default_values="0"
+      animateable="0">
+      <BooleanDomain name="bool"/>
+      <Documentation>
+        A simple way to cause a reader GUI modification.
+      </Documentation>
+    </IntVectorProperty>
+
+
+    <!--
+       | Selections
+       -->
+
+    <!-- Available Blocks array -->
+    <StringVectorProperty
+      name="BlockArrayStatus"
+      information_only="1">
+      <ArraySelectionInformationHelper attribute_name="Block"/>
+    </StringVectorProperty>
+    <StringVectorProperty
+      name="BlockStatus"
+      label="Blocks"
+      command="SetBlockArrayStatus"
+      number_of_elements="0"
+      repeat_command="1"
+      number_of_elements_per_command="2"
+      element_types="2 0"
+      information_property="BlockArrayStatus"
+      animateable="0">
+      <ArraySelectionDomain name="array_list">
+        <RequiredProperties>
+          <Property name="BlockArrayStatus" function="ArrayList"/>
+        </RequiredProperties>
+      </ArraySelectionDomain>
+      <Documentation>
+        This property contains a list of the blocks
+      </Documentation>
+    </StringVectorProperty>
+
+    <!-- Available CurvedEdges array -->
+    <StringVectorProperty
+      name="CurvedEdgesArrayStatus"
+      information_only="1">
+      <ArraySelectionInformationHelper attribute_name="CurvedEdges"/>
+    </StringVectorProperty>
+    <StringVectorProperty
+      name="CurvedEdgesStatus"
+      label="Curved Edges"
+      command="SetCurvedEdgesArrayStatus"
+      number_of_elements="0"
+      repeat_command="1"
+      number_of_elements_per_command="2"
+      element_types="2 0"
+      information_property="CurvedEdgesArrayStatus"
+      animateable="0">
+      <ArraySelectionDomain name="array_list">
+        <RequiredProperties>
+          <Property name="CurvedEdgesArrayStatus" function="ArrayList"/>
+        </RequiredProperties>
+      </ArraySelectionDomain>
+      <Documentation>
+        This property contains a list of the curved edges
+      </Documentation>
+    </StringVectorProperty>
+
+  <Hints>
+    <Property name="FileName" show="0"/>
+    <Property name="UiShowPointNumbers" show="0"/>
+  </Hints>
+
+  </SourceProxy>
+  </ProxyGroup>
+</ServerManagerConfiguration>
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/PV398blockMeshReader/pqPV398blockMeshReaderPanel.cxx b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/PV398blockMeshReader/pqPV398blockMeshReaderPanel.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..9d6ac19ae2404aa6eaea0209a34d5a716e09b0ab
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/PV398blockMeshReader/pqPV398blockMeshReaderPanel.cxx
@@ -0,0 +1,110 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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 "pqPV398blockMeshReaderPanel.h"
+
+// QT
+#include <QGridLayout>
+#include <QCheckBox>
+#include <QLabel>
+#include <QLayout>
+#include <QString>
+#include <QPushButton>
+#include <QtDebug>
+
+// Paraview <-> QT UI
+#include "pqAnimationScene.h"
+#include "pqApplicationCore.h"
+#include "pqPipelineRepresentation.h"
+#include "pqServerManagerModel.h"
+#include "pqView.h"
+
+// Paraview Server Manager
+#include "vtkSMDoubleVectorProperty.h"
+#include "vtkSMIntVectorProperty.h"
+#include "vtkSMProperty.h"
+#include "vtkSMSourceProxy.h"
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+pqPV398blockMeshReaderPanel::pqPV398blockMeshReaderPanel
+(
+    pqProxy *proxy,
+    QWidget *p
+)
+:
+    pqAutoGeneratedObjectPanel(proxy, p)
+{
+    // create first sublayout (at top of the panel)
+    QGridLayout *form = new QGridLayout();
+    this->PanelLayout->addLayout(form, 0, 0, 1, -1);
+
+    vtkSMProperty* prop = 0;
+    // checkbox for showing point numbers
+    if ((prop = this->proxy()->GetProperty("UiShowPointNumbers")) != 0)
+    {
+        prop->SetImmediateUpdate(true);
+
+        ShowPointNumbers_ = new QCheckBox("Show Point Numbers");
+        ShowPointNumbers_->setToolTip("Show point numbers in render window.");
+        ShowPointNumbers_->setChecked
+        (
+            vtkSMIntVectorProperty::SafeDownCast(prop)->GetElement(0)
+        );
+
+        form->addWidget(ShowPointNumbers_);
+
+        connect
+        (
+            ShowPointNumbers_,
+            SIGNAL(stateChanged(int)),
+            this,
+            SLOT(ShowPointNumbersToggled())
+        );
+    }
+
+}
+
+// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
+
+void pqPV398blockMeshReaderPanel::ShowPointNumbersToggled()
+{
+    vtkSMIntVectorProperty::SafeDownCast
+    (
+        this->proxy()->GetProperty("UiShowPointNumbers")
+    )->SetElement(0, ShowPointNumbers_->isChecked());
+
+    // update the active view
+    if (this->view())
+    {
+        this->view()->render();
+    }
+    // OR: update all views
+    // pqApplicationCore::instance()->render();
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/PV398blockMeshReader/pqPV398blockMeshReaderPanel.h b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/PV398blockMeshReader/pqPV398blockMeshReaderPanel.h
new file mode 100644
index 0000000000000000000000000000000000000000..ec8a1b44d9c1c3069308fa1b5e127ebe447275f2
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/PV398blockMeshReader/pqPV398blockMeshReaderPanel.h
@@ -0,0 +1,89 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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
+    pqPV398blockMeshReaderPanel
+
+Description
+    GUI modifications for the ParaView reader panel
+
+    A custom panel for the PV398blockMeshReader.
+
+SourceFiles
+    pqPV398blockMeshReaderPanel.cxx
+
+\*---------------------------------------------------------------------------*/
+#ifndef pqPV398blockMeshReaderPanel_h
+#define pqPV398blockMeshReaderPanel_h
+
+#include "pqAutoGeneratedObjectPanel.h"
+
+// Forward declaration of QT classes
+
+class QCheckBox;
+class QLineEdit;
+class QTimer;
+class QToolButton;
+
+// Forward declaration of ParaView classes
+class vtkSMSourceProxy;
+
+
+/*---------------------------------------------------------------------------*\
+                 Class pqPV398blockMeshReaderPanel Declaration
+\*---------------------------------------------------------------------------*/
+
+class pqPV398blockMeshReaderPanel
+:
+    public pqAutoGeneratedObjectPanel
+{
+    // Private data
+    Q_OBJECT;
+    typedef pqAutoGeneratedObjectPanel Superclass;
+
+    //- Show Point Numbers checkbox
+    QCheckBox* ShowPointNumbers_;
+
+protected slots:
+
+    void ShowPointNumbersToggled();
+
+
+public:
+
+    // Constructors
+
+        //- Construct from components
+        pqPV398blockMeshReaderPanel(pqProxy*, QWidget*);
+
+
+    //- Destructor
+    // virtual ~pqPV398blockMeshReaderPanel();
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/PV398blockMeshReader/vtkPV398blockMeshReader.cxx b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/PV398blockMeshReader/vtkPV398blockMeshReader.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..5b08a352496de60b4172a662294455c12c4b5126
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/PV398blockMeshReader/vtkPV398blockMeshReader.cxx
@@ -0,0 +1,419 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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 "vtkPV398blockMeshReader.h"
+
+#include "pqApplicationCore.h"
+#include "pqRenderView.h"
+#include "pqServerManagerModel.h"
+
+// VTK includes
+#include "vtkCallbackCommand.h"
+#include "vtkDataArraySelection.h"
+#include "vtkInformation.h"
+#include "vtkInformationVector.h"
+#include "vtkMultiBlockDataSet.h"
+#include "vtkObjectFactory.h"
+#include "vtkSMRenderViewProxy.h"
+#include "vtkStreamingDemandDrivenPipeline.h"
+#include "vtkStringArray.h"
+
+// OpenFOAM includes
+#include "vtkPV398blockMesh.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+vtkStandardNewMacro(vtkPV398blockMeshReader);
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+vtkPV398blockMeshReader::vtkPV398blockMeshReader()
+{
+    Debug = 0;
+    vtkDebugMacro(<<"Constructor");
+
+    SetNumberOfInputPorts(0);
+
+    FileName  = NULL;
+    foamData_ = NULL;
+
+    ShowPointNumbers = 1;
+    UpdateGUI = 0;
+
+    BlockSelection = vtkDataArraySelection::New();
+    CurvedEdgesSelection = vtkDataArraySelection::New();
+
+    // Setup the selection callback to modify this object when an array
+    // selection is changed.
+    SelectionObserver = vtkCallbackCommand::New();
+    SelectionObserver->SetCallback
+    (
+        &vtkPV398blockMeshReader::SelectionModifiedCallback
+    );
+    SelectionObserver->SetClientData(this);
+
+
+    BlockSelection->AddObserver
+    (
+        vtkCommand::ModifiedEvent,
+        this->SelectionObserver
+    );
+
+    CurvedEdgesSelection->AddObserver
+    (
+        vtkCommand::ModifiedEvent,
+        this->SelectionObserver
+    );
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+vtkPV398blockMeshReader::~vtkPV398blockMeshReader()
+{
+    vtkDebugMacro(<<"Deconstructor");
+
+    if (foamData_)
+    {
+        // remove point numbers
+        updatePointNumbersView(false);
+        delete foamData_;
+    }
+
+    if (FileName)
+    {
+        delete [] FileName;
+    }
+
+    BlockSelection->RemoveObserver(this->SelectionObserver);
+    CurvedEdgesSelection->RemoveObserver(this->SelectionObserver);
+
+    SelectionObserver->Delete();
+    BlockSelection->Delete();
+}
+
+
+// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
+
+// Do everything except set the output info
+int vtkPV398blockMeshReader::RequestInformation
+(
+    vtkInformation* vtkNotUsed(request),
+    vtkInformationVector** vtkNotUsed(inputVector),
+    vtkInformationVector* outputVector
+)
+{
+    vtkDebugMacro(<<"RequestInformation");
+
+    if (Foam::vtkPV398blockMesh::debug)
+    {
+        cout<<"REQUEST_INFORMATION\n";
+    }
+
+    if (!FileName)
+    {
+        vtkErrorMacro("FileName has to be specified!");
+        return 0;
+    }
+
+    int nInfo = outputVector->GetNumberOfInformationObjects();
+
+    if (Foam::vtkPV398blockMesh::debug)
+    {
+        cout<<"RequestInformation with " << nInfo << " item(s)\n";
+        for (int infoI = 0; infoI < nInfo; ++infoI)
+        {
+            outputVector->GetInformationObject(infoI)->Print(cout);
+        }
+    }
+
+    if (!foamData_)
+    {
+        foamData_ = new Foam::vtkPV398blockMesh(FileName, this);
+    }
+    else
+    {
+        foamData_->updateInfo();
+    }
+
+    // might need some other type of error handling
+
+//    {
+//        vtkErrorMacro("could not find valid OpenFOAM blockMesh");
+//
+//        // delete foamData and flag it as fatal error
+//        delete foamData_;
+//        foamData_ = NULL;
+//        return 0;
+//    }
+
+
+    return 1;
+}
+
+
+// Set the output info
+int vtkPV398blockMeshReader::RequestData
+(
+    vtkInformation* vtkNotUsed(request),
+    vtkInformationVector** vtkNotUsed(inputVector),
+    vtkInformationVector* outputVector
+)
+{
+    vtkDebugMacro(<<"RequestData");
+
+    if (!FileName)
+    {
+        vtkErrorMacro("FileName has to be specified!");
+        return 0;
+    }
+
+    // catch previous error
+    if (!foamData_)
+    {
+        vtkErrorMacro("Reader failed - perhaps no mesh?");
+        return 0;
+    }
+
+    int nInfo = outputVector->GetNumberOfInformationObjects();
+
+    if (Foam::vtkPV398blockMesh::debug)
+    {
+        cout<<"RequestData with " << nInfo << " item(s)\n";
+        for (int infoI = 0; infoI < nInfo; ++infoI)
+        {
+            outputVector->GetInformationObject(infoI)->Print(cout);
+        }
+    }
+
+    vtkMultiBlockDataSet* output = vtkMultiBlockDataSet::SafeDownCast
+    (
+        outputVector->GetInformationObject(0)->Get
+        (
+            vtkMultiBlockDataSet::DATA_OBJECT()
+        )
+    );
+
+    if (Foam::vtkPV398blockMesh::debug)
+    {
+        cout<< "update output with "
+            << output->GetNumberOfBlocks() << " blocks\n";
+    }
+
+
+    foamData_->Update(output);
+    updatePointNumbersView(ShowPointNumbers);
+
+    // Do any cleanup on the OpenFOAM side
+    foamData_->CleanUp();
+
+    return 1;
+}
+
+
+
+void vtkPV398blockMeshReader::SetShowPointNumbers(const int val)
+{
+    if (ShowPointNumbers != val)
+    {
+        ShowPointNumbers = val;
+        updatePointNumbersView(ShowPointNumbers);
+    }
+}
+
+
+void vtkPV398blockMeshReader::updatePointNumbersView(const bool show)
+{
+    pqApplicationCore* appCore = pqApplicationCore::instance();
+
+    // need to check this, since our destructor calls this
+    if (!appCore)
+    {
+        return;
+    }
+
+    // Server manager model for querying items in the server manager
+    pqServerManagerModel* smModel = appCore->getServerManagerModel();
+    if (!smModel || !foamData_)
+    {
+        return;
+    }
+
+
+    // Get all the pqRenderView instances
+    QList<pqRenderView*> renderViews = smModel->findItems<pqRenderView*>();
+    for (int viewI=0; viewI<renderViews.size(); ++viewI)
+    {
+        foamData_->renderPointNumbers
+        (
+            renderViews[viewI]->getRenderViewProxy()->GetRenderer(),
+            show
+        );
+    }
+
+    // use refresh here?
+}
+
+
+void vtkPV398blockMeshReader::PrintSelf(ostream& os, vtkIndent indent)
+{
+    vtkDebugMacro(<<"PrintSelf");
+
+    this->Superclass::PrintSelf(os,indent);
+    os  << indent << "File name: "
+        << (this->FileName ? this->FileName : "(none)") << "\n";
+
+    foamData_->PrintSelf(os, indent);
+}
+
+
+// ----------------------------------------------------------------------
+// Block selection list control
+
+vtkDataArraySelection* vtkPV398blockMeshReader::GetBlockSelection()
+{
+    vtkDebugMacro(<<"GetBlockSelection");
+    return BlockSelection;
+}
+
+
+int vtkPV398blockMeshReader::GetNumberOfBlockArrays()
+{
+    vtkDebugMacro(<<"GetNumberOfBlockArrays");
+    return BlockSelection->GetNumberOfArrays();
+}
+
+
+const char* vtkPV398blockMeshReader::GetBlockArrayName(int index)
+{
+    vtkDebugMacro(<<"GetBlockArrayName");
+    return BlockSelection->GetArrayName(index);
+}
+
+
+int vtkPV398blockMeshReader::GetBlockArrayStatus(const char* name)
+{
+    vtkDebugMacro(<<"GetBlockArrayStatus");
+    return BlockSelection->ArrayIsEnabled(name);
+}
+
+
+void vtkPV398blockMeshReader::SetBlockArrayStatus
+(
+    const char* name,
+    int status
+)
+{
+    vtkDebugMacro(<<"SetBlockArrayStatus");
+    if (status)
+    {
+        BlockSelection->EnableArray(name);
+    }
+    else
+    {
+        BlockSelection->DisableArray(name);
+    }
+}
+
+
+// ----------------------------------------------------------------------
+// CurvedEdges selection list control
+
+vtkDataArraySelection* vtkPV398blockMeshReader::GetCurvedEdgesSelection()
+{
+    vtkDebugMacro(<<"GetCurvedEdgesSelection");
+    return CurvedEdgesSelection;
+}
+
+
+int vtkPV398blockMeshReader::GetNumberOfCurvedEdgesArrays()
+{
+    vtkDebugMacro(<<"GetNumberOfCurvedEdgesArrays");
+    return CurvedEdgesSelection->GetNumberOfArrays();
+}
+
+
+const char* vtkPV398blockMeshReader::GetCurvedEdgesArrayName(int index)
+{
+    vtkDebugMacro(<<"GetCurvedEdgesArrayName");
+    return CurvedEdgesSelection->GetArrayName(index);
+}
+
+
+int vtkPV398blockMeshReader::GetCurvedEdgesArrayStatus(const char* name)
+{
+    vtkDebugMacro(<<"GetCurvedEdgesArrayStatus");
+    return CurvedEdgesSelection->ArrayIsEnabled(name);
+}
+
+
+void vtkPV398blockMeshReader::SetCurvedEdgesArrayStatus
+(
+    const char* name,
+    int status
+)
+{
+    vtkDebugMacro(<<"SetCurvedEdgesArrayStatus");
+    if (status)
+    {
+        CurvedEdgesSelection->EnableArray(name);
+    }
+    else
+    {
+        CurvedEdgesSelection->DisableArray(name);
+    }
+}
+
+
+// ----------------------------------------------------------------------
+
+void vtkPV398blockMeshReader::SelectionModifiedCallback
+(
+    vtkObject*,
+    unsigned long,
+    void* clientdata,
+    void*
+)
+{
+    static_cast<vtkPV398blockMeshReader*>(clientdata)->Modified();
+}
+
+
+int vtkPV398blockMeshReader::FillOutputPortInformation
+(
+    int port,
+    vtkInformation* info
+)
+{
+    if (port == 0)
+    {
+        return this->Superclass::FillOutputPortInformation(port, info);
+    }
+    info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkMultiBlockDataSet");
+    return 1;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/PV398blockMeshReader/vtkPV398blockMeshReader.h b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/PV398blockMeshReader/vtkPV398blockMeshReader.h
new file mode 100644
index 0000000000000000000000000000000000000000..6238ce650216058856bc6e55749e559a626763b9
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/PV398blockMeshReader/vtkPV398blockMeshReader.h
@@ -0,0 +1,177 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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
+    vtkPV398blockMeshReader
+
+Description
+    reads a dataset in OpenFOAM bockMesh format
+
+    vtkPV398blockMeshReader creates an multiblock dataset.
+    It uses the OpenFOAM infrastructure (blockMesh).
+
+SourceFiles
+    vtkPV398blockMeshReader.cxx
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef vtkPV398blockMeshReader_h
+#define vtkPV398blockMeshReader_h
+
+// VTK includes
+#include "vtkMultiBlockDataSetAlgorithm.h"
+
+// * * * * * * * * * * * * * Forward Declarations  * * * * * * * * * * * * * //
+
+// VTK forward declarations
+class vtkDataArraySelection;
+class vtkCallbackCommand;
+
+namespace Foam
+{
+    class vtkPV398blockMesh;
+}
+
+/*---------------------------------------------------------------------------*\
+                   Class vtkPV398blockMeshReader Declaration
+\*---------------------------------------------------------------------------*/
+
+class vtkPV398blockMeshReader
+:
+    public vtkMultiBlockDataSetAlgorithm
+{
+public:
+    vtkTypeMacro(vtkPV398blockMeshReader, vtkMultiBlockDataSetAlgorithm);
+    void PrintSelf(ostream&, vtkIndent);
+
+    static vtkPV398blockMeshReader* New();
+
+    // Description:
+    // Set/Get the filename.
+    vtkSetStringMacro(FileName);
+    vtkGetStringMacro(FileName);
+
+    // Description:
+    // Display corner point labels
+    virtual void SetShowPointNumbers(int);
+    vtkGetMacro(ShowPointNumbers, int);
+
+    // Description:
+    // GUI update control
+    vtkSetMacro(UpdateGUI, int);
+    vtkGetMacro(UpdateGUI, int);
+
+
+    // Description:
+    // Blocks selection list control
+    vtkDataArraySelection* GetBlockSelection();
+    int  GetNumberOfBlockArrays();
+    int  GetBlockArrayStatus(const char*);
+    void SetBlockArrayStatus(const char*, int status);
+    const char* GetBlockArrayName(int index);
+
+    // Description:
+    // CurvedEdges selection list control
+    vtkDataArraySelection* GetCurvedEdgesSelection();
+    int  GetNumberOfCurvedEdgesArrays();
+    int  GetCurvedEdgesArrayStatus(const char*);
+    void SetCurvedEdgesArrayStatus(const char*, int status);
+    const char* GetCurvedEdgesArrayName(int index);
+
+    // Description:
+    // Callback registered with the SelectionObserver
+    // for all the selection lists
+    static void SelectionModifiedCallback
+    (
+        vtkObject* caller,
+        unsigned long eid,
+        void* clientdata,
+        void* calldata
+    );
+
+
+protected:
+
+    //- Construct null
+    vtkPV398blockMeshReader();
+
+    //- Destructor
+    ~vtkPV398blockMeshReader();
+
+    //- Return information about mesh, times, etc without loading anything
+    virtual int RequestInformation
+    (
+        vtkInformation*,
+        vtkInformationVector**,
+        vtkInformationVector*
+    );
+
+    //- Get the mesh/fields for a particular time
+    virtual int RequestData
+    (
+        vtkInformation*,
+        vtkInformationVector**,
+        vtkInformationVector*
+    );
+
+    //- Fill in additional port information
+    virtual int FillOutputPortInformation(int, vtkInformation*);
+
+    // The observer to modify this object when array selections are modified
+    vtkCallbackCommand* SelectionObserver;
+
+    char* FileName;
+
+
+private:
+
+    //- Disallow default bitwise copy construct
+    vtkPV398blockMeshReader(const vtkPV398blockMeshReader&);
+
+    //- Disallow default bitwise assignment
+    void operator=(const vtkPV398blockMeshReader&);
+
+    //- Add/remove point numbers to/from the view
+    void updatePointNumbersView(const bool show);
+
+
+    //- Show Point Numbers
+    int ShowPointNumbers;
+
+    //- Dummy variable/switch to invoke a reader update
+    int UpdateGUI;
+
+    vtkDataArraySelection* BlockSelection;
+
+    vtkDataArraySelection* CurvedEdgesSelection;
+
+    //BTX
+    Foam::vtkPV398blockMesh* foamData_;
+    //ETX
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/vtkPV398blockMesh/Make/files b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/vtkPV398blockMesh/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..dce0b1f5431cddba7e3d1d872383cbc3da83b185
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/vtkPV398blockMesh/Make/files
@@ -0,0 +1,5 @@
+vtkPV398blockMesh.C
+vtkPV398blockMeshConvert.C
+vtkPV398blockMeshUtils.C
+
+LIB = $(FOAM_LIBBIN)/libvtkPV398blockMesh
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/vtkPV398blockMesh/Make/options b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/vtkPV398blockMesh/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..b1613989de3c12c88f8fb0a0906f7dd8afc637e8
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/vtkPV398blockMesh/Make/options
@@ -0,0 +1,12 @@
+EXE_INC = \
+    -I$(LIB_SRC)/meshTools/lnInclude \
+    -I$(LIB_SRC)/mesh/blockMesh/lnInclude \
+    -I$(ParaView_INCLUDE_DIR) \
+    -I../../vtkPV398Readers/lnInclude \
+    -I../PV398blockMeshReader
+
+LIB_LIBS = \
+    -lmeshTools \
+    -lblockMesh \
+    -L$(FOAM_LIBBIN) -lvtkPV398Readers \
+    $(GLIBS)
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/vtkPV398blockMesh/vtkDataArrayTemplateImplicit.txx b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/vtkPV398blockMesh/vtkDataArrayTemplateImplicit.txx
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/vtkPV398blockMesh/vtkOpenFOAMPoints.H b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/vtkPV398blockMesh/vtkOpenFOAMPoints.H
new file mode 100644
index 0000000000000000000000000000000000000000..c7ef0c9601e160cab0873e5c682e5ed13a5d93d9
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/vtkPV398blockMesh/vtkOpenFOAMPoints.H
@@ -0,0 +1,65 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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/>.
+
+InClass
+    vtkPV398blockMesh
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef vtkOpenFOAMPoints_H
+#define vtkOpenFOAMPoints_H
+
+// VTK includes
+#include "vtkPoints.h"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+inline void vtkInsertNextOpenFOAMPoint
+(
+    vtkPoints *points,
+    const Foam::point& p
+)
+{
+    points->InsertNextPoint(p.x(), p.y(), p.z());
+}
+
+inline void vtkInsertNextOpenFOAMPoint
+(
+    vtkPoints *points,
+    const Foam::point& p,
+    const Foam::scalar scaleFactor
+)
+{
+    points->InsertNextPoint
+    (
+        p.x()*scaleFactor,
+        p.y()*scaleFactor,
+        p.z()*scaleFactor
+    );
+}
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/vtkPV398blockMesh/vtkPV398blockMesh.C b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/vtkPV398blockMesh/vtkPV398blockMesh.C
new file mode 100644
index 0000000000000000000000000000000000000000..ebeddae80c7f01c603ca78d8b9561bd1ef1c6a88
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/vtkPV398blockMesh/vtkPV398blockMesh.C
@@ -0,0 +1,473 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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 "vtkPV398blockMesh.H"
+#include "vtkPV398blockMeshReader.h"
+
+// OpenFOAM includes
+#include "blockMesh.H"
+#include "Time.H"
+#include "patchZones.H"
+#include "OStringStream.H"
+
+// VTK includes
+#include "vtkDataArraySelection.h"
+#include "vtkMultiBlockDataSet.h"
+#include "vtkRenderer.h"
+#include "vtkTextActor.h"
+#include "vtkTextProperty.h"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+defineTypeNameAndDebug(vtkPV398blockMesh, 0);
+}
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+void Foam::vtkPV398blockMesh::resetCounters()
+{
+    // Reset mesh part ids and sizes
+    arrayRangeBlocks_.reset();
+    arrayRangeEdges_.reset();
+    arrayRangeCorners_.reset();
+}
+
+
+void Foam::vtkPV398blockMesh::updateInfoBlocks
+(
+    vtkDataArraySelection* arraySelection
+)
+{
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398blockMesh::updateInfoBlocks"
+            << " [meshPtr=" << (meshPtr_ ? "set" : "NULL") << "]" << endl;
+    }
+
+    arrayRangeBlocks_.reset( arraySelection->GetNumberOfArrays() );
+
+    const blockMesh& blkMesh = *meshPtr_;
+    const int nBlocks = blkMesh.size();
+    for (int blockI = 0; blockI < nBlocks; ++blockI)
+    {
+        const blockDescriptor& blockDef = blkMesh[blockI].blockDef();
+
+        word partName = Foam::name(blockI);
+
+        // append the (optional) zone name
+        if (!blockDef.zoneName().empty())
+        {
+            partName += " - " + blockDef.zoneName();
+        }
+
+        // Add blockId and zoneName to GUI list
+        arraySelection->AddArray(partName.c_str());
+    }
+
+    arrayRangeBlocks_ += nBlocks;
+
+    if (debug)
+    {
+        // just for debug info
+        getSelectedArrayEntries(arraySelection);
+
+        Info<< "<end> Foam::vtkPV398blockMesh::updateInfoBlocks" << endl;
+    }
+}
+
+
+void Foam::vtkPV398blockMesh::updateInfoEdges
+(
+    vtkDataArraySelection* arraySelection
+)
+{
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398blockMesh::updateInfoEdges"
+            << " [meshPtr=" << (meshPtr_ ? "set" : "NULL") << "]" << endl;
+    }
+
+    arrayRangeEdges_.reset( arraySelection->GetNumberOfArrays() );
+
+    const blockMesh& blkMesh = *meshPtr_;
+    const curvedEdgeList& edges = blkMesh.edges();
+
+    const int nEdges = edges.size();
+    forAll(edges, edgeI)
+    {
+        OStringStream ostr;
+
+        ostr<< edges[edgeI].start() << ":" << edges[edgeI].end() << " - "
+            << edges[edgeI].type();
+
+        // Add "beg:end - type" to GUI list
+        arraySelection->AddArray(ostr.str().c_str());
+    }
+
+    arrayRangeEdges_ += nEdges;
+
+    if (debug)
+    {
+        // just for debug info
+        getSelectedArrayEntries(arraySelection);
+
+        Info<< "<end> Foam::vtkPV398blockMesh::updateInfoEdges" << endl;
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::vtkPV398blockMesh::vtkPV398blockMesh
+(
+    const char* const FileName,
+    vtkPV398blockMeshReader* reader
+)
+:
+    reader_(reader),
+    dbPtr_(NULL),
+    meshPtr_(NULL),
+    meshRegion_(polyMesh::defaultRegion),
+    meshDir_(polyMesh::meshSubDir),
+    arrayRangeBlocks_("block"),
+    arrayRangeEdges_("edges"),
+    arrayRangeCorners_("corners")
+{
+    if (debug)
+    {
+        Info<< "Foam::vtkPV398blockMesh::vtkPV398blockMesh - "
+            << FileName << endl;
+    }
+
+    // avoid argList and get rootPath/caseName directly from the file
+    fileName fullCasePath(fileName(FileName).path());
+
+    if (!isDir(fullCasePath))
+    {
+        return;
+    }
+    if (fullCasePath == ".")
+    {
+        fullCasePath = cwd();
+    }
+
+    // Set the case as an environment variable - some BCs might use this
+    if (fullCasePath.name().find("processor", 0) == 0)
+    {
+        const fileName globalCase = fullCasePath.path();
+
+        setEnv("FOAM_CASE", globalCase, true);
+        setEnv("FOAM_CASENAME", globalCase.name(), true);
+    }
+    else
+    {
+        setEnv("FOAM_CASE", fullCasePath, true);
+        setEnv("FOAM_CASENAME", fullCasePath.name(), true);
+    }
+
+    // look for 'case{region}.OpenFOAM'
+    // could be stringent and insist the prefix match the directory name...
+    // Note: cannot use fileName::name() due to the embedded '{}'
+    string caseName(fileName(FileName).lessExt());
+    string::size_type beg = caseName.find_last_of("/{");
+    string::size_type end = caseName.find('}', beg);
+
+    if
+    (
+        beg != string::npos && caseName[beg] == '{'
+     && end != string::npos && end == caseName.size()-1
+    )
+    {
+        meshRegion_ = caseName.substr(beg+1, end-beg-1);
+
+        // some safety
+        if (meshRegion_.empty())
+        {
+            meshRegion_ = polyMesh::defaultRegion;
+        }
+
+        if (meshRegion_ != polyMesh::defaultRegion)
+        {
+            meshDir_ = meshRegion_/polyMesh::meshSubDir;
+        }
+    }
+
+    if (debug)
+    {
+        Info<< "fullCasePath=" << fullCasePath << nl
+            << "FOAM_CASE=" << getEnv("FOAM_CASE") << nl
+            << "FOAM_CASENAME=" << getEnv("FOAM_CASENAME") << endl;
+    }
+
+    // Create time object
+    dbPtr_.reset
+    (
+        new Time
+        (
+            Time::controlDictName,
+            fileName(fullCasePath.path()),
+            fileName(fullCasePath.name())
+        )
+    );
+
+    dbPtr_().functionObjects().off();
+
+    updateInfo();
+}
+
+
+// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+
+Foam::vtkPV398blockMesh::~vtkPV398blockMesh()
+{
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398blockMesh::~vtkPV398blockMesh" << endl;
+    }
+
+    // Hmm. pointNumberTextActors are not getting removed
+    //
+    forAll(pointNumberTextActorsPtrs_, pointI)
+    {
+        pointNumberTextActorsPtrs_[pointI]->Delete();
+    }
+    pointNumberTextActorsPtrs_.clear();
+
+    delete meshPtr_;
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::vtkPV398blockMesh::updateInfo()
+{
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398blockMesh::updateInfo"
+            << " [meshPtr=" << (meshPtr_ ? "set" : "NULL") << "] " << endl;
+    }
+
+    resetCounters();
+
+    vtkDataArraySelection* blockSelection = reader_->GetBlockSelection();
+    vtkDataArraySelection* edgeSelection = reader_->GetCurvedEdgesSelection();
+
+    // enable 'internalMesh' on the first call
+    // or preserve the enabled selections
+    stringList enabledParts;
+    stringList enabledEdges;
+    bool firstTime = false;
+    if (!blockSelection->GetNumberOfArrays() && !meshPtr_)
+    {
+        firstTime = true;
+    }
+    else
+    {
+        enabledParts = getSelectedArrayEntries(blockSelection);
+        enabledEdges = getSelectedArrayEntries(edgeSelection);
+    }
+
+    // Clear current mesh parts list
+    blockSelection->RemoveAllArrays();
+    edgeSelection->RemoveAllArrays();
+
+    // need a blockMesh
+    updateFoamMesh();
+
+    // Update mesh parts list
+    updateInfoBlocks( blockSelection );
+
+    // Update curved edges list
+    updateInfoEdges( edgeSelection );
+
+    // restore the enabled selections
+    if (!firstTime)
+    {
+        setSelectedArrayEntries(blockSelection, enabledParts);
+        setSelectedArrayEntries(edgeSelection, enabledEdges);
+    }
+
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398blockMesh::updateInfo" << endl;
+    }
+}
+
+
+void Foam::vtkPV398blockMesh::updateFoamMesh()
+{
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398blockMesh::updateFoamMesh" << endl;
+    }
+
+    // Check to see if the OpenFOAM mesh has been created
+    if (!meshPtr_)
+    {
+        if (debug)
+        {
+            Info<< "Creating blockMesh at time=" << dbPtr_().timeName()
+                << endl;
+        }
+
+        IOdictionary meshDict
+        (
+            IOobject
+            (
+                "blockMeshDict",
+                dbPtr_().constant(),
+                meshDir_,
+                dbPtr_(),
+                IOobject::MUST_READ_IF_MODIFIED,
+                IOobject::NO_WRITE,
+                false
+            )
+        );
+
+        meshPtr_ = new blockMesh(meshDict, meshRegion_);
+    }
+
+
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398blockMesh::updateFoamMesh" << endl;
+    }
+}
+
+
+void Foam::vtkPV398blockMesh::Update
+(
+    vtkMultiBlockDataSet* output
+)
+{
+    reader_->UpdateProgress(0.1);
+
+    // Set up mesh parts selection(s)
+    updateBoolListStatus(blockStatus_, reader_->GetBlockSelection());
+
+    // Set up curved edges selection(s)
+    updateBoolListStatus(edgeStatus_, reader_->GetCurvedEdgesSelection());
+
+    reader_->UpdateProgress(0.2);
+
+    // Update the OpenFOAM mesh
+    updateFoamMesh();
+    reader_->UpdateProgress(0.5);
+
+    // Convert mesh elemente
+    int blockNo = 0;
+
+    convertMeshCorners(output, blockNo);
+    convertMeshBlocks(output, blockNo);
+    convertMeshEdges(output, blockNo);
+
+    reader_->UpdateProgress(0.8);
+
+}
+
+
+void Foam::vtkPV398blockMesh::CleanUp()
+{
+    reader_->UpdateProgress(1.0);
+}
+
+
+void Foam::vtkPV398blockMesh::renderPointNumbers
+(
+    vtkRenderer* renderer,
+    const bool show
+)
+{
+    // always remove old actors first
+
+    forAll(pointNumberTextActorsPtrs_, pointI)
+    {
+        renderer->RemoveViewProp(pointNumberTextActorsPtrs_[pointI]);
+        pointNumberTextActorsPtrs_[pointI]->Delete();
+    }
+    pointNumberTextActorsPtrs_.clear();
+
+    if (show && meshPtr_)
+    {
+        const pointField& cornerPts = meshPtr_->blockPointField();
+        const scalar scaleFactor = meshPtr_->scaleFactor();
+
+        pointNumberTextActorsPtrs_.setSize(cornerPts.size());
+        forAll(cornerPts, pointI)
+        {
+            vtkTextActor* txt = vtkTextActor::New();
+
+            txt->SetInput(Foam::name(pointI).c_str());
+
+            // Set text properties
+            vtkTextProperty* tprop = txt->GetTextProperty();
+            tprop->SetFontFamilyToArial();
+            tprop->BoldOn();
+            tprop->ShadowOff();
+            tprop->SetLineSpacing(1.0);
+            tprop->SetFontSize(14);
+            tprop->SetColor(1.0, 0.0, 1.0);
+            tprop->SetJustificationToCentered();
+
+            // Set text to use 3-D world co-ordinates
+            txt->GetPositionCoordinate()->SetCoordinateSystemToWorld();
+
+            txt->GetPositionCoordinate()->SetValue
+            (
+                cornerPts[pointI].x()*scaleFactor,
+                cornerPts[pointI].y()*scaleFactor,
+                cornerPts[pointI].z()*scaleFactor
+            );
+
+            // Add text to each renderer
+            renderer->AddViewProp(txt);
+
+            // Maintain a list of text labels added so that they can be
+            // removed later
+            pointNumberTextActorsPtrs_[pointI] = txt;
+        }
+    }
+}
+
+
+
+void Foam::vtkPV398blockMesh::PrintSelf(ostream& os, vtkIndent indent) const
+{
+#if 0
+    os  << indent << "Number of nodes: "
+        << (meshPtr_ ? meshPtr_->nPoints() : 0) << "\n";
+
+    os  << indent << "Number of cells: "
+        << (meshPtr_ ? meshPtr_->nCells() : 0) << "\n";
+
+    os  << indent << "Number of available time steps: "
+        << (dbPtr_.valid() ? dbPtr_().times().size() : 0) << endl;
+#endif
+}
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/vtkPV398blockMesh/vtkPV398blockMesh.H b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/vtkPV398blockMesh/vtkPV398blockMesh.H
new file mode 100644
index 0000000000000000000000000000000000000000..46020d4eb3262f861f2ccb8d2a645d53aef62023
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/vtkPV398blockMesh/vtkPV398blockMesh.H
@@ -0,0 +1,353 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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::vtkPV398blockMesh
+
+Description
+    Provides a reader interface for OpenFOAM blockMesh to VTK interaction
+
+SourceFiles
+    vtkPV398blockMesh.C
+    vtkPV398blockMeshConvert.C
+    vtkPV398blockMeshUpdate.C
+    vtkPV398blockMeshUtils.C
+
+    // Needed by VTK:
+    vtkDataArrayTemplateImplicit.txx
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef vtkPV398blockMesh_H
+#define vtkPV398blockMesh_H
+
+// do not include legacy strstream headers
+#ifndef  VTK_EXCLUDE_STRSTREAM_HEADERS
+# define VTK_EXCLUDE_STRSTREAM_HEADERS
+#endif
+
+#include "className.H"
+#include "fileName.H"
+#include "stringList.H"
+#include "wordList.H"
+
+#include "primitivePatch.H"
+
+// * * * * * * * * * * * * * Forward Declarations  * * * * * * * * * * * * * //
+
+class vtkDataArraySelection;
+class vtkDataSet;
+class vtkPoints;
+class vtkPV398blockMeshReader;
+class vtkRenderer;
+class vtkTextActor;
+class vtkMultiBlockDataSet;
+class vtkPolyData;
+class vtkUnstructuredGrid;
+class vtkIndent;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// OpenFOAM class forward declarations
+class argList;
+class Time;
+class blockMesh;
+
+template<class Type> class List;
+
+/*---------------------------------------------------------------------------*\
+                     Class vtkPV398blockMesh Declaration
+\*---------------------------------------------------------------------------*/
+
+class vtkPV398blockMesh
+{
+    // Private classes
+
+        //- Bookkeeping for GUI checklists and the multi-block organization
+        class arrayRange
+        {
+            const char *name_;
+            int block_;
+            int start_;
+            int size_;
+
+        public:
+
+            arrayRange(const char *name, const int blockNo=0)
+            :
+                name_(name),
+                block_(blockNo),
+                start_(0),
+                size_(0)
+            {}
+
+            //- Return the block holding these datasets
+            int block() const
+            {
+                return block_;
+            }
+
+            //- Assign block number, return previous value
+            int block(int blockNo)
+            {
+                int prev = block_;
+                block_ = blockNo;
+                return prev;
+            }
+
+            //- Return block name
+            const char* name() const
+            {
+                return name_;
+            }
+
+            //- Return array start index
+            int start() const
+            {
+                return start_;
+            }
+
+            //- Return array end index
+            int end() const
+            {
+                return start_ + size_;
+            }
+
+            //- Return sublist size
+            int size() const
+            {
+                return size_;
+            }
+
+            bool empty() const
+            {
+                return !size_;
+            }
+
+            //- Reset the size to zero and optionally assign a new start
+            void reset(const int startAt = 0)
+            {
+                start_ = startAt;
+                size_ = 0;
+            }
+
+            //- Increment the size
+            void operator+=(const int n)
+            {
+                size_ += n;
+            }
+        };
+
+
+    // Private Data
+
+        //- Access to the controlling vtkPV398blockMeshReader
+        vtkPV398blockMeshReader* reader_;
+
+        //- OpenFOAM time control
+        autoPtr<Time> dbPtr_;
+
+        //- OpenFOAM mesh
+        blockMesh* meshPtr_;
+
+        //- The mesh region
+        word meshRegion_;
+
+        //- The mesh directory for the region
+        fileName meshDir_;
+
+        //- Selected geometrical parts
+        boolList blockStatus_;
+
+        //- Selected curved edges
+        boolList edgeStatus_;
+
+        //- First instance and size of bleckMesh blocks
+        //  used to index into blockStatus_
+        arrayRange arrayRangeBlocks_;
+
+        //- First instance and size of CurvedEdges (only partially used)
+        arrayRange arrayRangeEdges_;
+
+        //- First instance and size of block corners (only partially used)
+        arrayRange arrayRangeCorners_;
+
+        //- List of point numbers for rendering to window
+        List<vtkTextActor*> pointNumberTextActorsPtrs_;
+
+    // Private Member Functions
+
+        // Convenience method use to convert the readers from VTK 5
+        // multiblock API to the current composite data infrastructure
+        static void AddToBlock
+        (
+            vtkMultiBlockDataSet* output,
+            vtkDataSet* dataset,
+            const arrayRange&,
+            const label datasetNo,
+            const std::string& datasetName
+        );
+
+        // Convenience method use to convert the readers from VTK 5
+        // multiblock API to the current composite data infrastructure
+        static vtkDataSet* GetDataSetFromBlock
+        (
+            vtkMultiBlockDataSet* output,
+            const arrayRange&,
+            const label datasetNo
+        );
+
+        // Convenience method use to convert the readers from VTK 5
+        // multiblock API to the current composite data infrastructure
+        static label GetNumberOfDataSets
+        (
+            vtkMultiBlockDataSet* output,
+            const arrayRange&
+        );
+
+        //- Update boolList from GUI selection
+        static void updateBoolListStatus
+        (
+            boolList&,
+            vtkDataArraySelection*
+        );
+
+        //- Reset data counters
+        void resetCounters();
+
+        // Update information helper functions
+
+            //- Internal block info
+            void updateInfoBlocks(vtkDataArraySelection*);
+
+            //- block curved edges info
+            void updateInfoEdges(vtkDataArraySelection*);
+
+        // Update helper functions
+
+            //- OpenFOAM mesh
+            void updateFoamMesh();
+
+        // Mesh conversion functions
+
+            //- mesh blocks
+            void convertMeshBlocks(vtkMultiBlockDataSet*, int& blockNo);
+
+            //- mesh curved edges
+            void convertMeshEdges(vtkMultiBlockDataSet*, int& blockNo);
+
+            //- mesh corners
+            void convertMeshCorners(vtkMultiBlockDataSet*, int& blockNo);
+
+
+       // GUI selection helper functions
+
+            //- Retrieve the current selections
+            static wordHashSet getSelected(vtkDataArraySelection*);
+
+            //- Retrieve a sub-list of the current selections
+            static wordHashSet getSelected
+            (
+                vtkDataArraySelection*,
+                const arrayRange&
+            );
+
+            //- Retrieve the current selections
+            static stringList getSelectedArrayEntries(vtkDataArraySelection*);
+
+            //- Retrieve a sub-list of the current selections
+            static stringList getSelectedArrayEntries
+            (
+                vtkDataArraySelection*,
+                const arrayRange&
+            );
+
+            //- Set selection(s)
+            static void setSelectedArrayEntries
+            (
+                vtkDataArraySelection*,
+                const stringList&
+            );
+
+
+        //- Disallow default bitwise copy construct
+        vtkPV398blockMesh(const vtkPV398blockMesh&);
+
+        //- Disallow default bitwise assignment
+        void operator=(const vtkPV398blockMesh&);
+
+
+public:
+
+    //- Static data members
+
+        ClassName("vtkPV398blockMesh");
+
+
+    // Constructors
+
+        //- Construct from components
+        vtkPV398blockMesh
+        (
+            const char* const FileName,
+            vtkPV398blockMeshReader* reader
+        );
+
+
+    //- Destructor
+    ~vtkPV398blockMesh();
+
+
+    // Member Functions
+
+        //- Update
+        void updateInfo();
+
+        void Update(vtkMultiBlockDataSet* output);
+
+        //- Clean any storage
+        void CleanUp();
+
+        //- Add/remove point numbers to/from the view
+        void renderPointNumbers(vtkRenderer*, const bool show);
+
+     // Access
+
+        //- Debug information
+        void PrintSelf(ostream&, vtkIndent) const;
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/vtkPV398blockMesh/vtkPV398blockMeshConvert.C b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/vtkPV398blockMesh/vtkPV398blockMeshConvert.C
new file mode 100644
index 0000000000000000000000000000000000000000..b9d96fdcc29a5f49d24678cb367af1673ee2eddf
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/vtkPV398blockMesh/vtkPV398blockMeshConvert.C
@@ -0,0 +1,319 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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 "vtkPV398blockMesh.H"
+#include "vtkPV398blockMeshReader.h"
+
+// OpenFOAM includes
+#include "blockMesh.H"
+#include "Time.H"
+
+#include "vtkOpenFOAMPoints.H"
+
+// VTK includes
+#include "vtkCellArray.h"
+#include "vtkDataArraySelection.h"
+#include "vtkMultiBlockDataSet.h"
+#include "vtkPoints.h"
+#include "vtkPolyData.h"
+#include "vtkUnstructuredGrid.h"
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::vtkPV398blockMesh::convertMeshBlocks
+(
+    vtkMultiBlockDataSet* output,
+    int& blockNo
+)
+{
+    vtkDataArraySelection* selection = reader_->GetBlockSelection();
+    arrayRange& range = arrayRangeBlocks_;
+    range.block(blockNo);   // set output block
+    label datasetNo = 0;       // restart at dataset 0
+
+    const blockMesh& blkMesh = *meshPtr_;
+    const Foam::pointField& blockPoints = blkMesh.blockPointField();
+
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398blockMesh::convertMeshBlocks" << endl;
+    }
+
+    int blockI = 0;
+    const scalar scaleFactor = blkMesh.scaleFactor();
+
+    for
+    (
+        int partId = range.start();
+        partId < range.end();
+        ++partId, ++blockI
+    )
+    {
+        if (!blockStatus_[partId])
+        {
+            continue;
+        }
+
+        const blockDescriptor& blockDef = blkMesh[blockI].blockDef();
+
+        vtkUnstructuredGrid* vtkmesh = vtkUnstructuredGrid::New();
+
+        // Convert OpenFOAM mesh vertices to VTK
+        vtkPoints *vtkpoints = vtkPoints::New();
+        vtkpoints->Allocate( blockDef.nPoints() );
+        const labelList& blockLabels = blockDef.blockShape();
+
+        vtkmesh->Allocate(1);
+        vtkIdType nodeIds[8];
+
+        forAll(blockLabels, ptI)
+        {
+            vtkInsertNextOpenFOAMPoint
+            (
+                vtkpoints,
+                blockPoints[blockLabels[ptI]],
+                scaleFactor
+            );
+
+            nodeIds[ptI] = ptI;
+        }
+
+        vtkmesh->InsertNextCell
+        (
+            VTK_HEXAHEDRON,
+            8,
+            nodeIds
+        );
+
+        vtkmesh->SetPoints(vtkpoints);
+        vtkpoints->Delete();
+
+        AddToBlock
+        (
+            output, vtkmesh, range, datasetNo,
+            selection->GetArrayName(partId)
+        );
+
+        vtkmesh->Delete();
+        datasetNo++;
+    }
+
+
+    // anything added?
+    if (datasetNo)
+    {
+        ++blockNo;
+    }
+
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398blockMesh::convertMeshBlocks" << endl;
+    }
+}
+
+
+void Foam::vtkPV398blockMesh::convertMeshEdges
+(
+    vtkMultiBlockDataSet* output,
+    int& blockNo
+)
+{
+    vtkDataArraySelection* selection = reader_->GetCurvedEdgesSelection();
+    arrayRange& range = arrayRangeEdges_;
+
+    range.block(blockNo);      // set output block
+    label datasetNo = 0;       // restart at dataset 0
+
+    const blockMesh& blkMesh = *meshPtr_;
+    const curvedEdgeList& edges = blkMesh.edges();
+
+    int edgeI = 0;
+    const scalar scaleFactor = blkMesh.scaleFactor();
+
+    for
+    (
+        int partId = range.start();
+        partId < range.end();
+        ++partId, ++edgeI
+    )
+    {
+        if (!edgeStatus_[partId])
+        {
+            continue;
+        }
+
+        // search each block
+        forAll(blkMesh, blockI)
+        {
+            const blockDescriptor& blockDef = blkMesh[blockI].blockDef();
+
+            edgeList blkEdges = blockDef.blockShape().edges();
+
+            // find the corresponding edge within the block
+            label foundEdgeI = -1;
+            forAll(blkEdges, blkEdgeI)
+            {
+                if (edges[edgeI].compare(blkEdges[blkEdgeI]))
+                {
+                    foundEdgeI = blkEdgeI;
+                    break;
+                }
+            }
+
+            if (foundEdgeI != -1)
+            {
+                const List<point>& edgePoints =
+                    blockDef.blockEdgePoints()[foundEdgeI];
+
+
+                vtkPolyData* vtkmesh = vtkPolyData::New();
+                vtkPoints* vtkpoints = vtkPoints::New();
+
+                vtkpoints->Allocate( edgePoints.size() );
+                vtkmesh->Allocate(1);
+
+                vtkIdType pointIds[edgePoints.size()];
+                forAll(edgePoints, ptI)
+                {
+                    vtkInsertNextOpenFOAMPoint
+                    (
+                        vtkpoints,
+                        edgePoints[ptI],
+                        scaleFactor
+                    );
+                    pointIds[ptI] = ptI;
+                }
+
+                vtkmesh->InsertNextCell
+                (
+                    VTK_POLY_LINE,
+                    edgePoints.size(),
+                    pointIds
+                );
+
+                vtkmesh->SetPoints(vtkpoints);
+                vtkpoints->Delete();
+
+                AddToBlock
+                (
+                    output, vtkmesh, range, datasetNo,
+                    selection->GetArrayName(partId)
+                );
+
+                vtkmesh->Delete();
+                datasetNo++;
+
+                break;
+            }
+        }
+    }
+
+
+    // anything added?
+    if (datasetNo)
+    {
+        ++blockNo;
+    }
+
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398blockMesh::convertMeshEdges" << endl;
+    }
+
+}
+
+
+void Foam::vtkPV398blockMesh::convertMeshCorners
+(
+    vtkMultiBlockDataSet* output,
+    int& blockNo
+)
+{
+    arrayRange& range = arrayRangeCorners_;
+    range.block(blockNo);      // set output block
+    label datasetNo = 0;       // restart at dataset 0
+
+    const pointField& blockPoints = meshPtr_->blockPointField();
+    const scalar& scaleFactor = meshPtr_->scaleFactor();
+
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398blockMesh::convertMeshCorners" << endl;
+    }
+
+    if (true)  // or some flag or other condition
+    {
+        vtkPolyData* vtkmesh = vtkPolyData::New();
+        vtkPoints* vtkpoints = vtkPoints::New();
+        vtkCellArray* vtkcells = vtkCellArray::New();
+
+        vtkpoints->Allocate( blockPoints.size() );
+        vtkcells->Allocate( blockPoints.size() );
+
+        vtkIdType pointId = 0;
+        forAll(blockPoints, ptI)
+        {
+            vtkInsertNextOpenFOAMPoint
+            (
+                vtkpoints,
+                blockPoints[ptI],
+                scaleFactor
+            );
+
+            vtkcells->InsertNextCell(1, &pointId);
+            pointId++;
+        }
+
+        vtkmesh->SetPoints(vtkpoints);
+        vtkpoints->Delete();
+
+        vtkmesh->SetVerts(vtkcells);
+        vtkcells->Delete();
+
+        AddToBlock
+        (
+            output, vtkmesh, range, datasetNo,
+            arrayRangeCorners_.name()
+        );
+        vtkmesh->Delete();
+
+        datasetNo++;
+    }
+
+    // anything added?
+    if (datasetNo)
+    {
+        ++blockNo;
+    }
+
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398blockMesh::convertMeshCorners" << endl;
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/vtkPV398blockMesh/vtkPV398blockMeshUtils.C b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/vtkPV398blockMesh/vtkPV398blockMeshUtils.C
new file mode 100644
index 0000000000000000000000000000000000000000..d2556575af6a86f41c5c28988b30bea99c4efb4f
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/PV398blockMeshReader/vtkPV398blockMesh/vtkPV398blockMeshUtils.C
@@ -0,0 +1,357 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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/>.
+
+Description
+    Misc helper methods and utilities
+
+\*---------------------------------------------------------------------------*/
+
+#include "vtkPV398blockMesh.H"
+#include "vtkPV398blockMeshReader.h"
+
+// VTK includes
+#include "vtkDataArraySelection.h"
+#include "vtkDataSet.h"
+#include "vtkMultiBlockDataSet.h"
+#include "vtkInformation.h"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    //! \cond fileScope
+    //  Extract up to the first non-word characters
+    inline word getFirstWord(const char* str)
+    {
+        if (str)
+        {
+            label n = 0;
+            while (str[n] && word::valid(str[n]))
+            {
+                ++n;
+            }
+            return word(str, n, true);
+        }
+        else
+        {
+            return word::null;
+        }
+
+    }
+    //! \endcond
+
+} // End namespace Foam
+
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+void Foam::vtkPV398blockMesh::AddToBlock
+(
+    vtkMultiBlockDataSet* output,
+    vtkDataSet* dataset,
+    const arrayRange& range,
+    const label datasetNo,
+    const std::string& datasetName
+)
+{
+    const int blockNo = range.block();
+
+    vtkDataObject* blockDO = output->GetBlock(blockNo);
+    vtkMultiBlockDataSet* block = vtkMultiBlockDataSet::SafeDownCast(blockDO);
+
+    if (!block)
+    {
+        if (blockDO)
+        {
+            FatalErrorIn("Foam::vtkPV398blockMesh::AddToBlock")
+                << "Block already has a vtkDataSet assigned to it"
+                << endl;
+            return;
+        }
+
+        block = vtkMultiBlockDataSet::New();
+        output->SetBlock(blockNo, block);
+        block->Delete();
+    }
+
+    if (debug)
+    {
+        Info<< "block[" << blockNo << "] has "
+            << block->GetNumberOfBlocks()
+            <<  " datasets prior to adding set " << datasetNo
+            <<  " with name: " << datasetName << endl;
+    }
+
+    block->SetBlock(datasetNo, dataset);
+
+    // name the block when assigning dataset 0
+    if (datasetNo == 0)
+    {
+        output->GetMetaData(blockNo)->Set
+        (
+            vtkCompositeDataSet::NAME(),
+            range.name()
+        );
+    }
+
+    if (datasetName.size())
+    {
+        block->GetMetaData(datasetNo)->Set
+        (
+            vtkCompositeDataSet::NAME(),
+            datasetName.c_str()
+        );
+    }
+}
+
+
+vtkDataSet* Foam::vtkPV398blockMesh::GetDataSetFromBlock
+(
+    vtkMultiBlockDataSet* output,
+    const arrayRange& range,
+    const label datasetNo
+)
+{
+    const int blockNo = range.block();
+
+    vtkDataObject* blockDO = output->GetBlock(blockNo);
+    vtkMultiBlockDataSet* block = vtkMultiBlockDataSet::SafeDownCast(blockDO);
+
+    if (block)
+    {
+        return vtkDataSet::SafeDownCast(block->GetBlock(datasetNo));
+    }
+
+    return 0;
+}
+
+
+// ununsed at the moment
+Foam::label Foam::vtkPV398blockMesh::GetNumberOfDataSets
+(
+    vtkMultiBlockDataSet* output,
+    const arrayRange& range
+)
+{
+    const int blockNo = range.block();
+
+    vtkDataObject* blockDO = output->GetBlock(blockNo);
+    vtkMultiBlockDataSet* block = vtkMultiBlockDataSet::SafeDownCast(blockDO);
+    if (block)
+    {
+        return block->GetNumberOfBlocks();
+    }
+
+    return 0;
+}
+
+
+Foam::wordHashSet Foam::vtkPV398blockMesh::getSelected
+(
+    vtkDataArraySelection* select
+)
+{
+    int nElem = select->GetNumberOfArrays();
+    wordHashSet selections(2*nElem);
+
+    for (int elemI=0; elemI < nElem; ++elemI)
+    {
+        if (select->GetArraySetting(elemI))
+        {
+            selections.insert(getFirstWord(select->GetArrayName(elemI)));
+        }
+    }
+
+    return selections;
+}
+
+
+Foam::wordHashSet Foam::vtkPV398blockMesh::getSelected
+(
+    vtkDataArraySelection* select,
+    const arrayRange& range
+)
+{
+    int nElem = select->GetNumberOfArrays();
+    wordHashSet selections(2*nElem);
+
+    for (int elemI = range.start(); elemI < range.end(); ++elemI)
+    {
+        if (select->GetArraySetting(elemI))
+        {
+            selections.insert(getFirstWord(select->GetArrayName(elemI)));
+        }
+    }
+
+    return selections;
+}
+
+
+Foam::stringList Foam::vtkPV398blockMesh::getSelectedArrayEntries
+(
+    vtkDataArraySelection* select
+)
+{
+    stringList selections(select->GetNumberOfArrays());
+    label nElem = 0;
+
+    forAll(selections, elemI)
+    {
+        if (select->GetArraySetting(elemI))
+        {
+            selections[nElem++] = select->GetArrayName(elemI);
+        }
+    }
+    selections.setSize(nElem);
+
+
+    if (debug)
+    {
+        label nElem = select->GetNumberOfArrays();
+        Info<< "available(";
+        for (int elemI = 0; elemI < nElem; ++elemI)
+        {
+            Info<< " \"" << select->GetArrayName(elemI) << "\"";
+        }
+        Info<< " )\nselected(";
+
+        forAll(selections, elemI)
+        {
+            Info<< " " << selections[elemI];
+        }
+        Info<< " )\n";
+    }
+
+    return selections;
+}
+
+
+Foam::stringList Foam::vtkPV398blockMesh::getSelectedArrayEntries
+(
+    vtkDataArraySelection* select,
+    const arrayRange& range
+)
+{
+    stringList selections(range.size());
+    label nElem = 0;
+
+    for (int elemI = range.start(); elemI < range.end(); ++elemI)
+    {
+        if (select->GetArraySetting(elemI))
+        {
+            selections[nElem++] = select->GetArrayName(elemI);
+        }
+    }
+    selections.setSize(nElem);
+
+
+    if (debug)
+    {
+        Info<< "available(";
+        for (int elemI = range.start(); elemI < range.end(); ++elemI)
+        {
+            Info<< " \"" << select->GetArrayName(elemI) << "\"";
+        }
+        Info<< " )\nselected(";
+
+        forAll(selections, elemI)
+        {
+            Info<< " " << selections[elemI];
+        }
+        Info<< " )\n";
+    }
+
+    return selections;
+}
+
+
+void Foam::vtkPV398blockMesh::setSelectedArrayEntries
+(
+    vtkDataArraySelection* select,
+    const stringList& selections
+)
+{
+    const int nElem = select->GetNumberOfArrays();
+    select->DisableAllArrays();
+
+    // Loop through entries, setting values from selectedEntries
+    for (int elemI=0; elemI < nElem; ++elemI)
+    {
+        string arrayName(select->GetArrayName(elemI));
+
+        forAll(selections, elemI)
+        {
+            if (selections[elemI] == arrayName)
+            {
+                select->EnableArray(arrayName.c_str());
+                break;
+            }
+        }
+    }
+}
+
+
+void Foam::vtkPV398blockMesh::updateBoolListStatus
+(
+    boolList& status,
+    vtkDataArraySelection* selection
+)
+{
+    if (debug)
+    {
+        Info<< "<beg> Foam::vtkPV398blockMesh::updateBoolListStatus" << endl;
+    }
+
+    const label nElem = selection->GetNumberOfArrays();
+    if (status.size() != nElem)
+    {
+        status.setSize(nElem);
+        status = false;
+    }
+
+    forAll(status, elemI)
+    {
+        const int setting = selection->GetArraySetting(elemI);
+
+        status[elemI] = setting;
+
+        if (debug)
+        {
+            Info<< "  part[" << elemI << "] = "
+                << status[elemI]
+                << " : " << selection->GetArrayName(elemI) << endl;
+        }
+    }
+    if (debug)
+    {
+        Info<< "<end> Foam::vtkPV398blockMesh::updateBoolListStatus" << endl;
+    }
+}
+
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/vtkPV398Readers/Make/files b/applications/utilities/postProcessing/graphics/PV398Readers/vtkPV398Readers/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..2b5d071cb3bc1aaabf44aa70b31e965daf83d594
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/vtkPV398Readers/Make/files
@@ -0,0 +1,3 @@
+vtkPV398Readers.C
+
+LIB = $(FOAM_LIBBIN)/libvtkPV398Readers
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/vtkPV398Readers/Make/options b/applications/utilities/postProcessing/graphics/PV398Readers/vtkPV398Readers/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..11c006c3bea328b82dc705da5f4b29e830c23635
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/vtkPV398Readers/Make/options
@@ -0,0 +1,5 @@
+EXE_INC = \
+    -I$(ParaView_INCLUDE_DIR)
+
+LIB_LIBS = \
+    $(GLIBS)
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/vtkPV398Readers/vtkPV398Readers.C b/applications/utilities/postProcessing/graphics/PV398Readers/vtkPV398Readers/vtkPV398Readers.C
new file mode 100644
index 0000000000000000000000000000000000000000..2bdfb92a8c809b4bdf86e893ad0cdf9927f490f7
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/vtkPV398Readers/vtkPV398Readers.C
@@ -0,0 +1,333 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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/>.
+
+Description
+    Misc helper methods and utilities
+
+\*---------------------------------------------------------------------------*/
+
+#include "vtkPV398Readers.H"
+
+// OpenFOAM includes
+#include "IFstream.H"
+
+// VTK includes
+#include "vtkDataArraySelection.h"
+#include "vtkDataSet.h"
+#include "vtkMultiBlockDataSet.h"
+#include "vtkInformation.h"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+defineTypeNameAndDebug(vtkPV398Readers, 0);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    //! \cond fileScope
+    //  Extract up to the first non-word characters
+    inline word getFirstWord(const char* str)
+    {
+        if (str)
+        {
+            label n = 0;
+            while (str[n] && word::valid(str[n]))
+            {
+                ++n;
+            }
+            return word(str, n, true);
+        }
+        else
+        {
+            return word::null;
+        }
+
+    }
+    //! \endcond
+
+} // End namespace Foam
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+void Foam::vtkPV398Readers::AddToBlock
+(
+    vtkMultiBlockDataSet* output,
+    vtkDataSet* dataset,
+    const partInfo& selector,
+    const label datasetNo,
+    const std::string& datasetName
+)
+{
+    const int blockNo = selector.block();
+
+    vtkDataObject* blockDO = output->GetBlock(blockNo);
+    vtkMultiBlockDataSet* block = vtkMultiBlockDataSet::SafeDownCast(blockDO);
+
+    if (!block)
+    {
+        if (blockDO)
+        {
+            FatalErrorIn("Foam::vtkPV398Readers::AddToBlock")
+                << "Block already has a vtkDataSet assigned to it"
+                << endl;
+            return;
+        }
+
+        block = vtkMultiBlockDataSet::New();
+        output->SetBlock(blockNo, block);
+        block->Delete();
+    }
+
+    if (debug)
+    {
+        Info<< "block[" << blockNo << "] has "
+            << block->GetNumberOfBlocks()
+            <<  " datasets prior to adding set " << datasetNo
+            <<  " with name: " << datasetName << endl;
+    }
+
+    block->SetBlock(datasetNo, dataset);
+
+    // name the block when assigning dataset 0
+    if (datasetNo == 0)
+    {
+        output->GetMetaData(blockNo)->Set
+        (
+            vtkCompositeDataSet::NAME(),
+            selector.name()
+        );
+    }
+
+    if (datasetName.size())
+    {
+        block->GetMetaData(datasetNo)->Set
+        (
+            vtkCompositeDataSet::NAME(),
+            datasetName.c_str()
+        );
+    }
+}
+
+
+vtkDataSet* Foam::vtkPV398Readers::GetDataSetFromBlock
+(
+    vtkMultiBlockDataSet* output,
+    const partInfo& selector,
+    const label datasetNo
+)
+{
+    const int blockNo = selector.block();
+
+    vtkDataObject* blockDO = output->GetBlock(blockNo);
+    vtkMultiBlockDataSet* block = vtkMultiBlockDataSet::SafeDownCast(blockDO);
+
+    if (block)
+    {
+        return vtkDataSet::SafeDownCast(block->GetBlock(datasetNo));
+    }
+
+    return 0;
+}
+
+
+// ununsed at the moment
+Foam::label Foam::vtkPV398Readers::GetNumberOfDataSets
+(
+    vtkMultiBlockDataSet* output,
+    const partInfo& selector
+)
+{
+    const int blockNo = selector.block();
+
+    vtkDataObject* blockDO = output->GetBlock(blockNo);
+    vtkMultiBlockDataSet* block = vtkMultiBlockDataSet::SafeDownCast(blockDO);
+    if (block)
+    {
+        return block->GetNumberOfBlocks();
+    }
+
+    return 0;
+}
+
+
+// Foam::word Foam::vtkPV398Readers::getPartName(int partId)
+// {
+//     return getFirstWord(reader_->GetPartArrayName(partId));
+// }
+
+
+Foam::wordHashSet Foam::vtkPV398Readers::getSelected
+(
+    vtkDataArraySelection* select
+)
+{
+    int nElem = select->GetNumberOfArrays();
+    wordHashSet selections(2*nElem);
+
+    for (int elemI=0; elemI < nElem; ++elemI)
+    {
+        if (select->GetArraySetting(elemI))
+        {
+            selections.insert(getFirstWord(select->GetArrayName(elemI)));
+        }
+    }
+
+    return selections;
+}
+
+
+Foam::wordHashSet Foam::vtkPV398Readers::getSelected
+(
+    vtkDataArraySelection* select,
+    const partInfo& selector
+)
+{
+    int nElem = select->GetNumberOfArrays();
+    wordHashSet selections(2*nElem);
+
+    for (int elemI = selector.start(); elemI < selector.end(); ++elemI)
+    {
+        if (select->GetArraySetting(elemI))
+        {
+            selections.insert(getFirstWord(select->GetArrayName(elemI)));
+        }
+    }
+
+    return selections;
+}
+
+
+Foam::stringList Foam::vtkPV398Readers::getSelectedArrayEntries
+(
+    vtkDataArraySelection* select
+)
+{
+    stringList selections(select->GetNumberOfArrays());
+    label nElem = 0;
+
+    forAll(selections, elemI)
+    {
+        if (select->GetArraySetting(elemI))
+        {
+            selections[nElem++] = select->GetArrayName(elemI);
+        }
+    }
+    selections.setSize(nElem);
+
+
+    if (debug)
+    {
+        label nElem = select->GetNumberOfArrays();
+        Info<< "available(";
+        for (int elemI = 0; elemI < nElem; ++elemI)
+        {
+            Info<< " \"" << select->GetArrayName(elemI) << "\"";
+        }
+        Info<< " )\nselected(";
+
+        forAll(selections, elemI)
+        {
+            Info<< " " << selections[elemI];
+        }
+        Info<< " )\n";
+    }
+
+    return selections;
+}
+
+
+Foam::stringList Foam::vtkPV398Readers::getSelectedArrayEntries
+(
+    vtkDataArraySelection* select,
+    const partInfo& selector
+)
+{
+    stringList selections(selector.size());
+    label nElem = 0;
+
+    for (int elemI = selector.start(); elemI < selector.end(); ++elemI)
+    {
+        if (select->GetArraySetting(elemI))
+        {
+            selections[nElem++] = select->GetArrayName(elemI);
+        }
+    }
+    selections.setSize(nElem);
+
+
+    if (debug)
+    {
+        Info<< "available(";
+        for (int elemI = selector.start(); elemI < selector.end(); ++elemI)
+        {
+            Info<< " \"" << select->GetArrayName(elemI) << "\"";
+        }
+        Info<< " )\nselected(";
+
+        forAll(selections, elemI)
+        {
+            Info<< " " << selections[elemI];
+        }
+        Info<< " )\n";
+    }
+
+    return selections;
+}
+
+
+void Foam::vtkPV398Readers::setSelectedArrayEntries
+(
+    vtkDataArraySelection* select,
+    const stringList& selections
+)
+{
+    const int nElem = select->GetNumberOfArrays();
+    select->DisableAllArrays();
+
+    // Loop through entries, setting values from selectedEntries
+    for (int elemI=0; elemI < nElem; ++elemI)
+    {
+        string arrayName(select->GetArrayName(elemI));
+
+        forAll(selections, elemI)
+        {
+            if (selections[elemI] == arrayName)
+            {
+                select->EnableArray(arrayName.c_str());
+                break;
+            }
+        }
+    }
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+
+// ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV398Readers/vtkPV398Readers/vtkPV398Readers.H b/applications/utilities/postProcessing/graphics/PV398Readers/vtkPV398Readers/vtkPV398Readers.H
new file mode 100644
index 0000000000000000000000000000000000000000..a5ab69a45281734d71ef141f890798d01d56b103
--- /dev/null
+++ b/applications/utilities/postProcessing/graphics/PV398Readers/vtkPV398Readers/vtkPV398Readers.H
@@ -0,0 +1,228 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+     \\/     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/>.
+
+Namespace
+    Foam::vtkPV398Readers
+
+Description
+    A collection of helper functions when building a reader interface in
+    ParaView3.
+
+SourceFiles
+    vtkPV398Readers.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef vtkPV398Readers_H
+#define vtkPV398Readers_H
+
+// do not include legacy strstream headers
+#ifndef  VTK_EXCLUDE_STRSTREAM_HEADERS
+# define VTK_EXCLUDE_STRSTREAM_HEADERS
+#endif
+
+#include "className.H"
+#include "fileName.H"
+#include "stringList.H"
+#include "wordList.H"
+#include "HashSet.H"
+
+
+// * * * * * * * * * * * * * Forward Declarations  * * * * * * * * * * * * * //
+
+class vtkDataArraySelection;
+class vtkDataSet;
+class vtkPoints;
+class vtkPV398FoamReader;
+class vtkRenderer;
+class vtkTextActor;
+class vtkMultiBlockDataSet;
+class vtkPolyData;
+class vtkUnstructuredGrid;
+class vtkIndent;
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace vtkPV398Readers
+{
+    //- Declare name of the class and its debug switch
+    NamespaceName("vtkPV398Readers");
+
+    //- Bookkeeping for GUI checklists and the multi-block organization
+    class partInfo
+    {
+        const char *name_;
+        int block_;
+        int start_;
+        int size_;
+
+    public:
+
+        partInfo(const char *name, const int blockNo=0)
+        :
+            name_(name),
+            block_(blockNo),
+            start_(-1),
+            size_(0)
+        {}
+
+        //- Return the block holding these datasets
+        int block() const
+        {
+            return block_;
+        }
+
+        //- Assign block number, return previous value
+        int block(int blockNo)
+        {
+            int prev = block_;
+            block_ = blockNo;
+            return prev;
+        }
+
+        const char* name() const
+        {
+            return name_;
+        }
+
+        int start() const
+        {
+            return start_;
+        }
+
+        int end() const
+        {
+            return start_ + size_;
+        }
+
+        int size() const
+        {
+            return size_;
+        }
+
+        bool empty() const
+        {
+            return !size_;
+        }
+
+        void reset()
+        {
+            start_ = -1;
+            size_ = 0;
+        }
+
+        //- Assign new start and reset the size
+        void operator=(const int i)
+        {
+            start_ = i;
+            size_ = 0;
+        }
+
+        //- Increment the size
+        void operator+=(const int n)
+        {
+            size_ += n;
+        }
+    };
+
+
+    //- Convenience method use to convert the readers from VTK 5
+    //  multiblock API to the current composite data infrastructure
+    void AddToBlock
+    (
+        vtkMultiBlockDataSet* output,
+        vtkDataSet* dataset,
+        const partInfo& selector,
+        const label datasetNo,
+        const std::string& datasetName
+    );
+
+
+    //- Convenience method use to convert the readers from VTK 5
+    // multiblock API to the current composite data infrastructure
+    vtkDataSet* GetDataSetFromBlock
+    (
+        vtkMultiBlockDataSet* output,
+        const partInfo& selector,
+        const label datasetNo
+    );
+
+    //- Convenience method use to convert the readers from VTK 5
+    // multiblock API to the current composite data infrastructure
+    // ununsed at the moment
+    label GetNumberOfDataSets
+    (
+        vtkMultiBlockDataSet* output,
+        const partInfo& selector
+    );
+
+
+    //- Retrieve the current selections as a wordHashSet
+    wordHashSet getSelected
+    (
+        vtkDataArraySelection* select
+    );
+
+
+    //- Retrieve a sub-list of the current selections
+    wordHashSet getSelected
+    (
+        vtkDataArraySelection*,
+        const partInfo&
+    );
+
+
+    //- Retrieve the current selections
+    stringList getSelectedArrayEntries(vtkDataArraySelection*);
+
+    //- Retrieve a sub-list of the current selections
+    stringList getSelectedArrayEntries
+    (
+        vtkDataArraySelection* select,
+        const partInfo& selector
+    );
+
+
+    //- Set selection(s)
+    void setSelectedArrayEntries
+    (
+        vtkDataArraySelection*,
+        const stringList&
+    );
+
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace vtkPV398
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/bin/paraFoam398 b/bin/paraFoam398
new file mode 100755
index 0000000000000000000000000000000000000000..95cf1cc88dbdda850334469315f299df0968bf40
--- /dev/null
+++ b/bin/paraFoam398
@@ -0,0 +1,271 @@
+#!/bin/sh
+#------------------------------------------------------------------------------
+# =========                 |
+# \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+#  \\    /   O peration     |
+#   \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+#    \\/     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/>.
+#
+# Script
+#     paraFoam
+#
+# Description
+#     start paraview with the OpenFOAM libraries
+#
+# Note
+#     combining -block or -builtin options with the -region option yields
+#     undefined behaviour
+#------------------------------------------------------------------------------
+usage() {
+    exec 1>&2
+    while [ "$#" -ge 1 ]; do echo "$1"; shift; done
+    cat<<USAGE
+
+Usage: ${0##*/} [OPTION] [PARAVIEW_OPTION]
+options:
+  -block            use blockMesh reader  (uses .blockMesh extension)
+  -builtin          use VTK builtin OpenFOAM reader  (uses .foam extension)
+  -case <dir>       specify alternative case directory, default is the cwd
+  -region <name>    specify alternative mesh region
+  -touch            only create the file  (eg, .blockMesh, .OpenFOAM, etc)
+  -touchAll         create .blockMesh, .OpenFOAM files (and for all regions)
+  -help             print the usage
+
+
+paraview options start with a double dashes
+
+* start paraview $ParaView_VERSION with the OpenFOAM libraries
+
+USAGE
+    exit 1
+}
+
+# We want to do nice exit when running paraview to give paraview opportunity
+# to clean up
+unset FOAM_ABORT
+
+unset regionName optTouch
+
+# Hack: change all locale to 'C' i.e. using '.' for decimal point. This is
+# only needed temporarily until paraview is locale aware. (git version is
+# already 2010-07)
+export LC_ALL=C
+
+# reader extension
+extension=OpenFOAM
+
+requirePV=1
+
+# parse options
+while [ "$#" -gt 0 ]
+do
+    case "$1" in
+    -h | -help)
+        usage
+        ;;
+    -block | -blockMesh)
+        extension=blockMesh
+        shift
+        ;;
+    -builtin)
+        extension=foam
+        requirePV=0
+        shift
+        ;;
+    -case)
+        [ "$#" -ge 2 ] || usage "'$1' option requires an argument"
+        cd "$2" 2>/dev/null || usage "directory does not exist:  '$2'"
+        shift 2
+        ;;
+    -region)
+        [ "$#" -ge 2 ] || usage "'$1' option requires an argument"
+        regionName=$2
+        shift 2
+        ;;
+    -touch)
+        optTouch=true
+        requirePV=0
+        shift
+        ;;
+    -touchAll)
+        optTouch=all
+        requirePV=0
+        shift
+        ;;
+    --)
+        shift
+        break    # stop here, treat balance as paraview options
+        ;;
+    --*)
+        break    # stop here, treat this and balance as paraview options
+        ;;
+    *)
+        usage "unknown option/argument: '$*'"
+        ;;
+    esac
+done
+
+
+#
+# check that reader module has been built
+#
+if [ $requirePV -eq 1 -a ! -f $PV_PLUGIN_PATH/libPV398FoamReader_SM.so ]
+then
+    cat<< BUILDREADER
+
+FATAL ERROR: ParaView reader module libraries do not exist
+
+Please build the reader module before continuing:
+cd \$FOAM_UTILITIES/postProcessing/graphics/PV398Readers
+./Allwclean
+./Allwmake
+
+BUILDREADER
+    exit 1
+fi
+
+#
+# check for --data=... argument
+#
+hasDataArg()
+{
+    hasData=false
+    while [ "$#" -gt 0 ]
+    do
+        case "$1" in
+        (--data=*)
+            hasData=true
+            break
+            ;;
+        esac
+        shift
+    done
+}
+
+hasDataArg $@
+
+
+# get a sensible caseName from the directory name
+caseName=${PWD##*/}
+caseFile="$caseName.$extension"
+fvControls="system"
+
+if [ -n "$regionName" ]
+then
+    if [ ! -d constant/$regionName ]
+    then
+        echo "FATAL ERROR: Region $regionName does not exist"
+        exit 1
+    else
+        caseFile="$caseName{$regionName}.$extension"
+        fvControls="$fvControls/$regionName"
+    fi
+fi
+
+case "${optTouch:-false}" in
+all)
+    extension=OpenFOAM
+    if [ -f constant/polyMesh/blockMeshDict ]
+    then
+        touch "$caseName.blockMesh"
+        echo "created '$caseName.blockMesh'"
+    fi
+    touch "$caseName.$extension"
+    echo "created '$caseName.$extension'"
+    # discover probable regions
+    for region in constant/*
+    do
+        if [ -d $region -a -d $region/polyMesh ]
+        then
+            regionName=${region##*/}
+            touch "$caseName{$regionName}.$extension"
+            echo "created '$caseName{$regionName}.$extension'"
+        fi
+    done
+    exit 0
+    ;;
+true)
+    touch "$caseFile"
+    echo "created '$caseFile'"
+    exit 0
+    ;;
+esac
+
+
+# parent directory for normal or parallel results
+case "$caseName" in
+    processor*) parentDir=".." ;;
+    *)          parentDir="."  ;;
+esac
+
+
+if [ "${hasData:-false}" = true ]
+then
+
+    # has --data=.., send directly to paraview
+    exec paraview "$@"
+
+else
+
+    # check existence of essential files
+    warn="WARN file does not exist:"
+    case $extension in
+    blockMesh)
+        for check in \
+            system/controlDict \
+            constant/polyMesh/blockMeshDict \
+            ;
+        do
+            [ -s "$parentDir/$check" ] || {
+                [ -n "$warn" ] && echo "$warn" 1>&2
+                echo "    $parentDir/$check" 1>&2
+                unset warn
+            }
+        done
+        ;;
+
+    builtin | OpenFOAM)
+        for check in \
+            system/controlDict \
+            $fvControls/fvSchemes \
+            $fvControls/fvSolution \
+            ;
+        do
+            [ -s "$parentDir/$check" ] || {
+                [ -n "$warn" ] && echo "$warn" 1>&2
+                echo "    $parentDir/$check" 1>&2
+                unset warn
+            }
+        done
+        ;;
+    esac
+
+    # only create/remove caseFile if it didn't already exist
+    [ -e $caseFile ] || {
+        trap "rm -f $caseFile 2>/dev/null; exit 0" EXIT TERM INT
+        touch "$caseFile"
+        echo "created temporary '$caseFile'"
+    }
+
+    # For now filter out any ld.so errors. Caused by non-system compiler?
+    paraview --data="$caseFile" "$@" 2>&1 | fgrep -v 'Inconsistency detected by ld.so'
+fi
+
+
+#------------------------------------------------------------------------------
diff --git a/etc/config/paraview398.sh b/etc/config/paraview398.sh
new file mode 100644
index 0000000000000000000000000000000000000000..ab1dda6d9c8fab5938f5440758d3bd28a438a6fa
--- /dev/null
+++ b/etc/config/paraview398.sh
@@ -0,0 +1,141 @@
+#----------------------------------*-sh-*--------------------------------------
+# =========                 |
+# \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+#  \\    /   O peration     |
+#   \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
+#    \\/     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/>.
+#
+# File
+#     config/paraview.sh
+#
+# Description
+#     Setup file for paraview-3.x
+#     Sourced from OpenFOAM-<VERSION>/etc/bashrc or from foamPV alias
+#
+# Note
+#     The env. variables 'ParaView_DIR' and 'ParaView_MAJOR'
+#     are required for building plugins
+#------------------------------------------------------------------------------
+
+# clean the PATH
+cleaned=`$WM_PROJECT_DIR/bin/foamCleanPath "$PATH" "$WM_THIRD_PARTY_DIR/platforms/$WM_ARCH$WM_COMPILER/cmake- $WM_THIRD_PARTY_DIR/platforms/$WM_ARCH$WM_COMPILER/paraview-"` && PATH="$cleaned"
+
+# determine the cmake to be used
+unset CMAKE_HOME
+for cmake in cmake-2.8.4 cmake-2.8.3 cmake-2.8.1
+do
+    cmake=$WM_THIRD_PARTY_DIR/platforms/$WM_ARCH$WM_COMPILER/$cmake
+    if [ -r $cmake ]
+    then
+        export CMAKE_HOME=$cmake
+        export PATH=$CMAKE_HOME/bin:$PATH
+        break
+    fi
+done
+
+
+#- ParaView version, automatically determine major version
+#export ParaView_VERSION=3.12.0
+export ParaView_VERSION=3.98.1
+export ParaView_MAJOR=detect
+
+
+# Evaluate command-line parameters for ParaView
+_foamParaviewEval()
+{
+    while [ $# -gt 0 ]
+    do
+        case "$1" in
+        ParaView*=*)
+            # name=value  -> export name=value
+            eval "export $1"
+            ;;
+        esac
+        shift
+    done
+}
+
+# Evaluate command-line parameters
+_foamParaviewEval $@
+
+
+# set MAJOR version to correspond to VERSION
+# ParaView_MAJOR is "<digits>.<digits>" from ParaView_VERSION
+case "$ParaView_VERSION" in
+"$ParaView_MAJOR".* )
+    # version and major appear to correspond
+    ;;
+
+[0-9]*)
+    # extract major from the version
+    ParaView_MAJOR=`echo $ParaView_VERSION | sed -e 's/^\([0-9][0-9]*\.[0-9][0-9]*\).*$/\1/'`
+    ;;
+esac
+export ParaView_VERSION ParaView_MAJOR
+
+paraviewInstDir=$WM_THIRD_PARTY_DIR/ParaView-$ParaView_VERSION
+export ParaView_DIR=$WM_THIRD_PARTY_DIR/platforms/$WM_ARCH$WM_COMPILER/ParaView-$ParaView_VERSION
+
+# set paths if binaries or source are present
+if [ -r $ParaView_DIR -o -r $paraviewInstDir ]
+then
+    export ParaView_INCLUDE_DIR=$ParaView_DIR/include/paraview-$ParaView_MAJOR
+    if [ ! -d $ParaView_INCLUDE_DIR -a -d $ParaView_DIR/include/paraview ]
+    then
+        export ParaView_INCLUDE_DIR=$ParaView_DIR/include/paraview
+    fi
+
+    ParaView_LIB_DIR=$ParaView_DIR/lib/paraview-$ParaView_MAJOR
+    if [ ! -d $ParaView_LIB_DIR -a -d $ParaView_DIR/lib/paraview ]
+    then
+        ParaView_LIB_DIR=$ParaView_DIR/lib/paraview
+    fi
+
+    export PATH=$ParaView_DIR/bin:$PATH
+    export LD_LIBRARY_PATH=$ParaView_LIB_DIR:$LD_LIBRARY_PATH
+    export PV_PLUGIN_PATH=$FOAM_LIBBIN/paraview-$ParaView_MAJOR
+
+    if [ "$FOAM_VERBOSE" -a "$PS1" ]
+    then
+        echo "Using paraview"
+        echo "    ParaView_DIR         : $ParaView_DIR"
+        echo "    ParaView_LIB_DIR     : $ParaView_LIB_DIR"
+        echo "    ParaView_INCLUDE_DIR : $ParaView_INCLUDE_DIR"
+        echo "    PV_PLUGIN_PATH       : $PV_PLUGIN_PATH"
+    fi
+
+    # add in python libraries if required
+    paraviewPython=$ParaView_DIR/Utilities/VTKPythonWrapping
+    if [ -r $paraviewPython ]
+    then
+        if [ "$PYTHONPATH" ]
+        then
+            export PYTHONPATH=$PYTHONPATH:$paraviewPython:$ParaView_LIB_DIR
+        else
+            export PYTHONPATH=$paraviewPython:$ParaView_LIB_DIR
+        fi
+    fi
+else
+    unset PV_PLUGIN_PATH
+fi
+
+unset _foamParaviewEval
+unset cleaned cmake paraviewInstDir paraviewPython
+
+# -----------------------------------------------------------------------------