From a072d183805c853a635e0e6f7930b578dc2f8203 Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@esi-group.com>
Date: Wed, 14 Nov 2018 11:55:38 +0100
Subject: [PATCH] ENH: add sync() for faceBitSet, faceBoolSet, pointBitSet
 (#1060)

- fix range checks
---
 src/meshTools/sets/topoSets/cellSet.C      | 28 ++++---
 src/meshTools/sets/topoSets/cellZoneSet.C  |  5 +-
 src/meshTools/sets/topoSets/faceBitSet.C   | 28 +++++++
 src/meshTools/sets/topoSets/faceBitSet.H   |  9 +--
 src/meshTools/sets/topoSets/faceBoolSet.C  | 22 +++++-
 src/meshTools/sets/topoSets/faceBoolSet.H  |  9 +--
 src/meshTools/sets/topoSets/faceSet.C      | 71 ++++++++----------
 src/meshTools/sets/topoSets/faceZoneSet.C  |  2 +-
 src/meshTools/sets/topoSets/pointBitSet.C  | 29 ++++++++
 src/meshTools/sets/topoSets/pointBitSet.H  |  9 +--
 src/meshTools/sets/topoSets/pointSet.C     | 61 +++++++--------
 src/meshTools/sets/topoSets/pointSet.H     |  3 -
 src/meshTools/sets/topoSets/pointZoneSet.C |  7 +-
 src/meshTools/sets/topoSets/topoBitSet.C   | 78 +++++++++++++++++++
 src/meshTools/sets/topoSets/topoBitSet.H   |  8 ++
 src/meshTools/sets/topoSets/topoBoolSet.C  | 87 ++++++++++++++++++++++
 src/meshTools/sets/topoSets/topoBoolSet.H  |  8 ++
 src/meshTools/sets/topoSets/topoSet.C      | 54 ++++++++------
 src/meshTools/sets/topoSets/topoSet.H      | 20 +++--
 19 files changed, 398 insertions(+), 140 deletions(-)

diff --git a/src/meshTools/sets/topoSets/cellSet.C b/src/meshTools/sets/topoSets/cellSet.C
index df5704da16d..cc6afd277ba 100644
--- a/src/meshTools/sets/topoSets/cellSet.C
+++ b/src/meshTools/sets/topoSets/cellSet.C
@@ -190,34 +190,40 @@ void Foam::cellSet::updateMesh(const mapPolyMesh& morphMap)
 
 void Foam::cellSet::distribute(const mapDistributePolyMesh& map)
 {
-    boolList inSet(map.nOldCells());
+    labelHashSet& labels = *this;
 
-    const labelHashSet& labels = *this;
+    boolList contents(map.nOldCells(), false);
 
     for (const label celli : labels)
     {
-        inSet[celli] = true;
+        contents.set(celli);
     }
 
-    map.distributeCellData(inSet);
+    map.distributeCellData(contents);
+
+    // The new length
+    const label len = contents.size();
 
     // Count
     label n = 0;
-    forAll(inSet, celli)
+    for (label i=0; i < len; ++i)
     {
-        if (inSet[celli])
+        if (contents.test(i))
         {
             ++n;
         }
     }
 
-    clear();
-    resize(n);
-    forAll(inSet, celli)
+    // Update labelHashSet
+
+    labels.clear();
+    labels.resize(2*n);
+
+    for (label i=0; i < len; ++i)
     {
-        if (inSet[celli])
+        if (contents.test(i))
         {
-            insert(celli);
+            labels.set(i);
         }
     }
 }
diff --git a/src/meshTools/sets/topoSets/cellZoneSet.C b/src/meshTools/sets/topoSets/cellZoneSet.C
index 0ca2fdc96da..4afc73d22d0 100644
--- a/src/meshTools/sets/topoSets/cellZoneSet.C
+++ b/src/meshTools/sets/topoSets/cellZoneSet.C
@@ -276,9 +276,8 @@ void Foam::cellZoneSet::updateMesh(const mapPolyMesh& morphMap)
     labelList newAddressing(addressing_.size());
 
     label n = 0;
-    forAll(addressing_, i)
+    for (const label celli : addressing_)
     {
-        label celli = addressing_[i];
         label newCelli = morphMap.reverseCellMap()[celli];
         if (newCelli >= 0)
         {
@@ -286,7 +285,7 @@ void Foam::cellZoneSet::updateMesh(const mapPolyMesh& morphMap)
             ++n;
         }
     }
-    newAddressing.setSize(n);
+    newAddressing.resize(n);
 
     addressing_.transfer(newAddressing);
 
diff --git a/src/meshTools/sets/topoSets/faceBitSet.C b/src/meshTools/sets/topoSets/faceBitSet.C
index 12718c69bb5..7cda9cf888f 100644
--- a/src/meshTools/sets/topoSets/faceBitSet.C
+++ b/src/meshTools/sets/topoSets/faceBitSet.C
@@ -25,6 +25,9 @@ License
 
 #include "faceBitSet.H"
 #include "polyMesh.H"
+#include "mapPolyMesh.H"
+#include "syncTools.H"
+#include "mapDistributePolyMesh.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -70,12 +73,37 @@ Foam::faceBitSet::faceBitSet
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
+void Foam::faceBitSet::sync(const polyMesh& mesh)
+{
+    syncTools::syncFaceList(mesh, selected_, orEqOp<unsigned int>());
+}
+
+
 Foam::label Foam::faceBitSet::maxSize(const polyMesh& mesh) const
 {
     return mesh.nFaces();
 }
 
 
+void Foam::faceBitSet::updateMesh(const mapPolyMesh& morphMap)
+{
+    updateLabels(morphMap.reverseFaceMap());
+}
+
+
+void Foam::faceBitSet::distribute(const mapDistributePolyMesh& map)
+{
+    bitSet& labels = selected_;
+
+    boolList contents(labels.values());
+
+    map.distributeFaceData(contents);
+
+    // The new length is contents.size();
+    labels.assign(contents);
+}
+
+
 void Foam::faceBitSet::writeDebug
 (
     Ostream& os,
diff --git a/src/meshTools/sets/topoSets/faceBitSet.H b/src/meshTools/sets/topoSets/faceBitSet.H
index 5c978862942..a4f5d42b68e 100644
--- a/src/meshTools/sets/topoSets/faceBitSet.H
+++ b/src/meshTools/sets/topoSets/faceBitSet.H
@@ -79,19 +79,16 @@ public:
     // Member Functions
 
         //- Sync faceBitSet across coupled patches.
-        virtual void sync(const polyMesh& mesh)
-        {}
+        virtual void sync(const polyMesh& mesh);
 
         //- Return max index+1.
         virtual label maxSize(const polyMesh& mesh) const;
 
         //- Update any stored data for new labels.
-        virtual void updateMesh(const mapPolyMesh& morphMap)
-        {}
+        virtual void updateMesh(const mapPolyMesh& morphMap);
 
         //- Update any stored data for mesh redistribution.
-        virtual void distribute(const mapDistributePolyMesh& map)
-        {}
+        virtual void distribute(const mapDistributePolyMesh& map);
 
         //- Write maxLen items with label and coordinates.
         virtual void writeDebug
diff --git a/src/meshTools/sets/topoSets/faceBoolSet.C b/src/meshTools/sets/topoSets/faceBoolSet.C
index 8ad806e4249..6f77618dd89 100644
--- a/src/meshTools/sets/topoSets/faceBoolSet.C
+++ b/src/meshTools/sets/topoSets/faceBoolSet.C
@@ -25,7 +25,9 @@ License
 
 #include "faceBoolSet.H"
 #include "polyMesh.H"
-#include "Time.H"
+#include "mapPolyMesh.H"
+#include "syncTools.H"
+#include "mapDistributePolyMesh.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -71,12 +73,30 @@ Foam::faceBoolSet::faceBoolSet
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
+void Foam::faceBoolSet::sync(const polyMesh& mesh)
+{
+    syncTools::syncFaceList(mesh, selected_, orEqOp<bool>());
+}
+
+
 Foam::label Foam::faceBoolSet::maxSize(const polyMesh& mesh) const
 {
     return mesh.nFaces();
 }
 
 
+void Foam::faceBoolSet::updateMesh(const mapPolyMesh& morphMap)
+{
+    updateLabels(morphMap.reverseFaceMap());
+}
+
+
+void Foam::faceBoolSet::distribute(const mapDistributePolyMesh& map)
+{
+    map.distributeFaceData(selected_);
+}
+
+
 void Foam::faceBoolSet::writeDebug
 (
     Ostream& os,
diff --git a/src/meshTools/sets/topoSets/faceBoolSet.H b/src/meshTools/sets/topoSets/faceBoolSet.H
index e4cf69997d0..0c0f6d701aa 100644
--- a/src/meshTools/sets/topoSets/faceBoolSet.H
+++ b/src/meshTools/sets/topoSets/faceBoolSet.H
@@ -79,19 +79,16 @@ public:
     // Member Functions
 
         //- Sync faceBoolSet across coupled patches.
-        virtual void sync(const polyMesh& mesh)
-        {}
+        virtual void sync(const polyMesh& mesh);
 
         //- Return max index+1.
         virtual label maxSize(const polyMesh& mesh) const;
 
         //- Update any stored data for new labels.
-        virtual void updateMesh(const mapPolyMesh& morphMap)
-        {}
+        virtual void updateMesh(const mapPolyMesh& morphMap);
 
         //- Update any stored data for mesh redistribution.
-        virtual void distribute(const mapDistributePolyMesh& map)
-        {}
+        virtual void distribute(const mapDistributePolyMesh& map);
 
         //- Write maxLen items with label and coordinates.
         virtual void writeDebug
diff --git a/src/meshTools/sets/topoSets/faceSet.C b/src/meshTools/sets/topoSets/faceSet.C
index b4839065a8e..f09aabaf462 100644
--- a/src/meshTools/sets/topoSets/faceSet.C
+++ b/src/meshTools/sets/topoSets/faceSet.C
@@ -24,8 +24,8 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "faceSet.H"
-#include "mapPolyMesh.H"
 #include "polyMesh.H"
+#include "mapPolyMesh.H"
 #include "syncTools.H"
 #include "mapDistributePolyMesh.H"
 #include "addToRunTimeSelectionTable.H"
@@ -126,43 +126,32 @@ Foam::faceSet::faceSet
 
 void Foam::faceSet::sync(const polyMesh& mesh)
 {
-    boolList set(mesh.nFaces(), false);
+    labelHashSet& labels = *this;
+
+    // Convert to boolList
+    // TBD: could change to using bitSet for the synchronization
+
+    const label len = mesh.nFaces();
 
-    const labelHashSet& labels = *this;
+    boolList contents(len, false);
 
     for (const label facei : labels)
     {
-        set[facei] = true;
+        contents.set(facei);
     }
 
-    syncTools::syncFaceList(mesh, set, orEqOp<bool>());
+    syncTools::syncFaceList(mesh, contents, orEqOp<bool>());
 
-    label nAdded = 0;
 
-    forAll(set, facei)
+    // Update labelHashSet
+
+    for (label i=0; i < len; ++i)
     {
-        if (set[facei])
-        {
-            if (this->set(facei))
-            {
-                ++nAdded;
-            }
-        }
-        else if (found(facei))
+        if (contents.test(i))
         {
-            FatalErrorInFunction
-                << "Problem : syncing removed faces from set."
-                << abort(FatalError);
+            labels.set(i);
         }
     }
-
-    reduce(nAdded, sumOp<label>());
-    if (debug && nAdded > 0)
-    {
-        Info<< "Added an additional " << nAdded
-            << " faces on coupled patches. "
-            << "(processorPolyPatch, cyclicPolyPatch)" << endl;
-    }
 }
 
 
@@ -180,34 +169,40 @@ void Foam::faceSet::updateMesh(const mapPolyMesh& morphMap)
 
 void Foam::faceSet::distribute(const mapDistributePolyMesh& map)
 {
-    boolList inSet(map.nOldFaces());
+    labelHashSet& labels = *this;
 
-    const labelHashSet& labels = *this;
+    boolList contents(map.nOldFaces(), false);
 
     for (const label facei : labels)
     {
-        inSet[facei] = true;
+        contents.set(facei);
     }
 
-    map.distributeFaceData(inSet);
+    map.distributeFaceData(contents);
 
-    // Count
+    // The new length
+    const label len = contents.size();
+
+    // Count - as per BitOps::count(contents)
     label n = 0;
-    forAll(inSet, facei)
+    for (label i=0; i < len; ++i)
     {
-        if (inSet[facei])
+        if (contents.test(i))
         {
             ++n;
         }
     }
 
-    clear();
-    resize(n);
-    forAll(inSet, facei)
+    // Update labelHashSet
+
+    labels.clear();
+    labels.resize(2*n);
+
+    for (label i=0; i < len; ++i)
     {
-        if (inSet[facei])
+        if (contents.test(i))
         {
-            this->set(facei);
+            labels.set(i);
         }
     }
 }
diff --git a/src/meshTools/sets/topoSets/faceZoneSet.C b/src/meshTools/sets/topoSets/faceZoneSet.C
index ff0431ac69f..2e42af97dda 100644
--- a/src/meshTools/sets/topoSets/faceZoneSet.C
+++ b/src/meshTools/sets/topoSets/faceZoneSet.C
@@ -497,7 +497,7 @@ void Foam::faceZoneSet::updateMesh(const mapPolyMesh& morphMap)
 {
     // faceZone
     labelList newAddressing(addressing_.size());
-    boolList newFlipMap(flipMap_.size());
+    boolList newFlipMap(flipMap_.size(), false);
 
     label n = 0;
     forAll(addressing_, i)
diff --git a/src/meshTools/sets/topoSets/pointBitSet.C b/src/meshTools/sets/topoSets/pointBitSet.C
index f7c8aceb5a7..c02f4830bfd 100644
--- a/src/meshTools/sets/topoSets/pointBitSet.C
+++ b/src/meshTools/sets/topoSets/pointBitSet.C
@@ -25,6 +25,9 @@ License
 
 #include "pointBitSet.H"
 #include "polyMesh.H"
+#include "mapPolyMesh.H"
+#include "syncTools.H"
+#include "mapDistributePolyMesh.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -70,12 +73,38 @@ Foam::pointBitSet::pointBitSet
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
+void Foam::pointBitSet::sync(const polyMesh& mesh)
+{
+    // The nullValue = '0u'
+    syncTools::syncPointList(mesh, selected_, orEqOp<unsigned int>(), 0u);
+}
+
+
 Foam::label Foam::pointBitSet::maxSize(const polyMesh& mesh) const
 {
     return mesh.nPoints();
 }
 
 
+void Foam::pointBitSet::updateMesh(const mapPolyMesh& morphMap)
+{
+    updateLabels(morphMap.reversePointMap());
+}
+
+
+void Foam::pointBitSet::distribute(const mapDistributePolyMesh& map)
+{
+    bitSet& labels = selected_;
+
+    boolList contents(labels.values());
+
+    map.distributePointData(contents);
+
+    // The new length is contents.size();
+    labels.assign(contents);
+}
+
+
 void Foam::pointBitSet::writeDebug
 (
     Ostream& os,
diff --git a/src/meshTools/sets/topoSets/pointBitSet.H b/src/meshTools/sets/topoSets/pointBitSet.H
index 4b9c27108a2..5a431e808c9 100644
--- a/src/meshTools/sets/topoSets/pointBitSet.H
+++ b/src/meshTools/sets/topoSets/pointBitSet.H
@@ -79,19 +79,16 @@ public:
     // Member Functions
 
         //- Sync pointBitSet across coupled patches.
-        virtual void sync(const polyMesh& mesh)
-        {}
+        virtual void sync(const polyMesh& mesh);
 
         //- Return max index+1.
         virtual label maxSize(const polyMesh& mesh) const;
 
         //- Update any stored data for new labels.
-        virtual void updateMesh(const mapPolyMesh& morphMap)
-        {}
+        virtual void updateMesh(const mapPolyMesh& morphMap);
 
         //- Update any stored data for mesh redistribution.
-        virtual void distribute(const mapDistributePolyMesh& map)
-        {}
+        virtual void distribute(const mapDistributePolyMesh& map);
 
         //- Write maxLen items with label and coordinates.
         virtual void writeDebug
diff --git a/src/meshTools/sets/topoSets/pointSet.C b/src/meshTools/sets/topoSets/pointSet.C
index d0c9459420d..3cb9664c8dc 100644
--- a/src/meshTools/sets/topoSets/pointSet.C
+++ b/src/meshTools/sets/topoSets/pointSet.C
@@ -126,38 +126,33 @@ Foam::pointSet::pointSet
 
 void Foam::pointSet::sync(const polyMesh& mesh)
 {
+    labelHashSet& labels = *this;
+
     // Convert to boolList
+    // TBD: could change to using bitSet for the synchronization
 
-    boolList contents(mesh.nPoints(), false);
+    const label len = mesh.nPoints();
 
-    const labelHashSet& labels = *this;
+    boolList contents(len, false);
 
     for (const label pointi : labels)
     {
-        contents[pointi] = true;
+        contents.set(pointi);
     }
 
-    syncTools::syncPointList
-    (
-        mesh,
-        contents,
-        orEqOp<bool>(),
-        false           // null value
-    );
+    // The nullValue = 'false'
+    syncTools::syncPointList(mesh, contents, orEqOp<bool>(), false);
 
-    // Convert back to labelHashSet
 
-    labelHashSet newContents(size());
+    // Update labelHashSet
 
-    forAll(contents, pointi)
+    for (label pointi=0; pointi < len; ++pointi)
     {
-        if (contents[pointi])
+        if (contents.test(pointi))
         {
-            newContents.set(pointi);
+            labels.set(pointi);
         }
     }
-
-    transfer(newContents);
 }
 
 
@@ -175,34 +170,41 @@ void Foam::pointSet::updateMesh(const mapPolyMesh& morphMap)
 
 void Foam::pointSet::distribute(const mapDistributePolyMesh& map)
 {
-    boolList inSet(map.nOldPoints());
+    labelHashSet& labels = *this;
 
-    const labelHashSet& labels = *this;
+    boolList contents(map.nOldPoints(), false);
 
     for (const label pointi : labels)
     {
-        inSet[pointi] = true;
+        contents.set(pointi);
     }
 
-    map.distributePointData(inSet);
+    map.distributePointData(contents);
 
-    // Count
+    // The new length
+    const label len = contents.size();
+
+    // Count - as per BitOps::count(contents)
     label n = 0;
-    forAll(inSet, pointi)
+    for (label i=0; i < len; ++i)
     {
-        if (inSet[pointi])
+        if (contents.test(i))
         {
             ++n;
         }
     }
 
-    clear();
-    resize(n);
-    forAll(inSet, pointi)
+
+    // Update labelHashSet
+
+    labels.clear();
+    labels.resize(2*n);
+
+    for (label i=0; i < len; ++i)
     {
-        if (inSet[pointi])
+        if (contents.test(i))
         {
-            this->set(pointi);
+            labels.set(i);
         }
     }
 }
@@ -218,4 +220,5 @@ void Foam::pointSet::writeDebug
     topoSet::writeDebug(os, mesh.points(), maxLen);
 }
 
+
 // ************************************************************************* //
diff --git a/src/meshTools/sets/topoSets/pointSet.H b/src/meshTools/sets/topoSets/pointSet.H
index 89f1009d290..8bf6fdf6e69 100644
--- a/src/meshTools/sets/topoSets/pointSet.H
+++ b/src/meshTools/sets/topoSets/pointSet.H
@@ -131,9 +131,6 @@ public:
         //- Update any stored data for new labels
         virtual void updateMesh(const mapPolyMesh& morphMap);
 
-        //- Update any stored data for new labels
-        //virtual void updateMesh(const polyTopoChange& meshMod);
-
         //- Update any stored data for mesh redistribution.
         virtual void distribute(const mapDistributePolyMesh&);
 
diff --git a/src/meshTools/sets/topoSets/pointZoneSet.C b/src/meshTools/sets/topoSets/pointZoneSet.C
index 647adac1999..5a14c7c48de 100644
--- a/src/meshTools/sets/topoSets/pointZoneSet.C
+++ b/src/meshTools/sets/topoSets/pointZoneSet.C
@@ -276,17 +276,16 @@ void Foam::pointZoneSet::updateMesh(const mapPolyMesh& morphMap)
     labelList newAddressing(addressing_.size());
 
     label n = 0;
-    forAll(addressing_, i)
+    for (const label pointi : addressing_)
     {
-        label pointi = addressing_[i];
-        label newPointi = morphMap.reversePointMap()[pointi];
+        const label newPointi = morphMap.reversePointMap()[pointi];
         if (newPointi >= 0)
         {
             newAddressing[n] = newPointi;
             ++n;
         }
     }
-    newAddressing.setSize(n);
+    newAddressing.resize(n);
 
     addressing_.transfer(newAddressing);
 
diff --git a/src/meshTools/sets/topoSets/topoBitSet.C b/src/meshTools/sets/topoSets/topoBitSet.C
index a90d9d02f1e..0ea3b9a5d28 100644
--- a/src/meshTools/sets/topoSets/topoBitSet.C
+++ b/src/meshTools/sets/topoSets/topoBitSet.C
@@ -27,6 +27,84 @@ License
 #include "polyMesh.H"
 #include "Time.H"
 
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+// Update stored cell numbers using map.
+// Do in two passes to prevent allocation if nothing changed.
+void Foam::topoBitSet::updateLabels(const labelUList& map)
+{
+    bitSet& labels = selected_;
+
+    {
+        const label oldId = labels.find_last();
+
+        if (oldId >= map.size())
+        {
+            FatalErrorInFunction
+                << "Illegal content " << oldId << " of set:" << name()
+                << " of type " << type() << nl
+                << "Value should be between [0," << map.size() << ')'
+                << endl
+                << abort(FatalError);
+        }
+    }
+
+    // Iterate over map to see if anything changed
+
+    bool changed = false;
+
+    for (const label oldId : labels)
+    {
+        const label newId = map[oldId];
+
+        if (newId != oldId)
+        {
+            changed = true;
+            break;
+        }
+    }
+
+    if (!changed)
+    {
+        return;
+    }
+
+
+    // Relabel. Use second bitSet to prevent overlapping.
+
+    // The new length is given by the map
+    const label len = map.size();
+
+    bitSet newLabels(len);
+
+    for (const label oldId : labels)
+    {
+        const label newId = map[oldId];
+        newLabels.set(newId);  // Ignores -ve indices
+    }
+
+    labels.transfer(newLabels);
+}
+
+
+void Foam::topoBitSet::check(const label maxSize)
+{
+    const bitSet& labels = selected_;
+
+    const label oldId = labels.find_last();
+
+    if (oldId >= maxSize)
+    {
+        FatalErrorInFunction
+            << "Illegal content " << oldId << " of set:" << name()
+            << " of type " << type() << nl
+            << "Value should be between [0," << maxSize << ')'
+            << endl
+            << abort(FatalError);
+    }
+}
+
+
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
 Foam::topoBitSet::topoBitSet
diff --git a/src/meshTools/sets/topoSets/topoBitSet.H b/src/meshTools/sets/topoSets/topoBitSet.H
index e73b4621e90..f9107a387af 100644
--- a/src/meshTools/sets/topoSets/topoBitSet.H
+++ b/src/meshTools/sets/topoSets/topoBitSet.H
@@ -60,6 +60,14 @@ protected:
 
     // Protected Member Functions
 
+        //- Update map from map.
+        //  Used to update cell/face labels after morphing
+        virtual void updateLabels(const labelUList& map);
+
+        //- Check limits on addressable range.
+        virtual void check(const label maxSize);
+
+
         //- Construct with empty selection
         topoBitSet(const polyMesh& mesh, const word& setName);
 
diff --git a/src/meshTools/sets/topoSets/topoBoolSet.C b/src/meshTools/sets/topoSets/topoBoolSet.C
index bc08fdb3dd9..47cca64fa5a 100644
--- a/src/meshTools/sets/topoSets/topoBoolSet.C
+++ b/src/meshTools/sets/topoSets/topoBoolSet.C
@@ -27,6 +27,93 @@ License
 #include "polyMesh.H"
 #include "Time.H"
 
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+// Update stored cell numbers using map.
+// Do in two passes to prevent allocation if nothing changed.
+void Foam::topoBoolSet::updateLabels(const labelUList& map)
+{
+    boolList& labels = selected_;
+
+    // Iterate over map to see if anything changed
+    // Must iterate over ALL elements, to properly trap bounds errors
+
+    bool changed = false;
+
+    forAll(labels, oldId)
+    {
+        if (!labels.test(oldId))
+        {
+            continue;
+        }
+
+        if (oldId >= map.size())
+        {
+            FatalErrorInFunction
+                << "Illegal content " << oldId << " of set:" << name()
+                << " of type " << type() << nl
+                << "Value should be between [0," << map.size() << ')'
+                << endl
+                << abort(FatalError);
+        }
+
+        const label newId = map[oldId];
+
+        if (newId != oldId)
+        {
+            changed = true;
+            #ifdef FULLDEBUG
+            continue;  // Check all elements in FULLDEBUG mode
+            #endif
+            break;
+        }
+    }
+
+    if (!changed)
+    {
+        return;
+    }
+
+
+    // Relabel. Use second boolList to prevent overlapping.
+
+    // The new length is given by the map
+    const label len = map.size();
+
+    boolList newLabels(len, false);
+
+    forAll(labels, oldId)
+    {
+        const label newId = map[oldId];
+
+        if (newId >= 0)
+        {
+            newLabels.set(newId);  // Ignores -ve indices
+        }
+    }
+
+    labels.transfer(newLabels);
+}
+
+
+void Foam::topoBoolSet::check(const label maxSize)
+{
+    const boolList& labels = selected_;
+
+    const label oldId = labels.rfind(true);
+
+    if (oldId >= maxSize)
+    {
+        FatalErrorInFunction
+            << "Illegal content " << oldId << " of set:" << name()
+            << " of type " << type() << nl
+            << "Value should be between [0," << maxSize << ')'
+            << endl
+            << abort(FatalError);
+    }
+}
+
+
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
 Foam::topoBoolSet::topoBoolSet
diff --git a/src/meshTools/sets/topoSets/topoBoolSet.H b/src/meshTools/sets/topoSets/topoBoolSet.H
index d7b93c4f2f1..7a9fb756427 100644
--- a/src/meshTools/sets/topoSets/topoBoolSet.H
+++ b/src/meshTools/sets/topoSets/topoBoolSet.H
@@ -60,6 +60,14 @@ protected:
 
     // Protected Member Functions
 
+        //- Update map from map.
+        //  Used to update cell/face labels after morphing
+        virtual void updateLabels(const labelUList& map);
+
+        //- Check limits on addressable range.
+        virtual void check(const label maxSize);
+
+
         //- Construct with empty selection
         topoBoolSet(const polyMesh& mesh, const word& setName);
 
diff --git a/src/meshTools/sets/topoSets/topoSet.C b/src/meshTools/sets/topoSets/topoSet.C
index 040eec3c0d7..c0929ad9a02 100644
--- a/src/meshTools/sets/topoSets/topoSet.C
+++ b/src/meshTools/sets/topoSets/topoSet.C
@@ -45,7 +45,7 @@ namespace Foam
 }
 
 
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+// * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
 
 Foam::autoPtr<Foam::topoSet> Foam::topoSet::New
 (
@@ -122,6 +122,8 @@ Foam::autoPtr<Foam::topoSet> Foam::topoSet::New
 }
 
 
+// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
+
 Foam::fileName Foam::topoSet::localPath
 (
     const polyMesh& mesh,
@@ -136,21 +138,23 @@ Foam::fileName Foam::topoSet::localPath
 
 // Update stored cell numbers using map.
 // Do in two passes to prevent allocation if nothing changed.
-void Foam::topoSet::updateLabels(const labelList& map)
+void Foam::topoSet::updateLabels(const labelUList& map)
 {
+    labelHashSet& labels = *this;
+
     // Iterate over map to see if anything changed
-    bool changed = false;
 
-    const labelHashSet& labels = *this;
+    bool changed = false;
 
     for (const label oldId : labels)
     {
-        if (oldId < 0 || oldId > map.size())
+        if (oldId < 0 || oldId >= map.size())
         {
             FatalErrorInFunction
                 << "Illegal content " << oldId << " of set:" << name()
-                << " of type " << type() << endl
+                << " of type " << type() << nl
                 << "Value should be between [0," << map.size() << ')'
+                << endl
                 << abort(FatalError);
         }
 
@@ -159,42 +163,50 @@ void Foam::topoSet::updateLabels(const labelList& map)
         if (newId != oldId)
         {
             changed = true;
+            #ifdef FULLDEBUG
+            continue;  // Check all elements in FULLDEBUG mode
+            #endif
             break;
         }
     }
 
-    // Relabel (use second Map to prevent overlapping)
-    if (changed)
+    if (!changed)
     {
-        labelHashSet newSet(2*size());
+        return;
+    }
 
-        for (const label oldId : labels)
-        {
-            const label newId = map[oldId];
 
-            if (newId >= 0)
-            {
-                newSet.set(newId);
-            }
-        }
+    // Relabel. Use second labelHashSet to prevent overlapping.
 
-        transfer(newSet);
+    labelHashSet newLabels(2*labels.size());
+
+    for (const label oldId : labels)
+    {
+        const label newId = map[oldId];
+
+        if (newId >= 0)
+        {
+            newLabels.set(newId);
+        }
     }
+
+    labels.transfer(newLabels);
 }
 
 
-void Foam::topoSet::check(const label maxLabel)
+void Foam::topoSet::check(const label maxSize)
 {
     const labelHashSet& labels = *this;
 
     for (const label oldId : labels)
     {
-        if (oldId < 0 || oldId > maxLabel)
+        if (oldId < 0 || oldId >= maxSize)
         {
             FatalErrorInFunction
                 << "Illegal content " << oldId << " of set:" << name()
                 << " of type " << type() << nl
-                << "Value should be between [0," << maxLabel << ']'
+                << "Value should be between [0," << maxSize << ')'
+                << endl
                 << abort(FatalError);
         }
     }
diff --git a/src/meshTools/sets/topoSets/topoSet.H b/src/meshTools/sets/topoSets/topoSet.H
index 9a88f13149e..13622d3ed20 100644
--- a/src/meshTools/sets/topoSets/topoSet.H
+++ b/src/meshTools/sets/topoSets/topoSet.H
@@ -70,12 +70,12 @@ protected:
 
     // Protected Member Functions
 
-        //- Update map from map. Used to update cell/face labels
-        //  after morphing
-        void updateLabels(const labelList& map);
+        //- Update map from map.
+        //  Used to update cell/face labels after morphing
+        virtual void updateLabels(const labelUList& map);
 
-        //- Check validity of contents.
-        void check(const label maxLabel);
+        //- Check limits on addressable range.
+        virtual void check(const label maxSize);
 
         //- Write part of contents nicely formatted. Prints labels only.
         void writeDebug
@@ -106,12 +106,6 @@ protected:
         ) const;
 
 
-        //- No copy construct
-        topoSet(const topoSet&) = delete;
-
-
-protected:
-
         //- Helper for constructor - return IOobject in the polyMesh/sets
         static IOobject findIOobject
         (
@@ -131,6 +125,10 @@ protected:
         );
 
 
+        //- No copy construct
+        topoSet(const topoSet&) = delete;
+
+
 public:
 
     //- Runtime type information
-- 
GitLab