diff --git a/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatch.C b/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatch.C
index 3ce1c4232c20ee25d23051d2281c614207d22c79..cd68f4d9b4186343d4deadf0313285ec190d4308 100644
--- a/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatch.C
+++ b/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatch.C
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2016-2020 OpenCFD Ltd.
+    Copyright (C) 2016-2021 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -33,6 +33,7 @@ License
 #include "OFstream.H"
 #include "meshTools.H"
 #include "addToRunTimeSelectionTable.H"
+#include "cyclicPolyPatch.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -286,6 +287,54 @@ void Foam::cyclicAMIPolyPatch::calcTransforms
 }
 
 
+Foam::autoPtr<Foam::coordSystem::cylindrical>
+Foam::cyclicAMIPolyPatch::cylindricalCS() const
+{
+    autoPtr<coordSystem::cylindrical> csPtr;
+
+    const label periodicID = periodicPatchID();
+    if (periodicID != -1)
+    {
+        // Get the periodic patch
+        const coupledPolyPatch& perPp
+        (
+            refCast<const coupledPolyPatch>
+            (
+                boundaryMesh()[periodicID]
+            )
+        );
+        if (!perPp.parallel())
+        {
+            vector axis(Zero);
+            point axisPoint(Zero);
+            if (isA<cyclicPolyPatch>(perPp))
+            {
+                axis =
+                    refCast<const cyclicPolyPatch>(perPp).rotationAxis();
+                axisPoint =
+                    refCast<const cyclicPolyPatch>(perPp).rotationCentre();
+            }
+            else if (isA<cyclicAMIPolyPatch>(perPp))
+            {
+                axis =
+                    refCast<const cyclicAMIPolyPatch>(perPp).rotationAxis();
+                axisPoint =
+                    refCast<const cyclicAMIPolyPatch>(perPp).rotationCentre();
+            }
+            else
+            {
+                FatalErrorInFunction << "On patch " << name()
+                    << " have unsupported periodicPatch " << perPp.name()
+                    << exit(FatalError);
+            }
+
+            csPtr.set(new coordSystem::cylindrical(axisPoint, axis));
+        }
+    }
+    return csPtr;
+}
+
+
 // * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * * * //
 
 const Foam::autoPtr<Foam::searchableSurface>&
@@ -574,6 +623,8 @@ Foam::cyclicAMIPolyPatch::cyclicAMIPolyPatch
     rotationAngleDefined_(false),
     rotationAngle_(0.0),
     separationVector_(Zero),
+    periodicPatchName_(word::null),
+    periodicPatchID_(-1),
     AMIPtr_(AMIInterpolation::New(defaultAMIMethod)),
     surfDict_(fileName("surface")),
     surfPtr_(nullptr),
@@ -610,6 +661,8 @@ Foam::cyclicAMIPolyPatch::cyclicAMIPolyPatch
     rotationAngleDefined_(false),
     rotationAngle_(0.0),
     separationVector_(Zero),
+    periodicPatchName_(dict.getOrDefault<word>("periodicPatch", word::null)),
+    periodicPatchID_(-1),
     AMIPtr_
     (
         AMIInterpolation::New
@@ -715,6 +768,8 @@ Foam::cyclicAMIPolyPatch::cyclicAMIPolyPatch
     rotationAngleDefined_(pp.rotationAngleDefined_),
     rotationAngle_(pp.rotationAngle_),
     separationVector_(pp.separationVector_),
+    periodicPatchName_(pp.periodicPatchName_),
+    periodicPatchID_(-1),
     AMIPtr_(pp.AMIPtr_->clone()),
     surfDict_(pp.surfDict_),
     surfPtr_(nullptr),
@@ -751,6 +806,8 @@ Foam::cyclicAMIPolyPatch::cyclicAMIPolyPatch
     rotationAngleDefined_(pp.rotationAngleDefined_),
     rotationAngle_(pp.rotationAngle_),
     separationVector_(pp.separationVector_),
+    periodicPatchName_(pp.periodicPatchName_),
+    periodicPatchID_(-1),
     AMIPtr_(pp.AMIPtr_->clone()),
     surfDict_(pp.surfDict_),
     surfPtr_(nullptr),
@@ -794,6 +851,8 @@ Foam::cyclicAMIPolyPatch::cyclicAMIPolyPatch
     rotationAngleDefined_(pp.rotationAngleDefined_),
     rotationAngle_(pp.rotationAngle_),
     separationVector_(pp.separationVector_),
+    periodicPatchName_(pp.periodicPatchName_),
+    periodicPatchID_(-1),
     AMIPtr_(pp.AMIPtr_->clone()),
     surfDict_(pp.surfDict_),
     surfPtr_(nullptr),
@@ -876,6 +935,32 @@ Foam::label Foam::cyclicAMIPolyPatch::neighbPatchID() const
 }
 
 
+Foam::label Foam::cyclicAMIPolyPatch::periodicPatchID() const
+{
+    if (periodicPatchName_ == word::null)
+    {
+        return -1;
+    }
+    else
+    {
+        if (periodicPatchID_ == -1)
+        {
+            periodicPatchID_ = boundaryMesh().findPatchID(periodicPatchName_);
+
+            if (periodicPatchID_ == -1)
+            {
+                FatalErrorInFunction
+                    << "Illegal neighbourPatch name " << periodicPatchName_
+                    << nl << "Valid patch names are "
+                    << this->boundaryMesh().names()
+                    << exit(FatalError);
+            }
+        }
+        return periodicPatchID_;
+    }
+}
+
+
 bool Foam::cyclicAMIPolyPatch::owner() const
 {
     return index() < neighbPatchID();
@@ -1175,6 +1260,11 @@ void Foam::cyclicAMIPolyPatch::write(Ostream& os) const
         }
     }
 
+    if (periodicPatchName_ != word::null)
+    {
+        os.writeEntry("periodicPatch", periodicPatchName_);
+    }
+
     AMIPtr_->write(os);
 
     if (!surfDict_.empty())
diff --git a/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatch.H b/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatch.H
index 5b1fcdeb4458e756a23da659d6b122b7e0226caf..9c19f0b15dd69b8d1c63e136c54830ec30499089 100644
--- a/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatch.H
+++ b/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatch.H
@@ -6,7 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
-    Copyright (C) 2018-2020 OpenCFD Ltd.
+    Copyright (C) 2018-2021 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -55,6 +55,7 @@ SourceFiles
 #include "polyBoundaryMesh.H"
 #include "coupleGroupIdentifier.H"
 #include "faceAreaWeightAMI.H"
+#include "cylindricalCS.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -124,6 +125,15 @@ protected:
                 vector separationVector_;
 
 
+            // Triggering periodic interpolation
+
+                //- Periodic patch name
+                word periodicPatchName_;
+
+                //- Periodic patch
+                mutable label periodicPatchID_;
+
+
         //- AMI interpolation class
         mutable autoPtr<AMIPatchToPatchInterpolation> AMIPtr_;
 
@@ -177,6 +187,9 @@ protected:
         //- Create and return pointer to the projection surface
         const autoPtr<searchableSurface>& surfPtr() const;
 
+        //- Create a coordinate system from the periodic patch (or nullptr)
+        autoPtr<coordSystem::cylindrical> cylindricalCS() const;
+
         //- Reset the AMI interpolator, supply patch points
         virtual void resetAMI(const UList<point>& points) const;
 
@@ -401,6 +414,9 @@ public:
             //- Return a reference to the neighbour patch
             virtual const cyclicAMIPolyPatch& neighbPatch() const;
 
+            //- Periodic patch ID (or -1)
+            label periodicPatchID() const;
+
             //- Return a reference to the AMI interpolator
             const AMIPatchToPatchInterpolation& AMI() const;
 
@@ -477,6 +493,14 @@ public:
                     const UList<Type>& defaultValues = UList<Type>()
                 ) const;
 
+                //- Interpolate without periodic
+                template<class Type>
+                tmp<Field<Type>> interpolateUntransformed
+                (
+                    const Field<Type>& fld,
+                    const UList<Type>& defaultValues
+                ) const;
+
                 //- Low-level interpolate List
                 template<class Type, class CombineOp>
                 void interpolate
diff --git a/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatchTemplates.C b/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatchTemplates.C
index b998889cda093a306cd549fb42dd22443f03b57e..e5230eb628a139bffe3c12c03df393caf742a120 100644
--- a/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatchTemplates.C
+++ b/src/meshTools/AMIInterpolation/patches/cyclicAMI/cyclicAMIPolyPatch/cyclicAMIPolyPatchTemplates.C
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2016 OpenFOAM Foundation
+    Copyright (C) 2021 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -28,7 +29,7 @@ License
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 template<class Type>
-Foam::tmp<Foam::Field<Type>> Foam::cyclicAMIPolyPatch::interpolate
+Foam::tmp<Foam::Field<Type>> Foam::cyclicAMIPolyPatch::interpolateUntransformed
 (
     const Field<Type>& fld,
     const UList<Type>& defaultValues
@@ -45,6 +46,103 @@ Foam::tmp<Foam::Field<Type>> Foam::cyclicAMIPolyPatch::interpolate
 }
 
 
+template<class Type>
+Foam::tmp<Foam::Field<Type>> Foam::cyclicAMIPolyPatch::interpolate
+(
+    const Field<Type>& fld,
+    const UList<Type>& defaultValues
+) const
+{
+    if (pTraits<Type>::rank == 0)
+    {
+        return interpolateUntransformed(fld, defaultValues);
+    }
+    else
+    {
+        autoPtr<coordSystem::cylindrical> cs(cylindricalCS());
+        if (!cs.valid())
+        {
+            return interpolateUntransformed(fld, defaultValues);
+        }
+        else
+        {
+            const cyclicAMIPolyPatch& nbrPp = this->neighbPatch();
+
+            if (debug)
+            {
+                Pout<< "cyclicAMIPolyPatch::interpolate :"
+                    << " patch:" << this->name()
+                    << " size:" << this->size()
+                    << " nbrPatch:" << nbrPp.name()
+                    << " size:" << nbrPp.size()
+                    << endl;
+            }
+
+            if (fld.size() != nbrPp.size())
+            {
+                FatalErrorInFunction
+                    << "Patch:" << this->name()
+                    << " size:" << this->size()
+                    << " neighbour patch:" << nbrPp.name()
+                    << " size:" << nbrPp.size()
+                    << " fld size:" << fld.size()
+                    << exit(FatalError);
+            }
+
+
+            auto tlocalFld(tmp<Field<Type>>::New(fld.size()));
+            Field<Type>& localFld = tlocalFld.ref();
+            List<Type> localDeflt(defaultValues.size());
+
+            // Transform to cylindrical coords
+            {
+                tmp<tensorField> nbrT(cs().R(nbrPp.faceCentres()));
+                localFld = Foam::invTransform(nbrT(), fld);
+                if (defaultValues.size() == fld.size())
+                {
+                    // We get in UList (why? Copied from cyclicAMI). Convert to
+                    // Field so we can use transformField routines.
+                    const SubField<Type> defaultSubFld(defaultValues);
+                    const Field<Type>& defaultFld(defaultSubFld);
+                    localDeflt = Foam::invTransform(nbrT, defaultFld);
+                }
+            }
+
+            if (debug&2)
+            {
+                const vectorField::subField nbrFc(nbrPp.faceCentres());
+
+                Pout<< "On patch:" << this->name()
+                    << " size:" << this->size()
+                    << " fc:" << gAverage(this->faceCentres())
+                    << " getting remote data from:" << nbrPp.name()
+                    << " size:" << nbrPp.size()
+                    << " fc:" << gAverage(nbrFc)
+                    << endl;
+
+                forAll(fld, i)
+                {
+                    Pout<< "At:" << nbrFc[i] << nl
+                        << "    cart:" << fld[i] << nl
+                        << "    cyli:" << localFld[i] << nl
+                        << endl;
+                }
+            }
+
+            const vectorField::subField fc(this->faceCentres());
+
+            // Do the actual interpolation and interpolate back to cartesian
+            // coords
+            return Foam::transform
+            (
+                cs().R(fc),
+                interpolateUntransformed(localFld, localDeflt)
+            );
+        }
+    }
+}
+
+
 template<class Type>
 Foam::tmp<Foam::Field<Type>> Foam::cyclicAMIPolyPatch::interpolate
 (
@@ -65,25 +163,78 @@ void Foam::cyclicAMIPolyPatch::interpolate
     const UList<Type>& defaultValues
 ) const
 {
-    if (owner())
+    //- Commented out for now since called with non-primitives (e.g. wallPoint
+    //  from FaceCellWave) - these are missing the pTraits<Type>::rank and
+    //  Foam::transform
+    /*
+    autoPtr<coordSystem::cylindrical> cs(cylindricalCS());
+
+    if (cs.valid() && pTraits<Type>::rank > 0)
     {
-        AMI().interpolateToSource
-        (
-            fld,
-            cop,
-            result,
-            defaultValues
-        );
+        const cyclicAMIPolyPatch& nbrPp = this->neighbPatch();
+
+        tmp<tensorField> nbrT(cs().R(nbrPp.faceCentres()));
+
+        result = Foam::invTransform(nbrT, result);
+        List<Type> localDeflt(defaultValues.size());
+        if (defaultValues.size() == nbrT().size())
+        {
+            // We get in UList (why? Copied from cyclicAMI). Convert to
+            // Field so we can use transformField routines.
+            const SubField<Type> defaultSubFld(defaultValues);
+            const Field<Type>& defaultFld(defaultSubFld);
+            localDeflt = Foam::invTransform(nbrT, defaultFld);
+        }
+
+        // Do actual AMI interpolation
+        if (owner())
+        {
+            AMI().interpolateToSource
+            (
+                fld,
+                cop,
+                result,
+                localDeflt
+            );
+        }
+        else
+        {
+            neighbPatch().AMI().interpolateToTarget
+            (
+                fld,
+                cop,
+                result,
+                localDeflt
+            );
+        }
+
+        // Transform back. Result is now at *this
+        const vectorField::subField fc(this->faceCentres());
+        result = Foam::transform(cs().R(fc), result);
     }
     else
+    */
     {
-        neighbPatch().AMI().interpolateToTarget
-        (
-            fld,
-            cop,
-            result,
-            defaultValues
-        );
+        if (owner())
+        {
+            AMI().interpolateToSource
+            (
+                fld,
+                cop,
+                result,
+                defaultValues
+            );
+        }
+        else
+        {
+            neighbPatch().AMI().interpolateToTarget
+            (
+                fld,
+                cop,
+                result,
+                defaultValues
+            );
+        }
     }
 }
 
diff --git a/src/meshTools/AMIInterpolation/patches/cyclicPeriodicAMI/cyclicPeriodicAMIPolyPatch/cyclicPeriodicAMIPolyPatch.C b/src/meshTools/AMIInterpolation/patches/cyclicPeriodicAMI/cyclicPeriodicAMIPolyPatch/cyclicPeriodicAMIPolyPatch.C
index a7e652c6b8c93dfa4ebbab2831ac4755c9a08add..21a23c264be7173abc15e4b85152423228e5fa67 100644
--- a/src/meshTools/AMIInterpolation/patches/cyclicPeriodicAMI/cyclicPeriodicAMIPolyPatch/cyclicPeriodicAMIPolyPatch.C
+++ b/src/meshTools/AMIInterpolation/patches/cyclicPeriodicAMI/cyclicPeriodicAMIPolyPatch/cyclicPeriodicAMIPolyPatch.C
@@ -561,8 +561,6 @@ Foam::cyclicPeriodicAMIPolyPatch::cyclicPeriodicAMIPolyPatch
         transform,
         faceAreaWeightAMI::typeName
     ),
-    periodicPatchName_(word::null),
-    periodicPatchID_(-1),
     nTransforms_(0),
     nSectors_(0),
     maxIter_(36)
@@ -589,8 +587,6 @@ Foam::cyclicPeriodicAMIPolyPatch::cyclicPeriodicAMIPolyPatch
         patchType,
         faceAreaWeightAMI::typeName
     ),
-    periodicPatchName_(dict.lookup("periodicPatch")),
-    periodicPatchID_(-1),
     nTransforms_(dict.getOrDefault<label>("nTransforms", 0)),
     nSectors_(dict.getOrDefault<label>("nSectors", 0)),
     maxIter_(dict.getOrDefault<label>("maxIter", 36))
@@ -606,8 +602,6 @@ Foam::cyclicPeriodicAMIPolyPatch::cyclicPeriodicAMIPolyPatch
 )
 :
     cyclicAMIPolyPatch(pp, bm),
-    periodicPatchName_(pp.periodicPatchName_),
-    periodicPatchID_(-1),
     nTransforms_(pp.nTransforms_),
     nSectors_(pp.nSectors_),
     maxIter_(pp.maxIter_)
@@ -627,8 +621,6 @@ Foam::cyclicPeriodicAMIPolyPatch::cyclicPeriodicAMIPolyPatch
 )
 :
     cyclicAMIPolyPatch(pp, bm, index, newSize, newStart, nbrPatchName),
-    periodicPatchName_(pp.periodicPatchName_),
-    periodicPatchID_(-1),
     nTransforms_(pp.nTransforms_),
     nSectors_(pp.nSectors_),
     maxIter_(pp.maxIter_)
@@ -647,8 +639,6 @@ Foam::cyclicPeriodicAMIPolyPatch::cyclicPeriodicAMIPolyPatch
 )
 :
     cyclicAMIPolyPatch(pp, bm, index, mapAddressing, newStart),
-    periodicPatchName_(pp.periodicPatchName_),
-    periodicPatchID_(-1),
     nTransforms_(pp.nTransforms_),
     nSectors_(pp.nSectors_),
     maxIter_(pp.maxIter_)
@@ -665,44 +655,10 @@ Foam::cyclicPeriodicAMIPolyPatch::~cyclicPeriodicAMIPolyPatch()
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-Foam::label Foam::cyclicPeriodicAMIPolyPatch::periodicPatchID() const
-{
-    if (periodicPatchName_ == word::null)
-    {
-        periodicPatchID_ = -1;
-
-        return periodicPatchID_;
-    }
-
-    if (periodicPatchID_ == -1)
-    {
-        periodicPatchID_ = this->boundaryMesh().findPatchID(periodicPatchName_);
-
-        if (periodicPatchID_ == -1)
-        {
-            FatalErrorInFunction
-                << "Illegal periodicPatch name " << periodicPatchName_
-                << nl << "Valid patch names are "
-                << this->boundaryMesh().names()
-                << exit(FatalError);
-        }
-
-        // Check that it is a coupled patch
-        refCast<const coupledPolyPatch>
-        (
-            this->boundaryMesh()[periodicPatchID_]
-        );
-    }
-
-    return periodicPatchID_;
-}
-
-
 void Foam::cyclicPeriodicAMIPolyPatch::write(Ostream& os) const
 {
     cyclicAMIPolyPatch::write(os);
 
-    os.writeEntry("periodicPatch", periodicPatchName_);
     os.writeEntryIfDifferent<label>("nTransforms", 0, nTransforms_);
     os.writeEntryIfDifferent<label>("nSectors", 0, nSectors_);
     os.writeEntryIfDifferent<label>("maxIter", 36, maxIter_);
diff --git a/src/meshTools/AMIInterpolation/patches/cyclicPeriodicAMI/cyclicPeriodicAMIPolyPatch/cyclicPeriodicAMIPolyPatch.H b/src/meshTools/AMIInterpolation/patches/cyclicPeriodicAMI/cyclicPeriodicAMIPolyPatch/cyclicPeriodicAMIPolyPatch.H
index 297c5c3189310d8ef90faf64244c4b0332005075..5a2b7a59bb5d49af7c9b3a67684d7f63701aaa46 100644
--- a/src/meshTools/AMIInterpolation/patches/cyclicPeriodicAMI/cyclicPeriodicAMIPolyPatch/cyclicPeriodicAMIPolyPatch.H
+++ b/src/meshTools/AMIInterpolation/patches/cyclicPeriodicAMI/cyclicPeriodicAMIPolyPatch/cyclicPeriodicAMIPolyPatch.H
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2015 OpenCFD Ltd.
+    Copyright (C) 2015-2021 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -58,12 +58,6 @@ private:
 
     // Private data
 
-        //- Periodic patch name
-        mutable word periodicPatchName_;
-
-        //- Periodic patch ID
-        mutable label periodicPatchID_;
-
         //- Current number of transformations (+ve forward, -ve backward)
         mutable label nTransforms_;
 
@@ -209,9 +203,6 @@ public:
 
     // Member Functions
 
-        //- Periodic patch ID
-        virtual label periodicPatchID() const;
-
         //- Write the polyPatch data as a dictionary
         virtual void write(Ostream&) const;
 };