diff --git a/applications/utilities/parallelProcessing/decomposePar/decomposeParDict b/applications/utilities/parallelProcessing/decomposePar/decomposeParDict
index e60757fffdd1194a24794025fbf9be27ec3c8d02..c42bdc1c9aa8360aab93cfc6b1f1b64a07c779a3 100644
--- a/applications/utilities/parallelProcessing/decomposePar/decomposeParDict
+++ b/applications/utilities/parallelProcessing/decomposePar/decomposeParDict
@@ -15,7 +15,7 @@ FoamFile
 }
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-numberOfSubdomains  8;
+numberOfSubdomains  2;
 
 //- Keep owner and neighbour on same processor for faces in zones:
 // preserveFaceZones (heater solid1 solid3);
@@ -24,13 +24,22 @@ numberOfSubdomains  8;
 //  (makes sense only for cyclic patches)
 //preservePatches (cyclic_half0 cyclic_half1);
 
+//- Keep all of faceZone on a single processor. This puts all cells
+//  connected with a point, edge or face on the same processor.
+//  (just having face connected cells might not guarantee a balanced
+//  decomposition)
+// The processor can be explicitly provided or -1 to have
+// decompositionMethod choose.
+//singleProcessorFaceZones ((f0 -1));
+
+
 //- Use the volScalarField named here as a weight for each cell in the
 //  decomposition.  For example, use a particle population field to decompose
 //  for a balanced number of particles in a lagrangian simulation.
 // weightField dsmcRhoNMean;
 
 method          scotch;
-// method          hierarchical;
+//method          hierarchical;
 // method          simple;
 // method          metis;
 // method          manual;
@@ -70,7 +79,7 @@ simpleCoeffs
 
 hierarchicalCoeffs
 {
-    n           (2 2 1);
+    n           (1 2 1);
     delta       0.001;
     order       xyz;
 }
diff --git a/applications/utilities/parallelProcessing/decomposePar/domainDecompositionDistribute.C b/applications/utilities/parallelProcessing/decomposePar/domainDecompositionDistribute.C
index 4ee3c7555e9a93e940a8dfd704af3e4664c2d55f..0d40f8b232abe4127f4535a6e243c93b88c8b6ff 100644
--- a/applications/utilities/parallelProcessing/decomposePar/domainDecompositionDistribute.C
+++ b/applications/utilities/parallelProcessing/decomposePar/domainDecompositionDistribute.C
@@ -28,6 +28,7 @@ License
 #include "cpuTime.H"
 #include "cellSet.H"
 #include "regionSplit.H"
+#include "Tuple2.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -47,7 +48,8 @@ void Foam::domainDecomposition::distributeCells()
     {
         wordList pNames(decompositionDict_.lookup("preservePatches"));
 
-        Info<< "Keeping owner of faces in patches " << pNames
+        Info<< nl
+            << "Keeping owner of faces in patches " << pNames
             << " on same processor. This only makes sense for cyclics." << endl;
 
         const polyBoundaryMesh& patches = boundaryMesh();
@@ -76,7 +78,8 @@ void Foam::domainDecomposition::distributeCells()
     {
         wordList zNames(decompositionDict_.lookup("preserveFaceZones"));
 
-        Info<< "Keeping owner and neighbour of faces in zones " << zNames
+        Info<< nl
+            << "Keeping owner and neighbour of faces in zones " << zNames
             << " on same processor" << endl;
 
         const faceZoneMesh& fZones = faceZones();
@@ -103,6 +106,67 @@ void Foam::domainDecomposition::distributeCells()
     }
 
 
+    // Specified processor for owner and neighbour of faces
+    Map<label> specifiedProcessorFaces;
+
+    if (decompositionDict_.found("singleProcessorFaceZones"))
+    {
+        List<Tuple2<word, label> > zNameAndProcs
+        (
+            decompositionDict_.lookup("singleProcessorFaceZones")
+        );
+
+        const faceZoneMesh& fZones = faceZones();
+
+        label nCells = 0;
+
+        Info<< endl;
+
+        forAll(zNameAndProcs, i)
+        {
+            Info<< "Keeping all cells connected to faceZone "
+                << zNameAndProcs[i].first()
+                << " on processor " << zNameAndProcs[i].second() << endl;
+
+            label zoneI = fZones.findZoneID(zNameAndProcs[i].first());
+
+            if (zoneI == -1)
+            {
+                FatalErrorIn("domainDecomposition::distributeCells()")
+                    << "Unknown singleProcessorFaceZone "
+                    << zNameAndProcs[i].first()
+                    << endl << "Valid faceZones are " << fZones.names()
+                    << exit(FatalError);
+            }
+
+            const faceZone& fz = fZones[zoneI];
+
+            nCells += fz.size();
+        }
+
+
+        // Size
+        specifiedProcessorFaces.resize(2*nCells);
+
+
+        // Fill
+        forAll(zNameAndProcs, i)
+        {
+            label zoneI = fZones.findZoneID(zNameAndProcs[i].first());
+            const faceZone& fz = fZones[zoneI];
+
+            label procI = zNameAndProcs[i].second();
+
+            forAll(fz, fzI)
+            {
+                label faceI = fz[fzI];
+
+                specifiedProcessorFaces.insert(faceI, procI);
+            }
+        }
+    }
+
+
     // Construct decomposition method and either do decomposition on
     // cell centres or on agglomeration
 
@@ -112,7 +176,8 @@ void Foam::domainDecomposition::distributeCells()
         decompositionDict_
     );
 
-    if (sameProcFaces.empty())
+
+    if (sameProcFaces.empty() && specifiedProcessorFaces.empty())
     {
         if (decompositionDict_.found("weightField"))
         {
@@ -146,9 +211,11 @@ void Foam::domainDecomposition::distributeCells()
     }
     else
     {
-        Info<< "Selected " << sameProcFaces.size()
-            << " faces whose owner and neighbour cell should be kept on the"
-            << " same processor" << endl;
+        Info<< "Constrained decomposition:" << endl
+            << "    faces with same processor owner and neighbour : "
+            << sameProcFaces.size() << endl
+            << "    faces all on same processor                   : "
+            << specifiedProcessorFaces.size() << endl << endl;
 
         // Faces where owner and neighbour are not 'connected' (= all except
         // sameProcFaces)
@@ -159,6 +226,24 @@ void Foam::domainDecomposition::distributeCells()
             blockedFace[iter.key()] = false;
         }
 
+
+        // For specifiedProcessorFaces add all point connected faces
+        {
+            forAllConstIter(Map<label>, specifiedProcessorFaces, iter)
+            {
+                const face& f = faces()[iter.key()];
+                forAll(f, fp)
+                {
+                    const labelList& pFaces = pointFaces()[f[fp]];
+                    forAll(pFaces, i)
+                    {
+                        blockedFace[pFaces[i]] = false;
+                    }
+                }
+            }
+        }
+
+
         // Connect coupled boundary faces
         const polyBoundaryMesh& patches =  boundaryMesh();
 
@@ -201,10 +286,11 @@ void Foam::domainDecomposition::distributeCells()
 
         // Do decomposition on agglomeration
         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+        scalarField regionWeights(globalRegion.nRegions(), 0);
+
         if (decompositionDict_.found("weightField"))
         {
-            scalarField regionWeights(globalRegion.nRegions(), 0);
-
             word weightName = decompositionDict_.lookup("weightField");
 
             volScalarField weights
@@ -226,23 +312,46 @@ void Foam::domainDecomposition::distributeCells()
 
                 regionWeights[regionI] += weights.internalField()[cellI];
             }
-
-            cellToProc_ = decomposePtr().decompose
-            (
-                *this,
-                globalRegion,
-                regionCentres,
-                regionWeights
-            );
         }
         else
         {
-            cellToProc_ = decomposePtr().decompose
-            (
-                *this,
-                globalRegion,
-                regionCentres
-            );
+            forAll(globalRegion, cellI)
+            {
+                label regionI = globalRegion[cellI];
+
+                regionWeights[regionI] += 1.0;
+            }
+        }
+
+        cellToProc_ = decomposePtr().decompose
+        (
+            *this,
+            globalRegion,
+            regionCentres,
+            regionWeights
+        );
+
+
+        // For specifiedProcessorFaces rework the cellToProc. Note that
+        // this makes the decomposition unbalanced.
+        if (specifiedProcessorFaces.size())
+        {
+            labelList procMap(identity(cellToProc_.size()));
+
+            forAllConstIter(Map<label>, specifiedProcessorFaces, iter)
+            {
+                label faceI = iter.key();
+                label wantedProcI = iter();
+
+                if (wantedProcI != -1)
+                {
+                    cellToProc_[faceOwner()[faceI]] = wantedProcI;
+                    if (isInternalFace(faceI))
+                    {
+                        cellToProc_[faceNeighbour()[faceI]] = wantedProcI;
+                    }
+                }
+            }
         }
     }
 
diff --git a/src/parallel/decompose/decompositionMethods/decompositionMethod/decompositionMethod.C b/src/parallel/decompose/decompositionMethods/decompositionMethod/decompositionMethod.C
index 663f5b003bdac244bbf1612c7bde847576a28aa5..1808fc84ab5b554a0af4aca1008d712de3586cb0 100644
--- a/src/parallel/decompose/decompositionMethods/decompositionMethod/decompositionMethod.C
+++ b/src/parallel/decompose/decompositionMethods/decompositionMethod/decompositionMethod.C
@@ -403,6 +403,7 @@ void Foam::decompositionMethod::calcCellCells
     forAll(cellCells, cellI)
     {
         nbrCells.clear();
+        nbrCells.insert(cellI);
 
         label& endIndex = cellCells.offsets()[cellI+1];