diff --git a/applications/utilities/mesh/generation/foamyMesh/foamyHexMeshBackgroundMesh/foamyHexMeshBackgroundMesh.C b/applications/utilities/mesh/generation/foamyMesh/foamyHexMeshBackgroundMesh/foamyHexMeshBackgroundMesh.C
index 39729a2a787cbead11c1adcc3e37d2ff9927af3d..e2965da1e381a68823a2412d8a9948d1eb554119 100644
--- a/applications/utilities/mesh/generation/foamyMesh/foamyHexMeshBackgroundMesh/foamyHexMeshBackgroundMesh.C
+++ b/applications/utilities/mesh/generation/foamyMesh/foamyHexMeshBackgroundMesh/foamyHexMeshBackgroundMesh.C
@@ -727,14 +727,12 @@ int main(int argc, char *argv[])
 
     pointField mergedPoints;
     faceList mergedFaces;
-    labelList pointMergeMap;
     PatchTools::gatherAndMerge
     (
         tolDim,
         primitivePatch(SubList<face>(isoFaces), isoPoints),
         mergedPoints,
-        mergedFaces,
-        pointMergeMap
+        mergedFaces
     );
 
     if (Pstream::master())
diff --git a/src/OpenFOAM/meshes/primitiveMesh/PatchTools/PatchTools.H b/src/OpenFOAM/meshes/primitiveMesh/PatchTools/PatchTools.H
index 6f6a95daf0df58307f14658e4e75fa9c9446ae62..0a96cfb0cdd925aa148502424de3b4ec28631d04 100644
--- a/src/OpenFOAM/meshes/primitiveMesh/PatchTools/PatchTools.H
+++ b/src/OpenFOAM/meshes/primitiveMesh/PatchTools/PatchTools.H
@@ -221,9 +221,48 @@ public:
     //
     //  \param[in] mergeDist Geometric merge tolerance for Foam::mergePoints
     //  \param[in] pp The patch to merge
-    //  \param[out] mergedPoints
-    //  \param[out] mergedFaces
-    //  \param[out] pointMergeMap
+    //  \param[out] mergedPoints merged points (master only, empty elsewhere)
+    //  \param[out] mergedFaces merged faces (master only, empty elsewhere)
+    //  \param[out] pointAddr Points globalIndex gather addressing
+    //      (master only, empty elsewhere)
+    //  \param[out] faceAddr Faces globalIndex gather addressing
+    //      (master only, empty elsewhere)
+    //  \param[out] pointMergeMap An old-to-new mapping from original
+    //      point index to the index into merged points.
+    //  \param[in]  useLocal  gather/merge patch localFaces/localPoints
+    //      instead of faces/points
+    //
+    //  \note
+    //  - OpenFOAM-v2112 and earlier: geometric merge on all patch points.
+    //  - OpenFOAM-v2206 and later: geometric merge on patch boundary points.
+    template<class FaceList, class PointField>
+    static void gatherAndMerge
+    (
+        const scalar mergeDist,
+        const PrimitivePatch<FaceList, PointField>& pp,
+        Field
+        <
+            typename PrimitivePatch<FaceList, PointField>::point_type
+        >& mergedPoints,
+        List
+        <
+            typename PrimitivePatch<FaceList, PointField>::face_type
+        >& mergedFaces,
+        globalIndex& pointAddr,
+        globalIndex& faceAddr,
+        labelList& pointMergeMap = const_cast<labelList&>(labelList::null()),
+        const bool useLocal = false
+    );
+
+    //- Gather points and faces onto master and merge into single patch.
+    //  Note: Normally uses faces/points (not localFaces/localPoints)
+    //
+    //  \param[in] mergeDist Geometric merge tolerance for Foam::mergePoints
+    //  \param[in] pp The patch to merge
+    //  \param[out] mergedPoints merged points (master only, empty elsewhere)
+    //  \param[out] mergedFaces merged faces (master only, empty elsewhere)
+    //  \param[out] pointMergeMap An old-to-new mapping from original
+    //      point index to the index into merged points.
     //  \param[in] useLocal gather/merge patch localFaces/localPoints
     //      instead of faces/points
     //
@@ -243,19 +282,20 @@ public:
         <
             typename PrimitivePatch<FaceList, PointField>::face_type
         >& mergedFaces,
-        labelList& pointMergeMap,
+        labelList& pointMergeMap = const_cast<labelList&>(labelList::null()),
         const bool useLocal = false
     );
 
     //- Gather (mesh!) points and faces onto master and merge collocated
     //  points into a single patch. Uses coupled point mesh
     //  structure so does not need tolerances.
-    //  On master and slave returns:
+    //  On master and sub-ranks returns:
     //  - pointToGlobal : for every local point index the global point index
     //  - uniqueMeshPointLabels : my local mesh points
     //  - globalPoints : global numbering for the global points
     //  - globalFaces : global numbering for the faces
-    //  On master only:
+    //  .
+    //  On master only returns:
     //  - mergedFaces : the merged faces
     //  - mergedPoints : the merged points
     template<class FaceList>
diff --git a/src/OpenFOAM/meshes/primitiveMesh/PatchTools/PatchToolsGatherAndMerge.C b/src/OpenFOAM/meshes/primitiveMesh/PatchTools/PatchToolsGatherAndMerge.C
index d5db54c94940941181a998dd7429cfe429556c1d..074f86bdc0c6ece9620a4fa0ddfaa6f4f810eaf9 100644
--- a/src/OpenFOAM/meshes/primitiveMesh/PatchTools/PatchToolsGatherAndMerge.C
+++ b/src/OpenFOAM/meshes/primitiveMesh/PatchTools/PatchToolsGatherAndMerge.C
@@ -46,17 +46,19 @@ void Foam::PatchTools::gatherAndMerge
     <
         typename PrimitivePatch<FaceList, PointField>::face_type
     >& mergedFaces,
+    globalIndex& pointAddr,
+    globalIndex& faceAddr,
     labelList& pointMergeMap,
     const bool useLocal
 )
 {
-    typedef typename PrimitivePatch<FaceList,PointField>::face_type FaceType;
+    typedef typename PrimitivePatch<FaceList, PointField>::face_type FaceType;
 
     // Faces from all ranks
-    const globalIndex faceAddr(pp.size(), globalIndex::gatherOnly{});
+    faceAddr = globalIndex(pp.size(), globalIndex::gatherOnly{});
 
     // Points from all ranks
-    const globalIndex pointAddr
+    pointAddr = globalIndex
     (
         (useLocal ? pp.localPoints().size() : pp.points().size()),
         globalIndex::gatherOnly{}
@@ -152,6 +154,40 @@ void Foam::PatchTools::gatherAndMerge
 }
 
 
+template<class FaceList, class PointField>
+void Foam::PatchTools::gatherAndMerge
+(
+    const scalar mergeDist,
+    const PrimitivePatch<FaceList, PointField>& pp,
+    Field
+    <
+        typename PrimitivePatch<FaceList, PointField>::point_type
+    >& mergedPoints,
+    List
+    <
+        typename PrimitivePatch<FaceList, PointField>::face_type
+    >& mergedFaces,
+    labelList& pointMergeMap,
+    const bool useLocal
+)
+{
+    globalIndex pointAddr;
+    globalIndex faceAddr;
+
+    PatchTools::gatherAndMerge<FaceList, PointField>
+    (
+        mergeDist,
+        pp,
+        mergedPoints,
+        mergedFaces,
+        pointAddr,
+        faceAddr,
+        pointMergeMap,
+        useLocal
+    );
+}
+
+
 template<class FaceList>
 void Foam::PatchTools::gatherAndMerge
 (
diff --git a/src/OpenFOAM/parallel/globalIndex/globalIndex.H b/src/OpenFOAM/parallel/globalIndex/globalIndex.H
index 4f84920416c40b9c26799a07a4a6d6545760987f..1be1ac216c896093fab9bbeea0ae0e89450c01ca 100644
--- a/src/OpenFOAM/parallel/globalIndex/globalIndex.H
+++ b/src/OpenFOAM/parallel/globalIndex/globalIndex.H
@@ -108,8 +108,8 @@ public:
 
     // Constructors
 
-        //- Default construct
-        globalIndex() = default;
+        //- Default construct (empty)
+        globalIndex() noexcept = default;
 
         //- Copy construct from a list of offsets.
         //- No communication required
@@ -184,9 +184,15 @@ public:
         //- Global max of localSizes
         inline label maxSize() const;
 
+
+    // Access
+
         //- Const-access to the offsets
         inline const labelList& offsets() const noexcept;
 
+        //- Write-access to the offsets, for changing after construction
+        inline labelList& offsets() noexcept;
+
 
     // Dimensions
 
@@ -202,8 +208,8 @@ public:
 
     // Edit
 
-        //- Write-access to the offsets, for changing after construction
-        inline labelList& offsets() noexcept;
+        //- Reset to be empty (no offsets)
+        inline void clear();
 
         //- Reset from local size, using gather/broadcast
         //- with default/specified communicator if parallel.
diff --git a/src/OpenFOAM/parallel/globalIndex/globalIndexI.H b/src/OpenFOAM/parallel/globalIndex/globalIndexI.H
index a586a3c07af6b50ff47e93373eda623f0c9e4c4b..6b90865f45e82d9fc920e58341a6df64c91f6798 100644
--- a/src/OpenFOAM/parallel/globalIndex/globalIndexI.H
+++ b/src/OpenFOAM/parallel/globalIndex/globalIndexI.H
@@ -176,6 +176,12 @@ inline Foam::labelList& Foam::globalIndex::offsets() noexcept
 }
 
 
+inline void Foam::globalIndex::clear()
+{
+    offsets_.clear();
+}
+
+
 inline const Foam::labelUList Foam::globalIndex::localStarts() const
 {
     const label len = (offsets_.size() - 1);
diff --git a/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.C b/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.C
index 6147c65fb95c69ba87e0b60b4b61b9be1871fdec..33a2837ccdb862f2e4d4f965196ed7777690967e 100644
--- a/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.C
+++ b/src/functionObjects/field/fieldValues/surfaceFieldValue/surfaceFieldValue.C
@@ -418,15 +418,12 @@ combineSurfaceGeometry
             // Dimension as fraction of surface
             const scalar mergeDim = 1e-10*boundBox(s.points(), true).mag();
 
-            labelList pointsMap;
-
-            PatchTools::gatherAndMerge
+            Foam::PatchTools::gatherAndMerge
             (
                 mergeDim,
                 primitivePatch(SubList<face>(s.faces()), s.points()),
                 points,
-                faces,
-                pointsMap
+                faces
             );
         }
         else
@@ -444,15 +441,12 @@ combineSurfaceGeometry
             // Dimension as fraction of mesh bounding box
             const scalar mergeDim = 1e-10*mesh_.bounds().mag();
 
-            labelList pointsMap;
-
-            PatchTools::gatherAndMerge
+            Foam::PatchTools::gatherAndMerge
             (
                 mergeDim,
                 primitivePatch(SubList<face>(s.faces()), s.points()),
                 points,
-                faces,
-                pointsMap
+                faces
             );
         }
         else
diff --git a/src/meshTools/AMIInterpolation/patches/cyclicPeriodicAMI/cyclicPeriodicAMIPolyPatch/cyclicPeriodicAMIPolyPatch.C b/src/meshTools/AMIInterpolation/patches/cyclicPeriodicAMI/cyclicPeriodicAMIPolyPatch/cyclicPeriodicAMIPolyPatch.C
index 22bfe08812d044e0c58b732bbd518457e55055a4..78e8877f6075068d1a4d136aee982a3e84aeb053 100644
--- a/src/meshTools/AMIInterpolation/patches/cyclicPeriodicAMI/cyclicPeriodicAMIPolyPatch/cyclicPeriodicAMIPolyPatch.C
+++ b/src/meshTools/AMIInterpolation/patches/cyclicPeriodicAMI/cyclicPeriodicAMIPolyPatch/cyclicPeriodicAMIPolyPatch.C
@@ -206,14 +206,12 @@ void Foam::cyclicPeriodicAMIPolyPatch::writeOBJ
     // Collect faces and points
     pointField allPoints;
     faceList allFaces;
-    labelList pointMergeMap;
     PatchTools::gatherAndMerge
     (
         -1.0,           // do not merge points
         p,
         allPoints,
-        allFaces,
-        pointMergeMap
+        allFaces
     );
 
     if (Pstream::master())