From 6aa8b82744c91c6e3571ac1c79ffbbd65a624068 Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@esi-group.com>
Date: Fri, 1 Sep 2023 14:10:29 +0200
Subject: [PATCH] ENH: zone improvements

- retain group information when copying zones
- support construct empty (add details later)
- improve consistency for zone and boundaryMesh construction

- support front/back/both selection for faceZoneToCell

STYLE: prefer faceZone patch() method instead of operator()

STYLE: use std::unique_ptr instead of manual pointer management

- for zones and core patch types.
  Easier data management, allows default destructors (for example)
---
 etc/caseDicts/annotated/topoSetSourcesDict    |   6 +-
 .../Identifiers/patch/patchIdentifier.C       |  31 +-
 .../Identifiers/patch/patchIdentifier.H       |  19 +-
 .../meshes/Identifiers/zone/zoneIdentifier.C  |  29 +-
 .../meshes/Identifiers/zone/zoneIdentifier.H  |  19 +-
 .../meshes/polyMesh/mapPolyMesh/mapPolyMesh.C |   2 +-
 .../polyBoundaryMesh/polyBoundaryMesh.C       |  41 +-
 .../polyBoundaryMesh/polyBoundaryMesh.H       |  25 +-
 .../polyBoundaryMeshEntries.C                 |  28 +-
 .../polyBoundaryMeshEntries.H                 |  18 +-
 .../constraint/cyclic/cyclicPolyPatch.C       |  28 +-
 .../constraint/cyclic/cyclicPolyPatch.H       |  33 +-
 .../polyPatches/polyPatch/polyPatch.C         |  20 +-
 .../polyPatches/polyPatch/polyPatch.H         |   8 +-
 .../meshes/polyMesh/zones/ZoneMesh/ZoneMesh.C | 120 ++++--
 .../meshes/polyMesh/zones/ZoneMesh/ZoneMesh.H |  44 +-
 .../meshes/polyMesh/zones/cellZone/cellZone.C |  96 ++++-
 .../meshes/polyMesh/zones/cellZone/cellZone.H |  73 +++-
 .../meshes/polyMesh/zones/faceZone/faceZone.C | 383 +++++++++++-------
 .../meshes/polyMesh/zones/faceZone/faceZone.H | 176 +++++---
 .../polyMesh/zones/pointZone/pointZone.C      |  96 ++++-
 .../polyMesh/zones/pointZone/pointZone.H      |  70 +++-
 .../meshes/polyMesh/zones/zone/zone.C         |  75 ++--
 .../meshes/polyMesh/zones/zone/zone.H         |  26 +-
 .../polyTopoChanger/polyTopoChanger.C         |  15 +-
 .../faMesh/faBoundaryMesh/faBoundaryMesh.C    |  58 ++-
 .../faMesh/faBoundaryMesh/faBoundaryMesh.H    |  28 +-
 .../faBoundaryMesh/faBoundaryMeshEntries.C    |  29 +-
 .../faBoundaryMesh/faBoundaryMeshEntries.H    |  17 +-
 .../faMesh/faPatches/faPatch/faPatch.C        |  23 +-
 .../faMesh/faPatches/faPatch/faPatch.H        |   6 +-
 .../fvMesh/fvBoundaryMesh/fvBoundaryMesh.H    |  23 +-
 src/meshTools/cellFeatures/cellFeatures.C     |  11 +-
 src/meshTools/cellFeatures/cellFeatures.H     |   8 +-
 src/meshTools/polyTopoChange/polyTopoChange.C |   4 +-
 .../faceZoneToCell/faceZoneToCell.C           |  82 +++-
 .../faceZoneToCell/faceZoneToCell.H           |  18 +-
 src/surfMesh/surfZone/surfZoneIOList.C        |  61 ++-
 src/surfMesh/surfZone/surfZoneIOList.H        |  13 +-
 .../cpuCabinet/system/topoSetDict.f1          |  15 +-
 .../pisoFoam/RAS/cavity/system/topoSetDict    |   6 +-
 41 files changed, 1288 insertions(+), 595 deletions(-)

diff --git a/etc/caseDicts/annotated/topoSetSourcesDict b/etc/caseDicts/annotated/topoSetSourcesDict
index 53a868b7f6c..11e2608439d 100644
--- a/etc/caseDicts/annotated/topoSetSourcesDict
+++ b/etc/caseDicts/annotated/topoSetSourcesDict
@@ -1,7 +1,7 @@
 /*--------------------------------*- C++ -*----------------------------------*\
 | =========                 |                                                 |
 | \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
-|  \\    /   O peration     | Version:  v2306                                 |
+|  \\    /   O peration     | Version:  v2312                                 |
 |   \\  /    A nd           | Website:  www.openfoam.com                      |
 |    \\/     M anipulation  |                                                 |
 \*---------------------------------------------------------------------------*/
@@ -71,14 +71,14 @@ cellSet_doc
     }
 
 
-    //- Cells on master or slave side of faceZone
+    //- Cells on front/back/both side of faceZone
     {
         source  faceZoneToCell;
         zones   (".*Zone");     // Names of faceZones, word or regex
         // or
         zone    ".*Zone";       // Name of faceZone, word or regex
 
-        option  master;         // master/slave
+        option  front;          // front/back/both
     }
 
 
diff --git a/src/OpenFOAM/meshes/Identifiers/patch/patchIdentifier.C b/src/OpenFOAM/meshes/Identifiers/patch/patchIdentifier.C
index e0c59d99dd5..a76ade8c7d5 100644
--- a/src/OpenFOAM/meshes/Identifiers/patch/patchIdentifier.C
+++ b/src/OpenFOAM/meshes/Identifiers/patch/patchIdentifier.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2013 OpenFOAM Foundation
-    Copyright (C) 2020-2021 OpenCFD Ltd.
+    Copyright (C) 2020-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -81,14 +81,31 @@ Foam::patchIdentifier::patchIdentifier
 Foam::patchIdentifier::patchIdentifier
 (
     const patchIdentifier& ident,
-    const label index
+    const label newIndex
 )
 :
-    name_(ident.name_),
-    index_(index),
-    physicalType_(ident.physicalType_),
-    inGroups_(ident.inGroups_)
-{}
+    patchIdentifier(ident)
+{
+    if (newIndex >= 0)
+    {
+        index_ = newIndex;
+    }
+}
+
+
+Foam::patchIdentifier::patchIdentifier
+(
+    patchIdentifier&& ident,
+    const label newIndex
+)
+:
+    patchIdentifier(std::move(ident))
+{
+    if (newIndex >= 0)
+    {
+        index_ = newIndex;
+    }
+}
 
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
diff --git a/src/OpenFOAM/meshes/Identifiers/patch/patchIdentifier.H b/src/OpenFOAM/meshes/Identifiers/patch/patchIdentifier.H
index e5e5ba43e6c..f6796d603de 100644
--- a/src/OpenFOAM/meshes/Identifiers/patch/patchIdentifier.H
+++ b/src/OpenFOAM/meshes/Identifiers/patch/patchIdentifier.H
@@ -90,16 +90,22 @@ public:
         //- Copy construct
         patchIdentifier(const patchIdentifier&) = default;
 
+        //- Move construct
+        patchIdentifier(patchIdentifier&&) = default;
+
         //- Copy assignment
         patchIdentifier& operator=(const patchIdentifier&) = default;
 
+        //- Move assignment
+        patchIdentifier& operator=(patchIdentifier&&) = default;
+
         //- Destructor
         virtual ~patchIdentifier() = default;
 
 
     // Constructors
 
-        //- Default construct. Uses name="", index=0
+        //- Default construct: name="", index=0
         patchIdentifier();
 
         //- Construct from mandatory components
@@ -122,11 +128,18 @@ public:
             const label index
         );
 
-        //- Copy construct, resetting the index
+        //- Copy construct, resetting the index (if non-negative)
         patchIdentifier
         (
             const patchIdentifier& ident,
-            const label index
+            const label newIndex
+        );
+
+        //- Move construct, resetting the index (if non-negative)
+        patchIdentifier
+        (
+            patchIdentifier&& ident,
+            const label newIndex
         );
 
 
diff --git a/src/OpenFOAM/meshes/Identifiers/zone/zoneIdentifier.C b/src/OpenFOAM/meshes/Identifiers/zone/zoneIdentifier.C
index c28b53f7556..acfa9f67434 100644
--- a/src/OpenFOAM/meshes/Identifiers/zone/zoneIdentifier.C
+++ b/src/OpenFOAM/meshes/Identifiers/zone/zoneIdentifier.C
@@ -80,14 +80,31 @@ Foam::zoneIdentifier::zoneIdentifier
 Foam::zoneIdentifier::zoneIdentifier
 (
     const zoneIdentifier& ident,
-    const label index
+    const label newIndex
 )
 :
-    name_(ident.name_),
-    index_(index),
-    physicalType_(ident.physicalType_),
-    inGroups_(ident.inGroups_)
-{}
+    zoneIdentifier(ident)
+{
+    if (newIndex >= 0)
+    {
+        index_ = newIndex;
+    }
+}
+
+
+Foam::zoneIdentifier::zoneIdentifier
+(
+    zoneIdentifier&& ident,
+    const label newIndex
+)
+:
+    zoneIdentifier(std::move(ident))
+{
+    if (newIndex >= 0)
+    {
+        index_ = newIndex;
+    }
+}
 
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
diff --git a/src/OpenFOAM/meshes/Identifiers/zone/zoneIdentifier.H b/src/OpenFOAM/meshes/Identifiers/zone/zoneIdentifier.H
index 19d9bdb662d..9a6c9437291 100644
--- a/src/OpenFOAM/meshes/Identifiers/zone/zoneIdentifier.H
+++ b/src/OpenFOAM/meshes/Identifiers/zone/zoneIdentifier.H
@@ -78,16 +78,22 @@ public:
         //- Copy construct
         zoneIdentifier(const zoneIdentifier&) = default;
 
+        //- Move construct
+        zoneIdentifier(zoneIdentifier&&) = default;
+
         //- Copy assignment
         zoneIdentifier& operator=(const zoneIdentifier&) = default;
 
+        //- Move assignment
+        zoneIdentifier& operator=(zoneIdentifier&&) = default;
+
         //- Destructor
         virtual ~zoneIdentifier() = default;
 
 
     // Constructors
 
-        //- Default construct. Uses name="", index=0
+        //- Default construct: name="", index=0
         zoneIdentifier();
 
         //- Construct from mandatory components
@@ -110,11 +116,18 @@ public:
             const label index
         );
 
-        //- Copy construct, resetting the index
+        //- Copy construct, resetting the index (if non-negative)
         zoneIdentifier
         (
             const zoneIdentifier& ident,
-            const label index
+            const label newIndex
+        );
+
+        //- Move construct, resetting the index (if non-negative)
+        zoneIdentifier
+        (
+            zoneIdentifier&& ident,
+            const label newIndex
         );
 
 
diff --git a/src/OpenFOAM/meshes/polyMesh/mapPolyMesh/mapPolyMesh.C b/src/OpenFOAM/meshes/polyMesh/mapPolyMesh/mapPolyMesh.C
index 0bae7021c7e..ee7694bb112 100644
--- a/src/OpenFOAM/meshes/polyMesh/mapPolyMesh/mapPolyMesh.C
+++ b/src/OpenFOAM/meshes/polyMesh/mapPolyMesh/mapPolyMesh.C
@@ -81,7 +81,7 @@ Foam::mapPolyMesh::mapPolyMesh(const polyMesh& mesh)
     forAll(faceZonePointMap_, zonei)
     {
         faceZonePointMap_[zonei] =
-            identity(mesh.faceZones()[zonei]().meshPoints().size());
+            identity(mesh.faceZones()[zonei].patch().meshPoints().size());
     }
 
     forAll(faceZoneFaceMap_, zonei)
diff --git a/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMesh.C b/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMesh.C
index 29ffe6f3f18..531500637f5 100644
--- a/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMesh.C
+++ b/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMesh.C
@@ -105,12 +105,12 @@ void Foam::polyBoundaryMesh::calcGroupIDs() const
 }
 
 
-bool Foam::polyBoundaryMesh::readContents(const bool allowReadIfPresent)
+bool Foam::polyBoundaryMesh::readContents(const bool allowOptionalRead)
 {
     if
     (
         this->isReadRequired()
-     || (allowReadIfPresent && this->isReadOptional() && this->headerOk())
+     || (allowOptionalRead && this->isReadOptional() && this->headerOk())
     )
     {
         // Warn for MUST_READ_IF_MODIFIED
@@ -118,12 +118,11 @@ bool Foam::polyBoundaryMesh::readContents(const bool allowReadIfPresent)
 
         polyPatchList& patches = *this;
 
-        // Read polyPatchList
+        // Read entries
         Istream& is = readStream(typeName);
 
-        // Read patches as entries
-        PtrList<entry> patchEntries(is);
-        patches.resize(patchEntries.size());
+        PtrList<entry> entries(is);
+        patches.resize_null(entries.size());
 
         // Transcribe
         forAll(patches, patchi)
@@ -133,8 +132,8 @@ bool Foam::polyBoundaryMesh::readContents(const bool allowReadIfPresent)
                 patchi,
                 polyPatch::New
                 (
-                    patchEntries[patchi].keyword(),
-                    patchEntries[patchi].dict(),
+                    entries[patchi].keyword(),
+                    entries[patchi].dict(),
                     patchi,
                     *this
                 )
@@ -146,6 +145,7 @@ bool Foam::polyBoundaryMesh::readContents(const bool allowReadIfPresent)
         return true;
     }
 
+    // Nothing read
     return false;
 }
 
@@ -162,10 +162,23 @@ Foam::polyBoundaryMesh::polyBoundaryMesh
     regIOobject(io),
     mesh_(mesh)
 {
-    readContents(false);  // READ_IF_PRESENT allowed: False
+    readContents(false);  // allowOptionalRead = false
 }
 
 
+Foam::polyBoundaryMesh::polyBoundaryMesh
+(
+    const IOobject& io,
+    const polyMesh& pm,
+    Foam::zero
+)
+:
+    polyPatchList(),
+    regIOobject(io),
+    mesh_(pm)
+{}
+
+
 Foam::polyBoundaryMesh::polyBoundaryMesh
 (
     const IOobject& io,
@@ -183,20 +196,22 @@ Foam::polyBoundaryMesh::polyBoundaryMesh
 (
     const IOobject& io,
     const polyMesh& pm,
-    const polyPatchList& ppl
+    const polyPatchList& list
 )
 :
     polyPatchList(),
     regIOobject(io),
     mesh_(pm)
 {
-    if (!readContents(true))  // READ_IF_PRESENT allowed: True
+    if (!readContents(true))  // allowOptionalRead = true
     {
+        // Nothing read. Use supplied patches
         polyPatchList& patches = *this;
-        patches.resize(ppl.size());
+        patches.resize(list.size());
+
         forAll(patches, patchi)
         {
-            patches.set(patchi, ppl[patchi].clone(*this));
+            patches.set(patchi, list[patchi].clone(*this));
         }
     }
 }
diff --git a/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMesh.H b/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMesh.H
index ab953dd029c..625b2d7a3ef 100644
--- a/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMesh.H
+++ b/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMesh.H
@@ -91,8 +91,9 @@ class polyBoundaryMesh
         //- Calculate group name to patch ids lookup
         void calcGroupIDs() const;
 
-        //- Read if IOobject flags set. Return true if read.
-        bool readContents(const bool allowReadIfPresent);
+        //- Return true if contents were read
+        //- (controlled by IOobject readOption flags).
+        bool readContents(const bool allowOptionalRead);
 
 public:
 
@@ -114,15 +115,24 @@ public:
 
     // Constructors
 
-        //- Read constructor given IOobject and a polyMesh reference
-        //  Note point pointers are unset, only used in copying meshes
+        //- Read construct given IOobject and a mesh reference.
+        //- It will only read for MUST_READ variants (not READ_IF_PRESENT).
         polyBoundaryMesh
         (
             const IOobject& io,
             const polyMesh& mesh
         );
 
-        //- Construct given size
+        //- Construct empty with IOobject properties and a mesh reference.
+        //- Does not read.
+        polyBoundaryMesh
+        (
+            const IOobject& io,
+            const polyMesh& mesh,
+            Foam::zero
+        );
+
+        //- Construct with specified size. Does not read.
         polyBoundaryMesh
         (
             const IOobject& io,
@@ -130,12 +140,13 @@ public:
             const label size
         );
 
-        //- Construct given polyPatchList
+        //- Read construct (mandatory, optional) based on IOobject properties
+        //- or use the fallback PtrList (with cloning).
         polyBoundaryMesh
         (
             const IOobject& io,
             const polyMesh& mesh,
-            const polyPatchList& ppl
+            const polyPatchList& list
         );
 
 
diff --git a/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMeshEntries.C b/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMeshEntries.C
index 05e419e4d50..a58a4ad6843 100644
--- a/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMeshEntries.C
+++ b/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMeshEntries.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2012 OpenFOAM Foundation
-    Copyright (C) 2020 OpenCFD Ltd.
+    Copyright (C) 2020-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -27,6 +27,7 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "polyBoundaryMeshEntries.H"
+#include "processorPolyPatch.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -36,4 +37,29 @@ namespace Foam
 }
 
 
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::polyBoundaryMeshEntries::removeProcPatches()
+{
+    // Truncate at the first processor patch entry
+    PtrList<entry>& entries = *this;
+
+    label nNonProcessor = entries.size();
+
+    forAll(entries, patchi)
+    {
+        const dictionary& dict = entries[patchi].dict();
+
+        const word pType = dict.get<word>("type");
+        if (pType == processorPolyPatch::typeName)
+        {
+            nNonProcessor = patchi;
+            break;
+        }
+    }
+
+    entries.resize(nNonProcessor);
+}
+
+
 // ************************************************************************* //
diff --git a/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMeshEntries.H b/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMeshEntries.H
index aa2f97635a3..671aa229588 100644
--- a/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMeshEntries.H
+++ b/src/OpenFOAM/meshes/polyMesh/polyBoundaryMesh/polyBoundaryMeshEntries.H
@@ -53,8 +53,8 @@ namespace Foam
 
 class polyBoundaryMeshEntries
 :
-    public regIOobject,
-    public PtrList<entry>
+    public PtrList<entry>,
+    public regIOobject
 {
 public:
 
@@ -64,20 +64,28 @@ public:
 
     // Constructors
 
+        //- Read construct from IOobject
         explicit polyBoundaryMeshEntries(const IOobject& io)
         :
-            regIOobject(io),
-            PtrList<entry>()
+            regIOobject(io)
         {
             if (isReadRequired() || (isReadOptional() && headerOk()))
             {
-                readStream(typeName) >> *this;
+                // Read as entries
+                Istream& is = readStream(typeName);
+
+                is >> *this;
+                close();
             }
         }
 
 
    // Member Functions
 
+        //- Truncate at the first processor patch entry
+        void removeProcPatches();
+
+        //- The class is probably read-only
         bool writeData(Ostream&) const
         {
             NotImplemented;
diff --git a/src/OpenFOAM/meshes/polyMesh/polyPatches/constraint/cyclic/cyclicPolyPatch.C b/src/OpenFOAM/meshes/polyMesh/polyPatches/constraint/cyclic/cyclicPolyPatch.C
index f42eb85f155..ea0bfbbc848 100644
--- a/src/OpenFOAM/meshes/polyMesh/polyPatches/constraint/cyclic/cyclicPolyPatch.C
+++ b/src/OpenFOAM/meshes/polyMesh/polyPatches/constraint/cyclic/cyclicPolyPatch.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2015-2020 OpenCFD Ltd.
+    Copyright (C) 2015-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -30,7 +30,6 @@ License
 #include "addToRunTimeSelectionTable.H"
 #include "polyBoundaryMesh.H"
 #include "polyMesh.H"
-#include "demandDrivenData.H"
 #include "OFstream.H"
 #include "matchPoints.H"
 #include "edgeHashes.H"
@@ -50,7 +49,7 @@ namespace Foam
 }
 
 
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
 Foam::label Foam::cyclicPolyPatch::findMaxArea
 (
@@ -813,10 +812,7 @@ Foam::cyclicPolyPatch::cyclicPolyPatch
 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
 
 Foam::cyclicPolyPatch::~cyclicPolyPatch()
-{
-    deleteDemandDrivenData(coupledPointsPtr_);
-    deleteDemandDrivenData(coupledEdgesPtr_);
-}
+{}
 
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
@@ -1022,8 +1018,8 @@ void Foam::cyclicPolyPatch::initUpdateMesh(PstreamBuffers& pBufs)
 void Foam::cyclicPolyPatch::updateMesh(PstreamBuffers& pBufs)
 {
     polyPatch::updateMesh(pBufs);
-    deleteDemandDrivenData(coupledPointsPtr_);
-    deleteDemandDrivenData(coupledEdgesPtr_);
+    coupledPointsPtr_.reset(nullptr);
+    coupledEdgesPtr_.reset(nullptr);
 }
 
 
@@ -1063,8 +1059,8 @@ const Foam::edgeList& Foam::cyclicPolyPatch::coupledPoints() const
             }
         }
 
-        coupledPointsPtr_ = new edgeList(nPoints());
-        edgeList& connected = *coupledPointsPtr_;
+        coupledPointsPtr_.reset(new edgeList(nPoints()));
+        auto& connected = *coupledPointsPtr_;
 
         // Extract coupled points.
         label connectedI = 0;
@@ -1153,8 +1149,8 @@ const Foam::edgeList& Foam::cyclicPolyPatch::coupledEdges() const
         const labelList& mp = meshPoints();
 
 
-        coupledEdgesPtr_ = new edgeList(edgeMap.size());
-        edgeList& coupledEdges = *coupledEdgesPtr_;
+        coupledEdgesPtr_.reset(new edgeList(edgeMap.size()));
+        auto& coupledEdges = *coupledEdgesPtr_;
         label coupleI = 0;
 
         forAll(neighbPatch, patchFacei)
@@ -1275,10 +1271,10 @@ bool Foam::cyclicPolyPatch::order
             << " neighbour:" << neighbPatchName()
             << endl;
     }
-    faceMap.setSize(pp.size());
+    faceMap.resize_nocopy(pp.size());
     faceMap = -1;
 
-    rotation.setSize(pp.size());
+    rotation.resize_nocopy(pp.size());
     rotation = 0;
 
     if (transform() == NOORDERING)
@@ -1434,7 +1430,7 @@ bool Foam::cyclicPolyPatch::order
             }
         }
 
-        ownerPatchPtr_.clear();
+        ownerPatchPtr_.reset(nullptr);
 
         // Return false if no change necessary, true otherwise.
 
diff --git a/src/OpenFOAM/meshes/polyMesh/polyPatches/constraint/cyclic/cyclicPolyPatch.H b/src/OpenFOAM/meshes/polyMesh/polyPatches/constraint/cyclic/cyclicPolyPatch.H
index 13302a8f469..19d0c9406e2 100644
--- a/src/OpenFOAM/meshes/polyMesh/polyPatches/constraint/cyclic/cyclicPolyPatch.H
+++ b/src/OpenFOAM/meshes/polyMesh/polyPatches/constraint/cyclic/cyclicPolyPatch.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2015 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -46,8 +46,8 @@ SourceFiles
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef cyclicPolyPatch_H
-#define cyclicPolyPatch_H
+#ifndef Foam_cyclicPolyPatch_H
+#define Foam_cyclicPolyPatch_H
 
 #include "coupledPolyPatch.H"
 #include "edgeList.H"
@@ -68,7 +68,7 @@ class cyclicPolyPatch
 :
     public coupledPolyPatch
 {
-    // Private data
+    // Private Data
 
         //- Name of other half
         mutable word neighbPatchName_;
@@ -93,16 +93,19 @@ class cyclicPolyPatch
             vector separationVector_;
 
 
-        //- List of edges formed from connected points. e[0] is the point on
-        //  the first half of the patch, e[1] the corresponding point on the
-        //  second half.
-        mutable edgeList* coupledPointsPtr_;
+        //- List of edges formed from connected points.
+        //  From first half of the patch to the corresponding point
+        //  on the second half.
+        mutable std::unique_ptr<edgeList> coupledPointsPtr_;
 
-        //- List of connected edges. e[0] is the edge on the first half of the
-        //  patch, e[1] the corresponding edge on the second half.
-        mutable edgeList* coupledEdgesPtr_;
+        //- List of connected edges.
+        //  From first half of the patch to the corresponding edge
+        //  on the second half.
+        mutable std::unique_ptr<edgeList> coupledEdgesPtr_;
 
         //- Temporary storage of owner side patch during ordering.
+        //  Saved as autoPtr instead of std::unique_ptr to allow
+        //  extra nullptr checking
         mutable autoPtr<primitivePatch> ownerPatchPtr_;
 
 
@@ -323,7 +326,7 @@ public:
 
         // Implicit Functions
 
-             //- Return number of new internal of this polyPatch faces
+            //- Return number of new internal of this polyPatch faces
             virtual void newInternalProcFaces
             (
                 label& newFaces,
@@ -424,19 +427,19 @@ public:
         }
 
         //- Axis of rotation for rotational cyclics
-        const vector& rotationAxis() const
+        const vector& rotationAxis() const noexcept
         {
             return rotationAxis_;
         }
 
         //- Point on axis of rotation for rotational cyclics
-        const point& rotationCentre() const
+        const point& rotationCentre() const noexcept
         {
             return rotationCentre_;
         }
 
         //- Translation vector for translational cyclics
-        const vector& separationVector() const
+        const vector& separationVector() const noexcept
         {
             return separationVector_;
         }
diff --git a/src/OpenFOAM/meshes/polyMesh/polyPatches/polyPatch/polyPatch.C b/src/OpenFOAM/meshes/polyMesh/polyPatches/polyPatch/polyPatch.C
index 7ad617d3112..1a5e79754c9 100644
--- a/src/OpenFOAM/meshes/polyMesh/polyPatches/polyPatch/polyPatch.C
+++ b/src/OpenFOAM/meshes/polyMesh/polyPatches/polyPatch/polyPatch.C
@@ -35,7 +35,6 @@ License
 #include "entry.H"
 #include "dictionary.H"
 #include "pointPatchField.H"
-#include "demandDrivenData.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -260,7 +259,7 @@ Foam::polyPatch::polyPatch
 :
     polyPatch(p)
 {
-    faceCellsPtr_ = new labelList::subList(faceCells, faceCells.size());
+    faceCellsPtr_.reset(new labelList::subList(faceCells, faceCells.size()));
 }
 
 
@@ -374,9 +373,12 @@ const Foam::labelUList& Foam::polyPatch::faceCells() const
 {
     if (!faceCellsPtr_)
     {
-        faceCellsPtr_ = new labelList::subList
+        faceCellsPtr_.reset
         (
-            patchSlice(boundaryMesh().mesh().faceOwner())
+            new labelList::subList
+            (
+                patchSlice(boundaryMesh().mesh().faceOwner())
+            )
         );
     }
 
@@ -388,7 +390,8 @@ const Foam::labelList& Foam::polyPatch::meshEdges() const
 {
     if (!mePtr_)
     {
-        mePtr_ =
+        mePtr_.reset
+        (
             new labelList
             (
                 primitivePatch::meshEdges
@@ -396,7 +399,8 @@ const Foam::labelList& Foam::polyPatch::meshEdges() const
                     boundaryMesh().mesh().edges(),
                     boundaryMesh().mesh().pointEdges()
                 )
-            );
+            )
+        );
     }
 
     return *mePtr_;
@@ -407,8 +411,8 @@ void Foam::polyPatch::clearAddressing()
 {
     primitivePatch::clearTopology();
     primitivePatch::clearPatchMeshAddr();
-    deleteDemandDrivenData(faceCellsPtr_);
-    deleteDemandDrivenData(mePtr_);
+    faceCellsPtr_.reset(nullptr);
+    mePtr_.reset(nullptr);
 }
 
 
diff --git a/src/OpenFOAM/meshes/polyMesh/polyPatches/polyPatch/polyPatch.H b/src/OpenFOAM/meshes/polyMesh/polyPatches/polyPatch/polyPatch.H
index 42104698df3..c6761791975 100644
--- a/src/OpenFOAM/meshes/polyMesh/polyPatches/polyPatch/polyPatch.H
+++ b/src/OpenFOAM/meshes/polyMesh/polyPatches/polyPatch/polyPatch.H
@@ -83,10 +83,10 @@ class polyPatch
         const polyBoundaryMesh& boundaryMesh_;
 
         //- Demand-driven: face-cell addressing
-        mutable labelList::subList* faceCellsPtr_;
+        mutable std::unique_ptr<labelList::subList> faceCellsPtr_;
 
         //- Demand-driven: global edge addressing
-        mutable labelList* mePtr_;
+        mutable std::unique_ptr<labelList> mePtr_;
 
 
 protected:
@@ -500,8 +500,8 @@ public:
 
     // Member Operators
 
-        //- Assignment
-        void operator=(const polyPatch&);
+        //- Copy assignment
+        void operator=(const polyPatch& p);
 
 
     // Ostream Operator
diff --git a/src/OpenFOAM/meshes/polyMesh/zones/ZoneMesh/ZoneMesh.C b/src/OpenFOAM/meshes/polyMesh/zones/ZoneMesh/ZoneMesh.C
index ed35f4a3414..622365e95d9 100644
--- a/src/OpenFOAM/meshes/polyMesh/zones/ZoneMesh/ZoneMesh.C
+++ b/src/OpenFOAM/meshes/polyMesh/zones/ZoneMesh/ZoneMesh.C
@@ -47,6 +47,22 @@ namespace Foam
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
+template<class ZoneType, class MeshType>
+Foam::label Foam::ZoneMesh<ZoneType, MeshType>::totalSize() const
+{
+    // Count number of objects in all zones
+    const PtrList<ZoneType>& zones = *this;
+
+    label total = 0;
+    for (const ZoneType& zn : zones)
+    {
+        total += zn.size();
+    }
+
+    return total;
+}
+
+
 template<class ZoneType, class MeshType>
 void Foam::ZoneMesh<ZoneType, MeshType>::calcZoneMap() const
 {
@@ -58,31 +74,22 @@ void Foam::ZoneMesh<ZoneType, MeshType>::calcZoneMap() const
     }
     else
     {
-        // Count number of objects in all zones
-        label nObjects = 0;
-
-        const PtrList<ZoneType>& zones = *this;
-
-        for (const ZoneType& zn : zones)
-        {
-            nObjects += zn.size();
-        }
-
-        zoneMapPtr_.emplace(2*nObjects);
-        auto& zm = *zoneMapPtr_;
+        zoneMapPtr_.reset(new Map<label>());
+        auto& map = *zoneMapPtr_;
 
         // Fill in objects of all zones into the map.
         // The key is the global object index, value is the zone index
 
+        map.reserve(this->totalSize());
+
+        const PtrList<ZoneType>& zones = *this;
         label zonei = 0;
 
         for (const ZoneType& zn : zones)
         {
-            const labelList& labels = zn;
-
-            for (const label idx : labels)
+            for (const label id : static_cast<const labelList&>(zn))
             {
-                zm.insert(idx, zonei);
+                map.insert(id, zonei);
             }
 
             ++zonei;
@@ -122,7 +129,7 @@ void Foam::ZoneMesh<ZoneType, MeshType>::calcGroupIDs() const
         return;  // Or FatalError
     }
 
-    groupIDsPtr_.emplace(16);
+    groupIDsPtr_.reset(new HashTable<labelList>(16));
     auto& groupLookup = *groupIDsPtr_;
 
     const PtrList<ZoneType>& zones = *this;
@@ -151,20 +158,27 @@ void Foam::ZoneMesh<ZoneType, MeshType>::calcGroupIDs() const
 
 
 template<class ZoneType, class MeshType>
-bool Foam::ZoneMesh<ZoneType, MeshType>::readContents()
+bool Foam::ZoneMesh<ZoneType, MeshType>::readContents
+(
+    const bool allowOptionalRead
+)
 {
-    if (isReadRequired() || (isReadOptional() && headerOk()))
+    if
+    (
+        isReadRequired()
+     || (allowOptionalRead && isReadOptional() && headerOk())
+    )
     {
         // Warn for MUST_READ_IF_MODIFIED
         warnNoRereading<ZoneMesh<ZoneType, MeshType>>();
 
         PtrList<ZoneType>& zones = *this;
 
-        // Read zones as entries
+        // Read entries
         Istream& is = readStream(typeName);
 
-        PtrList<entry> patchEntries(is);
-        zones.resize(patchEntries.size());
+        PtrList<entry> entries(is);
+        zones.resize_null(entries.size());
 
         // Transcribe
         forAll(zones, zonei)
@@ -174,8 +188,8 @@ bool Foam::ZoneMesh<ZoneType, MeshType>::readContents()
                 zonei,
                 ZoneType::New
                 (
-                    patchEntries[zonei].keyword(),
-                    patchEntries[zonei].dict(),
+                    entries[zonei].keyword(),
+                    entries[zonei].dict(),
                     zonei,
                     *this
                 )
@@ -205,10 +219,26 @@ Foam::ZoneMesh<ZoneType, MeshType>::ZoneMesh
     regIOobject(io),
     mesh_(mesh)
 {
-    readContents();
+    // Note: this is inconsistent with polyBoundaryMesh
+    // which does not permit optional reading
+    readContents(true);  // allowOptionalRead = true
 }
 
 
+template<class ZoneType, class MeshType>
+Foam::ZoneMesh<ZoneType, MeshType>::ZoneMesh
+(
+    const IOobject& io,
+    const MeshType& mesh,
+    Foam::zero
+)
+:
+    PtrList<ZoneType>(),
+    regIOobject(io),
+    mesh_(mesh)
+{}
+
+
 template<class ZoneType, class MeshType>
 Foam::ZoneMesh<ZoneType, MeshType>::ZoneMesh
 (
@@ -221,8 +251,9 @@ Foam::ZoneMesh<ZoneType, MeshType>::ZoneMesh
     regIOobject(io),
     mesh_(mesh)
 {
-    // Optionally read contents, otherwise keep size
-    readContents();
+    // Note: this is inconsistent with polyBoundaryMesh
+    // which does not read all
+    readContents(true);  // allowOptionalRead = true
 }
 
 
@@ -231,36 +262,27 @@ Foam::ZoneMesh<ZoneType, MeshType>::ZoneMesh
 (
     const IOobject& io,
     const MeshType& mesh,
-    const PtrList<ZoneType>& pzm
+    const PtrList<ZoneType>& list
 )
 :
     PtrList<ZoneType>(),
     regIOobject(io),
     mesh_(mesh)
 {
-    if (!readContents())
+    if (!readContents(true))  // allowOptionalRead = true
     {
         // Nothing read. Use supplied zones
         PtrList<ZoneType>& zones = *this;
-        zones.resize(pzm.size());
+        zones.resize(list.size());
 
         forAll(zones, zonei)
         {
-            zones.set(zonei, pzm[zonei].clone(*this));
+            zones.set(zonei, list[zonei].clone(*this));
         }
     }
 }
 
 
-// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
-
-template<class ZoneType, class MeshType>
-Foam::ZoneMesh<ZoneType, MeshType>::~ZoneMesh()
-{
-    clearAddressing();
-}
-
-
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 template<class ZoneType, class MeshType>
@@ -710,7 +732,7 @@ void Foam::ZoneMesh<ZoneType, MeshType>::setGroup
     const labelUList& zoneIDs
 )
 {
-    groupIDsPtr_.clear();
+    groupIDsPtr_.reset(nullptr);
 
     PtrList<ZoneType>& zones = *this;
 
@@ -740,8 +762,8 @@ void Foam::ZoneMesh<ZoneType, MeshType>::setGroup
 template<class ZoneType, class MeshType>
 void Foam::ZoneMesh<ZoneType, MeshType>::clearAddressing()
 {
-    zoneMapPtr_.clear();
-    groupIDsPtr_.clear();
+    zoneMapPtr_.reset(nullptr);
+    groupIDsPtr_.reset(nullptr);
 
     PtrList<ZoneType>& zones = *this;
 
@@ -752,6 +774,18 @@ void Foam::ZoneMesh<ZoneType, MeshType>::clearAddressing()
 }
 
 
+template<class ZoneType, class MeshType>
+void Foam::ZoneMesh<ZoneType, MeshType>::clearPrimitives()
+{
+    PtrList<ZoneType>& zones = *this;
+
+    for (ZoneType& zn : zones)
+    {
+        zn.clearPrimitives();
+    }
+}
+
+
 template<class ZoneType, class MeshType>
 void Foam::ZoneMesh<ZoneType, MeshType>::clear()
 {
diff --git a/src/OpenFOAM/meshes/polyMesh/zones/ZoneMesh/ZoneMesh.H b/src/OpenFOAM/meshes/polyMesh/zones/ZoneMesh/ZoneMesh.H
index 54863912e21..841819e3d1b 100644
--- a/src/OpenFOAM/meshes/polyMesh/zones/ZoneMesh/ZoneMesh.H
+++ b/src/OpenFOAM/meshes/polyMesh/zones/ZoneMesh/ZoneMesh.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2016-2022 OpenCFD Ltd.
+    Copyright (C) 2016-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -74,16 +74,20 @@ class ZoneMesh
         const MeshType& mesh_;
 
         //- Demand-driven: map of zone labels for given element
-        mutable autoPtr<Map<label>> zoneMapPtr_;
+        mutable std::unique_ptr<Map<label>> zoneMapPtr_;
 
         //- Demand-driven: list of zone ids per group
-        mutable autoPtr<HashTable<labelList>> groupIDsPtr_;
+        mutable std::unique_ptr<HashTable<labelList>> groupIDsPtr_;
 
 
     // Private Member Functions
 
-        //- Read if IOobject flags set. Return true if read.
-        bool readContents();
+        //- Return true if contents were read
+        //- (controlled by IOobject readOption flags).
+        bool readContents(const bool allowOptionalRead);
+
+        //- Total of number of addressed items (all zones)
+        label totalSize() const;
 
         //- Create zone map
         void calcZoneMap() const;
@@ -109,14 +113,25 @@ public:
 
     // Constructors
 
-        //- Read constructor given IOobject and a MeshType reference
+        //- Read construct from IOobject and mesh reference
+        //- Any reading (mandatory, optional) based on IOobject properties.
         ZoneMesh
         (
             const IOobject& io,
             const MeshType& mesh
         );
 
-        //- Construct given size
+        //- Construct empty with IOobject properties and a mesh reference.
+        //- Does not read.
+        ZoneMesh
+        (
+            const IOobject& io,
+            const MeshType& mesh,
+            Foam::zero
+        );
+
+        //- Construct with specified size if not read.
+        //- Any reading (mandatory, optional) based on IOobject properties.
         ZoneMesh
         (
             const IOobject& io,
@@ -124,26 +139,24 @@ public:
             const label size
         );
 
-        //- Construct given a PtrList
+        //- Read construct (mandatory, optional) based on IOobject properties
+        //- or use the fallback PtrList (with cloning).
         ZoneMesh
         (
             const IOobject& io,
             const MeshType& mesh,
-            const PtrList<ZoneType>& pzm
+            const PtrList<ZoneType>& list
         );
 
 
     //- Destructor
-    ~ZoneMesh();
+    ~ZoneMesh() = default;
 
 
     // Member Functions
 
         //- Return the mesh reference
-        const MeshType& mesh() const noexcept
-        {
-            return mesh_;
-        }
+        const MeshType& mesh() const noexcept { return mesh_; }
 
         //- Map of zones containing zone index for all zoned elements
         //  Return -1 if the object is not in the zone
@@ -280,6 +293,9 @@ public:
         //- Clear addressing
         void clearAddressing();
 
+        //- Clear primitive addressing
+        void clearPrimitives();
+
         //- Clear the zones
         void clear();
 
diff --git a/src/OpenFOAM/meshes/polyMesh/zones/cellZone/cellZone.C b/src/OpenFOAM/meshes/polyMesh/zones/cellZone/cellZone.C
index a8f5d287c68..092081f418e 100644
--- a/src/OpenFOAM/meshes/polyMesh/zones/cellZone/cellZone.C
+++ b/src/OpenFOAM/meshes/polyMesh/zones/cellZone/cellZone.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011 OpenFOAM Foundation
-    Copyright (C) 2017-2021 OpenCFD Ltd.
+    Copyright (C) 2017-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -47,6 +47,12 @@ const char * const Foam::cellZone::labelsName = "cellLabels";
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
+Foam::cellZone::cellZone(const cellZoneMesh& zm)
+:
+    cellZone(word::null, 0, zm)
+{}
+
+
 Foam::cellZone::cellZone
 (
     const word& name,
@@ -100,28 +106,56 @@ Foam::cellZone::cellZone
 
 Foam::cellZone::cellZone
 (
-    const cellZone& origZone,
-    const labelUList& addr,
+    const cellZone& originalZone,
+    const Foam::zero,
+    const cellZoneMesh& zm,
+    const label newIndex
+)
+:
+    zone(originalZone, labelList(), newIndex),
+    zoneMesh_(zm)
+{}
+
+
+Foam::cellZone::cellZone
+(
+    const cellZone& originalZone,
+    const Foam::zero,
     const label index,
     const cellZoneMesh& zm
 )
 :
-    zone(origZone, addr, index),
+    zone(originalZone, labelList(), index),
     zoneMesh_(zm)
 {}
 
 
 Foam::cellZone::cellZone
 (
-    const cellZone& origZone,
+    const cellZone& originalZone,
+    const labelUList& addr,
+    const label index,
+    const cellZoneMesh& zm
+)
+:
+    cellZone(originalZone, Foam::zero{}, index, zm)
+{
+    labelList::operator=(addr);
+}
+
+
+Foam::cellZone::cellZone
+(
+    const cellZone& originalZone,
     labelList&& addr,
     const label index,
     const cellZoneMesh& zm
 )
 :
-    zone(origZone, std::move(addr), index),
-    zoneMesh_(zm)
-{}
+    cellZone(originalZone, Foam::zero{}, index, zm)
+{
+    labelList::transfer(addr);
+}
 
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
@@ -150,12 +184,56 @@ void Foam::cellZone::writeDict(Ostream& os) const
 }
 
 
+void Foam::cellZone::resetAddressing(cellZone&& zn)
+{
+    if (this == &zn)
+    {
+        return;  // Self-assignment is a no-op
+    }
+
+    clearAddressing();
+    labelList::transfer(static_cast<labelList&>(zn));
+    zn.clearAddressing();
+}
+
+
+void Foam::cellZone::resetAddressing(const cellZone& zn)
+{
+    if (this == &zn)
+    {
+        return;  // Self-assignment is a no-op
+    }
+
+    clearAddressing();
+    labelList::operator=(static_cast<const labelList&>(zn));
+}
+
+
+void Foam::cellZone::resetAddressing(const labelUList& addr)
+{
+    clearAddressing();
+    labelList::operator=(addr);
+}
+
+
+void Foam::cellZone::resetAddressing(labelList&& addr)
+{
+    clearAddressing();
+    labelList::transfer(addr);
+}
+
+
 // * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
 
 void Foam::cellZone::operator=(const cellZone& zn)
 {
+    if (this == &zn)
+    {
+        return;  // Self-assignment is a no-op
+    }
+
     clearAddressing();
-    labelList::operator=(zn);
+    labelList::operator=(static_cast<const labelList&>(zn));
 }
 
 
diff --git a/src/OpenFOAM/meshes/polyMesh/zones/cellZone/cellZone.H b/src/OpenFOAM/meshes/polyMesh/zones/cellZone/cellZone.H
index 01be2b30bae..00279ef242c 100644
--- a/src/OpenFOAM/meshes/polyMesh/zones/cellZone/cellZone.H
+++ b/src/OpenFOAM/meshes/polyMesh/zones/cellZone/cellZone.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2017-2021 OpenCFD Ltd.
+    Copyright (C) 2017-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -41,8 +41,8 @@ SourceFiles
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef cellZone_H
-#define cellZone_H
+#ifndef Foam_cellZone_H
+#define Foam_cellZone_H
 
 #include "zone.H"
 #include "cellZoneMeshFwd.H"
@@ -70,12 +70,6 @@ class cellZone
         const cellZoneMesh& zoneMesh_;
 
 
-    // Private Member Functions
-
-        //- No copy construct
-        cellZone(const cellZone&) = delete;
-
-
 public:
 
     // Static Data Members
@@ -108,7 +102,13 @@ public:
 
     // Constructors
 
-        //- Construct an empty zone
+        //- No copy construct
+        cellZone(const cellZone&) = delete;
+
+        //- Construct an empty zone - name="", index=0
+        explicit cellZone(const cellZoneMesh& zm);
+
+        //- Construct an empty zone with specified name and index
         cellZone
         (
             const word& name,
@@ -143,21 +143,41 @@ public:
             const cellZoneMesh& zm
         );
 
-        //- Construct given the original zone (name is used),
-        //- and resetting the cell list and zone mesh information
+        //- Construct empty with original zone information (name, index, groups)
+        //- and mesh reference. Optionally specify a new index.
+        cellZone
+        (
+            const cellZone& originalZone,
+            const Foam::zero,
+            const cellZoneMesh& zm,
+            const label newIndex = -1
+        );
+
+        //- Construct empty with original zone information (name, groups),
+        //- resetting the index and zone mesh reference.
+        cellZone
+        (
+            const cellZone& originalZone,
+            const Foam::zero,
+            const label index,
+            const cellZoneMesh& zm
+        );
+
+        //- Construct with original zone information (name, groups),
+        //- resetting the cell list, the index and zone mesh reference.
         cellZone
         (
-            const cellZone& origZone,
+            const cellZone& originalZone,
             const labelUList& addr,
             const label index,
             const cellZoneMesh& zm
         );
 
-        //- Construct with a new index and zone mesh information, the name
-        //- of the original zone, resetting the cell addressing.
+        //- Construct with original zone information (name, groups),
+        //- resetting the cell list, the index and zone mesh reference.
         cellZone
         (
-            const cellZone& origZone,
+            const cellZone& originalZone,
             labelList&& addr,
             const label index,
             const cellZoneMesh& zm
@@ -203,9 +223,12 @@ public:
     // Member Functions
 
         //- Return reference to the zone mesh
-        const cellZoneMesh& zoneMesh() const noexcept
+        const cellZoneMesh& zoneMesh() const noexcept { return zoneMesh_; }
+
+        //- The addressing (cell IDs) used for the zone
+        const labelList& addressing() const noexcept
         {
-            return zoneMesh_;
+            return static_cast<const labelList&>(*this);
         }
 
         //- Helper function to re-direct to zone::localID(...)
@@ -226,7 +249,19 @@ public:
         virtual void writeDict(Ostream& os) const;
 
 
-    // Member Operators
+    // Assign addressing
+
+        //- Move reset addressing from another zone
+        virtual void resetAddressing(cellZone&& zn);
+
+        //- Copy reset addressing from another zone
+        virtual void resetAddressing(const cellZone& zn);
+
+        //- Copy assign addressing
+        virtual void resetAddressing(const labelUList& addr);
+
+        //- Move assign addressing
+        virtual void resetAddressing(labelList&& addr);
 
         //- Assign addressing, clearing demand-driven data
         void operator=(const cellZone& zn);
diff --git a/src/OpenFOAM/meshes/polyMesh/zones/faceZone/faceZone.C b/src/OpenFOAM/meshes/polyMesh/zones/faceZone/faceZone.C
index c4dc8934242..d943495ddf0 100644
--- a/src/OpenFOAM/meshes/polyMesh/zones/faceZone/faceZone.C
+++ b/src/OpenFOAM/meshes/polyMesh/zones/faceZone/faceZone.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2017-2022 OpenCFD Ltd.
+    Copyright (C) 2017-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -31,7 +31,6 @@ License
 #include "faceZoneMesh.H"
 #include "polyMesh.H"
 #include "primitiveMesh.H"
-#include "demandDrivenData.H"
 #include "mapPolyMesh.H"
 #include "syncTools.H"
 
@@ -52,16 +51,8 @@ const char* const Foam::faceZone::labelsName = "faceLabels";
 void Foam::faceZone::setFlipMap(const bool val)
 {
     // Match size for flipMap
-    if (flipMap_.size() == this->size())
-    {
-        flipMap_ = val;
-    }
-    else
-    {
-        // Avoid copying old values on resize
-        flipMap_.clear();
-        flipMap_.resize(this->size(), val);
-    }
+    flipMap_.resize_nocopy(this->size());
+    flipMap_ = val;
 }
 
 
@@ -78,23 +69,24 @@ void Foam::faceZone::calcFaceZonePatch() const
             << abort(FatalError);
     }
 
-    patchPtr_ =
+    patchPtr_.reset
+    (
         new primitiveFacePatch
         (
             faceList(size()),
             zoneMesh().mesh().points()
-        );
-
-    primitiveFacePatch& patch = *patchPtr_;
+        )
+    );
+    auto& patch = *patchPtr_;
 
     const faceList& f = zoneMesh().mesh().faces();
 
     const labelList& addr = *this;
-    const boolList& flip = flipMap();
+    const boolList& flips = flipMap();
 
     forAll(addr, facei)
     {
-        if (flip[facei])
+        if (flips[facei])
         {
             patch[facei] = f[addr[facei]].reverseFace();
         }
@@ -110,11 +102,9 @@ void Foam::faceZone::calcFaceZonePatch() const
 
 void Foam::faceZone::calcCellLayers() const
 {
-    DebugInFunction << "Calculating master cells" << endl;
+    DebugInFunction << "Calculating cell layers" << endl;
 
-    // It is an error to attempt to recalculate edgeCells
-    // if the pointer is already set
-    if (masterCellsPtr_ || slaveCellsPtr_)
+    if (frontCellsPtr_ || backCellsPtr_)
     {
         FatalErrorInFunction
             << "cell layers already calculated"
@@ -122,48 +112,82 @@ void Foam::faceZone::calcCellLayers() const
     }
     else
     {
-        // Go through all the faces in the master zone.  Choose the
-        // master or slave cell based on the face flip
+        // Go through all the faces in the zone.
+        // Choose the front/back cell based on the face flip
 
         const labelList& own = zoneMesh().mesh().faceOwner();
         const labelList& nei = zoneMesh().mesh().faceNeighbour();
 
-        const labelList& mf = *this;
-
-        const boolList& faceFlip = flipMap();
+        const labelList& addr = *this;
+        const boolList& flips = flipMap();
 
-        masterCellsPtr_ = new labelList(mf.size());
-        labelList& mc = *masterCellsPtr_;
+        frontCellsPtr_.reset(new labelList(addr.size()));
+        backCellsPtr_.reset(new labelList(addr.size()));
 
-        slaveCellsPtr_ = new labelList(mf.size());
-        labelList& sc = *slaveCellsPtr_;
+        auto& fronts = *frontCellsPtr_;
+        auto& backs = *backCellsPtr_;
 
-        forAll(mf, facei)
+        forAll(addr, facei)
         {
-            const label ownCelli = own[mf[facei]];
+            const label ownCelli = own[addr[facei]];
             const label neiCelli =
             (
-                zoneMesh().mesh().isInternalFace(mf[facei])
-              ? nei[mf[facei]]
+                zoneMesh().mesh().isInternalFace(addr[facei])
+              ? nei[addr[facei]]
               : -1
             );
 
-            if (!faceFlip[facei])
+            if (flips[facei])
             {
-                // Face is oriented correctly, no flip needed
-                mc[facei] = neiCelli;
-                sc[facei] = ownCelli;
+                fronts[facei] = ownCelli;
+                backs[facei] = neiCelli;
             }
             else
             {
-                mc[facei] = ownCelli;
-                sc[facei] = neiCelli;
+                fronts[facei] = neiCelli;
+                backs[facei] = ownCelli;
             }
         }
     }
 }
 
 
+// Foam::label Foam::faceZone::getLayerCell
+// (
+//     const side which,
+//     const label i
+// ) const
+// {
+//     const label facei = labelList::operator[](i);
+//     const bool flipped = flipMap_[i];
+//
+//     if (which == side::FRONT ? flipped : !flipped)
+//     {
+//         return zoneMesh().mesh().faceOwner()[facei];
+//     }
+//     else if (zoneMesh().mesh().isInternalFace(facei))
+//     {
+//         return zoneMesh().mesh().faceNeighbour()[facei];
+//     }
+//     else
+//     {
+//         return -1;
+//     }
+// }
+//
+//
+// Foam::label Foam::faceZone::frontCell(const label i) const
+// {
+//     return getLayerCell(side::FRONT, i);
+// }
+//
+//
+// Foam::label Foam::faceZone::backCell(const label i) const
+// {
+//     return getLayerCell(side::BACK, i);
+// }
+
+
 void Foam::faceZone::checkAddressing() const
 {
     const labelList& addr = *this;
@@ -194,6 +218,12 @@ void Foam::faceZone::checkAddressing() const
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
+Foam::faceZone::faceZone(const faceZoneMesh& zm)
+:
+    faceZone(word::null, 0, zm)
+{}
+
+
 Foam::faceZone::faceZone
 (
     const word& name,
@@ -202,12 +232,7 @@ Foam::faceZone::faceZone
 )
 :
     zone(name, index),
-    flipMap_(),
-    zoneMesh_(zm),
-    patchPtr_(nullptr),
-    masterCellsPtr_(nullptr),
-    slaveCellsPtr_(nullptr),
-    mePtr_(nullptr)
+    zoneMesh_(zm)
 {}
 
 
@@ -220,15 +245,11 @@ Foam::faceZone::faceZone
     const faceZoneMesh& zm
 )
 :
-    zone(name, addr, index),
-    flipMap_(),
-    zoneMesh_(zm),
-    patchPtr_(nullptr),
-    masterCellsPtr_(nullptr),
-    slaveCellsPtr_(nullptr),
-    mePtr_(nullptr)
-{
-    flipMap_.resize(size(), flipMapValue);
+    faceZone(name, index, zm)
+{
+    labelList::operator=(addr);
+    flipMap_.resize(labelList::size(), flipMapValue);
+
     checkAddressing();
 }
 
@@ -242,15 +263,10 @@ Foam::faceZone::faceZone
     const faceZoneMesh& zm
 )
 :
-    zone(name, std::move(addr), index),
-    flipMap_(),
-    zoneMesh_(zm),
-    patchPtr_(nullptr),
-    masterCellsPtr_(nullptr),
-    slaveCellsPtr_(nullptr),
-    mePtr_(nullptr)
-{
-    flipMap_.resize(size(), flipMapValue);
+    faceZone(name, index, zm)
+{
+    labelList::transfer(addr);
+    flipMap_.resize(labelList::size(), flipMapValue);
     checkAddressing();
 }
 
@@ -264,14 +280,18 @@ Foam::faceZone::faceZone
     const faceZoneMesh& zm
 )
 :
-    zone(name, addr, index),
-    flipMap_(fm),
-    zoneMesh_(zm),
-    patchPtr_(nullptr),
-    masterCellsPtr_(nullptr),
-    slaveCellsPtr_(nullptr),
-    mePtr_(nullptr)
+    faceZone(name, index, zm)
 {
+    labelList::operator=(addr);
+    flipMap_ = fm;
+
+    // TBD
+    // if (flipMap_.empty())
+    // {
+    //     // An empty flipMap is treated like 'false' instead of as an error
+    //     flipMap_.resize(labelList::size(), false);
+    // }
+
     checkAddressing();
 }
 
@@ -285,14 +305,18 @@ Foam::faceZone::faceZone
     const faceZoneMesh& zm
 )
 :
-    zone(name, std::move(addr), index),
-    flipMap_(std::move(fm)),
-    zoneMesh_(zm),
-    patchPtr_(nullptr),
-    masterCellsPtr_(nullptr),
-    slaveCellsPtr_(nullptr),
-    mePtr_(nullptr)
+    faceZone(name, index, zm)
 {
+    labelList::transfer(addr);
+    flipMap_.transfer(fm);
+
+    // TBD
+    // if (flipMap_.empty())
+    // {
+    //     // An empty flipMap is treated like 'false' instead of as an error
+    //     flipMap_.resize(labelList::size(), false);
+    // }
+
     checkAddressing();
 }
 
@@ -306,12 +330,8 @@ Foam::faceZone::faceZone
 )
 :
     zone(name, dict, this->labelsName, index),
-    flipMap_(dict.lookup("flipMap")),
-    zoneMesh_(zm),
-    patchPtr_(nullptr),
-    masterCellsPtr_(nullptr),
-    slaveCellsPtr_(nullptr),
-    mePtr_(nullptr)
+    flipMap_(dict.lookup("flipMap")),  // OR: dict.get<boolList>("flipMap")
+    zoneMesh_(zm)
 {
     checkAddressing();
 }
@@ -319,51 +339,63 @@ Foam::faceZone::faceZone
 
 Foam::faceZone::faceZone
 (
-    const faceZone& origZone,
+    const faceZone& originalZone,
+    const Foam::zero,
+    const faceZoneMesh& zm,
+    const label newIndex
+)
+:
+    zone(originalZone, labelList(), newIndex),
+    zoneMesh_(zm)
+{}
+
+
+Foam::faceZone::faceZone
+(
+    const faceZone& originalZone,
+    const Foam::zero,
+    const label index,
+    const faceZoneMesh& zm
+)
+:
+    zone(originalZone, labelList(), index),
+    zoneMesh_(zm)
+{}
+
+
+Foam::faceZone::faceZone
+(
+    const faceZone& originalZone,
     const labelUList& addr,
     const boolUList& fm,
     const label index,
     const faceZoneMesh& zm
 )
 :
-    zone(origZone, addr, index),
-    flipMap_(fm),
-    zoneMesh_(zm),
-    patchPtr_(nullptr),
-    masterCellsPtr_(nullptr),
-    slaveCellsPtr_(nullptr),
-    mePtr_(nullptr)
+    faceZone(originalZone, Foam::zero{}, index, zm)
 {
+    labelList::operator=(addr);
+    flipMap_ = fm;
+
     checkAddressing();
 }
 
 
 Foam::faceZone::faceZone
 (
-    const faceZone& origZone,
+    const faceZone& originalZone,
     labelList&& addr,
     boolList&& fm,
     const label index,
     const faceZoneMesh& zm
 )
 :
-    zone(origZone, std::move(addr), index),
-    flipMap_(std::move(fm)),
-    zoneMesh_(zm),
-    patchPtr_(nullptr),
-    masterCellsPtr_(nullptr),
-    slaveCellsPtr_(nullptr),
-    mePtr_(nullptr)
+    faceZone(originalZone, Foam::zero{}, index, zm)
 {
-    checkAddressing();
-}
-
-
-// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+    labelList::transfer(addr);
+    flipMap_.transfer(fm);
 
-Foam::faceZone::~faceZone()
-{
-    clearAddressing();
+    checkAddressing();
 }
 
 
@@ -375,36 +407,33 @@ Foam::label Foam::faceZone::whichFace(const label globalFaceID) const
 }
 
 
-const Foam::primitiveFacePatch& Foam::faceZone::operator()() const
+const Foam::primitiveFacePatch& Foam::faceZone::patch() const
 {
     if (!patchPtr_)
     {
         calcFaceZonePatch();
     }
-
     return *patchPtr_;
 }
 
 
-const Foam::labelList& Foam::faceZone::masterCells() const
+const Foam::labelList& Foam::faceZone::frontCells() const
 {
-    if (!masterCellsPtr_)
+    if (!frontCellsPtr_)
     {
         calcCellLayers();
     }
-
-    return *masterCellsPtr_;
+    return *frontCellsPtr_;
 }
 
 
-const Foam::labelList& Foam::faceZone::slaveCells() const
+const Foam::labelList& Foam::faceZone::backCells() const
 {
-    if (!slaveCellsPtr_)
+    if (!backCellsPtr_)
     {
         calcCellLayers();
     }
-
-    return *slaveCellsPtr_;
+    return *backCellsPtr_;
 }
 
 
@@ -412,31 +441,72 @@ const Foam::labelList& Foam::faceZone::meshEdges() const
 {
     if (!mePtr_)
     {
-        mePtr_ =
+        mePtr_.reset
+        (
             new labelList
             (
-                operator()().meshEdges
+                this->patch().meshEdges
                 (
                     zoneMesh().mesh().edges(),
                     zoneMesh().mesh().pointEdges()
                 )
-            );
+            )
+        );
     }
 
     return *mePtr_;
 }
 
 
+void Foam::faceZone::clearGeom()
+{
+    patchPtr_.reset(nullptr);
+    frontCellsPtr_.reset(nullptr);
+    backCellsPtr_.reset(nullptr);
+    mePtr_.reset(nullptr);
+}
+
+
 void Foam::faceZone::clearAddressing()
 {
     zone::clearAddressing();
+    clearGeom();
+}
 
-    deleteDemandDrivenData(patchPtr_);
 
-    deleteDemandDrivenData(masterCellsPtr_);
-    deleteDemandDrivenData(slaveCellsPtr_);
+void Foam::faceZone::clearPrimitives()
+{
+    zone::clearPrimitives();
+    flipMap_.clear();
+}
 
-    deleteDemandDrivenData(mePtr_);
+
+void Foam::faceZone::resetAddressing(faceZone&& zn)
+{
+    // TDB: clearGeom();
+    if (this == &zn)
+    {
+        return;  // Self-assignment is a no-op
+    }
+
+    clearAddressing();
+    labelList::transfer(static_cast<labelList&>(zn));
+    flipMap_.transfer(zn.flipMap_);
+    zn.clearAddressing();
+}
+
+
+void Foam::faceZone::resetAddressing(const faceZone& zn)
+{
+    // TDB: clearGeom();
+    if (this == &zn)
+    {
+        return;  // Self-assignment is a no-op
+    }
+
+    clearAddressing();
+    labelList::operator=(static_cast<const labelList&>(zn));
+    flipMap_ = zn.flipMap_;
 }
 
 
@@ -454,25 +524,25 @@ void Foam::faceZone::resetAddressing
 
 void Foam::faceZone::resetAddressing
 (
-    const labelUList& addr,
-    const boolUList& flipMap
+    labelList&& addr,
+    const bool flipMapValue
 )
 {
     clearAddressing();
-    labelList::operator=(addr);
-    flipMap_ = flipMap;
+    labelList::transfer(addr);
+    setFlipMap(flipMapValue);
 }
 
 
 void Foam::faceZone::resetAddressing
 (
-    labelList&& addr,
-    const bool flipMapValue
+    const labelUList& addr,
+    const boolUList& flipMap
 )
 {
     clearAddressing();
-    labelList::transfer(addr);
-    setFlipMap(flipMapValue);
+    labelList::operator=(addr);
+    flipMap_ = flipMap;
 }
 
 
@@ -485,6 +555,7 @@ void Foam::faceZone::updateMesh(const mapPolyMesh& mpm)
     label nFaces = 0;
 
     const labelList& addr = *this;
+    const boolList& flips = flipMap();
     const labelList& faceMap = mpm.reverseFaceMap();
 
     forAll(addr, i)
@@ -494,15 +565,15 @@ void Foam::faceZone::updateMesh(const mapPolyMesh& mpm)
         if (faceMap[facei] >= 0)
         {
             newAddressing[nFaces] = faceMap[facei];
-            newFlipMap[nFaces] = flipMap_[i];       // Keep flip map.
-            nFaces++;
+            newFlipMap[nFaces] = flips[i];  // Keep flip map
+            ++nFaces;
         }
     }
 
-    newAddressing.setSize(nFaces);
-    newFlipMap.setSize(nFaces);
+    newAddressing.resize(nFaces);
+    newFlipMap.resize(nFaces);
 
-    transfer(newAddressing);
+    labelList::transfer(newAddressing);
     flipMap_.transfer(newFlipMap);
 }
 
@@ -526,6 +597,7 @@ bool Foam::faceZone::checkParallelSync(const bool report) const
 
     {
         const labelList& addr = *this;
+        const boolList& flips = flipMap();
 
         boolList neiZoneFace(mesh.nBoundaryFaces(), false);
         boolList neiZoneFlip(mesh.nBoundaryFaces(), false);
@@ -536,13 +608,14 @@ bool Foam::faceZone::checkParallelSync(const bool report) const
 
             if (!mesh.isInternalFace(facei))
             {
-                neiZoneFace[facei-mesh.nInternalFaces()] = true;
-                neiZoneFlip[facei-mesh.nInternalFaces()] = flipMap()[i];
+                const label bFacei = facei-mesh.nInternalFaces();
+                neiZoneFace[bFacei] = true;
+                neiZoneFlip[bFacei] = flips[i];
             }
         }
         boolList myZoneFace(neiZoneFace);
-        syncTools::swapBoundaryFaceList(mesh, neiZoneFace);
         boolList myZoneFlip(neiZoneFlip);
+        syncTools::swapBoundaryFaceList(mesh, neiZoneFace);
         syncTools::swapBoundaryFaceList(mesh, neiZoneFlip);
 
         forAll(addr, i)
@@ -564,9 +637,8 @@ bool Foam::faceZone::checkParallelSync(const bool report) const
                         Pout<< " ***Problem with faceZone " << index()
                             << " named " << name()
                             << ". Face " << facei
-                            << " on coupled patch "
-                            << bm[patchi].name()
-                            << " is not consistent with its coupled neighbour."
+                            << " on coupled patch " << bm[patchi].name()
+                            << " is inconsistent with its coupled neighbour."
                             << endl;
                     }
                     else
@@ -585,10 +657,8 @@ bool Foam::faceZone::checkParallelSync(const bool report) const
                         Pout<< " ***Problem with faceZone " << index()
                             << " named " << name()
                             << ". Face " << facei
-                            << " on coupled patch "
-                            << bm[patchi].name()
-                            << " does not have consistent flipMap"
-                            << " across coupled faces."
+                            << " on coupled patch " << bm[patchi].name()
+                            << " has inconsistent flipMap across coupled faces."
                             << endl;
                     }
                     else
@@ -634,6 +704,21 @@ void Foam::faceZone::writeDict(Ostream& os) const
 }
 
 
+// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+
+void Foam::faceZone::operator=(const faceZone& zn)
+{
+    if (this == &zn)
+    {
+        return;  // Self-assignment is a no-op
+    }
+
+    clearAddressing();
+    labelList::operator=(static_cast<const labelList&>(zn));
+    flipMap_ = zn.flipMap_;
+}
+
+
 // * * * * * * * * * * * * * * * Ostream Operator  * * * * * * * * * * * * * //
 
 Foam::Ostream& Foam::operator<<(Ostream& os, const faceZone& zn)
diff --git a/src/OpenFOAM/meshes/polyMesh/zones/faceZone/faceZone.H b/src/OpenFOAM/meshes/polyMesh/zones/faceZone/faceZone.H
index dc9c2019da8..74bb5264e51 100644
--- a/src/OpenFOAM/meshes/polyMesh/zones/faceZone/faceZone.H
+++ b/src/OpenFOAM/meshes/polyMesh/zones/faceZone/faceZone.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2017-2021 OpenCFD Ltd.
+    Copyright (C) 2017-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -66,6 +66,16 @@ class faceZone
 :
     public zone
 {
+    // // Public Data Types
+    //
+    //     //- Side of the face zone
+    //     enum side
+    //     {
+    //         FRONT = 1,  //!< The front (positive normal) side of the face
+    //         BACK  = -1, //!< The back (negative normal) side of the face
+    //     };
+
+
     // Private Data
 
         //- Flip map for all faces in the zone.
@@ -76,16 +86,16 @@ class faceZone
         const faceZoneMesh& zoneMesh_;
 
         //- Demand-driven: Primitive patch of correctly flipped faces
-        mutable primitiveFacePatch* patchPtr_;
+        mutable std::unique_ptr<primitiveFacePatch> patchPtr_;
 
-        //- Demand-driven: Master cell layer
-        mutable labelList* masterCellsPtr_;
+        //- Demand-driven: front cell layer (positive normal) side of faces
+        mutable std::unique_ptr<labelList> frontCellsPtr_;
 
-        //- Demand-driven: Slave cell layer
-        mutable labelList* slaveCellsPtr_;
+        //- Demand-driven: back cell layer (negative normal) side of faces
+        mutable std::unique_ptr<labelList> backCellsPtr_;
 
         //- Demand-driven: Global edge addressing
-        mutable labelList* mePtr_;
+        mutable std::unique_ptr<labelList> mePtr_;
 
 
     // Private Member Functions
@@ -96,19 +106,14 @@ class faceZone
         //- Build primitive patch
         void calcFaceZonePatch() const;
 
-        //- Calculate master and slave face layer
+        //- Calculate front/back cell layers
         void calcCellLayers() const;
 
         //- Check addressing
         void checkAddressing() const;
 
-
-        //- No copy construct
-        faceZone(const faceZone&) = delete;
-
-        //- No copy assignment
-        void operator=(const faceZone&) = delete;
-
+        //- Clear out geometry and demand-driven data
+        void clearGeom();
 
 public:
 
@@ -142,7 +147,13 @@ public:
 
     // Constructors
 
-        //- Construct an empty zone
+        //- No copy construct
+        faceZone(const faceZone&) = delete;
+
+        //- Construct an empty zone - name="", index=0
+        explicit faceZone(const faceZoneMesh& zm);
+
+        //- Construct an empty zone with specified name and index
         faceZone
         (
             const word& name,
@@ -171,7 +182,7 @@ public:
             const faceZoneMesh& zm
         );
 
-        //- Construct from components
+        //- Construct from components, copying addressing
         faceZone
         (
             const word& name,
@@ -200,12 +211,32 @@ public:
             const faceZoneMesh& zm
         );
 
+        //- Construct empty with original zone information (name, index, groups)
+        //- and mesh reference. Optionally specify a new index.
+        faceZone
+        (
+            const faceZone& originalZone,
+            const Foam::zero,
+            const faceZoneMesh& zm,
+            const label newIndex = -1
+        );
+
+        //- Construct empty with original zone information (name, groups),
+        //- resetting the index and zone mesh reference.
+        faceZone
+        (
+            const faceZone& originalZone,
+            const Foam::zero,
+            const label index,
+            const faceZoneMesh& zm
+        );
+
         //- Construct with a new index and zone mesh information, the name
         //- of the original zone, resetting the face addressing
         //- and flip-map.
         faceZone
         (
-            const faceZone& origZone,
+            const faceZone& originalZone,
             const labelUList& addr,
             const boolUList& fm,
             const label index,
@@ -217,7 +248,7 @@ public:
         //- and flip-map.
         faceZone
         (
-            const faceZone& origZone,
+            const faceZone& originalZone,
             labelList&& addr,
             boolList&& fm,
             const label index,
@@ -258,46 +289,81 @@ public:
 
 
     //- Destructor
-    virtual ~faceZone();
+    virtual ~faceZone() = default;
 
 
     // Member Functions
 
         //- Return reference to the zone mesh
-        const faceZoneMesh& zoneMesh() const noexcept
+        const faceZoneMesh& zoneMesh() const noexcept { return zoneMesh_; }
+
+        //- The addressing (face IDs) used for the zone
+        const labelList& addressing() const noexcept
         {
-            return zoneMesh_;
+            return static_cast<const labelList&>(*this);
         }
 
         //- Return face flip map
-        const boolList& flipMap() const noexcept
-        {
-            return flipMap_;
-        }
+        const boolList& flipMap() const noexcept { return flipMap_; }
 
         //- Helper function to re-direct to zone::localID(...)
         label whichFace(const label globalCellID) const;
 
-        //- Return reference to primitive patch
-        const primitiveFacePatch& operator()() const;
+        //- Return [demand-driven] reference to an equivalent primitive patch,
+        //- with faces oriented according to flipMap()
+        const primitiveFacePatch& patch() const;
 
 
     // Addressing into mesh
 
-        //- Return labels of master cells (cells next to the master face
-        //- zone in the prescribed direction)
-        const labelList& masterCells() const;
+        //- The front cells layer.
+        //- Cells on the positive normal side of faces.
+        //  \warning may contain negative indices for boundary faces!
+        const labelList& frontCells() const;
 
-        //- Return labels of slave cells
-        const labelList& slaveCells() const;
+        //- The back cells layer.
+        //- Cells on the negative normal side of faces.
+        //  \warning may contain negative indices for boundary faces!
+        const labelList& backCells() const;
 
         //- Return global edge index for local edges
         const labelList& meshEdges() const;
 
+        //- Check zone definition. Return true if in error.
+        virtual bool checkDefinition(const bool report = false) const;
+
+        //- Check whether all procs have faces synchronised.
+        //  \return True if any errors.
+        virtual bool checkParallelSync(const bool report = false) const;
+
+        //- Correct patch after moving points
+        virtual void movePoints(const pointField& pts);
+
+        //- Update for changes in topology
+        virtual void updateMesh(const mapPolyMesh& mpm);
+
+        //- Write
+        virtual void write(Ostream& os) const;
+
+        //- Write dictionary
+        virtual void writeDict(Ostream& os) const;
+
+
+    // Assign addressing
 
         //- Clear addressing
+        //- (remove lookup maps, patch/geometric information)
         virtual void clearAddressing();
 
+        //- Clear primitive addressing
+        virtual void clearPrimitives();
+
+        //- Move reset addressing and flip map from another zone
+        virtual void resetAddressing(faceZone&& zn);
+
+        //- Copy reset addressing and flip map from another zone
+        virtual void resetAddressing(const faceZone& zn);
+
         //- Reset addressing - use uniform flip map value
         //  Clears demand-driven data.
         virtual void resetAddressing
@@ -306,47 +372,45 @@ public:
             const bool flipMapValue
         );
 
-        //- Reset addressing and flip map.
+        //- Move reset addressing - use uniform flip map value
         //  Clears demand-driven data.
         virtual void resetAddressing
         (
-            const labelUList& addr,
-            const boolUList& flipMap
+            labelList&& addr,
+            const bool flipMapValue
         );
 
-        //- Move reset addressing - use uniform flip map value
+        //- Copy reset addressing and flip map.
         //  Clears demand-driven data.
         virtual void resetAddressing
         (
-            labelList&& addr,
-            const bool flipMapValue
+            const labelUList& addr,
+            const boolUList& flipMap
         );
 
+        //- Assign addressing, clearing demand-driven data
+        void operator=(const faceZone& zn);
 
-        //- Check zone definition. Return true if in error.
-        virtual bool checkDefinition(const bool report = false) const;
-
-        //- Check whether all procs have faces synchronised.
-        //  \return True if any errors.
-        virtual bool checkParallelSync(const bool report = false) const;
 
-        //- Correct patch after moving points
-        virtual void movePoints(const pointField& pts);
+    // I-O
 
-        //- Update for changes in topology
-        virtual void updateMesh(const mapPolyMesh& mpm);
+        //- Ostream Operator
+        friend Ostream& operator<<(Ostream& os, const faceZone& zn);
 
-        //- Write
-        virtual void write(Ostream& os) const;
 
-        //- Write dictionary
-        virtual void writeDict(Ostream& os) const;
+    // Housekeeping
 
+        //- Deprecated(2023-09) same as patch()
+        //  \deprecated(2023-09) same as patch()
+        const primitiveFacePatch& operator()() const { return this->patch(); }
 
-    // I-O
+        //- Deprecated(2023-09) same as frontCells
+        //  \deprecated(2023-09) same as frontCells #1832
+        const labelList& masterCells() const { return frontCells(); }
 
-        //- Ostream Operator
-        friend Ostream& operator<<(Ostream& os, const faceZone& zn);
+        //- Deprecated(2023-09) same as backCells
+        //  \deprecated(2023-09) same as backCells #1832
+        const labelList& slaveCells() const { return backCells(); }
 };
 
 
diff --git a/src/OpenFOAM/meshes/polyMesh/zones/pointZone/pointZone.C b/src/OpenFOAM/meshes/polyMesh/zones/pointZone/pointZone.C
index a6a4a09e1d4..6e0b3e558c0 100644
--- a/src/OpenFOAM/meshes/polyMesh/zones/pointZone/pointZone.C
+++ b/src/OpenFOAM/meshes/polyMesh/zones/pointZone/pointZone.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2017-2021 OpenCFD Ltd.
+    Copyright (C) 2017-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -47,6 +47,12 @@ const char* const Foam::pointZone::labelsName = "pointLabels";
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
+Foam::pointZone::pointZone(const pointZoneMesh& zm)
+:
+    pointZone(word::null, 0, zm)
+{}
+
+
 Foam::pointZone::pointZone
 (
     const word& name,
@@ -100,28 +106,56 @@ Foam::pointZone::pointZone
 
 Foam::pointZone::pointZone
 (
-    const pointZone& origZone,
-    const labelUList& addr,
+    const pointZone& originalZone,
+    const Foam::zero,
+    const pointZoneMesh& zm,
+    const label newIndex
+)
+:
+    zone(originalZone, labelList(), newIndex),
+    zoneMesh_(zm)
+{}
+
+
+Foam::pointZone::pointZone
+(
+    const pointZone& originalZone,
+    const Foam::zero,
     const label index,
     const pointZoneMesh& zm
 )
 :
-    zone(origZone, addr, index),
+    zone(originalZone, labelList(), index),
     zoneMesh_(zm)
 {}
 
 
 Foam::pointZone::pointZone
 (
-    const pointZone& origZone,
+    const pointZone& originalZone,
+    const labelUList& addr,
+    const label index,
+    const pointZoneMesh& zm
+)
+:
+    pointZone(originalZone, Foam::zero{}, index, zm)
+{
+    labelList::operator=(addr);
+}
+
+
+Foam::pointZone::pointZone
+(
+    const pointZone& originalZone,
     labelList&& addr,
     const label index,
     const pointZoneMesh& zm
 )
 :
-    zone(origZone, std::move(addr), index),
-    zoneMesh_(zm)
-{}
+    pointZone(originalZone, Foam::zero{}, index, zm)
+{
+    labelList::transfer(addr);
+}
 
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
@@ -204,12 +238,56 @@ void Foam::pointZone::writeDict(Ostream& os) const
 }
 
 
+void Foam::pointZone::resetAddressing(pointZone&& zn)
+{
+    if (this == &zn)
+    {
+        return;  // Self-assignment is a no-op
+    }
+
+    clearAddressing();
+    labelList::transfer(static_cast<labelList&>(zn));
+    zn.clearAddressing();
+}
+
+
+void Foam::pointZone::resetAddressing(const pointZone& zn)
+{
+    if (this == &zn)
+    {
+        return;  // Self-assignment is a no-op
+    }
+
+    clearAddressing();
+    labelList::operator=(static_cast<const labelList&>(zn));
+}
+
+
+void Foam::pointZone::resetAddressing(const labelUList& addr)
+{
+    clearAddressing();
+    labelList::operator=(addr);
+}
+
+
+void Foam::pointZone::resetAddressing(labelList&& addr)
+{
+    clearAddressing();
+    labelList::transfer(addr);
+}
+
+
 // * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
 
 void Foam::pointZone::operator=(const pointZone& zn)
 {
+    if (this == &zn)
+    {
+        return;  // Self-assignment is a no-op
+    }
+
     clearAddressing();
-    labelList::operator=(zn);
+    labelList::operator=(static_cast<const labelList&>(zn));
 }
 
 
diff --git a/src/OpenFOAM/meshes/polyMesh/zones/pointZone/pointZone.H b/src/OpenFOAM/meshes/polyMesh/zones/pointZone/pointZone.H
index 6702c027d58..987080dea2b 100644
--- a/src/OpenFOAM/meshes/polyMesh/zones/pointZone/pointZone.H
+++ b/src/OpenFOAM/meshes/polyMesh/zones/pointZone/pointZone.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011 OpenFOAM Foundation
-    Copyright (C) 2017-2021 OpenCFD Ltd.
+    Copyright (C) 2017-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -43,8 +43,8 @@ SourceFiles
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef pointZone_H
-#define pointZone_H
+#ifndef Foam_pointZone_H
+#define Foam_pointZone_H
 
 #include "zone.H"
 #include "pointZoneMeshFwd.H"
@@ -72,13 +72,6 @@ class pointZone
         //- Reference to zone list
         const pointZoneMesh& zoneMesh_;
 
-
-    // Private Member Functions
-
-        //- No copy construct
-        pointZone(const pointZone&) = delete;
-
-
 public:
 
     // Static Data Members
@@ -111,7 +104,13 @@ public:
 
     // Constructors
 
-        //- Construct an empty zone
+        //- No copy construct
+        pointZone(const pointZone&) = delete;
+
+        //- Construct an empty zone - name="", index=0
+        explicit pointZone(const pointZoneMesh& zm);
+
+        //- Construct an empty zone with specified name and index
         pointZone
         (
             const word& name,
@@ -146,11 +145,31 @@ public:
             const pointZoneMesh& zm
         );
 
-        //- Construct with a new index and zone mesh information, the name
-        //- of the original zone, resetting the point addressing.
+        //- Construct empty with original zone information (name, index, groups)
+        //- and mesh reference. Optionally specify a new index.
         pointZone
         (
-            const pointZone& origZone,
+            const pointZone& originalZone,
+            const Foam::zero,
+            const pointZoneMesh& zm,
+            const label newIndex = -1
+        );
+
+        //- Construct empty with original zone information (name, groups),
+        //- resetting the index and zone mesh reference.
+        pointZone
+        (
+            const pointZone& originalZone,
+            const Foam::zero,
+            const label index,
+            const pointZoneMesh& zm
+        );
+
+        //- Construct with original zone information (name, groups),
+        //- resetting the point addressing, the index and zone mesh reference.
+        pointZone
+        (
+            const pointZone& originalZone,
             const labelUList& addr,
             const label index,
             const pointZoneMesh& zm
@@ -160,7 +179,7 @@ public:
         //- of the original zone, (move) resetting the point addressing.
         pointZone
         (
-            const pointZone& origZone,
+            const pointZone& originalZone,
             labelList&& addr,
             const label index,
             const pointZoneMesh& zm
@@ -206,9 +225,12 @@ public:
     // Member Functions
 
         //- Return reference to the zone mesh
-        const pointZoneMesh& zoneMesh() const noexcept
+        const pointZoneMesh& zoneMesh() const noexcept { return zoneMesh_; }
+
+        //- The addressing (point IDs) used for the zone
+        const labelList& addressing() const noexcept
         {
-            return zoneMesh_;
+            return static_cast<const labelList&>(*this);
         }
 
         //- Helper function to re-direct to zone::localID(...)
@@ -230,7 +252,19 @@ public:
         virtual void writeDict(Ostream& os) const;
 
 
-    // Member Operators
+    // Assign addressing
+
+        //- Move reset addressing from another zone.
+        virtual void resetAddressing(pointZone&& zn);
+
+        //- Copy reset addressing from another zone
+        virtual void resetAddressing(const pointZone& zn);
+
+        //- Copy assign addressing
+        virtual void resetAddressing(const labelUList& addr);
+
+        //- Move assign addressing
+        virtual void resetAddressing(labelList&& addr);
 
         //- Assign addressing, clearing demand-driven data
         void operator=(const pointZone& zn);
diff --git a/src/OpenFOAM/meshes/polyMesh/zones/zone/zone.C b/src/OpenFOAM/meshes/polyMesh/zones/zone/zone.C
index 67e400cef3c..28d017d11bd 100644
--- a/src/OpenFOAM/meshes/polyMesh/zones/zone/zone.C
+++ b/src/OpenFOAM/meshes/polyMesh/zones/zone/zone.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2017-2022 OpenCFD Ltd.
+    Copyright (C) 2017-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -30,13 +30,12 @@ License
 #include "dictionary.H"
 #include "HashSet.H"
 #include "IOstream.H"
-#include "demandDrivenData.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
 namespace Foam
 {
-    defineTypeNameAndDebug(zone, 0);
+    defineTypeName(zone);
 }
 
 
@@ -65,10 +64,10 @@ Foam::zone::zone
     const label index
 )
 :
-    zoneIdentifier(name, index),
-    labelList(addr),
-    lookupMapPtr_(nullptr)
-{}
+    zone(name, index)
+{
+    labelList::operator=(addr);
+}
 
 
 Foam::zone::zone
@@ -78,10 +77,10 @@ Foam::zone::zone
     const label index
 )
 :
-    zoneIdentifier(name, index),
-    labelList(std::move(addr)),
-    lookupMapPtr_(nullptr)
-{}
+    zone(name, index)
+{
+    labelList::transfer(addr);
+}
 
 
 Foam::zone::zone
@@ -100,50 +99,44 @@ Foam::zone::zone
 
 Foam::zone::zone
 (
-    const zone& origZone,
+    const zone& originalZone,
     const labelUList& addr,
-    const label index
+    const label newIndex
 )
 :
-    zone(origZone.name(), addr, index)
+    zoneIdentifier(originalZone, newIndex),
+    labelList(addr),
+    lookupMapPtr_(nullptr)
 {}
 
 
 Foam::zone::zone
 (
-    const zone& origZone,
+    const zone& originalZone,
     labelList&& addr,
-    const label index
+    const label newIndex
 )
 :
-    zone(origZone.name(), std::move(addr), index)
+    zoneIdentifier(originalZone, newIndex),
+    labelList(std::move(addr)),
+    lookupMapPtr_(nullptr)
 {}
 
 
-// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
-
-Foam::zone::~zone()
-{
-    clearAddressing();
-}
-
-
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 const Foam::Map<Foam::label>& Foam::zone::lookupMap() const
 {
     if (!lookupMapPtr_)
     {
-        DebugInFunction << "Calculating lookup map" << endl;
-
         const labelList& addr = *this;
 
-        lookupMapPtr_ = new Map<label>(2*addr.size());
-        auto& lm = *lookupMapPtr_;
+        lookupMapPtr_.reset(new Map<label>(2*addr.size()));
+        auto& map = *lookupMapPtr_;
 
-        forAll(addr, i)
+        for (const label id : addr)
         {
-            lm.insert(addr[i], i);
+            map.insert(id, map.size());
         }
     }
 
@@ -159,7 +152,13 @@ Foam::label Foam::zone::localID(const label globalID) const
 
 void Foam::zone::clearAddressing()
 {
-    deleteDemandDrivenData(lookupMapPtr_);
+    lookupMapPtr_.reset(nullptr);
+}
+
+
+void Foam::zone::clearPrimitives()
+{
+    static_cast<labelList&>(*this).clear();
 }
 
 
@@ -170,11 +169,11 @@ bool Foam::zone::checkDefinition(const label maxSize, const bool report) const
     bool hasError = false;
 
     // To check for duplicate entries
-    labelHashSet elems(size());
+    labelHashSet elems(2*size());
 
-    for (const label idx : addr)
+    for (const label id : addr)
     {
-        if (idx < 0 || idx >= maxSize)
+        if (id < 0 || id >= maxSize)
         {
             hasError = true;
 
@@ -182,7 +181,7 @@ bool Foam::zone::checkDefinition(const label maxSize, const bool report) const
             {
                 SeriousErrorInFunction
                     << "Zone " << this->name()
-                    << " contains invalid index label " << idx << nl
+                    << " contains invalid index label " << id << nl
                     << "Valid index labels are 0.."
                     << maxSize-1 << endl;
             }
@@ -192,13 +191,13 @@ bool Foam::zone::checkDefinition(const label maxSize, const bool report) const
                 break;
             }
         }
-        else if (!elems.insert(idx))
+        else if (!elems.insert(id))
         {
             if (report)
             {
                 WarningInFunction
                     << "Zone " << this->name()
-                    << " contains duplicate index label " << idx << endl;
+                    << " contains duplicate index label " << id << endl;
             }
         }
     }
diff --git a/src/OpenFOAM/meshes/polyMesh/zones/zone/zone.H b/src/OpenFOAM/meshes/polyMesh/zones/zone/zone.H
index f99a63bff42..4702a26ea4a 100644
--- a/src/OpenFOAM/meshes/polyMesh/zones/zone/zone.H
+++ b/src/OpenFOAM/meshes/polyMesh/zones/zone/zone.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2017-2021 OpenCFD Ltd.
+    Copyright (C) 2017-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -38,8 +38,8 @@ SourceFiles
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef zone_H
-#define zone_H
+#ifndef Foam_zone_H
+#define Foam_zone_H
 
 #include "zoneIdentifier.H"
 #include "labelList.H"
@@ -69,13 +69,13 @@ class zone
     // Private Data
 
         //- Demand-driven: map of labels in zone for fast location lookup
-        mutable Map<label>* lookupMapPtr_;
+        mutable std::unique_ptr<Map<label>> lookupMapPtr_;
 
 
 public:
 
     //- Runtime type information
-    TypeName("zone");
+    TypeNameNoDebug("zone");
 
 
     // Constructors
@@ -83,7 +83,7 @@ public:
         //- Default construct
         zone();
 
-        //- Construct an empty zone
+        //- Construct an empty zone with specified name and index
         zone(const word& name, const label index);
 
         //- Copy construct from components
@@ -112,26 +112,26 @@ public:
         );
 
         //- Construct given the name of the original zone (name is used)
-        //- and resetting addressing and index.
+        //- with new addressing and index (-ve: retain zone index).
         zone
         (
-            const zone& origZone,
+            const zone& originalZone,
             const labelUList& addr,
             const label index
         );
 
         //- Construct given the name of the original zone (name is used)
-        //- and (move) resetting addressing and index.
+        //- and (move) resetting addressing and index (-ve: retain zone index).
         zone
         (
-            const zone& origZone,
+            const zone& originalZone,
             labelList&& addr,
             const label index
         );
 
 
     //- Destructor
-    virtual ~zone();
+    virtual ~zone() = default;
 
 
     // Member Functions
@@ -143,7 +143,6 @@ public:
         //  \return the local address, or -1 if the item is not in the zone
         label localID(const label globalID) const;
 
-
         //- The addressing used by the zone
         const labelList& addressing() const noexcept
         {
@@ -151,8 +150,11 @@ public:
         }
 
         //- Clear addressing
+        //- (remove lookup maps and other auxiliary information)
         virtual void clearAddressing();
 
+        //- Clear primitive addressing
+        virtual void clearPrimitives();
 
         //- Check zone definition. Return true if in error.
         virtual bool checkDefinition(const bool report = false) const = 0;
diff --git a/src/dynamicMesh/polyTopoChange/polyTopoChanger/polyTopoChanger.C b/src/dynamicMesh/polyTopoChange/polyTopoChanger/polyTopoChanger.C
index 4f13ccc2238..022de1d90db 100644
--- a/src/dynamicMesh/polyTopoChange/polyTopoChanger/polyTopoChanger.C
+++ b/src/dynamicMesh/polyTopoChange/polyTopoChanger/polyTopoChanger.C
@@ -51,19 +51,19 @@ bool Foam::polyTopoChanger::readContents()
         // Read modifiers
         Istream& is = readStream(typeName);
 
-        PtrList<entry> patchEntries(is);
-        modifiers.setSize(patchEntries.size());
+        PtrList<entry> entries(is);
+        modifiers.resize_null(entries.size());
 
-        forAll(modifiers, modifierI)
+        forAll(modifiers, modifieri)
         {
             modifiers.set
             (
-                modifierI,
+                modifieri,
                 polyMeshModifier::New
                 (
-                    patchEntries[modifierI].keyword(),
-                    patchEntries[modifierI].dict(),
-                    modifierI,
+                    entries[modifieri].keyword(),
+                    entries[modifieri].dict(),
+                    modifieri,
                     *this
                 )
             );
@@ -101,7 +101,6 @@ Foam::polyTopoChanger::polyTopoChanger
 (
     polyMesh& mesh,
     IOobjectOption::readOption rOpt
-
 )
 :
     polyTopoChanger
diff --git a/src/finiteArea/faMesh/faBoundaryMesh/faBoundaryMesh.C b/src/finiteArea/faMesh/faBoundaryMesh/faBoundaryMesh.C
index 2417132a1e9..ffa44926012 100644
--- a/src/finiteArea/faMesh/faBoundaryMesh/faBoundaryMesh.C
+++ b/src/finiteArea/faMesh/faBoundaryMesh/faBoundaryMesh.C
@@ -101,12 +101,12 @@ void Foam::faBoundaryMesh::calcGroupIDs() const
 }
 
 
-bool Foam::faBoundaryMesh::readContents(const bool allowReadIfPresent)
+bool Foam::faBoundaryMesh::readContents(const bool allowOptionalRead)
 {
     if
     (
         isReadRequired()
-     || (allowReadIfPresent && isReadOptional() && headerOk())
+     || (allowOptionalRead && this->isReadOptional() && this->headerOk())
     )
     {
         // Warn for MUST_READ_IF_MODIFIED
@@ -114,12 +114,11 @@ bool Foam::faBoundaryMesh::readContents(const bool allowReadIfPresent)
 
         faPatchList& patches = *this;
 
-        // Read faPatch list
+        // Read entries
         Istream& is = readStream(typeName);
 
-        // Read patches as entries
-        PtrList<entry> patchEntries(is);
-        patches.resize(patchEntries.size());
+        PtrList<entry> entries(is);
+        patches.resize_null(entries.size());
 
         // Transcribe
         forAll(patches, patchi)
@@ -129,8 +128,8 @@ bool Foam::faBoundaryMesh::readContents(const bool allowReadIfPresent)
                 patchi,
                 faPatch::New
                 (
-                    patchEntries[patchi].keyword(),
-                    patchEntries[patchi].dict(),
+                    entries[patchi].keyword(),
+                    entries[patchi].dict(),
                     patchi,
                     *this
                 )
@@ -142,6 +141,7 @@ bool Foam::faBoundaryMesh::readContents(const bool allowReadIfPresent)
         return true;
     }
 
+    // Nothing read
     return false;
 }
 
@@ -158,10 +158,23 @@ Foam::faBoundaryMesh::faBoundaryMesh
     regIOobject(io),
     mesh_(mesh)
 {
-    readContents(false);  // READ_IF_PRESENT allowed: False
+    readContents(false);  // allowOptionalRead = false
 }
 
 
+Foam::faBoundaryMesh::faBoundaryMesh
+(
+    const IOobject& io,
+    const faMesh& pm,
+    Foam::zero
+)
+:
+    faPatchList(),
+    regIOobject(io),
+    mesh_(pm)
+{}
+
+
 Foam::faBoundaryMesh::faBoundaryMesh
 (
     const IOobject& io,
@@ -175,6 +188,31 @@ Foam::faBoundaryMesh::faBoundaryMesh
 {}
 
 
+Foam::faBoundaryMesh::faBoundaryMesh
+(
+    const IOobject& io,
+    const faMesh& fam,
+    const faPatchList& list
+)
+:
+    faPatchList(),
+    regIOobject(io),
+    mesh_(fam)
+{
+    if (!readContents(true))  // allowOptionalRead = true
+    {
+        // Nothing read. Use supplied patches
+        faPatchList& patches = *this;
+        patches.resize(list.size());
+
+        forAll(patches, patchi)
+        {
+            patches.set(patchi, list[patchi].clone(*this));
+        }
+    }
+}
+
+
 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
 
 void Foam::faBoundaryMesh::clear()
@@ -360,7 +398,7 @@ void Foam::faBoundaryMesh::setGroup
     const labelUList& patchIDs
 )
 {
-    groupIDsPtr_.clear();
+    groupIDsPtr_.reset(nullptr);
 
     faPatchList& patches = *this;
 
diff --git a/src/finiteArea/faMesh/faBoundaryMesh/faBoundaryMesh.H b/src/finiteArea/faMesh/faBoundaryMesh/faBoundaryMesh.H
index 219fcafa828..0bb9ae7c185 100644
--- a/src/finiteArea/faMesh/faBoundaryMesh/faBoundaryMesh.H
+++ b/src/finiteArea/faMesh/faBoundaryMesh/faBoundaryMesh.H
@@ -87,8 +87,9 @@ class faBoundaryMesh
         //- Calculate group name to patch ids lookup
         void calcGroupIDs() const;
 
-        //- Read if IOobject flags set. Return true if read.
-        bool readContents(const bool allowReadIfPresent);
+        //- Return true if contents were read
+        //- (controlled by IOobject readOption flags).
+        bool readContents(const bool allowOptionalRead);
 
 
 public:
@@ -108,14 +109,24 @@ public:
 
     // Constructors
 
-        //- Construct from faMesh
+        //- Read construct given IOobject and a mesh reference.
+        //- It will only read for MUST_READ variants (not READ_IF_PRESENT).
         faBoundaryMesh
         (
             const IOobject& io,
             const faMesh& fam
         );
 
-        //- Construct from faMesh and given size
+        //- Construct empty with IOobject properties and a mesh reference.
+        //- Does not read.
+        faBoundaryMesh
+        (
+            const IOobject& io,
+            const faMesh& fam,
+            Foam::zero
+        );
+
+        //- Construct with specified size. Does not read.
         faBoundaryMesh
         (
             const IOobject& io,
@@ -123,6 +134,15 @@ public:
             const label size
         );
 
+        //- Read construct (mandatory, optional) based on IOobject properties
+        //- or use the fallback PtrList (with cloning).
+        faBoundaryMesh
+        (
+            const IOobject& io,
+            const faMesh& fam,
+            const faPatchList& list
+        );
+
 
     //- Destructor
     ~faBoundaryMesh() = default;
diff --git a/src/finiteArea/faMesh/faBoundaryMesh/faBoundaryMeshEntries.C b/src/finiteArea/faMesh/faBoundaryMesh/faBoundaryMeshEntries.C
index a2d9c3b0211..999c2a0f54e 100644
--- a/src/finiteArea/faMesh/faBoundaryMesh/faBoundaryMeshEntries.C
+++ b/src/finiteArea/faMesh/faBoundaryMesh/faBoundaryMeshEntries.C
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2022 OpenCFD Ltd.
+    Copyright (C) 2022-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -26,6 +26,7 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "faBoundaryMeshEntries.H"
+#include "processorFaPatch.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -34,4 +35,30 @@ namespace Foam
     defineTypeName(faBoundaryMeshEntries);
 }
 
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::faBoundaryMeshEntries::removeProcPatches()
+{
+    // Truncate at the first processor patch entry
+    PtrList<entry>& entries = *this;
+
+    label nNonProcessor = entries.size();
+
+    forAll(entries, patchi)
+    {
+        const dictionary& dict = entries[patchi].dict();
+
+        const word pType = dict.get<word>("type");
+        if (pType == processorFaPatch::typeName)
+        {
+            nNonProcessor = patchi;
+            break;
+        }
+    }
+
+    entries.resize(nNonProcessor);
+}
+
+
 // ************************************************************************* //
diff --git a/src/finiteArea/faMesh/faBoundaryMesh/faBoundaryMeshEntries.H b/src/finiteArea/faMesh/faBoundaryMesh/faBoundaryMeshEntries.H
index a8f954b5516..7ec1ce69964 100644
--- a/src/finiteArea/faMesh/faBoundaryMesh/faBoundaryMeshEntries.H
+++ b/src/finiteArea/faMesh/faBoundaryMesh/faBoundaryMeshEntries.H
@@ -52,8 +52,8 @@ namespace Foam
 
 class faBoundaryMeshEntries
 :
-    public regIOobject,
-    public PtrList<entry>
+    public PtrList<entry>,
+    public regIOobject
 {
 public:
 
@@ -66,18 +66,25 @@ public:
         //- Read construct from IOobject
         explicit faBoundaryMeshEntries(const IOobject& io)
         :
-            regIOobject(io),
-            PtrList<entry>()
+            regIOobject(io)
         {
             if (isReadRequired() || (isReadOptional() && headerOk()))
             {
-                readStream(typeName) >> *this;
+                // Read as entries
+                Istream& is = readStream(typeName);
+
+                is >> *this;
+                close();
             }
         }
 
 
    // Member Functions
 
+        //- Truncate at the first processor patch entry
+        void removeProcPatches();
+
+        //- The class is probably read-only
         bool writeData(Ostream&) const
         {
             NotImplemented;
diff --git a/src/finiteArea/faMesh/faPatches/faPatch/faPatch.C b/src/finiteArea/faMesh/faPatches/faPatch/faPatch.C
index 22ddea24c65..39c1627d59b 100644
--- a/src/finiteArea/faMesh/faPatches/faPatch/faPatch.C
+++ b/src/finiteArea/faMesh/faPatches/faPatch/faPatch.C
@@ -36,7 +36,6 @@ License
 #include "polyMesh.H"
 #include "polyPatch.H"
 //#include "pointPatchField.H"
-#include "demandDrivenData.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -85,9 +84,9 @@ Foam::wordList Foam::faPatch::constraintTypes()
 
 void Foam::faPatch::clearOut()
 {
-    deleteDemandDrivenData(edgeFacesPtr_);
-    deleteDemandDrivenData(pointLabelsPtr_);
-    deleteDemandDrivenData(pointEdgesPtr_);
+    edgeFacesPtr_.reset(nullptr);
+    pointLabelsPtr_.reset(nullptr);
+    pointEdgesPtr_.reset(nullptr);
 }
 
 
@@ -332,8 +331,9 @@ void Foam::faPatch::calcPointLabels() const
     }
 
     // Transfer to plain list (reuse storage)
-    pointLabelsPtr_ = new labelList(std::move(dynEdgePoints));
-    /// const labelList& edgePoints = *pointLabelsPtr_;
+    pointLabelsPtr_.reset(new labelList(std::move(dynEdgePoints)));
+
+    /// const auto& edgePoints = *pointLabelsPtr_;
     ///
     /// // Cannot use invertManyToMany - we have non-local edge numbering
     ///
@@ -350,7 +350,7 @@ void Foam::faPatch::calcPointLabels() const
     /// }
     ///
     /// // Flatten to regular list
-    /// pointEdgesPtr_ = new labelListList(edgePoints.size());
+    /// pointEdgesPtr_.reset(new labelListList(edgePoints.size()));
     /// auto& pEdges = *pointEdgesPtr_;
     ///
     /// forAll(pEdges, pointi)
@@ -381,7 +381,7 @@ void Foam::faPatch::calcPointEdges() const
     }
 
     // Flatten to regular list
-    pointEdgesPtr_ = new labelListList(edgePoints.size());
+    pointEdgesPtr_.reset(new labelListList(edgePoints.size()));
     auto& pEdges = *pointEdgesPtr_;
 
     forAll(pEdges, pointi)
@@ -441,9 +441,12 @@ const Foam::labelUList& Foam::faPatch::edgeFaces() const
 {
     if (!edgeFacesPtr_)
     {
-        edgeFacesPtr_ = new labelList::subList
+        edgeFacesPtr_.reset
         (
-            patchSlice(boundaryMesh().mesh().edgeOwner())
+            new labelList::subList
+            (
+                patchSlice(boundaryMesh().mesh().edgeOwner())
+            )
         );
     }
 
diff --git a/src/finiteArea/faMesh/faPatches/faPatch/faPatch.H b/src/finiteArea/faMesh/faPatches/faPatch/faPatch.H
index e0f41c84f5d..448b82d1e0a 100644
--- a/src/finiteArea/faMesh/faPatches/faPatch/faPatch.H
+++ b/src/finiteArea/faMesh/faPatches/faPatch/faPatch.H
@@ -86,13 +86,13 @@ class faPatch
         const faBoundaryMesh& boundaryMesh_;
 
         //- Demand-driven: edge-face addressing
-        mutable labelList::subList* edgeFacesPtr_;
+        mutable std::unique_ptr<labelList::subList> edgeFacesPtr_;
 
         //- Demand-driven: local points labels
-        mutable labelList* pointLabelsPtr_;
+        mutable std::unique_ptr<labelList> pointLabelsPtr_;
 
         //- Demand-driven: point-edge addressing
-        mutable labelListList* pointEdgesPtr_;
+        mutable std::unique_ptr<labelListList> pointEdgesPtr_;
 
 
     // Private Member Functions
diff --git a/src/finiteVolume/fvMesh/fvBoundaryMesh/fvBoundaryMesh.H b/src/finiteVolume/fvMesh/fvBoundaryMesh/fvBoundaryMesh.H
index e28aaf870ba..0f34a63144c 100644
--- a/src/finiteVolume/fvMesh/fvBoundaryMesh/fvBoundaryMesh.H
+++ b/src/finiteVolume/fvMesh/fvBoundaryMesh/fvBoundaryMesh.H
@@ -70,14 +70,6 @@ class fvBoundaryMesh
         //- Assign fvPatches corresponding to the given polyBoundaryMesh
         void addPatches(const polyBoundaryMesh& pbm);
 
-
-        //- No copy construct
-        fvBoundaryMesh(const fvBoundaryMesh&) = delete;
-
-        //- No copy assignment
-        void operator=(const fvBoundaryMesh&) = delete;
-
-
 protected:
 
         //- Update boundary based on new polyBoundaryMesh
@@ -86,9 +78,19 @@ protected:
 
 public:
 
+    //- Declare friendship with fvMesh
     friend class fvMesh;
 
 
+    // Generated Methods
+
+        //- No copy construct
+        fvBoundaryMesh(const fvBoundaryMesh&) = delete;
+
+        //- No copy assignment
+        void operator=(const fvBoundaryMesh&) = delete;
+
+
     // Constructors
 
         //- Construct zero size with mesh reference
@@ -101,10 +103,7 @@ public:
     // Member Functions
 
         //- Return the mesh reference
-        const fvMesh& mesh() const noexcept
-        {
-            return mesh_;
-        }
+        const fvMesh& mesh() const noexcept { return mesh_; }
 
         //- Return a list of faceCells for each patch
         UPtrList<const labelUList> faceCells() const;
diff --git a/src/meshTools/cellFeatures/cellFeatures.C b/src/meshTools/cellFeatures/cellFeatures.C
index 3d00718efa6..9cac148f60e 100644
--- a/src/meshTools/cellFeatures/cellFeatures.C
+++ b/src/meshTools/cellFeatures/cellFeatures.C
@@ -30,7 +30,6 @@ License
 #include "primitiveMesh.H"
 #include "HashSet.H"
 #include "Map.H"
-#include "demandDrivenData.H"
 #include "ListOps.H"
 #include "meshTools.H"
 
@@ -257,9 +256,8 @@ void Foam::cellFeatures::calcSuperFaces() const
 
     // Construct superFaces
 
-    facesPtr_ = new faceList(superFacei);
-
-    faceList& faces = *facesPtr_;
+    facesPtr_.reset(new faceList(superFacei));
+    auto& faces = *facesPtr_;
 
     forAll(cFaces, cFacei)
     {
@@ -390,16 +388,13 @@ Foam::cellFeatures::cellFeatures
             featureEdge_.insert(edgeI);
         }
     }
-
 }
 
 
 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
 
 Foam::cellFeatures::~cellFeatures()
-{
-    deleteDemandDrivenData(facesPtr_);
-}
+{}
 
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
diff --git a/src/meshTools/cellFeatures/cellFeatures.H b/src/meshTools/cellFeatures/cellFeatures.H
index 17dcdc7d41b..abce9f7f2c0 100644
--- a/src/meshTools/cellFeatures/cellFeatures.H
+++ b/src/meshTools/cellFeatures/cellFeatures.H
@@ -39,8 +39,8 @@ SourceFiles
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef cellFeatures_H
-#define cellFeatures_H
+#ifndef Foam_cellFeatures_H
+#define Foam_cellFeatures_H
 
 #include "faceList.H"
 #include "labelList.H"
@@ -54,7 +54,7 @@ SourceFiles
 namespace Foam
 {
 
-// Forward declaration of classes
+// Forward Declarations
 class primitiveMesh;
 
 /*---------------------------------------------------------------------------*\
@@ -77,7 +77,7 @@ class cellFeatures
         labelHashSet featureEdge_;
 
         //- (demand driven) Faces after removing internal points&edges
-        mutable faceList* facesPtr_;
+        mutable std::unique_ptr<faceList> facesPtr_;
 
         //- New to old face mapping
         mutable List<DynamicList<label>> faceMap_;
diff --git a/src/meshTools/polyTopoChange/polyTopoChange.C b/src/meshTools/polyTopoChange/polyTopoChange.C
index 3756807f041..9d63159f40c 100644
--- a/src/meshTools/polyTopoChange/polyTopoChange.C
+++ b/src/meshTools/polyTopoChange/polyTopoChange.C
@@ -1865,7 +1865,7 @@ void Foam::polyTopoChange::calcFaceZonePointMap
     {
         const faceZone& newZone = faceZones[zonei];
 
-        const labelList& newZoneMeshPoints = newZone().meshPoints();
+        const labelList& newZoneMeshPoints = newZone.patch().meshPoints();
 
         const Map<label>& oldZoneMeshPointMap = oldFaceZoneMeshPointMaps[zonei];
 
@@ -2146,7 +2146,7 @@ void Foam::polyTopoChange::compactAndReorder
     {
         const faceZone& oldZone = mesh.faceZones()[zonei];
 
-        oldFaceZoneMeshPointMaps[zonei] = oldZone().meshPointMap();
+        oldFaceZoneMeshPointMaps[zonei] = oldZone.patch().meshPointMap();
     }
 }
 
diff --git a/src/meshTools/topoSet/cellSources/faceZoneToCell/faceZoneToCell.C b/src/meshTools/topoSet/cellSources/faceZoneToCell/faceZoneToCell.C
index 412a69ab4bc..3e31508d4cf 100644
--- a/src/meshTools/topoSet/cellSources/faceZoneToCell/faceZoneToCell.C
+++ b/src/meshTools/topoSet/cellSources/faceZoneToCell/faceZoneToCell.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2016-2021 OpenCFD Ltd.
+    Copyright (C) 2016-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -45,8 +45,8 @@ namespace Foam
 Foam::topoSetSource::addToUsageTable Foam::faceZoneToCell::usage_
 (
     faceZoneToCell::typeName,
-    "\n    Usage: faceZoneToCell zone master|slave\n\n"
-    "    Select master or slave side of the faceZone."
+    "\n    Usage: faceZoneToCell zone front|back|both\n\n"
+    "    Select front, back or both sides of the faceZone."
     " Note:accepts wildcards for zone.\n\n"
 );
 
@@ -57,9 +57,12 @@ const Foam::Enum
 >
 Foam::faceZoneToCell::faceActionNames_
 ({
-    { faceAction::MASTER, "master" },
-    { faceAction::SLAVE, "slave" },
-    //TBD: { faceAction::BOTH, "attached" },
+    { faceAction::FRONT, "front" },
+    { faceAction::BACK, "back" },
+    { faceAction::BOTH, "both" },
+    // Compatibility
+    { faceAction::FRONT, "master" },
+    { faceAction::BACK, "slave" },
 });
 
 
@@ -89,31 +92,66 @@ void Foam::faceZoneToCell::combine
 
         const auto& zone = mesh_.faceZones()[zonei];
 
-        const labelList& cellLabels =
-        (
-            option_ == MASTER
-          ? zone.masterCells()
-          : zone.slaveCells()
-        );
-
         if (verbosity)
         {
-            Info<< "    Using matching zone " << zone.name() << " with "
-                << returnReduce(cellLabels.size(), sumOp<label>())
-                << " cells on "
-                << faceActionNames_[option_] << " side" << endl;
+            Info<< "    Using matching zone " << zone.name();
+
+            if (option_ == faceAction::FRONT)
+            {
+                Info<< " [front] cells:";
+            }
+            else if (option_ == faceAction::BACK)
+            {
+                Info<< " : [back] cells:";
+            }
+            if (option_ == faceAction::BOTH)
+            {
+                Info<< " : [front/back] cells:";
+            }
         }
 
-        // NOTE could also handle both sides directly if required
+        if (option_ == faceAction::FRONT || option_ == faceAction::BOTH)
+        {
+            const labelList& cellLabels = zone.frontCells();
+
+            if (verbosity)
+            {
+                Info<< ' ' << returnReduce(cellLabels.size(), sumOp<label>());
+            }
+
+            for (const label celli : cellLabels)
+            {
+                // Only do active cells
+                if (celli >= 0 && celli < mesh_.nCells())
+                {
+                    addOrDelete(set, celli, add);
+                }
+            }
+        }
 
-        for (const label celli : cellLabels)
+        if (option_ == faceAction::BACK || option_ == faceAction::BOTH)
         {
-            // Only do active cells
-            if (celli >= 0 && celli < mesh_.nCells())
+            const labelList& cellLabels = zone.backCells();
+
+            if (verbosity)
+            {
+                Info<< ' ' << returnReduce(cellLabels.size(), sumOp<label>());
+            }
+
+            for (const label celli : cellLabels)
             {
-                addOrDelete(set, celli, add);
+                // Only do active cells
+                if (celli >= 0 && celli < mesh_.nCells())
+                {
+                    addOrDelete(set, celli, add);
+                }
             }
         }
+
+        if (verbosity)
+        {
+            Info<< endl;
+        }
     }
 }
 
diff --git a/src/meshTools/topoSet/cellSources/faceZoneToCell/faceZoneToCell.H b/src/meshTools/topoSet/cellSources/faceZoneToCell/faceZoneToCell.H
index a471c6f76e5..44da5e124dc 100644
--- a/src/meshTools/topoSet/cellSources/faceZoneToCell/faceZoneToCell.H
+++ b/src/meshTools/topoSet/cellSources/faceZoneToCell/faceZoneToCell.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011 OpenFOAM Foundation
-    Copyright (C) 2018-2021 OpenCFD Ltd.
+    Copyright (C) 2018-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -28,8 +28,8 @@ Class
     Foam::faceZoneToCell
 
 Description
-    A \c topoSetCellSource to select cells based on \c master
-    or \c slave side of given \c faceZone(s).
+    A \c topoSetCellSource to select cells based on \c front
+    or \c back side of given \c faceZone(s).
 
     Operands:
     \table
@@ -86,8 +86,9 @@ Usage
 
     Options for the \c option entry:
     \verbatim
-      master   | Master side of the faceZone
-      slave    | Slave side of the faceZone
+      front   | Cells on the front side of the faceZone (also as 'master')
+      back    | Cells on the back side of the faceZone (also as 'slave')
+      both    | Both front and back side of the faceZone
     \endverbatim
 
     Options for the conditional mandatory entries:
@@ -134,8 +135,11 @@ public:
         //- Enumeration defining the valid options
         enum faceAction
         {
-            MASTER,
-            SLAVE
+            FRONT,  //!< The front (positive normal) side of the faces
+            BACK,   //!< The back (negative normal) side of the faces
+            BOTH,   //!< Both front and back side of faces
+            // Compatibility
+            MASTER = FRONT, SLAVE = BACK
         };
 
 
diff --git a/src/surfMesh/surfZone/surfZoneIOList.C b/src/surfMesh/surfZone/surfZoneIOList.C
index d2b38ee762a..b2567d286ca 100644
--- a/src/surfMesh/surfZone/surfZoneIOList.C
+++ b/src/surfMesh/surfZone/surfZoneIOList.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2018-2022 OpenCFD Ltd.
+    Copyright (C) 2018-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -36,50 +36,67 @@ namespace Foam
 }
 
 
-// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
-Foam::surfZoneIOList::surfZoneIOList
-(
-    const IOobject& io
-)
-:
-    regIOobject(io),
-    surfZoneList()
+bool Foam::surfZoneIOList::readContents()
 {
-    if (isReadRequired())
+    if
+    (
+        this->isReadRequired()
+    )
     {
         surfZoneList& zones = *this;
 
+        // Read entries
         Istream& is = readStream(typeName);
 
-        PtrList<entry> dictEntries(is);
-        zones.resize(dictEntries.size());
+        PtrList<entry> entries(is);
+        zones.resize(entries.size());
 
-        label facei = 0;
+        // Transcribe
+        label startOffset = 0;
         forAll(zones, zonei)
         {
             zones[zonei] = surfZone
             (
-                dictEntries[zonei].keyword(),
-                dictEntries[zonei].dict(),
+                entries[zonei].keyword(),
+                entries[zonei].dict(),
                 zonei
             );
 
-            if (zones[zonei].start() != facei)
+            if (zones[zonei].start() != startOffset)
             {
                 FatalErrorInFunction
                     << "surfZones are not ordered. Start of zone " << zonei
                     << " does not correspond to sum of preceding zones." << nl
-                    << "while reading " << io.objectPath() << endl
+                    << "while reading " << this->objectRelPath() << endl
                     << exit(FatalError);
             }
 
-            facei += zones[zonei].size();
+            startOffset += zones[zonei].size();
         }
 
         is.check(FUNCTION_NAME);
         close();
+        return true;
     }
+
+    // Nothing read
+    return false;
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::surfZoneIOList::surfZoneIOList
+(
+    const IOobject& io
+)
+:
+    regIOobject(io),
+    surfZoneList()
+{
+    readContents();  // allowOptionalRead = false
 }
 
 
@@ -110,11 +127,11 @@ Foam::surfZoneIOList::surfZoneIOList
 bool Foam::surfZoneIOList::writeData(Ostream& os) const
 {
     const surfZoneList& zones = *this;
-    const label sz = zones.size();
+    const label len = zones.size();
 
-    if (sz)
+    if (len)
     {
-        os  << sz << nl << token::BEGIN_LIST << incrIndent << nl;
+        os  << len << nl << token::BEGIN_LIST << incrIndent << nl;
 
         for (const surfZone& zn : zones)
         {
@@ -125,7 +142,7 @@ bool Foam::surfZoneIOList::writeData(Ostream& os) const
     }
     else
     {
-        os  << sz << token::BEGIN_LIST << token::END_LIST;
+        os  << len << token::BEGIN_LIST << token::END_LIST;
     }
 
     return os.good();
diff --git a/src/surfMesh/surfZone/surfZoneIOList.H b/src/surfMesh/surfZone/surfZoneIOList.H
index 10681a89290..4ceb9237582 100644
--- a/src/surfMesh/surfZone/surfZoneIOList.H
+++ b/src/surfMesh/surfZone/surfZoneIOList.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2018-2020 OpenCFD Ltd.
+    Copyright (C) 2018-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -35,8 +35,8 @@ SourceFiles
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef surfZoneIOList_H
-#define surfZoneIOList_H
+#ifndef Foam_surfZoneIOList_H
+#define Foam_surfZoneIOList_H
 
 #include "surfZoneList.H"
 #include "regIOobject.H"
@@ -56,6 +56,13 @@ class surfZoneIOList
     public regIOobject,
     public surfZoneList
 {
+    // Private Member Functions
+
+        //- Return true if contents were read
+        //- (controlled by IOobject readOption flags).
+        bool readContents();
+
+
 public:
 
     //- Runtime type information
diff --git a/tutorials/heatTransfer/chtMultiRegionSimpleFoam/cpuCabinet/system/topoSetDict.f1 b/tutorials/heatTransfer/chtMultiRegionSimpleFoam/cpuCabinet/system/topoSetDict.f1
index 620bc9043b3..917d3e52739 100644
--- a/tutorials/heatTransfer/chtMultiRegionSimpleFoam/cpuCabinet/system/topoSetDict.f1
+++ b/tutorials/heatTransfer/chtMultiRegionSimpleFoam/cpuCabinet/system/topoSetDict.f1
@@ -1,7 +1,7 @@
 /*--------------------------------*- C++ -*----------------------------------*\
 | =========                 |                                                 |
 | \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
-|  \\    /   O peration     | Version:  v2306                                 |
+|  \\    /   O peration     | Version:  v2312                                 |
 |   \\  /    A nd           | Website:  www.openfoam.com                      |
 |    \\/     M anipulation  |                                                 |
 \*---------------------------------------------------------------------------*/
@@ -30,17 +30,8 @@ actions
         name    c1;
         type    cellSet;
         action  new;
-        source  faceZoneToCell;//zoneToCel;
-        option  master;
-        zones   (domain0_to_v_CPU);
-    }
-
-    {
-        name    c1;
-        type    cellSet;
-        action  add;
-        source  faceZoneToCell;//zoneToCel;
-        option  slave;
+        source  faceZoneToCell;
+        option  both;
         zones   (domain0_to_v_CPU);
     }
 
diff --git a/tutorials/incompressible/pisoFoam/RAS/cavity/system/topoSetDict b/tutorials/incompressible/pisoFoam/RAS/cavity/system/topoSetDict
index 19f5459e7fb..0a067445798 100644
--- a/tutorials/incompressible/pisoFoam/RAS/cavity/system/topoSetDict
+++ b/tutorials/incompressible/pisoFoam/RAS/cavity/system/topoSetDict
@@ -1,7 +1,7 @@
 /*--------------------------------*- C++ -*----------------------------------*\
 | =========                 |                                                 |
 | \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
-|  \\    /   O peration     | Version:  v2306                                 |
+|  \\    /   O peration     | Version:  v2312                                 |
 |   \\  /    A nd           | Website:  www.openfoam.com                      |
 |    \\/     M anipulation  |                                                 |
 \*---------------------------------------------------------------------------*/
@@ -589,7 +589,7 @@ actions
         type    cellSet;
         action  new;
         source  faceZoneToCell;
-        option  slave;
+        option  back;
         zones
         (
             faceZone1
@@ -601,7 +601,7 @@ actions
         type    cellSet;
         action  new;
         source  faceZoneToCell;
-        option  master;
+        option  front;
         zone    faceZone1;
     }
 
-- 
GitLab