From db16d8084019b787560a9229e4ee82713697919c Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@esi-group.com>
Date: Mon, 17 Jul 2023 18:27:55 +0200
Subject: [PATCH] ENH: use objectRegistry/IOobjectList sorted instead of
 lookupClass

- in most cases a parallel-consistent order is required.
  Even when the order is not important, it will generally require
  fewer allocations to create a UPtrList of entries instead of a
  HashTable or even a wordList.
---
 .../localDensityAbsorptionEmission.C          |   6 +-
 .../utilities/mesh/advanced/PDRMesh/PDRMesh.C | 383 ++++++++----------
 .../mesh/manipulation/rotateMesh/rotateMesh.C |   9 +-
 .../splitMeshRegions/splitMeshRegions.C       |  24 +-
 .../mesh/manipulation/subsetMesh/subsetMesh.C | 270 +++++-------
 .../miscellaneous/patchSummary/patchSummary.C | 115 +++---
 .../patchSummary/patchSummaryTemplates.C      |  46 ++-
 .../patchSummary/patchSummaryTemplates.H      |  53 +--
 .../decomposePar/domainDecomposition.C        |  29 +-
 .../reconstructPar/reconstructPar.C           |  12 +-
 .../parFvFieldDistributorTemplates.C          |  73 ++--
 .../parLagrangianDistributor.C                |   2 +-
 .../parLagrangianDistributorTemplates.C       |  13 +-
 .../foamDataToFluent/foamDataToFluent.C       |  57 +--
 .../foamDataToFluent/writeFluentFields.H      |  42 +-
 .../foamDataToFluent/writeFluentScalarField.C |  30 +-
 .../foamDataToFluent/writeFluentVectorField.C |  30 +-
 .../foamToEnsight/checkFieldAvailability.H    |   6 +-
 .../dataConversion/foamToEnsight/readFields.H |  20 +-
 .../foamToEnsight/writeAreaFields.H           |   8 +-
 .../foamToEnsight/writeDimFields.H            |   8 +-
 .../foamToEnsight/writePointFields.H          |  10 +-
 .../foamToEnsight/writeVolFields.H            |   8 +-
 .../foamToTetDualMesh/foamToTetDualMesh.C     |  22 +-
 .../dataConversion/foamToVTK/readFields.C     |   4 +-
 .../steadyParticleTracksTemplates.C           |  22 +-
 .../temporalInterpolate/temporalInterpolate.C |  35 +-
 .../foamUpgradeCyclics/foamUpgradeCyclics.C   | 181 ++-------
 .../mapFields/MapConsistentVolFields.H        |  19 +-
 .../mapFields/MapLagrangianFields.H           | 186 ++++-----
 .../preProcessing/mapFields/MapVolFields.H    |  15 +-
 .../preProcessing/mapFields/UnMapped.H        |   6 +-
 .../mapFieldsPar/MapLagrangianFields.H        | 215 ++++------
 .../preProcessing/mapFieldsPar/MapVolFields.H |  25 +-
 .../preProcessing/mapFieldsPar/UnMapped.H     |   6 +-
 .../DimensionedField/MapDimensionedFields.H   |  20 +-
 .../GeometricField/MapGeometricFields.H       |  33 +-
 .../fields/ReadFields/ReadFieldsTemplates.C   |  86 ++--
 src/OpenFOAM/fields/cloud/mapClouds.H         |  12 +-
 .../Identifiers/patch/coupleGroupIdentifier.C |  15 +-
 .../fieldsDistributorTemplates.C              |  16 +-
 .../dynamicRefineFvMesh/dynamicRefineFvMesh.C |  54 ++-
 .../dynamicRefineFvMeshTemplates.C            |  38 +-
 .../fvMeshAdder/fvMeshAdderTemplates.C        | 187 ++++-----
 .../fvMeshDistributeTemplates.C               | 132 +++---
 .../polyMeshFilter/polyMeshFilter.H           |   5 +-
 .../polyMeshFilter/polyMeshFilterTemplates.C  |  33 +-
 src/dynamicMesh/setUpdater/setUpdater.H       |   6 +-
 .../setUpdater/setUpdaterTemplates.C          |  49 ++-
 .../vtk/read/vtkUnstructuredReaderTemplates.C |  14 +-
 .../solutionControl/loopControl/loopControl.C |  10 +-
 .../solutionControlTemplates.C                |   6 +-
 .../fvMesh/fvMeshTools/fvMeshToolsTemplates.C |  46 +--
 .../field/externalCoupled/externalCoupled.C   |   2 +-
 .../field/mapFields/mapFieldsTemplates.C      |  20 +-
 .../nearWallFields/nearWallFieldsTemplates.C  |  25 +-
 .../particleDistribution.C                    |   8 +-
 .../regionSizeDistribution.C                  |  25 +-
 src/functionObjects/field/setFlow/setFlow.C   |   2 +-
 .../surfaceInterpolateTemplates.C             |  10 +-
 src/functionObjects/forces/forces/forces.C    |   9 +-
 .../forces/propellerInfo/propellerInfo.C      |   2 +-
 .../meshRefinement/meshRefinementTemplates.C  |  36 +-
 .../cellCellStencilTemplates.C                |  14 +-
 .../distributedTriSurfaceMeshTemplates.C      |  11 +-
 .../setTimeStepFaRegionsFunctionObject.C      |  23 +-
 ...sRadiativeCoupledMixedFvPatchScalarField.C |  46 ++-
 ...sRadiativeCoupledMixedFvPatchScalarField.H |   9 +-
 .../sampledSet/sampledSets/sampledSets.C      |   3 +-
 .../basic/basicThermo/basicThermo.C           |  17 +-
 70 files changed, 1278 insertions(+), 1736 deletions(-)

diff --git a/applications/solvers/multiphase/icoReactingMultiphaseInterFoam/laserDTRM/localDensityAbsorptionEmission/localDensityAbsorptionEmission.C b/applications/solvers/multiphase/icoReactingMultiphaseInterFoam/laserDTRM/localDensityAbsorptionEmission/localDensityAbsorptionEmission.C
index 11225dc2a15..72e3d08d90e 100644
--- a/applications/solvers/multiphase/icoReactingMultiphaseInterFoam/laserDTRM/localDensityAbsorptionEmission/localDensityAbsorptionEmission.C
+++ b/applications/solvers/multiphase/icoReactingMultiphaseInterFoam/laserDTRM/localDensityAbsorptionEmission/localDensityAbsorptionEmission.C
@@ -52,7 +52,9 @@ namespace Foam
 const Foam::volScalarField&
 Foam::radiation::localDensityAbsorptionEmission::alpha(word alphaName) const
 {
-    if (!mesh_.foundObject<volScalarField>(alphaName))
+    const volScalarField* ptr = mesh_.cfindObject<volScalarField>(alphaName);
+
+    if (!ptr)
     {
         FatalErrorInFunction
             << "Unable to retrieve density field " << alphaName << " from "
@@ -60,7 +62,7 @@ Foam::radiation::localDensityAbsorptionEmission::alpha(word alphaName) const
             << exit(FatalError);
     }
 
-    return mesh_.lookupObject<volScalarField>(alphaName);
+    return *ptr;
 }
 
 
diff --git a/applications/utilities/mesh/advanced/PDRMesh/PDRMesh.C b/applications/utilities/mesh/advanced/PDRMesh/PDRMesh.C
index b3ec7e2fd75..645a5073d18 100644
--- a/applications/utilities/mesh/advanced/PDRMesh/PDRMesh.C
+++ b/applications/utilities/mesh/advanced/PDRMesh/PDRMesh.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2016-2022 OpenCFD Ltd.
+    Copyright (C) 2016-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -131,40 +131,56 @@ void modifyOrAddFace
 
 
 template<class Type>
-void subsetVolFields
+PtrList<GeometricField<Type, fvPatchField, volMesh>> subsetVolFields
 (
     const fvMeshSubset& subsetter,
     const IOobjectList& objects,
     const label patchi,
-    const Type& exposedValue,
-    PtrList<GeometricField<Type, fvPatchField, volMesh>>& subFields
+    const Type& exposedValue
 )
 {
     typedef GeometricField<Type, fvPatchField, volMesh> GeoField;
 
     const fvMesh& baseMesh = subsetter.baseMesh();
 
-    label nFields = 0;
+    const UPtrList<const IOobject> fieldObjects
+    (
+        objects.csorted<GeoField>()
+    );
 
-    for (const word& fieldName : objects.sortedNames<GeoField>())
-    {
-        const IOobject* ioptr = objects.findObject(fieldName);
+    PtrList<GeoField> subFields(fieldObjects.size());
 
+    label nFields = 0;
+    for (const IOobject& io : fieldObjects)
+    {
         if (!nFields)
         {
-            Info<< "Subsetting " << GeoField::typeName << nl;
+            Info<< "Subsetting " << GeoField::typeName << " (";
+        }
+        else
+        {
+            Info<< ' ';
         }
-        Info<< "    " << fieldName << endl;
+        Info<< "    " << io.name() << endl;
 
-        GeoField origField(*ioptr, baseMesh);
+        // Read unregistered
+        IOobject rio(io, IOobjectOption::NO_REGISTER);
+        GeoField origField(rio, baseMesh);
 
         subFields.set(nFields, subsetter.interpolate(origField));
+        auto& subField = subFields[nFields];
+        ++nFields;
+
+
+        // Subsetting adds 'subset' prefix. Rename field to be like original.
+        subField.rename(io.name());
+        subField.writeOpt(IOobjectOption::AUTO_WRITE);
+
 
         // Explicitly set exposed faces (in patchi) to exposedValue.
         if (patchi >= 0)
         {
-            fvPatchField<Type>& fld =
-                subFields[nFields].boundaryFieldRef()[patchi];
+            fvPatchField<Type>& fld = subField.boundaryFieldRef()[patchi];
 
             const label newStart = fld.patch().patch().start();
             const label oldPatchi = subsetter.patchMap()[patchi];
@@ -195,48 +211,68 @@ void subsetVolFields
                     }
                 }
             }
-
-            ++nFields;
         }
     }
+
+    if (nFields)
+    {
+        Info<< ')' << nl;
+    }
+
+    return subFields;
 }
 
 
 template<class Type>
-void subsetSurfaceFields
+PtrList<GeometricField<Type, fvsPatchField, surfaceMesh>> subsetSurfaceFields
 (
     const fvMeshSubset& subsetter,
     const IOobjectList& objects,
     const label patchi,
-    const Type& exposedValue,
-    PtrList<GeometricField<Type, fvsPatchField, surfaceMesh>>& subFields
+    const Type& exposedValue
 )
 {
     typedef GeometricField<Type, fvsPatchField, surfaceMesh> GeoField;
 
     const fvMesh& baseMesh = subsetter.baseMesh();
 
-    label nFields = 0;
+    const UPtrList<const IOobject> fieldObjects
+    (
+        objects.csorted<GeoField>()
+    );
 
-    for (const word& fieldName : objects.sortedNames<GeoField>())
-    {
-        const IOobject* ioptr = objects.findObject(fieldName);
+    PtrList<GeoField> subFields(fieldObjects.size());
 
+    label nFields = 0;
+    for (const IOobject& io : fieldObjects)
+    {
         if (!nFields)
         {
-            Info<< "Subsetting " << GeoField::typeName << nl;
+            Info<< "Subsetting " << GeoField::typeName << " (";
+        }
+        else
+        {
+            Info<< ' ';
         }
-        Info<< "    " << fieldName << endl;
+        Info<< io.name();
 
-        GeoField origField(*ioptr, baseMesh);
+        // Read unregistered
+        IOobject rio(io, IOobjectOption::NO_REGISTER);
+        GeoField origField(rio, baseMesh);
 
         subFields.set(nFields, subsetter.interpolate(origField));
+        auto& subField = subFields[nFields];
+        ++nFields;
+
+        // Subsetting adds 'subset' prefix. Rename field to be like original.
+        subField.rename(io.name());
+        subField.writeOpt(IOobjectOption::AUTO_WRITE);
+
 
         // Explicitly set exposed faces (in patchi) to exposedValue.
         if (patchi >= 0)
         {
-            fvsPatchField<Type>& fld =
-                subFields[nFields].boundaryFieldRef()[patchi];
+            fvsPatchField<Type>& fld = subField.boundaryFieldRef()[patchi];
 
             const label newStart = fld.patch().patch().start();
             const label oldPatchi = subsetter.patchMap()[patchi];
@@ -268,9 +304,14 @@ void subsetSurfaceFields
                 }
             }
         }
+    }
 
-        ++nFields;
+    if (nFields)
+    {
+        Info<< ')' << nl;
     }
+
+    return subFields;
 }
 
 
@@ -284,16 +325,9 @@ void initCreatedPatches
     const typename GeoField::value_type initValue
 )
 {
-    HashTable<const GeoField*> fields
-    (
-        mesh.objectRegistry::lookupClass<GeoField>()
-    );
-
-    forAllIters(fields, fieldIter)
+    for (const GeoField& field : mesh.objectRegistry::csorted<GeoField>())
     {
-        GeoField& field = const_cast<GeoField&>(*fieldIter());
-
-        auto& fieldBf = field.boundaryFieldRef();
+        auto& fieldBf = const_cast<GeoField&>(field).boundaryFieldRef();
 
         forAll(fieldBf, patchi)
         {
@@ -326,43 +360,36 @@ void subsetTopoSets
     PtrList<TopoSet> sets;
     ReadFields<TopoSet>(objects, sets);
 
-    subSets.resize(sets.size());
+    subSets.resize_null(sets.size());
+
     forAll(sets, seti)
     {
-        TopoSet& set = sets[seti];
+        const TopoSet& set = sets[seti];
 
-        Info<< "Subsetting " << set.type() << " " << set.name() << endl;
+        Info<< "Subsetting " << set.type() << ' ' << set.name() << endl;
 
-        // Map the data
-        bitSet isSet(set.maxSize(mesh));
-        for (const label id : set)
-        {
-            isSet.set(id);
-        }
+        labelHashSet subset(2*min(set.size(), map.size()));
 
-        label nSet = 0;
-        for (const label id : map)
+        // Map the data
+        forAll(map, i)
         {
-            if (isSet.test(id))
+            if (set.contains(map[i]))
             {
-                ++nSet;
+                subset.insert(i);
             }
         }
 
         subSets.set
         (
             seti,
-            new TopoSet(subMesh, set.name(), nSet, IOobject::AUTO_WRITE)
+            new TopoSet
+            (
+                subMesh,
+                set.name(),
+                std::move(subset),
+                IOobjectOption::AUTO_WRITE
+            )
         );
-        TopoSet& subSet = subSets[seti];
-
-        forAll(map, i)
-        {
-            if (isSet.test(map[i]))
-            {
-                subSet.insert(i);
-            }
-        }
     }
 }
 
@@ -613,6 +640,7 @@ label findPatch(const polyBoundaryMesh& patches, const word& patchName)
 }
 
 
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 int main(int argc, char *argv[])
 {
@@ -844,138 +872,117 @@ int main(int argc, char *argv[])
             }
         }
     }
-    // Read vol fields and subset.
 
-    wordList scalarNames(objects.sortedNames<volScalarField>());
-    PtrList<volScalarField> scalarFlds(scalarNames.size());
-    subsetVolFields
+    // Read vol fields and subset.
+    PtrList<volScalarField> scalarFlds
     (
-        subsetter,
-        objects,
-        defaultPatchi,
-        scalar(Zero),
-        scalarFlds
+        subsetVolFields<scalar>
+        (
+            subsetter,
+            objects,
+            defaultPatchi,
+            scalar(Zero)
+        )
     );
 
-    wordList vectorNames(objects.sortedNames<volVectorField>());
-    PtrList<volVectorField> vectorFlds(vectorNames.size());
-    subsetVolFields
+    PtrList<volVectorField> vectorFlds
     (
-        subsetter,
-        objects,
-        defaultPatchi,
-        vector(Zero),
-        vectorFlds
+        subsetVolFields<vector>
+        (
+            subsetter,
+            objects,
+            defaultPatchi,
+            vector(Zero)
+        )
     );
 
-    wordList sphTensorNames
-    (
-        objects.sortedNames<volSphericalTensorField>()
-    );
     PtrList<volSphericalTensorField> sphTensorFlds
     (
-        sphTensorNames.size()
-    );
-    subsetVolFields
-    (
-        subsetter,
-        objects,
-        defaultPatchi,
-        sphericalTensor(Zero),
-        sphTensorFlds
+        subsetVolFields<sphericalTensor>
+        (
+            subsetter,
+            objects,
+            defaultPatchi,
+            sphericalTensor(Zero)
+        )
     );
 
-    wordList symmTensorNames(objects.sortedNames<volSymmTensorField>());
-    PtrList<volSymmTensorField> symmTensorFlds(symmTensorNames.size());
-    subsetVolFields
+    PtrList<volSymmTensorField> symmTensorFlds
     (
-        subsetter,
-        objects,
-        defaultPatchi,
-        symmTensor(Zero),
-        symmTensorFlds
+        subsetVolFields<symmTensor>
+        (
+            subsetter,
+            objects,
+            defaultPatchi,
+            symmTensor(Zero)
+        )
     );
 
-    wordList tensorNames(objects.sortedNames<volTensorField>());
-    PtrList<volTensorField> tensorFlds(tensorNames.size());
-    subsetVolFields
+    PtrList<volTensorField> tensorFlds
     (
-        subsetter,
-        objects,
-        defaultPatchi,
-        tensor(Zero),
-        tensorFlds
+        subsetVolFields<tensor>
+        (
+            subsetter,
+            objects,
+            defaultPatchi,
+            tensor(Zero)
+        )
     );
 
     // Read surface fields and subset.
-
-    wordList surfScalarNames(objects.sortedNames<surfaceScalarField>());
-    PtrList<surfaceScalarField> surfScalarFlds(surfScalarNames.size());
-    subsetSurfaceFields
+    PtrList<surfaceScalarField> surfScalarFlds
     (
-        subsetter,
-        objects,
-        defaultPatchi,
-        scalar(Zero),
-        surfScalarFlds
+        subsetSurfaceFields<scalar>
+        (
+            subsetter,
+            objects,
+            defaultPatchi,
+            scalar(Zero)
+        )
     );
 
-    wordList surfVectorNames(objects.sortedNames<surfaceVectorField>());
-    PtrList<surfaceVectorField> surfVectorFlds(surfVectorNames.size());
-    subsetSurfaceFields
+    PtrList<surfaceVectorField> surfVectorFlds
     (
-        subsetter,
-        objects,
-        defaultPatchi,
-        vector(Zero),
-        surfVectorFlds
+        subsetSurfaceFields<vector>
+        (
+            subsetter,
+            objects,
+            defaultPatchi,
+            vector(Zero)
+        )
     );
 
-    wordList surfSphTensorNames
-    (
-        objects.sortedNames<surfaceSphericalTensorField>()
-    );
     PtrList<surfaceSphericalTensorField> surfSphericalTensorFlds
     (
-        surfSphTensorNames.size()
-    );
-    subsetSurfaceFields
-    (
-        subsetter,
-        objects,
-        defaultPatchi,
-        sphericalTensor(Zero),
-        surfSphericalTensorFlds
-    );
-
-    wordList surfSymmTensorNames
-    (
-        objects.sortedNames<surfaceSymmTensorField>()
+        subsetSurfaceFields<sphericalTensor>
+        (
+            subsetter,
+            objects,
+            defaultPatchi,
+            sphericalTensor(Zero)
+        )
     );
 
     PtrList<surfaceSymmTensorField> surfSymmTensorFlds
     (
-        surfSymmTensorNames.size()
-    );
-
-    subsetSurfaceFields
-    (
-        subsetter,
-        objects,
-        defaultPatchi,
-        symmTensor(Zero),
-        surfSymmTensorFlds
+        subsetSurfaceFields<symmTensor>
+        (
+            subsetter,
+            objects,
+            defaultPatchi,
+            symmTensor(Zero)
+        )
     );
 
-    wordList surfTensorNames(objects.sortedNames<surfaceTensorField>());
-    PtrList<surfaceTensorField> surfTensorFlds(surfTensorNames.size());
-    subsetSurfaceFields
+    PtrList<surfaceTensorField> surfTensorFlds
     (
-        subsetter,
-        objects,
-        defaultPatchi,
-        tensor(Zero),
-        surfTensorFlds
+        subsetSurfaceFields<tensor>
+        (
+            subsetter,
+            objects,
+            defaultPatchi,
+            tensor(Zero)
+        )
     );
 
 
@@ -1017,62 +1024,8 @@ int main(int argc, char *argv[])
         ++runTime;
     }
 
-    Info<< "Writing mesh without blockedCells to time " << runTime.value()
-        << endl;
-
-    // Subsetting adds 'subset' prefix. Rename field to be like original.
-    forAll(scalarFlds, i)
-    {
-        scalarFlds[i].rename(scalarNames[i]);
-        scalarFlds[i].writeOpt(IOobject::AUTO_WRITE);
-    }
-    forAll(vectorFlds, i)
-    {
-        vectorFlds[i].rename(vectorNames[i]);
-        vectorFlds[i].writeOpt(IOobject::AUTO_WRITE);
-    }
-    forAll(sphTensorFlds, i)
-    {
-        sphTensorFlds[i].rename(sphTensorNames[i]);
-        sphTensorFlds[i].writeOpt(IOobject::AUTO_WRITE);
-    }
-    forAll(symmTensorFlds, i)
-    {
-        symmTensorFlds[i].rename(symmTensorNames[i]);
-        symmTensorFlds[i].writeOpt(IOobject::AUTO_WRITE);
-    }
-    forAll(tensorFlds, i)
-    {
-        tensorFlds[i].rename(tensorNames[i]);
-        tensorFlds[i].writeOpt(IOobject::AUTO_WRITE);
-    }
-
-    // Surface ones.
-    forAll(surfScalarFlds, i)
-    {
-        surfScalarFlds[i].rename(surfScalarNames[i]);
-        surfScalarFlds[i].writeOpt(IOobject::AUTO_WRITE);
-    }
-    forAll(surfVectorFlds, i)
-    {
-        surfVectorFlds[i].rename(surfVectorNames[i]);
-        surfVectorFlds[i].writeOpt(IOobject::AUTO_WRITE);
-    }
-    forAll(surfSphericalTensorFlds, i)
-    {
-        surfSphericalTensorFlds[i].rename(surfSphTensorNames[i]);
-        surfSphericalTensorFlds[i].writeOpt(IOobject::AUTO_WRITE);
-    }
-    forAll(surfSymmTensorFlds, i)
-    {
-        surfSymmTensorFlds[i].rename(surfSymmTensorNames[i]);
-        surfSymmTensorFlds[i].writeOpt(IOobject::AUTO_WRITE);
-    }
-    forAll(surfTensorNames, i)
-    {
-        surfTensorFlds[i].rename(surfTensorNames[i]);
-        surfTensorFlds[i].writeOpt(IOobject::AUTO_WRITE);
-    }
+    Info<< "Writing mesh without blockedCells to time "
+        << runTime.value() << endl;
 
     subsetter.subMesh().write();
 
diff --git a/applications/utilities/mesh/manipulation/rotateMesh/rotateMesh.C b/applications/utilities/mesh/manipulation/rotateMesh/rotateMesh.C
index 19405995ef5..c798553561f 100644
--- a/applications/utilities/mesh/manipulation/rotateMesh/rotateMesh.C
+++ b/applications/utilities/mesh/manipulation/rotateMesh/rotateMesh.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2019-2022 OpenCFD Ltd.
+    Copyright (C) 2019-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -55,12 +55,9 @@ void ReadAndRotateFields
     const dimensionedTensor& rotT
 )
 {
-    // Objects of field type
-    IOobjectList fields(objects.lookupClass<GeoField>());
-
-    forAllConstIters(fields, fieldIter)
+    for (const IOobject& io : objects.csorted<GeoField>())
     {
-        GeoField fld(*fieldIter(), mesh);
+        GeoField fld(io, mesh);
         Info<< "    Rotating " << fld.name() << endl;
         transform(fld, rotT, fld);
         fld.write();
diff --git a/applications/utilities/mesh/manipulation/splitMeshRegions/splitMeshRegions.C b/applications/utilities/mesh/manipulation/splitMeshRegions/splitMeshRegions.C
index 6dcd2f11999..fcb64691812 100644
--- a/applications/utilities/mesh/manipulation/splitMeshRegions/splitMeshRegions.C
+++ b/applications/utilities/mesh/manipulation/splitMeshRegions/splitMeshRegions.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2017 OpenFOAM Foundation
-    Copyright (C) 2015-2022 OpenCFD Ltd.
+    Copyright (C) 2015-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -164,14 +164,8 @@ void subsetVolFields
 {
     const labelList patchMap(identity(mesh.boundaryMesh().size()));
 
-    HashTable<const GeoField*> fields
-    (
-        mesh.objectRegistry::lookupClass<GeoField>()
-    );
-    forAllConstIters(fields, iter)
+    for (const GeoField& fld : mesh.objectRegistry::csorted<GeoField>())
     {
-        const GeoField& fld = *iter.val();
-
         Info<< "Mapping field " << fld.name() << endl;
 
         tmp<GeoField> tSubFld
@@ -192,8 +186,7 @@ void subsetVolFields
         {
             if (addedPatches.found(patchi))
             {
-                tSubFld.ref().boundaryFieldRef()[patchi] ==
-                    typename GeoField::value_type(Zero);
+                tSubFld.ref().boundaryFieldRef()[patchi] == Zero;
             }
         }
 
@@ -218,14 +211,8 @@ void subsetSurfaceFields
 {
     const labelList patchMap(identity(mesh.boundaryMesh().size()));
 
-    HashTable<const GeoField*> fields
-    (
-        mesh.objectRegistry::lookupClass<GeoField>()
-    );
-    forAllConstIters(fields, iter)
+    for (const GeoField& fld : mesh.objectRegistry::csorted<GeoField>())
     {
-        const GeoField& fld = *iter.val();
-
         Info<< "Mapping field " << fld.name() << endl;
 
         tmp<GeoField> tSubFld
@@ -246,8 +233,7 @@ void subsetSurfaceFields
         {
             if (addedPatches.found(patchi))
             {
-                tSubFld.ref().boundaryFieldRef()[patchi] ==
-                    typename GeoField::value_type(Zero);
+                tSubFld.ref().boundaryFieldRef()[patchi] == Zero;
             }
         }
 
diff --git a/applications/utilities/mesh/manipulation/subsetMesh/subsetMesh.C b/applications/utilities/mesh/manipulation/subsetMesh/subsetMesh.C
index ee0fe7cfaec..3add00384d2 100644
--- a/applications/utilities/mesh/manipulation/subsetMesh/subsetMesh.C
+++ b/applications/utilities/mesh/manipulation/subsetMesh/subsetMesh.C
@@ -149,178 +149,127 @@ labelList nearestPatch(const polyMesh& mesh, const labelList& patchIDs)
 
 
 //
-// Subset field-type, availability information cached
-// in the availableFields hashtable.
+// Subset DimensionedField/GeometricField
 //
-template<class Type, template<class> class PatchField, class GeoMesh>
-void subsetFields
+template<class FieldType>
+PtrList<FieldType> subsetFields
 (
     const fvMeshSubset& subsetter,
-    HashTable<wordHashSet>& availableFields,
-    PtrList<GeometricField<Type, PatchField, GeoMesh>>& subFields
+    const IOobjectList& objects
 )
 {
-    typedef GeometricField<Type, PatchField, GeoMesh> FieldType;
-    const word fieldType = FieldType::typeName;
+    const fvMesh& baseMesh = subsetter.baseMesh();
 
-    const wordList fieldNames = availableFields(fieldType).sortedToc();
-    subFields.setSize(fieldNames.size());
+    const UPtrList<const IOobject> fieldObjects
+    (
+        objects.csorted<FieldType>()
+    );
 
-    const fvMesh& baseMesh = subsetter.baseMesh();
+    PtrList<FieldType> subFields(fieldObjects.size());
 
     label nFields = 0;
-    for (const word& fieldName : fieldNames)
+    for (const IOobject& io : fieldObjects)
     {
         if (!nFields)
         {
-            Info<< "Subsetting " << fieldType << " (";
+            Info<< "Subsetting " << FieldType::typeName << " (";
         }
         else
         {
             Info<< ' ';
         }
-        Info<< fieldName;
+        Info<< io.name();
 
         FieldType fld
         (
             IOobject
             (
-                fieldName,
+                io.name(),
                 baseMesh.time().timeName(),
                 baseMesh,
-                IOobject::MUST_READ,
-                IOobject::NO_WRITE
+                IOobjectOption::MUST_READ,
+                IOobjectOption::NO_WRITE,
+                IOobjectOption::NO_REGISTER
             ),
             baseMesh
         );
 
         subFields.set(nFields, subsetter.interpolate(fld));
+        auto& subField = subFields[nFields];
+        ++nFields;
 
         // Subsetting adds 'subset' prefix - rename to match original.
-        subFields[nFields].rename(fieldName);
-
-        ++nFields;
+        subField.rename(io.name());
     }
 
     if (nFields)
     {
         Info<< ')' << nl;
     }
+
+    return subFields;
 }
 
 
-template<class Type>
-void subsetPointFields
+// Subset point fields
+template<class FieldType>
+PtrList<FieldType> subsetFields
 (
     const fvMeshSubset& subsetter,
-    const pointMesh& pMesh,
-    HashTable<wordHashSet>& availableFields,
-    PtrList<GeometricField<Type, pointPatchField, pointMesh>>& subFields
+    const IOobjectList& objects,
+    const pointMesh& pMesh
 )
 {
-    typedef GeometricField<Type, pointPatchField, pointMesh> FieldType;
-    const word fieldType = FieldType::typeName;
+    const fvMesh& baseMesh = subsetter.baseMesh();
 
-    const wordList fieldNames = availableFields(fieldType).sortedToc();
-    subFields.setSize(fieldNames.size());
+    const UPtrList<const IOobject> fieldObjects
+    (
+        objects.csorted<FieldType>()
+    );
 
-    const fvMesh& baseMesh = subsetter.baseMesh();
+    PtrList<FieldType> subFields(fieldObjects.size());
 
     label nFields = 0;
-    for (const word& fieldName : fieldNames)
+    for (const IOobject& io : fieldObjects)
     {
         if (!nFields)
         {
-            Info<< "Subsetting " << fieldType << " (";
+            Info<< "Subsetting " << FieldType::typeName << " (";
         }
         else
         {
             Info<< ' ';
         }
-        Info<< fieldName;
+        Info<< io.name();
 
         FieldType fld
         (
             IOobject
             (
-                fieldName,
+                io.name(),
                 baseMesh.time().timeName(),
                 baseMesh,
-                IOobject::MUST_READ,
-                IOobject::NO_WRITE
+                IOobjectOption::MUST_READ,
+                IOobjectOption::NO_WRITE,
+                IOobjectOption::NO_REGISTER
             ),
             pMesh
         );
 
         subFields.set(nFields, subsetter.interpolate(fld));
-
-        // Subsetting adds 'subset' prefix - rename to match original.
-        subFields[nFields].rename(fieldName);
-
+        auto& subField = subFields[nFields];
         ++nFields;
-    }
-
-    if (nFields)
-    {
-        Info<< ')' << nl;
-    }
-}
-
-
-template<class Type>
-void subsetDimensionedFields
-(
-    const fvMeshSubset& subsetter,
-    HashTable<wordHashSet>& availableFields,
-    PtrList<DimensionedField<Type, volMesh>>& subFields
-)
-{
-    typedef DimensionedField<Type, volMesh> FieldType;
-    const word fieldType = FieldType::typeName;
-
-    const wordList fieldNames = availableFields(fieldType).sortedToc();
-    subFields.setSize(fieldNames.size());
-
-    const fvMesh& baseMesh = subsetter.baseMesh();
-
-    label nFields = 0;
-    for (const word& fieldName : fieldNames)
-    {
-        if (!nFields)
-        {
-            Info<< "Subsetting " << fieldType << " (";
-        }
-        else
-        {
-            Info<< ' ';
-        }
-        Info<< fieldName;
-
-        FieldType fld
-        (
-            IOobject
-            (
-                fieldName,
-                baseMesh.time().timeName(),
-                baseMesh,
-                IOobject::MUST_READ,
-                IOobject::NO_WRITE
-            ),
-            baseMesh
-        );
-
-        subFields.set(nFields, subsetter.interpolate(fld));
 
         // Subsetting adds 'subset' prefix - rename to match original.
-        subFields[nFields].rename(fieldName);
-
-        ++nFields;
+        subField.rename(io.name());
     }
 
     if (nFields)
     {
         Info<< ')' << nl;
     }
+
+    return subFields;
 }
 
 
@@ -338,7 +287,8 @@ void subsetTopoSets
     PtrList<TopoSet> sets;
     ReadFields<TopoSet>(objects, sets);
 
-    subSets.setSize(sets.size());
+    subSets.resize_null(sets.size());
+
     forAll(sets, seti)
     {
         const TopoSet& set = sets[seti];
@@ -347,6 +297,7 @@ void subsetTopoSets
 
         labelHashSet subset(2*min(set.size(), map.size()));
 
+        // Map the data
         forAll(map, i)
         {
             if (set.found(map[i]))
@@ -363,13 +314,14 @@ void subsetTopoSets
                 subMesh,
                 set.name(),
                 std::move(subset),
-                IOobject::AUTO_WRITE
+                IOobjectOption::AUTO_WRITE
             )
         );
     }
 }
 
 
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 int main(int argc, char *argv[])
 {
@@ -568,54 +520,51 @@ int main(int argc, char *argv[])
             );
         }
 
-        Info<< "Subset "
-            << returnReduce(subsetter.subMesh().nCells(), sumOp<label>())
-            << " of "
-            << returnReduce(mesh.nCells(), sumOp<label>())
+        FixedList<label, 2> cellCount;
+        cellCount[0] = subsetter.subMesh().nCells();
+        cellCount[1] = mesh.nCells();
+        reduce(cellCount, sumOp<label>());
+
+        Info<< "Subset " << cellCount[0] << " of " << cellCount[1]
             << " cells" << nl << nl;
     }
 
 
     IOobjectList objects(mesh, runTime.timeName());
-    HashTable<wordHashSet> availableFields = objects.classes();
-
-
-    // Read vol fields and subset
-    // ~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-    PtrList<volScalarField> vScalarFlds;
-    subsetFields(subsetter, availableFields, vScalarFlds);
 
-    PtrList<volVectorField> vVectorFlds;
-    subsetFields(subsetter, availableFields, vVectorFlds);
-
-    PtrList<volSphericalTensorField> vSphTensorFlds;
-    subsetFields(subsetter, availableFields, vSphTensorFlds);
-
-    PtrList<volSymmTensorField> vSymmTensorFlds;
-    subsetFields(subsetter, availableFields, vSymmTensorFlds);
+    // Read fields and subset
+    #undef  createSubsetFields
+    #define createSubsetFields(FieldType, Variable)             \
+    PtrList<FieldType> Variable                                 \
+    (                                                           \
+        subsetFields<FieldType>(subsetter, objects)             \
+    );
 
-    PtrList<volTensorField> vTensorFlds;
-    subsetFields(subsetter, availableFields, vTensorFlds);
 
+    // Read vol fields and subset
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~
+    createSubsetFields(volScalarField, vScalarFlds);
+    createSubsetFields(volVectorField, vVectorFlds);
+    createSubsetFields(volSphericalTensorField, vSphTensorFlds);
+    createSubsetFields(volSymmTensorField, vSymmTensorFlds);
+    createSubsetFields(volTensorField, vTensorFlds);
 
     // Read surface fields and subset
     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    createSubsetFields(surfaceScalarField, sScalarFlds);
+    createSubsetFields(surfaceVectorField, sVectorFlds);
+    createSubsetFields(surfaceSphericalTensorField, sSphTensorFlds);
+    createSubsetFields(surfaceSymmTensorField, sSymmTensorFlds);
+    createSubsetFields(surfaceTensorField, sTensorFlds);
 
-    PtrList<surfaceScalarField> sScalarFlds;
-    subsetFields(subsetter, availableFields, sScalarFlds);
-
-    PtrList<surfaceVectorField> sVectorFlds;
-    subsetFields(subsetter, availableFields, sVectorFlds);
-
-    PtrList<surfaceSphericalTensorField> sSphTensorFlds;
-    subsetFields(subsetter, availableFields, sSphTensorFlds);
-
-    PtrList<surfaceSymmTensorField> sSymmTensorFlds;
-    subsetFields(subsetter, availableFields, sSymmTensorFlds);
-
-    PtrList<surfaceTensorField> sTensorFlds;
-    subsetFields(subsetter, availableFields, sTensorFlds);
+    // Read dimensioned fields and subset
+    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    createSubsetFields(volScalarField::Internal, dScalarFlds);
+    createSubsetFields(volVectorField::Internal, dVectorFlds);
+    createSubsetFields(volSphericalTensorField::Internal, dSphTensorFlds);
+    createSubsetFields(volSymmTensorField::Internal, dSymmTensorFlds);
+    createSubsetFields(volTensorField::Internal, dTensorFlds);
 
 
     // Read point fields and subset
@@ -623,39 +572,20 @@ int main(int argc, char *argv[])
 
     const pointMesh& pMesh = pointMesh::New(mesh);
 
-    PtrList<pointScalarField> pScalarFlds;
-    subsetPointFields(subsetter, pMesh, availableFields, pScalarFlds);
-
-    PtrList<pointVectorField> pVectorFlds;
-    subsetPointFields(subsetter, pMesh, availableFields, pVectorFlds);
-
-    PtrList<pointSphericalTensorField> pSphTensorFlds;
-    subsetPointFields(subsetter, pMesh, availableFields, pSphTensorFlds);
-
-    PtrList<pointSymmTensorField> pSymmTensorFlds;
-    subsetPointFields(subsetter, pMesh, availableFields, pSymmTensorFlds);
-
-    PtrList<pointTensorField> pTensorFlds;
-    subsetPointFields(subsetter, pMesh, availableFields, pTensorFlds);
-
-
-    // Read dimensioned fields and subset
-    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-    PtrList<volScalarField::Internal> dScalarFlds;
-    subsetDimensionedFields(subsetter, availableFields, dScalarFlds);
-
-    PtrList<volVectorField::Internal> dVectorFlds;
-    subsetDimensionedFields(subsetter, availableFields, dVectorFlds);
-
-    PtrList<volSphericalTensorField::Internal> dSphTensorFlds;
-    subsetDimensionedFields(subsetter, availableFields, dSphTensorFlds);
+    #undef  createSubsetFields
+    #define createSubsetFields(FieldType, Variable)             \
+    PtrList<FieldType> Variable                                 \
+    (                                                           \
+        subsetFields<FieldType>(subsetter, objects, pMesh)      \
+    );
 
-    PtrList<volSymmTensorField::Internal> dSymmTensorFlds;
-    subsetDimensionedFields(subsetter, availableFields, dSymmTensorFlds);
+    createSubsetFields(pointScalarField, pScalarFlds);
+    createSubsetFields(pointVectorField, pVectorFlds);
+    createSubsetFields(pointSphericalTensorField, pSphTensorFlds);
+    createSubsetFields(pointSymmTensorField, pSymmTensorFlds);
+    createSubsetFields(pointTensorField, pTensorFlds);
 
-    PtrList<volTensorField::Internal> dTensorFlds;
-    subsetDimensionedFields(subsetter, availableFields, dTensorFlds);
+    #undef createSubsetFields
 
 
     // Read topoSets and subset
@@ -735,13 +665,6 @@ int main(int argc, char *argv[])
     for (const auto& fld : sSymmTensorFlds) { fld.write(); }
     for (const auto& fld : sTensorFlds)     { fld.write(); }
 
-    // Point fields
-    for (const auto& fld : pScalarFlds)     { fld.write(); }
-    for (const auto& fld : pVectorFlds)     { fld.write(); }
-    for (const auto& fld : pSphTensorFlds)  { fld.write(); }
-    for (const auto& fld : pSymmTensorFlds) { fld.write(); }
-    for (const auto& fld : pTensorFlds)     { fld.write(); }
-
     // Dimensioned fields
     for (const auto& fld : dScalarFlds)     { fld.write(); }
     for (const auto& fld : dVectorFlds)     { fld.write(); }
@@ -749,6 +672,13 @@ int main(int argc, char *argv[])
     for (const auto& fld : dSymmTensorFlds) { fld.write(); }
     for (const auto& fld : dTensorFlds)     { fld.write(); }
 
+    // Point fields
+    for (const auto& fld : pScalarFlds)     { fld.write(); }
+    for (const auto& fld : pVectorFlds)     { fld.write(); }
+    for (const auto& fld : pSphTensorFlds)  { fld.write(); }
+    for (const auto& fld : pSymmTensorFlds) { fld.write(); }
+    for (const auto& fld : pTensorFlds)     { fld.write(); }
+
     Info<< "\nEnd\n" << endl;
 
     return 0;
diff --git a/applications/utilities/miscellaneous/patchSummary/patchSummary.C b/applications/utilities/miscellaneous/patchSummary/patchSummary.C
index 857862a8395..14d9e3f9ea6 100644
--- a/applications/utilities/miscellaneous/patchSummary/patchSummary.C
+++ b/applications/utilities/miscellaneous/patchSummary/patchSummary.C
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
+    Copyright (C) 2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -89,50 +90,41 @@ int main(int argc, char *argv[])
                 << endl;
         }
 
-        const wordList objNames
-        (
-            IOobjectList(mesh, runTime.timeName()).sortedNames()
+        const IOobjectList objects(mesh, runTime.timeName());
+
+        Info<< "Reading fields:" << endl;
+
+        // Read fields
+        #undef  createFields
+        #define createFields(FieldType, Variable)                   \
+        PtrList<FieldType> Variable                                 \
+        (                                                           \
+            readFields<FieldType>(objects, mesh)                    \
         );
 
-        PtrList<volScalarField> vsf(objNames.size());
-        PtrList<volVectorField> vvf(objNames.size());
-        PtrList<volSphericalTensorField> vsptf(objNames.size());
-        PtrList<volSymmTensorField> vsytf(objNames.size());
-        PtrList<volTensorField> vtf(objNames.size());
+        createFields(volScalarField, vsf);
+        createFields(volVectorField, vvf);
+        createFields(volSphericalTensorField, vsptf);
+        createFields(volSymmTensorField, vsytf);
+        createFields(volTensorField, vtf);
 
-        PtrList<pointScalarField> psf(objNames.size());
-        PtrList<pointVectorField> pvf(objNames.size());
-        PtrList<pointSphericalTensorField> psptf(objNames.size());
-        PtrList<pointSymmTensorField> psytf(objNames.size());
-        PtrList<pointTensorField> ptf(objNames.size());
+        // Point fields
+        const pointMesh& pMesh = pointMesh::New(mesh);
 
-        Info<< "Valid fields:" << endl;
+        #undef  createFields
+        #define createFields(FieldType, Variable)                   \
+        PtrList<FieldType> Variable                                 \
+        (                                                           \
+            readFields<FieldType>(objects, pMesh)                   \
+        );
 
-        forAll(objNames, objI)
-        {
-            IOobject obj
-            (
-                objNames[objI],
-                runTime.timeName(),
-                mesh,
-                IOobject::MUST_READ
-            );
-
-            if (obj.typeHeaderOk<volScalarField>(false))
-            {
-                addToFieldList(vsf, obj, objI, mesh);
-                addToFieldList(vvf, obj, objI, mesh);
-                addToFieldList(vsptf, obj, objI, mesh);
-                addToFieldList(vsytf, obj, objI, mesh);
-                addToFieldList(vtf, obj, objI, mesh);
-
-                addToFieldList(psf, obj, objI, pointMesh::New(mesh));
-                addToFieldList(pvf, obj, objI, pointMesh::New(mesh));
-                addToFieldList(psptf, obj, objI, pointMesh::New(mesh));
-                addToFieldList(psytf, obj, objI, pointMesh::New(mesh));
-                addToFieldList(ptf, obj, objI, pointMesh::New(mesh));
-            }
-        }
+        createFields(pointScalarField, psf);
+        createFields(pointVectorField, pvf);
+        createFields(pointSphericalTensorField, psptf);
+        createFields(pointSymmTensorField, psytf);
+        createFields(pointTensorField, ptf);
+
+        #undef createFields
 
         Info<< endl;
 
@@ -144,6 +136,7 @@ int main(int argc, char *argv[])
             forAll(bm, patchi)
             {
                 Info<< bm[patchi].type() << "\t: " << bm[patchi].name() << nl;
+
                 outputFieldList(vsf, patchi);
                 outputFieldList(vvf, patchi);
                 outputFieldList(vsptf, patchi);
@@ -167,6 +160,7 @@ int main(int argc, char *argv[])
             DynamicList<HashTable<word>> fieldToTypes(bm.size());
             // Per 'group' the patches
             DynamicList<DynamicList<label>> groupToPatches(bm.size());
+
             forAll(bm, patchi)
             {
                 HashTable<word> fieldToType;
@@ -208,40 +202,39 @@ int main(int argc, char *argv[])
                     labelHashSet nonGroupPatches;
                     bm.matchGroups(patchIDs, groups, nonGroupPatches);
 
-                    const labelList sortedPatches(nonGroupPatches.sortedToc());
-                    forAll(sortedPatches, i)
+                    for (const label patchi : nonGroupPatches.sortedToc())
                     {
-                        Info<< bm[sortedPatches[i]].type()
-                            << "\t: " << bm[sortedPatches[i]].name() << nl;
+                        Info<< bm[patchi].type()
+                            << "\t: " << bm[patchi].name() << nl;
                     }
-                    if (groups.size())
+                    for (const word& groupName : groups)
                     {
-                        forAll(groups, i)
-                        {
-                            Info<< "group\t: " << groups[i] << nl;
-                        }
+                        Info<< "group\t: " << groupName << nl;
                     }
-                    outputFieldList(vsf, patchIDs[0]);
-                    outputFieldList(vvf, patchIDs[0]);
-                    outputFieldList(vsptf, patchIDs[0]);
-                    outputFieldList(vsytf, patchIDs[0]);
-                    outputFieldList(vtf, patchIDs[0]);
-
-                    outputFieldList(psf, patchIDs[0]);
-                    outputFieldList(pvf, patchIDs[0]);
-                    outputFieldList(psptf, patchIDs[0]);
-                    outputFieldList(psytf, patchIDs[0]);
-                    outputFieldList(ptf, patchIDs[0]);
+
+                    const label patchi = patchIDs[0];
+
+                    outputFieldList(vsf, patchi);
+                    outputFieldList(vvf, patchi);
+                    outputFieldList(vsptf, patchi);
+                    outputFieldList(vsytf, patchi);
+                    outputFieldList(vtf, patchi);
+
+                    outputFieldList(psf, patchi);
+                    outputFieldList(pvf, patchi);
+                    outputFieldList(psptf, patchi);
+                    outputFieldList(psytf, patchi);
+                    outputFieldList(ptf, patchi);
                     Info<< endl;
                 }
                 else
                 {
                     // No group.
-                    forAll(patchIDs, i)
+                    for (const label patchi : patchIDs)
                     {
-                        label patchi = patchIDs[i];
                         Info<< bm[patchi].type()
                             << "\t: " << bm[patchi].name() << nl;
+
                         outputFieldList(vsf, patchi);
                         outputFieldList(vvf, patchi);
                         outputFieldList(vsptf, patchi);
diff --git a/applications/utilities/miscellaneous/patchSummary/patchSummaryTemplates.C b/applications/utilities/miscellaneous/patchSummary/patchSummaryTemplates.C
index 96ec1ead4e0..00077b0501c 100644
--- a/applications/utilities/miscellaneous/patchSummary/patchSummaryTemplates.C
+++ b/applications/utilities/miscellaneous/patchSummary/patchSummaryTemplates.C
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
+    Copyright (C) 2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -31,30 +32,49 @@ License
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 template<class GeoField>
-void Foam::addToFieldList
+Foam::PtrList<GeoField> Foam::readFields
 (
-    PtrList<GeoField>& fieldList,
-    const IOobject& obj,
-    const label fieldi,
+    const IOobjectList& objects,
     const typename GeoField::Mesh& mesh
 )
 {
-    if (obj.isHeaderClass<GeoField>())
+    const UPtrList<const IOobject> fieldObjects
+    (
+        objects.csorted<GeoField>()
+    );
+
+    PtrList<GeoField> fields(fieldObjects.size());
+
+    label nFields = 0;
+    for (const IOobject& io : fieldObjects)
     {
-        fieldList.set
-        (
-            fieldi,
-            new GeoField(obj, mesh)
-        );
-        Info<< "    " << GeoField::typeName << tab << obj.name() << endl;
+        if (!nFields)
+        {
+            Info<< "    " << GeoField::typeName << " (";
+        }
+        else
+        {
+            Info<< ' ';
+        }
+        Info<< io.name();
+
+        fields.emplace_set(nFields, io, mesh);
+        ++nFields;
     }
+
+    if (nFields)
+    {
+        Info<< ')' << nl;
+    }
+
+    return fields;
 }
 
 
 template<class GeoField>
 void Foam::outputFieldList
 (
-    const PtrList<GeoField>& fieldList,
+    const UPtrList<GeoField>& fieldList,
     const label patchi
 )
 {
@@ -74,7 +94,7 @@ void Foam::outputFieldList
 template<class GeoField>
 void Foam::collectFieldList
 (
-    const PtrList<GeoField>& fieldList,
+    const UPtrList<GeoField>& fieldList,
     const label patchi,
     HashTable<word>& fieldToType
 )
diff --git a/applications/utilities/miscellaneous/patchSummary/patchSummaryTemplates.H b/applications/utilities/miscellaneous/patchSummary/patchSummaryTemplates.H
index 480b7afd973..b0c35235bf3 100644
--- a/applications/utilities/miscellaneous/patchSummary/patchSummaryTemplates.H
+++ b/applications/utilities/miscellaneous/patchSummary/patchSummaryTemplates.H
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
+    Copyright (C) 2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -25,39 +26,39 @@ License
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef patchSummaryTemplates_H
-#define patchSummaryTemplates_H
+#ifndef Foam_patchSummaryTemplates_H
+#define Foam_patchSummaryTemplates_H
 
-#include "fvCFD.H"
 #include "volFields.H"
+#include "IOobjectList.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 namespace Foam
 {
-    template<class GeoField>
-    void addToFieldList
-    (
-        PtrList<GeoField>& fieldList,
-        const IOobject& obj,
-        const label fieldi,
-        const typename GeoField::Mesh& mesh
-    );
-
-    template<class GeoField>
-    void outputFieldList
-    (
-        const PtrList<GeoField>& fieldList,
-        const label patchi
-    );
-
-    template<class GeoField>
-    void collectFieldList
-    (
-        const PtrList<GeoField>& fieldList,
-        const label patchi,
-        HashTable<word>& fieldToType
-    );
+
+template<class GeoField>
+PtrList<GeoField> readFields
+(
+    const IOobjectList& objects,
+    const typename GeoField::Mesh& mesh
+);
+
+template<class GeoField>
+void outputFieldList
+(
+    const UPtrList<GeoField>& fieldList,
+    const label patchi
+);
+
+template<class GeoField>
+void collectFieldList
+(
+    const UPtrList<GeoField>& fieldList,
+    const label patchi,
+    HashTable<word>& fieldToType
+);
+
 } // End namespace Foam
 
 
diff --git a/applications/utilities/parallelProcessing/decomposePar/domainDecomposition.C b/applications/utilities/parallelProcessing/decomposePar/domainDecomposition.C
index b74b27975be..44526285c78 100644
--- a/applications/utilities/parallelProcessing/decomposePar/domainDecomposition.C
+++ b/applications/utilities/parallelProcessing/decomposePar/domainDecomposition.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2019-2022 OpenCFD Ltd.
+    Copyright (C) 2019-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -186,26 +186,17 @@ bool Foam::domainDecomposition::writeDecomposition(const bool decomposeSets)
     {
         // Read sets
         IOobjectList objects(*this, facesInstance(), "polyMesh/sets");
+        for (const IOobject& io : objects.csorted<cellSet>())
         {
-            IOobjectList sets(objects.lookupClass<cellSet>());
-            forAllConstIters(sets, iter)
-            {
-                cellSets.append(new cellSet(*(iter.val())));
-            }
+            cellSets.emplace_back(io);
         }
+        for (const IOobject& io : objects.csorted<faceSet>())
         {
-            IOobjectList sets(objects.lookupClass<faceSet>());
-            forAllConstIters(sets, iter)
-            {
-                faceSets.append(new faceSet(*(iter.val())));
-            }
+            faceSets.emplace_back(io);
         }
+        for (const IOobject& io : objects.csorted<pointSet>())
         {
-            IOobjectList sets(objects.lookupClass<pointSet>());
-            forAllConstIters(sets, iter)
-            {
-                pointSets.append(new pointSet(*(iter.val())));
-            }
+            pointSets.emplace_back(io);
         }
     }
 
@@ -219,9 +210,9 @@ bool Foam::domainDecomposition::writeDecomposition(const bool decomposeSets)
             facesInstance(),
             polyMesh::meshSubDir,
             *this,
-            IOobject::READ_IF_PRESENT,
-            IOobject::NO_WRITE,
-            IOobject::NO_REGISTER
+            IOobjectOption::READ_IF_PRESENT,
+            IOobjectOption::NO_WRITE,
+            IOobjectOption::NO_REGISTER
         )
     );
 
diff --git a/applications/utilities/parallelProcessing/reconstructPar/reconstructPar.C b/applications/utilities/parallelProcessing/reconstructPar/reconstructPar.C
index 1ae4fb4ca88..0dd1078dd0a 100644
--- a/applications/utilities/parallelProcessing/reconstructPar/reconstructPar.C
+++ b/applications/utilities/parallelProcessing/reconstructPar/reconstructPar.C
@@ -597,19 +597,19 @@ int main(int argc, char *argv[])
                         polyMesh::meshSubDir/"sets"
                     );
 
-                    for (const word& setName : objects.sortedNames<cellSet>())
+                    for (const IOobject& io : objects.csorted<cellSet>())
                     {
-                        cSetNames.insert(setName, cSetNames.size());
+                        cSetNames.insert(io.name(), cSetNames.size());
                     }
 
-                    for (const word& setName : objects.sortedNames<faceSet>())
+                    for (const IOobject& io : objects.csorted<faceSet>())
                     {
-                        fSetNames.insert(setName, fSetNames.size());
+                        fSetNames.insert(io.name(), fSetNames.size());
                     }
 
-                    for (const word& setName : objects.sortedNames<pointSet>())
+                    for (const IOobject& io : objects.csorted<pointSet>())
                     {
-                        pSetNames.insert(setName, pSetNames.size());
+                        pSetNames.insert(io.name(), pSetNames.size());
                     }
                 }
 
diff --git a/applications/utilities/parallelProcessing/redistributePar/parFvFieldDistributorTemplates.C b/applications/utilities/parallelProcessing/redistributePar/parFvFieldDistributorTemplates.C
index 9b347a17dba..2f65cef9037 100644
--- a/applications/utilities/parallelProcessing/redistributePar/parFvFieldDistributorTemplates.C
+++ b/applications/utilities/parallelProcessing/redistributePar/parFvFieldDistributorTemplates.C
@@ -405,20 +405,20 @@ Foam::label Foam::parFvFieldDistributor::distributeInternalFields
 {
     typedef DimensionedField<Type, volMesh> fieldType;
 
-    // Available fields, sorted order
-    const wordList fieldNames =
-    (
-        selectedFields.empty()
-      ? objects.sortedNames<fieldType>()
-      : objects.sortedNames<fieldType>(selectedFields)
-    );
-
     label nFields = 0;
-    for (const word& fieldName : fieldNames)
+    for
+    (
+        const IOobject& io :
+        (
+            selectedFields.empty()
+          ? objects.csorted<fieldType>()
+          : objects.csorted<fieldType>(selectedFields)
+        )
+    )
     {
-        if ("cellDist" == fieldName)
+        if ("cellDist" == io.name())
         {
-            // There is an odd chance this is an internal field
+            // Ignore cellDist (internal or volume) field
             continue;
         }
         if (verbose_)
@@ -428,13 +428,13 @@ Foam::label Foam::parFvFieldDistributor::distributeInternalFields
                 Info<< "    Reconstructing "
                     << fieldType::typeName << "s\n" << nl;
             }
-            Info<< "        " << fieldName << nl;
+            Info<< "        " << io.name() << nl;
         }
         ++nFields;
 
         tmp<fieldType> tfld
         (
-            distributeInternalField<Type>(*(objects[fieldName]))
+            distributeInternalField<Type>(io)
         );
 
         if (isWriteProc_.good())
@@ -470,19 +470,20 @@ Foam::label Foam::parFvFieldDistributor::distributeVolumeFields
 {
     typedef GeometricField<Type, fvPatchField, volMesh> fieldType;
 
-    // Available fields, sorted order
-    const wordList fieldNames =
-    (
-        selectedFields.empty()
-      ? objects.sortedNames<fieldType>()
-      : objects.sortedNames<fieldType>(selectedFields)
-    );
-
     label nFields = 0;
-    for (const word& fieldName : fieldNames)
+    for
+    (
+        const IOobject& io :
+        (
+            selectedFields.empty()
+          ? objects.csorted<fieldType>()
+          : objects.csorted<fieldType>(selectedFields)
+        )
+    )
     {
-        if ("cellDist" == fieldName)
+        if ("cellDist" == io.name())
         {
+            // Ignore cellDist (internal or volume) field
             continue;
         }
         if (verbose_)
@@ -492,13 +493,13 @@ Foam::label Foam::parFvFieldDistributor::distributeVolumeFields
                 Info<< "    Reconstructing "
                     << fieldType::typeName << "s\n" << nl;
             }
-            Info<< "        " << fieldName << nl;
+            Info<< "        " << io.name() << nl;
         }
         ++nFields;
 
         tmp<fieldType> tfld
         (
-            distributeVolumeField<Type>(*(objects[fieldName]))
+            distributeVolumeField<Type>(io)
         );
 
         if (isWriteProc_.good())
@@ -534,16 +535,16 @@ Foam::label Foam::parFvFieldDistributor::distributeSurfaceFields
 {
     typedef GeometricField<Type, fvsPatchField, surfaceMesh> fieldType;
 
-    // Available fields, sorted order
-    const wordList fieldNames =
-    (
-        selectedFields.empty()
-      ? objects.sortedNames<fieldType>()
-      : objects.sortedNames<fieldType>(selectedFields)
-    );
-
     label nFields = 0;
-    for (const word& fieldName : fieldNames)
+    for
+    (
+        const IOobject& io :
+        (
+            selectedFields.empty()
+          ? objects.csorted<fieldType>()
+          : objects.csorted<fieldType>(selectedFields)
+        )
+    )
     {
         if (verbose_)
         {
@@ -552,13 +553,13 @@ Foam::label Foam::parFvFieldDistributor::distributeSurfaceFields
                 Info<< "    Reconstructing "
                     << fieldType::typeName << "s\n" << nl;
             }
-            Info<< "        " << fieldName << nl;
+            Info<< "        " << io.name() << nl;
         }
         ++nFields;
 
         tmp<fieldType> tfld
         (
-            distributeSurfaceField<Type>(*(objects[fieldName]))
+            distributeSurfaceField<Type>(io)
         );
 
         if (isWriteProc_.good())
diff --git a/applications/utilities/parallelProcessing/redistributePar/parLagrangianDistributor.C b/applications/utilities/parallelProcessing/redistributePar/parLagrangianDistributor.C
index 820434fcb85..b269a43a3c7 100644
--- a/applications/utilities/parallelProcessing/redistributePar/parLagrangianDistributor.C
+++ b/applications/utilities/parallelProcessing/redistributePar/parLagrangianDistributor.C
@@ -82,7 +82,7 @@ void Foam::parLagrangianDistributor::findClouds
         )
     );
 
-    cloudNames.setSize(localCloudDirs.size());
+    cloudNames.resize_nocopy(localCloudDirs.size());
     forAll(localCloudDirs, i)
     {
         cloudNames[i] = localCloudDirs[i];
diff --git a/applications/utilities/parallelProcessing/redistributePar/parLagrangianDistributorTemplates.C b/applications/utilities/parallelProcessing/redistributePar/parLagrangianDistributorTemplates.C
index 8cb5119bedb..3ea8ec4a50b 100644
--- a/applications/utilities/parallelProcessing/redistributePar/parLagrangianDistributorTemplates.C
+++ b/applications/utilities/parallelProcessing/redistributePar/parLagrangianDistributorTemplates.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2015 OpenFOAM Foundation
-    Copyright (C) 2018-2022 OpenCFD Ltd.
+    Copyright (C) 2018-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -324,18 +324,11 @@ Foam::label Foam::parLagrangianDistributor::distributeStoredFields
     passivePositionParticleCloud& cloud
 ) const
 {
-    HashTable<Container*> fields
-    (
-        cloud.lookupClass<Container>()
-    );
-
     bool reconstruct = false;
-
     label nFields = 0;
-    forAllIters(fields, iter)
-    {
-        Container& field = *(iter.val());
 
+    for (Container& field : cloud.sorted<Container>())
+    {
         if (!nFields)
         {
             // Performing an all-to-one (reconstruct)?
diff --git a/applications/utilities/postProcessing/dataConversion/foamDataToFluent/foamDataToFluent.C b/applications/utilities/postProcessing/dataConversion/foamDataToFluent/foamDataToFluent.C
index b5e60a546c7..513ce7f410c 100644
--- a/applications/utilities/postProcessing/dataConversion/foamDataToFluent/foamDataToFluent.C
+++ b/applications/utilities/postProcessing/dataConversion/foamDataToFluent/foamDataToFluent.C
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
+    Copyright (C) 2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -105,8 +106,9 @@ int main(int argc, char *argv[])
                 "foamDataToFluentDict",
                 runTime.system(),
                 mesh,
-                IOobject::MUST_READ_IF_MODIFIED,
-                IOobject::NO_WRITE
+                IOobjectOption::MUST_READ,
+                IOobjectOption::NO_WRITE,
+                IOobjectOption::NO_REGISTER
             )
         );
 
@@ -115,44 +117,21 @@ int main(int argc, char *argv[])
         IOobjectList objects(mesh, runTime.timeName());
 
 
-        // volScalarField
-        for (const word& fieldName : objects.sortedNames<volScalarField>())
-        {
-            // Lookup field from dictionary and convert field
-            label unitNumber;
-            if
-            (
-                foamDataToFluentDict.readIfPresent(fieldName, unitNumber)
-             && unitNumber > 0
-            )
-            {
-                // Read field
-                volScalarField field(*(objects[fieldName]), mesh);
-
-                Info<< "    Converting field " << fieldName << nl;
-                writeFluentField(field, unitNumber, fluentDataFile);
-            }
-        }
-
-
-        // volVectorField
-        for (const word& fieldName : objects.sortedNames<volVectorField>())
-        {
-            // Lookup field from dictionary and convert field
-            label unitNumber;
-            if
-            (
-                foamDataToFluentDict.readIfPresent(fieldName, unitNumber)
-             && unitNumber > 0
-            )
-            {
-                // Read field
-                volVectorField field(*(objects[fieldName]), mesh);
+        readFieldsAndWriteFluent<volScalarField>
+        (
+            foamDataToFluentDict,
+            objects,
+            mesh,
+            fluentDataFile
+        );
 
-                Info<< "    Converting field " << fieldName << nl;
-                writeFluentField(field, unitNumber, fluentDataFile);
-            }
-        }
+        readFieldsAndWriteFluent<volVectorField>
+        (
+            foamDataToFluentDict,
+            objects,
+            mesh,
+            fluentDataFile
+        );
 
         Info<< endl;
     }
diff --git a/applications/utilities/postProcessing/dataConversion/foamDataToFluent/writeFluentFields.H b/applications/utilities/postProcessing/dataConversion/foamDataToFluent/writeFluentFields.H
index 904d170885e..3d70ebd6bc1 100644
--- a/applications/utilities/postProcessing/dataConversion/foamDataToFluent/writeFluentFields.H
+++ b/applications/utilities/postProcessing/dataConversion/foamDataToFluent/writeFluentFields.H
@@ -28,10 +28,12 @@ InClass
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef writeFluentFields_H
-#define writeFluentFields_H
+#ifndef Foam_writeFluentFields_H
+#define Foam_writeFluentFields_H
 
 #include "volFields.H"
+#include "dictionary.H"
+#include "IOobjectList.H"
 #include "Ostream.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@@ -43,16 +45,48 @@ void writeFluentField
 (
     const volScalarField& phi,
     const label fluentFieldIdentifier,
-    Ostream& stream
+    Ostream& os
 );
 
 void writeFluentField
 (
     const volVectorField& phi,
     const label fluentFieldIdentifier,
-    Ostream& stream
+    Ostream& os
 );
 
+
+template<class GeoField>
+void readFieldsAndWriteFluent
+(
+    const dictionary& dict,
+    const IOobjectList& objects,
+    const fvMesh& mesh,
+    Ostream& os
+)
+{
+    for (const IOobject& io : objects.csorted<GeoField>())
+    {
+        // Lookup field from dictionary and convert field
+        const word& fieldName = io.name();
+        label unitNumber;
+        if
+        (
+            dict.readIfPresent(fieldName, unitNumber)
+         && unitNumber > 0
+        )
+        {
+            // Read field
+            GeoField field(io, mesh);
+
+            Info<< "    Converting field " << fieldName << nl;
+            writeFluentField(field, unitNumber, os);
+        }
+    }
+}
+
+
+
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 } // End namespace Foam
diff --git a/applications/utilities/postProcessing/dataConversion/foamDataToFluent/writeFluentScalarField.C b/applications/utilities/postProcessing/dataConversion/foamDataToFluent/writeFluentScalarField.C
index aa50c2edcd6..56dd1c626dd 100644
--- a/applications/utilities/postProcessing/dataConversion/foamDataToFluent/writeFluentScalarField.C
+++ b/applications/utilities/postProcessing/dataConversion/foamDataToFluent/writeFluentScalarField.C
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
+    Copyright (C) 2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -35,12 +36,7 @@ Description
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-namespace Foam
-{
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-void writeFluentField
+void Foam::writeFluentField
 (
     const volScalarField& phi,
     const label fluentFieldIdentifier,
@@ -58,15 +54,15 @@ void writeFluentField
         << "1 "                  // Number of components (scalar=1, vector=3)
         << "0 0 "                // Unused
         << "1 " << phiInternal.size() // Start and end of list
-        << ")(" << endl;
+        << ")(" << nl;
 
-    forAll(phiInternal, celli)
+    for (const scalar val : phiInternal)
     {
-        stream << phiInternal[celli] << endl;
+        stream << val << nl;
     }
 
     stream
-        << "))" << endl;
+        << "))" << nl;
 
     label nWrittenFaces = phiInternal.size();
 
@@ -92,13 +88,13 @@ void writeFluentField
                 << "0 0 "                // Unused
                 << nWrittenFaces + 1 << " "
                 << nWrittenFaces + emptyFaceCells.size()// Start and end of list
-                << ")(" << endl;
+                << ")(" << nl;
 
             nWrittenFaces += emptyFaceCells.size();
 
             forAll(emptyFaceCells, facei)
             {
-                stream << phiInternal[emptyFaceCells[facei]] << endl;
+                stream << phiInternal[emptyFaceCells[facei]] << nl;
             }
 
             stream
@@ -120,13 +116,13 @@ void writeFluentField
                 << "0 0 "            // Unused
                 << nWrittenFaces + 1 << " " << nWrittenFaces + patchPhi.size()
                                  // Start and end of list
-                << ")(" << endl;
+                << ")(" << nl;
 
             nWrittenFaces += patchPhi.size();
 
-            forAll(patchPhi, facei)
+            for (const scalar val : patchPhi)
             {
-                stream << patchPhi[facei] << endl;
+                stream << val << nl;
             }
 
             stream
@@ -136,8 +132,4 @@ void writeFluentField
 }
 
 
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-} // End namespace Foam
-
 // ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamDataToFluent/writeFluentVectorField.C b/applications/utilities/postProcessing/dataConversion/foamDataToFluent/writeFluentVectorField.C
index 51ee0520fef..d3b0f29f239 100644
--- a/applications/utilities/postProcessing/dataConversion/foamDataToFluent/writeFluentVectorField.C
+++ b/applications/utilities/postProcessing/dataConversion/foamDataToFluent/writeFluentVectorField.C
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
+    Copyright (C) 2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -34,12 +35,7 @@ Description
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-namespace Foam
-{
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-void writeFluentField
+void Foam::writeFluentField
 (
     const volVectorField& phi,
     const label fluentFieldIdentifier,
@@ -57,19 +53,16 @@ void writeFluentField
         << "3 "                  // Number of components (scalar=1, vector=3)
         << "0 0 "                // Unused
         << "1 " << phiInternal.size() // Start and end of list
-        << ")(" << endl;
+        << ")(" << nl;
 
-    forAll(phiInternal, celli)
+    for (const vector& val : phiInternal)
     {
         stream
-            << phiInternal[celli].x() << " "
-            << phiInternal[celli].y() << " "
-            << phiInternal[celli].z() << " "
-            << endl;
+            << val.x() << ' ' << val.y() << ' ' << val.z() << nl;
     }
 
     stream
-        << "))" << endl;
+        << "))" << nl;
 
     label nWrittenFaces = phiInternal.size();
 
@@ -87,17 +80,14 @@ void writeFluentField
             << "0 0 "            // Unused
             << nWrittenFaces + 1 << " " << nWrittenFaces + patchPhi.size()
                                  // Start and end of list
-            << ")(" << endl;
+            << ")(" << nl;
 
         nWrittenFaces += patchPhi.size();
 
-        forAll(patchPhi, facei)
+        for (const vector& val : patchPhi)
         {
             stream
-                << patchPhi[facei].x() << " "
-                << patchPhi[facei].y() << " "
-                << patchPhi[facei].z() << " "
-                << endl;
+                << val.x() << ' ' << val.y() << ' ' << val.z() << nl;
         }
 
         stream
@@ -106,6 +96,4 @@ void writeFluentField
 }
 
 
-} // End namespace Foam
-
 // ************************************************************************* //
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/checkFieldAvailability.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/checkFieldAvailability.H
index 0733064cd5f..2cb2c78530d 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/checkFieldAvailability.H
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/checkFieldAvailability.H
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2021-2022 OpenCFD Ltd.
+    Copyright (C) 2021-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
@@ -28,9 +28,9 @@ forAll(meshes, regioni)
 
     IOobjectList objects(0);
 
-    if (doConvertFields)
+    if (doConvertFields && !timeDirs.empty())
     {
-        objects = IOobjectList(mesh, timeDirs.last().name());
+        objects = IOobjectList(mesh, timeDirs.back().name());
 
         if (fieldSelector && !fieldSelector().empty())
         {
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/readFields.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/readFields.H
index fdf2e3d48d6..eee09efd9ec 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/readFields.H
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/readFields.H
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2018-2022 OpenCFD Ltd.
+    Copyright (C) 2018-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -35,18 +35,30 @@ SourceFiles
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef readFields_H
-#define readFields_H
+#ifndef ensight_readFields_H
+#define ensight_readFields_H
 
 #include "instantList.H"
 #include "IOobjectList.H"
-#include "zeroGradientFvPatchFields.H"
+#include "fvPatchField.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 namespace Foam
 {
 
+//- Get the field or FatalError
+template<class GeoField>
+tmp<GeoField> getField
+(
+    const IOobject& io,
+    const typename GeoField::Mesh& mesh
+)
+{
+    return tmp<GeoField>::New(io, mesh);
+}
+
+
 //- Get the field or return nullptr
 template<class GeoField>
 tmp<GeoField> getField
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeAreaFields.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeAreaFields.H
index e9abb624e96..ad1b2487094 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeAreaFields.H
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeAreaFields.H
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2021-2022 OpenCFD Ltd.
+    Copyright (C) 2021-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
@@ -72,7 +72,7 @@ label writeAreaFields
 
     label count = 0;
 
-    for (const word& fieldName : objects.sortedNames<FieldType>())
+    for (const IOobject& io : objects.csorted<FieldType>())
     {
         if
         (
@@ -80,11 +80,11 @@ label writeAreaFields
             (
                 ensCase,
                 ensMesh,
-                getField<FieldType>(objects.findObject(fieldName), mesh)
+                getField<FieldType>(io, mesh)
             )
         )
         {
-            Info<< ' ' << fieldName;
+            Info<< ' ' << io.name();
             ++count;
         }
     }
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeDimFields.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeDimFields.H
index 3e18a7185eb..ab567f51530 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeDimFields.H
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeDimFields.H
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2018-2022 OpenCFD Ltd.
+    Copyright (C) 2018-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
@@ -69,7 +69,7 @@ label writeDimFields
 
     label count = 0;
 
-    for (const word& fieldName : objects.sortedNames<FieldType>())
+    for (const IOobject& io : objects.csorted<FieldType>())
     {
         if
         (
@@ -77,11 +77,11 @@ label writeDimFields
             (
                 ensCase,
                 ensMesh,
-                getField<FieldType>(objects.findObject(fieldName), mesh)
+                getField<FieldType>(io, mesh)
             )
         )
         {
-            Info<< ' ' << fieldName;
+            Info<< ' ' << io.name();
             ++count;
         }
     }
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/writePointFields.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/writePointFields.H
index 8fb8764ad40..199bb91d2f7 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/writePointFields.H
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/writePointFields.H
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2020-2022 OpenCFD Ltd.
+    Copyright (C) 2020-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
@@ -70,11 +70,11 @@ label writePointFields
 {
     typedef PointField<Type> FieldType;
 
-    const pointMesh& ptMesh = pointMesh::New(ensMesh.mesh());
+    const pointMesh& pMesh = pointMesh::New(ensMesh.mesh());
 
     label count = 0;
 
-    for (const word& fieldName : objects.sortedNames<FieldType>())
+    for (const IOobject& io : objects.csorted<FieldType>())
     {
         if
         (
@@ -82,11 +82,11 @@ label writePointFields
             (
                 ensCase,
                 ensMesh,
-                getField<FieldType>(ptMesh, objects, fieldName)
+                getField<FieldType>(io, pMesh)
             )
         )
         {
-            Info<< ' ' << fieldName;
+            Info<< ' ' << io.name();
             ++count;
         }
     }
diff --git a/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeVolFields.H b/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeVolFields.H
index 18561396e3c..2c1f1500879 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeVolFields.H
+++ b/applications/utilities/postProcessing/dataConversion/foamToEnsight/writeVolFields.H
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2018-2022 OpenCFD Ltd.
+    Copyright (C) 2018-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
@@ -92,7 +92,7 @@ label writeVolFields
 
     label count = 0;
 
-    for (const word& fieldName : objects.sortedNames<FieldType>())
+    for (const IOobject& io : objects.csorted<FieldType>())
     {
         if
         (
@@ -100,12 +100,12 @@ label writeVolFields
             (
                 ensCase,
                 ensMesh,
-                getField<FieldType>(objects.findObject(fieldName), mesh),
+                getField<FieldType>(io, mesh),
                 nearCellValue
             )
         )
         {
-            Info<< ' ' << fieldName;
+            Info<< ' ' << io.name();
             ++count;
         }
     }
diff --git a/applications/utilities/postProcessing/dataConversion/foamToTetDualMesh/foamToTetDualMesh.C b/applications/utilities/postProcessing/dataConversion/foamToTetDualMesh/foamToTetDualMesh.C
index 6dcc567e190..09c72fd744c 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToTetDualMesh/foamToTetDualMesh.C
+++ b/applications/utilities/postProcessing/dataConversion/foamToTetDualMesh/foamToTetDualMesh.C
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
+    Copyright (C) 2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -58,18 +59,21 @@ void ReadAndMapFields
 {
     typedef typename MappedGeoField::value_type Type;
 
-    // Search list of objects for wanted type
-    IOobjectList fieldObjects(objects.lookupClass(ReadGeoField::typeName));
+    // Objects of wanted type
+    const UPtrList<const IOobject> fieldObjects
+    (
+        objects.csorted<ReadGeoField>()
+    );
 
-    tetFields.setSize(fieldObjects.size());
+    tetFields.resize(fieldObjects.size());
 
     label i = 0;
-    forAllConstIters(fieldObjects, iter)
+    for (const IOobject& io : fieldObjects)
     {
-        Info<< "Converting " << ReadGeoField::typeName << ' ' << iter.key()
-            << endl;
+        Info<< "Converting "
+            << ReadGeoField::typeName << ' ' << io.name() << endl;
 
-        ReadGeoField readField(*iter(), mesh);
+        ReadGeoField readField(io, mesh);
 
         tetFields.set
         (
@@ -82,8 +86,8 @@ void ReadAndMapFields
                     readField.instance(),
                     readField.local(),
                     tetDualMesh,
-                    IOobject::NO_READ,
-                    IOobject::AUTO_WRITE,
+                    IOobjectOption::NO_READ,
+                    IOobjectOption::AUTO_WRITE,
                     readField.registerObject()
                 ),
                 pointMesh::New(tetDualMesh),
diff --git a/applications/utilities/postProcessing/dataConversion/foamToVTK/readFields.C b/applications/utilities/postProcessing/dataConversion/foamToVTK/readFields.C
index f160eeb0277..a7c8457b45d 100644
--- a/applications/utilities/postProcessing/dataConversion/foamToVTK/readFields.C
+++ b/applications/utilities/postProcessing/dataConversion/foamToVTK/readFields.C
@@ -79,8 +79,8 @@ Foam::tmp<GeoField> Foam::getField
         {
             // Move field to the cache
             IOobject newIO(tfield(), *cache);
-            newIO.readOpt(IOobject::NO_READ);
-            newIO.writeOpt(IOobject::NO_WRITE);
+            newIO.readOpt(IOobjectOption::NO_READ);
+            newIO.writeOpt(IOobjectOption::NO_WRITE);
 
             tfield.ref().checkOut();  // Paranoid
             cache->store(new GeoField(newIO, tfield));
diff --git a/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/steadyParticleTracksTemplates.C b/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/steadyParticleTracksTemplates.C
index 3aaddb0ecce..9e0f14803d4 100644
--- a/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/steadyParticleTracksTemplates.C
+++ b/applications/utilities/postProcessing/lagrangian/steadyParticleTracks/steadyParticleTracksTemplates.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2016-2022 OpenCFD Ltd.
+    Copyright (C) 2016-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -108,24 +108,12 @@ void Foam::processFields
     const IOobjectList& cloudObjects
 )
 {
-    for (const word& fldName : cloudObjects.sortedNames<IOField<Type>>())
+    for (const IOobject& io : cloudObjects.csorted<IOField<Type>>())
     {
-        const IOobject* io = cloudObjects.cfindObject<IOField<Type>>(fldName);
+        Info<< "        reading field " << io.name() << endl;
+        IOField<Type> field(io);
 
-        if (!io)
-        {
-            FatalErrorInFunction
-                << "Could not read field:" << fldName
-                << " type:" << IOField<Type>::typeName
-                << abort(FatalError);
-        }
-        else
-        {
-            Info<< "        reading field " << fldName << endl;
-            IOField<Type> field(*io);
-
-            writeVTKField<Type>(os, field, addr);
-        }
+        writeVTKField<Type>(os, field, addr);
     }
 }
 
diff --git a/applications/utilities/postProcessing/miscellaneous/temporalInterpolate/temporalInterpolate.C b/applications/utilities/postProcessing/miscellaneous/temporalInterpolate/temporalInterpolate.C
index 3fcff800210..d4e4fdc27c8 100644
--- a/applications/utilities/postProcessing/miscellaneous/temporalInterpolate/temporalInterpolate.C
+++ b/applications/utilities/postProcessing/miscellaneous/temporalInterpolate/temporalInterpolate.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2015 OpenFOAM Foundation
-    Copyright (C) 2018-2020 OpenCFD Ltd.
+    Copyright (C) 2018-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -97,22 +97,24 @@ public:
 template<class GeoFieldType>
 void fieldInterpolator::interpolate()
 {
-    const word& clsName = GeoFieldType::typeName;
-
-    const wordList fieldNames =
+    label nFields = 0;
+    for
     (
-        selectedFields_.empty()
-      ? objects_.sortedNames(clsName)
-      : objects_.sortedNames(clsName, selectedFields_)
-    );
-
-    if (fieldNames.size())
+        const IOobject& io :
+        (
+            selectedFields_.empty()
+          ? objects_.csorted<GeoFieldType>()
+          : objects_.csorted<GeoFieldType>(selectedFields_)
+        )
+    )
     {
-        Info<< "    " << clsName << 's';
-    }
+        const word& fieldName = io.name();
+
+        if (!nFields)
+        {
+            Info<< "    " << GeoFieldType::typeName << 's';
+        }
 
-    for (const word& fieldName : fieldNames)
-    {
         Info<< ' ' << fieldName << '(';
 
         const scalar deltaT = (ti1_.value() - ti_.value())/(divisions_ + 1);
@@ -166,7 +168,7 @@ void fieldInterpolator::interpolate()
                     (
                         fieldName,
                         runTime_.timeName(),
-                        objects_[fieldName]->db(),
+                        io.db(),
                         IOobject::NO_READ,
                         IOobject::NO_WRITE,
                         IOobject::NO_REGISTER
@@ -181,9 +183,10 @@ void fieldInterpolator::interpolate()
         }
 
         Info<< ')';
+        ++nFields;
     }
 
-    if (fieldNames.size()) Info<< endl;
+    if (nFields) Info<< endl;
 }
 
 
diff --git a/applications/utilities/preProcessing/foamUpgradeCyclics/foamUpgradeCyclics.C b/applications/utilities/preProcessing/foamUpgradeCyclics/foamUpgradeCyclics.C
index 39d2a84f136..37ea689149f 100644
--- a/applications/utilities/preProcessing/foamUpgradeCyclics/foamUpgradeCyclics.C
+++ b/applications/utilities/preProcessing/foamUpgradeCyclics/foamUpgradeCyclics.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2019-2022 OpenCFD Ltd.
+    Copyright (C) 2019-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -285,7 +285,7 @@ void rewriteField
             fieldName,
             runTime.timeName(),
             runTime,
-            IOobject::MUST_READ_IF_MODIFIED,
+            IOobject::MUST_READ,
             IOobject::NO_WRITE,
             IOobject::NO_REGISTER
         )
@@ -369,29 +369,7 @@ void rewriteField
 }
 
 
-void rewriteFields
-(
-    const bool dryrun,
-    const Time& runTime,
-    const wordList& fieldNames,
-    const HashTable<word>& thisNames,
-    const HashTable<word>& nbrNames
-)
-{
-    for (const word& fieldName : fieldNames)
-    {
-        rewriteField
-        (
-            dryrun,
-            runTime,
-            fieldName,
-            thisNames,
-            nbrNames
-        );
-    }
-}
-
-
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 int main(int argc, char *argv[])
 {
@@ -473,9 +451,9 @@ int main(int argc, char *argv[])
 
     // Convert any fields
 
-    forAll(timeDirs, timeI)
+    forAll(timeDirs, timei)
     {
-        runTime.setTime(timeDirs[timeI], timeI);
+        runTime.setTime(timeDirs[timei], timei);
 
         Info<< "Time: " << runTime.timeName() << endl;
 
@@ -514,139 +492,44 @@ int main(int argc, char *argv[])
             entry::disableFunctionEntries = 1;
         }
 
+        // Rewriting of fields:
+
+        #undef  rewriteFields
+        #define rewriteFields(FieldType)                                      \
+        for (const word& fieldName : objects.sortedNames<FieldType>())        \
+        {                                                                     \
+            rewriteField(dryrun, runTime, fieldName, thisNames, nbrNames);    \
+        }
+
         // volFields
         // ~~~~~~~~~
 
-        rewriteFields
-        (
-            dryrun,
-            runTime,
-            objects.names(volScalarField::typeName),
-            thisNames,
-            nbrNames
-        );
-        rewriteFields
-        (
-            dryrun,
-            runTime,
-            objects.names(volVectorField::typeName),
-            thisNames,
-            nbrNames
-        );
-        rewriteFields
-        (
-            dryrun,
-            runTime,
-            objects.names(volSphericalTensorField::typeName),
-            thisNames,
-            nbrNames
-        );
-        rewriteFields
-        (
-            dryrun,
-            runTime,
-            objects.names(volSymmTensorField::typeName),
-            thisNames,
-            nbrNames
-        );
-        rewriteFields
-        (
-            dryrun,
-            runTime,
-            objects.names(volTensorField::typeName),
-            thisNames,
-            nbrNames
-        );
-
+        rewriteFields(volScalarField);
+        rewriteFields(volVectorField);
+        rewriteFields(volSphericalTensorField);
+        rewriteFields(volSymmTensorField);
+        rewriteFields(volTensorField);
 
         // pointFields
         // ~~~~~~~~~~~
 
-        rewriteFields
-        (
-            dryrun,
-            runTime,
-            objects.names(pointScalarField::typeName),
-            thisNames,
-            nbrNames
-        );
-        rewriteFields
-        (
-            dryrun,
-            runTime,
-            objects.names(pointVectorField::typeName),
-            thisNames,
-            nbrNames
-        );
-        rewriteFields
-        (
-            dryrun,
-            runTime,
-            objects.names(pointSphericalTensorField::typeName),
-            thisNames,
-            nbrNames
-        );
-        rewriteFields
-        (
-            dryrun,
-            runTime,
-            objects.names(pointSymmTensorField::typeName),
-            thisNames,
-            nbrNames
-        );
-        rewriteFields
-        (
-            dryrun,
-            runTime,
-            objects.names(pointTensorField::typeName),
-            thisNames,
-            nbrNames
-        );
+        rewriteFields(pointScalarField);
+        rewriteFields(pointVectorField);
+        rewriteFields(pointSphericalTensorField);
+        rewriteFields(pointSymmTensorField);
+        rewriteFields(pointTensorField);
 
 
         // surfaceFields
-        // ~~~~~~~~~~~
+        // ~~~~~~~~~~~~~
 
-        rewriteFields
-        (
-            dryrun,
-            runTime,
-            objects.names(surfaceScalarField::typeName),
-            thisNames,
-            nbrNames
-        );
-        rewriteFields
-        (
-            dryrun,
-            runTime,
-            objects.names(surfaceVectorField::typeName),
-            thisNames,
-            nbrNames
-        );
-        rewriteFields
-        (
-            dryrun,
-            runTime,
-            objects.names(surfaceSphericalTensorField::typeName),
-            thisNames,
-            nbrNames
-        );
-        rewriteFields
-        (
-            dryrun,
-            runTime,
-            objects.names(surfaceSymmTensorField::typeName),
-            thisNames,
-            nbrNames
-        );
-        rewriteFields
-        (
-            dryrun,
-            runTime,
-            objects.names(surfaceTensorField::typeName),
-            thisNames,
-            nbrNames
-        );
+        rewriteFields(surfaceScalarField);
+        rewriteFields(surfaceVectorField);
+        rewriteFields(surfaceSphericalTensorField);
+        rewriteFields(surfaceSymmTensorField);
+        rewriteFields(surfaceTensorField);
+
+        #undef rewriteFields
 
         entry::disableFunctionEntries = oldFlag;
     }
diff --git a/applications/utilities/preProcessing/mapFields/MapConsistentVolFields.H b/applications/utilities/preProcessing/mapFields/MapConsistentVolFields.H
index 4b55d582ed0..092abdbad35 100644
--- a/applications/utilities/preProcessing/mapFields/MapConsistentVolFields.H
+++ b/applications/utilities/preProcessing/mapFields/MapConsistentVolFields.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2017 OpenFOAM Foundation
-    Copyright (C) 2019-2021 OpenCFD Ltd.
+    Copyright (C) 2019-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -52,23 +52,20 @@ void MapConsistentVolFields
     const fvMesh& meshSource = meshToMesh0Interp.fromMesh();
     const fvMesh& meshTarget = meshToMesh0Interp.toMesh();
 
-    IOobjectList fields = objects.lookupClass(fieldType::typeName);
-
-    forAllConstIters(fields, fieldIter)
+    for (const IOobject& io : objects.csorted<fieldType>())
     {
-        Info<< "    interpolating " << (*fieldIter)->name()
-            << endl;
+        Info<< "    interpolating " << io.name() << endl;
 
         // Read field. Do not auto-load old-time field
-        fieldType fieldSource(*fieldIter(), meshSource, false);
+        fieldType fieldSource(io, meshSource, false);
 
         IOobject fieldTargetIOobject
         (
-            (*fieldIter)->name(),
+            io.name(),
             meshTarget.time().timeName(),
             meshTarget,
-            IOobject::MUST_READ,
-            IOobject::AUTO_WRITE
+            IOobjectOption::MUST_READ,
+            IOobjectOption::AUTO_WRITE
         );
 
         if (fieldTargetIOobject.typeHeaderOk<fieldType>(true))
@@ -90,7 +87,7 @@ void MapConsistentVolFields
         }
         else
         {
-            fieldTargetIOobject.readOpt(IOobject::NO_READ);
+            fieldTargetIOobject.readOpt(IOobjectOption::NO_READ);
 
             // Interpolate field
             fieldType fieldTarget
diff --git a/applications/utilities/preProcessing/mapFields/MapLagrangianFields.H b/applications/utilities/preProcessing/mapFields/MapLagrangianFields.H
index d62f4256a85..a4ecd85ae01 100644
--- a/applications/utilities/preProcessing/mapFields/MapLagrangianFields.H
+++ b/applications/utilities/preProcessing/mapFields/MapLagrangianFields.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -33,8 +33,8 @@ Description
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef MapLagrangianFields_H
-#define MapLagrangianFields_H
+#ifndef Foam_MapLagrangianFields_H
+#define Foam_MapLagrangianFields_H
 
 #include "cloud.H"
 #include "GeometricField.H"
@@ -49,130 +49,110 @@ namespace Foam
 
 //- Gets the indices of (source)particles that have been appended to the
 //  target cloud and maps the lagrangian fields accordingly.
-template<class Type>
+template<class SourceIOFieldType, class TargetIOFieldType>
 void MapLagrangianFields
 (
     const string& cloudName,
     const IOobjectList& objects,
     const meshToMesh0& meshToMesh0Interp,
-    const labelList& addParticles
+    const labelList& addParticles,
+    const char* msg
 )
 {
     const fvMesh& meshTarget = meshToMesh0Interp.toMesh();
 
+    for (const IOobject& io : objects.csorted<SourceIOFieldType>())
     {
-        IOobjectList fields = objects.lookupClass(IOField<Type>::typeName);
+        Info<< "    mapping lagrangian " << msg << ' ' << io.name() << endl;
 
-        forAllConstIters(fields, fieldIter)
-        {
-            Info<< "    mapping lagrangian field "
-                << (*fieldIter)->name() << endl;
+        // Read field (does not need mesh)
+        // Note: some fieldFields are 0 size (e.g. collision records)
+        //   if not used, so catch any of those for Field as well
 
-            // Read field (does not need mesh)
-            IOField<Type> fieldSource(*fieldIter());
+        SourceIOFieldType fieldSource(io);
 
-            // Map
-            IOField<Type> fieldTarget
+        // Map
+        TargetIOFieldType fieldTarget
+        (
+            IOobject
             (
-                IOobject
-                (
-                    (*fieldIter)->name(),
-                    meshTarget.time().timeName(),
-                    cloud::prefix/cloudName,
-                    meshTarget,
-                    IOobject::NO_READ,
-                    IOobject::NO_WRITE,
-                    IOobject::NO_REGISTER
-                ),
-                addParticles.size()
-            );
-
-            forAll(addParticles, i)
-            {
-                fieldTarget[i] = fieldSource[addParticles[i]];
-            }
-
-            // Write field
-            fieldTarget.write();
-        }
-    }
-
-    {
-        IOobjectList fieldFields =
-            objects.lookupClass(IOField<Field<Type>>::typeName);
-
-        forAllConstIters(fieldFields, fieldIter)
+                io.name(),
+                meshTarget.time().timeName(),
+                cloud::prefix/cloudName,
+                meshTarget,
+                IOobjectOption::NO_READ,
+                IOobjectOption::NO_WRITE,
+                IOobjectOption::NO_REGISTER
+            ),
+            min(fieldSource.size(), addParticles.size())  // handle 0 size
+        );
+
+        if (!fieldSource.empty())
         {
-            Info<< "    mapping lagrangian fieldField "
-                << (*fieldIter)->name() << endl;
-
-            // Read field (does not need mesh)
-            IOField<Field<Type>> fieldSource(*fieldIter());
-
-            // Map - use CompactIOField to automatically write in
-            // compact form for binary format.
-            CompactIOField<Field<Type>, Type> fieldTarget
-            (
-                IOobject
-                (
-                    (*fieldIter)->name(),
-                    meshTarget.time().timeName(),
-                    cloud::prefix/cloudName,
-                    meshTarget,
-                    IOobject::NO_READ,
-                    IOobject::NO_WRITE,
-                    IOobject::NO_REGISTER
-                ),
-                addParticles.size()
-            );
-
             forAll(addParticles, i)
             {
                 fieldTarget[i] = fieldSource[addParticles[i]];
             }
-
-            // Write field
-            fieldTarget.write();
         }
-    }
 
-    {
-        IOobjectList fieldFields =
-            objects.lookupClass(CompactIOField<Field<Type>, Type>::typeName);
-
-        forAllConstIters(fieldFields, fieldIter)
-        {
-            Info<< "    mapping lagrangian fieldField "
-                << (*fieldIter)->name() << endl;
-
-            // Read field (does not need mesh)
-            CompactIOField<Field<Type>, Type> fieldSource(*fieldIter());
+        fieldTarget.write();
+    }
+}
 
-            // Map
-            CompactIOField<Field<Type>, Type> fieldTarget
-            (
-                IOobject
-                (
-                    (*fieldIter)->name(),
-                    meshTarget.time().timeName(),
-                    cloud::prefix/cloudName,
-                    meshTarget,
-                    IOobject::NO_READ,
-                    IOobject::NO_WRITE,
-                    IOobject::NO_REGISTER
-                ),
-                addParticles.size()
-            );
 
-            forAll(addParticles, i)
-            {
-                fieldTarget[i] = fieldSource[addParticles[i]];
-            }
+//- Gets the indices of (source)particles that have been appended to the
+//  target cloud and maps the lagrangian fields accordingly.
+template<class Type>
+void MapLagrangianFields
+(
+    const string& cloudName,
+    const IOobjectList& objects,
+    const meshToMesh0& meshToMesh0Interp,
+    const labelList& addParticles
+)
+{
+    const fvMesh& meshTarget = meshToMesh0Interp.toMesh();
 
-            // Write field
-            fieldTarget.write();
-        }
-    }
+    MapLagrangianFields
+    <
+        IOField<Type>,
+        IOField<Type>
+    >
+    (
+        cloudName,
+        objects,
+        meshToMesh0Interp,
+        addParticles,
+        "Field"
+    );
+
+    // Target is CompactIOField to automatically write in
+    // compact form for binary format.
+    MapLagrangianFields
+    <
+        IOField<Field<Type>>,
+        CompactIOField<Field<Type>, Type>
+    >
+    (
+        cloudName,
+        objects,
+        meshToMesh0Interp,
+        addParticles,
+        "FieldField"
+    );
+
+    MapLagrangianFields
+    <
+        CompactIOField<Field<Type>, Type>,
+        CompactIOField<Field<Type>, Type>
+    >
+    (
+        cloudName,
+        objects,
+        meshToMesh0Interp,
+        addParticles,
+        "FieldField"
+    );
 }
 
 
diff --git a/applications/utilities/preProcessing/mapFields/MapVolFields.H b/applications/utilities/preProcessing/mapFields/MapVolFields.H
index 6bc977ceacc..0fc9d63cec7 100644
--- a/applications/utilities/preProcessing/mapFields/MapVolFields.H
+++ b/applications/utilities/preProcessing/mapFields/MapVolFields.H
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2017 OpenFOAM Foundation
+    Copyright (C) 2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -51,25 +52,23 @@ void MapVolFields
     const fvMesh& meshSource = meshToMesh0Interp.fromMesh();
     const fvMesh& meshTarget = meshToMesh0Interp.toMesh();
 
-    IOobjectList fields = objects.lookupClass(fieldType::typeName);
-
-    forAllConstIters(fields, fieldIter)
+    for (const IOobject& io : objects.csorted<fieldType>())
     {
         IOobject fieldTargetIOobject
         (
-            (*fieldIter)->name(),
+            io.name(),
             meshTarget.time().timeName(),
             meshTarget,
-            IOobject::MUST_READ,
-            IOobject::AUTO_WRITE
+            IOobjectOption::MUST_READ,
+            IOobjectOption::AUTO_WRITE
         );
 
         if (fieldTargetIOobject.typeHeaderOk<fieldType>(true))
         {
-            Info<< "    interpolating " << (*fieldIter)->name() << endl;
+            Info<< "    interpolating " << io.name() << endl;
 
             // Read field fieldSource. Do not auto-load old-time fields
-            fieldType fieldSource(*fieldIter(), meshSource, false);
+            fieldType fieldSource(io, meshSource, false);
 
             // Read fieldTarget. Do not auto-load old-time fields
             fieldType fieldTarget
diff --git a/applications/utilities/preProcessing/mapFields/UnMapped.H b/applications/utilities/preProcessing/mapFields/UnMapped.H
index 835641653c7..2582a495719 100644
--- a/applications/utilities/preProcessing/mapFields/UnMapped.H
+++ b/applications/utilities/preProcessing/mapFields/UnMapped.H
@@ -40,11 +40,9 @@ namespace Foam
 template<class Type>
 void UnMapped(const IOobjectList& objects)
 {
-    IOobjectList fields = objects.lookupClass(Type::typeName);
-
-    forAllConstIters(fields, fieldIter)
+    for (const IOobject& io : objects.csorted<Type>())
     {
-        mvBak((*fieldIter)->objectPath(), "unmapped");
+        mvBak(io.objectPath(), "unmapped");
     }
 }
 
diff --git a/applications/utilities/preProcessing/mapFieldsPar/MapLagrangianFields.H b/applications/utilities/preProcessing/mapFieldsPar/MapLagrangianFields.H
index 7f142c0221b..34538671eaa 100644
--- a/applications/utilities/preProcessing/mapFieldsPar/MapLagrangianFields.H
+++ b/applications/utilities/preProcessing/mapFieldsPar/MapLagrangianFields.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -33,8 +33,8 @@ Description
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef MapLagrangianFields_H
-#define MapLagrangianFields_H
+#ifndef Foam_MapLagrangianFields_H
+#define Foam_MapLagrangianFields_H
 
 #include "cloud.H"
 #include "GeometricField.H"
@@ -49,153 +49,112 @@ namespace Foam
 
 //- Gets the indices of (source)particles that have been appended to the
 //  target cloud and maps the lagrangian fields accordingly.
-template<class Type>
+template<class SourceIOFieldType, class TargetIOFieldType>
 void MapLagrangianFields
 (
     const string& cloudName,
     const IOobjectList& objects,
     const polyMesh& meshTarget,
-    const labelList& addParticles
+    const labelList& addParticles,
+    const char* msg
 )
 {
+    for (const IOobject& io : objects.csorted<SourceIOFieldType>())
     {
-        IOobjectList fields = objects.lookupClass(IOField<Type>::typeName);
-
-        forAllConstIters(fields, fieldIter)
-        {
-            const word& fieldName = (*fieldIter)->name();
+        Info<< "    mapping lagrangian " << msg << ' ' << io.name() << endl;
 
-            Info<< "    mapping lagrangian field " << fieldName << endl;
+        // Read field (does not need mesh)
+        // Note: some fieldFields are 0 size (e.g. collision records)
+        //   if not used, so catch any of those for Field as well
 
-            // Read field (does not need mesh)
-            IOField<Type> fieldSource(*fieldIter());
+        SourceIOFieldType fieldSource(io);
 
-            // Map
-            IOField<Type> fieldTarget
+        // Map
+        TargetIOFieldType fieldTarget
+        (
+            IOobject
             (
-                IOobject
-                (
-                    fieldName,
-                    meshTarget.time().timeName(),
-                    cloud::prefix/cloudName,
-                    meshTarget,
-                    IOobject::NO_READ,
-                    IOobject::NO_WRITE,
-                    IOobject::NO_REGISTER
-                ),
-                addParticles.size()
-            );
-
+                io.name(),
+                meshTarget.time().timeName(),
+                cloud::prefix/cloudName,
+                meshTarget,
+                IOobjectOption::NO_READ,
+                IOobjectOption::NO_WRITE,
+                IOobjectOption::NO_REGISTER
+            ),
+            min(fieldSource.size(), addParticles.size())  // handle 0 size
+        );
+
+        if (!fieldSource.empty())
+        {
             forAll(addParticles, i)
             {
                 fieldTarget[i] = fieldSource[addParticles[i]];
             }
-
-            // Write field
-            fieldTarget.write();
         }
-    }
-
-    {
-        IOobjectList fieldFields =
-            objects.lookupClass(IOField<Field<Type>>::typeName);
-
-        forAllConstIters(fieldFields, fieldIter)
+        else if (cloud::debug && !addParticles.empty())
         {
-            const word& fieldName = (*fieldIter)->name();
-
-            Info<< "    mapping lagrangian fieldField " << fieldName << endl;
-
-            // Read field (does not need mesh)
-            // Note: some fieldFields are 0 size (e.g. collision records) if
-            //       not used
-            IOField<Field<Type>> fieldSource(*fieldIter());
-
-            // Map - use CompactIOField to automatically write in
-            // compact form for binary format.
-            CompactIOField<Field<Type>, Type> fieldTarget
-            (
-                IOobject
-                (
-                    fieldName,
-                    meshTarget.time().timeName(),
-                    cloud::prefix/cloudName,
-                    meshTarget,
-                    IOobject::NO_READ,
-                    IOobject::NO_WRITE,
-                    IOobject::NO_REGISTER
-                ),
-                min(fieldSource.size(), addParticles.size()) // handle 0 size
-            );
-
-            if (fieldSource.size())
-            {
-                forAll(addParticles, i)
-                {
-                    fieldTarget[i] = fieldSource[addParticles[i]];
-                }
-            }
-            else if (cloud::debug)
-            {
-                Pout<< "Not mapping " << fieldName << " since source size "
-                    << fieldSource.size() << " different to"
-                    << " cloud size " << addParticles.size()
-                    << endl;
-            }
-
-            // Write field
-            fieldTarget.write();
+            Pout<< "Not mapping " << io.name()
+                << " since source size = 0 and cloud size = "
+                << addParticles.size() << endl;
         }
-    }
-
-    {
-        IOobjectList fieldFields =
-            objects.lookupClass(CompactIOField<Field<Type>, Type>::typeName);
 
-        forAllConstIters(fieldFields, fieldIter)
-        {
-            const word& fieldName = (*fieldIter)->name();
-
-            Info<< "    mapping lagrangian fieldField " << fieldName << endl;
-
-            // Read field (does not need mesh)
-            CompactIOField<Field<Type>, Type> fieldSource(*fieldIter());
+        fieldTarget.write();
+    }
+}
 
-            // Map
-            CompactIOField<Field<Type>, Type> fieldTarget
-            (
-                IOobject
-                (
-                    fieldName,
-                    meshTarget.time().timeName(),
-                    cloud::prefix/cloudName,
-                    meshTarget,
-                    IOobject::NO_READ,
-                    IOobject::NO_WRITE,
-                    IOobject::NO_REGISTER
-                ),
-                min(fieldSource.size(), addParticles.size()) // handle 0 size
-            );
-
-            if (fieldSource.size())
-            {
-                forAll(addParticles, i)
-                {
-                    fieldTarget[i] = fieldSource[addParticles[i]];
-                }
-            }
-            else if (cloud::debug)
-            {
-                Pout<< "Not mapping " << fieldName << " since source size "
-                    << fieldSource.size() << " different to"
-                    << " cloud size " << addParticles.size()
-                    << endl;
-            }
 
-            // Write field
-            fieldTarget.write();
-        }
-    }
+//- Gets the indices of (source)particles that have been appended to the
+//  target cloud and maps the lagrangian fields accordingly.
+template<class Type>
+void MapLagrangianFields
+(
+    const string& cloudName,
+    const IOobjectList& objects,
+    const polyMesh& meshTarget,
+    const labelList& addParticles
+)
+{
+    MapLagrangianFields
+    <
+        IOField<Type>,
+        IOField<Type>
+    >
+    (
+        cloudName,
+        objects,
+        meshTarget,
+        addParticles,
+        "Field"
+    );
+
+    // Target is CompactIOField to automatically write in
+    // compact form for binary format.
+    MapLagrangianFields
+    <
+        IOField<Field<Type>>,
+        CompactIOField<Field<Type>, Type>
+    >
+    (
+        cloudName,
+        objects,
+        meshTarget,
+        addParticles,
+        "FieldField"
+    );
+
+    MapLagrangianFields
+    <
+        CompactIOField<Field<Type>, Type>,
+        CompactIOField<Field<Type>, Type>
+    >
+    (
+        cloudName,
+        objects,
+        meshTarget,
+        addParticles,
+        "FieldField"
+    );
 }
 
 
diff --git a/applications/utilities/preProcessing/mapFieldsPar/MapVolFields.H b/applications/utilities/preProcessing/mapFieldsPar/MapVolFields.H
index d4f928aed05..1257d47aeb6 100644
--- a/applications/utilities/preProcessing/mapFieldsPar/MapVolFields.H
+++ b/applications/utilities/preProcessing/mapFieldsPar/MapVolFields.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2017 OpenFOAM Foundation
-    Copyright (C) 2018-2021 OpenCFD Ltd.
+    Copyright (C) 2018-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -132,20 +132,21 @@ void MapVolFields
     const fvMesh& meshTarget = static_cast<const fvMesh&>(interp.tgtRegion());
 
     // Available fields, sorted order
-    const wordList fieldNames =
+    for
     (
-        selectedFields.empty()
-      ? objects.sortedNames<fieldType>()
-      : objects.sortedNames<fieldType>(selectedFields)
-    );
-
-    for (const word& fieldName : fieldNames)
+        const IOobject& io :
+        (
+            selectedFields.empty()
+          ? objects.csorted<fieldType>()
+          : objects.csorted<fieldType>(selectedFields)
+        )
+    )
     {
-        const fieldType fieldSource(*(objects[fieldName]), meshSource, false);
+        const fieldType fieldSource(io, meshSource, false);
 
         IOobject targetIO
         (
-            fieldName,
+            io.name(),
             meshTarget.time().timeName(),
             meshTarget,
             IOobject::MUST_READ
@@ -154,7 +155,7 @@ void MapVolFields
         if (targetIO.typeHeaderOk<fieldType>(true))
         {
             Info<< "    interpolating onto existing field "
-                << fieldName << endl;
+                << targetIO.name() << endl;
 
             fieldType fieldTarget(targetIO, meshTarget, false);
 
@@ -167,7 +168,7 @@ void MapVolFields
         else
         {
             Info<< "    creating new field "
-                << fieldName << endl;
+                << targetIO.name() << endl;
 
             targetIO.readOpt(IOobject::NO_READ);
 
diff --git a/applications/utilities/preProcessing/mapFieldsPar/UnMapped.H b/applications/utilities/preProcessing/mapFieldsPar/UnMapped.H
index 835641653c7..2582a495719 100644
--- a/applications/utilities/preProcessing/mapFieldsPar/UnMapped.H
+++ b/applications/utilities/preProcessing/mapFieldsPar/UnMapped.H
@@ -40,11 +40,9 @@ namespace Foam
 template<class Type>
 void UnMapped(const IOobjectList& objects)
 {
-    IOobjectList fields = objects.lookupClass(Type::typeName);
-
-    forAllConstIters(fields, fieldIter)
+    for (const IOobject& io : objects.csorted<Type>())
     {
-        mvBak((*fieldIter)->objectPath(), "unmapped");
+        mvBak(io.objectPath(), "unmapped");
     }
 }
 
diff --git a/src/OpenFOAM/fields/DimensionedFields/DimensionedField/MapDimensionedFields.H b/src/OpenFOAM/fields/DimensionedFields/DimensionedField/MapDimensionedFields.H
index b2b613e62d8..b92ee92dd66 100644
--- a/src/OpenFOAM/fields/DimensionedFields/DimensionedField/MapDimensionedFields.H
+++ b/src/OpenFOAM/fields/DimensionedFields/DimensionedField/MapDimensionedFields.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2012 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -46,20 +46,23 @@ template<class Type, class MeshMapper, class GeoMesh>
 void MapDimensionedFields(const MeshMapper& mapper)
 {
     typedef DimensionedField<Type, GeoMesh> FieldType;
-    typedef HashTable<const FieldType*> TableType;
 
-    TableType fields(mapper.thisDb().template lookupClass<FieldType>(true));
+    // Note: use strict=true to avoid picking up volFields
+    const UPtrList<const FieldType> fields
+    (
+        mapper.thisDb().template csorted<FieldType, true>()
+    );
 
-    forAllConstIters(fields, fieldIter)
+    for (const auto& fld : fields)
     {
-        FieldType& field = const_cast<FieldType&>(*fieldIter());
+        FieldType& field = const_cast<FieldType&>(fld);
 
         if (&field.mesh() == &mapper.mesh())
         {
             if (polyMesh::debug)
             {
-                Info<< "Mapping " << field.typeName << ' ' << field.name()
-                    << endl;
+                Info<< "Mapping "
+                    << FieldType::typeName << ' ' << field.name() << endl;
             }
 
             MapInternalField<Type, MeshMapper, GeoMesh>()(field, mapper);
@@ -68,7 +71,8 @@ void MapDimensionedFields(const MeshMapper& mapper)
         }
         else if (polyMesh::debug)
         {
-            Info<< "Not mapping " << field.typeName << ' ' << field.name()
+            Info<< "Not mapping "
+                << FieldType::typeName << ' ' << field.name()
                 << " since originating mesh differs from that of mapper."
                 << endl;
         }
diff --git a/src/OpenFOAM/fields/GeometricFields/GeometricField/MapGeometricFields.H b/src/OpenFOAM/fields/GeometricFields/GeometricField/MapGeometricFields.H
index 419bcbead2f..8b272a44931 100644
--- a/src/OpenFOAM/fields/GeometricFields/GeometricField/MapGeometricFields.H
+++ b/src/OpenFOAM/fields/GeometricFields/GeometricField/MapGeometricFields.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2017-2019 OpenCFD Ltd.
+    Copyright (C) 2017-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -49,8 +49,7 @@ class MapInternalField
 {
 public:
 
-    MapInternalField()
-    {}
+    MapInternalField() = default;
 
     void operator()
     (
@@ -77,10 +76,9 @@ void MapGeometricFields
 {
     typedef GeometricField<Type, PatchField, GeoMesh> FieldType;
 
-    HashTable<const FieldType*> fields
+    const UPtrList<const FieldType> fields
     (
-        mapper.thisDb().objectRegistry::template
-            lookupClass<FieldType>()
+        mapper.thisDb().objectRegistry::template csorted<FieldType>()
     );
 
     // It is necessary to enforce that all old-time fields are stored
@@ -88,39 +86,37 @@ void MapGeometricFields
     // old-time-level field is mapped before the field itself, sizes
     // will not match.
 
-    forAllConstIters(fields, fieldIter)
+    for (const auto& field : fields)
     {
-        FieldType& field = const_cast<FieldType&>(*fieldIter());
-
         //Note: check can be removed once pointFields are actually stored on
         //      the pointMesh instead of now on the polyMesh!
         if (&field.mesh() == &mapper.mesh())
         {
-            field.storeOldTimes();
+            const_cast<FieldType&>(field).storeOldTimes();
         }
     }
 
-    forAllConstIters(fields, fieldIter)
+    for (const auto& field : fields)
     {
-        FieldType& field = const_cast<FieldType&>(*fieldIter());
+        FieldType& fld = const_cast<FieldType&>(field);
 
         if (&field.mesh() == &mapper.mesh())
         {
             if (polyMesh::debug)
             {
-                Info<< "Mapping " << field.typeName << ' ' << field.name()
-                    << endl;
+                Info<< "Mapping "
+                    << FieldType::typeName << ' ' << field.name() << endl;
             }
 
             // Map the internal field
             MapInternalField<Type, MeshMapper, GeoMesh>()
             (
-                field.internalFieldRef(),
+                fld.internalFieldRef(),
                 mapper
             );
 
             // Map the patch fields
-            auto& bfield = field.boundaryFieldRef();
+            auto& bfield = fld.boundaryFieldRef();
 
             forAll(bfield, patchi)
             {
@@ -132,11 +128,12 @@ void MapGeometricFields
                 bfield[patchi].autoMap(mapper.boundaryMap()[patchi]);
             }
 
-            field.instance() = field.time().timeName();
+            fld.instance() = fld.time().timeName();
         }
         else if (polyMesh::debug)
         {
-            Info<< "Not mapping " << field.typeName << ' ' << field.name()
+            Info<< "Not mapping "
+                << FieldType::typeName << ' ' << field.name()
                 << " since originating mesh differs from that of mapper."
                 << endl;
         }
diff --git a/src/OpenFOAM/fields/ReadFields/ReadFieldsTemplates.C b/src/OpenFOAM/fields/ReadFields/ReadFieldsTemplates.C
index c819a2ada7a..e7a1f326622 100644
--- a/src/OpenFOAM/fields/ReadFields/ReadFieldsTemplates.C
+++ b/src/OpenFOAM/fields/ReadFields/ReadFieldsTemplates.C
@@ -45,10 +45,10 @@ Foam::wordList Foam::ReadFields
     typedef GeometricField<Type, PatchField, GeoMesh> GeoField;
 
     // Names of GeoField objects, sorted order.
-    const wordList fieldNames(objects.names(GeoField::typeName, syncPar));
+    const wordList fieldNames(objects.sortedNames<GeoField>(syncPar));
 
     // Construct the fields - reading in consistent (master) order.
-    fields.resize(fieldNames.size());
+    fields.resize_null(fieldNames.size());
 
     label nFields = 0;
 
@@ -73,8 +73,8 @@ Foam::wordList Foam::ReadFields
                     io.instance(),
                     io.local(),
                     io.db(),
-                    IOobject::MUST_READ,
-                    IOobject::AUTO_WRITE,
+                    IOobjectOption::MUST_READ,
+                    IOobjectOption::AUTO_WRITE,
                     io.registerObject()
                 ),
                 mesh,
@@ -99,10 +99,10 @@ Foam::wordList Foam::ReadFields
 )
 {
     // Names of GeoField objects, sorted order.
-    const wordList fieldNames(objects.names(GeoField::typeName, syncPar));
+    const wordList fieldNames(objects.sortedNames<GeoField>(syncPar));
 
     // Construct the fields - reading in consistent (master) order.
-    fields.resize(fieldNames.size());
+    fields.resize_null(fieldNames.size());
 
     label nFields = 0;
 
@@ -127,8 +127,8 @@ Foam::wordList Foam::ReadFields
                     io.instance(),
                     io.local(),
                     io.db(),
-                    IOobject::MUST_READ,
-                    IOobject::AUTO_WRITE,
+                    IOobjectOption::MUST_READ,
+                    IOobjectOption::AUTO_WRITE,
                     io.registerObject()
                 ),
                 mesh
@@ -151,10 +151,10 @@ Foam::wordList Foam::ReadFields
 )
 {
     // Names of GeoField objects, sorted order.
-    const wordList fieldNames(objects.names(GeoField::typeName, syncPar));
+    const wordList fieldNames(objects.sortedNames<GeoField>(syncPar));
 
     // Construct the fields - reading in consistent (master) order.
-    fields.resize(fieldNames.size());
+    fields.resize_null(fieldNames.size());
 
     label nFields = 0;
 
@@ -179,8 +179,8 @@ Foam::wordList Foam::ReadFields
                     io.instance(),
                     io.local(),
                     io.db(),
-                    IOobject::MUST_READ,
-                    IOobject::AUTO_WRITE,
+                    IOobjectOption::MUST_READ,
+                    IOobjectOption::AUTO_WRITE,
                     io.registerObject()
                 )
             )
@@ -235,9 +235,9 @@ void Foam::ReadFields
                     timeName,
                     timeName,
                     fieldsCache,
-                    IOobject::NO_READ,
-                    IOobject::NO_WRITE,
-                    IOobject::REGISTER
+                    IOobjectOption::NO_READ,
+                    IOobjectOption::NO_WRITE,
+                    IOobjectOption::REGISTER
                 )
             );
             timeCachePtr->store();
@@ -260,9 +260,9 @@ void Foam::ReadFields
                     fieldName,
                     timeName,
                     mesh.thisDb(),
-                    IOobject::MUST_READ,
-                    IOobject::NO_WRITE,
-                    IOobject::NO_REGISTER
+                    IOobjectOption::MUST_READ,
+                    IOobjectOption::NO_WRITE,
+                    IOobjectOption::NO_REGISTER
                 ),
                 mesh
             );
@@ -275,9 +275,9 @@ void Foam::ReadFields
                     fieldName,
                     timeName,
                     timeCache,
-                    IOobject::NO_READ,
-                    IOobject::NO_WRITE,
-                    IOobject::REGISTER
+                    IOobjectOption::NO_READ,
+                    IOobjectOption::NO_WRITE,
+                    IOobjectOption::REGISTER
                 ),
                 loadedFld
             );
@@ -318,39 +318,37 @@ void Foam::readFields
     DynamicList<regIOobject*>& storedObjects
 )
 {
-    // Names of GeoField objects, sorted order. Not synchronised.
-    const wordList fieldNames
+    // GeoField objects, sorted order. Not synchronised.
+    const UPtrList<const IOobject> fieldObjects
     (
-        objects.sortedNames<GeoFieldType>(selectedFields)
+        objects.csorted<GeoFieldType>(selectedFields)
     );
 
 
     // pre-extend reserve
-    storedObjects.reserve(storedObjects.size() + fieldNames.size());
+    storedObjects.reserve(storedObjects.size() + fieldObjects.size());
 
     label nFields = 0;
 
-    for (const word& fieldName : fieldNames)
+    for (const IOobject& io : fieldObjects)
     {
-        const IOobject& io = *objects[fieldName];
-
         if (!nFields)
         {
             Info<< "    " << GeoFieldType::typeName << ':';
         }
-        Info<< ' ' << fieldName;
+        Info<< ' ' << io.name();
 
         GeoFieldType* fieldPtr = new GeoFieldType
         (
             IOobject
             (
-                fieldName,
+                io.name(),
                 io.instance(),
                 io.local(),
                 io.db(),
-                IOobject::MUST_READ,
-                IOobject::NO_WRITE,
-                IOobject::REGISTER
+                IOobjectOption::MUST_READ,
+                IOobjectOption::NO_WRITE,
+                IOobjectOption::REGISTER
             ),
             mesh
         );
@@ -373,38 +371,36 @@ void Foam::readUniformFields
     const bool syncPar
 )
 {
-    // Names of UniformField objects, sorted order.
-    const wordList fieldNames
+    // UniformField objects, sorted order, synchronised.
+    const UPtrList<const IOobject> fieldObjects
     (
-        objects.names<UniformFieldType>(selectedFields, syncPar)
+        objects.csorted<UniformFieldType>(selectedFields, syncPar)
     );
 
     // pre-extend reserve
-    storedObjects.reserve(storedObjects.size() + fieldNames.size());
+    storedObjects.reserve(storedObjects.size() + fieldObjects.size());
 
     label nFields = 0;
 
-    for (const word& fieldName : fieldNames)
+    for (const IOobject& io : fieldObjects)
     {
-        const IOobject& io = *objects[fieldName];
-
         if (!nFields)
         {
             Info<< "    " << UniformFieldType::typeName << ':';
         }
-        Info<< ' ' << fieldName;
+        Info<< ' ' << io.name();
 
         UniformFieldType* fieldPtr = new UniformFieldType
         (
             IOobject
             (
-                fieldName,
+                io.name(),
                 io.instance(),
                 io.local(),
                 io.db(),
-                IOobject::MUST_READ,
-                IOobject::NO_WRITE,
-                IOobject::REGISTER
+                IOobjectOption::MUST_READ,
+                IOobjectOption::NO_WRITE,
+                IOobjectOption::REGISTER
             )
         );
         fieldPtr->store();
diff --git a/src/OpenFOAM/fields/cloud/mapClouds.H b/src/OpenFOAM/fields/cloud/mapClouds.H
index 60b09519157..f5fafffb5ae 100644
--- a/src/OpenFOAM/fields/cloud/mapClouds.H
+++ b/src/OpenFOAM/fields/cloud/mapClouds.H
@@ -34,8 +34,8 @@ Description
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef mapClouds_H
-#define mapClouds_H
+#ifndef Foam_mapClouds_H
+#define Foam_mapClouds_H
 
 #include "cloud.H"
 #include "objectRegistry.H"
@@ -50,18 +50,14 @@ namespace Foam
 //  fields depending on mesh type.
 inline void mapClouds(const objectRegistry& db, const mapPolyMesh& mapper)
 {
-    HashTable<const cloud*> clouds(db.lookupClass<cloud>());
-
-    forAllIters(clouds, iter)
+    for (const cloud& c : db.csorted<cloud>())
     {
-        cloud& c = const_cast<cloud&>(*iter());
-
         if (polyMesh::debug)
         {
             Info<< "Mapping cloud " << c.name() << endl;
         }
 
-        c.autoMap(mapper);
+        const_cast<cloud&>(c).autoMap(mapper);
     }
 }
 
diff --git a/src/OpenFOAM/meshes/Identifiers/patch/coupleGroupIdentifier.C b/src/OpenFOAM/meshes/Identifiers/patch/coupleGroupIdentifier.C
index 4199fc52ba1..6442c647070 100644
--- a/src/OpenFOAM/meshes/Identifiers/patch/coupleGroupIdentifier.C
+++ b/src/OpenFOAM/meshes/Identifiers/patch/coupleGroupIdentifier.C
@@ -161,14 +161,10 @@ Foam::label Foam::coupleGroupIdentifier::findOtherPatchID
 
 
     // Loop over all regions to find other patch in coupleGroup
-    HashTable<const polyMesh*> meshSet = runTime.lookupClass<polyMesh>();
-
     label otherPatchID = -1;
 
-    forAllConstIters(meshSet, iter)
+    for (const polyMesh& mesh : runTime.cobjects<polyMesh>())
     {
-        const polyMesh& mesh = *iter();
-
         const label patchID = findOtherPatchID(mesh, thisPatch);
 
         if (patchID != -1)
@@ -178,15 +174,15 @@ Foam::label Foam::coupleGroupIdentifier::findOtherPatchID
                 FatalErrorInFunction
                     << "Couple patchGroup " << name()
                     << " should be present on only two patches"
-                    << " in any of the meshes in " << meshSet.sortedToc()
-                    << endl
+                    << " in any of the meshes in "
+                    << runTime.sortedNames<polyMesh>() << nl
                     << "    It seems to be present on patch "
                     << thisPatch.name()
                     << " in region " << thisMesh.name()
                     << ", on patch " << otherPatchID
                     << " in region " << otherRegion
                     << " and on patch " << patchID
-                    << " in region " << mesh.name()
+                    << " in region " << mesh.name() << endl
                     << exit(FatalError);
             }
             otherPatchID = patchID;
@@ -198,7 +194,8 @@ Foam::label Foam::coupleGroupIdentifier::findOtherPatchID
     {
         FatalErrorInFunction
             << "Couple patchGroup " << name()
-            << " not found in any of the other meshes " << meshSet.sortedToc()
+            << " not found in any of the other meshes "
+            << flatOutput(runTime.sortedNames<polyMesh>())
             << " on patch " << thisPatch.name()
             << " region " << thisMesh.name()
             << exit(FatalError);
diff --git a/src/OpenFOAM/parallel/fieldsDistributor/fieldsDistributorTemplates.C b/src/OpenFOAM/parallel/fieldsDistributor/fieldsDistributorTemplates.C
index 8bddfe91301..491b8f31ee0 100644
--- a/src/OpenFOAM/parallel/fieldsDistributor/fieldsDistributorTemplates.C
+++ b/src/OpenFOAM/parallel/fieldsDistributor/fieldsDistributorTemplates.C
@@ -68,7 +68,7 @@ void Foam::fieldsDistributor::readFields
     const UPtrList<const IOobject> fieldObjects(objects.csorted<GeoField>());
 
     // Construct the fields
-    fields.resize(fieldObjects.size());
+    fields.resize_null(fieldObjects.size());
 
     forAll(fieldObjects, i)
     {
@@ -89,7 +89,7 @@ void Foam::fieldsDistributor::readFields
     const UPtrList<const IOobject> fieldObjects(objects.csorted<GeoField>());
 
     // Construct the fields
-    fields.resize(fieldObjects.size());
+    fields.resize_null(fieldObjects.size());
 
     forAll(fieldObjects, i)
     {
@@ -167,18 +167,16 @@ void Foam::fieldsDistributor::readFieldsImpl
         if (deregister)
         {
             // Extra safety - remove all such types
-            HashTable<const GeoField*> other
+            const UPtrList<const GeoField> other
             (
-                mesh.thisDb().objectRegistry::template lookupClass<GeoField>()
+                mesh.thisDb().objectRegistry::template cobjects<GeoField>()
             );
 
-            forAllConstIters(other, iter)
+            for (const GeoField& field : other)
             {
-                GeoField& fld = const_cast<GeoField&>(*iter.val());
-
-                if (!fld.ownedByRegistry())
+                if (!field.ownedByRegistry())
                 {
-                    fld.checkOut();
+                    const_cast<GeoField&>(field).checkOut();
                 }
             }
         }
diff --git a/src/dynamicFvMesh/dynamicRefineFvMesh/dynamicRefineFvMesh.C b/src/dynamicFvMesh/dynamicRefineFvMesh/dynamicRefineFvMesh.C
index 96c019f9b6f..b32abd951fd 100644
--- a/src/dynamicFvMesh/dynamicRefineFvMesh/dynamicRefineFvMesh.C
+++ b/src/dynamicFvMesh/dynamicRefineFvMesh/dynamicRefineFvMesh.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2017 OpenFOAM Foundation
-    Copyright (C) 2018-2022 OpenCFD Ltd.
+    Copyright (C) 2018-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -295,9 +295,9 @@ void Foam::dynamicRefineFvMesh::mapFields(const mapPolyMesh& mpm)
             Pout<< "Found " << masterFaces.count() << " split faces " << endl;
         }
 
-        HashTable<surfaceScalarField*> fluxes
+        UPtrList<surfaceScalarField> fluxes
         (
-            lookupClass<surfaceScalarField>()
+            this->objectRegistry::sorted<surfaceScalarField>()
         );
 
         // Remove surfaceInterpolation to allow re-calculation on demand
@@ -305,44 +305,39 @@ void Foam::dynamicRefineFvMesh::mapFields(const mapPolyMesh& mpm)
         // might need the old interpolation fields (weights, etc).
         surfaceInterpolation::clearOut();
 
-        forAllIters(fluxes, iter)
+        for (surfaceScalarField& phi : fluxes)
         {
-            if (!correctFluxes_.found(iter.key()))
+            const word& UName = correctFluxes_.lookup(phi.name(), word::null);
+
+            if (UName.empty())
             {
                 WarningInFunction
-                    << "Cannot find surfaceScalarField " << iter.key()
+                    << "Cannot find surfaceScalarField " << phi.name()
                     << " in user-provided flux mapping table "
                     << correctFluxes_ << endl
                     << "    The flux mapping table is used to recreate the"
                     << " flux on newly created faces." << endl
                     << "    Either add the entry if it is a flux or use ("
-                    << iter.key() << " none) to suppress this warning."
+                    << phi.name() << " none) to suppress this warning."
                     << endl;
                 continue;
             }
-
-            const word& UName = correctFluxes_[iter.key()];
-
             if (UName == "none")
             {
                 continue;
             }
-
-            surfaceScalarField& phi = *iter();
-
             if (UName == "NaN")
             {
-                Pout<< "Setting surfaceScalarField " << iter.key()
+                Pout<< "Setting surfaceScalarField " << phi.name()
                     << " to NaN" << endl;
 
                 sigFpe::fillNan(phi.primitiveFieldRef());
-
                 continue;
             }
 
             if (debug)
             {
-                Pout<< "Mapping flux " << iter.key()
+                Pout<< "Mapping flux " << phi.name()
                     << " using interpolated flux " << UName
                     << endl;
             }
@@ -374,7 +369,7 @@ void Foam::dynamicRefineFvMesh::mapFields(const mapPolyMesh& mpm)
             }
 
             // Recalculate new boundary faces.
-            surfaceScalarField::Boundary& phiBf = phi.boundaryFieldRef();
+            auto& phiBf = phi.boundaryFieldRef();
 
             forAll(phiBf, patchi)
             {
@@ -617,42 +612,39 @@ Foam::dynamicRefineFvMesh::unrefine
         const labelList& reversePointMap = map().reversePointMap();
         const labelList& reverseFaceMap = map().reverseFaceMap();
 
-        HashTable<surfaceScalarField*> fluxes
+        UPtrList<surfaceScalarField> fluxes
         (
-            lookupClass<surfaceScalarField>()
+            this->objectRegistry::sorted<surfaceScalarField>()
         );
-        forAllIters(fluxes, iter)
+
+        for (surfaceScalarField& phi : fluxes)
         {
-            if (!correctFluxes_.found(iter.key()))
+            const word& UName = correctFluxes_.lookup(phi.name(), word::null);
+
+            if (UName.empty())
             {
                 WarningInFunction
-                    << "Cannot find surfaceScalarField " << iter.key()
+                    << "Cannot find surfaceScalarField " << phi.name()
                     << " in user-provided flux mapping table "
                     << correctFluxes_ << endl
                     << "    The flux mapping table is used to recreate the"
                     << " flux on newly created faces." << endl
                     << "    Either add the entry if it is a flux or use ("
-                    << iter.key() << " none) to suppress this warning."
+                    << phi.name() << " none) to suppress this warning."
                     << endl;
                 continue;
             }
-
-            const word& UName = correctFluxes_[iter.key()];
-
             if (UName == "none")
             {
                 continue;
             }
 
             DebugInfo
-                << "Mapping flux " << iter.key()
+                << "Mapping flux " << phi.name()
                 << " using interpolated flux " << UName
                 << endl;
 
-
-            surfaceScalarField& phi = *iter();
-            surfaceScalarField::Boundary& phiBf =
-                phi.boundaryFieldRef();
+            auto& phiBf = phi.boundaryFieldRef();
 
             const surfaceScalarField phiU
             (
diff --git a/src/dynamicFvMesh/dynamicRefineFvMesh/dynamicRefineFvMeshTemplates.C b/src/dynamicFvMesh/dynamicRefineFvMesh/dynamicRefineFvMeshTemplates.C
index 588d6be8336..70d109bee89 100644
--- a/src/dynamicFvMesh/dynamicRefineFvMesh/dynamicRefineFvMeshTemplates.C
+++ b/src/dynamicFvMesh/dynamicRefineFvMesh/dynamicRefineFvMeshTemplates.C
@@ -105,24 +105,20 @@ void Foam::dynamicRefineFvMesh::mapNewInternalFaces
 )
 {
     typedef GeometricField<T, fvsPatchField, surfaceMesh> GeoField;
-    HashTable<GeoField*> sFlds(this->objectRegistry::lookupClass<GeoField>());
 
-    forAllIters(sFlds, iter)
+    for (GeoField& sFld : this->objectRegistry::sorted<GeoField>())
     {
-        //if (mapSurfaceFields_.found(iter.key()))
+        //if (mapSurfaceFields_.found(sFld.name()))
         {
             DebugInfo
                 << "dynamicRefineFvMesh::mapNewInternalFaces():"
                 << " Mapping new internal faces by interpolation on "
-                << iter.key()<< endl;
-
-            GeoField& sFld = *iter();
+                << sFld.name()<< endl;
 
             if (sFld.is_oriented())
             {
                 WarningInFunction << "Ignoring mapping oriented field "
-                    << sFld.name() << " since of type " << sFld.type()
-                    << endl;
+                    << sFld.name() << " since of type " << sFld.type() << endl;
             }
             else
             {
@@ -141,36 +137,34 @@ void Foam::dynamicRefineFvMesh::mapNewInternalFaces
 )
 {
     typedef GeometricField<T, fvsPatchField, surfaceMesh> GeoField;
-    HashTable<GeoField*> sFlds(this->objectRegistry::lookupClass<GeoField>());
 
-    forAllIters(sFlds, iter)
+    typedef GeometricField
+    <
+        typename outerProduct<vector, T>::type,
+        fvsPatchField,
+        surfaceMesh
+    > NormalGeoField;
+
+
+    for (GeoField& sFld : this->objectRegistry::sorted<GeoField>())
     {
-        //if (mapSurfaceFields_.found(iter.key()))
+        //if (mapSurfaceFields_.found(sFld.name()))
         {
             DebugInfo
                 << "dynamicRefineFvMesh::mapNewInternalFaces():"
                 << " Mapping new internal faces by interpolation on "
-                << iter.key() << endl;
-
-            GeoField& sFld = *iter();
+                << sFld.name() << endl;
 
             if (sFld.is_oriented())
             {
                 DebugInfo
                     << "dynamicRefineFvMesh::mapNewInternalFaces(): "
-                    << "Converting oriented field " << iter.key()
+                    << "Converting oriented field " << sFld.name()
                     << " to intensive field and mapping" << endl;
 
                 // Assume any oriented field is face area weighted (i.e. a flux)
                 // Convert to intensive (& oriented) before mapping. Untested.
 
-                typedef GeometricField
-                <
-                    typename outerProduct<vector, T>::type,
-                    fvsPatchField,
-                    surfaceMesh
-                > NormalGeoField;
-
                 // Convert to intensive and non oriented
                 NormalGeoField fFld(sFld*Sf/Foam::sqr(magSf));
 
diff --git a/src/dynamicMesh/fvMeshAdder/fvMeshAdderTemplates.C b/src/dynamicMesh/fvMeshAdder/fvMeshAdderTemplates.C
index e3d0bc37930..7b4163e6822 100644
--- a/src/dynamicMesh/fvMeshAdder/fvMeshAdderTemplates.C
+++ b/src/dynamicMesh/fvMeshAdder/fvMeshAdderTemplates.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2015-2021 OpenCFD Ltd.
+    Copyright (C) 2015-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -272,14 +272,9 @@ void Foam::fvMeshAdder::MapVolFields
 {
     typedef GeometricField<Type, fvPatchField, volMesh> fldType;
 
-    HashTable<const fldType*> fields
+    const UPtrList<const fldType> fields
     (
-        mesh.objectRegistry::lookupClass<fldType>()
-    );
-
-    HashTable<const fldType*> fieldsToAdd
-    (
-        meshToAdd.objectRegistry::lookupClass<fldType>()
+        mesh.objectRegistry::csorted<fldType>()
     );
 
     // It is necessary to enforce that all old-time fields are stored
@@ -287,36 +282,35 @@ void Foam::fvMeshAdder::MapVolFields
     // old-time-level field is mapped before the field itself, sizes
     // will not match.
 
-    forAllIters(fields, fieldIter)
+    for (const auto& field : fields)
     {
-        fldType& fld = const_cast<fldType&>(*fieldIter());
-
         DebugPout
-            << "MapVolFields : Storing old time for " << fld.name() << endl;
+            << "MapVolFields : Storing old time for "
+            << field.name() << endl;
 
-        fld.storeOldTimes();
+        const_cast<fldType&>(field).storeOldTimes();
     }
 
 
-    forAllIters(fields, fieldIter)
+    for (const auto& field : fields)
     {
-        fldType& fld = const_cast<fldType&>(*fieldIter());
+        fldType& fld = const_cast<fldType&>(field);
 
-        if (fieldsToAdd.found(fld.name()))
-        {
-            const fldType& fldToAdd = *fieldsToAdd[fld.name()];
+        const auto* toAdd =
+            meshToAdd.objectRegistry::cfindObject<fldType>(field.name());
 
+        if (toAdd)
+        {
             DebugPout
-                << "MapVolFields : mapping " << fld.name()
-                << " and " << fldToAdd.name() << endl;
+                << "MapVolFields : mapping " << field.name() << endl;
 
-            MapVolField<Type>(meshMap, fld, fldToAdd, fullyMapped);
+            MapVolField<Type>(meshMap, fld, *toAdd, fullyMapped);
         }
         else
         {
             WarningInFunction
-                << "Not mapping field " << fld.name()
-                << " since not present on mesh to add" << endl;
+                << "Not mapping field " << field.name()
+                << " - not present on mesh to add" << endl;
         }
     }
 }
@@ -582,14 +576,9 @@ void Foam::fvMeshAdder::MapSurfaceFields
 {
     typedef GeometricField<Type, fvsPatchField, surfaceMesh> fldType;
 
-    HashTable<const fldType*> fields
+    const UPtrList<const fldType> fields
     (
-        mesh.objectRegistry::lookupClass<fldType>()
-    );
-
-    HashTable<const fldType*> fieldsToAdd
-    (
-        meshToAdd.objectRegistry::lookupClass<fldType>()
+        mesh.objectRegistry::csorted<fldType>()
     );
 
     // It is necessary to enforce that all old-time fields are stored
@@ -597,36 +586,34 @@ void Foam::fvMeshAdder::MapSurfaceFields
     // old-time-level field is mapped before the field itself, sizes
     // will not match.
 
-    forAllIters(fields, fieldIter)
+    for (const auto& field : fields)
     {
-        fldType& fld = const_cast<fldType&>(*fieldIter());
-
         DebugPout
-            << "MapSurfaceFields : Storing old time for " << fld.name() << endl;
+            << "MapSurfaceFields : Storing old time for "
+            << field.name() << endl;
 
-        fld.storeOldTimes();
+        const_cast<fldType&>(field).storeOldTimes();
     }
 
-
-    forAllIters(fields, fieldIter)
+    for (const auto& field : fields)
     {
-        fldType& fld = const_cast<fldType&>(*fieldIter());
+        fldType& fld = const_cast<fldType&>(field);
 
-        if (fieldsToAdd.found(fld.name()))
-        {
-            const fldType& fldToAdd = *fieldsToAdd[fld.name()];
+        const auto* toAdd =
+            meshToAdd.objectRegistry::cfindObject<fldType>(field.name());
 
+        if (toAdd)
+        {
             DebugPout
-                << "MapSurfaceFields : mapping " << fld.name()
-                << " and " << fldToAdd.name() << endl;
+                << "MapSurfaceFields : mapping " << field.name() << endl;
 
-            MapSurfaceField<Type>(meshMap, fld, fldToAdd, fullyMapped);
+            MapSurfaceField<Type>(meshMap, fld, *toAdd, fullyMapped);
         }
         else
         {
             WarningInFunction
-                << "Not mapping field " << fld.name()
-                << " since not present on mesh to add" << endl;
+                << "Not mapping field " << field.name()
+                << " - not present on mesh to add" << endl;
         }
     }
 }
@@ -663,37 +650,32 @@ void Foam::fvMeshAdder::MapDimFields
 {
     typedef DimensionedField<Type, volMesh> fldType;
 
-    // Note: use strict flag on lookupClass to avoid picking up
-    //       volFields
-    HashTable<const fldType*> fields
+    // NB: strict=true to avoid picking up volFields
+    const UPtrList<const fldType> fields
     (
-        mesh.objectRegistry::lookupClass<fldType>(true)
+        mesh.objectRegistry::csorted<fldType, true>()
     );
 
-    HashTable<const fldType*> fieldsToAdd
-    (
-        meshToAdd.objectRegistry::lookupClass<fldType>(true)
-    );
-
-    forAllIters(fields, fieldIter)
+    for (const auto& field : fields)
     {
-        fldType& fld = const_cast<fldType&>(*fieldIter());
+        fldType& fld = const_cast<fldType&>(field);
 
-        if (fieldsToAdd.found(fld.name()))
-        {
-            const fldType& fldToAdd = *fieldsToAdd[fld.name()];
+        const auto* toAdd =
+            meshToAdd.objectRegistry::cfindObject<fldType>(field.name());
 
+        // Apply strict check (to avoid picking volFields)
+        if (toAdd && Foam::isType<fldType>(*toAdd))
+        {
             DebugPout
-                << "MapDimFields : mapping " << fld.name()
-                << " and " << fldToAdd.name() << endl;
+                << "MapDimFields : mapping " << field.name() << endl;
 
-            MapDimField<Type>(meshMap, fld, fldToAdd);
+            MapDimField<Type>(meshMap, fld, *toAdd);
         }
         else
         {
             WarningInFunction
-                << "Not mapping field " << fld.name()
-                << " since not present on mesh to add" << endl;
+                << "Not mapping field " << field.name()
+                << " - not present on mesh to add" << endl;
         }
     }
 }
@@ -1115,9 +1097,9 @@ void Foam::fvMeshAdder::MapVolFields
     }
     const auto& mesh0 = meshes[0];
 
-    HashTable<const fldType*> fields
+    const UPtrList<const fldType> fields
     (
-        mesh0.objectRegistry::lookupClass<fldType>()
+        mesh0.objectRegistry::csorted<fldType>()
     );
 
 
@@ -1126,19 +1108,19 @@ void Foam::fvMeshAdder::MapVolFields
     // old-time-level field is mapped before the field itself, sizes
     // will not match.
 
-    for (const auto& fld : fields)
+    for (const auto& field : fields)
     {
         DebugPout
-            << "MapVolFields : Storing old time for " << fld->name()
-            << endl;
+            << "MapVolFields : Storing old time for "
+            << field.name() << endl;
 
-        const_cast<fldType&>(*fld).storeOldTimes();
+        const_cast<fldType&>(field).storeOldTimes();
     }
 
 
-    for (const auto& fld : fields)
+    for (const auto& field : fields)
     {
-        const word& name0 = fld->name();
+        const word& name0 = field.name();
 
         DebugPout
             << "MapVolFields : mapping " << name0 << endl;
@@ -1177,7 +1159,6 @@ void Foam::fvMeshAdder::MapDimFields
 )
 {
     typedef DimensionedField<Type, volMesh> fldType;
-    typedef GeometricField<Type, fvPatchField, volMesh> excludeType;
 
     if (!meshes.test(0))
     {
@@ -1188,39 +1169,31 @@ void Foam::fvMeshAdder::MapDimFields
     }
     const auto& mesh0 = meshes[0];
 
-    HashTable<const fldType*> fields
+    // NB: strict=true to avoid picking up volFields
+    const UPtrList<const fldType> fields
     (
-        mesh0.objectRegistry::lookupClass<fldType>()
+        mesh0.objectRegistry::csorted<fldType, true>()
     );
 
-
-    for (const auto& fld : fields)
+    for (const auto& field : fields)
     {
-        if (!isA<excludeType>(*fld))
-        {
-            const word& name0 = fld->name();
+        const word& name0 = field.name();
 
-            DebugPout
-                << "MapDimFields : mapping " << name0 << endl;
+        DebugPout
+            << "MapDimFields : mapping " << name0 << endl;
 
-            UPtrList<fldType> meshToField(meshes.size());
-            forAll(meshes, meshi)
+        UPtrList<fldType> meshToField(meshes.size());
+        forAll(meshes, meshi)
+        {
+            if (meshes.set(meshi))
             {
-                if (meshes.set(meshi))
-                {
-                    auto& meshFld = meshes[meshi].
-                        objectRegistry::lookupObjectRef<fldType>(name0);
-                    meshToField.set(meshi, &meshFld);
-                }
+                auto& meshFld = meshes[meshi].
+                    objectRegistry::lookupObjectRef<fldType>(name0);
+                meshToField.set(meshi, &meshFld);
             }
-
-            MapDimField(meshToField, cellProcAddressing, fullyMapped);
-        }
-        else
-        {
-            DebugPout
-                << "MapDimFields : ignoring " << fld->name() << endl;
         }
+
+        MapDimField(meshToField, cellProcAddressing, fullyMapped);
     }
 }
 
@@ -1250,9 +1223,9 @@ void Foam::fvMeshAdder::MapSurfaceFields
     }
     const auto& mesh0 = meshes[0];
 
-    HashTable<const fldType*> fields
+    const UPtrList<const fldType> fields
     (
-        mesh0.objectRegistry::lookupClass<fldType>()
+        mesh0.objectRegistry::csorted<fldType>()
     );
 
 
@@ -1261,22 +1234,22 @@ void Foam::fvMeshAdder::MapSurfaceFields
     // old-time-level field is mapped before the field itself, sizes
     // will not match.
 
-    for (const auto& fld : fields)
+    for (const auto& field : fields)
     {
         DebugPout
-            << "MapSurfaceFields : Storing old time for " << fld->name()
-            << endl;
+            << "MapSurfaceFields : Storing old time for "
+            << field.name() << endl;
 
-        const_cast<fldType&>(*fld).storeOldTimes();
+        const_cast<fldType&>(field).storeOldTimes();
     }
 
 
-    for (const auto& fld : fields)
+    for (const auto& field : fields)
     {
-        const word& name0 = fld->name();
+        const word& name0 = field.name();
 
         DebugPout
-            << "MapSurfaceFields : Mapping " << fld->name() << endl;
+            << "MapSurfaceFields : Mapping " << field.name() << endl;
 
         UPtrList<fldType> meshToField(meshes.size());
         forAll(meshes, meshi)
diff --git a/src/dynamicMesh/fvMeshDistribute/fvMeshDistributeTemplates.C b/src/dynamicMesh/fvMeshDistribute/fvMeshDistributeTemplates.C
index 7ba8162ff36..caab9774490 100644
--- a/src/dynamicMesh/fvMeshDistribute/fvMeshDistributeTemplates.C
+++ b/src/dynamicMesh/fvMeshDistribute/fvMeshDistributeTemplates.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2015-2022 OpenCFD Ltd.
+    Copyright (C) 2015-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -87,18 +87,12 @@ void Foam::fvMeshDistribute::printIntFieldInfo(const fvMesh& mesh)
         volMesh
     > excludeType;
 
-    const HashTable<const GeoField*> flds
-    (
-        mesh.objectRegistry::lookupClass<GeoField>()
-    );
-
-    forAllConstIters(flds, iter)
+    for (const GeoField& field : mesh.objectRegistry::csorted<GeoField>())
     {
-        const GeoField& fld = *iter();
-        if (!isA<excludeType>(fld))
+        if (!isA<excludeType>(field))
         {
-            Pout<< "Field:" << iter.key() << " internalsize:" << fld.size()
-                //<< " value:" << fld
+            Pout<< "Field:" << field.name() << " size:" << field.size()
+                //<< " value:" << field
                 << endl;
         }
     }
@@ -108,20 +102,13 @@ void Foam::fvMeshDistribute::printIntFieldInfo(const fvMesh& mesh)
 template<class GeoField>
 void Foam::fvMeshDistribute::printFieldInfo(const fvMesh& mesh)
 {
-    const HashTable<const GeoField*> flds
-    (
-        mesh.objectRegistry::lookupClass<GeoField>()
-    );
-
-    forAllConstIters(flds, iter)
+    for (const GeoField& field : mesh.objectRegistry::csorted<GeoField>())
     {
-        const GeoField& fld = *iter();
-
-        Pout<< "Field:" << iter.key() << " internalsize:" << fld.size()
-            //<< " value:" << fld
+        Pout<< "Field:" << field.name() << " size:" << field.size()
+            //<< " value:" << field
             << endl;
 
-        for (const auto& patchFld : fld.boundaryField())
+        for (const auto& patchFld : field.boundaryField())
         {
             Pout<< "    " << patchFld.patch().index()
                 << ' ' << patchFld.patch().name()
@@ -143,21 +130,19 @@ void Foam::fvMeshDistribute::saveBoundaryFields
 
     typedef GeometricField<T, fvsPatchField, Mesh> fldType;
 
-    HashTable<const fldType*> flds
+    const UPtrList<const fldType> flds
     (
-        mesh_.objectRegistry::lookupClass<const fldType>()
+        mesh_.objectRegistry::csorted<fldType>()
     );
 
-    bflds.resize(flds.size());
+    bflds.resize_null(flds.size());
 
-    label i = 0;
-    forAllConstIters(flds, iter)
+    label fieldi = 0;
+    for (const fldType& fld : flds)
     {
-        const fldType& fld = *iter();
+        bflds.set(fieldi, fld.boundaryField().clone());
 
-        bflds.set(i, fld.boundaryField().clone());
-
-        ++i;
+        ++fieldi;
     }
 }
 
@@ -176,9 +161,9 @@ void Foam::fvMeshDistribute::mapBoundaryFields
 
     typedef GeometricField<T, fvsPatchField, Mesh> fldType;
 
-    HashTable<fldType*> flds
+    UPtrList<fldType> flds
     (
-        mesh_.objectRegistry::lookupClass<fldType>()
+        mesh_.objectRegistry::sorted<fldType>()
     );
 
     if (flds.size() != oldBflds.size())
@@ -187,14 +172,10 @@ void Foam::fvMeshDistribute::mapBoundaryFields
             << abort(FatalError);
     }
 
-    label fieldi = 0;
-
-    forAllIters(flds, iter)
+    forAll(flds, fieldi)
     {
-        fldType& fld = *iter();
-        auto& bfld = fld.boundaryFieldRef();
-
-        const FieldField<fvsPatchField, T>& oldBfld = oldBflds[fieldi++];
+        auto& bfld = flds[fieldi].boundaryFieldRef();
+        const auto& oldBfld = oldBflds[fieldi];
 
         // Pull from old boundary field into bfld.
 
@@ -231,22 +212,16 @@ void Foam::fvMeshDistribute::saveInternalFields
 {
     typedef GeometricField<T, fvsPatchField, surfaceMesh> fldType;
 
-    HashTable<const fldType*> flds
+    const UPtrList<const fldType> fields
     (
-        mesh_.objectRegistry::lookupClass<const fldType>()
+        mesh_.objectRegistry::csorted<fldType>()
     );
 
-    iflds.resize(flds.size());
-
-    label i = 0;
+    iflds.resize_null(fields.size());
 
-    forAllConstIters(flds, iter)
+    forAll(fields, fieldi)
     {
-        const fldType& fld = *iter();
-
-        iflds.set(i, fld.primitiveField().clone());
-
-        ++i;
+        iflds.set(fieldi, fields[fieldi].primitiveField().clone());
     }
 }
 
@@ -264,9 +239,9 @@ void Foam::fvMeshDistribute::mapExposedFaces
 
     typedef GeometricField<T, fvsPatchField, surfaceMesh> fldType;
 
-    HashTable<fldType*> flds
+    UPtrList<fldType> flds
     (
-        mesh_.objectRegistry::lookupClass<fldType>()
+        mesh_.objectRegistry::sorted<fldType>()
     );
 
     if (flds.size() != oldFlds.size())
@@ -277,16 +252,15 @@ void Foam::fvMeshDistribute::mapExposedFaces
     }
 
 
-    label fieldI = 0;
-
-    forAllIters(flds, iter)
+    forAll(flds, fieldi)
     {
-        fldType& fld = *iter();
+        auto& fld = flds[fieldi];
+        const auto& oldInternal = oldFlds[fieldi];
+
         const bool oriented = fld.is_oriented();
 
-        typename fldType::Boundary& bfld = fld.boundaryFieldRef();
+        auto& bfld = fld.boundaryFieldRef();
 
-        const Field<T>& oldInternal = oldFlds[fieldI++];
 
         // Pull from old internal field into bfld.
 
@@ -322,16 +296,10 @@ void Foam::fvMeshDistribute::initPatchFields
 )
 {
     // Init patch fields of certain type
+    // - field order is irrelevant
 
-    HashTable<GeoField*> flds
-    (
-        mesh_.objectRegistry::lookupClass<GeoField>()
-    );
-
-    forAllIters(flds, iter)
+    for (GeoField& fld : mesh_.objectRegistry::objects<GeoField>())
     {
-        GeoField& fld = *iter();
-
         auto& bfld = fld.boundaryFieldRef();
 
         forAll(bfld, patchi)
@@ -350,14 +318,8 @@ void Foam::fvMeshDistribute::initPatchFields
 //{
 //    // CorrectBoundaryConditions patch fields of certain type
 //
-//    HashTable<GeoField*> flds
-//    (
-//        mesh_.objectRegistry::lookupClass<GeoField>()
-//    );
-//
-//    forAllIters(flds, iter)
+//    for (GeoField& fld : mesh_.objectRegistry::sorted<GeoField>())
 //    {
-//        GeoField& fld = *iter();
 //        fld.correctBoundaryConditions();
 //    }
 //}
@@ -377,19 +339,23 @@ void Foam::fvMeshDistribute::getFieldNames
 
     if (!excludeType.empty())
     {
-        const wordList& excludeList = allFieldNames(excludeType);
+        const wordList& excludeList =
+            allFieldNames.lookup(excludeType, wordList::null());
 
-        DynamicList<word> newList(list.size());
-        for(const auto& name : list)
+        if (!excludeList.empty())
         {
-            if (!excludeList.found(name))
+            DynamicList<word> newList(list.size());
+            for (const auto& name : list)
             {
-                newList.append(name);
+                if (!excludeList.contains(name))
+                {
+                    newList.push_back(name);
+                }
+            }
+            if (newList.size() < list.size())
+            {
+                list = std::move(newList);
             }
-        }
-        if (newList.size() < list.size())
-        {
-            list = std::move(newList);
         }
     }
 
diff --git a/src/dynamicMesh/polyMeshFilter/polyMeshFilter.H b/src/dynamicMesh/polyMeshFilter/polyMeshFilter.H
index 6efd53b78a5..afe81a21b4c 100644
--- a/src/dynamicMesh/polyMeshFilter/polyMeshFilter.H
+++ b/src/dynamicMesh/polyMeshFilter/polyMeshFilter.H
@@ -92,10 +92,11 @@ class polyMeshFilter
 
     // Private Member Functions
 
-        template<class T>
+        //- Update all sets of the given type
+        template<class SetType>
         static void updateSets(const mapPolyMesh& map);
 
-        template<class T>
+        template<class SetType>
         static void copySets(const polyMesh& oldMesh, const polyMesh& newMesh);
 
         label filterFacesLoop(const label nOriginalBadFaces);
diff --git a/src/dynamicMesh/polyMeshFilter/polyMeshFilterTemplates.C b/src/dynamicMesh/polyMeshFilter/polyMeshFilterTemplates.C
index 4d13814c236..e7cd13a9741 100644
--- a/src/dynamicMesh/polyMeshFilter/polyMeshFilterTemplates.C
+++ b/src/dynamicMesh/polyMeshFilter/polyMeshFilterTemplates.C
@@ -36,16 +36,26 @@ License
 template<class SetType>
 void Foam::polyMeshFilter::updateSets(const mapPolyMesh& map)
 {
-    HashTable<const SetType*> sets =
-        map.mesh().objectRegistry::lookupClass<const SetType>();
+    //
+    // Update all sets in memory
+    //
 
-    forAllIters(sets, iter)
+    const HashTable<const SetType*> sets
+    (
+        map.mesh().objectRegistry::lookupClass<const SetType>()
+    );
+
+    for (const auto& iter : sets.csorted())
     {
-        SetType& set = const_cast<SetType&>(*iter());
+        SetType& set = const_cast<SetType&>(*iter.val());
         set.updateMesh(map);
         set.sync(map.mesh());
     }
 
+    //
+    // Update all sets on disk
+    //
+
     IOobjectList objs
     (
         map.mesh().time(),
@@ -53,14 +63,12 @@ void Foam::polyMeshFilter::updateSets(const mapPolyMesh& map)
         "polyMesh/sets"
     );
 
-    IOobjectList fileSets(objs.lookupClass<SetType>());
-
-    forAllConstIters(fileSets, iter)
+    for (const IOobject& io : objs.csorted<SetType>())
     {
-        if (!sets.found(iter.key()))
+        if (!sets.contains(io.name()))
         {
             // Not in memory. Load it.
-            SetType set(*iter());
+            SetType set(io);
             set.updateMesh(map);
 
             set.write();
@@ -76,13 +84,8 @@ void Foam::polyMeshFilter::copySets
     const polyMesh& newMesh
 )
 {
-    HashTable<const SetType*> sets =
-        oldMesh.objectRegistry::lookupClass<const SetType>();
-
-    forAllConstIters(sets, iter)
+    for (const SetType& set : oldMesh.objectRegistry::csorted<SetType>())
     {
-        const SetType& set = *iter();
-
         auto* setPtr =
             newMesh.objectRegistry::getObjectPtr<SetType>(set.name());
 
diff --git a/src/dynamicMesh/setUpdater/setUpdater.H b/src/dynamicMesh/setUpdater/setUpdater.H
index 278d3dc67c9..3fd01c7909b 100644
--- a/src/dynamicMesh/setUpdater/setUpdater.H
+++ b/src/dynamicMesh/setUpdater/setUpdater.H
@@ -57,9 +57,9 @@ class setUpdater
 {
     // Private Member Functions
 
-        //- Updates all sets
-        template<class Type>
-        void updateSets(const mapPolyMesh& morphMap) const;
+        //- Update all sets of the given type
+        template<class SetType>
+        static void updateSets(const mapPolyMesh& map);
 
         //- No copy construct
         setUpdater(const setUpdater&) = delete;
diff --git a/src/dynamicMesh/setUpdater/setUpdaterTemplates.C b/src/dynamicMesh/setUpdater/setUpdaterTemplates.C
index 2f43bc46d4d..d1f7ade2b2c 100644
--- a/src/dynamicMesh/setUpdater/setUpdaterTemplates.C
+++ b/src/dynamicMesh/setUpdater/setUpdaterTemplates.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -32,27 +32,29 @@ License
 #include "mapPolyMesh.H"
 #include "IOobjectList.H"
 
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
 
-template<class Type>
-void Foam::setUpdater::updateSets(const mapPolyMesh& morphMap) const
+template<class SetType>
+void Foam::setUpdater::updateSets(const mapPolyMesh& map)
 {
     //
-    // Update all sets in memory.
+    // Update all sets in memory
     //
 
-    HashTable<const Type*> memSets =
-        morphMap.mesh().objectRegistry::lookupClass<Type>();
+    const HashTable<const SetType*> sets
+    (
+        map.mesh().objectRegistry::lookupClass<const SetType>()
+    );
 
-    forAllIters(memSets, iter)
+    for (const auto& iter : sets.csorted())
     {
-        Type& set = const_cast<Type&>(*iter());
+        SetType& set = const_cast<SetType&>(*iter.val());
 
         DebugPout
             << "Set:" << set.name() << " size:" << set.size()
             << " updated in memory" << endl;
 
-        set.updateMesh(morphMap);
+        set.updateMesh(map);
 
         // Write or not? Debatable.
         set.write();
@@ -66,35 +68,30 @@ void Foam::setUpdater::updateSets(const mapPolyMesh& morphMap) const
     // Get last valid mesh (discard points-only change)
     IOobjectList objs
     (
-        morphMap.mesh().time(),
-        morphMap.mesh().facesInstance(),
+        map.mesh().time(),
+        map.mesh().facesInstance(),
         "polyMesh/sets"
     );
 
-    IOobjectList fileSets(objs.lookupClass<Type>());
-
-    forAllConstIters(fileSets, iter)
+    for (const IOobject& io : objs.csorted<SetType>())
     {
-        if (!memSets.found(iter.key()))
+        if (!sets.contains(io.name()))
         {
             // Not in memory. Load it.
-            Type set(*iter());
+            SetType set(io);
 
-            if (debug)
-            {
-                Pout<< "Set:" << set.name() << " size:" << set.size()
-                    << " updated on disk" << endl;
-            }
-
-            set.updateMesh(morphMap);
+            DebugPout
+                << "Set:" << set.name() << " size:" << set.size()
+                << " updated on disk" << endl;
 
+            set.updateMesh(map);
             set.write();
         }
         else
         {
             DebugPout
-                << "Set:" << iter.key() << " already updated from memory"
-                << endl;
+                << "Set:" << io.name()
+                << " already updated from memory" << endl;
         }
     }
 }
diff --git a/src/fileFormats/vtk/read/vtkUnstructuredReaderTemplates.C b/src/fileFormats/vtk/read/vtkUnstructuredReaderTemplates.C
index d9e230efd51..6447f94a590 100644
--- a/src/fileFormats/vtk/read/vtkUnstructuredReaderTemplates.C
+++ b/src/fileFormats/vtk/read/vtkUnstructuredReaderTemplates.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2012 OpenFOAM Foundation
-    Copyright (C) 2021 OpenCFD Ltd.
+    Copyright (C) 2021-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -33,20 +33,18 @@ License
 template<class Type>
 void Foam::vtkUnstructuredReader::printFieldStats(const objectRegistry& obj)
 {
-    const wordList fieldNames(obj.sortedNames<Type>());
+    const UPtrList<const Type> fields(obj.csorted<Type>());
 
-    if (fieldNames.size())
+    if (!fields.empty())
     {
-        Info<< "Read " << fieldNames.size() << ' ' << Type::typeName
+        Info<< "Read " << fields.size() << ' ' << Type::typeName
             << " fields:" << nl
             << "Size\tName" << nl
             << "----\t----" << nl;
 
-        for (const word& fieldName : fieldNames)
+        for (const Type& field : fields)
         {
-            Info<< obj.lookupObject<Type>(fieldName).size()
-                << '\t' << fieldName
-                << nl;
+            Info<< field.size() << '\t' << field.name() << nl;
         }
         Info<< endl;
     }
diff --git a/src/finiteVolume/cfdTools/general/solutionControl/loopControl/loopControl.C b/src/finiteVolume/cfdTools/general/solutionControl/loopControl/loopControl.C
index 39909cf99e1..8a19ccb1667 100644
--- a/src/finiteVolume/cfdTools/general/solutionControl/loopControl/loopControl.C
+++ b/src/finiteVolume/cfdTools/general/solutionControl/loopControl/loopControl.C
@@ -101,14 +101,16 @@ bool Foam::loopControl::checkConverged() const
         return false;
     }
 
-    HashTable<const fvMesh*> meshes = time_.lookupClass<const fvMesh>();
-
     bool achieved = true;
     bool checked = false; // safety that some checks were indeed performed
 
-    forAllConstIters(meshes, meshIter)
+    const objectRegistry& obr = time_;
+
+    forAllConstIters(obr, iter)
     {
-        const fvMesh& regionMesh = *(meshIter.val());
+        const fvMesh* meshPtr = dynamic_cast<const fvMesh*>(iter.val());
+        if (!meshPtr) continue;
+        const fvMesh& regionMesh = *meshPtr;
 
         const dictionary& solverDict = regionMesh.solverPerformanceDict();
         for (const entry& dataDictEntry : solverDict)
diff --git a/src/finiteVolume/cfdTools/general/solutionControl/solutionControl/solutionControlTemplates.C b/src/finiteVolume/cfdTools/general/solutionControl/solutionControl/solutionControlTemplates.C
index 42a1cfd6748..eac74386367 100644
--- a/src/finiteVolume/cfdTools/general/solutionControl/solutionControl/solutionControlTemplates.C
+++ b/src/finiteVolume/cfdTools/general/solutionControl/solutionControl/solutionControlTemplates.C
@@ -37,12 +37,8 @@ void Foam::solutionControl::storePrevIter() const
 {
     typedef GeometricField<Type, fvPatchField, volMesh> GeoField;
 
-    HashTable<GeoField*> flds(mesh_.objectRegistry::lookupClass<GeoField>());
-
-    forAllIters(flds, iter)
+    for (GeoField& fld : mesh_.objectRegistry::sorted<GeoField>())
     {
-        GeoField& fld = *iter();
-
         const word& fldName = fld.name();
 
         if (!fldName.contains("PrevIter") && mesh_.relaxField(fldName))
diff --git a/src/finiteVolume/fvMesh/fvMeshTools/fvMeshToolsTemplates.C b/src/finiteVolume/fvMesh/fvMeshTools/fvMeshToolsTemplates.C
index a22b5a69413..32a7c938e60 100644
--- a/src/finiteVolume/fvMesh/fvMeshTools/fvMeshToolsTemplates.C
+++ b/src/finiteVolume/fvMesh/fvMeshTools/fvMeshToolsTemplates.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2012-2016 OpenFOAM Foundation
-    Copyright (C) 2019-2022 OpenCFD Ltd.
+    Copyright (C) 2019-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -41,14 +41,8 @@ void Foam::fvMeshTools::addPatchFields
     const typename GeoField::value_type& defaultPatchValue
 )
 {
-    HashTable<GeoField*> flds
-    (
-        mesh.objectRegistry::lookupClass<GeoField>()
-    );
-
-    forAllIters(flds, iter)
+    for (GeoField& fld : mesh.objectRegistry::sorted<GeoField>())
     {
-        GeoField& fld = *iter.val();
         auto& bfld = fld.boundaryFieldRef();
 
         const label newPatchi = bfld.size();
@@ -95,14 +89,8 @@ void Foam::fvMeshTools::setPatchFields
     const dictionary& patchFieldDict
 )
 {
-    HashTable<GeoField*> flds
-    (
-        mesh.objectRegistry::lookupClass<GeoField>()
-    );
-
-    forAllIters(flds, iter)
+    for (GeoField& fld : mesh.objectRegistry::sorted<GeoField>())
     {
-        GeoField& fld = *iter.val();
         auto& bfld = fld.boundaryFieldRef();
 
         const dictionary* dict = patchFieldDict.findDict(fld.name());
@@ -132,14 +120,8 @@ void Foam::fvMeshTools::setPatchFields
     const typename GeoField::value_type& value
 )
 {
-    HashTable<GeoField*> flds
-    (
-        mesh.objectRegistry::lookupClass<GeoField>()
-    );
-
-    forAllIters(flds, iter)
+    for (GeoField& fld : mesh.objectRegistry::sorted<GeoField>())
     {
-        GeoField& fld = *iter.val();
         auto& bfld = fld.boundaryFieldRef();
 
         bfld[patchi] == value;
@@ -151,15 +133,11 @@ void Foam::fvMeshTools::setPatchFields
 template<class GeoField>
 void Foam::fvMeshTools::trimPatchFields(fvMesh& mesh, const label nPatches)
 {
-    HashTable<GeoField*> flds
-    (
-        mesh.objectRegistry::lookupClass<GeoField>()
-    );
-
-    forAllIters(flds, iter)
+    for (GeoField& fld : mesh.objectRegistry::sorted<GeoField>())
     {
-        GeoField& fld = *iter.val();
-        fld.boundaryFieldRef().resize(nPatches);
+        auto& bfld = fld.boundaryFieldRef();
+
+        bfld.resize(nPatches);
     }
 }
 
@@ -172,14 +150,8 @@ void Foam::fvMeshTools::reorderPatchFields
     const labelList& oldToNew
 )
 {
-    HashTable<GeoField*> flds
-    (
-        mesh.objectRegistry::lookupClass<GeoField>()
-    );
-
-    forAllIters(flds, iter)
+    for (GeoField& fld : mesh.objectRegistry::sorted<GeoField>())
     {
-        GeoField& fld = *iter.val();
         auto& bfld = fld.boundaryFieldRef();
 
         bfld.reorder(oldToNew);
diff --git a/src/functionObjects/field/externalCoupled/externalCoupled.C b/src/functionObjects/field/externalCoupled/externalCoupled.C
index d2c5982d6c3..9ea75ad387a 100644
--- a/src/functionObjects/field/externalCoupled/externalCoupled.C
+++ b/src/functionObjects/field/externalCoupled/externalCoupled.C
@@ -568,7 +568,7 @@ bool Foam::functionObjects::externalCoupled::read(const dictionary& dict)
     // Leave trigger intact
 
     // Get names of all fvMeshes (and derived types)
-    wordList allRegionNames(time_.lookupClass<fvMesh>().sortedToc());
+    wordList allRegionNames(time_.sortedNames<fvMesh>());
 
     const dictionary& allRegionsDict = dict.subDict("regions");
     for (const entry& dEntry : allRegionsDict)
diff --git a/src/functionObjects/field/mapFields/mapFieldsTemplates.C b/src/functionObjects/field/mapFields/mapFieldsTemplates.C
index aa35e007160..280ef62c097 100644
--- a/src/functionObjects/field/mapFields/mapFieldsTemplates.C
+++ b/src/functionObjects/field/mapFields/mapFieldsTemplates.C
@@ -119,14 +119,12 @@ bool Foam::functionObjects::mapFields::mapFieldType() const
 
     const fvMesh& mapRegion = mapRegionPtr_();
 
-    wordList fieldNames(this->mesh_.names(VolFieldType::typeName));
+    wordList fieldNames(this->mesh_.sortedNames<VolFieldType>(fieldNames_));
 
-    const labelList selected(fieldNames_.matching(fieldNames));
+    const bool processed = !fieldNames.empty();
 
-    for (const label fieldi : selected)
+    for (const word& fieldName : fieldNames)
     {
-        const word& fieldName = fieldNames[fieldi];
-
         const VolFieldType& field = lookupObject<VolFieldType>(fieldName);
 
         auto* mapFieldPtr = mapRegion.getObjectPtr<VolFieldType>(fieldName);
@@ -159,7 +157,7 @@ bool Foam::functionObjects::mapFields::mapFieldType() const
         evaluateConstraintTypes(mappedField);
     }
 
-    return !selected.empty();
+    return processed;
 }
 
 
@@ -170,14 +168,12 @@ bool Foam::functionObjects::mapFields::writeFieldType() const
 
     const fvMesh& mapRegion = mapRegionPtr_();
 
-    wordList fieldNames(this->mesh_.names(VolFieldType::typeName));
+    wordList fieldNames(this->mesh_.sortedNames<VolFieldType>(fieldNames_));
 
-    const labelList selected(fieldNames_.matching(fieldNames));
+    const bool processed = !fieldNames.empty();
 
-    for (const label fieldi : selected)
+    for (const word& fieldName : fieldNames)
     {
-        const word& fieldName = fieldNames[fieldi];
-
         const VolFieldType& mappedField =
             mapRegion.template lookupObject<VolFieldType>(fieldName);
 
@@ -186,7 +182,7 @@ bool Foam::functionObjects::mapFields::writeFieldType() const
         Log << "    " << fieldName << ": written";
     }
 
-    return !selected.empty();
+    return processed;
 }
 
 
diff --git a/src/functionObjects/field/nearWallFields/nearWallFieldsTemplates.C b/src/functionObjects/field/nearWallFields/nearWallFieldsTemplates.C
index e8c20782f1c..93b5b434d68 100644
--- a/src/functionObjects/field/nearWallFields/nearWallFieldsTemplates.C
+++ b/src/functionObjects/field/nearWallFields/nearWallFieldsTemplates.C
@@ -38,15 +38,13 @@ void Foam::functionObjects::nearWallFields::createFields
 {
     typedef GeometricField<Type, fvPatchField, volMesh> VolFieldType;
 
-    HashTable<const VolFieldType*> flds(obr_.lookupClass<VolFieldType>());
-
-    forAllConstIters(flds, iter)
+    for (const VolFieldType& fld : obr_.csorted<VolFieldType>())
     {
-        const VolFieldType& fld = *(iter.val());
+        const auto fieldMapIter = fieldMap_.cfind(fld.name());
 
-        if (fieldMap_.found(fld.name()))
+        if (fieldMapIter.good())
         {
-            const word& sampleFldName = fieldMap_[fld.name()];
+            const word& sampleFldName = fieldMapIter.val();
 
             if (obr_.found(sampleFldName))
             {
@@ -57,19 +55,18 @@ void Foam::functionObjects::nearWallFields::createFields
             }
             else
             {
-                label sz = sflds.size();
-                sflds.setSize(sz+1);
-
                 IOobject io(fld);
-                io.readOpt(IOobject::NO_READ);
-                io.writeOpt(IOobject::NO_WRITE);
-
+                io.readOpt(IOobjectOption::NO_READ);
+                io.writeOpt(IOobjectOption::NO_WRITE);
                 io.rename(sampleFldName);
 
                 // Override bc to be calculated
+                const label newFieldi = sflds.size();
+                sflds.resize(newFieldi+1);
+
                 sflds.set
                 (
-                    sz,
+                    newFieldi,
                     new VolFieldType
                     (
                         io,
@@ -79,7 +76,7 @@ void Foam::functionObjects::nearWallFields::createFields
                     )
                 );
 
-                Log << "    created " << sflds[sz].name()
+                Log << "    created " << io.name()
                     << " to sample " << fld.name() << endl;
             }
         }
diff --git a/src/functionObjects/field/particleDistribution/particleDistribution.C b/src/functionObjects/field/particleDistribution/particleDistribution.C
index 247c897c2fa..d9c5ac5ba62 100644
--- a/src/functionObjects/field/particleDistribution/particleDistribution.C
+++ b/src/functionObjects/field/particleDistribution/particleDistribution.C
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2016-2022 OpenCFD Ltd.
+    Copyright (C) 2016-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -107,7 +107,9 @@ bool Foam::functionObjects::particleDistribution::write()
 {
     Log << type() << " " << name() << " output:" << endl;
 
-    if (!mesh_.foundObject<cloud>(cloudName_))
+    const cloud* cloudPtr = mesh_.cfindObject<cloud>(cloudName_);
+
+    if (!cloudPtr)
     {
         WarningInFunction
             << "Unable to find cloud " << cloudName_
@@ -117,7 +119,7 @@ bool Foam::functionObjects::particleDistribution::write()
         return false;
     }
 
-    const cloud& c = mesh_.lookupObject<cloud>(cloudName_);
+    const cloud& c = *cloudPtr;
 
     objectRegistry cloudObr
     (
diff --git a/src/functionObjects/field/regionSizeDistribution/regionSizeDistribution.C b/src/functionObjects/field/regionSizeDistribution/regionSizeDistribution.C
index bb60583fc58..a15639fe343 100644
--- a/src/functionObjects/field/regionSizeDistribution/regionSizeDistribution.C
+++ b/src/functionObjects/field/regionSizeDistribution/regionSizeDistribution.C
@@ -907,16 +907,15 @@ bool Foam::functionObjects::regionSizeDistribution::write()
         {
             for
             (
-                const word& fldName
-              : obr_.sortedNames<volScalarField>(fields_)
+                const volScalarField& vfield
+              : obr_.csorted<volScalarField>(fields_)
             )
             {
+                const word& fldName = vfield.name();
+
                 Log << "    Scalar field " << fldName << endl;
 
-                tmp<Field<scalar>> tfld
-                (
-                    obr_.lookupObject<volScalarField>(fldName).primitiveField()
-                );
+                tmp<Field<scalar>> tfld(vfield.primitiveField());
                 const auto& fld = tfld();
 
                 writeGraphs
@@ -938,23 +937,21 @@ bool Foam::functionObjects::regionSizeDistribution::write()
         {
             for
             (
-                const word& fldName
-              : obr_.sortedNames<volVectorField>(fields_)
+                const volVectorField& vfield
+              : obr_.csorted<volVectorField>(fields_)
             )
             {
+                const word& fldName = vfield.name();
+
                 Log << "    Vector field " << fldName << endl;
 
-                tmp<Field<vector>> tfld
-                (
-                    obr_.lookupObject<volVectorField>(fldName).primitiveField()
-                );
+                tmp<Field<vector>> tfld(vfield.primitiveField());
 
                 if (csysPtr_)
                 {
                     Log << "Transforming vector field " << fldName
                         << " with coordinate system "
-                        << csysPtr_->name()
-                        << endl;
+                        << csysPtr_->name() << endl;
 
                     tfld = csysPtr_->localVector(tfld());
                 }
diff --git a/src/functionObjects/field/setFlow/setFlow.C b/src/functionObjects/field/setFlow/setFlow.C
index bd12f0ef08b..78532336f3b 100644
--- a/src/functionObjects/field/setFlow/setFlow.C
+++ b/src/functionObjects/field/setFlow/setFlow.C
@@ -84,7 +84,7 @@ void Foam::functionObjects::setFlow::setPhi(const volVectorField& U)
             FatalErrorInFunction
                 << "Unable to find rho field'" << rhoName_
                 << "' in the mesh database.  Available fields are:"
-                << mesh_.names<volScalarField>()
+                << flatOutput(mesh_.sortedNames<volScalarField>())
                 << exit(FatalError);
         }
     }
diff --git a/src/functionObjects/field/surfaceInterpolate/surfaceInterpolateTemplates.C b/src/functionObjects/field/surfaceInterpolate/surfaceInterpolateTemplates.C
index 17895405b04..be53edfc451 100644
--- a/src/functionObjects/field/surfaceInterpolate/surfaceInterpolateTemplates.C
+++ b/src/functionObjects/field/surfaceInterpolate/surfaceInterpolateTemplates.C
@@ -45,12 +45,8 @@ void Foam::functionObjects::surfaceInterpolate::interpolateFields()
     }
 
 
-    HashTable<const VolFieldType*> flds(obr_.lookupClass<VolFieldType>());
-
-    forAllConstIters(flds, iter)
+    for (const VolFieldType& fld : obr_.csorted<VolFieldType>())
     {
-        const VolFieldType& fld = *iter();
-
         if (fieldMap.found(fld.name()))
         {
             // const word sName = "interpolate(" + fld.name() + ')';
@@ -62,8 +58,8 @@ void Foam::functionObjects::surfaceInterpolate::interpolateFields()
             }
             else
             {
-                Log << "        interpolating " << fld.name() << " to create "
-                    << sName << endl;
+                Log << "        interpolating "
+                    << fld.name() << " to create " << sName << endl;
             }
 
             store(sName, linearInterpolate(fld));
diff --git a/src/functionObjects/forces/forces/forces.C b/src/functionObjects/forces/forces/forces.C
index e1ff6bba1d1..b5caaf7b3c2 100644
--- a/src/functionObjects/forces/forces/forces.C
+++ b/src/functionObjects/forces/forces/forces.C
@@ -756,7 +756,10 @@ void Foam::functionObjects::forces::calcForcesMoments()
         const volScalarField rho(this->rho());
         const volScalarField mu(this->mu());
 
-        const auto models = obr_.lookupClass<porosityModel>();
+        const UPtrList<const porosityModel> models
+        (
+            obr_.csorted<porosityModel>()
+        );
 
         if (models.empty())
         {
@@ -766,10 +769,10 @@ void Foam::functionObjects::forces::calcForcesMoments()
                 << endl;
         }
 
-        forAllConstIters(models, iter)
+        for (const porosityModel& mdl : models)
         {
             // Non-const access required if mesh is changing
-            auto& pm = const_cast<porosityModel&>(*iter());
+            auto& pm = const_cast<porosityModel&>(mdl);
 
             const vectorField fPTot(pm.force(U, rho, mu));
 
diff --git a/src/functionObjects/forces/propellerInfo/propellerInfo.C b/src/functionObjects/forces/propellerInfo/propellerInfo.C
index 7f233b3f255..c6ed2737dd6 100644
--- a/src/functionObjects/forces/propellerInfo/propellerInfo.C
+++ b/src/functionObjects/forces/propellerInfo/propellerInfo.C
@@ -220,7 +220,7 @@ const Foam::volVectorField& Foam::functionObjects::propellerInfo::U() const
         FatalErrorInFunction
             << "Unable to find velocity field " << UName_
             << " . Available vector fields are: "
-            << mesh_.names<volVectorField>()
+            << flatOutput(mesh_.sortedNames<volVectorField>())
             << exit(FatalError);
     }
 
diff --git a/src/mesh/snappyHexMesh/meshRefinement/meshRefinementTemplates.C b/src/mesh/snappyHexMesh/meshRefinement/meshRefinementTemplates.C
index f28ba6d468b..324c6d2972b 100644
--- a/src/mesh/snappyHexMesh/meshRefinement/meshRefinementTemplates.C
+++ b/src/mesh/snappyHexMesh/meshRefinement/meshRefinementTemplates.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2015 OpenFOAM Foundation
-    Copyright (C) 2019-2020 OpenCFD Ltd.
+    Copyright (C) 2019-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -203,26 +203,22 @@ void Foam::meshRefinement::addPatchFields
     const word& patchFieldType
 )
 {
-    HashTable<GeoField*> flds
-    (
-        mesh.objectRegistry::lookupClass<GeoField>()
-    );
-
-    forAllIters(flds, iter)
+    // Field order is irrelevant...
+    for (GeoField& fld : mesh.objectRegistry::objects<GeoField>())
     {
-        GeoField& fld = *iter();
-        auto& fldBf = fld.boundaryFieldRef();
+        auto& bfld = fld.boundaryFieldRef();
+
+        const label newPatchi = bfld.size();
+        bfld.resize(newPatchi+1);
 
-        label sz = fldBf.size();
-        fldBf.setSize(sz+1);
-        fldBf.set
+        bfld.set
         (
-            sz,
+            newPatchi,
             GeoField::Patch::New
             (
                 patchFieldType,
-                mesh.boundary()[sz],
-                fld()
+                mesh.boundary()[newPatchi],
+                fld.internalField()
             )
         );
     }
@@ -236,14 +232,10 @@ void Foam::meshRefinement::reorderPatchFields
     const labelList& oldToNew
 )
 {
-    HashTable<GeoField*> flds
-    (
-        mesh.objectRegistry::lookupClass<GeoField>()
-    );
-
-    forAllIters(flds, iter)
+    // Field order is irrelevant...
+    for (GeoField& fld : mesh.objectRegistry::objects<GeoField>())
     {
-        iter()->boundaryFieldRef().reorder(oldToNew);
+        fld.boundaryFieldRef().reorder(oldToNew);
     }
 }
 
diff --git a/src/overset/cellCellStencil/cellCellStencil/cellCellStencilTemplates.C b/src/overset/cellCellStencil/cellCellStencil/cellCellStencilTemplates.C
index fd5ebc59920..bb441cb79a2 100644
--- a/src/overset/cellCellStencil/cellCellStencil/cellCellStencilTemplates.C
+++ b/src/overset/cellCellStencil/cellCellStencil/cellCellStencilTemplates.C
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2018-2022 OpenCFD Ltd.
+    Copyright (C) 2018-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -116,10 +116,10 @@ void Foam::cellCellStencil::interpolate
 {
     const cellCellStencil& overlap = *this;
 
-    auto flds(mesh.lookupClass<GeoField>());
-    for (auto fldPtr : flds)
+    for (const GeoField& field : mesh.thisDb().csorted<GeoField>())
     {
-        const word& name = fldPtr->name();
+        const word& name = field.name();
+
         if (!suppressed.found(baseName(name)))
         {
             if (debug)
@@ -128,7 +128,7 @@ void Foam::cellCellStencil::interpolate
                     << name << endl;
             }
 
-            auto& fld = const_cast<GeoField&>(*fldPtr);
+            auto& fld = const_cast<GeoField&>(field);
 
             interpolate
             (
@@ -142,8 +142,8 @@ void Foam::cellCellStencil::interpolate
         {
             if (debug)
             {
-                Pout<< "cellCellStencil::interpolate: skipping : " << name
-                    << endl;
+                Pout<< "cellCellStencil::interpolate: skipping : "
+                    << name << endl;
             }
         }
     }
diff --git a/src/parallel/distributed/distributedTriSurfaceMesh/distributedTriSurfaceMeshTemplates.C b/src/parallel/distributed/distributedTriSurfaceMesh/distributedTriSurfaceMeshTemplates.C
index 3c700a6b0d4..42464a3c023 100644
--- a/src/parallel/distributed/distributedTriSurfaceMesh/distributedTriSurfaceMeshTemplates.C
+++ b/src/parallel/distributed/distributedTriSurfaceMesh/distributedTriSurfaceMeshTemplates.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2013 OpenFOAM Foundation
-    Copyright (C) 2019 OpenCFD Ltd.
+    Copyright (C) 2019-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -88,15 +88,8 @@ void Foam::distributedTriSurfaceMesh::distributeFields
 {
     typedef DimensionedField<Type, triSurfaceGeoMesh> fieldType;
 
-    HashTable<fieldType*> fields
-    (
-        objectRegistry::lookupClass<fieldType>()
-    );
-
-    forAllIters(fields, fieldIter)
+    for (fieldType& field : objectRegistry::sorted<fieldType>())
     {
-        fieldType& field = *fieldIter();
-
         const label oldSize = field.size();
 
         map.distribute(field);
diff --git a/src/regionFaModels/functionObjects/setTimeStep/setTimeStepFaRegionsFunctionObject.C b/src/regionFaModels/functionObjects/setTimeStep/setTimeStepFaRegionsFunctionObject.C
index 3b5e95ffd1f..bf28446e867 100644
--- a/src/regionFaModels/functionObjects/setTimeStep/setTimeStepFaRegionsFunctionObject.C
+++ b/src/regionFaModels/functionObjects/setTimeStep/setTimeStepFaRegionsFunctionObject.C
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2020 OpenCFD Ltd.
+    Copyright (C) 2020-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -114,25 +114,20 @@ bool Foam::functionObjects::setTimeStepFaRegionsFunctionObject::read
 Foam::scalar Foam::functionObjects::setTimeStepFaRegionsFunctionObject::
 regionDeltaT() const
 {
-    const wordList names(time_.sortedNames<regionFaModel>());
+    bool adjust = false;
+    scalar Co = 0;
 
-    scalar Co = 0.0;
-
-    forAll (names, i)
+    for (const regionFaModel& reg : time_.cobjects<regionFaModel>())
     {
-        const auto* regionFa = time_.cfindObject<regionFaModel>(names[i]);
-
-        if (regionFa)
+        const scalar regionCo = reg.CourantNumber();
+        if (Co < regionCo)
         {
-            const scalar regionCo = regionFa->CourantNumber();
-            if (regionCo > Co)
-            {
-                Co = regionCo;
-            }
+            Co = regionCo;
+            adjust = true;
         }
     }
 
-    if (names.size() > 0)
+    if (adjust)
     {
         const scalar regionFaMaxCo =
             time_.controlDict().get<scalar>("regionFaMaxCo");
diff --git a/src/regionModels/regionCoupling/derivedFvPatchFields/filmPyrolysisRadiativeCoupledMixed/filmPyrolysisRadiativeCoupledMixedFvPatchScalarField.C b/src/regionModels/regionCoupling/derivedFvPatchFields/filmPyrolysisRadiativeCoupledMixed/filmPyrolysisRadiativeCoupledMixedFvPatchScalarField.C
index c121f240420..4ce0f3ef447 100644
--- a/src/regionModels/regionCoupling/derivedFvPatchFields/filmPyrolysisRadiativeCoupledMixed/filmPyrolysisRadiativeCoupledMixedFvPatchScalarField.C
+++ b/src/regionModels/regionCoupling/derivedFvPatchFields/filmPyrolysisRadiativeCoupledMixed/filmPyrolysisRadiativeCoupledMixedFvPatchScalarField.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2013-2017 OpenFOAM Foundation
-    Copyright (C) 2019-2020 OpenCFD Ltd.
+    Copyright (C) 2019-2023 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -41,21 +41,25 @@ const filmPyrolysisRadiativeCoupledMixedFvPatchScalarField::filmModelType&
 filmPyrolysisRadiativeCoupledMixedFvPatchScalarField::
 filmModel() const
 {
-    HashTable<const filmModelType*> models
-        = db().time().lookupClass<filmModelType>();
+    typedef filmModelType ModelType;
 
-    forAllConstIters(models, iter)
+    const UPtrList<const ModelType> models
+    (
+        db().time().csorted<ModelType>()
+    );
+
+    for (const ModelType& mdl : models)
     {
-        if (iter()->regionMesh().name() == filmRegionName_)
+        if (mdl.regionMesh().name() == filmRegionName_)
         {
-            return *iter();
+            return mdl;
         }
     }
 
-    DynamicList<word> modelNames;
-    forAllConstIters(models, iter)
+    DynamicList<word> modelNames(models.size());
+    for (const ModelType& mdl : models)
     {
-        modelNames.append(iter()->regionMesh().name());
+        modelNames.push_back(mdl.regionMesh().name());
     }
 
     FatalErrorInFunction
@@ -63,7 +67,7 @@ filmModel() const
         << ".  Available regions include: " << modelNames
         << abort(FatalError);
 
-    return **models.begin();
+    return models.front();  // Failure
 }
 
 
@@ -72,21 +76,25 @@ pyrolysisModelType&
 filmPyrolysisRadiativeCoupledMixedFvPatchScalarField::
 pyrModel() const
 {
-    HashTable<const pyrolysisModelType*> models =
-        db().time().lookupClass<pyrolysisModelType>();
+    typedef pyrolysisModelType ModelType;
+
+    const UPtrList<const ModelType> models
+    (
+        db().time().csorted<ModelType>()
+    );
 
-    forAllConstIters(models, iter)
+    for (const ModelType& mdl : models)
     {
-        if (iter()->regionMesh().name() == pyrolysisRegionName_)
+        if (mdl.regionMesh().name() == pyrolysisRegionName_)
         {
-            return *iter();
+            return mdl;
         }
     }
 
-    DynamicList<word> modelNames;
-    forAllConstIters(models, iter)
+    DynamicList<word> modelNames(models.size());
+    for (const ModelType& mdl : models)
     {
-        modelNames.append(iter()->regionMesh().name());
+        modelNames.push_back(mdl.regionMesh().name());
     }
 
     FatalErrorInFunction
@@ -94,7 +102,7 @@ pyrModel() const
         << ".  Available regions include: " << modelNames
         << abort(FatalError);
 
-    return **models.begin();
+    return models.front();  // Failure
 }
 
 
diff --git a/src/regionModels/regionCoupling/derivedFvPatchFields/filmPyrolysisRadiativeCoupledMixed/filmPyrolysisRadiativeCoupledMixedFvPatchScalarField.H b/src/regionModels/regionCoupling/derivedFvPatchFields/filmPyrolysisRadiativeCoupledMixed/filmPyrolysisRadiativeCoupledMixedFvPatchScalarField.H
index 66e0625638b..92b6a4111a4 100644
--- a/src/regionModels/regionCoupling/derivedFvPatchFields/filmPyrolysisRadiativeCoupledMixed/filmPyrolysisRadiativeCoupledMixedFvPatchScalarField.H
+++ b/src/regionModels/regionCoupling/derivedFvPatchFields/filmPyrolysisRadiativeCoupledMixed/filmPyrolysisRadiativeCoupledMixedFvPatchScalarField.H
@@ -113,7 +113,7 @@ public:
 
 private:
 
-    // Private data
+    // Private Data
 
         //- Name of film region
         const word filmRegionName_;
@@ -136,10 +136,13 @@ private:
         //- Maximum delta film to be considered wet
         const scalar filmDeltaWet_;
 
-        //- Retrieve film model from the database
+
+    // Private Member Functions
+
+        //- Retrieve film model from the database, or FatalError
         const filmModelType& filmModel() const;
 
-        //- Retrieve pyrolysis model from the database
+        //- Retrieve pyrolysis model from the database, or FatalError
         const pyrolysisModelType& pyrModel() const;
 
 
diff --git a/src/sampling/sampledSet/sampledSets/sampledSets.C b/src/sampling/sampledSet/sampledSets/sampledSets.C
index cfebcab8121..f8b8ea35b04 100644
--- a/src/sampling/sampledSet/sampledSets/sampledSets.C
+++ b/src/sampling/sampledSet/sampledSets/sampledSets.C
@@ -155,8 +155,7 @@ void Foam::sampledSets::gatherAllSets()
 
     const PtrList<sampledSet>& localSets = *this;
 
-    gatheredSets_.free();
-    gatheredSets_.resize(localSets.size());
+    gatheredSets_.resize_null(localSets.size());
     gatheredSorting_.resize_nocopy(localSets.size());
     globalIndices_.resize_nocopy(localSets.size());
 
diff --git a/src/thermophysicalModels/basic/basicThermo/basicThermo.C b/src/thermophysicalModels/basic/basicThermo/basicThermo.C
index d994878872d..e4bcf751c7c 100644
--- a/src/thermophysicalModels/basic/basicThermo/basicThermo.C
+++ b/src/thermophysicalModels/basic/basicThermo/basicThermo.C
@@ -456,29 +456,26 @@ const Foam::basicThermo& Foam::basicThermo::lookupThermo
     const fvPatchScalarField& pf
 )
 {
-    const basicThermo* thermo = pf.db().findObject<basicThermo>(dictName);
+    const basicThermo* thermoPtr = pf.db().cfindObject<basicThermo>(dictName);
 
-    if (thermo)
+    if (thermoPtr)
     {
-        return *thermo;
+        return *thermoPtr;
     }
 
-    HashTable<const basicThermo*> thermos =
-        pf.db().lookupClass<basicThermo>();
-
-    forAllConstIters(thermos, iter)
+    for (const basicThermo& thermo : pf.db().cobjects<basicThermo>())
     {
-        thermo = iter.val();
         if
         (
-            &(thermo->he().internalField())
+            &(thermo.he().internalField())
          == &(pf.internalField())
         )
         {
-            return *thermo;
+            return thermo;
         }
     }
 
+    // Failure
     return pf.db().lookupObject<basicThermo>(dictName);
 }
 
-- 
GitLab