diff --git a/applications/utilities/postProcessing/graphics/PV3FoamReader/PV3FoamReader/vtkPV3FoamReader.cxx b/applications/utilities/postProcessing/graphics/PV3FoamReader/PV3FoamReader/vtkPV3FoamReader.cxx
index c0a32e40daaba3e2d0535b5cf7fed51f8b6b3972..2a78ad0133ada4a796c427f832f135fc713098dc 100644
--- a/applications/utilities/postProcessing/graphics/PV3FoamReader/PV3FoamReader/vtkPV3FoamReader.cxx
+++ b/applications/utilities/postProcessing/graphics/PV3FoamReader/PV3FoamReader/vtkPV3FoamReader.cxx
@@ -112,10 +112,7 @@ vtkPV3FoamReader::~vtkPV3FoamReader()
 {
     vtkDebugMacro(<<"Deconstructor");
 
-    if (foamData_)
-    {
-        delete foamData_;
-    }
+    delete foamData_;
 
     if (FileName)
     {
@@ -186,6 +183,16 @@ int vtkPV3FoamReader::RequestInformation
     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)
     {
@@ -248,6 +255,13 @@ int vtkPV3FoamReader::RequestData
         return 0;
     }
 
+    // catch previous error
+    if (!foamData_)
+    {
+        vtkErrorMacro("Reader failed - perhaps no mesh?");
+        return 0;
+    }
+
     int nInfo = outputVector->GetNumberOfInformationObjects();
 
     if (Foam::vtkPV3Foam::debug)
@@ -262,6 +276,7 @@ int vtkPV3FoamReader::RequestData
     // take port0 as the lead for other outputs
     vtkInformation *outInfo = outputVector->GetInformationObject(0);
 
+
     vtkMultiBlockDataSet* output = vtkMultiBlockDataSet::SafeDownCast
     (
         outInfo->Get
diff --git a/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3Foam.C b/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3Foam.C
index 75baf87517f34d11602639d537743c3858751dbb..fea710ac1adb315a5d35fcb5bda0d88a89d9a36d 100644
--- a/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3Foam.C
+++ b/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3Foam.C
@@ -204,7 +204,8 @@ Foam::vtkPV3Foam::vtkPV3Foam
     reader_(reader),
     dbPtr_(NULL),
     meshPtr_(NULL),
-    nMesh_(0),
+    meshRegion_(polyMesh::defaultRegion),
+    meshDir_(polyMesh::meshSubDir),
     timeIndex_(-1),
     meshChanged_(true),
     fieldsChanged_(true),
@@ -246,10 +247,33 @@ Foam::vtkPV3Foam::vtkPV3Foam
         setEnv("FOAM_CASE", fullCasePath, true);
     }
 
+    // get the caseName, and look for '=regionName' in it
+    // we could also be more stringent and insist that the
+    // prefix match the directory name, etc ..
+    fileName caseName(fileName(FileName).lessExt());
+
+    string::size_type delimiter = caseName.find("=");
+    if (delimiter != string::npos)
+    {
+        meshRegion_ = caseName.substr(delimiter+1);
+
+        // some safety
+        if (!meshRegion_.size())
+        {
+            meshRegion_ = polyMesh::defaultRegion;
+        }
+
+        if (meshRegion_ != polyMesh::defaultRegion)
+        {
+            meshDir_ = meshRegion_/polyMesh::meshSubDir;
+        }
+    }
+
     if (debug)
     {
         Info<< "fullCasePath=" << fullCasePath << nl
-            << "FOAM_CASE=" << getEnv("FOAM_CASE") << endl;
+            << "FOAM_CASE=" << getEnv("FOAM_CASE") << nl
+            << "region=" << meshRegion_ << endl;
     }
 
     // Create time object
@@ -366,15 +390,20 @@ void Foam::vtkPV3Foam::updateFoamMesh()
     {
         if (debug)
         {
-            Info<< "Creating Foam mesh" << endl;
+            Info<< "Creating Foam mesh for region " << meshRegion_
+                << " at time=" << dbPtr_().timeName()
+                << endl;
+
         }
+
         meshPtr_ = new fvMesh
         (
             IOobject
             (
-                fvMesh::defaultRegion,
+                meshRegion_,
                 dbPtr_().timeName(),
-                dbPtr_()
+                dbPtr_(),
+                IOobject::MUST_READ
             )
         );
 
@@ -476,11 +505,26 @@ double* Foam::vtkPV3Foam::findTimes(int& nTimeSteps)
         Time& runTime = dbPtr_();
         instantList timeLst = runTime.times();
 
-        // always skip "constant" time, unless there are no other times
-        nTimes = timeLst.size();
+        // 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
+            (
+                file(runTime.path()/timeName/meshDir_/"points")
+             && IOobject("points", timeName, meshDir_, runTime).headerOk()
+            )
+            {
+                break;
+            }
+        }
 
-        if (nTimes > 1)
+        nTimes = timeLst.size() - timeI;
+
+        // always skip "constant" time if possible
+        if (timeI == 0 && nTimes > 1)
         {
             timeI = 1;
             --nTimes;
@@ -697,7 +741,6 @@ void Foam::vtkPV3Foam::removePatchNames(vtkRenderer* renderer)
 
 void Foam::vtkPV3Foam::PrintSelf(ostream& os, vtkIndent indent) const
 {
-    os  << indent << "Number of meshes: " << nMesh_ << "\n";
     os  << indent << "Number of nodes: "
         << (meshPtr_ ? meshPtr_->nPoints() : 0) << "\n";
 
@@ -706,6 +749,8 @@ void Foam::vtkPV3Foam::PrintSelf(ostream& os, vtkIndent indent) const
 
     os  << indent << "Number of available time steps: "
         << (dbPtr_.valid() ? dbPtr_().times().size() : 0) << endl;
+
+    os  << indent << "mesh region: " << meshRegion_ << "\n";
 }
 
 // ************************************************************************* //
diff --git a/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3Foam.H b/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3Foam.H
index f4d7c32b112d45bb6238da2d2845f65e2132d49c..72d1edee5716aadb5037e57d1cdd91d09f9fc7ef 100644
--- a/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3Foam.H
+++ b/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3Foam.H
@@ -92,11 +92,8 @@ class polyPatch;
 class faceSet;
 class pointSet;
 
-template<class Type>
-class IOField;
-
-template<class Type>
-class List;
+template<class Type> class IOField;
+template<class Type> class List;
 
 /*---------------------------------------------------------------------------*\
                         Class vtkPV3Foam Declaration
@@ -248,9 +245,11 @@ class vtkPV3Foam
         //- Foam mesh
         fvMesh* meshPtr_;
 
-        //- Number of meshes
-        // TODO - for info only - only set up to process ONE mesh
-        int nMesh_;
+        //- The mesh region
+        word meshRegion_;
+
+        //- The mesh directory for the region
+        fileName meshDir_;
 
         //- The time index
         int timeIndex_;
diff --git a/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3FoamFields.C b/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3FoamFields.C
index bf5742e3a8671751db6527f789283ee78f00f65f..4f320c802c4e76ab22e85b8380d47fe847837309 100644
--- a/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3FoamFields.C
+++ b/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3FoamFields.C
@@ -72,6 +72,8 @@ void Foam::vtkPV3Foam::convertVolFields
     vtkMultiBlockDataSet* output
 )
 {
+    const fvMesh& mesh = *meshPtr_;
+
     wordHashSet selectedFields = getSelected
     (
         reader_->GetVolFieldSelection()
@@ -82,8 +84,8 @@ void Foam::vtkPV3Foam::convertVolFields
         return;
     }
 
-    const fvMesh& mesh = *meshPtr_;
     // 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);
 
@@ -158,6 +160,8 @@ void Foam::vtkPV3Foam::convertPointFields
     vtkMultiBlockDataSet* output
 )
 {
+    const fvMesh& mesh = *meshPtr_;
+
     wordHashSet selectedFields = getSelected
     (
         reader_->GetPointFieldSelection()
@@ -168,8 +172,8 @@ void Foam::vtkPV3Foam::convertPointFields
         return;
     }
 
-    const fvMesh& mesh = *meshPtr_;
     // 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);
 
@@ -257,8 +261,10 @@ void Foam::vtkPV3Foam::convertLagrangianFields
             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,
diff --git a/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3FoamMesh.C b/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3FoamMesh.C
index 8539bca001ce85a70819c92cdefb85cfeaad790b..087790f9de41f295dac34b6288042dcc6e9fd960 100644
--- a/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3FoamMesh.C
+++ b/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3FoamMesh.C
@@ -64,7 +64,7 @@ void Foam::vtkPV3Foam::convertMeshVolume
     }
 
     // Convert the internalMesh
-    // TODO: multiple mesh regions
+    // this looks like more than one part, but it isn't
     for (int partId = selector.start(); partId < selector.end(); ++partId)
     {
         const word partName = "internalMesh";
@@ -239,7 +239,6 @@ void Foam::vtkPV3Foam::convertMeshCellZones
     }
 
     const cellZoneMesh& zMesh = mesh.cellZones();
-
     for (int partId = selector.start(); partId < selector.end(); ++partId)
     {
         const word zoneName = getPartName(partId);
@@ -408,7 +407,6 @@ void Foam::vtkPV3Foam::convertMeshFaceZones
     }
 
     const faceZoneMesh& zMesh = mesh.faceZones();
-
     for (int partId = selector.start(); partId < selector.end(); ++partId)
     {
         const word zoneName = getPartName(partId);
@@ -515,6 +513,7 @@ void Foam::vtkPV3Foam::convertMeshPointZones
     partInfo& selector = partInfoPointZones_;
     selector.block(blockNo);   // set output block
     label datasetNo = 0;       // restart at dataset 0
+    const fvMesh& mesh = *meshPtr_;
 
     if (debug)
     {
@@ -522,12 +521,9 @@ void Foam::vtkPV3Foam::convertMeshPointZones
         printMemory();
     }
 
-    const fvMesh& mesh = *meshPtr_;
-
     if (selector.size())
     {
         const pointZoneMesh& zMesh = mesh.pointZones();
-
         for (int partId = selector.start(); partId < selector.end(); ++partId)
         {
             word zoneName = getPartName(partId);
diff --git a/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3FoamMeshLagrangian.C b/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3FoamMeshLagrangian.C
index ec5e87a4ba12b062c2d5d362142b42fed893aeda..ce050d1ae0499740db6e85c5bb1d118b2f1692ec 100644
--- a/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3FoamMeshLagrangian.C
+++ b/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3FoamMeshLagrangian.C
@@ -57,6 +57,8 @@ vtkPolyData* Foam::vtkPV3Foam::lagrangianVTKMesh
         printMemory();
     }
 
+
+    // the region name is already in the mesh db
     IOobjectList sprayObjs
     (
         mesh,
diff --git a/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3FoamUpdateInfo.C b/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3FoamUpdateInfo.C
index 1c00a04a8573edf498772061a60d081b95e06a1c..32d78c9d17485e495e78f5c62fcb2d5bbd8c4735 100644
--- a/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3FoamUpdateInfo.C
+++ b/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3FoamUpdateInfo.C
@@ -91,11 +91,11 @@ Foam::wordList Foam::vtkPV3Foam::readZoneNames(const word& zoneType)
         zoneType,
         dbPtr_().findInstance
         (
-            polyMesh::meshSubDir,
+            meshDir_,
             zoneType,
             IOobject::READ_IF_PRESENT
         ),
-        polyMesh::meshSubDir,
+        meshDir_,
         dbPtr_(),
         IOobject::READ_IF_PRESENT,
         IOobject::NO_WRITE,
@@ -126,10 +126,6 @@ void Foam::vtkPV3Foam::updateInfoInternalMesh()
 
     vtkDataArraySelection* partSelection = reader_->GetPartSelection();
 
-    // Determine number of meshes available
-    HashTable<const fvMesh*> meshObjects = dbPtr_().lookupClass<const fvMesh>();
-    nMesh_ = meshObjects.size();
-
     // Determine mesh parts (internalMesh, patches...)
     //- Add internal mesh as first entry
     partInfoVolume_ = partSelection->GetNumberOfArrays();
@@ -155,10 +151,19 @@ void Foam::vtkPV3Foam::updateInfoLagrangian()
             << "    " << dbPtr_->timePath()/"lagrangian" << endl;
     }
 
+
+    // use the db directly since this might be called without a mesh,
+    // but the region must get added back in
+    fileName lagrangianPrefix("lagrangian");
+    if (meshRegion_ != polyMesh::defaultRegion)
+    {
+        lagrangianPrefix = meshRegion_/"lagrangian";
+    }
+
     // Search for list of lagrangian objects for this time
     fileNameList cloudDirs
     (
-        readDir(dbPtr_->timePath()/"lagrangian", fileName::DIRECTORY)
+        readDir(dbPtr_->timePath()/lagrangianPrefix, fileName::DIRECTORY)
     );
 
     vtkDataArraySelection* partSelection = reader_->GetPartSelection();
@@ -221,43 +226,50 @@ void Foam::vtkPV3Foam::updateInfoPatches()
     }
     else
     {
-        // Read patches
-        polyBoundaryMeshEntries patchEntries
+        // mesh not loaded - read from file
+        // but this could fail if we've supplied a bad region name
+        IOobject ioObj
         (
-            IOobject
+            "boundary",
+            dbPtr_().findInstance
             (
+                meshDir_,
                 "boundary",
-                dbPtr_().findInstance(polyMesh::meshSubDir, "boundary"),
-                polyMesh::meshSubDir,
-                dbPtr_(),
-                IOobject::MUST_READ,
-                IOobject::NO_WRITE,
-                false
-            )
+                IOobject::READ_IF_PRESENT
+            ),
+            meshDir_,
+            dbPtr_(),
+            IOobject::READ_IF_PRESENT,
+            IOobject::NO_WRITE,
+            false
         );
 
-        // Add (non-zero) patches to the list of mesh parts
-        forAll(patchEntries, entryI)
+        // this should only ever fail if the mesh region doesn't exist
+        if (ioObj.headerOk())
         {
-            label nFaces
-            (
-                readLabel(patchEntries[entryI].dict().lookup("nFaces"))
-            );
+            polyBoundaryMeshEntries patchEntries(ioObj);
 
-            // Valid patch if nFace > 0
-            if (nFaces)
+            // Add (non-zero) patches to the list of mesh parts
+            forAll(patchEntries, entryI)
             {
-                // Add patch to GUI list
-                partSelection->AddArray
+                label nFaces
                 (
-                    (patchEntries[entryI].keyword() + " - patch").c_str()
+                    readLabel(patchEntries[entryI].dict().lookup("nFaces"))
                 );
 
-                ++nPatches;
+                // Valid patch if nFace > 0 - add patch to GUI list
+                if (nFaces)
+                {
+                    partSelection->AddArray
+                    (
+                        (patchEntries[entryI].keyword() + " - patch").c_str()
+                    );
+
+                    ++nPatches;
+                }
             }
         }
     }
-
     partInfoPatches_ += nPatches;
 
     if (debug)
@@ -380,8 +392,8 @@ void Foam::vtkPV3Foam::updateInfoSets()
     IOobjectList objects
     (
         dbPtr_(),
-        dbPtr_().findInstance(polyMesh::meshSubDir, "faces"),
-        polyMesh::meshSubDir/"sets"
+        dbPtr_().findInstance(meshDir_, "faces", IOobject::READ_IF_PRESENT),
+        meshDir_/"sets"
     );
 
 
@@ -449,11 +461,19 @@ void Foam::vtkPV3Foam::updateInfoLagrangianFields()
 
     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("lagrangian");
+    if (meshRegion_ != polyMesh::defaultRegion)
+    {
+        lagrangianPrefix = meshRegion_/"lagrangian";
+    }
+
     IOobjectList objects
     (
         dbPtr_(),
         dbPtr_().timeName(),
-        "lagrangian"/cloudName
+        lagrangianPrefix/cloudName
     );
 
     addToSelection<IOField<label> >
diff --git a/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3FoamUpdateInfoFields.H b/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3FoamUpdateInfoFields.H
index bd18d66d944640a02ad8fdc30bad1333d7117b28..89eb653c8369aa98ca7fd8982829230b46e74bd9 100644
--- a/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3FoamUpdateInfoFields.H
+++ b/applications/utilities/postProcessing/graphics/PV3FoamReader/vtkPV3Foam/vtkPV3FoamUpdateInfoFields.H
@@ -59,8 +59,16 @@ void Foam::vtkPV3Foam::updateInfoFields
 
     select->RemoveAllArrays();
 
-    // Search for list of objects for this time
-    IOobjectList objects(dbPtr_(), dbPtr_().timeName());
+    // 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> >