diff --git a/src/conversion/ensight/output/ensightOutputAreaField.H b/src/conversion/ensight/output/ensightOutputAreaField.H
new file mode 100644
index 0000000000000000000000000000000000000000..37618cca6d097ef1cf2ee65e067d44b3c03d3fa3
--- /dev/null
+++ b/src/conversion/ensight/output/ensightOutputAreaField.H
@@ -0,0 +1,79 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2021 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/>.
+
+InNamespace
+    Foam::ensightOutput
+
+Description
+    A collection of functions for writing areaField content in ensight format.
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef ensightOutputAreaField_H
+#define ensightOutputAreaField_H
+
+#include "ensightOutput.H"
+#include "ensightFaces.H"
+#include "areaFields.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Forward Declarations
+class ensightFaMesh;
+
+namespace ensightOutput
+{
+
+/*---------------------------------------------------------------------------*\
+                            Namespace ensightOutput
+\*---------------------------------------------------------------------------*/
+
+//- Write finite-area field component-wise
+template<class Type>
+bool writeAreaField
+(
+    ensightFile& os,
+    const GeometricField<Type, faPatchField, areaMesh>& fld,
+    const ensightFaMesh& ensMesh
+);
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace ensightOutput
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+    #include "ensightOutputAreaFieldTemplates.C"
+#endif
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/conversion/ensight/output/ensightOutputAreaFieldTemplates.C b/src/conversion/ensight/output/ensightOutputAreaFieldTemplates.C
new file mode 100644
index 0000000000000000000000000000000000000000..aaccbd3cc212cdb6dc2ce61c06c412dc68d5e98e
--- /dev/null
+++ b/src/conversion/ensight/output/ensightOutputAreaFieldTemplates.C
@@ -0,0 +1,59 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2021 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 "ensightOutputAreaField.H"
+#include "ensightFaMesh.H"
+#include "areaFaMesh.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+template<class Type>
+bool Foam::ensightOutput::writeAreaField
+(
+    ensightFile& os,
+    const GeometricField<Type, faPatchField, areaMesh>& fld,
+    const ensightFaMesh& ensMesh
+)
+{
+    bool parallel = Pstream::parRun();
+
+    // Write area part(s)
+    {
+        ensightOutput::Detail::writeFaceLocalField
+        (
+            os,
+            fld,
+            ensMesh.areaPart(),
+            parallel
+        );
+    }
+
+    return true;
+}
+
+
+// ************************************************************************* //
diff --git a/src/fileFormats/ensight/mesh/ensightMesh.H b/src/fileFormats/ensight/mesh/ensightMesh.H
index f85dddb5bf992a40c4045c73ec3a9aeec7c0dd40..6c0427f9772ffb6608f90d2223bba69dd5517aa8 100644
--- a/src/fileFormats/ensight/mesh/ensightMesh.H
+++ b/src/fileFormats/ensight/mesh/ensightMesh.H
@@ -146,7 +146,10 @@ public:
     // Access
 
         //- Reference to the underlying polyMesh
-        inline const polyMesh& mesh() const;
+        const polyMesh& mesh() const noexcept
+        {
+            return mesh_;
+        }
 
         //- Reference to the writer/mesh options
         inline const ensightMesh::options& option() const;
@@ -154,30 +157,42 @@ public:
         //- Face elements per selected patch, lookup by patch index
         //  Process in sorted order.
         //  May require special treatment for zone -1 (internal).
-        inline const Map<ensightCells>& cellZoneParts() const;
+        const Map<ensightCells>& cellZoneParts() const noexcept
+        {
+            return cellZoneParts_;
+        }
 
         //- Face elements per faceZone, lookup by zone index.
         //  Process in sorted order.
-        inline const Map<ensightFaces>& faceZoneParts() const;
+        const Map<ensightFaces>& faceZoneParts() const noexcept
+        {
+            return faceZoneParts_;
+        }
 
         //- Face elements per selected patch, lookup by patch index
         //  Process in sorted order.
-        inline const Map<ensightFaces>& boundaryParts() const;
+        const Map<ensightFaces>& boundaryParts() const noexcept
+        {
+            return boundaryParts_;
+        }
 
 
     // Sizing Information
 
         //- Any parts?
-        inline bool empty() const;
+        inline bool empty() const noexcept;
 
         //- Number of parts
-        inline label size() const;
+        inline label size() const noexcept;
 
 
     // Other
 
         //- Does the content need an update?
-        inline bool needsUpdate() const;
+        bool needsUpdate() const noexcept
+        {
+            return needsUpdate_;
+        }
 
         //- Mark as needing an update.
         //  May also free up unneeded data.
@@ -191,16 +206,16 @@ public:
     // Output
 
         //- Write geometry to file. Normally in parallel
-        inline void write
+        void write
         (
-            autoPtr<ensightGeoFile>& os,
+            ensightGeoFile& os,
             bool parallel = Pstream::parRun()
         ) const;
 
         //- Write geometry to file. Normally in parallel
-        void write
+        inline void write
         (
-            ensightGeoFile& os,
+            autoPtr<ensightGeoFile>& os,
             bool parallel = Pstream::parRun()
         ) const;
 };
@@ -252,32 +267,44 @@ public:
 
     // Access
 
-        //- Lazy creation? (ie, ensightMesh starts as needsUpdate)
-        bool lazy() const;
+        //- Lazy creation? (ie, starts as needsUpdate)
+        bool lazy() const noexcept;
 
         //- Using internal?
-        bool useInternalMesh() const;
+        bool useInternalMesh() const noexcept;
 
         //- Using boundary?
-        bool useBoundaryMesh() const;
+        bool useBoundaryMesh() const noexcept;
 
         //- Using faceZones?
-        bool useFaceZones() const;
+        bool useFaceZones() const noexcept;
 
         //- Using cellZones?
-        bool useCellZones() const;
+        bool useCellZones() const noexcept;
 
         //- Selection of patches. Empty if unspecified.
-        const wordRes& patchSelection() const;
+        const wordRes& patchSelection() const noexcept
+        {
+            return patchInclude_;
+        }
 
         //- Selection of black listed patches. Empty if unspecified.
-        const wordRes& patchExclude() const;
+        const wordRes& patchExclude() const noexcept
+        {
+            return patchExclude_;
+        }
 
         //- Selection of faceZones. Empty if unspecified.
-        const wordRes& faceZoneSelection() const;
+        const wordRes& faceZoneSelection() const noexcept
+        {
+            return faceZoneInclude_;
+        }
 
         //- Selection of faceZones. Empty if unspecified.
-        const wordRes& cellZoneSelection() const;
+        const wordRes& cellZoneSelection() const noexcept
+        {
+            return cellZoneInclude_;
+        }
 
 
     // Edit
@@ -286,16 +313,20 @@ public:
         void reset();
 
         //- Lazy creation - ensightMesh starts as needsUpdate
-        void lazy(bool beLazy);
+        //  \return old value
+        bool lazy(bool on) noexcept;
 
         //- Alter the useBoundaryMesh state
-        void useInternalMesh(bool on);
+        //  \return old value
+        bool useInternalMesh(bool on) noexcept;
 
         //- Alter the useBoundaryMesh state
-        void useBoundaryMesh(bool on);
+        //  \return old value
+        bool useBoundaryMesh(bool on);
 
         //- Alter the useCellZones state
-        void useCellZones(bool on);
+        //  \return old value
+        bool useCellZones(bool on);
 
         //- Define patch selection matcher
         void patchSelection(const UList<wordRe>& patterns);
diff --git a/src/fileFormats/ensight/mesh/ensightMeshI.H b/src/fileFormats/ensight/mesh/ensightMeshI.H
index a9cdbfbc730f8dfb34a7b87404ef52793990b55a..ed8499fd54508777bc68921685f24b69321895a6 100644
--- a/src/fileFormats/ensight/mesh/ensightMeshI.H
+++ b/src/fileFormats/ensight/mesh/ensightMeshI.H
@@ -27,39 +27,12 @@ License
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-inline const Foam::polyMesh& Foam::ensightMesh::mesh() const
-{
-    return mesh_;
-}
-
-
 inline const Foam::ensightMesh::options& Foam::ensightMesh::option() const
 {
     return *options_;
 }
 
 
-inline const Foam::Map<Foam::ensightCells>&
-Foam::ensightMesh::cellZoneParts() const
-{
-    return cellZoneParts_;
-}
-
-
-inline const Foam::Map<Foam::ensightFaces>&
-Foam::ensightMesh::faceZoneParts() const
-{
-    return faceZoneParts_;
-}
-
-
-inline const Foam::Map<Foam::ensightFaces>&
-Foam::ensightMesh::boundaryParts() const
-{
-    return boundaryParts_;
-}
-
-
 inline bool Foam::ensightMesh::expire()
 {
     clear();
@@ -75,13 +48,7 @@ inline bool Foam::ensightMesh::expire()
 }
 
 
-inline bool Foam::ensightMesh::needsUpdate() const
-{
-    return needsUpdate_;
-}
-
-
-inline bool Foam::ensightMesh::empty() const
+inline bool Foam::ensightMesh::empty() const noexcept
 {
     return
     (
@@ -92,7 +59,7 @@ inline bool Foam::ensightMesh::empty() const
 }
 
 
-inline Foam::label Foam::ensightMesh::size() const
+inline Foam::label Foam::ensightMesh::size() const noexcept
 {
     return
     (
diff --git a/src/fileFormats/ensight/mesh/ensightMeshOptions.C b/src/fileFormats/ensight/mesh/ensightMeshOptions.C
index 831d076897fdddeeb2a9fad57e06c988ccf19f37..333ce8602a15411b6e81510d9969822f6c3cee84 100644
--- a/src/fileFormats/ensight/mesh/ensightMeshOptions.C
+++ b/src/fileFormats/ensight/mesh/ensightMeshOptions.C
@@ -43,9 +43,9 @@ static Ostream& printPatterns(Ostream& os, const wordRes& list)
     for (const wordRe& item : list)
     {
         if (sep) os << token::SPACE;
-        os << item;
-
         sep = true;
+
+        os << item;
     }
     os << token::END_LIST;
 
@@ -72,31 +72,31 @@ Foam::ensightMesh::options::options()
 
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
-bool Foam::ensightMesh::options::lazy() const
+bool Foam::ensightMesh::options::lazy() const noexcept
 {
     return lazy_;
 }
 
 
-bool Foam::ensightMesh::options::useInternalMesh() const
+bool Foam::ensightMesh::options::useInternalMesh() const noexcept
 {
     return internal_;
 }
 
 
-bool Foam::ensightMesh::options::useBoundaryMesh() const
+bool Foam::ensightMesh::options::useBoundaryMesh() const noexcept
 {
     return boundary_;
 }
 
 
-bool Foam::ensightMesh::options::useCellZones() const
+bool Foam::ensightMesh::options::useCellZones() const noexcept
 {
     return cellZones_;
 }
 
 
-bool Foam::ensightMesh::options::useFaceZones() const
+bool Foam::ensightMesh::options::useFaceZones() const noexcept
 {
     return faceZoneInclude_.size();
 }
@@ -114,20 +114,25 @@ void Foam::ensightMesh::options::reset()
 }
 
 
-void Foam::ensightMesh::options::lazy(bool beLazy)
+bool Foam::ensightMesh::options::lazy(bool on) noexcept
 {
-    lazy_ = beLazy;
+    bool old(lazy_);
+    lazy_ = on;
+    return old;
 }
 
 
-void Foam::ensightMesh::options::useInternalMesh(bool on)
+bool Foam::ensightMesh::options::useInternalMesh(bool on) noexcept
 {
+    bool old(internal_);
     internal_ = on;
+    return old;
 }
 
 
-void Foam::ensightMesh::options::useBoundaryMesh(bool on)
+bool Foam::ensightMesh::options::useBoundaryMesh(bool on)
 {
+    bool old(boundary_);
     boundary_ = on;
 
     if (!boundary_)
@@ -141,11 +146,14 @@ void Foam::ensightMesh::options::useBoundaryMesh(bool on)
                 << endl;
         }
     }
+
+    return old;
 }
 
 
-void Foam::ensightMesh::options::useCellZones(bool on)
+bool Foam::ensightMesh::options::useCellZones(bool on)
 {
+    bool old(cellZones_);
     cellZones_ = on;
 
     if (!cellZones_ && cellZoneInclude_.size())
@@ -156,6 +164,8 @@ void Foam::ensightMesh::options::useCellZones(bool on)
             << "Deactivating cellZones, removed old zone selection"
             << endl;
     }
+
+    return old;
 }
 
 
@@ -267,30 +277,6 @@ void Foam::ensightMesh::options::cellZoneSelection
 }
 
 
-const Foam::wordRes& Foam::ensightMesh::options::patchSelection() const
-{
-    return patchInclude_;
-}
-
-
-const Foam::wordRes& Foam::ensightMesh::options::patchExclude() const
-{
-    return patchExclude_;
-}
-
-
-const Foam::wordRes& Foam::ensightMesh::options::faceZoneSelection() const
-{
-    return faceZoneInclude_;
-}
-
-
-const Foam::wordRes& Foam::ensightMesh::options::cellZoneSelection() const
-{
-    return cellZoneInclude_;
-}
-
-
 void Foam::ensightMesh::options::print(Ostream& os) const
 {
     os << "internal: " << Switch::name(internal_) << nl;
diff --git a/src/fileFormats/ensight/output/ensightOutput.H b/src/fileFormats/ensight/output/ensightOutput.H
index 4a2f77dcbf4f0ea411e9ca1e4ea5de6a98335a13..fefe06a5358e69eb1fc278a68b8fbba46c423fa4 100644
--- a/src/fileFormats/ensight/output/ensightOutput.H
+++ b/src/fileFormats/ensight/output/ensightOutput.H
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2016-2020 OpenCFD Ltd.
+    Copyright (C) 2016-2021 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -307,6 +307,18 @@ bool writeFaceSubField
 );
 
 
+//- Write a field of faces values as an indirect list,
+//- using the face order from ensightFaces
+template<class Type>
+bool writeFaceLocalField
+(
+    ensightFile& os,
+    const Field<Type>& fld,
+    const ensightFaces& part,
+    bool parallel  //!< Collective write?
+);
+
+
 } // End namespace Detail
 
 
diff --git a/src/fileFormats/ensight/output/ensightOutputTemplates.C b/src/fileFormats/ensight/output/ensightOutputTemplates.C
index 00f5ab4d234585be2db9c44cb2f69c30c4da475e..3c408d6fc2ff39c88dc0f67776f5ce258b580ef2 100644
--- a/src/fileFormats/ensight/output/ensightOutputTemplates.C
+++ b/src/fileFormats/ensight/output/ensightOutputTemplates.C
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2019-2020 OpenCFD Ltd.
+    Copyright (C) 2019-2021 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -236,8 +236,6 @@ bool Foam::ensightOutput::Detail::writeFaceSubField
         os.beginPart(part.index());
     }
 
-    labelList localAddr;
-
     for (int typei=0; typei < ensightFaces::nTypes; ++typei)
     {
         const auto etype = ensightFaces::elemType(typei);
@@ -255,6 +253,71 @@ bool Foam::ensightOutput::Detail::writeFaceSubField
 }
 
 
+template<class Type>
+bool Foam::ensightOutput::Detail::writeFaceLocalField
+(
+    ensightFile& os,
+    const Field<Type>& fld,
+    const ensightFaces& part,
+    bool parallel
+)
+{
+    parallel = parallel && Pstream::parRun();
+
+    // Preliminary checks: total() contains pre-reduced information
+    {
+        // No geometry
+        if (parallel ? !part.total() : !part.size()) return false;
+
+        bool hasField = !fld.empty();
+
+        if (parallel)
+        {
+            reduce(hasField, orOp<bool>());
+        }
+
+        // No field
+        if (!hasField) return false;
+    }
+
+    bool validAddressing = (part.size() == part.faceOrder().size());
+
+    if (parallel)
+    {
+        reduce(validAddressing, orOp<bool>());
+    }
+
+    if (!validAddressing)
+    {
+        FatalErrorInFunction
+            << "Called without faceOrder having been set" << nl
+            << exit(FatalError);
+    }
+
+    if (Pstream::master())
+    {
+        os.beginPart(part.index());
+    }
+
+    for (int typei=0; typei < ensightFaces::nTypes; ++typei)
+    {
+        const auto etype = ensightFaces::elemType(typei);
+
+        ensightOutput::Detail::writeFieldComponents
+        (
+            os,
+            ensightFaces::key(etype),
+            UIndirectList<Type>(fld, part.faceOrder(etype)),
+            parallel
+        );
+    }
+
+    return true;
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
 template<class Type>
 bool Foam::ensightOutput::writeField
 (
diff --git a/src/fileFormats/ensight/part/cells/ensightCells.C b/src/fileFormats/ensight/part/cells/ensightCells.C
index 4cc92045e87f5591a3cc357b968829afee73821b..2aca01bd2555b4bd0ec15d5131453c2be0bac42d 100644
--- a/src/fileFormats/ensight/part/cells/ensightCells.C
+++ b/src/fileFormats/ensight/part/cells/ensightCells.C
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2016-2020 OpenCFD Ltd.
+    Copyright (C) 2016-2021 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -39,7 +39,9 @@ namespace Foam
 }
 
 const char* Foam::ensightCells::elemNames[5] =
-    { "tetra4", "pyramid5", "penta6", "hexa8", "nfaced" };
+{
+    "tetra4", "pyramid5", "penta6", "hexa8", "nfaced"
+};
 
 static_assert
 (
@@ -106,12 +108,12 @@ Foam::FixedList<Foam::label, 5> Foam::ensightCells::sizes() const
 
 Foam::label Foam::ensightCells::total() const
 {
-    label n = 0;
+    label nTotal = 0;
     forAll(sizes_, typei)
     {
-        n += sizes_[typei];
+        nTotal += sizes_[typei];
     }
-    return n;
+    return nTotal;
 }
 
 
diff --git a/src/fileFormats/ensight/part/cells/ensightCells.H b/src/fileFormats/ensight/part/cells/ensightCells.H
index ee5c1ea7cf4baa2baa072a3c6fdf7a66e667f28a..e24e712ad5ba65ed2d057930dc4e5dd7c1bf3cfb 100644
--- a/src/fileFormats/ensight/part/cells/ensightCells.H
+++ b/src/fileFormats/ensight/part/cells/ensightCells.H
@@ -99,7 +99,8 @@ private:
     // Private Member Functions
 
         //- Low-level internal addition routine
-        inline void add(const elemType etype, label id);
+        //  \return insertion locaion
+        inline label add(const elemType etype, label id);
 
         //- Use temporarily stored sizes to redimension the element lists
         void resizeAll();
diff --git a/src/fileFormats/ensight/part/cells/ensightCellsI.H b/src/fileFormats/ensight/part/cells/ensightCellsI.H
index cfccab8eed477d488552471acf5de617f30702a3..58e80324f35a26e0beca0d1b29a0bd7df7dad142 100644
--- a/src/fileFormats/ensight/part/cells/ensightCellsI.H
+++ b/src/fileFormats/ensight/part/cells/ensightCellsI.H
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2016-2020 OpenCFD Ltd.
+    Copyright (C) 2016-2021 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -27,12 +27,14 @@ License
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
-inline void Foam::ensightCells::add(const elemType etype, label id)
+inline Foam::label Foam::ensightCells::add(const elemType etype, label id)
 {
     // Linear addressing location
     const label index = offsets_[etype] + sizes_[etype]++;
 
     addressing()[index] = id;
+
+    return index;
 }
 
 
diff --git a/src/fileFormats/ensight/part/faces/ensightFaces.C b/src/fileFormats/ensight/part/faces/ensightFaces.C
index d818a06536e1e704463fb3e7c48bebba9ca78d66..e3ee917d1215154505f6cf74782dfd3a6d5fe84e 100644
--- a/src/fileFormats/ensight/part/faces/ensightFaces.C
+++ b/src/fileFormats/ensight/part/faces/ensightFaces.C
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2016-2020 OpenCFD Ltd.
+    Copyright (C) 2016-2021 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -37,7 +37,9 @@ namespace Foam
 }
 
 const char* Foam::ensightFaces::elemNames[3] =
-    { "tria3", "quad4", "nsided" };
+{
+    "tria3", "quad4", "nsided"
+};
 
 static_assert
 (
@@ -52,7 +54,7 @@ namespace
 {
 
 // Trivial shape classifier
-static inline Foam::ensightFaces::elemType whatType(const Foam::face& f)
+inline Foam::ensightFaces::elemType whatType(const Foam::face& f)
 {
     return
     (
@@ -71,6 +73,12 @@ static inline Foam::ensightFaces::elemType whatType(const Foam::face& f)
 
 void Foam::ensightFaces::resizeAll()
 {
+    // Invalidate any previous face ordering
+    faceOrder_.clear();
+
+    // Invalidate any previous flipMap
+    flipMap_.clear();
+
     // Assign sub-list offsets, determine overall size
 
     label len = 0;
@@ -87,9 +95,6 @@ void Foam::ensightFaces::resizeAll()
 
     // The addressing space
     addressing().resize(len, Zero);
-
-    // Normally assume no flipMap
-    flipMap_.clear();
 }
 
 
@@ -98,6 +103,7 @@ void Foam::ensightFaces::resizeAll()
 Foam::ensightFaces::ensightFaces()
 :
     ensightPart(),
+    faceOrder_(),
     flipMap_(),
     offsets_(Zero),
     sizes_(Zero)
@@ -129,12 +135,12 @@ Foam::FixedList<Foam::label, 3> Foam::ensightFaces::sizes() const
 
 Foam::label Foam::ensightFaces::total() const
 {
-    label n = 0;
+    label nTotal = 0;
     forAll(sizes_, typei)
     {
-        n += sizes_[typei];
+        nTotal += sizes_[typei];
     }
-    return n;
+    return nTotal;
 }
 
 
@@ -144,6 +150,7 @@ void Foam::ensightFaces::clear()
 
     ensightPart::clear();
 
+    faceOrder_.clear();
     flipMap_.clear();
     sizes_ = Zero;
     offsets_ = Zero;
@@ -167,42 +174,42 @@ void Foam::ensightFaces::reduce()
 
 void Foam::ensightFaces::sort()
 {
-    const bool useFlip = (size() == flipMap_.size());
+    // Some extra safety
+    if (faceOrder_.size() != size())
+    {
+        faceOrder_.clear();
+    }
+    if (flipMap_.size() != size())
+    {
+        flipMap_.clear();
+    }
 
-    if (useFlip)
+    // Sort by face Ids.
+    // Use to reorder flip maps and face-order too.
+
+    for (int typei=0; typei < nTypes; ++typei)
     {
-        // Must sort flip map as well
-        labelList order;
+        const labelRange sub(range(elemType(typei)));
 
-        for (int typei=0; typei < nTypes; ++typei)
+        if (!sub.empty())
         {
-            const labelRange sub(range(elemType(typei)));
+            SubList<label> ids(sub, addressing());
+            labelList order(Foam::sortedOrder(ids));
+
+            ids = reorder<labelList>(order, ids);
 
-            if (!sub.empty())
+            // Sort flip map as well
+            if (!flipMap_.empty())
             {
-                SubList<label> ids(addressing(), sub);
                 SubList<bool> flips(flipMap_, sub);
-
-                Foam::sortedOrder(ids, order);
-
-                ids  = reorder<labelList>(order, ids);
-                flips = reorder<boolList>(order,  flips);
+                flips = reorder<boolList>(order, flips);
             }
-        }
-    }
-    else
-    {
-        flipMap_.clear();  // Extra safety
 
-        // No flip-maps, simply sort addresses
-        for (int typei=0; typei < nTypes; ++typei)
-        {
-            const labelRange sub(range(elemType(typei)));
-
-            if (!sub.empty())
+            // Sort face ordering as well
+            if (!faceOrder_.empty())
             {
-                SubList<label> ids(addressing(), sub);
-                Foam::sort(ids);
+                SubList<label> faceOrder(faceOrder_, sub);
+                faceOrder = reorder<labelList>(order, faceOrder);
             }
         }
     }
@@ -226,7 +233,6 @@ void Foam::ensightFaces::classify(const UList<face>& faces)
     resizeAll();    // adjust allocation
     sizes_ = Zero;  // reset sizes - use for local indexing here
 
-
     // Pass 2: Assign face-id per shape type
 
     for (label listi = 0; listi < len; ++listi)
@@ -283,28 +289,34 @@ void Foam::ensightFaces::classify
     resizeAll();    // adjust allocation
     sizes_ = Zero;  // reset sizes - use for local indexing here
 
+    label nUsed = addressing().size();
+
     if (useFlip)
     {
-        flipMap_.resize(len);
+        flipMap_.resize(nUsed);
         flipMap_ = false;
     }
-    else
-    {
-        flipMap_.clear();  // Extra safety
-    }
+
+    faceOrder_.resize(nUsed);
 
     // Pass 2: Assign face-id per shape type
+    // - also record the face order
 
+    nUsed = 0;
     for (label listi = 0; listi < len; ++listi)
     {
         const label faceId = addr[listi];
-        const bool  doFlip = useFlip && flipMap[listi];
 
         if (!exclude.test(faceId))
         {
+            const bool doFlip = useFlip && flipMap.test(listi);
+
             const auto etype = whatType(faces[faceId]);
 
-            add(etype, faceId, doFlip);
+            const label idx = add(etype, faceId, doFlip);
+
+            faceOrder_[nUsed] = idx;
+            ++nUsed;
         }
     }
 }
diff --git a/src/fileFormats/ensight/part/faces/ensightFaces.H b/src/fileFormats/ensight/part/faces/ensightFaces.H
index dd77bac66fb902794f466ab929f49e697624794d..38b804859e076d8bcff72be2091da022fe443cf6 100644
--- a/src/fileFormats/ensight/part/faces/ensightFaces.H
+++ b/src/fileFormats/ensight/part/faces/ensightFaces.H
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2016-2020 OpenCFD Ltd.
+    Copyright (C) 2016-2021 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -43,14 +43,17 @@ Description
         // Can now address into boundaryField
     \endcode
 
+    Additionally, for some uses (eg, finiteArea), the ordered
+    list of faces can be used for a direct local lookup into the field
+    instead of via the overall mesh face addressing.
+
 \*---------------------------------------------------------------------------*/
 
 #ifndef ensightFaces_H
 #define ensightFaces_H
 
 #include "ensightPart.H"
-#include "boolList.H"
-#include "faceList.H"
+#include "face.H"
 #include "FixedList.H"
 #include "bitSet.H"
 
@@ -100,7 +103,10 @@ private:
 
     // Private Data
 
-        //- Linear list of face-flips
+        //- The input face order, for indirect face lists
+        labelList faceOrder_;
+
+        //- List of face-flips (optional)
         boolList flipMap_;
 
         //- Begin/end offsets for address/flips of each element type
@@ -113,8 +119,9 @@ private:
 
     // Private Member Functions
 
-        //- Low-level internal addition routine
-        inline void add(const elemType etype, label id, bool flip=false);
+        //- Low-level internal addition routine.
+        //  \return insertion locaion
+        inline label add(const elemType etype, label id, bool flip=false);
 
         //- Use temporarily stored sizes to redimension the element lists
         void resizeAll();
@@ -168,7 +175,7 @@ public:
         FixedList<label, nTypes> sizes() const;
 
         //- Processor-local face ids of all elements
-        inline const labelList& faceIds() const;
+        inline const labelList& faceIds() const noexcept;
 
         //- Processor-local face ids of the specified element type
         inline const labelUList faceIds(const elemType etype) const;
@@ -179,6 +186,14 @@ public:
         //- True for non-zero flip-map that spans the addresses
         inline bool usesFlipMap() const;
 
+        //- Processor-local face order
+        //- (where applicable)
+        inline const labelList& faceOrder() const noexcept;
+
+        //- Processor-local face order of specified element type
+        //- (where applicable)
+        inline const labelUList faceOrder(const elemType etype) const;
+
 
     // Edit
 
@@ -211,7 +226,7 @@ public:
         //- Sum element counts across all processes.
         void reduce();
 
-        //- Sort element lists numerically.
+        //- Inplace sort element lists numerically.
         void sort();
 
 
diff --git a/src/fileFormats/ensight/part/faces/ensightFacesI.H b/src/fileFormats/ensight/part/faces/ensightFacesI.H
index b971115ac8e8dcfbb2146d8c10b9a6f89cbb05d2..24ff96a866c8b7c8c700de72d1f87b710b701b96 100644
--- a/src/fileFormats/ensight/part/faces/ensightFacesI.H
+++ b/src/fileFormats/ensight/part/faces/ensightFacesI.H
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2016-2020 OpenCFD Ltd.
+    Copyright (C) 2016-2021 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -27,7 +27,8 @@ License
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
-inline void Foam::ensightFaces::add(const elemType etype, label id, bool flip)
+inline Foam::label
+Foam::ensightFaces::add(const elemType etype, label id, bool flip)
 {
     // Linear addressing location
     const label index = offsets_[etype] + sizes_[etype]++;
@@ -38,6 +39,8 @@ inline void Foam::ensightFaces::add(const elemType etype, label id, bool flip)
     {
         flipMap_[index] = flip;
     }
+
+    return index;
 }
 
 
@@ -73,7 +76,7 @@ inline Foam::labelRange Foam::ensightFaces::range(const elemType etype) const
 }
 
 
-inline const Foam::labelList& Foam::ensightFaces::faceIds() const
+inline const Foam::labelList& Foam::ensightFaces::faceIds() const noexcept
 {
     return addressing();
 }
@@ -98,6 +101,20 @@ inline bool Foam::ensightFaces::usesFlipMap() const
 }
 
 
+inline const Foam::labelList&
+Foam::ensightFaces::faceOrder() const noexcept
+{
+    return faceOrder_;
+}
+
+
+inline const Foam::labelUList
+Foam::ensightFaces::faceOrder(const elemType etype) const
+{
+    return faceOrder_[range(etype)];
+}
+
+
 inline void Foam::ensightFaces::incrFaceIds(const label off)
 {
     incrAddressing(off);
diff --git a/src/fileFormats/ensight/part/part/ensightPart.C b/src/fileFormats/ensight/part/part/ensightPart.C
index 70d7d51e2ea64f4330369839990e6eb1c814fac8..4f218b7864573e70e1342493099fcb0c25e04464 100644
--- a/src/fileFormats/ensight/part/part/ensightPart.C
+++ b/src/fileFormats/ensight/part/part/ensightPart.C
@@ -58,7 +58,7 @@ void Foam::ensightPart::decrAddressing(const label off)
 
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
-Foam::ensightPart::ensightPart() noexcept
+Foam::ensightPart::ensightPart()
 :
     index_(0),
     identifier_(-1),
diff --git a/src/fileFormats/ensight/part/part/ensightPart.H b/src/fileFormats/ensight/part/part/ensightPart.H
index 9bb3d4e250e91eb9b8573ed643e6f06cfface2a6..a420b6bb1e304f19419608dbdd3c6d9f63db575d 100644
--- a/src/fileFormats/ensight/part/part/ensightPart.H
+++ b/src/fileFormats/ensight/part/part/ensightPart.H
@@ -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.
@@ -74,13 +74,13 @@ class ensightPart
 protected:
 
         //- Element addressing
-        const labelList& addressing() const
+        const labelList& addressing() const noexcept
         {
             return address_;
         }
 
         //- Element addressing
-        labelList& addressing()
+        labelList& addressing() noexcept
         {
             return address_;
         }
@@ -109,7 +109,7 @@ public:
     // Constructors
 
         //- Default construct. Index=0, identifier = -1
-        ensightPart() noexcept;
+        ensightPart();
 
         //- Default construct, with description/partName
         explicit ensightPart(const string& description);
@@ -122,43 +122,43 @@ public:
     // Member Functions
 
         //- The index in a list (0-based)
-        label index() const
+        label index() const noexcept
         {
             return index_;
         }
 
         //- The index in a list (0-based)
-        label& index()
+        label& index() noexcept
         {
             return index_;
         }
 
         //- OpenFOAM identifier (patch, zone, etc), -1 when not in use.
-        label identifier() const
+        label identifier() const noexcept
         {
             return identifier_;
         }
 
         //- OpenFOAM identifier (patch, zone, etc), -1 when not in use.
-        label& identifier()
+        label& identifier() noexcept
         {
             return identifier_;
         }
 
         //- Processor-local test for any elements.
-        bool empty() const
+        bool empty() const noexcept
         {
             return address_.empty();
         }
 
         //- Processor-local size of all elements.
-        label size() const
+        label size() const noexcept
         {
             return address_.size();
         }
 
         //- The part name or description
-        const string& name() const
+        const string& name() const noexcept
         {
             return name_;
         }
diff --git a/src/finiteArea/Make/files b/src/finiteArea/Make/files
index 7a96d8c4a1ef5c25e0f3b7611f220daccd7c9d14..14d538ace1fe33eb3e0905b77024e0f32019a259 100644
--- a/src/finiteArea/Make/files
+++ b/src/finiteArea/Make/files
@@ -16,6 +16,9 @@ $(faPatches)/constraint/wedge/wedgeFaPatch.C
 $(faPatches)/constraint/cyclic/cyclicFaPatch.C
 $(faPatches)/constraint/symmetry/symmetryFaPatch.C
 
+ensight = output/ensight
+$(ensight)/ensightFaMesh.C
+
 faMeshMapper = faMesh/faMeshMapper
 $(faMeshMapper)/faMeshMapper.C
 $(faMeshMapper)/faAreaMapper.C
diff --git a/src/finiteArea/output/ensight/ensightFaMesh.C b/src/finiteArea/output/ensight/ensightFaMesh.C
new file mode 100644
index 0000000000000000000000000000000000000000..09a88c5332a31ebba9db422e9eac43561dc38101
--- /dev/null
+++ b/src/finiteArea/output/ensight/ensightFaMesh.C
@@ -0,0 +1,114 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2021 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 "ensightFaMesh.H"
+#include "ensightGeoFile.H"
+#include "faMesh.H"
+
+// * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
+
+void Foam::ensightFaMesh::clear()
+{
+    areaPart_.clear();
+}
+
+
+void Foam::ensightFaMesh::renumber()
+{
+    label partNo = 0;
+
+    areaPart_.index() = partNo++;
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+Foam::ensightFaMesh::ensightFaMesh
+(
+    const faMesh& mesh
+)
+:
+    mesh_(mesh),
+    needsUpdate_(true)
+{
+    // Lazy?
+    if (true)
+    {
+        correct();
+    }
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+void Foam::ensightFaMesh::correct()
+{
+    clear();
+
+    // Area meshes (currently only one)
+    const label areaId = 0;
+    {
+        ensightFaces& part = areaPart_;
+
+        part.clear();
+        part.identifier() = areaId;
+        part.rename("finite-area");
+
+        part.classify
+        (
+            mesh_.mesh().faces(),
+            mesh_.faceLabels()
+        );
+
+        // Finalize
+        part.reduce();
+
+        // if (!part.total())
+        // {
+        //     areaParts_.erase(areaId);
+        // }
+    }
+
+    renumber();
+
+    needsUpdate_ = false;
+}
+
+
+void Foam::ensightFaMesh::write
+(
+    ensightGeoFile& os,
+    bool parallel
+) const
+{
+    // Area meshes (currently only one)
+    // const label areaId = 0;
+    areaPart_.write(os, mesh_.mesh(), parallel);
+}
+
+
+// ************************************************************************* //
diff --git a/src/finiteArea/output/ensight/ensightFaMesh.H b/src/finiteArea/output/ensight/ensightFaMesh.H
new file mode 100644
index 0000000000000000000000000000000000000000..ee42b6aa240d8839cde63786d89816bf0557404a
--- /dev/null
+++ b/src/finiteArea/output/ensight/ensightFaMesh.H
@@ -0,0 +1,162 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2021 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::ensightFaMesh
+
+Description
+    Encapsulation of area meshes for writing in ensight format.
+
+Note
+    Currently restricted to a single faMesh representation.
+    The face elements are created from a specified subset of polyMesh
+    faces. The original ordering of these faces is retained in the
+    ensightFaces faceOrder().
+
+SourceFiles
+    ensightFaMesh.C
+    ensightFaMeshI.H
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef fa_ensightMesh_H
+#define fa_ensightMesh_H
+
+#include "ensightFaces.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+// Forward Declarations
+class faMesh;
+class ensightGeoFile;
+class ensightFaMesh;
+
+/*---------------------------------------------------------------------------*\
+                         Class ensightMesh Declaration
+\*---------------------------------------------------------------------------*/
+
+class ensightFaMesh
+{
+    // Private Data
+
+        //- Reference to the finite-area mesh
+        const faMesh& mesh_;
+
+        //- Face elements for the area mesh (currently only one)
+        ensightFaces areaPart_;
+
+        //- Track if it needs an update
+        mutable bool needsUpdate_;
+
+
+    // Private Member Functions
+
+        //- Clear all storage
+        void clear();
+
+        //- Enforce consistent index/part numbering
+        void renumber();
+
+        //- No copy construct
+        ensightFaMesh(const ensightFaMesh&) = delete;
+
+        //- No copy assignment
+        void operator=(const ensightFaMesh&) = delete;
+
+
+public:
+
+    // Constructors
+
+        //- Construct from mesh with all default options
+        explicit ensightFaMesh(const faMesh& mesh);
+
+
+    // Member Functions
+
+    // Access
+
+        //- Reference to the underlying faMesh
+        const faMesh& mesh() const noexcept
+        {
+            return mesh_;
+        }
+
+        //- Face elements for finite-area
+        const ensightFaces& areaPart() const noexcept
+        {
+            return areaPart_;
+        }
+
+
+    // Other
+
+        //- Does the content need an update?
+        bool needsUpdate() const noexcept
+        {
+            return needsUpdate_;
+        }
+
+        //- Mark as needing an update.
+        //  May also free up unneeded data.
+        //  Return false if already marked as expired.
+        inline bool expire();
+
+        //- Update for new mesh
+        void correct();
+
+
+    // Output
+
+        //- Write geometry to file. Normally in parallel
+        void write
+        (
+            ensightGeoFile& os,
+            bool parallel = Pstream::parRun()
+        ) const;
+
+        //- Write geometry to file. Normally in parallel
+        inline void write
+        (
+            autoPtr<ensightGeoFile>& os,
+            bool parallel = Pstream::parRun()
+        ) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#include "ensightFaMeshI.H"
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/finiteArea/output/ensight/ensightFaMeshI.H b/src/finiteArea/output/ensight/ensightFaMeshI.H
new file mode 100644
index 0000000000000000000000000000000000000000..6e989cc12f54bc72e7a5c9ee6c33dc85fc865a18
--- /dev/null
+++ b/src/finiteArea/output/ensight/ensightFaMeshI.H
@@ -0,0 +1,55 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2021 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/>.
+
+\*---------------------------------------------------------------------------*/
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+inline bool Foam::ensightFaMesh::expire()
+{
+    clear();
+
+    // Already marked as expired
+    if (needsUpdate_)
+    {
+        return false;
+    }
+
+    needsUpdate_ = true;
+    return true;
+}
+
+
+inline void Foam::ensightFaMesh::write
+(
+    autoPtr<ensightGeoFile>& os,
+    bool parallel
+) const
+{
+    write(os.ref(), parallel);
+}
+
+
+// ************************************************************************* //