diff --git a/src/lagrangian/intermediate/conversion/ensight/ensightOutputCloud.C b/src/lagrangian/intermediate/conversion/ensight/ensightOutputCloud.C
index 747bb0abebf7ccf0091c3f42726467e6f2c3aa4d..720ad68a457ed125b8e89bdeeef5738ea342e63e 100644
--- a/src/lagrangian/intermediate/conversion/ensight/ensightOutputCloud.C
+++ b/src/lagrangian/intermediate/conversion/ensight/ensightOutputCloud.C
@@ -43,7 +43,7 @@ static inline void writeMeasured_binary
     const UList<floatVector>& points
 )
 {
-    for (const floatVector& p : points)
+    for (const auto& p : points)
     {
         os.write(p.x());
         os.write(p.y());
@@ -59,7 +59,7 @@ static inline label writeMeasured_ascii
     const UList<floatVector>& points
 )
 {
-    for (const floatVector& p : points)
+    for (const auto& p : points)
     {
         os.writeInt(++pointId, 8);  // 1-index and an unusual width
         os.write(p.x());
@@ -79,75 +79,24 @@ static inline label writeMeasured_ascii
 bool Foam::ensightOutput::writeCloudPositions
 (
     ensightFile& os,
-    const fvMesh& mesh,
-    const word& cloudName,
-    bool exists
+    DynamicList<floatVector>& positions,
+    const globalIndex& procAddr
 )
 {
-    label nLocalParcels(0);
-    autoPtr<Cloud<passiveParticle>> parcelsPtr;
+    // Total number of parcels across all ranks
+    const label nTotParcels = procAddr.totalSize();
 
-    if (exists)
-    {
-        parcelsPtr.reset(new Cloud<passiveParticle>(mesh, cloudName, false));
-        nLocalParcels = parcelsPtr().size();
-    }
-
-    // Total number of parcels on all processes
-    const label nTotParcels = returnReduce(nLocalParcels, sumOp<label>());
+    bool noCloud(!procAddr.totalSize());
+    Pstream::broadcast(noCloud);
 
     if (UPstream::master())
     {
         os.beginParticleCoordinates(nTotParcels);
     }
 
-    if (!nTotParcels)
-    {
-        return false;  // DONE
-    }
-
-
-    // Gather sizes (offsets irrelevant)
-    const globalIndex procAddr(globalIndex::gatherOnly{}, nLocalParcels);
-
-
-    DynamicList<floatVector> positions;
-    positions.reserve(UPstream::master() ? procAddr.maxSize() : nLocalParcels);
-
-    // Extract positions from parcel.
-    // Store as floatVector, since that is what Ensight will write anyhow
-
-    if (parcelsPtr)
+    if (noCloud)
     {
-        const auto& parcels = *parcelsPtr;
-
-        positions.resize_nocopy(parcels.size());  // same as nLocalParcels
-
-        auto outIter = positions.begin();
-
-        if (std::is_same<float, vector::cmptType>::value)
-        {
-            for (const passiveParticle& p : parcels)
-            {
-                *outIter = p.position();
-                ++outIter;
-            }
-        }
-        else
-        {
-            for (const passiveParticle& p : parcels)
-            {
-                vector pos(p.position());
-
-                (*outIter).x() = narrowFloat(pos.x());
-                (*outIter).y() = narrowFloat(pos.y());
-                (*outIter).z() = narrowFloat(pos.z());
-
-                ++outIter;
-            }
-        }
-
-        parcelsPtr.reset(nullptr);
+        return false;  // All empty
     }
 
     if (UPstream::master())
@@ -178,6 +127,9 @@ bool Foam::ensightOutput::writeCloudPositions
         }
 
 
+        positions.clear();
+        positions.reserve_nocopy(procAddr.maxNonLocalSize());
+
         // Receive and write
         for (const label proci : procAddr.subProcs())
         {
@@ -186,6 +138,7 @@ bool Foam::ensightOutput::writeCloudPositions
             if (procSize)
             {
                 positions.resize_nocopy(procSize);
+
                 UIPstream::read
                 (
                     UPstream::commsTypes::scheduled,
@@ -205,7 +158,7 @@ bool Foam::ensightOutput::writeCloudPositions
             }
         }
     }
-    else
+    else if (UPstream::is_subrank())
     {
         if (positions.size())
         {
@@ -223,4 +176,86 @@ bool Foam::ensightOutput::writeCloudPositions
 }
 
 
+bool Foam::ensightOutput::writeCloudPositions
+(
+    ensightFile& os,
+    DynamicList<floatVector>& positions
+)
+{
+    return ensightOutput::writeCloudPositions
+    (
+        os,
+        positions,
+        // Gather sizes (offsets irrelevant)
+        globalIndex(globalIndex::gatherOnly{}, positions.size())
+    );
+}
+
+
+bool Foam::ensightOutput::writeCloudPositions
+(
+    ensightFile& os,
+    const fvMesh& mesh,
+    const word& cloudName,
+    bool exists
+)
+{
+    autoPtr<Cloud<passiveParticle>> parcelsPtr;
+
+    if (exists)
+    {
+        parcelsPtr.reset(new Cloud<passiveParticle>(mesh, cloudName, false));
+    }
+
+    const label nLocalParcels
+    (
+        parcelsPtr ? parcelsPtr->size() : 0
+    );
+
+    // Gather sizes (offsets irrelevant)
+    // and total number of parcels (all processes)
+    const globalIndex procAddr(globalIndex::gatherOnly{}, nLocalParcels);
+
+    // Extract positions from parcel.
+    // Store as floatVector, since that is what Ensight will write anyhow
+
+    DynamicList<floatVector> positions;
+    positions.reserve(UPstream::master() ? procAddr.maxSize() : nLocalParcels);
+
+    if (parcelsPtr)
+    {
+        const auto& parcels = *parcelsPtr;
+
+        positions.resize_nocopy(parcels.size());  // same as nLocalParcels
+
+        auto iter = positions.begin();
+
+        if (std::is_same<float, vector::cmptType>::value)
+        {
+            for (const auto& p : parcels)
+            {
+                *iter = p.position();
+                ++iter;
+            }
+        }
+        else
+        {
+            for (const auto& p : parcels)
+            {
+                const vector pos(p.position());
+
+                (*iter).x() = narrowFloat(pos.x());
+                (*iter).y() = narrowFloat(pos.y());
+                (*iter).z() = narrowFloat(pos.z());
+                ++iter;
+            }
+        }
+
+        parcelsPtr.reset(nullptr);
+    }
+
+    return ensightOutput::writeCloudPositions(os, positions, procAddr);
+}
+
+
 // ************************************************************************* //
diff --git a/src/lagrangian/intermediate/conversion/ensight/ensightOutputCloud.H b/src/lagrangian/intermediate/conversion/ensight/ensightOutputCloud.H
index e83fbecec0cbf7e582206856ddf079135b4ab1b6..323296eb261c59da3de3156a1605708f8c833732 100644
--- a/src/lagrangian/intermediate/conversion/ensight/ensightOutputCloud.H
+++ b/src/lagrangian/intermediate/conversion/ensight/ensightOutputCloud.H
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2016-2022 OpenCFD Ltd.
+    Copyright (C) 2016-2024 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -40,6 +40,8 @@ SourceFiles
 
 #include "ensightFile.H"
 #include "IOField.H"
+#include "DynamicList.H"
+#include "vector.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
@@ -48,6 +50,7 @@ namespace Foam
 
 // Forward Declarations
 class fvMesh;
+class globalIndex;
 
 namespace ensightOutput
 {
@@ -55,6 +58,34 @@ namespace ensightOutput
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
 
 
+//- Write cloud positions
+bool writeCloudPositions
+(
+    //! Output file (must be valid on master)
+    ensightFile& os,
+
+    //! The positions (measured data) to write.
+    //! Also used as intermediate buffer (on master)
+    DynamicList<floatVector>& positions,
+
+    //! The global sizes of \p positions (must be valid on master)
+    //! and consistent with \p positions dimensions
+    const globalIndex& procAddr
+);
+
+
+//- Write cloud positions
+bool writeCloudPositions
+(
+    //! Output file (must be valid on master)
+    ensightFile& os,
+
+    //! The positions (measured data) to write.
+    //! Also used as intermediate buffer (on master)
+    DynamicList<floatVector>& positions
+);
+
+
 //- Write cloud positions
 bool writeCloudPositions
 (
@@ -80,7 +111,23 @@ bool writeCloudField
     ensightFile& os,
 
     //! The cloud field
-    const IOField<Type>& field
+    const UList<Type>& field,
+
+    //! The global sizes of \p field (must be valid on master)
+    //! and consistent with \p field dimensions
+    const globalIndex& procAddr
+);
+
+
+//- Write cloud field, returning true if the field is non-empty.
+template<class Type>
+bool writeCloudField
+(
+    //! Output file (must be valid on master)
+    ensightFile& os,
+
+    //! The cloud field
+    const UList<Type>& field
 );
 
 
diff --git a/src/lagrangian/intermediate/conversion/ensight/ensightOutputCloudTemplates.C b/src/lagrangian/intermediate/conversion/ensight/ensightOutputCloudTemplates.C
index cc865cc7d3bd0a21b7916f782a25d42993d3f3d4..85b5d8a898a51c65a5973819648f1b896ef029a0 100644
--- a/src/lagrangian/intermediate/conversion/ensight/ensightOutputCloudTemplates.C
+++ b/src/lagrangian/intermediate/conversion/ensight/ensightOutputCloudTemplates.C
@@ -5,7 +5,7 @@
     \\  /    A nd           | www.openfoam.com
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
-    Copyright (C) 2016-2022 OpenCFD Ltd.
+    Copyright (C) 2016-2024 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -39,7 +39,6 @@ Foam::label Foam::ensightOutput::Detail::writeCloudFieldContent
     label count
 )
 {
-    // Write master data
     for (Type val : field)          // <-- working on a copy!
     {
         if (mag(val) < 1e-90)       // approximately root(ROOTVSMALL)
@@ -70,18 +69,20 @@ template<class Type>
 bool Foam::ensightOutput::writeCloudField
 (
     ensightFile& os,
-    const IOField<Type>& field
+    const UList<Type>& field,
+    const globalIndex& procAddr
 )
 {
-    if (returnReduceAnd(field.empty()))
+    bool allEmpty(!procAddr.totalSize());
+    Pstream::broadcast(allEmpty);
+
+    if (allEmpty)
     {
-        return false;
+        return false;  // All empty
     }
 
-    // Gather sizes (offsets irrelevant)
-    const globalIndex procAddr(globalIndex::gatherOnly{}, field.size());
 
-    if (Pstream::master())
+    if (UPstream::master())
     {
         // 6 values per line
         label count = 0;
@@ -128,7 +129,7 @@ bool Foam::ensightOutput::writeCloudField
             os.newline();
         }
     }
-    else
+    else if (UPstream::is_subrank())
     {
         if (field.size())
         {
@@ -146,6 +147,23 @@ bool Foam::ensightOutput::writeCloudField
 }
 
 
+template<class Type>
+bool Foam::ensightOutput::writeCloudField
+(
+    ensightFile& os,
+    const UList<Type>& field
+)
+{
+    return ensightOutput::writeCloudField
+    (
+        os,
+        field,
+        // Gather sizes (offsets irrelevant)
+        globalIndex(globalIndex::gatherOnly{}, field.size())
+    );
+}
+
+
 template<class Type>
 bool Foam::ensightOutput::readWriteCloudField
 (
@@ -162,10 +180,11 @@ bool Foam::ensightOutput::readWriteCloudField
 
         IOobject io(fieldObject);
         io.readOpt(IOobject::READ_IF_PRESENT);
+        io.registerObject(IOobject::NO_REGISTER);
 
         IOField<Type> field(io);
 
-        writeCloudField(os, field);
+        ensightOutput::writeCloudField(os, field);
     }
 
     return true;