diff --git a/applications/test/HashTable/Test-hashTable.C b/applications/test/HashTable/Test-hashTable.C
index 8352a88ae0c05615b0fff10cd6198a7f6fc50b0b..5dd3ca0fa4ec675b7b1a7fb3de879efe5a0e830f 100644
--- a/applications/test/HashTable/Test-hashTable.C
+++ b/applications/test/HashTable/Test-hashTable.C
@@ -234,6 +234,97 @@ int main()
 
     Info<<"\ntable1: " << table1 << endl;
 
+    // Start again
+    HashTable<scalar> table1start
+    {
+        {"aaa", 1.0},
+        {"aba", 2.0},
+        {"a_ca", 3.0},
+        {"ada", 4.0},
+        {"aeq_", 5.0},
+        {"aaw", 6.0},
+        {"abs", 7.0},
+        {"a_cr", 8.0},
+        {"adx", 9.0},
+        {"ae_c", 10.0}
+    };
+
+    table1 = table1start;
+    Info<< "\ntable has keys: "
+        << flatOutput(table1.sortedToc()) << nl;
+
+    wordRe matcher(".*_.*", wordRe::REGEX);
+    table1.filterKeys
+    (
+        [&matcher](const word& k){ return matcher.match(k); }
+    );
+    Info<< "retain things matching " << matcher << " => "
+        << flatOutput(table1.sortedToc()) << nl;
+
+    table1 = table1start;
+    table1.filterKeys
+    (
+        [&matcher](const word& k){ return matcher.match(k); },
+        true
+    );
+
+    Info<< "prune things matching " << matcher << " => "
+        << flatOutput(table1.sortedToc()) << nl;
+
+    // Same, without a lambda
+    table1 = table1start;
+    table1.filterKeys(matcher, true);
+
+    Info<< "prune things matching " << matcher << " => "
+        << flatOutput(table1.sortedToc()) << nl;
+
+
+    // Same idea, but inverted logic inside the lambda
+    table1 = table1start;
+    table1.filterKeys
+    (
+        [&matcher](const word& k){ return !matcher.match(k); },
+        true
+    );
+
+    Info<< "prune things matching " << matcher << " => "
+        << flatOutput(table1.sortedToc()) << nl;
+
+
+    table1 = table1start;
+    Info<< "\ntable:" << table1 << nl;
+
+    table1.filterValues
+    (
+        [](const scalar& v){ return (v >= 5); }
+    );
+
+    Info<< "\ntable with values >= 5:" << table1 << nl;
+
+    table1 = table1start;
+    Info<< "\ntable:" << table1 << nl;
+
+    table1.filterEntries
+    (
+        [&matcher](const word& k, const scalar& v)
+        {
+            return matcher(k) && (v >= 5);
+        }
+    );
+
+    Info<< "\ntable with values >= 5 and matching " << matcher
+        << table1 << nl;
+
+
+    table1 = table1start;
+    Info<< "\ntable:" << table1 << nl;
+    Info<< "has "
+        << table1.countValues([](const scalar& v) { return v >= 7; })
+        << " values >= 7 with these keys: "
+        << table1.tocValues([](const scalar& v) { return v >= 7; })
+        << nl;
+
+
     Info<< "\nDone\n";
 
     return 0;
diff --git a/applications/test/IOobjectList/Make/files b/applications/test/IOobjectList/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..c09b00ecaaf4c1b9875e168bfb5d87a7a697eca7
--- /dev/null
+++ b/applications/test/IOobjectList/Make/files
@@ -0,0 +1,3 @@
+Test-IOobjectList.C
+
+EXE = $(FOAM_USER_APPBIN)/Test-IOobjectList
diff --git a/applications/test/IOobjectList/Make/options b/applications/test/IOobjectList/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..d9745f69a080fe0e7e312968c0a3355745247cb0
--- /dev/null
+++ b/applications/test/IOobjectList/Make/options
@@ -0,0 +1,3 @@
+EXE_INC = -I$(LIB_SRC)/finiteVolume/lnInclude
+
+EXE_LIBS = -lfiniteVolume
diff --git a/applications/test/IOobjectList/Test-IOobjectList.C b/applications/test/IOobjectList/Test-IOobjectList.C
new file mode 100644
index 0000000000000000000000000000000000000000..27bd495950638d839550e13b999726ead22daffd
--- /dev/null
+++ b/applications/test/IOobjectList/Test-IOobjectList.C
@@ -0,0 +1,104 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2017 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Description
+    Basic tests of IOobjectList
+\*---------------------------------------------------------------------------*/
+
+#include "argList.H"
+#include "Time.H"
+#include "volFields.H"
+#include "timeSelector.H"
+#include "IOobjectList.H"
+#include "hashedWordList.H"
+
+using namespace Foam;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+// Main program:
+
+int main(int argc, char *argv[])
+{
+    argList::noParallel();
+    argList::addOption("re", "wordReList");
+
+    // timeSelector::addOptions();
+    timeSelector::addOptions(true, true);
+
+    #include "setRootCase.H"
+    #include "createTime.H"
+
+    wordReList matcher;
+    if (args.optionFound("re"))
+    {
+        matcher = args.optionReadList<wordRe>("re");
+        Info<<"limit names: " << matcher << nl;
+
+    }
+
+    const hashedWordList subsetTypes
+    {
+        volScalarField::typeName,
+        volScalarField::Internal::typeName,
+        volVectorField::typeName,
+    };
+
+
+    instantList timeDirs = timeSelector::select0(runTime, args);
+
+    forAll(timeDirs, timeI)
+    {
+        runTime.setTime(timeDirs[timeI], timeI);
+
+        // Objects at this time
+        IOobjectList objects(runTime, runTime.timeName());
+        HashTable<wordHashSet> classes =
+        (
+            matcher.size()
+          ? objects.classes(matcher)
+          : objects.classes()
+        );
+
+        Info<< "Time: " << runTime.timeName() << nl;
+
+        Info<<"Name:    " << flatOutput(objects.sortedNames()) << nl
+            <<"Objects: " << objects << nl
+            <<"Classes: " << classes << nl;
+
+        classes.filterKeys(subsetTypes);
+        Info<<"only retain: " << flatOutput(subsetTypes) << nl;
+        Info<<"Pruned: " << classes << nl;
+
+        classes = objects.classes();
+        classes.erase(subsetTypes);
+        Info<<"remove: " << flatOutput(subsetTypes) << nl;
+        Info<<"Pruned: " << classes << nl;
+    }
+
+    Info<< "\nEnd\n" << endl;
+
+    return 0;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/test/fileName/Test-fileName.C b/applications/test/fileName/Test-fileName.C
index 18f89b6db046d049aa071dc6ada3a044cc2cb9d2..5de8912bd880e5c6c78dc80442abe76661031cd4 100644
--- a/applications/test/fileName/Test-fileName.C
+++ b/applications/test/fileName/Test-fileName.C
@@ -180,9 +180,9 @@ int main(int argc, char *argv[])
         // A regex with a zero length matcher doesn't work at all:
         // eg "(png|jpg|txt|)" regex matcher itself
 
-        wordRe matcher0("()", wordRe::REGEXP);
-        wordRe matcher1("(png|jpg|txt)", wordRe::REGEXP);
-        wordRe matcher2("(png|txt)", wordRe::REGEXP);
+        wordRe matcher0("()", wordRe::REGEX);
+        wordRe matcher1("(png|jpg|txt)", wordRe::REGEX);
+        wordRe matcher2("(png|txt)", wordRe::REGEX);
 
         Info<<"Has extension(s):" << nl
             << "input: " << endWithDot << nl;
diff --git a/applications/test/predicates/Make/files b/applications/test/predicates/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..6197f71dfaf0cd13fd79cd56683dc968c3e47a8f
--- /dev/null
+++ b/applications/test/predicates/Make/files
@@ -0,0 +1,3 @@
+Test-predicates.C
+
+EXE = $(FOAM_USER_APPBIN)/Test-predicates
diff --git a/applications/test/predicates/Make/options b/applications/test/predicates/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..9d6f459ad89282e21723bb39b2c290797efb0edb
--- /dev/null
+++ b/applications/test/predicates/Make/options
@@ -0,0 +1 @@
+/**/
diff --git a/applications/test/predicates/Test-predicates.C b/applications/test/predicates/Test-predicates.C
new file mode 100644
index 0000000000000000000000000000000000000000..9b9e77ddbb303a86988a472da1277f898d2f481c
--- /dev/null
+++ b/applications/test/predicates/Test-predicates.C
@@ -0,0 +1,112 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2017 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Application
+    Test-predicates
+
+Description
+    Simple tests using predicates
+
+\*---------------------------------------------------------------------------*/
+
+#include "IOstreams.H"
+#include "labelList.H"
+#include "wordList.H"
+#include "predicates.H"
+#include "FlatOutput.H"
+#include "regExp.H"
+
+using namespace Foam;
+
+
+template<class ListType, class UnaryPredicate>
+label printMatching(const ListType& list, const UnaryPredicate& pred)
+{
+    label count = 0;
+
+    Info<< "(";
+
+    for (const auto& val : list)
+    {
+        if (pred(val))
+        {
+            if (count) Info<< ' ';
+            Info<< val;
+            ++count;
+        }
+    }
+
+    Info<< ") => " << count << nl;
+
+    return count;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+//  Main program:
+
+int main(int argc, char *argv[])
+{
+    wordList words
+    {
+        "abc",
+        "def",
+        "hij",
+        "abc_",
+        "def_",
+        "hij_",
+    };
+
+    labelRange range(-10, 40);
+    labelList values(range.begin(), range.end());
+
+    Info<<"words:  " << flatOutput(words) << endl;
+    Info<<"values: " << flatOutput(values)  << endl;
+
+    regExp matcher(".*_.*");
+
+    Info<<"With '_': ";
+    printMatching(words, matcher);
+
+    Info<<"All: ";
+    printMatching(words, predicates::always());
+
+    Info<<"None: ";
+    printMatching(words, predicates::never());
+
+    Info<<"Neg values: ";
+    printMatching(values, [](const label v) { return v < 0; });
+
+    Info<<"Even values: ";
+    printMatching(values, [](const label v) { return !(v % 2); });
+
+    Info<<"All: ";
+    printMatching(values, predicates::always());
+
+    Info<<"None: ";
+    printMatching(values, predicates::never());
+
+    return 0;
+}
+
+// ************************************************************************* //
diff --git a/applications/test/wordRe/Test-wordRe.C b/applications/test/wordRe/Test-wordRe.C
index f5dfcda831f617efd6acace0e04d94a324035102..be1af08a5497ecf699bc0e539cc57c6501146620 100644
--- a/applications/test/wordRe/Test-wordRe.C
+++ b/applications/test/wordRe/Test-wordRe.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -30,7 +30,10 @@ Description
 #include "IFstream.H"
 #include "List.H"
 #include "Tuple2.H"
+#include "keyType.H"
 #include "wordRe.H"
+#include "wordRes.H"
+#include "predicates.H"
 
 using namespace Foam;
 
@@ -44,12 +47,37 @@ int main(int argc, char *argv[])
     Foam::string s2("this .* file");
     const char * s3 = "this .* file";
 
+    keyType keyre("x.*", true);
+
+    wordReList wordrelist
+    {
+        {"this", wordRe::LITERAL},
+        {"x.*", wordRe::REGEX},
+        {"file[a-b]", wordRe::REGEX},
+    };
+
+    wordRes wrelist(wordrelist);
+
+    Info<< "re-list:" << wrelist() << endl;
+    Info<< "match this: " << wrelist("this") << endl;
+    Info<< "match xyz: "  << wrelist("xyz") << endl;
+    Info<< "match zyx: "  << wrelist("zyx") << endl;
+    Info<< "match xyz: "  << wrelist.match("xyz") << endl;
+    Info<< "match any: "  << predicates::always()("any junk") << endl;
+    Info<< "keyre match: "  << keyre("xyz") << endl;
+    Info<< "string match: "  << string("this").match("xyz") << endl;
+    Info<< "string match: "  << string("x.*")("xyz") << endl;
+    Info<< "string match: "  << string("x.*")(keyre) << endl;
+
     wordRe(s1, wordRe::DETECT).info(Info) << endl;
     wordRe(s2).info(Info) << endl;
     wordRe(s2, wordRe::DETECT).info(Info) << endl;
-    wordRe(s3, wordRe::REGEXP).info(Info) << endl;
+    wordRe(s3, wordRe::REGEX).info(Info) << endl;
 
     wre = "this .* file";
+
+    Info<<"substring: " << wre(4) << endl;
+
     wre.info(Info) << endl;
     wre = s1;
     wre.info(Info) << endl;
diff --git a/applications/utilities/mesh/manipulation/subsetMesh/subsetMesh.C b/applications/utilities/mesh/manipulation/subsetMesh/subsetMesh.C
index 4e03eb9cc878697f3369b0ee221bc2337f94754f..2947edb02b14a4c61c7281b3516fd7e4d3adde1e 100644
--- a/applications/utilities/mesh/manipulation/subsetMesh/subsetMesh.C
+++ b/applications/utilities/mesh/manipulation/subsetMesh/subsetMesh.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -112,7 +112,7 @@ labelList nearestPatch(const polyMesh& mesh, const labelList& patchIDs)
             {
                 WarningInFunction
                     << "Did not visit some faces, e.g. face " << faceI
-                    << " at " << mesh.faceCentres()[faceI] << endl
+                    << " at " << mesh.faceCentres()[faceI] << nl
                     << "Using patch " << patchIDs[0] << " as nearest"
                     << endl;
                 haveWarned = true;
@@ -129,57 +129,38 @@ labelList nearestPatch(const polyMesh& mesh, const labelList& patchIDs)
 }
 
 
-template<class Type>
-void subsetVolFields
+//
+// Subset field-type, availability information cached
+// in the availableFields hashtable.
+//
+template<class Type, template<class> class PatchField, class GeoMesh>
+void subsetFields
 (
     const fvMeshSubset& subsetter,
-    const wordList& fieldNames,
-    PtrList<GeometricField<Type, fvPatchField, volMesh>>& subFields
+    HashTable<wordHashSet>& availableFields,
+    PtrList<GeometricField<Type, PatchField, GeoMesh>>& subFields
 )
 {
-    const fvMesh& baseMesh = subsetter.baseMesh();
-
-    forAll(fieldNames, i)
-    {
-        const word& fieldName = fieldNames[i];
-
-        Info<< "Subsetting field " << fieldName << endl;
-
-        GeometricField<Type, fvPatchField, volMesh> fld
-        (
-            IOobject
-            (
-                fieldName,
-                baseMesh.time().timeName(),
-                baseMesh,
-                IOobject::MUST_READ,
-                IOobject::NO_WRITE
-            ),
-            baseMesh
-        );
+    typedef GeometricField<Type, PatchField, GeoMesh> FieldType;
+    const word fieldType = FieldType::typeName;
 
-        subFields.set(i, subsetter.interpolate(fld));
-    }
-}
+    const wordList fieldNames = availableFields(fieldType).sortedToc();
+    subFields.setSize(fieldNames.size());
 
-
-template<class Type>
-void subsetSurfaceFields
-(
-    const fvMeshSubset& subsetter,
-    const wordList& fieldNames,
-    PtrList<GeometricField<Type, fvsPatchField, surfaceMesh>>& subFields
-)
-{
     const fvMesh& baseMesh = subsetter.baseMesh();
 
+    if (fieldNames.empty())
+    {
+        return;
+    }
+    Info<< "Subsetting " << fieldType << " (";
     forAll(fieldNames, i)
     {
         const word& fieldName = fieldNames[i];
+        if (i) Info<< ' ';
+        Info<< fieldName;
 
-        Info<< "Subsetting field " << fieldName << endl;
-
-        GeometricField<Type, fvsPatchField, surfaceMesh> fld
+        FieldType fld
         (
             IOobject
             (
@@ -193,7 +174,11 @@ void subsetSurfaceFields
         );
 
         subFields.set(i, subsetter.interpolate(fld));
+
+        // Subsetting adds 'subset' prefix - rename to match original.
+        subFields[i].rename(fieldName);
     }
+    Info<< ")" << nl;
 }
 
 
@@ -202,19 +187,30 @@ void subsetPointFields
 (
     const fvMeshSubset& subsetter,
     const pointMesh& pMesh,
-    const wordList& fieldNames,
+    HashTable<wordHashSet>& availableFields,
     PtrList<GeometricField<Type, pointPatchField, pointMesh>>& subFields
 )
 {
+    typedef GeometricField<Type, pointPatchField, pointMesh> FieldType;
+    const word fieldType = FieldType::typeName;
+
+    const wordList fieldNames = availableFields(fieldType).sortedToc();
+    subFields.setSize(fieldNames.size());
+
     const fvMesh& baseMesh = subsetter.baseMesh();
 
+    if (fieldNames.empty())
+    {
+        return;
+    }
+    Info<< "Subsetting " << fieldType << " (";
     forAll(fieldNames, i)
     {
         const word& fieldName = fieldNames[i];
+        if (i) Info<< ' ';
+        Info<< fieldName;
 
-        Info<< "Subsetting field " << fieldName << endl;
-
-        GeometricField<Type, pointPatchField, pointMesh> fld
+        FieldType fld
         (
             IOobject
             (
@@ -228,7 +224,11 @@ void subsetPointFields
         );
 
         subFields.set(i, subsetter.interpolate(fld));
+
+        // Subsetting adds 'subset' prefix - rename to match original.
+        subFields[i].rename(fieldName);
     }
+    Info<< ")" << nl;
 }
 
 
@@ -236,19 +236,30 @@ template<class Type>
 void subsetDimensionedFields
 (
     const fvMeshSubset& subsetter,
-    const wordList& fieldNames,
+    HashTable<wordHashSet>& availableFields,
     PtrList<DimensionedField<Type, volMesh>>& subFields
 )
 {
+    typedef DimensionedField<Type, volMesh> FieldType;
+    const word fieldType = FieldType::typeName;
+
+    const wordList fieldNames = availableFields(fieldType).sortedToc();
+    subFields.setSize(fieldNames.size());
+
     const fvMesh& baseMesh = subsetter.baseMesh();
 
+    if (fieldNames.empty())
+    {
+        return;
+    }
+    Info<< "Subsetting " << fieldType << " (";
     forAll(fieldNames, i)
     {
         const word& fieldName = fieldNames[i];
+        if (i) Info<< ' ';
+        Info<< fieldName;
 
-        Info<< "Subsetting field " << fieldName << endl;
-
-        DimensionedField<Type, volMesh> fld
+        FieldType fld
         (
             IOobject
             (
@@ -262,7 +273,11 @@ void subsetDimensionedFields
         );
 
         subFields.set(i, subsetter.interpolate(fld));
+
+        // Subsetting adds 'subset' prefix - rename to match original.
+        subFields[i].rename(fieldName);
     }
+    Info<< ")" << nl;
 }
 
 
@@ -289,7 +304,7 @@ void subsetTopoSets
 
         // Map the data
         PackedBoolList isSet(set.maxSize(mesh));
-        forAllConstIter(labelHashSet, set, iter)
+        forAllConstIters(set, iter)
         {
             isSet[iter.key()] = true;
         }
@@ -359,7 +374,6 @@ int main(int argc, char *argv[])
 
     #include "createNamedMesh.H"
 
-
     const word setName = args[1];
 
     word meshInstance = mesh.pointsInstance();
@@ -378,7 +392,7 @@ int main(int argc, char *argv[])
     }
 
 
-    Info<< "Reading cell set from " << setName << endl << endl;
+    Info<< "Reading cell set from " << setName << nl << endl;
 
     // Create mesh subsetting engine
     fvMeshSubset subsetter(mesh);
@@ -389,11 +403,7 @@ int main(int argc, char *argv[])
     {
         const word patchName = args["patch"];
 
-        exposedPatchIDs = labelList
-        (
-            1,
-            mesh.boundaryMesh().findPatchID(patchName)
-        );
+        exposedPatchIDs = { mesh.boundaryMesh().findPatchID(patchName) };
 
         if (exposedPatchIDs[0] == -1)
         {
@@ -402,8 +412,8 @@ int main(int argc, char *argv[])
                 << exit(FatalError);
         }
 
-        Info<< "Adding exposed internal faces to patch " << patchName << endl
-            << endl;
+        Info<< "Adding exposed internal faces to patch " << patchName
+            << nl << endl;
     }
     else if (args.optionFound("patches"))
     {
@@ -412,14 +422,14 @@ int main(int argc, char *argv[])
         exposedPatchIDs = mesh.boundaryMesh().patchSet(patchNames).sortedToc();
 
         Info<< "Adding exposed internal faces to nearest of patches "
-            << patchNames << endl << endl;
+            << patchNames << nl << endl;
     }
     else
     {
         Info<< "Adding exposed internal faces to a patch called"
             << " \"oldInternalFaces\" (created if necessary)" << endl
             << endl;
-        exposedPatchIDs = labelList(1, label(-1));
+        exposedPatchIDs = { -1 };
     }
 
 
@@ -431,7 +441,6 @@ int main(int argc, char *argv[])
     }
     else
     {
-
         // Find per face the nearest patch
         labelList nearestExposedPatch(nearestPatch(mesh, exposedPatchIDs));
 
@@ -454,77 +463,45 @@ int main(int argc, char *argv[])
 
 
     IOobjectList objects(mesh, runTime.timeName());
+    HashTable<wordHashSet> availableFields = objects.classes();
 
 
     // Read vol fields and subset
     // ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-    wordList scalarNames(objects.names(volScalarField::typeName));
-    PtrList<volScalarField> scalarFlds(scalarNames.size());
-    subsetVolFields(subsetter, scalarNames, scalarFlds);
+    PtrList<volScalarField> scalarFlds;
+    subsetFields(subsetter, availableFields, scalarFlds);
 
-    wordList vectorNames(objects.names(volVectorField::typeName));
-    PtrList<volVectorField> vectorFlds(vectorNames.size());
-    subsetVolFields(subsetter, vectorNames, vectorFlds);
+    PtrList<volVectorField> vectorFlds;
+    subsetFields(subsetter, availableFields, vectorFlds);
 
-    wordList sphericalTensorNames
-    (
-        objects.names(volSphericalTensorField::typeName)
-    );
-    PtrList<volSphericalTensorField> sphericalTensorFlds
-    (
-        sphericalTensorNames.size()
-    );
-    subsetVolFields(subsetter, sphericalTensorNames, sphericalTensorFlds);
+    PtrList<volSphericalTensorField> sphTensorFlds;
+    subsetFields(subsetter, availableFields, sphTensorFlds);
 
-    wordList symmTensorNames(objects.names(volSymmTensorField::typeName));
-    PtrList<volSymmTensorField> symmTensorFlds(symmTensorNames.size());
-    subsetVolFields(subsetter, symmTensorNames, symmTensorFlds);
+    PtrList<volSymmTensorField> symmTensorFlds;
+    subsetFields(subsetter, availableFields, symmTensorFlds);
 
-    wordList tensorNames(objects.names(volTensorField::typeName));
-    PtrList<volTensorField> tensorFlds(tensorNames.size());
-    subsetVolFields(subsetter, tensorNames, tensorFlds);
+    PtrList<volTensorField> tensorFlds;
+    subsetFields(subsetter, availableFields, tensorFlds);
 
 
     // Read surface fields and subset
     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-    wordList surfScalarNames(objects.names(surfaceScalarField::typeName));
-    PtrList<surfaceScalarField> surfScalarFlds(surfScalarNames.size());
-    subsetSurfaceFields(subsetter, surfScalarNames, surfScalarFlds);
+    PtrList<surfaceScalarField> surfScalarFlds;
+    subsetFields(subsetter, availableFields, surfScalarFlds);
 
-    wordList surfVectorNames(objects.names(surfaceVectorField::typeName));
-    PtrList<surfaceVectorField> surfVectorFlds(surfVectorNames.size());
-    subsetSurfaceFields(subsetter, surfVectorNames, surfVectorFlds);
+    PtrList<surfaceVectorField> surfVectorFlds;
+    subsetFields(subsetter, availableFields, surfVectorFlds);
 
-    wordList surfSphericalTensorNames
-    (
-        objects.names(surfaceSphericalTensorField::typeName)
-    );
-    PtrList<surfaceSphericalTensorField> surfSphericalTensorFlds
-    (
-        surfSphericalTensorNames.size()
-    );
-    subsetSurfaceFields
-    (
-        subsetter,
-        surfSphericalTensorNames,
-        surfSphericalTensorFlds
-    );
+    PtrList<surfaceSphericalTensorField> surfSphTensorFlds;
+    subsetFields(subsetter, availableFields, surfSphTensorFlds);
 
-    wordList surfSymmTensorNames
-    (
-        objects.names(surfaceSymmTensorField::typeName)
-    );
-    PtrList<surfaceSymmTensorField> surfSymmTensorFlds
-    (
-        surfSymmTensorNames.size()
-    );
-    subsetSurfaceFields(subsetter, surfSymmTensorNames, surfSymmTensorFlds);
+    PtrList<surfaceSymmTensorField> surfSymmTensorFlds;
+    subsetFields(subsetter, availableFields, surfSymmTensorFlds);
 
-    wordList surfTensorNames(objects.names(surfaceTensorField::typeName));
-    PtrList<surfaceTensorField> surfTensorFlds(surfTensorNames.size());
-    subsetSurfaceFields(subsetter, surfTensorNames, surfTensorFlds);
+    PtrList<surfaceTensorField> surfTensorFlds;
+    subsetFields(subsetter, availableFields, surfTensorFlds);
 
 
     // Read point fields and subset
@@ -532,86 +509,39 @@ int main(int argc, char *argv[])
 
     const pointMesh& pMesh = pointMesh::New(mesh);
 
-    wordList pointScalarNames(objects.names(pointScalarField::typeName));
-    PtrList<pointScalarField> pointScalarFlds(pointScalarNames.size());
-    subsetPointFields(subsetter, pMesh, pointScalarNames, pointScalarFlds);
+    PtrList<pointScalarField> pointScalarFlds;
+    subsetPointFields(subsetter, pMesh, availableFields, pointScalarFlds);
 
-    wordList pointVectorNames(objects.names(pointVectorField::typeName));
-    PtrList<pointVectorField> pointVectorFlds(pointVectorNames.size());
-    subsetPointFields(subsetter, pMesh, pointVectorNames, pointVectorFlds);
+    PtrList<pointVectorField> pointVectorFlds;
+    subsetPointFields(subsetter, pMesh, availableFields, pointVectorFlds);
 
-    wordList pointSphericalTensorNames
-    (
-        objects.names(pointSphericalTensorField::typeName)
-    );
-    PtrList<pointSphericalTensorField> pointSphericalTensorFlds
-    (
-        pointSphericalTensorNames.size()
-    );
-    subsetPointFields
-    (
-        subsetter,
-        pMesh,
-        pointSphericalTensorNames,
-        pointSphericalTensorFlds
-    );
+    PtrList<pointSphericalTensorField> pointSphTensorFlds;
+    subsetPointFields(subsetter, pMesh, availableFields, pointSphTensorFlds);
 
-    wordList pointSymmTensorNames
-    (
-        objects.names(pointSymmTensorField::typeName)
-    );
-    PtrList<pointSymmTensorField> pointSymmTensorFlds
-    (
-        pointSymmTensorNames.size()
-    );
-    subsetPointFields
-    (
-        subsetter,
-        pMesh,
-        pointSymmTensorNames,
-        pointSymmTensorFlds
-    );
+    PtrList<pointSymmTensorField> pointSymmTensorFlds;
+    subsetPointFields(subsetter, pMesh, availableFields, pointSymmTensorFlds);
 
-    wordList pointTensorNames(objects.names(pointTensorField::typeName));
-    PtrList<pointTensorField> pointTensorFlds(pointTensorNames.size());
-    subsetPointFields(subsetter, pMesh, pointTensorNames, pointTensorFlds);
+    PtrList<pointTensorField> pointTensorFlds;
+    subsetPointFields(subsetter, pMesh, availableFields, pointTensorFlds);
 
 
     // Read dimensioned fields and subset
     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-    typedef volScalarField::Internal dimScalType;
-    wordList scalarDimNames(objects.names(dimScalType::typeName));
-    PtrList<dimScalType> scalarDimFlds(scalarDimNames.size());
-    subsetDimensionedFields(subsetter, scalarDimNames, scalarDimFlds);
+    PtrList<volScalarField::Internal> scalarDimFlds;
+    subsetDimensionedFields(subsetter, availableFields, scalarDimFlds);
 
-    typedef volVectorField::Internal dimVecType;
-    wordList vectorDimNames(objects.names(dimVecType::typeName));
-    PtrList<dimVecType> vectorDimFlds(vectorDimNames.size());
-    subsetDimensionedFields(subsetter, vectorDimNames, vectorDimFlds);
+    PtrList<volVectorField::Internal> vectorDimFlds;
+    subsetDimensionedFields(subsetter, availableFields, vectorDimFlds);
 
-    typedef volSphericalTensorField::Internal dimSphereType;
-    wordList sphericalTensorDimNames(objects.names(dimSphereType::typeName));
-    PtrList<dimSphereType> sphericalTensorDimFlds
-    (
-        sphericalTensorDimNames.size()
-    );
-    subsetDimensionedFields
-    (
-        subsetter,
-        sphericalTensorDimNames,
-        sphericalTensorDimFlds
-    );
+    PtrList<volSphericalTensorField::Internal> sphTensorDimFlds;
+    subsetDimensionedFields(subsetter, availableFields, sphTensorDimFlds);
 
-    typedef volSymmTensorField::Internal dimSymmTensorType;
-    wordList symmTensorDimNames(objects.names(dimSymmTensorType::typeName));
-    PtrList<dimSymmTensorType> symmTensorDimFlds(symmTensorDimNames.size());
-    subsetDimensionedFields(subsetter, symmTensorDimNames, symmTensorDimFlds);
+    PtrList<volSymmTensorField::Internal> symmTensorDimFlds;
+    subsetDimensionedFields(subsetter, availableFields, symmTensorDimFlds);
 
-    typedef volTensorField::Internal dimTensorType;
-    wordList tensorDimNames(objects.names(dimTensorType::typeName));
-    PtrList<dimTensorType> tensorDimFlds(tensorDimNames.size());
-    subsetDimensionedFields(subsetter, tensorDimNames, tensorDimFlds);
+    PtrList<volTensorField::Internal> tensorDimFlds;
+    subsetDimensionedFields(subsetter, availableFields, tensorDimFlds);
 
 
     // topoSets and subset
@@ -620,6 +550,7 @@ int main(int argc, char *argv[])
     PtrList<cellSet> cellSets;
     PtrList<faceSet> faceSets;
     PtrList<pointSet> pointSets;
+
     {
         IOobjectList objects(mesh, mesh.facesInstance(), "polyMesh/sets");
         objects.remove(currentSet);
@@ -650,7 +581,6 @@ int main(int argc, char *argv[])
     }
 
 
-
     // Write mesh and fields to new time
     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -668,123 +598,100 @@ int main(int argc, char *argv[])
         subsetter.subMesh().setInstance(runTime.timeName());
     }
 
-
-
     Info<< "Writing subsetted mesh and fields to time " << runTime.timeName()
         << endl;
     subsetter.subMesh().write();
     processorMeshes::removeFiles(subsetter.subMesh());
 
 
-    // Subsetting adds 'subset' prefix. Rename field to be like original.
+    // Volume fields
     forAll(scalarFlds, i)
     {
-        scalarFlds[i].rename(scalarNames[i]);
         scalarFlds[i].write();
     }
     forAll(vectorFlds, i)
     {
-        vectorFlds[i].rename(vectorNames[i]);
         vectorFlds[i].write();
     }
-    forAll(sphericalTensorFlds, i)
+    forAll(sphTensorFlds, i)
     {
-        sphericalTensorFlds[i].rename(sphericalTensorNames[i]);
-        sphericalTensorFlds[i].write();
+        sphTensorFlds[i].write();
     }
     forAll(symmTensorFlds, i)
     {
-        symmTensorFlds[i].rename(symmTensorNames[i]);
         symmTensorFlds[i].write();
     }
     forAll(tensorFlds, i)
     {
-        tensorFlds[i].rename(tensorNames[i]);
         tensorFlds[i].write();
     }
 
-    // Surface ones.
+    // Surface fields.
     forAll(surfScalarFlds, i)
     {
-        surfScalarFlds[i].rename(surfScalarNames[i]);
         surfScalarFlds[i].write();
     }
     forAll(surfVectorFlds, i)
     {
-        surfVectorFlds[i].rename(surfVectorNames[i]);
         surfVectorFlds[i].write();
     }
-    forAll(surfSphericalTensorFlds, i)
+    forAll(surfSphTensorFlds, i)
     {
-        surfSphericalTensorFlds[i].rename(surfSphericalTensorNames[i]);
-        surfSphericalTensorFlds[i].write();
+        surfSphTensorFlds[i].write();
     }
     forAll(surfSymmTensorFlds, i)
     {
-        surfSymmTensorFlds[i].rename(surfSymmTensorNames[i]);
         surfSymmTensorFlds[i].write();
     }
-    forAll(surfTensorNames, i)
+    forAll(surfTensorFlds, i)
     {
-        surfTensorFlds[i].rename(surfTensorNames[i]);
         surfTensorFlds[i].write();
     }
 
-    // Point ones
+    // Point fields
     forAll(pointScalarFlds, i)
     {
-        pointScalarFlds[i].rename(pointScalarNames[i]);
         pointScalarFlds[i].write();
     }
     forAll(pointVectorFlds, i)
     {
-        pointVectorFlds[i].rename(pointVectorNames[i]);
         pointVectorFlds[i].write();
     }
-    forAll(pointSphericalTensorFlds, i)
+    forAll(pointSphTensorFlds, i)
     {
-        pointSphericalTensorFlds[i].rename(pointSphericalTensorNames[i]);
-        pointSphericalTensorFlds[i].write();
+        pointSphTensorFlds[i].write();
     }
     forAll(pointSymmTensorFlds, i)
     {
-        pointSymmTensorFlds[i].rename(pointSymmTensorNames[i]);
         pointSymmTensorFlds[i].write();
     }
-    forAll(pointTensorNames, i)
+    forAll(pointTensorFlds, i)
     {
-        pointTensorFlds[i].rename(pointTensorNames[i]);
         pointTensorFlds[i].write();
     }
 
-    // DimensionedFields
+    // Dimensioned fields
     forAll(scalarDimFlds, i)
     {
-        scalarDimFlds[i].rename(scalarDimNames[i]);
         scalarDimFlds[i].write();
     }
     forAll(vectorDimFlds, i)
     {
-        vectorDimFlds[i].rename(vectorDimNames[i]);
         vectorDimFlds[i].write();
     }
-    forAll(sphericalTensorDimFlds, i)
+    forAll(sphTensorDimFlds, i)
     {
-        sphericalTensorDimFlds[i].rename(sphericalTensorDimNames[i]);
-        sphericalTensorDimFlds[i].write();
+        sphTensorDimFlds[i].write();
     }
     forAll(symmTensorDimFlds, i)
     {
-        symmTensorDimFlds[i].rename(symmTensorDimNames[i]);
         symmTensorDimFlds[i].write();
     }
     forAll(tensorDimFlds, i)
     {
-        tensorDimFlds[i].rename(tensorDimNames[i]);
         tensorDimFlds[i].write();
     }
 
-
     Info<< "End\n" << endl;
 
     return 0;
diff --git a/applications/utilities/miscellaneous/foamHelp/helpTypes/doxygenXmlParser/doxygenXmlParser.C b/applications/utilities/miscellaneous/foamHelp/helpTypes/doxygenXmlParser/doxygenXmlParser.C
index 0de175b4b7053d4d7c3c55a5a3c91645e568c6f7..bc67aabd7f4e14ffade559226dd298e34c4f86a8 100644
--- a/applications/utilities/miscellaneous/foamHelp/helpTypes/doxygenXmlParser/doxygenXmlParser.C
+++ b/applications/utilities/miscellaneous/foamHelp/helpTypes/doxygenXmlParser/doxygenXmlParser.C
@@ -24,7 +24,7 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "doxygenXmlParser.H"
-#include "wordRe.H"
+#include "regExp.H"
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
@@ -40,8 +40,8 @@ Foam::doxygenXmlParser::doxygenXmlParser
     dictionary(dictionary::null)
 {
     // Pre-construct and compile regular expressions
-    const wordRe nameRe(".*.H", wordRe::DETECT);
-    const wordRe searchStrRe(searchStr, wordRe::DETECT);
+    const regExp nameRe(".*.H");
+    const regExp searchStrRe(searchStr);
 
     // Pre-construct constant strings and names to speed-up comparisons
     const string slashStartTag('/' + startTag);
@@ -163,7 +163,7 @@ Foam::doxygenXmlParser::doxygenXmlParser
                     (
                         !exactMatch
                      && !found(tName) // not already added
-                     && wordRe(".*" + tName + ".*", wordRe::DETECT).match(name)
+                     && regExp(".*" + tName + ".*").match(name)
                     )
                     {
                         dictionary dict(dictionary::null);
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/checkData.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/checkData.H
index f33a8f727f21e606d4cd0340df2c61f1cbd68c41..62cb39030b4fc38f980783f255780b3b0acbfe1e 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/checkData.H
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/checkData.H
@@ -23,7 +23,7 @@ if (!fieldsToUse.found(fieldName))
             ).typeHeaderOk<volScalarField>(false, false)
         );
 
-        if (variableGood)
+        if (!variableGood)
         {
             break;
         }
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/findCloudFields.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/findCloudFields.H
index a37bbb7c09b96c4e778ad4f403155b1f71befc3c..89e1084abcbff8a9b2c495b363b1a7607875acd0 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/findCloudFields.H
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/findCloudFields.H
@@ -35,36 +35,25 @@ if (timeDirs.size() && !noLagrangian)
                 cloudPrefix/cloudName
             );
 
-            // clouds always require "positions"
+            // Clouds always have "positions"
             if (cloudObjs.found("positions"))
             {
-                HashTable<HashTable<word>>::iterator cloudIter =
-                    cloudFields.find(cloudName);
+                // Save the cloud fields on a per cloud basis
+                auto fieldsPerCloud = cloudFields(cloudName);
 
-                if (cloudIter == cloudFields.end())
+                forAllConstIters(cloudObjs, fieldIter)
                 {
-                    // A newly discovered cloud
-                    cloudFields.insert(cloudName, HashTable<word>());
-                    cloudIter = cloudFields.find(cloudName);
-                }
+                    const IOobject* obj = fieldIter();
 
-                forAllConstIter(IOobjectList, cloudObjs, fieldIter)
-                {
-                    const IOobject& obj = *fieldIter();
-
-                    // Add field and field type
-                    cloudIter().insert
-                    (
-                        obj.name(),
-                        obj.headerClassName()
-                    );
+                    // Field name/type
+                    fieldsPerCloud.insert(obj->name(), obj->headerClassName());
                 }
             }
         }
     }
 
-    // prune out "positions" again since it gets treated specially
-    forAllIter(HashTable<HashTable<word>>, cloudFields, cloudIter)
+    // Prune out "positions" again since it gets treated specially
+    forAllIters(cloudFields, cloudIter)
     {
         cloudIter().erase("positions");
     }
@@ -76,18 +65,13 @@ if (timeDirs.size() && !noLagrangian)
 }
 
 
-// sorted list of cloud names
+// Sorted list of cloud names
 const wordList cloudNames(cloudFields.sortedToc());
 
 if (cloudNames.size())
 {
-    // complete the echo information
-    Info<< "(";
-    forAll(cloudNames, cloudNo)
-    {
-        Info<< ' ' << cloudNames[cloudNo];
-    }
-    Info<< " ) " << endl;
+    // Complete the echo information - as flatOutput
+    cloudNames.writeList(Info) << endl;
 }
 
 // ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C b/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C
index 5080d840ebc1e3da0ab29f58a411f2c9a43da133..2c411b5cf5acb40b797d0f43bafe66549bc763ba 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/foamToEnsight.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -78,6 +78,7 @@ Note
 
 #include "fvc.H"
 #include "volFields.H"
+#include "hashedWordList.H"
 
 #include "labelIOField.H"
 #include "scalarIOField.H"
@@ -190,7 +191,7 @@ int main(int argc, char *argv[])
     );
 
     // The volume field types that we handle
-    const wordList volFieldTypes
+    const hashedWordList volFieldTypes
     {
         volScalarField::typeName,
         volVectorField::typeName,
@@ -207,7 +208,7 @@ int main(int argc, char *argv[])
 
     #include "setRootCase.H"
 
-    // default to binary output, unless otherwise specified
+    // Default to binary output, unless otherwise specified
     const IOstream::streamFormat format =
     (
         args.optionFound("ascii")
@@ -234,7 +235,7 @@ int main(int argc, char *argv[])
     }
 
     //
-    // general (case) output options
+    // General (case) output options
     //
     ensightCase::options caseOpts(format);
 
@@ -257,7 +258,7 @@ int main(int argc, char *argv[])
 
 
     //
-    // output configuration (geometry related)
+    // Output configuration (geometry related)
     //
     ensightMesh::options writeOpts(format);
     writeOpts.noPatches(args.optionFound("noPatches"));
@@ -313,12 +314,6 @@ int main(int argc, char *argv[])
         ensCase.printInfo(Info) << endl;
     }
 
-
-    // Set Time to the last time before looking for lagrangian objects
-    runTime.setTime(timeDirs.last(), timeDirs.size()-1);
-
-    IOobjectList objects(mesh, runTime.timeName());
-
     #include "checkMeshMoving.H"
     #include "findCloudFields.H"
 
@@ -331,6 +326,40 @@ int main(int argc, char *argv[])
         << timer.cpuTimeIncrement() << " s, "
         << mem.update().size() << " kB" << nl << endl;
 
+    // Get the list of supported classes/fields
+    HashTable<wordHashSet> usableObjects;
+    {
+        // Initially all possible objects that are available at the final time
+        IOobjectList objects(mesh, timeDirs.last().name());
+
+        // Categorize by classes, pre-filter on name (if requested)
+        usableObjects =
+        (
+            fieldPatterns.empty()
+          ? objects.classes()
+          : objects.classes(fieldPatterns)
+        );
+
+        // Limit to types that we explicitly handle
+        usableObjects.filterKeys(volFieldTypes);
+
+        // Force each field-type into existence (simplifies code logic
+        // and doesn't cost much) and simultaneously remove all
+        // "*_0" restart fields
+
+        for (auto fieldType : volFieldTypes)
+        {
+            usableObjects
+            (
+                fieldType
+            ).filterKeys
+            (
+                [](const word& k){ return k.endsWith("_0"); },
+                true  // prune
+            );
+        }
+    }
+
     // ignore special fields (_0 fields),
     // ignore fields we don't handle,
     // ignore fields that are not available for all time-steps
@@ -362,25 +391,22 @@ int main(int argc, char *argv[])
         // ~~~~~~~~~~~~~~~~~~~~~~
         Info<< "Write volume field (";
 
-        forAll(volFieldTypes, typei)
+        for (auto fieldType : volFieldTypes)
         {
-            const word& fieldType = volFieldTypes[typei];
-            wordList fieldNames = objects.names(fieldType);
+            // For convenience, just force each field-type into existence.
+            // This simplifies code logic and doesn't cost much at all.
+            wordHashSet& fieldNames = usableObjects(fieldType);
 
-            // Filter on name as required
-            if (!fieldPatterns.empty())
+            forAllIters(fieldNames, fieldIter)
             {
-                inplaceSubsetStrings(fieldPatterns, fieldNames);
-            }
-
-            forAll(fieldNames, fieldi)
-            {
-                const word& fieldName = fieldNames[fieldi];
+                const word& fieldName = fieldIter.key();
 
                 #include "checkData.H"
 
+                // Partially complete field?
                 if (!fieldsToUse[fieldName])
                 {
+                    fieldNames.erase(fieldIter);
                     continue;
                 }
 
@@ -597,7 +623,8 @@ int main(int argc, char *argv[])
                 }
                 else
                 {
-                    // Do not currently handle this type - blacklist for the future.
+                    // Do not currently handle this type
+                    // - blacklist for the future.
                     fieldsToUse.set(fieldName, false);
                 }
 
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK.C b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK.C
index c2a6f3b29810977ee869310d9c56f5feb2463420..602f68b2d048f973828d76498e5838c988f76dac 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK.C
+++ b/applications/utilities/postProcessing/dataConversion/foamToVTK/foamToVTK.C
@@ -199,7 +199,7 @@ void print(Ostream& os, const wordList& flds)
 labelList getSelectedPatches
 (
     const polyBoundaryMesh& patches,
-    const List<wordRe>& excludePatches
+    const wordRes& excludePatches
 )
 {
     DynamicList<label> patchIDs(patches.size());
@@ -219,7 +219,7 @@ labelList getSelectedPatches
             Info<< "    discarding empty/processor patch " << patchi
                 << " " << pp.name() << endl;
         }
-        else if (findStrings(excludePatches, pp.name()))
+        else if (excludePatches.match(pp.name()))
         {
             Info<< "    excluding patch " << patchi
                 << " " << pp.name() << endl;
@@ -379,7 +379,7 @@ int main(int argc, char *argv[])
 
     const bool allPatches = args.optionFound("allPatches");
 
-    List<wordRe> excludePatches;
+    wordReList excludePatches;
     if (args.optionFound("excludePatches"))
     {
         args.optionLookup("excludePatches")() >> excludePatches;
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/vtkPVFoamReader.h b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/vtkPVFoamReader.h
index c634f667fbed06eef77307d64b11170c2f5a73ef..0de09a5547b4da6319fa38959f4a7955fd08d56f 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/vtkPVFoamReader.h
+++ b/applications/utilities/postProcessing/graphics/PVReaders/PVFoamReader/PVFoamReader/vtkPVFoamReader.h
@@ -55,7 +55,7 @@ namespace Foam
 
 
 /*---------------------------------------------------------------------------*\
-                     Class vtkPVFoamReader Declaration
+                       Class vtkPVFoamReader Declaration
 \*---------------------------------------------------------------------------*/
 
 class vtkPVFoamReader
@@ -64,7 +64,7 @@ class vtkPVFoamReader
 {
 public:
     vtkTypeMacro(vtkPVFoamReader, vtkMultiBlockDataSetAlgorithm);
-    void PrintSelf(ostream&, vtkIndent);
+    void PrintSelf(ostream&, vtkIndent) VTK_OVERRIDE;
 
     static vtkPVFoamReader* New();
 
@@ -199,7 +199,7 @@ protected:
         vtkInformation*,
         vtkInformationVector**,
         vtkInformationVector*
-    );
+    ) VTK_OVERRIDE;
 
     //- Get the mesh/fields for a particular time
     virtual int RequestData
@@ -207,10 +207,10 @@ protected:
         vtkInformation*,
         vtkInformationVector**,
         vtkInformationVector*
-    );
+    ) VTK_OVERRIDE;
 
     //- Fill in additional port information
-    virtual int FillOutputPortInformation(int, vtkInformation*);
+    virtual int FillOutputPortInformation(int, vtkInformation*) VTK_OVERRIDE;
 
     //- The observer to modify this object when array selections are modified
     vtkCallbackCommand* SelectionObserver;
diff --git a/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/PVblockMeshReader/vtkPVblockMeshReader.h b/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/PVblockMeshReader/vtkPVblockMeshReader.h
index 66805716eec674fac90a804ea2e7887f93149732..f881d3c4ed7f8d49833408a7f45d82b59c5bb4e8 100644
--- a/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/PVblockMeshReader/vtkPVblockMeshReader.h
+++ b/applications/utilities/postProcessing/graphics/PVReaders/PVblockMeshReader/PVblockMeshReader/vtkPVblockMeshReader.h
@@ -62,7 +62,7 @@ class vtkPVblockMeshReader
 {
 public:
     vtkTypeMacro(vtkPVblockMeshReader, vtkMultiBlockDataSetAlgorithm);
-    void PrintSelf(ostream&, vtkIndent);
+    void PrintSelf(ostream&, vtkIndent) VTK_OVERRIDE;
 
     static vtkPVblockMeshReader* New();
 
@@ -127,7 +127,7 @@ protected:
         vtkInformation* unusedRequest,
         vtkInformationVector** unusedInputVector,
         vtkInformationVector* outputVector
-    );
+    ) VTK_OVERRIDE;
 
     //- Get the mesh for a particular time
     virtual int RequestData
@@ -135,10 +135,10 @@ protected:
         vtkInformation* unusedRequest,
         vtkInformationVector** unusedInputVector,
         vtkInformationVector* outputVector
-    );
+    ) VTK_OVERRIDE;
 
     //- Fill in additional port information
-    virtual int FillOutputPortInformation(int, vtkInformation*);
+    virtual int FillOutputPortInformation(int, vtkInformation*) VTK_OVERRIDE;
 
     // The observer to modify this object when array selections are modified
     vtkCallbackCommand* SelectionObserver;
diff --git a/applications/utilities/preProcessing/createZeroDirectory/boundaryInfo.C b/applications/utilities/preProcessing/createZeroDirectory/boundaryInfo.C
index 62ca3f5514036e093a3eef1e54a80721cedea9e2..a44a9066642ed6d93d1009f105eb02dda63111f3 100644
--- a/applications/utilities/preProcessing/createZeroDirectory/boundaryInfo.C
+++ b/applications/utilities/preProcessing/createZeroDirectory/boundaryInfo.C
@@ -169,7 +169,7 @@ void Foam::boundaryInfo::setType(const label patchI, const word& condition)
         return;
     }
 
-    if (wordRe(".*[Mm]apped.*", wordRe::REGEXP).match(types_[patchI]))
+    if (regExp(".*[Mm]apped.*").match(types_[patchI]))
     {
         // ugly hack to avoid overriding mapped types
         return;
diff --git a/doc/Allwmake b/doc/Allwmake
index f6684e337c50d0946ec6e957bddbd74d3c57bd00..57d993de842535f03966d2857eb88c443fef3660 100755
--- a/doc/Allwmake
+++ b/doc/Allwmake
@@ -1,9 +1,9 @@
 #!/bin/sh
 cd ${0%/*} || exit 1    # Run from this directory
 
-# fix permissions (NB: '+X' and not '+x'!)
+# Fix permissions (NB: '+X' and not '+x'!)
 chmod a+rX $WM_PROJECT_DIR $WM_PROJECT_DIR/doc Doxygen
 
-Doxygen/Allwmake
+exec Doxygen/Allwmake "$@"
 
 #------------------------------------------------------------------------------
diff --git a/doc/Doxygen/Allwmake b/doc/Doxygen/Allwmake
index 9947ab925d1f8184601057a17d0cbd5edb94eab7..726c5fbbe7e152ccc3a995ed783b6fa572c1a92c 100755
--- a/doc/Doxygen/Allwmake
+++ b/doc/Doxygen/Allwmake
@@ -14,13 +14,17 @@ usage() {
 
 usage: ${0##*/} [OPTION]
 options:
-  -online    use links to the Github repositories instead of the local source code
+  -config name      use alternative doxygen config
+  -dir    name      process given directory name directly
+  -online           use links to the Github repositories instead of the
+                    local source code
   -help
 
 USAGE
     exit 1
 }
 
+# -----------------------------------------------------------------------------
 
 defineURL() {
     WEB_PATH="https://develop.openfoam.com"
@@ -39,13 +43,43 @@ defineURL() {
     export FOAM_ONLINE_REPO="$FOAM_BASE_REPO/blob/${FOAM_REPO_TAG}"
 }
 
-# parse options
+
+unset configName dirName
+
+# Parse options
 while [ "$#" -gt 0 ]
 do
     case "$1" in
     -h | -help)
         usage
         ;;
+    -config)
+        configName="$2"
+        [ -f "$configName" ] || {
+            # No such file. Try some common alternatives
+            for ending in $configName ".$configName" "-$configName"
+            do
+                if [ -f "Doxyfile$ending" ]
+                then
+                    configName="Doxyfile$ending"
+                    break
+                fi
+            done
+        }
+        [ -f "$configName" ] || {
+            echo "Could not resolve Doxyfile config: $configName" 1>&2
+            exit 1
+        }
+        shift
+        ;;
+    -dir)
+        dirName="$2"
+        [ -d "$dirName" ] || {
+            echo "Could not resolve input directory: $dirName" 1>&2
+            exit 1
+        }
+        shift
+        ;;
     -online)
         defineURL
         ;;
@@ -56,19 +90,31 @@ do
     shift
 done
 
+
 #------------------------------------------------------------------------------
 
 rm -rf latex man
 
-# remove html directory in background
+# Remove html directory in background
 mv html html-stagedRemove$$ 2> /dev/null
 rm -rf html-stagedRemove$$ >/dev/null 2>&1 &
 
-# ensure that created files are readable by everyone
+# Ensure that created files are readable by everyone
 umask 22
-doxygen
 
-# fix permissions (NB: '+X' and not '+x'!)
+if [ -n "$dirName" ]
+then
+    # Create a temporary with only the specified directory
+    tmpConfig="${TMPDIR:-/tmp}/Doxyfile.$$"
+    trap 'rm -f $tmpConfig 2>/dev/null; exit 0' EXIT TERM INT
+    cat $PWD/Doxyfile > $tmpConfig
+    echo "INPUT = $dirName" >> $tmpConfig
+    doxygen $tmpConfig
+else
+    doxygen $configName
+fi
+
+# Fix permissions (NB: '+X' and not '+x'!)
 chmod -R a+rX html latex man 2>/dev/null
 
 echo
diff --git a/src/OSspecific/POSIX/regExp.C b/src/OSspecific/POSIX/regExp.C
index a22ba01a56330a202b409bf38ca4cb40f8fa8659..95e70ece9d4280b80a7e2892836d33f2fd229d20 100644
--- a/src/OSspecific/POSIX/regExp.C
+++ b/src/OSspecific/POSIX/regExp.C
@@ -111,7 +111,7 @@ Foam::regExp::~regExp()
 
 // * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
 
-void Foam::regExp::set(const char* pattern, bool ignoreCase)
+bool Foam::regExp::set(const char* pattern, bool ignoreCase)
 {
     clear();
 
@@ -137,7 +137,7 @@ void Foam::regExp::set(const char* pattern, bool ignoreCase)
             // avoid zero-length patterns
             if (!*pat)
             {
-                return;
+                return false;
             }
         }
 
@@ -154,11 +154,15 @@ void Foam::regExp::set(const char* pattern, bool ignoreCase)
                 << nl << errbuf
                 << exit(FatalError);
         }
+
+        return true;
     }
+
+    return false;  // Was cleared and nothing was set
 }
 
 
-void Foam::regExp::set(const std::string& pattern, bool ignoreCase)
+bool Foam::regExp::set(const std::string& pattern, bool ignoreCase)
 {
     return set(pattern.c_str(), ignoreCase);
 }
@@ -208,7 +212,7 @@ bool Foam::regExp::match(const std::string& text) const
         if
         (
             regexec(preg_, text.c_str(), nmatch, pmatch, 0) == 0
-         && (pmatch[0].rm_so == 0 && pmatch[0].rm_eo == label(text.size()))
+         && (pmatch[0].rm_so == 0 && pmatch[0].rm_eo == regoff_t(text.size()))
         )
         {
             return true;
diff --git a/src/OSspecific/POSIX/regExp.H b/src/OSspecific/POSIX/regExp.H
index 76d2deba93c8128ac6652a23167af074860b6c22..640f6a819e1566374c312a1fc5910b4e4dafa296 100644
--- a/src/OSspecific/POSIX/regExp.H
+++ b/src/OSspecific/POSIX/regExp.H
@@ -128,20 +128,23 @@ public:
 
       // Editing
 
-        //- Compile pattern into a regular expression, optionally ignore case
-        void set(const char* pattern, bool ignoreCase=false);
+        //- Compile pattern into a regular expression, optionally ignore case.
+        //  \return True if the pattern was compiled
+        bool set(const char* pattern, bool ignoreCase=false);
 
         //- Compile pattern into a regular expression, optionally ignore case
-        void set(const std::string& pattern, bool ignoreCase=false);
+        //  \return True if the pattern was compiled
+        bool set(const std::string& pattern, bool ignoreCase=false);
 
-        //- Clear expression, return true if expression had existed.
+        //- Clear expression.
+        //  \return True if expression had existed prior to the clear.
         bool clear();
 
 
       // Matching/Searching
 
         //- Find position within string.
-        //  Returns the index where it begins or string::npos if not found
+        //  \Return The index where it begins or string::npos if not found
         std::string::size_type find(const std::string& text) const;
 
         //- Return true if it matches the entire string
@@ -158,6 +161,9 @@ public:
 
     // Member Operators
 
+        //- Perform match on text
+        inline bool operator()(const std::string& text) const;
+
         //- Assign and compile pattern from a character array
         //  Always case sensitive
         inline void operator=(const char* pattern);
diff --git a/src/OSspecific/POSIX/regExpI.H b/src/OSspecific/POSIX/regExpI.H
index 64865c95fa0169272806eb986090db6ecc24b253..e33564e611a8e79b8225a2a1f83aad2bb8e2bd51 100644
--- a/src/OSspecific/POSIX/regExpI.H
+++ b/src/OSspecific/POSIX/regExpI.H
@@ -66,6 +66,12 @@ inline bool Foam::regExp::search(const std::string& text) const
 
 // * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * * //
 
+inline bool Foam::regExp::operator()(const std::string& text) const
+{
+    return match(text);
+}
+
+
 inline void Foam::regExp::operator=(const char* pattern)
 {
     set(pattern);
diff --git a/src/OpenFOAM/Make/files b/src/OpenFOAM/Make/files
index 5636f7c937b067ef33523779a938d677a3847e1d..bc08c99154c17160d0780c2083c5aa15caf6af77 100644
--- a/src/OpenFOAM/Make/files
+++ b/src/OpenFOAM/Make/files
@@ -97,8 +97,8 @@ $(strings)/fileName/fileName.C
 $(strings)/fileName/fileNameIO.C
 $(strings)/keyType/keyType.C
 $(strings)/wordRe/wordRe.C
+$(strings)/wordRes/wordRes.C
 $(strings)/lists/hashedWordList.C
-$(strings)/lists/wordReListMatcher.C
 $(strings)/stringOps/stringOps.C
 
 ops = primitives/ops
diff --git a/src/OpenFOAM/containers/HashTables/HashSet/HashSet.C b/src/OpenFOAM/containers/HashTables/HashSet/HashSet.C
index 77ab200a42c7d72c7a7c16b066a88e263da06e12..5b1f45b8395a9cf7e57d1cf171bcfb645a7145d6 100644
--- a/src/OpenFOAM/containers/HashTables/HashSet/HashSet.C
+++ b/src/OpenFOAM/containers/HashTables/HashSet/HashSet.C
@@ -158,6 +158,20 @@ Foam::label Foam::HashSet<Key, Hash>::insert(std::initializer_list<Key> lst)
 
 // * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
 
+template<class Key, class Hash>
+inline bool Foam::HashSet<Key, Hash>::operator()(const Key& key) const
+{
+    return this->found(key);
+}
+
+
+template<class Key, class Hash>
+inline bool Foam::HashSet<Key, Hash>::operator[](const Key& key) const
+{
+    return this->found(key);
+}
+
+
 template<class Key, class Hash>
 void Foam::HashSet<Key, Hash>::operator=(const UList<Key>& lst)
 {
@@ -180,12 +194,6 @@ void Foam::HashSet<Key, Hash>::operator=(std::initializer_list<Key> lst)
 }
 
 
-template<class Key, class Hash>
-inline bool Foam::HashSet<Key, Hash>::operator[](const Key& key) const
-{
-    return this->found(key);
-}
-
 
 template<class Key, class Hash>
 bool Foam::HashSet<Key, Hash>::operator==(const HashSet<Key, Hash>& rhs) const
diff --git a/src/OpenFOAM/containers/HashTables/HashSet/HashSet.H b/src/OpenFOAM/containers/HashTables/HashSet/HashSet.H
index d6171ad585486595217201e44685c404cda8bfd4..fe82253bc0fb205411c9bc54e8493f4cffac0196 100644
--- a/src/OpenFOAM/containers/HashTables/HashSet/HashSet.H
+++ b/src/OpenFOAM/containers/HashTables/HashSet/HashSet.H
@@ -156,22 +156,24 @@ public:
       // Edit
 
         //- Insert a new entry
+        //  \return True if the entry inserted, which means that it did
+        //  not previously exist in the set.
         bool insert(const Key& key)
         {
             return this->parent_type::insert(key, nil());
         }
 
         //- Insert keys from the list of Key
-        //  Return the number of new elements inserted
+        //  \return The number of new elements inserted
         label insert(const UList<Key>& lst);
 
         //- Insert keys from the list of Key
-        //  Return the number of new elements inserted
+        //  \return The number of new elements inserted
         template<unsigned Size>
         label insert(const FixedList<Key, Size>& lst);
 
         //- Insert keys from a initializer list of Key
-        //  Return the number of new elements inserted
+        //  \return The number of new elements inserted
         label insert(std::initializer_list<Key> lst);
 
         //- Same as insert (cannot overwrite nil content)
@@ -200,18 +202,21 @@ public:
         }
 
         //- Unset the specified key - same as erase
+        //  \return True if the entry existed and was removed
         bool unset(const Key& key)
         {
             return this->parent_type::erase(key);
         }
 
         //- Unset the listed keys - same as erase
+        //  \return The number of items removed
         label unset(const UList<Key>& lst)
         {
             return this->parent_type::erase(lst);
         }
 
         //- Unset the listed keys - same as erase
+        //  \return The number of items removed
         template<unsigned Size>
         label unset(const FixedList<Key, Size>& lst)
         {
@@ -219,11 +224,36 @@ public:
         }
 
         //- Unset the listed keys - same as erase
+        //  \return The number of items removed
         label unset(std::initializer_list<Key> lst)
         {
             return this->parent_type::erase(lst);
         }
 
+        //- Not applicable for HashSet
+        template<class UnaryPredicate>
+        List<Key> tocValues(const UnaryPredicate&, const bool) = delete;
+
+        //- Not applicable for HashSet
+        template<class BinaryPredicate>
+        List<Key> tocEntries(const BinaryPredicate&, const bool) = delete;
+
+        //- Not applicable for HashSet
+        template<class UnaryPredicate>
+        label countValues(const UnaryPredicate&, const bool) = delete;
+
+        //- Not applicable for HashSet
+        template<class BinaryPredicate>
+        label countEntries(const BinaryPredicate&, const bool) = delete;
+
+        //- Not applicable for HashSet
+        template<class UnaryPredicate>
+        label filterValues(const UnaryPredicate&, const bool) = delete;
+
+        //- Not applicable for HashSet
+        template<class BinaryPredicate>
+        label filterEntries(const BinaryPredicate&, const bool) = delete;
+
 
     // STL iterators
 
@@ -248,12 +278,15 @@ public:
 
     // Member Operators
 
-        //- This operation doesn't make much sense for a hash-set
-        void operator()(const Key& key) = delete;
-
         //- Return true if the entry exists, same as found()
+        inline bool operator()(const Key& key) const;
+
+        //- Return true if the entry exists, same as found().
         inline bool operator[](const Key& key) const;
 
+
+      // Comparison
+
         //- Equality. Two hashset are equal when they have the same keys.
         //  Independent of table size or order.
         bool operator==(const this_type& rhs) const;
@@ -262,6 +295,8 @@ public:
         bool operator!=(const this_type& rhs) const;
 
 
+      // Assignment
+
         //- Assignment from a UList of keys
         void operator=(const UList<Key>& lst);
 
@@ -273,6 +308,8 @@ public:
         void operator=(std::initializer_list<Key> lst);
 
 
+      // Logical operations
+
         //- Combine entries from HashSets
         void operator|=(const HashSet<Key, Hash>& rhs);
 
diff --git a/src/OpenFOAM/containers/HashTables/HashTable/HashTable.C b/src/OpenFOAM/containers/HashTables/HashTable/HashTable.C
index 276f617dba102f5ef1fcc6b2005c0081f2553967..2c8167adcee45afb665e519a15231d7113468879 100644
--- a/src/OpenFOAM/containers/HashTables/HashTable/HashTable.C
+++ b/src/OpenFOAM/containers/HashTables/HashTable/HashTable.C
@@ -231,25 +231,169 @@ Foam::HashTable<T, Key, Hash>::find
 template<class T, class Key, class Hash>
 Foam::List<Key> Foam::HashTable<T, Key, Hash>::toc() const
 {
-    List<Key> keys(nElmts_);
-    label keyI = 0;
+    List<Key> keyLst(nElmts_);
+    label count = 0;
 
     for (const_iterator iter = cbegin(); iter != cend(); ++iter)
     {
-        keys[keyI++] = iter.key();
+        keyLst[count++] = iter.key();
     }
 
-    return keys;
+    return keyLst;
 }
 
 
 template<class T, class Key, class Hash>
 Foam::List<Key> Foam::HashTable<T, Key, Hash>::sortedToc() const
 {
-    List<Key> sortedLst = this->toc();
-    sort(sortedLst);
+    List<Key> keyLst = this->toc();
+    Foam::sort(keyLst);
 
-    return sortedLst;
+    return keyLst;
+}
+
+
+template<class T, class Key, class Hash>
+template<class UnaryPredicate>
+Foam::List<Key> Foam::HashTable<T, Key, Hash>::tocKeys
+(
+    const UnaryPredicate& pred,
+    const bool invert
+) const
+{
+    List<Key> keyLst(nElmts_);
+    label count = 0;
+
+    for (const_iterator iter = cbegin(); iter != cend(); ++iter)
+    {
+        if ((pred(iter.key()) ? !invert : invert))
+        {
+            keyLst[count++] = iter.key();
+        }
+    }
+
+    keyLst.setSize(count);
+    Foam::sort(keyLst);
+
+    return keyLst;
+}
+
+
+template<class T, class Key, class Hash>
+template<class UnaryPredicate>
+Foam::List<Key> Foam::HashTable<T, Key, Hash>::tocValues
+(
+    const UnaryPredicate& pred,
+    const bool invert
+) const
+{
+    List<Key> keyLst(nElmts_);
+    label count = 0;
+
+    for (const_iterator iter = cbegin(); iter != cend(); ++iter)
+    {
+        if ((pred(iter.object()) ? !invert : invert))
+        {
+            keyLst[count++] = iter.key();
+        }
+    }
+
+    keyLst.setSize(count);
+    Foam::sort(keyLst);
+
+    return keyLst;
+}
+
+
+template<class T, class Key, class Hash>
+template<class BinaryPredicate>
+Foam::List<Key> Foam::HashTable<T, Key, Hash>::tocEntries
+(
+    const BinaryPredicate& pred,
+    const bool invert
+) const
+{
+    List<Key> keyLst(nElmts_);
+    label count = 0;
+
+    for (const_iterator iter = cbegin(); iter != cend(); ++iter)
+    {
+        if ((pred(iter.key(), iter.object()) ? !invert : invert))
+        {
+            keyLst[count++] = iter.key();
+        }
+    }
+
+    keyLst.setSize(count);
+    Foam::sort(keyLst);
+
+    return keyLst;
+}
+
+
+template<class T, class Key, class Hash>
+template<class UnaryPredicate>
+Foam::label Foam::HashTable<T, Key, Hash>::countKeys
+(
+    const UnaryPredicate& pred,
+    const bool invert
+) const
+{
+    label count = 0;
+
+    for (const_iterator iter = cbegin(); iter != cend(); ++iter)
+    {
+        if ((pred(iter.key()) ? !invert : invert))
+        {
+            ++count;
+        }
+    }
+
+    return count;
+}
+
+
+template<class T, class Key, class Hash>
+template<class UnaryPredicate>
+Foam::label Foam::HashTable<T, Key, Hash>::countValues
+(
+    const UnaryPredicate& pred,
+    const bool invert
+) const
+{
+    label count = 0;
+
+    for (const_iterator iter = cbegin(); iter != cend(); ++iter)
+    {
+        if ((pred(iter.object()) ? !invert : invert))
+        {
+            ++count;
+        }
+    }
+
+    return count;
+}
+
+
+template<class T, class Key, class Hash>
+template<class BinaryPredicate>
+Foam::label Foam::HashTable<T, Key, Hash>::countEntries
+(
+    const BinaryPredicate& pred,
+    const bool invert
+) const
+{
+    label count = 0;
+
+    for (const_iterator iter = cbegin(); iter != cend(); ++iter)
+    {
+        if ((pred(iter.key(), iter.object()) ? !invert : invert))
+        {
+            ++count;
+        }
+    }
+
+    return count;
 }
 
 
@@ -617,6 +761,87 @@ void Foam::HashTable<T, Key, Hash>::transfer(HashTable<T, Key, Hash>& ht)
 }
 
 
+template<class T, class Key, class Hash>
+template<class UnaryPredicate>
+Foam::label Foam::HashTable<T, Key, Hash>::filterKeys
+(
+    const UnaryPredicate& pred,
+    const bool pruning
+)
+{
+    label changed = 0;
+
+    for (iterator iter = begin(); iter != end(); ++iter)
+    {
+        // Matches? either prune (pruning) or keep (!pruning)
+        if
+        (
+            (pred(iter.key()) ? pruning : !pruning)
+         && erase(iter)
+        )
+        {
+            ++changed;
+        }
+    }
+
+    return changed;
+}
+
+
+template<class T, class Key, class Hash>
+template<class UnaryPredicate>
+Foam::label Foam::HashTable<T, Key, Hash>::filterValues
+(
+    const UnaryPredicate& pred,
+    const bool pruning
+)
+{
+    label changed = 0;
+
+    for (iterator iter = begin(); iter != end(); ++iter)
+    {
+        // Matches? either prune (pruning) or keep (!pruning)
+        if
+        (
+            (pred(iter.object()) ? pruning : !pruning)
+         && erase(iter)
+        )
+        {
+            ++changed;
+        }
+    }
+
+    return changed;
+}
+
+
+template<class T, class Key, class Hash>
+template<class BinaryPredicate>
+Foam::label Foam::HashTable<T, Key, Hash>::filterEntries
+(
+    const BinaryPredicate& pred,
+    const bool pruning
+)
+{
+    label changed = 0;
+
+    for (iterator iter = begin(); iter != end(); ++iter)
+    {
+        // Matches? either prune (pruning) or keep (!pruning)
+        if
+        (
+            (pred(iter.key(), iter.object()) ? pruning : !pruning)
+         && erase(iter)
+        )
+        {
+            ++changed;
+        }
+    }
+
+    return changed;
+}
+
+
 // * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
 
 template<class T, class Key, class Hash>
diff --git a/src/OpenFOAM/containers/HashTables/HashTable/HashTable.H b/src/OpenFOAM/containers/HashTables/HashTable/HashTable.H
index 9eef011d10e1b471b8e0d246ed350805758bdeb4..3b3338084d9b1a3d46fcd8fe308d6d93f2a2cb71 100644
--- a/src/OpenFOAM/containers/HashTables/HashTable/HashTable.H
+++ b/src/OpenFOAM/containers/HashTables/HashTable/HashTable.H
@@ -255,7 +255,7 @@ private:
         inline label hashKeyIndex(const Key& key) const;
 
         //- Assign a new hash-entry to a possibly already existing key.
-        //  Return true if the new entry was set.
+        //  \return True if the new entry was set.
         bool set(const Key& key, const T& obj, const bool protect);
 
 
@@ -330,22 +330,83 @@ public:
         //- Return hashed entry if it exists, or return the given default
         inline const T& lookup(const Key& key, const T& deflt) const;
 
+
+      // Table of contents
+
         //- Return the table of contents
         List<Key> toc() const;
 
         //- Return the table of contents as a sorted list
         List<Key> sortedToc() const;
 
+        //- Return the sorted table of contents with keys that satisfy
+        //  the unary predicate, optionally with inverted logic.
+        template<class UnaryPredicate>
+        List<Key> tocKeys
+        (
+            const UnaryPredicate& pred,
+            const bool invert = false
+        ) const;
+
+        //- Return the sorted table of contents with values that satisfy
+        // the unary predicate, optionally with inverted logic.
+        template<class UnaryPredicate>
+        List<Key> tocValues
+        (
+            const UnaryPredicate& pred,
+            const bool invert = false
+        ) const;
+
+        //- Return the sorted table of contents with keys/values that satisfy
+        //  the binary predicate, optionally with inverted logic.
+        template<class BinaryPredicate>
+        List<Key> tocEntries
+        (
+            const BinaryPredicate& pred,
+            const bool invert = false
+        ) const;
+
+
+      // Counting
+
+        //- Count the number of keys that satisfy the unary predicate,
+        //  optionally with inverted logic.
+        template<class UnaryPredicate>
+        label countKeys
+        (
+            const UnaryPredicate& pred,
+            const bool invert = false
+        ) const;
+
+        //- Count the number of values that satisfy the unary predicate,
+        //  optionally with inverted logic.
+        template<class UnaryPredicate>
+        label countValues
+        (
+            const UnaryPredicate& pred,
+            const bool invert = false
+        ) const;
+
+        //- Count the number of entries that satisfy the binary predicate,
+        //  optionally with inverted logic.
+        template<class BinaryPredicate>
+        label countEntries
+        (
+            const BinaryPredicate& pred,
+            const bool invert = false
+        ) const;
+
 
       // Edit
 
         //- Insert a new entry
-        //  Return true if the entry inserted, which means that it did
+        //  \return True if the entry inserted, which means that it did
         //  not previously exist in the table.
         inline bool insert(const Key& key, const T& obj);
 
         //- Assign a new entry, overwriting existing entries.
-        //  Returns true.
+        //
+        //  \return True, since it always overwrites any entries.
         inline bool set(const Key& key, const T& obj);
 
         //- Erase an entry specified by given iterator
@@ -357,30 +418,34 @@ public:
         //      auto iter = table.find(unknownKey);
         //      table.erase(iter);
         //  \endcode
-        //  which is what \code table.erase(unknownKey) \endcode does anyhow
+        //  which is what \code table.erase(unknownKey) \endcode does anyhow.
+        //
+        //  \return True if the corresponding entry existed and was removed
         bool erase(const iterator& iter);
 
         //- Erase an entry specified by the given key
+        //  \return True if the entry existed and was removed
         bool erase(const Key& key);
 
         //- Remove table entries given by the listed keys
-        //  Return the number of elements removed
+        //  \return The number of items removed
         label erase(const UList<Key>& keys);
 
         //- Remove table entries given by the listed keys
-        //  Return the number of elements removed
+        //  \return The number of items removed
         template<unsigned Size>
         label erase(const FixedList<Key, Size>& keys);
 
         //- Remove table entries given by the listed keys
-        //  Return the number of elements removed
+        //  \return The number of items removed
         label erase(std::initializer_list<Key> keys);
 
         //- Remove table entries given by keys of the other hash-table.
-        //  Return the number of elements removed.
         //
         //  The other hash-table must have the same type of key, but the
         //  type of values held and the hashing function are arbitrary.
+        //
+        //  \return The number of items removed
         template<class AnyType, class AnyHash>
         label erase(const HashTable<AnyType, Key, AnyHash>& other);
 
@@ -388,9 +453,66 @@ public:
         //
         //  The other hash-table must have the same type of key, but the
         //  type of values held and the hashing function are arbitrary.
+        //
+        //  \return The number of items changed (removed)
         template<class AnyType, class AnyHash>
         label retain(const HashTable<AnyType, Key, AnyHash>& other);
 
+        //- Generalized means to filter table entries based on their keys.
+        //  Keep (or optionally prune) entries with keys that satisfy
+        //  the unary predicate, which has the following signature:
+        //  \code
+        //  bool operator()(const Key& k);
+        //  \endcode
+        //
+        //  For example,
+        //  \code
+        //  wordRes goodFields = ...;
+        //  allFieldNames.filterKeys
+        //  (
+        //      [&goodFields](const word& k){ return goodFields.match(k); }
+        //  );
+        //  \endcode
+        //
+        //  \return The number of items changed (removed)
+        template<class UnaryPredicate>
+        label filterKeys
+        (
+            const UnaryPredicate& pred,
+            const bool pruning = false
+        );
+
+        //- Generalized means to filter table entries based on their values.
+        //  Keep (or optionally prune) entries with values that satisfy
+        //  the unary predicate, which has the following signature:
+        //  \code
+        //  bool operator()(const T& v);
+        //  \endcode
+        //
+        //  \return The number of items changed (removed)
+        template<class UnaryPredicate>
+        label filterValues
+        (
+            const UnaryPredicate& pred,
+            const bool pruning = false
+        );
+
+        //- Generalized means to filter table entries based on their key/value.
+        //  Keep (or optionally prune) entries with keys/values that satisfy
+        //  the binary predicate, which has the following signature:
+        //  \code
+        //  bool operator()(const Key& k, const T& v);
+        //  \endcode
+        //
+        //  \return The number of items changed (removed)
+        template<class BinaryPredicate>
+        label filterEntries
+        (
+            const BinaryPredicate& pred,
+            const bool pruning = false
+        );
+
+
         //- Resize the hash table for efficiency
         void resize(const label sz);
 
diff --git a/src/OpenFOAM/containers/HashTables/HashTable/HashTableCore.C b/src/OpenFOAM/containers/HashTables/HashTable/HashTableCore.C
index e57192f1e36a2dbf26979f738d6290e6cd732666..9a8b205b9ed79c363026091352ad2f99cf2ae246 100644
--- a/src/OpenFOAM/containers/HashTables/HashTable/HashTableCore.C
+++ b/src/OpenFOAM/containers/HashTables/HashTable/HashTableCore.C
@@ -46,26 +46,26 @@ Foam::label Foam::HashTableCore::canonicalSize(const label requested_size)
     {
         return 0;
     }
+    else if (requested_size >= maxTableSize)
+    {
+        return maxTableSize;
+    }
 
-    // Enforce power of two - makes for a vey fast modulus etc.
+    // Enforce power of two - makes for a very fast modulus.
     // Use unsigned for these calculations.
     //
     // - The lower limit (8) is somewhat arbitrary, but if the hash table
     //   is too small, there will be many direct table collisions.
-    // - The uper limit (approx. labelMax/4) must be a power of two,
+    // - The upper limit (approx. labelMax/4) must be a power of two,
     //   need not be extremely large for hashing.
 
     uLabel powerOfTwo = 8; // lower-limit
 
     const uLabel size = requested_size;
-    if (size < powerOfTwo)
+    if (size <= powerOfTwo)
     {
         return powerOfTwo;
     }
-    else if (requested_size >= maxTableSize)
-    {
-        return maxTableSize;
-    }
     else if (size & (size-1))  // <- Modulus of i^2
     {
         // Determine power-of-two. Brute-force is fast enough.
diff --git a/src/OpenFOAM/containers/HashTables/StaticHashTable/StaticHashTableCore.C b/src/OpenFOAM/containers/HashTables/StaticHashTable/StaticHashTableCore.C
index 31c02ebf5ecb3a2848f701f46319a517b2f55021..6ce8fc31ba9aa372bed2047dfff77f6b8bc7b431 100644
--- a/src/OpenFOAM/containers/HashTables/StaticHashTable/StaticHashTableCore.C
+++ b/src/OpenFOAM/containers/HashTables/StaticHashTable/StaticHashTableCore.C
@@ -46,26 +46,26 @@ Foam::label Foam::StaticHashTableCore::canonicalSize(const label requested_size)
     {
         return 0;
     }
+    else if (requested_size >= maxTableSize)
+    {
+        return maxTableSize;
+    }
 
-    // Enforce power of two - makes for a vey fast modulus etc.
+    // Enforce power of two - makes for a very fast modulus.
     // Use unsigned for these calculations.
     //
     // - The lower limit (8) is somewhat arbitrary, but if the hash table
     //   is too small, there will be many direct table collisions.
-    // - The uper limit (approx. labelMax/4) must be a power of two,
+    // - The upper limit (approx. labelMax/4) must be a power of two,
     //   need not be extremely large for hashing.
 
     uLabel powerOfTwo = 8; // lower-limit
 
     const uLabel size = requested_size;
-    if (size < powerOfTwo)
+    if (size <= powerOfTwo)
     {
         return powerOfTwo;
     }
-    else if (requested_size >= maxTableSize)
-    {
-        return maxTableSize;
-    }
     else if (size & (size-1))  // <- Modulus of i^2
     {
         // Determine power-of-two. Brute-force is fast enough.
diff --git a/src/OpenFOAM/db/IOobjectList/IOobjectList.C b/src/OpenFOAM/db/IOobjectList/IOobjectList.C
index 1f96009a528904e7205c13230f7b9831e6eb6349..981e5ca2e579dcd38079617c1692c6165fcfa44a 100644
--- a/src/OpenFOAM/db/IOobjectList/IOobjectList.C
+++ b/src/OpenFOAM/db/IOobjectList/IOobjectList.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -27,7 +27,99 @@ License
 #include "Time.H"
 #include "OSspecific.H"
 #include "IOList.H"
-#include "stringListOps.H"
+#include "predicates.H"
+
+// * * * * * * * * * * * * * * Static Functions * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    // Templated implementation for lookup() - file-scope
+    template<class UnaryMatchPredicate>
+    static IOobjectList lookupImpl
+    (
+        const IOobjectList& list,
+        const UnaryMatchPredicate& matcher
+    )
+    {
+        IOobjectList results(list.size());
+
+        forAllConstIters(list, iter)
+        {
+            if (matcher(iter.key()))
+            {
+                if (IOobject::debug)
+                {
+                    InfoInFunction << "Found " << iter.key() << endl;
+                }
+
+                results.insert
+                (
+                    iter.key(),
+                    new IOobject(*(iter.object()))
+                );
+            }
+        }
+
+        return results;
+    }
+
+
+    // Templated implementation for classes() - file-scope
+    template<class UnaryMatchPredicate>
+    static HashTable<wordHashSet> classesImpl
+    (
+        const IOobjectList& list,
+        const UnaryMatchPredicate& matcher
+    )
+    {
+        HashTable<wordHashSet> summary(2*list.size());
+
+        // Summary (key,val) = (class-name, object-names)
+        forAllConstIters(list, iter)
+        {
+            if (matcher(iter.key()))
+            {
+                // Create entry (if needed) and insert
+                summary(iter.object()->headerClassName()).insert(iter.key());
+            }
+        }
+
+        return summary;
+    }
+
+
+    // Templated implementation for names(), sortedNames() - file-scope
+    template<class UnaryMatchPredicate>
+    static wordList namesImpl
+    (
+        const IOobjectList& list,
+        const word& clsName,
+        const UnaryMatchPredicate& matcher,
+        const bool doSort
+    )
+    {
+        wordList objNames(list.size());
+
+        label count = 0;
+        forAllConstIters(list, iter)
+        {
+            if (iter()->headerClassName() == clsName && matcher(iter.key()))
+            {
+                objNames[count++] = iter.key();
+            }
+        }
+
+        objNames.setSize(count);
+
+        if (doSort)
+        {
+            Foam::sort(objNames);
+        }
+
+        return objNames;
+    }
+}
+
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
@@ -62,14 +154,14 @@ Foam::IOobjectList::IOobjectList
     }
 
     // Create a list of file names in this directory
-    fileNameList ObjectNames =
+    fileNameList objNames =
         readDir(db.path(newInstance, db.dbDir()/local), fileName::FILE);
 
-    forAll(ObjectNames, i)
+    forAll(objNames, i)
     {
         IOobject* objectPtr = new IOobject
         (
-            ObjectNames[i],
+            objNames[i],
             newInstance,
             local,
             db,
@@ -81,7 +173,7 @@ Foam::IOobjectList::IOobjectList
         // Use object with local scope
         if (objectPtr->typeHeaderOk<IOList<label>>(false))
         {
-            insert(ObjectNames[i], objectPtr);
+            insert(objectPtr->name(), objectPtr);
         }
         else
         {
@@ -119,7 +211,7 @@ bool Foam::IOobjectList::remove(IOobject& io)
 
 Foam::IOobject* Foam::IOobjectList::lookup(const word& name) const
 {
-    HashPtrTable<IOobject>::const_iterator iter = find(name);
+    const_iterator iter = find(name);
 
     if (iter.found())
     {
@@ -144,38 +236,23 @@ Foam::IOobject* Foam::IOobjectList::lookup(const word& name) const
 
 Foam::IOobjectList Foam::IOobjectList::lookup(const wordRe& matcher) const
 {
-    IOobjectList results(size());
-
-    forAllConstIters(*this, iter)
-    {
-        if (matcher.match(iter.key()))
-        {
-            if (IOobject::debug)
-            {
-                InfoInFunction << "Found " << iter.key() << endl;
-            }
+    return lookupImpl(*this, matcher);
+}
 
-            results.insert
-            (
-                iter.key(),
-                new IOobject(*(iter.object()))
-            );
-        }
-    }
 
-    return results;
+Foam::IOobjectList Foam::IOobjectList::lookup(const wordRes& matcher) const
+{
+    return lookupImpl(*this, matcher);
 }
 
 
-Foam::IOobjectList Foam::IOobjectList::lookup(const wordReList& matcher) const
+Foam::IOobjectList Foam::IOobjectList::lookupClass(const word& clsName) const
 {
-    wordReListMatcher mat(matcher);
-
     IOobjectList results(size());
 
     forAllConstIters(*this, iter)
     {
-        if (mat.match(iter.key()))
+        if (iter()->headerClassName() == clsName)
         {
             if (IOobject::debug)
             {
@@ -194,28 +271,23 @@ Foam::IOobjectList Foam::IOobjectList::lookup(const wordReList& matcher) const
 }
 
 
-Foam::IOobjectList Foam::IOobjectList::lookupClass(const word& clsName) const
+Foam::HashTable<Foam::wordHashSet> Foam::IOobjectList::classes() const
 {
-    IOobjectList results(size());
+    return classesImpl(*this, predicates::always());
+}
 
-    forAllConstIters(*this, iter)
-    {
-        if (iter()->headerClassName() == clsName)
-        {
-            if (IOobject::debug)
-            {
-                InfoInFunction << "Found " << iter.key() << endl;
-            }
 
-            results.insert
-            (
-                iter.key(),
-                new IOobject(*(iter.object()))
-            );
-        }
-    }
+Foam::HashTable<Foam::wordHashSet>
+Foam::IOobjectList::classes(const wordRe& matcher) const
+{
+    return classesImpl(*this, matcher);
+}
 
-    return results;
+
+Foam::HashTable<Foam::wordHashSet>
+Foam::IOobjectList::classes(const wordRes& matcher) const
+{
+    return classesImpl(*this, matcher);
 }
 
 
@@ -236,20 +308,7 @@ Foam::wordList Foam::IOobjectList::names
     const word& clsName
 ) const
 {
-    wordList objNames(size());
-
-    label count = 0;
-    forAllConstIters(*this, iter)
-    {
-        if (iter()->headerClassName() == clsName)
-        {
-            objNames[count++] = iter.key();
-        }
-    }
-
-    objNames.setSize(count);
-
-    return objNames;
+    return namesImpl(*this, clsName, predicates::always(), false);
 }
 
 
@@ -259,21 +318,17 @@ Foam::wordList Foam::IOobjectList::names
     const wordRe& matcher
 ) const
 {
-    wordList objNames = names(clsName);
-
-    return wordList(objNames, findStrings(matcher, objNames));
+    return namesImpl(*this, clsName, matcher, false);
 }
 
 
 Foam::wordList Foam::IOobjectList::names
 (
     const word& clsName,
-    const wordReList& matcher
+    const wordRes& matcher
 ) const
 {
-    wordList objNames = names(clsName);
-
-    return wordList(objNames, findStrings(matcher, objNames));
+    return namesImpl(*this, clsName, matcher, false);
 }
 
 
@@ -282,10 +337,7 @@ Foam::wordList Foam::IOobjectList::sortedNames
     const word& clsName
 ) const
 {
-    wordList sortedLst = names(clsName);
-    sort(sortedLst);
-
-    return sortedLst;
+    return namesImpl(*this, clsName, predicates::always(), true);
 }
 
 
@@ -295,23 +347,35 @@ Foam::wordList Foam::IOobjectList::sortedNames
     const wordRe& matcher
 ) const
 {
-    wordList sortedLst = names(clsName, matcher);
-    sort(sortedLst);
-
-    return sortedLst;
+    return namesImpl(*this, clsName, matcher, true);
 }
 
 
 Foam::wordList Foam::IOobjectList::sortedNames
 (
     const word& clsName,
-    const wordReList& matcher
+    const wordRes& matcher
 ) const
 {
-    wordList sortedLst = names(clsName, matcher);
-    sort(sortedLst);
+    return namesImpl(*this, clsName, matcher, true);
+}
+
+
+// * * * * * * * * * * * * * * * IOstream Operators  * * * * * * * * * * * * //
+
+Foam::Ostream& Foam::operator<<(Ostream& os, const IOobjectList& list)
+{
+    os << nl << list.size() << nl << token::BEGIN_LIST << nl;
+
+    forAllConstIters(list, it)
+    {
+        os << it.key() << token::SPACE << it.object()->headerClassName() << nl;
+    }
+
+    os << token::END_LIST;
+    os.check(FUNCTION_NAME);
 
-    return sortedLst;
+    return os;
 }
 
 
diff --git a/src/OpenFOAM/db/IOobjectList/IOobjectList.H b/src/OpenFOAM/db/IOobjectList/IOobjectList.H
index 17f75233ed38e01385e752c6edbda806477f386f..0976e1540ff6dc7b66add388f755001f7ba7fff7 100644
--- a/src/OpenFOAM/db/IOobjectList/IOobjectList.H
+++ b/src/OpenFOAM/db/IOobjectList/IOobjectList.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -36,14 +36,20 @@ SourceFiles
 #define IOobjectList_H
 
 #include "HashPtrTable.H"
+#include "HashSet.H"
 #include "IOobject.H"
-#include "wordReList.H"
+#include "wordRes.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 namespace Foam
 {
 
+// Forward declaration of friend functions and operators
+class IOobjectList;
+Ostream& operator<<(Ostream& os, const IOobjectList& list);
+
+
 /*---------------------------------------------------------------------------*\
                         Class IOobjectList Declaration
 \*---------------------------------------------------------------------------*/
@@ -86,12 +92,17 @@ public:
 
     // Member functions
 
+      // Basic methods
+
         //- Add an IOobject to the list
         bool add(IOobject& io);
 
         //- Remove an IOobject from the list
         bool remove(IOobject& io);
 
+
+      // Lookup
+
         //- Lookup a given name and return IOobject ptr if found else nullptr
         IOobject* lookup(const word& name) const;
 
@@ -99,12 +110,94 @@ public:
         IOobjectList lookup(const wordRe& matcher) const;
 
         //- The list of all IOobjects with matching names
-        IOobjectList lookup(const wordReList& matcher) const;
+        IOobjectList lookup(const wordRes& matcher) const;
 
         //- The list of all IOobjects with the given class name
         IOobjectList lookupClass(const word& clsName) const;
 
 
+      // Summary of classes
+
+        //- A summary hash of classes used and their associated object names.
+        //  The HashTable representation allows us to leverage various
+        //  HashTable methods.
+        //  This hashed summary view can be useful when querying particular
+        //  aspects. For example,
+        //
+        //  \code
+        //  IOobjectList objects(runTime, runTime.timeName());
+        //  HashTable<wordHashSet> classes = objects.classes();
+        //
+        //  // How many volScalarField?
+        //  word checkType = volScalarField::typeName;
+        //
+        //  Info<< checkType << "="
+        //      << (classes.found(checkType) ? classes[checkType].size() : 0)
+        //      << nl;
+        //  \endcode
+        //  Using the two-parameter HashTable::lookup method lets us avoid
+        //  the \c '?' ternary, but still looks fairly ugly:
+        //  \code
+        //  Info<< checkType << "="
+        //      << classes.lookup(checkType, wordHashSet()).size() << nl;
+        //  \endcode
+        //
+        //  If we have non-const access to the hash table, and don't mind
+        //  incidentally creating empty entries,
+        //  we can use the HashTable::operator() directly:
+        //  \code
+        //  Info<< checkType << "=" << classes(checkType).size() << nl;
+        //  \endcode
+        //
+        //  Of course, for a single query it would have been easier
+        //  and simpler to have used a direct query of the names:
+        //  \code
+        //  Info<< checkType << "=" << objects.names(checkType).size() << nl;
+        //  \endcode
+        //
+        //  The summary hash, however, becomes most useful when reducing
+        //  the objects in consideration to a particular subset. For example,
+        //  \code
+        //  const wordHashSet interestingTypes
+        //  {
+        //      volScalarField::typeName,
+        //      volVectorField::typeName
+        //  };
+        //
+        //  classes.retain(interestingTypes);
+        //  \endcode
+        //  Or do just the opposite:
+        //  \code
+        //  classes.erase(unsupportedTypes);
+        //  \endcode
+        //  This also works with a hashedWordList, since it provides the
+        //  expected '()' operator. But in this case the more general
+        //  HashTable::filterKeys is required:
+        //  \code
+        //  const hashedWordList interestingTypes
+        //  {
+        //      volScalarField::typeName,
+        //      volVectorField::typeName
+        //  };
+        //
+        //  classes.filterKeys(interestingTypes);
+        //  \endcode
+        //
+        //  Of course, there are many other ways to use and manipulate the
+        //  summary information.
+        HashTable<wordHashSet> classes() const;
+
+        //- A summary hash of classes used and their associated object names
+        //  restricted to objects with names that satisfy the input matcher
+        HashTable<wordHashSet> classes(const wordRe& matcher) const;
+
+        //- A summary hash of classes used and their associated object names
+        //  restricted to objects with names that satisfy the input matcher
+        HashTable<wordHashSet> classes(const wordRes& matcher) const;
+
+
+      // Summary of names
+
         //- A list of names of the IOobjects
         wordList names() const;
 
@@ -117,9 +210,11 @@ public:
 
         //- The names of IOobjects with the given class name that also
         //  have a name satisfying the input matcher
-        wordList names(const word& clsName, const wordReList& matcher) const;
+        wordList names(const word& clsName, const wordRes& matcher) const;
 
 
+      // Summary of names (sorted)
+
         //- A sorted list of names of the IOobjects
         wordList sortedNames() const;
 
@@ -132,11 +227,12 @@ public:
 
         //- The sorted names of IOobjects with the given class name that also
         //  have a name satisfying the input matcher
-        wordList sortedNames
-        (
-            const word& clsName,
-            const wordReList& matcher
-        ) const;
+        wordList sortedNames(const word& clsName, const wordRes& matcher) const;
+
+
+    // Ostream Operator
+
+        friend Ostream& operator<<(Ostream& os, const IOobjectList& list);
 };
 
 
diff --git a/src/OpenFOAM/db/objectRegistry/objectRegistry.C b/src/OpenFOAM/db/objectRegistry/objectRegistry.C
index d72efda11cab30f7eecb11dbc88e7b807150af8a..2f048ea71c7a5835a1a5999803f2b7f1c783cdb5 100644
--- a/src/OpenFOAM/db/objectRegistry/objectRegistry.C
+++ b/src/OpenFOAM/db/objectRegistry/objectRegistry.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2015-2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2015-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -25,6 +25,7 @@ License
 
 #include "objectRegistry.H"
 #include "Time.H"
+#include "predicates.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -103,7 +104,7 @@ Foam::objectRegistry::~objectRegistry()
         }
     }
 
-    for (label i=0; i < nMyObjects; i++)
+    for (label i=0; i < nMyObjects; ++i)
     {
         checkOut(*myObjects[i]);
     }
@@ -112,6 +113,26 @@ Foam::objectRegistry::~objectRegistry()
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
+Foam::HashTable<Foam::wordHashSet> Foam::objectRegistry::classes() const
+{
+    return classesImpl(*this, predicates::always());
+}
+
+
+Foam::HashTable<Foam::wordHashSet>
+Foam::objectRegistry::classes(const wordRe& matcher) const
+{
+    return classesImpl(*this, matcher);
+}
+
+
+Foam::HashTable<Foam::wordHashSet>
+Foam::objectRegistry::classes(const wordRes& matcher) const
+{
+    return classesImpl(*this, matcher);
+}
+
+
 Foam::wordList Foam::objectRegistry::names() const
 {
     return HashTable<regIOobject*>::toc();
@@ -124,31 +145,31 @@ Foam::wordList Foam::objectRegistry::sortedNames() const
 }
 
 
-Foam::wordList Foam::objectRegistry::names(const word& ClassName) const
+Foam::wordList Foam::objectRegistry::names(const word& clsName) const
 {
-    wordList objectNames(size());
+    wordList objNames(size());
 
     label count=0;
     for (const_iterator iter = cbegin(); iter != cend(); ++iter)
     {
-        if (iter()->type() == ClassName)
+        if (iter()->type() == clsName)
         {
-            objectNames[count++] = iter.key();
+            objNames[count++] = iter.key();
         }
     }
 
-    objectNames.setSize(count);
+    objNames.setSize(count);
 
-    return objectNames;
+    return objNames;
 }
 
 
-Foam::wordList Foam::objectRegistry::sortedNames(const word& ClassName) const
+Foam::wordList Foam::objectRegistry::sortedNames(const word& clsName) const
 {
-    wordList sortedLst = names(ClassName);
-    sort(sortedLst);
+    wordList objNames = names(clsName);
+    Foam::sort(objNames);
 
-    return sortedLst;
+    return objNames;
 }
 
 
@@ -224,7 +245,7 @@ bool Foam::objectRegistry::checkOut(regIOobject& io) const
 {
     iterator iter = const_cast<objectRegistry&>(*this).find(io.name());
 
-    if (iter != end())
+    if (iter.found())
     {
         if (objectRegistry::debug)
         {
diff --git a/src/OpenFOAM/db/objectRegistry/objectRegistry.H b/src/OpenFOAM/db/objectRegistry/objectRegistry.H
index 16dc0e17780da30f9381c0e8035b73d0e99125b5..77d390754f6aef1aa479644f8cc5dc7ebd06c9ad 100644
--- a/src/OpenFOAM/db/objectRegistry/objectRegistry.H
+++ b/src/OpenFOAM/db/objectRegistry/objectRegistry.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -37,8 +37,9 @@ SourceFiles
 #define objectRegistry_H
 
 #include "HashTable.H"
+#include "HashSet.H"
 #include "regIOobject.H"
-#include "wordReList.H"
+#include "wordRes.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -75,6 +76,24 @@ class objectRegistry
         //  Used to terminate searching within the ancestors
         bool parentNotTime() const;
 
+        //- Templated implementation for classes()
+        template<class UnaryMatchPredicate>
+        static HashTable<wordHashSet> classesImpl
+        (
+            const objectRegistry& list,
+            const UnaryMatchPredicate& matcher
+        );
+
+        //- Templated implementation for names()
+        template<class Type, class UnaryMatchPredicate>
+        static wordList namesImpl
+        (
+            const objectRegistry& list,
+            const UnaryMatchPredicate& matcher,
+            const bool doSort
+        );
+
+
         //- Disallow Copy constructor
         objectRegistry(const objectRegistry&) = delete;
 
@@ -113,184 +132,209 @@ public:
 
     // Member functions
 
-        // Access
-
-            //- Return time
-            const Time& time() const
-            {
-                return time_;
-            }
-
-            //- Return the parent objectRegistry
-            const objectRegistry& parent() const
-            {
-                return parent_;
-            }
-
-            //- Local directory path of this objectRegistry relative to the time
-            virtual const fileName& dbDir() const
-            {
-                return dbDir_;
-            }
-
-            //- A list of names of the objects
-            wordList names() const;
-
-            //- A sorted list of names of the objects
-            wordList sortedNames() const;
-
-            //- A list of names of objects that have the given class name
-            wordList names(const word& className) const;
-
-            //- A sorted list of names of objects that have the given class name
-            wordList sortedNames(const word& className) const;
-
-            //- A list of names of objects that have the given type
-            template<class Type>
-            wordList names() const;
-
-            //- A list of names of objects that have the given type,
-            //  and that also satisfy the input matcher
-            template<class Type>
-            wordList names(const wordRe&) const;
-
-            //- A list of names for objects that have the given type,
-            //  and that also satisfy the input matchers
-            template<class Type>
-            wordList names(const wordReList&) const;
-
-            //- A sorted list of names of objects that have the given type
-            template<class Type>
-            wordList sortedNames() const;
-
-            //- A sorted list of names of objects that have the given type,
-            //  and that also satisfy the input matcher
-            template<class Type>
-            wordList sortedNames(const wordRe&) const;
-
-            //- A sorted list of names of objects that have the given type,
-            //  and that also satisfy the input matchers
-            template<class Type>
-            wordList sortedNames(const wordReList&) const;
-
-
-            //- Lookup and return a const sub-objectRegistry.
-            //  Optionally create it if it does not exist.
-            //  If recursive, search parent registries.
-            const objectRegistry& subRegistry
-            (
-                const word& name,
-                const bool forceCreate = false,
-                const bool recursive = false
-            ) const;
-
-
-            //- Lookup and return all objects of the given Type
-            template<class Type>
-            HashTable<const Type*> lookupClass(const bool strict = false) const;
-
-            //- Lookup and return all objects of the given Type
-            template<class Type>
-            HashTable<Type*> lookupClass(const bool strict = false);
-
-            //- Is the named Type found?
-            //  If recursive, search parent registries.
-            template<class Type>
-            bool foundObject
-            (
-                const word& name,
-                const bool recursive = false
-            ) const;
-
-            //- Lookup and return the object of the given Type.
-            //  If recursive, search parent registries.
-            template<class Type>
-            const Type& lookupObject
-            (
-                const word& name,
-                const bool recursive = false
-            ) const;
-
-            //- Lookup and return the object of the given Type.
-            //  If recursive, search parent registries.
-            template<class Type>
-            Type& lookupObjectRef
-            (
-                const word& name,
-                const bool recursive = false
-            ) const;
-
-            //- Lookup and return pointer to the object of the given Type,
-            //  otherwise nullptr if the object was not found,
-            //  or had the incorrect type.
-            //  If recursive, search parent registries.
-            template<class Type>
-            const Type* lookupObjectPtr
-            (
-                const word& name,
-                const bool recursive = false
-            ) const;
-
-
-            //- Lookup and return non-const pointer to the object
-            //  of the given Type,
-            //  otherwise nullptr if the object was not found,
-            //  or had the incorrect type.
-            //  If recursive, search parent registries.
-            template<class Type>
-            Type* lookupObjectRefPtr
-            (
-                const word& name,
-                const bool recursive = false
-            ) const;
-
-
-            //- Return new event number.
-            label getEvent() const;
-
-
-        // Edit
-
-            //- Rename
-            virtual void rename(const word& newName);
-
-            //- Add an regIOobject to registry
-            bool checkIn(regIOobject&) const;
-
-            //- Remove an regIOobject from registry
-            bool checkOut(regIOobject&) const;
-
-
-        // Reading
-
-            //- Return true if any of the object's files have been modified
-            virtual bool modified() const;
-
-            //- Read the objects that have been modified
-            void readModifiedObjects();
-
-            //- Read object if modified
-            virtual bool readIfModified();
-
-
-        // Writing
-
-            //- writeData function required by regIOobject but not used
-            //  for this class, write is used instead
-            virtual bool writeData(Ostream&) const
-            {
-                NotImplemented;
-
-                return false;
-            }
-
-            //- Write the objects
-            virtual bool writeObject
-            (
-                IOstream::streamFormat fmt,
-                IOstream::versionNumber ver,
-                IOstream::compressionType cmp
-            ) const;
+      // Access
+
+        //- Return time
+        const Time& time() const
+        {
+            return time_;
+        }
+
+        //- Return the parent objectRegistry
+        const objectRegistry& parent() const
+        {
+            return parent_;
+        }
+
+        //- Local directory path of this objectRegistry relative to the time
+        virtual const fileName& dbDir() const
+        {
+            return dbDir_;
+        }
+
+
+      // Summary of classes
+
+        //- A summary hash of classes used and their associated object names.
+        //  Behaviour and usage as per IOobjectList::classes
+        HashTable<wordHashSet> classes() const;
+
+        //- A summary hash of classes used and their associated object names
+        //  restricted to objects with names that satisfy the input matcher
+        HashTable<wordHashSet> classes(const wordRe& matcher) const;
+
+        //- A summary hash of classes used and their associated object names
+        //  restricted to objects with names that satisfy the input matcher
+        HashTable<wordHashSet> classes(const wordRes& matcher) const;
+
+
+      // Summary of names
+
+        //- A list of names of the objects
+        wordList names() const;
+
+        //- The names of objects with the given class name
+        wordList names(const word& clsName) const;
+
+        //- The names of objects with the given type
+        template<class Type>
+        wordList names() const;
+
+        //- The names of objects with the given type that also
+        //  have a name satisfying the input matcher
+        template<class Type>
+        wordList names(const wordRe& matcher) const;
+
+        //- The names of objects with the given type that also
+        //  have a name satisfying the input matcher
+        template<class Type>
+        wordList names(const wordRes& matcher) const;
+
+
+      // Summary of names (sorted)
+
+        //- A sorted list of names of the objects
+        wordList sortedNames() const;
+
+        //- The sorted names of objects with the given class name
+        wordList sortedNames(const word& clsName) const;
+
+        //- The sorted names of objects with the given type
+        template<class Type>
+        wordList sortedNames() const;
+
+        //- The sorted names of objects with the given type that also
+        //  have a name satisfying the input matcher
+        template<class Type>
+        wordList sortedNames(const wordRe& matcher) const;
+
+        //- The sorted names of objects with the given type that also
+        //  have a name satisfying the input matcher
+        template<class Type>
+        wordList sortedNames(const wordRes& matcher) const;
+
+
+      // Lookup
+
+        //- Lookup and return a const sub-objectRegistry.
+        //  Optionally create it if it does not exist.
+        //  If recursive, search parent registries.
+        const objectRegistry& subRegistry
+        (
+            const word& name,
+            const bool forceCreate = false,
+            const bool recursive = false
+        ) const;
+
+
+        //- Lookup and return all objects of the given Type
+        template<class Type>
+        HashTable<const Type*> lookupClass(const bool strict = false) const;
+
+        //- Lookup and return all objects of the given Type
+        template<class Type>
+        HashTable<Type*> lookupClass(const bool strict = false);
+
+        //- Is the named Type found?
+        //  If recursive, search parent registries.
+        template<class Type>
+        bool foundObject
+        (
+            const word& name,
+            const bool recursive = false
+        ) const;
+
+        //- Lookup and return the object of the given Type.
+        //  If recursive, search parent registries.
+        template<class Type>
+        const Type& lookupObject
+        (
+            const word& name,
+            const bool recursive = false
+        ) const;
+
+        //- Lookup and return the object of the given Type.
+        //  If recursive, search parent registries.
+        template<class Type>
+        Type& lookupObjectRef
+        (
+            const word& name,
+            const bool recursive = false
+        ) const;
+
+        //- Lookup and return pointer to the object of the given Type,
+        //  otherwise nullptr if the object was not found,
+        //  or had the incorrect type.
+        //  If recursive, search parent registries.
+        template<class Type>
+        const Type* lookupObjectPtr
+        (
+            const word& name,
+            const bool recursive = false
+        ) const;
+
+
+        //- Lookup and return non-const pointer to the object
+        //  of the given Type,
+        //  otherwise nullptr if the object was not found,
+        //  or had the incorrect type.
+        //  If recursive, search parent registries.
+        template<class Type>
+        Type* lookupObjectRefPtr
+        (
+            const word& name,
+            const bool recursive = false
+        ) const;
+
+
+      // Events
+
+        //- Return new event number.
+        label getEvent() const;
+
+
+      // Edit
+
+        //- Rename
+        virtual void rename(const word& newName);
+
+        //- Add an regIOobject to registry
+        bool checkIn(regIOobject& io) const;
+
+        //- Remove an regIOobject from registry
+        bool checkOut(regIOobject& io) const;
+
+
+      // Reading
+
+        //- Return true if any of the object's files have been modified
+        virtual bool modified() const;
+
+        //- Read the objects that have been modified
+        void readModifiedObjects();
+
+        //- Read object if modified
+        virtual bool readIfModified();
+
+
+      // Writing
+
+        //- writeData function required by regIOobject but not used
+        //  for this class, write is used instead
+        virtual bool writeData(Ostream&) const
+        {
+            NotImplemented;
+
+            return false;
+        }
+
+        //- Write the objects
+        virtual bool writeObject
+        (
+            IOstream::streamFormat fmt,
+            IOstream::versionNumber ver,
+            IOstream::compressionType cmp
+        ) const;
 };
 
 
diff --git a/src/OpenFOAM/db/objectRegistry/objectRegistryTemplates.C b/src/OpenFOAM/db/objectRegistry/objectRegistryTemplates.C
index c5c583ad2666e24f3b6f37f5415c79d65e3923a8..040b05f6a3c34ec7ec52ee2e1bd0d1414941d362 100644
--- a/src/OpenFOAM/db/objectRegistry/objectRegistryTemplates.C
+++ b/src/OpenFOAM/db/objectRegistry/objectRegistryTemplates.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2015 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -25,95 +25,115 @@ License
 
 #include "objectRegistry.H"
 #include "stringListOps.H"
+#include "predicates.H"
 
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
-template<class Type>
-Foam::wordList Foam::objectRegistry::names() const
+// Templated implementation for classes()
+template<class UnaryMatchPredicate>
+Foam::HashTable<Foam::wordHashSet> Foam::objectRegistry::classesImpl
+(
+    const objectRegistry& list,
+    const UnaryMatchPredicate& matcher
+)
 {
-    wordList objectNames(size());
+    HashTable<wordHashSet> summary(2*list.size());
 
-    label count=0;
-    forAllConstIter(HashTable<regIOobject*>, *this, iter)
+    // Summary (key,val) = (class-name, object-names)
+    forAllConstIters(list, iter)
     {
-        if (isA<Type>(*iter()))
+        if (matcher(iter.key()))
         {
-            objectNames[count++] = iter()->name();
+            // Create entry (if needed) and insert
+            summary(iter.object()->type()).insert(iter.key());
         }
     }
 
-    objectNames.setSize(count);
-
-    return objectNames;
+    return summary;
 }
 
 
-template<class Type>
-Foam::wordList Foam::objectRegistry::names(const wordRe& matcher) const
+// Templated implementation for names()
+template<class Type, class UnaryMatchPredicate>
+Foam::wordList Foam::objectRegistry::namesImpl
+(
+    const objectRegistry& list,
+    const UnaryMatchPredicate& matcher,
+    const bool doSort
+)
 {
-    wordList objectNames(size());
+    wordList objNames(list.size());
 
     label count = 0;
-    forAllConstIter(HashTable<regIOobject*>, *this, iter)
+    forAllConstIters(list, iter)
     {
-        if (isA<Type>(*iter()))
+        if (isA<Type>(*iter()) && matcher(iter()->name()))
         {
-            const word& objectName = iter()->name();
-
-            if (matcher.match(objectName))
-            {
-                objectNames[count++] = objectName;
-            }
+            objNames[count++] = iter()->name();
         }
     }
 
-    objectNames.setSize(count);
+    objNames.setSize(count);
+
+    if (doSort)
+    {
+        Foam::sort(objNames);
+    }
 
-    return objectNames;
+    return objNames;
 }
 
 
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
 template<class Type>
-Foam::wordList Foam::objectRegistry::names(const wordReList& matcher) const
+Foam::wordList Foam::objectRegistry::names() const
 {
-    wordList names(this->names<Type>());
+    return namesImpl<Type>(*this, predicates::always(), false);
+}
+
 
-    return wordList(names, findStrings(matcher, names));
+template<class Type>
+Foam::wordList Foam::objectRegistry::names(const wordRe& matcher) const
+{
+    return namesImpl<Type>(*this, matcher, false);
 }
 
 
 template<class Type>
-Foam::wordList Foam::objectRegistry::sortedNames() const
+Foam::wordList Foam::objectRegistry::names
+(
+    const wordRes& matcher
+) const
 {
-    wordList sorted(this->names<Type>());
-    sort(sorted);
+    return namesImpl<Type>(*this, matcher, false);
+}
+
 
-    return sorted;
+template<class Type>
+Foam::wordList Foam::objectRegistry::sortedNames() const
+{
+    return namesImpl<Type>(*this, predicates::always(), true);
 }
 
+
 template<class Type>
 Foam::wordList Foam::objectRegistry::sortedNames
 (
-    const wordRe& match
+    const wordRe& matcher
 ) const
 {
-    wordList sorted(this->names<Type>(match));
-    sort(sorted);
-
-    return sorted;
+    return namesImpl<Type>(*this, matcher, true);
 }
 
 
 template<class Type>
 Foam::wordList Foam::objectRegistry::sortedNames
 (
-    const wordReList& matcher
+    const wordRes& matcher
 ) const
 {
-    wordList sorted(this->names<Type>(matcher));
-    sort(sorted);
-
-    return sorted;
+    return namesImpl<Type>(*this, matcher, true);
 }
 
 
@@ -125,7 +145,7 @@ Foam::HashTable<const Type*> Foam::objectRegistry::lookupClass
 {
     HashTable<const Type*> objectsOfClass(size());
 
-    forAllConstIter(HashTable<regIOobject*>, *this, iter)
+    forAllConstIters(*this, iter)
     {
         if (strict ? isType<Type>(*iter()) : isA<Type>(*iter()))
         {
@@ -149,7 +169,7 @@ Foam::HashTable<Type*> Foam::objectRegistry::lookupClass
 {
     HashTable<Type*> objectsOfClass(size());
 
-    forAllIter(HashTable<regIOobject*>, *this, iter)
+    forAllIters(*this, iter)
     {
         if (strict ? isType<Type>(*iter()) : isA<Type>(*iter()))
         {
@@ -194,7 +214,7 @@ const Type& Foam::objectRegistry::lookupObject
 {
     const_iterator iter = find(name);
 
-    if (iter != end())
+    if (iter.found())
     {
         const Type* ptr = dynamic_cast<const Type*>(iter());
 
@@ -252,7 +272,7 @@ const Type* Foam::objectRegistry::lookupObjectPtr
 {
     const_iterator iter = find(name);
 
-    if (iter != end())
+    if (iter.found())
     {
         const Type* ptr = dynamic_cast<const Type*>(iter());
 
diff --git a/src/OpenFOAM/meshes/polyMesh/zones/ZoneMesh/ZoneMesh.C b/src/OpenFOAM/meshes/polyMesh/zones/ZoneMesh/ZoneMesh.C
index 94f1c23a752ba0a07091ecff23b286ecee02dfc6..066c9c268f86493bfb163225a4be24629b5870c3 100644
--- a/src/OpenFOAM/meshes/polyMesh/zones/ZoneMesh/ZoneMesh.C
+++ b/src/OpenFOAM/meshes/polyMesh/zones/ZoneMesh/ZoneMesh.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -47,23 +47,23 @@ void Foam::ZoneMesh<ZoneType, MeshType>::calcZoneMap() const
         // Count number of objects in all zones
         label nObjects = 0;
 
-        forAll(*this, zoneI)
+        forAll(*this, zonei)
         {
-            nObjects += this->operator[](zoneI).size();
+            nObjects += this->operator[](zonei).size();
         }
 
         zoneMapPtr_ = new Map<label>(2*nObjects);
         Map<label>& zm = *zoneMapPtr_;
 
-        // Fill in objects of all zones into the map.  The key is the global
-        // object index and the result is the zone index
-        forAll(*this, zoneI)
+        // Fill in objects of all zones into the map.
+        // The key is the global object index, value is the zone index
+        forAll(*this, zonei)
         {
-            const labelList& zoneObjects = this->operator[](zoneI);
+            const labelList& zoneObjects = this->operator[](zonei);
 
             forAll(zoneObjects, objI)
             {
-                zm.insert(zoneObjects[objI], zoneI);
+                zm.insert(zoneObjects[objI], zonei);
             }
         }
     }
@@ -91,27 +91,23 @@ bool Foam::ZoneMesh<ZoneType, MeshType>::read()
         PtrList<entry> patchEntries(is);
         zones.setSize(patchEntries.size());
 
-        forAll(zones, zoneI)
+        forAll(zones, zonei)
         {
             zones.set
             (
-                zoneI,
+                zonei,
                 ZoneType::New
                 (
-                    patchEntries[zoneI].keyword(),
-                    patchEntries[zoneI].dict(),
-                    zoneI,
+                    patchEntries[zonei].keyword(),
+                    patchEntries[zonei].dict(),
+                    zonei,
                     *this
                 )
             );
         }
 
         // Check state of IOstream
-        is.check
-        (
-            "ZoneMesh::ZoneMesh"
-            "(const IOobject&, const MeshType&)"
-        );
+        is.check(FUNCTION_NAME);
 
         close();
 
@@ -125,6 +121,40 @@ bool Foam::ZoneMesh<ZoneType, MeshType>::read()
 }
 
 
+// Templated implementation for names()
+template<class ZoneType, class MeshType>
+template<class UnaryMatchPredicate>
+Foam::wordList Foam::ZoneMesh<ZoneType, MeshType>::namesImpl
+(
+    const PtrList<ZoneType>& zones,
+    const UnaryMatchPredicate& matcher,
+    const bool doSort
+)
+{
+    wordList lst(zones.size());
+
+    label count = 0;
+    forAll(zones, zonei)
+    {
+        const word& zname = zones[zonei].name();
+
+        if (matcher(zname))
+        {
+            lst[count++] = zname;
+        }
+    }
+
+    lst.setSize(count);
+
+    if (doSort)
+    {
+        Foam::sort(lst);
+    }
+
+    return lst;
+}
+
+
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
 template<class ZoneType, class MeshType>
@@ -179,9 +209,9 @@ Foam::ZoneMesh<ZoneType, MeshType>::ZoneMesh
         // Nothing read. Use supplied zones
         PtrList<ZoneType>& zones = *this;
         zones.setSize(pzm.size());
-        forAll(zones, zoneI)
+        forAll(zones, zonei)
         {
-            zones.set(zoneI, pzm[zoneI].clone(*this).ptr());
+            zones.set(zonei, pzm[zonei].clone(*this).ptr());
         }
     }
 }
@@ -238,9 +268,9 @@ Foam::wordList Foam::ZoneMesh<ZoneType, MeshType>::types() const
 
     wordList lst(zones.size());
 
-    forAll(zones, zoneI)
+    forAll(zones, zonei)
     {
-        lst[zoneI] = zones[zoneI].type();
+        lst[zonei] = zones[zonei].type();
     }
 
     return lst;
@@ -254,9 +284,9 @@ Foam::wordList Foam::ZoneMesh<ZoneType, MeshType>::names() const
 
     wordList lst(zones.size());
 
-    forAll(zones, zoneI)
+    forAll(zones, zonei)
     {
-        lst[zoneI] = zones[zoneI].name();
+        lst[zonei] = zones[zonei].name();
     }
 
     return lst;
@@ -269,22 +299,18 @@ Foam::wordList Foam::ZoneMesh<ZoneType, MeshType>::names
     const wordRe& matcher
 ) const
 {
-    wordList lst = this->names();
-
-    return wordList(lst, findStrings(matcher, lst));
+    return namesImpl(*this, matcher, false);
 }
 
 
 template<class ZoneType, class MeshType>
 Foam::wordList Foam::ZoneMesh<ZoneType, MeshType>::names
 (
-    const wordReList& matcher
+    const wordRes& matcher
 )
 const
 {
-    wordList lst = this->names();
-
-    return wordList(lst, findStrings(matcher, lst));
+    return namesImpl(*this, matcher, false);
 }
 
 
@@ -304,24 +330,18 @@ Foam::wordList Foam::ZoneMesh<ZoneType, MeshType>::sortedNames
     const wordRe& matcher
 ) const
 {
-    wordList sortedLst = this->names(matcher);
-    sort(sortedLst);
-
-    return sortedLst;
+    return namesImpl(*this, matcher, true);
 }
 
 
 template<class ZoneType, class MeshType>
 Foam::wordList Foam::ZoneMesh<ZoneType, MeshType>::sortedNames
 (
-    const wordReList& matcher
+    const wordRes& matcher
 )
 const
 {
-    wordList sortedLst = this->names(matcher);
-    sort(sortedLst);
-
-    return sortedLst;
+    return namesImpl(*this, matcher, true);
 }
 
 
@@ -342,15 +362,15 @@ Foam::labelList Foam::ZoneMesh<ZoneType, MeshType>::findIndices
         else
         {
             indices.setSize(this->size());
-            label nFound = 0;
+            label count = 0;
             forAll(*this, i)
             {
                 if (key == operator[](i).name())
                 {
-                    indices[nFound++] = i;
+                    indices[count++] = i;
                 }
             }
-            indices.setSize(nFound);
+            indices.setSize(count);
         }
     }
 
@@ -388,7 +408,7 @@ Foam::label Foam::ZoneMesh<ZoneType, MeshType>::findIndex
         }
     }
 
-    // not found
+    // Not found
     return -1;
 }
 
@@ -401,11 +421,11 @@ Foam::label Foam::ZoneMesh<ZoneType, MeshType>::findZoneID
 {
     const PtrList<ZoneType>& zones = *this;
 
-    forAll(zones, zoneI)
+    forAll(zones, zonei)
     {
-        if (zones[zoneI].name() == zoneName)
+        if (zones[zonei].name() == zoneName)
         {
-            return zoneI;
+            return zonei;
         }
     }
 
@@ -417,7 +437,7 @@ Foam::label Foam::ZoneMesh<ZoneType, MeshType>::findZoneID
             << "List of available zone names: " << names() << endl;
     }
 
-    // not found
+    // Not found
     return -1;
 }
 
@@ -447,9 +467,9 @@ void Foam::ZoneMesh<ZoneType, MeshType>::clearAddressing()
 
     PtrList<ZoneType>& zones = *this;
 
-    forAll(zones, zoneI)
+    forAll(zones, zonei)
     {
-        zones[zoneI].clearAddressing();
+        zones[zonei].clearAddressing();
     }
 }
 
@@ -472,9 +492,9 @@ bool Foam::ZoneMesh<ZoneType, MeshType>::checkDefinition
 
     const PtrList<ZoneType>& zones = *this;
 
-    forAll(zones, zoneI)
+    forAll(zones, zonei)
     {
-        inError |= zones[zoneI].checkDefinition(report);
+        inError |= zones[zonei].checkDefinition(report);
     }
     return inError;
 }
@@ -535,16 +555,16 @@ bool Foam::ZoneMesh<ZoneType, MeshType>::checkParallelSync
     // Check contents
     if (!hasError)
     {
-        forAll(zones, zoneI)
+        forAll(zones, zonei)
         {
-            if (zones[zoneI].checkParallelSync(false))
+            if (zones[zonei].checkParallelSync(false))
             {
                 hasError = true;
 
                 if (debug || (report && Pstream::master()))
                 {
-                    Info<< " ***Zone " << zones[zoneI].name()
-                        << " of type " << zones[zoneI].type()
+                    Info<< " ***Zone " << zones[zonei].name()
+                        << " of type " << zones[zonei].type()
                         << " is not correctly synchronised"
                         << " across coupled boundaries."
                         << " (coupled faces are either not both"
@@ -563,9 +583,9 @@ void Foam::ZoneMesh<ZoneType, MeshType>::movePoints(const pointField& p)
 {
     PtrList<ZoneType>& zones = *this;
 
-    forAll(zones, zoneI)
+    forAll(zones, zonei)
     {
-        zones[zoneI].movePoints(p);
+        zones[zonei].movePoints(p);
     }
 }
 
@@ -586,9 +606,9 @@ const ZoneType& Foam::ZoneMesh<ZoneType, MeshType>::operator[]
     const word& zoneName
 ) const
 {
-    const label zoneI = findZoneID(zoneName);
+    const label zonei = findZoneID(zoneName);
 
-    if (zoneI < 0)
+    if (zonei < 0)
     {
         FatalErrorInFunction
             << "Zone named " << zoneName << " not found." << nl
@@ -596,7 +616,7 @@ const ZoneType& Foam::ZoneMesh<ZoneType, MeshType>::operator[]
             << abort(FatalError);
     }
 
-    return operator[](zoneI);
+    return operator[](zonei);
 }
 
 
@@ -606,9 +626,9 @@ ZoneType& Foam::ZoneMesh<ZoneType, MeshType>::operator[]
     const word& zoneName
 )
 {
-    const label zoneI = findZoneID(zoneName);
+    const label zonei = findZoneID(zoneName);
 
-    if (zoneI < 0)
+    if (zonei < 0)
     {
         FatalErrorInFunction
             << "Zone named " << zoneName << " not found." << nl
@@ -616,7 +636,7 @@ ZoneType& Foam::ZoneMesh<ZoneType, MeshType>::operator[]
             << abort(FatalError);
     }
 
-    return operator[](zoneI);
+    return operator[](zonei);
 }
 
 
@@ -631,9 +651,9 @@ Foam::Ostream& Foam::operator<<
 {
     os  << zones.size() << nl << token::BEGIN_LIST;
 
-    forAll(zones, zoneI)
+    forAll(zones, zonei)
     {
-        zones[zoneI].writeDict(os);
+        zones[zonei].writeDict(os);
     }
 
     os  << token::END_LIST;
diff --git a/src/OpenFOAM/meshes/polyMesh/zones/ZoneMesh/ZoneMesh.H b/src/OpenFOAM/meshes/polyMesh/zones/ZoneMesh/ZoneMesh.H
index 7d79a37a1e8237bccf670c24cd8decec59665142..d76823b85222ea5bd57b5abb494a40bbc75e6f11 100644
--- a/src/OpenFOAM/meshes/polyMesh/zones/ZoneMesh/ZoneMesh.H
+++ b/src/OpenFOAM/meshes/polyMesh/zones/ZoneMesh/ZoneMesh.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -40,7 +40,7 @@ SourceFiles
 #include "pointField.H"
 #include "Map.H"
 #include "PackedBoolList.H"
-#include "wordReList.H"
+#include "wordRes.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -54,7 +54,7 @@ namespace Foam
 template<class ZoneType, class MeshType> class ZoneMesh;
 
 template<class ZoneType, class MeshType>
-Ostream& operator<<(Ostream&, const ZoneMesh<ZoneType, MeshType>&);
+Ostream& operator<<(Ostream& os, const ZoneMesh<ZoneType, MeshType>& zones);
 
 /*---------------------------------------------------------------------------*\
                            Class ZoneMesh Declaration
@@ -80,6 +80,19 @@ class ZoneMesh
         //- Read if IOobject flags set. Return true if read.
         bool read();
 
+        //- Create zone map
+        void calcZoneMap() const;
+
+        //- Templated implementation for names()
+        template<class UnaryMatchPredicate>
+        static wordList namesImpl
+        (
+            const PtrList<ZoneType>& zones,
+            const UnaryMatchPredicate& matcher,
+            const bool doSort
+        );
+
+
         //- Disallow construct as copy
         ZoneMesh(const ZoneMesh&) = delete;
 
@@ -87,10 +100,6 @@ class ZoneMesh
         void operator=(const ZoneMesh<ZoneType, MeshType>&) = delete;
 
 
-        //- Create zone map
-        void calcZoneMap() const;
-
-
 public:
 
     // Constructors
@@ -98,24 +107,24 @@ public:
         //- Read constructor given IOobject and a MeshType reference
         ZoneMesh
         (
-            const IOobject&,
-            const MeshType&
+            const IOobject& io,
+            const MeshType& mesh
         );
 
         //- Construct given size
         ZoneMesh
         (
-            const IOobject&,
-            const MeshType&,
+            const IOobject& io,
+            const MeshType& mesh,
             const label size
         );
 
-         //- Construct given a PtrList
+        //- Construct given a PtrList
         ZoneMesh
         (
-            const IOobject&,
-            const MeshType&,
-            const PtrList<ZoneType>&
+            const IOobject& io,
+            const MeshType& mesh,
+            const PtrList<ZoneType>& pzm
         );
 
 
@@ -146,32 +155,32 @@ public:
         wordList names() const;
 
         //- A list of the zone names satisfying the input matcher
-        wordList names(const wordRe&) const;
+        wordList names(const wordRe& matcher) const;
 
         //- A list of the zone names satisfying the input matchers
-        wordList names(const wordReList&) const;
+        wordList names(const wordRes& matcher) const;
 
         //- Sorted list of the zone names
         wordList sortedNames() const;
 
         //- Sorted list of the zone names satisfying the input matcher
-        wordList sortedNames(const wordRe&) const;
+        wordList sortedNames(const wordRe& matcher) const;
 
         //- Sorted list of the zone names satisfying the input matchers
-        wordList sortedNames(const wordReList&) const;
+        wordList sortedNames(const wordRes& matcher) const;
 
 
         //- Return zone indices for all matches
-        labelList findIndices(const keyType&) const;
+        labelList findIndices(const keyType& key) const;
 
         //- Return zone index for the first match, return -1 if not found
-        label findIndex(const keyType&) const;
+        label findIndex(const keyType& key) const;
 
         //- Find zone index given a name
         label findZoneID(const word& zoneName) const;
 
         //- Mark cells that match the zone specification
-        PackedBoolList findMatching(const keyType&) const;
+        PackedBoolList findMatching(const keyType& key) const;
 
         //- Clear addressing
         void clearAddressing();
@@ -187,10 +196,10 @@ public:
         bool checkParallelSync(const bool report = false) const;
 
         //- Correct zone mesh after moving points
-        void movePoints(const pointField&);
+        void movePoints(const pointField& p);
 
         //- writeData member function required by regIOobject
-        bool writeData(Ostream&) const;
+        bool writeData(Ostream& os) const;
 
     // Member Operators
 
@@ -198,18 +207,18 @@ public:
         using PtrList<ZoneType>::operator[];
 
         //- Return const reference to ZoneType by name.
-        const ZoneType& operator[](const word&) const;
+        const ZoneType& operator[](const word& zoneName) const;
 
         //- Return reference to ZoneType by name.
-        ZoneType& operator[](const word&);
+        ZoneType& operator[](const word& zoneName);
 
 
     // Ostream operator
 
         friend Ostream& operator<< <ZoneType, MeshType>
         (
-            Ostream&,
-            const ZoneMesh<ZoneType, MeshType>&
+            Ostream& os,
+            const ZoneMesh<ZoneType, MeshType>& zones
         );
 };
 
diff --git a/src/OpenFOAM/primitives/bools/Switch/Switch.H b/src/OpenFOAM/primitives/bools/Switch/Switch.H
index 25b79905ac78e3dbb218daf7d030f7911bdba920..63ef5ead5276c2a5516b82a251dfe2d72b8f123e 100644
--- a/src/OpenFOAM/primitives/bools/Switch/Switch.H
+++ b/src/OpenFOAM/primitives/bools/Switch/Switch.H
@@ -50,8 +50,8 @@ namespace Foam
 class Switch;
 class dictionary;
 
-Istream& operator>>(Istream&, Switch&);
-Ostream& operator<<(Ostream&, const Switch&);
+Istream& operator>>(Istream& is, Switch& s);
+Ostream& operator<<(Ostream& is, const Switch& s);
 
 
 /*---------------------------------------------------------------------------*\
@@ -108,8 +108,12 @@ private:
 
     // Static Member Functions
 
-        //- Return a switchType representation of a word
-        static switchType asEnum(const std::string&, const bool allowInvalid);
+        //- Return a switchType representation of an input string
+        static switchType asEnum
+        (
+            const std::string& str,
+            const bool allowInvalid
+        );
 
 
 public:
@@ -161,8 +165,8 @@ public:
         //  value is not found, it is added into the dictionary.
         static Switch lookupOrAddToDict
         (
-            const word&,
-            dictionary&,
+            const word& name,
+            dictionary& dict,
             const Switch& defaultValue = false
         );
 
@@ -176,7 +180,7 @@ public:
         const char* asText() const;
 
         //- Update the value of the Switch if it is found in the dictionary
-        bool readIfPresent(const word&, const dictionary&);
+        bool readIfPresent(const word& name, const dictionary& dict);
 
 
     // Member Operators
@@ -202,8 +206,8 @@ public:
 
     // IOstream Operators
 
-        friend Istream& operator>>(Istream&, Switch&);
-        friend Ostream& operator<<(Ostream&, const Switch&);
+        friend Istream& operator>>(Istream& is, Switch& s);
+        friend Ostream& operator<<(Ostream& os, const Switch& s);
 };
 
 
diff --git a/src/OpenFOAM/primitives/bools/Switch/SwitchIO.C b/src/OpenFOAM/primitives/bools/Switch/SwitchIO.C
index e716820d5f0f0c015d0025421f97e1f0d386282b..b0bda84bebb12d3dae2903d1388fc8d3d65b08e2 100644
--- a/src/OpenFOAM/primitives/bools/Switch/SwitchIO.C
+++ b/src/OpenFOAM/primitives/bools/Switch/SwitchIO.C
@@ -79,10 +79,7 @@ Foam::Istream& Foam::operator>>(Istream& is, Switch& s)
         return is;
     }
 
-
-    // Check state of Istream
-    is.check("Istream& operator>>(Istream&, Switch&)");
-
+    is.check(FUNCTION_NAME);
     return is;
 }
 
@@ -90,7 +87,7 @@ Foam::Istream& Foam::operator>>(Istream& is, Switch& s)
 Foam::Ostream& Foam::operator<<(Ostream& os, const Switch& s)
 {
     os << Switch::names[s.switch_];
-    os.check("Ostream& operator<<(Ostream&, const Switch&)");
+    os.check(FUNCTION_NAME);
     return os;
 }
 
diff --git a/src/OpenFOAM/primitives/bools/bool/bool.H b/src/OpenFOAM/primitives/bools/bool/bool.H
index 19d8fb63de0805d39b462ca061241f2e55f04a07..b3cbe5567ca6995781cb9de951dfebf03366398b 100644
--- a/src/OpenFOAM/primitives/bools/bool/bool.H
+++ b/src/OpenFOAM/primitives/bools/bool/bool.H
@@ -45,10 +45,10 @@ class Ostream;
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-Istream& operator>>(Istream&, bool&);
-Ostream& operator<<(Ostream&, const bool);
+Istream& operator>>(Istream& is, bool& b);
+Ostream& operator<<(Ostream& os, const bool b);
 
-bool readBool(Istream&);
+bool readBool(Istream& is);
 
 } // End namespace Foam
 
@@ -61,7 +61,7 @@ bool readBool(Istream&);
 namespace Foam
 {
 
-// template specialisation for pTraits<bool>
+// Template specialisation for pTraits<bool>
 template<>
 class pTraits<bool>
 {
@@ -95,10 +95,10 @@ public:
     // Constructors
 
         //- Construct from primitive
-        explicit pTraits(const bool&);
+        explicit pTraits(const bool& p);
 
         //- Construct from Istream
-        pTraits(Istream&);
+        pTraits(Istream& is);
 
 
     // Member Functions
diff --git a/src/OpenFOAM/primitives/bools/bool/boolIO.C b/src/OpenFOAM/primitives/bools/bool/boolIO.C
index 60518849cfa5381e527cdc6a3b7714e23951df12..f098a3e1864e74bbebc61ca0247a29cc73cd6a44 100644
--- a/src/OpenFOAM/primitives/bools/bool/boolIO.C
+++ b/src/OpenFOAM/primitives/bools/bool/boolIO.C
@@ -21,17 +21,11 @@ License
     You should have received a copy of the GNU General Public License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
-Description
-    Reads an bool from an input stream, for a given version number and file
-    format. If an ASCII file is being read, then the line numbers are counted
-    and an erroneous read is reported.
-
 \*---------------------------------------------------------------------------*/
 
-#include "error.H"
-
 #include "bool.H"
 #include "Switch.H"
+#include "error.H"
 #include "IOstreams.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@@ -51,8 +45,8 @@ Foam::Ostream& Foam::operator<<(Ostream& os, const bool b)
 {
     // we could also write as text string without any difficulty
     // os  << (b ? "true" : "false");
-    os.write(label(b));
-    os.check("Ostream& operator<<(Ostream&, const bool)");
+    os.write(int(b));
+    os.check(FUNCTION_NAME);
     return os;
 }
 
diff --git a/src/OpenFOAM/primitives/direction/direction.H b/src/OpenFOAM/primitives/direction/direction.H
index b382c20aee4101084af51d96b1fa37eb3abcee09..8f8c8c27277ca3e7bffc32e81fc38cb529542b51 100644
--- a/src/OpenFOAM/primitives/direction/direction.H
+++ b/src/OpenFOAM/primitives/direction/direction.H
@@ -48,10 +48,10 @@ class Ostream;
 
 typedef uint8_t direction;
 
-direction readDirection(Istream&);
-Istream& operator>>(Istream&, direction&);
-Ostream& operator<<(Ostream&, const direction);
-std::ostream& operator<<(std::ostream&, const direction);
+direction readDirection(Istream& is);
+Istream& operator>>(Istream& is, direction& d);
+Ostream& operator<<(Ostream& os, const direction d);
+std::ostream& operator<<(std::ostream& os, const direction d);
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
diff --git a/src/OpenFOAM/primitives/direction/directionIO.C b/src/OpenFOAM/primitives/direction/directionIO.C
index f8a8812a01c722b4e8a4ecaa39c42ec89731beb2..e73351593329d81092cb9abe93248bff8d81064a 100644
--- a/src/OpenFOAM/primitives/direction/directionIO.C
+++ b/src/OpenFOAM/primitives/direction/directionIO.C
@@ -61,17 +61,15 @@ Foam::Istream& Foam::operator>>(Istream& is, direction& d)
         return is;
     }
 
-    // Check state of Istream
-    is.check("Istream& operator>>(Istream&, direction&)");
-
+    is.check(FUNCTION_NAME);
     return is;
 }
 
 
 Foam::Ostream& Foam::operator<<(Ostream& os, const direction d)
 {
-    os.write(label(d));
-    os.check("Ostream& operator<<(Ostream&, const direction)");
+    os.write(int(d));
+    os.check(FUNCTION_NAME);
     return os;
 }
 
diff --git a/src/OpenFOAM/primitives/predicates/predicates.H b/src/OpenFOAM/primitives/predicates/predicates.H
new file mode 100644
index 0000000000000000000000000000000000000000..8731fb451899bfc348202d340d0c9d71a608c006
--- /dev/null
+++ b/src/OpenFOAM/primitives/predicates/predicates.H
@@ -0,0 +1,142 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2017 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Namespace
+    Foam::predicates
+
+Description
+    Various constant predicate types.
+
+SourceFiles
+    predicates.H
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef predicates_H
+#define predicates_H
+
+#include <string>
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+namespace predicates
+{
+
+/*---------------------------------------------------------------------------*\
+                           Class always Declaration
+\*---------------------------------------------------------------------------*/
+
+//- Unary and binary predicates returning true, useful for templating.
+class always
+{
+public:
+    typedef always value_type;
+
+    //- Construct null
+    inline always()
+    {}
+
+    //- Evalulated as a bool - return true
+    inline operator bool() const
+    {
+        return true;
+    }
+
+    //- Unary predicate returning true
+    template<class T>
+    inline bool operator()(const T&) const
+    {
+        return true;
+    }
+
+    //- Binary predicate returning false
+    template<class T1, class T2>
+    inline bool operator()(const T1&, const T2&) const
+    {
+        return true;
+    }
+
+    //- String matching returning true
+    inline bool match(const std::string& unused, bool literal=false) const
+    {
+        return true;
+    }
+};
+
+
+/*---------------------------------------------------------------------------*\
+                            Class never Declaration
+\*---------------------------------------------------------------------------*/
+
+//- Unary and binary predicates returning false, useful for templating.
+class never
+{
+public:
+    typedef never value_type;
+
+    //- Construct null
+    inline never()
+    {}
+
+    //- Evalulated as a bool - return false
+    inline operator bool() const
+    {
+        return false;
+    }
+
+    //- Unary predicate returning false
+    template<class T>
+    inline bool operator()(const T&) const
+    {
+        return false;
+    }
+
+    //- Binary predicate returning false
+    template<class T1, class T2>
+    inline bool operator()(const T1&, const T2&) const
+    {
+        return false;
+    }
+
+    //- String matching returning false
+    inline bool match(const std::string& unused, bool literal=false) const
+    {
+        return false;
+    }
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace predicates
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/primitives/strings/keyType/keyType.C b/src/OpenFOAM/primitives/strings/keyType/keyType.C
index 5b27421414fe57d3ddfebe9927d3f134ebbfea99..05f54c255455d1b4aec02782cb118c75a9ce3225 100644
--- a/src/OpenFOAM/primitives/strings/keyType/keyType.C
+++ b/src/OpenFOAM/primitives/strings/keyType/keyType.C
@@ -52,13 +52,11 @@ bool Foam::keyType::match(const std::string& text, bool literal) const
 {
     if (literal || !isPattern_)
     {
-        // check as string
-        return (text == *this);
+        return !compare(text);  // Compare as literal string
     }
     else
     {
-        // check as regex
-        return regExp(*this).match(text);
+        return regExp(*this).match(text);  // Match as regex
     }
 }
 
diff --git a/src/OpenFOAM/primitives/strings/keyType/keyType.H b/src/OpenFOAM/primitives/strings/keyType/keyType.H
index 3f342e0e2232967658349a1b6f71274bed65e00b..82713fd9ffeb440cdd9a49868bcf4794abd4c70b 100644
--- a/src/OpenFOAM/primitives/strings/keyType/keyType.H
+++ b/src/OpenFOAM/primitives/strings/keyType/keyType.H
@@ -121,19 +121,26 @@ public:
 
     // Member operators
 
-        // Assignment
+        //- Avoid masking the normal operator()
+        using word::operator();
 
-            //- Assignment operator, retaining type (literal or regex)
-            inline void operator=(const keyType& s);
+        //- Perform smart match on text
+        inline bool operator()(const std::string& text) const;
 
-            //- Assign as word, not treated as a regular expression.
-            inline void operator=(const word& s);
 
-            //- Assign as regular expression
-            inline void operator=(const string& s);
+      // Assignment
 
-            //- Assign as word, not treated as a regular expression.
-            inline void operator=(const char* s);
+        //- Assignment operator, retaining type (literal or regex)
+        inline void operator=(const keyType& s);
+
+        //- Assign as word, not treated as a regular expression.
+        inline void operator=(const word& s);
+
+        //- Assign as regular expression
+        inline void operator=(const string& s);
+
+        //- Assign as word, not treated as a regular expression.
+        inline void operator=(const char* s);
 
 
     // IOstream operators
diff --git a/src/OpenFOAM/primitives/strings/keyType/keyTypeI.H b/src/OpenFOAM/primitives/strings/keyType/keyTypeI.H
index 99b73ac10908a2a6be9464822170e786a4a73ce6..964f48cbb033bb7e59db0fcec83b944dcb8281d6 100644
--- a/src/OpenFOAM/primitives/strings/keyType/keyTypeI.H
+++ b/src/OpenFOAM/primitives/strings/keyType/keyTypeI.H
@@ -81,6 +81,12 @@ inline bool Foam::keyType::isPattern() const
 
 // * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
 
+inline bool Foam::keyType::operator()(const std::string& text) const
+{
+    return match(text);  // Use smart match
+}
+
+
 inline void Foam::keyType::operator=(const keyType& s)
 {
     string::operator=(s); // Bypass checking
diff --git a/src/OpenFOAM/primitives/strings/lists/hashedWordList.H b/src/OpenFOAM/primitives/strings/lists/hashedWordList.H
index 9ecab0f382553b239cdd9caa4ceae20aece676cc..a2e68df9df32b56fcd542997773ed952adbd9155 100644
--- a/src/OpenFOAM/primitives/strings/lists/hashedWordList.H
+++ b/src/OpenFOAM/primitives/strings/lists/hashedWordList.H
@@ -47,8 +47,8 @@ namespace Foam
 class hashedWordList;
 
 // Forward declaration of friend functions and operators
-Istream& operator>>(Istream&, hashedWordList&);
-Ostream& operator<<(Ostream&, const hashedWordList&);
+Istream& operator>>(Istream& is, hashedWordList& lst);
+Ostream& operator<<(Ostream& os, const hashedWordList& lst);
 
 
 /*---------------------------------------------------------------------------*\
@@ -97,7 +97,7 @@ public:
         );
 
         //- Construct from an initializer list
-        inline hashedWordList(std::initializer_list<word>);
+        inline hashedWordList(std::initializer_list<word> lst);
 
         //- Construct from the word keys of any HashTable, sorting immediately.
         //  This also handles a wordHashSet, which is derived from a HashTable.
@@ -105,7 +105,7 @@ public:
         template<class AnyType, class AnyHash>
         explicit inline hashedWordList
         (
-            const HashTable<AnyType, word, AnyHash>& h
+            const HashTable<AnyType, word, AnyHash>& tbl
         );
 
         //- Construct from number and list of words,
@@ -122,7 +122,7 @@ public:
         hashedWordList(const char** lst, const bool removeDuplicates=false);
 
         //- Construct from Istream
-        hashedWordList(Istream&);
+        hashedWordList(Istream& is);
 
 
     // Member Functions
@@ -161,26 +161,33 @@ public:
 
     // Member Operators
 
-        //- Assignment operator from list of words
+        //- Return name corresponding to specified index
+        inline const word& operator[](const label index) const;
+
+        //- Return index corresponding to specified name, or -1 on failure
+        inline label operator[](const word& name) const;
+
+        //- Does the list contain the specified name - same as found.
+        //  Makes hashedWordList suitable as a unary predicate.
+        inline bool operator()(const word& name) const;
+
+
+      // Assignment
+
+        //- Assignment operator from list of words. Rehashes the indices.
         inline void operator=(const UList<word>& lst);
 
-        //- Assignment operator from initializer list
+        //- Assignment operator from initializer list. Rehashes the indices.
         inline void operator=(std::initializer_list<word> lst);
 
-        //- Assignment operator.
+        //- Assignment operator. Rehashes the indices.
         inline void operator=(const hashedWordList& lst);
 
-        //- Return name corresponding to specified index
-        inline const word& operator[](const label index) const;
-
-        //- Return index corresponding to specified name
-        inline label operator[](const word& name) const;
-
 
     // Istream operators
 
-        friend Istream& operator>>(Istream&, hashedWordList&);
-        friend Ostream& operator<<(Ostream&, const hashedWordList&);
+        friend Istream& operator>>(Istream& is, hashedWordList& lst);
+        friend Ostream& operator<<(Ostream& os, const hashedWordList& lst);
 };
 
 
diff --git a/src/OpenFOAM/primitives/strings/lists/hashedWordListI.H b/src/OpenFOAM/primitives/strings/lists/hashedWordListI.H
index 80f8d28be0841295f8363ce9745fcb42c9fb92b7..aa42bf697c4fbf8d280dc1bf47ce3efb62d7241d 100644
--- a/src/OpenFOAM/primitives/strings/lists/hashedWordListI.H
+++ b/src/OpenFOAM/primitives/strings/lists/hashedWordListI.H
@@ -90,21 +90,15 @@ inline Foam::hashedWordList::hashedWordList(std::initializer_list<word> lst)
 template<class AnyType, class AnyHash>
 inline Foam::hashedWordList::hashedWordList
 (
-    const HashTable<AnyType, word, AnyHash>& h
+    const HashTable<AnyType, word, AnyHash>& tbl
 )
 :
-    List<word>(h.size())
-{
-    label nElem = 0;
-    for
-    (
-        typename HashTable<AnyType, word, AnyHash>::const_iterator
-        iter = h.cbegin();
-        iter != h.cend();
-        ++iter
-    )
+    List<word>(tbl.size())
+{
+    label count = 0;
+    for (auto iter = tbl.cbegin(); iter != tbl.cend(); ++iter)
     {
-        List<word>::operator[](nElem++) = iter.key();
+        List<word>::operator[](count++) = iter.key();
     }
 
     this->sort();
@@ -162,39 +156,51 @@ inline void Foam::hashedWordList::sort()
 
 // * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
 
-inline void Foam::hashedWordList::operator=(const UList<word>& lst)
+inline const Foam::word& Foam::hashedWordList::operator[]
+(
+    const label index
+) const
 {
-    List<word>::operator=(lst);
-    rehash();
+    return List<word>::operator[](index);
 }
 
 
-inline void Foam::hashedWordList::operator=(std::initializer_list<word> lst)
+inline Foam::label Foam::hashedWordList::operator[](const word& name) const
 {
-    List<word>::operator=(lst);
-    rehash();
+    auto iter = indices_.find(name);
+
+    if (iter.found())
+    {
+        return iter.object();
+    }
+
+    return -1;  // Not found (or not hashed?)
 }
 
 
-inline void Foam::hashedWordList::operator=(const hashedWordList& lst)
+inline bool Foam::hashedWordList::operator()(const word& name) const
 {
-    operator=(static_cast<const UList<word>&>(lst));
+    return indices_.found(name);
 }
 
 
-inline const Foam::word& Foam::hashedWordList::operator[]
-(
-    const label index
-) const
+inline void Foam::hashedWordList::operator=(const UList<word>& lst)
 {
-    return List<word>::operator[](index);
+    List<word>::operator=(lst);
+    rehash();
 }
 
 
-inline Foam::label Foam::hashedWordList::operator[](const word& name) const
+inline void Foam::hashedWordList::operator=(std::initializer_list<word> lst)
 {
-    // Could return -1 instead of bombing out
-    return indices_[name];
+    List<word>::operator=(lst);
+    rehash();
+}
+
+
+inline void Foam::hashedWordList::operator=(const hashedWordList& lst)
+{
+    operator=(static_cast<const UList<word>&>(lst));
 }
 
 
diff --git a/src/OpenFOAM/primitives/strings/lists/stringListOps.H b/src/OpenFOAM/primitives/strings/lists/stringListOps.H
index 677d4e8a07190445b490687c79e0fa292e71ed8e..0ea3266d3ea204820b2bdad78243ed04de3044b9 100644
--- a/src/OpenFOAM/primitives/strings/lists/stringListOps.H
+++ b/src/OpenFOAM/primitives/strings/lists/stringListOps.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -35,91 +35,99 @@ SourceFiles
 #ifndef stringListOps_H
 #define stringListOps_H
 
-#include "regExp.H"
 #include "labelList.H"
 #include "stringList.H"
-#include "wordReList.H"
-#include "wordReListMatcher.H"
+#include "regExp.H"
+#include "wordRes.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 namespace Foam
 {
-    // Single-string matches:
+  // Single-string matches:
 
-    //- Return true if string matches one of the regular expressions
-    inline bool findStrings
-    (
-        const wordReListMatcher& matcher,
-        const std::string& str
-    )
+    //- Return true if text matches one of the regular expressions
+    //  The primary purpose of this function is to automatically convert
+    //  a wordReList to a wordRes for matching.
+    inline bool findStrings(const wordRes& matcher, const std::string& text)
     {
-        return matcher.match(str);
+        return matcher(text);
     }
 
-    // Multi-string matches:
 
-    //- Return list indices for matching strings
-    template<class Matcher, class StringType>
+  // Multi-string matches:
+
+    //- Extract list indices
+    //  The unary match predicate has the following signature:
+    //  \code
+    //  bool operator()(const std::string& text);
+    //  \endcode
+    //
+    //  \return List indices for matching strings
+    template<class UnaryMatchPredicate, class StringType>
     labelList findMatchingStrings
     (
-        const Matcher& matcher,
+        const UnaryMatchPredicate& matcher,
         const UList<StringType>& lst,
         const bool invert=false
     );
 
+
     //- Return list indices for strings matching the regular expression
     //  Template partial specialization of findMatchingStrings
     template<class StringType>
     labelList findStrings
     (
-        const regExp& re,
+        const regExp& matcher,
         const UList<StringType>& lst,
         const bool invert=false
     )
     {
-        return findMatchingStrings(re, lst, invert);
+        return findMatchingStrings(matcher, lst, invert);
     }
 
+
     //- Return list indices for strings matching the regular expression
     //  Template partial specialization of findMatchingStrings
     template<class StringType>
     labelList findStrings
     (
-        const char* rePattern,
+        const char* re,
         const UList<StringType>& lst,
         const bool invert=false
     )
     {
-        const regExp re(rePattern);
-        return findMatchingStrings(re, lst, invert);
+        const regExp matcher(re);
+        return findMatchingStrings(matcher, lst, invert);
     }
 
+
     //- Return list indices for strings matching the regular expression
     //  Template partial specialization of findMatchingStrings
     template<class StringType>
     labelList findStrings
     (
-        const std::string& rePattern,
+        const std::string& re,
         const UList<StringType>& lst,
         const bool invert=false
     )
     {
-        const regExp re(rePattern);
-        return findMatchingStrings(re, lst, invert);
+        const regExp matcher(re);
+        return findMatchingStrings(matcher, lst, invert);
     }
 
+
     //- Return list indices for strings matching the regular expression
     //  Template partial specialization of findMatchingStrings
     template<class StringType>
     labelList findStrings
     (
-        const wordRe& wre,
+        const wordRe& matcher,
         const UList<StringType>& lst,
         const bool invert=false
     )
     {
-        return findMatchingStrings(wre, lst, invert);
+        return findMatchingStrings(matcher, lst, invert);
     }
 
 
@@ -128,7 +136,7 @@ namespace Foam
     template<class StringType>
     labelList findStrings
     (
-        const wordReListMatcher& matcher,
+        const wordRes& matcher,
         const UList<StringType>& lst,
         const bool invert=false
     )
@@ -136,45 +144,50 @@ namespace Foam
         return findMatchingStrings(matcher, lst, invert);
     }
 
-    // subsetting multi-string matches (similar to ListOp):
+
+  // Subsetting multi-string matches (similar to ListOp):
 
     //- Extract elements of StringList when regular expression matches
     //  optionally invert the match
     //  eg, to extract all selected elements:
+    //  \code
     //    subsetMatchingStrings<regExp, stringList>(myRegExp, lst);
-    template<class Matcher, class StringListType>
+    //  \endcode
+    template<class UnaryMatchPredicate, class StringListType>
     StringListType subsetMatchingStrings
     (
-        const Matcher&,
-        const StringListType&,
+        const UnaryMatchPredicate& matcher,
+        const StringListType& lst,
         const bool invert=false
     );
 
+
     //- Extract elements of StringList when regular expression matches
     //  Template partial specialization of subsetMatchingStrings
     template<class StringListType>
     StringListType subsetStrings
     (
-        const regExp& re,
+        const regExp& matcher,
         const StringListType& lst,
         const bool invert=false
     )
     {
-        return subsetMatchingStrings(re, lst, invert);
+        return subsetMatchingStrings(matcher, lst, invert);
     }
 
+
     //- Extract elements of StringList when regular expression matches
     //  Template partial specialization of subsetMatchingStrings
     template<class StringListType>
     StringListType subsetStrings
     (
-        const char* rePattern,
+        const char* re,
         const StringListType& lst,
         const bool invert=false
     )
     {
-        const regExp re(rePattern);
-        return subsetMatchingStrings(re, lst, invert);
+        const regExp matcher(re);
+        return subsetMatchingStrings(matcher, lst, invert);
     }
 
     //- Extract elements of StringList when regular expression matches
@@ -182,13 +195,13 @@ namespace Foam
     template<class StringListType>
     StringListType subsetStrings
     (
-        const std::string& rePattern,
+        const std::string& re,
         const StringListType& lst,
         const bool invert=false
     )
     {
-        const regExp re(rePattern);
-        return subsetMatchingStrings(re, lst, invert);
+        const regExp matcher(re);
+        return subsetMatchingStrings(matcher, lst, invert);
     }
 
     //- Extract elements of StringList when regular expression matches
@@ -196,12 +209,12 @@ namespace Foam
     template<class StringListType>
     StringListType subsetStrings
     (
-        const wordRe& wre,
+        const wordRe& matcher,
         const StringListType& lst,
         const bool invert=false
     )
     {
-        return subsetMatchingStrings(wre, lst, invert);
+        return subsetMatchingStrings(matcher, lst, invert);
     }
 
     //- Extract elements of StringList when regular expression matches
@@ -209,7 +222,7 @@ namespace Foam
     template<class StringListType>
     StringListType subsetStrings
     (
-        const wordReListMatcher& matcher,
+        const wordRes& matcher,
         const StringListType& lst,
         const bool invert=false
     )
@@ -222,11 +235,11 @@ namespace Foam
     //  optionally invert the match
     //  eg, to extract all selected elements:
     //    inplaceSubsetMatchingStrings<regExp, stringList>(myRegExp, lst);
-    template<class Matcher, class StringListType>
+    template<class UnaryMatchPredicate, class StringListType>
     void inplaceSubsetMatchingStrings
     (
-        const Matcher&,
-        StringListType&,
+        const UnaryMatchPredicate& matcher,
+        StringListType& lst,
         const bool invert=false
     );
 
@@ -235,12 +248,12 @@ namespace Foam
     template<class StringListType>
     void inplaceSubsetStrings
     (
-        const regExp& re,
+        const regExp& matcher,
         StringListType& lst,
         const bool invert=false
     )
     {
-        inplaceSubsetMatchingStrings(re, lst, invert);
+        inplaceSubsetMatchingStrings(matcher, lst, invert);
     }
 
     //- Inplace extract elements of StringList when regular expression matches
@@ -248,13 +261,13 @@ namespace Foam
     template<class StringListType>
     void inplaceSubsetStrings
     (
-        const char* rePattern,
+        const char* re,
         StringListType& lst,
         const bool invert=false
     )
     {
-        const regExp re(rePattern);
-        inplaceSubsetMatchingStrings(re, lst, invert);
+        const regExp matcher(re);
+        inplaceSubsetMatchingStrings(matcher, lst, invert);
     }
 
     //- Inplace extract elements of StringList when regular expression matches
@@ -262,13 +275,13 @@ namespace Foam
     template<class StringListType>
     void inplaceSubsetStrings
     (
-        const std::string& rePattern,
+        const std::string& re,
         StringListType& lst,
         const bool invert=false
     )
     {
-        const regExp re(rePattern);
-        inplaceSubsetMatchingStrings(re, lst, invert);
+        const regExp matcher(re);
+        inplaceSubsetMatchingStrings(matcher, lst, invert);
     }
 
     //- Inplace extract elements of StringList when regular expression matches
@@ -276,12 +289,12 @@ namespace Foam
     template<class StringListType>
     void inplaceSubsetStrings
     (
-        const wordRe& wre,
+        const wordRe& matcher,
         StringListType& lst,
         const bool invert=false
     )
     {
-        inplaceSubsetMatchingStrings(wre, lst, invert);
+        inplaceSubsetMatchingStrings(matcher, lst, invert);
     }
 
     //- Inplace extract elements of StringList when regular expression matches
@@ -289,7 +302,7 @@ namespace Foam
     template<class StringListType>
     void inplaceSubsetStrings
     (
-        const wordReListMatcher& matcher,
+        const wordRes& matcher,
         StringListType& lst,
         const bool invert=false
     )
diff --git a/src/OpenFOAM/primitives/strings/lists/stringListOpsTemplates.C b/src/OpenFOAM/primitives/strings/lists/stringListOpsTemplates.C
index 88cf093846fb8848201e85da9cd13772c30abd82..89dda345ffde519e44c442e39465cf7d06debca4 100644
--- a/src/OpenFOAM/primitives/strings/lists/stringListOpsTemplates.C
+++ b/src/OpenFOAM/primitives/strings/lists/stringListOpsTemplates.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -25,75 +25,79 @@ License
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-template<class Matcher, class StringType>
+template<class UnaryMatchPredicate, class StringType>
 Foam::labelList Foam::findMatchingStrings
 (
-    const Matcher& matcher,
+    const UnaryMatchPredicate& matcher,
     const UList<StringType>& lst,
     const bool invert
 )
 {
     labelList indices(lst.size());
 
-    label nElem = 0;
-    forAll(lst, elemI)
+    label count = 0;
+    forAll(lst, elemi)
     {
-        if (matcher.match(lst[elemI]) ? !invert : invert)
+        if (matcher(lst[elemi]) ? !invert : invert)
         {
-            indices[nElem++] = elemI;
+            indices[count++] = elemi;
         }
     }
-    indices.setSize(nElem);
+    indices.setSize(count);
 
     return indices;
 }
 
 
-template<class Matcher, class StringListType>
+template<class UnaryMatchPredicate, class StringListType>
 StringListType Foam::subsetMatchingStrings
 (
-    const Matcher& matcher,
+    const UnaryMatchPredicate& matcher,
     const StringListType& lst,
     const bool invert
 )
 {
-    // Create copy
+    // Create as a copy
     StringListType newLst(lst.size());
 
-    // ensure consistent addressable size (eg, DynamicList)
+    // Ensure consistent addressable size (eg, DynamicList)
     newLst.setSize(lst.size());
 
-    label nElem = 0;
-    forAll(lst, elemI)
+    label count = 0;
+    forAll(lst, elemi)
     {
-        if (matcher.match(lst[elemI]) ? !invert : invert)
+        if (matcher(lst[elemi]) ? !invert : invert)
         {
-            newLst[nElem++] = lst[elemI];
+            newLst[count++] = lst[elemi];
         }
     }
-    newLst.setSize(nElem);
+    newLst.setSize(count);
 
     return newLst;
 }
 
 
-template<class Matcher, class StringListType>
+template<class UnaryMatchPredicate, class StringListType>
 void Foam::inplaceSubsetMatchingStrings
 (
-    const Matcher& matcher,
+    const UnaryMatchPredicate& matcher,
     StringListType& lst,
     const bool invert
 )
 {
-    label nElem = 0;
-    forAll(lst, elemI)
+    label count = 0;
+    forAll(lst, elemi)
     {
-        if (matcher.match(lst[elemI]) ? !invert : invert)
+        if (matcher(lst[elemi]) ? !invert : invert)
         {
-            lst[nElem++] = lst[elemI];
+            if (count != elemi)
+            {
+                lst[count] = lst[elemi];
+            }
+            ++count;
         }
     }
-    lst.setSize(nElem);
+    lst.setSize(count);
 }
 
 
diff --git a/src/OpenFOAM/primitives/strings/string/string.H b/src/OpenFOAM/primitives/strings/string/string.H
index b1129c7c3a6519e7ab3dd37bdab7279afc84b01f..87cb00104b2f507b787cd71e0d6a48006838fb0e 100644
--- a/src/OpenFOAM/primitives/strings/string/string.H
+++ b/src/OpenFOAM/primitives/strings/string/string.H
@@ -94,7 +94,9 @@ public:
         hash()
         {}
 
-        inline unsigned operator()(const string&, unsigned seed = 0) const;
+        //- Hash for string.
+        //  Uses Foam::string instead of std::string for automatic conversions.
+        inline unsigned operator()(const string& str, unsigned seed = 0) const;
     };
 
 
@@ -109,7 +111,7 @@ public:
         //- Construct as copy of character array
         inline string(const char* str);
 
-        //- Construct as copy of specified number of characters
+        //- Construct as copy with a maximum number of characters
         inline string(const char* str, const size_type len);
 
         //- Construct from a single character
@@ -222,14 +224,18 @@ public:
 
     // Member Operators
 
-        //- Return the sub-string from the i-th character for \a n characters
+        //- Match text
+        //  \return True when strings match literally.
+        inline bool operator()(const std::string& text) const;
+
+        //- Return sub-string from the i-th character for \a n characters
         inline string operator()
         (
             const size_type i,
             const size_type n
         ) const;
 
-        //- Return the sub-string from the first character for \a n characters
+        //- Return sub-string from the first character for \a n characters
         inline string operator()
         (
             const size_type n
diff --git a/src/OpenFOAM/primitives/strings/string/stringI.H b/src/OpenFOAM/primitives/strings/string/stringI.H
index ccd5d29616e1baee69ef287a8b9b0785f0925377..b23a71b2d53e0c7d52c23be2895f09b5eb8a7ac8 100644
--- a/src/OpenFOAM/primitives/strings/string/stringI.H
+++ b/src/OpenFOAM/primitives/strings/string/stringI.H
@@ -178,15 +178,21 @@ inline String Foam::string::validate(const std::string& str)
     return ss;
 }
 
+
 inline bool Foam::string::match(const std::string& text) const
 {
-    // check as string
-    return (text == *this);
+    return !compare(text);  // Always compare as literal string
 }
 
 
 // * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
 
+inline bool Foam::string::operator()(const std::string& text) const
+{
+    return !compare(text);  // Always compare as literal string
+}
+
+
 inline Foam::string Foam::string::operator()
 (
     const size_type i,
@@ -205,11 +211,11 @@ inline Foam::string Foam::string::operator()(const size_type n) const
 
 inline unsigned Foam::string::hash::operator()
 (
-    const string& key,
+    const string& str,
     unsigned seed
 ) const
 {
-    return Hasher(key.data(), key.size(), seed);
+    return Hasher(str.data(), str.size(), seed);
 }
 
 // ************************************************************************* //
diff --git a/src/OpenFOAM/primitives/strings/word/word.H b/src/OpenFOAM/primitives/strings/word/word.H
index 1bc258bac9616738fc7a045b020c78cee85c7e3d..4561292ab9076b66cf60c377b00df8ccf4dbd8a8 100644
--- a/src/OpenFOAM/primitives/strings/word/word.H
+++ b/src/OpenFOAM/primitives/strings/word/word.H
@@ -25,7 +25,7 @@ Class
     Foam::word
 
 Description
-    A class for handling words, derived from string.
+    A class for handling words, derived from Foam::string.
 
     A word is a string of characters without whitespace, quotes, slashes,
     semicolons or brace brackets. Words are delimited by whitespace.
@@ -93,7 +93,7 @@ public:
         inline word
         (
             const char* s,
-            const size_type,
+            const size_type len,
             const bool doStripInvalid
         );
 
@@ -119,12 +119,12 @@ public:
 
     // Member operators
 
-        // Assignment
+      // Assignment
 
-            inline void operator=(const word& w);
-            inline void operator=(const string& s);
-            inline void operator=(const std::string& s);
-            inline void operator=(const char* s);
+        inline void operator=(const word& w);
+        inline void operator=(const string& s);
+        inline void operator=(const std::string& s);
+        inline void operator=(const char* s);
 
 
     // Friend Operators
diff --git a/src/OpenFOAM/primitives/strings/word/wordI.H b/src/OpenFOAM/primitives/strings/word/wordI.H
index e19356f912d57214a5e6665cd9babb702f5cfd26..7f7aa10829b813e04404ccd5fb1e47b8d59aa901 100644
--- a/src/OpenFOAM/primitives/strings/word/wordI.H
+++ b/src/OpenFOAM/primitives/strings/word/wordI.H
@@ -99,11 +99,11 @@ inline Foam::word::word(const char* s, const bool doStripInvalid)
 inline Foam::word::word
 (
     const char* s,
-    const size_type n,
+    const size_type len,
     const bool doStripInvalid
 )
 :
-    string(s, n)
+    string(s, len)
 {
     if (doStripInvalid)
     {
diff --git a/src/OpenFOAM/primitives/strings/wordRe/wordRe.H b/src/OpenFOAM/primitives/strings/wordRe/wordRe.H
index 21eba6421d09bb86c913cc208e34b699af607b1a..ede0a7a047ea7714941da7ef2aae17e7ddd1d789 100644
--- a/src/OpenFOAM/primitives/strings/wordRe/wordRe.H
+++ b/src/OpenFOAM/primitives/strings/wordRe/wordRe.H
@@ -92,15 +92,15 @@ public:
     // Public data types
 
         //- Enumeration with compile options
-        //  Note that 'REGEXP' is implicit if 'NOCASE' is specified alone.
+        //  Note that 'REGEX' is implicit if 'NOCASE' is specified alone.
         enum compOption
         {
             LITERAL = 0, //!< Treat as a string literal
             DETECT  = 1, //!< Detect if the string contains meta-characters
-            REGEXP  = 2, //!< Treat as regular expression
+            REGEX   = 2, //!< Treat as regular expression
             NOCASE  = 4, //!< Ignore case in regular expression
-            DETECT_NOCASE = DETECT | NOCASE,  //!< Combined DETECT and NOCASE
-            REGEXP_NOCASE = REGEXP | NOCASE   //!< Combined REGEXP and NOCASE
+            DETECT_NOCASE = DETECT|NOCASE,  //!< Combined DETECT and NOCASE
+            REGEX_NOCASE  = REGEX|NOCASE    //!< Combined REGEX and NOCASE
         };
 
 
@@ -119,30 +119,35 @@ public:
         //- Construct as copy
         inline wordRe(const wordRe& str);
 
-        //- Construct from keyType
+        //- Construct from keyType, using its compile information
         inline explicit wordRe(const keyType& str);
 
+        //- Construct as copy of character array, treat as a literal
+        inline explicit wordRe(const char* str);
+
+        //- Construct as copy of std::string, treat as a literal
+        inline explicit wordRe(const std::string& str);
+
+        //- Construct as copy of string, treat as a literal
+        inline explicit wordRe(const string& str);
+
+        //- Construct as copy of word, treat as a literal
+        inline explicit wordRe(const word& str);
+
         //- Construct from keyType, use specified compile option
         inline wordRe(const keyType& str, const compOption);
 
-        //- Construct as copy of word
-        inline explicit wordRe(const word& str);
+        //- Construct as copy of character array, use specified compile option
+        inline wordRe(const char* str, const compOption);
 
-        //- Construct as copy of character array
-        //  Optionally specify how it should be treated.
-        inline explicit wordRe(const char* str, const compOption = LITERAL);
+        //- Construct as copy of std::string, use specified compile option
+        inline wordRe(const std::string& str, const compOption);
 
-        //- Construct as copy of string.
-        //  Optionally specify how it should be treated.
-        inline explicit wordRe(const string& str, const compOption = LITERAL);
+        //- Construct as copy of string, use specified compile option
+        inline wordRe(const string& str, const compOption);
 
-        //- Construct as copy of std::string
-        //  Optionally specify how it should be treated.
-        inline explicit wordRe
-        (
-            const std::string& str,
-            const compOption = LITERAL
-        );
+        //- Construct as copy of word, use specified compile option
+        inline wordRe(const word& str, const compOption);
 
         //- Construct from Istream
         //  Words are treated as literals, strings with an auto-test
@@ -200,6 +205,13 @@ public:
 
     // Member operators
 
+        //- Avoid masking the normal operator()
+        using word::operator();
+
+        //- Perform smart match on text, as per match()
+        inline bool operator()(const std::string& text) const;
+
+
       // Assignment
 
         //- Copy wordRe and its type (literal or regex)
diff --git a/src/OpenFOAM/primitives/strings/wordRe/wordReI.H b/src/OpenFOAM/primitives/strings/wordRe/wordReI.H
index 78de818e3afac02ee387498bf1a111ead2f9ac71..b01c590554682b995dbb7236cc7afdd24ab9b346 100644
--- a/src/OpenFOAM/primitives/strings/wordRe/wordReI.H
+++ b/src/OpenFOAM/primitives/strings/wordRe/wordReI.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -48,7 +48,7 @@ inline Foam::wordRe::wordRe()
 
 inline Foam::wordRe::wordRe(const wordRe& str)
 :
-    word(str),
+    word(str, false),
     re_()
 {
     if (str.isPattern())
@@ -58,13 +58,6 @@ inline Foam::wordRe::wordRe(const wordRe& str)
 }
 
 
-inline Foam::wordRe::wordRe(const word& str)
-:
-    word(str),
-    re_()
-{}
-
-
 inline Foam::wordRe::wordRe(const keyType& str)
 :
     word(str, false),
@@ -77,6 +70,34 @@ inline Foam::wordRe::wordRe(const keyType& str)
 }
 
 
+inline Foam::wordRe::wordRe(const char* str)
+:
+    word(str, false),
+    re_()
+{}
+
+
+inline Foam::wordRe::wordRe(const std::string& str)
+:
+    word(str, false),
+    re_()
+{}
+
+
+inline Foam::wordRe::wordRe(const string& str)
+:
+    word(str, false),
+    re_()
+{}
+
+
+inline Foam::wordRe::wordRe(const word& str)
+:
+    word(str, false),
+    re_()
+{}
+
+
 inline Foam::wordRe::wordRe(const keyType& str, const compOption opt)
 :
     word(str, false),
@@ -91,8 +112,15 @@ inline Foam::wordRe::wordRe(const keyType& str, const compOption opt)
 
 inline Foam::wordRe::wordRe(const char* str, const compOption opt)
 :
-    word(str, false),
-    re_()
+    wordRe(str)
+{
+    compile(opt);
+}
+
+
+inline Foam::wordRe::wordRe(const std::string& str, const compOption opt)
+:
+    wordRe(str)
 {
     compile(opt);
 }
@@ -100,17 +128,15 @@ inline Foam::wordRe::wordRe(const char* str, const compOption opt)
 
 inline Foam::wordRe::wordRe(const string& str, const compOption opt)
 :
-    word(str, false),
-    re_()
+    wordRe(str)
 {
     compile(opt);
 }
 
 
-inline Foam::wordRe::wordRe(const std::string& str, const compOption opt)
+inline Foam::wordRe::wordRe(const word& str, const compOption opt)
 :
-    word(str, false),
-    re_()
+    wordRe(str)
 {
     compile(opt);
 }
@@ -126,42 +152,38 @@ inline bool Foam::wordRe::isPattern() const
 
 inline bool Foam::wordRe::compile(const compOption opt) const
 {
-    bool doCompile = false;
-
-    if (opt & wordRe::REGEXP)
+    if (opt)
     {
-        doCompile = true;
-    }
-    else if (opt & wordRe::DETECT)
-    {
-        if (string::meta<regExp>(*this) || !string::valid<word>(*this))
+        bool comp = false;
+
+        if (opt & wordRe::REGEX)
         {
-            doCompile = true;
+            comp = true;
+        }
+        else if (opt & wordRe::DETECT)
+        {
+            comp = string::meta<regExp>(*this) || !string::valid<word>(*this);
+        }
+        else if (opt & wordRe::NOCASE)
+        {
+            comp = true;
         }
-    }
-    else if (opt & wordRe::NOCASE)
-    {
-        doCompile = true;
-    }
-
 
-    if (doCompile)
-    {
-        re_.set(*this, (opt & wordRe::NOCASE));
-    }
-    else
-    {
-        re_.clear();
+        if (comp)
+        {
+            return re_.set(*this, (opt & wordRe::NOCASE));
+        }
     }
 
-    return re_.exists();
+    // Fall-through behaviour - not a regex
+    re_.clear();
+    return false;
 }
 
 
 inline bool Foam::wordRe::compile() const
 {
-    re_ = *this;
-    return re_.exists();
+    return re_.set(*this);
 }
 
 
@@ -169,7 +191,7 @@ inline void Foam::wordRe::uncompile(const bool doStripInvalid) const
 {
     if (re_.clear() && doStripInvalid)
     {
-        // skip stripping unless debug is active to avoid costly operations
+        // Skip stripping unless debug is active to avoid costly operations
         if (word::debug)
         {
             string::stripInvalid<word>
@@ -192,13 +214,11 @@ inline bool Foam::wordRe::match(const std::string& text, bool literal) const
 {
     if (literal || !re_.exists())
     {
-        // check as string
-        return (text == *this);
+        return !compare(text);  // Compare as literal string
     }
     else
     {
-        // check as regex
-        return re_.match(text);
+        return re_.match(text); // Match as regex
     }
 }
 
@@ -225,6 +245,12 @@ inline void Foam::wordRe::set(const char* str, const compOption opt)
 
 // * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
 
+inline bool Foam::wordRe::operator()(const std::string& text) const
+{
+    return match(text);
+}
+
+
 inline void Foam::wordRe::operator=(const wordRe& str)
 {
     string::operator=(str);
@@ -263,21 +289,21 @@ inline void Foam::wordRe::operator=(const keyType& str)
 inline void Foam::wordRe::operator=(const string& str)
 {
     string::operator=(str);
-    compile(wordRe::DETECT);  // auto-detect regex
+    compile(wordRe::DETECT);  // Auto-detect regex
 }
 
 
 inline void Foam::wordRe::operator=(const std::string& str)
 {
     string::operator=(str);
-    compile(wordRe::DETECT);  // auto-detect regex
+    compile(wordRe::DETECT);  // Auto-detect regex
 }
 
 
 inline void Foam::wordRe::operator=(const char* str)
 {
     string::operator=(str);
-    compile(wordRe::DETECT);  // auto-detect regex
+    compile(wordRe::DETECT);  // Auto-detect regex
 }
 
 
diff --git a/src/OpenFOAM/primitives/strings/wordRes/wordReListMatcher.H b/src/OpenFOAM/primitives/strings/wordRes/wordReListMatcher.H
new file mode 100644
index 0000000000000000000000000000000000000000..b7b63a5680ee48b56bda0aebdd2abbe1c8964a73
--- /dev/null
+++ b/src/OpenFOAM/primitives/strings/wordRes/wordReListMatcher.H
@@ -0,0 +1,51 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2017 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Typedef
+    Foam::wordReListMatcher
+
+Description
+    The older name for Foam::wordRes, which is a wrapper for matching
+    a std::string against wordRe list.
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef wordReListMatcher_H
+#define wordReListMatcher_H
+
+#include "wordRes.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+     typedef wordRes wordReListMatcher;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/primitives/strings/lists/wordReListMatcher.C b/src/OpenFOAM/primitives/strings/wordRes/wordRes.C
similarity index 89%
rename from src/OpenFOAM/primitives/strings/lists/wordReListMatcher.C
rename to src/OpenFOAM/primitives/strings/wordRes/wordRes.C
index 1a24dcbbb1949e1f8902c97e90f0e6aa4d13b017..3f53f6492ff3a0b8909add61b50f5911cec516a5 100644
--- a/src/OpenFOAM/primitives/strings/lists/wordReListMatcher.C
+++ b/src/OpenFOAM/primitives/strings/wordRes/wordRes.C
@@ -23,17 +23,17 @@ License
 
 \*---------------------------------------------------------------------------*/
 
-#include "wordReListMatcher.H"
+#include "wordRes.H"
 #include "HashSet.H"
 
 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
 
-Foam::wordReList Foam::wordReListMatcher::uniq(const UList<wordRe>& input)
+Foam::wordReList Foam::wordRes::uniq(const UList<wordRe>& input)
 {
     wordReList retain(input.size());
     wordHashSet uniqWord;
 
-    label nUniq = 0;
+    label count = 0;
     forAll(input, i)
     {
         const wordRe& select = input[i];
@@ -44,11 +44,11 @@ Foam::wordReList Foam::wordReListMatcher::uniq(const UList<wordRe>& input)
          || uniqWord.insert(static_cast<const word&>(select))
         )
         {
-            retain[nUniq++] = select;
+            retain[count++] = select;
         }
     }
 
-    retain.setSize(nUniq);
+    retain.setSize(count);
     return retain;
 }
 
diff --git a/src/OpenFOAM/primitives/strings/lists/wordReListMatcher.H b/src/OpenFOAM/primitives/strings/wordRes/wordRes.H
similarity index 57%
rename from src/OpenFOAM/primitives/strings/lists/wordReListMatcher.H
rename to src/OpenFOAM/primitives/strings/wordRes/wordRes.H
index 1f5785d3e493bd1effa133076d9804c171974107..5cfe6b9b5758ca341ce4db9b96cd5d16b241700e 100644
--- a/src/OpenFOAM/primitives/strings/lists/wordReListMatcher.H
+++ b/src/OpenFOAM/primitives/strings/wordRes/wordRes.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -22,23 +22,23 @@ License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
 Class
-    Foam::wordReListMatcher
+    Foam::wordRes
 
 Description
-    A wrapper for matching a List of wordRe.
+    A wrapper for matching a std::string against a wordRe list.
 
 Note
     The constructor should remain non-explicit. This allows automatic
-    conversion from UList\<wordRe\> to wordReListMatcher in search
-    functions.
+    conversion from UList\<wordRe\> to wordRes in search functions.
 
 SourceFiles
-    wordReListMatcherI.H
+    wordResI.H
+    wordRes.C
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef wordReListMatcher_H
-#define wordReListMatcher_H
+#ifndef wordRes_H
+#define wordRes_H
 
 #include "wordReList.H"
 
@@ -48,48 +48,70 @@ namespace Foam
 {
 
 /*---------------------------------------------------------------------------*\
-                      Class wordReListMatcher Declaration
+                           Class wordRes Declaration
 \*---------------------------------------------------------------------------*/
 
-class wordReListMatcher
+class wordRes
 {
     // Private data
 
         //- Reference to underlying list
-        const UList<wordRe>& reList_;
+        const UList<wordRe>& list_;
 
 public:
 
+    // STL type definitions
+
+        //- Type of values the list contains
+        typedef wordRe value_type;
+
+
     // Constructors
 
-        //- Construct from a List of wordRe
-        inline wordReListMatcher(const UList<wordRe>&);
+        //- Construct from a list of wordRe
+        inline wordRes(const UList<wordRe>& list);
+
+
+    // Static Constructors, Helpers
+
+        //- Return a wordReList with duplicate words filtered out.
+        //  No filtering is done on regular expressions.
+        static wordReList uniq(const UList<wordRe>& input);
 
 
     // Member Functions
 
       // Access
 
+        //- The number of elements in the list
         inline label size() const;
-        inline bool  empty() const;
 
-        //- Return underlying list of wordRe
-        inline const UList<wordRe>& operator()() const;
+        //- True if the list is empty
+        inline bool empty() const;
+
 
+      // Searching
 
-     // Searching
+        //- Return true if string matches any of the regular expressions
+        //  Smart match as regular expression or as a string.
+        //  Optionally specify a literal match only.
+        inline bool match
+        (
+            const std::string& text,
+            const bool literal = false
+        ) const;
 
-       //- Return true if string matches any of the regular expressions
-       //  Smart match as regular expression or as a string.
-       //  Optionally specify a literal match only.
-       inline bool match(const std::string&, bool literalMatch=false) const;
 
+    // Member operators
+
+        //- Return underlying list of wordRe
+        inline const UList<wordRe>& operator()() const;
 
-     // Helpers
+        //- Perform smart match on text, as per match()
+        inline bool operator()(const std::string& text) const;
 
-       //- Return a wordReList with duplicate words filtered out.
-       //  No filtering is done on regular expressions.
-       static wordReList uniq(const UList<wordRe>& input);
+        //- Return element of constant list
+        inline const wordRe& operator[](const label i) const;
 
 };
 
@@ -100,7 +122,7 @@ public:
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-#include "wordReListMatcherI.H"
+#include "wordResI.H"
 
 #endif
 
diff --git a/src/OpenFOAM/primitives/strings/lists/wordReListMatcherI.H b/src/OpenFOAM/primitives/strings/wordRes/wordResI.H
similarity index 67%
rename from src/OpenFOAM/primitives/strings/lists/wordReListMatcherI.H
rename to src/OpenFOAM/primitives/strings/wordRes/wordResI.H
index d4b3c7dce23f9747d68055548187e2b10c8910f3..600c228340d80851c6b96be1c57cde3648d387ce 100644
--- a/src/OpenFOAM/primitives/strings/lists/wordReListMatcherI.H
+++ b/src/OpenFOAM/primitives/strings/wordRes/wordResI.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -26,46 +26,40 @@ License
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-inline Foam::wordReListMatcher::wordReListMatcher
+inline Foam::wordRes::wordRes
 (
-    const UList<wordRe>& lst
+    const UList<wordRe>& list
 )
 :
-    reList_(lst)
+    list_(list)
 {}
 
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-inline Foam::label Foam::wordReListMatcher::size() const
+inline Foam::label Foam::wordRes::size() const
 {
-    return reList_.size();
+    return list_.size();
 }
 
 
-inline bool Foam::wordReListMatcher::empty() const
+inline bool Foam::wordRes::empty() const
 {
-    return reList_.empty();
+    return list_.empty();
 }
 
 
-inline const Foam::UList<Foam::wordRe>&
-Foam::wordReListMatcher::operator()() const
-{
-    return reList_;
-}
-
-
-inline bool Foam::wordReListMatcher::match
+inline bool Foam::wordRes::match
 (
     const std::string& text,
-    bool literalMatch
+    const bool literal
 ) const
 {
-    const label n = reList_.size();
+    const label n = list_.size();
+
     for (label i = 0; i < n; ++i)
     {
-        if (reList_[i].match(text, literalMatch))
+        if (list_[i].match(text, literal))
         {
             return true;
         }
@@ -75,4 +69,24 @@ inline bool Foam::wordReListMatcher::match
 }
 
 
+// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+
+inline const Foam::UList<Foam::wordRe>& Foam::wordRes::operator()() const
+{
+    return list_;
+}
+
+
+inline bool Foam::wordRes::operator()(const std::string& text) const
+{
+    return match(text);
+}
+
+
+inline const Foam::wordRe& Foam::wordRes::operator[](const label i) const
+{
+    return list_[i];
+}
+
+
 // ************************************************************************* //
diff --git a/src/conversion/ensight/mesh/ensightMesh.C b/src/conversion/ensight/mesh/ensightMesh.C
index b769c2b154e5581930fd798f85c4df3f6474fdf7..5a541f79fbb26567c3b4ae59b3781aecc914de26 100644
--- a/src/conversion/ensight/mesh/ensightMesh.C
+++ b/src/conversion/ensight/mesh/ensightMesh.C
@@ -151,7 +151,7 @@ void Foam::ensightMesh::correct()
                 useAll = false;
                 matched = findMatchingStrings
                 (
-                    wordReListMatcher(matcher),
+                    wordRes(matcher),
                     patchNames
                 );
             }
@@ -250,7 +250,7 @@ void Foam::ensightMesh::correct()
         wordList selectZones = mesh_.faceZones().names();
         inplaceSubsetMatchingStrings
         (
-            wordReListMatcher(matcher),
+            wordRes(matcher),
             selectZones
         );
 
diff --git a/src/functionObjects/field/ddt2/ddt2.C b/src/functionObjects/field/ddt2/ddt2.C
index 08c23fd42f000a65da79d733ebb40902263bc4e9..859e4f627610f9c1151798a31b7ce0d985b094ba 100644
--- a/src/functionObjects/field/ddt2/ddt2.C
+++ b/src/functionObjects/field/ddt2/ddt2.C
@@ -27,7 +27,7 @@ License
 
 #include "volFields.H"
 #include "dictionary.H"
-#include "wordReListMatcher.H"
+#include "wordRes.H"
 #include "steadyStateDdtScheme.H"
 #include "addToRunTimeSelectionTable.H"
 
@@ -142,7 +142,7 @@ bool Foam::functionObjects::ddt2::read(const dictionary& dict)
         return false;
     }
 
-    selectFields_ = wordReListMatcher::uniq
+    selectFields_ = wordRes::uniq
     (
         wordReList(dict.lookup("fields"))
     );
diff --git a/src/functionObjects/field/zeroGradient/zeroGradient.C b/src/functionObjects/field/zeroGradient/zeroGradient.C
index dedde1fe994816cacd52731038107f08ddc0ac98..97a07cdfaf71072defbca47f221c737b0e46b250 100644
--- a/src/functionObjects/field/zeroGradient/zeroGradient.C
+++ b/src/functionObjects/field/zeroGradient/zeroGradient.C
@@ -27,7 +27,7 @@ License
 
 #include "volFields.H"
 #include "dictionary.H"
-#include "wordReListMatcher.H"
+#include "wordRes.H"
 #include "addToRunTimeSelectionTable.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@@ -120,7 +120,7 @@ bool Foam::functionObjects::zeroGradient::read(const dictionary& dict)
 {
     fvMeshFunctionObject::read(dict);
 
-    selectFields_ = wordReListMatcher::uniq
+    selectFields_ = wordRes::uniq
     (
         wordReList(dict.lookup("fields"))
     );
diff --git a/src/functionObjects/graphics/runTimePostProcessing/fieldVisualisationBase.C b/src/functionObjects/graphics/runTimePostProcessing/fieldVisualisationBase.C
index 084bcc1e99b20ed9e36f3d6e045a6d506f281112..1bd8614b6889766d77889416a8ad35db89c11740 100644
--- a/src/functionObjects/graphics/runTimePostProcessing/fieldVisualisationBase.C
+++ b/src/functionObjects/graphics/runTimePostProcessing/fieldVisualisationBase.C
@@ -480,8 +480,7 @@ void Foam::functionObjects::fieldVisualisationBase::addGlyphs
     else
     {
         WarningInFunction
-            << "Glyphs can only be added to " << pTraits<scalar>::typeName
-            << " and " << pTraits<vector>::typeName << " fields. "
+            << "Glyphs can only be added to scalar and vector fields."
             << " Field " << scaleFieldName << " has " << nComponents
             << " components" << endl;
 
diff --git a/src/sampling/probes/probes.H b/src/sampling/probes/probes.H
index 28a7ac2e24dbc753f24eafab13292fb38261fa76..8feb83a229abdabd77f67577b47ecd80eacee9c9 100644
--- a/src/sampling/probes/probes.H
+++ b/src/sampling/probes/probes.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -133,45 +133,46 @@ protected:
         //- Load fields from files (not from objectRegistry)
         bool loadFromFiles_;
 
-        // Read from dictonary
 
-            //- Names of fields to probe
-            wordReList fieldSelection_;
+      // Read from dictonary
 
-            //- Fixed locations, default = yes
-            //  Note: set to false for moving mesh calculations where locations
-            //        should move with the mesh
-            bool fixedLocations_;
+        //- Names of fields to probe
+        wordReList fieldSelection_;
 
-            //- Interpolation scheme name
-            //  Note: only possible when fixedLocations_ is true
-            word interpolationScheme_;
+        //- Fixed locations, default = yes
+        //  Note: set to false for moving mesh calculations where locations
+        //        should move with the mesh
+        bool fixedLocations_;
 
+        //- Interpolation scheme name
+        //  Note: only possible when fixedLocations_ is true
+        word interpolationScheme_;
 
-        // Calculated
 
-            //- Categorized scalar/vector/tensor vol fields
-            fieldGroup<scalar> scalarFields_;
-            fieldGroup<vector> vectorFields_;
-            fieldGroup<sphericalTensor> sphericalTensorFields_;
-            fieldGroup<symmTensor> symmTensorFields_;
-            fieldGroup<tensor> tensorFields_;
+      // Calculated
 
-            //- Categorized scalar/vector/tensor surf fields
-            fieldGroup<scalar> surfaceScalarFields_;
-            fieldGroup<vector> surfaceVectorFields_;
-            fieldGroup<sphericalTensor> surfaceSphericalTensorFields_;
-            fieldGroup<symmTensor> surfaceSymmTensorFields_;
-            fieldGroup<tensor> surfaceTensorFields_;
+        //- Categorized scalar/vector/tensor vol fields
+        fieldGroup<scalar> scalarFields_;
+        fieldGroup<vector> vectorFields_;
+        fieldGroup<sphericalTensor> sphericalTensorFields_;
+        fieldGroup<symmTensor> symmTensorFields_;
+        fieldGroup<tensor> tensorFields_;
 
-            // Cells to be probed (obtained from the locations)
-            labelList elementList_;
+        //- Categorized scalar/vector/tensor surf fields
+        fieldGroup<scalar> surfaceScalarFields_;
+        fieldGroup<vector> surfaceVectorFields_;
+        fieldGroup<sphericalTensor> surfaceSphericalTensorFields_;
+        fieldGroup<symmTensor> surfaceSymmTensorFields_;
+        fieldGroup<tensor> surfaceTensorFields_;
 
-            // Faces to be probed
-            labelList faceList_;
+        // Cells to be probed (obtained from the locations)
+        labelList elementList_;
 
-            //- Current open files
-            HashPtrTable<OFstream> probeFilePtrs_;
+        // Faces to be probed
+        labelList faceList_;
+
+        //- Current open files
+        HashPtrTable<OFstream> probeFilePtrs_;
 
 
     // Protected Member Functions
@@ -179,16 +180,13 @@ protected:
         //- Clear old field groups
         void clearFieldGroups();
 
-        //- Append fieldName to the appropriate group
-        label appendFieldGroup(const word& fieldName, const word& fieldType);
-
         //- Classify field types, returns the number of fields
         label classifyFields();
 
         //- Find cells and faces containing probes
-        virtual void findElements(const fvMesh&);
+        virtual void findElements(const fvMesh& mesh);
 
-        //- Classify field type and Open/close file streams,
+        //- Classify field type and open/close file streams,
         //  returns number of fields to sample
         label prepare();
 
@@ -219,10 +217,10 @@ private:
         void sampleAndWriteSurfaceFields(const fieldGroup<Type>&);
 
         //- Disallow default bitwise copy construct
-        probes(const probes&);
+        probes(const probes&) = delete;
 
         //- Disallow default bitwise assignment
-        void operator=(const probes&);
+        void operator=(const probes&) = delete;
 
 
 public:
diff --git a/src/sampling/probes/probesGrouping.C b/src/sampling/probes/probesGrouping.C
index 5d228f1152d7e5820596ed41efdee43497d300ae..946cc93d30450d18326407f587ac0695b7c6de06 100644
--- a/src/sampling/probes/probesGrouping.C
+++ b/src/sampling/probes/probesGrouping.C
@@ -47,106 +47,74 @@ void Foam::probes::clearFieldGroups()
 }
 
 
-Foam::label Foam::probes::appendFieldGroup
-(
-    const word& fieldName,
-    const word& fieldType
-)
-{
-    if (fieldType == volScalarField::typeName)
-    {
-        scalarFields_.append(fieldName);
-        return 1;
-    }
-    else if (fieldType == volVectorField::typeName)
-    {
-        vectorFields_.append(fieldName);
-        return 1;
-    }
-    else if (fieldType == volSphericalTensorField::typeName)
-    {
-        sphericalTensorFields_.append(fieldName);
-        return 1;
-    }
-    else if (fieldType == volSymmTensorField::typeName)
-    {
-        symmTensorFields_.append(fieldName);
-        return 1;
-    }
-    else if (fieldType == volTensorField::typeName)
-    {
-        tensorFields_.append(fieldName);
-        return 1;
-    }
-    else if (fieldType == surfaceScalarField::typeName)
-    {
-        surfaceScalarFields_.append(fieldName);
-        return 1;
-    }
-    else if (fieldType == surfaceVectorField::typeName)
-    {
-        surfaceVectorFields_.append(fieldName);
-        return 1;
-    }
-    else if (fieldType == surfaceSphericalTensorField::typeName)
-    {
-        surfaceSphericalTensorFields_.append(fieldName);
-        return 1;
-    }
-    else if (fieldType == surfaceSymmTensorField::typeName)
-    {
-        surfaceSymmTensorFields_.append(fieldName);
-        return 1;
-    }
-    else if (fieldType == surfaceTensorField::typeName)
-    {
-        surfaceTensorFields_.append(fieldName);
-        return 1;
-    }
-
-    return 0;
-}
-
-
 Foam::label Foam::probes::classifyFields()
 {
     label nFields = 0;
     clearFieldGroups();
 
-    if (loadFromFiles_)
+    HashTable<wordHashSet> available =
+    (
+        loadFromFiles_
+      ? IOobjectList(mesh_, mesh_.time().timeName()).classes(fieldSelection_)
+      : mesh_.classes(fieldSelection_)
+    );
+
+    forAllConstIters(available, iter)
     {
-        // Check files for a particular time
-        IOobjectList objects(mesh_, mesh_.time().timeName());
-        wordList allFields = objects.sortedNames();
+        const word& fieldType = iter.key();
+        const wordList fieldNames = iter.object().sortedToc();
 
-        labelList indices = findStrings(fieldSelection_, allFields);
+        const label count = fieldNames.size(); // pre-filtered, so non-empty
 
-        forAll(indices, fieldi)
+        if (fieldType == volScalarField::typeName)
         {
-            const word& fieldName = allFields[indices[fieldi]];
-
-            nFields += appendFieldGroup
-            (
-                fieldName,
-                objects.find(fieldName)()->headerClassName()
-            );
+            scalarFields_.append(fieldNames);
+            nFields += count;
         }
-    }
-    else
-    {
-        // Check currently available fields
-        wordList allFields = mesh_.sortedNames();
-        labelList indices = findStrings(fieldSelection_, allFields);
-
-        forAll(indices, fieldi)
+        else if (fieldType == volVectorField::typeName)
         {
-            const word& fieldName = allFields[indices[fieldi]];
-
-            nFields += appendFieldGroup
-            (
-                fieldName,
-                mesh_.find(fieldName)()->type()
-            );
+            vectorFields_.append(fieldNames);
+            nFields += count;
+        }
+        else if (fieldType == volSphericalTensorField::typeName)
+        {
+            sphericalTensorFields_.append(fieldNames);
+            nFields += count;
+        }
+        else if (fieldType == volSymmTensorField::typeName)
+        {
+            symmTensorFields_.append(fieldNames);
+            nFields += count;
+        }
+        else if (fieldType == volTensorField::typeName)
+        {
+            tensorFields_.append(fieldNames);
+            nFields += count;
+        }
+        else if (fieldType == surfaceScalarField::typeName)
+        {
+            surfaceScalarFields_.append(fieldNames);
+            nFields += count;
+        }
+        else if (fieldType == surfaceVectorField::typeName)
+        {
+            surfaceVectorFields_.append(fieldNames);
+            nFields += count;
+        }
+        else if (fieldType == surfaceSphericalTensorField::typeName)
+        {
+            surfaceSphericalTensorFields_.append(fieldNames);
+            nFields += count;
+        }
+        else if (fieldType == surfaceSymmTensorField::typeName)
+        {
+            surfaceSymmTensorFields_.append(fieldNames);
+            nFields += count;
+        }
+        else if (fieldType == surfaceTensorField::typeName)
+        {
+            surfaceTensorFields_.append(fieldNames);
+            nFields += count;
         }
     }
 
diff --git a/src/sampling/sampledSet/sampledSets/sampledSets.H b/src/sampling/sampledSet/sampledSets/sampledSets.H
index 20d8b3c5769591a912fab619cd9c876a9b3f443c..4f64c305fc4a391b066341bb72cd0bbe02b5d684 100644
--- a/src/sampling/sampledSet/sampledSets/sampledSets.H
+++ b/src/sampling/sampledSet/sampledSets/sampledSets.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2015-2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2015-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -104,7 +104,6 @@ class sampledSets
             {
                 formatter = writer<Type>::New(writeFormat);
             }
-
         };
 
 
@@ -173,31 +172,31 @@ class sampledSets
         meshSearch searchEngine_;
 
 
-        // Read from dictonary
+      // Read from dictonary
 
-            //- Names of fields to sample
-            wordReList fieldSelection_;
+        //- Names of fields to sample
+        wordReList fieldSelection_;
 
-            //- Interpolation scheme to use
-            word interpolationScheme_;
+        //- Interpolation scheme to use
+        word interpolationScheme_;
 
-            //- Output format to use
-            word writeFormat_;
+        //- Output format to use
+        word writeFormat_;
 
 
-        // Categorized scalar/vector/tensor fields
+      // Categorized scalar/vector/tensor fields
 
-            fieldGroup<scalar> scalarFields_;
-            fieldGroup<vector> vectorFields_;
-            fieldGroup<sphericalTensor> sphericalTensorFields_;
-            fieldGroup<symmTensor> symmTensorFields_;
-            fieldGroup<tensor> tensorFields_;
+        fieldGroup<scalar> scalarFields_;
+        fieldGroup<vector> vectorFields_;
+        fieldGroup<sphericalTensor> sphericalTensorFields_;
+        fieldGroup<symmTensor> symmTensorFields_;
+        fieldGroup<tensor> tensorFields_;
 
 
-        // Merging structures
+      // Merging structures
 
-            PtrList<coordSet> masterSampledSets_;
-            labelListList indexSets_;
+        PtrList<coordSet> masterSampledSets_;
+        labelListList indexSets_;
 
 
     // Private Member Functions
@@ -205,9 +204,6 @@ class sampledSets
         //- Clear old field groups
         void clearFieldGroups();
 
-        //- Append fieldName to the appropriate group
-        label appendFieldGroup(const word& fieldName, const word& fieldType);
-
         //- Classify field types, returns the number of fields
         label classifyFields();
 
@@ -245,8 +241,8 @@ class sampledSets
 
 
         //- Disallow default bitwise copy construct and assignment
-        sampledSets(const sampledSets&);
-        void operator=(const sampledSets&);
+        sampledSets(const sampledSets&) = delete;
+        void operator=(const sampledSets&) = delete;
 
 
 public:
diff --git a/src/sampling/sampledSet/sampledSets/sampledSetsGrouping.C b/src/sampling/sampledSet/sampledSets/sampledSetsGrouping.C
index bdf8c18581e3b2f8e73a9cd0e897fead0cb74e0e..4d57af3ebeedba025984cae070dd916a63ea3c88 100644
--- a/src/sampling/sampledSet/sampledSets/sampledSetsGrouping.C
+++ b/src/sampling/sampledSet/sampledSets/sampledSetsGrouping.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -27,6 +27,7 @@ License
 #include "volFields.H"
 #include "IOobjectList.H"
 #include "stringListOps.H"
+#include "UIndirectList.H"
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
@@ -40,107 +41,81 @@ void Foam::sampledSets::clearFieldGroups()
 }
 
 
-Foam::label Foam::sampledSets::appendFieldGroup
-(
-    const word& fieldName,
-    const word& fieldType
-)
-{
-    if (fieldType == volScalarField::typeName)
-    {
-        scalarFields_.append(fieldName);
-        return 1;
-    }
-    else if (fieldType == volVectorField::typeName)
-    {
-        vectorFields_.append(fieldName);
-        return 1;
-    }
-    else if (fieldType == volSphericalTensorField::typeName)
-    {
-        sphericalTensorFields_.append(fieldName);
-        return 1;
-    }
-    else if (fieldType == volSymmTensorField::typeName)
-    {
-        symmTensorFields_.append(fieldName);
-        return 1;
-    }
-    else if (fieldType == volTensorField::typeName)
-    {
-        tensorFields_.append(fieldName);
-        return 1;
-    }
-
-    return 0;
-}
-
-
 Foam::label Foam::sampledSets::classifyFields()
 {
     label nFields = 0;
     clearFieldGroups();
 
+    wordList allFields;    // Just needed for warnings
+    HashTable<wordHashSet> available;
+
     if (loadFromFiles_)
     {
         // Check files for a particular time
         IOobjectList objects(mesh_, mesh_.time().timeName());
-        wordList allFields = objects.sortedNames();
 
-        forAll(fieldSelection_, i)
-        {
-            labelList indices = findStrings(fieldSelection_[i], allFields);
-
-            if (indices.size())
-            {
-                forAll(indices, fieldi)
-                {
-                    const word& fieldName = allFields[indices[fieldi]];
-
-                    nFields += appendFieldGroup
-                    (
-                        fieldName,
-                        objects.find(fieldName)()->headerClassName()
-                    );
-                }
-            }
-            else
-            {
-                WarningInFunction
-                    << "Cannot find field file matching "
-                    << fieldSelection_[i] << endl;
-            }
-        }
+        allFields = objects.names();
+        available = objects.classes(fieldSelection_);
     }
     else
     {
         // Check currently available fields
-        wordList allFields = mesh_.sortedNames();
-        labelList indices = findStrings(fieldSelection_, allFields);
+        allFields = mesh_.names();
+        available = mesh_.classes(fieldSelection_);
+    }
+
+    DynamicList<label> missed(fieldSelection_.size());
 
-        forAll(fieldSelection_, i)
+    // Detect missing fields
+    forAll(fieldSelection_, i)
+    {
+        if (findStrings(fieldSelection_[i], allFields).empty())
+        {
+            missed.append(i);
+        }
+    }
+
+    if (missed.size())
+    {
+        WarningInFunction
+            << nl
+            << "Cannot find "
+            << (loadFromFiles_ ? "field file" : "registered field")
+            << " matching "
+            << UIndirectList<wordRe>(fieldSelection_, missed) << endl;
+    }
+
+    forAllConstIters(available, iter)
+    {
+        const word& fieldType = iter.key();
+        const wordList fieldNames = iter.object().sortedToc();
+
+        const label count = fieldNames.size(); // pre-filtered, so non-empty
+
+        if (fieldType == volScalarField::typeName)
+        {
+            scalarFields_.append(fieldNames);
+            nFields += count;
+        }
+        else if (fieldType == volVectorField::typeName)
+        {
+            vectorFields_.append(fieldNames);
+            nFields += count;
+        }
+        else if (fieldType == volSphericalTensorField::typeName)
+        {
+            sphericalTensorFields_.append(fieldNames);
+            nFields += count;
+        }
+        else if (fieldType == volSymmTensorField::typeName)
+        {
+            symmTensorFields_.append(fieldNames);
+            nFields += count;
+        }
+        else if (fieldType == volTensorField::typeName)
         {
-            labelList indices = findStrings(fieldSelection_[i], allFields);
-
-            if (indices.size())
-            {
-                forAll(indices, fieldi)
-                {
-                    const word& fieldName = allFields[indices[fieldi]];
-
-                    nFields += appendFieldGroup
-                    (
-                        fieldName,
-                        mesh_.find(fieldName)()->type()
-                    );
-                }
-            }
-            else
-            {
-                WarningInFunction
-                    << "Cannot find registered field matching "
-                    << fieldSelection_[i] << endl;
-            }
+            tensorFields_.append(fieldNames);
+            nFields += count;
         }
     }
 
diff --git a/src/sampling/sampledSurface/sampledSurfaces/sampledSurfacesGrouping.C b/src/sampling/sampledSurface/sampledSurfaces/sampledSurfacesGrouping.C
index 143837a4eb3294936e916089e57103e155b95bd8..233bb65e1046e7e6671ba28e9bb170ed78c88e8e 100644
--- a/src/sampling/sampledSurface/sampledSurfaces/sampledSurfacesGrouping.C
+++ b/src/sampling/sampledSurface/sampledSurfaces/sampledSurfacesGrouping.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2015 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -24,9 +24,9 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "sampledSurfaces.H"
-#include "volFields.H"
 #include "IOobjectList.H"
 #include "stringListOps.H"
+#include "UIndirectList.H"
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
@@ -34,50 +34,52 @@ Foam::label Foam::sampledSurfaces::classifyFields()
 {
     label nFields = 0;
 
+    wordList allFields;    // Just needed for warnings
+    HashTable<wordHashSet> available;
+
     if (loadFromFiles_)
     {
         // Check files for a particular time
         IOobjectList objects(obr_, obr_.time().timeName());
-        wordList allFields = objects.sortedNames();
 
-        forAll(fieldSelection_, i)
-        {
-            labelList indices = findStrings(fieldSelection_[i], allFields);
-
-            if (indices.size())
-            {
-                nFields += indices.size();
-            }
-            else
-            {
-                WarningInFunction
-                    << "Cannot find field file matching "
-                    << fieldSelection_[i] << endl;
-            }
-        }
+        allFields = objects.names();
+        available = objects.classes(fieldSelection_);
     }
     else
     {
         // Check currently available fields
-        wordList allFields = obr_.sortedNames();
+        allFields = obr_.names();
+        available = obr_.classes(fieldSelection_);
+    }
 
-        forAll(fieldSelection_, i)
+    DynamicList<label> missed(fieldSelection_.size());
+
+    // Detect missing fields
+    forAll(fieldSelection_, i)
+    {
+        if (findStrings(fieldSelection_[i], allFields).empty())
         {
-            labelList indices = findStrings(fieldSelection_[i], allFields);
-
-            if (indices.size())
-            {
-                nFields += indices.size();
-            }
-            else
-            {
-                WarningInFunction
-                    << "Cannot find registered field matching "
-                    << fieldSelection_[i] << endl;
-            }
+            missed.append(i);
         }
     }
 
+    if (missed.size())
+    {
+        WarningInFunction
+            << nl
+            << "Cannot find "
+            << (loadFromFiles_ ? "field file" : "registered field")
+            << " matching "
+            << UIndirectList<wordRe>(fieldSelection_, missed) << endl;
+    }
+
+
+    // Total number selected
+    forAllConstIters(available, iter)
+    {
+        nFields += iter.object().size();
+    }
+
     return nFields;
 }
 
diff --git a/src/sampling/surfMeshSampler/surfMeshSamplers/surfMeshSamplers.C b/src/sampling/surfMeshSampler/surfMeshSamplers/surfMeshSamplers.C
index 1ac7008f498bee9ebe534da721b978c33502a227..bf4dea789a0dbfd656938145156a2a32bf4f5a6e 100644
--- a/src/sampling/surfMeshSampler/surfMeshSamplers/surfMeshSamplers.C
+++ b/src/sampling/surfMeshSampler/surfMeshSamplers/surfMeshSamplers.C
@@ -31,7 +31,7 @@ License
 #include "volPointInterpolation.H"
 #include "PatchTools.H"
 #include "mapPolyMesh.H"
-#include "wordReListMatcher.H"
+#include "wordRes.H"
 #include "addToRunTimeSelectionTable.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@@ -268,7 +268,7 @@ bool Foam::surfMeshSamplers::write()
     }
 
     // avoid duplicate entries
-    select = wordReListMatcher::uniq(select);
+    select = wordRes::uniq(select);
 
     forAll(*this, surfI)
     {
@@ -290,7 +290,7 @@ bool Foam::surfMeshSamplers::read(const dictionary& dict)
 
     if (dict.found("surfaces"))
     {
-        fieldSelection_ = wordReListMatcher::uniq
+        fieldSelection_ = wordRes::uniq
         (
             wordReList(dict.lookup("fields"))
         );