diff --git a/applications/test/LabelledItem/Make/files b/applications/test/LabelledItem/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..b01e4b4fe9c964e5206aabe4da55bb09240fc446
--- /dev/null
+++ b/applications/test/LabelledItem/Make/files
@@ -0,0 +1,3 @@
+Test-LabelledItem.C
+
+EXE = $(FOAM_USER_APPBIN)/Test-LabelledItem
diff --git a/applications/test/LabelledItem/Make/options b/applications/test/LabelledItem/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..18e6fe47afacb902cddccf82632772447704fd88
--- /dev/null
+++ b/applications/test/LabelledItem/Make/options
@@ -0,0 +1,2 @@
+/* EXE_INC = */
+/* EXE_LIBS = */
diff --git a/applications/test/LabelledItem/Test-LabelledItem.C b/applications/test/LabelledItem/Test-LabelledItem.C
new file mode 100644
index 0000000000000000000000000000000000000000..79ef7ca46b5274ec2c11f92d78a22454911397ee
--- /dev/null
+++ b/applications/test/LabelledItem/Test-LabelledItem.C
@@ -0,0 +1,74 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2021 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Description
+    Test LabelledItem (formerly 'Keyed', but that was never used)
+
+\*---------------------------------------------------------------------------*/
+
+#include "IOstreams.H"
+#include "IOobject.H"
+#include "IFstream.H"
+#include "edge.H"
+#include "LabelledItem.H"
+#include "List.H"
+
+using namespace Foam;
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+// Main program:
+
+int main(int argc, char *argv[])
+{
+    typedef LabelledItem<edge> labelledEdge;
+
+    List<labelledEdge> edges(10);
+
+    forAll(edges, edgei)
+    {
+        auto& e = edges[edgei];
+
+        e.insert(20-edgei);
+        e.insert(edgei);
+
+        if (!(edgei % 3))
+        {
+            e.setIndex(edgei);
+        }
+    }
+
+    Info<< "edges: " << edges << nl;
+
+    Foam::sort(edges);
+
+    Info<< "sorted: " << edges << nl;
+
+    Info<< "\nEnd\n" << endl;
+
+    return 0;
+}
+
+
+// ************************************************************************* //
diff --git a/applications/test/primitivePatch/Test-PrimitivePatch.C b/applications/test/primitivePatch/Test-PrimitivePatch.C
index e53f81b40985cb0f8c1b15c81120f73a1f99447a..86a6b5060cf86e887e72d9de28d0e08453b7a64d 100644
--- a/applications/test/primitivePatch/Test-PrimitivePatch.C
+++ b/applications/test/primitivePatch/Test-PrimitivePatch.C
@@ -244,9 +244,10 @@ int main(int argc, char *argv[])
 
         writeFaceFaces(localPoints, localFaces, faceFaces);
 
-        const labelList bndFaceIds(pp.boundaryFaces());
+        const labelList bndFaceIds(pp.uniqBoundaryFaces());
 
-        Info<< "Have: " << bndFaceIds.size() << " boundary faces" << nl;
+        Info<< "Have: " << bndFaceIds.size()
+            << " unique boundary faces" << nl;
 
         // Can calculate by hand
         if (!pp.hasFaceCentres())
diff --git a/src/OpenFOAM/containers/Identifiers/Keyed/Keyed.H b/src/OpenFOAM/containers/Identifiers/Keyed/Keyed.H
deleted file mode 100644
index e609c2940f3aac9ffd8d4a371f58c3ce3bcf77b5..0000000000000000000000000000000000000000
--- a/src/OpenFOAM/containers/Identifiers/Keyed/Keyed.H
+++ /dev/null
@@ -1,133 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | www.openfoam.com
-     \\/     M anipulation  |
--------------------------------------------------------------------------------
-    Copyright (C) 2011-2016 OpenFOAM Foundation
--------------------------------------------------------------------------------
-License
-    This file is part of OpenFOAM.
-
-    OpenFOAM is free software: you can redistribute it and/or modify it
-    under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
-    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-    for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
-
-Class
-    Foam::Keyed
-
-Description
-    A container with an integer key attached to any item.
-
-    The key can useful for sorting.
-
-SourceFiles
-    KeyedI.H
-
-\*---------------------------------------------------------------------------*/
-
-#ifndef Keyed_H
-#define Keyed_H
-
-#include "List.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-namespace Foam
-{
-
-// Forward declaration of friend functions and operators
-
-template<class T> class Keyed;
-
-template<class T> Istream& operator>>(Istream&, Keyed<T>&);
-template<class T> Ostream& operator<<(Ostream&, const Keyed<T>&);
-
-/*---------------------------------------------------------------------------*\
-                       Class Keyed Declaration
-\*---------------------------------------------------------------------------*/
-
-template<class T>
-class Keyed
-:
-    public T
-{
-    // Private data
-
-        label key_;
-
-public:
-
-    // Static Members
-
-        //- Add labels to a list of values
-        inline static List<Keyed<T>> createList
-        (
-            const UList<T>& lst,
-            const label key=0
-        );
-
-        //- Add labels to a list of values
-        inline static List<Keyed<T>> createList
-        (
-            const UList<T>& lst,
-            const labelUList& keys
-        );
-
-
-    // Constructors
-
-        //- Construct null
-        inline Keyed();
-
-        //- Copy construct item, with a key
-        inline Keyed(const T& item, const label key=0);
-
-        //- Move construct item, with a key
-        inline Keyed(T&& item, const label key=0);
-
-        //- Construct from Istream
-        inline Keyed(Istream& is);
-
-
-    // Member Functions
-
-        // Access
-
-            //- Return const access to the integer key
-            inline label key() const;
-
-            //- Return non-const access to the integer key
-            inline label& key();
-
-
-    // IOstream Operators
-
-        friend Istream& operator>> <T>(Istream&, Keyed<T>&);
-        friend Ostream& operator<< <T>(Ostream&, const Keyed<T>&);
-};
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-} // End namespace Foam
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#include "KeyedI.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#endif
-
-// ************************************************************************* //
diff --git a/src/OpenFOAM/containers/Identifiers/Keyed/KeyedI.H b/src/OpenFOAM/containers/Identifiers/Keyed/KeyedI.H
deleted file mode 100644
index 93aca20ed85c7cc518a2699a51515ad0e8d2385e..0000000000000000000000000000000000000000
--- a/src/OpenFOAM/containers/Identifiers/Keyed/KeyedI.H
+++ /dev/null
@@ -1,139 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | www.openfoam.com
-     \\/     M anipulation  |
--------------------------------------------------------------------------------
-    Copyright (C) 2011-2016 OpenFOAM Foundation
--------------------------------------------------------------------------------
-License
-    This file is part of OpenFOAM.
-
-    OpenFOAM is free software: you can redistribute it and/or modify it
-    under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
-    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-    for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
-
-\*---------------------------------------------------------------------------*/
-
-#include "IOstreams.H"
-
-// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
-
-template<class T>
-inline Foam::Keyed<T>::Keyed()
-:
-    key_(-1)
-{}
-
-
-template<class T>
-inline Foam::Keyed<T>::Keyed(const T& item, const label key)
-:
-    T(item),
-    key_(key)
-{}
-
-
-template<class T>
-inline Foam::Keyed<T>::Keyed(T&& item, const label key)
-:
-    T(std::move(item)),
-    key_(key)
-{}
-
-
-template<class T>
-inline Foam::Keyed<T>::Keyed(Istream& is)
-{
-    is >> *this;
-}
-
-
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
-
-template<class T>
-inline Foam::label Foam::Keyed<T>::key() const
-{
-    return key_;
-}
-
-template<class T>
-inline Foam::label& Foam::Keyed<T>::key()
-{
-    return key_;
-}
-
-
-template<class T>
-inline Foam::List<Foam::Keyed<T>>
-Foam::Keyed<T>::createList(const UList<T>& lst, const label key)
-{
-    List<Keyed<T>> newList(lst.size());
-
-    forAll(lst, elemI)
-    {
-        newList[elemI] = Keyed(lst[elemI], key);
-    }
-    return newList;
-}
-
-
-template<class T>
-inline Foam::List<Foam::Keyed<T>>
-Foam::Keyed<T>::createList(const UList<T>& lst, const labelUList& keys)
-{
-    if (lst.size() != keys.size())
-    {
-        FatalErrorInFunction
-            << "size mismatch adding keys to a list:" << nl
-            << "List has size " << lst.size()
-            << " and keys has size " << keys.size() << nl
-            << abort(FatalError);
-    }
-
-    List<Keyed<T>> newList(lst.size());
-
-    forAll(lst, elemI)
-    {
-        newList[elemI] = Keyed(lst[elemI], keys[elemI]);
-    }
-    return newList;
-}
-
-
-// * * * * * * * * * * * * * * * Ostream Operator  * * * * * * * * * * * * * //
-
-template<class T>
-inline Foam::Istream& Foam::operator>>(Istream& is, Keyed<T>& item)
-{
-    is.readBegin("Keyed");
-    is >> static_cast<T&>(item) >> item.key_;
-    is.readEnd("Keyed");
-
-    is.check(FUNCTION_NAME);
-    return is;
-}
-
-
-template<class T>
-inline Foam::Ostream& Foam::operator<<(Ostream& os, const Keyed<T>& item)
-{
-    os  << token::BEGIN_LIST
-        << static_cast<const T&>(item) << token::SPACE << item.key_
-        << token::END_LIST;
-
-    return os;
-}
-
-
-// ************************************************************************* //
diff --git a/src/OpenFOAM/containers/Identifiers/LabelledItem/LabelledItem.H b/src/OpenFOAM/containers/Identifiers/LabelledItem/LabelledItem.H
new file mode 100644
index 0000000000000000000000000000000000000000..6d9fc1429591d9669d318ed1013cb7c6abb0a5e8
--- /dev/null
+++ b/src/OpenFOAM/containers/Identifiers/LabelledItem/LabelledItem.H
@@ -0,0 +1,172 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2011 OpenFOAM Foundation
+    Copyright (C) 2021 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::LabelledItem
+
+Description
+    A container with an integer index that can be attached to any item.
+    The index may be useful for sorting or storing additional information.
+
+SeeAlso
+    Foam::objectHit
+    Foam::PointIndexHit
+
+SourceFiles
+    LabelledItemI.H
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef LabelledItem_H
+#define LabelledItem_H
+
+#include "label.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Forward Declarations
+template<class T> class LabelledItem;
+template<class T> Istream& operator>>(Istream&, LabelledItem<T>&);
+template<class T> Ostream& operator<<(Ostream&, const LabelledItem<T>&);
+
+/*---------------------------------------------------------------------------*\
+                        Class LabelledItem Declaration
+\*---------------------------------------------------------------------------*/
+
+template<class T>
+class LabelledItem
+:
+    public T
+{
+    // Private Data
+
+        //- The object index
+        label index_;
+
+
+public:
+
+
+    // Constructors
+
+        //- Default construct item, with index = -1
+        LabelledItem()
+        :
+            T(),
+            index_(-1)
+        {}
+
+        //- Copy construct item, with index = -1
+        explicit LabelledItem(const T& item)
+        :
+            T(item),
+            index_(-1)
+        {}
+
+        //- Move construct item, with index = -1
+        explicit LabelledItem(T&& item)
+        :
+            T(std::move(item)),
+            index_(-1)
+        {}
+
+        //- Construct from components
+        LabelledItem(const T& item, label idx)
+        :
+            T(item),
+            index_(idx)
+        {}
+
+        //- Construct from Istream
+        explicit LabelledItem(Istream& is)
+        {
+            is >> *this;
+        }
+
+
+    // Member Functions
+
+        //- Return the index
+        label index() const noexcept
+        {
+            return index_;
+        }
+
+        //- Non-const access to the index
+        label& index() noexcept
+        {
+            return index_;
+        }
+
+        //- Set the index
+        void setIndex(const label idx) noexcept
+        {
+            index_ = idx;
+        }
+
+
+    // Member Operators
+
+        //- Test for equality of components
+        bool operator==(const LabelledItem<T>& rhs) const
+        {
+            return
+            (
+                index_ == rhs.index_
+             && static_cast<const T&>(*this) == static_cast<const T&>(rhs)
+            );
+        }
+
+        //- Test for inequality of components
+        bool operator!=(const LabelledItem<T>& rhs) const
+        {
+            return !(*this == rhs);
+        }
+
+
+    // IOstream Operators
+
+        friend Istream& operator>> <T>(Istream&, LabelledItem<T>&);
+        friend Ostream& operator<< <T>(Ostream&, const LabelledItem<T>&);
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#include "LabelledItemI.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/containers/Identifiers/LabelledItem/LabelledItemI.H b/src/OpenFOAM/containers/Identifiers/LabelledItem/LabelledItemI.H
new file mode 100644
index 0000000000000000000000000000000000000000..d4061413acacda8c93eb17c2194a1bad3fa8c732
--- /dev/null
+++ b/src/OpenFOAM/containers/Identifiers/LabelledItem/LabelledItemI.H
@@ -0,0 +1,66 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2011 OpenFOAM Foundation
+    Copyright (C) 2021 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "IOstreams.H"
+
+// * * * * * * * * * * * * * * * IOstream Operators  * * * * * * * * * * * * //
+
+template<class T>
+inline Foam::Istream& Foam::operator>>
+(
+    Istream& is,
+    LabelledItem<T>& item
+)
+{
+    is.readBegin("LabelledItem");
+    is >> static_cast<T&>(item) >> item.index();
+    is.readEnd("LabelledItem");
+
+    is.check(FUNCTION_NAME);
+    return is;
+}
+
+
+template<class T>
+inline Foam::Ostream& Foam::operator<<
+(
+    Ostream& os,
+    const LabelledItem<T>& item
+)
+{
+    // Output like Tuple2
+    os  << token::BEGIN_LIST
+        << static_cast<const T&>(item) << token::SPACE
+        << item.index()
+        << token::END_LIST;
+
+    return os;
+}
+
+
+// ************************************************************************* //
diff --git a/src/OpenFOAM/meshes/meshShapes/labelledTri/labelledTri.H b/src/OpenFOAM/meshes/meshShapes/labelledTri/labelledTri.H
index 0d0f20985b91de00a9395e256361039a4c401000..4ce38cc5a02219c679da9c8ea33ac575ca0cfc20 100644
--- a/src/OpenFOAM/meshes/meshShapes/labelledTri/labelledTri.H
+++ b/src/OpenFOAM/meshes/meshShapes/labelledTri/labelledTri.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2016-2019 OpenCFD Ltd.
+    Copyright (C) 2016-2021 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -28,7 +28,7 @@ Class
     Foam::labelledTri
 
 Description
-    Triangle with additional region number.
+    A triFace with additional (region) index.
 
 SourceFiles
     labelledTriI.H
@@ -52,7 +52,7 @@ inline Istream& operator>>(Istream&, labelledTri&);
 inline Ostream& operator<<(Ostream&, const labelledTri&);
 
 /*---------------------------------------------------------------------------*\
-                           Class labelledTri Declaration
+                         Class labelledTri Declaration
 \*---------------------------------------------------------------------------*/
 
 class labelledTri
@@ -61,14 +61,16 @@ class labelledTri
 {
     // Private Data
 
-        label region_;
+        //- The object index (region)
+        label index_;
 
 
     // Private Member Functions
 
-        //- Assign from a list of 3 or 4 labels.
-        //  Default region is 0.
-        inline void assign(const labelUList&);
+        //- Assign from 3 or 4 labels, default region is 0.
+        template<class ListType>
+        inline void assignList(const ListType& list);
+
 
 public:
 
@@ -77,16 +79,16 @@ public:
         //- Default construct, with invalid point labels and region (-1).
         inline labelledTri();
 
-        //- Construct from triFace and region label.
-        //  Default region is 0 if not specified.
+        //- Construct from triFace
+        //- and optional region index (0 if unspecified)
         inline labelledTri
         (
-            const triFace&,
+            const triFace& tri,
             const label region = 0
         );
 
-        //- Construct from three point labels and a region label.
-        //  Default region is 0 if not specified.
+        //- Construct from three point labels
+        //- and optional region index (0 if unspecified)
         inline labelledTri
         (
             const label a,
@@ -95,26 +97,47 @@ public:
             const label region = 0
         );
 
-        //- Construct from a list of 3 or 4 labels.
-        //  Default region is 0.
-        inline explicit labelledTri(const labelUList&);
+        //- Construct from a list of 3 or 4 labels. Default region is 0.
+        inline explicit labelledTri(const labelUList& list);
 
-        //- Construct from an initializer list of 3 or 4 labels.
+        //- Construct from a list of 3 or 4 labels. Default region is 0.
         inline explicit labelledTri(std::initializer_list<label>);
 
         //- Construct from Istream
-        inline labelledTri(Istream&);
+        inline labelledTri(Istream& is);
 
 
     // Member Functions
 
-        // Access
+        //- Return the index (eg, the region)
+        label index() const noexcept
+        {
+            return index_;
+        }
 
-            //- Return region label
-            inline label region() const;
+        //- Non-const access to the index (eg, the region)
+        label& index() noexcept
+        {
+            return index_;
+        }
 
-            //- Return region label
-            inline label& region();
+        //- Set the index (eg, the region)
+        void setIndex(const label idx) noexcept
+        {
+            index_ = idx;
+        }
+
+        //- Return the region index
+        label region() const noexcept
+        {
+            return index_;
+        }
+
+        //- Non-const access to the region index
+        label& region() noexcept
+        {
+            return index_;
+        }
 
 
     // IOstream Operators
@@ -137,17 +160,13 @@ template<> struct is_contiguous_label<labelledTri> : std::true_type {};
 template<>
 struct offsetOp<labelledTri>
 {
-    inline labelledTri operator()
-    (
-        const labelledTri& x,
-        const label offset
-    ) const
+    labelledTri operator()(const labelledTri& x, const label offset) const
     {
         labelledTri result(x);
 
-        forAll(x, xI)
+        forAll(x, xi)
         {
-            result[xI] = x[xI] + offset;
+            result[xi] = x[xi] + offset;
         }
         return result;
     }
diff --git a/src/OpenFOAM/meshes/meshShapes/labelledTri/labelledTriI.H b/src/OpenFOAM/meshes/meshShapes/labelledTri/labelledTriI.H
index dbeaf90d33152848506f41e75af0a63c6b749830..0d9af81586bee33a5a410a6bda7fc5f1119ef738 100644
--- a/src/OpenFOAM/meshes/meshShapes/labelledTri/labelledTriI.H
+++ b/src/OpenFOAM/meshes/meshShapes/labelledTri/labelledTriI.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011 OpenFOAM Foundation
-    Copyright (C) 2016 OpenCFD Ltd.
+    Copyright (C) 2016-2021 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -30,24 +30,28 @@ License
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
-inline void Foam::labelledTri::assign(const labelUList& lst)
+template<class ListType>
+inline void Foam::labelledTri::assignList(const ListType& list)
 {
-    const label sz = lst.size();
+    const label len = list.size();
 
     // checkSize
-    if (sz < 3 || sz > 4)
+    if (len < 3 || len > 4)
     {
          FatalErrorInFunction
-            << "size " << sz << " != (3 or 4)"
+            << "size " << len << " != (3 or 4)"
             << abort(FatalError);
     }
 
+    auto iter = list.begin();
+
     for (label i=0; i<3; ++i)
     {
-        operator[](i) = lst[i];
+        this->operator[](i) = *iter;
+        ++iter;
     }
 
-    region_ = (sz > 3 ? lst[3] : 0);
+    index_ = (len == 4) ? *iter : 0;
 }
 
 
@@ -56,7 +60,7 @@ inline void Foam::labelledTri::assign(const labelUList& lst)
 inline Foam::labelledTri::labelledTri()
 :
     triFace(),
-    region_(-1)
+    index_(-1)
 {}
 
 
@@ -67,7 +71,7 @@ inline Foam::labelledTri::labelledTri
 )
 :
     triFace(tri),
-    region_(region)
+    index_(region)
 {}
 
 
@@ -80,25 +84,25 @@ inline Foam::labelledTri::labelledTri
 )
 :
     triFace(a, b, c),
-    region_(region)
+    index_(region)
 {}
 
 
-inline Foam::labelledTri::labelledTri(const labelUList& lst)
+inline Foam::labelledTri::labelledTri(const labelUList& list)
 :
     triFace(),
-    region_(0)
+    index_(0)
 {
-    assign(lst);
+    assignList(list);
 }
 
 
-inline Foam::labelledTri::labelledTri(std::initializer_list<label> initLst)
+inline Foam::labelledTri::labelledTri(std::initializer_list<label> list)
 :
     triFace(),
-    region_(0)
+    index_(0)
 {
-    assign(labelList(initLst));
+    assignList(list);
 }
 
 
@@ -108,19 +112,6 @@ inline Foam::labelledTri::labelledTri(Istream& is)
 }
 
 
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
-
-inline Foam::label Foam::labelledTri::region() const
-{
-    return region_;
-}
-
-inline Foam::label& Foam::labelledTri::region()
-{
-    return region_;
-}
-
-
 // * * * * * * * * * * * * * * * Ostream Operator  * * * * * * * * * * * * * //
 
 inline Foam::Istream& Foam::operator>>(Istream& is, labelledTri& t)
@@ -129,7 +120,7 @@ inline Foam::Istream& Foam::operator>>(Istream& is, labelledTri& t)
     {
         is.readBegin("labelledTri");
 
-        is  >> static_cast<triFace&>(t) >> t.region_;
+        is  >> static_cast<triFace&>(t) >> t.index();
 
         is.readEnd("labelledTri");
     }
@@ -153,7 +144,7 @@ inline Foam::Ostream& Foam::operator<<(Ostream& os, const labelledTri& t)
     if (os.format() == IOstream::ASCII)
     {
         os  << token::BEGIN_LIST
-            << static_cast<const triFace&>(t) << token::SPACE << t.region_
+            << static_cast<const triFace&>(t) << token::SPACE << t.index()
             << token::END_LIST;
     }
     else
diff --git a/src/OpenFOAM/meshes/primitiveMesh/PatchTools/PatchToolsMatch.C b/src/OpenFOAM/meshes/primitiveMesh/PatchTools/PatchToolsMatch.C
index fc32a55b05d1bca8ee8f31ad0312cbd2fd9e3594..115832ff977d849efdd114a70dc2e1e74d875f0d 100644
--- a/src/OpenFOAM/meshes/primitiveMesh/PatchTools/PatchToolsMatch.C
+++ b/src/OpenFOAM/meshes/primitiveMesh/PatchTools/PatchToolsMatch.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2019-2020 OpenCFD Ltd.
+    Copyright (C) 2019-2021 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -44,8 +44,8 @@ void Foam::PatchTools::matchPoints
     labelList& p2PointLabels
 )
 {
-    p1PointLabels.setSize(p1.nPoints());
-    p2PointLabels.setSize(p1.nPoints());
+    p1PointLabels.resize(p1.nPoints());
+    p2PointLabels.resize(p1.nPoints());
 
     label nMatches = 0;
 
@@ -59,11 +59,12 @@ void Foam::PatchTools::matchPoints
         {
             p1PointLabels[nMatches] = pointi;
             p2PointLabels[nMatches] = iter.val();
-            nMatches++;
+            ++nMatches;
         }
     }
-    p1PointLabels.setSize(nMatches);
-    p2PointLabels.setSize(nMatches);
+
+    p1PointLabels.resize(nMatches);
+    p2PointLabels.resize(nMatches);
 }
 
 
@@ -82,43 +83,38 @@ void Foam::PatchTools::matchEdges
     bitSet& sameOrientation
 )
 {
-    p1EdgeLabels.setSize(p1.nEdges());
-    p2EdgeLabels.setSize(p1.nEdges());
-    sameOrientation.setSize(p1.nEdges());
+    p1EdgeLabels.resize(p1.nEdges());
+    p2EdgeLabels.resize(p1.nEdges());
+    sameOrientation.resize(p1.nEdges());
     sameOrientation = false;
 
     label nMatches = 0;
 
     EdgeMap<label> edgeToIndex(2*p1.nEdges());
-    forAll(p1.edges(), edgeI)
+    forAll(p1.edges(), edgei)
     {
-        const edge& e = p1.edges()[edgeI];
-        const edge meshE
-        (
-            p1.meshPoints()[e[0]],
-            p1.meshPoints()[e[1]]
-        );
-        edgeToIndex.insert(meshE, edgeI);
+        // Map lookup with globalEdge
+        edgeToIndex.insert(p1.meshEdge(edgei), edgei);
     }
 
-    forAll(p2.edges(), edgeI)
+    forAll(p2.edges(), edgei)
     {
-        const edge& e = p2.edges()[edgeI];
-        const edge meshE(p2.meshPoints()[e[0]], p2.meshPoints()[e[1]]);
+        const edge meshEdge2(p2.meshEdge(edgei));
 
-        const auto iter = edgeToIndex.cfind(meshE);
+        const auto iter = edgeToIndex.cfind(meshEdge2);
 
         if (iter.found())
         {
             p1EdgeLabels[nMatches] = iter.val();
-            p2EdgeLabels[nMatches] = edgeI;
-            sameOrientation.set(nMatches, (meshE[0] == iter.key()[0]));
+            p2EdgeLabels[nMatches] = edgei;
+            sameOrientation.set(nMatches, (meshEdge2[0] == iter.key()[0]));
             ++nMatches;
         }
     }
-    p1EdgeLabels.setSize(nMatches);
-    p2EdgeLabels.setSize(nMatches);
-    sameOrientation.setSize(nMatches);
+
+    p1EdgeLabels.resize(nMatches);
+    p2EdgeLabels.resize(nMatches);
+    sameOrientation.resize(nMatches);
 }
 
 
diff --git a/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatch.H b/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatch.H
index e05ed53e468db403c947e0dca2cec08e6d1b9abe..ef0b045a134c34289da466d03e3874013791d8b0 100644
--- a/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatch.H
+++ b/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatch.H
@@ -367,10 +367,14 @@ public:
             //- Return patch faces addressing into local point list
             const List<face_type>& localFaces() const;
 
-            //- Calculate and return list of local boundary faces.
-            //  These are the faces attached to boundary edges.
+            //- Extract list of local faces corresponding to
+            //- the boundary edges.
             labelList boundaryFaces() const;
 
+            //- Extract sorted list of unique local faces associated with
+            //- the boundary edges.
+            labelList uniqBoundaryFaces() const;
+
 
         // Addressing into mesh
 
@@ -393,9 +397,15 @@ public:
             //  If the point is not found, return -1
             label whichPoint(const label gp) const;
 
-            //- Given an edge in local point labels, return its
-            //- index in the edge list.  If the edge is not found, return -1
-            label whichEdge(const edge& e) const;
+            //- Return local edge in terms of the mesh points in patch.
+            edge meshEdge(const label edgei) const;
+
+            //- Return local edge in terms of the mesh points in patch.
+            edge meshEdge(const edge& e) const;
+
+            //- Search for edge (local point labels) and return its
+            //- index in the edge list or -1 if not found.
+            label findEdge(const edge& e) const;
 
             //- Return labels of patch edges in the global edge list using
             //- cell addressing
@@ -406,7 +416,7 @@ public:
                 const labelList& faceCells
             ) const;
 
-            //- Return labels of patch edges in the global edge list using
+            //- Return labels of patch edges into the global edge list using
             //- basic edge addressing.
             labelList meshEdges
             (
@@ -414,6 +424,25 @@ public:
                 const labelListList& pointEdges
             ) const;
 
+            //- Return label of the local patch edge
+            //- into the global edge list using basic edge addressing.
+            label meshEdge
+            (
+                const label edgei,
+                const edgeList& allEdges,
+                const labelListList& pointEdges
+            ) const;
+
+            //- Return labels of specified patch edges
+            //- into the global edge list using basic edge addressing.
+            labelList meshEdges
+            (
+                const labelUList& edgeLabels,
+                const edgeList& allEdges,
+                const labelListList& pointEdges
+            ) const;
+
+
             //- Return face centres for patch
             const Field<point_type>& faceCentres() const;
 
@@ -510,6 +539,12 @@ public:
 
         //- Move assign faces. Leave points alone (could be a reference).
         void operator=(PrimitivePatch<FaceList, PointField>&& rhs);
+
+
+    // Housekeeping
+
+        //- Identical to findEdge
+        label whichEdge(const edge& e) const { return this->findEdge(e); }
 };
 
 
diff --git a/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatchBdryFaces.C b/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatchBdryFaces.C
index 61bba9d782f2f467de38305f636eb9c12e2be968..2d866ce633e92787cc0402b63f38898fc7e7e0be 100644
--- a/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatchBdryFaces.C
+++ b/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatchBdryFaces.C
@@ -26,27 +26,62 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "PrimitivePatch.H"
-#include "HashSet.H"
 
-// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 template<class FaceList, class PointField>
 Foam::labelList
 Foam::PrimitivePatch<FaceList, PointField>::boundaryFaces() const
 {
-    // By definition boundary edges have a _single_ face attached,
-    // but a face can easily have multiple boundary edges.
+    labelList bndFaces(nBoundaryEdges());
 
-    const labelListList& edgeToFace = edgeFaces();
+    // The boundary slice
+    const SubList<labelList> bndEdgeToFace
+    (
+        edgeFaces(),
+        bndFaces.size(),
+        nInternalEdges()
+    );
 
-    labelHashSet bndFaces(2*nBoundaryEdges());
+    // By definition boundary edges have a _single_ face attached
+    forAll(bndFaces, i)
+    {
+        bndFaces[i] = bndEdgeToFace[i][0];
+    }
+
+    return bndFaces;
+}
 
-    for (label edgei = nInternalEdges(); edgei < edgeToFace.size(); ++edgei)
+
+template<class FaceList, class PointField>
+Foam::labelList
+Foam::PrimitivePatch<FaceList, PointField>::uniqBoundaryFaces() const
+{
+    labelList bndFaces(this->boundaryFaces());
+
+    const label len = bndFaces.size();
+
+    if (len > 1)
     {
-        bndFaces.insert(edgeToFace[edgei][0]);
+        Foam::sort(bndFaces);
+
+        label prev = bndFaces[0];
+        label nUniq = 1;
+
+        for (label i=1; i < len; ++i)
+        {
+            if (prev != bndFaces[i])
+            {
+                prev = bndFaces[i];
+                bndFaces[nUniq] = prev;
+                ++nUniq;
+            }
+        }
+
+        bndFaces.resize(nUniq);
     }
 
-    return bndFaces.sortedToc();
+    return bndFaces;
 }
 
 
diff --git a/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatchMeshEdges.C b/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatchMeshEdges.C
index cf1a5af2fdc9a442d24052f842fd92d281dd08a1..43442748f810ab6d93852fa98f48daa7b2da21df 100644
--- a/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatchMeshEdges.C
+++ b/src/OpenFOAM/meshes/primitiveMesh/PrimitivePatch/PrimitivePatchMeshEdges.C
@@ -28,7 +28,23 @@ License
 
 #include "PrimitivePatch.H"
 
-// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+template<class FaceList, class PointField>
+Foam::edge
+Foam::PrimitivePatch<FaceList, PointField>::meshEdge(const label edgei) const
+{
+    return Foam::edge(this->meshPoints(), this->edges()[edgei]);
+}
+
+
+template<class FaceList, class PointField>
+Foam::edge
+Foam::PrimitivePatch<FaceList, PointField>::meshEdge(const edge& e) const
+{
+    return Foam::edge(this->meshPoints(), e);
+}
+
 
 template<class FaceList, class PointField>
 Foam::labelList
@@ -43,24 +59,18 @@ meshEdges
     DebugInFunction
         << "Calculating labels of patch edges in mesh edge list" << nl;
 
-    // The list of edges on the patch
-    const edgeList& PatchEdges = edges();
-
     // The output storage
-    labelList meshEdges(PatchEdges.size());
+    labelList meshEdgeLabels(this->nEdges());
 
     const labelListList& EdgeFaces = edgeFaces();
 
-    // The mesh points associated with the patch
-    const labelList& pp = meshPoints();
-
     // WARNING: Remember that local edges address into local point list;
     // local-to-global point label translation is necessary
-    forAll(PatchEdges, edgei)
+    forAll(meshEdgeLabels, edgei)
     {
-        bool found = false;
+        const edge globalEdge(this->meshEdge(edgei));
 
-        const edge globalEdge(pp, PatchEdges[edgei]);
+        bool found = false;
 
         // For each patch face sharing the edge
         for (const label patchFacei : EdgeFaces[edgei])
@@ -74,7 +84,7 @@ meshEdges
                 if (allEdges[cellEdgei] == globalEdge)
                 {
                     found = true;
-                    meshEdges[edgei] = cellEdgei;
+                    meshEdgeLabels[edgei] = cellEdgei;
                     break;
                 }
             }
@@ -83,7 +93,7 @@ meshEdges
         }
     }
 
-    return meshEdges;
+    return meshEdgeLabels;
 }
 
 
@@ -98,41 +108,78 @@ Foam::PrimitivePatch<FaceList, PointField>::meshEdges
     DebugInFunction
         << "Calculating labels of patch edges in mesh edge list" << nl;
 
-    // The list of edges on the patch
-    const edgeList& PatchEdges = edges();
-
-    // The output storage
-    labelList meshEdges(PatchEdges.size());
-
-    // The mesh points associated with the patch
-    const labelList& pp = meshPoints();
+    labelList meshEdgeLabels(this->nEdges());
 
     // WARNING: Remember that local edges address into local point list;
     // local-to-global point label translation is necessary
-    forAll(PatchEdges, edgei)
+    forAll(meshEdgeLabels, edgei)
     {
-        const edge globalEdge(pp, PatchEdges[edgei]);
+        const edge globalEdge(this->meshEdge(edgei));
 
         // Check the attached edges
-        for (const label patchEdgei : pointEdges[globalEdge.start()])
+        for (const label meshEdgei : pointEdges[globalEdge.start()])
         {
-            if (allEdges[patchEdgei] == globalEdge)
+            if (allEdges[meshEdgei] == globalEdge)
             {
-                meshEdges[edgei] = patchEdgei;
+                meshEdgeLabels[edgei] = meshEdgei;
                 break;
             }
         }
     }
 
-    return meshEdges;
+    return meshEdgeLabels;
 }
 
 
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+template<class FaceList, class PointField>
+Foam::label
+Foam::PrimitivePatch<FaceList, PointField>::meshEdge
+(
+    const label edgei,
+    const edgeList& allEdges,
+    const labelListList& pointEdges
+) const
+{
+    // Need local-to-global point label translation
+    const edge globalEdge(this->meshEdge(edgei));
+
+    // Check attached edges
+    for (const label meshEdgei : pointEdges[globalEdge.start()])
+    {
+        if (allEdges[meshEdgei] == globalEdge)
+        {
+            return meshEdgei;
+        }
+    }
+
+    return -1;
+}
+
+
+template<class FaceList, class PointField>
+Foam::labelList
+Foam::PrimitivePatch<FaceList, PointField>::meshEdges
+(
+    const labelUList& edgeLabels,
+    const edgeList& allEdges,
+    const labelListList& pointEdges
+) const
+{
+    labelList meshEdgeLabels(edgeLabels.size());
+
+    forAll(meshEdgeLabels, edgei)
+    {
+        meshEdgeLabels[edgei] =
+            this->meshEdge(edgeLabels[edgei], allEdges, pointEdges);
+    }
+
+    return meshEdgeLabels;
+}
+
 
 template<class FaceList, class PointField>
 Foam::label
-Foam::PrimitivePatch<FaceList, PointField>::whichEdge
+Foam::PrimitivePatch<FaceList, PointField>::findEdge
 (
     const edge& e
 ) const
@@ -140,19 +187,18 @@ Foam::PrimitivePatch<FaceList, PointField>::whichEdge
     if (e.start() >= 0 && e.start() < nPoints())
     {
         // Get pointEdges from the starting point and search all the candidates
-        const edgeList& Edges = edges();
+        const edgeList& myEdges = this->edges();
 
         for (const label patchEdgei : pointEdges()[e.start()])
         {
-            if (e == Edges[patchEdgei])
+            if (e == myEdges[patchEdgei])
             {
                 return patchEdgei;
             }
         }
     }
 
-    // Edge not found.  Return -1
-    return -1;
+    return -1;  // Not found
 }
 
 
diff --git a/src/OpenFOAM/meshes/primitiveShapes/objectHit/PointIndexHit.H b/src/OpenFOAM/meshes/primitiveShapes/objectHit/PointIndexHit.H
index 7337b865479177602a2e6ea53c2787153cb72424..5afe8a88dbecf80974fe75ffae662747792dde81 100644
--- a/src/OpenFOAM/meshes/primitiveShapes/objectHit/PointIndexHit.H
+++ b/src/OpenFOAM/meshes/primitiveShapes/objectHit/PointIndexHit.H
@@ -243,7 +243,7 @@ public:
              && index_ == rhs.index_
              && point_ == rhs.point_
             );
-         }
+        }
 
         //- Test for inequality of components
         bool operator!=(const PointIndexHit& rhs) const