diff --git a/applications/utilities/mesh/manipulation/renumberMesh/renumberMesh.C b/applications/utilities/mesh/manipulation/renumberMesh/renumberMesh.C
index 64011258c6ae2f67ac49b81ed44f5caaa56ac67f..3702cfe8ce81df764b4124e1112847ebe3428566 100644
--- a/applications/utilities/mesh/manipulation/renumberMesh/renumberMesh.C
+++ b/applications/utilities/mesh/manipulation/renumberMesh/renumberMesh.C
@@ -145,6 +145,7 @@ Usage
 #include "hexRef8Data.H"
 #include "regionProperties.H"
 #include "polyMeshTools.H"
+#include "subsetAdjacency.H"
 
 using namespace Foam;
 
@@ -194,21 +195,56 @@ tmp<volScalarField> createScalarField
 }
 
 
-// Calculate band of matrix
-label getBand(const labelList& owner, const labelList& neighbour)
+// Calculate band of mesh
+// label getBand(const labelUList& owner, const labelUList& neighbour)
+// {
+//     label bandwidth = 0;
+//
+//     forAll(neighbour, facei)
+//     {
+//         const label width = neighbour[facei] - owner[facei];
+//
+//         if (bandwidth < width)
+//         {
+//             bandwidth = width;
+//         }
+//     }
+//     return bandwidth;
+// }
+
+
+// Calculate band and profile of matrix. Profile is scalar to avoid overflow
+Tuple2<label, scalar> getBand
+(
+    const CompactListList<label>& mat
+)
 {
-    label band = 0;
+    Tuple2<label, scalar> metrics(0, 0);
 
-    forAll(neighbour, facei)
+    auto& bandwidth = metrics.first();
+    auto& profile = metrics.second();
+
+    forAll(mat, celli)
     {
-        label diff = neighbour[facei] - owner[facei];
+        const auto& neighbours = mat[celli];
+
+        const label nNbr = neighbours.size();
 
-        if (diff > band)
+        if (nNbr)
         {
-            band = diff;
+            // Max distance
+            const label width = (neighbours[nNbr-1] - celli);
+
+            if (bandwidth < width)
+            {
+                bandwidth = width;
+            }
+
+            profile += scalar(width);
         }
     }
-    return band;
+
+    return metrics;
 }
 
 
@@ -217,27 +253,35 @@ void getBand
 (
     const bool calculateIntersect,
     const label nCells,
-    const labelList& owner,
-    const labelList& neighbour,
+    const labelUList& owner,
+    const labelUList& neighbour,
     label& bandwidth,
     scalar& profile,            // scalar to avoid overflow
     scalar& sumSqrIntersect     // scalar to avoid overflow
 )
 {
     labelList cellBandwidth(nCells, Foam::zero{});
-    scalarField nIntersect(nCells, Foam::zero{});
+
+    bandwidth = 0;
 
     forAll(neighbour, facei)
     {
-        label own = owner[facei];
-        label nei = neighbour[facei];
+        const label own = owner[facei];
+        const label nei = neighbour[facei];
 
         // Note: mag not necessary for correct (upper-triangular) ordering.
-        label diff = nei-own;
-        cellBandwidth[nei] = max(cellBandwidth[nei], diff);
-    }
+        const label width = nei - own;
+
+        if (cellBandwidth[nei] < width)
+        {
+            cellBandwidth[nei] = width;
 
-    bandwidth = max(cellBandwidth);
+            if (bandwidth < width)
+            {
+                bandwidth = width;
+            }
+        }
+    }
 
     // Do not use field algebra because of conversion label to scalar
     profile = 0;
@@ -246,14 +290,16 @@ void getBand
         profile += scalar(width);
     }
 
-    sumSqrIntersect = 0.0;
+    sumSqrIntersect = 0;
     if (calculateIntersect)
     {
+        scalarField nIntersect(nCells, Foam::zero{});
+
         forAll(nIntersect, celli)
         {
             for (label colI = celli-cellBandwidth[celli]; colI <= celli; colI++)
             {
-                nIntersect[colI] += 1.0;
+                nIntersect[colI] += scalar(1);
             }
         }
 
@@ -675,9 +721,8 @@ CompactListList<label> regionRenumber
 
         forAll(regionCellOrder, regioni)
         {
-            // Info<< "    region " << regioni
-            //     << " starts at " << regionCellOrder.localStart(regioni)
-            //     << nl;
+            // Info<< "    region " << regioni << " starts at "
+            //     << regionCellOrder.localStart(regioni) << nl;
 
             // No parallel communication
             const bool oldParRun = UPstream::parRun(false);
@@ -703,27 +748,42 @@ CompactListList<label> regionRenumber
     {
         timer.resetTimeIncrement();
 
+        // Create adjacency matrix of the full mesh and subset subsequently.
+        // This is more efficient than creating adjacency matrices of
+        // sub-meshes.
+
+        // No parallel communication
+        const bool oldParRun = UPstream::parRun(false);
+
+        // The local connectivity of the full (non-subsetted) mesh
+        CompactListList<label> meshCellCells;
+        globalMeshData::calcCellCells(mesh, meshCellCells);
+        UPstream::parRun(oldParRun);  // Restore parallel state
+
+        timings[TimingType::CELL_CELLS] += timer.timeIncrement();
+
+        // For the respective subMesh selections
+        bitSet subsetCells(mesh.nCells());
+
         forAll(regionCellOrder, regioni)
         {
-            // Info<< "    region " << regioni
-            //     << " starts at " << regionCellOrder.localStart(regioni)
-            //     << nl;
+            // Info<< "    region " << regioni << " starts at "
+            //     << regionCellOrder.localStart(regioni) << nl;
 
-            // No parallel communication
-            const bool oldParRun = UPstream::parRun(false);
+            subsetCells = false;
+            subsetCells.set(regionCellOrder[regioni]);
 
             // Connectivity of local sub-mesh
-            CompactListList<label> cellCells;
-            labelList cellMap = globalMeshData::calcCellCells
-            (
-                mesh,
-                regionCellOrder[regioni],
-                cellCells
-            );
+            labelList cellMap;
+            CompactListList<label> subCellCells =
+                subsetAdjacency(subsetCells, meshCellCells, cellMap);
 
             timings[TimingType::CELL_CELLS] += timer.timeIncrement();
 
-            labelList subCellOrder = method.renumber(cellCells);
+            // No parallel communication
+            const bool oldParRun = UPstream::parRun(false);
+
+            labelList subCellOrder = method.renumber(subCellCells);
 
             UPstream::parRun(oldParRun);  // Restore parallel state
 
@@ -835,10 +895,10 @@ int main(int argc, char *argv[])
     const bool dryrun = args.dryRun();
 
     const bool readDict = args.found("dict");
-    const bool doFrontWidth = args.found("frontWidth");
+    const bool doDecompose = args.found("decompose");
     const bool overwrite = args.found("overwrite");
     const bool doFields = !args.found("no-fields");
-    const bool doDecompose = args.found("decompose");
+    const bool doFrontWidth = args.found("frontWidth") && !doDecompose;
 
     word renumberMethodName;
     args.readIfPresent("renumber-method", renumberMethodName);
@@ -846,8 +906,7 @@ int main(int argc, char *argv[])
     if (doDecompose && UPstream::parRun())
     {
         FatalErrorIn(args.executable())
-            << "Cannot use -decompose option in parallel"
-            << " ... giving up" << nl
+            << "Cannot use -decompose option in parallel ... giving up" << nl
             << exit(FatalError);
     }
 
@@ -908,21 +967,21 @@ int main(int argc, char *argv[])
 
         reduce(band, maxOp<label>());
         reduce(profile, sumOp<scalar>());
-        reduce(sumSqrIntersect, sumOp<scalar>());
-
-        scalar rmsFrontwidth = Foam::sqrt
-        (
-            sumSqrIntersect/mesh.globalData().nTotalCells()
-        );
 
         Info<< "Mesh " << mesh.name()
             << " size: " << mesh.globalData().nTotalCells() << nl
-            << "Before renumbering :" << nl
+            << "Before renumbering" << nl
             << "    band           : " << band << nl
             << "    profile        : " << profile << nl;
 
         if (doFrontWidth)
         {
+            reduce(sumSqrIntersect, sumOp<scalar>());
+            scalar rmsFrontwidth = Foam::sqrt
+            (
+                sumSqrIntersect/mesh.globalData().nTotalCells()
+            );
+
             Info<< "    rms frontwidth : " << rmsFrontwidth << nl;
         }
 
@@ -1091,10 +1150,7 @@ int main(int argc, char *argv[])
         );
 
 
-        // List of objects read from time directory
-        // List of stored objects to clear from mesh
-
-        IOobjectList objects;
+        // List of stored objects to clear from mesh (after reading)
         DynamicList<regIOobject*> storedObjects;
 
         if (!dryrun && doFields)
@@ -1103,55 +1159,60 @@ int main(int argc, char *argv[])
 
             timer.resetTimeIncrement();
 
-            objects = IOobjectList(mesh, runTime.timeName());
+            IOobjectList objects(mesh, runTime.timeName());
             storedObjects.reserve(objects.size());
 
             const predicates::always nameMatcher;
 
             // Read GeometricFields
 
-            #undef  ReadFields
-            #define ReadFields(FieldType)                                     \
+            #undef  doLocalCode
+            #define doLocalCode(FieldType)                                    \
             readFields<FieldType>(mesh, objects, nameMatcher, storedObjects);
 
             // Read volume fields
-            ReadFields(volScalarField);
-            ReadFields(volVectorField);
-            ReadFields(volSphericalTensorField);
-            ReadFields(volSymmTensorField);
-            ReadFields(volTensorField);
+            doLocalCode(volScalarField);
+            doLocalCode(volVectorField);
+            doLocalCode(volSphericalTensorField);
+            doLocalCode(volSymmTensorField);
+            doLocalCode(volTensorField);
 
             // Read internal fields
-            ReadFields(volScalarField::Internal);
-            ReadFields(volVectorField::Internal);
-            ReadFields(volSphericalTensorField::Internal);
-            ReadFields(volSymmTensorField::Internal);
-            ReadFields(volTensorField::Internal);
+            doLocalCode(volScalarField::Internal);
+            doLocalCode(volVectorField::Internal);
+            doLocalCode(volSphericalTensorField::Internal);
+            doLocalCode(volSymmTensorField::Internal);
+            doLocalCode(volTensorField::Internal);
 
             // Read surface fields
-            ReadFields(surfaceScalarField);
-            ReadFields(surfaceVectorField);
-            ReadFields(surfaceSphericalTensorField);
-            ReadFields(surfaceSymmTensorField);
-            ReadFields(surfaceTensorField);
+            doLocalCode(surfaceScalarField);
+            doLocalCode(surfaceVectorField);
+            doLocalCode(surfaceSphericalTensorField);
+            doLocalCode(surfaceSymmTensorField);
+            doLocalCode(surfaceTensorField);
 
 
             // Read point fields
             const pointMesh& pMesh = pointMesh::New(mesh);
-            #undef  ReadPointFields
-            #define ReadPointFields(FieldType)                                \
+            #undef  doLocalCode
+            #define doLocalCode(FieldType)                                    \
             readFields<FieldType>(pMesh, objects, nameMatcher, storedObjects);
 
-            ReadPointFields(pointScalarField);
-            ReadPointFields(pointVectorField);
-            ReadPointFields(pointSphericalTensorField);
-            ReadPointFields(pointSymmTensorField);
-            ReadPointFields(pointTensorField);
+            doLocalCode(pointScalarField);
+            doLocalCode(pointVectorField);
+            doLocalCode(pointSphericalTensorField);
+            doLocalCode(pointSymmTensorField);
+            doLocalCode(pointTensorField);
 
-            #undef ReadFields
-            #undef ReadPointFields
+            #undef doLocalCode
 
             timings[TimingType::READ_FIELDS] += timer.timeIncrement();
+
+            // Write loaded fields when mesh.write() is called
+            for (auto* fldptr : storedObjects)
+            {
+                fldptr->writeOpt(IOobject::AUTO_WRITE);
+            }
         }
 
 
@@ -1224,7 +1285,13 @@ int main(int argc, char *argv[])
 
 
             CompactListList<label> regionCellOrder =
-                regionRenumber(renumberPtr(), mesh, cellToRegion);
+                regionRenumber
+                (
+                    renumberPtr(),
+                    mesh,
+                    cellToRegion,
+                    decomposePtr().nDomains()
+                );
 
             cellOrder = regionCellOrder.values();
 
@@ -1586,19 +1653,25 @@ int main(int argc, char *argv[])
             );
             reduce(band, maxOp<label>());
             reduce(profile, sumOp<scalar>());
-            reduce(sumSqrIntersect, sumOp<scalar>());
 
-            scalar rmsFrontwidth = Foam::sqrt
-            (
-                sumSqrIntersect/mesh.globalData().nTotalCells()
-            );
+            Info<< "After renumbering";
+            if (doDecompose)
+            {
+                Info<< " [values are misleading with -decompose option]";
+            }
 
-            Info<< "After renumbering :" << nl
+            Info<< nl
                 << "    band           : " << band << nl
                 << "    profile        : " << profile << nl;
 
             if (doFrontWidth)
             {
+                reduce(sumSqrIntersect, sumOp<scalar>());
+                scalar rmsFrontwidth = Foam::sqrt
+                (
+                    sumSqrIntersect/mesh.globalData().nTotalCells()
+                );
+
                 Info<< "    rms frontwidth : " << rmsFrontwidth << nl;
             }
 
diff --git a/applications/utilities/mesh/manipulation/renumberMesh/subsetAdjacency.H b/applications/utilities/mesh/manipulation/renumberMesh/subsetAdjacency.H
new file mode 100644
index 0000000000000000000000000000000000000000..0c098616cf2396faa4daa85f53bc0742157e0464
--- /dev/null
+++ b/applications/utilities/mesh/manipulation/renumberMesh/subsetAdjacency.H
@@ -0,0 +1,168 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2024 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+   This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
+
+Description
+    Subsetting of an adjacency matrix (as CompactListList).
+    Can be relocated elsewhere.
+
+\*---------------------------------------------------------------------------*/
+
+#include "CompactListList.H"
+#include "bitSet.H"
+#include "ListOps.H"
+#include "Map.H"
+
+namespace Foam
+{
+
+// Perform a subset of the adjacency matrix
+CompactListList<label> subsetAdjacency
+(
+    const bitSet& select,   // could also be labelHashSet
+    const CompactListList<label>& input,
+    labelList& subMap
+)
+{
+    // Corresponds to cellMap etc (the original selection)
+    subMap = select.sortedToc();
+
+    // Ensure that the subMap corresponds to a valid subset
+    {
+        label validSize = 0;
+
+        const label nTotal = input.size();
+
+        forAllReverse(subMap, i)
+        {
+            if (subMap[i] < nTotal)
+            {
+                validSize = i + 1;
+                break;
+            }
+        }
+
+        subMap.resize(validSize);
+    }
+
+
+    // Assumed to be sparse - use Map for reverse lookup
+    const Map<label> reverseMap(invertToMap(subMap));
+
+
+    // Pass 1: determine the selected sub-sizes
+    labelList sizes(subMap.size(), Foam::zero{});
+
+    forAll(subMap, idx)
+    {
+        for (const label nbr : input[subMap[idx]])
+        {
+            if
+            (
+                select.test(nbr)
+             && reverseMap.contains(nbr)  // extra consistency (paranoid)
+            )
+            {
+                ++sizes[idx];
+            }
+        }
+    }
+
+
+    CompactListList<label> output(sizes);
+
+    // Reuse sizes as output offset into output.values()
+    sizes = labelList::subList(output.offsets(), output.size());
+    labelList& values = output.values();
+
+
+    // Pass 2: extract sub-adjacent matrix
+
+    label newNbr = -1;
+
+    forAll(subMap, idx)
+    {
+        for (const label nbr : input[subMap[idx]])
+        {
+            if
+            (
+                select.test(nbr)
+             && (newNbr = reverseMap.lookup(nbr, -1)) >= 0
+            )
+            {
+                values[sizes[idx]++] = newNbr;
+            }
+        }
+    }
+
+    return output;
+}
+
+
+// Perform a subset of the adjacency matrix
+CompactListList<label> subsetAdjacency
+(
+    const labelRange& slice,
+    const CompactListList<label>& input,
+    labelList& subMap
+)
+{
+    // Ensure that the selection corresponds to a valid subset
+    const labelRange select = slice.subset0(input.size());
+
+    // Corresponds to cellMap etc (the original selection)
+    subMap = Foam::identity(select);
+
+
+    // Pass 1: determine the selected sub-sizes
+    labelList sizes(subMap.size(), Foam::zero{});
+
+    forAll(subMap, idx)
+    {
+        for (const label nbr : input[subMap[idx]])
+        {
+            if (select.contains(nbr))
+            {
+                ++sizes[idx];
+            }
+        }
+    }
+
+
+    CompactListList<label> output(sizes);
+
+    // Reuse sizes as output offset into output.values()
+    sizes = labelList::subList(output.offsets(), output.size());
+    labelList& values = output.values();
+
+
+    // Pass 2: extract sub-adjacent matrix
+
+    const label localOffset = select.start();
+
+    forAll(subMap, idx)
+    {
+        for (const label nbr : input[subMap[idx]])
+        {
+            if (select.contains(nbr))
+            {
+                values[sizes[idx]++] = nbr - localOffset;
+            }
+        }
+    }
+
+    return output;
+}
+
+} // End namespace Foam
+
+
+// ************************************************************************* //