diff --git a/applications/test/checkDecomposePar/Make/files b/applications/test/checkDecomposePar/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..512f2b1736000a070b0ba83547e9a8df4e62f69b
--- /dev/null
+++ b/applications/test/checkDecomposePar/Make/files
@@ -0,0 +1,3 @@
+Test-checkDecomposePar.C
+
+EXE = $(FOAM_APPBIN)/Test-checkDecomposePar
diff --git a/applications/test/checkDecomposePar/Make/options b/applications/test/checkDecomposePar/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..74501c5fddb82790d394fc11ebed6363095d1692
--- /dev/null
+++ b/applications/test/checkDecomposePar/Make/options
@@ -0,0 +1,10 @@
+EXE_INC = \
+    -I$(LIB_SRC)/parallel/decompose/decompose/lnInclude \
+    -I$(LIB_SRC)/parallel/decompose/decompositionMethods/lnInclude \
+    -I$(LIB_SRC)/finiteVolume/lnInclude \
+    -I$(LIB_SRC)/meshTools/lnInclude \
+    -I$(LIB_SRC)/regionModels/regionModel/lnInclude
+
+EXE_LIBS = \
+    -ldecompositionMethods \
+    -lregionModels
diff --git a/applications/test/checkDecomposePar/Test-checkDecomposePar.C b/applications/test/checkDecomposePar/Test-checkDecomposePar.C
new file mode 100644
index 0000000000000000000000000000000000000000..fc6aa405da21001d65d2bb8b3c383a8492a34dad
--- /dev/null
+++ b/applications/test/checkDecomposePar/Test-checkDecomposePar.C
@@ -0,0 +1,193 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  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
+    checkDecomposePar
+
+Group
+    grpParallelUtilities
+
+Description
+    Check decomposition from kaffpa (KaHIP) output.
+    foamToMetisGraph was likely used for producing the kaffpa input.
+
+\*---------------------------------------------------------------------------*/
+
+#include "OSspecific.H"
+#include "fvCFD.H"
+#include "cpuTime.H"
+#include "IFstream.H"
+#include "regionProperties.H"
+#include "decompositionInformation.H"
+#include "decompositionModel.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+int main(int argc, char *argv[])
+{
+    argList::addNote
+    (
+        "Check decomposition from kaffpa (KaHIP) output"
+    );
+
+    argList::noParallel();
+    argList::noBanner();
+
+    #include "addRegionOption.H"
+    argList::addBoolOption
+    (
+        "allRegions",
+        "operate on all regions in regionProperties"
+    );
+    argList::addBoolOption
+    (
+        "verbose",
+        "more information about decomposition"
+    );
+
+    argList::validArgs.append("kaffpa-output-file");
+
+    // Include explicit constant options, have zero from time range
+    timeSelector::addOptions(true, false);
+
+    #include "setRootCase.H"
+
+    const fileName decompFile = args[1];
+
+    const bool region     = args.optionFound("region");
+    const bool allRegions = args.optionFound("allRegions");
+    const bool verbose    = args.optionFound("verbose");
+
+    // Set time from database
+    #include "createTime.H"
+    // Allow override of time
+    instantList times = timeSelector::selectIfPresent(runTime, args);
+
+    // Allow override of decomposeParDict location
+    fileName decompDictFile;
+    args.optionReadIfPresent("decomposeParDict", decompDictFile);
+
+    wordList regionNames;
+    wordList regionDirs;
+    if (allRegions)
+    {
+        Info<< "Decomposing all regions in regionProperties" << nl << endl;
+        regionProperties rp(runTime);
+        forAllConstIters(rp, iter)
+        {
+            const wordList& regions = iter();
+            forAll(regions, i)
+            {
+                if (findIndex(regionNames, regions[i]) == -1)
+                {
+                    regionNames.append(regions[i]);
+                }
+            }
+        }
+        regionDirs = regionNames;
+    }
+    else
+    {
+        word regionName;
+        if (args.optionReadIfPresent("region", regionName))
+        {
+            regionNames = wordList(1, regionName);
+            regionDirs = regionNames;
+        }
+        else
+        {
+            regionNames = wordList(1, fvMesh::defaultRegion);
+            regionDirs = wordList(1, word::null);
+        }
+    }
+
+    labelList cellToProc;
+
+    forAll(regionNames, regioni)
+    {
+        const word& regionName = regionNames[regioni];
+        const word& regionDir = regionDirs[regioni];
+
+        Info<< "\n\nDecomposing mesh " << regionName << nl << endl;
+        Info<< "Create mesh..." << flush;
+
+        fvMesh mesh
+        (
+            IOobject
+            (
+                regionName,
+                runTime.timeName(),
+                runTime,
+                IOobject::MUST_READ,
+                IOobject::NO_WRITE,
+                false
+            )
+        );
+
+        Info<< " nCells = " << mesh.nCells() << endl;
+
+        // Expected format is a simple ASCII list
+        cellToProc.setSize(mesh.nCells());
+        {
+            IFstream is(decompFile);
+
+            forAll(cellToProc, celli)
+            {
+                cellToProc[celli] = readLabel(is);
+            }
+        }
+
+        const label nDomains = max(cellToProc) + 1;
+
+        CompactListList<label> cellCells;
+        decompositionMethod::calcCellCells
+        (
+            mesh,
+            identity(mesh.nCells()),
+            mesh.nCells(),
+            false,
+            cellCells
+        );
+
+        decompositionInformation info
+        (
+            cellCells,
+            cellToProc,
+            nDomains
+        );
+
+        if (verbose)
+        {
+            info.printDetails(Info);
+            Info<< nl;
+        }
+        info.printSummary(Info);
+    }
+
+    Info<< "\nEnd\n" << endl;
+
+    return 0;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/test/decomposePar/Make/files b/applications/test/decomposePar/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..d9ed6fcd8bf61aa4c1108f537af357e91a5f9b29
--- /dev/null
+++ b/applications/test/decomposePar/Make/files
@@ -0,0 +1,3 @@
+Test-decomposePar.C
+
+EXE = $(FOAM_APPBIN)/Test-decomposePar
diff --git a/applications/test/decomposePar/Make/options b/applications/test/decomposePar/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..1f62e3ffa8a9457043f395c800c3cac81a9dab23
--- /dev/null
+++ b/applications/test/decomposePar/Make/options
@@ -0,0 +1,12 @@
+EXE_INC = \
+    -I$(LIB_SRC)/parallel/decompose/decompose/lnInclude \
+    -I$(LIB_SRC)/parallel/decompose/decompositionMethods/lnInclude \
+    -I$(LIB_SRC)/finiteVolume/lnInclude \
+    -I$(LIB_SRC)/meshTools/lnInclude \
+    -I$(LIB_SRC)/regionModels/regionModel/lnInclude
+
+EXE_LIBS = \
+    -ldecompose \
+    -ldecompositionMethods \
+    -L$(FOAM_LIBBIN)/dummy -lmetisDecomp -lscotchDecomp -lkahipDecomp \
+    -lregionModels
diff --git a/applications/test/decomposePar/Test-decomposePar.C b/applications/test/decomposePar/Test-decomposePar.C
new file mode 100644
index 0000000000000000000000000000000000000000..7ad717f742158e49687e92e7e7ab87c9a99fb44d
--- /dev/null
+++ b/applications/test/decomposePar/Test-decomposePar.C
@@ -0,0 +1,278 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  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
+    decomposePar
+
+Group
+    grpParallelUtilities
+
+Description
+    Automatically decomposes a mesh and fields of a case for parallel
+    execution of OpenFOAM.
+
+Usage
+    \b decomposePar [OPTION]
+
+    Options:
+      - \par -region \<regionName\>
+        Decompose named region. Does not check for existence of processor*.
+
+      - \par -allRegions
+        Decompose all regions in regionProperties. Does not check for
+        existence of processor*.
+
+      - \par -constant
+
+      - \par -time xxx:yyy
+        Override controlDict settings and decompose selected times. Does not
+        re-decompose the mesh i.e. does not handle moving mesh or changing
+        mesh cases.
+
+\*---------------------------------------------------------------------------*/
+
+#include "OSspecific.H"
+#include "fvCFD.H"
+#include "cpuTime.H"
+#include "IOobjectList.H"
+#include "regionProperties.H"
+#include "decompositionInformation.H"
+#include "decompositionModel.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+int main(int argc, char *argv[])
+{
+    argList::addNote
+    (
+        "decompose a mesh and fields of a case for parallel execution"
+    );
+
+    argList::noParallel();
+    argList::addOption
+    (
+        "decomposeParDict",
+        "file",
+        "read decomposePar dictionary from specified location"
+    );
+    #include "addRegionOption.H"
+    argList::addBoolOption
+    (
+        "allRegions",
+        "operate on all regions in regionProperties"
+    );
+    argList::addBoolOption
+    (
+        "verbose",
+        "more information about decomposition"
+    );
+    argList::addOption
+    (
+        "domains",
+        "N"
+        "override numberOfSubdomains"
+    );
+
+    argList::addOption
+    (
+        "method",
+        "name"
+        "override method"
+    );
+
+    // Include explicit constant options, have zero from time range
+    timeSelector::addOptions(true, false);
+
+    #include "setRootCase.H"
+
+    const bool region     = args.optionFound("region");
+    const bool allRegions = args.optionFound("allRegions");
+    const bool verbose    = args.optionFound("verbose");
+
+    const label numSubdomains =
+        args.optionLookupOrDefault<label>("domains", 0);
+
+    const word methodName =
+        args.optionLookupOrDefault<word>("method", word::null);
+
+
+    // Set time from database
+    #include "createTime.H"
+    // Allow override of time
+    instantList times = timeSelector::selectIfPresent(runTime, args);
+
+    // Allow override of decomposeParDict location
+    fileName decompDictFile;
+    args.optionReadIfPresent("decomposeParDict", decompDictFile);
+
+    wordList regionNames;
+    wordList regionDirs;
+    if (allRegions)
+    {
+        Info<< "Decomposing all regions in regionProperties" << nl << endl;
+        regionProperties rp(runTime);
+        forAllConstIters(rp, iter)
+        {
+            const wordList& regions = iter();
+            forAll(regions, i)
+            {
+                if (findIndex(regionNames, regions[i]) == -1)
+                {
+                    regionNames.append(regions[i]);
+                }
+            }
+        }
+        regionDirs = regionNames;
+    }
+    else
+    {
+        word regionName;
+        if (args.optionReadIfPresent("region", regionName))
+        {
+            regionNames = wordList(1, regionName);
+            regionDirs = regionNames;
+        }
+        else
+        {
+            regionNames = wordList(1, fvMesh::defaultRegion);
+            regionDirs = wordList(1, word::null);
+        }
+    }
+
+
+    forAll(regionNames, regioni)
+    {
+        const word& regionName = regionNames[regioni];
+        const word& regionDir = regionDirs[regioni];
+
+        Info<< "\n\nDecomposing mesh " << regionName << nl << endl;
+        Info<< "Create mesh..." << flush;
+
+        fvMesh mesh
+        (
+            IOobject
+            (
+                regionName,
+                runTime.timeName(),
+                runTime,
+                IOobject::MUST_READ,
+                IOobject::NO_WRITE,
+                false
+            )
+        );
+
+        Info<< " nCells = " << mesh.nCells() << endl;
+
+        Info<< "\nCalculating distribution of cells" << endl;
+        cpuTime decompositionTime;
+
+        const decompositionModel& model = decompositionModel::New
+        (
+            mesh,
+            decompDictFile
+        );
+
+        // Allow command-line override for quick testing
+
+        dictionary& modelDict = const_cast<decompositionModel&>(model);
+
+        if (numSubdomains)
+        {
+            modelDict.add
+            (
+                word("numberOfSubdomains"),
+                numSubdomains,
+                true
+            );
+        }
+
+        if (!methodName.empty())
+        {
+            modelDict.add
+            (
+                word("method"),
+                methodName,
+                true
+            );
+        }
+
+        scalarField cellWeights;
+        word weightName;
+        if (model.readIfPresent("weightField", weightName))
+        {
+            volScalarField weights
+            (
+                IOobject
+                (
+                    weightName,
+                    mesh.time().timeName(),
+                    mesh,
+                    IOobject::MUST_READ,
+                    IOobject::NO_WRITE
+                ),
+                mesh
+            );
+            cellWeights = weights.primitiveField();
+        }
+
+        decompositionMethod& method = model.decomposer();
+
+        CompactListList<label> cellCells;
+        decompositionMethod::calcCellCells
+        (
+            mesh,
+            identity(mesh.nCells()),
+            mesh.nCells(),
+            false,
+            cellCells
+        );
+
+        labelList cellToProc = method.decompose(mesh, cellWeights);
+
+        Info<< "\nFinished decomposition into "
+            << method.nDomains() << " domains in "
+            << decompositionTime.elapsedCpuTime()
+            << " s" << nl << endl;
+
+        decompositionInformation info
+        (
+            cellCells,
+            cellToProc,
+            method.nDomains()
+        );
+
+        if (verbose)
+        {
+            info.printDetails(Info);
+            Info<< nl;
+        }
+        info.printSummary(Info);
+    }
+
+    Info<< "\nEnd\n" << endl;
+
+    return 0;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/test/foamToMetisGraph/Make/files b/applications/test/foamToMetisGraph/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..6c63ebbc7ffed052c18ec04da85d19ef19894563
--- /dev/null
+++ b/applications/test/foamToMetisGraph/Make/files
@@ -0,0 +1,3 @@
+foamToMetisGraph.C
+
+EXE = $(FOAM_USER_APPBIN)/foamToMetisGraph
diff --git a/applications/test/foamToMetisGraph/Make/options b/applications/test/foamToMetisGraph/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..4c3dd783cb4170feefb3f5385510a83257b43b18
--- /dev/null
+++ b/applications/test/foamToMetisGraph/Make/options
@@ -0,0 +1,3 @@
+EXE_INC =
+
+EXE_LIBS =
diff --git a/applications/test/foamToMetisGraph/foamToMetisGraph.C b/applications/test/foamToMetisGraph/foamToMetisGraph.C
new file mode 100644
index 0000000000000000000000000000000000000000..d4019842d483438716523e8f90fd2614c08008f8
--- /dev/null
+++ b/applications/test/foamToMetisGraph/foamToMetisGraph.C
@@ -0,0 +1,86 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  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
+    Create a metis graph file representation of an OpenFOAM mesh
+
+\*---------------------------------------------------------------------------*/
+
+#include "argList.H"
+#include "Time.H"
+#include "polyMesh.H"
+#include "OFstream.H"
+
+using namespace Foam;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+// Main program:
+
+int main(int argc, char *argv[])
+{
+    argList::noParallel();
+    argList::noFunctionObjects();
+    argList::addNote
+    (
+        "Create a metis graph file representation for an OpenFOAM mesh"
+    );
+
+    #include "setRootCase.H"
+    #include "createTime.H"
+    #include "createPolyMesh.H"
+
+    const labelListList& cellCells = mesh.cellCells();
+
+    // No. of Nodes = nCells
+    // No. of Edges connecting Nodes = nInternalFaces
+
+    OFstream os(args.caseName() + ".graph", IOstream::ASCII);
+
+    os  << "%% metis graph file, of an OpenFOAM mesh %%" << nl
+        << "%% nCells=" << mesh.nCells()
+        << " nFaces=" << mesh.nFaces()
+        << " nInternalFaces=" << mesh.nInternalFaces() << nl;
+
+    os  << cellCells.size() << " " << mesh.nInternalFaces() << nl;
+
+    for (const auto& edges : cellCells)
+    {
+        forAll(edges, i)
+        {
+            if (i) os << " ";
+            os << edges[i] + 1;  // index starts at 1.
+        }
+        os << nl;
+    }
+
+    Info<<"Wrote graph with "
+        << mesh.nCells() << " nodes and "
+        << mesh.nInternalFaces() << " edges to "
+        << os.name() << nl;
+
+    Info<< nl << "End\n" << endl;
+
+    return 0;
+}
+
+// ************************************************************************* //
diff --git a/applications/utilities/mesh/manipulation/renumberMesh/Make/options b/applications/utilities/mesh/manipulation/renumberMesh/Make/options
index f073a1c4140abf625f7d2513c66f4bb933aa27ed..5803e893aac14a9ff81ac883220c07eca188e661 100644
--- a/applications/utilities/mesh/manipulation/renumberMesh/Make/options
+++ b/applications/utilities/mesh/manipulation/renumberMesh/Make/options
@@ -18,4 +18,4 @@ EXE_LIBS = \
     -lreconstruct \
     $(LINK_FLAGS) \
     -ldecompositionMethods \
-    -L$(FOAM_LIBBIN)/dummy -lmetisDecomp -lscotchDecomp
+    -L$(FOAM_LIBBIN)/dummy -lmetisDecomp -lscotchDecomp -lkahipDecomp
diff --git a/applications/utilities/parallelProcessing/decomposePar/Make/options b/applications/utilities/parallelProcessing/decomposePar/Make/options
index cec9adc663b3feff9800d6a362cc32f27c436150..34f3e5de3339d7499348f4924325311c904b4648 100644
--- a/applications/utilities/parallelProcessing/decomposePar/Make/options
+++ b/applications/utilities/parallelProcessing/decomposePar/Make/options
@@ -11,7 +11,8 @@ EXE_LIBS = \
     -ldynamicMesh \
     -ldecompose \
     -lgenericPatchFields \
-    -ldecompositionMethods -L$(FOAM_LIBBIN)/dummy -lmetisDecomp -lscotchDecomp \
+    -ldecompositionMethods \
+    -L$(FOAM_LIBBIN)/dummy -lmetisDecomp -lscotchDecomp -lkahipDecomp \
     -llagrangian \
     -ldynamicMesh \
     -lregionModels
diff --git a/etc/config.sh/kahip b/etc/config.sh/kahip
new file mode 100644
index 0000000000000000000000000000000000000000..9212e7a80a374e2b10267740ff570a71efe619ad
--- /dev/null
+++ b/etc/config.sh/kahip
@@ -0,0 +1,59 @@
+#----------------------------------*-sh-*--------------------------------------
+# =========                 |
+# \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+#  \\    /   O peration     |
+#   \\  /    A nd           | Copyright (C) 2017 OpenCFD Ltd.
+#    \\/     M anipulation  |
+#------------------------------------------------------------------------------
+# This file is part of OpenFOAM, licensed under the GNU General Public License
+# <http://www.gnu.org/licenses/>.
+#
+# File
+#     etc/config.sh/kahip
+#
+# Description
+#     Setup for kahip include/libraries.
+#     Sourced during wmake process only.
+#
+#     Normally used to specify the kahip version and location for a
+#     ThirdParty installation.
+#
+#     If using system-wide installations, use the following setting:
+#
+#         KAHIP_VERSION=kahip-system
+#
+#     If the system kahip is unusable (eg, too old) and you don't
+#     have or want a ThirdParty installation:
+#
+#         KAHIP_VERSION=kahip-none
+#
+#     If using a central installation, but not located under ThirdParty:
+#         - specify kahip-system
+#         - provide full path for KAHIP_ARCH_PATH
+#
+# Note
+#     A csh version is not needed, since the values here are only sourced
+#     during the wmake process.
+#
+#     KaHIP can also be entirely disabled, by either renaming this file or
+#     by creating an empty one with the same name at a user or site location.
+#
+#     KaHIP is 32-bit precision only.
+#     An Int64 OpenFOAM version can use it, but the mesh size is limited
+#     accordingly.
+#
+#     If KaHIP was compiled with openmp, you may need to add in additional
+#     compile or link flags in KAHIP_COMP_FLAGS KAHIP_LINK_FLAGS
+#
+#------------------------------------------------------------------------------
+# USER EDITABLE PART: Changes made here may be lost with the next upgrade
+
+KAHIP_VERSION=kahip-2.00
+export KAHIP_ARCH_PATH=$WM_THIRD_PARTY_DIR/platforms/$WM_ARCH$WM_COMPILER/$KAHIP_VERSION
+
+# Adjust as required
+# export KAHIP_COMP_FLAGS="-fopenmp"
+# export KAHIP_LINK_FLAGS="-lgomp"
+
+# END OF (NORMAL) USER EDITABLE PART
+#------------------------------------------------------------------------------
diff --git a/etc/config.sh/unset b/etc/config.sh/unset
index fe8b8f18e10267cf5121e0e22c26c3872ad2185d..31710db372ce80745e4b39ca92d96fa1fcc61d4d 100644
--- a/etc/config.sh/unset
+++ b/etc/config.sh/unset
@@ -134,6 +134,7 @@ unset GPERFTOOLS_ARCH_PATH
 unset GMP_ARCH_PATH
 unset MPFR_ARCH_PATH
 unset MESA_ARCH_PATH
+unset KAHIP_ARCH_PATH
 unset METIS_ARCH_PATH
 unset SCOTCH_ARCH_PATH
 
diff --git a/src/dummyThirdParty/Allwmake b/src/dummyThirdParty/Allwmake
index 3dac95f4106ee4aa1fdb1c3f869f769b1b5a99b9..a1628e356fbfd99ca5942bd05ce496b349a5f652 100755
--- a/src/dummyThirdParty/Allwmake
+++ b/src/dummyThirdParty/Allwmake
@@ -7,6 +7,7 @@ cd ${0%/*} || exit 1    # Run from this directory
 wmake $targetType scotchDecomp
 wmake $targetType ptscotchDecomp
 wmake $targetType metisDecomp
+wmake $targetType kahipDecomp
 wmake $targetType MGridGen
 
 #------------------------------------------------------------------------------
diff --git a/src/dummyThirdParty/kahipDecomp/Make/files b/src/dummyThirdParty/kahipDecomp/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..1a0227567673cdcf37523150efa34acc1ff94b25
--- /dev/null
+++ b/src/dummyThirdParty/kahipDecomp/Make/files
@@ -0,0 +1,3 @@
+dummyKahipDecomp.C
+
+LIB = $(FOAM_LIBBIN)/dummy/libkahipDecomp
diff --git a/src/dummyThirdParty/kahipDecomp/Make/options b/src/dummyThirdParty/kahipDecomp/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..0aad6a146fa63c9bc92a594d13d34ef9a43a2d95
--- /dev/null
+++ b/src/dummyThirdParty/kahipDecomp/Make/options
@@ -0,0 +1,5 @@
+EXE_INC = \
+    -I$(LIB_SRC)/parallel/decompose/decompositionMethods/lnInclude \
+    -I$(LIB_SRC)/parallel/decompose/kahipDecomp/lnInclude
+
+LIB_LIBS =
diff --git a/src/dummyThirdParty/kahipDecomp/dummyKahipDecomp.C b/src/dummyThirdParty/kahipDecomp/dummyKahipDecomp.C
new file mode 100644
index 0000000000000000000000000000000000000000..d3844087e44b3ecfb8ba75bf6ccb749fad073250
--- /dev/null
+++ b/src/dummyThirdParty/kahipDecomp/dummyKahipDecomp.C
@@ -0,0 +1,83 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  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/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "kahipDecomp.H"
+#include "addToRunTimeSelectionTable.H"
+#include "Time.H"
+
+static const char* notImplementedMessage =
+"You are trying to use kahip but do not have the kahipDecomp library loaded."
+"\nThis message is from the dummy kahipDecomp stub library instead.\n"
+"\n"
+"Please install kahip and make sure that libkahip.so is in your "
+"LD_LIBRARY_PATH.\n"
+"The kahipDecomp library can then be built from "
+"src/parallel/decompose/kahipDecomp and dynamically loading or linking"
+" this library will add kahip as a decomposition method.\n";
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineTypeNameAndDebug(kahipDecomp, 0);
+
+    addToRunTimeSelectionTable
+    (
+        decompositionMethod,
+        kahipDecomp,
+        dictionary
+    );
+}
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+Foam::label Foam::kahipDecomp::decomposeSerial
+(
+    const UList<label>& adjncy,
+    const UList<label>& xadj,
+    const UList<scalar>& cellWeights,
+    List<label>& decomp
+)
+{
+    FatalErrorInFunction
+        << notImplementedMessage << exit(FatalError);
+
+    return -1;
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::kahipDecomp::kahipDecomp
+(
+    const dictionary& decompositionDict
+)
+:
+    metisLikeDecomp(decompositionDict)
+{}
+
+
+// ************************************************************************* //
diff --git a/src/dummyThirdParty/kahipDecomp/kaHIP_interface.h b/src/dummyThirdParty/kahipDecomp/kaHIP_interface.h
new file mode 100644
index 0000000000000000000000000000000000000000..90bf1afc23b4f77fb10356e58653dee7f142b5fc
--- /dev/null
+++ b/src/dummyThirdParty/kahipDecomp/kaHIP_interface.h
@@ -0,0 +1,37 @@
+#ifndef KAHIP_H
+#define KAHIP_H
+
+/* *** DUMMY VERSION of kaHIP_interface.h - this file should not be included if you have KaHIP
+ *     installed in the correct position in $WM_THIRD_PARTY_DIR - see
+ *     decompositionMethods/kahipDecomp/Make/options
+ */
+
+#warning "Dummy kahip.h - included since it cannot find KaHIP installation."
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void kaffpa
+(
+    // [inputs]
+    int* n,
+    int* vwgt,
+    int* xadj,
+    int* adjcwgt,
+    int* adjncy,
+    int* nparts,
+    double* imbalance,
+    bool suppress_output,
+    int seed,
+    int mode,
+    // [outputs]
+    int* edgecut,
+    int* part
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/dummyThirdParty/metisDecomp/dummyMetisDecomp.C b/src/dummyThirdParty/metisDecomp/dummyMetisDecomp.C
index ea3ee98863f90952819a2c734ccab49105a2c6ac..aabfa95fee9eecc17f91c2e4d756bb06c707bde2 100644
--- a/src/dummyThirdParty/metisDecomp/dummyMetisDecomp.C
+++ b/src/dummyThirdParty/metisDecomp/dummyMetisDecomp.C
@@ -35,8 +35,7 @@ static const char* notImplementedMessage =
 "LD_LIBRARY_PATH.\n"
 "The metisDecomp library can then be built from "
 "src/parallel/decompose/metisDecomp and dynamically loading or linking"
-" this library will add metis as a decomposition method.\n"
-"Please be aware that there are license restrictions on using Metis.";
+" this library will add metis as a decomposition method.\n";
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -55,12 +54,12 @@ namespace Foam
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
-Foam::label Foam::metisDecomp::decompose
+Foam::label Foam::metisDecomp::decomposeSerial
 (
-    const List<label>& adjncy,
-    const List<label>& xadj,
-    const scalarField& cellWeights,
-    List<label>& finalDecomp
+    const UList<label>& adjncy,
+    const UList<label>& xadj,
+    const UList<scalar>& cellWeights,
+    List<label>& decomp
 )
 {
     FatalErrorInFunction
@@ -77,53 +76,8 @@ Foam::metisDecomp::metisDecomp
     const dictionary& decompositionDict
 )
 :
-    decompositionMethod(decompositionDict)
+    metisLikeDecomp(decompositionDict)
 {}
 
 
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
-
-Foam::labelList Foam::metisDecomp::decompose
-(
-    const polyMesh& mesh,
-    const pointField& points,
-    const scalarField& pointWeights
-)
-{
-    FatalErrorInFunction
-        << notImplementedMessage << exit(FatalError);
-
-    return labelList();
-}
-
-
-Foam::labelList Foam::metisDecomp::decompose
-(
-    const polyMesh& mesh,
-    const labelList& agglom,
-    const pointField& agglomPoints,
-    const scalarField& agglomWeights
-)
-{
-    FatalErrorInFunction
-        << notImplementedMessage << exit(FatalError);
-
-    return labelList();
-}
-
-
-Foam::labelList Foam::metisDecomp::decompose
-(
-    const labelListList& globalCellCells,
-    const pointField& cellCentres,
-    const scalarField& cellWeights
-)
-{
-    FatalErrorInFunction
-        << notImplementedMessage << exit(FatalError);
-
-    return labelList();
-}
-
-
 // ************************************************************************* //
diff --git a/src/dummyThirdParty/ptscotchDecomp/dummyPtscotchDecomp.C b/src/dummyThirdParty/ptscotchDecomp/dummyPtscotchDecomp.C
index 25287d72befdacd028480e72acc1a147ff8b3a89..d924b711b64464740db829e2f450b1dddc3a0321 100644
--- a/src/dummyThirdParty/ptscotchDecomp/dummyPtscotchDecomp.C
+++ b/src/dummyThirdParty/ptscotchDecomp/dummyPtscotchDecomp.C
@@ -54,17 +54,19 @@ namespace Foam
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
+void Foam::ptscotchDecomp::graphPath(const polyMesh& unused)
+{}
+
+
 void Foam::ptscotchDecomp::check(const int retVal, const char* str)
 {}
 
 
 Foam::label Foam::ptscotchDecomp::decompose
 (
-    const fileName& meshPath,
-    const List<label>& initxadj,
-    const List<label>& initadjncy,
-    const scalarField& initcWeights,
-
+    const UList<label>& initxadj,
+    const UList<label>& initadjncy,
+    const UList<scalar>& initcWeights,
     List<label>& finalDecomp
 ) const
 {
@@ -77,12 +79,11 @@ Foam::label Foam::ptscotchDecomp::decompose
 
 Foam::label Foam::ptscotchDecomp::decompose
 (
-    const fileName& meshPath,
     const label adjncySize,
     const label adjncy[],
     const label xadjSize,
     const label xadj[],
-    const scalarField& cWeights,
+    const UList<scalar>& cWeights,
     List<label>& finalDecomp
 ) const
 {
diff --git a/src/dummyThirdParty/scotchDecomp/dummyScotchDecomp.C b/src/dummyThirdParty/scotchDecomp/dummyScotchDecomp.C
index f1088d487bce61935a622fc3350db8fdab6ffeb7..e5102774b5e74b146810ab2915340fd5b88adefc 100644
--- a/src/dummyThirdParty/scotchDecomp/dummyScotchDecomp.C
+++ b/src/dummyThirdParty/scotchDecomp/dummyScotchDecomp.C
@@ -53,18 +53,20 @@ namespace Foam
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
+void Foam::scotchDecomp::graphPath(const polyMesh& unused)
+{}
+
+
 void Foam::scotchDecomp::check(const int retVal, const char* str)
 {}
 
 
-Foam::label Foam::scotchDecomp::decompose
+Foam::label Foam::scotchDecomp::decomposeSerial
 (
-    const fileName& meshPath,
-    const List<label>& adjncy,
-    const List<label>& xadj,
-    const scalarField& cWeights,
-
-    List<label>& finalDecomp
+    const UList<label>& adjncy,
+    const UList<label>& xadj,
+    const UList<scalar>& cWeights,
+    List<label>& decomp
 )
 {
     FatalErrorInFunction
@@ -81,7 +83,7 @@ Foam::scotchDecomp::scotchDecomp
     const dictionary& decompositionDict
 )
 :
-    decompositionMethod(decompositionDict)
+    metisLikeDecomp(decompositionDict)
 {}
 
 
diff --git a/src/parallel/decompose/Allwclean b/src/parallel/decompose/Allwclean
index 88c606b523c26c7b8eefe57107d0c6937ab4568d..5fd3b3d4991b846d541dbd59bd78bc7f489655aa 100755
--- a/src/parallel/decompose/Allwclean
+++ b/src/parallel/decompose/Allwclean
@@ -17,8 +17,9 @@ wcleanMpiLib()
 }
 
 
-wclean scotchDecomp
 wclean metisDecomp
+wclean kahipDecomp
+wclean scotchDecomp
 wclean decompositionMethods
 wclean decompose
 wcleanMpiLib ptscotchDecomp
diff --git a/src/parallel/decompose/Allwmake b/src/parallel/decompose/Allwmake
index a90f705601ba1a0848ea2bdd0ba49862f1d525e4..19dced9e316f5a47a40bd480cac83d390ea1b742 100755
--- a/src/parallel/decompose/Allwmake
+++ b/src/parallel/decompose/Allwmake
@@ -25,6 +25,54 @@ findFirstFile()
 }
 
 
+# Test for kahip.
+# - return 0 and export KAHIP_ARCH_PATH on success
+hasKahip()
+{
+    local warning="==> skip kahip"
+    local header label settings
+
+    unset KAHIP_ARCH_PATH KAHIP_VERSION
+    unset KAHIP_COMP_FLAGS KAHIP_LINK_FLAGS
+    settings=$($WM_PROJECT_DIR/bin/foamEtcFile config.sh/kahip) || {
+        echo "$warning (no config.sh/kahip settings)"
+        return 1
+    }
+
+    . $settings
+    if [ -z "$KAHIP_ARCH_PATH" -o "${KAHIP_ARCH_PATH##*-}" = none ]
+    then
+        echo "$warning (not available)"
+        return 1
+    fi
+
+    # Header
+    header=$(findFirstFile \
+        $KAHIP_ARCH_PATH/include/kaHIP_interface.h \
+        /usr/include/kaHIP_interface.h \
+    ) || {
+        echo "$warning (no header)"
+        return 2  # file not found
+    }
+
+    # Library
+    [ "${KAHIP_ARCH_PATH##*-}" = system ] || \
+    findFirstFile \
+        $KAHIP_ARCH_PATH/lib/libkahip.a  \
+        $KAHIP_ARCH_PATH/lib$WM_COMPILER_LIB_ARCH/libkahip.a \
+    > /dev/null || {
+        echo "$warning (missing library)"
+        return 2
+    }
+
+    # kahip itself is 32-bit int, but our interface itself handles some
+    # 64-bit conversion (mesh size).
+
+    export KAHIP_ARCH_PATH
+    echo "kahip (label=32) - $KAHIP_ARCH_PATH"
+}
+
+
 # Test for metis.
 # - return 0 and export METIS_ARCH_PATH on success
 hasMetis()
@@ -208,6 +256,11 @@ then
     wmake $targetType metisDecomp
 fi
 
+if hasKahip
+then
+    wmake $targetType kahipDecomp
+fi
+
 wmake $targetType decompositionMethods
 wmake $targetType decompose
 
diff --git a/src/parallel/decompose/decompose/Make/files b/src/parallel/decompose/decompose/Make/files
index 5fabd38ccef57caf31d6d495eb45184fa8bb9fa9..225a27dfad890ce4248954ff1be2aca2c4dfbf16 100644
--- a/src/parallel/decompose/decompose/Make/files
+++ b/src/parallel/decompose/decompose/Make/files
@@ -1,3 +1,4 @@
+decompositionInformation.C
 decompositionModel.C
 fvFieldDecomposer.C
 
diff --git a/src/parallel/decompose/decompose/decompositionInformation.C b/src/parallel/decompose/decompose/decompositionInformation.C
new file mode 100644
index 0000000000000000000000000000000000000000..08f80d2cad774423df1c9696e17b66b067249d01
--- /dev/null
+++ b/src/parallel/decompose/decompose/decompositionInformation.C
@@ -0,0 +1,236 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  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/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "decompositionInformation.H"
+#include "ListOps.H"
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+void Foam::decompositionInformation::populate
+(
+    const labelUList& adjncy,
+    const labelUList& xadj,
+    const labelUList& decomp,
+    const label nDomain
+)
+{
+    nDomains_ = nDomain;
+
+    distrib_.clear();
+    distrib_.setSize(nDomain);
+
+    for (labelList& subdist : distrib_)
+    {
+        subdist.clear();
+        subdist.setSize(nDomain, Zero);
+    }
+
+    const label nCells = xadj.size()-1;
+    for (label celli = 0; celli < nCells; ++celli)
+    {
+        const label ownProc = decomp[celli];
+
+        labelList& subdist = distrib_[ownProc];
+
+        // Number of cells
+        ++subdist[ownProc];
+
+        for (label i = xadj[celli]; i < xadj[celli+1]; ++i)
+        {
+            const label neiProc = decomp[adjncy[i]];
+
+            if (neiProc != ownProc)
+            {
+                // Number of processor faces
+                ++subdist[neiProc];
+            }
+        }
+    }
+
+    // Build summary
+
+    labelList cellsCount(nDomains_, Zero);
+    labelList neighCount(nDomains_, Zero);
+    labelList facesCount(nDomains_, Zero);
+
+    forAll(distrib_, ownProc)
+    {
+        const labelList& subdist = distrib_[ownProc];
+
+        cellsCount[ownProc] = subdist[ownProc];
+
+        forAll(subdist, neiProc)
+        {
+            const label n = subdist[neiProc];
+
+            if (n && ownProc != neiProc)
+            {
+                ++neighCount[ownProc];
+                facesCount[ownProc] += n;
+            }
+        }
+    }
+
+    const label n2 = (nDomains_ / 2);
+
+    sort(cellsCount);
+    cellsInfo_.min    = cellsCount.first();
+    cellsInfo_.max    = cellsCount.last();
+    cellsInfo_.median = cellsCount[n2];
+
+    sort(neighCount);
+    neighInfo_.min    = neighCount.first();
+    neighInfo_.max    = neighCount.last();
+    neighInfo_.median = neighCount[n2];
+
+    sort(facesCount);
+    facesInfo_.min    = facesCount.first();
+    facesInfo_.max    = facesCount.last();
+    facesInfo_.median = facesCount[n2];
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::decompositionInformation::decompositionInformation
+(
+    const labelUList& adjncy,
+    const labelUList& xadj,
+    const labelUList& decomp,
+    const label nDomains
+)
+:
+    distrib_(),
+    nDomains_(0)
+{
+    populate(adjncy, xadj, decomp, nDomains);
+}
+
+
+Foam::decompositionInformation::decompositionInformation
+(
+    const CompactListList<label>& cellCells,
+    const labelUList& decomp,
+    const label nDomains
+)
+:
+    distrib_(),
+    nDomains_(0)
+{
+    populate(cellCells.m(), cellCells.offsets(), decomp, nDomains);
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::decompositionInformation::clear()
+{
+    distrib_.clear();
+    cellsInfo_.clear();
+    neighInfo_.clear();
+    facesInfo_.clear();
+}
+
+
+void Foam::decompositionInformation::printSummary(Ostream& os) const
+{
+    os  << "Cells "; cellsInfo_.print(os) << nl;
+    os  << "Neigh "; neighInfo_.print(os)<< nl;
+    os  << "Faces "; facesInfo_.print(os)<< nl;
+}
+
+
+void Foam::decompositionInformation::printDetails(Ostream& os) const
+{
+    forAll(distrib_, ownProc)
+    {
+        const labelList& subdist = distrib_[ownProc];
+
+        // First pass:
+        label neighCount = 0;
+        label facesCount = 0;
+
+        forAll(subdist, neiProc)
+        {
+            const label n = subdist[neiProc];
+
+            if (n && ownProc != neiProc)
+            {
+                ++neighCount;
+                facesCount += n;
+            }
+        }
+
+        os  << "Part[" << ownProc << "] cells:" << subdist[ownProc]
+            << " neigh:" << neighCount
+            << " faces:" << facesCount;
+
+        // Second pass with details:
+        if (facesCount)
+        {
+            Info<< " ";
+
+            forAll(subdist, neiProc)
+            {
+                const label n = subdist[neiProc];
+
+                if (n && ownProc != neiProc)
+                {
+                    os  << " (" << neiProc << " " << n << ")";
+                }
+            }
+        }
+
+        os  << nl;
+    }
+}
+
+
+void Foam::decompositionInformation::printAll(Ostream& os) const
+{
+    printDetails(os);
+    printSummary(os);
+}
+
+
+// * * * * * * * * * * * * * * * Ostream Operator  * * * * * * * * * * * * * //
+
+
+Foam::Ostream& Foam::decompositionInformation::stats::print(Ostream& os) const
+{
+    os  << "max/median/min: "
+        << this->max << " / " << this->median << " / " << this->min;
+
+    if (this->median)
+    {
+        const scalar ratio = scalar(100*this->max)/this->median;
+
+        os  << " (" << ratio << "%)";
+    }
+
+    return os;
+}
+
+// ************************************************************************* //
diff --git a/src/parallel/decompose/decompose/decompositionInformation.H b/src/parallel/decompose/decompose/decompositionInformation.H
new file mode 100644
index 0000000000000000000000000000000000000000..c0f24bb2cf38429c394198273b7e932761eb9741
--- /dev/null
+++ b/src/parallel/decompose/decompose/decompositionInformation.H
@@ -0,0 +1,149 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  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/>.
+
+Class
+    Foam::decompositionInformation
+
+Description
+    Abstract base class for decomposition
+
+SourceFiles
+    decompositionInformation.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef decompositionInformation_H
+#define decompositionInformation_H
+
+#include "polyMesh.H"
+#include "CompactListList.H"
+#include "IOstreams.H"
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                  Class decompositionInformation Declaration
+\*---------------------------------------------------------------------------*/
+
+class decompositionInformation
+{
+    //- Simple storage for organizing min/max/median quantities
+    struct stats
+    {
+        label min;
+        label max;
+        label median;
+
+        stats() : min(0), max(0), median(0) {}
+
+        void clear()
+        {
+            min = 0;
+            max = 0;
+            median = 0;
+        }
+
+        Ostream& print(Ostream& os) const;
+    };
+
+    // Private data
+
+        labelListList distrib_;
+        label nDomains_;
+
+        stats cellsInfo_;
+        stats neighInfo_;
+        stats facesInfo_;
+
+
+    // Private Member Functions
+
+        //- Populate from cell decomposition list
+        void populate
+        (
+            const labelUList& adjncy,
+            const labelUList& xadj,
+            const labelUList& decomp,
+            const label nDomains
+        );
+
+        //- Disallow default bitwise copy construct and assignment
+        decompositionInformation(const decompositionInformation&) = delete;
+        void operator=(const decompositionInformation&) = delete;
+
+
+public:
+
+    // Constructors
+
+        //- Construct
+        decompositionInformation
+        (
+            const labelUList& adjncy,
+            const labelUList& xadj,
+            const labelUList& decomp,
+            const label nDomains
+        );
+
+        //- Construct
+        decompositionInformation
+        (
+            const CompactListList<label>& cellCells,
+            const labelUList& decomp,
+            const label nDomains
+        );
+
+
+    //- Destructor
+    ~decompositionInformation()
+    {}
+
+
+    // Member Functions
+
+        void clear();
+
+        label nDomains() const
+        {
+            return nDomains_;
+        }
+
+
+        void printSummary(Ostream& os) const;
+
+        void printDetails(Ostream& os) const;
+
+        void printAll(Ostream& os) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/parallel/decompose/decompositionMethods/Make/files b/src/parallel/decompose/decompositionMethods/Make/files
index 2aef948ff7a22d15cb43a6f84f1437e200f2edd3..0bae18c40d6bdd40a0b60e042b1625087f1b15a5 100644
--- a/src/parallel/decompose/decompositionMethods/Make/files
+++ b/src/parallel/decompose/decompositionMethods/Make/files
@@ -4,6 +4,7 @@ simpleGeomDecomp/simpleGeomDecomp.C
 hierarchGeomDecomp/hierarchGeomDecomp.C
 manualDecomp/manualDecomp.C
 multiLevelDecomp/multiLevelDecomp.C
+metisLikeDecomp/metisLikeDecomp.C
 structuredDecomp/structuredDecomp.C
 noDecomp/noDecomp.C
 
diff --git a/src/parallel/decompose/decompositionMethods/decompositionMethod/decompositionMethod.C b/src/parallel/decompose/decompositionMethods/decompositionMethod/decompositionMethod.C
index a66acf8dbd331f260d3dae05e611261eb531018c..f03667084ed23533f2a4bfe5096b31d446ed07d5 100644
--- a/src/parallel/decompose/decompositionMethods/decompositionMethod/decompositionMethod.C
+++ b/src/parallel/decompose/decompositionMethods/decompositionMethod/decompositionMethod.C
@@ -21,9 +21,6 @@ License
     You should have received a copy of the GNU General Public License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
-InClass
-    decompositionMethod
-
 \*---------------------------------------------------------------------------*/
 
 #include "decompositionMethod.H"
@@ -49,6 +46,7 @@ namespace Foam
     defineRunTimeSelectionTable(decompositionMethod, dictionary);
 }
 
+
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
 Foam::decompositionMethod::decompositionMethod
@@ -349,8 +347,8 @@ void Foam::decompositionMethod::calcCellCells
 
     for (label facei = 0; facei < mesh.nInternalFaces(); facei++)
     {
-        label own = agglom[faceOwner[facei]];
-        label nei = agglom[faceNeighbour[facei]];
+        const label own = agglom[faceOwner[facei]];
+        const label nei = agglom[faceNeighbour[facei]];
 
         nFacesPerCell[own]++;
         nFacesPerCell[nei]++;
@@ -367,7 +365,7 @@ void Foam::decompositionMethod::calcCellCells
 
             forAll(pp, i)
             {
-                label own = agglom[faceOwner[facei]];
+                const label own = agglom[faceOwner[facei]];
 
                 label globalNei = globalNeighbour[bFacei];
                 if
@@ -399,8 +397,8 @@ void Foam::decompositionMethod::calcCellCells
     // For internal faces is just offsetted owner and neighbour
     for (label facei = 0; facei < mesh.nInternalFaces(); facei++)
     {
-        label own = agglom[faceOwner[facei]];
-        label nei = agglom[faceNeighbour[facei]];
+        const label own = agglom[faceOwner[facei]];
+        const label nei = agglom[faceNeighbour[facei]];
 
         m[offsets[own] + nFacesPerCell[own]++] = globalAgglom.toGlobal(nei);
         m[offsets[nei] + nFacesPerCell[nei]++] = globalAgglom.toGlobal(own);
@@ -418,9 +416,9 @@ void Foam::decompositionMethod::calcCellCells
 
             forAll(pp, i)
             {
-                label own = agglom[faceOwner[facei]];
+                const label own = agglom[faceOwner[facei]];
 
-                label globalNei = globalNeighbour[bFacei];
+                const label globalNei = globalNeighbour[bFacei];
 
                 if
                 (
@@ -457,7 +455,7 @@ void Foam::decompositionMethod::calcCellCells
         nbrCells.clear();
         nbrCells.insert(globalAgglom.toGlobal(celli));
 
-        label endIndex = cellCells.offsets()[celli+1];
+        const label endIndex = cellCells.offsets()[celli+1];
 
         for (label i = startIndex; i < endIndex; i++)
         {
@@ -555,8 +553,8 @@ void Foam::decompositionMethod::calcCellCells
 
     for (label faceI = 0; faceI < mesh.nInternalFaces(); faceI++)
     {
-        label own = agglom[faceOwner[faceI]];
-        label nei = agglom[faceNeighbour[faceI]];
+        const label own = agglom[faceOwner[faceI]];
+        const label nei = agglom[faceNeighbour[faceI]];
 
         nFacesPerCell[own]++;
         nFacesPerCell[nei]++;
@@ -573,9 +571,9 @@ void Foam::decompositionMethod::calcCellCells
 
             forAll(pp, i)
             {
-                label own = agglom[faceOwner[faceI]];
+                const label own = agglom[faceOwner[faceI]];
 
-                label globalNei = globalNeighbour[bFaceI];
+                const label globalNei = globalNeighbour[bFaceI];
                 if
                 (
                    !globalAgglom.isLocal(globalNei)
@@ -607,11 +605,11 @@ void Foam::decompositionMethod::calcCellCells
     // For internal faces is just offsetted owner and neighbour
     for (label faceI = 0; faceI < mesh.nInternalFaces(); faceI++)
     {
-        label own = agglom[faceOwner[faceI]];
-        label nei = agglom[faceNeighbour[faceI]];
+        const label own = agglom[faceOwner[faceI]];
+        const label nei = agglom[faceNeighbour[faceI]];
 
-        label ownIndex = offsets[own] + nFacesPerCell[own]++;
-        label neiIndex = offsets[nei] + nFacesPerCell[nei]++;
+        const label ownIndex = offsets[own] + nFacesPerCell[own]++;
+        const label neiIndex = offsets[nei] + nFacesPerCell[nei]++;
 
         m[ownIndex] = globalAgglom.toGlobal(nei);
         w[ownIndex] = mag(mesh.faceAreas()[faceI]);
@@ -631,9 +629,9 @@ void Foam::decompositionMethod::calcCellCells
 
             forAll(pp, i)
             {
-                label own = agglom[faceOwner[faceI]];
+                const label own = agglom[faceOwner[faceI]];
 
-                label globalNei = globalNeighbour[bFaceI];
+                const label globalNei = globalNeighbour[bFaceI];
 
                 if
                 (
@@ -672,7 +670,7 @@ void Foam::decompositionMethod::calcCellCells
         nbrCells.clear();
         nbrCells.insert(globalAgglom.toGlobal(cellI));
 
-        label endIndex = cellCells.offsets()[cellI+1];
+        const label endIndex = cellCells.offsets()[cellI+1];
 
         for (label i = startIndex; i < endIndex; i++)
         {
diff --git a/src/parallel/decompose/decompositionMethods/decompositionMethod/decompositionMethod.H b/src/parallel/decompose/decompositionMethods/decompositionMethod/decompositionMethod.H
index 9a8a3a1f1cef9098a83cd7b8230936bbdea7d72f..75a797e1aeeb4a9965959f3816ac9ba802221087 100644
--- a/src/parallel/decompose/decompositionMethods/decompositionMethod/decompositionMethod.H
+++ b/src/parallel/decompose/decompositionMethods/decompositionMethod/decompositionMethod.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 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2015-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
diff --git a/src/parallel/decompose/decompositionMethods/metisLikeDecomp/metisLikeDecomp.C b/src/parallel/decompose/decompositionMethods/metisLikeDecomp/metisLikeDecomp.C
new file mode 100644
index 0000000000000000000000000000000000000000..a5dffec83c02e7c3ae0ae9c8b5656e2fed1b5312
--- /dev/null
+++ b/src/parallel/decompose/decompositionMethods/metisLikeDecomp/metisLikeDecomp.C
@@ -0,0 +1,264 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  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/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "metisLikeDecomp.H"
+#include "Time.H"
+#include "globalIndex.H"
+
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+Foam::label Foam::metisLikeDecomp::decomposeGeneral
+(
+    const UList<label>& adjncy,
+    const UList<label>& xadj,
+    const UList<scalar>& cWeights,
+    List<label>& decomp
+)
+{
+    if (!Pstream::parRun())
+    {
+        return decomposeSerial
+        (
+            adjncy,
+            xadj,
+            cWeights,
+            decomp
+        );
+    }
+
+    if (debug)
+    {
+        Info<< type() << "Decomp : running in parallel."
+            << " Decomposing all of graph on master processor." << endl;
+    }
+    globalIndex globalCells(xadj.size()-1);
+    label nTotalConnections = returnReduce(adjncy.size(), sumOp<label>());
+
+    // Send all to master. Use scheduled to save some storage.
+    if (Pstream::master())
+    {
+        List<label> allAdjncy(nTotalConnections);
+        List<label> allXadj(globalCells.size()+1);
+        List<scalar> allWeights(globalCells.size());
+
+        // Insert my own
+        label nTotalCells = 0;
+        forAll(cWeights, celli)
+        {
+            allXadj[nTotalCells] = xadj[celli];
+            allWeights[nTotalCells++] = cWeights[celli];
+        }
+        nTotalConnections = 0;
+        forAll(adjncy, i)
+        {
+            allAdjncy[nTotalConnections++] = adjncy[i];
+        }
+
+        for (int slave=1; slave<Pstream::nProcs(); ++slave)
+        {
+            IPstream fromSlave(Pstream::commsTypes::scheduled, slave);
+            List<label> nbrAdjncy(fromSlave);
+            List<label> nbrXadj(fromSlave);
+            List<scalar> nbrWeights(fromSlave);
+
+            // Append.
+            forAll(nbrXadj, celli)
+            {
+                allXadj[nTotalCells] = nTotalConnections+nbrXadj[celli];
+                allWeights[nTotalCells++] = nbrWeights[celli];
+            }
+            // No need to renumber xadj since already global.
+            forAll(nbrAdjncy, i)
+            {
+                allAdjncy[nTotalConnections++] = nbrAdjncy[i];
+            }
+        }
+        allXadj[nTotalCells] = nTotalConnections;
+
+        labelList allDecomp;
+        decomposeSerial
+        (
+            allAdjncy,
+            allXadj,
+            allWeights,
+            allDecomp
+        );
+
+
+        // Send allFinalDecomp back
+        for (int slave=1; slave<Pstream::nProcs(); ++slave)
+        {
+            OPstream toSlave(Pstream::commsTypes::scheduled, slave);
+            toSlave << SubList<label>
+            (
+                allDecomp,
+                globalCells.localSize(slave),
+                globalCells.offset(slave)
+            );
+        }
+
+        // Get my own part (always first)
+        decomp = SubList<label>(allDecomp, globalCells.localSize());
+    }
+    else
+    {
+        // Send my part of the graph (already in global numbering)
+        {
+            OPstream toMaster
+            (
+                Pstream::commsTypes::scheduled,
+                Pstream::masterNo()
+            );
+            toMaster<< adjncy << SubList<label>(xadj, xadj.size()-1)
+                << cWeights;
+        }
+
+        // Receive back decomposition
+        IPstream fromMaster
+        (
+            Pstream::commsTypes::scheduled,
+            Pstream::masterNo()
+        );
+        fromMaster >> decomp;
+    }
+
+    return 0;
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::metisLikeDecomp::metisLikeDecomp(const dictionary& decompositionDict)
+:
+    decompositionMethod(decompositionDict)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+Foam::labelList Foam::metisLikeDecomp::decompose
+(
+    const polyMesh& mesh,
+    const pointField& points,
+    const scalarField& pointWeights
+)
+{
+    if (points.size() != mesh.nCells())
+    {
+        FatalErrorInFunction
+            << "Can use this decomposition method only for entire mesh" << nl
+            << "and supply one coordinate (cellCentre) for every cell." << nl
+            << "The number of coordinates " << points.size() << nl
+            << "The number of cells in the mesh " << mesh.nCells()
+            << exit(FatalError);
+    }
+
+    CompactListList<label> cellCells;
+    calcCellCells
+    (
+        mesh,
+        identity(mesh.nCells()),
+        mesh.nCells(),
+        false,
+        cellCells
+    );
+
+    // Decompose using default weights
+    labelList decomp;
+    decomposeGeneral(cellCells.m(), cellCells.offsets(), pointWeights, decomp);
+
+    return decomp;
+}
+
+
+Foam::labelList Foam::metisLikeDecomp::decompose
+(
+    const polyMesh& mesh,
+    const labelList& agglom,
+    const pointField& agglomPoints,
+    const scalarField& agglomWeights
+)
+{
+    if (agglom.size() != mesh.nCells())
+    {
+        FatalErrorInFunction
+            << "Size of cell-to-coarse map " << agglom.size()
+            << " differs from number of cells in mesh " << mesh.nCells()
+            << exit(FatalError);
+    }
+
+    // Make Metis CSR (Compressed Storage Format) storage
+    //   adjncy      : contains neighbours (= edges in graph)
+    //   xadj(celli) : start of information in adjncy for celli
+
+    CompactListList<label> cellCells;
+    calcCellCells(mesh, agglom, agglomPoints.size(), false, cellCells);
+
+    // Decompose using default weights
+    labelList decomp;
+    decomposeGeneral(cellCells.m(), cellCells.offsets(), agglomWeights, decomp);
+
+
+    // Rework back into decomposition for original mesh
+    labelList fineDistribution(agglom.size());
+
+    forAll(fineDistribution, i)
+    {
+        fineDistribution[i] = decomp[agglom[i]];
+    }
+
+    return fineDistribution;
+}
+
+
+Foam::labelList Foam::metisLikeDecomp::decompose
+(
+    const labelListList& globalCellCells,
+    const pointField& cellCentres,
+    const scalarField& cellWeights
+)
+{
+    if (cellCentres.size() != globalCellCells.size())
+    {
+        FatalErrorInFunction
+            << "Inconsistent number of cells (" << globalCellCells.size()
+            << ") and number of cell centres (" << cellCentres.size()
+            << ")." << exit(FatalError);
+    }
+
+    // Make Metis CSR (Compressed Storage Format) storage
+    //   adjncy      : contains neighbours (= edges in graph)
+    //   xadj(celli) : start of information in adjncy for celli
+
+    CompactListList<label> cellCells(globalCellCells);
+
+    // Decompose using default weights
+    labelList decomp;
+    decomposeGeneral(cellCells.m(), cellCells.offsets(), cellWeights, decomp);
+
+    return decomp;
+}
+
+// ************************************************************************* //
diff --git a/src/parallel/decompose/decompositionMethods/metisLikeDecomp/metisLikeDecomp.H b/src/parallel/decompose/decompositionMethods/metisLikeDecomp/metisLikeDecomp.H
new file mode 100644
index 0000000000000000000000000000000000000000..8c8a6c9e87f12fda6e78d7732645eb901450c97c
--- /dev/null
+++ b/src/parallel/decompose/decompositionMethods/metisLikeDecomp/metisLikeDecomp.H
@@ -0,0 +1,151 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  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/>.
+
+Class
+    Foam::metisLikeDecomp
+
+Description
+    Domain decomposition using METIS-like data structures.
+
+    When run in parallel will collect the entire graph on to the master,
+    decompose and send back.
+
+SourceFiles
+    metisLikeDecomp.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef metisLikeDecomp_H
+#define metisLikeDecomp_H
+
+#include "decompositionMethod.H"
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                       Class metisLikeDecomp Declaration
+\*---------------------------------------------------------------------------*/
+
+class metisLikeDecomp
+:
+    public decompositionMethod
+{
+    // Private Member Functions
+
+        //- Disallow default bitwise copy construct and assignment
+        void operator=(const metisLikeDecomp&) = delete;
+        metisLikeDecomp(const metisLikeDecomp&) = delete;
+
+
+protected:
+
+    // Protected Member Functions
+
+        //- Serial and/or collect/distribute for parallel operation
+        virtual label decomposeGeneral
+        (
+            const UList<label>& adjncy,
+            const UList<label>& xadj,
+            const UList<scalar>& cellWeights,
+            List<label>& decomp
+        );
+
+        //- Decomposition with metis-like parameters
+        virtual label decomposeSerial
+        (
+            const UList<label>& adjncy,
+            const UList<label>& xadj,
+            const UList<scalar>& cellWeights,
+            List<label>& decomp
+        ) = 0;
+
+public:
+
+    // Constructors
+
+        //- Construct given the decomposition dictionary
+        metisLikeDecomp(const dictionary& decompositionDict);
+
+
+    //- Destructor
+    virtual ~metisLikeDecomp()
+    {}
+
+
+    // Member Functions
+
+        //- Inherit decompose from decompositionMethod
+        using decompositionMethod::decompose;
+
+        //- Return for every coordinate the wanted processor number.
+        //  Uses the mesh connectivity (if needed).
+        //  Weights get normalised so the minimum value is 1 before truncation
+        //  to an integer so the weights should be multiples of the minimum
+        //  value. The overall sum of weights might otherwise overflow.
+        virtual labelList decompose
+        (
+            const polyMesh& mesh,
+            const pointField& points,
+            const scalarField& pointWeights
+        );
+
+        //- Return for every coordinate the wanted processor number.
+        //  Gets passed agglomeration map (from fine to coarse cells) and coarse
+        //  cell location. Can be overridden by decomposers that provide this
+        //  functionality natively.
+        //  See note on weights above.
+        virtual labelList decompose
+        (
+            const polyMesh& mesh,
+            const labelList& agglom,
+            const pointField& regionPoints,
+            const scalarField& regionWeights
+        );
+
+        //- Return for every coordinate the wanted processor number.
+        //  Explicitly provided mesh connectivity.
+        //  The connectivity is equal to mesh.cellCells() except for
+        //  - in parallel the cell numbers are global cell numbers (starting
+        //    from 0 at processor0 and then incrementing all through the
+        //    processors)
+        //  - the connections are across coupled patches
+        //  See note on weights above.
+        virtual labelList decompose
+        (
+            const labelListList& globalCellCells,
+            const pointField& cellCentres,
+            const scalarField& cellWeights
+        );
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/parallel/decompose/kahipDecomp/Make/files b/src/parallel/decompose/kahipDecomp/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..eb01da59a368268784cc0c2cde796efc3c71c0b7
--- /dev/null
+++ b/src/parallel/decompose/kahipDecomp/Make/files
@@ -0,0 +1,3 @@
+kahipDecomp.C
+
+LIB = $(FOAM_LIBBIN)/libkahipDecomp
diff --git a/src/parallel/decompose/kahipDecomp/Make/options b/src/parallel/decompose/kahipDecomp/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..9c746b309c7f2b795507d0ac3c705fdea9727266
--- /dev/null
+++ b/src/parallel/decompose/kahipDecomp/Make/options
@@ -0,0 +1,13 @@
+EXE_INC = \
+    -I$(KAHIP_ARCH_PATH)/include \
+    -I../decompositionMethods/lnInclude \
+    $(KAHIP_COMP_FLAGS)
+
+/*
+ * The $(KAHIP_ARCH_PATH)/lib$WM_COMPILER_LIB_ARCH path is provided
+ * to support central, non-thirdparty installations
+ */
+LIB_LIBS = \
+    -L$(KAHIP_ARCH_PATH)/lib \
+    -L$(KAHIP_ARCH_PATH)/lib$(WM_COMPILER_LIB_ARCH) \
+    -L$(FOAM_EXT_LIBBIN) $(KAHIP_LINK_FLAGS) -lkahip
diff --git a/src/parallel/decompose/kahipDecomp/kahipDecomp.C b/src/parallel/decompose/kahipDecomp/kahipDecomp.C
new file mode 100644
index 0000000000000000000000000000000000000000..180f8783e040e6bf43da8399e845a560b3a072dc
--- /dev/null
+++ b/src/parallel/decompose/kahipDecomp/kahipDecomp.C
@@ -0,0 +1,329 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  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/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "kahipDecomp.H"
+#include "addToRunTimeSelectionTable.H"
+#include "Time.H"
+
+#include "kaHIP_interface.h"
+
+#include <string>
+#include <map>
+#include <vector>
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    defineTypeNameAndDebug(kahipDecomp, 0);
+    addToRunTimeSelectionTable(decompositionMethod, kahipDecomp, dictionary);
+}
+
+
+const Foam::Enum
+<
+    Foam::kahipDecomp::configs
+>
+Foam::kahipDecomp::configNames
+{
+    { kahipDecomp::configs::FAST, "fast" },
+    { kahipDecomp::configs::ECO, "eco" },
+    { kahipDecomp::configs::STRONG, "strong" },
+    { kahipDecomp::configs::FASTSOCIAL, "fast-social" },
+    { kahipDecomp::configs::ECOSOCIAL, "eco-social" },
+    { kahipDecomp::configs::STRONGSOCIAL, "strong-social" },
+};
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+Foam::label Foam::kahipDecomp::decomposeSerial
+(
+    const UList<label>& adjncy,
+    const UList<label>& xadj,
+    const UList<scalar>& cWeights,
+    List<label>& decomp
+)
+{
+    // Default setup
+    enum configs kahipConfig = configs::FAST;
+    double imbalance = 0.01;
+    int seed = 0;
+    bool verbose = false;
+
+    const dictionary* coeffsDictPtr =
+        decompositionDict_.subDictPtr("kahipCoeffs");
+
+    #if WM_LABEL_SIZE == 64
+    if (xadj.size()-1 > INT_MAX)
+    {
+        FatalErrorInFunction
+            << "Cannot decompose " << (xadj.size()-1) << " cells," << nl
+            << "Exceeded integer limit of " << INT_MAX << nl
+            << exit(FatalError);
+    }
+    #endif
+
+    int numCells = xadj.size()-1;
+
+    // Cell weights (so on the vertices of the dual)
+    List<int> cellWeights;
+
+    // Check for externally provided cellweights and if so initialise weights
+    const scalar minWeights = gMin(cWeights);
+    if (!cWeights.empty())
+    {
+        if (minWeights <= 0)
+        {
+            WarningInFunction
+                << "Illegal minimum weight " << minWeights
+                << endl;
+        }
+
+        if (cWeights.size() != numCells)
+        {
+            FatalErrorInFunction
+                << "Number of cell weights " << cWeights.size()
+                << " does not equal number of cells " << numCells
+                << exit(FatalError);
+        }
+
+        // Convert to integers.
+        cellWeights.setSize(cWeights.size());
+        forAll(cellWeights, i)
+        {
+            cellWeights[i] = int(cWeights[i]/minWeights);
+        }
+    }
+
+    // Additional sizing parameters (testing only)
+    std::map<std::string, std::vector<int>> sizingParams;
+
+    // Check for user supplied weights and decomp options
+    if (coeffsDictPtr)
+    {
+        const dictionary& coeffDict = *coeffsDictPtr;
+
+        //- Find the key in the dictionary and return the corresponding
+        //  enumeration element based on its name.
+        //  Return the default value if the key was not found in the dictionary.
+        //  Fatal if the enumerated name was incorrect.
+
+        kahipConfig =
+            configNames.lookupOrDefault("config", coeffDict, kahipConfig);
+
+        coeffDict.readIfPresent("imbalance", imbalance);
+        coeffDict.readIfPresent("verbose", verbose);
+
+        Info<< "kahipDecomp :"
+            << " config=" << configNames[kahipConfig]
+            << " imbalance=" << imbalance;
+
+        List<int> labels;
+        if
+        (
+            coeffDict.readIfPresent("hierarchy", labels)
+         && !labels.empty()
+        )
+        {
+            std::vector<int> vec;
+            vec.reserve(labels.size()+1);
+
+            // Verify sizing
+
+            int n = 1;
+            for (auto val : labels)
+            {
+                n *= val;
+                vec.push_back(val);
+            }
+
+            if (n != nProcessors_)
+            {
+                // Size mismatch. Try to correct.
+
+                if (nProcessors_ % n)
+                {
+                    WarningInFunction
+                        << "Mismatch in number of processors and "
+                        << "hierarchy specified" << flatOutput(labels) << endl;
+
+                    vec.clear();
+                }
+                else
+                {
+                    // Evenly divisible, add extra hierarchy level
+                    vec.push_back(nProcessors_ / n);
+                }
+            }
+
+            if (!vec.empty())
+            {
+                sizingParams["hierarchy"] = std::move(vec);
+
+                Info<< " hierarchy=" << flatOutput(labels);
+            }
+        }
+
+        if
+        (
+            coeffDict.readIfPresent("distance", labels)
+         && !labels.empty()
+        )
+        {
+            std::vector<int> vec(labels.size());
+
+            forAll(labels, i)
+            {
+                vec[i] = labels[i];
+            }
+
+            sizingParams["distance"] = std::move(vec);
+
+            Info<< " distance=" << flatOutput(labels);
+        }
+
+        if (coeffDict.readIfPresent("seed", seed))
+        {
+            Info<< " seed=" << seed;
+        }
+
+        Info<< endl;
+    }
+    else
+    {
+        Info<< "kahipDecomp :"
+            << " config=" << configNames[kahipConfig]
+            << " imbalance=" << imbalance << endl;
+    }
+
+    // Number of partitions
+    int nParts = nProcessors_;
+
+    // Output: number of cut edges
+    int edgeCut = 0;
+
+    #if WM_LABEL_SIZE == 32
+
+    // Input:
+    int* xadjPtr   = const_cast<UList<int>&>(xadj).begin();
+    int* adjncyPtr = const_cast<UList<int>&>(adjncy).begin();
+
+    // Output: cell -> processor addressing
+    decomp.setSize(numCells);
+    int* decompPtr = decomp.begin();
+
+    #elif WM_LABEL_SIZE == 64
+
+    // input (copy)
+    List<int> xadjCopy(xadj.size());
+    List<int> adjncyCopy(adjncy.size());
+
+    forAll(xadj,i)
+    {
+        xadjCopy[i] = xadj[i];
+    }
+    forAll(adjncy,i)
+    {
+        adjncyCopy[i] = adjncy[i];
+    }
+
+    int* xadjPtr   = xadjCopy.begin();
+    int* adjncyPtr = adjncyCopy.begin();
+
+    if (decomp.size() != numCells)
+    {
+        decomp.clear();
+    }
+
+    // Output: cell -> processor addressing
+    List<int> decompCopy(numCells);
+    int* decompPtr = decompCopy.begin();
+    #endif
+
+#if 0 // WIP: #ifdef KAFFPA_CPP_INTERFACE
+    kaffpa_cpp
+    (
+        &numCells,          // num vertices in graph
+        (cellWeights.size() ? cellWeights.begin() : nullptr), // vertex wts
+        xadjPtr,            // indexing into adjncy
+        nullptr,            // edge wts
+        adjncyPtr,          // neighbour info
+        &nParts,            // nparts
+        &imbalance,         // amount of imbalance allowed
+        !verbose,           // suppress output
+        seed,               // for random
+        int(kahipConfig),
+        &edgeCut,           // [output]
+        decompPtr,          // [output]
+        sizingParams
+    );
+#else
+    kaffpa
+    (
+        &numCells,          // num vertices in graph
+        (cellWeights.size() ? cellWeights.begin() : nullptr), // vertex wts
+        xadjPtr,            // indexing into adjncy
+        nullptr,            // edge wts
+        adjncyPtr,          // neighbour info
+        &nParts,            // nparts
+        &imbalance,         // amount of imbalance allowed
+        !verbose,           // suppress output
+        seed,               // for random
+        int(kahipConfig),
+        &edgeCut,           // [output]
+        decompPtr           // [output]
+    );
+#endif
+
+    #if WM_LABEL_SIZE == 64
+
+    // Drop input copy
+    xadjCopy.clear();
+    adjncyCopy.clear();
+
+    // Copy back to List<label>
+    decomp.setSize(numCells);
+    forAll(decompCopy, i)
+    {
+        decomp[i] = decompCopy[i];
+    }
+
+    decompCopy.clear();
+    #endif
+
+    return edgeCut;
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::kahipDecomp::kahipDecomp(const dictionary& decompositionDict)
+:
+    metisLikeDecomp(decompositionDict)
+{}
+
+
+// ************************************************************************* //
diff --git a/src/parallel/decompose/kahipDecomp/kahipDecomp.H b/src/parallel/decompose/kahipDecomp/kahipDecomp.H
new file mode 100644
index 0000000000000000000000000000000000000000..37cd4b574c6c168dd12b3a8ee50baa4fce83190d
--- /dev/null
+++ b/src/parallel/decompose/kahipDecomp/kahipDecomp.H
@@ -0,0 +1,143 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  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/>.
+
+Class
+    Foam::kahipDecomp
+
+Description
+    Domain decomposition using KaHIP
+    http://algo2.iti.kit.edu/documents/kahip/
+
+    When run in parallel will collect the entire graph on to the master,
+    decompose and send back.
+
+    \verbatim
+    numberOfSubdomains   N;
+    method               kahip;
+
+    kahipCoeffs
+    {
+        config          fast;
+        imbalance       0.01;
+    }
+    \endverbatim
+
+    Where the coefficients dictionary is optional, as are all its entries:
+    \table
+        Property  | Description                                 | Default value
+        config    | fast / eco / strong                         | fast
+        imbalance | imbalance on cells between domains          | 0.01
+        seed      | initial value for random number generator   | 0
+    \endtable
+
+SourceFiles
+    kahipDecomp.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef kahipDecomp_H
+#define kahipDecomp_H
+
+#include "metisLikeDecomp.H"
+#include "Enum.H"
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                         Class kahipDecomp Declaration
+\*---------------------------------------------------------------------------*/
+
+class kahipDecomp
+:
+    public metisLikeDecomp
+{
+
+    // Private Member Functions
+
+        //- Call kahip with options from dictionary.
+        virtual label decomposeSerial
+        (
+            const UList<label>& adjncy,
+            const UList<label>& xadj,
+            const UList<scalar>& cellWeights,
+            List<label>& decomp
+        );
+
+        //- Disallow default bitwise copy construct and assignment
+        void operator=(const kahipDecomp&) = delete;
+        kahipDecomp(const kahipDecomp&) = delete;
+
+
+public:
+
+    //- The predefined KaHIP configuration types
+    enum class configs
+    {
+        FAST = 0, //!< default
+        ECO = 1,
+        STRONG = 2,
+        FASTSOCIAL = 3,
+        ECOSOCIAL = 4,
+        STRONGSOCIAL = 5,
+    };
+
+
+    //- The selection names for predefined KaHIP configurations
+    static const Enum<configs> configNames;
+
+
+    //- Runtime type information
+    TypeName("kahip");
+
+
+    // Constructors
+
+        //- Construct given the decomposition dictionary
+        kahipDecomp(const dictionary& decompositionDict);
+
+
+    //- Destructor
+    virtual ~kahipDecomp()
+    {}
+
+
+    // Member Functions
+
+        virtual bool parallelAware() const
+        {
+            return true;
+        }
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/parallel/decompose/metisDecomp/metisDecomp.C b/src/parallel/decompose/metisDecomp/metisDecomp.C
index 2cb09cbb77cbc672438f9d0954f2616435d16b82..cfc896d2518d1a00cd6e0e79f44277538e940bfc 100644
--- a/src/parallel/decompose/metisDecomp/metisDecomp.C
+++ b/src/parallel/decompose/metisDecomp/metisDecomp.C
@@ -45,13 +45,12 @@ namespace Foam
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
-Foam::label Foam::metisDecomp::decompose
+Foam::label Foam::metisDecomp::decomposeSerial
 (
-    const List<label>& adjncy,
-    const List<label>& xadj,
-    const scalarField& cWeights,
-
-    List<label>& finalDecomp
+    const UList<label>& adjncy,
+    const UList<label>& xadj,
+    const UList<scalar>& cWeights,
+    List<label>& decomp
 )
 {
     // Method of decomposition
@@ -59,6 +58,9 @@ Foam::label Foam::metisDecomp::decompose
     // k-way: multi-level k-way
     word method("recursive");
 
+    const dictionary* coeffsDictPtr =
+        decompositionDict_.subDictPtr("metisCoeffs");
+
     label numCells = xadj.size()-1;
 
     // Decomposition options
@@ -77,7 +79,7 @@ Foam::label Foam::metisDecomp::decompose
 
 
     // Check for externally provided cellweights and if so initialise weights
-    scalar minWeights = gMin(cWeights);
+    const scalar minWeights = gMin(cWeights);
     if (cWeights.size() > 0)
     {
         if (minWeights <= 0)
@@ -105,14 +107,13 @@ Foam::label Foam::metisDecomp::decompose
 
 
     // Check for user supplied weights and decomp options
-    if (decompositionDict_.found("metisCoeffs"))
+    if (coeffsDictPtr)
     {
-        const dictionary& metisCoeffs =
-            decompositionDict_.subDict("metisCoeffs");
+        const dictionary& coeffDict = *coeffsDictPtr;
 
         word weightsFile;
 
-        if (metisCoeffs.readIfPresent("method", method))
+        if (coeffDict.readIfPresent("method", method))
         {
             if (method != "recursive" && method != "k-way")
             {
@@ -127,7 +128,7 @@ Foam::label Foam::metisDecomp::decompose
                 << nl << endl;
         }
 
-        if (metisCoeffs.readIfPresent("options", options))
+        if (coeffDict.readIfPresent("options", options))
         {
             if (options.size() != METIS_NOPTIONS)
             {
@@ -142,7 +143,7 @@ Foam::label Foam::metisDecomp::decompose
                 << nl << endl;
         }
 
-        if (metisCoeffs.readIfPresent("processorWeights", processorWeights))
+        if (coeffDict.readIfPresent("processorWeights", processorWeights))
         {
             processorWeights /= sum(processorWeights);
 
@@ -161,7 +162,7 @@ Foam::label Foam::metisDecomp::decompose
     label nProcs = nProcessors_;
 
     // Output: cell -> processor addressing
-    finalDecomp.setSize(numCells);
+    decomp.setSize(numCells);
 
     // Output: number of cut edges
     label edgeCut = 0;
@@ -172,17 +173,17 @@ Foam::label Foam::metisDecomp::decompose
         (
             &numCells,          // num vertices in graph
             &ncon,              // num balancing constraints
-            const_cast<List<label>&>(xadj).begin(),   // indexing into adjncy
-            const_cast<List<label>&>(adjncy).begin(), // neighbour info
-            cellWeights.begin(),// vertexweights
+            const_cast<UList<label>&>(xadj).begin(),   // indexing into adjncy
+            const_cast<UList<label>&>(adjncy).begin(), // neighbour info
+            cellWeights.begin(),// vertex wts
             nullptr,               // vsize: total communication vol
-            faceWeights.begin(),// edgeweights
+            faceWeights.begin(),// edge wts
             &nProcs,            // nParts
             processorWeights.begin(),   // tpwgts
             nullptr,               // ubvec: processor imbalance (default)
             options.begin(),
             &edgeCut,
-            finalDecomp.begin()
+            decomp.begin()
         );
     }
     else
@@ -191,17 +192,17 @@ Foam::label Foam::metisDecomp::decompose
         (
             &numCells,          // num vertices in graph
             &ncon,              // num balancing constraints
-            const_cast<List<label>&>(xadj).begin(),   // indexing into adjncy
-            const_cast<List<label>&>(adjncy).begin(), // neighbour info
-            cellWeights.begin(),// vertexweights
+            const_cast<UList<label>&>(xadj).begin(),   // indexing into adjncy
+            const_cast<UList<label>&>(adjncy).begin(), // neighbour info
+            cellWeights.begin(),// vertex wts
             nullptr,               // vsize: total communication vol
-            faceWeights.begin(),// edgeweights
+            faceWeights.begin(),// edge wts
             &nProcs,            // nParts
             processorWeights.begin(),   // tpwgts
             nullptr,               // ubvec: processor imbalance (default)
             options.begin(),
             &edgeCut,
-            finalDecomp.begin()
+            decomp.begin()
         );
     }
 
@@ -213,116 +214,8 @@ Foam::label Foam::metisDecomp::decompose
 
 Foam::metisDecomp::metisDecomp(const dictionary& decompositionDict)
 :
-    decompositionMethod(decompositionDict)
+    metisLikeDecomp(decompositionDict)
 {}
 
 
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
-
-Foam::labelList Foam::metisDecomp::decompose
-(
-    const polyMesh& mesh,
-    const pointField& points,
-    const scalarField& pointWeights
-)
-{
-    if (points.size() != mesh.nCells())
-    {
-        FatalErrorInFunction
-            << "Can use this decomposition method only for the whole mesh"
-            << endl
-            << "and supply one coordinate (cellCentre) for every cell." << endl
-            << "The number of coordinates " << points.size() << endl
-            << "The number of cells in the mesh " << mesh.nCells()
-            << exit(FatalError);
-    }
-
-    CompactListList<label> cellCells;
-    calcCellCells
-    (
-        mesh,
-        identity(mesh.nCells()),
-        mesh.nCells(),
-        false,
-        cellCells
-    );
-
-    // Decompose using default weights
-    labelList decomp;
-    decompose(cellCells.m(), cellCells.offsets(), pointWeights, decomp);
-
-    return decomp;
-}
-
-
-Foam::labelList Foam::metisDecomp::decompose
-(
-    const polyMesh& mesh,
-    const labelList& agglom,
-    const pointField& agglomPoints,
-    const scalarField& agglomWeights
-)
-{
-    if (agglom.size() != mesh.nCells())
-    {
-        FatalErrorInFunction
-            << "Size of cell-to-coarse map " << agglom.size()
-            << " differs from number of cells in mesh " << mesh.nCells()
-            << exit(FatalError);
-    }
-
-    // Make Metis CSR (Compressed Storage Format) storage
-    //   adjncy      : contains neighbours (= edges in graph)
-    //   xadj(celli) : start of information in adjncy for celli
-
-    CompactListList<label> cellCells;
-    calcCellCells(mesh, agglom, agglomPoints.size(), false, cellCells);
-
-    // Decompose using default weights
-    labelList finalDecomp;
-    decompose(cellCells.m(), cellCells.offsets(), agglomWeights, finalDecomp);
-
-
-    // Rework back into decomposition for original mesh
-    labelList fineDistribution(agglom.size());
-
-    forAll(fineDistribution, i)
-    {
-        fineDistribution[i] = finalDecomp[agglom[i]];
-    }
-
-    return fineDistribution;
-}
-
-
-Foam::labelList Foam::metisDecomp::decompose
-(
-    const labelListList& globalCellCells,
-    const pointField& cellCentres,
-    const scalarField& cellWeights
-)
-{
-    if (cellCentres.size() != globalCellCells.size())
-    {
-        FatalErrorInFunction
-            << "Inconsistent number of cells (" << globalCellCells.size()
-            << ") and number of cell centres (" << cellCentres.size()
-            << ")." << exit(FatalError);
-    }
-
-
-    // Make Metis CSR (Compressed Storage Format) storage
-    //   adjncy      : contains neighbours (= edges in graph)
-    //   xadj(celli) : start of information in adjncy for celli
-
-    CompactListList<label> cellCells(globalCellCells);
-
-    // Decompose using default weights
-    labelList decomp;
-    decompose(cellCells.m(), cellCells.offsets(), cellWeights, decomp);
-
-    return decomp;
-}
-
-
 // ************************************************************************* //
diff --git a/src/parallel/decompose/metisDecomp/metisDecomp.H b/src/parallel/decompose/metisDecomp/metisDecomp.H
index 84dc04bd938d48ac0cb5c46ebed4ff1024741fbb..a851b0496b5cb6d937f94060e43e45128c64b784 100644
--- a/src/parallel/decompose/metisDecomp/metisDecomp.H
+++ b/src/parallel/decompose/metisDecomp/metisDecomp.H
@@ -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.
@@ -27,6 +27,29 @@ Class
 Description
     Metis domain decomposition
 
+    When run in parallel will collect the entire graph on to the master,
+    decompose and send back.
+
+    \verbatim
+    numberOfSubdomains   N;
+    method               metis;
+
+    metisCoeffs
+    {
+        method          recursive;  // k-way
+        options          ( ...);
+        processorWeights (   ... );
+    }
+    \endverbatim
+
+    Where the coefficients dictionary is optional, as are all its entries:
+    \table
+        Property  | Description                             | Default value
+        method    | recursive / k-way                       | recursive
+        options   | metis options                           |
+        processorWeights | list of weighting per partition  |
+    \endtable
+
 SourceFiles
     metisDecomp.C
 
@@ -35,7 +58,7 @@ SourceFiles
 #ifndef metisDecomp_H
 #define metisDecomp_H
 
-#include "decompositionMethod.H"
+#include "metisLikeDecomp.H"
 
 namespace Foam
 {
@@ -46,23 +69,23 @@ namespace Foam
 
 class metisDecomp
 :
-    public decompositionMethod
+    public metisLikeDecomp
 {
 
     // Private Member Functions
 
         //- Call Metis with options from dictionary.
-        label decompose
+        virtual label decomposeSerial
         (
-            const List<label>& adjncy,
-            const List<label>& xadj,
-            const scalarField& cellWeights,
-            List<label>& finalDecomp
+            const UList<label>& adjncy,
+            const UList<label>& xadj,
+            const UList<scalar>& cellWeights,
+            List<label>& decomp
         );
 
         //- Disallow default bitwise copy construct and assignment
-        void operator=(const metisDecomp&);
-        metisDecomp(const metisDecomp&);
+        void operator=(const metisDecomp&) = delete;
+        metisDecomp(const metisDecomp&) = delete;
 
 
 public:
@@ -74,7 +97,7 @@ public:
     // Constructors
 
         //- Construct given the decomposition dictionary
-        metisDecomp(const dictionary&);
+        metisDecomp(const dictionary& decompositionDict);
 
 
     //- Destructor
@@ -86,52 +109,9 @@ public:
 
         virtual bool parallelAware() const
         {
-            // Metis does not know about proc boundaries
-            return false;
+            return true;
         }
 
-        //- Inherit decompose from decompositionMethod
-        using decompositionMethod::decompose;
-
-        //- Return for every coordinate the wanted processor number. Use the
-        //  mesh connectivity (if needed)
-        //  Weights get normalised so the minimum value is 1 before truncation
-        //  to an integer so the weights should be multiples of the minimum
-        //  value. The overall sum of weights might otherwise overflow.
-        virtual labelList decompose
-        (
-            const polyMesh& mesh,
-            const pointField& points,
-            const scalarField& pointWeights
-        );
-
-        //- Return for every coordinate the wanted processor number. Gets
-        //  passed agglomeration map (from fine to coarse cells) and coarse cell
-        //  location. Can be overridden by decomposers that provide this
-        //  functionality natively.
-        //  See note on weights above.
-        virtual labelList decompose
-        (
-            const polyMesh& mesh,
-            const labelList& agglom,
-            const pointField& regionPoints,
-            const scalarField& regionWeights
-        );
-
-        //- Return for every coordinate the wanted processor number. Explicitly
-        //  provided mesh connectivity.
-        //  The connectivity is equal to mesh.cellCells() except for
-        //  - in parallel the cell numbers are global cell numbers (starting
-        //    from 0 at processor0 and then incrementing all through the
-        //    processors)
-        //  - the connections are across coupled patches
-        //  See note on weights above.
-        virtual labelList decompose
-        (
-            const labelListList& globalCellCells,
-            const pointField& cc,
-            const scalarField& cWeights
-        );
 };
 
 
diff --git a/src/parallel/decompose/ptscotchDecomp/ptscotchDecomp.C b/src/parallel/decompose/ptscotchDecomp/ptscotchDecomp.C
index d0035de8d8b1e337e22000a97b4cabcc5568e023..95b8647ee4a0a09dd25144c07747bcbd9b806a2d 100644
--- a/src/parallel/decompose/ptscotchDecomp/ptscotchDecomp.C
+++ b/src/parallel/decompose/ptscotchDecomp/ptscotchDecomp.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2017 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2015 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2015-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -228,12 +228,17 @@ License
 namespace Foam
 {
     defineTypeNameAndDebug(ptscotchDecomp, 0);
-
     addToRunTimeSelectionTable(decompositionMethod, ptscotchDecomp, dictionary);
 }
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
+void Foam::ptscotchDecomp::graphPath(const polyMesh& mesh)
+{
+    graphPath_ = mesh.time().path()/mesh.name();
+}
+
+
 void Foam::ptscotchDecomp::check(const int retVal, const char* str)
 {
     if (retVal)
@@ -248,11 +253,9 @@ void Foam::ptscotchDecomp::check(const int retVal, const char* str)
 ////- Does prevention of 0 cell domains and calls ptscotch.
 //Foam::label Foam::ptscotchDecomp::decomposeZeroDomains
 //(
-//    const fileName& meshPath,
-//    const List<label>& initadjncy,
-//    const List<label>& initxadj,
-//    const scalarField& initcWeights,
-//
+//    const UList<label>& initadjncy,
+//    const UList<label>& initxadj,
+//    const UList<scalar>& initcWeights,
 //    List<label>& finalDecomp
 //) const
 //{
@@ -272,7 +275,6 @@ void Foam::ptscotchDecomp::check(const int retVal, const char* str)
 //    {
 //        return decompose
 //        (
-//            meshPath,
 //            initadjncy,
 //            initxadj,
 //            initcWeights,
@@ -381,7 +383,7 @@ void Foam::ptscotchDecomp::check(const int retVal, const char* str)
 //
 //
 //    // Do decomposition as normal. Sets finalDecomp.
-//    label result = decompose(meshPath, adjncy, xadj, cWeights, finalDecomp);
+//    label result = decompose(adjncy, xadj, cWeights, finalDecomp);
 //
 //
 //    if (debug)
@@ -437,23 +439,19 @@ void Foam::ptscotchDecomp::check(const int retVal, const char* str)
 //}
 
 
-// Call scotch with options from dictionary.
 Foam::label Foam::ptscotchDecomp::decompose
 (
-    const fileName& meshPath,
-    const List<label>& adjncy,
-    const List<label>& xadj,
-    const scalarField& cWeights,
+    const UList<label>& adjncy,
+    const UList<label>& xadj,
+    const UList<scalar>& cWeights,
     List<label>& finalDecomp
 ) const
 {
-    List<label> dummyAdjncy(1);
-    List<label> dummyXadj(1);
-    dummyXadj[0] = 0;
+    List<label> dummyAdjncy { 0 };
+    List<label> dummyXadj { 0 };
 
     return decompose
     (
-        meshPath,
         adjncy.size(),
         (adjncy.size() ? adjncy.begin() : dummyAdjncy.begin()),
         xadj.size(),
@@ -464,16 +462,13 @@ Foam::label Foam::ptscotchDecomp::decompose
 }
 
 
-// Call scotch with options from dictionary.
 Foam::label Foam::ptscotchDecomp::decompose
 (
-    const fileName& meshPath,
     const label adjncySize,
     const label adjncy[],
     const label xadjSize,
     const label xadj[],
-    const scalarField& cWeights,
-
+    const UList<scalar>& cWeights,
     List<label>& finalDecomp
 ) const
 {
@@ -492,7 +487,7 @@ Foam::label Foam::ptscotchDecomp::decompose
         {
             OFstream str
             (
-               meshPath + "_" + Foam::name(Pstream::myProcNo()) + ".dgr"
+               graphPath_ + "_" + Foam::name(Pstream::myProcNo()) + ".dgr"
             );
 
             Pout<< "Dumping Scotch graph file to " << str.name() << endl
@@ -572,8 +567,8 @@ Foam::label Foam::ptscotchDecomp::decompose
 
     // Check for externally provided cellweights and if so initialise weights
 
-    scalar minWeights = gMin(cWeights);
-    scalar maxWeights = gMax(cWeights);
+    const scalar minWeights = gMin(cWeights);
+    const scalar maxWeights = gMax(cWeights);
 
     if (maxWeights > minWeights)
     {
@@ -719,7 +714,10 @@ Foam::label Foam::ptscotchDecomp::decompose
         }
         check
         (
-            SCOTCH_archCmpltw(&archdat, nProcessors_, processorWeights.begin()),
+            SCOTCH_archCmpltw
+            (
+                &archdat, nProcessors_, processorWeights.begin()
+            ),
             "SCOTCH_archCmpltw"
         );
     }
@@ -819,6 +817,9 @@ Foam::labelList Foam::ptscotchDecomp::decompose
     const scalarField& pointWeights
 )
 {
+    // Where to write graph
+    graphPath(mesh);
+
     if (points.size() != mesh.nCells())
     {
         FatalErrorInFunction
@@ -835,7 +836,6 @@ Foam::labelList Foam::ptscotchDecomp::decompose
     //   adjncy      : contains neighbours (= edges in graph)
     //   xadj(celli) : start of information in adjncy for celli
 
-
     CompactListList<label> cellCells;
     calcCellCells
     (
@@ -847,22 +847,15 @@ Foam::labelList Foam::ptscotchDecomp::decompose
     );
 
     // Decompose using default weights
-    List<label> finalDecomp;
+    labelList decomp;
     decompose
     (
-        mesh.time().path()/mesh.name(),
         cellCells.m(),
         cellCells.offsets(),
         pointWeights,
-        finalDecomp
+        decomp
     );
 
-    // Copy back to labelList
-    labelList decomp(points.size());
-    forAll(decomp, i)
-    {
-        decomp[i] = finalDecomp[i];
-    }
     return decomp;
 }
 
@@ -875,6 +868,9 @@ Foam::labelList Foam::ptscotchDecomp::decompose
     const scalarField& pointWeights
 )
 {
+    // Where to write graph
+    graphPath(mesh);
+
     if (agglom.size() != mesh.nCells())
     {
         FatalErrorInFunction
@@ -898,14 +894,13 @@ Foam::labelList Foam::ptscotchDecomp::decompose
     );
 
     // Decompose using weights
-    List<label> finalDecomp;
+    labelList decomp;
     decompose
     (
-        mesh.time().path()/mesh.name(),
         cellCells.m(),
         cellCells.offsets(),
         pointWeights,
-        finalDecomp
+        decomp
     );
 
     // Rework back into decomposition for original mesh
@@ -913,7 +908,7 @@ Foam::labelList Foam::ptscotchDecomp::decompose
 
     forAll(fineDistribution, i)
     {
-        fineDistribution[i] = finalDecomp[agglom[i]];
+        fineDistribution[i] = decomp[agglom[i]];
     }
 
     return fineDistribution;
@@ -927,6 +922,9 @@ Foam::labelList Foam::ptscotchDecomp::decompose
     const scalarField& cWeights
 )
 {
+    // Where to write graph
+    graphPath_ = "ptscotch";
+
     if (cellCentres.size() != globalCellCells.size())
     {
         FatalErrorInFunction
@@ -943,22 +941,15 @@ Foam::labelList Foam::ptscotchDecomp::decompose
     CompactListList<label> cellCells(globalCellCells);
 
     // Decompose using weights
-    List<label> finalDecomp;
+    labelList decomp;
     decompose
     (
-        "ptscotch",
         cellCells.m(),
         cellCells.offsets(),
         cWeights,
-        finalDecomp
+        decomp
     );
 
-    // Copy back to labelList
-    labelList decomp(cellCentres.size());
-    forAll(decomp, i)
-    {
-        decomp[i] = finalDecomp[i];
-    }
     return decomp;
 }
 
diff --git a/src/parallel/decompose/ptscotchDecomp/ptscotchDecomp.H b/src/parallel/decompose/ptscotchDecomp/ptscotchDecomp.H
index 5ff4d47e8471927c5a6876ad2b990c1183052c26..039dd511d01baae1da7f6c67fcee572e3b64493e 100644
--- a/src/parallel/decompose/ptscotchDecomp/ptscotchDecomp.H
+++ b/src/parallel/decompose/ptscotchDecomp/ptscotchDecomp.H
@@ -64,36 +64,43 @@ class ptscotchDecomp
 :
     public decompositionMethod
 {
+    // Private data
+
+        //- Output path and name for optional grf file.
+        fileName graphPath_;
+
+
     // Private Member Functions
 
+        //- Set graph path and name
+        void graphPath(const polyMesh& mesh);
+
         //- Check and print error message
         static void check(const int, const char*);
 
         //- Decompose. Handles size 0 arrays
         label decompose
         (
-            const fileName& meshPath,
-            const List<label>& adjncy,
-            const List<label>& xadj,
-            const scalarField& cWeights,
+            const UList<label>& adjncy,
+            const UList<label>& xadj,
+            const UList<scalar>& cWeights,
             List<label>& finalDecomp
         ) const;
 
         //- Low level decompose
         label decompose
         (
-            const fileName& meshPath,
             const label adjncySize,
             const label adjncy[],
             const label xadjSize,
             const label xadj[],
-            const scalarField& cWeights,
+            const UList<scalar>& cWeights,
             List<label>& finalDecomp
         ) const;
 
         //- Disallow default bitwise copy construct and assignment
-        void operator=(const ptscotchDecomp&);
-        ptscotchDecomp(const ptscotchDecomp&);
+        void operator=(const ptscotchDecomp&) = delete;
+        ptscotchDecomp(const ptscotchDecomp&) = delete;
 
 
 public:
diff --git a/src/parallel/decompose/scotchDecomp/scotchDecomp.C b/src/parallel/decompose/scotchDecomp/scotchDecomp.C
index 45af4fa1e64b1661ca0989899f632e8e608c4f1c..faea40b866832bcc6d139c3f400a4d2d3f3781b5 100644
--- a/src/parallel/decompose/scotchDecomp/scotchDecomp.C
+++ b/src/parallel/decompose/scotchDecomp/scotchDecomp.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2017 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2015 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2015-2017 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -126,8 +126,6 @@ License
 #include "floatScalar.H"
 #include "Time.H"
 #include "OFstream.H"
-#include "globalIndex.H"
-#include "SubField.H"
 
 extern "C"
 {
@@ -161,6 +159,12 @@ namespace Foam
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
+void Foam::scotchDecomp::graphPath(const polyMesh& mesh)
+{
+    graphPath_ = mesh.time().path()/mesh.name() + ".grf";
+}
+
+
 void Foam::scotchDecomp::check(const int retVal, const char* str)
 {
     if (retVal)
@@ -172,186 +176,53 @@ void Foam::scotchDecomp::check(const int retVal, const char* str)
 }
 
 
-Foam::label Foam::scotchDecomp::decompose
+Foam::label Foam::scotchDecomp::decomposeSerial
 (
-    const fileName& meshPath,
-    const List<label>& adjncy,
-    const List<label>& xadj,
-    const scalarField& cWeights,
-
-    List<label>& finalDecomp
+    const UList<label>& adjncy,
+    const UList<label>& xadj,
+    const UList<scalar>& cWeights,
+    List<label>& decomp
 )
 {
-    if (!Pstream::parRun())
-    {
-        decomposeOneProc
-        (
-            meshPath,
-            adjncy,
-            xadj,
-            cWeights,
-            finalDecomp
-        );
-    }
-    else
-    {
-        if (debug)
-        {
-            Info<< "scotchDecomp : running in parallel."
-                << " Decomposing all of graph on master processor." << endl;
-        }
-        globalIndex globalCells(xadj.size()-1);
-        label nTotalConnections = returnReduce(adjncy.size(), sumOp<label>());
-
-        // Send all to master. Use scheduled to save some storage.
-        if (Pstream::master())
-        {
-            Field<label> allAdjncy(nTotalConnections);
-            Field<label> allXadj(globalCells.size()+1);
-            scalarField allWeights(globalCells.size());
-
-            // Insert my own
-            label nTotalCells = 0;
-            forAll(cWeights, celli)
-            {
-                allXadj[nTotalCells] = xadj[celli];
-                allWeights[nTotalCells++] = cWeights[celli];
-            }
-            nTotalConnections = 0;
-            forAll(adjncy, i)
-            {
-                allAdjncy[nTotalConnections++] = adjncy[i];
-            }
+    const dictionary* coeffsDictPtr =
+        decompositionDict_.subDictPtr("scotchCoeffs");
 
-            for (int slave=1; slave<Pstream::nProcs(); slave++)
-            {
-                IPstream fromSlave(Pstream::commsTypes::scheduled, slave);
-                Field<label> nbrAdjncy(fromSlave);
-                Field<label> nbrXadj(fromSlave);
-                scalarField nbrWeights(fromSlave);
-
-                // Append.
-                //label procStart = nTotalCells;
-                forAll(nbrXadj, celli)
-                {
-                    allXadj[nTotalCells] = nTotalConnections+nbrXadj[celli];
-                    allWeights[nTotalCells++] = nbrWeights[celli];
-                }
-                // No need to renumber xadj since already global.
-                forAll(nbrAdjncy, i)
-                {
-                    allAdjncy[nTotalConnections++] = nbrAdjncy[i];
-                }
-            }
-            allXadj[nTotalCells] = nTotalConnections;
+    // Dump graph
+    if (coeffsDictPtr && coeffsDictPtr->lookupOrDefault("writeGraph", false))
+    {
+        OFstream str(graphPath_);
 
+        Info<< "Dumping Scotch graph file to " << str.name() << endl
+            << "Use this in combination with gpart." << endl;
 
-            Field<label> allFinalDecomp;
-            decomposeOneProc
-            (
-                meshPath,
-                allAdjncy,
-                allXadj,
-                allWeights,
-                allFinalDecomp
-            );
+        const label version = 0;
+        str << version << nl;
+        // Numer of vertices
+        str << xadj.size()-1 << ' ' << adjncy.size() << nl;
 
+        // Numbering starts from 0
+        const label baseval = 0;
+        // Has weights?
+        const label hasEdgeWeights = 0;
+        const label hasVertexWeights = 0;
+        const label numericflag = 10*hasEdgeWeights+hasVertexWeights;
+        str << baseval << ' ' << numericflag << nl;
 
-            // Send allFinalDecomp back
-            for (int slave=1; slave<Pstream::nProcs(); slave++)
-            {
-                OPstream toSlave(Pstream::commsTypes::scheduled, slave);
-                toSlave << SubField<label>
-                (
-                    allFinalDecomp,
-                    globalCells.localSize(slave),
-                    globalCells.offset(slave)
-                );
-            }
-            // Get my own part (always first)
-            finalDecomp = SubField<label>
-            (
-                allFinalDecomp,
-                globalCells.localSize()
-            );
-        }
-        else
+        for (label celli = 0; celli < xadj.size()-1; ++celli)
         {
-            // Send my part of the graph (already in global numbering)
-            {
-                OPstream toMaster
-                (
-                    Pstream::commsTypes::scheduled,
-                    Pstream::masterNo()
-                );
-                toMaster<< adjncy << SubField<label>(xadj, xadj.size()-1)
-                    << cWeights;
-            }
-
-            // Receive back decomposition
-            IPstream fromMaster
-            (
-                Pstream::commsTypes::scheduled,
-                Pstream::masterNo()
-            );
-            fromMaster >> finalDecomp;
-        }
-    }
-    return 0;
-}
+            const label start = xadj[celli];
+            const label end = xadj[celli+1];
 
+            str << end-start; // size
 
-// Call scotch with options from dictionary.
-Foam::label Foam::scotchDecomp::decomposeOneProc
-(
-    const fileName& meshPath,
-    const List<label>& adjncy,
-    const List<label>& xadj,
-    const scalarField& cWeights,
-
-    List<label>& finalDecomp
-)
-{
-    // Dump graph
-    if (decompositionDict_.found("scotchCoeffs"))
-    {
-        const dictionary& scotchCoeffs =
-            decompositionDict_.subDict("scotchCoeffs");
-
-        if (scotchCoeffs.lookupOrDefault("writeGraph", false))
-        {
-            OFstream str(meshPath + ".grf");
-
-            Info<< "Dumping Scotch graph file to " << str.name() << endl
-                << "Use this in combination with gpart." << endl;
-
-            label version = 0;
-            str << version << nl;
-            // Numer of vertices
-            str << xadj.size()-1 << ' ' << adjncy.size() << nl;
-            // Numbering starts from 0
-            label baseval = 0;
-            // Has weights?
-            label hasEdgeWeights = 0;
-            label hasVertexWeights = 0;
-            label numericflag = 10*hasEdgeWeights+hasVertexWeights;
-            str << baseval << ' ' << numericflag << nl;
-            for (label celli = 0; celli < xadj.size()-1; celli++)
+            for (label i = start; i < end; ++i)
             {
-                label start = xadj[celli];
-                label end = xadj[celli+1];
-                str << end-start;
-
-                for (label i = start; i < end; i++)
-                {
-                    str << ' ' << adjncy[i];
-                }
-                str << nl;
+                str << ' ' << adjncy[i];
             }
+            str << nl;
         }
     }
 
-
     // Strategy
     // ~~~~~~~~
 
@@ -359,13 +230,10 @@ Foam::label Foam::scotchDecomp::decomposeOneProc
     SCOTCH_Strat stradat;
     check(SCOTCH_stratInit(&stradat), "SCOTCH_stratInit");
 
-    if (decompositionDict_.found("scotchCoeffs"))
+    if (coeffsDictPtr)
     {
-        const dictionary& scotchCoeffs =
-            decompositionDict_.subDict("scotchCoeffs");
-
         string strategy;
-        if (scotchCoeffs.readIfPresent("strategy", strategy))
+        if (coeffsDictPtr->readIfPresent("strategy", strategy))
         {
             if (debug)
             {
@@ -384,10 +252,9 @@ Foam::label Foam::scotchDecomp::decomposeOneProc
 
     List<label> velotab;
 
-
     // Check for externally provided cellweights and if so initialise weights
     // Note: min, not gMin since routine runs on master only.
-    scalar minWeights = min(cWeights);
+    const scalar minWeights = min(cWeights);
     if (!cWeights.empty())
     {
         if (minWeights <= 0)
@@ -431,7 +298,6 @@ Foam::label Foam::scotchDecomp::decomposeOneProc
     }
 
 
-
     SCOTCH_Graph grafdat;
     check(SCOTCH_graphInit(&grafdat), "SCOTCH_graphInit");
     check
@@ -462,14 +328,12 @@ Foam::label Foam::scotchDecomp::decomposeOneProc
     check(SCOTCH_archInit(&archdat), "SCOTCH_archInit");
 
     List<label> processorWeights;
-    if (decompositionDict_.found("scotchCoeffs"))
-    {
-        const dictionary& scotchCoeffs =
-            decompositionDict_.subDict("scotchCoeffs");
-
-        scotchCoeffs.readIfPresent("processorWeights", processorWeights);
-    }
-    if (processorWeights.size())
+    if
+    (
+        coeffsDictPtr
+     && coeffsDictPtr->readIfPresent("processorWeights", processorWeights)
+     && processorWeights.size()
+    )
     {
         if (debug)
         {
@@ -478,7 +342,10 @@ Foam::label Foam::scotchDecomp::decomposeOneProc
         }
         check
         (
-            SCOTCH_archCmpltw(&archdat, nProcessors_, processorWeights.begin()),
+            SCOTCH_archCmpltw
+            (
+                &archdat, nProcessors_, processorWeights.begin()
+            ),
             "SCOTCH_archCmpltw"
         );
     }
@@ -491,7 +358,7 @@ Foam::label Foam::scotchDecomp::decomposeOneProc
         );
 
 
-        //- Hack to test clustering. Note that finalDecomp is non-compact
+        //- Hack to test clustering. Note that decomp is non-compact
         //  numbers!
         //
         ////- Set up variable sizes architecture
@@ -542,16 +409,16 @@ Foam::label Foam::scotchDecomp::decomposeOneProc
     );
     #endif
 
-    finalDecomp.setSize(xadj.size()-1);
-    finalDecomp = 0;
+    decomp.setSize(xadj.size()-1);
+    decomp = 0;
     check
     (
         SCOTCH_graphMap
         (
             &grafdat,
             &archdat,
-            &stradat,           // const SCOTCH_Strat *
-            finalDecomp.begin() // parttab
+            &stradat,       // const SCOTCH_Strat *
+            decomp.begin()  // parttab
         ),
         "SCOTCH_graphMap"
     );
@@ -560,17 +427,15 @@ Foam::label Foam::scotchDecomp::decomposeOneProc
     feenableexcept(oldExcepts);
     #endif
 
-
-
-    //finalDecomp.setSize(xadj.size()-1);
+    //decomp.setSize(xadj.size()-1);
     //check
     //(
     //    SCOTCH_graphPart
     //    (
     //        &grafdat,
-    //        nProcessors_,       // partnbr
-    //        &stradat,           // const SCOTCH_Strat *
-    //        finalDecomp.begin() // parttab
+    //        nProcessors_,   // partnbr
+    //        &stradat,       // const SCOTCH_Strat *
+    //        decomp.begin()  // parttab
     //    ),
     //    "SCOTCH_graphPart"
     //);
@@ -590,7 +455,7 @@ Foam::label Foam::scotchDecomp::decomposeOneProc
 
 Foam::scotchDecomp::scotchDecomp(const dictionary& decompositionDict)
 :
-    decompositionMethod(decompositionDict)
+    metisLikeDecomp(decompositionDict)
 {}
 
 
@@ -603,46 +468,15 @@ Foam::labelList Foam::scotchDecomp::decompose
     const scalarField& pointWeights
 )
 {
-    if (points.size() != mesh.nCells())
-    {
-        FatalErrorInFunction
-            << "Can use this decomposition method only for the whole mesh"
-            << endl
-            << "and supply one coordinate (cellCentre) for every cell." << endl
-            << "The number of coordinates " << points.size() << endl
-            << "The number of cells in the mesh " << mesh.nCells()
-            << exit(FatalError);
-    }
+    // Where to write graph
+    graphPath(mesh);
 
-    // Calculate local or global (if Pstream::parRun()) connectivity
-    CompactListList<label> cellCells;
-    calcCellCells
+    return metisLikeDecomp::decompose
     (
         mesh,
-        identity(mesh.nCells()),
-        mesh.nCells(),
-        true,
-        cellCells
-    );
-
-    // Decompose using default weights
-    List<label> finalDecomp;
-    decompose
-    (
-        mesh.time().path()/mesh.name(),
-        cellCells.m(),
-        cellCells.offsets(),
-        pointWeights,
-        finalDecomp
+        points,
+        pointWeights
     );
-
-    // Copy back to labelList
-    labelList decomp(finalDecomp.size());
-    forAll(decomp, i)
-    {
-        decomp[i] = finalDecomp[i];
-    }
-    return decomp;
 }
 
 
@@ -654,45 +488,16 @@ Foam::labelList Foam::scotchDecomp::decompose
     const scalarField& pointWeights
 )
 {
-    if (agglom.size() != mesh.nCells())
-    {
-        FatalErrorInFunction
-            << "Size of cell-to-coarse map " << agglom.size()
-            << " differs from number of cells in mesh " << mesh.nCells()
-            << exit(FatalError);
-    }
+    // Where to write graph
+    graphPath(mesh);
 
-    // Calculate local or global (if Pstream::parRun()) connectivity
-    CompactListList<label> cellCells;
-    calcCellCells
+    return metisLikeDecomp::decompose
     (
         mesh,
         agglom,
-        agglomPoints.size(),
-        true,
-        cellCells
+        agglomPoints,
+        pointWeights
     );
-
-    // Decompose using weights
-    List<label> finalDecomp;
-    decompose
-    (
-        mesh.time().path()/mesh.name(),
-        cellCells.m(),
-        cellCells.offsets(),
-        pointWeights,
-        finalDecomp
-    );
-
-    // Rework back into decomposition for original mesh_
-    labelList fineDistribution(agglom.size());
-
-    forAll(fineDistribution, i)
-    {
-        fineDistribution[i] = finalDecomp[agglom[i]];
-    }
-
-    return fineDistribution;
 }
 
 
@@ -703,39 +508,15 @@ Foam::labelList Foam::scotchDecomp::decompose
     const scalarField& cWeights
 )
 {
-    if (cellCentres.size() != globalCellCells.size())
-    {
-        FatalErrorInFunction
-            << "Inconsistent number of cells (" << globalCellCells.size()
-            << ") and number of cell centres (" << cellCentres.size()
-            << ")." << exit(FatalError);
-    }
-
+    // Where to write graph
+    graphPath_ = "scotch.grf";
 
-    // Make Metis CSR (Compressed Storage Format) storage
-    //   adjncy      : contains neighbours (= edges in graph)
-    //   xadj(celli) : start of information in adjncy for celli
-
-    CompactListList<label> cellCells(globalCellCells);
-
-    // Decompose using weights
-    List<label> finalDecomp;
-    decompose
+    return metisLikeDecomp::decompose
     (
-        "scotch",
-        cellCells.m(),
-        cellCells.offsets(),
-        cWeights,
-        finalDecomp
+        globalCellCells,
+        cellCentres,
+        cWeights
     );
-
-    // Copy back to labelList
-    labelList decomp(finalDecomp.size());
-    forAll(decomp, i)
-    {
-        decomp[i] = finalDecomp[i];
-    }
-    return decomp;
 }
 
 
diff --git a/src/parallel/decompose/scotchDecomp/scotchDecomp.H b/src/parallel/decompose/scotchDecomp/scotchDecomp.H
index a2a2a298ca17549e45d2472483943b6827627d1b..7a44f095f27376f31e492fa31bf6ecf9369e999d 100644
--- a/src/parallel/decompose/scotchDecomp/scotchDecomp.H
+++ b/src/parallel/decompose/scotchDecomp/scotchDecomp.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.
@@ -213,7 +213,7 @@ SourceFiles
 #ifndef scotchDecomp_H
 #define scotchDecomp_H
 
-#include "decompositionMethod.H"
+#include "metisLikeDecomp.H"
 
 namespace Foam
 {
@@ -224,35 +224,34 @@ namespace Foam
 
 class scotchDecomp
 :
-    public decompositionMethod
+    public metisLikeDecomp
 {
+    // Private data
+
+        //- Output path and name for optional grf file.
+        fileName graphPath_;
+
+
     // Private Member Functions
 
+        //- Set graph path and name
+        void graphPath(const polyMesh& mesh);
+
         //- Check and print error message
         static void check(const int, const char*);
 
-        label decompose
-        (
-            const fileName& meshPath,
-            const List<label>& adjncy,
-            const List<label>& xadj,
-            const scalarField& cWeights,
-            List<label>& finalDecomp
-        );
-
         //- Decompose non-parallel
-        label decomposeOneProc
+        virtual label decomposeSerial
         (
-            const fileName& meshPath,
-            const List<label>& adjncy,
-            const List<label>& xadj,
-            const scalarField& cWeights,
-            List<label>& finalDecomp
+            const UList<label>& adjncy,
+            const UList<label>& xadj,
+            const UList<scalar>& cWeights,
+            List<label>& decomp
         );
 
         //- Disallow default bitwise copy construct and assignment
-        void operator=(const scotchDecomp&);
-        scotchDecomp(const scotchDecomp&);
+        void operator=(const scotchDecomp&) = delete;
+        scotchDecomp(const scotchDecomp&) = delete;
 
 
 public:
@@ -280,14 +279,10 @@ public:
             return true;
         }
 
-        //- Inherit decompose from decompositionMethod
+        //- Inherit all decompose methods
         using decompositionMethod::decompose;
 
-        //- Return for every coordinate the wanted processor number. Use the
-        //  mesh connectivity (if needed)
-        //  Weights get normalised with minimum weight and truncated to
-        //  convert into integer so e.g. 3.5 is seen as 3. The overall sum
-        //  of weights might otherwise overflow.
+        //- Return for every coordinate the wanted processor number.
         virtual labelList decompose
         (
             const polyMesh& mesh,
@@ -295,11 +290,7 @@ public:
             const scalarField& pointWeights
         );
 
-        //- Return for every coordinate the wanted processor number. Gets
-        //  passed agglomeration map (from fine to coarse cells) and coarse cell
-        //  location. Can be overridden by decomposers that provide this
-        //  functionality natively.
-        //  See note on weights above.
+        //- Return for every coordinate the wanted processor number.
         virtual labelList decompose
         (
             const polyMesh& mesh,
@@ -308,14 +299,7 @@ public:
             const scalarField& regionWeights
         );
 
-        //- Return for every coordinate the wanted processor number. Explicitly
-        //  provided mesh connectivity.
-        //  The connectivity is equal to mesh.cellCells() except for
-        //  - in parallel the cell numbers are global cell numbers (starting
-        //    from 0 at processor0 and then incrementing all through the
-        //    processors)
-        //  - the connections are across coupled patches
-        //  See note on weights above.
+        //- Return for every coordinate the wanted processor number.
         virtual labelList decompose
         (
             const labelListList& globalCellCells,