diff --git a/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/createSolidFields.H b/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/createSolidFields.H
index 2cc60f7b9b0655e26c23bef010c214687bbc5793..fa5966905bcd906bc01291489259ad1fbbe7a164 100644
--- a/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/createSolidFields.H
+++ b/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/createSolidFields.H
@@ -31,7 +31,12 @@
             coordinates.set
             (
                 i,
-                coordinateSystem::New(solidRegions[i], thermos[i])
+                coordinateSystem::New
+                (
+                    solidRegions[i],
+                    thermos[i],
+                    coordinateSystem::typeName_()
+                )
             );
 
             tmp<volVectorField> tkappaByCp =
@@ -57,7 +62,11 @@
             );
 
             aniAlphas[i].primitiveFieldRef() =
-                coordinates[i].R().transformVector(tkappaByCp());
+                coordinates[i].transformPrincipal
+                (
+                    solidRegions[i].cellCentres(),
+                    tkappaByCp()
+                );
             aniAlphas[i].correctBoundaryConditions();
 
         }
diff --git a/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/setRegionSolidFields.H b/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/setRegionSolidFields.H
index 98b081952c65944c1470fd768ba5a82edfd71040..7790ac9659ae6fe83cf9e9ab96edbd1656590bed 100644
--- a/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/setRegionSolidFields.H
+++ b/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/setRegionSolidFields.H
@@ -15,7 +15,12 @@ if (!thermo.isotropic())
     const coordinateSystem& coodSys = coordinates[i];
 
     aniAlpha.primitiveFieldRef() =
-        coodSys.R().transformVector(tkappaByCp());
+        coodSys.transformPrincipal
+        (
+            mesh.cellCentres(),
+            tkappaByCp()
+        );
+
     aniAlpha.correctBoundaryConditions();
 
     taniAlpha = tmp<volSymmTensorField>
diff --git a/applications/test/coordinateSystem/Test-coordinateSystem.C b/applications/test/coordinateSystem/Test-coordinateSystem.C
index 3f68919a520079264ae8052af3c3a9adefd9f4e4..d8ea6c3e0e731e98fd96e11adbfb5290424e8c14 100644
--- a/applications/test/coordinateSystem/Test-coordinateSystem.C
+++ b/applications/test/coordinateSystem/Test-coordinateSystem.C
@@ -30,12 +30,68 @@ Description
 \*---------------------------------------------------------------------------*/
 
 #include "argList.H"
-#include "coordinateSystem.H"
+#include "Time.H"
+#include "coordinateSystems.H"
+#include "identityRotation.H"
+#include "indirectCS.H"
 #include "Fstream.H"
 #include "IOstreams.H"
+#include "transform.H"
 
 using namespace Foam;
 
+
+template<class T>
+void testTransform(const coordinateSystem& cs, const point& p, const T& val)
+{
+    Info<< "    " << pTraits<T>::typeName << ": " << val
+        << " transform: " << cs.transform(p, val)
+        << " invTransform: " << cs.invTransform(p, val) << nl;
+
+    // Info<< " both: " << cs.invTransform(p, cs.transform(p, val)) << nl;
+}
+
+
+void basicTests(const coordinateSystem& cs)
+{
+    cs.writeEntry(cs.name(), Info);
+
+    if (isA<coordSystem::indirect>(cs))
+    {
+        Info<< "indirect from:" << nl;
+        dynamicCast<const coordSystem::indirect>(cs).cs()
+            .writeEntry(cs.name(), Info);
+    }
+
+
+    Info<< "rotation: " << cs.R() << nl;
+
+    List<point> testPoints
+    ({
+        {1,0,0}, {0,1,0}, {0,0,1}, {1,1,1},
+    });
+
+
+    for (const point& p : testPoints)
+    {
+        Info<< nl
+            << "  test point: " << p
+            << " = local point " << cs.transformPoint(p)
+            << " = local coord " << cs.localPosition(p) << nl;
+
+        const vector v1(1, 1, 1);
+        const tensor t1(tensor::I);
+        const tensor t2(1, 2, 3, 4, 5, 6, 7, 8, 9);
+
+        testTransform(cs, p, v1);
+        testTransform(cs, p, t1);
+        testTransform(cs, p, t2);
+    }
+
+    Info<< nl;
+}
+
+
 void doTest(const dictionary& dict)
 {
     Info<< dict.dictName() << dict << nl;
@@ -43,18 +99,42 @@ void doTest(const dictionary& dict)
     // Could fail?
     const bool throwingIOError = FatalIOError.throwExceptions();
     const bool throwingError = FatalError.throwExceptions();
+
     try
     {
-        coordinateSystem cs1(dict.dictName(), dict);
+        auto cs1ptr = coordinateSystem::New(dict, "");
+        coordinateSystem& cs1 = *cs1ptr;
+        cs1.rename(dict.dictName());
+
+        basicTests(cs1);
+    }
+    catch (Foam::IOerror& err)
+    {
+        Info<< "Caught FatalIOError " << err << nl << endl;
+    }
+    catch (Foam::error& err)
+    {
+        Info<< "Caught FatalError " << err << nl << endl;
+    }
+    FatalError.throwExceptions(throwingError);
+    FatalIOError.throwExceptions(throwingIOError);
+}
 
-        coordinateSystem cs2;
 
-        // Move assign
-        cs2 = std::move(cs1);
+void doTest(const objectRegistry& obr, const dictionary& dict)
+{
+    Info<< dict.dictName() << dict << nl;
 
-        // Info<<cs2 << nl;
-        cs2.writeDict(Info, true);
-        Info<< nl;
+    // Could fail?
+    const bool throwingIOError = FatalIOError.throwExceptions();
+    const bool throwingError = FatalError.throwExceptions();
+
+    try
+    {
+        auto cs1ptr = coordinateSystem::New(obr, dict, word::null);
+        coordinateSystem& cs1 = *cs1ptr;
+
+        basicTests(cs1);
     }
     catch (Foam::IOerror& err)
     {
@@ -78,7 +158,40 @@ int main(int argc, char *argv[])
     argList::addArgument("dict .. dictN");
     argList args(argc, argv, false, true);
 
-    if (args.size() <= 1)
+    if (args.found("case"))
+    {
+        Info<<"using case for tests" << nl;
+
+        #include "createTime.H"
+
+        const coordinateSystems& systems = coordinateSystems::New(runTime);
+
+        Info<< systems.size() << " global systems" << nl;
+
+        for (const coordinateSystem& cs : systems)
+        {
+            basicTests(cs);
+        }
+
+        // systems.write();
+
+        for (label argi=1; argi < args.size(); ++argi)
+        {
+            const string& dictFile = args[argi];
+            IFstream is(dictFile);
+
+            dictionary inputDict(is);
+
+            forAllConstIters(inputDict, iter)
+            {
+                if (iter().isDict())
+                {
+                    doTest(runTime, iter().dict());
+                }
+            }
+        }
+    }
+    else if (args.size() <= 1)
     {
         Info<<"no coordinateSystem dictionaries to expand" << nl;
     }
diff --git a/applications/test/coordinateSystem/testCase0/constant/coordinateSystems b/applications/test/coordinateSystem/testCase0/constant/coordinateSystems
new file mode 100644
index 0000000000000000000000000000000000000000..514ade0ee108cc0b348a7dcc71bc42784b209f04
--- /dev/null
+++ b/applications/test/coordinateSystem/testCase0/constant/coordinateSystems
@@ -0,0 +1,32 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1806                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       IOPtrList<coordinateSystem>;       //<-- Older name
+    object      coordinateSystems;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+(
+cs1
+{
+    type    cartesian;
+    origin  (1 2 3);
+    coordinateRotation
+    {
+        type    axes;
+        e1      (0 0 1);
+        e2      (0 1 0);
+    }
+}
+
+)
+
+// ************************************************************************* //
diff --git a/applications/test/coordinateSystem/testCase0/system/controlDict b/applications/test/coordinateSystem/testCase0/system/controlDict
new file mode 100644
index 0000000000000000000000000000000000000000..4173430aa13f8da691a84933ecb235a02740e398
--- /dev/null
+++ b/applications/test/coordinateSystem/testCase0/system/controlDict
@@ -0,0 +1,48 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1806                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      controlDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+application     simpleFoam;
+
+startFrom       latestTime;
+
+startTime       0;
+
+stopAt          endTime;
+
+endTime         4;
+
+deltaT          1;
+
+writeControl    timeStep;
+
+writeInterval   100;
+
+purgeWrite      0;
+
+writeFormat     binary;
+
+writePrecision  6;
+
+writeCompression off;
+
+timeFormat      general;
+
+timePrecision   6;
+
+runTimeModifiable true;
+
+
+// ************************************************************************* //
diff --git a/applications/test/coordinateSystem/testCase1/constant/coordinateSystems b/applications/test/coordinateSystem/testCase1/constant/coordinateSystems
new file mode 100644
index 0000000000000000000000000000000000000000..7facad08d3a38eb2d921eb4be5a410da13875f19
--- /dev/null
+++ b/applications/test/coordinateSystem/testCase1/constant/coordinateSystems
@@ -0,0 +1,86 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1806                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+//OLD  class       IOPtrList<coordinateSystem>;
+    class       coordinateSystems;
+    object      coordinateSystems;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+(
+cs1
+{
+    type    cartesian;
+    origin  (1 2 3);
+    rotation
+    {
+        type    axes;
+        e1      (0 0 1);
+        e2      (0 1 0);
+    }
+}
+
+cs2
+{
+    type    cartesian;
+    origin  (0 3 5);
+    e1      (1 2 0);
+    e2      (2 0 2);
+}
+
+cs3
+{
+    type    cartesian;
+    origin  (0 3 5);
+    coordinateRotation  // older name
+    {
+        type    euler;
+        angles  (90 0 0);
+    }
+}
+
+cs4
+{
+    type    cylindrical;
+    origin  (0 3 5);
+    rotation
+    {
+        type    euler;
+        angles  (90 0 0);
+    }
+}
+
+cyl
+{
+    type    cylindrical;
+    origin  (0 0 0);
+    degrees false;
+
+    rotation
+    {
+        type    axisAngle;
+        axis    (0 0 1);
+        angle   90;
+    }
+}
+
+ident
+{
+    origin  (0 0 0);
+    rotation
+    {
+        type    none;
+    }
+}
+
+)
+
+// ************************************************************************* //
diff --git a/applications/test/coordinateSystem/testCase1/system/controlDict b/applications/test/coordinateSystem/testCase1/system/controlDict
new file mode 100644
index 0000000000000000000000000000000000000000..4173430aa13f8da691a84933ecb235a02740e398
--- /dev/null
+++ b/applications/test/coordinateSystem/testCase1/system/controlDict
@@ -0,0 +1,48 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1806                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      controlDict;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+application     simpleFoam;
+
+startFrom       latestTime;
+
+startTime       0;
+
+stopAt          endTime;
+
+endTime         4;
+
+deltaT          1;
+
+writeControl    timeStep;
+
+writeInterval   100;
+
+purgeWrite      0;
+
+writeFormat     binary;
+
+writePrecision  6;
+
+writeCompression off;
+
+timeFormat      general;
+
+timePrecision   6;
+
+runTimeModifiable true;
+
+
+// ************************************************************************* //
diff --git a/applications/test/coordinateSystem/testDict1 b/applications/test/coordinateSystem/testCsys1
similarity index 58%
rename from applications/test/coordinateSystem/testDict1
rename to applications/test/coordinateSystem/testCsys1
index 2fa9cdb21b8c7f980be4531f0e62e630d1513b50..320fb21b7aee6b51b245dddb7927a0476368bd30 100644
--- a/applications/test/coordinateSystem/testDict1
+++ b/applications/test/coordinateSystem/testCsys1
@@ -10,12 +10,19 @@ FoamFile
     version     2.0;
     format      ascii;
     class       dictionary;
-    object      testDict;
+    object      testCsys1;
 }
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 // Rotate 90 deg around x: y -> z, z -> -y
 
+rot_x90
+{
+    origin  (0 0 0);
+    e1      (1 0 0);
+    e3      (0 -1 0);
+}
+
 rot_x90_axesRotation
 {
     origin  (0 0 0);
@@ -27,13 +34,24 @@ rot_x90_axesRotation
     }
 }
 
+rot_x90_axisAngle
+{
+    origin  (0 0 0);
+    coordinateRotation
+    {
+        type    axisAngle;
+        axis    (1 0 0);        // non-unit also OK
+        angle   90;
+    }
+}
+
 rot_x90_euler
 {
     origin  (0 0 0);
     coordinateRotation
     {
-        type    EulerRotation;
-        rotation (0 90 0);      // z-x'-z''
+        type    euler;
+        angles  (0 90 0);      // z-x'-z''
     }
 }
 
@@ -51,18 +69,40 @@ rot_z45_axesRotation
     }
 }
 
+rot_z45_axisAngle
+{
+    origin  (0 0 0);
+    coordinateRotation
+    {
+        type    axisAngle;
+        axis    (0 0 10);       // non-unit also OK
+        angle   45;
+    }
+}
+
 rot_z45_euler
 {
     origin  (0 0 0);
     coordinateRotation
     {
-        type    EulerRotation;
-        rotation (45 0 0);      // z-x'-z''
+        type    euler;
+        angles  (45 0 0);      // z-x'-z''
+    }
+}
+
+rot_z45_starcd
+{
+    origin  (0 0 0);
+    coordinateRotation
+    {
+        type    starcd;
+        angles  (45 0 0);      // z-x'-y''
     }
 }
 
 
 // Rotate -45 deg around z: x -> (1 -1 0), y = (1 1 0)
+
 rot_zm45_axesRotation
 {
     origin  (0 0 0);
@@ -74,13 +114,24 @@ rot_zm45_axesRotation
     }
 }
 
+rot_zm45_axisAngle
+{
+    origin  (0 0 0);
+    coordinateRotation
+    {
+        type    axisAngle;
+        axis    (0 0 10);       // non-unit also OK
+        angle   -45;
+    }
+}
+
 rot_zm45_euler
 {
     origin  (0 0 0);
     coordinateRotation
     {
-        type    EulerRotation;
-        rotation (-45 0 0);      // z-x'-z''
+        type    euler;
+        angles  (-45 0 0);      // z-x'-z''
     }
 }
 
@@ -98,13 +149,35 @@ null_axesRotation
     }
 }
 
+null_axisAngle0
+{
+    origin  (0 0 0);
+    coordinateRotation
+    {
+        type    axisAngle;
+        axis    (0 0 0);       // non-unit also OK
+        angle   0;
+    }
+}
+
+null_axisAngle1
+{
+    origin  (0 0 0);
+    coordinateRotation
+    {
+        type    axisAngle;
+        axis    (1 1 1);       // non-unit also OK
+        angle   0;
+    }
+}
+
 null_euler
 {
     origin  (0 0 0);
     coordinateRotation
     {
-        type    EulerRotation;
-        rotation (0 0 0);      // z-x'-z''
+        type    euler;
+        angles  (0 0 0);      // z-x'-z''
     }
 }
 
diff --git a/applications/test/coordinateSystem/testCsys2 b/applications/test/coordinateSystem/testCsys2
new file mode 100644
index 0000000000000000000000000000000000000000..13caeacd5ae2a5aceab2fe1b6e1fe53d1f98b5e9
--- /dev/null
+++ b/applications/test/coordinateSystem/testCsys2
@@ -0,0 +1,59 @@
+/*--------------------------------*- C++ -*----------------------------------*\
+| =========                 |                                                 |
+| \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox           |
+|  \\    /   O peration     | Version:  v1806                                 |
+|   \\  /    A nd           | Web:      www.OpenFOAM.com                      |
+|    \\/     M anipulation  |                                                 |
+\*---------------------------------------------------------------------------*/
+FoamFile
+{
+    version     2.0;
+    format      ascii;
+    class       dictionary;
+    object      testCsys1;
+}
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// This dictionary only works in combination with constant/coordinateSystems
+
+mycs1
+{
+    type   indirect;
+    name   cs1;
+}
+
+mycs2
+{
+    type   indirect;
+    name   cs2;
+}
+
+mycs3
+{
+    type   indirect;
+    name   cs3;
+}
+
+mycyl
+{
+    type   indirect;
+    name   cyl;
+}
+
+
+mycy2
+{
+    coordinateSystem
+    {
+        type   indirect;
+        name   cyl;
+    }
+}
+
+mycy3
+{
+    coordinateSystem cyl;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/applications/utilities/surface/surfaceMeshConvert/coordinateSystems b/applications/utilities/surface/surfaceMeshConvert/coordinateSystems
index c527806a2141ec7b1bd3ec4b38eca5c7151fbeda..9f46501ae7a2e59e504ed745e68d56a1f5a648bc 100644
--- a/applications/utilities/surface/surfaceMeshConvert/coordinateSystems
+++ b/applications/utilities/surface/surfaceMeshConvert/coordinateSystems
@@ -9,74 +9,74 @@ FoamFile
 {
     version     2.0;
     format      ascii;
-    class       IOPtrList<coordinateSystem>;
+    class       coordinateSystems;
     object      coordinateSystems;
 }
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-7
+
 (
-system_9
+_9
 {
     type            cartesian;
     origin          (1.03291515 -0.114391257 -0.0826236662);
-    e3              (1 0 0);
     e1              (0 1 0);
-    // STARCDRotation  (0 90 90);
+    e3              (1 0 0);
+    // rotation { type starcd; angles (0 90 90); }
 }
 
-system_10
+_10
 {
     type            cartesian;
     origin          (0.623151719 -0.286472935 -0.113933262);
-    e3              (0.99508851 0.09829095 0.01173645);
     e1              (0.01179356 0 -0.99993045);
-    // STARCDRotation  (5.6403745 -0.0664172952 89.3275351);
+    e3              (0.99508851 0.09829095 0.01173645);
+    // rotation { type starcd; angles (5.6403745 -0.0664172952 89.3275351); }
 }
 
-system_15
+_15
 {
     type            cartesian;
     origin          (0.644772231 -0.240036493 0.155972187);
-    e3              (-0.01346388 -0.90616979 -0.42269969);
     e1              (0.00627978 0.42265304 -0.90626981);
-    // STARCDRotation  (-90.8512386 0 115.005148);
+    e3              (-0.01346388 -0.90616979 -0.42269969);
+    // rotation { type starcd; angles (-90.8512386 0 115.005148); }
 }
 
-system_16
+_16
 {
     type            cartesian;
     origin          (0.540824938 -0.240036415 0.15928296);
-    e3              (-0.01346388 -0.90616979 -0.42269969);
     e1              (0.00627978 0.42265304 -0.90626981);
-    // STARCDRotation  (-90.8512386 0 115.005148);
+    e3              (-0.01346388 -0.90616979 -0.42269969);
+    // rotation { type starcd; angles (-90.8512386 0 115.005148); }
 }
 
-system_17
+_17
 {
     type            cartesian;
     origin          (0.436877646 -0.240036339 0.162593737);
-    e3              (-0.01346388 -0.90616979 -0.42269969);
     e1              (0.00627978 0.42265304 -0.90626981);
-    // STARCDRotation  (-90.8512386 0 115.005148);
+    e3              (-0.01346388 -0.90616979 -0.42269969);
+    // rotation { type starcd; angles (-90.8512386 0 115.005148); }
 }
 
-system_18
+_18
 {
     type            cartesian;
     origin          (0.332930354 -0.240036261 0.16590451);
-    e3              (-0.01346388 -0.90616979 -0.42269969);
     e1              (0.00627978 0.42265304 -0.90626981);
-    // STARCDRotation  (-90.8512386 0 115.005148);
+    e3              (-0.01346388 -0.90616979 -0.42269969);
+    // rotation { type starcd; angles (-90.8512386 0 115.005148); }
 }
 
-system_21
+_21
 {
     type            cartesian;
     origin          (0.55863733 -0.300866705 0.00317260982);
-    e3              (0.42110287 0.02470132 -0.90667647);
     e1              (0.90646036 0.02342535 0.42164069);
-    // STARCDRotation  (-178.185897 -0.71772221 -155.059695);
+    e3              (0.42110287 0.02470132 -0.90667647);
+    // rotation { type starcd; angles (-178.185897 -0.71772221 -155.059695); }
 }
 )
 
diff --git a/applications/utilities/surface/surfaceMeshConvert/surfaceMeshConvert.C b/applications/utilities/surface/surfaceMeshConvert/surfaceMeshConvert.C
index 0ca90a5b7ace7b1e0ddbf20f28fa9866536706fb..a030599286aa739a76077cfa81258b427b1f49b4 100644
--- a/applications/utilities/surface/surfaceMeshConvert/surfaceMeshConvert.C
+++ b/applications/utilities/surface/surfaceMeshConvert/surfaceMeshConvert.C
@@ -66,6 +66,7 @@ Note
 
 #include "MeshedSurfaces.H"
 #include "coordinateSystems.H"
+#include "cartesianCS.H"
 
 using namespace Foam;
 
@@ -146,9 +147,9 @@ int main(int argc, char *argv[])
     }
 
 
-    // get the coordinate transformations
-    autoPtr<coordinateSystem> fromCsys;
-    autoPtr<coordinateSystem> toCsys;
+    // The coordinate transformations (must be cartesian)
+    autoPtr<coordSystem::cartesian> fromCsys;
+    autoPtr<coordSystem::cartesian> toCsys;
 
     if (args.found("from") || args.found("to"))
     {
@@ -174,46 +175,47 @@ int main(int argc, char *argv[])
                 << exit(FatalError);
         }
 
-        coordinateSystems csLst(ioCsys);
+        coordinateSystems globalCoords(ioCsys);
 
         if (args.found("from"))
         {
-            const word csName = args["from"];
+            const word csName(args["from"]);
+            const auto* csPtr = globalCoords.lookupPtr(csName);
 
-            const label csIndex = csLst.findIndex(csName);
-            if (csIndex < 0)
+            if (!csPtr)
             {
                 FatalErrorInFunction
                     << "Cannot find -from " << csName << nl
-                    << "available coordinateSystems: " << csLst.toc() << nl
+                    << "available coordinateSystems: "
+                    << flatOutput(globalCoords.names()) << nl
                     << exit(FatalError);
             }
 
-            fromCsys.reset(new coordinateSystem(csLst[csIndex]));
+            fromCsys = autoPtr<coordSystem::cartesian>::New(*csPtr);
         }
 
         if (args.found("to"))
         {
-            const word csName = args["to"];
+            const word csName(args["to"]);
+            const auto* csPtr = globalCoords.lookupPtr(csName);
 
-            const label csIndex = csLst.findIndex(csName);
-            if (csIndex < 0)
+            if (!csPtr)
             {
                 FatalErrorInFunction
                     << "Cannot find -to " << csName << nl
-                    << "available coordinateSystems: " << csLst.toc() << nl
+                    << "available coordinateSystems: "
+                    << flatOutput(globalCoords.names()) << nl
                     << exit(FatalError);
             }
 
-            toCsys.reset(new coordinateSystem(csLst[csIndex]));
+            toCsys = autoPtr<coordSystem::cartesian>::New(*csPtr);
         }
 
-
-        // maybe fix this later
-        if (fromCsys.valid() && toCsys.valid())
+        // Maybe fix this later
+        if (fromCsys && toCsys)
         {
             FatalErrorInFunction
-                << "Only allowed  '-from' or '-to' option at the moment."
+                << "Only allowed '-from' or '-to' option at the moment."
                 << exit(FatalError);
         }
     }
@@ -230,29 +232,30 @@ int main(int argc, char *argv[])
         scalar scaleIn = 0;
         if (args.readIfPresent("scaleIn", scaleIn) && scaleIn > 0)
         {
-            Info<< " -scaleIn " << scaleIn << endl;
+            Info<< "scale input " << scaleIn << endl;
             surf.scalePoints(scaleIn);
         }
 
-
-        if (fromCsys.valid())
+        if (fromCsys)
         {
-            Info<< " -from " << fromCsys().name() << endl;
-            tmp<pointField> tpf = fromCsys().localPosition(surf.points());
+            Info<< "move points from coordinate system: "
+                << fromCsys->name() << endl;
+            tmp<pointField> tpf = fromCsys->localPosition(surf.points());
             surf.movePoints(tpf());
         }
 
-        if (toCsys.valid())
+        if (toCsys)
         {
-            Info<< " -to " << toCsys().name() << endl;
-            tmp<pointField> tpf = toCsys().globalPosition(surf.points());
+            Info<< "move points to coordinate system: "
+                << toCsys->name() << endl;
+            tmp<pointField> tpf = toCsys->globalPosition(surf.points());
             surf.movePoints(tpf());
         }
 
         scalar scaleOut = 0;
         if (args.readIfPresent("scaleOut", scaleOut) && scaleOut > 0)
         {
-            Info<< " -scaleOut " << scaleOut << endl;
+            Info<< "scale output " << scaleOut << endl;
             surf.scalePoints(scaleOut);
         }
 
diff --git a/applications/utilities/surface/surfaceMeshExport/surfaceMeshExport.C b/applications/utilities/surface/surfaceMeshExport/surfaceMeshExport.C
index 65abe34eb9d25fcab874fac64a5fe6a572c84b25..62e515e2eb7072f0fbbab6c6c83e60cce099718f 100644
--- a/applications/utilities/surface/surfaceMeshExport/surfaceMeshExport.C
+++ b/applications/utilities/surface/surfaceMeshExport/surfaceMeshExport.C
@@ -67,6 +67,7 @@ Note
 
 #include "MeshedSurfaces.H"
 #include "coordinateSystems.H"
+#include "cartesianCS.H"
 
 using namespace Foam;
 
@@ -135,9 +136,9 @@ int main(int argc, char *argv[])
     }
 
 
-    // get the coordinate transformations
-    autoPtr<coordinateSystem> fromCsys;
-    autoPtr<coordinateSystem> toCsys;
+    // The coordinate transformations (must be cartesian)
+    autoPtr<coordSystem::cartesian> fromCsys;
+    autoPtr<coordSystem::cartesian> toCsys;
 
     if (args.found("from") || args.found("to"))
     {
@@ -162,45 +163,47 @@ int main(int argc, char *argv[])
                 << exit(FatalError);
         }
 
-        coordinateSystems csLst(ioCsys);
+        coordinateSystems globalCoords(ioCsys);
 
         if (args.found("from"))
         {
-            const word csName = args["from"];
+            const word csName(args["from"]);
+            const auto* csPtr = globalCoords.lookupPtr(csName);
 
-            const label csIndex = csLst.findIndex(csName);
-            if (csIndex < 0)
+            if (!csPtr)
             {
                 FatalErrorInFunction
                     << "Cannot find -from " << csName << nl
-                    << "available coordinateSystems: " << csLst.toc() << nl
+                    << "available coordinateSystems: "
+                    << flatOutput(globalCoords.names()) << nl
                     << exit(FatalError);
             }
 
-            fromCsys.reset(new coordinateSystem(csLst[csIndex]));
+            fromCsys = autoPtr<coordSystem::cartesian>::New(*csPtr);
         }
 
         if (args.found("to"))
         {
-            const word csName = args["to"];
+            const word csName(args["to"]);
+            const auto* csPtr = globalCoords.lookupPtr(csName);
 
-            const label csIndex = csLst.findIndex(csName);
-            if (csIndex < 0)
+            if (!csPtr)
             {
                 FatalErrorInFunction
                     << "Cannot find -to " << csName << nl
-                    << "available coordinateSystems: " << csLst.toc() << nl
+                    << "available coordinateSystems: "
+                    << flatOutput(globalCoords.names()) << nl
                     << exit(FatalError);
             }
 
-            toCsys.reset(new coordinateSystem(csLst[csIndex]));
+            toCsys = autoPtr<coordSystem::cartesian>::New(*csPtr);
         }
 
-
-        // maybe fix this later
-        if (fromCsys.valid() && toCsys.valid())
+        // Maybe fix this later
+        if (fromCsys && toCsys)
         {
             FatalErrorInFunction
+                << "Only allowed '-from' or '-to' option at the moment."
                 << exit(FatalError);
         }
     }
@@ -233,28 +236,30 @@ int main(int argc, char *argv[])
     scalar scaleIn = 0;
     if (args.readIfPresent("scaleIn", scaleIn) && scaleIn > 0)
     {
-        Info<< " -scaleIn " << scaleIn << endl;
+        Info<< "scale input " << scaleIn << endl;
         surf.scalePoints(scaleIn);
     }
 
     if (fromCsys.valid())
     {
-        Info<< " -from " << fromCsys().name() << endl;
-        tmp<pointField> tpf = fromCsys().localPosition(surf.points());
+        Info<< "move points from coordinate system: "
+            << fromCsys->name() << endl;
+        tmp<pointField> tpf = fromCsys->localPosition(surf.points());
         surf.movePoints(tpf());
     }
 
     if (toCsys.valid())
     {
-        Info<< " -to " << toCsys().name() << endl;
-        tmp<pointField> tpf = toCsys().globalPosition(surf.points());
+        Info<< "move points to coordinate system: "
+            << toCsys->name() << endl;
+        tmp<pointField> tpf = toCsys->globalPosition(surf.points());
         surf.movePoints(tpf());
     }
 
     scalar scaleOut = 0;
     if (args.readIfPresent("scaleOut", scaleOut) && scaleOut > 0)
     {
-        Info<< " -scaleOut " << scaleOut << endl;
+        Info<< "scale output " << scaleOut << endl;
         surf.scalePoints(scaleOut);
     }
 
diff --git a/applications/utilities/surface/surfaceMeshImport/surfaceMeshImport.C b/applications/utilities/surface/surfaceMeshImport/surfaceMeshImport.C
index 48b29a2118a95cd2e2eb3898b358b1c1d9cccf68..eb233b30e3b9be424fd54f4bf9e1c51cf0b4d23d 100644
--- a/applications/utilities/surface/surfaceMeshImport/surfaceMeshImport.C
+++ b/applications/utilities/surface/surfaceMeshImport/surfaceMeshImport.C
@@ -67,6 +67,7 @@ Note
 
 #include "MeshedSurfaces.H"
 #include "coordinateSystems.H"
+#include "cartesianCS.H"
 
 using namespace Foam;
 
@@ -148,9 +149,9 @@ int main(int argc, char *argv[])
     }
 
 
-    // get the coordinate transformations
-    autoPtr<coordinateSystem> fromCsys;
-    autoPtr<coordinateSystem> toCsys;
+    // The coordinate transformations (must be cartesian)
+    autoPtr<coordSystem::cartesian> fromCsys;
+    autoPtr<coordSystem::cartesian> toCsys;
 
     if (args.found("from") || args.found("to"))
     {
@@ -175,51 +176,52 @@ int main(int argc, char *argv[])
                 << exit(FatalError);
         }
 
-        coordinateSystems csLst(ioCsys);
+        coordinateSystems globalCoords(ioCsys);
 
         if (args.found("from"))
         {
-            const word csName = args["from"];
+            const word csName(args["from"]);
+            const auto* csPtr = globalCoords.lookupPtr(csName);
 
-            const label csIndex = csLst.findIndex(csName);
-            if (csIndex < 0)
+            if (!csPtr)
             {
                 FatalErrorInFunction
                     << "Cannot find -from " << csName << nl
-                    << "available coordinateSystems: " << csLst.toc() << nl
+                    << "available coordinateSystems: "
+                    << flatOutput(globalCoords.names()) << nl
                     << exit(FatalError);
             }
 
-            fromCsys.reset(new coordinateSystem(csLst[csIndex]));
+            fromCsys = autoPtr<coordSystem::cartesian>::New(*csPtr);
         }
 
         if (args.found("to"))
         {
-            const word csName = args["to"];
+            const word csName(args["to"]);
+            const auto* csPtr = globalCoords.lookupPtr(csName);
 
-            const label csIndex = csLst.findIndex(csName);
-            if (csIndex < 0)
+            if (!csPtr)
             {
                 FatalErrorInFunction
                     << "Cannot find -to " << csName << nl
-                    << "available coordinateSystems: " << csLst.toc() << nl
+                    << "available coordinateSystems: "
+                    << flatOutput(globalCoords.names()) << nl
                     << exit(FatalError);
             }
 
-            toCsys.reset(new coordinateSystem(csLst[csIndex]));
+            toCsys = autoPtr<coordSystem::cartesian>::New(*csPtr);
         }
 
-
-        // maybe fix this later
-        if (fromCsys.valid() && toCsys.valid())
+        // Maybe fix this later
+        if (fromCsys && toCsys)
         {
             FatalErrorInFunction
+                << "Only allowed '-from' or '-to' option at the moment."
                 << exit(FatalError);
         }
     }
 
 
-
     MeshedSurface<face> surf(importName);
 
     if (args.found("clean"))
@@ -231,28 +233,30 @@ int main(int argc, char *argv[])
     scalar scaleIn = 0;
     if (args.readIfPresent("scaleIn", scaleIn) && scaleIn > 0)
     {
-        Info<< " -scaleIn " << scaleIn << endl;
+        Info<< "scale input " << scaleIn << endl;
         surf.scalePoints(scaleIn);
     }
 
-    if (fromCsys.valid())
+    if (fromCsys)
     {
-        Info<< " -from " << fromCsys().name() << endl;
-        tmp<pointField> tpf = fromCsys().localPosition(surf.points());
+        Info<< "move points from coordinate system: "
+            << fromCsys->name() << endl;
+        tmp<pointField> tpf = fromCsys->localPosition(surf.points());
         surf.movePoints(tpf());
     }
 
-    if (toCsys.valid())
+    if (toCsys)
     {
-        Info<< " -to " << toCsys().name() << endl;
-        tmp<pointField> tpf = toCsys().globalPosition(surf.points());
+        Info<< "move points to coordinate system: "
+            << toCsys->name() << endl;
+        tmp<pointField> tpf = toCsys->globalPosition(surf.points());
         surf.movePoints(tpf());
     }
 
     scalar scaleOut = 0;
     if (args.readIfPresent("scaleOut", scaleOut) && scaleOut > 0)
     {
-        Info<< " -scaleOut " << scaleOut << endl;
+        Info<< "scale output " << scaleOut << endl;
         surf.scalePoints(scaleOut);
     }
 
diff --git a/etc/caseDicts/general/coordinateSystem/cartesianXY b/etc/caseDicts/general/coordinateSystem/cartesianXY
index 2fe0d38a5e6e5abcec2e941ec6add0a1350deb9f..ffea8c2b9cd38ecf60bdc2f34f2a816ff29b3575 100644
--- a/etc/caseDicts/general/coordinateSystem/cartesianXY
+++ b/etc/caseDicts/general/coordinateSystem/cartesianXY
@@ -15,10 +15,12 @@ FoamFile
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 type      cartesian;
+
 origin    (0 0 0);
-coordinateRotation
+
+rotation
 {
-    type  axesRotation;
+    type  axes;
     e1    $x;
     e2    $y;
 }
diff --git a/etc/caseDicts/general/coordinateSystem/cartesianXZ b/etc/caseDicts/general/coordinateSystem/cartesianXZ
index 4915e791bd55f1674e49c581e8a9e3cdb52b87fb..dc26fd49fcb75ef172852296dd587987511e1332 100644
--- a/etc/caseDicts/general/coordinateSystem/cartesianXZ
+++ b/etc/caseDicts/general/coordinateSystem/cartesianXZ
@@ -15,10 +15,12 @@ FoamFile
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 type      cartesian;
+
 origin    (0 0 0);
-coordinateRotation
+
+rotation
 {
-    type  axesRotation;
+    type  axes;
     e1    $x;
     e3    $z;
 }
diff --git a/etc/caseDicts/general/coordinateSystem/cartesianYZ b/etc/caseDicts/general/coordinateSystem/cartesianYZ
index 0452b239c1080b41968682426d10658ad64430d4..b531dcf4d6ca0a383431006f2c741029b6fc7a60 100644
--- a/etc/caseDicts/general/coordinateSystem/cartesianYZ
+++ b/etc/caseDicts/general/coordinateSystem/cartesianYZ
@@ -15,12 +15,14 @@ FoamFile
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 type      cartesian;
+
 origin    (0 0 0);
-coordinateRotation
+
+rotation
 {
-    type  axesRotation;
+    type  axes;
     e2    $y;
-    e3    $z
+    e3    $z;
 }
 
 //************************************************************************* //
diff --git a/etc/caseDicts/general/coordinateSystem/cylindrical b/etc/caseDicts/general/coordinateSystem/cylindrical
index 332e0f4a8f443a7f534d2b52743508be81251a34..1f20c75654816617edbd493822ddf03e9710f2d7 100644
--- a/etc/caseDicts/general/coordinateSystem/cylindrical
+++ b/etc/caseDicts/general/coordinateSystem/cylindrical
@@ -14,8 +14,9 @@ FoamFile
 }
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-type      cartesian;
-coordinateRotation
+type      cylindrical;
+
+rotation
 {
     type  cylindrical;
     e3    $axis;
diff --git a/etc/controlDict b/etc/controlDict
index 918ac112ca2f0d8cab866f7afac91e8ed91216cc..950e5adc2b08b9d9242954ceff0c3224ea165166 100644
--- a/etc/controlDict
+++ b/etc/controlDict
@@ -208,7 +208,6 @@ DebugSwitches
     Ergun               0;
     Euler               0;
     EulerImplicit       0;
-    EulerRotation       0;
     extendedCellToFaceStencil 0;
     FDIC                0;
     FaceCellWave        0;
@@ -239,7 +238,6 @@ DebugSwitches
     IFstream            0;
     IOMap<dictionary>   0;
     IOPtrList<MRFZone>  0;
-    IOPtrList<coordinateSystem> 0;
     IOPtrList<injector> 0;
     IOPtrList<porousZone>   0;
     IOobject            0;
@@ -336,7 +334,6 @@ DebugSwitches
     SLTS                0;
     SRFModel            0;
     SRFVelocity         0;
-    STARCDRotation      0;
     Schaeffer           0;
     SchillerNaumann     0;
     SinclairJackson     0;
@@ -456,9 +453,7 @@ DebugSwitches
     constantAbsorptionEmission  0;
     constantAlphaContactAngle   0;
     constantScatter     0;
-    coordinateRotation  0;
     coordinateSystem    0;
-    coordinateSystems   0;
     corrected           0;
     coupled             0;
     cubeRootVol         0;
@@ -478,9 +473,9 @@ DebugSwitches
     diagonal            0;
     dictionary          0;
     dimensionSet        1;
-    mappedBase    0;
-    mappedPatch   0;
-    mappedVelocityFlux 0;
+    mappedBase          0;
+    mappedPatch         0;
+    mappedVelocityFlux  0;
     directionMixed      0;
     directional         0;
     disallowGenericFvPatchField 0;
@@ -745,7 +740,6 @@ DebugSwitches
     outletInlet         0;
     outletStabilised    0;
     pair                0;
-    parabolicCylindrical 0;
     parcel              0;
     partialSlip         0;
     passiveParticle     0;
@@ -1101,5 +1095,4 @@ DimensionSets
 }
 
 
-
 // ************************************************************************* //
diff --git a/src/OpenFOAM/primitives/Tensor/Tensor.H b/src/OpenFOAM/primitives/Tensor/Tensor.H
index d39f8b10e136d607aa71230d1cde320b7124b873..d3d635391d988eccfdef1743456391d7abaee2e9 100644
--- a/src/OpenFOAM/primitives/Tensor/Tensor.H
+++ b/src/OpenFOAM/primitives/Tensor/Tensor.H
@@ -242,11 +242,6 @@ public:
         //- Inner-product of this with another Tensor.
         inline Tensor<Cmpt> inner(const Tensor<Cmpt>& t2) const;
 
-        //- Inner-product of this with transpose of another Tensor.
-        //  Primarily useful for coordinate transformations
-        //  (where transpose is the same as the inverse).
-        inline Tensor<Cmpt> innerT(const Tensor<Cmpt>& t2) const;
-
         //- Schur-product of this with another Tensor.
         inline Tensor<Cmpt> schur(const Tensor<Cmpt>& t2) const;
 
diff --git a/src/OpenFOAM/primitives/Tensor/TensorI.H b/src/OpenFOAM/primitives/Tensor/TensorI.H
index 933b39a5c2e9c6efbcb95ae6e4c671beec6ee50f..78c59a0c37dee450838ae37b02e8c95c1fad0747 100644
--- a/src/OpenFOAM/primitives/Tensor/TensorI.H
+++ b/src/OpenFOAM/primitives/Tensor/TensorI.H
@@ -504,29 +504,6 @@ Foam::Tensor<Cmpt>::inner(const Tensor<Cmpt>& t2) const
 }
 
 
-template<class Cmpt>
-inline Foam::Tensor<Cmpt>
-Foam::Tensor<Cmpt>::innerT(const Tensor<Cmpt>& t2) const
-{
-    const Tensor<Cmpt>& t1 = *this;
-
-    return Tensor<Cmpt>
-    (
-        t1.xx()*t2.xx() + t1.xy()*t2.xy() + t1.xz()*t2.xz(),
-        t1.xx()*t2.yx() + t1.xy()*t2.yy() + t1.xz()*t2.yz(),
-        t1.xx()*t2.zx() + t1.xy()*t2.zy() + t1.xz()*t2.zz(),
-
-        t1.yx()*t2.xx() + t1.yy()*t2.xy() + t1.yz()*t2.xz(),
-        t1.yx()*t2.yx() + t1.yy()*t2.yy() + t1.yz()*t2.yz(),
-        t1.yx()*t2.zx() + t1.yy()*t2.zy() + t1.yz()*t2.zz(),
-
-        t1.zx()*t2.xx() + t1.zy()*t2.xy() + t1.zz()*t2.xz(),
-        t1.zx()*t2.yx() + t1.zy()*t2.yy() + t1.zz()*t2.yz(),
-        t1.zx()*t2.zx() + t1.zy()*t2.zy() + t1.zz()*t2.zz()
-    );
-}
-
-
 template<class Cmpt>
 inline Foam::Tensor<Cmpt>
 Foam::Tensor<Cmpt>::schur(const Tensor<Cmpt>& t2) const
diff --git a/src/OpenFOAM/primitives/Tensor2D/Tensor2D.H b/src/OpenFOAM/primitives/Tensor2D/Tensor2D.H
index 38de0da43392abee0ae5cd9762813ab6cb5ff1b7..8de4754acb91c717efbbac93b97b210c06fd84cd 100644
--- a/src/OpenFOAM/primitives/Tensor2D/Tensor2D.H
+++ b/src/OpenFOAM/primitives/Tensor2D/Tensor2D.H
@@ -156,11 +156,6 @@ public:
         //- Inner-product of this with another Tensor2D.
         inline Tensor2D<Cmpt> inner(const Tensor2D<Cmpt>& t2) const;
 
-        //- Inner-product of this with transpose of another Tensor2D.
-        //  Primarily useful for coordinate transformations
-        //  (where transpose is the same as the inverse).
-        inline Tensor2D<Cmpt> innerT(const Tensor2D<Cmpt>& t2) const;
-
         //- Schur-product of this with another Tensor2D.
         inline Tensor2D<Cmpt> schur(const Tensor2D<Cmpt>& t2) const;
 
diff --git a/src/OpenFOAM/primitives/Tensor2D/Tensor2DI.H b/src/OpenFOAM/primitives/Tensor2D/Tensor2DI.H
index 147155035f122d449f93ca2fac3883ae5669e02c..fd253dd7ac158ef980bf86afe4935622a1a9a25b 100644
--- a/src/OpenFOAM/primitives/Tensor2D/Tensor2DI.H
+++ b/src/OpenFOAM/primitives/Tensor2D/Tensor2DI.H
@@ -202,23 +202,6 @@ Foam::Tensor2D<Cmpt>::inner(const Tensor2D<Cmpt>& t2) const
 }
 
 
-template<class Cmpt>
-inline Foam::Tensor2D<Cmpt>
-Foam::Tensor2D<Cmpt>::innerT(const Tensor2D<Cmpt>& t2) const
-{
-    const Tensor2D<Cmpt>& t1 = *this;
-
-    return Tensor2D<Cmpt>
-    (
-        t1.xx()*t2.xx() + t1.xy()*t2.xy(),
-        t1.xx()*t2.yx() + t1.xy()*t2.yy(),
-
-        t1.yx()*t2.xx() + t1.yy()*t2.xy(),
-        t1.yx()*t2.yx() + t1.yy()*t2.yy()
-    );
-}
-
-
 template<class Cmpt>
 inline Foam::Tensor2D<Cmpt>
 Foam::Tensor2D<Cmpt>::schur(const Tensor2D<Cmpt>& t2) const
diff --git a/src/atmosphericModels/derivedFvPatchFields/nutkAtmRoughWallFunction/nutkAtmRoughWallFunctionFvPatchScalarField.H b/src/atmosphericModels/derivedFvPatchFields/nutkAtmRoughWallFunction/nutkAtmRoughWallFunctionFvPatchScalarField.H
index 858ab1fd914660e36b63e156455dd768f2427a96..955fa72d7ee4d4a4871fded35b38656ca7a82e76 100644
--- a/src/atmosphericModels/derivedFvPatchFields/nutkAtmRoughWallFunction/nutkAtmRoughWallFunctionFvPatchScalarField.H
+++ b/src/atmosphericModels/derivedFvPatchFields/nutkAtmRoughWallFunction/nutkAtmRoughWallFunctionFvPatchScalarField.H
@@ -43,7 +43,7 @@ Description
         U_f | frictional velocity
         K   | Von Karman's constant
         z_0 | surface roughness length
-        z   | vertical co-ordinate
+        z   | vertical coordinate
     \endvartable
 
 Usage
diff --git a/src/dynamicMesh/meshCut/directions/directions.C b/src/dynamicMesh/meshCut/directions/directions.C
index 68deece2545eee83ff710c61b8ae51616f6b8ff5..b6a4db66e53ca4f3cf9dfe55510baea520ec86a0 100644
--- a/src/dynamicMesh/meshCut/directions/directions.C
+++ b/src/dynamicMesh/meshCut/directions/directions.C
@@ -276,7 +276,7 @@ Foam::directions::directions
     List<vectorField>(wordList(dict.lookup("directions")).size())
 {
     const wordList wantedDirs(dict.lookup("directions"));
-    const word coordSystem(dict.lookup("coordinateSystem"));
+    const word coordSystem(dict.get<word>("coordinateSystem"));
 
     bool wantNormal = false;
     bool wantTan1 = false;
diff --git a/src/dynamicMesh/motionSolvers/displacement/points0/points0MotionSolver.C b/src/dynamicMesh/motionSolvers/displacement/points0/points0MotionSolver.C
index 1a204d67a5ee5a4d44d5eb26c0a095813f9182f0..8af0c320c1e16e5a9d663d370277ce7ee84f36fd 100644
--- a/src/dynamicMesh/motionSolvers/displacement/points0/points0MotionSolver.C
+++ b/src/dynamicMesh/motionSolvers/displacement/points0/points0MotionSolver.C
@@ -230,8 +230,8 @@ void Foam::points0MotionSolver::updateMesh(const mapPolyMesh& mpm)
         else
         {
             FatalErrorInFunction
-                << "Cannot determine co-ordinates of introduced vertices."
-                << " New vertex " << pointi << " at co-ordinate "
+                << "Cannot determine coordinates of introduced vertices."
+                << " New vertex " << pointi << " at coordinate "
                 << points[pointi] << exit(FatalError);
         }
     }
diff --git a/src/engine/enginePiston/enginePiston.C b/src/engine/enginePiston/enginePiston.C
index 68be48ec087718d67c21051c8aec3cef43c945da..3314e566a5f279e7b16d3f6af5a0b302b5029a23 100644
--- a/src/engine/enginePiston/enginePiston.C
+++ b/src/engine/enginePiston/enginePiston.C
@@ -30,7 +30,6 @@ License
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-// Construct from components
 Foam::enginePiston::enginePiston
 (
     const polyMesh& mesh,
@@ -43,13 +42,12 @@ Foam::enginePiston::enginePiston
     mesh_(mesh),
     engineDB_(refCast<const engineTime>(mesh.time())),
     patchID_(pistonPatchName, mesh.boundaryMesh()),
-    csPtr_(pistonCS),
+    csysPtr_(pistonCS),
     minLayer_(minLayer),
     maxLayer_(maxLayer)
 {}
 
 
-// Construct from dictionary
 Foam::enginePiston::enginePiston
 (
     const polyMesh& mesh,
@@ -59,22 +57,15 @@ Foam::enginePiston::enginePiston
     mesh_(mesh),
     engineDB_(refCast<const engineTime>(mesh_.time())),
     patchID_(dict.lookup("patch"), mesh.boundaryMesh()),
-    csPtr_
+    csysPtr_
     (
-        coordinateSystem::New
-        (
-            mesh_,
-            dict.subDict("coordinateSystem")
-        )
+        coordinateSystem::New(mesh_, dict, coordinateSystem::typeName_())
     ),
-    minLayer_(readScalar(dict.lookup("minLayer"))),
-    maxLayer_(readScalar(dict.lookup("maxLayer")))
+    minLayer_(dict.get<scalar>("minLayer")),
+    maxLayer_(dict.get<scalar>("maxLayer"))
 {}
 
 
-// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
-
-
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 void Foam::enginePiston::writeDict(Ostream& os) const
diff --git a/src/engine/enginePiston/enginePiston.H b/src/engine/enginePiston/enginePiston.H
index 03c2291216ef91379ab49b75e875775d6d25674e..470b437411194e552ecd208ae1f4711ed6413634 100644
--- a/src/engine/enginePiston/enginePiston.H
+++ b/src/engine/enginePiston/enginePiston.H
@@ -65,7 +65,7 @@ class enginePiston
         polyPatchID patchID_;
 
         //- Coordinate system
-        autoPtr<coordinateSystem> csPtr_;
+        autoPtr<coordinateSystem> csysPtr_;
 
 
         // Piston layering data
@@ -112,7 +112,8 @@ public:
         );
 
 
-    // Destructor - default
+    //- Destructor
+    ~enginePiston() = default;
 
 
     // Member Functions
@@ -120,7 +121,7 @@ public:
         //- Return coordinate system
         const coordinateSystem& cs() const
         {
-            return *csPtr_;
+            return *csysPtr_;
         }
 
         //- Return ID of piston patch
diff --git a/src/engine/engineValve/engineValve.C b/src/engine/engineValve/engineValve.C
index 0be19c39f28fdec6f6972f80354f05224c8e1b2e..28b8572ab5906cb583b7aacf2d30afe241998f53 100644
--- a/src/engine/engineValve/engineValve.C
+++ b/src/engine/engineValve/engineValve.C
@@ -63,7 +63,6 @@ Foam::scalar Foam::engineValve::adjustCrankAngle(const scalar theta) const
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-// Construct from components
 Foam::engineValve::engineValve
 (
     const word& name,
@@ -89,7 +88,7 @@ Foam::engineValve::engineValve
     name_(name),
     mesh_(mesh),
     engineDB_(refCast<const engineTime>(mesh.time())),
-    csPtr_(valveCS),
+    csysPtr_(valveCS.clone()),
     bottomPatch_(bottomPatchName, mesh.boundaryMesh()),
     poppetPatch_(poppetPatchName, mesh.boundaryMesh()),
     stemPatch_(stemPatchName, mesh.boundaryMesh()),
@@ -110,7 +109,6 @@ Foam::engineValve::engineValve
 {}
 
 
-// Construct from dictionary
 Foam::engineValve::engineValve
 (
     const word& name,
@@ -121,13 +119,9 @@ Foam::engineValve::engineValve
     name_(name),
     mesh_(mesh),
     engineDB_(refCast<const engineTime>(mesh_.time())),
-    csPtr_
+    csysPtr_
     (
-        coordinateSystem::New
-        (
-            mesh_,
-            dict.subDict("coordinateSystem")
-        )
+        coordinateSystem::New(mesh_, dict, coordinateSystem::typeName_())
     ),
     bottomPatch_(dict.lookup("bottomPatch"), mesh.boundaryMesh()),
     poppetPatch_(dict.lookup("poppetPatch"), mesh.boundaryMesh()),
@@ -156,18 +150,15 @@ Foam::engineValve::engineValve
     liftProfile_("theta", "lift", name_, dict.lookup("liftProfile")),
     liftProfileStart_(min(liftProfile_.x())),
     liftProfileEnd_(max(liftProfile_.x())),
-    minLift_(readScalar(dict.lookup("minLift"))),
-    minTopLayer_(readScalar(dict.lookup("minTopLayer"))),
-    maxTopLayer_(readScalar(dict.lookup("maxTopLayer"))),
-    minBottomLayer_(readScalar(dict.lookup("minBottomLayer"))),
-    maxBottomLayer_(readScalar(dict.lookup("maxBottomLayer"))),
-    diameter_(readScalar(dict.lookup("diameter")))
+    minLift_(dict.get<scalar>("minLift")),
+    minTopLayer_(dict.get<scalar>("minTopLayer")),
+    maxTopLayer_(dict.get<scalar>("maxTopLayer")),
+    minBottomLayer_(dict.get<scalar>("minBottomLayer")),
+    maxBottomLayer_(dict.get<scalar>("maxBottomLayer")),
+    diameter_(dict.get<scalar>("diameter"))
 {}
 
 
-// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
-
-
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 Foam::scalar Foam::engineValve::lift(const scalar theta) const
@@ -238,7 +229,7 @@ void Foam::engineValve::writeDict(Ostream& os) const
 {
     os  << nl << name() << nl << token::BEGIN_BLOCK;
 
-    cs().writeDict(os);
+    cs().writeEntry(coordinateSystem::typeName_(), os);
 
     os  << "bottomPatch " << bottomPatch_.name() << token::END_STATEMENT << nl
         << "poppetPatch " << poppetPatch_.name() << token::END_STATEMENT << nl
diff --git a/src/engine/engineValve/engineValve.H b/src/engine/engineValve/engineValve.H
index e34b88f65f8257f735892ef17ac84983af026c2d..9121ae45ea9ccb35e1b5814d700e4e047eab0948 100644
--- a/src/engine/engineValve/engineValve.H
+++ b/src/engine/engineValve/engineValve.H
@@ -45,7 +45,7 @@ SourceFiles
 namespace Foam
 {
 
-// Forward declaration of classes
+// Forward declarations
 class polyMesh;
 class engineTime;
 
@@ -67,7 +67,7 @@ class engineValve
         const engineTime& engineDB_;
 
         //- Coordinate system
-        autoPtr<coordinateSystem> csPtr_;
+        autoPtr<coordinateSystem> csysPtr_;
 
 
         // Patch and zone names
@@ -145,9 +145,6 @@ class engineValve
 
 public:
 
-    // Static data members
-
-
     // Constructors
 
         //- Construct from components
@@ -171,7 +168,6 @@ public:
             const scalar minBottomLayer,
             const scalar maxBottomLayer,
             const scalar diameter
-
         );
 
         //- Construct from dictionary
@@ -183,7 +179,8 @@ public:
         );
 
 
-    // Destructor - default
+    //- Destructor
+    ~engineValve() = default;
 
 
     // Member Functions
@@ -197,7 +194,7 @@ public:
         //- Return coordinate system
         const coordinateSystem& cs() const
         {
-            return *csPtr_;
+            return *csysPtr_;
         }
 
         //- Return lift profile
@@ -308,7 +305,7 @@ public:
 
 
         //- Write dictionary
-        void writeDict(Ostream&) const;
+        void writeDict(Ostream& os) const;
 };
 
 
diff --git a/src/finiteArea/faMesh/faMeshDemandDrivenData.C b/src/finiteArea/faMesh/faMeshDemandDrivenData.C
index e4050c7610d95879937bc53601fc79d323210bc5..a2c0dc14beb6c2b116a2a66838ee23c3486c7071 100644
--- a/src/finiteArea/faMesh/faMeshDemandDrivenData.C
+++ b/src/finiteArea/faMesh/faMeshDemandDrivenData.C
@@ -34,7 +34,7 @@ License
 #include "processorFaPatch.H"
 #include "wedgeFaPatch.H"
 #include "PstreamCombineReduceOps.H"
-#include "coordinateSystem.H"
+#include "cartesianCS.H"
 #include "scalarMatrices.H"
 #include "processorFaPatchFields.H"
 #include "emptyFaPatchFields.H"
@@ -1271,7 +1271,7 @@ void Foam::faMesh::calcPointAreaNormalsByQuadricsFit() const
             curPoints = pointSet.toc();
         }
 
-        vectorField allPoints(curPoints.size());
+        pointField allPoints(curPoints.size());
         scalarField W(curPoints.size(), 1.0);
         for (label i=0; i<curPoints.size(); ++i)
         {
@@ -1280,17 +1280,16 @@ void Foam::faMesh::calcPointAreaNormalsByQuadricsFit() const
         }
 
         // Transform points
-        const vector& origin = points[curPoint];
-        const vector axis = normalised(result[curPoint]);
-        vector dir(allPoints[0] - points[curPoint]);
-        dir -= axis*(axis&dir);
-        dir.normalise();
-
-        coordinateSystem cs("cs", origin, axis, dir);
+        coordSystem::cartesian cs
+        (
+            points[curPoint],   // origin
+            result[curPoint],   // axis [e3] (normalized by constructor)
+            allPoints[0] - points[curPoint] // direction [e1]
+        );
 
-        forAll(allPoints, pI)
+        for (point& p : allPoints)
         {
-            allPoints[pI] = cs.localPosition(allPoints[pI]);
+            p = cs.localPosition(p);
         }
 
         scalarRectangularMatrix M
diff --git a/src/finiteVolume/cfdTools/general/porosityModel/DarcyForchheimer/DarcyForchheimer.C b/src/finiteVolume/cfdTools/general/porosityModel/DarcyForchheimer/DarcyForchheimer.C
index 35a9a246d1818af6e5905fedf77705905f96043e..86a76d66254c0242888723954dc9da08daa4dad0 100644
--- a/src/finiteVolume/cfdTools/general/porosityModel/DarcyForchheimer/DarcyForchheimer.C
+++ b/src/finiteVolume/cfdTools/general/porosityModel/DarcyForchheimer/DarcyForchheimer.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2012-2016 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2018 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -27,6 +27,7 @@ License
 #include "DarcyForchheimer.H"
 #include "geometricOneField.H"
 #include "fvMatrices.H"
+#include "pointIndList.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -67,69 +68,50 @@ Foam::porosityModels::DarcyForchheimer::DarcyForchheimer
 }
 
 
-// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
-
-Foam::porosityModels::DarcyForchheimer::~DarcyForchheimer()
-{}
-
-
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 void Foam::porosityModels::DarcyForchheimer::calcTransformModelData()
 {
-    if (coordSys_.R().uniform())
+    // The Darcy coefficient as a tensor
+    tensor darcyCoeff(Zero);
+    darcyCoeff.xx() = dXYZ_.value().x();
+    darcyCoeff.yy() = dXYZ_.value().y();
+    darcyCoeff.zz() = dXYZ_.value().z();
+
+    // The Forchheimer coefficient as a tensor
+    // - the leading 0.5 is from 1/2*rho
+    tensor forchCoeff(Zero);
+    forchCoeff.xx() = 0.5*fXYZ_.value().x();
+    forchCoeff.yy() = 0.5*fXYZ_.value().y();
+    forchCoeff.zz() = 0.5*fXYZ_.value().z();
+
+    if (csys().uniform())
     {
-        forAll(cellZoneIDs_, zoneI)
+        forAll(cellZoneIDs_, zonei)
         {
-            D_[zoneI].setSize(1);
-            F_[zoneI].setSize(1);
-
-            D_[zoneI][0] = Zero;
-            D_[zoneI][0].xx() = dXYZ_.value().x();
-            D_[zoneI][0].yy() = dXYZ_.value().y();
-            D_[zoneI][0].zz() = dXYZ_.value().z();
-
-            D_[zoneI][0] = coordSys_.R().transformTensor(D_[zoneI][0]);
-
-            // leading 0.5 is from 1/2*rho
-            F_[zoneI][0] = Zero;
-            F_[zoneI][0].xx() = 0.5*fXYZ_.value().x();
-            F_[zoneI][0].yy() = 0.5*fXYZ_.value().y();
-            F_[zoneI][0].zz() = 0.5*fXYZ_.value().z();
+            D_[zonei].resize(1);
+            F_[zonei].resize(1);
 
-            F_[zoneI][0] = coordSys_.R().transformTensor(F_[zoneI][0]);
+            D_[zonei] = csys().transform(darcyCoeff);
+            F_[zonei] = csys().transform(forchCoeff);
         }
     }
     else
     {
-        forAll(cellZoneIDs_, zoneI)
+        forAll(cellZoneIDs_, zonei)
         {
-            const labelList& cells = mesh_.cellZones()[cellZoneIDs_[zoneI]];
-
-            D_[zoneI].setSize(cells.size());
-            F_[zoneI].setSize(cells.size());
-
-            forAll(cells, i)
-            {
-                D_[zoneI][i] = Zero;
-                D_[zoneI][i].xx() = dXYZ_.value().x();
-                D_[zoneI][i].yy() = dXYZ_.value().y();
-                D_[zoneI][i].zz() = dXYZ_.value().z();
-
-                // leading 0.5 is from 1/2*rho
-                F_[zoneI][i] = Zero;
-                F_[zoneI][i].xx() = 0.5*fXYZ_.value().x();
-                F_[zoneI][i].yy() = 0.5*fXYZ_.value().y();
-                F_[zoneI][i].zz() = 0.5*fXYZ_.value().z();
-            }
-
-            const coordinateRotation& R = coordSys_.R(mesh_, cells);
+            const pointUIndList cc
+            (
+                mesh_.cellCentres(),
+                mesh_.cellZones()[cellZoneIDs_[zonei]]
+            );
 
-            D_[zoneI] = R.transformTensor(D_[zoneI], cells);
-            F_[zoneI] = R.transformTensor(F_[zoneI], cells);
+            D_[zonei] = csys().transform(cc, darcyCoeff);
+            F_[zonei] = csys().transform(cc, forchCoeff);
         }
     }
 
+
     if (debug && mesh_.time().writeTime())
     {
         volTensorField Dout
@@ -159,8 +141,22 @@ void Foam::porosityModels::DarcyForchheimer::calcTransformModelData()
             dimensionedTensor(fXYZ_.dimensions(), Zero)
         );
 
-        UIndirectList<tensor>(Dout, mesh_.cellZones()[cellZoneIDs_[0]]) = D_[0];
-        UIndirectList<tensor>(Fout, mesh_.cellZones()[cellZoneIDs_[0]]) = F_[0];
+
+        forAll(cellZoneIDs_, zonei)
+        {
+            const labelList& cells = mesh_.cellZones()[cellZoneIDs_[zonei]];
+
+            if (csys().uniform())
+            {
+                UIndirectList<tensor>(Dout, cells) = D_[zonei].first();
+                UIndirectList<tensor>(Fout, cells) = F_[zonei].first();
+            }
+            else
+            {
+                UIndirectList<tensor>(Dout, cells) = D_[zonei];
+                UIndirectList<tensor>(Fout, cells) = F_[zonei];
+            }
+        }
 
         Dout.write();
         Fout.write();
@@ -176,7 +172,7 @@ void Foam::porosityModels::DarcyForchheimer::calcForce
     vectorField& force
 ) const
 {
-    scalarField Udiag(U.size(), 0.0);
+    scalarField Udiag(U.size(), Zero);
     vectorField Usource(U.size(), Zero);
     const scalarField& V = mesh_.V();
 
@@ -202,19 +198,17 @@ void Foam::porosityModels::DarcyForchheimer::correct
 
     if (UEqn.dimensions() == dimForce)
     {
-        const volScalarField& rho = mesh_.lookupObject<volScalarField>(rhoName);
+        const auto& rho = mesh_.lookupObject<volScalarField>(rhoName);
 
         if (mesh_.foundObject<volScalarField>(muName))
         {
-            const volScalarField& mu =
-                mesh_.lookupObject<volScalarField>(muName);
+            const auto& mu = mesh_.lookupObject<volScalarField>(muName);
 
             apply(Udiag, Usource, V, rho, mu, U);
         }
         else
         {
-            const volScalarField& nu =
-                mesh_.lookupObject<volScalarField>(nuName);
+            const auto& nu = mesh_.lookupObject<volScalarField>(nuName);
 
             apply(Udiag, Usource, V, rho, rho*nu, U);
         }
@@ -223,17 +217,14 @@ void Foam::porosityModels::DarcyForchheimer::correct
     {
         if (mesh_.foundObject<volScalarField>(nuName))
         {
-            const volScalarField& nu =
-                mesh_.lookupObject<volScalarField>(nuName);
+            const auto& nu = mesh_.lookupObject<volScalarField>(nuName);
 
             apply(Udiag, Usource, V, geometricOneField(), nu, U);
         }
         else
         {
-            const volScalarField& rho =
-                mesh_.lookupObject<volScalarField>(rhoName);
-            const volScalarField& mu =
-                mesh_.lookupObject<volScalarField>(muName);
+            const auto& rho = mesh_.lookupObject<volScalarField>(rhoName);
+            const auto& mu = mesh_.lookupObject<volScalarField>(muName);
 
             apply(Udiag, Usource, V, geometricOneField(), mu/rho, U);
         }
@@ -271,8 +262,8 @@ void Foam::porosityModels::DarcyForchheimer::correct
 
     if (UEqn.dimensions() == dimForce)
     {
-        const volScalarField& rho = mesh_.lookupObject<volScalarField>(rhoName);
-        const volScalarField& mu = mesh_.lookupObject<volScalarField>(muName);
+        const auto& rho = mesh_.lookupObject<volScalarField>(rhoName);
+        const auto& mu = mesh_.lookupObject<volScalarField>(muName);
 
         apply(AU, rho, mu, U);
     }
@@ -280,17 +271,14 @@ void Foam::porosityModels::DarcyForchheimer::correct
     {
         if (mesh_.foundObject<volScalarField>(nuName))
         {
-            const volScalarField& nu =
-                mesh_.lookupObject<volScalarField>(nuName);
+            const auto& nu = mesh_.lookupObject<volScalarField>(nuName);
 
             apply(AU, geometricOneField(), nu, U);
         }
         else
         {
-            const volScalarField& rho =
-                mesh_.lookupObject<volScalarField>(rhoName);
-            const volScalarField& mu =
-                mesh_.lookupObject<volScalarField>(muName);
+            const auto& rho = mesh_.lookupObject<volScalarField>(rhoName);
+            const auto& mu = mesh_.lookupObject<volScalarField>(muName);
 
             apply(AU, geometricOneField(), mu/rho, U);
         }
diff --git a/src/finiteVolume/cfdTools/general/porosityModel/DarcyForchheimer/DarcyForchheimer.H b/src/finiteVolume/cfdTools/general/porosityModel/DarcyForchheimer/DarcyForchheimer.H
index 96bcd160c64f660fe0640defa0b3f4a569ea50f0..038d9510986674f0a8a83d4b2e54ab3eac2ca949 100644
--- a/src/finiteVolume/cfdTools/general/porosityModel/DarcyForchheimer/DarcyForchheimer.H
+++ b/src/finiteVolume/cfdTools/general/porosityModel/DarcyForchheimer/DarcyForchheimer.H
@@ -41,7 +41,7 @@ Description
     to specify a multiplier (of the max component).
 
     The orientation of the porous region is defined with the same notation as
-    a co-ordinate system, but only a Cartesian co-ordinate system is valid.
+    a coordinate system, but only a Cartesian coordinate system is valid.
 
 SourceFiles
     DarcyForchheimer.C
@@ -141,7 +141,7 @@ public:
     );
 
     //- Destructor
-    virtual ~DarcyForchheimer();
+    virtual ~DarcyForchheimer() = default;
 
 
     // Member Functions
diff --git a/src/finiteVolume/cfdTools/general/porosityModel/fixedCoeff/fixedCoeff.C b/src/finiteVolume/cfdTools/general/porosityModel/fixedCoeff/fixedCoeff.C
index b94fbde938c996d29916c64ae8b21737d8ab0b77..bdea960dfe1ed5f73f08c0aeef469b73bdc25b23 100644
--- a/src/finiteVolume/cfdTools/general/porosityModel/fixedCoeff/fixedCoeff.C
+++ b/src/finiteVolume/cfdTools/general/porosityModel/fixedCoeff/fixedCoeff.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2012-2016 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2018 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -26,6 +26,7 @@ License
 #include "addToRunTimeSelectionTable.H"
 #include "fixedCoeff.H"
 #include "fvMatrices.H"
+#include "pointIndList.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -78,7 +79,6 @@ void Foam::porosityModels::fixedCoeff::apply
     const scalar rho
 ) const
 {
-
     forAll(cellZoneIDs_, zoneI)
     {
         const tensorField& alphaZones = alpha_[zoneI];
@@ -123,62 +123,45 @@ Foam::porosityModels::fixedCoeff::fixedCoeff
 }
 
 
-// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
-
-Foam::porosityModels::fixedCoeff::~fixedCoeff()
-{}
-
-
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 void Foam::porosityModels::fixedCoeff::calcTransformModelData()
 {
-    if (coordSys_.R().uniform())
+    // The alpha coefficient as a tensor
+    tensor alphaCoeff(Zero);
+    alphaCoeff.xx() = alphaXYZ_.value().x();
+    alphaCoeff.yy() = alphaXYZ_.value().y();
+    alphaCoeff.zz() = alphaXYZ_.value().z();
+
+    // The beta coefficient as a tensor
+    tensor betaCoeff(Zero);
+    betaCoeff.xx() = betaXYZ_.value().x();
+    betaCoeff.yy() = betaXYZ_.value().y();
+    betaCoeff.zz() = betaXYZ_.value().z();
+
+    if (csys().uniform())
     {
-        forAll(cellZoneIDs_, zoneI)
+        forAll(cellZoneIDs_, zonei)
         {
-            alpha_[zoneI].setSize(1);
-            beta_[zoneI].setSize(1);
-
-            alpha_[zoneI][0] = Zero;
-            alpha_[zoneI][0].xx() = alphaXYZ_.value().x();
-            alpha_[zoneI][0].yy() = alphaXYZ_.value().y();
-            alpha_[zoneI][0].zz() = alphaXYZ_.value().z();
-            alpha_[zoneI][0] = coordSys_.R().transformTensor(alpha_[zoneI][0]);
-
-            beta_[zoneI][0] = Zero;
-            beta_[zoneI][0].xx() = betaXYZ_.value().x();
-            beta_[zoneI][0].yy() = betaXYZ_.value().y();
-            beta_[zoneI][0].zz() = betaXYZ_.value().z();
-            beta_[zoneI][0] = coordSys_.R().transformTensor(beta_[zoneI][0]);
+            alpha_[zonei].resize(1);
+            beta_[zonei].resize(1);
+
+            alpha_[zonei] = csys().transform(alphaCoeff);
+            beta_[zonei] = csys().transform(betaCoeff);
         }
     }
     else
     {
-        forAll(cellZoneIDs_, zoneI)
+        forAll(cellZoneIDs_, zonei)
         {
-            const labelList& cells = mesh_.cellZones()[cellZoneIDs_[zoneI]];
-
-            alpha_[zoneI].setSize(cells.size());
-            beta_[zoneI].setSize(cells.size());
-
-            forAll(cells, i)
-            {
-                alpha_[zoneI][i] = Zero;
-                alpha_[zoneI][i].xx() = alphaXYZ_.value().x();
-                alpha_[zoneI][i].yy() = alphaXYZ_.value().y();
-                alpha_[zoneI][i].zz() = alphaXYZ_.value().z();
-
-                beta_[zoneI][i] = Zero;
-                beta_[zoneI][i].xx() = betaXYZ_.value().x();
-                beta_[zoneI][i].yy() = betaXYZ_.value().y();
-                beta_[zoneI][i].zz() = betaXYZ_.value().z();
-            }
-
-            const coordinateRotation& R = coordSys_.R(mesh_, cells);
-
-            alpha_[zoneI] = R.transformTensor(alpha_[zoneI], cells);
-            beta_[zoneI] = R.transformTensor(beta_[zoneI], cells);
+            const pointUIndList cc
+            (
+                mesh_.cellCentres(),
+                mesh_.cellZones()[cellZoneIDs_[zonei]]
+            );
+
+            alpha_[zonei] = csys().transform(cc, alphaCoeff);
+            beta_[zonei] = csys().transform(cc, betaCoeff);
         }
     }
 }
@@ -195,7 +178,7 @@ void Foam::porosityModels::fixedCoeff::calcForce
     scalarField Udiag(U.size(), 0.0);
     vectorField Usource(U.size(), Zero);
     const scalarField& V = mesh_.V();
-    scalar rhoRef = readScalar(coeffs_.lookup("rhoRef"));
+    const scalar rhoRef = coeffs_.get<scalar>("rhoRef");
 
     apply(Udiag, Usource, V, U, rhoRef);
 
diff --git a/src/finiteVolume/cfdTools/general/porosityModel/fixedCoeff/fixedCoeff.H b/src/finiteVolume/cfdTools/general/porosityModel/fixedCoeff/fixedCoeff.H
index af67f523d4b17b7e95d7cb3a8d6195b665ca9864..1090eb5c8ef3b3175f5a1bf15e19c066543692ea 100644
--- a/src/finiteVolume/cfdTools/general/porosityModel/fixedCoeff/fixedCoeff.H
+++ b/src/finiteVolume/cfdTools/general/porosityModel/fixedCoeff/fixedCoeff.H
@@ -118,7 +118,7 @@ public:
     );
 
     //- Destructor
-    virtual ~fixedCoeff();
+    virtual ~fixedCoeff() = default;
 
 
     // Member Functions
diff --git a/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/IOporosityModelList.C b/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/IOporosityModelList.C
index 0ed573c356ea6786018a03be5606d59bcc2f3371..f6cab47ee1f11c4ecfdc7236711a906c2a387c85 100644
--- a/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/IOporosityModelList.C
+++ b/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/IOporosityModelList.C
@@ -48,15 +48,15 @@ Foam::IOobject Foam::IOporosityModelList::createIOobject
         Info<< "Creating porosity model list from " << io.name() << nl << endl;
 
         io.readOpt() = IOobject::MUST_READ_IF_MODIFIED;
-        return io;
     }
     else
     {
         Info<< "No porosity models present" << nl << endl;
 
         io.readOpt() = IOobject::NO_READ;
-        return io;
     }
+
+    return io;
 }
 
 
@@ -79,10 +79,8 @@ bool Foam::IOporosityModelList::read()
         porosityModelList::read(*this);
         return true;
     }
-    else
-    {
-        return false;
-    }
+
+    return false;
 }
 
 
diff --git a/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/IOporosityModelList.H b/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/IOporosityModelList.H
index 62502570d1270063834a33e8190abbb52360d73d..8509897429e0326a7c47c71f622126b8487dc788 100644
--- a/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/IOporosityModelList.H
+++ b/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/IOporosityModelList.H
@@ -71,12 +71,11 @@ public:
     // Constructors
 
         //- Construct from mesh
-        IOporosityModelList(const fvMesh& mesh);
+        explicit IOporosityModelList(const fvMesh& mesh);
 
 
         //- Destructor
-        virtual ~IOporosityModelList()
-        {}
+        virtual ~IOporosityModelList() = default;
 
 
     // Member Functions
diff --git a/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/porosityModel.C b/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/porosityModel.C
index 19f9bbb3d4400a1a5657e8862876bac50ebb22df..781d53daa33b8a30e43ace54f66e3de134fa4b33 100644
--- a/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/porosityModel.C
+++ b/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/porosityModel.C
@@ -61,17 +61,6 @@ void Foam::porosityModel::adjustNegativeResistance(dimensionedVector& resist)
 }
 
 
-Foam::label Foam::porosityModel::fieldIndex(const label i) const
-{
-    label index = 0;
-    if (!coordSys_.R().uniform())
-    {
-        index = i;
-    }
-    return index;
-}
-
-
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
 Foam::porosityModel::porosityModel
@@ -101,7 +90,10 @@ Foam::porosityModel::porosityModel
     active_(true),
     zoneName_(cellZoneName),
     cellZoneIDs_(),
-    coordSys_(*(coordinateSystem::New(mesh, coeffs_)))
+    csysPtr_
+    (
+        coordinateSystem::New(mesh, coeffs_, coordinateSystem::typeName_())
+    )
 {
     if (zoneName_ == word::null)
     {
@@ -123,45 +115,36 @@ Foam::porosityModel::porosityModel
             << exit(FatalError);
     }
 
-    Info<< incrIndent << indent << coordSys_ << decrIndent << endl;
+    Info<< incrIndent << indent << csys() << decrIndent << endl;
 
     const pointField& points = mesh_.points();
     const cellList& cells = mesh_.cells();
     const faceList& faces = mesh_.faces();
-    forAll(cellZoneIDs_, zoneI)
+
+    for (const label zonei : cellZoneIDs_)
     {
-        const cellZone& cZone = mesh_.cellZones()[cellZoneIDs_[zoneI]];
-        point bbMin = point::max;
-        point bbMax = point::min;
+        const cellZone& cZone = mesh_.cellZones()[zonei];
+
+        boundBox bb;
 
-        forAll(cZone, i)
+        for (const label celli : cZone)
         {
-            const label cellI = cZone[i];
-            const cell& c = cells[cellI];
+            const cell& c = cells[celli];
             const pointField cellPoints(c.points(faces, points));
 
-            forAll(cellPoints, pointI)
+            for (const point& pt : cellPoints)
             {
-                const point pt = coordSys_.localPosition(cellPoints[pointI]);
-                bbMin = min(bbMin, pt);
-                bbMax = max(bbMax, pt);
+                bb.add(csys().localPosition(pt));
             }
         }
 
-        reduce(bbMin, minOp<point>());
-        reduce(bbMax, maxOp<point>());
+        bb.reduce();
 
-        Info<< "    local bounds: " << (bbMax - bbMin) << nl << endl;
+        Info<< "    local bounds: " << bb.span() << nl << endl;
     }
 }
 
 
-// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
-
-Foam::porosityModel::~porosityModel()
-{}
-
-
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 void Foam::porosityModel::transformModelData()
diff --git a/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/porosityModel.H b/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/porosityModel.H
index f8dd0a31fbde63e06a1b7a3e9090d95c53917296..8be1e311a15af1d8c184a88bd6d41745b6a62d42 100644
--- a/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/porosityModel.H
+++ b/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/porosityModel.H
@@ -91,13 +91,12 @@ protected:
         //- Cell zone IDs
         labelList cellZoneIDs_;
 
-        //- Local co-ordinate system
-        coordinateSystem coordSys_;
+        //- Local coordinate system
+        autoPtr<coordinateSystem> csysPtr_;
 
 
     // Protected Member Functions
 
-
         //- Transform the model data wrt mesh changes
         virtual void calcTransformModelData() = 0;
 
@@ -128,8 +127,12 @@ protected:
             volTensorField& AU
         ) const = 0;
 
+
+        //- Local coordinate system
+        inline const coordinateSystem& csys() const;
+
         //- Return label index
-        label fieldIndex(const label index) const;
+        inline label fieldIndex(const label index) const;
 
 
 public:
@@ -209,7 +212,7 @@ public:
     );
 
     //- Destructor
-    virtual ~porosityModel();
+    virtual ~porosityModel() = default;
 
 
     // Member Functions
diff --git a/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/porosityModelI.H b/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/porosityModelI.H
index ecf384a2749f1bc4c51e8a6dfc80daaa290efaec..26d34727444607ca6cbaa381088ff3672f8f1a76 100644
--- a/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/porosityModelI.H
+++ b/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/porosityModelI.H
@@ -23,6 +23,22 @@ License
 
 \*---------------------------------------------------------------------------*/
 
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+inline const Foam::coordinateSystem& Foam::porosityModel::csys() const
+{
+    return *csysPtr_;
+}
+
+
+inline Foam::label Foam::porosityModel::fieldIndex(const label i) const
+{
+    return (csysPtr_->uniform() ? 0 : i);
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
 inline const Foam::word& Foam::porosityModel::name() const
 {
     return name_;
diff --git a/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/porosityModelList.C b/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/porosityModelList.C
index bb39e241382eacd91baf96f3f87bb0e0602ffbd0..588624f71bc3941114cfdafe251bccbc70f68699 100644
--- a/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/porosityModelList.C
+++ b/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/porosityModelList.C
@@ -38,33 +38,26 @@ Foam::porosityModelList::porosityModelList
     mesh_(mesh)
 {
     reset(dict);
-
     active(true);
 }
 
 
-// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
-
-Foam::porosityModelList::~porosityModelList()
-{}
-
-
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 bool Foam::porosityModelList::active(const bool warn) const
 {
-    bool a = false;
+    bool anyOk = false;
     forAll(*this, i)
     {
-        a = a || this->operator[](i).active();
+        anyOk = anyOk || this->operator[](i).active();
     }
 
-    if (warn && this->size() && !a)
+    if (warn && this->size() && !anyOk)
     {
         Info<< "No porosity models active" << endl;
     }
 
-    return a;
+    return anyOk;
 }
 
 
diff --git a/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/porosityModelList.H b/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/porosityModelList.H
index fb48794662671af00cfbc6a5f29641f5b42117db..4674865685b30a7e24dcf9b1bf63949bba551968 100644
--- a/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/porosityModelList.H
+++ b/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/porosityModelList.H
@@ -45,7 +45,7 @@ SourceFiles
 namespace Foam
 {
 
-// Forward declaration of friend functions and operators
+// Forward declarations
 class porosityModelList;
 Ostream& operator<<(Ostream& os, const porosityModelList& models);
 
@@ -82,13 +82,13 @@ public:
     porosityModelList(const fvMesh& mesh, const dictionary& dict);
 
     //- Destructor
-    ~porosityModelList();
+    ~porosityModelList() = default;
 
 
     // Member Functions
 
         //- Return active status
-        bool active(const bool active = false) const;
+        bool active(const bool warn = false) const;
 
         //- Reset the source list
         void reset(const dictionary& dict);
diff --git a/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/porosityModelNew.C b/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/porosityModelNew.C
index 811023faaaee87ef90a82e4c4fb3662f58b09c5b..b1e05ae0887e015e1e6c236bc361c56b6c948625 100644
--- a/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/porosityModelNew.C
+++ b/src/finiteVolume/cfdTools/general/porosityModel/porosityModel/porosityModelNew.C
@@ -35,7 +35,7 @@ Foam::autoPtr<Foam::porosityModel> Foam::porosityModel::New
     const word& cellZoneName
 )
 {
-    const word modelType(dict.lookup("type"));
+    const word modelType(dict.get<word>("type"));
 
     Info<< "Porosity region " << name << ":" << nl
         << "    selecting model: " << modelType << endl;
@@ -46,7 +46,7 @@ Foam::autoPtr<Foam::porosityModel> Foam::porosityModel::New
     {
         FatalErrorInFunction
             << "Unknown " << typeName << " type " << modelType << nl << nl
-            << "Valid " << typeName << " types are:" << nl
+            << "Valid types are:" << nl
             << meshConstructorTablePtr_->sortedToc()
             << exit(FatalError);
     }
diff --git a/src/finiteVolume/cfdTools/general/porosityModel/powerLaw/powerLaw.C b/src/finiteVolume/cfdTools/general/porosityModel/powerLaw/powerLaw.C
index 280b0e4ba27af5ed6d0f13eb84ae3c1059cd78a0..aca0860bbccd7ece8298c57b8b0316f0082a4da9 100644
--- a/src/finiteVolume/cfdTools/general/porosityModel/powerLaw/powerLaw.C
+++ b/src/finiteVolume/cfdTools/general/porosityModel/powerLaw/powerLaw.C
@@ -52,18 +52,12 @@ Foam::porosityModels::powerLaw::powerLaw
 )
 :
     porosityModel(name, modelType, mesh, dict, cellZoneName),
-    C0_(readScalar(coeffs_.lookup("C0"))),
-    C1_(readScalar(coeffs_.lookup("C1"))),
+    C0_(coeffs_.get<scalar>("C0")),
+    C1_(coeffs_.get<scalar>("C1")),
     rhoName_(coeffs_.lookupOrDefault<word>("rho", "rho"))
 {}
 
 
-// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
-
-Foam::porosityModels::powerLaw::~powerLaw()
-{}
-
-
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 void Foam::porosityModels::powerLaw::calcTransformModelData()
@@ -100,7 +94,7 @@ void Foam::porosityModels::powerLaw::correct
 
     if (UEqn.dimensions() == dimForce)
     {
-        const volScalarField& rho = mesh_.lookupObject<volScalarField>
+        const auto& rho = mesh_.lookupObject<volScalarField>
         (
             IOobject::groupName(rhoName_, U.group())
         );
@@ -139,7 +133,7 @@ void Foam::porosityModels::powerLaw::correct
 
     if (UEqn.dimensions() == dimForce)
     {
-        const volScalarField& rho = mesh_.lookupObject<volScalarField>
+        const auto& rho = mesh_.lookupObject<volScalarField>
         (
             IOobject::groupName(rhoName_, U.group())
         );
diff --git a/src/finiteVolume/cfdTools/general/porosityModel/powerLaw/powerLaw.H b/src/finiteVolume/cfdTools/general/porosityModel/powerLaw/powerLaw.H
index 3d97f2786fb4d4fa98d10cfc4cd5a8b2f383ba51..305e60e5e3c265ea5c9ac4f54454da1efbdc322c 100644
--- a/src/finiteVolume/cfdTools/general/porosityModel/powerLaw/powerLaw.H
+++ b/src/finiteVolume/cfdTools/general/porosityModel/powerLaw/powerLaw.H
@@ -119,7 +119,7 @@ public:
     );
 
     //- Destructor
-    virtual ~powerLaw();
+    virtual ~powerLaw() = default;
 
 
     // Member Functions
diff --git a/src/finiteVolume/cfdTools/general/porosityModel/powerLaw/powerLawTemplates.C b/src/finiteVolume/cfdTools/general/porosityModel/powerLaw/powerLawTemplates.C
index 7ed3d2ead772cf7eaeebb3033490046a8a933a69..30df618f66ae5c415dfaa36ade16d44ad7ebd620 100644
--- a/src/finiteVolume/cfdTools/general/porosityModel/powerLaw/powerLawTemplates.C
+++ b/src/finiteVolume/cfdTools/general/porosityModel/powerLaw/powerLawTemplates.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2012-2016 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2018 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -37,14 +37,12 @@ void Foam::porosityModels::powerLaw::apply
     const scalar C0 = C0_;
     const scalar C1m1b2 = (C1_ - 1.0)/2.0;
 
-    forAll(cellZoneIDs_, zoneI)
+    for (const label zonei : cellZoneIDs_)
     {
-        const labelList& cells = mesh_.cellZones()[cellZoneIDs_[zoneI]];
+        const labelList& cells = mesh_.cellZones()[zonei];
 
-        forAll(cells, i)
+        for (const label celli : cells)
         {
-            const label celli = cells[i];
-
             Udiag[celli] +=
                 V[celli]*rho[celli]*C0*pow(magSqr(U[celli]), C1m1b2);
         }
@@ -63,14 +61,12 @@ void Foam::porosityModels::powerLaw::apply
     const scalar C0 = C0_;
     const scalar C1m1b2 = (C1_ - 1.0)/2.0;
 
-    forAll(cellZoneIDs_, zoneI)
+    for (const label zonei : cellZoneIDs_)
     {
-        const labelList& cells = mesh_.cellZones()[cellZoneIDs_[zoneI]];
+        const labelList& cells = mesh_.cellZones()[zonei];
 
-        forAll(cells, i)
+        for (const label celli : cells)
         {
-            const label celli = cells[i];
-
             AU[celli] =
                 AU[celli] + I*(rho[celli]*C0*pow(magSqr(U[celli]), C1m1b2));
         }
diff --git a/src/finiteVolume/cfdTools/general/porosityModel/solidification/solidification.C b/src/finiteVolume/cfdTools/general/porosityModel/solidification/solidification.C
index 68d3edcf774cab5822d157e55284aa0218558c06..50276c115bdeb60fe9c21b880e45b167e992e596 100644
--- a/src/finiteVolume/cfdTools/general/porosityModel/solidification/solidification.C
+++ b/src/finiteVolume/cfdTools/general/porosityModel/solidification/solidification.C
@@ -99,7 +99,7 @@ void Foam::porosityModels::solidification::correct
 
     if (UEqn.dimensions() == dimForce)
     {
-        const volScalarField& rho = mesh_.lookupObject<volScalarField>
+        const auto& rho = mesh_.lookupObject<volScalarField>
         (
             IOobject::groupName(rhoName_, U.group())
         );
@@ -138,7 +138,7 @@ void Foam::porosityModels::solidification::correct
 
     if (UEqn.dimensions() == dimForce)
     {
-        const volScalarField& rho = mesh_.lookupObject<volScalarField>
+        const auto& rho = mesh_.lookupObject<volScalarField>
         (
             IOobject::groupName(rhoName_, U.group())
         );
diff --git a/src/finiteVolume/cfdTools/general/porosityModel/solidification/solidification.H b/src/finiteVolume/cfdTools/general/porosityModel/solidification/solidification.H
index 3922d54775448f60ee3214f473bcb34700c1452a..ee83b6ee7e00a397579e2c9e35b1ca187fb9e3e8 100644
--- a/src/finiteVolume/cfdTools/general/porosityModel/solidification/solidification.H
+++ b/src/finiteVolume/cfdTools/general/porosityModel/solidification/solidification.H
@@ -63,14 +63,9 @@ Description
             // use the global coordinate system
             coordinateSystem
             {
-                type    cartesian;
                 origin  (0 0 0);
-                coordinateRotation
-                {
-                    type    axesRotation;
-                    e1      (1 0 0);
-                    e2      (0 1 0);
-                }
+                e1      (1 0 0);
+                e2      (0 1 0);
             }
         }
     \endverbatim
diff --git a/src/finiteVolume/cfdTools/general/porosityModel/solidification/solidificationTemplates.C b/src/finiteVolume/cfdTools/general/porosityModel/solidification/solidificationTemplates.C
index d9ea04d59eb99dcbed77a68179efad455eb17fd7..9abd56a62f4f2db0ff792ff0b6bb2905f1ac5cb2 100644
--- a/src/finiteVolume/cfdTools/general/porosityModel/solidification/solidificationTemplates.C
+++ b/src/finiteVolume/cfdTools/general/porosityModel/solidification/solidificationTemplates.C
@@ -38,18 +38,17 @@ void Foam::porosityModels::solidification::apply
     const volVectorField& U
 ) const
 {
-    const volScalarField& T = mesh_.lookupObject<volScalarField>
+    const auto& T = mesh_.lookupObject<volScalarField>
     (
         IOobject::groupName(TName_, U.group())
     );
 
-    forAll(cellZoneIDs_, zoneI)
+    for (const label zonei : cellZoneIDs_)
     {
-        const labelList& cells = mesh_.cellZones()[cellZoneIDs_[zoneI]];
+        const labelList& cells = mesh_.cellZones()[zonei];
 
-        forAll(cells, i)
+        for (const label celli : cells)
         {
-            const label celli = cells[i];
             Udiag[celli] +=
                 V[celli]*alpha[celli]*rho[celli]*D_->value(T[celli]);
         }
@@ -66,18 +65,17 @@ void Foam::porosityModels::solidification::apply
     const volVectorField& U
 ) const
 {
-    const volScalarField& T = mesh_.lookupObject<volScalarField>
+    const auto& T = mesh_.lookupObject<volScalarField>
     (
         IOobject::groupName(TName_, U.group())
     );
 
-    forAll(cellZoneIDs_, zoneI)
+    for (const label zonei : cellZoneIDs_)
     {
-        const labelList& cells = mesh_.cellZones()[cellZoneIDs_[zoneI]];
+        const labelList& cells = mesh_.cellZones()[zonei];
 
-        forAll(cells, i)
+        for (const label celli : cells)
         {
-            const label celli = cells[i];
             AU[celli] +=
                 tensor::I*alpha[celli]*rho[celli]*D_->value(T[celli]);
         }
@@ -100,7 +98,7 @@ void Foam::porosityModels::solidification::apply
     }
     else
     {
-        const volScalarField& alpha = mesh_.lookupObject<volScalarField>
+        const auto& alpha = mesh_.lookupObject<volScalarField>
         (
             IOobject::groupName(alphaName_, U.group())
         );
@@ -124,7 +122,7 @@ void Foam::porosityModels::solidification::apply
     }
     else
     {
-        const volScalarField& alpha = mesh_.lookupObject<volScalarField>
+        const auto& alpha = mesh_.lookupObject<volScalarField>
         (
             IOobject::groupName(alphaName_, U.group())
         );
diff --git a/src/finiteVolume/fields/fvPatchFields/derived/cylindricalInletVelocity/cylindricalInletVelocityFvPatchVectorField.H b/src/finiteVolume/fields/fvPatchFields/derived/cylindricalInletVelocity/cylindricalInletVelocityFvPatchVectorField.H
index 833714cce15350444fab4fdf34837db49e65176e..f97698335d29d63878107e49fa2fb1f6710fda7c 100644
--- a/src/finiteVolume/fields/fvPatchFields/derived/cylindricalInletVelocity/cylindricalInletVelocityFvPatchVectorField.H
+++ b/src/finiteVolume/fields/fvPatchFields/derived/cylindricalInletVelocity/cylindricalInletVelocityFvPatchVectorField.H
@@ -29,7 +29,7 @@ Group
 
 Description
     This boundary condition describes an inlet vector boundary condition in
-    cylindrical co-ordinates given a central axis, central point, rpm, axial
+    cylindrical coordinates given a central axis, central point, rpm, axial
     and radial velocity.
 
 Usage
diff --git a/src/finiteVolume/fields/fvPatchFields/derived/phaseHydrostaticPressure/phaseHydrostaticPressureFvPatchScalarField.H b/src/finiteVolume/fields/fvPatchFields/derived/phaseHydrostaticPressure/phaseHydrostaticPressureFvPatchScalarField.H
index 94b71defce7109cac83e51561ddbd2b4f79c39a5..94ae12a9fd8faf53c8dbd3a389a499aee0911e26 100644
--- a/src/finiteVolume/fields/fvPatchFields/derived/phaseHydrostaticPressure/phaseHydrostaticPressureFvPatchScalarField.H
+++ b/src/finiteVolume/fields/fvPatchFields/derived/phaseHydrostaticPressure/phaseHydrostaticPressureFvPatchScalarField.H
@@ -39,7 +39,7 @@ Description
     \vartable
         p_{hyd} | hyrostatic pressure [Pa]
         p_{ref} | reference pressure [Pa]
-        x_{ref} | reference point in Cartesian co-ordinates
+        x_{ref} | reference point in Cartesian coordinates
         \rho    | density (assumed uniform)
         g       | acceleration due to gravity [m/s2]
     \endtable
diff --git a/src/finiteVolume/fields/fvPatchFields/derived/rotatingWallVelocity/rotatingWallVelocityFvPatchVectorField.H b/src/finiteVolume/fields/fvPatchFields/derived/rotatingWallVelocity/rotatingWallVelocityFvPatchVectorField.H
index 485a417bda5770936b57e67acb9c072bb69691ed..19e85084858193fba3917439a88eb384acc7876e 100644
--- a/src/finiteVolume/fields/fvPatchFields/derived/rotatingWallVelocity/rotatingWallVelocityFvPatchVectorField.H
+++ b/src/finiteVolume/fields/fvPatchFields/derived/rotatingWallVelocity/rotatingWallVelocityFvPatchVectorField.H
@@ -33,7 +33,7 @@ Description
 Usage
     \table
         Property     | Description             | Required    | Default value
-        origin       | origin of rotation in Cartesian co-ordinates | yes|
+        origin       | origin of rotation in Cartesian coordinates | yes|
         axis         | axis of rotation        | yes         |
         omega        | angular velocty of the frame [rad/s] | yes    |
     \endtable
diff --git a/src/finiteVolume/fields/fvPatchFields/derived/swirlInletVelocity/swirlInletVelocityFvPatchVectorField.H b/src/finiteVolume/fields/fvPatchFields/derived/swirlInletVelocity/swirlInletVelocityFvPatchVectorField.H
index d56fcc8f2e983d608b40003c6ad08cd151bc884b..5b22c192b44e89ad3b1290868699a5b216b110d6 100644
--- a/src/finiteVolume/fields/fvPatchFields/derived/swirlInletVelocity/swirlInletVelocityFvPatchVectorField.H
+++ b/src/finiteVolume/fields/fvPatchFields/derived/swirlInletVelocity/swirlInletVelocityFvPatchVectorField.H
@@ -29,7 +29,7 @@ Group
 
 Description
     This boundary condition describes an inlet vector boundary condition in
-    swirl co-ordinates given a central axis, central point, axial, radial and
+    swirl coordinates given a central axis, central point, axial, radial and
     tangential velocity profiles.
 
 Usage
diff --git a/src/finiteVolume/fields/fvPatchFields/derived/turbulentDFSEMInlet/eddy/eddy.H b/src/finiteVolume/fields/fvPatchFields/derived/turbulentDFSEMInlet/eddy/eddy.H
index be527caa2f3813cc74a599977fef50eac7d78a19..c1c91145b7a908e525bd715997da5f4f00d47a45 100644
--- a/src/finiteVolume/fields/fvPatchFields/derived/turbulentDFSEMInlet/eddy/eddy.H
+++ b/src/finiteVolume/fields/fvPatchFields/derived/turbulentDFSEMInlet/eddy/eddy.H
@@ -42,19 +42,18 @@ SourceFiles
 #include "point.H"
 #include "tensor.H"
 #include "Random.H"
-#include "coordinateSystem.H"
+#include "boundBox.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 namespace Foam
 {
 
-// Forward declaration of classes
+// Forward declarations
+class eddy;
 class Istream;
 class Ostream;
 
-// Forward declaration of friend functions and operators
-class eddy;
 bool operator==(const eddy& a, const eddy& b);
 bool operator!=(const eddy& a, const eddy& b);
 Istream& operator>>(Istream& is, eddy& e);
@@ -87,7 +86,7 @@ class eddy
         //- Time-averaged intensity
         vector alpha_;
 
-        //- Co-ordinate system transformation from local to global axes
+        //- Coordinate system transformation from local to global axes
         //  X-direction aligned with max stress eigenvalue
         tensor Rpg_;
 
@@ -161,7 +160,7 @@ public:
             //- Return the time-averaged intensity
             inline const vector& alpha() const;
 
-            //- Return the co-ordinate system transformation from local
+            //- Return the coordinate system transformation from local
             //  principal to global axes
             inline const tensor& Rpg() const;
 
diff --git a/src/finiteVolume/fields/fvPatchFields/derived/uniformDensityHydrostaticPressure/uniformDensityHydrostaticPressureFvPatchScalarField.H b/src/finiteVolume/fields/fvPatchFields/derived/uniformDensityHydrostaticPressure/uniformDensityHydrostaticPressureFvPatchScalarField.H
index fb61f2f0143e0cf505e45192d7c8f88bc61b4103..7497873c39abdc08eab11cf70b03d3c11cf346f3 100644
--- a/src/finiteVolume/fields/fvPatchFields/derived/uniformDensityHydrostaticPressure/uniformDensityHydrostaticPressureFvPatchScalarField.H
+++ b/src/finiteVolume/fields/fvPatchFields/derived/uniformDensityHydrostaticPressure/uniformDensityHydrostaticPressureFvPatchScalarField.H
@@ -39,7 +39,7 @@ Description
     \vartable
         p_{hyd} | hyrostatic pressure [Pa]
         p_{ref} | reference pressure [Pa]
-        x_{ref} | reference point in Cartesian co-ordinates
+        x_{ref} | reference point in Cartesian coordinates
         \rho    | density (assumed uniform)
         g       | acceleration due to gravity [m/s2]
     \endtable
diff --git a/src/finiteVolume/interpolation/interpolation/interpolationCellPoint/cellPointWeight/cellPointWeight.H b/src/finiteVolume/interpolation/interpolation/interpolationCellPoint/cellPointWeight/cellPointWeight.H
index ed064281c1d973370e328a93738cc45632705c64..80b2e5a835bd5759463a07ec74887741bc5d3ea3 100644
--- a/src/finiteVolume/interpolation/interpolation/interpolationCellPoint/cellPointWeight/cellPointWeight.H
+++ b/src/finiteVolume/interpolation/interpolation/interpolationCellPoint/cellPointWeight/cellPointWeight.H
@@ -89,7 +89,7 @@ public:
     //- Debug switch
     static int debug;
 
-    //- Tolerance used in calculating barycentric co-ordinates
+    //- Tolerance used in calculating barycentric coordinates
     //  (applied to normalised values)
     static scalar tol;
 
diff --git a/src/finiteVolume/interpolation/interpolation/interpolationPointMVC/pointMVCWeight.H b/src/finiteVolume/interpolation/interpolation/interpolationPointMVC/pointMVCWeight.H
index a76fc7f951eca91837c87bdc19b97bb0f9489ba0..2228f1a5b37d81ddd11e4c39351c3248abd74aa0 100644
--- a/src/finiteVolume/interpolation/interpolation/interpolationPointMVC/pointMVCWeight.H
+++ b/src/finiteVolume/interpolation/interpolation/interpolationPointMVC/pointMVCWeight.H
@@ -107,7 +107,7 @@ public:
     //- Debug switch
     static int debug;
 
-    //- Tolerance used in calculating barycentric co-ordinates
+    //- Tolerance used in calculating barycentric coordinates
     //  (applied to normalised values)
     static scalar tol;
 
diff --git a/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransform.C b/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransform.C
index 2c4ea97f34d8a7b837714a213d23bf69dfef30cb..eefc9ca268caba0ab7d537319f57dcbd362a7693 100644
--- a/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransform.C
+++ b/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransform.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2017 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2017-2018 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -56,23 +56,19 @@ fieldCoordinateSystemTransform
 :
     fvMeshFunctionObject(name, runTime, dict),
     fieldSet_(mesh_),
-    coordSys_(mesh_, dict.subDict("coordinateSystem"))
+    csysPtr_
+    (
+        coordinateSystem::New(mesh_, dict, coordinateSystem::typeName_())
+    )
 {
     read(dict);
 
     Info<< type() << " " << name << ":" << nl
         << "   Applying transformation from global Cartesian to local "
-        << coordSys_ << nl << endl;
+        << *csysPtr_ << nl << endl;
 }
 
 
-// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
-
-Foam::functionObjects::fieldCoordinateSystemTransform::
-~fieldCoordinateSystemTransform()
-{}
-
-
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 Foam::word
diff --git a/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransform.H b/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransform.H
index dbc0446cb7f9a4714ce2e09b07738aba109714ee..5f68d09f8b0294aed6da6e2807dbd561d51f7621 100644
--- a/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransform.H
+++ b/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransform.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2017 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2015 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2015-2018 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -29,7 +29,7 @@ Group
 
 Description
     Transforms a user-specified selection of fields from global Cartesian
-    co-ordinates to a local co-ordinate system.  The fields are run-time
+    coordinates to a local coordinate system.  The fields are run-time
     modifiable.
 
 Usage
@@ -50,11 +50,11 @@ Usage
         coordinateSystem
         {
             origin      (0.001 0 0);
-            coordinateRotation
+            rotation
             {
-                type        axesRotation;
-                e1          (1      0.15    0);
-                e3          (0      0      -1);
+                type    axes;
+                e1      (1 0.15 0);
+                e3      (0 0 -1);
             }
         }
     }
@@ -65,7 +65,7 @@ Usage
         Property     | Description             | Required    | Default value
         type         | type name: fieldCoordinateSystemTransform | yes |
         fields       | list of fields to be transformed |yes |
-        coordinateSystem | local co-ordinate system | yes    |
+        coordinateSystem | local coordinate system | yes    |
     \endtable
 
 See also
@@ -107,8 +107,8 @@ protected:
         //- Fields to transform
         volFieldSelection fieldSet_;
 
-        //- Co-ordinate system to transform to
-        coordinateSystem coordSys_;
+        //- Coordinate system to transform to
+        autoPtr<coordinateSystem> csysPtr_;
 
 
     // Protected Member Functions
@@ -143,7 +143,7 @@ public:
 
 
     //- Destructor
-    virtual ~fieldCoordinateSystemTransform();
+    virtual ~fieldCoordinateSystemTransform() = default;
 
 
     // Member Functions
diff --git a/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransformTemplates.C b/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransformTemplates.C
index 2e26c96343c6ca95d2c1973947b764c6fe3f3969..2cf380522b7df86ea6e09d8a6f0e20aa6d4c56c6 100644
--- a/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransformTemplates.C
+++ b/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransformTemplates.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2017 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2016-2017 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2016-2018 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -41,7 +41,7 @@ void Foam::functionObjects::fieldCoordinateSystemTransform::transformField
     store
     (
         transFieldName,
-        Foam::transform(dimensionedTensor(coordSys_.R().R()), field)
+        Foam::transform(dimensionedTensor(csysPtr_->R()), field)
     );
 }
 
@@ -61,7 +61,10 @@ void Foam::functionObjects::fieldCoordinateSystemTransform::transform
             << type() << ": Field " << fieldName << " already in database"
             << endl;
 
-        transformField<VolFieldType>(lookupObject<VolFieldType>(fieldName));
+        transformField<VolFieldType>
+        (
+            lookupObject<VolFieldType>(fieldName)
+        );
     }
     else if (foundObject<SurfaceFieldType>(fieldName))
     {
diff --git a/src/functionObjects/field/fieldCoordinateSystemTransform/postProcessingDict b/src/functionObjects/field/fieldCoordinateSystemTransform/postProcessingDict
index c1ffcfcb73bfff4762fbae6ead7a6556e2b2ff89..d2604fe00208fcec93c932a6969354e26e3ce2f3 100644
--- a/src/functionObjects/field/fieldCoordinateSystemTransform/postProcessingDict
+++ b/src/functionObjects/field/fieldCoordinateSystemTransform/postProcessingDict
@@ -41,12 +41,8 @@ functions
         coordinateSystem
         {
             origin  (0 0 0);
-            coordinateRotation
-            {
-                type    axesRotation;
-                e1      (1  0.15  0);
-                e3      (0  0    -1);
-            }
+            e1      (1 0.15 0);
+            e3      (0 0 -1);
         }
     }
 }
diff --git a/src/functionObjects/field/regionSizeDistribution/regionSizeDistribution.C b/src/functionObjects/field/regionSizeDistribution/regionSizeDistribution.C
index 98aa128897acd1ff53537b493d76251e9340086e..ef509267b87ad9fd7c6a5a148b35df3c602ca989 100644
--- a/src/functionObjects/field/regionSizeDistribution/regionSizeDistribution.C
+++ b/src/functionObjects/field/regionSizeDistribution/regionSizeDistribution.C
@@ -350,12 +350,19 @@ bool Foam::functionObjects::regionSizeDistribution::read(const dictionary& dict)
     const word format(dict.get<word>("setFormat"));
     formatterPtr_ = writer<scalar>::New(format);
 
-    if (dict.found("coordinateSystem"))
+    if (dict.found(coordinateSystem::typeName_()))
     {
-        coordSysPtr_.reset(new coordinateSystem(obr_, dict));
+        csysPtr_.reset
+        (
+            coordinateSystem::New(obr_, dict, coordinateSystem::typeName_())
+        );
 
         Info<< "Transforming all vectorFields with coordinate system "
-            << coordSysPtr_().name() << endl;
+            << csysPtr_->name() << endl;
+    }
+    else
+    {
+        csysPtr_.clear();
     }
 
     if (isoPlanes_)
@@ -897,14 +904,14 @@ bool Foam::functionObjects::regionSizeDistribution::write()
                     volVectorField
                 >(fldName).primitiveField();
 
-                if (coordSysPtr_.valid())
+                if (csysPtr_.valid())
                 {
                     Log << "Transforming vector field " << fldName
                         << " with coordinate system "
-                        << coordSysPtr_().name()
+                        << csysPtr_->name()
                         << endl;
 
-                    fld = coordSysPtr_().localVector(fld);
+                    fld = csysPtr_->localVector(fld);
                 }
 
 
diff --git a/src/functionObjects/field/regionSizeDistribution/regionSizeDistribution.H b/src/functionObjects/field/regionSizeDistribution/regionSizeDistribution.H
index 1ab6800d10efbdaa07a12817eeda2ead919112ac..6110888cabd6b88af6b4f51e6b95de4763cc309f 100644
--- a/src/functionObjects/field/regionSizeDistribution/regionSizeDistribution.H
+++ b/src/functionObjects/field/regionSizeDistribution/regionSizeDistribution.H
@@ -113,8 +113,8 @@ Usage
         maxDiameter  | maximum region equivalent diameter | yes |
         minDiameter  | minimum region equivalent diameter | no  | 0
         setFormat    | writing format          | yes         |
-        origin       | origin of local co-ordinate system | yes    |
-        coordinateRoation | orientation of local co-ordinate system | no
+        origin       | origin of local coordinate system | yes    |
+        coordinateRoation | orientation of local coordinate system | no
         log          | Log to standard output  | no          | yes
         isoPlanes    | switch for isoPlanes    | no          | false
         origin       | origin of the plane when isoPlanes is used | no | none
@@ -198,7 +198,7 @@ class regionSizeDistribution
         autoPtr<writer<scalar>> formatterPtr_;
 
         //- Optional coordinate system
-        autoPtr<coordinateSystem> coordSysPtr_;
+        autoPtr<coordinateSystem> csysPtr_;
 
         // Optional extra definition of bins on planes downstream to the origin
         // point and maximum diameter
diff --git a/src/functionObjects/forces/forces/forces.C b/src/functionObjects/forces/forces/forces.C
index cc166499ea4a5ffb92a7dc5c9be6e7b378ab03a0..ece9acc17ddab5b88ce9ea46074f0cec709d360a 100644
--- a/src/functionObjects/forces/forces/forces.C
+++ b/src/functionObjects/forces/forces/forces.C
@@ -29,6 +29,7 @@ License
 #include "turbulentTransportModel.H"
 #include "turbulentFluidThermoModel.H"
 #include "addToRunTimeSelectionTable.H"
+#include "cartesianCS.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -37,7 +38,6 @@ namespace Foam
 namespace functionObjects
 {
     defineTypeNameAndDebug(forces, 0);
-
     addToRunTimeSelectionTable(functionObject, forces, dictionary);
 }
 }
@@ -857,7 +857,23 @@ bool Foam::functionObjects::forces::read(const dictionary& dict)
     // specified directly, from coordinate system, or implicitly (0 0 0)
     if (!dict.readIfPresent<point>("CofR", coordSys_.origin()))
     {
-        coordSys_ = coordinateSystem(obr_, dict);
+        // The 'coordinateSystem' sub-dictionary is optional,
+        // but enforce use of a cartesian system.
+
+        if (dict.found(coordinateSystem::typeName_()))
+        {
+            // New() for access to indirect (global) coordinate system
+            coordSys_ =
+                coordinateSystem::New
+                (
+                    obr_, dict, coordinateSystem::typeName_()
+                );
+        }
+        else
+        {
+            coordSys_ = coordSystem::cartesian(dict);
+        }
+
         localSystem_ = true;
     }
 
diff --git a/src/functionObjects/forces/forces/forces.H b/src/functionObjects/forces/forces/forces.H
index 4a27514c6abe370f742caab8329c7759c057539e..94b89a56358496352faaeb0b5ed8eea106f01097 100644
--- a/src/functionObjects/forces/forces/forces.H
+++ b/src/functionObjects/forces/forces/forces.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2015-2016 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2015-2018 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -32,21 +32,21 @@ Description
     skin-friction forces over a given list of patches, and the resistance
     from porous zones.
 
-    Forces and moments are calculated, with optional co-ordinate system and
+    Forces and moments are calculated, with optional coordinate system and
     writing of binned data, where force and moment contributions are collected
     into a user-defined number of bins that span the input geometries for a
     user-defined direction vector.
 
     Data is written into multiple files in the
     postProcessing/\<functionObjectName\> directory:
-    - force.dat          : forces in global Cartesian co-ordinate system
-    - moment.dat         : moments in global Cartesian co-ordinate system
-    - forceBin.dat       : force bins in global Cartesian co-ordinate system
-    - momentBin.dat      : moment bins in global Cartesian co-ordinate system
-    - localForce.dat     : forces in local co-ordinate system
-    - localMoment.dat    : moments in local co-ordinate system
-    - localForceBin.dat  : force bins in local co-ordinate system
-    - localMomentBin.dat : moment bins in local co-ordinate system
+    - force.dat          : forces in global Cartesian coordinate system
+    - moment.dat         : moments in global Cartesian coordinate system
+    - forceBin.dat       : force bins in global Cartesian coordinate system
+    - momentBin.dat      : moment bins in global Cartesian coordinate system
+    - localForce.dat     : forces in local Cartesian coordinate system
+    - localMoment.dat    : moments in local Cartesian coordinate system
+    - localForceBin.dat  : force bins in local Cartesian coordinate system
+    - localMomentBin.dat : moment bins in local Cartesian coordinate system
 
 Usage
     Example of function object specification:
@@ -107,13 +107,19 @@ Note
         CofR        (0 0 0);
     \endverbatim
     or
+    \verbatim
+        origin  (0 0 0);
+        e1      (0 1 0);
+        e3      (0 0 1);
+    \endverbatim
+    or
     \verbatim
         coordinateSystem
         {
             origin  (0 0 0);
-            coordinateRotation
+            rotation
             {
-                type    axesRotation;
+                type    axes;
                 e3      (0 0 1);
                 e1      (1 0 0);
             }
@@ -136,7 +142,7 @@ SourceFiles
 
 #include "fvMeshFunctionObject.H"
 #include "writeFile.H"
-#include "coordinateSystem.H"
+#include "cartesianCS.H"
 #include "volFieldsFwd.H"
 #include "HashSet.H"
 #include "Tuple2.H"
@@ -224,9 +230,9 @@ protected:
             scalar pRef_;
 
             //- Coordinate system used when evaluting forces/moments
-            coordinateSystem coordSys_;
+            coordSystem::cartesian coordSys_;
 
-            //- Flag to indicate whether we are using a local co-ordinate sys
+            //- Flag to indicate whether we are using a local coordinates
             bool localSystem_;
 
             //- Flag to include porosity effects
diff --git a/src/fvOptions/sources/derived/explicitPorositySource/explicitPorositySource.H b/src/fvOptions/sources/derived/explicitPorositySource/explicitPorositySource.H
index 4b17b1717415f87cab5a27e41e7a21da98fe4ea1..74afb15cbcce5a3107c52cd6e844a2b88d3f20b3 100644
--- a/src/fvOptions/sources/derived/explicitPorositySource/explicitPorositySource.H
+++ b/src/fvOptions/sources/derived/explicitPorositySource/explicitPorositySource.H
@@ -44,14 +44,9 @@ Usage
 
             coordinateSystem
             {
-                type    cartesian;
                 origin  (0 0 0);
-                coordinateRotation
-                {
-                    type    axesRotation;
-                    e1  (0.70710678 0.70710678 0);
-                    e2  (0 0 1);
-                }
+                e1      (0.70710678 0.70710678 0);
+                e2      (0 0 1);
             }
         }
     }
diff --git a/src/fvOptions/sources/derived/jouleHeatingSource/jouleHeatingSource.C b/src/fvOptions/sources/derived/jouleHeatingSource/jouleHeatingSource.C
index 0ecc8d31dd78201f95f416fd40181401403f4001..b2f4df53430e8ec81788b3dafd2865522260a3bc 100644
--- a/src/fvOptions/sources/derived/jouleHeatingSource/jouleHeatingSource.C
+++ b/src/fvOptions/sources/derived/jouleHeatingSource/jouleHeatingSource.C
@@ -2,7 +2,7 @@
   =========                 |
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2016-2017 OpenCFD Ltd.
+    \\  /    A nd           | Copyright (C) 2016-2018 OpenCFD Ltd.
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
 License
@@ -53,16 +53,16 @@ const Foam::word Foam::fv::jouleHeatingSource::sigmaName(typeName + ":sigma");
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
-const Foam::coordinateSystem& Foam::fv::jouleHeatingSource::coordSys() const
+const Foam::coordinateSystem& Foam::fv::jouleHeatingSource::csys() const
 {
-    if (!coordSysPtr_.valid())
+    if (!csysPtr_ || !csysPtr_.valid())
     {
         FatalErrorInFunction
-            << "Co-ordinate system invalid"
+            << "Coordinate system invalid"
             << abort(FatalError);
     }
 
-    return *coordSysPtr_;
+    return *csysPtr_;
 }
 
 
@@ -87,10 +87,18 @@ Foam::fv::jouleHeatingSource::transformSigma
         dimensionedSymmTensor(sigmaLocal.dimensions(), Zero),
         zeroGradientFvPatchField<symmTensor>::typeName
     );
-
     auto& sigma = tsigma.ref();
 
-    sigma.primitiveFieldRef() = coordSys().R().transformVector(sigmaLocal);
+    if (csys().uniform())
+    {
+        sigma.primitiveFieldRef() =
+            csys().transformPrincipal(sigmaLocal);
+    }
+    else
+    {
+        sigma.primitiveFieldRef() =
+            csys().transformPrincipal(mesh_.cellCentres(), sigmaLocal);
+    }
 
     sigma.correctBoundaryConditions();
 
@@ -125,7 +133,7 @@ Foam::fv::jouleHeatingSource::jouleHeatingSource
     anisotropicElectricalConductivity_(false),
     scalarSigmaVsTPtr_(nullptr),
     vectorSigmaVsTPtr_(nullptr),
-    coordSysPtr_(nullptr),
+    csysPtr_(nullptr),
     curTimeIndex_(-1)
 {
     // Set the field name to that of the energy field from which the temperature
@@ -223,7 +231,14 @@ bool Foam::fv::jouleHeatingSource::read(const dictionary& dict)
             Info<< "    Using vector electrical conductivity" << endl;
 
             initialiseSigma(coeffs_, vectorSigmaVsTPtr_);
-            coordSysPtr_ = coordinateSystem::New(mesh_, coeffs_);
+
+            csysPtr_ =
+                coordinateSystem::New
+                (
+                    mesh_,
+                    coeffs_,
+                    coordinateSystem::typeName_()
+                );
         }
         else
         {
diff --git a/src/fvOptions/sources/derived/jouleHeatingSource/jouleHeatingSource.H b/src/fvOptions/sources/derived/jouleHeatingSource/jouleHeatingSource.H
index 4842cfa1edc8dc1526662317f1727d7f4ec6b994..02e003975f5fc83fb399c33144c8d310a1a06922 100644
--- a/src/fvOptions/sources/derived/jouleHeatingSource/jouleHeatingSource.H
+++ b/src/fvOptions/sources/derived/jouleHeatingSource/jouleHeatingSource.H
@@ -91,15 +91,9 @@ Usage
 
         coordinateSystem
         {
-            type        cartesian;
-            origin      (0 0 0);
-
-            coordinateRotation
-            {
-                type        axesRotation;
-                e1          (1 0 0);
-                e3          (0 0 1);
-            }
+            origin  (0 0 0);
+            e1      (1 0 0);
+            e3      (0 0 1);
         }
 
         // Optionally specify sigma as a function of temperature
@@ -179,8 +173,8 @@ class jouleHeatingSource
         //- Electrical conductivity as a vector function of temperature
         autoPtr<Function1<vector>> vectorSigmaVsTPtr_;
 
-        //- Co-ordinate system - used for vectorial electrical conductivity
-        autoPtr<coordinateSystem> coordSysPtr_;
+        //- Coordinate system - used for vectorial electrical conductivity
+        autoPtr<coordinateSystem> csysPtr_;
 
         //- Current time index (used for updating)
         label curTimeIndex_;
@@ -194,9 +188,8 @@ class jouleHeatingSource
         //- No copy assignment
         void operator=(const jouleHeatingSource&) = delete;
 
-        //- Return the co-ordinate system for anisotropic electrical
-        //  conductivity
-        const coordinateSystem& coordSys() const;
+        //- The coordinate system for anisotropic electrical conductivity
+        const coordinateSystem& csys() const;
 
         //- Transform the anisotropic electrical conductivity into global system
         tmp<volSymmTensorField> transformSigma
diff --git a/src/fvOptions/sources/derived/rotorDiskSource/rotorDiskSource.C b/src/fvOptions/sources/derived/rotorDiskSource/rotorDiskSource.C
index 851cc93315e2d9a8d1574b577161871d4b028f78..77c13c70d9bf7ce29eccfe03d9b8c4645d4ac399 100644
--- a/src/fvOptions/sources/derived/rotorDiskSource/rotorDiskSource.C
+++ b/src/fvOptions/sources/derived/rotorDiskSource/rotorDiskSource.C
@@ -91,7 +91,7 @@ void Foam::fv::rotorDiskSource::checkData()
                 case ifSurfaceNormal:
                 {
                     scalar UIn(coeffs_.get<scalar>("inletNormalVelocity"));
-                    inletVelocity_ = -coordSys_.R().e3()*UIn;
+                    inletVelocity_ = -coordSys_.e3()*UIn;
                     break;
                 }
                 case ifLocal:
@@ -333,17 +333,6 @@ void Foam::fv::rotorDiskSource::createCoordinateSystem()
 
             coeffs_.readEntry("refDirection", refDir);
 
-            cylindrical_.reset
-            (
-                new cylindrical
-                (
-                    mesh_,
-                    axis,
-                    origin,
-                    cells_
-                )
-            );
-
             // Set the face areas and apply correction to calculated axis
             // e.g. if cellZone is more than a single layer in thickness
             setFaceArea(axis, true);
@@ -356,17 +345,6 @@ void Foam::fv::rotorDiskSource::createCoordinateSystem()
             coeffs_.readEntry("axis", axis);
             coeffs_.readEntry("refDirection", refDir);
 
-            cylindrical_.reset
-            (
-                new cylindrical
-                (
-                    mesh_,
-                    axis,
-                    origin,
-                    cells_
-                )
-            );
-
             setFaceArea(axis, false);
 
             break;
@@ -381,7 +359,7 @@ void Foam::fv::rotorDiskSource::createCoordinateSystem()
         }
     }
 
-    coordSys_ = cylindricalCS("rotorCoordSys", origin, axis, refDir, false);
+    coordSys_ = coordSystem::cylindrical(origin, axis, refDir);
 
     const scalar sumArea = gSum(area_);
     const scalar diameter = Foam::sqrt(4.0*sumArea/mathematical::pi);
@@ -389,24 +367,25 @@ void Foam::fv::rotorDiskSource::createCoordinateSystem()
         << "    - disk diameter = " << diameter << nl
         << "    - disk area     = " << sumArea << nl
         << "    - origin        = " << coordSys_.origin() << nl
-        << "    - r-axis        = " << coordSys_.R().e1() << nl
-        << "    - psi-axis      = " << coordSys_.R().e2() << nl
-        << "    - z-axis        = " << coordSys_.R().e3() << endl;
+        << "    - r-axis        = " << coordSys_.e1() << nl
+        << "    - psi-axis      = " << coordSys_.e2() << nl
+        << "    - z-axis        = " << coordSys_.e3() << endl;
 }
 
 
 void Foam::fv::rotorDiskSource::constructGeometry()
 {
-    const vectorField& C = mesh_.C();
+    const pointUIndList cc(mesh_.C(), cells_);
+
+    // Optional: for later transform(), invTransform()
+    /// Rcyl_.reset(coordSys_.R(cc).ptr());
 
     forAll(cells_, i)
     {
         if (area_[i] > ROOTVSMALL)
         {
-            const label celli = cells_[i];
-
             // Position in (planar) rotor coordinate system
-            x_[i] = coordSys_.localPosition(C[celli]);
+            x_[i] = coordSys_.localPosition(cc[i]);
 
             // Cache max radius
             rMax_ = max(rMax_, x_[i].x());
@@ -422,8 +401,7 @@ void Foam::fv::rotorDiskSource::constructGeometry()
             // rotor cone system
             scalar c = cos(beta);
             scalar s = sin(beta);
-            R_[i] = tensor(c, 0, -s, 0, 1, 0, s, 0, c);
-            invR_[i] = R_[i].T();
+            Rcone_[i] = tensor(c, 0, -s, 0, 1, 0, s, 0, c);
         }
     }
 }
@@ -480,11 +458,9 @@ Foam::fv::rotorDiskSource::rotorDiskSource
     tipEffect_(1.0),
     flap_(),
     x_(cells_.size(), Zero),
-    R_(cells_.size(), I),
-    invR_(cells_.size(), I),
-    area_(cells_.size(), 0.0),
-    coordSys_(false),
-    cylindrical_(),
+    Rcone_(cells_.size(), I),
+    area_(cells_.size(), Zero),
+    coordSys_(),
     rMax_(0.0),
     trim_(trimModel::New(*this, coeffs_)),
     blade_(coeffs_.subDict("blade")),
diff --git a/src/fvOptions/sources/derived/rotorDiskSource/rotorDiskSource.H b/src/fvOptions/sources/derived/rotorDiskSource/rotorDiskSource.H
index 611a26b77534a7d9858ba671de6d5eb7591a68cf..9a607d7c045f4fe33db6585b9aa6b0506404cc32 100644
--- a/src/fvOptions/sources/derived/rotorDiskSource/rotorDiskSource.H
+++ b/src/fvOptions/sources/derived/rotorDiskSource/rotorDiskSource.H
@@ -102,7 +102,6 @@ SourceFiles
 
 #include "cellSetOption.H"
 #include "cylindricalCS.H"
-#include "cylindrical.H"
 #include "Enum.H"
 #include "bladeModel.H"
 #include "profileModelList.H"
@@ -184,23 +183,20 @@ protected:
         flapData flap_;
 
         //- Cell centre positions in local rotor frame
-        //  (Cylindrical r, theta, z)
+        //  (Cylindrical r-theta-z)
         List<point> x_;
 
         //- Rotation tensor for flap angle
-        List<tensor> R_;
-
-        //- Inverse rotation tensor for flap angle
-        List<tensor> invR_;
+        List<tensor> Rcone_;
 
         //- Area [m2]
         List<scalar> area_;
 
-        //- Rotor local cylindrical coordinate system (r, theta, z)
-        cylindricalCS coordSys_;
+        //- Rotor local cylindrical coordinate system (r-theta-z)
+        coordSystem::cylindrical coordSys_;
 
-        //- Rotor transformation coordinate system
-        autoPtr<cylindrical> cylindrical_;
+        //- Cached rotation tensors for cylindrical coordinates
+        autoPtr<tensorField> Rcyl_;
 
         //- Maximum radius
         scalar rMax_;
@@ -276,11 +272,11 @@ public:
             inline scalar omega() const;
 
             //- Return the cell centre positions in local rotor frame
-            // (Cylindrical r, theta, z)
+            //  (Cylindrical r-theta-z)
             inline const List<point>& x() const;
 
-            //- Return the rotor coordinate system (r, theta, z)
-            inline const cylindricalCS& coordSys() const;
+            //- Return the rotor coordinate system (r-theta-z)
+            inline const coordSystem::cylindrical& coordSys() const;
 
 
         // Evaluation
diff --git a/src/fvOptions/sources/derived/rotorDiskSource/rotorDiskSourceI.H b/src/fvOptions/sources/derived/rotorDiskSource/rotorDiskSourceI.H
index e923790514390a98f8670493d6f183a127f7df92..2e8a4581b4901e1680e7cdd4a6ed6cf6c999c3ee 100644
--- a/src/fvOptions/sources/derived/rotorDiskSource/rotorDiskSourceI.H
+++ b/src/fvOptions/sources/derived/rotorDiskSource/rotorDiskSourceI.H
@@ -27,25 +27,26 @@ License
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-Foam::scalar Foam::fv::rotorDiskSource::rhoRef() const
+inline Foam::scalar Foam::fv::rotorDiskSource::rhoRef() const
 {
     return rhoRef_;
 }
 
 
-Foam::scalar Foam::fv::rotorDiskSource::omega() const
+inline Foam::scalar Foam::fv::rotorDiskSource::omega() const
 {
     return omega_;
 }
 
 
-const Foam::List<Foam::point>& Foam::fv::rotorDiskSource::x() const
+inline const Foam::List<Foam::point>& Foam::fv::rotorDiskSource::x() const
 {
     return x_;
 }
 
 
-const Foam::cylindricalCS& Foam::fv::rotorDiskSource::coordSys() const
+inline const Foam::coordSystem::cylindrical&
+Foam::fv::rotorDiskSource::coordSys() const
 {
     return coordSys_;
 }
diff --git a/src/fvOptions/sources/derived/rotorDiskSource/rotorDiskSourceTemplates.C b/src/fvOptions/sources/derived/rotorDiskSource/rotorDiskSourceTemplates.C
index bcec1750a039d1bc2d7e6bf1fe6904096ec1d905..89eabc7fa6fcb0a9a363c5f11a90bc01761ff8b5 100644
--- a/src/fvOptions/sources/derived/rotorDiskSource/rotorDiskSourceTemplates.C
+++ b/src/fvOptions/sources/derived/rotorDiskSource/rotorDiskSourceTemplates.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2018 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -50,6 +50,9 @@ void Foam::fv::rotorDiskSource::calculate
     scalar AOAmin = GREAT;
     scalar AOAmax = -GREAT;
 
+    // Cached position-dependent rotations available?
+    const bool hasCache = Rcyl_.valid();
+
     forAll(cells_, i)
     {
         if (area_[i] > ROOTVSMALL)
@@ -58,11 +61,18 @@ void Foam::fv::rotorDiskSource::calculate
 
             const scalar radius = x_[i].x();
 
+            const tensor Rcyl =
+            (
+                hasCache
+              ? (*Rcyl_)[i]
+              : coordSys_.R(mesh_.C()[celli])
+            );
+
             // Transform velocity into local cylindrical reference frame
-            vector Uc = cylindrical_->invTransform(U[celli], i);
+            vector Uc = invTransform(Rcyl, U[celli]);
 
             // Transform velocity into local coning system
-            Uc = R_[i] & Uc;
+            Uc = transform(Rcone_[i], Uc);
 
             // Set radial component of velocity to zero
             Uc.x() = 0.0;
@@ -129,10 +139,10 @@ void Foam::fv::rotorDiskSource::calculate
             liftEff += rhoRef_*localForce.z();
 
             // Transform force from local coning system into rotor cylindrical
-            localForce = invR_[i] & localForce;
+            localForce = invTransform(Rcone_[i], localForce);
 
-            // Transform force into global Cartesian co-ordinate system
-            force[celli] = cylindrical_->transform(localForce, i);
+            // Transform force into global Cartesian coordinate system
+            force[celli] = transform(Rcyl, localForce);
 
             if (divideVolume)
             {
diff --git a/src/fvOptions/sources/derived/rotorDiskSource/trimModel/targetCoeff/targetCoeffTrim.C b/src/fvOptions/sources/derived/rotorDiskSource/trimModel/targetCoeff/targetCoeffTrim.C
index bfc457b95f43a71a53b115d2e010fd159a8e2700..fd2d7a82ed37e2da1b81835c08281ffde4403239 100644
--- a/src/fvOptions/sources/derived/rotorDiskSource/trimModel/targetCoeff/targetCoeffTrim.C
+++ b/src/fvOptions/sources/derived/rotorDiskSource/trimModel/targetCoeff/targetCoeffTrim.C
@@ -57,9 +57,9 @@ Foam::vector Foam::targetCoeffTrim::calcCoeffs
     const List<point>& x = rotor_.x();
 
     const vector& origin = rotor_.coordSys().origin();
-    const vector& rollAxis = rotor_.coordSys().R().e1();
-    const vector& pitchAxis = rotor_.coordSys().R().e2();
-    const vector& yawAxis = rotor_.coordSys().R().e3();
+    const vector& rollAxis = rotor_.coordSys().e1();
+    const vector& pitchAxis = rotor_.coordSys().e2();
+    const vector& yawAxis = rotor_.coordSys().e3();
 
     scalar coeff1 = alpha_*sqr(rotor_.omega())*mathematical::pi;
 
diff --git a/src/fvOptions/sources/interRegion/interRegionExplicitPorositySource/interRegionExplicitPorositySource.H b/src/fvOptions/sources/interRegion/interRegionExplicitPorositySource/interRegionExplicitPorositySource.H
index c8d7602a7f80323665c642f324d9b45ca4b505ef..2946c9801f1e69c76ec65d84d82b7e02233ce85b 100644
--- a/src/fvOptions/sources/interRegion/interRegionExplicitPorositySource/interRegionExplicitPorositySource.H
+++ b/src/fvOptions/sources/interRegion/interRegionExplicitPorositySource/interRegionExplicitPorositySource.H
@@ -43,13 +43,9 @@ Description
 
             coordinateSystem
             {
-                origin      (0 0 0);
-                coordinateRotation
-                {
-                    type axesRotation;
-                    e1  (0.70710678 0.70710678 0);
-                    e2  (0 0 1);
-                }
+                origin  (0 0 0);
+                e1      (0.70710678 0.70710678 0);
+                e2      (0 0 1);
             }
         }
     }
diff --git a/src/lagrangian/basic/injectedParticle/injectedParticleIO.C b/src/lagrangian/basic/injectedParticle/injectedParticleIO.C
index 9c5842682bbff1e50a4dbb2530b4aea301e0eb68..4fa325b9e4c5902e89d7f97db5e8ff9d964348fc 100644
--- a/src/lagrangian/basic/injectedParticle/injectedParticleIO.C
+++ b/src/lagrangian/basic/injectedParticle/injectedParticleIO.C
@@ -63,7 +63,7 @@ Foam::injectedParticle::injectedParticle
     if (readFields)
     {
         // After the base particle class has read the fields from file and
-        // constructed the necessary barycentric co-ordinates we can update the
+        // constructed the necessary barycentric coordinates we can update the
         // particle position on this mesh
         position_ = particle::position();
 
diff --git a/src/lagrangian/intermediate/submodels/CloudFunctionObjects/ParticleCollector/ParticleCollector.C b/src/lagrangian/intermediate/submodels/CloudFunctionObjects/ParticleCollector/ParticleCollector.C
index 988eca02c4e8ec75d98c06b3e1dde66da9804766..593da8386652672e9ad28aed16b36781b86f4351 100644
--- a/src/lagrangian/intermediate/submodels/CloudFunctionObjects/ParticleCollector/ParticleCollector.C
+++ b/src/lagrangian/intermediate/submodels/CloudFunctionObjects/ParticleCollector/ParticleCollector.C
@@ -207,7 +207,7 @@ void Foam::ParticleCollector<CloudType>::initConcentricCircles()
     faces_.setSize(nFace);
     area_.setSize(nFace);
 
-    coordSys_ = cylindricalCS("coordSys", origin, normal_[0], refDir, false);
+    coordSys_ = coordSystem::cylindrical(origin, normal_[0], refDir);
 
     List<label> ptIDs(identity(nPointPerRadius));
 
@@ -356,7 +356,7 @@ void Foam::ParticleCollector<CloudType>::collectParcelConcentricCircles
         return;
     }
 
-    // Intersection point in cylindrical co-ordinate system
+    // Intersection point in cylindrical coordinate system
     const point pCyl = coordSys_.localPosition(p1 + (d1/(d1 - d2))*(p2 - p1));
 
     scalar r = pCyl[0];
@@ -539,7 +539,7 @@ Foam::ParticleCollector<CloudType>::ParticleCollector
     faceTris_(),
     nSector_(0),
     radius_(),
-    coordSys_(false),
+    coordSys_(),
     normal_(),
     negateParcelsOppositeNormal_
     (
diff --git a/src/lagrangian/intermediate/submodels/CloudFunctionObjects/ParticleCollector/ParticleCollector.H b/src/lagrangian/intermediate/submodels/CloudFunctionObjects/ParticleCollector/ParticleCollector.H
index 12a13129ecb06b9178b24ec0ed2a8ff125e04123..3dfedad22215e42c6331fe4f4e248c8a3780f450 100644
--- a/src/lagrangian/intermediate/submodels/CloudFunctionObjects/ParticleCollector/ParticleCollector.H
+++ b/src/lagrangian/intermediate/submodels/CloudFunctionObjects/ParticleCollector/ParticleCollector.H
@@ -160,8 +160,8 @@ private:
             //- List of radii
             List<scalar> radius_;
 
-            //- Cylindrical co-ordinate system
-            cylindricalCS coordSys_;
+            //- Cylindrical coordinate system
+            coordSystem::cylindrical coordSys_;
 
 
         //- Face areas
diff --git a/src/lagrangian/intermediate/submodels/Kinematic/InjectionModel/KinematicLookupTableInjection/KinematicLookupTableInjection.H b/src/lagrangian/intermediate/submodels/Kinematic/InjectionModel/KinematicLookupTableInjection/KinematicLookupTableInjection.H
index 343e46dc1e505080b9e66bc706338702ed28cd5a..18ae20461aa604c7f6a36ca2e8c50561cbf58f76 100644
--- a/src/lagrangian/intermediate/submodels/Kinematic/InjectionModel/KinematicLookupTableInjection/KinematicLookupTableInjection.H
+++ b/src/lagrangian/intermediate/submodels/Kinematic/InjectionModel/KinematicLookupTableInjection/KinematicLookupTableInjection.H
@@ -42,7 +42,7 @@ Description
 
     where:
     \plaintable
-        x, y, z | global cartesian co-ordinates [m]
+        x, y, z | global cartesian coordinates [m]
         u, v, w | global cartesian velocity components [m/s]
         d       | diameter [m]
         rho     | density [kg/m3]
diff --git a/src/lagrangian/intermediate/submodels/Reacting/InjectionModel/ReactingLookupTableInjection/ReactingLookupTableInjection.H b/src/lagrangian/intermediate/submodels/Reacting/InjectionModel/ReactingLookupTableInjection/ReactingLookupTableInjection.H
index dfe38af74cb04d9cb4e7c23b8d3c08531148e2db..152d5fe9529d47e607e65b5cb759eb0d6c2cb42b 100644
--- a/src/lagrangian/intermediate/submodels/Reacting/InjectionModel/ReactingLookupTableInjection/ReactingLookupTableInjection.H
+++ b/src/lagrangian/intermediate/submodels/Reacting/InjectionModel/ReactingLookupTableInjection/ReactingLookupTableInjection.H
@@ -39,7 +39,7 @@ Description
     );
 
     where:
-        x, y, z = global cartesian co-ordinates [m]
+        x, y, z = global cartesian coordinates [m]
         u, v, w = global cartesian velocity components [m/s]
         d       = diameter [m]
         rho     = density [kg/m3]
diff --git a/src/lagrangian/intermediate/submodels/ReactingMultiphase/InjectionModel/ReactingMultiphaseLookupTableInjection/ReactingMultiphaseLookupTableInjection.H b/src/lagrangian/intermediate/submodels/ReactingMultiphase/InjectionModel/ReactingMultiphaseLookupTableInjection/ReactingMultiphaseLookupTableInjection.H
index 2541f65755f9a0ec90e2e8f183cf171485817999..e02579fb8dee5a71083dada913e48f7d30d68e97 100644
--- a/src/lagrangian/intermediate/submodels/ReactingMultiphase/InjectionModel/ReactingMultiphaseLookupTableInjection/ReactingMultiphaseLookupTableInjection.H
+++ b/src/lagrangian/intermediate/submodels/ReactingMultiphase/InjectionModel/ReactingMultiphaseLookupTableInjection/ReactingMultiphaseLookupTableInjection.H
@@ -39,7 +39,7 @@ Description
     );
 
     where:
-        x, y, z  = global cartesian co-ordinates [m]
+        x, y, z  = global cartesian coordinates [m]
         u, v, w  = global cartesian velocity components [m/s]
         d        = diameter [m]
         rho      = density [kg/m3]
diff --git a/src/lagrangian/intermediate/submodels/Thermodynamic/InjectionModel/ThermoLookupTableInjection/ThermoLookupTableInjection.H b/src/lagrangian/intermediate/submodels/Thermodynamic/InjectionModel/ThermoLookupTableInjection/ThermoLookupTableInjection.H
index 7ef9b9227ca380ca92a0fdcf8f38edae8f841680..8c312b8eabe54852db0650d786358ff39cc0d357 100644
--- a/src/lagrangian/intermediate/submodels/Thermodynamic/InjectionModel/ThermoLookupTableInjection/ThermoLookupTableInjection.H
+++ b/src/lagrangian/intermediate/submodels/Thermodynamic/InjectionModel/ThermoLookupTableInjection/ThermoLookupTableInjection.H
@@ -39,7 +39,7 @@ Description
     );
 
     where:
-        x, y, z = global cartesian co-ordinates [m]
+        x, y, z = global cartesian coordinates [m]
         u, v, w = global cartesian velocity components [m/s]
         d       = diameter [m]
         rho     = density [kg/m3]
diff --git a/src/lumpedPointMotion/lumpedPointStateWriter.C b/src/lumpedPointMotion/lumpedPointStateWriter.C
index 22ad1b893c879474f29533a747babf45eb9c50f5..2340d0876180db9778822da08f2f7c44fea8f85c 100644
--- a/src/lumpedPointMotion/lumpedPointStateWriter.C
+++ b/src/lumpedPointMotion/lumpedPointStateWriter.C
@@ -26,7 +26,7 @@ License
 #include "lumpedPointState.H"
 #include "OFstream.H"
 #include "axesRotation.H"
-
+#include "coordinateSystem.H"
 #include "foamVtkOutput.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@@ -183,14 +183,17 @@ void Foam::lumpedPointState::writeVTP
     }
 
     // Standard corners in local axis
-    const axesRotation cornerTransform(axis);
-
     FixedList<point, 4> corners;
-    forAll(standardCorners, corni)
+
     {
-        corners[corni] = cornerTransform.transform(standardCorners[corni]);
-    }
+        coordinateRotations::axes orient(axis);
+        coordinateSystem cornerTransform(orient);
 
+        forAll(standardCorners, corni)
+        {
+            corners[corni] = cornerTransform.transform(standardCorners[corni]);
+        }
+    }
 
     //
     // Planes to visualize location/rotation
diff --git a/src/mesh/blockMesh/blockEdges/arcEdge/arcEdge.C b/src/mesh/blockMesh/blockEdges/arcEdge/arcEdge.C
index 0de1a2f906f4875472137f64af4d23ca3c3e74f9..ec5519f56d1d8f80617685a956ef103a06dd5563 100644
--- a/src/mesh/blockMesh/blockEdges/arcEdge/arcEdge.C
+++ b/src/mesh/blockMesh/blockEdges/arcEdge/arcEdge.C
@@ -41,7 +41,7 @@ namespace blockEdges
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
-Foam::cylindricalCS Foam::blockEdges::arcEdge::calcAngle()
+Foam::coordSystem::cylindrical Foam::blockEdges::arcEdge::calcAngle()
 {
     const vector a = p2_ - p1_;
     const vector b = p3_ - p1_;
@@ -98,8 +98,8 @@ Foam::cylindricalCS Foam::blockEdges::arcEdge::calcAngle()
 
     radius_ = mag(r3);
 
-    // The corresponding local cylindrical coordinate system (degrees)
-    return cylindricalCS("arcEdgeCS", centre, arcAxis, r1, true);
+    // The corresponding local cylindrical coordinate system (radians)
+    return coordSystem::cylindrical("arc", centre, arcAxis, r1);
 }
 
 
@@ -158,13 +158,14 @@ Foam::point Foam::blockEdges::arcEdge::position(const scalar lambda) const
         return p3_;
     }
 
-    return cs_.globalPosition(vector(radius_, lambda*angle_, 0.0));
+    // The angle is degrees, the coordinate system in radians
+    return cs_.globalPosition(vector(radius_, degToRad(lambda*angle_), 0));
 }
 
 
 Foam::scalar Foam::blockEdges::arcEdge::length() const
 {
-    return degToRad(angle_*radius_);
+    return degToRad(radius_*angle_);
 }
 
 
diff --git a/src/mesh/blockMesh/blockEdges/arcEdge/arcEdge.H b/src/mesh/blockMesh/blockEdges/arcEdge/arcEdge.H
index 3b1062ea96737efcb972d7bf15923013b58fe6da..267795a30069dff03b30cc0c234effe3b1b03711 100644
--- a/src/mesh/blockMesh/blockEdges/arcEdge/arcEdge.H
+++ b/src/mesh/blockMesh/blockEdges/arcEdge/arcEdge.H
@@ -64,15 +64,15 @@ class arcEdge
         //- The arc radius
         scalar radius_;
 
-        //- The local cylindrical coordinate system (degrees)
-        cylindricalCS cs_;
+        //- The local cylindrical coordinate system
+        coordSystem::cylindrical cs_;
 
 
     // Private Member Functions
 
         //- Calculate the angle, radius and axis
-        //  \return the coordinate system
-        cylindricalCS calcAngle();
+        //  \return the cylindrical coordinate system
+        coordSystem::cylindrical calcAngle();
 
         //- No copy construct
         arcEdge(const arcEdge&) = delete;
diff --git a/src/meshTools/Make/files b/src/meshTools/Make/files
index 83d30309b7c0e6a0aa61c7377ebbc8f2d4bbae15..1759739ff91fbda6d589e89bb9d7b9a7bacc316c 100644
--- a/src/meshTools/Make/files
+++ b/src/meshTools/Make/files
@@ -59,17 +59,20 @@ cellFeatures/cellFeatures.C
 csys = coordinate/systems
 $(csys)/coordinateSystem.C
 $(csys)/coordinateSystemNew.C
+$(csys)/coordinateSystemTransform.C
 $(csys)/coordinateSystems.C
-$(csys)/cylindricalCS.C
 $(csys)/cartesianCS.C
+$(csys)/cylindricalCS.C
+$(csys)/indirectCS.C
 
 crot = coordinate/rotation
 $(crot)/axesRotation.C
+$(crot)/axisAngleRotation.C
 $(crot)/coordinateRotation.C
-$(crot)/coordinateRotationNew.C
+$(crot)/cylindricalRotation.C
+$(crot)/identityRotation.C
 $(crot)/EulerCoordinateRotation.C
 $(crot)/STARCDCoordinateRotation.C
-$(crot)/cylindrical.C
 
 polyMeshZipUpCells/polyMeshZipUpCells.C
 primitiveMeshGeometry/primitiveMeshGeometry.C
diff --git a/src/meshTools/coordinate/rotation/EulerCoordinateRotation.C b/src/meshTools/coordinate/rotation/EulerCoordinateRotation.C
index 495adc57d01a358373b96d567e823da0f48fe5c9..d9f76803aeb366a81f368dde32416b18918f9736 100644
--- a/src/meshTools/coordinate/rotation/EulerCoordinateRotation.C
+++ b/src/meshTools/coordinate/rotation/EulerCoordinateRotation.C
@@ -31,24 +31,34 @@ License
 
 namespace Foam
 {
-    defineTypeNameAndDebug(EulerCoordinateRotation, 0);
-    addToRunTimeSelectionTable
-    (
-        coordinateRotation,
-        EulerCoordinateRotation,
-        dictionary
-    );
-    addToRunTimeSelectionTable
-    (
-        coordinateRotation,
-        EulerCoordinateRotation,
-        objectRegistry
-    );
+    namespace coordinateRotations
+    {
+        defineTypeName(euler);
+
+        // Standard short name
+        addNamedToRunTimeSelectionTable
+        (
+            coordinateRotation,
+            euler,
+            dictionary,
+            euler
+        );
+
+        // Longer name - Compat 1806
+        addNamedToRunTimeSelectionTable
+        (
+            coordinateRotation,
+            euler,
+            dictionary,
+            EulerRotation
+        );
+    }
 }
 
+
 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
 
-Foam::tensor Foam::EulerCoordinateRotation::rotation
+Foam::tensor Foam::coordinateRotations::euler::rotation
 (
     const vector& angles,
     bool degrees
@@ -84,174 +94,96 @@ Foam::tensor Foam::EulerCoordinateRotation::rotation
 }
 
 
-// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-Foam::vector Foam::EulerCoordinateRotation::transform(const vector& st) const
-{
-    return (R_ & st);
-}
+Foam::coordinateRotations::euler::euler()
+:
+    coordinateRotation(),
+    angles_(Zero),
+    degrees_(true)
+{}
 
 
-Foam::vector Foam::EulerCoordinateRotation::invTransform
-(
-    const vector& st
-) const
-{
-    return (Rtr_ & st);
-}
+Foam::coordinateRotations::euler::euler(const euler& crot)
+:
+    coordinateRotation(crot),
+    angles_(crot.angles_),
+    degrees_(crot.degrees_)
+{}
 
 
-Foam::tmp<Foam::vectorField> Foam::EulerCoordinateRotation::transform
+Foam::coordinateRotations::euler::euler
 (
-    const vectorField& st
-) const
-{
-    NotImplemented;
-    return nullptr;
-}
+    const vector& phiThetaPsi,
+    bool degrees
+)
+:
+    coordinateRotation(),
+    angles_(phiThetaPsi),
+    degrees_(degrees)
+{}
 
 
-Foam::tmp<Foam::vectorField> Foam::EulerCoordinateRotation::invTransform
+Foam::coordinateRotations::euler::euler
 (
-    const vectorField& st
-) const
-{
-    NotImplemented;
-    return nullptr;
-}
+    scalar phi,
+    scalar theta,
+    scalar psi,
+    bool degrees
+)
+:
+    coordinateRotation(),
+    angles_(phi, theta, psi),
+    degrees_(degrees)
+{}
 
 
-const Foam::tensorField& Foam::EulerCoordinateRotation::Tr() const
-{
-    NotImplemented;
-    return NullObjectRef<tensorField>();
-}
+Foam::coordinateRotations::euler::euler(const dictionary& dict)
+:
+    coordinateRotation(),
+    angles_(dict.getCompat<vector>("angles", {{"rotation", 1806}})),
+    degrees_(dict.lookupOrDefault("degrees", true))
+{}
 
 
-Foam::tmp<Foam::tensorField> Foam::EulerCoordinateRotation::transformTensor
-(
-    const tensorField& st
-) const
+// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
+
+void Foam::coordinateRotations::euler::clear()
 {
-    NotImplemented;
-    return nullptr;
+    angles_ = Zero;
+    degrees_ = true;
 }
 
 
-Foam::tensor Foam::EulerCoordinateRotation::transformTensor
-(
-    const tensor& st
-) const
+Foam::tensor Foam::coordinateRotations::euler::R() const
 {
-    return (R_ & st & Rtr_);
+    return euler::rotation(angles_, degrees_);
 }
 
 
-Foam::tmp<Foam::tensorField> Foam::EulerCoordinateRotation::transformTensor
-(
-    const tensorField& st,
-    const labelList& cellMap
-) const
+void Foam::coordinateRotations::euler::write(Ostream& os) const
 {
-    NotImplemented;
-    return nullptr;
+    os  << "euler-angles(" << (degrees_ ? "deg" : "rad") << "): " << angles_;
 }
 
 
-Foam::tmp<Foam::symmTensorField> Foam::EulerCoordinateRotation::
-transformVector
+void Foam::coordinateRotations::euler::writeEntry
 (
-    const vectorField& st
+    const word& keyword,
+    Ostream& os
 ) const
 {
-    tmp<symmTensorField> tfld(new symmTensorField(st.size()));
-    symmTensorField& fld = tfld.ref();
+    os.beginBlock(keyword);
 
-    forAll(fld, i)
+    os.writeEntry("type", type());
+    os.writeEntry("angles", angles_);
+    if (!degrees_)
     {
-        fld[i] = transformPrincipal(R_, st[i]);
+        os.writeEntry("degrees", "false");
     }
-    return tfld;
-}
 
-
-Foam::symmTensor Foam::EulerCoordinateRotation::transformVector
-(
-    const vector& st
-) const
-{
-    return transformPrincipal(R_, st);
+    os.endBlock();
 }
 
 
-// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
-
-Foam::EulerCoordinateRotation::EulerCoordinateRotation()
-:
-    R_(sphericalTensor::I),
-    Rtr_(sphericalTensor::I)
-{}
-
-
-Foam::EulerCoordinateRotation::EulerCoordinateRotation
-(
-    const EulerCoordinateRotation& r
-)
-:
-    R_(r.R_),
-    Rtr_(r.Rtr_)
-{}
-
-
-Foam::EulerCoordinateRotation::EulerCoordinateRotation
-(
-    const vector& phiThetaPsi,
-    const bool degrees
-)
-:
-    R_(rotation(phiThetaPsi, degrees)),
-    Rtr_(R_.T())
-{}
-
-
-Foam::EulerCoordinateRotation::EulerCoordinateRotation
-(
-    const scalar phi,
-    const scalar theta,
-    const scalar psi,
-    const bool degrees
-)
-:
-    R_(rotation(vector(phi, theta, psi), degrees)),
-    Rtr_(R_.T())
-{}
-
-
-Foam::EulerCoordinateRotation::EulerCoordinateRotation
-(
-    const dictionary& dict
-)
-:
-    R_
-    (
-        rotation
-        (
-            dict.get<vector>("rotation"),
-            dict.lookupOrDefault("degrees", true)
-        )
-    ),
-    Rtr_(R_.T())
-{}
-
-
-Foam::EulerCoordinateRotation::EulerCoordinateRotation
-(
-    const dictionary& dict,
-    const objectRegistry&
-)
-:
-    EulerCoordinateRotation(dict)
-{}
-
-
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/src/meshTools/coordinate/rotation/EulerCoordinateRotation.H b/src/meshTools/coordinate/rotation/EulerCoordinateRotation.H
index 4a60558ff54ad89b32708731f0b354564644c866..e30529a53df667d8de4c926d031c0bc5e7463a32 100644
--- a/src/meshTools/coordinate/rotation/EulerCoordinateRotation.H
+++ b/src/meshTools/coordinate/rotation/EulerCoordinateRotation.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2017 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2017 OpenCFD Ltd.
+     \\/     M anipulation  | Copyright (C) 2017-2018 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -22,7 +22,7 @@ License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
 Class
-    Foam::EulerCoordinateRotation
+    Foam::coordinateRotations::euler
 
 Description
     A coordinateRotation defined in the z-x-z (intrinsic) Euler convention.
@@ -34,24 +34,29 @@ Description
     For reference and illustration, see
     https://en.wikipedia.org/wiki/Euler_angles
 
-    The rotation angles are in degrees, unless otherwise explicitly specified:
-
     \verbatim
     coordinateRotation
     {
-        type        EulerRotation;
-        degrees     false;
-        rotation    (0 0 3.141592654);
+        type    euler;
+        angles  (0 0 180);
     }
     \endverbatim
 
+    \heading Dictionary entries
+    \table
+        Property    | Description                           | Required | Default
+        type        | Type name: euler (or EulerRotation)   | yes   |
+        angles      | The z-x-z rotation angles             | yes   |
+        degrees     | Angles are in degrees                 | no    | true
+    \endtable
+
 SourceFiles
     EulerCoordinateRotation.C
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef EulerCoordinateRotation_H
-#define EulerCoordinateRotation_H
+#ifndef coordinateRotations_euler_H
+#define coordinateRotations_euler_H
 
 #include "coordinateRotation.H"
 
@@ -59,73 +64,62 @@ SourceFiles
 
 namespace Foam
 {
+namespace coordinateRotations
+{
 
 /*---------------------------------------------------------------------------*\
-                   Class EulerCoordinateRotation Declaration
+                 Class coordinateRotations::euler Declaration
 \*---------------------------------------------------------------------------*/
 
-class EulerCoordinateRotation
+class euler
 :
     public coordinateRotation
 {
-    // Private Member Data
+    // Private Data
 
-        //- Local-to-global transformation tensor
-        tensor R_;
+        //- The rotation angles
+        vector angles_;
 
-        //- Global-to-Local transformation tensor
-        tensor Rtr_;
+        //- Angles measured in degrees
+        bool degrees_;
 
 
 public:
 
     //- Runtime type information
-    TypeName("EulerRotation");
+    TypeNameNoDebug("euler");
 
 
     // Constructors
 
-        //- Construct null
-        EulerCoordinateRotation();
+        //- Construct null - an identity transform
+        euler();
 
-        //- Construct as copy
-        EulerCoordinateRotation(const EulerCoordinateRotation& r);
+        //- Copy construct
+        euler(const euler& crot);
 
-        //- Construct from rotation vector
-        EulerCoordinateRotation
-        (
-            const vector& phiThetaPsi,
-            const bool degrees
-        );
+        //- Construct from Euler rotation angles (z-x-z)
+        euler(const vector& phiThetaPsi, bool degrees);
 
-        //- Construct from components of rotation vector
-        EulerCoordinateRotation
-        (
-            const scalar phi,
-            const scalar theta,
-            const scalar psi,
-            const bool degrees
-        );
+        //- Construct from Euler rotation angles (z-x-z)
+        euler(scalar phi, scalar theta, scalar psi, bool degrees);
 
         //- Construct from dictionary
-        explicit EulerCoordinateRotation(const dictionary& dict);
-
-        //- Construct from dictionary and a registry (typically a mesh)
-        EulerCoordinateRotation
-        (
-            const dictionary& dict,
-            const objectRegistry& unused
-        );
+        explicit euler(const dictionary& dict);
 
         //- Return clone
         autoPtr<coordinateRotation> clone() const
         {
             return
                 autoPtr<coordinateRotation>::NewFrom
-                <EulerCoordinateRotation>(*this);
+                <coordinateRotations::euler>(*this);
         }
 
 
+    //- Destructor
+    virtual ~euler() = default;
+
+
     // Static Member Functions
 
         //- The rotation tensor calculated for the specified Euler angles
@@ -135,90 +129,28 @@ public:
 
     // Member Functions
 
-        //- Reset rotation to an identity rotation
-        virtual void clear()
-        {
-            R_ = sphericalTensor::I;
-            Rtr_ = sphericalTensor::I;
-        }
-
-        //- Update the rotation for a list of cells
-        virtual void updateCells(const polyMesh&, const labelList&)
-        {}
+        //- Reset specification
+        virtual void clear();
 
-        //- Return local-to-global transformation tensor
-        virtual const tensor& R() const
-        {
-            return R_;
-        }
+        //- The rotation tensor calculated for the specified Euler angles.
+        virtual tensor R() const;
 
-        //- Return global-to-local transformation tensor
-        virtual const tensor& Rtr() const
-        {
-            return Rtr_;
-        };
+        //- Write information
+        virtual void write(Ostream& os) const;
 
-        //- Return local Cartesian x-axis in global coordinates
-        virtual const vector e1() const
-        {
-            return Rtr_.x();
-        }
+        //- Write dictionary entry
+        virtual void writeEntry(const word& keyword, Ostream& os) const;
 
-        //- Return local Cartesian y-axis in global coordinates
-        virtual const vector e2() const
-        {
-            return Rtr_.y();
-        }
-
-        //- Return local Cartesian z-axis in global coordinates
-        virtual const vector e3() const
-        {
-            return Rtr_.z();
-        }
-
-        //- Return transformation tensor field
-        virtual const tensorField& Tr() const;
-
-        //- Transform vectorField using transformation tensor field
-        virtual tmp<vectorField> transform(const vectorField& st) const;
-
-        //- Transform vector using transformation tensor
-        virtual vector transform(const vector& st) const;
-
-        //- Inverse transform vectorField using transformation tensor field
-        virtual tmp<vectorField> invTransform(const vectorField& st) const;
-
-        //- Inverse transform vector using transformation tensor
-        virtual vector invTransform(const vector& st) const;
-
-        //- Transform tensor field using transformation tensorField
-        virtual tmp<tensorField> transformTensor(const tensorField& st) const;
-
-        //- Transform tensor using transformation tensorField
-        virtual tensor transformTensor(const tensor& st) const;
-
-        //- Transform tensor sub-field using transformation tensorField
-        virtual tmp<tensorField> transformTensor
-        (
-            const tensorField& st,
-            const labelList& cellMap
-        ) const;
+};
 
-        //- Transform vectorField using transformation tensorField and return
-        // symmetrical tensorField
-        virtual tmp<symmTensorField> transformVector
-        (
-            const vectorField& st
-        ) const;
 
-        //- Transform vector using transformation tensor and return
-        // symmetrical tensor
-        virtual symmTensor transformVector(const vector& st) const;
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-};
+} // End namespace coordinateRotations
 
 
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+//- Compatibility typedef 1806
+typedef coordinateRotations::euler EulerCoordinateRotation;
 
 } // End namespace Foam
 
diff --git a/src/meshTools/coordinate/rotation/STARCDCoordinateRotation.C b/src/meshTools/coordinate/rotation/STARCDCoordinateRotation.C
index 00276ca92d46c714f7d3c5dd654ea886eac1c05b..0074ce3250acec7fd6f17a4f062aa1a2b1dcefc7 100644
--- a/src/meshTools/coordinate/rotation/STARCDCoordinateRotation.C
+++ b/src/meshTools/coordinate/rotation/STARCDCoordinateRotation.C
@@ -31,128 +31,37 @@ License
 
 namespace Foam
 {
-    defineTypeNameAndDebug(STARCDCoordinateRotation, 0);
-    addToRunTimeSelectionTable
-    (
-        coordinateRotation,
-        STARCDCoordinateRotation,
-        dictionary
-    );
-    addToRunTimeSelectionTable
-    (
-        coordinateRotation,
-        STARCDCoordinateRotation,
-        objectRegistry
-    );
-}
-
-
-// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
-
-Foam::vector Foam::STARCDCoordinateRotation::transform(const vector& st) const
-{
-    return (R_ & st);
-}
-
-
-Foam::vector Foam::STARCDCoordinateRotation::invTransform
-(
-    const vector& st
-) const
-{
-    return (Rtr_ & st);
-}
-
-
-Foam::tmp<Foam::vectorField> Foam::STARCDCoordinateRotation::transform
-(
-    const vectorField& st
-) const
-{
-    NotImplemented;
-    return nullptr;
-}
-
-
-Foam::tmp<Foam::vectorField> Foam::STARCDCoordinateRotation::invTransform
-(
-    const vectorField& st
-) const
-{
-    NotImplemented;
-    return nullptr;
-}
-
-
-const Foam::tensorField& Foam::STARCDCoordinateRotation::Tr() const
-{
-    NotImplemented;
-    return NullObjectRef<tensorField>();
-}
-
-
-Foam::tmp<Foam::tensorField> Foam::STARCDCoordinateRotation::transformTensor
-(
-    const tensorField& st
-) const
-{
-    NotImplemented;
-    return nullptr;
-}
-
-
-Foam::tensor Foam::STARCDCoordinateRotation::transformTensor
-(
-    const tensor& st
-) const
-{
-    return (R_ & st & Rtr_);
-}
-
-
-Foam::tmp<Foam::tensorField> Foam::STARCDCoordinateRotation::transformTensor
-(
-    const tensorField& st,
-    const labelList& cellMap
-) const
-{
-    NotImplemented;
-    return nullptr;
-}
-
-
-Foam::tmp<Foam::symmTensorField> Foam::STARCDCoordinateRotation::
-transformVector
-(
-    const vectorField& st
-) const
-{
-    tmp<symmTensorField> tfld(new symmTensorField(st.size()));
-    symmTensorField& fld = tfld.ref();
-
-    forAll(fld, i)
+    namespace coordinateRotations
     {
-        fld[i] = transformPrincipal(R_, st[i]);
-    }
-    return tfld;
-}
+        defineTypeName(starcd);
 
+        // Standard short name
+        addNamedToRunTimeSelectionTable
+        (
+            coordinateRotation,
+            starcd,
+            dictionary,
+            starcd
+        );
 
-Foam::symmTensor Foam::STARCDCoordinateRotation::transformVector
-(
-    const vector& st
-) const
-{
-    return transformPrincipal(R_, st);
+        // Longer name - Compat 1806
+        addNamedToRunTimeSelectionTable
+        (
+            coordinateRotation,
+            starcd,
+            dictionary,
+            STARCDRotation
+        );
+    }
 }
 
 
 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
 
-Foam::tensor Foam::STARCDCoordinateRotation::rotation
+Foam::tensor Foam::coordinateRotations::starcd::rotation
 (
     const vector& angles,
-    const bool degrees
+    bool degrees
 )
 {
     scalar z = angles.component(vector::X);    // 1. Rotate about Z
@@ -170,7 +79,6 @@ Foam::tensor Foam::STARCDCoordinateRotation::rotation
     const scalar cy = cos(y);  const scalar sy = sin(y);
     const scalar cz = cos(z);  const scalar sz = sin(z);
 
-
     return
         tensor
         (
@@ -183,72 +91,94 @@ Foam::tensor Foam::STARCDCoordinateRotation::rotation
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-Foam::STARCDCoordinateRotation::STARCDCoordinateRotation()
+Foam::coordinateRotations::starcd::starcd()
 :
-    R_(sphericalTensor::I),
-    Rtr_(sphericalTensor::I)
+    coordinateRotation(),
+    angles_(Zero),
+    degrees_(true)
 {}
 
 
-Foam::STARCDCoordinateRotation::STARCDCoordinateRotation
-(
-    const STARCDCoordinateRotation& r
-)
+Foam::coordinateRotations::starcd::starcd(const starcd& crot)
 :
-    R_(r.R_),
-    Rtr_(r.Rtr_)
+    coordinateRotation(crot),
+    angles_(crot.angles_),
+    degrees_(crot.degrees_)
 {}
 
 
-Foam::STARCDCoordinateRotation::STARCDCoordinateRotation
+Foam::coordinateRotations::starcd::starcd
 (
     const vector& rotZrotXrotY,
-    const bool degrees
+    bool degrees
 )
 :
-    R_(rotation(rotZrotXrotY, degrees)),
-    Rtr_(R_.T())
+    coordinateRotation(),
+    angles_(rotZrotXrotY),
+    degrees_(degrees)
 {}
 
 
-Foam::STARCDCoordinateRotation::STARCDCoordinateRotation
+Foam::coordinateRotations::starcd::starcd
 (
-    const scalar rotZ,
-    const scalar rotX,
-    const scalar rotY,
-    const bool degrees
+    scalar rotZ,
+    scalar rotX,
+    scalar rotY,
+    bool degrees
 )
 :
-    R_(rotation(vector(rotZ, rotX, rotY), degrees)),
-    Rtr_(R_.T())
+    coordinateRotation(),
+    angles_(rotZ, rotX, rotY),
+    degrees_(degrees)
 {}
 
 
-Foam::STARCDCoordinateRotation::STARCDCoordinateRotation
-(
-    const dictionary& dict
-)
+Foam::coordinateRotations::starcd::starcd(const dictionary& dict)
 :
-    R_
-    (
-        rotation
-        (
-            dict.get<vector>("rotation"),
-            dict.lookupOrDefault("degrees", true)
-        )
-    ),
-    Rtr_(R_.T())
+    coordinateRotation(),
+    angles_(dict.getCompat<vector>("angles", {{"rotation", 1806}})),
+    degrees_(dict.lookupOrDefault("degrees", true))
 {}
 
 
-Foam::STARCDCoordinateRotation::STARCDCoordinateRotation
+// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
+
+void Foam::coordinateRotations::starcd::clear()
+{
+    angles_ = Zero;
+    degrees_ = true;
+}
+
+
+Foam::tensor Foam::coordinateRotations::starcd::R() const
+{
+    return starcd::rotation(angles_, degrees_);
+}
+
+
+void Foam::coordinateRotations::starcd::write(Ostream& os) const
+{
+    os  << "starcd-angles(" << (degrees_ ? "deg" : "rad") << "): " << angles_;
+}
+
+
+void Foam::coordinateRotations::starcd::writeEntry
 (
-    const dictionary& dict,
-    const objectRegistry&
-)
-:
-    STARCDCoordinateRotation(dict)
-{}
+    const word& keyword,
+    Ostream& os
+) const
+{
+    os.beginBlock(keyword);
+
+    os.writeEntry("type", type());
+    os.writeEntry("angles", angles_);
+    if (!degrees_)
+    {
+        os.writeEntry("degrees", "false");
+    }
+
+    os.endBlock();
+}
 
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/src/meshTools/coordinate/rotation/STARCDCoordinateRotation.H b/src/meshTools/coordinate/rotation/STARCDCoordinateRotation.H
index a6094a8653f6eb43e3e09482e4c404ad433381ba..f10ac9f80f64492642e07e122f3f7ba6bd06b8e4 100644
--- a/src/meshTools/coordinate/rotation/STARCDCoordinateRotation.H
+++ b/src/meshTools/coordinate/rotation/STARCDCoordinateRotation.H
@@ -22,7 +22,7 @@ License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
 Class
-    Foam::STARCDCoordinateRotation
+    Foam::coordinateRotations::starcd
 
 Description
     A coordinateRotation defined by the STAR-CD convention.
@@ -36,19 +36,26 @@ Description
     \verbatim
     coordinateRotation
     {
-        type        STARCDRotation;
-        degrees     false;
-        rotation    (0 0 3.141592654);
+        type    starcd;
+        angles  (0 0 180);
     }
     \endverbatim
 
+    \heading Dictionary entries
+    \table
+        Property    | Description                           | Required | Default
+        type        | Type name: starcd (or STARCDRotation) | yes   |
+        angles      | The z-x-y rotation angles             | yes   |
+        degrees     | Angles are in degrees                 | no    | true
+    \endtable
+
 SourceFiles
     STARCDCoordinateRotation.C
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef STARCDCoordinateRotation_H
-#define STARCDCoordinateRotation_H
+#ifndef coordinateRotations_starcd_H
+#define coordinateRotations_starcd_H
 
 #include "coordinateRotation.H"
 
@@ -56,74 +63,62 @@ SourceFiles
 
 namespace Foam
 {
+namespace coordinateRotations
+{
 
 /*---------------------------------------------------------------------------*\
-                  Class STARCDCoordinateRotation Declaration
+                 Class coordinateRotations::starcd Declaration
 \*---------------------------------------------------------------------------*/
 
-class STARCDCoordinateRotation
+class starcd
 :
     public coordinateRotation
 {
-    // Private Member Data
+    // Private Data
 
-        //- Local-to-Global transformation tensor
-        tensor R_;
+        //- The rotation angles
+        vector angles_;
 
-        //- Global-to-Local transformation tensor
-        tensor Rtr_;
+        //- Angles measured in degrees
+        bool degrees_;
 
 
 public:
 
     //- Runtime type information
-    TypeName("STARCDRotation");
+    TypeNameNoDebug("starcd");
 
 
     // Constructors
 
-        //- Construct null
-        STARCDCoordinateRotation();
+        //- Construct null - an identity transform
+        starcd();
 
-        //- Construct as copy
-        STARCDCoordinateRotation(const STARCDCoordinateRotation& r);
+        //- Copy construct
+        starcd(const starcd& crot);
 
         //- Construct from rotation vector
-        STARCDCoordinateRotation
-        (
-            const vector& rotZrotXrotY,
-            const bool degrees
-        );
+        starcd(const vector& rotZrotXrotY, bool degrees);
 
         //- Construct from components of rotation vector
-        STARCDCoordinateRotation
-        (
-            const scalar rotZ,
-            const scalar rotX,
-            const scalar rotY,
-            const bool degrees
-        );
+        starcd(scalar rotZ, scalar rotX, scalar rotY, bool degrees);
 
         //- Construct from dictionary
-        explicit STARCDCoordinateRotation(const dictionary& dict);
-
-        //- Construct from dictionary and a registry (typically a mesh)
-        STARCDCoordinateRotation
-        (
-            const dictionary& dict,
-            const objectRegistry& unused
-        );
-
+        explicit starcd(const dictionary& dict);
 
         //- Return clone
         autoPtr<coordinateRotation> clone() const
         {
             return
                 autoPtr<coordinateRotation>::NewFrom
-                <STARCDCoordinateRotation>(*this);
+                <coordinateRotations::starcd>(*this);
         }
 
 
+    //- Destructor
+    virtual ~starcd() = default;
+
+
     // Static Member Functions
 
         //- The rotation tensor calculated for the specified STARCD angles
@@ -133,90 +128,28 @@ public:
 
     // Member Functions
 
-        //- Reset rotation to an identity rotation
-        virtual void clear()
-        {
-            R_ = sphericalTensor::I;
-            Rtr_ = sphericalTensor::I;
-        }
-
-        //- Update the rotation for a list of cells
-        virtual void updateCells(const polyMesh&, const labelList&)
-        {}
+        //- Reset specification
+        virtual void clear();
 
-        //- Return local-to-global transformation tensor
-        virtual const tensor& R() const
-        {
-            return R_;
-        }
+        //- The rotation tensor calculated for the specified STARCD angles.
+        virtual tensor R() const;
 
-        //- Return global-to-local transformation tensor
-        virtual const tensor& Rtr() const
-        {
-            return Rtr_;
-        };
+        //- Write information
+        virtual void write(Ostream& os) const;
 
-        //- Return local Cartesian x-axis in global coordinates
-        virtual const vector e1() const
-        {
-            return Rtr_.x();
-        }
+        //- Write dictionary entry
+        virtual void writeEntry(const word& keyword, Ostream& os) const;
 
-        //- Return local Cartesian y-axis in global coordinates
-        virtual const vector e2() const
-        {
-            return Rtr_.y();
-        }
-
-        //- Return local Cartesian z-axis in global coordinates
-        virtual const vector e3() const
-        {
-            return Rtr_.z();
-        }
-
-        //- Return transformation tensor field
-        virtual const tensorField& Tr() const;
-
-        //- Transform vectorField using transformation tensor field
-        virtual tmp<vectorField> transform(const vectorField& st) const;
-
-        //- Transform vector using transformation tensor
-        virtual vector transform(const vector& st) const;
-
-        //- Inverse transform vectorField using transformation tensor field
-        virtual tmp<vectorField> invTransform(const vectorField& st) const;
-
-        //- Inverse transform vector using transformation tensor
-        virtual vector invTransform(const vector& st) const;
-
-        //- Transform tensor field using transformation tensorField
-        virtual tmp<tensorField> transformTensor(const tensorField& st) const;
-
-        //- Transform tensor using transformation tensorField
-        virtual tensor transformTensor(const tensor& st) const;
-
-        //- Transform tensor sub-field using transformation tensorField
-        virtual tmp<tensorField> transformTensor
-        (
-            const tensorField& st,
-            const labelList& cellMap
-        ) const;
+};
 
-        //- Transform vectorField using transformation tensorField and return
-        // symmetrical tensorField
-        virtual tmp<symmTensorField> transformVector
-        (
-            const vectorField& st
-        ) const;
 
-        //- Transform vector using transformation tensor and return
-        // symmetrical tensor
-        virtual symmTensor transformVector(const vector& st) const;
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
-};
+} // End namespace coordinateRotations
 
 
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+//- Compatibility typedef 1806
+typedef coordinateRotations::starcd STARCDCoordinateRotation;
 
 } // End namespace Foam
 
diff --git a/src/meshTools/coordinate/rotation/axesRotation.C b/src/meshTools/coordinate/rotation/axesRotation.C
index e40e11fe9ea6bd3cda6c58f153f1960f8e39ae09..8534d82460ae73a350a7ce2b60b7edb83b85bb8c 100644
--- a/src/meshTools/coordinate/rotation/axesRotation.C
+++ b/src/meshTools/coordinate/rotation/axesRotation.C
@@ -31,25 +31,34 @@ License
 
 namespace Foam
 {
-    defineTypeNameAndDebug(axesRotation, 0);
-    addToRunTimeSelectionTable
-    (
-        coordinateRotation,
-        axesRotation,
-        dictionary
-    );
-    addToRunTimeSelectionTable
-    (
-        coordinateRotation,
-        axesRotation,
-        objectRegistry
-    );
+    namespace coordinateRotations
+    {
+        defineTypeName(axes);
+
+        // Standard short name
+        addNamedToRunTimeSelectionTable
+        (
+            coordinateRotation,
+            axes,
+            dictionary,
+            axes
+        );
+
+        // Longer name - Compat 1806
+        addNamedToRunTimeSelectionTable
+        (
+            coordinateRotation,
+            axes,
+            dictionary,
+            axesRotation
+        );
+    }
 }
 
 
 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
 
-Foam::tensor Foam::axesRotation::rotation
+Foam::tensor Foam::coordinateRotations::axes::rotation
 (
     const vector& axis1,
     const vector& axis2,
@@ -143,221 +152,193 @@ Foam::tensor Foam::axesRotation::rotation
 
 // * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
 
-void Foam::axesRotation::read(const dictionary& dict)
+void Foam::coordinateRotations::axes::read(const dictionary& dict)
 {
-    vector axis1, axis2;
-    axisOrder order = E3_E1;
-
     if
     (
-        dict.readIfPresent("e1", axis1)
-     && dict.readIfPresent("e2", axis2)
+        dict.readIfPresent("e1", axis1_)
+     && dict.readIfPresent("e2", axis2_)
     )
     {
-        order = E1_E2;
+        order_ = E1_E2;
     }
     else if
     (
-        dict.readIfPresent("e2", axis1)
-     && dict.readIfPresent("e3", axis2)
+        dict.readIfPresent("e2", axis1_)
+     && dict.readIfPresent("e3", axis2_)
     )
     {
-        order = E2_E3;
+        order_ = E2_E3;
     }
     else if
     (
-        dict.readIfPresent("e3", axis1)
-     && dict.readIfPresent("e1", axis2)
+        dict.readIfPresent("e3", axis1_)
+     && dict.readIfPresent("e1", axis2_)
     )
     {
-        order = E3_E1;
+        order_ = E3_E1;
     }
     else if
     (
-        dict.readIfPresent("axis", axis1)
-     && dict.readIfPresent("direction", axis2)
+        dict.readIfPresent("axis", axis1_)
+     && dict.readIfPresent("direction", axis2_)
     )
     {
-        order = E3_E1_COMPAT;
+        order_ = E3_E1_COMPAT;
     }
     else
     {
-        FatalErrorInFunction
+        FatalIOErrorInFunction(dict)
             << "No entries of the type (e1, e2) or (e2, e3) or (e3, e1) found"
-            << exit(FatalError);
+            << exit(FatalIOError);
     }
-
-    R_ = rotation(axis1, axis2, order);
-    Rtr_ = R_.T();
 }
 
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-Foam::axesRotation::axesRotation()
+Foam::coordinateRotations::axes::axes()
 :
-    R_(sphericalTensor::I),
-    Rtr_(sphericalTensor::I)
+    coordinateRotation(),
+    axis1_(0,0,1),  // e3 = global Z
+    axis2_(1,0,0),  // e1 = global X
+    order_(E3_E1)
 {}
 
 
-Foam::axesRotation::axesRotation(const axesRotation& r)
+Foam::coordinateRotations::axes::axes(const axes& crot)
 :
-    R_(r.R_),
-    Rtr_(r.Rtr_)
+    coordinateRotation(crot),
+    axis1_(crot.axis1_),
+    axis2_(crot.axis2_),
+    order_(crot.order_)
 {}
 
 
-Foam::axesRotation::axesRotation(const tensor& R)
+Foam::coordinateRotations::axes::axes(axes&& crot)
 :
-    R_(R),
-    Rtr_(R_.T())
+    coordinateRotation(std::move(crot)),
+    axis1_(std::move(crot.axis1_)),
+    axis2_(std::move(crot.axis2_)),
+    order_(crot.order_)
 {}
 
 
-Foam::axesRotation::axesRotation
+Foam::coordinateRotations::axes::axes
 (
-    const vector& axis,
-    const vector& dir,
-    const axisOrder& order
+    const vector& axis1,
+    const vector& axis2,
+    axisOrder order
 )
 :
-    R_(rotation(axis, dir, order)),
-    Rtr_(R_.T())
+    coordinateRotation(),
+    axis1_(axis1),
+    axis2_(axis2),
+    order_(order)
 {}
 
 
-Foam::axesRotation::axesRotation
-(
-    const vector& axis
-)
+Foam::coordinateRotations::axes::axes(const vector& axis)
 :
-    R_(rotation(axis, findOrthogonal(axis), E3_E1)),
-    Rtr_(R_.T())
+    coordinateRotations::axes(axis, Zero, E3_E1_COMPAT)  // Guess second axis
 {}
 
 
-Foam::axesRotation::axesRotation
-(
-    const dictionary& dict
-)
+Foam::coordinateRotations::axes::axes(const dictionary& dict)
 :
-    R_(sphericalTensor::I),
-    Rtr_(sphericalTensor::I)
+    coordinateRotations::axes()
 {
     read(dict);
 }
 
 
-Foam::axesRotation::axesRotation
-(
-    const dictionary& dict,
-    const objectRegistry&
-)
-:
-    axesRotation(dict)
-{}
-
-
 // * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
 
-const Foam::tensorField& Foam::axesRotation::Tr() const
+void Foam::coordinateRotations::axes::clear()
 {
-    NotImplemented;
-    return NullObjectRef<tensorField>();
+    axis1_ = vector(0,0,1);  // e3 = global Z
+    axis2_ = vector(1,0,0);  // e1 = global X
+    order_ = E3_E1;
 }
 
 
-Foam::tmp<Foam::vectorField> Foam::axesRotation::transform
-(
-    const vectorField& st
-) const
+Foam::tensor Foam::coordinateRotations::axes::R() const
 {
-    return (R_ & st);
+    return axes::rotation(axis1_, axis2_, order_);
 }
 
 
-Foam::vector Foam::axesRotation::transform(const vector& st) const
-{
-    return (R_ & st);
-}
-
-
-Foam::tmp<Foam::vectorField> Foam::axesRotation::invTransform
-(
-    const vectorField& st
-) const
-{
-    return (Rtr_ & st);
-}
-
-
-Foam::vector Foam::axesRotation::invTransform(const vector& st) const
-{
-    return (Rtr_ & st);
-}
-
-
-Foam::tmp<Foam::tensorField> Foam::axesRotation::transformTensor
-(
-    const tensorField& st
-) const
-{
-    NotImplemented;
-    return nullptr;
-}
-
+// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
 
-Foam::tensor Foam::axesRotation::transformTensor
-(
-    const tensor& st
-) const
+void Foam::coordinateRotations::axes::write(Ostream& os) const
 {
-    return (R_ & st & Rtr_);
+    switch (order_)
+    {
+        case E1_E2:
+            os << "e1: " << axis1_ << " e2: " << axis2_;
+            break;
+        case E2_E3:
+            os << "e2: " << axis1_ << " e3: " << axis2_;
+            break;
+        case E3_E1:
+            os << "e1: " << axis2_ << " e3: " << axis1_;
+            break;
+        case E3_E1_COMPAT:
+            os << "axis: " << axis1_ << " direction: " << axis2_;
+            break;
+    }
 }
 
 
-Foam::tmp<Foam::tensorField> Foam::axesRotation::transformTensor
+void Foam::coordinateRotations::axes::writeEntry
 (
-    const tensorField& st,
-    const labelList& cellMap
+    const word& keyword,
+    Ostream& os
 ) const
 {
-    NotImplemented;
-    return nullptr;
-}
-
+    // We permit direct embedding of the axes specification without
+    // requiring a sub-dictionary.
 
-Foam::tmp<Foam::symmTensorField> Foam::axesRotation::transformVector
-(
-    const vectorField& st
-) const
-{
-    tmp<symmTensorField> tfld(new symmTensorField(st.size()));
-    symmTensorField& fld = tfld.ref();
+    const bool subDict = !keyword.empty();
 
-    forAll(fld, i)
+    if (subDict)
     {
-        fld[i] = transformPrincipal(R_, st[i]);
+        os.beginBlock(keyword);
+        os.writeEntry("type", type());
     }
-    return tfld;
-}
-
-
-Foam::symmTensor Foam::axesRotation::transformVector
-(
-    const vector& st
-) const
-{
-    return transformPrincipal(R_, st);
-}
-
 
-// * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
+    switch (order_)
+    {
+        case E1_E2:
+        {
+            os.writeEntry("e1", axis1_);
+            os.writeEntry("e2", axis2_);
+            break;
+        }
+        case E2_E3:
+        {
+            os.writeEntry("e2", axis1_);
+            os.writeEntry("e3", axis2_);
+            break;
+        }
+        case E3_E1:
+        {
+            os.writeEntry("e1", axis2_);
+            os.writeEntry("e3", axis1_);
+            break;
+        }
+        case E3_E1_COMPAT:
+        {
+            os.writeEntry("axis", axis1_);
+            os.writeEntry("direction", axis2_);
+            break;
+        }
+    }
 
-void Foam::axesRotation::operator=(const dictionary& dict)
-{
-    read(dict);
+    if (subDict)
+    {
+        os.endBlock();
+    }
 }
 
 
diff --git a/src/meshTools/coordinate/rotation/axesRotation.H b/src/meshTools/coordinate/rotation/axesRotation.H
index 3a3583211bdd691689bc806a35ec686fa4d94199..cb5fcd313629db41246de67eba2190be7bd6985b 100644
--- a/src/meshTools/coordinate/rotation/axesRotation.H
+++ b/src/meshTools/coordinate/rotation/axesRotation.H
@@ -22,48 +22,59 @@ License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
 Class
-    Foam::axesRotation
+    Foam::coordinateRotations::axes
 
 Description
-    A coordinate rotation specified using global axes
+    A coordinateRotation specified using global axes.
 
     The rotation is defined by a combination of vectors (e1/e2), (e2/e3)
-    or (e3/e1). Any nonorthogonality will be absorbed into the second
-    vector. In terms of cylindrical coordinates, the 'axis' would
-    correspond to the \a z-axis and the 'direction' to the \a r-axis.
+    or (e3/e1). Any nonorthogonality is absorbed into the second vector.
 
     \verbatim
-    axesRotation
+    coordinateRotation
     {
-        type        axesRotation;
+        type        axes;
         e1          (1 0 0);
         e2          (0 1 0);
     }
     \endverbatim
 
+    \heading Dictionary entries
+    \table
+        Property    | Description                       | Required  | Default
+        type        | type name: axes (previously axesRotation)     | yes   |
+        e1          | local x-axis                      | partly    |
+        e2          | local y-axis                      | partly    |
+        e3          | local z-axis                      | partly    |
+    \endtable
+
+Note
+    It is also possible to specify in terms of \c axis and \c direction.
+    For cylindrical coordinates, the \c axis would correspond to the
+    \a z-axis and the \c direction to the \a r-axis.
+
 SourceFiles
     axesRotation.C
 
 \*---------------------------------------------------------------------------*/
 
-#ifndef axesRotation_H
-#define axesRotation_H
+#ifndef coordinateRotations_axes_H
+#define coordinateRotations_axes_H
 
-#include "vector.H"
 #include "coordinateRotation.H"
-#include "dictionary.H"
-#include "runTimeSelectionTables.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 namespace Foam
 {
+namespace coordinateRotations
+{
 
 /*---------------------------------------------------------------------------*\
-                    Class axesRotation Declaration
+                  Class coordinateRotations::axes Declaration
 \*---------------------------------------------------------------------------*/
 
-class axesRotation
+class axes
 :
     public coordinateRotation
 {
@@ -76,19 +87,22 @@ public:
         E1_E2,  //!< The axis1 (dominant) is local X, axis2 is local Y.
         E2_E3,  //!< The axis1 (dominant) is local Y, axis2 is local Z.
         E3_E1,  //!< The axis1 (dominant) is local Z, axis2 is local X.
-        E3_E1_COMPAT, //!< E3_E1 specified as axis/direction.
+        E3_E1_COMPAT  //!< E3_E1 specified as axis/direction.
     };
 
 
-private:
+protected:
 
-    // Private data
+    // Protected Data
 
-        //- Local-to-Global transformation tensor
-        tensor R_;
+        //- The primary axis
+        vector axis1_;
 
-        //- Global-to-Local transformation tensor
-        tensor Rtr_;
+        //- The secondary axis
+        vector axis2_;
+
+        //- The axis order
+        axisOrder order_;
 
 
     // Protected Member Functions
@@ -100,67 +114,52 @@ private:
 public:
 
     //- Runtime type information
-    TypeName("axesRotation");
+    TypeNameNoDebug("axes");
+
 
     // Constructors
 
-        //- Construct null
-        axesRotation();
+        //- Construct null - an identity transform
+        axes();
 
-        //- Construct as copy
-        axesRotation(const axesRotation& r);
+        //- Copy construct
+        axes(const axes& crot);
 
-        //- Construct from local to global rotation matrix
-        explicit axesRotation(const tensor& R);
+        //- Move construct
+        axes(axes&& crot);
 
-        //- Construct from two axes (axis and direction)
-        axesRotation
-        (
-            const vector& axis,
-            const vector& dir,
-            const axisOrder& order = E3_E1
-        );
+        //- Construct from two axes
+        axes(const vector& axis1, const vector& axis2, axisOrder order=E3_E1);
 
-        //- Construct from a single axis using a best-guess for the second axis
-        //  For the best-guess, the largest component value and sign of the
-        //  axis determines the direction orientation.
-        explicit axesRotation(const vector& axis);
+        //- Construct from a single axis (as e3) using a best-guess for the
+        //- second axis.
+        //  The largest component and its sign are used when guessing
+        //  an appropriate orientation (direction).
+        explicit axes(const vector& axis);
 
         //- Construct from dictionary
-        explicit axesRotation(const dictionary& dict);
-
-        //- Construct from dictionary and a registry (typically a mesh)
-        axesRotation
-        (
-            const dictionary& dict,
-            const objectRegistry& unused
-        );
+        explicit axes(const dictionary& dict);
 
         //- Return clone
         autoPtr<coordinateRotation> clone() const
         {
-            return autoPtr<coordinateRotation>::NewFrom<axesRotation>(*this);
+            return
+                autoPtr<coordinateRotation>::NewFrom
+                <coordinateRotations::axes>(*this);
         }
 
 
     //- Destructor
-    virtual ~axesRotation() = default;
-
-
-    // Member Functions
-
-        //- Reset rotation to an identity rotation
-        virtual void clear()
-        {
-            R_ = sphericalTensor::I;
-            Rtr_ = sphericalTensor::I;
-        }
+    virtual ~axes() = default;
 
 
     // Static Member Functions
 
         //- The rotation tensor calculated from two axes and their order.
         //  The input axes will be normalised.
+        //  If axis2 is zero, an axis orthogonal to axis1 will be guessed.
+        //  The largest component and its sign are used when guessing
+        //  an appropriate orientation (direction).
         static tensor rotation
         (
             const vector& axis1,
@@ -169,90 +168,29 @@ public:
         );
 
 
-        //- Update the rotation for a list of cells
-        virtual void updateCells(const polyMesh&, const labelList&)
-        {}
-
-        //- Return local-to-global transformation tensor
-        virtual const tensor& R() const
-        {
-            return R_;
-        }
-
-        //- Return global-to-local transformation tensor
-        virtual const tensor& Rtr() const
-        {
-            return Rtr_;
-        }
-
-        //- Return local Cartesian x-axis in global coordinates
-        virtual const vector e1() const
-        {
-            return Rtr_.x();
-        }
-
-        //- Return local Cartesian y-axis in global coordinates
-        virtual const vector e2() const
-        {
-            return Rtr_.y();
-        }
-
-        //- Return local Cartesian z-axis in global coordinates
-        virtual const vector e3() const
-        {
-            return Rtr_.z();
-        }
-
-        //- Return transformation tensor field
-        virtual const tensorField& Tr() const;
-
-        //- Transform vectorField using transformation tensor field
-        virtual tmp<vectorField> transform(const vectorField& st) const;
-
-        //- Transform vector using transformation tensor
-        virtual vector transform(const vector& st) const;
-
-        //- Inverse transform vectorField using transformation tensor field
-        virtual tmp<vectorField> invTransform(const vectorField& st) const;
-
-        //- Inverse transform vector using transformation tensor
-        virtual vector invTransform(const vector& st) const;
-
-        //- Transform tensor field using transformation tensorField
-        virtual tmp<tensorField> transformTensor(const tensorField& st) const;
-
-        //- Transform tensor using transformation tensorField
-        virtual tensor transformTensor(const tensor& st) const;
-
-        //- Transform tensor sub-field using transformation tensorField
-        virtual tmp<tensorField> transformTensor
-        (
-            const tensorField& st,
-            const labelList& cellMap
-        ) const;
-
-        //- Transform vectorField using transformation tensorField and return
-        //  symmetric tensorField
-        virtual tmp<symmTensorField> transformVector
-        (
-            const vectorField& st
-        ) const;
-
-        //- Transform vector using transformation tensor and return
-        //  symmetric tensor
-        virtual symmTensor transformVector(const vector& st) const;
+    // Member Functions
 
+        //- Reset specification
+        virtual void clear();
 
-    // Member Operators
+        //- The rotation tensor calculated from the specified axes and order
+        virtual tensor R() const;
 
-        //- Assign from dictionary
-        void operator=(const dictionary& dict);
+        //- Write information
+        virtual void write(Ostream& os) const;
 
+        //- Write dictionary entry
+        virtual void writeEntry(const word& keyword, Ostream& os) const;
 };
 
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+} // End namespace coordinateRotations
+
+// Compatibility typedef 1806
+typedef coordinateRotations::axes axesRotation;
+
 } // End namespace Foam
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
diff --git a/src/meshTools/coordinate/rotation/axisAngleRotation.C b/src/meshTools/coordinate/rotation/axisAngleRotation.C
new file mode 100644
index 0000000000000000000000000000000000000000..97a7f70d89abd4e789507dddb950280e14e57c2a
--- /dev/null
+++ b/src/meshTools/coordinate/rotation/axisAngleRotation.C
@@ -0,0 +1,167 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2018 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "axisAngleRotation.H"
+#include "dictionary.H"
+#include "quaternion.H"
+#include "unitConversion.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    namespace coordinateRotations
+    {
+        defineTypeName(axisAngle);
+        addToRunTimeSelectionTable
+        (
+            coordinateRotation,
+            axisAngle,
+            dictionary
+        );
+    }
+}
+
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+void Foam::coordinateRotations::axisAngle::checkSpec()
+{
+    if (mag(angle_) < VSMALL || mag(axis_) < SMALL)
+    {
+        clear(); // identity rotation
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::coordinateRotations::axisAngle::axisAngle()
+:
+    coordinateRotation(),
+    axis_ (0,0,1),  // e3 = global Z
+    angle_(Zero),
+    degrees_(true)
+{}
+
+
+Foam::coordinateRotations::axisAngle::axisAngle(const axisAngle& crot)
+:
+    coordinateRotation(crot),
+    axis_(crot.axis_),
+    angle_(crot.angle_),
+    degrees_(crot.degrees_)
+{
+    checkSpec();
+}
+
+
+Foam::coordinateRotations::axisAngle::axisAngle(axisAngle&& crot)
+:
+    coordinateRotation(std::move(crot)),
+    axis_(std::move(crot.axis_)),
+    angle_(std::move(crot.angle_)),
+    degrees_(crot.degrees_)
+{
+    checkSpec();
+}
+
+
+Foam::coordinateRotations::axisAngle::axisAngle
+(
+    const vector& axis,
+    scalar angle,
+    bool degrees
+)
+:
+    coordinateRotation(),
+    axis_(axis),
+    angle_(angle),
+    degrees_(degrees)
+{
+    checkSpec();
+}
+
+
+Foam::coordinateRotations::axisAngle::axisAngle(const dictionary& dict)
+:
+    axisAngle
+    (
+        dict.get<vector>("axis"),
+        dict.get<scalar>("angle"),
+        dict.lookupOrDefault("degrees", true)
+    )
+{}
+
+
+// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
+
+void Foam::coordinateRotations::axisAngle::clear()
+{
+    axis_  = vector(0,0,1);  // e3 = global Z
+    angle_ = Zero;
+}
+
+
+Foam::tensor Foam::coordinateRotations::axisAngle::R() const
+{
+    if (mag(angle_) < VSMALL || mag(axis_) < SMALL)
+    {
+        return sphericalTensor::I; // identity rotation
+    }
+
+    return quaternion(axis_, (degrees_ ? degToRad(angle_) : angle_)).R();
+}
+
+
+void Foam::coordinateRotations::axisAngle::write(Ostream& os) const
+{
+    os  << "rotation axis: " << axis_
+        << " angle(" << (degrees_ ? "deg" : "rad") << "): " << angle_;
+}
+
+
+void Foam::coordinateRotations::axisAngle::writeEntry
+(
+    const word& keyword,
+    Ostream& os
+) const
+{
+    os.beginBlock(keyword);
+
+    os.writeEntry("type", type());
+    os.writeEntry("axis",  axis_);
+    os.writeEntry("angle", angle_);
+    if (!degrees_)
+    {
+        os.writeEntry("degrees", "false");
+    }
+
+    os.endBlock();
+}
+
+
+// ************************************************************************* //
diff --git a/src/meshTools/coordinate/rotation/axisAngleRotation.H b/src/meshTools/coordinate/rotation/axisAngleRotation.H
new file mode 100644
index 0000000000000000000000000000000000000000..a08053400d15c0ce16baa0b879b3e01631cd2391
--- /dev/null
+++ b/src/meshTools/coordinate/rotation/axisAngleRotation.H
@@ -0,0 +1,156 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2018 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::coordinateRotations::axisAngle
+
+Description
+    A coordinateRotation specified by a rotation axis and a rotation angle
+    about that axis.
+
+    \verbatim
+    coordinateRotation
+    {
+        type        axisAngle;
+        axis        (1 0 0);
+        angle       90;
+    }
+    \endverbatim
+
+    \heading Dictionary entries
+    \table
+        Property    | Description                           | Required | Default
+        type        | Type name: axisAngle                  | yes   |
+        axis        | Axis of rotation (vector)             | yes   |
+        angle       | Rotation angle                        | yes   |
+        degrees     | The angle is in degrees               | no    | true
+    \endtable
+
+Note
+    The rotation axis will be normalized internally.
+
+SourceFiles
+    axisAngle.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef coordinateRotations_axisAngle_H
+#define coordinateRotations_axisAngle_H
+
+#include "coordinateRotation.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace coordinateRotations
+{
+
+/*---------------------------------------------------------------------------*\
+               Class coordinateRotations::axisAngle Declaration
+\*---------------------------------------------------------------------------*/
+
+class axisAngle
+:
+    public coordinateRotation
+{
+    // Private Data
+
+        //- The rotation axis
+        vector axis_;
+
+        //- The rotation angle
+        scalar angle_;
+
+        //- Angle measured in degrees
+        bool degrees_;
+
+
+    // Private Member Functions
+
+        //- Check specification for an identity rotation
+        void checkSpec();
+
+
+public:
+
+    //- Runtime type information
+    TypeNameNoDebug("axisAngle");
+
+    // Constructors
+
+        //- Construct null
+        axisAngle();
+
+        //- Copy construct
+        axisAngle(const axisAngle& crot);
+
+        //- Move construct
+        axisAngle(axisAngle&& crot);
+
+        //- Construct from axis and angle
+        axisAngle(const vector& axis, scalar angle, bool degrees);
+
+        //- Construct from dictionary
+        explicit axisAngle(const dictionary& dict);
+
+        //- Return clone
+        autoPtr<coordinateRotation> clone() const
+        {
+            return
+                autoPtr<coordinateRotation>::NewFrom
+                <coordinateRotations::axisAngle>(*this);
+        }
+
+
+    //- Destructor
+    virtual ~axisAngle() = default;
+
+
+    // Member Functions
+
+        //- Reset specification
+        virtual void clear();
+
+        //- Calculate and return the rotation tensor
+        //- calculated from axis and angle
+        virtual tensor R() const;
+
+        //- Write information
+        virtual void write(Ostream& os) const;
+
+        //- Write dictionary entry
+        virtual void writeEntry(const word& keyword, Ostream& os) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace coordinateRotations
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/meshTools/coordinate/rotation/coordinateRotation.C b/src/meshTools/coordinate/rotation/coordinateRotation.C
index 41892d013d340187faca65389a575a3d40eaefdf..3cf52ef1a4c89b0f49ecbd75d124f2aec3c38c65 100644
--- a/src/meshTools/coordinate/rotation/coordinateRotation.C
+++ b/src/meshTools/coordinate/rotation/coordinateRotation.C
@@ -31,9 +31,8 @@ License
 
 namespace Foam
 {
-    defineTypeNameAndDebug(coordinateRotation, 0);
+    defineTypeName(coordinateRotation);
     defineRunTimeSelectionTable(coordinateRotation, dictionary);
-    defineRunTimeSelectionTable(coordinateRotation, objectRegistry);
 }
 
 
@@ -64,46 +63,28 @@ Foam::vector Foam::coordinateRotation::findOrthogonal(const vector& axis)
 }
 
 
-Foam::symmTensor Foam::coordinateRotation::transformPrincipal
+// * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
+
+Foam::autoPtr<Foam::coordinateRotation> Foam::coordinateRotation::New
 (
-    const tensor& tt,
-    const vector& v
+    const dictionary& dict
 )
 {
-    return symmTensor
-    (
-        tt.xx()*v.x()*tt.xx()
-      + tt.xy()*v.y()*tt.xy()
-      + tt.xz()*v.z()*tt.xz(),
-
-        tt.xx()*v.x()*tt.yx()
-      + tt.xy()*v.y()*tt.yy()
-      + tt.xz()*v.z()*tt.yz(),
-
-        tt.xx()*v.x()*tt.zx()
-      + tt.xy()*v.y()*tt.zy()
-      + tt.xz()*v.z()*tt.zz(),
-
-        tt.yx()*v.x()*tt.yx()
-      + tt.yy()*v.y()*tt.yy()
-      + tt.yz()*v.z()*tt.yz(),
-
-        tt.yx()*v.x()*tt.zx()
-      + tt.yy()*v.y()*tt.zy()
-      + tt.yz()*v.z()*tt.zz(),
-
-        tt.zx()*v.x()*tt.zx()
-      + tt.zy()*v.y()*tt.zy()
-      + tt.zz()*v.z()*tt.zz()
-    );
-}
+    const word modelType(dict.get<word>("type"));
 
+    auto cstrIter = dictionaryConstructorTablePtr_->cfind(modelType);
 
-void Foam::coordinateRotation::write(Ostream& os) const
-{
-     os.writeEntry("e1", e1());
-     os.writeEntry("e2", e2());
-     os.writeEntry("e3", e3());
+    if (!cstrIter.found())
+    {
+        FatalIOErrorInFunction(dict)
+            << "Unknown coordinateRotation type "
+            << modelType << nl << nl
+            << "Valid types: "
+            << flatOutput(dictionaryConstructorTablePtr_->sortedToc())
+            << exit(FatalIOError);
+    }
+
+    return autoPtr<coordinateRotation>(cstrIter()(dict));
 }
 
 
diff --git a/src/meshTools/coordinate/rotation/coordinateRotation.H b/src/meshTools/coordinate/rotation/coordinateRotation.H
index 4c725756a17d4e14530de2fc10b194df52098eff..bfb51b18c2a28b08ff28aefa12fc0963d39799b1 100644
--- a/src/meshTools/coordinate/rotation/coordinateRotation.H
+++ b/src/meshTools/coordinate/rotation/coordinateRotation.H
@@ -21,43 +21,47 @@ License
     You should have received a copy of the GNU General Public License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
+Namespace
+    Foam::coordinateRotations
+
+Description
+    Namespace for coordinate system rotations.
+
 Class
     Foam::coordinateRotation
 
 Description
-    Abstract base class for coordinate rotation
+    User specification of a coordinate rotation.
 
     \verbatim
     coordinateRotation
     {
-        type        axesRotation
-        e1          (1 0 0);
-        e2          (0 1 0);
+        type    axes
+        e1      (1 0 0);
+        e2      (0 1 0);
     }
     \endverbatim
 
-    Types of coordinateRotation:
-      -# axesRotation
-      -# STARCDRotation
-      -# cylindrical
-      -# EulerCoordinateRotation
+    Types of coordinateRotations:
+      -# \link coordinateRotations::identity none \endlink
+      -# \link coordinateRotations::axes axes \endlink
+      -# \link coordinateRotations::axisAngle axisAngle \endlink
+      -# \link coordinateRotations::cylindrical cylindrical \endlink
+      -# \link coordinateRotations::euler euler \endlink
+      -# \link coordinateRotations::starcd starcd \endlink
 
 SourceFiles
     coordinateRotation.C
-    coordinateRotationNew.C
 
 \*---------------------------------------------------------------------------*/
 
 #ifndef coordinateRotation_H
 #define coordinateRotation_H
 
-#include "vector.H"
-#include "tensor.H"
+#include "vectorField.H"
 #include "tensorField.H"
 #include "dictionary.H"
 #include "runTimeSelectionTables.H"
-#include "objectRegistry.H"
-#include "polyMesh.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -65,17 +69,14 @@ namespace Foam
 {
 
 /*---------------------------------------------------------------------------*\
-                    Class coordinateRotation Declaration
+                     Class coordinateRotation Declaration
 \*---------------------------------------------------------------------------*/
 
 class coordinateRotation
 {
 protected:
 
-    // Protected member functions
-
-        //- Transform principal
-        static symmTensor transformPrincipal(const tensor&, const vector&);
+    // Protected Member Functions
 
         //- Determine best-guess for an orthogonal axis
         static vector findOrthogonal(const vector& axis);
@@ -84,25 +85,9 @@ protected:
 public:
 
     //- Runtime type information
-    TypeName("coordinateRotation");
-
+    TypeNameNoDebug("coordinateRotation");
 
-    // Declare run-time constructor selection table
-    // for constructors with dictionary and objectRegistry
-    declareRunTimeSelectionTable
-    (
-        autoPtr,
-        coordinateRotation,
-        objectRegistry,
-        (
-            const dictionary& dict, const objectRegistry& obr
-        ),
-        (dict, obr)
-    );
-
-
-    // Declare run-time constructor selection table
-    // for constructors with dictionary
+    // Declare run-time constructor selection table from dictionary
     declareRunTimeSelectionTable
     (
         autoPtr,
@@ -114,26 +99,19 @@ public:
         (dict)
     );
 
+
     // Constructors
 
+        // Uses all default constructors
+
         //- Construct and return a clone
         virtual autoPtr<coordinateRotation> clone() const = 0;
 
 
     // Selectors
 
-        //- Select constructed from dictionary and objectRegistry
-        static autoPtr<coordinateRotation> New
-        (
-            const dictionary& dict,
-            const objectRegistry& obr
-        );
-
         //- Select constructed from dictionary
-        static autoPtr<coordinateRotation> New
-        (
-            const dictionary& dict
-        );
+        static autoPtr<coordinateRotation> New(const dictionary& dict);
 
 
     //- Destructor
@@ -142,84 +120,20 @@ public:
 
     // Member Functions
 
-        //- Reset rotation to an identity rotation
+        //- Reset specification
         virtual void clear() = 0;
 
-        //- Update the rotation for a list of cells
-        virtual void updateCells
-        (
-            const polyMesh& mesh,
-            const labelList& cells
-        ) = 0;
-
-        //- Return local-to-global transformation tensor
-        virtual const tensor& R() const = 0;
-
-        //- Return global-to-local transformation tensor
-        virtual const tensor& Rtr() const = 0;
-
-        //- Return local Cartesian x-axis
-        virtual const vector e1() const = 0;
-
-        //- Return local Cartesian y-axis
-        virtual const vector e2() const = 0;
-
-        //- Return local Cartesian z-axis
-        virtual const vector e3() const = 0;
-
-        //- Return local-to-global transformation tensor
-        virtual const tensorField& Tr() const = 0;
-
-        //- Return true if the rotation tensor is uniform
-        virtual bool uniform() const
-        {
-            return true;
-        }
-
-        //- Transform vectorField using transformation tensor field
-        virtual tmp<vectorField> transform(const vectorField& st) const = 0;
-
-        //- Transform vector using transformation tensor
-        virtual vector transform(const vector& st) const = 0;
-
-        //- Inverse transform vectorField using transformation tensor field
-        virtual tmp<vectorField> invTransform(const vectorField& st) const = 0;
-
-        //- Inverse transform vector using transformation tensor
-        virtual vector invTransform(const vector& st) const = 0;
-
-        //- Transform tensor field using transformation tensorField
-        virtual tmp<tensorField> transformTensor
-        (
-            const tensorField& st
-        ) const = 0;
-
-        //- Transform tensor sub-field using transformation tensorField
-        virtual tmp<tensorField> transformTensor
-        (
-            const tensorField& st,
-            const labelList& cellMap
-        ) const = 0;
-
-        //- Transform tensor using transformation tensorField
-        virtual tensor transformTensor(const tensor& st) const = 0;
-
-        //- Transform vectorField using transformation tensorField and return
-        // symmetrical tensorField
-        virtual tmp<symmTensorField> transformVector
-        (
-            const vectorField& st
-        ) const = 0;
-
-        //- Transform vector using transformation tensor and return
-        // symmetrical tensor
-        virtual symmTensor transformVector(const vector& st) const = 0;
+        //- Calculate and return the rotation tensor
+        virtual tensor R() const = 0;
 
 
     // Write
 
-        //- Write coordinateRotation as e1,e2,e3 vectors
-        virtual void write(Ostream& os) const;
+        //- Write information
+        virtual void write(Ostream& os) const = 0;
+
+        //- Write dictionary entry
+        virtual void writeEntry(const word& keyword, Ostream& os) const = 0;
 
 };
 
diff --git a/src/meshTools/coordinate/rotation/coordinateRotationNew.C b/src/meshTools/coordinate/rotation/coordinateRotationNew.C
deleted file mode 100644
index f9ed1f1e00f051de25cb8fcf38cc90a31931794b..0000000000000000000000000000000000000000
--- a/src/meshTools/coordinate/rotation/coordinateRotationNew.C
+++ /dev/null
@@ -1,76 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2017 OpenFOAM Foundation
-     \\/     M anipulation  | Copyright (C) 2017-2018 OpenCFD Ltd.
--------------------------------------------------------------------------------
-License
-    This file is part of OpenFOAM.
-
-    OpenFOAM is free software: you can redistribute it and/or modify it
-    under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
-    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-    for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
-
-\*---------------------------------------------------------------------------*/
-
-#include "coordinateRotation.H"
-#include "objectRegistry.H"
-
-// * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
-
-Foam::autoPtr<Foam::coordinateRotation> Foam::coordinateRotation::New
-(
-    const dictionary& dict,
-    const objectRegistry& obr
-)
-{
-    const word modelType(dict.get<word>("type"));
-
-    auto cstrIter = objectRegistryConstructorTablePtr_->cfind(modelType);
-
-    if (!cstrIter.found())
-    {
-        FatalIOErrorInFunction(dict)
-            << "Unknown coordinateRotation type " << modelType << nl << nl
-            << "Valid types:  "
-            << flatOutput(objectRegistryConstructorTablePtr_->sortedToc())
-            << exit(FatalIOError);
-    }
-
-    return autoPtr<coordinateRotation>(cstrIter()(dict, obr));
-}
-
-
-Foam::autoPtr<Foam::coordinateRotation> Foam::coordinateRotation::New
-(
-    const dictionary& dict
-)
-{
-    const word modelType(dict.get<word>("type"));
-
-    auto cstrIter = dictionaryConstructorTablePtr_->cfind(modelType);
-
-    if (!cstrIter.found())
-    {
-        FatalIOErrorInFunction(dict)
-            << "Unknown coordinateRotation type " << modelType << nl << nl
-            << "Valid types:  "
-            << flatOutput(dictionaryConstructorTablePtr_->sortedToc())
-            << exit(FatalIOError);
-    }
-
-    return autoPtr<coordinateRotation>(cstrIter()(dict));
-}
-
-
-// ************************************************************************* //
diff --git a/src/meshTools/coordinate/rotation/cylindrical.C b/src/meshTools/coordinate/rotation/cylindrical.C
deleted file mode 100644
index d6253fd8a4c8b43b92e0a521a17dbb395d05dbb3..0000000000000000000000000000000000000000
--- a/src/meshTools/coordinate/rotation/cylindrical.C
+++ /dev/null
@@ -1,360 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  |
--------------------------------------------------------------------------------
-License
-    This file is part of OpenFOAM.
-
-    OpenFOAM is free software: you can redistribute it and/or modify it
-    under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
-    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-    for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
-
-\*---------------------------------------------------------------------------*/
-
-#include "cylindrical.H"
-#include "axesRotation.H"
-#include "addToRunTimeSelectionTable.H"
-#include "polyMesh.H"
-#include "tensorIOField.H"
-
-// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
-
-namespace Foam
-{
-    defineTypeNameAndDebug(cylindrical, 0);
-    addToRunTimeSelectionTable
-    (
-        coordinateRotation,
-        cylindrical,
-        dictionary
-    );
-    addToRunTimeSelectionTable
-    (
-        coordinateRotation,
-        cylindrical,
-        objectRegistry
-    );
-}
-
-
-// * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * * //
-
-void Foam::cylindrical::init
-(
-    const objectRegistry& obr,
-    const labelUList& cells
-)
-{
-    const polyMesh& mesh = refCast<const polyMesh>(obr);
-    const vectorField& cc = mesh.cellCentres();
-
-    if (cells.size())
-    {
-        Rptr_.reset(new tensorField(cells.size()));
-
-        tensorField& R = Rptr_();
-        forAll(cells, i)
-        {
-            const label celli = cells[i];
-            vector dir = cc[celli] - origin_;
-            dir /= mag(dir) + VSMALL;
-
-            R[i] = axesRotation(e3_, dir).R();
-        }
-    }
-    else
-    {
-        Rptr_.reset(new tensorField(mesh.nCells()));
-
-        tensorField& R = Rptr_();
-        forAll(cc, celli)
-        {
-            vector dir = cc[celli] - origin_;
-            dir /= mag(dir) + VSMALL;
-
-            R[celli] = axesRotation(e3_, dir).R();
-        }
-    }
-}
-
-
-// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
-
-Foam::cylindrical::cylindrical(const cylindrical& r)
-:
-    Rptr_(r.Rptr_.clone()),
-    origin_(r.origin_),
-    e3_(r.e3_)
-{}
-
-
-Foam::cylindrical::cylindrical(const tensorField& R)
-:
-    Rptr_(),
-    origin_(Zero),
-    e3_(Zero)
-{
-    Rptr_() = R;
-}
-
-
-Foam::cylindrical::cylindrical(const dictionary& dict)
-:
-    Rptr_(),
-    origin_(Zero),
-    e3_(Zero)
-{
-    FatalErrorInFunction
-        << " cylindrical can not be constructed from dictionary "
-        << " use the constructor : "
-           "("
-           "    const dictionary&, const objectRegistry&"
-           ")"
-        << exit(FatalIOError);
-}
-
-
-Foam::cylindrical::cylindrical
-(
-    const dictionary& dict,
-    const objectRegistry& obr
-)
-:
-    Rptr_(),
-    origin_(Zero),
-    e3_(Zero)
-{
-    // If origin is specified in the coordinateSystem
-    dict.parent().readIfPresent("origin", origin_);
-
-    // Rotation axis
-    dict.readEntry("e3", e3_);
-
-    init(obr);
-}
-
-
-Foam::cylindrical::cylindrical
-(
-    const objectRegistry& obr,
-    const vector& axis,
-    const point& origin
-)
-:
-    Rptr_(),
-    origin_(origin),
-    e3_(axis)
-{
-    init(obr);
-}
-
-
-Foam::cylindrical::cylindrical
-(
-    const objectRegistry& obr,
-    const vector& axis,
-    const point& origin,
-    const List<label>& cells
-)
-:
-    Rptr_(),
-    origin_(origin),
-    e3_(axis)
-{
-    init(obr, cells);
-}
-
-
-// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
-
-void Foam::cylindrical::clear()
-{
-    Rptr_.clear();
-}
-
-
-void Foam::cylindrical::updateCells
-(
-    const polyMesh& mesh,
-    const labelList& cells
-)
-{
-    const vectorField& cc = mesh.cellCentres();
-    tensorField& R = Rptr_();
-
-    forAll(cells, i)
-    {
-        const label celli = cells[i];
-        vector dir = cc[celli] - origin_;
-        dir /= mag(dir) + VSMALL;
-
-        R[celli] = axesRotation(e3_, dir).R();
-    }
-}
-
-
-Foam::tmp<Foam::vectorField> Foam::cylindrical::transform
-(
-    const vectorField& vf
-) const
-{
-    if (Rptr_->size() != vf.size())
-    {
-        FatalErrorInFunction
-            << "vectorField st has different size to tensorField "
-            << abort(FatalError);
-    }
-
-    return (Rptr_() & vf);
-}
-
-
-Foam::vector Foam::cylindrical::transform(const vector& v) const
-{
-    NotImplemented;
-    return Zero;
-}
-
-
-Foam::vector Foam::cylindrical::transform
-(
-    const vector& v,
-    const label cmptI
-) const
-{
-    return (Rptr_()[cmptI] & v);
-}
-
-
-Foam::tmp<Foam::vectorField> Foam::cylindrical::invTransform
-(
-    const vectorField& vf
-) const
-{
-    return (Rptr_().T() & vf);
-}
-
-
-Foam::vector Foam::cylindrical::invTransform(const vector& v) const
-{
-    NotImplemented;
-    return Zero;
-}
-
-
-Foam::vector Foam::cylindrical::invTransform
-(
-    const vector& v,
-    const label cmptI
-) const
-{
-    return (Rptr_()[cmptI].T() & v);
-}
-
-
-Foam::tmp<Foam::tensorField> Foam::cylindrical::transformTensor
-(
-    const tensorField& tf
-) const
-{
-    if (Rptr_->size() != tf.size())
-    {
-        FatalErrorInFunction
-            << "tensorField st has different size to tensorField Tr"
-            << abort(FatalError);
-    }
-    return (Rptr_() & tf & Rptr_().T());
-}
-
-
-Foam::tensor Foam::cylindrical::transformTensor
-(
-    const tensor& t
-) const
-{
-    NotImplemented;
-
-    return Zero;
-}
-
-
-Foam::tmp<Foam::tensorField> Foam::cylindrical::transformTensor
-(
-    const tensorField& tf,
-    const labelList& cellMap
-) const
-{
-    if (cellMap.size() != tf.size())
-    {
-        FatalErrorInFunction
-            << "tensorField tf has different size to tensorField Tr"
-            << abort(FatalError);
-    }
-
-    const tensorField& R = Rptr_();
-    const tensorField Rtr(R.T());
-    tmp<tensorField> tt(new tensorField(cellMap.size()));
-    tensorField& t = tt.ref();
-    forAll(cellMap, i)
-    {
-        const label celli = cellMap[i];
-        t[i] = R[celli] & tf[i] & Rtr[celli];
-    }
-
-    return tt;
-}
-
-
-Foam::tmp<Foam::symmTensorField> Foam::cylindrical::transformVector
-(
-    const vectorField& vf
-) const
-{
-    if (Rptr_->size() != vf.size())
-    {
-        FatalErrorInFunction
-            << "tensorField vf has different size to tensorField Tr"
-            << abort(FatalError);
-    }
-
-    tmp<symmTensorField> tfld(new symmTensorField(Rptr_->size()));
-    symmTensorField& fld = tfld.ref();
-
-    const tensorField& R = Rptr_();
-    forAll(fld, i)
-    {
-        fld[i] = transformPrincipal(R[i], vf[i]);
-    }
-    return tfld;
-}
-
-
-Foam::symmTensor Foam::cylindrical::transformVector
-(
-    const vector& v
-) const
-{
-    NotImplemented;
-    return Zero;
-}
-
-
-void Foam::cylindrical::write(Ostream& os) const
-{
-     os.writeEntry("e3", e3());
-}
-
-
-// ************************************************************************* //
diff --git a/src/meshTools/coordinate/rotation/cylindrical.H b/src/meshTools/coordinate/rotation/cylindrical.H
deleted file mode 100644
index 9f7a2463e724211c93abee9e82a45c0c512f8825..0000000000000000000000000000000000000000
--- a/src/meshTools/coordinate/rotation/cylindrical.H
+++ /dev/null
@@ -1,251 +0,0 @@
-/*---------------------------------------------------------------------------*\
-  =========                 |
-  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
-   \\    /   O peration     |
-    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  |
--------------------------------------------------------------------------------
-License
-    This file is part of OpenFOAM.
-
-    OpenFOAM is free software: you can redistribute it and/or modify it
-    under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
-    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-    for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
-
-Class
-    Foam::cylindrical
-
-Description
-    A local coordinate rotation.
-
-    The cell based rotational field can be created in two ways:
-      -# Each rotational tensor is defined with two vectors (\c dir and \c e3)
-         where <tt>dir =  cellC - origin</tt> and \c e3 is the rotation axis.
-          Per each cell an axesRotation type of rotation is created
-          (cylindrical coordinates). For example:
-          \verbatim
-          cylindrical
-          {
-              type        localAxes;
-              e3          (0 0 1);
-          }
-          \endverbatim
-
-      -# The rotational tensor field is provided at construction.
-
-SourceFiles
-    cylindrical.C
-
-\*---------------------------------------------------------------------------*/
-
-#ifndef cylindrical_H
-#define cylindrical_H
-
-#include "point.H"
-#include "vector.H"
-#include "ListOps.H"
-#include "coordinateRotation.H"
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-namespace Foam
-{
-
-/*---------------------------------------------------------------------------*\
-                         Class cylindrical Declaration
-\*---------------------------------------------------------------------------*/
-
-class cylindrical
-:
-    public coordinateRotation
-{
-    // Private data
-
-        //- An autoPtr to the transformation tensor
-        autoPtr<tensorField> Rptr_;
-
-        //- Origin of the coordinate system
-        point origin_;
-
-        //- Rotation axis
-        vector e3_;
-
-
-    // Private members
-
-        //- Init transformation tensor field
-        void init
-        (
-            const objectRegistry& obr,
-            const labelUList& cells = Foam::emptyLabelList
-        );
-
-
-public:
-
-    //- Runtime type information
-    TypeName("cylindrical");
-
-    // Constructors
-
-        //- Construct as copy
-        cylindrical(const cylindrical& r);
-
-        //- Construct from tensor Field
-        explicit cylindrical(const tensorField& R);
-
-        //- Construct from dictionary - for API compatibility only
-        explicit cylindrical(const dictionary& dict);
-
-        //- Construct from dictionary and objectRegistry
-        cylindrical(const dictionary& dict, const objectRegistry& obr);
-
-        //- Construct from components for all cells
-        cylindrical
-        (
-            const objectRegistry& obr,
-            const vector& axis,
-            const point& origin
-        );
-
-        //- Construct from components for list of cells
-        cylindrical
-        (
-            const objectRegistry& obr,
-            const vector& axis,
-            const point& origin,
-            const List<label>& cells
-        );
-
-        //- Return clone
-        autoPtr<coordinateRotation> clone() const
-        {
-            return autoPtr<coordinateRotation>::NewFrom<cylindrical>(*this);
-        }
-
-
-    //- Destructor
-    virtual ~cylindrical() = default;
-
-
-    // Member Functions
-
-        //- Reset rotation to an identity rotation
-        virtual void clear();
-
-        //- Update the rotation for a list of cells
-        virtual void updateCells(const polyMesh& mesh, const labelList& cells);
-
-        //- Return local-to-global transformation tensor
-        virtual const tensor& R() const
-        {
-            NotImplemented;
-            return tensor::zero;
-        }
-
-        //- Return global-to-local transformation tensor
-        virtual const tensor& Rtr() const
-        {
-             NotImplemented;
-             return tensor::zero;
-        }
-
-        //- Return local Cartesian x-axis in global coordinates
-        virtual const vector e1() const
-        {
-            NotImplemented;
-            return vector::zero;
-        }
-
-        //- Return local Cartesian y-axis in global coordinates
-        virtual const vector e2() const
-        {
-            NotImplemented;
-            return vector::zero;
-        }
-
-        //- Return local Cartesian z-axis in global coordinates
-        virtual const vector e3() const
-        {
-            return e3_;
-        }
-
-        virtual const tensorField& Tr() const
-        {
-            return *Rptr_;
-        }
-
-        //- Transform vectorField using transformation tensor field
-        virtual tmp<vectorField> transform(const vectorField& tf) const;
-
-        //- Transform vector using transformation tensor
-        virtual vector transform(const vector& v) const;
-
-        //- Transform vector using transformation tensor for component
-        virtual vector transform(const vector& v, const label cmptI) const;
-
-        //- Inverse transform vectorField using transformation tensor field
-        virtual tmp<vectorField> invTransform(const vectorField& vf) const;
-
-        //- Inverse transform vector using transformation tensor
-        virtual vector invTransform(const vector& v) const;
-
-        //- Inverse transform vector using transformation tensor for component
-        virtual vector invTransform(const vector& v, const label cmptI) const;
-
-        //- Return if the rotation is uniform
-        virtual bool uniform() const
-        {
-            return false;
-        }
-
-        //- Transform tensor field using transformation tensorField
-        virtual tmp<tensorField> transformTensor(const tensorField& tf) const;
-
-        //- Transform tensor using transformation tensorField
-        virtual tensor transformTensor(const tensor& t) const;
-
-        //- Transform tensor sub-field using transformation tensorField
-        virtual tmp<tensorField> transformTensor
-        (
-            const tensorField& tf,
-            const labelList& cellMap
-        ) const;
-
-        //- Transform vectorField using transformation tensorField and return
-        // symmetrical tensorField
-        virtual tmp<symmTensorField> transformVector
-        (
-            const vectorField& vf
-        ) const;
-
-        //- Transform vector using transformation tensor and return
-        // symmetrical tensor (R & st & R.T())
-        virtual symmTensor transformVector(const vector& v) const;
-
-
-    // Write
-
-        //- Write
-        virtual void write(Ostream&) const;
-};
-
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-} // End namespace Foam
-
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
-
-#endif
-
-// ************************************************************************* //
diff --git a/src/meshTools/coordinate/rotation/cylindricalRotation.C b/src/meshTools/coordinate/rotation/cylindricalRotation.C
new file mode 100644
index 0000000000000000000000000000000000000000..8086c1095c2b20bda7c8b49a5382bdc64c326dc6
--- /dev/null
+++ b/src/meshTools/coordinate/rotation/cylindricalRotation.C
@@ -0,0 +1,101 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2018 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "cylindricalRotation.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    namespace coordinateRotations
+    {
+        defineTypeName(cylindrical);
+        addToRunTimeSelectionTable
+        (
+            coordinateRotation,
+            cylindrical,
+            dictionary
+        );
+    }
+}
+
+
+// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
+
+Foam::tensor Foam::coordinateRotations::cylindrical::rotation
+(
+    const vector& axis
+)
+{
+    // Guess second axis
+    return axes::rotation(axis, Zero, E3_E1);
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::coordinateRotations::cylindrical::cylindrical(const cylindrical& crot)
+:
+    coordinateRotations::axes(crot)
+{}
+
+
+Foam::coordinateRotations::cylindrical::cylindrical(const vector& axis)
+:
+    coordinateRotations::axes(axis)  // Guess second axis
+{}
+
+
+Foam::coordinateRotations::cylindrical::cylindrical(const dictionary& dict)
+:
+    cylindrical(dict.getCompat<vector>("axis", {{"e3", -1806}}))
+{}
+
+
+// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
+
+void Foam::coordinateRotations::cylindrical::write(Ostream& os) const
+{
+    os << type() << " axis: " << axis1_;
+}
+
+
+void Foam::coordinateRotations::cylindrical::writeEntry
+(
+    const word& keyword,
+    Ostream& os
+) const
+{
+    os.beginBlock(keyword);
+
+    os.writeEntry("type", type());
+    os.writeEntry("axis", axis1_);
+
+    os.endBlock();
+}
+
+
+// ************************************************************************* //
diff --git a/src/meshTools/coordinate/rotation/cylindricalRotation.H b/src/meshTools/coordinate/rotation/cylindricalRotation.H
new file mode 100644
index 0000000000000000000000000000000000000000..488da8676f9a09981768ca855175fa7ca47e7f7c
--- /dev/null
+++ b/src/meshTools/coordinate/rotation/cylindricalRotation.H
@@ -0,0 +1,122 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
+     \\/     M anipulation  | Copyright (C) 2018 OpenCFD Ltd.
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::coordinateRotations::cylindrical
+
+Description
+    A special purpose coordinateRotation that is generally for use in
+    combination with a cylindricalCS when only the orientation of the
+    local Z-axis is relevant.
+
+    \heading Dictionary entries
+    \table
+        Property    | Description                           | Required | Default
+        type        | Type name: cylindrical                | yes   |
+        axis        | The z-axis                            | yes   |
+        e3          | Alias for 'axis'                      | no    |
+    \endtable
+
+SourceFiles
+    cylindricalRotation.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef coordinateRotations_cylindrical_H
+#define coordinateRotations_cylindrical_H
+
+#include "axesRotation.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace coordinateRotations
+{
+
+/*---------------------------------------------------------------------------*\
+              Class coordinateRotations::cylindrical Declaration
+\*---------------------------------------------------------------------------*/
+
+class cylindrical
+:
+    public coordinateRotations::axes
+{
+public:
+
+    //- Runtime type information
+    TypeNameNoDebug("cylindrical");
+
+
+    // Constructors
+
+        //- Copy construct
+        cylindrical(const cylindrical& crot);
+
+        //- Construct from single axis (as e3) using best-guess for the
+        //- second axis.
+        explicit cylindrical(const vector& axis);
+
+        //- Construct from dictionary
+        explicit cylindrical(const dictionary& dict);
+
+        //- Return clone
+        autoPtr<coordinateRotation> clone() const
+        {
+            return
+                autoPtr<coordinateRotation>::NewFrom
+                <coordinateRotations::cylindrical>(*this);
+        }
+
+
+    //- Destructor
+    virtual ~cylindrical() = default;
+
+
+    // Static Member Functions
+
+        //- The rotation tensor calculated from axes and order.
+        //  The input axes will be normalised.
+        static tensor rotation(const vector& axis);
+
+
+    // Member Functions
+
+        //- Write information
+        virtual void write(Ostream& os) const;
+
+        //- Write dictionary entry
+        virtual void writeEntry(const word& keyword, Ostream& os) const;
+
+};
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace coordinateRotations
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/meshTools/coordinate/rotation/identityRotation.C b/src/meshTools/coordinate/rotation/identityRotation.C
new file mode 100644
index 0000000000000000000000000000000000000000..f97a014e25ddf0a2bed2841e096a86681de35731
--- /dev/null
+++ b/src/meshTools/coordinate/rotation/identityRotation.C
@@ -0,0 +1,99 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2018 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "identityRotation.H"
+#include "dictionary.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    namespace coordinateRotations
+    {
+        defineTypeName(identity);
+        addToRunTimeSelectionTable
+        (
+            coordinateRotation,
+            identity,
+            dictionary
+        );
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::coordinateRotations::identity::identity()
+:
+    coordinateRotation()
+{}
+
+
+Foam::coordinateRotations::identity::identity(const identity&)
+:
+    identity()
+{}
+
+
+Foam::coordinateRotations::identity::identity(const dictionary&)
+:
+    identity()
+{}
+
+
+// * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * * //
+
+void Foam::coordinateRotations::identity::clear()
+{}
+
+
+Foam::tensor Foam::coordinateRotations::identity::R() const
+{
+    return sphericalTensor::I;
+}
+
+
+void Foam::coordinateRotations::identity::write(Ostream& os) const
+{
+    os << "identity rotation";
+}
+
+
+void Foam::coordinateRotations::identity::writeEntry
+(
+    const word& keyword,
+    Ostream& os
+) const
+{
+    os.beginBlock(keyword);
+
+    os.writeEntry("type", type());
+
+    os.endBlock();
+}
+
+
+// ************************************************************************* //
diff --git a/src/meshTools/coordinate/rotation/identityRotation.H b/src/meshTools/coordinate/rotation/identityRotation.H
new file mode 100644
index 0000000000000000000000000000000000000000..b1243a02f784bb8117c8985583b89a9e8d870776
--- /dev/null
+++ b/src/meshTools/coordinate/rotation/identityRotation.H
@@ -0,0 +1,124 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2018 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::coordinateRotations::identity
+
+Description
+    An identity coordinateRotation.
+
+    \verbatim
+    coordinateRotation
+    {
+        type    none;
+    }
+    \endverbatim
+
+    \heading Dictionary entries
+    \table
+        Property    | Description                           | Required | Default
+        type        | Type name: none                       | yes      |
+    \endtable
+
+SourceFiles
+    identityRotation.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef coordinateRotations_identity_H
+#define coordinateRotations_identity_H
+
+#include "coordinateRotation.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace coordinateRotations
+{
+
+/*---------------------------------------------------------------------------*\
+                Class coordinateRotations::identity Declaration
+\*---------------------------------------------------------------------------*/
+
+class identity
+:
+    public coordinateRotation
+{
+public:
+
+    //- Runtime type information
+    TypeNameNoDebug("none");
+
+
+    // Constructors
+
+        //- Construct null
+        identity();
+
+        //- Copy construct
+        identity(const identity& unused);
+
+        //- Construct from dictionary
+        explicit identity(const dictionary& unused);
+
+        //- Return clone
+        autoPtr<coordinateRotation> clone() const
+        {
+            return
+                autoPtr<coordinateRotation>::NewFrom
+                <coordinateRotations::identity>(*this);
+        }
+
+
+    //- Destructor
+    virtual ~identity() = default;
+
+
+    // Member Functions
+
+        //- Reset specification (no-op)
+        virtual void clear();
+
+        //- Return an identity rotation tensor
+        virtual tensor R() const;
+
+        //- Write information
+        virtual void write(Ostream& os) const;
+
+        //- Write dictionary entry
+        virtual void writeEntry(const word& keyword, Ostream& os) const;
+
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace coordinateRotations
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/meshTools/coordinate/systems/cartesianCS.C b/src/meshTools/coordinate/systems/cartesianCS.C
index f01bc18c22ac2bde9f81ff014dedcca5ceb9405c..2ecdc4891bf91c5df1f680457ec6e1ca90d30573 100644
--- a/src/meshTools/coordinate/systems/cartesianCS.C
+++ b/src/meshTools/coordinate/systems/cartesianCS.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2014 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2018 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -24,137 +24,103 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "cartesianCS.H"
-
-#include "one.H"
-#include "mathematicalConstants.H"
 #include "addToRunTimeSelectionTable.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
 namespace Foam
 {
-    defineTypeNameAndDebug(cartesianCS, 0);
-    addToRunTimeSelectionTable(coordinateSystem, cartesianCS, dictionary);
+namespace coordSystem
+{
+    defineTypeName(cartesian);
+    addToRunTimeSelectionTable(coordinateSystem, cartesian, dictionary);
+}
 }
 
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-Foam::cartesianCS::cartesianCS()
+Foam::coordSystem::cartesian::cartesian()
 :
     coordinateSystem()
 {}
 
 
-Foam::cartesianCS::cartesianCS
-(
-    const coordinateSystem& cs
-)
+Foam::coordSystem::cartesian::cartesian(const coordinateSystem& csys)
 :
-    coordinateSystem(cs)
+    coordinateSystem(csys)
 {}
 
 
-Foam::cartesianCS::cartesianCS
-(
-    const word& name,
-    const coordinateSystem& cs
-)
+Foam::coordSystem::cartesian::cartesian(coordinateSystem&& csys)
+:
+    coordinateSystem(std::move(csys))
+{}
+
+
+Foam::coordSystem::cartesian::cartesian(autoPtr<coordinateSystem>&& csys)
 :
-    coordinateSystem(name, cs)
+    coordinateSystem(std::move(csys))
 {}
 
 
-Foam::cartesianCS::cartesianCS
+Foam::coordSystem::cartesian::cartesian
 (
-    const word& name,
     const point& origin,
-    const coordinateRotation& cr
+    const coordinateRotation& crot
 )
 :
-    coordinateSystem(name, origin, cr)
+    coordinateSystem(origin, crot)
 {}
 
 
-Foam::cartesianCS::cartesianCS
+Foam::coordSystem::cartesian::cartesian
 (
-    const word& name,
     const point& origin,
     const vector& axis,
     const vector& dirn
 )
 :
-    coordinateSystem(name, origin, axis, dirn)
+    coordinateSystem(origin, axis, dirn)
 {}
 
 
-Foam::cartesianCS::cartesianCS
+Foam::coordSystem::cartesian::cartesian
 (
     const word& name,
-    const dictionary& dict
+    const point& origin,
+    const vector& axis,
+    const vector& dirn
 )
 :
-    coordinateSystem(name, dict)
+    coordinateSystem(name, origin, axis, dirn)
 {}
 
 
-Foam::cartesianCS::cartesianCS
+Foam::coordSystem::cartesian::cartesian
 (
-    const objectRegistry& obr,
+    const word& name,
     const dictionary& dict
 )
 :
-    coordinateSystem(obr, dict)
+    coordinateSystem(name, dict)
 {}
 
 
-// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
-
-Foam::cartesianCS::~cartesianCS()
+Foam::coordSystem::cartesian::cartesian(const dictionary& dict)
+:
+    coordinateSystem(dict)
 {}
 
 
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
-
-
-Foam::vector Foam::cartesianCS::localToGlobal
-(
-    const vector& local,
-    bool translate
-) const
-{
-    return coordinateSystem::localToGlobal(local, translate);
-}
-
-
-Foam::tmp<Foam::vectorField> Foam::cartesianCS::localToGlobal
+Foam::coordSystem::cartesian::cartesian
 (
-    const vectorField& local,
-    bool translate
-) const
-{
-    return coordinateSystem::localToGlobal(local, translate);
-}
-
-
-Foam::vector Foam::cartesianCS::globalToLocal
-(
-    const vector& global,
-    bool translate
-) const
-{
-    return coordinateSystem::globalToLocal(global, translate);
-}
-
-
-Foam::tmp<Foam::vectorField> Foam::cartesianCS::globalToLocal
-(
-    const vectorField& global,
-    bool translate
-) const
-{
-    return coordinateSystem::globalToLocal(global, translate);
-}
+    const dictionary& dict,
+    const word& dictName
+)
+:
+    coordinateSystem(dict, dictName)
+{}
 
 
 // ************************************************************************* //
diff --git a/src/meshTools/coordinate/systems/cartesianCS.H b/src/meshTools/coordinate/systems/cartesianCS.H
index d499f790b4700626f68421a78c60a496fed6fe83..94d712ed58d7c40b318a1f328e05b9aa3c228b43 100644
--- a/src/meshTools/coordinate/systems/cartesianCS.H
+++ b/src/meshTools/coordinate/systems/cartesianCS.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2013 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2018 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -22,10 +22,16 @@ License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
 Class
-    Foam::cartesianCS
+    Foam::coordSystem::cartesian
 
 Description
-    Cartesian coordinate system
+    A Cartesian coordinate system
+
+    \heading Dictionary entries
+    \table
+        Property    | Description                           | Required | Default
+        type        | Type name: cartesian                  | yes   |
+    \endtable
 
 SourceFiles
     cartesianCS.C
@@ -36,85 +42,61 @@ SourceFiles
 #define cartesianCS_H
 
 #include "coordinateSystem.H"
-#include "typeInfo.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 namespace Foam
 {
+namespace coordSystem
+{
 
 /*---------------------------------------------------------------------------*\
-                        Class cartesianCS Declaration
+                   Class coordSystem::cartesian Declaration
 \*---------------------------------------------------------------------------*/
 
-class cartesianCS
+class cartesian
 :
     public coordinateSystem
 {
-protected:
-
-    // Protected Member Functions
-
-
-        //- Convert from local coordinate system to the global Cartesian system
-        //  with optional translation for the origin
-        virtual vector localToGlobal(const vector&, bool translate) const;
-
-        //- Convert from local coordinate system to the global Cartesian system
-        //  with optional translation for the origin
-        virtual tmp<vectorField> localToGlobal
-        (
-            const vectorField&,
-            bool translate
-        ) const;
-
-        //- Convert from global Cartesian system to the local coordinate system
-        //  with optional translation for the origin
-        virtual vector globalToLocal(const vector&, bool translate) const;
-
-        //- Convert from global Cartesian system to the local coordinate system
-        //  with optional translation for the origin
-        virtual tmp<vectorField> globalToLocal
-        (
-            const vectorField&,
-            bool translate
-        ) const;
-
-
 public:
 
     //- Runtime type information
-    TypeName("cartesian");
+    TypeNameNoDebug("cartesian");
 
 
     // Constructors
 
-        //- Construct null
-        cartesianCS();
+        //- Construct null. This is an identity coordinateSystem.
+        cartesian();
 
-        //- Construct copy
-        cartesianCS
-        (
-            const coordinateSystem&
-        );
+        //- Copy construct
+        cartesian(const cartesian& csys) = default;
 
-        //- Construct copy with a different name
-        cartesianCS
-        (
-            const word& name,
-            const coordinateSystem&
-        );
+        //- Move construct
+        cartesian(cartesian&& csys) = default;
+
+        //- Copy construct from another coordinateSystem type
+        explicit cartesian(const coordinateSystem& csys);
+
+        //- Move construct from another coordinateSystem type
+        explicit cartesian(coordinateSystem&& csys);
+
+        //- Move construct from autoPtr of another coordinateSystem type
+        explicit cartesian(autoPtr<coordinateSystem>&& csys);
 
         //- Construct from origin and rotation
-        cartesianCS
+        cartesian(const point& origin, const coordinateRotation& crot);
+
+        //- Construct from origin and 2 axes
+        cartesian
         (
-            const word& name,
             const point& origin,
-            const coordinateRotation&
+            const vector& axis,
+            const vector& dirn
         );
 
         //- Construct from origin and 2 axes
-        cartesianCS
+        cartesian
         (
             const word& name,
             const point& origin,
@@ -122,24 +104,54 @@ public:
             const vector& dirn
         );
 
-        //- Construct from dictionary
-        cartesianCS(const word&, const dictionary&);
+        //- Construct from dictionary with a given name
+        cartesian(const word& name, const dictionary& dict);
 
+        //- Construct from dictionary without a name
+        explicit cartesian(const dictionary& dict);
 
-        //- Construct from dictionary and objectRegistry
-        cartesianCS(const objectRegistry&, const dictionary&);
+        //- Construct from dictionary with optional subDict lookup.
+        //
+        //  \param dictName If non-empty, the sub-dictionary to use.
+        cartesian(const dictionary& dict, const word& dictName);
+
+        //- Return clone
+        virtual autoPtr<coordinateSystem> clone() const
+        {
+            return autoPtr<coordinateSystem>::NewFrom<cartesian>(*this);
+        }
 
 
     //- Destructor
-    virtual ~cartesianCS();
+    virtual ~cartesian() = default;
+
 
+    // Member Operators
+
+        //- Copy assignment
+        cartesian& operator=(const cartesian&) = default;
+
+        //- Move assignment
+        cartesian& operator=(cartesian&&) = default;
+
+        //- Copy/move assignment from coordinateSystem, autoPtr
+        using coordinateSystem::operator=;
 };
 
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
+} // End namespace coordSystem
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+//- Compatibility typedef 1806
+typedef coordSystem::cartesian cartesianCS;
+
+
 } // End namespace Foam
 
+
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 #endif
diff --git a/src/meshTools/coordinate/systems/coordinateSystem.C b/src/meshTools/coordinate/systems/coordinateSystem.C
index 0428153c8eb8ab3d008499cf556aa61b550cb49d..1b6cb2911dd8f85aa6f9062e443b2b3d767fdf9f 100644
--- a/src/meshTools/coordinate/systems/coordinateSystem.C
+++ b/src/meshTools/coordinate/systems/coordinateSystem.C
@@ -23,10 +23,12 @@ License
 
 \*---------------------------------------------------------------------------*/
 
+#include "coordinateSystem.H"
+#include "cartesianCS.H"
 #include "IOstream.H"
 #include "axesRotation.H"
-#include "coordinateSystem.H"
-#include "coordinateSystems.H"
+#include "identityRotation.H"
+#include "transform.H"
 #include "addToRunTimeSelectionTable.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@@ -35,47 +37,157 @@ namespace Foam
 {
     defineTypeNameAndDebug(coordinateSystem, 0);
     defineRunTimeSelectionTable(coordinateSystem, dictionary);
+    defineRunTimeSelectionTable(coordinateSystem, registry);
+}
+
+Foam::coordinateSystem Foam::coordinateSystem::dummy_(nullptr);
+
+
+// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+    //- Is it cartesian?
+    //  For output, can treat the base class as Cartesian too,
+    //  since it defaults to cartesian on input.
+    static inline bool isCartesian(const word& modelType)
+    {
+        return
+        (
+            modelType == coordinateSystem::typeName_()
+         || modelType == coordSystem::cartesian::typeName_()
+        );
+    }
+
+} // End namespace Foam
+
+
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+void Foam::coordinateSystem::assign(const dictionary& dict)
+{
+    dict.readEntry("origin", origin_);
+
+    note_.clear();
+    dict.readIfPresent("note", note_);
+
+    // Non-recursive, no pattern search for "rotation"
+    // or "coordinateRotation" (older) sub-dictionary.
+    // Don't warn about older naming for now (OCT-2018)
+
+    const auto finder = dict.csearchCompat
+    (
+        "rotation", {{"coordinateRotation", -1806}},
+        false, false
+    );
+
+    if (finder.isDict())
+    {
+        spec_ = coordinateRotation::New(finder.dict());
+    }
+    else
+    {
+        // Fall through to expecting e1/e2/e3 specification in the dictionary
+        spec_.reset(new coordinateRotations::axes(dict));
+    }
+
+    rot_ = spec_->R();
 }
 
+
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-Foam::coordinateSystem::coordinateSystem()
+Foam::coordinateSystem::coordinateSystem(std::nullptr_t)
 :
+    spec_(),
+    origin_(Zero),
+    rot_(sphericalTensor::I),
     name_(),
-    note_(),
+    note_()
+{}
+
+
+Foam::coordinateSystem::coordinateSystem()
+:
+    spec_(new coordinateRotations::identity()),
     origin_(Zero),
-    R_(new axesRotation(sphericalTensor::I))
+    rot_(sphericalTensor::I),
+    name_(),
+    note_()
 {}
 
 
-Foam::coordinateSystem::coordinateSystem(const coordinateSystem& cs)
+Foam::coordinateSystem::coordinateSystem(const coordinateRotation& crot)
 :
-    name_(cs.name_),
-    note_(cs.note_),
-    origin_(cs.origin_),
-    R_(cs.R_.clone())
+    coordinateSystem(word::null, point::zero, crot)
 {}
 
 
-Foam::coordinateSystem::coordinateSystem(coordinateSystem&& cs)
+Foam::coordinateSystem::coordinateSystem(coordinateRotation&& crot)
 :
-    name_(std::move(cs.name_)),
-    note_(std::move(cs.note_)),
-    origin_(std::move(cs.origin_)),
-    R_(std::move(cs.R_))
+    coordinateSystem(word::null, point::zero, std::move(crot))
 {}
 
 
+Foam::coordinateSystem::coordinateSystem(const coordinateSystem& csys)
+:
+    spec_(csys.spec_.clone()),
+    origin_(csys.origin_),
+    rot_(csys.rot_),
+    name_(csys.name_),
+    note_(csys.note_)
+{}
+
+
+Foam::coordinateSystem::coordinateSystem(coordinateSystem&& csys)
+:
+    spec_(std::move(csys.spec_)),
+    origin_(std::move(csys.origin_)),
+    rot_(std::move(csys.rot_)),
+    name_(std::move(csys.name_)),
+    note_(std::move(csys.note_))
+{}
+
+
+Foam::coordinateSystem::coordinateSystem(autoPtr<coordinateSystem>&& csys)
+:
+    coordinateSystem(nullptr)
+{
+    if (csys)
+    {
+        // Has valid autoPtr - move.
+        coordinateSystem::operator=(std::move(*csys));
+        csys.clear();
+    }
+    else
+    {
+        // No valid autoPtr - treat like identity
+        spec_.reset(new coordinateRotations::identity());
+    }
+}
+
+
 Foam::coordinateSystem::coordinateSystem
 (
     const word& name,
-    const coordinateSystem& cs
+    const coordinateSystem& csys
 )
 :
+    spec_(csys.spec_.clone()),
+    origin_(csys.origin_),
+    rot_(csys.rot_),
     name_(name),
-    note_(cs.note_),
-    origin_(cs.origin_),
-    R_(cs.R_.clone())
+    note_(csys.note_)
+{}
+
+
+Foam::coordinateSystem::coordinateSystem
+(
+    const point& origin,
+    const coordinateRotation& crot
+)
+:
+    coordinateSystem(word::null, origin, crot)
 {}
 
 
@@ -83,13 +195,25 @@ Foam::coordinateSystem::coordinateSystem
 (
     const word& name,
     const point& origin,
-    const coordinateRotation& cr
+    const coordinateRotation& crot
 )
 :
-    name_(name),
-    note_(),
+    spec_(crot.clone()),
     origin_(origin),
-    R_(cr.clone())
+    rot_(spec_->R()),
+    name_(name),
+    note_()
+{}
+
+
+Foam::coordinateSystem::coordinateSystem
+(
+    const point& origin,
+    const vector& axis,
+    const vector& dirn
+)
+:
+    coordinateSystem(word::null, origin, axis, dirn)
 {}
 
 
@@ -101,10 +225,11 @@ Foam::coordinateSystem::coordinateSystem
     const vector& dirn
 )
 :
-    name_(name),
-    note_(),
+    spec_(new coordinateRotations::axes(axis, dirn)),
     origin_(origin),
-    R_(new axesRotation(axis, dirn))
+    rot_(spec_->R()),
+    name_(name),
+    note_()
 {}
 
 
@@ -114,119 +239,91 @@ Foam::coordinateSystem::coordinateSystem
     const dictionary& dict
 )
 :
-    name_(name),
-    note_(),
+    spec_(nullptr),
     origin_(Zero),
-    R_()
+    rot_(sphericalTensor::I),
+    name_(name),
+    note_()
 {
-    init(dict);
+    assign(dict);
 }
 
 
 Foam::coordinateSystem::coordinateSystem(const dictionary& dict)
 :
-    name_(),
-    note_(),
-    origin_(Zero),
-    R_()
-{
-    init(dict);
-}
+    coordinateSystem(word::null, dict)
+{}
 
 
 Foam::coordinateSystem::coordinateSystem
 (
-    const objectRegistry& obr,
-    const dictionary& dict
+    const dictionary& dict,
+    const word& dictName
 )
 :
-    name_(),
-    note_(),
-    origin_(Zero),
-    R_()
+    coordinateSystem(nullptr)
 {
-    const entry* entryPtr = dict.lookupEntryPtr(typeName_(), false, false);
-
-    if (!entryPtr)
-    {
-        // No 'coordinateSystem' entry
-        init(dict, obr);
-    }
-    else if (entryPtr->isDict())
+    if (dictName.size())
     {
-        // 'coordinateSystem' as dictionary entry - use it
-        init(entryPtr->dict(), obr);
+        assign(dict.subDict(dictName));
     }
     else
     {
-        // 'coordinateSystem' as non-dictionary entry
-        // - this is a lookup into global coordinateSystems
+        assign(dict);
+    }
+}
 
-        keyType key(entryPtr->stream());
 
-        const coordinateSystems& lst = coordinateSystems::New(obr);
-        const label index = lst.findIndex(key);
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-        if (debug)
-        {
-            InfoInFunction
-                << "Using global coordinate system: "
-                << key << "=" << index << endl;
-        }
+void Foam::coordinateSystem::clear()
+{
+    spec_->clear();
+    origin_ = Zero;
+    rot_ = sphericalTensor::I;
+    note_.clear();
+}
 
-        if (index < 0)
-        {
-            FatalErrorInFunction
-                << "could not find coordinate system: " << key << nl
-                << "available coordinate systems: " << lst.toc() << nl << nl
-                << exit(FatalError);
-        }
 
-        // Copy from coordinateSystem, but assign the name as the typeName
-        // to avoid strange things in writeDict()
-        operator=(lst[index]);
-        name_ = typeName_();
-    }
+Foam::tensor Foam::coordinateSystem::R(const point& global) const
+{
+    return rot_;
 }
 
 
-Foam::coordinateSystem::coordinateSystem(Istream& is)
-:
-    name_(is),
-    note_(),
-    origin_(Zero),
-    R_()
+Foam::tmp<Foam::tensorField> Foam::coordinateSystem::R
+(
+    const UList<point>& global
+) const
 {
-    dictionary dict(is);
-    init(dict);
+    return rotationsImpl(global);
 }
 
 
-// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
-
-Foam::dictionary Foam::coordinateSystem::dict(bool ignoreType) const
+Foam::tmp<Foam::tensorField> Foam::coordinateSystem::R
+(
+    const pointUIndList& global
+) const
 {
-    dictionary dict;
-
-    dict.add("name", name_);
+    return rotationsImpl(global);
+}
 
-    // Only write type for derived types
-    if (!ignoreType && type() != typeName_())
-    {
-        dict.add("type", type());
-    }
 
-    // The note entry is optional
-    if (note_.size())
-    {
-        dict.add("note", note_);
-    }
+Foam::point Foam::coordinateSystem::transformPoint
+(
+    const point& localCart
+) const
+{
+    return Foam::transform(rot_, localCart) + origin_;
+}
 
-    dict.add("origin", origin_);
-    dict.add("e1", R_->e1());
-    dict.add("e3", R_->e3());
 
-    return dict;
+Foam::point Foam::coordinateSystem::invTransformPoint
+(
+    const point& global
+) const
+{
+    return Foam::invTransform(rot_, global - origin_);
 }
 
 
@@ -238,10 +335,10 @@ Foam::vector Foam::coordinateSystem::localToGlobal
 {
     if (translate)
     {
-        return (R_->transform(local)) + origin_;
+        return this->transform(local) + origin_;
     }
 
-    return R_->transform(local);
+    return this->transform(local);
 }
 
 
@@ -253,10 +350,10 @@ Foam::tmp<Foam::vectorField> Foam::coordinateSystem::localToGlobal
 {
     if (translate)
     {
-        return (R_->transform(local)) + origin_;
+        return this->transform(local) + origin_;
     }
 
-    return R_->transform(local);
+    return this->transform(local);
 }
 
 
@@ -268,10 +365,10 @@ Foam::vector Foam::coordinateSystem::globalToLocal
 {
     if (translate)
     {
-        return R_->invTransform(global - origin_);
+        return this->invTransform(global - origin_);
     }
 
-    return R_->invTransform(global);
+    return this->invTransform(global);
 }
 
 
@@ -283,54 +380,74 @@ Foam::tmp<Foam::vectorField> Foam::coordinateSystem::globalToLocal
 {
     if (translate)
     {
-        return R_->invTransform(global - origin_);
+        return this->invTransform(global - origin_);
     }
 
-    return R_->invTransform(global);
+    return this->invTransform(global);
 }
 
 
-void Foam::coordinateSystem::clear()
+void Foam::coordinateSystem::rotation(autoPtr<coordinateRotation>&& crot)
 {
-    note_.clear();
-    origin_ = Zero;
-    R_->clear();
+    spec_.reset(std::move(crot));
+    if (spec_)
+    {
+        rot_ = spec_->R();
+    }
+    else
+    {
+        rot_ = sphericalTensor::I;
+    }
 }
 
 
-void Foam::coordinateSystem::transfer(coordinateSystem& cs)
+void Foam::coordinateSystem::write(Ostream& os) const
 {
-    name_ = std::move(cs.name_);
-    note_ = std::move(cs.note_);
-    origin_ = std::move(cs.origin_);
-    R_ = std::move(cs.R_);
-}
+    if (!valid())
+    {
+        return;
+    }
 
+    // Suppress output of type for Cartesian
+    if (!isCartesian(type()))
+    {
+        os << type() << ' ';
+    }
 
-void Foam::coordinateSystem::write(Ostream& os) const
-{
-    os  << type() << " origin: " << origin() << nl;
-    R_->write(os);
+    os << "origin: " << origin_ << ' ';
+    spec_->write(os);
 }
 
 
-void Foam::coordinateSystem::writeDict(Ostream& os, bool subDict) const
+void Foam::coordinateSystem::writeEntry(const word& keyword, Ostream& os) const
 {
-    if (subDict)
+    if (!valid())
     {
-        os.beginBlock(name_);
+        return;
     }
 
-    os.writeEntry("type", type());
+    const bool subDict = !keyword.empty();
 
-    if (note_.size())
+    if (subDict)
     {
-        // The 'note' is optional
-        os.writeEntry("note", note_);
+        os.beginBlock(keyword);
+
+        // Suppress output of type for Cartesian
+        if (!isCartesian(type()))
+        {
+            os.writeEntry<word>("type", type());
+        }
+
+        if (note_.size())
+        {
+            // The 'note' is optional
+            os.writeEntry("note", note_);
+        }
     }
 
     os.writeEntry("origin", origin_);
-    R_->write(os);
+
+    spec_->writeEntry("rotation", os);
 
     if (subDict)
     {
@@ -341,71 +458,64 @@ void Foam::coordinateSystem::writeDict(Ostream& os, bool subDict) const
 
 // * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
 
-void Foam::coordinateSystem::operator=(const coordinateSystem& cs)
+void Foam::coordinateSystem::operator=(const coordinateSystem& csys)
 {
-    name_ = cs.name_;
-    note_ = cs.note_;
-    origin_ = cs.origin_;
+    name_ = csys.name_;
+    note_ = csys.note_;
+    origin_ = csys.origin_;
 
     // Some extra safety
-    if (cs.R_.valid())
+    if (csys.spec_)
     {
-        R_ = cs.R_.clone();
+        rotation(csys.spec_.clone());
     }
     else
     {
-        R_.reset(new axesRotation(sphericalTensor::I));
+        spec_.reset(new coordinateRotations::identity());
+        rot_ = sphericalTensor::I;
     }
 }
 
-void Foam::coordinateSystem::operator=(coordinateSystem&& cs)
+
+void Foam::coordinateSystem::operator=(coordinateSystem&& csys)
 {
-    transfer(cs);
+    name_ = std::move(csys.name_);
+    note_ = std::move(csys.note_);
+    spec_ = std::move(csys.spec_);
+    origin_ = csys.origin_;
+    rot_ = csys.rot_;
 }
 
 
-void Foam::coordinateSystem::init(const dictionary& dict)
+void Foam::coordinateSystem::operator=(const autoPtr<coordinateSystem>& csys)
 {
-    dict.readEntry("origin", origin_);
-    note_.clear();
-    dict.readIfPresent("note", note_);
-    R_ = coordinateRotation::New(dict.subDict("coordinateRotation"));
+    coordinateSystem::operator=(*csys);
 }
 
 
-void Foam::coordinateSystem::init
-(
-    const dictionary& dict,
-    const objectRegistry& obr
-)
+void Foam::coordinateSystem::operator=(autoPtr<coordinateSystem>&& csys)
 {
-    dict.readEntry("origin", origin_);
-
-    // The 'note' entry is optional
-    note_.clear();
-    dict.readIfPresent("note", note_);
-    R_ = coordinateRotation::New(dict.subDict("coordinateRotation"), obr);
+    coordinateSystem::operator=(std::move(*csys));
+    csys.clear();
 }
 
 
-// * * * * * * * * * * * * * * * Friend Operators  * * * * * * * * * * * * * //
+// * * * * * * * * * * * * * * * Global Operators  * * * * * * * * * * * * * //
 
 bool Foam::operator!=(const coordinateSystem& a, const coordinateSystem& b)
 {
     return
     (
-        a.origin() != b.origin()
-     || a.type() != b.type()
-     || a.R().R() != b.R().R()
+        a.type() != b.type()
+     || a.origin() != b.origin()
+     || a.R() != b.R()
     );
 }
 
 
-// * * * * * * * * * * * * * * * Friend Functions  * * * * * * * * * * * * * //
-
-Foam::Ostream& Foam::operator<<(Ostream& os, const coordinateSystem& cs)
+Foam::Ostream& Foam::operator<<(Ostream& os, const coordinateSystem& csys)
 {
-    cs.write(os);
+    csys.write(os);
     os.check(FUNCTION_NAME);
     return os;
 }
diff --git a/src/meshTools/coordinate/systems/coordinateSystem.H b/src/meshTools/coordinate/systems/coordinateSystem.H
index d47608b392e3d79eb5162a34e0252e3ce9f25029..e57f691e61f251caf9e681d70a65f7f98caab27b 100644
--- a/src/meshTools/coordinate/systems/coordinateSystem.H
+++ b/src/meshTools/coordinate/systems/coordinateSystem.H
@@ -21,40 +21,66 @@ License
     You should have received a copy of the GNU General Public License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
+Namespace
+    Foam::coordSystem
+
+Description
+    Namespace for coordinate systems.
+
 Class
     Foam::coordinateSystem
 
 Description
-    Base class for other coordinate system specifications.
+    Base class for coordinate system specification,
+    the default coordinate system type is
+    \link coordSystem::cartesian cartesian \endlink.
+
+    All systems are defined by an origin point and a coordinate rotation
+    By default, the \link coordinateRotations::axes axes \endlink
+    specification can be used directly as part of the
+    coordinate system specification. For example,
 
-    All systems are defined by an origin point and a co-ordinate rotation.
+    \verbatim
+    coordinateSystem
+    {
+        origin  (0 0 0);
+        e1      (0 1 0);
+        e3      (1 0 0);
+    }
+    \endverbatim
 
+    The same, but in more verbose format:
     \verbatim
     coordinateSystem
     {
         type    cartesian;
         origin  (0 0 0);
-        coordinateRotation
+        rotation
         {
-            type        cylindrical;
-            e3          (0 0 1);
+            type    axes;
+            e1      (0 1 0);
+            e3      (1 0 0);
         }
     }
     \endverbatim
 
     Types of coordinateRotation:
-      -# axesRotation
-      -# \link STARCDCoordinateRotation STARCDRotation \endlink
-      -# cylindricalCS cylindrical
-      -# EulerCoordinateRotation
-
-    Type of co-ordinates:
-      -# \link cartesianCS cartesian \endlink
-
+      -# \link coordinateRotations::identity none \endlink
+      -# \link coordinateRotations::axes axes \endlink
+      -# \link coordinateRotations::axisAngle axisAngle \endlink
+      -# \link coordinateRotations::euler euler \endlink
+      -# \link coordinateRotations::starcd starcd \endlink
+
+    Type of coordinateSystem:
+      -# \link coordSystem::cartesian cartesian \endlink
+      -# \link coordSystem::cylindrical cylindrical \endlink
+      -# \link coordSystem::indirect indirect \endlink (references
+      an entry in coordinateSystems).
 
 SourceFiles
     coordinateSystem.C
     coordinateSystemNew.C
+    coordinateSystemTransform.C
 
 \*---------------------------------------------------------------------------*/
 
@@ -66,79 +92,151 @@ SourceFiles
 #include "tensor.H"
 #include "vectorField.H"
 #include "pointField.H"
-#include "tmp.H"
+#include "tensorField.H"
+#include "pointIndList.H"
 #include "coordinateRotation.H"
-#include "objectRegistry.H"
 #include "autoPtr.H"
+#include "tmp.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 namespace Foam
 {
 
-// Forward declarations
-
+// Forward Declarations
 class coordinateSystem;
+class objectRegistry;
 
-bool operator!=(const coordinateSystem&, const coordinateSystem&);
-Ostream& operator<<(Ostream&, const coordinateSystem&);
+namespace coordSystem
+{
+class indirect;
+}
 
 
 /*---------------------------------------------------------------------------*\
-                     Class coordinateSystem Declaration
+                      Class coordinateSystem Declaration
 \*---------------------------------------------------------------------------*/
 
 class coordinateSystem
 {
-    // Private data
+    // Private Member Functions
 
-        //- Name of coordinate system
-        word name_;
+        //- Use 'coordinateSystem' sub-dictionary if present
+        static const dictionary* subDictCompat(const dictionary* dictPtr);
 
-        //- Optional note
-        string note_;
 
-        //- Origin
-        point origin_;
+protected:
+
+    //- Friendship with indirect for dispatching to its underlying system
+    friend coordSystem::indirect;
 
-        //- Local-to-Global transformation tensor.
+
+    // Protected Data
+
+        //- User specification of the coordinate rotation
         //  May be invalid after a move assignment or transfer
-        autoPtr<coordinateRotation> R_;
+        autoPtr<coordinateRotation> spec_;
+
+        //- The coordinate system origin
+        point origin_;
 
+        //- The rotation tensor
+        tensor rot_;
+
+        //- The name of the coordinate system (optional)
+        word name_;
+
+        //- An optional note describing the coordinate system
+        string note_;
+
+        //- Dummy coordinate system for suppressed manipulation
+        static coordinateSystem dummy_;
 
-protected:
 
     // Protected Member Functions
 
-        //- Convert from local coordinate system to the global Cartesian system
+        //- Implementation for R() methods
+        template<class PointField>
+        tmp<tensorField> rotationsImpl(const PointField& global) const;
+
+        //- Implementation for transformPoint() methods
+        template<class PointField>
+        tmp<pointField> transformPointImpl(const PointField& localCart) const;
+
+        //- Implementation for transformPosition() methods
+        template<class PointField>
+        tmp<pointField> invTransformPointImpl(const PointField& global) const;
+
+        //- Apply single transform tensor for multiple inputs
+        template<class RetType, class Type, class BinaryOp>
+        static tmp<Field<RetType>> manyTimesImpl
+        (
+            const tensor& tt,
+            const UList<Type>& input,
+            const BinaryOp& bop
+        );
+
+        //- Use position-dependent transform tensors for multiple inputs
+        template<class RetType, class PointField, class Type, class BinaryOp>
+        tmp<Field<RetType>> oneToOneImpl
+        (
+            const PointField& global,
+            const UList<Type>& input,
+            const BinaryOp& bop
+        ) const;
+
+        //- Use position-dependent transform tensors for single input
+        template<class RetType, class PointField, class Type, class BinaryOp>
+        tmp<Field<RetType>> oneToManyImpl
+        (
+            const PointField& global,
+            const Type& input,
+            const BinaryOp& bop
+        ) const;
+
+
+        //- From local coordinate system to the global Cartesian system
         //- with optional translation for the origin
-        virtual vector localToGlobal(const vector&, bool translate) const;
+        virtual vector localToGlobal
+        (
+            const vector& local,
+            bool translate
+        ) const;
 
-        //- Convert from local coordinate system to the global Cartesian system
+        //- From local coordinate system to the global Cartesian system
         //- with optional translation for the origin
         virtual tmp<vectorField> localToGlobal
         (
-            const vectorField&,
+            const vectorField& local,
             bool translate
         ) const;
 
-        //- Convert from global Cartesian system to the local coordinate system
+        //- From global Cartesian system to the local coordinate system
         //- with optional translation for the origin
-        virtual vector globalToLocal(const vector&, bool translate) const;
+        virtual vector globalToLocal
+        (
+            const vector& global,
+            bool translate
+        ) const;
 
-        //- Convert from global Cartesian system to the local coordinate system
+        //- From global Cartesian system to the local coordinate system
         //- with optional translation for the origin
         virtual tmp<vectorField> globalToLocal
         (
-            const vectorField&,
+            const vectorField& global,
             bool translate
         ) const;
 
-        //- Init from dict and obr
-        void init(const dictionary& dict);
 
-        //- Init from dictionary
-        void init(const dictionary& dict, const objectRegistry& obr);
+        //- Assign from dictionary content
+        void assign(const dictionary& dict);
+
+
+    // Constructors
+
+        //- Construct null, without allocating a coordinateRotation
+        //- specification.
+        coordinateSystem(std::nullptr_t);
 
 
 public:
@@ -146,23 +244,57 @@ public:
     //- Runtime type information
     TypeName("coordinateSystem");
 
+        //- Helper for construction of coordinateSystem PtrList
+        //  The Istream contains a word followed by a dictionary
+        struct iNew
+        {
+            autoPtr<coordinateSystem> operator()(Istream& is) const
+            {
+                return coordinateSystem::New(is);
+            }
+        };
+
 
     // Constructors
 
-        //- Construct null. This is equivalent to an identity coordinateSystem
+        //- Construct null. This is an identity coordinateSystem.
         coordinateSystem();
 
+        //- Copy construct from rotation with origin=0
+        explicit coordinateSystem(const coordinateRotation& crot);
+
+        //- Move construct from rotation with origin=0
+        explicit coordinateSystem(coordinateRotation&& crot);
+
         //- Copy construct
-        coordinateSystem(const coordinateSystem& cs);
+        coordinateSystem(const coordinateSystem& csys);
 
         //- Move construct
-        coordinateSystem(coordinateSystem&& cs);
+        coordinateSystem(coordinateSystem&& csys);
+
+        //- Move construct from autoPtr
+        explicit coordinateSystem(autoPtr<coordinateSystem>&& csys);
 
         //- Copy construct with a different name
         coordinateSystem
         (
             const word& name,
-            const coordinateSystem& cs
+            const coordinateSystem& csys
+        );
+
+        //- Construct from origin and rotation
+        coordinateSystem
+        (
+            const point& origin,
+            const coordinateRotation& crot
+        );
+
+        //- Construct from origin and 2 axes
+        coordinateSystem
+        (
+            const point& origin,
+            const vector& axis,
+            const vector& dirn
         );
 
         //- Construct from origin and rotation
@@ -170,7 +302,7 @@ public:
         (
             const word& name,
             const point& origin,
-            const coordinateRotation&
+            const coordinateRotation& crot
         );
 
         //- Construct from origin and 2 axes
@@ -185,20 +317,17 @@ public:
         //- Construct from dictionary with a given name
         coordinateSystem(const word& name, const dictionary& dict);
 
-        //- Construct from dictionary with default name
+        //- Construct from dictionary without a name
         explicit coordinateSystem(const dictionary& dict);
 
-        //- Construct from dictionary (default name)
-        //  With the ability to reference global coordinateSystems
-        coordinateSystem(const objectRegistry& obr, const dictionary& dict);
-
-        //- Construct from Istream
-        //  The Istream contains a word followed by a dictionary
-        coordinateSystem(Istream& is);
+        //- Construct from dictionary with optional subDict lookup.
+        //
+        //  \param dictName If non-empty, the sub-dictionary to use.
+        coordinateSystem(const dictionary& dict, const word& dictName);
 
 
     //- Return clone
-    autoPtr<coordinateSystem> clone() const
+    virtual autoPtr<coordinateSystem> clone() const
     {
         return autoPtr<coordinateSystem>::New(*this);
     }
@@ -210,6 +339,18 @@ public:
         autoPtr,
         coordinateSystem,
         dictionary,
+        (
+            const dictionary& dict
+        ),
+        (dict)
+    );
+
+    // Declare run-time constructor selection table
+    declareRunTimeSelectionTable
+    (
+        autoPtr,
+        coordinateSystem,
+        registry,
         (
             const objectRegistry& obr,
             const dictionary& dict
@@ -220,20 +361,57 @@ public:
 
     // Selectors
 
-        //- Select constructed from dictionary and objectRegistry
+        //- Select construct the specified coordinate system type
+        //- with reference to objectRegistry for indirect entries.
+        //
+        //  An empty modelType will be treated as "cartesian"
         static autoPtr<coordinateSystem> New
         (
+            word modelType,
             const objectRegistry& obr,
             const dictionary& dict
         );
 
-        //- Select constructed from dictionary
+        //- Select construct the specified coordinate system type
+        //
+        //  An empty modelType will be treated as "cartesian"
         static autoPtr<coordinateSystem> New
         (
+            word modelType,
             const dictionary& dict
         );
 
+        //- Select construct from dictionary with reference to objectRegistry
+        //- for indirect entries.
+        //
+        //  \param dictName If non-empty, the sub-dictionary name to use
+        //      for the coordinate system description.
+        //
+        //  \note When the dictName is empty, it includes an implicit search
+        //      for a "coordinateSystem" sub-dictionary for convenience and
+        //      compatibility with previous versions (1806 and earlier).
+        static autoPtr<coordinateSystem> New
+        (
+            const objectRegistry& obr,
+            const dictionary& dict,
+            const word& dictName = ""
+        );
+
+        //- Select constructed from dictionary
+        //  \param dictName If non-empty, the sub-dictionary name to use
+        //      for the coordinate system description.
+        //
+        //  \note When the dictName is empty, it includes an implicit search
+        //      for a "coordinateSystem" sub-dictionary for convenience and
+        //      compatibility with previous versions (1806 and earlier).
+        static autoPtr<coordinateSystem> New
+        (
+            const dictionary& dict,
+            const word& dictName = ""
+        );
+
         //- Select constructed from Istream
+        //  Expects a name/dictionary as input
         static autoPtr<coordinateSystem> New(Istream& is);
 
 
@@ -243,183 +421,308 @@ public:
 
     // Member Functions
 
-        // Access
+    // Access
 
-            //- Return name
-            const word& name() const
-            {
-                return name_;
-            }
+        //- Considered valid if it has a specification
+        virtual bool valid() const
+        {
+            return spec_.valid();
+        }
 
-            //- Return non-constant access to the optional note
-            string& note()
-            {
-                return note_;
-            }
+        //- True if the rotation tensor is uniform for all locations
+        virtual bool uniform() const
+        {
+            return true;
+        }
 
-            //- Return the optional note
-            const string& note() const
-            {
-                return note_;
-            }
+        //- The rotation specification
+        virtual const coordinateRotation& rotation() const
+        {
+            return *spec_;
+        }
 
-            //- Return origin
-            const point& origin() const
-            {
-                return origin_;
-            }
+        //- Return the name
+        virtual const word& name() const
+        {
+            return name_;
+        }
 
-            //- Return const reference to co-ordinate rotation
-            const coordinateRotation& R() const
-            {
-                return *R_;
-            }
+        //- Return the optional note
+        virtual const string& note() const
+        {
+            return note_;
+        }
 
-            //- Return non const reference to co-ordinate rotation
-            coordinateRotation& R()
-            {
-                return *R_;
-            }
+        //- Return origin
+        virtual const point& origin() const
+        {
+            return origin_;
+        }
 
-            //- Update and return the co-ordinate rotation for a list of cells
-            const coordinateRotation& R
-            (
-                const polyMesh& mesh,
-                const labelList& cells
-            )
-            {
-                R_->updateCells(mesh, cells);
-                return *R_;
-            }
+        //- Return const reference to the rotation tensor
+        virtual const tensor& R() const
+        {
+            return rot_;
+        }
 
-            //- Return as dictionary of entries
-            //  \param[in] ignoreType drop type (cartesian, cylindrical, etc)
-            //  when generating the dictionary
-            virtual dictionary dict(bool ignoreType=false) const;
+        //- The local Cartesian x-axis in global coordinates
+        virtual const vector e1() const
+        {
+            return rot_.cx();
+        }
 
+        //- The local Cartesian y-axis in global coordinates
+        virtual const vector e2() const
+        {
+            return rot_.cy();
+        }
 
-        // Edit
+        //- The local Cartesian z-axis in global coordinates
+        virtual const vector e3() const
+        {
+            return rot_.cz();
+        }
 
-            //- Rename
-            void rename(const word& newName)
-            {
-                name_ = newName;
-            }
 
-            //- Edit access to origin
-            point& origin()
-            {
-                return origin_;
-            }
+    // Edit
 
-            //- Reset origin and rotation to an identity coordinateSystem
-            //  Also resets the note
-            virtual void clear();
+        //- Rename
+        virtual void rename(const word& newName)
+        {
+            name_ = newName;
+        }
 
-            //- Transfer contents from parameter
-            void transfer(coordinateSystem& cs);
+        //- Provide non-constant access to the optional note
+        virtual string& note()
+        {
+            return note_;
+        }
 
+        //- Edit access to origin
+        virtual point& origin()
+        {
+            return origin_;
+        }
 
-        // Write
+        //- Reset origin and rotation to an identity coordinateSystem
+        //  Also resets the note
+        virtual void clear();
 
-            //- Write
-            virtual void write(Ostream& os) const;
+        //- Change the rotation
+        virtual void rotation(autoPtr<coordinateRotation>&& crot);
 
-            //- Write dictionary
-            void writeDict(Ostream& os, bool subDict=true) const;
 
+    // Write
 
-        // Transformations
+        //- Write
+        virtual void write(Ostream& os) const;
 
-            //- Convert from position in local coordinate system to global
-            //  Cartesian position
-            point globalPosition(const point& local) const
-            {
-                return localToGlobal(local, true);
-            }
+        //- Write dictionary entry
+        virtual void writeEntry(const word& keyword, Ostream& os) const;
 
-            //- Convert from position in local coordinate system to global
-            //  Cartesian position
-            tmp<pointField> globalPosition(const pointField& local) const
-            {
-                return localToGlobal(local, true);
-            }
 
-            //- Convert from vector components in local coordinate system to
-            //  global Cartesian vector
-            vector globalVector(const vector& local) const
-            {
-                return localToGlobal(local, false);
-            }
+    // Member Operators
 
-            //- Convert from vector components in local coordinate system to
-            //  global Cartesian vector
-            tmp<vectorField> globalVector(const vectorField& local) const
-            {
-                return localToGlobal(local, false);
-            }
+        //- Copy assignment
+        void operator=(const coordinateSystem& csys);
 
-            //- Convert from global Cartesian position to position in local
-            //  coordinate system
-            point localPosition(const point& global) const
-            {
-                return globalToLocal(global, true);
-            }
+        //- Move assignment
+        void operator=(coordinateSystem&& csys);
 
-            //- Convert from global Cartesian position to position in local
-            //  coordinate system
-            tmp<pointField> localPosition(const pointField& global) const
-            {
-                return globalToLocal(global, true);
-            }
+        //- Copy assignment from autoPtr
+        void operator=(const autoPtr<coordinateSystem>& csys);
 
-            //- Convert from global Cartesian vector to components in local
-            //  coordinate system
-            vector localVector(const vector& global) const
-            {
-                return globalToLocal(global, false);
-            }
+        //- Move assignment from autoPtr
+        void operator=(autoPtr<coordinateSystem>&& csys);
 
-            //- Convert from global Cartesian vector to components in local
-            //  coordinate system
-            tmp<vectorField> localVector(const vectorField& global) const
-            {
-                return globalToLocal(global, false);
-            }
 
+    // Rotation
 
-    // Member Operators
+        //- Position-dependent rotation tensor (when uniform = false)
+        //- \return tensor
+        virtual tensor R(const point& global) const;
 
-        //- Copy assignment
-        void operator=(const coordinateSystem& cs);
+        //- Position-dependent rotation tensors (when uniform = false)
+        //- \return tensorField
+        virtual tmp<tensorField> R(const UList<point>& global) const;
 
-        //- Move assignment
-        void operator=(coordinateSystem&& cs);
+        //- Position-dependent rotation tensors (when uniform = false)
+        //- \return tensorField
+        virtual tmp<tensorField> R(const pointUIndList& global) const;
+
+
+    // Position
+
+        //- Transform point and add origin offset.
+        //  Corresponds to a local-to-global transformation using Cartesian
+        //  coordinates for both local and global.
+        point transformPoint(const point& localCart) const;
+
+        //- Transform points and add origin offset.
+        tmp<pointField> transformPoint(const UList<point>& localCart) const;
 
+        //- Transform points and add origin offset.
+        tmp<pointField> transformPoint(const pointUIndList& localCart) const;
 
-        // Friend Operators
 
-            friend bool operator!=
-            (
-                const coordinateSystem& a,
-                const coordinateSystem& b
-            );
+        //- Remove origin offset and inverse transform point.
+        //  Corresponds to a global-to-local transformation using Cartesian
+        //  coordinates for both local and global.
+        point invTransformPoint(const point& global) const;
 
+        //- Remove origin offset and inverse transform points.
+        tmp<pointField> invTransformPoint(const UList<point>& global) const;
 
-        // IOstream Operators
+        //- Remove origin offset and inverse transform points.
+        tmp<pointField> invTransformPoint(const pointUIndList& global) const;
 
-            friend Ostream& operator<<
-            (
-                Ostream& os,
-                const coordinateSystem& cs
-            );
+
+    // Transformations with change of coordinate types
+
+        //- From local coordinate position to global (cartesian) position
+        point globalPosition(const point& local) const
+        {
+            return localToGlobal(local, true);
+        }
+
+        //- From local coordinate position to global (cartesian) position
+        tmp<pointField> globalPosition(const pointField& local) const
+        {
+            return localToGlobal(local, true);
+        }
+
+        //- From global (cartesian) position to local coordinate position
+        point localPosition(const point& global) const
+        {
+            return globalToLocal(global, true);
+        }
+
+        //- From global (cartesian) position to local coordinate position
+        tmp<pointField> localPosition(const pointField& global) const
+        {
+            return globalToLocal(global, true);
+        }
+
+
+
+        //- From local to global (cartesian) vector components
+        vector globalVector(const vector& local) const
+        {
+            return localToGlobal(local, false);
+        }
+
+        //- From local to global (cartesian) vector components
+        tmp<vectorField> globalVector(const vectorField& local) const
+        {
+            return localToGlobal(local, false);
+        }
+
+        //- From global (cartesian) to local vector components
+        vector localVector(const vector& global) const
+        {
+            return globalToLocal(global, false);
+        }
+
+        //- From global (cartesian) to local vector components
+        tmp<vectorField> localVector(const vectorField& global) const
+        {
+            return globalToLocal(global, false);
+        }
+
+
+    // Transformations (input and output are Cartesian)
+
+#undef  defineCoordinateSystemTransform
+#define defineCoordinateSystemTransform(Op, RetType, Type)                    \
+                                                                              \
+    /**! With constant rotation tensor */                                     \
+    virtual RetType Op(const Type& input) const;                              \
+                                                                              \
+    /**! With constant rotation tensor */                                     \
+    virtual tmp<Field<RetType>> Op(const UList<Type>& input) const;           \
+                                                                              \
+    /**! With rotation tensor at given global position */                     \
+    virtual RetType Op(const point& global, const Type& input) const;         \
+                                                                              \
+    /**! With rotation tensors at given global positions */                   \
+    virtual tmp<Field<RetType>> Op                                            \
+    (                                                                         \
+        const UList<point>& global,                                           \
+        const Type& input                                                     \
+    ) const;                                                                  \
+                                                                              \
+    /**! With rotation tensors at given global positions */                   \
+    virtual tmp<Field<RetType>> Op                                            \
+    (                                                                         \
+        const pointUIndList& global,                                          \
+        const Type& input                                                     \
+    ) const;                                                                  \
+                                                                              \
+    /**! With rotation tensors at given global positions */                   \
+    virtual tmp<Field<RetType>> Op                                            \
+    (                                                                         \
+        const UList<point>& global,                                           \
+        const UList<Type>& input                                              \
+    ) const;                                                                  \
+                                                                              \
+    /**! With rotation tensors at given global positions */                   \
+    virtual tmp<Field<RetType>> Op                                            \
+    (                                                                         \
+        const pointUIndList& global,                                          \
+        const UList<Type>& input                                              \
+    ) const;
+
+
+    defineCoordinateSystemTransform(transformPrincipal, symmTensor, vector);
+
+    defineCoordinateSystemTransform(transform, scalar, scalar);
+    defineCoordinateSystemTransform(transform, vector, vector);
+    defineCoordinateSystemTransform
+    (
+        transform,
+        sphericalTensor,
+        sphericalTensor
+    );
+    defineCoordinateSystemTransform(transform, symmTensor, symmTensor);
+    defineCoordinateSystemTransform(transform, tensor, tensor);
+
+    defineCoordinateSystemTransform(invTransform, scalar, scalar);
+    defineCoordinateSystemTransform(invTransform, vector, vector);
+    defineCoordinateSystemTransform
+    (
+        invTransform,
+        sphericalTensor,
+        sphericalTensor
+    );
+    defineCoordinateSystemTransform(invTransform, symmTensor, symmTensor);
+    defineCoordinateSystemTransform(invTransform, tensor, tensor);
+
+    #undef defineCoordinateSystemTransform
 };
 
 
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+// Global Operators
+
+//- Compare inequality
+bool operator!=(const coordinateSystem& a, const coordinateSystem& b);
+
+//- Output operator
+Ostream& operator<<(Ostream& os, const coordinateSystem& csys);
+
+
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 } // End namespace Foam
 
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+    #include "coordinateSystemTemplates.C"
+#endif
+
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 #endif
diff --git a/src/meshTools/coordinate/systems/coordinateSystemNew.C b/src/meshTools/coordinate/systems/coordinateSystemNew.C
index 9f0fd188663fdb6df7e38ec8125032c95cbaf24f..13c21578edaa77594bc34fd5ea772597d57f322f 100644
--- a/src/meshTools/coordinate/systems/coordinateSystemNew.C
+++ b/src/meshTools/coordinate/systems/coordinateSystemNew.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2015 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2018 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -23,58 +23,188 @@ License
 
 \*---------------------------------------------------------------------------*/
 
-#include "coordinateSystem.H"
-#include "dictionary.H"
+#include "objectRegistry.H"
+#include "cartesianCS.H"
+#include "indirectCS.H"
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+
+//- Handle a 'coordinateSystem' sub-dictionary
+// In 1806 and earlier, this was handled (rather poorly) in the
+// coordinateSystem constructor itself.
+const Foam::dictionary* Foam::coordinateSystem::subDictCompat
+(
+    const dictionary* dictPtr
+)
+{
+    if (dictPtr)
+    {
+        // Non-recursive, no pattern matching in the search
+        const auto finder =
+            dictPtr->csearch(coordinateSystem::typeName_(), false, false);
+
+        if (finder.isDict())
+        {
+            return finder.dictPtr();
+        }
+        else if (finder.found())
+        {
+            const word csName(finder.ref().stream());
+
+            // Deprecated, unsupported syntax
+
+            std::cerr
+                << "--> FOAM IOWarning :" << nl
+                << "    Ignoring 'coordinateSystem' as a keyword."
+                " Perhaps you meant this instead?" << nl
+                << '{' << nl
+                << "    type    " << coordSystem::indirect::typeName_()
+                << ';' << nl
+                << "    name    " << csName << ';' << nl
+                << '}' << nl
+                << std::endl;
+
+            error::warnAboutAge("syntax change", 1806);
+        }
+    }
+
+    return dictPtr;
+}
+
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 Foam::autoPtr<Foam::coordinateSystem> Foam::coordinateSystem::New
 (
+    word modelType,
     const objectRegistry& obr,
     const dictionary& dict
 )
 {
-    const dictionary& coordDict = dict.subDict(typeName_());
-    const word modelType(coordDict.get<word>("type"));
+    if (modelType.empty())
+    {
+        modelType = coordSystem::cartesian::typeName_();
+    }
+
+    auto cstrIter1 = registryConstructorTablePtr_->cfind(modelType);
+
+    if (cstrIter1.found())
+    {
+        return autoPtr<coordinateSystem>(cstrIter1()(obr, dict));
+    }
 
     auto cstrIter = dictionaryConstructorTablePtr_->cfind(modelType);
 
+    // Everything with a registry constructor also has a dictionary
+    // constructor, so just need to print those.
     if (!cstrIter.found())
     {
-        FatalIOErrorInFunction
-        (
-            dict
-        )   << "Unknown coordinateSystem type "
+        FatalIOErrorInFunction(dict)
+            << "Unknown coordinate system type "
             << modelType << nl << nl
             << "Valid types:  "
             << flatOutput(dictionaryConstructorTablePtr_->sortedToc())
             << exit(FatalIOError);
     }
 
-    return autoPtr<coordinateSystem>(cstrIter()(obr, coordDict));
+    return autoPtr<coordinateSystem>(cstrIter()(dict));
 }
 
 
 Foam::autoPtr<Foam::coordinateSystem> Foam::coordinateSystem::New
 (
+    word modelType,
     const dictionary& dict
 )
 {
-    const dictionary& coordDict = dict.subDict(typeName_());
+    if (modelType.empty())
+    {
+        modelType = coordSystem::cartesian::typeName_();
+    }
+
+    auto cstrIter = dictionaryConstructorTablePtr_->cfind(modelType);
+
+    if (!cstrIter.found())
+    {
+        FatalIOErrorInFunction(dict)
+            << "Unknown coordinate system type "
+            << modelType << nl << nl
+            << "Valid types:  "
+            << flatOutput(dictionaryConstructorTablePtr_->sortedToc())
+            << exit(FatalIOError);
+    }
+
+    return autoPtr<coordinateSystem>(cstrIter()(dict));
+}
+
+
+Foam::autoPtr<Foam::coordinateSystem> Foam::coordinateSystem::New
+(
+    const objectRegistry& obr,
+    const dictionary& dict,
+    const word& dictName
+)
+{
+    const dictionary* dictPtr = &dict;
+
+    if (dictName.size())
+    {
+        dictPtr = &(dictPtr->subDict(dictName));
+    }
+    else
+    {
+        // Use 'coordinateSystem' subDict if present
+        dictPtr = coordinateSystem::subDictCompat(dictPtr);
+    }
+
+    word modelType = dictPtr->lookupOrDefault<word>
+    (
+        "type",
+        coordSystem::cartesian::typeName_()
+    );
 
-    return autoPtr<coordinateSystem>::New(coordDict);
+    return coordinateSystem::New(modelType, obr, *dictPtr);
 }
 
 
 Foam::autoPtr<Foam::coordinateSystem> Foam::coordinateSystem::New
 (
-    Istream& is
+    const dictionary& dict,
+    const word& dictName
 )
 {
-    const word name(is);
+    const dictionary* dictPtr = &dict;
+
+    if (dictName.size())
+    {
+        dictPtr = &(dictPtr->subDict(dictName));
+    }
+    else
+    {
+        // Use 'coordinateSystem' subDict if present
+        dictPtr = coordinateSystem::subDictCompat(dictPtr);
+    }
+
+    word modelType = dictPtr->lookupOrDefault<word>
+    (
+        "type",
+        coordSystem::cartesian::typeName_()
+    );
+
+    return coordinateSystem::New(modelType, *dictPtr);
+}
+
+
+Foam::autoPtr<Foam::coordinateSystem> Foam::coordinateSystem::New(Istream& is)
+{
+    const word csName(is);
     const dictionary dict(is);
 
-    return autoPtr<coordinateSystem>::New(name, dict);
+    auto cs = coordinateSystem::New(dict, word::null);
+    cs->rename(csName);
+
+    return cs;
 }
 
 
diff --git a/src/meshTools/coordinate/systems/coordinateSystemTemplates.C b/src/meshTools/coordinate/systems/coordinateSystemTemplates.C
new file mode 100644
index 0000000000000000000000000000000000000000..e294b167f473184c804438d3819e7353143270cf
--- /dev/null
+++ b/src/meshTools/coordinate/systems/coordinateSystemTemplates.C
@@ -0,0 +1,161 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2018 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "coordinateSystem.H"
+#include "transform.H"
+
+// * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * //
+
+template<class PointField>
+Foam::tmp<Foam::tensorField>
+Foam::coordinateSystem::rotationsImpl(const PointField& global) const
+{
+    const label len = global.size();
+
+    auto tresult = tmp<tensorField>::New(len);
+    auto& result = tresult.ref();
+
+    for (label i=0; i<len; ++i)
+    {
+        result[i] = this->R(global[i]);
+    }
+
+    return tresult;
+}
+
+
+template<class PointField>
+Foam::tmp<Foam::pointField>
+Foam::coordinateSystem::transformPointImpl(const PointField& localCart) const
+{
+    const label len = localCart.size();
+
+    auto tresult = tmp<pointField>::New(len);
+    auto& result = tresult.ref();
+
+    for (label i=0; i<len; ++i)
+    {
+        result[i] = Foam::transform(rot_, localCart[i]) + origin_;
+    }
+
+    return tresult;
+}
+
+
+template<class PointField>
+Foam::tmp<Foam::pointField>
+Foam::coordinateSystem::invTransformPointImpl(const PointField& global) const
+{
+    const label len = global.size();
+
+    auto tresult = tmp<pointField>::New(len);
+    auto& result = tresult.ref();
+
+    for (label i=0; i<len; ++i)
+    {
+        result[i] = Foam::invTransform(rot_, global[i] - origin_);
+    }
+
+    return tresult;
+}
+
+
+template<class RetType, class Type, class BinaryOp>
+Foam::tmp<Foam::Field<RetType>>
+Foam::coordinateSystem::manyTimesImpl
+(
+    const tensor& tt,
+    const UList<Type>& input,
+    const BinaryOp& bop
+)
+{
+    const label len = input.size();
+
+    auto tresult = tmp<Field<RetType>>::New(len);
+    auto& result = tresult.ref();
+
+    for (label i=0; i<len; ++i)
+    {
+        result[i] = bop(tt, input[i]);
+    }
+
+    return tresult;
+}
+
+
+template<class RetType, class PointField, class Type, class BinaryOp>
+Foam::tmp<Foam::Field<RetType>>
+Foam::coordinateSystem::oneToOneImpl
+(
+    const PointField& global,
+    const UList<Type>& input,
+    const BinaryOp& bop
+) const
+{
+    const label len = input.size();
+
+    if (len != global.size())
+    {
+        FatalErrorInFunction
+            << "positions has different size from input field"
+            << abort(FatalError);
+    }
+
+    auto tresult = tmp<Field<RetType>>::New(len);
+    auto& result = tresult.ref();
+
+    for (label i=0; i<len; ++i)
+    {
+        result[i] = bop(this->R(global[i]), input[i]);
+    }
+
+    return tresult;
+}
+
+
+template<class RetType, class PointField, class Type, class BinaryOp>
+Foam::tmp<Foam::Field<RetType>>
+Foam::coordinateSystem::oneToManyImpl
+(
+    const PointField& global,
+    const Type& input,
+    const BinaryOp& bop
+) const
+{
+    const label len = global.size();
+
+    auto tresult = tmp<Field<RetType>>::New(len);
+    auto& result = tresult.ref();
+
+    for (label i=0; i<len; ++i)
+    {
+        result[i] = bop(this->R(global[i]), input);
+    }
+
+    return tresult;
+}
+
+
+// ************************************************************************* //
diff --git a/src/meshTools/coordinate/systems/coordinateSystemTransform.C b/src/meshTools/coordinate/systems/coordinateSystemTransform.C
new file mode 100644
index 0000000000000000000000000000000000000000..d08877a8c4207d7538156de119830e54e94cdac1
--- /dev/null
+++ b/src/meshTools/coordinate/systems/coordinateSystemTransform.C
@@ -0,0 +1,217 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2018 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "coordinateSystem.H"
+#include "transform.H"
+
+// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Resolve templated global functions via local non-templated function.
+// Lambda functions in the caller is a much messier solution.
+
+#undef  makeTransform
+#define makeTransform(Op, Type)                                               \
+    static inline Type Op##_##Type(const tensor& tt, const Type& in)          \
+    {                                                                         \
+        return Op(tt, in);                                                    \
+    }
+
+makeTransform(transform, scalar);
+makeTransform(transform, vector);
+makeTransform(transform, sphericalTensor);
+makeTransform(transform, symmTensor);
+makeTransform(transform, tensor);
+
+makeTransform(invTransform, scalar);
+makeTransform(invTransform, vector);
+makeTransform(invTransform, sphericalTensor);
+makeTransform(invTransform, symmTensor);
+makeTransform(invTransform, tensor);
+
+#undef makeTransform
+
+    //- Transform principal.
+    static inline symmTensor transformPrincipal_vector
+    (
+        const tensor& tt,
+        const vector& v
+    )
+    {
+        return symmTensor
+        (
+            tt.xx()*v.x()*tt.xx()
+          + tt.xy()*v.y()*tt.xy()
+          + tt.xz()*v.z()*tt.xz(),
+
+            tt.xx()*v.x()*tt.yx()
+          + tt.xy()*v.y()*tt.yy()
+          + tt.xz()*v.z()*tt.yz(),
+
+            tt.xx()*v.x()*tt.zx()
+          + tt.xy()*v.y()*tt.zy()
+          + tt.xz()*v.z()*tt.zz(),
+
+            tt.yx()*v.x()*tt.yx()
+          + tt.yy()*v.y()*tt.yy()
+          + tt.yz()*v.z()*tt.yz(),
+
+            tt.yx()*v.x()*tt.zx()
+          + tt.yy()*v.y()*tt.zy()
+          + tt.yz()*v.z()*tt.zz(),
+
+            tt.zx()*v.x()*tt.zx()
+          + tt.zy()*v.y()*tt.zy()
+          + tt.zz()*v.z()*tt.zz()
+        );
+    }
+
+} // End namespace Foam
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+Foam::tmp<Foam::pointField> Foam::coordinateSystem::transformPoint
+(
+    const UList<point>& localCart
+) const
+{
+    return transformPointImpl(localCart);
+}
+
+
+Foam::tmp<Foam::pointField> Foam::coordinateSystem::transformPoint
+(
+    const pointUIndList& localCart
+) const
+{
+    return transformPointImpl(localCart);
+}
+
+
+Foam::tmp<Foam::pointField> Foam::coordinateSystem::invTransformPoint
+(
+    const UList<point>& global
+) const
+{
+    return invTransformPointImpl(global);
+}
+
+
+Foam::tmp<Foam::pointField> Foam::coordinateSystem::invTransformPoint
+(
+    const pointUIndList& global
+) const
+{
+    return invTransformPointImpl(global);
+}
+
+
+// Transformations
+
+#undef  makeCoordinateSystemTransform
+#define makeCoordinateSystemTransform(Op, RetType, Type)                      \
+    Foam::RetType Foam::coordinateSystem::Op                                  \
+    (                                                                         \
+        const Type& input                                                     \
+    ) const                                                                   \
+    {                                                                         \
+        return Op##_##Type(rot_, input);                                      \
+    }                                                                         \
+                                                                              \
+    Foam::tmp<Foam::Field<Foam::RetType>> Foam::coordinateSystem::Op          \
+    (                                                                         \
+        const UList<Type>& input                                              \
+    ) const                                                                   \
+    {                                                                         \
+        return manyTimesImpl<RetType>(rot_, input, Op##_##Type);              \
+    }                                                                         \
+                                                                              \
+    Foam::RetType Foam::coordinateSystem::Op                                  \
+    (                                                                         \
+        const point& global,                                                  \
+        const Type& input                                                     \
+    ) const                                                                   \
+    {                                                                         \
+        return Op##_##Type(this->R(global), input);                           \
+    }                                                                         \
+                                                                              \
+    Foam::tmp<Foam::Field<Foam::RetType>> Foam::coordinateSystem::Op          \
+    (                                                                         \
+        const UList<point>& global,                                           \
+        const Type& input                                                     \
+    ) const                                                                   \
+    {                                                                         \
+        return oneToManyImpl<RetType>(global, input, Op##_##Type);            \
+    }                                                                         \
+                                                                              \
+    Foam::tmp<Foam::Field<Foam::RetType>> Foam::coordinateSystem::Op          \
+    (                                                                         \
+        const pointUIndList& global,                                          \
+        const Type& input                                                     \
+    ) const                                                                   \
+    {                                                                         \
+        return oneToManyImpl<RetType>(global, input, Op##_##Type);            \
+    }                                                                         \
+                                                                              \
+    Foam::tmp<Foam::Field<Foam::RetType>> Foam::coordinateSystem::Op          \
+    (                                                                         \
+        const UList<point>& global,                                           \
+        const UList<Type>& input                                              \
+    ) const                                                                   \
+    {                                                                         \
+        return oneToOneImpl<RetType>(global, input, Op##_##Type);             \
+    }                                                                         \
+                                                                              \
+    Foam::tmp<Foam::Field<Foam::RetType>> Foam::coordinateSystem::Op          \
+    (                                                                         \
+        const pointUIndList& global,                                          \
+        const UList<Type>& input                                              \
+    ) const                                                                   \
+    {                                                                         \
+        return oneToOneImpl<RetType>(global, input, Op##_##Type);             \
+    }
+
+
+makeCoordinateSystemTransform(transformPrincipal, symmTensor, vector);
+
+makeCoordinateSystemTransform(transform, scalar, scalar);
+makeCoordinateSystemTransform(transform, vector, vector);
+makeCoordinateSystemTransform(transform, sphericalTensor, sphericalTensor);
+makeCoordinateSystemTransform(transform, symmTensor, symmTensor);
+makeCoordinateSystemTransform(transform, tensor, tensor);
+
+makeCoordinateSystemTransform(invTransform, scalar, scalar);
+makeCoordinateSystemTransform(invTransform, vector, vector);
+makeCoordinateSystemTransform(invTransform, sphericalTensor, sphericalTensor);
+makeCoordinateSystemTransform(invTransform, symmTensor, symmTensor);
+makeCoordinateSystemTransform(invTransform, tensor, tensor);
+
+#undef makeCoordinateSystemTransform
+
+
+// ************************************************************************* //
diff --git a/src/meshTools/coordinate/systems/coordinateSystems.C b/src/meshTools/coordinate/systems/coordinateSystems.C
index 5a91c86fd1a61def6ab3452dd3211a503ee0b1c7..5fcb359ad5e6446763878f8fecef305841a69e93 100644
--- a/src/meshTools/coordinate/systems/coordinateSystems.C
+++ b/src/meshTools/coordinate/systems/coordinateSystems.C
@@ -24,18 +24,20 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "coordinateSystems.H"
-#include "IOPtrList.H"
 #include "Time.H"
-#include "stringListOps.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
 namespace Foam
 {
-    defineTypeNameAndDebug(coordinateSystems, 0);
-    defineTemplateTypeNameAndDebug(IOPtrList<coordinateSystem>, 0);
+    defineTypeName(coordinateSystems);
 }
 
+// File-local
+
+//- Header name for 1806 and earlier
+static const char* headerTypeCompat = "IOPtrList<coordinateSystem>";
+
 
 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
 
@@ -127,12 +129,77 @@ namespace Foam
 } // End namespace Foam
 
 
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+
+void Foam::coordinateSystems::readFromStream(const bool valid)
+{
+    Istream& is = readStream(word::null, valid);
+
+    if (valid)
+    {
+        if (headerClassName() == typeName)
+        {
+            this->readIstream(is, coordinateSystem::iNew());
+            close();
+        }
+        else if (headerClassName() == headerTypeCompat)
+        {
+            // Older (1806 and earlier) header name
+            std::cerr
+                << "--> FOAM IOWarning :" << nl
+                << "    Found header class name '" << headerTypeCompat
+                << "' instead of '" << typeName << "'" << nl;
+
+            error::warnAboutAge("header class", 1806);
+
+            this->readIstream(is, coordinateSystem::iNew());
+            close();
+        }
+        else
+        {
+            FatalIOErrorInFunction
+            (
+                is
+            )   << "unexpected class name " << headerClassName()
+                << " expected " << typeName
+                << " or " << headerTypeCompat << nl
+                << "    while reading object " << name()
+                << exit(FatalIOError);
+        }
+    }
+}
+
+
+bool Foam::coordinateSystems::readObject(const IOobject& io)
+{
+    if
+    (
+        (
+            io.readOpt() == IOobject::MUST_READ
+         || io.readOpt() == IOobject::MUST_READ_IF_MODIFIED
+        )
+     || (io.readOpt() == IOobject::READ_IF_PRESENT && headerOk())
+    )
+    {
+        readFromStream();
+        return true;
+    }
+
+    return false;
+}
+
+
+
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
 Foam::coordinateSystems::coordinateSystems(const IOobject& io)
 :
-    IOPtrList<coordinateSystem>(io)
-{}
+    regIOobject(io),
+    PtrList<coordinateSystem>()
+{
+    readObject(io);
+}
 
 
 Foam::coordinateSystems::coordinateSystems
@@ -141,8 +208,14 @@ Foam::coordinateSystems::coordinateSystems
     const PtrList<coordinateSystem>& content
 )
 :
-    IOPtrList<coordinateSystem>(io, content)
-{}
+    regIOobject(io),
+    PtrList<coordinateSystem>()
+{
+    if (!readObject(io))
+    {
+        static_cast<PtrList<coordinateSystem>&>(*this) = content;
+    }
+}
 
 
 Foam::coordinateSystems::coordinateSystems
@@ -151,8 +224,11 @@ Foam::coordinateSystems::coordinateSystems
     PtrList<coordinateSystem>&& content
 )
 :
-    IOPtrList<coordinateSystem>(io, std::move(content))
-{}
+    regIOobject(io),
+    PtrList<coordinateSystem>(std::move(content))
+{
+    readObject(io);
+}
 
 
 // * * * * * * * * * * * * * * * * Selectors * * * * * * * * * * * * * * * * //
@@ -253,18 +329,64 @@ bool Foam::coordinateSystems::found(const keyType& key) const
 }
 
 
+const Foam::coordinateSystem*
+Foam::coordinateSystems::lookupPtr(const word& name) const
+{
+    const label index = this->findIndex(name);
+
+    if (coordinateSystem::debug)
+    {
+        InfoInFunction
+            << "Global coordinate system: "
+            << name << "=" << index << endl;
+    }
+
+    if (index < 0)
+    {
+        return nullptr;
+    }
+
+    return this->operator()(index);
+}
+
+
+const Foam::coordinateSystem&
+Foam::coordinateSystems::lookup(const word& name) const
+{
+    const label index = this->findIndex(name);
+
+    if (index < 0)
+    {
+        FatalErrorInFunction
+            << "Could not find coordinate system: " << name << nl
+            << "available coordinate systems: "
+            << flatOutput(names()) << nl << nl
+            << exit(FatalError);
+    }
+    if (coordinateSystem::debug)
+    {
+        InfoInFunction
+            << "Global coordinate system: "
+            << name << "=" << index << endl;
+    }
+
+    return this->operator[](index);
+}
+
+
 Foam::wordList Foam::coordinateSystems::names() const
 {
-    const PtrList<coordinateSystem>& systems = *this;
+    const PtrList<coordinateSystem>& list = *this;
 
-    wordList list(systems.size());
+    wordList result(list.size());
 
-    forAll(systems, i)
+    forAll(list, i)
     {
-        list[i] = systems[i].name();
+        result[i] = list[i].name();
     }
 
-    return list;
+    return result;
+    // return ListOps::create<word>(list, nameOp<coordinateSystem>());
 }
 
 
@@ -303,12 +425,14 @@ Foam::wordList Foam::coordinateSystems::names(const wordRes& matcher) const
 
 bool Foam::coordinateSystems::writeData(Ostream& os) const
 {
+    const PtrList<coordinateSystem>& list = *this;
+
     os << nl << size() << nl << token::BEGIN_LIST;
 
-    forAll(*this, i)
+    for (const coordinateSystem& csys : list)
     {
         os << nl;
-        operator[](i).writeDict(os, true);
+        csys.writeEntry(csys.name(), os);
     }
 
     os << token::END_LIST << nl;
@@ -317,4 +441,23 @@ bool Foam::coordinateSystems::writeData(Ostream& os) const
 }
 
 
+bool Foam::coordinateSystems::writeObject
+(
+    IOstream::streamFormat,
+    IOstream::versionNumber ver,
+    IOstream::compressionType,
+    const bool valid
+) const
+{
+    // Force ASCII writing
+    return regIOobject::writeObject
+    (
+        IOstream::ASCII,
+        ver,
+        IOstream::UNCOMPRESSED,
+        valid
+    );
+}
+
+
 // ************************************************************************* //
diff --git a/src/meshTools/coordinate/systems/coordinateSystems.H b/src/meshTools/coordinate/systems/coordinateSystems.H
index a982f3c30c758214253ca1bb37bfca09f512aad4..643739571b3fca01a0ba8f5548a1f9691ac38b35 100644
--- a/src/meshTools/coordinate/systems/coordinateSystems.H
+++ b/src/meshTools/coordinate/systems/coordinateSystems.H
@@ -25,30 +25,31 @@ Class
     Foam::coordinateSystems
 
 Description
-    Provides a centralized coordinateSystem collection.
+    A centralized collection of named coordinate systems.
 
 Note
     Mixing normal constructors and the coordinateSystems::New constructor
     may yield unexpected results.
 
     \verbatim
-        1
-        (
-        cat1
+    cat1
+    {
+        coordinateSystem
+        {
+            type   indirect;
+            name   _10;
+        }
+        porosity    0.781;
+        Darcy
         {
-            coordinateSystem  system_10;
-            porosity        0.781;
-            Darcy
-            {
-                d   d [0 -2 0 0 0]  (-1000 -1000 0.50753e+08);
-                f   f [0 -1 0 0 0]  (-1000 -1000 12.83);
-            }
+            d   d [0 -2 0 0 0]  (-1000 -1000 0.50753e+08);
+            f   f [0 -1 0 0 0]  (-1000 -1000 12.83);
         }
-        )
+    }
     \endverbatim
 
     For this to work correctly, the coordinateSystem constructor must be
-    supplied with both a dictionary and an objectRegistry.
+    supplied with an objectRegistry as well as the dictionary.
 
 SourceFiles
     coordinateSystems.C
@@ -57,8 +58,9 @@ SourceFiles
 #ifndef coordinateSystems_H
 #define coordinateSystems_H
 
+#include "regIOobject.H"
+#include "PtrList.H"
 #include "coordinateSystem.H"
-#include "IOPtrList.H"
 #include "wordRes.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@@ -72,10 +74,19 @@ namespace Foam
 
 class coordinateSystems
 :
-    public IOPtrList<coordinateSystem>
+    public regIOobject,
+    public PtrList<coordinateSystem>
 {
     // Private Member Functions
 
+        //- Read "coordinateSystems" or older "IOPtrList<coordinateSystem>"
+        void readFromStream(const bool valid = true);
+
+        //- Attempt read if MUST_READ.., or READ_IF_PRESENT and has header
+        //  \return False if no read should have been attempted
+        bool readObject(const IOobject& io);
+
+
         //- No copy construct
         coordinateSystems(const coordinateSystems&) = delete;
 
@@ -86,21 +97,22 @@ class coordinateSystems
 public:
 
     //- Runtime type information
-    TypeName("coordinateSystems");
+    TypeNameNoDebug("coordinateSystems");
+
 
     // Constructors
 
         //- Read construct from IOobject
         explicit coordinateSystems(const IOobject& io);
 
-        //- Construct from IOobject and a PtrList
+        //- Construct from IOobject and PtrList content
         coordinateSystems
         (
             const IOobject& io,
             const PtrList<coordinateSystem>& content
         );
 
-        //- Construct from IOobject and transferring the PtrList content
+        //- Construct from IOobject and transferring PtrList content
         coordinateSystems
         (
             const IOobject& io,
@@ -111,7 +123,7 @@ public:
     // Selectors
 
         //- Return previously registered or read construct from "constant"
-        static const coordinateSystems& New(const objectRegistry&);
+        static const coordinateSystems& New(const objectRegistry& obr);
 
 
     // Member Functions
@@ -131,6 +143,12 @@ public:
         //- Search if given key exists
         bool found(const keyType& key) const;
 
+        //- Return reference to named coordinateSystem or FatalErrror
+        const coordinateSystem& lookup(const word& name) const;
+
+        //- Return pointer to named coordinateSystem or nullptr on error
+        const coordinateSystem* lookupPtr(const word& name) const;
+
         //- A list of the coordinate-system names
         wordList names() const;
 
@@ -149,8 +167,20 @@ public:
             return names();
         }
 
+
+    // IO
+
         //- Write data
-        bool writeData(Ostream&) const;
+        bool writeData(Ostream& os) const;
+
+        //- Write data
+        virtual bool writeObject
+        (
+            IOstream::streamFormat,
+            IOstream::versionNumber ver,
+            IOstream::compressionType,
+            const bool valid = true
+        ) const;
 
 
     // Housekeeping
diff --git a/src/meshTools/coordinate/systems/cylindricalCS.C b/src/meshTools/coordinate/systems/cylindricalCS.C
index fda455545ac1e325adb458d0e66e8c9a1c82b40b..26c049b63c2c634169c04e4210ab8048916f7274 100644
--- a/src/meshTools/coordinate/systems/cylindricalCS.C
+++ b/src/meshTools/coordinate/systems/cylindricalCS.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2018 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -24,212 +24,274 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "cylindricalCS.H"
-
-#include "one.H"
-#include "mathematicalConstants.H"
 #include "addToRunTimeSelectionTable.H"
 
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace coordSystem
+{
+    defineTypeName(cylindrical);
+    addToRunTimeSelectionTable(coordinateSystem, cylindrical, dictionary);
+}
+}
+
+
+// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Issue warning if 'degrees' keyword was specified and true.
+// Compatibility change after 1806.
+
+static inline void warnCompatDegrees(const Foam::dictionary& dict)
+{
+    if (Pstream::parRun() ? Pstream::master() : true)
+    {
+        std::cerr
+            << "--> FOAM IOWarning :" << nl
+            << "    Found [v1806] 'degrees' keyword in dictionary \""
+            << dict.name().c_str() << "\"    Ignored, now radians only." << nl
+            << std::endl;
+    }
+}
+
+
+//- Convert from Cartesian (to Cylindrical)
+static inline vector fromCartesian(const vector& v)
+{
+    return vector(hypot(v.x(), v.y()), atan2(v.y(), v.x()), v.z());
+}
+
+
+//- Convert to Cartesian (from Cylindrical)
+static inline vector toCartesian(const vector& v)
+{
+    return vector(v.x()*cos(v.y()), v.x()*sin(v.y()), v.z());
+}
+
+} // End namespace Foam
+
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-Foam::cylindricalCS::cylindricalCS(const bool inDegrees)
+Foam::coordSystem::cylindrical::cylindrical()
 :
-    coordinateSystem(),
-    inDegrees_(inDegrees)
+    coordinateSystem()
 {}
 
 
-Foam::cylindricalCS::cylindricalCS
-(
-    const coordinateSystem& cs,
-    const bool inDegrees
-)
+Foam::coordSystem::cylindrical::cylindrical(const coordinateSystem& csys)
 :
-    coordinateSystem(cs),
-    inDegrees_(inDegrees)
+    coordinateSystem(csys)
 {}
 
 
-Foam::cylindricalCS::cylindricalCS
-(
-    const word& name,
-    const coordinateSystem& cs,
-    const bool inDegrees
-)
+Foam::coordSystem::cylindrical::cylindrical(coordinateSystem&& csys)
 :
-    coordinateSystem(name, cs),
-    inDegrees_(inDegrees)
+    coordinateSystem(std::move(csys))
 {}
 
 
-Foam::cylindricalCS::cylindricalCS
+Foam::coordSystem::cylindrical::cylindrical(autoPtr<coordinateSystem>&& csys)
+:
+    coordinateSystem(std::move(csys))
+{}
+
+
+Foam::coordSystem::cylindrical::cylindrical
 (
-    const word& name,
     const point& origin,
-    const coordinateRotation& cr,
-    const bool inDegrees
+    const coordinateRotation& crot
 )
 :
-    coordinateSystem(name, origin, cr),
-    inDegrees_(inDegrees)
+    coordinateSystem(origin, crot)
 {}
 
 
-Foam::cylindricalCS::cylindricalCS
+Foam::coordSystem::cylindrical::cylindrical
 (
-    const word& name,
     const point& origin,
     const vector& axis,
-    const vector& dirn,
-    const bool inDegrees
+    const vector& dirn
 )
 :
-    coordinateSystem(name, origin, axis, dirn),
-    inDegrees_(inDegrees)
+    coordinateSystem(origin, axis, dirn)
 {}
 
 
-Foam::cylindricalCS::cylindricalCS
+Foam::coordSystem::cylindrical::cylindrical
 (
     const word& name,
-    const dictionary& dict
+    const point& origin,
+    const vector& axis,
+    const vector& dirn
 )
 :
-    coordinateSystem(name, dict),
-    inDegrees_(dict.lookupOrDefault("degrees", true))
+    coordinateSystem(name, origin, axis, dirn)
 {}
 
 
-Foam::cylindricalCS::cylindricalCS
+Foam::coordSystem::cylindrical::cylindrical
 (
-    const objectRegistry& obr,
+    const word& name,
     const dictionary& dict
 )
 :
-    coordinateSystem(obr, dict),
-    inDegrees_(dict.lookupOrDefault("degrees", true))
-{}
+    coordinateSystem(name, dict)
+{
+    if (dict.lookupOrDefault("degrees", false))
+    {
+        warnCompatDegrees(dict);
+    }
+}
 
 
-// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
+Foam::coordSystem::cylindrical::cylindrical(const dictionary& dict)
+:
+    coordinateSystem(dict)
+{
+    if (dict.lookupOrDefault("degrees", false))
+    {
+        warnCompatDegrees(dict);
+    }
+}
 
-Foam::cylindricalCS::~cylindricalCS()
-{}
+
+Foam::coordSystem::cylindrical::cylindrical
+(
+    const dictionary& dict,
+    const word& dictName
+)
+:
+    coordinateSystem(dict, dictName)
+{
+    const dictionary* dictPtr =
+    (
+        dictName.size()
+      ? &(dict.subDict(dictName))
+      : &(dict)
+    );
+
+    if (dictPtr->lookupOrDefault("degrees", false))
+    {
+        warnCompatDegrees(dict);
+    }
+}
 
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-bool Foam::cylindricalCS::inDegrees() const
+Foam::tensor Foam::coordSystem::cylindrical::R(const point& global) const
 {
-    return inDegrees_;
-}
+    // Robuster version of coordinateRotations::axes::rotation()
+    // using an E3_E1 order and falling back to the top-level rotation
+    // tensor if the directional input is borderline.
 
+    tensor rotTensor(rot_);
 
-bool& Foam::cylindricalCS::inDegrees()
-{
-    return inDegrees_;
+    const vector ax1 = rotTensor.col<2>(); // == e3 (already normalized)
+
+    vector ax2(global - origin_);
+
+    // Remove colinear component
+    ax2 -= ((ax1 & ax2) * ax1);
+
+    const scalar magAxis2(mag(ax2));
+
+    // Trap zero size and colinearity
+    if (magAxis2 < SMALL)
+    {
+        return rotTensor;
+    }
+
+    ax2 /= magAxis2;  // normalise
+
+    // Replace with updated local axes
+
+    rotTensor.col<0>(ax2);
+    rotTensor.col<1>(ax1^ax2);
+
+    return rotTensor;
 }
 
 
-Foam::vector Foam::cylindricalCS::localToGlobal
+Foam::vector Foam::coordSystem::cylindrical::localToGlobal
 (
     const vector& local,
     bool translate
 ) const
 {
-    scalar theta
-    (
-        local.y()*(inDegrees_ ? constant::mathematical::pi/180.0 : 1.0)
-    );
-
     return coordinateSystem::localToGlobal
     (
-        vector(local.x()*cos(theta), local.x()*sin(theta), local.z()),
+        toCartesian(local),
         translate
     );
 }
 
 
-Foam::tmp<Foam::vectorField> Foam::cylindricalCS::localToGlobal
+Foam::tmp<Foam::vectorField> Foam::coordSystem::cylindrical::localToGlobal
 (
     const vectorField& local,
     bool translate
 ) const
 {
-    scalarField theta
-    (
-        local.component(vector::Y)
-       *(inDegrees_ ? constant::mathematical::pi/180.0 : 1.0)
-    );
+    const label len = local.size();
 
+    auto tresult = tmp<vectorField>::New(len);
+    auto& result = tresult.ref();
 
-    vectorField lc(local.size());
-    lc.replace(vector::X, local.component(vector::X)*cos(theta));
-    lc.replace(vector::Y, local.component(vector::X)*sin(theta));
-    lc.replace(vector::Z, local.component(vector::Z));
+    for (label i=0; i<len; ++i)
+    {
+        result[i] =
+            coordinateSystem::localToGlobal
+            (
+                toCartesian(local[i]),
+                translate
+            );
+    }
 
-    return coordinateSystem::localToGlobal(lc, translate);
+    return tresult;
 }
 
 
-Foam::vector Foam::cylindricalCS::globalToLocal
+Foam::vector Foam::coordSystem::cylindrical::globalToLocal
 (
     const vector& global,
     bool translate
 ) const
 {
-    const vector lc
+    return fromCartesian
     (
         coordinateSystem::globalToLocal(global, translate)
     );
-
-    return vector
-    (
-        sqrt(sqr(lc.x()) + sqr(lc.y())),
-        atan2
-        (
-            lc.y(),
-            lc.x()
-        )*(inDegrees_ ? 180.0/constant::mathematical::pi : 1.0),
-        lc.z()
-    );
 }
 
 
-Foam::tmp<Foam::vectorField> Foam::cylindricalCS::globalToLocal
+Foam::tmp<Foam::vectorField> Foam::coordSystem::cylindrical::globalToLocal
 (
     const vectorField& global,
     bool translate
 ) const
 {
-    const vectorField lc
-    (
-        coordinateSystem::globalToLocal(global, translate)
-    );
-
-    tmp<vectorField> tresult(new vectorField(lc.size()));
-    vectorField& result = tresult.ref();
+    const label len = global.size();
 
-    result.replace
+    tmp<vectorField> tresult
     (
-        vector::X,
-        sqrt(sqr(lc.component(vector::X)) + sqr(lc.component(vector::Y)))
-    );
-
-    result.replace
-    (
-        vector::Y,
-        atan2
-        (
-            lc.component(vector::Y),
-            lc.component(vector::X)
-        )*(inDegrees_ ? 180.0/constant::mathematical::pi : 1.0)
+        coordinateSystem::globalToLocal(global, translate)
     );
+    auto& result = tresult.ref();
 
-    result.replace(vector::Z, lc.component(vector::Z));
+    for (label i=0; i<len; ++i)
+    {
+        result[i] = fromCartesian(result[i]);
+    }
 
     return tresult;
 }
 
 
+
 // ************************************************************************* //
diff --git a/src/meshTools/coordinate/systems/cylindricalCS.H b/src/meshTools/coordinate/systems/cylindricalCS.H
index 4504231caeec791f1ce012f02afbd1ce1372f667..53c7349260f833eed4cde57c3e8f93a774baf5d4 100644
--- a/src/meshTools/coordinate/systems/cylindricalCS.H
+++ b/src/meshTools/coordinate/systems/cylindricalCS.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2014 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2018 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -22,13 +22,21 @@ License
     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
 
 Class
-    Foam::cylindricalCS
+    Foam::coordSystem::cylindrical
 
 Description
-    Cylindrical coordinate system
+    A cylindrical coordinate system (r-theta-z).
+    The coordinate system angle theta is always in radians.
+
+    \heading Dictionary entries
+    \table
+        Property    | Description                           | Required | Default
+        type        | type name: cylindrical                | yes   |
+    \endtable
 
 SourceFiles
     cylindricalCS.C
+    cylindricalCSTransform.C
 
 \*---------------------------------------------------------------------------*/
 
@@ -41,114 +49,160 @@ SourceFiles
 
 namespace Foam
 {
+namespace coordSystem
+{
 
 /*---------------------------------------------------------------------------*\
-                        Class cylindricalCS Declaration
+                  Class coordSystem::cylindrical Declaration
 \*---------------------------------------------------------------------------*/
 
-class cylindricalCS
+class cylindrical
 :
     public coordinateSystem
 {
-    // Private data members
-
-        //- Are angles in degrees? (default = true)
-        bool inDegrees_;
-
-
 protected:
 
     // Protected Member Functions
 
+        //- From local coordinate system to the global Cartesian system
+        //- with optional translation for the origin
+        virtual vector localToGlobal
+        (
+            const vector& local,
+            bool translate
+        ) const;
 
-        //- Convert from local coordinate system to the global Cartesian system
-        //  with optional translation for the origin
-        virtual vector localToGlobal(const vector&, bool translate) const;
-
-        //- Convert from local coordinate system to the global Cartesian system
-        //  with optional translation for the origin
+        //- From local coordinate system to the global Cartesian system
+        //- with optional translation for the origin
         virtual tmp<vectorField> localToGlobal
         (
-            const vectorField&,
+            const vectorField& local,
             bool translate
         ) const;
 
-        //- Convert from global Cartesian system to the local coordinate system
-        //  with optional translation for the origin
-        virtual vector globalToLocal(const vector&, bool translate) const;
+        //- From global Cartesian system to the local coordinate system
+        //- with optional translation for the origin
+        virtual vector globalToLocal
+        (
+            const vector& global,
+            bool translate
+        ) const;
 
         //- Convert from global Cartesian system to the local coordinate system
-        //  with optional translation for the origin
+        //- with optional translation for the origin
         virtual tmp<vectorField> globalToLocal
         (
-            const vectorField&,
+            const vectorField& global,
             bool translate
         ) const;
 
 
 public:
 
+    //- Runtime type information
+    TypeNameNoDebug("cylindrical");
+
 
     // Constructors
 
-        //- Construct null
-        cylindricalCS(const bool inDegrees=true);
+        //- Construct null (identity coordinateSystem)
+        cylindrical();
 
-        //- Construct copy
-        cylindricalCS
-        (
-            const coordinateSystem&,
-            const bool inDegrees=true
-        );
+        //- Copy construct
+        cylindrical(const cylindrical& csys) = default;
 
-        //- Construct copy with a different name
-        cylindricalCS
-        (
-            const word& name,
-            const coordinateSystem&,
-            const bool inDegrees=true
-        );
+        //- Move construct
+        cylindrical(cylindrical&& csys) = default;
+
+        //- Copy construct from another coordinateSystem type
+        explicit cylindrical(const coordinateSystem& csys);
+
+        //- Move construct from another coordinateSystem type
+        explicit cylindrical(coordinateSystem&& csys);
+
+        //- Move construct from autoPtr of another coordinateSystem type
+        explicit cylindrical(autoPtr<coordinateSystem>&& csys);
 
         //- Construct from origin and rotation
-        cylindricalCS
+        cylindrical(const point& origin, const coordinateRotation& crot);
+
+        //- Construct from origin and 2 axes
+        cylindrical
         (
-            const word& name,
             const point& origin,
-            const coordinateRotation&,
-            const bool inDegrees=true
+            const vector& axis,
+            const vector& dirn
         );
 
         //- Construct from origin and 2 axes
-        cylindricalCS
+        cylindrical
         (
             const word& name,
             const point& origin,
             const vector& axis,
-            const vector& dirn,
-            const bool inDegrees=true
+            const vector& dirn
         );
 
-        //- Construct from dictionary and name
-        cylindricalCS(const word&, const dictionary&);
+        //- Construct from dictionary with a given name
+        cylindrical(const word& name, const dictionary& dict);
 
-        //- Construct from dictionary and objectRegistry
-        cylindricalCS(const objectRegistry&, const dictionary&);
+        //- Construct from dictionary without a name
+        explicit cylindrical(const dictionary& dict);
+
+        //- Construct from dictionary with optional subDict lookup.
+        //
+        //  \param dictName If non-empty, the sub-dictionary to use.
+        cylindrical(const dictionary& dict, const word& dictName);
+
+        //- Return clone
+        virtual autoPtr<coordinateSystem> clone() const
+        {
+            return autoPtr<coordinateSystem>::NewFrom<cylindrical>(*this);
+        }
 
 
     //- Destructor
-    virtual ~cylindricalCS();
+    virtual ~cylindrical() = default;
 
 
     // Member Functions
 
-        //- Are angles in degrees?
-        bool inDegrees() const;
+        //- Treat the rotation tensor as non-uniform
+        virtual bool uniform() const
+        {
+            return false;
+        }
+
+
+    // Rotations
+
+        //- Position-dependent rotation tensors at multiple points
+        using coordinateSystem::R;
 
-        //- Non-const access to inDegrees
-        bool& inDegrees();
+        //- Position-dependent rotation tensor at a single point
+        //- \return tensor
+        virtual tensor R(const point& global) const;
+
+
+    // Member Operators
+
+        //- Copy assignment
+        cylindrical& operator=(const cylindrical&) = default;
+
+        //- Move assignment
+        cylindrical& operator=(cylindrical&&) = default;
 };
 
 
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace coordSystem
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+//- Compatibility typedef 1806
+typedef coordSystem::cylindrical cylindricalCS;
+
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 } // End namespace Foam
diff --git a/src/meshTools/coordinate/systems/indirectCS.C b/src/meshTools/coordinate/systems/indirectCS.C
new file mode 100644
index 0000000000000000000000000000000000000000..c2ce19fb320c6bef06085b6c00548a845d147aac
--- /dev/null
+++ b/src/meshTools/coordinate/systems/indirectCS.C
@@ -0,0 +1,113 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2018 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+\*---------------------------------------------------------------------------*/
+
+#include "indirectCS.H"
+#include "coordinateSystems.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace coordSystem
+{
+    defineTypeNameAndDebug(indirect, 0);
+    addToRunTimeSelectionTable(coordinateSystem, indirect, registry);
+}
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::coordSystem::indirect::indirect(const indirect& csys)
+:
+    coordinateSystem(),
+    backend_(csys.backend_)
+{}
+
+
+Foam::coordSystem::indirect::indirect(indirect&& csys)
+:
+    coordinateSystem(),
+    backend_(std::move(csys.backend_))
+{}
+
+
+// Use lookup() instead of lookupPtr() to trigger FatalError on any problems
+Foam::coordSystem::indirect::indirect
+(
+    const objectRegistry& obr,
+    const word& name
+)
+:
+    coordinateSystem(),
+    backend_(&(coordinateSystems::New(obr).lookup(name)))
+{}
+
+
+Foam::coordSystem::indirect::indirect
+(
+    const objectRegistry& obr,
+    const dictionary& dict
+)
+:
+    indirect(obr, dict.get<word>("name"))
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::coordSystem::indirect::write(Ostream& os) const
+{
+    writeEntry(coordinateSystem::typeName_(), os);
+}
+
+
+void Foam::coordSystem::indirect::writeEntry
+(
+    const word& keyword,
+    Ostream& os
+) const
+{
+    if (!valid())
+    {
+        return;
+    }
+
+    const bool subDict = !keyword.empty();
+
+    if (subDict)
+    {
+        os.beginBlock(keyword);
+
+        os.writeEntry("type", type());
+        os.writeEntry("name", name());
+
+        os.endBlock();
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/src/meshTools/coordinate/systems/indirectCS.H b/src/meshTools/coordinate/systems/indirectCS.H
new file mode 100644
index 0000000000000000000000000000000000000000..2ae4160cd554d6c38285fbb373cc7b9d99a9e135
--- /dev/null
+++ b/src/meshTools/coordinate/systems/indirectCS.H
@@ -0,0 +1,304 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | Copyright (C) 2018 OpenCFD Ltd.
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+License
+    This file is part of OpenFOAM.
+
+    OpenFOAM is free software: you can redistribute it and/or modify it
+    under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
+    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+    for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
+
+Class
+    Foam::coordSystem::indirect
+
+Description
+    A coordinate system forward to a global coordinate system that is
+    normally provided by the constant/coordinateSystems file.
+
+    \heading Dictionary entries
+    \table
+        Property    | Description                           | Required | Default
+        type        | Type name: indirect                   | yes   |
+        name        | Name of the referenced system         | yes   |
+    \endtable
+
+SourceFiles
+    indirectCS.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef indirectCS_H
+#define indirectCS_H
+
+#include "coordinateSystem.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace coordSystem
+{
+
+/*---------------------------------------------------------------------------*\
+                    Class coordSystem::indirect Declaration
+\*---------------------------------------------------------------------------*/
+
+class indirect
+:
+    public coordinateSystem
+{
+    // Private Data
+
+        //- The real coordinate system
+        const coordinateSystem* backend_;
+
+
+    // Private Member Functions
+
+        //- Construct null is disallowed
+        indirect() = delete;
+
+
+protected:
+
+        // Protected Member Functions
+
+        //- Convert from local coordinate system to the global Cartesian system
+        //- with optional translation for the origin
+        virtual vector localToGlobal
+        (
+            const vector& local,
+            bool translate
+        ) const
+        {
+            return backend_->localToGlobal(local, translate);
+        }
+
+        //- Convert from local coordinate system to the global Cartesian system
+        //- with optional translation for the origin
+        virtual tmp<vectorField> localToGlobal
+        (
+            const vectorField& local,
+            bool translate
+        ) const
+        {
+            return backend_->localToGlobal(local, translate);
+        }
+
+        //- Convert from global Cartesian system to the local coordinate system
+        //- with optional translation for the origin
+        virtual vector globalToLocal
+        (
+            const vector& global,
+            bool translate
+        ) const
+        {
+            return backend_->globalToLocal(global, translate);
+        }
+
+        //- Convert from global Cartesian system to the local coordinate system
+        //- with optional translation for the origin
+        virtual tmp<vectorField> globalToLocal
+        (
+            const vectorField& global,
+            bool translate
+        ) const
+        {
+            return backend_->globalToLocal(global, translate);
+        }
+
+
+public:
+
+    //- Runtime type information
+    TypeName("indirect");
+
+
+    // Constructors
+
+        //- Copy construct
+        indirect(const indirect& csys);
+
+        //- Move construct
+        indirect(indirect&& csys);
+
+        //- Construct from global lookup
+        indirect(const objectRegistry& obr, const word& name);
+
+        //- Construct from global lookup
+        indirect(const objectRegistry& obr, const dictionary& dict);
+
+        //- Return clone
+        virtual autoPtr<coordinateSystem> clone() const
+        {
+            return autoPtr<coordinateSystem>::NewFrom<indirect>(*this);
+        }
+
+
+    //- Destructor
+    virtual ~indirect() = default;
+
+
+    // Member Functions
+
+    // Access
+
+        //- Reference to the underlying coordinate system
+        virtual const coordinateSystem& cs() const
+        {
+            return *backend_;
+        }
+
+        //- Is the coordinate system valid?
+        virtual bool valid() const
+        {
+            return backend_ && backend_->valid();
+        }
+
+        //- True if the rotation tensor is uniform for all positions
+        virtual bool uniform() const
+        {
+            return backend_->uniform();
+        }
+
+        //- The rotation specification
+        virtual const coordinateRotation& rotation() const
+        {
+            return backend_->rotation();
+        }
+
+        //- Return the name
+        virtual const word& name() const
+        {
+            return backend_->name_;
+        }
+
+        //- Return the optional note
+        virtual const string& note() const
+        {
+            return backend_->note();
+        }
+
+        //- Return origin
+        virtual const point& origin() const
+        {
+            return backend_->origin();
+        }
+
+        //- Return const reference to the rotation tensor
+        virtual const tensor& R() const
+        {
+            return backend_->R();
+        }
+
+        //- The local Cartesian x-axis in global coordinates
+        virtual const vector e1() const
+        {
+            return backend_->e1();
+        }
+
+        //- The local Cartesian y-axis in global coordinates
+        virtual const vector e2() const
+        {
+            return backend_->e2();
+        }
+
+        //- The local Cartesian z-axis in global coordinates
+        virtual const vector e3() const
+        {
+            return backend_->e3();
+        }
+
+
+    // Edit
+
+        //- Rename (ignored)
+        void rename(const word& newName) {}
+
+        //- Provide non-constant access to the optional note
+        string& note()
+        {
+            NotImplemented;
+            return dummy_.note();
+        }
+
+        //- Edit access to origin (disallowed)
+        virtual point& origin()
+        {
+            NotImplemented;
+            return dummy_.origin();
+        }
+
+        //- Clear (ignored)
+        virtual void clear() {}
+
+        //- Change the rotation (disallowed)
+        virtual void rotation(autoPtr<coordinateRotation>&& crot)
+        {
+            NotImplemented;
+        }
+
+
+    // Write
+
+        //- Write
+        virtual void write(Ostream& os) const;
+
+        //- Write dictionary entry
+        virtual void writeEntry(const word& keyword, Ostream& os) const;
+
+
+    // Member Operators
+
+        //- No copy assignment
+        void operator=(const coordinateSystem& csys) = delete;
+
+        //- No move assignment
+        void operator=(coordinateSystem&& csys) = delete;
+
+
+    // Rotations
+
+        //- Position-dependent rotation tensor at a single point
+        virtual tensor R(const point& global) const
+        {
+            return backend_->R(global);
+        }
+
+        //- Position-dependent rotation tensors at multiple points
+        virtual tmp<tensorField> R(const UList<point>& global) const
+        {
+            return backend_->R(global);
+        }
+
+        //- Position-dependent rotation tensors at multiple points
+        virtual tmp<tensorField> R(const pointUIndList& global) const
+        {
+            return backend_->R(global);
+        }
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace coordSystem
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/meshTools/searchableSurfaces/searchableRotatedBox/searchableRotatedBox.C b/src/meshTools/searchableSurfaces/searchableRotatedBox/searchableRotatedBox.C
index 13e85223e34d30a0b52e60f40fb937bf36e3889b..62355837e113161e28a737e5f24b592dc94afaed 100644
--- a/src/meshTools/searchableSurfaces/searchableRotatedBox/searchableRotatedBox.C
+++ b/src/meshTools/searchableSurfaces/searchableRotatedBox/searchableRotatedBox.C
@@ -25,7 +25,6 @@ License
 
 #include "searchableRotatedBox.H"
 #include "addToRunTimeSelectionTable.H"
-#include "axesRotation.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -73,7 +72,6 @@ Foam::searchableRotatedBox::searchableRotatedBox
     ),
     transform_
     (
-        "rotation",
         dict.get<point>("origin"),
         dict.get<vector>("e3"),
         dict.get<vector>("e1")
diff --git a/src/meshTools/searchableSurfaces/searchableRotatedBox/searchableRotatedBox.H b/src/meshTools/searchableSurfaces/searchableRotatedBox/searchableRotatedBox.H
index cb28c26c2912e52541cf848a3fd5e200a24c435c..3065fb00eca825bcd2b83509ef5956ff77282bb4 100644
--- a/src/meshTools/searchableSurfaces/searchableRotatedBox/searchableRotatedBox.H
+++ b/src/meshTools/searchableSurfaces/searchableRotatedBox/searchableRotatedBox.H
@@ -32,6 +32,7 @@ Description
 
     E.g. box with sides 1 1 1 rotated 45 degrees around z-axis at
          origin (0.5 0.5 0.5)
+
     \verbatim
         span    (1 1 1);
         origin  (0.5 0.5 0.5);
@@ -58,8 +59,8 @@ SourceFiles
 #define searchableRotatedBox_H
 
 #include "searchableSurface.H"
-#include "coordinateSystem.H"
 #include "searchableBox.H"
+#include "cartesianCS.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -82,7 +83,7 @@ private:
         searchableBox box_;
 
         //- Transformation from local to global coordinates
-        coordinateSystem transform_;
+        coordSystem::cartesian transform_;
 
         //- The (global) corner points (in treeBoundBox order)
         pointField points_;
diff --git a/src/meshTools/searchableSurfaces/searchableSurfaceCollection/searchableSurfaceCollection.C b/src/meshTools/searchableSurfaces/searchableSurfaceCollection/searchableSurfaceCollection.C
index 030010882b38c8379f2ecda1114406f1379c83f9..a55e2c37ff84837cd4a89050d28afe8a2a965efc 100644
--- a/src/meshTools/searchableSurfaces/searchableSurfaceCollection/searchableSurfaceCollection.C
+++ b/src/meshTools/searchableSurfaces/searchableSurfaceCollection/searchableSurfaceCollection.C
@@ -199,10 +199,7 @@ Foam::searchableSurfaceCollection::searchableSurfaceCollection
             transform_.set
             (
                 surfI,
-                coordinateSystem::New
-                (
-                    subDict.subDict("transform")
-                )
+                new coordSystem::cartesian(subDict, "transform")
             );
 
             const word subGeomName(subDict.get<word>("surface"));
@@ -229,7 +226,7 @@ Foam::searchableSurfaceCollection::searchableSurfaceCollection
             Info<< "    instance : " << instance_[surfI] << endl;
             Info<< "    surface  : " << s.name() << endl;
             Info<< "    scale    : " << scale_[surfI] << endl;
-            Info<< "    coordsys : " << transform_[surfI] << endl;
+            Info<< "    transform: " << transform_[surfI] << endl;
 
             surfI++;
         }
@@ -715,10 +712,7 @@ void Foam::searchableSurfaceCollection::distribute
         // pointField bbPoints =
         // cmptDivide
         // (
-        //     transform_[surfI].localPosition
-        //     (
-        //         bbs[i].points()
-        //     ),
+        //     transform_[surfI].localPosition(bbs[i].points()),
         //     scale_[surfI]
         // );
         // treeBoundBox newBb(bbPoints);
diff --git a/src/meshTools/searchableSurfaces/searchableSurfaceCollection/searchableSurfaceCollection.H b/src/meshTools/searchableSurfaces/searchableSurfaceCollection/searchableSurfaceCollection.H
index f35b64d3f742c99c3da2e5f8e915ff43dc3c58c8..e178dbaa2da6b5e187a659829e60063e1adb0d45 100644
--- a/src/meshTools/searchableSurfaces/searchableSurfaceCollection/searchableSurfaceCollection.H
+++ b/src/meshTools/searchableSurfaces/searchableSurfaceCollection/searchableSurfaceCollection.H
@@ -45,7 +45,7 @@ SourceFiles
 
 #include "searchableSurface.H"
 #include "treeBoundBox.H"
-#include "coordinateSystem.H"
+#include "cartesianCS.H"
 #include "UPtrList.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@@ -71,8 +71,8 @@ class searchableSurfaceCollection
             //- Scaling vector
             vectorField scale_;
 
-            //- transformation
-            PtrList<coordinateSystem> transform_;
+            //- Coordinate transformation
+            PtrList<coordSystem::cartesian> transform_;
 
             UPtrList<searchableSurface> subGeom_;
 
@@ -159,13 +159,13 @@ public:
         }
 
         //- Coordinate system per subsurface
-        const PtrList<coordinateSystem>& transform() const
+        const PtrList<coordSystem::cartesian>& transform() const
         {
             return transform_;
         }
 
         //- Coordinate system per subsurface
-        PtrList<coordinateSystem>& transform()
+        PtrList<coordSystem::cartesian>& transform()
         {
             return transform_;
         }
diff --git a/src/meshTools/triSurface/triSurfaceTools/pointToPointPlanarInterpolation.C b/src/meshTools/triSurface/triSurfaceTools/pointToPointPlanarInterpolation.C
index ac28865272bc3c0291efe196d58c568d0c657c7d..6c16efd3ebb8741fe4044fa942de3bc4c2e1f8ed 100644
--- a/src/meshTools/triSurface/triSurfaceTools/pointToPointPlanarInterpolation.C
+++ b/src/meshTools/triSurface/triSurfaceTools/pointToPointPlanarInterpolation.C
@@ -43,7 +43,7 @@ namespace Foam
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
-Foam::coordinateSystem
+Foam::coordSystem::cartesian
 Foam::pointToPointPlanarInterpolation::calcCoordinateSystem
 (
     const pointField& points
@@ -117,9 +117,8 @@ Foam::pointToPointPlanarInterpolation::calcCoordinateSystem
             << " to define coordinate system with normal " << n << endl;
     }
 
-    return coordinateSystem
+    return coordSystem::cartesian
     (
-        "reference",
         p0,  // origin
         n,   // normal
         e1   // 0-axis
@@ -192,11 +191,8 @@ void Foam::pointToPointPlanarInterpolation::calcWeights
     }
     else
     {
-        tmp<vectorField> tlocalVertices
-        (
-            referenceCS_.localPosition(sourcePoints)
-        );
-        vectorField& localVertices = tlocalVertices.ref();
+        auto tlocalVertices = referenceCS_.localPosition(sourcePoints);
+        auto& localVertices = tlocalVertices.ref();
 
         const boundBox bb(localVertices, true);
         const point bbMid(bb.midpoint());
@@ -228,13 +224,7 @@ void Foam::pointToPointPlanarInterpolation::calcWeights
 
         triSurface s(triSurfaceTools::delaunay2D(localVertices2D));
 
-        tmp<pointField> tlocalFaceCentres
-        (
-            referenceCS_.localPosition
-            (
-                destPoints
-            )
-        );
+        auto tlocalFaceCentres = referenceCS_.localPosition(destPoints);
         const pointField& localFaceCentres = tlocalFaceCentres();
 
         if (debug)
@@ -324,12 +314,13 @@ Foam::pointToPointPlanarInterpolation::pointToPointPlanarInterpolation
 :
     perturb_(perturb),
     nearestOnly_(nearestOnly),
-    referenceCS_
-    (
-        nearestOnly ? coordinateSystem() : calcCoordinateSystem(sourcePoints)
-    ),
+    referenceCS_(),
     nPoints_(sourcePoints.size())
 {
+    if (!nearestOnly)
+    {
+        referenceCS_ = calcCoordinateSystem(sourcePoints);
+    }
     calcWeights(sourcePoints, destPoints);
 }
 
diff --git a/src/meshTools/triSurface/triSurfaceTools/pointToPointPlanarInterpolation.H b/src/meshTools/triSurface/triSurfaceTools/pointToPointPlanarInterpolation.H
index 2d0df6a8eab0adf50561460d0f4a48d95d8406cf..36adb7e4b8439285d9b6fa7c00b1130210871a38 100644
--- a/src/meshTools/triSurface/triSurfaceTools/pointToPointPlanarInterpolation.H
+++ b/src/meshTools/triSurface/triSurfaceTools/pointToPointPlanarInterpolation.H
@@ -37,8 +37,8 @@ SourceFiles
 #define pointToPointPlanarInterpolation_H
 
 #include "FixedList.H"
-#include "coordinateSystem.H"
 #include "instantList.H"
+#include "cartesianCS.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -59,8 +59,8 @@ class pointToPointPlanarInterpolation
         //- Whether to use nearest point only (avoids triangulation, projection)
         const bool nearestOnly_;
 
-        //- Coordinate system
-        coordinateSystem referenceCS_;
+        //- Cartesian reference coordinate system
+        coordSystem::cartesian referenceCS_;
 
         //- Number of source points (for checking)
         label nPoints_;
@@ -77,7 +77,7 @@ class pointToPointPlanarInterpolation
     // Private Member Functions
 
         //- Calculate a local coordinate system from set of points
-        coordinateSystem calcCoordinateSystem(const pointField&) const;
+        coordSystem::cartesian calcCoordinateSystem(const pointField&) const;
 
         //- Calculate addressing and weights
         void calcWeights
@@ -145,8 +145,8 @@ public:
             return nearestOnly_;
         }
 
-        //- Return the coordinateSystem
-        const coordinateSystem& referenceCS() const
+        //- Return the Cartesian reference coordinate system
+        const coordSystem::cartesian& referenceCS() const
         {
             return referenceCS_;
         }
diff --git a/src/sampling/sampledSet/array/arraySet.C b/src/sampling/sampledSet/array/arraySet.C
index c4a25e39372db59e1b5013ab2d82a55ab2f46279..eb747ae80cd01885081d4d1319c63189b0a2c458 100644
--- a/src/sampling/sampledSet/array/arraySet.C
+++ b/src/sampling/sampledSet/array/arraySet.C
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011-2016 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2018 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -30,7 +30,6 @@ License
 #include "polyMesh.H"
 #include "addToRunTimeSelectionTable.H"
 #include "word.H"
-#include "transform.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
@@ -54,51 +53,37 @@ void Foam::arraySet::calcSamples
 {
     const meshSearch& queryMesh = searchEngine();
 
-    label nTotalSamples
-    (
-        pointsDensity_.x()
-       *pointsDensity_.y()
-       *pointsDensity_.z()
-    );
-
-    List<point> sampleCoords(nTotalSamples);
+    const scalar dx = spanBox_.x()/(pointsDensity_.x() + 1);
+    const scalar dy = spanBox_.y()/(pointsDensity_.y() + 1);
+    const scalar dz = spanBox_.z()/(pointsDensity_.z() + 1);
 
-    const scalar deltax = spanBox_.x()/(pointsDensity_.x() + 1);
-    const scalar deltay = spanBox_.y()/(pointsDensity_.y() + 1);
-    const scalar deltaz = spanBox_.z()/(pointsDensity_.z() + 1);
+    label sampleI(0);
 
-    label p(0);
     for (label k=1; k<=pointsDensity_.z(); ++k)
     {
         for (label j=1; j<=pointsDensity_.y(); ++j)
         {
             for (label i=1; i<=pointsDensity_.x(); ++i)
             {
-                vector t(deltax*i , deltay*j, deltaz*k);
-                sampleCoords[p] = coordSys_.origin() + t;
-                ++p;
+                // Local Cartesian
+                point pt(i*dx*i , j*dy, k*dz);
+
+                // Global Cartesian
+                pt = csys_.globalPosition(pt);
+
+                const label celli = queryMesh.findCell(pt);
+
+                if (celli != -1)
+                {
+                    samplingPts.append(pt);
+                    samplingCells.append(celli);
+                    samplingFaces.append(-1);
+                    samplingSegments.append(0);
+                    samplingCurveDist.append(1.0 * sampleI);
+                }
             }
         }
     }
-
-    forAll(sampleCoords, i)
-    {
-        sampleCoords[i] = transform(coordSys_.R().R(), sampleCoords[i]);
-    }
-
-    forAll(sampleCoords, sampleI)
-    {
-        label celli = queryMesh.findCell(sampleCoords[sampleI]);
-
-        if (celli != -1)
-        {
-            samplingPts.append(sampleCoords[sampleI]);
-            samplingCells.append(celli);
-            samplingFaces.append(-1);
-            samplingSegments.append(0);
-            samplingCurveDist.append(1.0 * sampleI);
-        }
-    }
 }
 
 
@@ -151,13 +136,13 @@ Foam::arraySet::arraySet
     const polyMesh& mesh,
     const meshSearch& searchEngine,
     const word& axis,
-    const coordinateSystem& origin,
+    const coordSystem::cartesian& csys,
     const Vector<label>& pointsDensity,
     const Vector<scalar>& spanBox
 )
 :
     sampledSet(name, mesh, searchEngine, axis),
-    coordSys_(origin),
+    csys_(csys),
     pointsDensity_(pointsDensity),
     spanBox_(spanBox)
 {
@@ -174,7 +159,7 @@ Foam::arraySet::arraySet
 )
 :
     sampledSet(name, mesh, searchEngine, dict),
-    coordSys_(dict),
+    csys_(dict),  // Note: no indirect cs with this constructor
     pointsDensity_(dict.get<labelVector>("pointsDensity")),
     spanBox_(dict.get<vector>("spanBox"))
 {
diff --git a/src/sampling/sampledSet/array/arraySet.H b/src/sampling/sampledSet/array/arraySet.H
index c176993891896aa7dd64082f17e9adae152e6050..f56831de9719ff56a53ef9b9105c67b7fa95726a 100644
--- a/src/sampling/sampledSet/array/arraySet.H
+++ b/src/sampling/sampledSet/array/arraySet.H
@@ -3,7 +3,7 @@
   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
    \\    /   O peration     |
     \\  /    A nd           | Copyright (C) 2011 OpenFOAM Foundation
-     \\/     M anipulation  |
+     \\/     M anipulation  | Copyright (C) 2018 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -49,17 +49,14 @@ SourceFiles
 #include "sampledSet.H"
 #include "labelVector.H"
 #include "DynamicList.H"
-#include "coordinateSystem.H"
+#include "cartesianCS.H"
+#include "cylindricalCS.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 namespace Foam
 {
 
-// Forward declarations
-class passiveParticle;
-template<class Type> class particle;
-
 /*---------------------------------------------------------------------------*\
                            Class arraySet Declaration
 \*---------------------------------------------------------------------------*/
@@ -70,8 +67,8 @@ class arraySet
 {
     // Private data
 
-        //- Coordinate system
-        coordinateSystem coordSys_;
+        //- Local Cartesian coordinate system
+        coordSystem::cartesian csys_;
 
         //- Point density vector
         labelVector pointsDensity_;
@@ -111,7 +108,7 @@ public:
             const polyMesh& mesh,
             const meshSearch& searchEngine,
             const word& axis,
-            const coordinateSystem& coordSys,
+            const coordSystem::cartesian& csys,
             const Vector<label>& pointsDensity,
             const Vector<scalar>& spanBox
         );
diff --git a/src/sampling/sampledSet/circle/circleSet.H b/src/sampling/sampledSet/circle/circleSet.H
index 5d4cb5973497e7bbeba5836db4138e39ce1cc401..ab122f8795490c70ae6dac384c792052b0dd8f20 100644
--- a/src/sampling/sampledSet/circle/circleSet.H
+++ b/src/sampling/sampledSet/circle/circleSet.H
@@ -69,13 +69,13 @@ class circleSet
 
         // Circle definition
 
-            //- Origin (x, y, z) in global cartesian co-ordinates
+            //- Origin (x, y, z) in global cartesian coordinates
             point origin_;
 
             //- Axis of the circle
             vector circleAxis_;
 
-            //- Point on circle (x, y, z) in global cartesian co-ordinates
+            //- Point on circle (x, y, z) in global cartesian coordinates
             //  Defines start point
             point startPoint_;
 
diff --git a/src/sampling/sampledSurface/readers/ensight/ensightSurfaceReader.C b/src/sampling/sampledSurface/readers/ensight/ensightSurfaceReader.C
index 11701aa55a7ba3e222163d5c923b49db99f55bcd..3c1759e3cf873b96d86d6acca299310c6869fac7 100644
--- a/src/sampling/sampledSurface/readers/ensight/ensightSurfaceReader.C
+++ b/src/sampling/sampledSurface/readers/ensight/ensightSurfaceReader.C
@@ -130,7 +130,7 @@ void Foam::ensightSurfaceReader::readGeometryHeader(ensightReadFile& is) const
     is.read(buffer);
     if (debug) Info<< "buffer: " << buffer << endl;
 
-    // Co-ordinates
+    // Coordinates
     is.read(buffer);
     if (debug) Info<< "buffer: " << buffer << endl;
 }
diff --git a/src/sampling/sampledSurface/sampledPlane/sampledPlane.C b/src/sampling/sampledSurface/sampledPlane/sampledPlane.C
index 954302f4a8313438e578637cbf8d21ec5cc760b5..32720169cf4f683acdd002c7bd14dcc72018d974 100644
--- a/src/sampling/sampledSurface/sampledPlane/sampledPlane.C
+++ b/src/sampling/sampledSurface/sampledPlane/sampledPlane.C
@@ -27,7 +27,7 @@ License
 #include "dictionary.H"
 #include "polyMesh.H"
 #include "volFields.H"
-#include "coordinateSystem.H"
+#include "cartesianCS.H"
 #include "addToRunTimeSelectionTable.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@@ -117,9 +117,12 @@ Foam::sampledPlane::sampledPlane
 
     // Make plane relative to the coordinateSystem (Cartesian)
     // allow lookup from global coordinate systems
-    if (dict.found("coordinateSystem"))
+    if (dict.found(coordinateSystem::typeName_()))
     {
-        coordinateSystem cs(mesh, dict.subDict("coordinateSystem"));
+        coordSystem::cartesian cs
+        (
+            coordinateSystem::New(mesh, dict, coordinateSystem::typeName_())
+        );
         plane& pln = planeDesc();
 
         const point  orig = cs.globalPosition(pln.origin());
diff --git a/src/sampling/surfMeshSample/plane/surfMeshSamplePlane.C b/src/sampling/surfMeshSample/plane/surfMeshSamplePlane.C
index 3eaaafd7df9a5176b3b69b368bf71fdf7e41960c..59eb7d33b9c789510428717fd43ab5c124e57398 100644
--- a/src/sampling/surfMeshSample/plane/surfMeshSamplePlane.C
+++ b/src/sampling/surfMeshSample/plane/surfMeshSamplePlane.C
@@ -27,7 +27,7 @@ License
 #include "dictionary.H"
 #include "polyMesh.H"
 #include "volFields.H"
-#include "coordinateSystem.H"
+#include "cartesianCS.H"
 #include "addToRunTimeSelectionTable.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@@ -117,9 +117,12 @@ Foam::surfMeshSamplePlane::surfMeshSamplePlane
 
     // Make plane relative to the coordinateSystem (Cartesian)
     // allow lookup from global coordinate systems
-    if (dict.found("coordinateSystem"))
+    if (dict.found(coordinateSystem::typeName_()))
     {
-        coordinateSystem cs(mesh, dict.subDict("coordinateSystem"));
+        coordSystem::cartesian cs
+        (
+            coordinateSystem::New(mesh, dict, coordinateSystem::typeName_())
+        );
         plane& pln = planeDesc();
 
         const point  orig = cs.globalPosition(pln.origin());
diff --git a/src/thermophysicalModels/radiation/submodels/solarCalculator/solarCalculator.C b/src/thermophysicalModels/radiation/submodels/solarCalculator/solarCalculator.C
index af4662addf901dce745c68e82c669078df066605..5a3063394882fa877bb074ed06c0b90374c66577 100644
--- a/src/thermophysicalModels/radiation/submodels/solarCalculator/solarCalculator.C
+++ b/src/thermophysicalModels/radiation/submodels/solarCalculator/solarCalculator.C
@@ -144,7 +144,7 @@ void Foam::solarCalculator::calculateSunDirection()
     }
 
     // Transform to actual coordinate system
-    direction_ = coord_->R().transform(direction_);
+    direction_ = coord_->transform(direction_);
 
     if (debug)
     {
diff --git a/src/topoChangerFvMesh/mixerFvMesh/mixerFvMesh.C b/src/topoChangerFvMesh/mixerFvMesh/mixerFvMesh.C
index d613e33906ebe782568f17b78aadb3817db49983..6686df17aa61459d1746f9c4d94cc44ab4adabf9 100644
--- a/src/topoChangerFvMesh/mixerFvMesh/mixerFvMesh.C
+++ b/src/topoChangerFvMesh/mixerFvMesh/mixerFvMesh.C
@@ -29,13 +29,13 @@ License
 #include "slidingInterface.H"
 #include "addToRunTimeSelectionTable.H"
 #include "mapPolyMesh.H"
+#include "unitConversion.H"
 
 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
 
 namespace Foam
 {
     defineTypeNameAndDebug(mixerFvMesh, 0);
-
     addToRunTimeSelectionTable(topoChangerFvMesh, mixerFvMesh, IOobject);
 }
 
@@ -110,7 +110,7 @@ void Foam::mixerFvMesh::addZonesAndModifiers()
     regionSplit rs(*this);
 
     // Get the region of the cell containing the origin.
-    const label originRegion = rs[findNearestCell(cs().origin())];
+    const label originRegion = rs[findNearestCell(csys_.origin())];
 
     labelList movingCells(nCells());
     label nMovingCells = 0;
@@ -207,8 +207,7 @@ void Foam::mixerFvMesh::calcMovingMasks() const
 
     const word innerSliderZoneName
     (
-        word(motionDict_.subDict("slider").lookup("inside"))
-      + "Zone"
+        motionDict_.subDict("slider").get<word>("inside") + "Zone"
     );
 
     const labelList& innerSliderAddr = faceZones()[innerSliderZoneName];
@@ -225,8 +224,7 @@ void Foam::mixerFvMesh::calcMovingMasks() const
 
     const word outerSliderZoneName
     (
-        word(motionDict_.subDict("slider").lookup("outside"))
-      + "Zone"
+        motionDict_.subDict("slider").get<word>("outside") + "Zone"
     );
 
     const labelList& outerSliderAddr = faceZones()[outerSliderZoneName];
@@ -245,7 +243,6 @@ void Foam::mixerFvMesh::calcMovingMasks() const
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-// Construct from components
 Foam::mixerFvMesh::mixerFvMesh
 (
     const IOobject& io
@@ -267,22 +264,26 @@ Foam::mixerFvMesh::mixerFvMesh
             )
         ).optionalSubDict(typeName + "Coeffs")
     ),
-    csPtr_
-    (
-        coordinateSystem::New
-        (
-            "coordinateSystem",
-            motionDict_.subDict("coordinateSystem")
-        )
-    ),
-    rpm_(readScalar(motionDict_.lookup("rpm"))),
+    csys_(),
+    rpm_(motionDict_.get<scalar>("rpm")),
     movingPointsMaskPtr_(nullptr)
 {
+    if (motionDict_.found(coordinateSystem::typeName_()))
+    {
+        // New() for access to indirect (global) coordSystem.
+        static_cast<coordinateSystem&>(csys_) =
+            *coordinateSystem::New(*this, motionDict_);
+    }
+    else
+    {
+        csys_ = coordSystem::cylindrical(motionDict_);
+    }
+
     addZonesAndModifiers();
 
     Info<< "Mixer mesh:" << nl
-        << "    origin: " << cs().origin() << nl
-        << "    axis: " << cs().axis() << nl
+        << "    origin: " << csys_.origin() << nl
+        << "    axis: " << csys_.e3() << nl
         << "    rpm: " << rpm_ << endl;
 }
 
@@ -294,6 +295,7 @@ Foam::mixerFvMesh::~mixerFvMesh()
     deleteDemandDrivenData(movingPointsMaskPtr_);
 }
 
+
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 // Return moving points mask.  Moving points marked with 1
@@ -310,13 +312,15 @@ const Foam::scalarField& Foam::mixerFvMesh::movingPointsMask() const
 
 bool Foam::mixerFvMesh::update()
 {
-    // Rotational speed needs to be converted from rpm
+    // The tangential sweep (radians)
+    const vector theta(0, rpmToRads(rpm_)*time().deltaTValue(), 0);
+
     movePoints
     (
-        csPtr_->globalPosition
+        csys_.globalPosition
         (
-            csPtr_->localPosition(points())
-          + vector(0, rpm_*360.0*time().deltaTValue()/60.0, 0)
+            csys_.localPosition(points())
+          + theta
             *movingPointsMask()
         )
     );
@@ -336,10 +340,10 @@ bool Foam::mixerFvMesh::update()
 
     movePoints
     (
-        csPtr_->globalPosition
+        csys_.globalPosition
         (
-            csPtr_->localPosition(oldPoints())
-          + vector(0, rpm_*360.0*time().deltaTValue()/60.0, 0)
+            csys_.localPosition(oldPoints())
+          + theta
             *movingPointsMask()
         )
     );
diff --git a/src/topoChangerFvMesh/mixerFvMesh/mixerFvMesh.H b/src/topoChangerFvMesh/mixerFvMesh/mixerFvMesh.H
index 5d4eb0c27097269acb53a7da031df8793385e6e4..bb2bd3dd42f2df20f3f3881c6bdf0071c8bae139 100644
--- a/src/topoChangerFvMesh/mixerFvMesh/mixerFvMesh.H
+++ b/src/topoChangerFvMesh/mixerFvMesh/mixerFvMesh.H
@@ -43,8 +43,6 @@ SourceFiles
 namespace Foam
 {
 
-// Forward declaration of classes
-
 /*---------------------------------------------------------------------------*\
                            Class mixerFvMesh Declaration
 \*---------------------------------------------------------------------------*/
@@ -58,10 +56,10 @@ class mixerFvMesh
         //- Motion dictionary
         dictionary motionDict_;
 
-        //- Coordinate system
-        autoPtr<coordinateSystem> csPtr_;
+        //- Cylindrical coordinate system
+        coordSystem::cylindrical csys_;
 
-        // - Rotational speed in rotations per minute (rpm)
+        // - Rotational speed in revolutions per minute (rpm)
         scalar rpm_;
 
         //- Markup field for points.  Moving points marked with 1
@@ -106,9 +104,9 @@ public:
     // Member Functions
 
         //- Return coordinate system
-        const coordinateSystem& cs() const
+        const coordSystem::cylindrical& cs() const
         {
-            return *csPtr_;
+            return csys_;
         }
 
         //- Update the mesh for both mesh motion and topology change
diff --git a/src/waveModels/waveModel/waveModel.C b/src/waveModels/waveModel/waveModel.C
index 829cd89d59aee7233a77661edc1a56a77d694a96..4a9f7d7135358322500a1ff94242df14bb4ce4fb 100644
--- a/src/waveModels/waveModel/waveModel.C
+++ b/src/waveModels/waveModel/waveModel.C
@@ -53,7 +53,7 @@ Foam::word Foam::waveModel::modelName(const word& patchName)
 
 void Foam::waveModel::initialiseGeometry()
 {
-    // Determine local patch co-ordinate system given by:
+    // Determine local patch coordinate system given by:
     // - X: streamwise: patch normal
     // - Y: spanwise: Z^X
     // - Z: up: (negative) gravity direction
@@ -396,7 +396,7 @@ void Foam::waveModel::correct(const scalar t)
             }
         }
 
-        // Transform velocity into global co-ordinate system
+        // Transform velocity into global coordinate system
         U_ = Rlg_ & U_;
 
         currTimeIndex_ = mesh_.time().timeIndex();
diff --git a/src/waveModels/waveModel/waveModel.H b/src/waveModels/waveModel/waveModel.H
index 84b6d39163b4e07fbbc8b057b7bb2bff23eac4d0..694acd6b80a26abeb1e82568b18b3d8b04a4f807 100644
--- a/src/waveModels/waveModel/waveModel.H
+++ b/src/waveModels/waveModel/waveModel.H
@@ -85,16 +85,16 @@ protected:
         //- Number of paddles
         label nPaddle_;
 
-        //- Paddle x co-ordinates / [m]
+        //- Paddle x coordinates / [m]
         scalarField xPaddle_;
 
-        //- Paddle y co-ordinates / [m]
+        //- Paddle y coordinates / [m]
         scalarField yPaddle_;
 
         //- Addressing from patch face index to paddle index
         labelList faceToPaddle_;
 
-        //- Patch face centre z co-ordinates / [m]
+        //- Patch face centre z coordinates / [m]
         scalarField z_;
 
         //- Overall (point) span in z-direction / [m]
diff --git a/tutorials/compressible/rhoPimpleFoam/RAS/angledDuct/constant/fvOptions b/tutorials/compressible/rhoPimpleFoam/RAS/angledDuct/constant/fvOptions
index 3d246ece8b7ac86d32e447b3aacb108d57b5ffe4..306f826cef7c73498ed38b0229640e79fc72c756 100644
--- a/tutorials/compressible/rhoPimpleFoam/RAS/angledDuct/constant/fvOptions
+++ b/tutorials/compressible/rhoPimpleFoam/RAS/angledDuct/constant/fvOptions
@@ -31,14 +31,9 @@ porosity1
 
         coordinateSystem
         {
-            type    cartesian;
             origin  (0 0 0);
-            coordinateRotation
-            {
-                type    axesRotation;
-                e1      (0.70710678 0.70710678 0);
-                e3      (0 0 1);
-            }
+            e1      (0.70710678 0.70710678 0);
+            e3      (0 0 1);
         }
     }
 }
diff --git a/tutorials/compressible/rhoPimpleFoam/RAS/angledDuctLTS/constant/fvOptions b/tutorials/compressible/rhoPimpleFoam/RAS/angledDuctLTS/constant/fvOptions
index 1a139a96d42795c03219a87c6d97c5bacc392918..adaebd15cfc0b5bb8bd9999a647796cfb2c0977b 100644
--- a/tutorials/compressible/rhoPimpleFoam/RAS/angledDuctLTS/constant/fvOptions
+++ b/tutorials/compressible/rhoPimpleFoam/RAS/angledDuctLTS/constant/fvOptions
@@ -31,14 +31,9 @@ porosity1
 
         coordinateSystem
         {
-            type    cartesian;
             origin  (0 0 0);
-            coordinateRotation
-            {
-                type    axesRotation;
-                e1  (0.70710678 0.70710678 0);
-                e2  (0 0 1);
-            }
+            e1      (0.70710678 0.70710678 0);
+            e2      (0 0 1);
         }
     }
 }
diff --git a/tutorials/compressible/rhoPimpleFoam/RAS/mixerVessel2D/constant/fvOptions b/tutorials/compressible/rhoPimpleFoam/RAS/mixerVessel2D/constant/fvOptions
index 1dca13888a90724ee205bd495e4745b750b7447d..04d38c69637a2dfc7bfadccb5fcaa603aea528a6 100644
--- a/tutorials/compressible/rhoPimpleFoam/RAS/mixerVessel2D/constant/fvOptions
+++ b/tutorials/compressible/rhoPimpleFoam/RAS/mixerVessel2D/constant/fvOptions
@@ -22,6 +22,7 @@ porosity1
     explicitPorositySourceCoeffs
     {
         selectionMode   cellZone;
+
         cellZone        stator;
 
         type            DarcyForchheimer;
@@ -31,13 +32,11 @@ porosity1
 
         coordinateSystem
         {
-            type    cartesian;
             origin  (0 0 0);
-            coordinateRotation
+
+            rotation
             {
-                type    axesRotation;
-                e1  (1 0 0);
-                e2  (0 1 0);
+                type    none;
             }
         }
     }
diff --git a/tutorials/compressible/rhoPorousSimpleFoam/angledDuct/common/constant/porosityProperties b/tutorials/compressible/rhoPorousSimpleFoam/angledDuct/common/constant/porosityProperties
index 8093402fc9173a766a8c048c986ccc2338a09ecd..77c3649255caf6e6061bdc6d4837788c8141d760 100644
--- a/tutorials/compressible/rhoPorousSimpleFoam/angledDuct/common/constant/porosityProperties
+++ b/tutorials/compressible/rhoPorousSimpleFoam/angledDuct/common/constant/porosityProperties
@@ -26,14 +26,9 @@ porosity1
 
     coordinateSystem
     {
-        type    cartesian;
         origin  (0 0 0);
-        coordinateRotation
-        {
-            type    axesRotation;
-            e1  (0.70710678 0.70710678 0);
-            e2  (0 0 1);
-        }
+        e1      (0.70710678 0.70710678 0);
+        e2      (0 0 1);
     }
 }
 
diff --git a/tutorials/compressible/rhoSimpleFoam/angledDuctExplicitFixedCoeff/constant/fvOptions b/tutorials/compressible/rhoSimpleFoam/angledDuctExplicitFixedCoeff/constant/fvOptions
index 1cf991953fe20be1ad46cc054ca2170b2d5fd878..4fc67a5490e3b9ef87dee628503dc70cd7c059f0 100644
--- a/tutorials/compressible/rhoSimpleFoam/angledDuctExplicitFixedCoeff/constant/fvOptions
+++ b/tutorials/compressible/rhoSimpleFoam/angledDuctExplicitFixedCoeff/constant/fvOptions
@@ -35,14 +35,9 @@ porosity
 
             coordinateSystem
             {
-                type    cartesian;
                 origin  (0 0 0);
-                coordinateRotation
-                {
-                    type    axesRotation;
-                    e1      (0.70710678 0.70710678 0);
-                    e2      (0 0 1);
-                }
+                e1      (0.70710678 0.70710678 0);
+                e2      (0 0 1);
             }
         }
     }
diff --git a/tutorials/heatTransfer/buoyantBoussinesqSimpleFoam/iglooWithFridges/system/snappyHexMeshDict b/tutorials/heatTransfer/buoyantBoussinesqSimpleFoam/iglooWithFridges/system/snappyHexMeshDict
index c75aa58ad7817330de576a564d9a1525ffeed24a..244b9b7177823732a9e78d1511cc3fe2a20015e1 100644
--- a/tutorials/heatTransfer/buoyantBoussinesqSimpleFoam/iglooWithFridges/system/snappyHexMeshDict
+++ b/tutorials/heatTransfer/buoyantBoussinesqSimpleFoam/iglooWithFridges/system/snappyHexMeshDict
@@ -54,17 +54,9 @@ geometry
             scale   (1.0 1.0 2.1);
             transform
             {
-                coordinateSystem
-                {
-                    type    cartesian;
-                    origin  (2 2 0);
-                    coordinateRotation
-                    {
-                        type    axesRotation;
-                        e1      (1 0 0);
-                        e3      (0 0 1);
-                    }
-                }
+                origin  (2 2 0);
+                e1      (1 0 0);
+                e3      (0 0 1);
             }
         }
         herring
@@ -73,17 +65,9 @@ geometry
             scale   (1.0 1.0 2.1);
             transform
             {
-                coordinateSystem
-                {
-                    type    cartesian;
-                    origin  (3.5 3 0);
-                    coordinateRotation
-                    {
-                        type    axesRotation;
-                        e1      (1 0 0);
-                        e3      (0 0 1);
-                    }
-                }
+                origin  (3.5 3 0);
+                e1      (1 0 0);
+                e3      (0 0 1);
             }
         }
     }
@@ -121,7 +105,6 @@ castellatedMeshControls
     nCellsBetweenLevels 1;
 
 
-
     // Explicit feature edge refinement
     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
@@ -136,7 +119,6 @@ castellatedMeshControls
     );
 
 
-
     // Surface based refinement
     // ~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/tutorials/heatTransfer/chtMultiRegionSimpleFoam/heatExchanger/constant/air/fvOptions b/tutorials/heatTransfer/chtMultiRegionSimpleFoam/heatExchanger/constant/air/fvOptions
index 870926abb9f90aa1d14bc015a4fe73f9de67b2ca..15fa8b1c2cbad1fbd42cf507cc67fd32f615b553 100644
--- a/tutorials/heatTransfer/chtMultiRegionSimpleFoam/heatExchanger/constant/air/fvOptions
+++ b/tutorials/heatTransfer/chtMultiRegionSimpleFoam/heatExchanger/constant/air/fvOptions
@@ -44,14 +44,9 @@ porosityBlockage
 
         coordinateSystem
         {
-            type    cartesian;
             origin  (0 0 0);
-            coordinateRotation
-            {
-                type    axesRotation;
-                e1      (0 1 0);
-                e2      (0 0 1);
-            }
+            e1      (0 1 0);
+            e2      (0 0 1);
         }
     }
 }
diff --git a/tutorials/incompressible/pisoFoam/laminar/porousBlockage/constant/fvOptions b/tutorials/incompressible/pisoFoam/laminar/porousBlockage/constant/fvOptions
index 5240f45df467c7c5bb86a1b03ad423123eec2fb1..7bfa2b4c72ed8764df0c498bb4a11a105fddbe78 100644
--- a/tutorials/incompressible/pisoFoam/laminar/porousBlockage/constant/fvOptions
+++ b/tutorials/incompressible/pisoFoam/laminar/porousBlockage/constant/fvOptions
@@ -22,6 +22,7 @@ porosity1
     explicitPorositySourceCoeffs
     {
         selectionMode   cellZone;
+
         cellZone        porousBlockage;
 
         type            DarcyForchheimer;
@@ -36,13 +37,11 @@ porosity1
 
         coordinateSystem
         {
-            type    cartesian;
             origin  (0 0 0);
-            coordinateRotation
+
+            rotation
             {
-                type    axesRotation;
-                e1  (1 0 0);
-                e2  (0 1 0);
+                type    none;
             }
         }
     }
diff --git a/tutorials/incompressible/porousSimpleFoam/angledDuct/common/constant/porosityProperties b/tutorials/incompressible/porousSimpleFoam/angledDuct/common/constant/porosityProperties
index bea521b859ae500b54af07f88a75788473c08192..77c3649255caf6e6061bdc6d4837788c8141d760 100644
--- a/tutorials/incompressible/porousSimpleFoam/angledDuct/common/constant/porosityProperties
+++ b/tutorials/incompressible/porousSimpleFoam/angledDuct/common/constant/porosityProperties
@@ -26,14 +26,9 @@ porosity1
 
     coordinateSystem
     {
-        type    cartesian;
         origin  (0 0 0);
-        coordinateRotation
-        {
-            type    axesRotation;
-            e1      (0.70710678 0.70710678 0);
-            e2      (0 0 1);
-        }
+        e1      (0.70710678 0.70710678 0);
+        e2      (0 0 1);
     }
 }
 
diff --git a/tutorials/incompressible/porousSimpleFoam/straightDuctImplicit/constant/porosityProperties b/tutorials/incompressible/porousSimpleFoam/straightDuctImplicit/constant/porosityProperties
index 9c81c5df7e1dee0ec104c283d060dd56acbc642c..13973aa67e953fdd662d54bc25bd938ca99a1ead 100644
--- a/tutorials/incompressible/porousSimpleFoam/straightDuctImplicit/constant/porosityProperties
+++ b/tutorials/incompressible/porousSimpleFoam/straightDuctImplicit/constant/porosityProperties
@@ -26,14 +26,9 @@ porosity1
 
     coordinateSystem
     {
-        type    cartesian;
         origin  (0 0 0);
-        coordinateRotation
-        {
-            type    axesRotation;
-            e1      (1 0 0);    //(0.70710678 0.70710678 0);
-            e2      (0 0 1);
-        }
+        e1      (1 0 0);
+        e2      (0 1 0);
     }
 }
 
diff --git a/tutorials/incompressible/simpleFoam/simpleCar/system/fvOptions b/tutorials/incompressible/simpleFoam/simpleCar/system/fvOptions
index 8619d8254bef8fef8a4d0d881222b2a2b4bfb79e..36dd8238364f8d3c85a8fdeed4c3445bba4fa4b0 100644
--- a/tutorials/incompressible/simpleFoam/simpleCar/system/fvOptions
+++ b/tutorials/incompressible/simpleFoam/simpleCar/system/fvOptions
@@ -33,14 +33,9 @@ porosity1
 
             coordinateSystem
             {
-                type            cartesian;
-                origin          (0 0 0);
-                coordinateRotation
-                {
-                    type            axesRotation;
-                    e1              (1 0 0);
-                    e2              (0 1 0);
-                }
+                origin  (0 0 0);
+                e1      (1 0 0);
+                e2      (0 1 0);
             }
         }
     }
diff --git a/tutorials/lagrangian/reactingParcelFoam/filter/constant/fvOptions b/tutorials/lagrangian/reactingParcelFoam/filter/constant/fvOptions
index fdbdbb37dbb24a022b35a3e0820587b2aaab3800..b2fd38d6d48e450160026ea041967eff3b8a7381 100644
--- a/tutorials/lagrangian/reactingParcelFoam/filter/constant/fvOptions
+++ b/tutorials/lagrangian/reactingParcelFoam/filter/constant/fvOptions
@@ -31,14 +31,9 @@ filter1
 
         coordinateSystem
         {
-            type    cartesian;
             origin  (0 0 0);
-            coordinateRotation
-            {
-                type    axesRotation;
-                e1  (1 0 0);
-                e2  (0 1 0);
-            }
+            e1      (1 0 0);
+            e2      (0 1 0);
         }
     }
 }
diff --git a/tutorials/mesh/parallel/filter/system/fvOptions b/tutorials/mesh/parallel/filter/system/fvOptions
index be0c86520ff4390b37ad04eb064afc260a2a8110..89094dc787b9104e5654f72c99c1816459048a5d 100644
--- a/tutorials/mesh/parallel/filter/system/fvOptions
+++ b/tutorials/mesh/parallel/filter/system/fvOptions
@@ -34,14 +34,9 @@ filter1
 
             coordinateSystem
             {
-                type    cartesian;
                 origin  (0 0 0);
-                coordinateRotation
-                {
-                    type    axesRotation;
-                    e1  (1 0 0);
-                    e2  (0 1 0);
-                }
+                e1      (1 0 0);
+                e2      (0 1 0);
             }
         }
     }
diff --git a/tutorials/multiphase/interFoam/RAS/angledDuct/constant/fvOptions b/tutorials/multiphase/interFoam/RAS/angledDuct/constant/fvOptions
index 84a023855686f37df4e4d616951ef3da371bde7f..e90a10d0965f8e46222eff7f2c9d987deffb3823 100644
--- a/tutorials/multiphase/interFoam/RAS/angledDuct/constant/fvOptions
+++ b/tutorials/multiphase/interFoam/RAS/angledDuct/constant/fvOptions
@@ -31,14 +31,9 @@ porosity1
 
         coordinateSystem
         {
-            type    cartesian;
             origin  (0 0 0);
-            coordinateRotation
-            {
-                type    axesRotation;
-                e1  (0.70710678 0.70710678 0);
-                e2  (0 0 1);
-            }
+            e1      (0.70710678 0.70710678 0);
+            e2      (0 0 1);
         }
     }
 }
diff --git a/tutorials/verificationAndValidation/schemes/divergenceExample/README b/tutorials/verificationAndValidation/schemes/divergenceExample/README
index 6b586a8f8ea32544a3f4eff4e319efcd141301d9..6e04d3a7603fd4739d903a7ce44453fb29a35a39 100644
--- a/tutorials/verificationAndValidation/schemes/divergenceExample/README
+++ b/tutorials/verificationAndValidation/schemes/divergenceExample/README
@@ -2,7 +2,7 @@ Divergence scheme test
 ======================
 
 Various divergence schemes are examined on a 2-D structured mesh, where a
-passive scalar is convected at 45deg to the mesh co-ordinate system using a
+passive scalar is convected at 45deg to the mesh coordinate system using a
 uniform flow velocity.  Executing:
 
 ./Allrun
diff --git a/wmake/rules/General/general b/wmake/rules/General/general
index d6584304cdde0b364fc915c57e562c5feeaff2bf..1421bb21a0c5e83f878015b41240b6c0f6a28043 100644
--- a/wmake/rules/General/general
+++ b/wmake/rules/General/general
@@ -1,5 +1,5 @@
 #-------------------------------*- makefile -*---------------------------------
-WM_VERSION = OPENFOAM=1807
+WM_VERSION = OPENFOAM=1810
 
 AR         = ar
 ARFLAGS    = cr