diff --git a/src/fvAgglomerationMethods/Allwmake b/src/fvAgglomerationMethods/Allwmake
index 61d951c8c6..8328d915fc 100755
--- a/src/fvAgglomerationMethods/Allwmake
+++ b/src/fvAgglomerationMethods/Allwmake
@@ -10,4 +10,6 @@ then
wmake $makeOption MGridGenGamgAgglomeration
fi
+wmake libso pairPatchAgglomeration
+
# ----------------------------------------------------------------- end-of-file
diff --git a/src/fvAgglomerationMethods/pairPatchAgglomeration/Make/files b/src/fvAgglomerationMethods/pairPatchAgglomeration/Make/files
new file mode 100644
index 0000000000..275c4795f3
--- /dev/null
+++ b/src/fvAgglomerationMethods/pairPatchAgglomeration/Make/files
@@ -0,0 +1,3 @@
+pairPatchAgglomeration.C
+
+LIB = $(FOAM_LIBBIN)/libpairPatchAgglomeration
diff --git a/src/fvAgglomerationMethods/pairPatchAgglomeration/Make/options b/src/fvAgglomerationMethods/pairPatchAgglomeration/Make/options
new file mode 100644
index 0000000000..6dddff38af
--- /dev/null
+++ b/src/fvAgglomerationMethods/pairPatchAgglomeration/Make/options
@@ -0,0 +1,10 @@
+EXE_INC = \
+ -I$(LIB_SRC)/finiteVolume/lnInclude \
+ -I$(LIB_SRC)/meshTools/lnInclude \
+ -I$(LIB_SRC)/OpenFOAM/lnInclude
+
+LIB_LIBS = \
+ -lfiniteVolume \
+ -lOpenFOAM \
+ -lmeshTools
+
diff --git a/src/fvAgglomerationMethods/pairPatchAgglomeration/pairPatchAgglomeration.C b/src/fvAgglomerationMethods/pairPatchAgglomeration/pairPatchAgglomeration.C
new file mode 100644
index 0000000000..d4657ef5e8
--- /dev/null
+++ b/src/fvAgglomerationMethods/pairPatchAgglomeration/pairPatchAgglomeration.C
@@ -0,0 +1,528 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | Copyright (C) 2011-2011 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 .
+
+\*---------------------------------------------------------------------------*/
+
+#include "pairPatchAgglomeration.H"
+//#include "OFstream.H"
+#include "meshTools.H"
+
+// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
+
+void Foam::pairPatchAgglomeration::compactLevels(const label nCreatedLevels)
+{
+ nFaces_.setSize(nCreatedLevels);
+ restrictAddressing_.setSize(nCreatedLevels);
+ patchLevels_.setSize(nCreatedLevels);
+}
+
+
+bool Foam::pairPatchAgglomeration::continueAgglomerating
+(
+ const label nCoarseFaces
+)
+{
+ // Check the need for further agglomeration on all processors
+ bool contAgg = nCoarseFaces >= nFacesInCoarsestLevel_;
+ reduce(contAgg, andOp());
+ return contAgg;
+}
+
+
+void Foam::pairPatchAgglomeration::setBasedEdgeWeights()
+{
+ const bPatch& coarsePatch = patchLevels_[0];
+ forAll(coarsePatch.edges(), i)
+ {
+ if(coarsePatch.isInternalEdge(i))
+ {
+ scalar edgeLength =
+ coarsePatch.edges()[i].mag(coarsePatch.localPoints());
+
+ const labelList& eFaces = coarsePatch.edgeFaces()[i];
+
+ if (eFaces.size() == 2)
+ {
+ scalar cosI =
+ coarsePatch.faceNormals()[eFaces[0]] &
+ coarsePatch.faceNormals()[eFaces[1]];
+
+ const edge edgeCommon = edge(eFaces[0], eFaces[1]);
+
+ if(facePairWeight_.found(edgeCommon))
+ {
+ facePairWeight_[edgeCommon] += edgeLength;
+ }
+ else
+ {
+ facePairWeight_.insert(edgeCommon, edgeLength);
+ }
+
+ if
+ (
+ cosI <
+ Foam::cos
+ (
+ featureAngle_*constant::mathematical::pi/180.0
+ )
+ )
+ {
+ facePairWeight_[edgeCommon] = -1.0;
+ }
+ }
+ else if (eFaces.size() == 3)
+ {
+ facePairWeight_.insert(edge(eFaces[1], eFaces[0]), -1.0);
+ facePairWeight_.insert(edge(eFaces[2], eFaces[0]), -1.0);
+ facePairWeight_.insert(edge(eFaces[1], eFaces[2]), -1.0);
+ }
+ }
+ }
+}
+
+
+void Foam::pairPatchAgglomeration::setEdgeWeights
+(
+ const label fineLevelIndex
+)
+{
+
+ const bPatch& coarsePatch = patchLevels_[fineLevelIndex];
+
+ const labelList& fineToCoarse = restrictAddressing_[fineLevelIndex];
+ const label nCoarseI = max(fineToCoarse)+1;
+ labelListList coarseToFine
+ (
+ invertOneToMany(nCoarseI, fineToCoarse)
+ );
+
+ HashSet > fineFeaturedFaces(coarsePatch.nEdges()/10);
+
+ // Map fine faces with featured edge into coarse faces
+ forAllConstIter(EdgeMap, facePairWeight_, iter)
+ {
+ if (iter() == -1.0)
+ {
+ const edge e = iter.key();
+ const edge edgeFeatured
+ (
+ fineToCoarse[e[0]],
+ fineToCoarse[e[1]]
+ );
+ fineFeaturedFaces.insert(edgeFeatured);
+ }
+ }
+
+ // Clean old weitghs
+ facePairWeight_.clear();
+ facePairWeight_.resize(coarsePatch.nEdges());
+
+ forAll(coarsePatch.edges(), i)
+ {
+ if(coarsePatch.isInternalEdge(i))
+ {
+ scalar edgeLength =
+ coarsePatch.edges()[i].mag(coarsePatch.localPoints());
+
+ const labelList& eFaces = coarsePatch.edgeFaces()[i];
+
+ if (eFaces.size() == 2)
+ {
+ const edge edgeCommon = edge(eFaces[0], eFaces[1]);
+ if(facePairWeight_.found(edgeCommon))
+ {
+ facePairWeight_[edgeCommon] += edgeLength;
+ }
+ else
+ {
+ facePairWeight_.insert(edgeCommon, edgeLength);
+ }
+ // If the fine 'pair' faces was featured edge so it is
+ // the coarse 'pair'
+ if (fineFeaturedFaces.found(edgeCommon))
+ {
+ facePairWeight_[edgeCommon] = -1.0;
+ }
+ }
+ else if (eFaces.size() == 3)
+ {
+ facePairWeight_.insert(edge(eFaces[1], eFaces[0]), -1.0);
+ facePairWeight_.insert(edge(eFaces[2], eFaces[0]), -1.0);
+ facePairWeight_.insert(edge(eFaces[1], eFaces[2]), -1.0);
+ }
+ }
+ }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
+
+Foam::pairPatchAgglomeration::pairPatchAgglomeration
+(
+ const polyPatch& patch,
+ const dictionary& controlDict,
+ const bool additionalWeights
+)
+:
+ mergeLevels_
+ (
+ controlDict.lookupOrDefault