diff --git a/applications/test/searchableSphere/Make/files b/applications/test/searchableSphere/Make/files
new file mode 100644
index 0000000000000000000000000000000000000000..6f2f01cd45ff11d3f0cb4e24bf0d4ece52540a2b
--- /dev/null
+++ b/applications/test/searchableSphere/Make/files
@@ -0,0 +1,3 @@
+Test-searchableSphere.C
+
+EXE = $(FOAM_USER_APPBIN)/Test-searchableSphere
diff --git a/applications/test/searchableSphere/Make/options b/applications/test/searchableSphere/Make/options
new file mode 100644
index 0000000000000000000000000000000000000000..b6fa4bff167cc416f0bfb0c78dac3c09cfeb2799
--- /dev/null
+++ b/applications/test/searchableSphere/Make/options
@@ -0,0 +1,9 @@
+EXE_INC = \
+    -I$(LIB_SRC)/fileFormats/lnInclude \
+    -I$(LIB_SRC)/surfMesh/lnInclude \
+    -I$(LIB_SRC)/meshTools/lnInclude
+
+EXE_LIBS = \
+    -lfileFormats \
+    -lsurfMesh \
+    -lmeshTools
diff --git a/applications/test/searchableSphere/Test-searchableSphere.C b/applications/test/searchableSphere/Test-searchableSphere.C
new file mode 100644
index 0000000000000000000000000000000000000000..5522aa5457e1c769240bfa195c1e0b74b16d883d
--- /dev/null
+++ b/applications/test/searchableSphere/Test-searchableSphere.C
@@ -0,0 +1,226 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2020 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/>.
+
+Application
+    Test-searchableSphere
+
+Description
+    Basic tests for searchable sphere
+
+\*---------------------------------------------------------------------------*/
+
+#include "argList.H"
+#include "Time.H"
+#include "searchableSphere.H"
+#include "unitConversion.H"
+#include "Random.H"
+
+using namespace Foam;
+using namespace Foam::constant::mathematical;
+
+//- Evaluate using implicit form of the spheroid equation.
+scalar evaluate(const point& p, const searchableSphere& sph)
+{
+    return
+    (
+        sqr((p.x() - sph.centre().x()) / sph.radii().x())
+      + sqr((p.y() - sph.centre().y()) / sph.radii().y())
+      + sqr((p.z() - sph.centre().z()) / sph.radii().z())
+    );
+}
+
+
+void doTest1(const searchableSphere& sph)
+{
+    Info<< nl << "origin:" << sph.centre() << " radius:" << sph.radius();
+
+    if (sph.shape() == searchableSphere::SPHERE)
+    {
+        Info<< " [sphere]" << nl;
+    }
+    else
+    {
+        Info<< " radii:" << sph.radii() << nl;
+    }
+
+//     boundBox bb(point(0, 0, 0), point(30, 30, 30));
+//     Info<< "overlaps: " << Switch(sph.overlaps(bb)) << endl;
+
+    Pair<scalar> angles(-pi/2, pi/2);
+
+    point surfPt = sph.surfacePoint(angles.first(), angles.second());
+    vector norm = sph.surfaceNormal(angles.first(), angles.second());
+
+    Info<< "point at ("
+        << radToDeg(angles.first()) << ' '
+        << radToDeg(angles.second()) << ") deg" << nl;
+
+    Info<< "surface" << nl
+        << "    eval: " << evaluate(surfPt, sph) << nl
+        << "   point:" << surfPt << nl
+        << "  normal:" << norm << nl;
+
+    {
+        List<pointIndexHit> hits(1);
+        vectorField norms;
+
+        hits[0].hitPoint(surfPt, 0);
+
+        sph.getNormal(hits, norms);
+
+        Info<< "  normal:" << norms[0] << nl;
+    }
+
+
+    Random rndGen;
+
+    point testPt1 =
+    (
+        surfPt + 0.1*sph.radius()*norm
+      + 0.01*rndGen.sample01<vector>()
+    );
+
+
+    // Scale by max radius and shift by origin
+    const auto adjustPoint =
+        [&](point& p) -> void
+        {
+            p *= sph.radius();
+            p += sph.centre();
+        };
+
+
+    List<pointIndexHit> hits;
+    pointField query
+    ({
+        testPt1,
+        point(-2, -2, -2)
+    });
+
+    forAll(query, pointi)
+    {
+        if (pointi) adjustPoint(query[pointi]);
+    }
+
+    sph.findNearest
+    (
+        query,
+        scalarField(query.size(), GREAT),
+        hits
+    );
+
+    Info<< "query:" << nl;
+
+    forAll(hits, pointi)
+    {
+        // Should never miss
+        Info<< "  "
+            << query[pointi] << " => "
+            << hits[pointi].hitPoint() << nl;
+    }
+
+
+    pointField lineBeg
+    ({
+        point(-2, -2, -2),
+        point(0,0,0),
+        point(0,0,0),
+        point(0,0,0)
+    });
+    pointField lineEnd
+    ({
+        point(2, 2, 2),
+        point(2, 0, 0),
+        point(0, 2, 0),
+        point(0, 0, 4)
+    });
+
+    for (point& p : lineBeg)
+    {
+        adjustPoint(p);
+    }
+
+    for (point& p : lineEnd)
+    {
+        adjustPoint(p);
+    }
+
+    sph.findLineAny
+    (
+        lineBeg,
+        lineEnd,
+        hits
+    );
+
+    Info<< "lines:" << nl;
+
+    forAll(hits, pointi)
+    {
+        // Should never miss
+        Info<< "  "
+            << lineBeg[pointi] << " -> "
+            << lineEnd[pointi] << " = "
+            << hits[pointi].hitPoint() << nl;
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+int main(int argc, char *argv[])
+{
+
+    argList::noBanner();
+    #include "setRootCase.H"
+
+    // Use dummy Time for objectRegistry
+    autoPtr<Time> dummyTimePtr(Time::New());
+
+    const IOobject io
+    (
+        "sphere",
+        *dummyTimePtr,
+        IOobject::NO_READ,
+        IOobject::NO_WRITE,
+        false  // do not register
+    );
+
+    Info<< "Testing searchable sphere" << endl;
+
+    doTest1
+    (
+        searchableSphere
+        (
+            io,
+            point(0.5, 0.5, 0.5),
+            scalar(2)
+        )
+    );
+
+    Info<< "\nDone\n" << endl;
+    return 0;
+}
+
+// ************************************************************************* //
diff --git a/src/meshTools/searchableSurfaces/searchableBox/searchableBox.C b/src/meshTools/searchableSurfaces/searchableBox/searchableBox.C
index c453c34618f475ab7807624ed9a3b8c750282f76..0461c3540059a480de5d9adc5fe7c961733eda44 100644
--- a/src/meshTools/searchableSurfaces/searchableBox/searchableBox.C
+++ b/src/meshTools/searchableSurfaces/searchableBox/searchableBox.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2018-2019 OpenCFD Ltd.
+    Copyright (C) 2018-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -77,7 +77,8 @@ void Foam::searchableBox::projectOntoCoordPlane
         FatalErrorInFunction
             << "Point on plane " << planePt
             << " is not on coordinate " << min()[dir]
-            << " nor " << max()[dir] << abort(FatalError);
+            << " nor " << max()[dir] << nl
+            << abort(FatalError);
     }
 }
 
@@ -135,31 +136,26 @@ Foam::pointIndexHit Foam::searchableBox::findNearest
     // using the three near distances. Project onto the nearest plane.
     if (!outside)
     {
-        vector dist(cmptMag(info.rawPoint() - near));
+        const vector dist(cmptMag(info.point() - near));
+
+        direction projNorm(vector::Z);
 
         if (dist.x() < dist.y())
         {
             if (dist.x() < dist.z())
             {
-                // Project onto x plane
-                projectOntoCoordPlane(vector::X, near, info);
-            }
-            else
-            {
-                projectOntoCoordPlane(vector::Z, near, info);
+                projNorm = vector::X;
             }
         }
         else
         {
             if (dist.y() < dist.z())
             {
-                projectOntoCoordPlane(vector::Y, near, info);
-            }
-            else
-            {
-                projectOntoCoordPlane(vector::Z, near, info);
+                projNorm = vector::Y;
             }
         }
+
+        projectOntoCoordPlane(projNorm, near, info);
     }
 
 
@@ -194,7 +190,7 @@ Foam::searchableBox::searchableBox
             << exit(FatalError);
     }
 
-    bounds() = static_cast<boundBox>(*this);
+    bounds() = static_cast<treeBoundBox>(*this);
 }
 
 
@@ -204,19 +200,12 @@ Foam::searchableBox::searchableBox
     const dictionary& dict
 )
 :
-    searchableSurface(io),
-    treeBoundBox(dict.get<point>("min"), dict.get<point>("max"))
-{
-    if (!treeBoundBox::valid())
-    {
-        FatalErrorInFunction
-            << "Illegal bounding box specification : "
-            << static_cast<const treeBoundBox>(*this) << nl
-            << exit(FatalError);
-    }
-
-    bounds() = static_cast<boundBox>(*this);
-}
+    searchableBox
+    (
+        io,
+        treeBoundBox(dict.get<point>("min"), dict.get<point>("max"))
+    )
+{}
 
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
@@ -257,7 +246,7 @@ void Foam::searchableBox::boundingSpheres
 {
     centres.setSize(size());
     radiusSqr.setSize(size());
-    radiusSqr = 0.0;
+    radiusSqr = Zero;
 
     const pointField pts(treeBoundBox::points());
     const faceList& fcs = treeBoundBox::faces;
@@ -527,8 +516,7 @@ void Foam::searchableBox::findLineAll
     const scalarField magSqrDirVec(magSqr(dirVec));
     const vectorField smallVec
     (
-        ROOTSMALL*dirVec
-      + vector(ROOTVSMALL,ROOTVSMALL,ROOTVSMALL)
+        ROOTSMALL*dirVec + vector::uniform(ROOTVSMALL)
     );
 
     forAll(start, pointi)
diff --git a/src/meshTools/searchableSurfaces/searchableBox/searchableBox.H b/src/meshTools/searchableSurfaces/searchableBox/searchableBox.H
index b931fc53c648f0e1ec1b7f6783dc0ce8fb04aeef..c02c7ea6c0ec7bd752694a9176763365ec33f6a4 100644
--- a/src/meshTools/searchableSurfaces/searchableBox/searchableBox.H
+++ b/src/meshTools/searchableSurfaces/searchableBox/searchableBox.H
@@ -33,11 +33,14 @@ Description
     \heading Dictionary parameters
     \table
         Property    | Description                       | Required | Default
-        type        | box / searchableBox               | selector |
+        type        | box                               | selector |
         min         | minimum point for bounding box    | yes   |
         max         | maximum point for bounding box    | yes   |
     \endtable
 
+Note
+    Longer type name : \c searchableBox
+
 SourceFiles
     searchableBox.C
 
@@ -115,6 +118,7 @@ public:
             const dictionary& dict
         );
 
+
     //- Destructor
     virtual ~searchableBox() = default;
 
diff --git a/src/meshTools/searchableSurfaces/searchableCone/searchableCone.C b/src/meshTools/searchableSurfaces/searchableCone/searchableCone.C
index e342b470db9d374aa502e5951775e9f730eb566d..321f5d6a386505c803b62ad988b0ae405263cd85 100644
--- a/src/meshTools/searchableSurfaces/searchableCone/searchableCone.C
+++ b/src/meshTools/searchableSurfaces/searchableCone/searchableCone.C
@@ -122,11 +122,11 @@ void Foam::searchableCone::findNearestAndNormal
 
     // Nearest and normal on cone. Initialise to far-away point so if not
     // set it picks one of the disk points
-    point nearCone(GREAT, GREAT, GREAT);
+    point nearCone(point::uniform(GREAT));
     vector normalCone(1, 0, 0);
 
     // Nearest and normal on inner cone. Initialise to far-away point
-    point iCnearCone(GREAT, GREAT, GREAT);
+    point iCnearCone(point::uniform(GREAT));
     vector iCnormalCone(1, 0, 0);
 
     point projPt1 = point1_+ radius1_*v;
diff --git a/src/meshTools/searchableSurfaces/searchableCone/searchableCone.H b/src/meshTools/searchableSurfaces/searchableCone/searchableCone.H
index 47da9967c045f4ae308c6e3b2b8dfaac5dbd14f4..77c7dea6681093a83c3cb7aab27783c234586749 100644
--- a/src/meshTools/searchableSurfaces/searchableCone/searchableCone.H
+++ b/src/meshTools/searchableSurfaces/searchableCone/searchableCone.H
@@ -32,7 +32,7 @@ Description
     \heading Dictionary parameters
     \table
         Property    | Description                       | Required | Default
-        type        | cone / searchableCone             | selector |
+        type        | cone                              | selector |
         point1      | coordinate of endpoint            | yes   |
         radius1     | radius at point1                  | yes   |
         innerRadius1| inner radius at point1            | no    | 0
@@ -44,6 +44,9 @@ Description
 Note
     Initial implementation, might suffer from robustness (e.g. radius1==radius2)
 
+Note
+    Longer type name : \c searchableCone
+
 SourceFiles
     searchableCone.C
 
diff --git a/src/meshTools/searchableSurfaces/searchableCylinder/searchableCylinder.H b/src/meshTools/searchableSurfaces/searchableCylinder/searchableCylinder.H
index bcdf2650b54f45fdbfd99fd8a5524613b50c38c8..9035af15f072502759167656c353a484dbbe1eeb 100644
--- a/src/meshTools/searchableSurfaces/searchableCylinder/searchableCylinder.H
+++ b/src/meshTools/searchableSurfaces/searchableCylinder/searchableCylinder.H
@@ -33,12 +33,15 @@ Description
     \heading Dictionary parameters
     \table
         Property    | Description                       | Required | Default
-        type        | cylinder / searchableCylinder     | selector |
+        type        | cylinder                          | selector |
         point1      | coordinate of endpoint            | yes   |
         point2      | coordinate of endpoint            | yes   |
         radius      | cylinder radius                   | yes   |
     \endtable
 
+Note
+    Longer type name : \c searchableCylinder
+
 SourceFiles
     searchableCylinder.C
 
diff --git a/src/meshTools/searchableSurfaces/searchableDisk/searchableDisk.H b/src/meshTools/searchableSurfaces/searchableDisk/searchableDisk.H
index a7e000ae52dd7ab90edfa187c043269fe0f96a74..43594ae8d740095339dfe7887c5bdad0319e5154 100644
--- a/src/meshTools/searchableSurfaces/searchableDisk/searchableDisk.H
+++ b/src/meshTools/searchableSurfaces/searchableDisk/searchableDisk.H
@@ -34,12 +34,15 @@ Description
     \heading Dictionary parameters
     \table
         Property    | Description                       | Required | Default
-        type        | disk / searchableDisk             | selector |
+        type        | disk                              | selector |
         origin      | centre of disk                    | yes   |
         normal      | normal vector                     | yes   |
         radius      | disk radius                       | yes   |
     \endtable
 
+Note
+    Longer type name : \c searchableDisk
+
 SourceFiles
     searchableDisk.C
 
diff --git a/src/meshTools/searchableSurfaces/searchableExtrudedCircle/searchableExtrudedCircle.H b/src/meshTools/searchableSurfaces/searchableExtrudedCircle/searchableExtrudedCircle.H
index c09c7c4d315b29330f18a84856d135aeb4f0f544..1231adfc071cdf2b9d90f049e1e5b3d1cbd06465 100644
--- a/src/meshTools/searchableSurfaces/searchableExtrudedCircle/searchableExtrudedCircle.H
+++ b/src/meshTools/searchableSurfaces/searchableExtrudedCircle/searchableExtrudedCircle.H
@@ -32,7 +32,7 @@ Description
     \heading Dictionary parameters
     \table
         Property    | Description                       | Required | Default
-        type        | extrudedCircle / searchableExtrudedCircle | selector |
+        type        | extrudedCircle                    | selector |
         file        | The name of the edge mesh         | yes   |
         radius      | Search radius around the edges    | yes   |
     \endtable
@@ -42,6 +42,9 @@ Note
     - Can not be used with snappyHexMesh since only implements nearest
       searching.
 
+Note
+    Longer type name : \c searchableExtrudedCircle
+
 SourceFiles
     searchableExtrudedCircle.C
 
diff --git a/src/meshTools/searchableSurfaces/searchablePlane/searchablePlane.C b/src/meshTools/searchableSurfaces/searchablePlane/searchablePlane.C
index c70348bb1af37dcf7ce77f42a35087261290637b..bef9bcb79a3e050b7c3761b7c302f7048daf5f19 100644
--- a/src/meshTools/searchableSurfaces/searchablePlane/searchablePlane.C
+++ b/src/meshTools/searchableSurfaces/searchablePlane/searchablePlane.C
@@ -80,21 +80,19 @@ Foam::pointIndexHit Foam::searchablePlane::findLine
 
 Foam::boundBox Foam::searchablePlane::calcBounds() const
 {
-    point max(VGREAT, VGREAT, VGREAT);
+    boundBox bb(boundBox::greatBox);
 
     for (direction dir = 0; dir < vector::nComponents; dir++)
     {
         if (mag(normal()[dir]) - 1 < SMALL)
         {
-            max[dir] = 0;
-
+            bb.min()[dir] = 0;
+            bb.max()[dir] = 0;
             break;
         }
     }
 
-    point min = -max;
-
-    return boundBox(min, max);
+    return bb;
 }
 
 
@@ -146,10 +144,10 @@ void Foam::searchablePlane::boundingSpheres
     scalarField& radiusSqr
 ) const
 {
-    centres.setSize(1);
-    centres[0] = origin();
+    centres.resize(1);
+    radiusSqr.resize(1);
 
-    radiusSqr.setSize(1);
+    centres[0] = origin();
     radiusSqr[0] = Foam::sqr(GREAT);
 }
 
diff --git a/src/meshTools/searchableSurfaces/searchablePlane/searchablePlane.H b/src/meshTools/searchableSurfaces/searchablePlane/searchablePlane.H
index 246b009c2d85fbf3dda703a5cc6a5450f82bfb1a..db9ae54b6b920ca6b40b56baaed8aecac26a843a 100644
--- a/src/meshTools/searchableSurfaces/searchablePlane/searchablePlane.H
+++ b/src/meshTools/searchableSurfaces/searchablePlane/searchablePlane.H
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2017 OpenFOAM Foundation
+    Copyright (C) 2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -34,9 +35,12 @@ Description
     \heading Dictionary parameters
     \table
         Property    | Description                       | Required  | Default
-        type        | plane / searchablePlane           | selector |
+        type        | plane                             | selector |
     \endtable
 
+Note
+    Longer type name : \c searchablePlane
+
 SourceFiles
     searchablePlane.C
 
@@ -111,6 +115,7 @@ public:
             const dictionary& dict
         );
 
+
     //- Destructor
     virtual ~searchablePlane() = default;
 
diff --git a/src/meshTools/searchableSurfaces/searchablePlate/searchablePlate.C b/src/meshTools/searchableSurfaces/searchablePlate/searchablePlate.C
index 05a8aa3f2d1c39e391f90bb8e19f8fb5151c1e4f..010e1c217313c75783a1e454fdf699efbaf8a45d 100644
--- a/src/meshTools/searchableSurfaces/searchablePlate/searchablePlate.C
+++ b/src/meshTools/searchableSurfaces/searchablePlate/searchablePlate.C
@@ -61,30 +61,29 @@ Foam::direction Foam::searchablePlate::calcNormal(const point& span)
     {
         if (span[dir] < 0)
         {
-            FatalErrorInFunction
-                << "Span should have two positive and one zero entry. Now:"
-                << span << exit(FatalError);
+            // Negative entry. Flag and exit.
+            normalDir = 3;
+            break;
         }
         else if (span[dir] < VSMALL)
         {
-            if (normalDir == 3)
-            {
-                normalDir = dir;
-            }
-            else
+            if (normalDir != 3)
             {
                 // Multiple zero entries. Flag and exit.
                 normalDir = 3;
                 break;
             }
+
+            normalDir = dir;
         }
     }
 
     if (normalDir == 3)
     {
         FatalErrorInFunction
-            << "Span should have two positive and one zero entry. Now:"
-            << span << exit(FatalError);
+            << "Span should have two positive and one zero entry: "
+            << span << nl
+            << exit(FatalError);
     }
 
     return normalDir;
@@ -246,18 +245,8 @@ Foam::searchablePlate::searchablePlate
     const dictionary& dict
 )
 :
-    searchableSurface(io),
-    origin_(dict.get<point>("origin")),
-    span_(dict.get<vector>("span")),
-    normalDir_(calcNormal(span_))
-{
-    DebugInFunction
-        << " origin:" << origin_
-        << " origin+span:" << origin_+span_
-        << " normal:" << vector::componentNames[normalDir_] << nl;
-
-    bounds() = boundBox(origin_, origin_ + span_);
-}
+    searchablePlate(io, dict.get<point>("origin"), dict.get<vector>("span"))
+{}
 
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
@@ -266,8 +255,8 @@ const Foam::wordList& Foam::searchablePlate::regions() const
 {
     if (regions_.empty())
     {
-        regions_.setSize(1);
-        regions_[0] = "region0";
+        regions_.resize(1);
+        regions_.first() = "region0";
     }
     return regions_;
 }
@@ -285,10 +274,10 @@ void Foam::searchablePlate::boundingSpheres
     scalarField& radiusSqr
 ) const
 {
-    centres.setSize(1);
-    centres[0] = origin_ + 0.5*span_;
+    centres.resize(1);
+    radiusSqr.resize(1);
 
-    radiusSqr.setSize(1);
+    centres[0] = origin_ + 0.5*span_;
     radiusSqr[0] = Foam::magSqr(0.5*span_);
 
     // Add a bit to make sure all points are tested inside
@@ -298,26 +287,25 @@ void Foam::searchablePlate::boundingSpheres
 
 Foam::tmp<Foam::pointField> Foam::searchablePlate::points() const
 {
-    auto tpts = tmp<pointField>::New(4);
+    auto tpts = tmp<pointField>::New(4, origin_);
     auto& pts = tpts.ref();
 
-    pts[0] = origin_;
-    pts[2] = origin_ + span_;
+    pts[2] += span_;
 
     if (span_.x() < span_.y() && span_.x() < span_.z())
     {
-        pts[1] = origin_ + point(0, span_.y(), 0);
-        pts[3] = origin_ + point(0, 0, span_.z());
+        pts[1].y() += span_.y();
+        pts[3].z() += span_.z();
     }
     else if (span_.y() < span_.z())
     {
-        pts[1] = origin_ + point(span_.x(), 0, 0);
-        pts[3] = origin_ + point(0, 0, span_.z());
+        pts[1].x() += span_.x();
+        pts[3].z() += span_.z();
     }
     else
     {
-        pts[1] = origin_ + point(span_.x(), 0, 0);
-        pts[3] = origin_ + point(0, span_.y(), 0);
+        pts[1].x() += span_.x();
+        pts[3].y() += span_.y();
     }
 
     return tpts;
@@ -326,15 +314,7 @@ Foam::tmp<Foam::pointField> Foam::searchablePlate::points() const
 
 bool Foam::searchablePlate::overlaps(const boundBox& bb) const
 {
-    return
-    (
-        (origin_.x() + span_.x()) >= bb.min().x()
-     && origin_.x() <= bb.max().x()
-     && (origin_.y() + span_.y()) >= bb.min().y()
-     && origin_.y() <= bb.max().y()
-     && (origin_.z() + span_.z()) >= bb.min().z()
-     && origin_.z() <= bb.max().z()
-    );
+    return bb.overlaps(bounds());
 }
 
 
diff --git a/src/meshTools/searchableSurfaces/searchablePlate/searchablePlate.H b/src/meshTools/searchableSurfaces/searchablePlate/searchablePlate.H
index 5834449dfb206755380c8f26a7dded264de2c4bc..f04371e1f488418254a3bee21a4734731b7744a3 100644
--- a/src/meshTools/searchableSurfaces/searchablePlate/searchablePlate.H
+++ b/src/meshTools/searchableSurfaces/searchablePlate/searchablePlate.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2017 OpenFOAM Foundation
-    Copyright (C) 2018 OpenCFD Ltd.
+    Copyright (C) 2018-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -43,11 +43,14 @@ Description
     \heading Dictionary parameters
     \table
         Property    | Description                       | Required | Default
-        type        | plate / searchablePlate           | selector |
-        origin      | centre of the plate               | yes   |
-        span        | The plate dimensions              | yes   |
+        type        | plate                             | selector |
+        origin      | The minimum corner of the plate   | yes |
+        span        | The plate dimensions              | yes |
     \endtable
 
+Note
+    Longer type name : \c searchablePlate
+
 SourceFiles
     searchablePlate.C
 
@@ -72,12 +75,12 @@ class searchablePlate
 :
     public searchableSurface
 {
-private:
-
     // Private Member Data
 
+        //- The minimum corner of the plate
         const point origin_;
 
+        //- The span size of the plate
         const vector span_;
 
         //- Coordinate direction which is normal
@@ -144,6 +147,12 @@ public:
 
     // Member Functions
 
+        //- The centre (origin) of the plate
+        inline const point& centre() const noexcept
+        {
+             return origin_;
+        }
+
         //- Names of regions
         virtual const wordList& regions() const;
 
diff --git a/src/meshTools/searchableSurfaces/searchableRotatedBox/searchableRotatedBox.C b/src/meshTools/searchableSurfaces/searchableRotatedBox/searchableRotatedBox.C
index e697d64014b1e79259cdc0171dd33a7faf069ad0..2fe886850cc5e6eebf890e690e76484f16463f3b 100644
--- a/src/meshTools/searchableSurfaces/searchableRotatedBox/searchableRotatedBox.C
+++ b/src/meshTools/searchableSurfaces/searchableRotatedBox/searchableRotatedBox.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2014 OpenFOAM Foundation
-    Copyright (C) 2015-2018 OpenCFD Ltd.
+    Copyright (C) 2015-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -55,7 +55,8 @@ namespace Foam
 Foam::searchableRotatedBox::searchableRotatedBox
 (
     const IOobject& io,
-    const dictionary& dict
+    const vector& span,
+    const coordSystem::cartesian& csys
 )
 :
     searchableSurface(io),
@@ -69,21 +70,36 @@ Foam::searchableRotatedBox::searchableRotatedBox
             io.db(),
             io.readOpt(),
             io.writeOpt(),
-            false      //io.registerObject(),
+            false      // never register
         ),
-        treeBoundBox(Zero, dict.get<vector>("span"))
+        treeBoundBox(Zero, span)
     ),
-    transform_
-    (
-        dict.get<point>("origin"),
-        dict.get<vector>("e3"),
-        dict.get<vector>("e1")
-    )
+    transform_(csys.origin(), csys.e3(), csys.e1())
 {
     points_ = transform_.globalPosition(box_.points());
 }
 
 
+Foam::searchableRotatedBox::searchableRotatedBox
+(
+    const IOobject& io,
+    const dictionary& dict
+)
+:
+    searchableRotatedBox
+    (
+        io,
+        dict.get<vector>("span"),
+        coordSystem::cartesian
+        (
+            dict.get<point>("origin"),
+            dict.get<vector>("e3"),
+            dict.get<vector>("e1")
+        )
+    )
+{}
+
+
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 const Foam::wordList& Foam::searchableRotatedBox::regions() const
@@ -125,14 +141,10 @@ bool Foam::searchableRotatedBox::overlaps(const boundBox& bb) const
         return false;
     }
 
-    // 2. Check if one or more face points inside
-    const faceList& fcs = treeBoundBox::faces;
-    forAll(fcs, faceI)
+    // 2. Check if any corner points inside
+    if (bb.containsAny(points_))
     {
-        if (bb.containsAny(points_))
-        {
-            return true;
-        }
+        return true;
     }
 
     // 3. Difficult case: all points are outside but connecting edges might
@@ -141,8 +153,7 @@ bool Foam::searchableRotatedBox::overlaps(const boundBox& bb) const
     const treeBoundBox treeBb(bb);
 
     // 3a. my edges through bb faces
-    const edgeList& edges = treeBoundBox::edges;
-    for (const edge& e : edges)
+    for (const edge& e : treeBoundBox::edges)
     {
         point inter;
         if (treeBb.intersects(points_[e[0]], points_[e[1]], inter))
@@ -155,11 +166,11 @@ bool Foam::searchableRotatedBox::overlaps(const boundBox& bb) const
 
     const pointField bbPoints(bb.points());
 
-    for (const face& f : fcs)
+    for (const face& f : treeBoundBox::faces)
     {
-        point fc = f.centre(points_);
+        const point fc = f.centre(points_);
 
-        for (const edge& e : edges)
+        for (const edge& e : treeBoundBox::edges)
         {
             pointHit inter = f.intersection
             (
diff --git a/src/meshTools/searchableSurfaces/searchableRotatedBox/searchableRotatedBox.H b/src/meshTools/searchableSurfaces/searchableRotatedBox/searchableRotatedBox.H
index 48e46e3966c41630a03480946fc401d08a38da54..8709528eece4a6e03d437111506b499673c216ce 100644
--- a/src/meshTools/searchableSurfaces/searchableRotatedBox/searchableRotatedBox.H
+++ b/src/meshTools/searchableSurfaces/searchableRotatedBox/searchableRotatedBox.H
@@ -46,13 +46,16 @@ Description
     \heading Dictionary parameters
     \table
         Property    | Description                       | Required | Default
-        type        | rotatedBox / searchableRotatedBox | selector |
+        type        | rotatedBox                        | selector |
         span        | The box dimensions                | yes   |
         origin      | The box corner                    | yes   |
         e1          | Local x-axis of the box           | yes   |
         e3          | Local z-axis of the box           | yes   |
     \endtable
 
+Note
+    Longer type name : \c searchableRotatedBox
+
 SourceFiles
     searchableRotatedBox.C
 
@@ -78,8 +81,6 @@ class searchableRotatedBox
 :
     public searchableSurface
 {
-private:
-
     // Private Member Data
 
         //- Box in local coordinate system
@@ -109,6 +110,14 @@ public:
 
     // Constructors
 
+        //- Construct from components
+        searchableRotatedBox
+        (
+            const IOobject& io,
+            const vector& span,
+            const coordSystem::cartesian& csys = coordSystem::cartesian{}
+        );
+
         //- Construct from dictionary (used by searchableSurface)
         searchableRotatedBox
         (
diff --git a/src/meshTools/searchableSurfaces/searchableSphere/searchableSphere.C b/src/meshTools/searchableSurfaces/searchableSphere/searchableSphere.C
index ac24c2e3d9275d156aa4224d52dde5c43b6816d1..cdb9f0002d122a16935b36ed8f7bc70230b22c52 100644
--- a/src/meshTools/searchableSurfaces/searchableSphere/searchableSphere.C
+++ b/src/meshTools/searchableSurfaces/searchableSphere/searchableSphere.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2017 OpenFOAM Foundation
-    Copyright (C) 2018 OpenCFD Ltd.
+    Copyright (C) 2018-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -50,6 +50,95 @@ namespace Foam
 }
 
 
+// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
+
+// General handling
+namespace Foam
+{
+
+// Dictionary entry with single scalar or vector quantity
+inline static vector getRadius(const word& name, const dictionary& dict)
+{
+    if (token(dict.lookup(name)).isNumber())
+    {
+        return vector::uniform(dict.get<scalar>(name));
+    }
+
+    return dict.get<vector>(name);
+}
+
+
+// Test point for negative components, return the sign-changes
+inline static unsigned getOctant(const point& p)
+{
+    unsigned octant = 0;
+
+    if (p.x() < 0) { octant |= 1; }
+    if (p.y() < 0) { octant |= 2; }
+    if (p.z() < 0) { octant |= 4; }
+
+    return octant;
+}
+
+
+// Apply sign-changes to point
+inline static void applyOctant(point& p, unsigned octant)
+{
+    if (octant & 1) { p.x() = -p.x(); }
+    if (octant & 2) { p.y() = -p.y(); }
+    if (octant & 4) { p.z() = -p.z(); }
+}
+
+} // End namespace Foam
+
+
+// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
+
+inline Foam::searchableSphere::componentOrder
+Foam::searchableSphere::getOrdering(const vector& radii)
+{
+    #ifdef FULLDEBUG
+    for (direction cmpt = 0; cmpt < vector::nComponents; ++cmpt)
+    {
+        if (radii[cmpt] <= 0)
+        {
+            FatalErrorInFunction
+                << "Radii must be positive, non-zero: " << radii << endl
+                << exit(FatalError);
+        }
+    }
+    #endif
+
+    std::array<direction, 3> idx{0, 1, 2};
+
+    // Reverse sort by magnitude (largest first...)
+    // Radii are positive (checked above, or just always true)
+    std::stable_sort
+    (
+        idx.begin(),
+        idx.end(),
+        [&](direction a, direction b){ return radii[a] > radii[b]; }
+    );
+
+    componentOrder order{idx[0], idx[1], idx[2], shapeType::GENERAL};
+
+    if (equal(radii[order.major], radii[order.minor]))
+    {
+        order.shape = shapeType::SPHERE;
+    }
+    else if (equal(radii[order.major], radii[order.mezzo]))
+    {
+        order.shape = shapeType::OBLATE;
+    }
+    else if (equal(radii[order.mezzo], radii[order.minor]))
+    {
+        order.shape = shapeType::PROLATE;
+    }
+
+    return order;
+}
+
+
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
 Foam::pointIndexHit Foam::searchableSphere::findNearest
@@ -60,23 +149,33 @@ Foam::pointIndexHit Foam::searchableSphere::findNearest
 {
     pointIndexHit info(false, sample, -1);
 
-    const vector n(sample - origin_);
-    scalar magN = mag(n);
+    // Handle special cases first
 
-    if (nearestDistSqr >= sqr(magN - radius_))
+    // if (order_.shape == shapeType::SPHERE)
+    if (true)
     {
-        if (magN < ROOTVSMALL)
-        {
-            info.rawPoint() = origin_ + vector(1,0,0)*radius_;
-        }
-        else
+        // Point relative to origin, simultaneously the normal on the sphere
+        const vector n(sample - origin_);
+        const scalar magN = mag(n);
+
+        // It is a sphere, all radii are identical
+
+        if (nearestDistSqr >= sqr(magN - radii_[0]))
         {
-            info.rawPoint() = origin_ + n/magN*radius_;
+            info.setPoint
+            (
+                origin_
+              + (magN < ROOTVSMALL ? vector(radii_[0],0,0) : (radii_[0]*n/magN))
+            );
+            info.setHit();
+            info.setIndex(0);
         }
-        info.setHit();
-        info.setIndex(0);
+
+        return info;
     }
 
+    //[code]
+
     return info;
 }
 
@@ -93,43 +192,47 @@ void Foam::searchableSphere::findLineAll
     near.setMiss();
     far.setMiss();
 
-    vector dir(end-start);
-    scalar magSqrDir = magSqr(dir);
-
-    if (magSqrDir > ROOTVSMALL)
+    // if (order_.shape == shapeType::SPHERE)
+    if (true)
     {
-        const vector toCentre(origin_ - start);
-        scalar magSqrToCentre = magSqr(toCentre);
-
-        dir /= Foam::sqrt(magSqrDir);
-
-        scalar v = (toCentre & dir);
+        vector dir(end-start);
+        const scalar magSqrDir = magSqr(dir);
 
-        scalar disc = sqr(radius_) - (magSqrToCentre - sqr(v));
-
-        if (disc >= 0)
+        if (magSqrDir > ROOTVSMALL)
         {
-            scalar d = Foam::sqrt(disc);
+            dir /= Foam::sqrt(magSqrDir);
 
-            scalar nearParam = v-d;
+            const vector relStart(start - origin_);
 
-            if (nearParam >= 0 && sqr(nearParam) <= magSqrDir)
-            {
-                near.setHit();
-                near.setPoint(start + nearParam*dir);
-                near.setIndex(0);
-            }
+            const scalar v = -(relStart & dir);
 
-            scalar farParam = v+d;
+            const scalar disc = sqr(radius()) - (magSqr(relStart) - sqr(v));
 
-            if (farParam >= 0 && sqr(farParam) <= magSqrDir)
+            if (disc >= 0)
             {
-                far.setHit();
-                far.setPoint(start + farParam*dir);
-                far.setIndex(0);
+                const scalar d = Foam::sqrt(disc);
+
+                const scalar nearParam = v - d;
+                const scalar farParam = v + d;
+
+                if (nearParam >= 0 && sqr(nearParam) <= magSqrDir)
+                {
+                    near.setHit();
+                    near.setPoint(start + nearParam*dir);
+                    near.setIndex(0);
+                }
+
+                if (farParam >= 0 && sqr(farParam) <= magSqrDir)
+                {
+                    far.setHit();
+                    far.setPoint(start + farParam*dir);
+                    far.setIndex(0);
+                }
             }
         }
     }
+
+    //[code]
 }
 
 
@@ -141,16 +244,26 @@ Foam::searchableSphere::searchableSphere
     const point& origin,
     const scalar radius
 )
+:
+    searchableSphere(io, origin, vector::uniform(radius))
+{}
+
+
+Foam::searchableSphere::searchableSphere
+(
+    const IOobject& io,
+    const point& origin,
+    const vector& radii
+)
 :
     searchableSurface(io),
     origin_(origin),
-    radius_(radius)
+    // radii_(radii),
+    radii_(vector::uniform(cmptMax(radii))) /* Transition */,
+    order_{getOrdering(radii_)}
 {
-    bounds() = boundBox
-    (
-        origin_ - radius_*vector::one,
-        origin_ + radius_*vector::one
-    );
+    bounds().min() = (centre() - radii_);
+    bounds().max() = (centre() + radii_);
 }
 
 
@@ -164,16 +277,61 @@ Foam::searchableSphere::searchableSphere
     (
         io,
         dict.getCompat<vector>("origin", {{"centre", -1806}}),
-        dict.get<scalar>("radius")
+        getRadius("radius", dict)
     )
 {}
 
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
+Foam::point Foam::searchableSphere::surfacePoint
+(
+    const scalar theta,
+    const scalar phi
+) const
+{
+    return point
+    (
+        origin_.x() + radii_.x() * cos(theta)*sin(phi),
+        origin_.y() + radii_.y() * sin(theta)*sin(phi),
+        origin_.z() + radii_.z() * cos(phi)
+    );
+}
+
+
+Foam::vector Foam::searchableSphere::surfaceNormal
+(
+    const scalar theta,
+    const scalar phi
+) const
+{
+    // Normal is (x0/r0^2, x1/r1^2, x2/r2^2)
+
+    return vector
+    (
+        cos(theta)*sin(phi) / radii_.x(),
+        sin(theta)*sin(phi) / radii_.y(),
+        cos(phi) / radii_.z()
+    ).normalise();
+}
+
+
 bool Foam::searchableSphere::overlaps(const boundBox& bb) const
 {
-    return bb.overlaps(origin_, sqr(radius_));
+    // if (order_.shape == shapeType::SPHERE)
+    if (true)
+    {
+        return bb.overlaps(origin_, sqr(radius()));
+    }
+
+    if (!bb.valid())
+    {
+        return false;
+    }
+
+    //[code]
+
+    return true;
 }
 
 
@@ -188,7 +346,6 @@ const Foam::wordList& Foam::searchableSphere::regions() const
 }
 
 
-
 void Foam::searchableSphere::boundingSpheres
 (
     pointField& centres,
@@ -196,10 +353,10 @@ void Foam::searchableSphere::boundingSpheres
 ) const
 {
     centres.resize(1);
-    centres[0] = origin_;
-
     radiusSqr.resize(1);
-    radiusSqr[0] = Foam::sqr(radius_);
+
+    centres[0] = origin_;
+    radiusSqr[0] = Foam::sqr(radius());
 
     // Add a bit to make sure all points are tested inside
     radiusSqr += Foam::sqr(SMALL);
@@ -213,7 +370,7 @@ void Foam::searchableSphere::findNearest
     List<pointIndexHit>& info
 ) const
 {
-    info.setSize(samples.size());
+    info.resize(samples.size());
 
     forAll(samples, i)
     {
@@ -229,14 +386,17 @@ void Foam::searchableSphere::findLine
     List<pointIndexHit>& info
 ) const
 {
-    info.setSize(start.size());
+    info.resize(start.size());
 
     pointIndexHit b;
 
     forAll(start, i)
     {
-        // Pick nearest intersection. If none intersected take second one.
+        // Pick nearest intersection.
+        // If none intersected take second one.
+
         findLineAll(start[i], end[i], info[i], b);
+
         if (!info[i].hit() && b.hit())
         {
             info[i] = b;
@@ -252,14 +412,17 @@ void Foam::searchableSphere::findLineAny
     List<pointIndexHit>& info
 ) const
 {
-    info.setSize(start.size());
+    info.resize(start.size());
 
     pointIndexHit b;
 
     forAll(start, i)
     {
+        // Pick nearest intersection.
         // Discard far intersection
+
         findLineAll(start[i], end[i], info[i], b);
+
         if (!info[i].hit() && b.hit())
         {
             info[i] = b;
@@ -275,24 +438,25 @@ void Foam::searchableSphere::findLineAll
     List<List<pointIndexHit>>& info
 ) const
 {
-    info.setSize(start.size());
+    info.resize(start.size());
 
     forAll(start, i)
     {
         pointIndexHit near, far;
+
         findLineAll(start[i], end[i], near, far);
 
         if (near.hit())
         {
             if (far.hit())
             {
-                info[i].setSize(2);
+                info[i].resize(2);
                 info[i][0] = near;
                 info[i][1] = far;
             }
             else
             {
-                info[i].setSize(1);
+                info[i].resize(1);
                 info[i][0] = near;
             }
         }
@@ -300,7 +464,7 @@ void Foam::searchableSphere::findLineAll
         {
             if (far.hit())
             {
-                info[i].setSize(1);
+                info[i].resize(1);
                 info[i][0] = far;
             }
             else
@@ -318,7 +482,7 @@ void Foam::searchableSphere::getRegion
     labelList& region
 ) const
 {
-    region.setSize(info.size());
+    region.resize(info.size());
     region = 0;
 }
 
@@ -329,18 +493,18 @@ void Foam::searchableSphere::getNormal
     vectorField& normal
 ) const
 {
-    normal.setSize(info.size());
-    normal = Zero;
+    normal.resize(info.size());
 
     forAll(info, i)
     {
         if (info[i].hit())
         {
-            normal[i] = normalised(info[i].hitPoint() - origin_);
+            normal[i] = normalised(info[i].point() - origin_);
         }
         else
         {
             // Set to what?
+            normal[i] = Zero;
         }
     }
 }
@@ -352,20 +516,26 @@ void Foam::searchableSphere::getVolumeType
     List<volumeType>& volType
 ) const
 {
-    volType.setSize(points.size());
-
-    const scalar rad2 = sqr(radius_);
+    volType.resize(points.size());
 
-    forAll(points, pointi)
+    // if (order_.shape == shapeType::SPHERE)
+    if (true)
     {
-        const point& pt = points[pointi];
+        const scalar rad2 = sqr(radius());
+
+        forAll(points, pointi)
+        {
+            const point& p = points[pointi];
 
-        volType[pointi] =
-        (
-            (magSqr(pt - origin_) <= rad2)
-          ? volumeType::INSIDE : volumeType::OUTSIDE
-        );
+            volType[pointi] =
+            (
+                (magSqr(p - origin_) <= rad2)
+              ? volumeType::INSIDE : volumeType::OUTSIDE
+            );
+        }
     }
+
+    //[code]
 }
 
 
diff --git a/src/meshTools/searchableSurfaces/searchableSphere/searchableSphere.H b/src/meshTools/searchableSurfaces/searchableSphere/searchableSphere.H
index 18e85ab8b44be659d6bacfb351bdf62204093f02..c630a8c4e2ce751bc298d8b0fd1fdaf3c0304757 100644
--- a/src/meshTools/searchableSurfaces/searchableSphere/searchableSphere.H
+++ b/src/meshTools/searchableSurfaces/searchableSphere/searchableSphere.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2017 OpenFOAM Foundation
-    Copyright (C) 2018 OpenCFD Ltd.
+    Copyright (C) 2018-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -33,12 +33,15 @@ Description
     \heading Dictionary parameters
     \table
         Property    | Description                           | Required | Default
-        type        | sphere / searchableSphere             | selector |
-        origin      | The origin (centre) of the sphere     | yes   |
-        radius      | The (outside) radius of sphere        | yes   |
-        centre      | Alternative for 'origin'              | no    |
+        type        | sphere                                | selector |
+        origin      | The origin (centre) of the sphere     | yes |
+        radius      | The (outside) radius of sphere        | yes |
+        centre      | Alternative name for 'origin'         | no  |
     \endtable
 
+Note
+    Longer type name : \c searchableSphere
+
 SourceFiles
     searchableSphere.C
 
@@ -63,15 +66,44 @@ class searchableSphere
 :
     public searchableSurface
 {
+public:
+
+    // Public Types
+
+        //- The type of shape
+        enum shapeType : uint8_t
+        {
+            SPHERE = 0,     //!< Sphere (all components equal)
+            OBLATE = 1,     //!< Oblate (major = mezzo > minor)
+            PROLATE = 2,    //!< Prolate (major > mezzo = minor)
+            GENERAL = 3     //!< General spheroid
+        };
+
+
 private:
 
-    // Private Member Data
+    // Private Types
+
+        //- Component order (largest to smallest)
+        struct componentOrder
+        {
+            uint8_t major;      //!< Component with major radius
+            uint8_t mezzo;      //!< Component with intermediate radius
+            uint8_t minor;      //!< Component with minor radius
+            shapeType shape;    //!< The type of shape
+        };
+
+
+    // Private Data
 
         //- Centre point of the sphere
         const point origin_;
 
-        //- The outer radius of the sphere
-        const scalar radius_;
+        //- The outer radii of the spheroid
+        const vector radii_;
+
+        //- The canonical (sorted) order and shape
+        const struct componentOrder order_;
 
         //- Names of regions
         mutable wordList regions_;
@@ -79,6 +111,9 @@ private:
 
     // Private Member Functions
 
+        //- Determine sorted order and classify the shape
+        inline static componentOrder getOrdering(const vector& radii);
+
         //- Inherit findNearest from searchableSurface
         using searchableSurface::findNearest;
 
@@ -114,14 +149,22 @@ public:
 
     // Constructors
 
-        //- Construct from components
+        //- Construct a sphere from components
         searchableSphere
         (
             const IOobject& io,
-            const point& centre,
+            const point& origin,
             const scalar radius
         );
 
+        //- Construct a spheroid from components
+        searchableSphere
+        (
+            const IOobject& io,
+            const point& centre,
+            const vector& radii
+        );
+
         //- Construct from dictionary (used by searchableSurface)
         searchableSphere
         (
@@ -136,6 +179,44 @@ public:
 
     // Member Functions
 
+    // Geometric
+
+        //- The centre (origin) of the sphere
+        const point& centre() const noexcept
+        {
+             return origin_;
+        }
+
+        //- The radius of the sphere, or major radius of the spheroid
+        scalar radius() const noexcept
+        {
+            return radii_[order_.major];
+        }
+
+        //- The radii of the spheroid
+        const vector& radii() const noexcept
+        {
+            return radii_;
+        }
+
+        //- The type of shape
+        enum shapeType shape() const noexcept
+        {
+            return shapeType::SPHERE;
+        }
+
+        //- A point on the sphere at given location
+        //  theta [-pi,pi], phi [0,pi]
+        point surfacePoint(const scalar theta, const scalar phi) const;
+
+        //- Surface normal on the sphere at given location
+        //  theta [-pi,pi], phi [0,pi]
+        vector surfaceNormal(const scalar theta, const scalar phi) const;
+
+
+
+    // Searching
+
         //- Names of regions
         virtual const wordList& regions() const;
 
@@ -228,7 +309,6 @@ public:
             ) const;
 
             //- Determine type (inside/outside/mixed) for point.
-            //  Unknown if cannot be determined (e.g. non-manifold surface)
             virtual void getVolumeType
             (
                 const pointField& points,
@@ -236,14 +316,14 @@ public:
             ) const;
 
 
-        // regIOobject implementation
-
-            bool writeData(Ostream&) const
-            {
-                NotImplemented;
-                return false;
-            }
+    // Output
 
+        // Implementation for regIOobject. NotImplemented
+        bool writeData(Ostream&) const
+        {
+            NotImplemented;
+            return false;
+        }
 };
 
 
diff --git a/src/meshTools/searchableSurfaces/searchableSurfaceCollection/searchableSurfaceCollection.C b/src/meshTools/searchableSurfaces/searchableSurfaceCollection/searchableSurfaceCollection.C
index 4497955bdfceb21951dffd3a866032ab3eb171d3..22bf80724a7c9cdb7565859154a42718d06610e9 100644
--- a/src/meshTools/searchableSurfaces/searchableSurfaceCollection/searchableSurfaceCollection.C
+++ b/src/meshTools/searchableSurfaces/searchableSurfaceCollection/searchableSurfaceCollection.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2017 OpenFOAM Foundation
-    Copyright (C) 2016-2018 OpenCFD Ltd.
+    Copyright (C) 2016-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -43,6 +43,13 @@ namespace Foam
         searchableSurfaceCollection,
         dict
     );
+    addNamedToRunTimeSelectionTable
+    (
+        searchableSurface,
+        searchableSurfaceCollection,
+        dict,
+        collection
+    );
 }
 
 
diff --git a/src/meshTools/searchableSurfaces/searchableSurfaceCollection/searchableSurfaceCollection.H b/src/meshTools/searchableSurfaces/searchableSurfaceCollection/searchableSurfaceCollection.H
index c69f27fe6d2d44a51cf1734932c1f5b3692a01b8..3cbf15f86ac38fa4fc615495284d6ffffd02fd75 100644
--- a/src/meshTools/searchableSurfaces/searchableSurfaceCollection/searchableSurfaceCollection.H
+++ b/src/meshTools/searchableSurfaces/searchableSurfaceCollection/searchableSurfaceCollection.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2017 OpenFOAM Foundation
-    Copyright (C) 2015 OpenCFD Ltd.
+    Copyright (C) 2015-2020 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -34,10 +34,13 @@ Description
     \heading Dictionary parameters
     \table
         Property    | Description                       | Required | Default
-        type        | searchableSurfaceCollection       | selector |
+        type        | collection                        | selector |
         mergeSubRegions | boolean                       | yes   |
     \endtable
 
+Note
+    Longer type name : \c searchableSurfaceCollection
+
 SourceFiles
     searchableSurfaceCollection.C
 
diff --git a/tutorials/heatTransfer/buoyantBoussinesqSimpleFoam/iglooWithFridges/system/snappyHexMeshDict b/tutorials/heatTransfer/buoyantBoussinesqSimpleFoam/iglooWithFridges/system/snappyHexMeshDict
index 6d9ac084be12d42481a4d9cc0d93ecfd3d9dd55c..cbb64949946e848990f34fa963e33ccda7126874 100644
--- a/tutorials/heatTransfer/buoyantBoussinesqSimpleFoam/iglooWithFridges/system/snappyHexMeshDict
+++ b/tutorials/heatTransfer/buoyantBoussinesqSimpleFoam/iglooWithFridges/system/snappyHexMeshDict
@@ -44,7 +44,7 @@ geometry
 
     twoFridgeFreezers
     {
-        type searchableSurfaceCollection;
+        type collection;
 
         mergeSubRegions true;
 
diff --git a/tutorials/incompressible/pimpleFoam/laminar/cylinder2D/system/snappyHexMeshDict b/tutorials/incompressible/pimpleFoam/laminar/cylinder2D/system/snappyHexMeshDict
index 5f9cee58ffa2c154134a192f3381eeea0e0982d6..7352d1245b63303620a2d14cc874a0d772eddb2b 100644
--- a/tutorials/incompressible/pimpleFoam/laminar/cylinder2D/system/snappyHexMeshDict
+++ b/tutorials/incompressible/pimpleFoam/laminar/cylinder2D/system/snappyHexMeshDict
@@ -22,7 +22,7 @@ geometry
 {
     cylinder
     {
-        type    searchableCylinder;
+        type    cylinder;
         point1  (0 0 -0.00375);
         point2  (0 0 0.00375);
         radius  0.06;
diff --git a/tutorials/incompressible/pimpleFoam/laminar/mixerVesselAMI2D/mixerVesselAMI2D-topologyChange/system/blockMeshDict.m4 b/tutorials/incompressible/pimpleFoam/laminar/mixerVesselAMI2D/mixerVesselAMI2D-topologyChange/system/blockMeshDict.m4
index 7a451acd5f88c384274f2bb08a7b9481b5051cc6..61cc0b89f6d5e1a2c2dd65957f650330393a58b2 100644
--- a/tutorials/incompressible/pimpleFoam/laminar/mixerVesselAMI2D/mixerVesselAMI2D-topologyChange/system/blockMeshDict.m4
+++ b/tutorials/incompressible/pimpleFoam/laminar/mixerVesselAMI2D/mixerVesselAMI2D-topologyChange/system/blockMeshDict.m4
@@ -1083,7 +1083,7 @@ boundary
 /* optional
         surface
         {
-            type            searchableCylinder; // none
+            type            cylinder; // none
             point1          (0 0 -1);
             point2          (0 0 1);
             radius          0.5;
@@ -1111,7 +1111,7 @@ boundary
 /* optional
         surface
         {
-            type            searchableCylinder; // none
+            type            cylinder; // none
             point1          (0 0 -1);
             point2          (0 0 1);
             radius          0.5;
diff --git a/tutorials/mesh/snappyHexMesh/iglooWithFridgesDirectionalRefinement/system/snappyHexMeshDict b/tutorials/mesh/snappyHexMesh/iglooWithFridgesDirectionalRefinement/system/snappyHexMeshDict
index 8503c699ae68b26ec658d6443de52c1c7a0428df..7a03d4e12ec70e2ac4482baee2909b2a276d41e3 100644
--- a/tutorials/mesh/snappyHexMesh/iglooWithFridgesDirectionalRefinement/system/snappyHexMeshDict
+++ b/tutorials/mesh/snappyHexMesh/iglooWithFridgesDirectionalRefinement/system/snappyHexMeshDict
@@ -30,21 +30,21 @@ geometry
 {
     igloo
     {
-        type searchableSphere;
+        type   sphere;
         origin (3 3 0);
         radius 4;
     }
 
     box1
     {
-        type searchableBox;
-        min (0 0 0);
-        max (1 1 1);
+        type box;
+        min  (0 0 0);
+        max  (1 1 1);
     }
 
     twoFridgeFreezers
     {
-        type searchableSurfaceCollection;
+        type collection;
 
         mergeSubRegions true;
 
@@ -87,13 +87,13 @@ geometry
     // For directional refinement
     dirRefineBox1
     {
-        type searchableBox;
+        type box;
         min (-10 -10 -10);
         max ( 10  10  0.5);
     }
     dirRefineBox2
     {
-        type searchableBox;
+        type box;
         min (-10 -10 -10);
         max ( 10  10  0.25);
     }
diff --git a/tutorials/mesh/snappyHexMesh/motorBike_leakDetection/system/snappyHexMeshDict b/tutorials/mesh/snappyHexMesh/motorBike_leakDetection/system/snappyHexMeshDict
index 1e73a8c49f7de6e8c5eded125ff0eafa9c341317..9615c000393de57e0d14c86ccd84b63fe8a748e0 100644
--- a/tutorials/mesh/snappyHexMesh/motorBike_leakDetection/system/snappyHexMeshDict
+++ b/tutorials/mesh/snappyHexMesh/motorBike_leakDetection/system/snappyHexMeshDict
@@ -43,7 +43,7 @@ geometry
 
     refinementBox
     {
-        type searchableBox;
+        type box;
         min (-1.0 -0.7 0.0);
         max ( 8.0  0.7 2.5);
     }
diff --git a/tutorials/mesh/snappyHexMesh/opposite_walls/system/snappyHexMeshDict b/tutorials/mesh/snappyHexMesh/opposite_walls/system/snappyHexMeshDict
index da73455f2622a370477b8fb3d6233f43ba8eb2f9..03e2ed50f5e27c5bfd75f6f01f4123d02197db96 100644
--- a/tutorials/mesh/snappyHexMesh/opposite_walls/system/snappyHexMeshDict
+++ b/tutorials/mesh/snappyHexMesh/opposite_walls/system/snappyHexMeshDict
@@ -40,7 +40,7 @@ geometry
     }
     all
     {
-        type searchableBox;
+        type box;
         min (-1000 -1000 -1000);
         max (1000 1000 1000);
     }