diff --git a/src/functionObjects/lagrangian/Make/files b/src/functionObjects/lagrangian/Make/files
index 8a65315b9adb9bfd649dd99e527e580e0e2331ea..e349d4f5454fbc240faf2ceb27ef1a052c0ea176 100644
--- a/src/functionObjects/lagrangian/Make/files
+++ b/src/functionObjects/lagrangian/Make/files
@@ -1,9 +1,9 @@
+common/parcelSelectionDetail.C
 dataCloud/dataCloud.C
 cloudInfo/cloudInfo.C
 icoUncoupledKinematicCloud/icoUncoupledKinematicCloud.C
 dsmcFields/dsmcFields.C
 
 vtkCloud/vtkCloud.C
-vtkCloud/parcelSelectionDetail.C
 
 LIB = $(FOAM_LIBBIN)/liblagrangianFunctionObjects
diff --git a/src/functionObjects/lagrangian/cloudInfo/cloudInfo.C b/src/functionObjects/lagrangian/cloudInfo/cloudInfo.C
index d1d379b817747ba3fff0df99df1db891806479ff..3bbe4a132f301c72bbfd9c80c527baf2a6c55653 100644
--- a/src/functionObjects/lagrangian/cloudInfo/cloudInfo.C
+++ b/src/functionObjects/lagrangian/cloudInfo/cloudInfo.C
@@ -78,12 +78,6 @@ Foam::functionObjects::cloudInfo::cloudInfo
 }
 
 
-// * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
-
-Foam::functionObjects::cloudInfo::~cloudInfo()
-{}
-
-
 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
 
 bool Foam::functionObjects::cloudInfo::read(const dictionary& dict)
@@ -96,10 +90,10 @@ bool Foam::functionObjects::cloudInfo::read(const dictionary& dict)
         if (writeToFile() && names().size())
         {
             Info<< "applying to clouds:" << nl;
-            forAll(names(), i)
+            forAll(names(), cloudi)
             {
-                Info<< "    " << names()[i] << nl;
-                writeFileHeader(files(i));
+                Info<< "    " << names()[cloudi] << nl;
+                writeFileHeader(files(cloudi));
             }
             Info<< endl;
         }
@@ -107,8 +101,6 @@ bool Foam::functionObjects::cloudInfo::read(const dictionary& dict)
         {
             Info<< "no clouds to be processed" << nl << endl;
         }
-
-        return true;
     }
 
     return true;
@@ -123,24 +115,26 @@ bool Foam::functionObjects::cloudInfo::execute()
 
 bool Foam::functionObjects::cloudInfo::write()
 {
-    forAll(names(), i)
+    forAll(names(), cloudi)
     {
-        const word& cloudName = names()[i];
+        const word& cloudName = names()[cloudi];
 
         const kinematicCloud& cloud =
             obr_.lookupObject<kinematicCloud>(cloudName);
 
-        label nParcels = returnReduce(cloud.nParcels(), sumOp<label>());
-        scalar massInSystem =
+        const label nTotParcels =
+            returnReduce(cloud.nParcels(), sumOp<label>());
+
+        const scalar totMass =
             returnReduce(cloud.massInSystem(), sumOp<scalar>());
 
-        scalar Dmax = cloud.Dmax();
-        scalar D10 = cloud.Dij(1, 0);
-        scalar D32 = cloud.Dij(3, 2);
+        const scalar Dmax = cloud.Dmax();
+        const scalar D10 = cloud.Dij(1, 0);
+        const scalar D32 = cloud.Dij(3, 2);
 
         Log << type() << " " << name() <<  " write:" << nl
-            << "    number of parcels : " << nParcels << nl
-            << "    mass in system    : " << massInSystem << nl
+            << "    number of parcels : " << nTotParcels << nl
+            << "    mass in system    : " << totMass << nl
             << "    maximum diameter  : " << Dmax << nl
             << "    D10 diameter      : " << D10 << nl
             << "    D32 diameter      : " << D32 << nl
@@ -148,14 +142,15 @@ bool Foam::functionObjects::cloudInfo::write()
 
         if (writeToFile())
         {
-            writeTime(files(i));
-            files(i)
-                << token::TAB
-                << nParcels << token::TAB
-                << massInSystem << token::TAB
-                << Dmax << token::TAB
-                << D10 << token::TAB
-                << D32 << token::TAB
+            auto& os = files(cloudi);
+
+            writeTime(os);
+            os
+                << token::TAB << nTotParcels
+                << token::TAB << totMass
+                << token::TAB << Dmax
+                << token::TAB << D10
+                << token::TAB << D32
                 << endl;
         }
     }
diff --git a/src/functionObjects/lagrangian/cloudInfo/cloudInfo.H b/src/functionObjects/lagrangian/cloudInfo/cloudInfo.H
index d4dad2889cdd8377c0579fb8fc4eef30a1cf229a..e01b1d4ffb8132c8e1c52057f758e079b1db43e2 100644
--- a/src/functionObjects/lagrangian/cloudInfo/cloudInfo.H
+++ b/src/functionObjects/lagrangian/cloudInfo/cloudInfo.H
@@ -52,9 +52,9 @@ Usage
 
     Where the entries comprise:
     \table
-        Property     | Description             | Required    | Default value
-        type         | type name: cloudInfo    | yes         |
-        clouds       | list of clouds names to process |yes  |
+        Property     | Description                          | Required | Default
+        type         | type name: cloudInfo                 | yes |
+        clouds       | list of clouds names to process      | yes |
     \endtable
 
     The output data of each cloud is written to a file named \<cloudName\>.dat
@@ -108,10 +108,6 @@ protected:
         virtual void writeFileHeader(Ostream& os) const;
 
 
-private:
-
-    // Private member functions
-
         //- No copy construct
         cloudInfo(const cloudInfo&) = delete;
 
@@ -137,13 +133,13 @@ public:
 
 
     //- Destructor
-    virtual ~cloudInfo();
+    virtual ~cloudInfo() = default;
 
 
     // Member Functions
 
         //- Read the controls
-        virtual bool read(const dictionary&);
+        virtual bool read(const dictionary& dict);
 
         //- Execute, currently does nothing
         virtual bool execute();
diff --git a/src/functionObjects/lagrangian/vtkCloud/parcelSelectionDetail.C b/src/functionObjects/lagrangian/common/parcelSelectionDetail.C
similarity index 100%
rename from src/functionObjects/lagrangian/vtkCloud/parcelSelectionDetail.C
rename to src/functionObjects/lagrangian/common/parcelSelectionDetail.C
diff --git a/src/functionObjects/lagrangian/vtkCloud/parcelSelectionDetail.H b/src/functionObjects/lagrangian/common/parcelSelectionDetail.H
similarity index 100%
rename from src/functionObjects/lagrangian/vtkCloud/parcelSelectionDetail.H
rename to src/functionObjects/lagrangian/common/parcelSelectionDetail.H
diff --git a/src/functionObjects/lagrangian/dataCloud/dataCloud.C b/src/functionObjects/lagrangian/dataCloud/dataCloud.C
index 53267ab0251a61e6d362fb57add2b0e2206cdf56..bf303c92a30f104f4e3324620931bfe053b80ec7 100644
--- a/src/functionObjects/lagrangian/dataCloud/dataCloud.C
+++ b/src/functionObjects/lagrangian/dataCloud/dataCloud.C
@@ -79,16 +79,29 @@ bool Foam::functionObjects::dataCloud::writeCloud
         return false;
     }
 
+    applyFilter_ = calculateFilter(obrTmp, log);
+    reduce(applyFilter_, orOp<bool>());
+
+
+    // Number of parcels (locally)
+    label nParcels = (applyFilter_ ? parcelAddr_.count() : pointsPtr->size());
+
     // Total number of parcels on all processes
-    label nTotParcels = pointsPtr->size();
-    reduce(nTotParcels, sumOp<label>());
+    const label nTotParcels = returnReduce(nParcels, sumOp<label>());
+
+    if (applyFilter_ && log)
+    {
+        // Report filtered/unfiltered count
+        Log << "After filtering using " << nTotParcels << '/'
+            << (returnReduce(pointsPtr->size(), sumOp<label>()))
+            << " parcels" << nl;
+    }
 
     if (!nTotParcels)
     {
         return false;
     }
 
-
     if (Pstream::master())
     {
         mkDir(outputName.path());
@@ -113,6 +126,9 @@ Foam::functionObjects::dataCloud::dataCloud
 )
 :
     fvMeshFunctionObject(name, runTime, dict),
+    printf_(),
+    precision_(IOstream::defaultPrecision()),
+    applyFilter_(false),
     selectClouds_(),
     fieldName_(),
     directory_()
@@ -139,6 +155,9 @@ bool Foam::functionObjects::dataCloud::read(const dictionary& dict)
         printf_ = "%0" + std::to_string(padWidth) + "d";
     }
 
+    precision_ =
+        dict.lookupOrDefault("precision", IOstream::defaultPrecision());
+
 
     selectClouds_.clear();
     dict.readIfPresent("clouds", selectClouds_);
@@ -152,6 +171,9 @@ bool Foam::functionObjects::dataCloud::read(const dictionary& dict)
 
     dict.readEntry("field", fieldName_);
 
+    // Actions to define selection
+    parcelSelect_ = dict.subOrEmptyDict("selection");
+
     // Output directory
 
     directory_.clear();
diff --git a/src/functionObjects/lagrangian/dataCloud/dataCloud.H b/src/functionObjects/lagrangian/dataCloud/dataCloud.H
index a1ef28b587fbe4ffe054228a817f8480add641b7..002dc54c2639760d84df77ca39bc01630bfb1f1b 100644
--- a/src/functionObjects/lagrangian/dataCloud/dataCloud.H
+++ b/src/functionObjects/lagrangian/dataCloud/dataCloud.H
@@ -43,19 +43,34 @@ Description
     }
     \endverbatim
 
-Usage
+    \heading Basic Usage
     \table
         Property     | Description                      | Required | Default
         type         | Type name: dataCloud             | yes   |
-        cloud        |                                  | no    | defaultCloud
-        clouds       | wordRe list of clouds            | no    |
+        clouds       | List of clouds (name or regex)   | no  |
+        cloud        | Cloud name                       | no  | defaultCloud
         field        | Name of the field                | yes   |
-        directory    | The output directory name     | no | postProcessing/NAME
-        width        | Padding width for file name      | no    | 8
+        selection    | Parcel selection control         | no  | empty-dict
     \endtable
 
+    \heading Output Options
+    \table
+        Property     | Description                      | Required | Default
+        precision    | The write precision              | no  | same as IOstream
+        directory    | The output directory name    | no | postProcessing/NAME
+        width        | Padding width for file name      | no  | 8
+        writeControl | Output control                   | recommended | timeStep
+    \endtable
+
+Note
+    See Foam::functionObjects::vtkCloud and Foam::Detail::parcelSelection
+    for more details about the parcel selection mechanism.
+
 See also
+    Foam::Detail::parcelSelection
     Foam::functionObjects::vtkCloud
+    Foam::functionObjects::fvMeshFunctionObject
+    Foam::functionObjects::timeControl
 
 SourceFiles
     dataCloud.C
@@ -67,6 +82,7 @@ SourceFiles
 #define functionObjects_dataCloud_H
 
 #include "fvMeshFunctionObject.H"
+#include "parcelSelectionDetail.H"
 #include "vectorField.H"
 
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@@ -82,13 +98,20 @@ namespace functionObjects
 
 class dataCloud
 :
-    public fvMeshFunctionObject
+    public fvMeshFunctionObject,
+    public Foam::Detail::parcelSelection
 {
     // Private data
 
         //- The printf format for zero-padding names
         string printf_;
 
+        //- The output precision
+        unsigned precision_;
+
+        //- Apply output filter (for the current cloud)
+        bool applyFilter_;
+
         //- Requested names of clouds to process
         wordRes selectClouds_;
 
@@ -101,12 +124,47 @@ class dataCloud
 
     // Private Member Functions
 
+        //- Output (point,value) combination on a single line
+        template<class Type>
+        static void writePointValue
+        (
+            Ostream& os,
+            const vector& pt,
+            const Type& val
+        );
+
+        template<class Type>
+        static void writeList
+        (
+            Ostream& os,
+            const vectorField& points,
+            const List<Type>& field
+        );
+
+        template<class Type>
+        static void writeListParallel
+        (
+            Ostream& os,
+            const vectorField& points,
+            const List<Type>& field
+        );
+
+        template<class Type>
+        static void writeList
+        (
+            Ostream& os,
+            const vectorField& points,
+            const List<Type>& field,
+            const bitSet& selected
+        );
+
         template<class Type>
-        static void writeField
+        static void writeListParallel
         (
             Ostream& os,
             const vectorField& points,
-            const Field<Type>& field
+            const List<Type>& field,
+            const bitSet& selected
         );
 
         //- Write to disk
diff --git a/src/functionObjects/lagrangian/dataCloud/dataCloudTemplates.C b/src/functionObjects/lagrangian/dataCloud/dataCloudTemplates.C
index c51033e9e56570c56eb2e5f139cf9a13b4b9563f..27412033208ccf63280c40ceea5b231ca2a3586e 100644
--- a/src/functionObjects/lagrangian/dataCloud/dataCloudTemplates.C
+++ b/src/functionObjects/lagrangian/dataCloud/dataCloudTemplates.C
@@ -25,33 +25,141 @@ License
 
 #include "IOField.H"
 #include "OFstream.H"
+#include "ListOps.H"
 #include "pointField.H"
 #include "vectorField.H"
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
 template<class Type>
-void Foam::functionObjects::dataCloud::writeField
+void Foam::functionObjects::dataCloud::writePointValue
+(
+    Ostream& os,
+    const vector& pt,
+    const Type& val
+)
+{
+    os << pt.x() << ' ' << pt.y() << ' ' << pt.z();
+
+    for (direction cmpt=0; cmpt < pTraits<Type>::nComponents; ++cmpt)
+    {
+        os << ' ' << component(val, cmpt);
+    }
+    os << nl;
+}
+
+
+template<class Type>
+void Foam::functionObjects::dataCloud::writeList
 (
     Ostream& os,
     const vectorField& points,
-    const Field<Type>& field
+    const List<Type>& field
 )
 {
     const label len = field.size();
 
     for (label pointi=0; pointi<len; ++pointi)
     {
-        const point& pt = points[pointi];
-        const Type& val = field[pointi];
+        writePointValue(os, points[pointi], field[pointi]);
+    }
+}
+
+
+template<class Type>
+void Foam::functionObjects::dataCloud::writeListParallel
+(
+    Ostream& os,
+    const vectorField& points,
+    const List<Type>& field
+)
+{
+    if (Pstream::master())
+    {
+        writeList(os, points, field);
+
+        vectorField recvPoints;
+        Field<Type> recvField;
+
+        // Receive and write
+        for (int slave=1; slave<Pstream::nProcs(); ++slave)
+        {
+            IPstream fromSlave(Pstream::commsTypes::blocking, slave);
+
+            fromSlave >> recvPoints >> recvField;
+
+            writeList(os, recvPoints, recvField);
+        }
+    }
+    else
+    {
+        // Send to master
+        OPstream toMaster
+        (
+            Pstream::commsTypes::blocking,
+            Pstream::masterNo()
+        );
+
+        toMaster
+            << points << field;
+    }
+}
+
+
+template<class Type>
+void Foam::functionObjects::dataCloud::writeList
+(
+    Ostream& os,
+    const vectorField& points,
+    const List<Type>& field,
+    const bitSet& selected
+)
+{
+    for (const label pointi : selected)
+    {
+        writePointValue(os, points[pointi], field[pointi]);
+    }
+}
+
+
+template<class Type>
+void Foam::functionObjects::dataCloud::writeListParallel
+(
+    Ostream& os,
+    const vectorField& points,
+    const List<Type>& field,
+    const bitSet& selected
+)
+{
+    if (Pstream::master())
+    {
+        writeList(os, points, field, selected);
 
-        os << pt.x() << ' ' << pt.y() << ' ' << pt.z();
+        vectorField recvPoints;
+        Field<Type> recvField;
 
-        for (direction cmpt=0; cmpt < pTraits<Type>::nComponents; ++cmpt)
+        // Receive and write
+        for (int slave=1; slave<Pstream::nProcs(); ++slave)
         {
-            os << ' ' << component(val, cmpt);
+            IPstream fromSlave(Pstream::commsTypes::blocking, slave);
+
+            fromSlave >> recvPoints >> recvField;
+
+            writeList(os, recvPoints, recvField);
         }
-        os << nl;
+    }
+    else
+    {
+        // Send to master
+        OPstream toMaster
+        (
+            Pstream::commsTypes::blocking,
+            Pstream::masterNo()
+        );
+
+        toMaster
+            << subset(selected, points)
+            << subset(selected, field);
     }
 }
 
@@ -63,64 +171,43 @@ bool Foam::functionObjects::dataCloud::writeField
     const objectRegistry& obrTmp
 ) const
 {
-    // Fields are not always on all processors (eg, multi-component parcels).
-    // Thus need to resolve between all processors.
-
-    const auto* fldPtr = obrTmp.findObject<IOField<Type>>(fieldName_);
+    const auto* pointsPtr = obrTmp.findObject<vectorField>("position");
 
-    if (!returnReduce((fldPtr != nullptr), orOp<bool>()))
+    if (!pointsPtr)
     {
+        // This should be impossible
         return false;
     }
 
-    const auto* pointsPtr = obrTmp.findObject<vectorField>("position");
+    // Fields are not always on all processors (eg, multi-component parcels).
+    // Thus need to resolve between all processors.
 
-    if (!pointsPtr)
+    const List<Type>* fldPtr = obrTmp.findObject<IOField<Type>>(fieldName_);
+    const List<Type>& values = (fldPtr ? *fldPtr : List<Type>());
+
+    if (!returnReduce((fldPtr != nullptr), orOp<bool>()))
     {
-        // This should be impossible
         return false;
     }
 
+    autoPtr<OFstream> osPtr;
+
     if (Pstream::master())
     {
-        OFstream os(outputName);
+        osPtr.reset(new OFstream(outputName));
+        osPtr->precision(precision_);
 
-        os << "# x y z " << fieldName_ << nl;
+        *(osPtr) << "# x y z " << fieldName_ << nl;
+    }
 
-        // Master
-        if (fldPtr)
-        {
-            writeField(os, *pointsPtr, *fldPtr);
-        }
 
-        // Slaves - recv
-        for (int slave=1; slave<Pstream::nProcs(); ++slave)
-        {
-            IPstream fromSlave(Pstream::commsTypes::blocking, slave);
-            vectorField points(fromSlave);
-            Field<Type> fld(fromSlave);
-
-            writeField(os, points, fld);
-        }
+    if (applyFilter_)
+    {
+        writeListParallel(osPtr.ref(), *pointsPtr, values, parcelAddr_);
     }
     else
     {
-        // Slaves
-
-        OPstream toMaster(Pstream::commsTypes::blocking, Pstream::masterNo());
-
-        if (fldPtr)
-        {
-            toMaster
-                << *pointsPtr
-                << *fldPtr;
-        }
-        else
-        {
-            toMaster
-                << vectorField()
-                << Field<Type>();
-        }
+        writeListParallel(osPtr.ref(), *pointsPtr, values);
     }
 
     return true;
diff --git a/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/dataCloud b/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/dataCloud
index 127d1ccf071103e071918e41837f82b9a90766e4..132e87de5e1168ad5a7b9cc15b3d0b1ec8019d31 100644
--- a/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/dataCloud
+++ b/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/dataCloud
@@ -1,5 +1,6 @@
 // -*- C++ -*-
 // Minimal example of using the dataCloud function object.
+
 dataCloud
 {
     type    dataCloud;
diff --git a/tutorials/lagrangian/reactingParcelFoam/filter/system/controlDict b/tutorials/lagrangian/reactingParcelFoam/filter/system/controlDict
index e54c5d788b5948b91a14eb793300131942c40dac..5a2262f2410e15cc14da3ce4b04bc9c8e3ca7ae8 100644
--- a/tutorials/lagrangian/reactingParcelFoam/filter/system/controlDict
+++ b/tutorials/lagrangian/reactingParcelFoam/filter/system/controlDict
@@ -53,6 +53,7 @@ maxDeltaT       1;
 
 functions
 {
+    #include "dataCloud"
     #include "vtkCloud"
     #include "vtkWrite"
 }
diff --git a/tutorials/lagrangian/reactingParcelFoam/filter/system/dataCloud b/tutorials/lagrangian/reactingParcelFoam/filter/system/dataCloud
new file mode 100644
index 0000000000000000000000000000000000000000..51a99a2332750a752e92546127c136e7ad71b40c
--- /dev/null
+++ b/tutorials/lagrangian/reactingParcelFoam/filter/system/dataCloud
@@ -0,0 +1,42 @@
+// -*- C++ -*-
+
+dataCloud
+{
+    type    dataCloud;
+    libs    ("liblagrangianFunctionObjects.so");
+    log     true;
+
+    // Nothing happens before this anyhow
+    timeStart 0.5;
+
+    writeControl    writeTime;
+
+    // cloud   reactingCloud1;
+    clouds  ( ".*" );
+
+    // Field to output
+    field   d;
+
+    // Optional selection mechanism
+    selection
+    {
+        // Reduced number of output parcels
+        stride
+        {
+            action  add;
+            source  stride;
+            stride  4;
+        }
+
+        Umin
+        {
+            action  subtract;
+            source  field;
+            field   U;
+            accept  (less 0.2);
+        }
+    }
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/lagrangian/reactingParcelFoam/filter/system/vtkCloud b/tutorials/lagrangian/reactingParcelFoam/filter/system/vtkCloud
index ce153de26ee2f60a0a3eeb30f1e9bfca926dd881..451312c593f17e2eb96bdd13f89078d118d5caf0 100644
--- a/tutorials/lagrangian/reactingParcelFoam/filter/system/vtkCloud
+++ b/tutorials/lagrangian/reactingParcelFoam/filter/system/vtkCloud
@@ -28,6 +28,7 @@ cloudWrite
     //- Output directory name - Default postProcessing
     // directory       "VTK";
 
+    // Optional selection mechanism
     selection
     {
         all