diff --git a/applications/utilities/miscellaneous/patchSummary/patchSummary.C b/applications/utilities/miscellaneous/patchSummary/patchSummary.C
index 9f35d900da2c8d52b3205e2ad17503f990b8e376..51d59163f2019e32e3a3348a7de26834abf95865 100644
--- a/applications/utilities/miscellaneous/patchSummary/patchSummary.C
+++ b/applications/utilities/miscellaneous/patchSummary/patchSummary.C
@@ -28,6 +28,11 @@ Description
     Writes fields and boundary condition info for each patch at each requested
     time instance.
 
+    Default action is to write a single entry for patches/patchGroups with the
+    same boundary conditions. Use the -expand option to print every patch
+    separately. In case of multiple groups matching it will print only the
+    first one.
+
 \*---------------------------------------------------------------------------*/
 
 #include "fvCFD.H"
@@ -37,6 +42,60 @@ Description
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+// Return names of groups and patches. If multiple groups the first one wins.
+wordHashSet matchGroupOrPatch
+(
+    const polyBoundaryMesh& bm,
+    const labelList& patchIDs
+)
+{
+    // Current matched groups
+    wordHashSet matchedGroups;
+
+    // Current set of unmatched patches
+    labelHashSet nonGroupPatches(patchIDs);
+
+    const HashTable<labelList, word>& groupPatchIDs =
+        bm.groupPatchIDs();
+    for
+    (
+        HashTable<labelList,word>::const_iterator iter =
+            groupPatchIDs.begin();
+        iter != groupPatchIDs.end();
+        ++iter
+    )
+    {
+        // Store currently unmatched patches
+        labelHashSet oldNonGroupPatches(nonGroupPatches);
+
+        // Match by deleting patches in group from the current set and seeing
+        // if all have been deleted.
+        labelHashSet groupPatchSet(iter());
+
+        label nMatch = nonGroupPatches.erase(groupPatchSet);
+
+        if (nMatch == groupPatchSet.size())
+        {
+            matchedGroups.insert(iter.key());
+        }
+        else
+        {
+            // No full match. Undo.
+            nonGroupPatches.transfer(oldNonGroupPatches);
+        }
+    }
+
+    // Add remaining patches
+    forAllConstIter(labelHashSet, nonGroupPatches, iter)
+    {
+        matchedGroups.insert(bm[iter.key()].name());
+    }
+
+    return matchedGroups;
+}
+
+
+
 int main(int argc, char *argv[])
 {
     timeSelector::addOptions();
@@ -44,18 +103,20 @@ int main(int argc, char *argv[])
 #   include "addRegionOption.H"
     argList::addBoolOption
     (
-        "collate",
-        "Combine similar patches"
+        "expand",
+        "Do not combine patches"
     );
 #   include "setRootCase.H"
 #   include "createTime.H"
 
     instantList timeDirs = timeSelector::select0(runTime, args);
 
-    const bool collate = args.optionFound("collate");
+    const bool expand = args.optionFound("expand");
 
 
 #   include "createNamedMesh.H"
+    const polyBoundaryMesh& bm = mesh.boundaryMesh();
+
 
     forAll(timeDirs, timeI)
     {
@@ -63,6 +124,14 @@ int main(int argc, char *argv[])
 
         Info<< "Time = " << runTime.timeName() << nl << endl;
 
+        // Update the mesh if changed
+        if (mesh.readUpdate() == polyMesh::TOPO_PATCH_CHANGE)
+        {
+            Info<< "Detected changed patches. Recreating patch group table."
+                << endl;
+        }
+
+
         const IOobjectList fieldObjs(mesh, runTime.timeName());
         const wordList objNames = fieldObjs.names();
 
@@ -96,13 +165,32 @@ int main(int argc, char *argv[])
 
         Info<< endl;
 
-        const polyBoundaryMesh& bm = mesh.boundaryMesh();
 
-        DynamicList<HashTable<word> > fieldToTypes(bm.size());
-        DynamicList<DynamicList<label> > groupToPatches(bm.size());
-        forAll(bm, patchI)
+        if (expand)
+        {
+            // Print each patch separately
+
+            forAll(bm, patchI)
+            {
+                Info<< bm[patchI].type() << ": " << bm[patchI].name() << nl;
+                outputFieldList<scalar>(vsf, patchI);
+                outputFieldList<vector>(vvf, patchI);
+                outputFieldList<sphericalTensor>(vsptf, patchI);
+                outputFieldList<symmTensor>(vsytf, patchI);
+                outputFieldList<tensor>(vtf, patchI);
+                Info<< endl;
+            }
+        }
+        else
         {
-            if (collate)
+            // Collect for each patch the bc type per field. Merge similar
+            // patches.
+
+            // Per 'group', the map from fieldname to patchfield type
+            DynamicList<HashTable<word> > fieldToTypes(bm.size());
+            // Per 'group' the patches
+            DynamicList<DynamicList<label> > groupToPatches(bm.size());
+            forAll(bm, patchI)
             {
                 HashTable<word> fieldToType;
                 collectFieldList<scalar>(vsf, patchI, fieldToType);
@@ -124,46 +212,28 @@ int main(int argc, char *argv[])
                     groupToPatches[groupI].append(patchI);
                 }
             }
-            else
-            {
-                Info<< bm[patchI].type() << ": " << bm[patchI].name() << nl;
-                outputFieldList<scalar>(vsf, patchI);
-                outputFieldList<vector>(vvf, patchI);
-                outputFieldList<sphericalTensor>(vsptf, patchI);
-                outputFieldList<symmTensor>(vsytf, patchI);
-                outputFieldList<tensor>(vtf, patchI);
-                Info<< endl;
-            }
-        }
-
-
-        bool hasGroups = false;
-        forAll(groupToPatches, groupI)
-        {
-            const DynamicList<label>& patchIDs = groupToPatches[groupI];
-            if (patchIDs.size() > 1)
-            {
-                hasGroups = true;
-                break;
-            }
-        }
 
 
-        if (hasGroups)
-        {
-            Info<< "Collated:" << endl;
             forAll(groupToPatches, groupI)
             {
                 const DynamicList<label>& patchIDs = groupToPatches[groupI];
 
                 if (patchIDs.size() > 1)
                 {
-                    Info<< '(' << bm[patchIDs[0]].name();
-                    for (label i = 1; i < patchIDs.size(); i++)
+                    // Check if part of a group
+                    wordList patchOrGroup
+                    (
+                        matchGroupOrPatch(bm, patchIDs).sortedToc()
+                    );
+
+                    //Info<< patchOrGroup << endl;
+                    Info<< patchOrGroup[0];
+                    for (label i = 1; i < patchOrGroup.size(); i++)
                     {
-                        Info<< ' ' << bm[patchIDs[i]].name();
+                        Info<< ' ' << patchOrGroup[i];
                     }
-                    Info<< ')' << endl;
+                    Info<< endl;
+
                     outputFieldList<scalar>(vsf, patchIDs[0]);
                     outputFieldList<vector>(vvf, patchIDs[0]);
                     outputFieldList<sphericalTensor>(vsptf, patchIDs[0]);