diff --git a/src/functionObjects/lagrangian/Make/files b/src/functionObjects/lagrangian/Make/files
index 921ca2d707..c7feb02e33 100644
--- a/src/functionObjects/lagrangian/Make/files
+++ b/src/functionObjects/lagrangian/Make/files
@@ -1,3 +1,4 @@
+dataCloud/dataCloud.C
cloudInfo/cloudInfo.C
icoUncoupledKinematicCloud/icoUncoupledKinematicCloud.C
dsmcFields/dsmcFields.C
diff --git a/src/functionObjects/lagrangian/dataCloud/dataCloud.C b/src/functionObjects/lagrangian/dataCloud/dataCloud.C
new file mode 100644
index 0000000000..53267ab025
--- /dev/null
+++ b/src/functionObjects/lagrangian/dataCloud/dataCloud.C
@@ -0,0 +1,227 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | Copyright (C) 2018 OpenCFD Ltd.
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+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 .
+
+\*---------------------------------------------------------------------------*/
+
+#include "dataCloud.H"
+#include "Cloud.H"
+#include "dictionary.H"
+#include "fvMesh.H"
+#include "pointList.H"
+#include "OFstream.H"
+#include "addToRunTimeSelectionTable.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace functionObjects
+{
+ defineTypeNameAndDebug(dataCloud, 0);
+ addToRunTimeSelectionTable(functionObject, dataCloud, dictionary);
+}
+}
+
+// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
+
+bool Foam::functionObjects::dataCloud::writeCloud
+(
+ const fileName& outputName,
+ const word& cloudName
+)
+{
+ const auto* objPtr = mesh_.findObject(cloudName);
+ if (!objPtr)
+ {
+ return false;
+ }
+
+ objectRegistry obrTmp
+ (
+ IOobject
+ (
+ "tmp::dataCloud::" + cloudName,
+ mesh_.time().constant(),
+ mesh_,
+ IOobject::NO_READ,
+ IOobject::NO_WRITE,
+ false
+ )
+ );
+
+ objPtr->writeObjects(obrTmp);
+
+ const auto* pointsPtr = obrTmp.findObject("position");
+
+ if (!pointsPtr)
+ {
+ // This should be impossible
+ return false;
+ }
+
+ // Total number of parcels on all processes
+ label nTotParcels = pointsPtr->size();
+ reduce(nTotParcels, sumOp());
+
+ if (!nTotParcels)
+ {
+ return false;
+ }
+
+
+ if (Pstream::master())
+ {
+ mkDir(outputName.path());
+ }
+
+ return
+ (
+ writeField(outputName, obrTmp)
+ || writeField(outputName, obrTmp)
+ || writeField(outputName, obrTmp)
+ );
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
+
+Foam::functionObjects::dataCloud::dataCloud
+(
+ const word& name,
+ const Time& runTime,
+ const dictionary& dict
+)
+:
+ fvMeshFunctionObject(name, runTime, dict),
+ selectClouds_(),
+ fieldName_(),
+ directory_()
+{
+ read(dict);
+}
+
+
+// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
+
+bool Foam::functionObjects::dataCloud::read(const dictionary& dict)
+{
+ fvMeshFunctionObject::read(dict);
+
+ const int padWidth = dict.lookupOrDefault("width", 8);
+
+ // Appropriate printf format - Enforce min/max sanity limits
+ if (padWidth < 1 || padWidth > 31)
+ {
+ printf_.clear();
+ }
+ else
+ {
+ printf_ = "%0" + std::to_string(padWidth) + "d";
+ }
+
+
+ selectClouds_.clear();
+ dict.readIfPresent("clouds", selectClouds_);
+
+ if (selectClouds_.empty())
+ {
+ selectClouds_.resize(1);
+ selectClouds_.first() =
+ dict.lookupOrDefault("cloud", cloud::defaultName);
+ }
+
+ dict.readEntry("field", fieldName_);
+
+ // Output directory
+
+ directory_.clear();
+ dict.readIfPresent("directory", directory_);
+
+ if (directory_.size())
+ {
+ // User-defined output directory
+ directory_.expand();
+ if (!directory_.isAbsolute())
+ {
+ directory_ = time_.globalPath()/directory_;
+ }
+ }
+ else
+ {
+ // Standard postProcessing/ naming
+ directory_ = time_.globalPath()/functionObject::outputPrefix/name();
+ }
+ directory_.clean();
+
+ return true;
+}
+
+
+bool Foam::functionObjects::dataCloud::execute()
+{
+ return true;
+}
+
+
+bool Foam::functionObjects::dataCloud::write()
+{
+ const wordList cloudNames(mesh_.sortedNames(selectClouds_));
+
+ if (cloudNames.empty())
+ {
+ return true; // skip - not available
+ }
+
+ const word timeDesc = "_" +
+ (
+ printf_.empty()
+ ? Foam::name(time_.timeIndex())
+ : word::printf(printf_, time_.timeIndex())
+ );
+
+ Log << name() << " output Time: " << time_.timeName() << nl;
+
+ // Each cloud separately
+ for (const word& cloudName : cloudNames)
+ {
+ // Legacy is not to be supported
+
+ const fileName outputName
+ (
+ directory_/cloudName + timeDesc + ".dat"
+ );
+
+ // writeCloud() includes mkDir (on master)
+
+ if (writeCloud(outputName, cloudName))
+ {
+ Log << " cloud : "
+ << outputName.relative(time_.globalPath()) << endl;
+ }
+ }
+
+ return true;
+}
+
+
+// ************************************************************************* //
diff --git a/src/functionObjects/lagrangian/dataCloud/dataCloud.H b/src/functionObjects/lagrangian/dataCloud/dataCloud.H
new file mode 100644
index 0000000000..a1ef28b587
--- /dev/null
+++ b/src/functionObjects/lagrangian/dataCloud/dataCloud.H
@@ -0,0 +1,180 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | Copyright (C) 2018 OpenCFD Ltd.
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+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 .
+
+Class
+ Foam::functionObjects::dataCloud
+
+Group
+ grpLagrangianFunctionObjects
+
+Description
+ This functionObject writes a cloud position and in ASCII.
+
+ Example of function object specification:
+ \verbatim
+ cloudWrite1
+ {
+ type dataCloud;
+ libs ("liblagrangianFunctionObjects.so");
+ writeControl writeTime;
+ writeInterval 1;
+ cloud myCloud;
+ field d;
+ }
+ \endverbatim
+
+Usage
+ \table
+ Property | Description | Required | Default
+ type | Type name: dataCloud | yes |
+ cloud | | no | defaultCloud
+ clouds | wordRe list of clouds | no |
+ field | Name of the field | yes |
+ directory | The output directory name | no | postProcessing/NAME
+ width | Padding width for file name | no | 8
+ \endtable
+
+See also
+ Foam::functionObjects::vtkCloud
+
+SourceFiles
+ dataCloud.C
+ dataCloudTemplates.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef functionObjects_dataCloud_H
+#define functionObjects_dataCloud_H
+
+#include "fvMeshFunctionObject.H"
+#include "vectorField.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+namespace functionObjects
+{
+
+/*---------------------------------------------------------------------------*\
+ Class dataCloud Declaration
+\*---------------------------------------------------------------------------*/
+
+class dataCloud
+:
+ public fvMeshFunctionObject
+{
+ // Private data
+
+ //- The printf format for zero-padding names
+ string printf_;
+
+ //- Requested names of clouds to process
+ wordRes selectClouds_;
+
+ //- Subset of cloud fields to process
+ word fieldName_;
+
+ //- Output directory
+ fileName directory_;
+
+
+ // Private Member Functions
+
+ template
+ static void writeField
+ (
+ Ostream& os,
+ const vectorField& points,
+ const Field& field
+ );
+
+ //- Write to disk
+ bool writeCloud(const fileName& outputName, const word& cloudName);
+
+ //- Write from objectRegistry entry
+ template
+ bool writeField
+ (
+ const fileName& outputName,
+ const objectRegistry& obrTmp
+ ) const;
+
+
+ //- No copy construct
+ dataCloud(const dataCloud&) = delete;
+
+ //- No copy assignment
+ void operator=(const dataCloud&) = delete;
+
+
+public:
+
+ //- Runtime type information
+ TypeName("dataCloud");
+
+
+ // Constructors
+
+ //- Construct from Time and dictionary
+ dataCloud
+ (
+ const word& name,
+ const Time& runTime,
+ const dictionary& dict
+ );
+
+
+ //- Destructor
+ virtual ~dataCloud() = default;
+
+
+ // Member Functions
+
+ //- Read the dataCloud specification
+ virtual bool read(const dictionary& dict);
+
+ //- Execute, currently does nothing
+ virtual bool execute();
+
+ //- Write fields
+ virtual bool write();
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace functionObjects
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+ #include "dataCloudTemplates.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/src/functionObjects/lagrangian/dataCloud/dataCloudTemplates.C b/src/functionObjects/lagrangian/dataCloud/dataCloudTemplates.C
new file mode 100644
index 0000000000..c51033e9e5
--- /dev/null
+++ b/src/functionObjects/lagrangian/dataCloud/dataCloudTemplates.C
@@ -0,0 +1,130 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | Copyright (C) 2018 OpenCFD Ltd.
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+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 .
+
+\*---------------------------------------------------------------------------*/
+
+#include "IOField.H"
+#include "OFstream.H"
+#include "pointField.H"
+#include "vectorField.H"
+
+// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
+
+template
+void Foam::functionObjects::dataCloud::writeField
+(
+ Ostream& os,
+ const vectorField& points,
+ const Field& field
+)
+{
+ const label len = field.size();
+
+ for (label pointi=0; pointi::nComponents; ++cmpt)
+ {
+ os << ' ' << component(val, cmpt);
+ }
+ os << nl;
+ }
+}
+
+
+template
+bool Foam::functionObjects::dataCloud::writeField
+(
+ const fileName& outputName,
+ 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>(fieldName_);
+
+ if (!returnReduce((fldPtr != nullptr), orOp()))
+ {
+ return false;
+ }
+
+ const auto* pointsPtr = obrTmp.findObject("position");
+
+ if (!pointsPtr)
+ {
+ // This should be impossible
+ return false;
+ }
+
+ if (Pstream::master())
+ {
+ OFstream os(outputName);
+
+ os << "# x y z " << fieldName_ << nl;
+
+ // Master
+ if (fldPtr)
+ {
+ writeField(os, *pointsPtr, *fldPtr);
+ }
+
+ // Slaves - recv
+ for (int slave=1; slave fld(fromSlave);
+
+ writeField(os, points, fld);
+ }
+ }
+ else
+ {
+ // Slaves
+
+ OPstream toMaster(Pstream::commsTypes::blocking, Pstream::masterNo());
+
+ if (fldPtr)
+ {
+ toMaster
+ << *pointsPtr
+ << *fldPtr;
+ }
+ else
+ {
+ toMaster
+ << vectorField()
+ << Field();
+ }
+ }
+
+ return true;
+}
+
+
+// ************************************************************************* //
diff --git a/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/controlDict b/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/controlDict
index 20916ea29a..a2f5fcfc88 100644
--- a/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/controlDict
+++ b/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/controlDict
@@ -54,6 +54,7 @@ maxDeltaT 1;
functions
{
#include "vtkCloud"
+ // #include "dataCloud"
#include "runTimePostProcessing"
}
diff --git a/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/dataCloud b/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/dataCloud
new file mode 100644
index 0000000000..127d1ccf07
--- /dev/null
+++ b/tutorials/lagrangian/coalChemistryFoam/simplifiedSiwek/system/dataCloud
@@ -0,0 +1,13 @@
+// -*- C++ -*-
+// Minimal example of using the dataCloud function object.
+dataCloud
+{
+ type dataCloud;
+ libs ("liblagrangianFunctionObjects.so");
+ log true;
+
+ cloud coalCloud1;
+ field d;
+}
+
+// ************************************************************************* //