From f269371dbc324cbaf714b4fff70519469f3c1e2a Mon Sep 17 00:00:00 2001
From: Mark Olesen <Mark.Olesen@esi-group.com>
Date: Fri, 16 Nov 2018 15:12:19 +0100
Subject: [PATCH] ENH: support cylindrical coordinates in
 fieldCoordinateSystemTransform (#1076)

---
 .../fieldCoordinateSystemTransform.C          | 97 ++++++++++++++++++-
 .../fieldCoordinateSystemTransform.H          | 38 ++++++--
 .../fieldCoordinateSystemTransformTemplates.C | 97 ++++++++++++++++---
 .../simpleFoam/pipeCyclic/system/controlDict  |  5 +
 .../pipeCyclic/system/coordinateTransform     | 24 +++++
 5 files changed, 234 insertions(+), 27 deletions(-)
 create mode 100644 tutorials/incompressible/simpleFoam/pipeCyclic/system/coordinateTransform

diff --git a/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransform.C b/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransform.C
index e1d06c1729f..7259d24ca84 100644
--- a/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransform.C
+++ b/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransform.C
@@ -64,7 +64,8 @@ fieldCoordinateSystemTransform
     read(dict);
 
     Info<< type() << " " << name << ":" << nl
-        << "   Applying uniform transformation from global Cartesian to local "
+        << "   Applying " << (csysPtr_->uniform() ? "" : "non-")
+        << "uniform transformation from global Cartesian to local "
         << *csysPtr_ << nl << endl;
 }
 
@@ -81,6 +82,96 @@ Foam::functionObjects::fieldCoordinateSystemTransform::transformFieldName
 }
 
 
+const Foam::surfaceTensorField&
+Foam::functionObjects::fieldCoordinateSystemTransform::srotTensor() const
+{
+    typedef surfaceTensorField FieldType;
+    typedef surfaceTensorField::Boundary BoundaryType;
+
+    if (!rotTensorSurface_.valid())
+    {
+        tensorField rotations(csysPtr_->R(mesh_.faceCentres()));
+
+        rotTensorSurface_.reset
+        (
+            new FieldType
+            (
+                IOobject
+                (
+                    "surfRotation",
+                    mesh_.objectRegistry::instance(),
+                    mesh_.objectRegistry::db(),
+                    IOobject::NO_READ,
+                    IOobject::NO_WRITE,
+                    false // no register
+                ),
+                mesh_,
+                dimless,
+                std::move(rotations)
+                // calculatedType
+            )
+        );
+
+        auto& rot = *rotTensorSurface_;
+
+        // Boundaries
+        BoundaryType& bf = const_cast<BoundaryType&>(rot.boundaryField());
+
+        forAll(bf, patchi)
+        {
+            bf[patchi] = csysPtr_->R(bf[patchi].patch().patch().faceCentres());
+        }
+    }
+
+    return *rotTensorSurface_;
+}
+
+
+const Foam::volTensorField&
+Foam::functionObjects::fieldCoordinateSystemTransform::vrotTensor() const
+{
+    typedef volTensorField FieldType;
+    typedef volTensorField::Boundary BoundaryType;
+
+    if (!rotTensorVolume_.valid())
+    {
+        tensorField rotations(csysPtr_->R(mesh_.cellCentres()));
+
+        rotTensorVolume_.reset
+        (
+            new FieldType
+            (
+                IOobject
+                (
+                    "volRotation",
+                    mesh_.objectRegistry::instance(),
+                    mesh_.objectRegistry::db(),
+                    IOobject::NO_READ,
+                    IOobject::NO_WRITE,
+                    false // no register
+                ),
+                mesh_,
+                dimless,
+                std::move(rotations)
+                // calculatedType
+            )
+        );
+
+        auto& rot = *rotTensorVolume_;
+
+        // Boundaries
+        BoundaryType& bf = const_cast<BoundaryType&>(rot.boundaryField());
+
+        forAll(bf, patchi)
+        {
+            bf[patchi] = csysPtr_->R(bf[patchi].patch().patch().faceCentres());
+        }
+    }
+
+    return *rotTensorVolume_;
+}
+
+
 bool Foam::functionObjects::fieldCoordinateSystemTransform::read
 (
     const dictionary& dict
@@ -109,6 +200,10 @@ bool Foam::functionObjects::fieldCoordinateSystemTransform::execute()
         transform<tensor>(fieldName);
     }
 
+    // Finished with these
+    rotTensorSurface_.clear();
+    rotTensorVolume_.clear();
+
     return true;
 }
 
diff --git a/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransform.H b/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransform.H
index 6247df0dca0..2f2e317e6d2 100644
--- a/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransform.H
+++ b/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransform.H
@@ -29,7 +29,7 @@ Group
 
 Description
     Transforms a user-specified selection of fields from global Cartesian
-    coordinates to a local Cartesian coordinate system.
+    coordinates to a local coordinate system.
     The fields are run-time modifiable.
 
 Usage
@@ -37,15 +37,10 @@ Usage
     \verbatim
     fieldCoordinateSystemTransform1
     {
-        type        fieldCoordinateSystemTransform;
-        libs        ("libfieldFunctionObjects.so");
+        type    fieldCoordinateSystemTransform;
+        libs    ("libfieldFunctionObjects.so");
         ...
-        fields
-        (
-            U
-            UMean
-            UPrime2Mean
-        );
+        fields  ( U UMean UPrime2Mean );
 
         coordinateSystem
         {
@@ -102,7 +97,7 @@ class fieldCoordinateSystemTransform
 {
 protected:
 
-    // Protected data
+    // Protected Data
 
         //- Fields to transform
         volFieldSelection fieldSet_;
@@ -110,16 +105,39 @@ protected:
         //- Coordinate system to transform to
         autoPtr<coordinateSystem> csysPtr_;
 
+        //- Demand-driven non-uniform rotation field (surface fields)
+        //  Eg, for cylindrical coordinates
+        mutable autoPtr<surfaceTensorField> rotTensorSurface_;
+
+        //- Demand-driven non-uniform rotation field (volume fields)
+        //  Eg, for cylindrical coordinates
+        mutable autoPtr<volTensorField> rotTensorVolume_;
+
 
     // Protected Member Functions
 
         //- Return the name of the transformed field
         word transformFieldName(const word& fieldName) const;
 
+        //- Demand-driven non-uniform rotation field for surface fields
+        const surfaceTensorField& srotTensor() const;
+
+        //- Demand-driven non-uniform rotation field for volume fields
+        const volTensorField& vrotTensor() const;
+
+
         //- Transform the given field
         template<class FieldType>
         void transformField(const FieldType& field);
 
+        //- Transform the given field
+        template<class FieldType, class RotationFieldType>
+        void transformField
+        (
+            const RotationFieldType& rot,
+            const FieldType& field
+        );
+
         //- Transform the given field if has the specified element type
         template<class Type>
         void transform(const word& fieldName);
diff --git a/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransformTemplates.C b/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransformTemplates.C
index a0ea180a432..4fd833b0e36 100644
--- a/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransformTemplates.C
+++ b/src/functionObjects/field/fieldCoordinateSystemTransform/fieldCoordinateSystemTransformTemplates.C
@@ -46,6 +46,23 @@ void Foam::functionObjects::fieldCoordinateSystemTransform::transformField
 }
 
 
+template<class FieldType, class RotationFieldType>
+void Foam::functionObjects::fieldCoordinateSystemTransform::transformField
+(
+    const RotationFieldType& rot,
+    const FieldType& field
+)
+{
+    word transFieldName(transformFieldName(field.name()));
+
+    store
+    (
+        transFieldName,
+        Foam::invTransform(rot, field)
+    );
+}
+
+
 template<class Type>
 void Foam::functionObjects::fieldCoordinateSystemTransform::transform
 (
@@ -55,16 +72,31 @@ void Foam::functionObjects::fieldCoordinateSystemTransform::transform
     typedef GeometricField<Type, fvPatchField, volMesh> VolFieldType;
     typedef GeometricField<Type, fvsPatchField, surfaceMesh> SurfaceFieldType;
 
+    // Scalar quantities (bool, label, scalar) and sphericalTensor quantities
+    // are transform invariant. Use (pTraits<Type>::nComponents == 1) to avoid
+    // avoid generating a tensor field for a non-uniform transformation.
+
     if (foundObject<VolFieldType>(fieldName))
     {
         DebugInfo
             << type() << ": Field " << fieldName << " already in database"
             << endl;
 
-        transformField<VolFieldType>
-        (
-            lookupObject<VolFieldType>(fieldName)
-        );
+        if (csysPtr_->uniform() || pTraits<Type>::nComponents == 1)
+        {
+            transformField<VolFieldType>
+            (
+                lookupObject<VolFieldType>(fieldName)
+            );
+        }
+        else
+        {
+            transformField<VolFieldType>
+            (
+                vrotTensor(),
+                lookupObject<VolFieldType>(fieldName)
+            );
+        }
     }
     else if (foundObject<SurfaceFieldType>(fieldName))
     {
@@ -72,10 +104,21 @@ void Foam::functionObjects::fieldCoordinateSystemTransform::transform
             << type() << ": Field " << fieldName << " already in database"
             << endl;
 
-        transformField<SurfaceFieldType>
-        (
-            lookupObject<SurfaceFieldType>(fieldName)
-        );
+        if (csysPtr_->uniform() || pTraits<Type>::nComponents == 1)
+        {
+            transformField<SurfaceFieldType>
+            (
+                lookupObject<SurfaceFieldType>(fieldName)
+            );
+        }
+        else
+        {
+            transformField<SurfaceFieldType>
+            (
+                srotTensor(),
+                lookupObject<SurfaceFieldType>(fieldName)
+            );
+        }
     }
     else
     {
@@ -94,10 +137,21 @@ void Foam::functionObjects::fieldCoordinateSystemTransform::transform
                 << type() << ": Field " << fieldName << " read from file"
                 << endl;
 
-            transformField<VolFieldType>
-            (
-                lookupObject<VolFieldType>(fieldName)
-            );
+            if (csysPtr_->uniform() || pTraits<Type>::nComponents == 1)
+            {
+                transformField<VolFieldType>
+                (
+                    lookupObject<VolFieldType>(fieldName)
+                );
+            }
+            else
+            {
+                transformField<VolFieldType>
+                (
+                    vrotTensor(),
+                    lookupObject<VolFieldType>(fieldName)
+                );
+            }
         }
         else if (fieldHeader.typeHeaderOk<SurfaceFieldType>(true, true, false))
         {
@@ -105,10 +159,21 @@ void Foam::functionObjects::fieldCoordinateSystemTransform::transform
                 << type() << ": Field " << fieldName << " read from file"
                 << endl;
 
-            transformField<SurfaceFieldType>
-            (
-                lookupObject<SurfaceFieldType>(fieldName)
-            );
+            if (csysPtr_->uniform() || pTraits<Type>::nComponents == 1)
+            {
+                transformField<SurfaceFieldType>
+                (
+                    lookupObject<SurfaceFieldType>(fieldName)
+                );
+            }
+            else
+            {
+                transformField<SurfaceFieldType>
+                (
+                    srotTensor(),
+                    lookupObject<SurfaceFieldType>(fieldName)
+                );
+            }
         }
     }
 }
diff --git a/tutorials/incompressible/simpleFoam/pipeCyclic/system/controlDict b/tutorials/incompressible/simpleFoam/pipeCyclic/system/controlDict
index 19c1063ae38..fae83278cb6 100644
--- a/tutorials/incompressible/simpleFoam/pipeCyclic/system/controlDict
+++ b/tutorials/incompressible/simpleFoam/pipeCyclic/system/controlDict
@@ -45,5 +45,10 @@ timePrecision   6;
 
 runTimeModifiable true;
 
+functions
+{
+    #include "coordinateTransform"
+}
+
 
 // ************************************************************************* //
diff --git a/tutorials/incompressible/simpleFoam/pipeCyclic/system/coordinateTransform b/tutorials/incompressible/simpleFoam/pipeCyclic/system/coordinateTransform
new file mode 100644
index 00000000000..4b340809e3d
--- /dev/null
+++ b/tutorials/incompressible/simpleFoam/pipeCyclic/system/coordinateTransform
@@ -0,0 +1,24 @@
+/// -*- C++ -*-
+coordinateTransform
+{
+    type    fieldCoordinateSystemTransform;
+    libs    ("libfieldFunctionObjects.so");
+    log     true;
+    fields  ( U );
+
+    writeControl writeTime;
+
+    coordinateSystem
+    {
+        type    cylindrical;
+        origin  (0 0 0);
+        rotation
+        {
+            type cylindrical;
+            axis (1 0 0);  //< local Z
+        }
+    }
+}
+
+
+// ************************************************************************* //
-- 
GitLab