diff --git a/src/functionObjects/lagrangian/Make/files b/src/functionObjects/lagrangian/Make/files
index c7feb02e33..8a65315b9a 100644
--- a/src/functionObjects/lagrangian/Make/files
+++ b/src/functionObjects/lagrangian/Make/files
@@ -4,5 +4,6 @@ icoUncoupledKinematicCloud/icoUncoupledKinematicCloud.C
dsmcFields/dsmcFields.C
vtkCloud/vtkCloud.C
+vtkCloud/parcelSelectionDetail.C
LIB = $(FOAM_LIBBIN)/liblagrangianFunctionObjects
diff --git a/src/functionObjects/lagrangian/vtkCloud/parcelSelectionDetail.C b/src/functionObjects/lagrangian/vtkCloud/parcelSelectionDetail.C
new file mode 100644
index 0000000000..d436f7f938
--- /dev/null
+++ b/src/functionObjects/lagrangian/vtkCloud/parcelSelectionDetail.C
@@ -0,0 +1,416 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / 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 "parcelSelectionDetail.H"
+#include "scalarPredicates.H"
+#include "labelField.H"
+#include "scalarField.H"
+#include "pointField.H"
+#include "ListListOps.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+const Foam::Enum
+<
+ Foam::Detail::parcelSelection::actionType
+>
+Foam::Detail::parcelSelection::actionNames
+({
+ { actionType::ALL, "all" },
+ { actionType::CLEAR, "clear" },
+ { actionType::INVERT, "invert" },
+ { actionType::ADD, "add" },
+ { actionType::SUBTRACT, "subtract" },
+ { actionType::SUBSET, "subset" },
+ { actionType::IGNORE, "ignore" },
+});
+
+
+const Foam::Enum
+<
+ Foam::Detail::parcelSelection::sourceType
+>
+Foam::Detail::parcelSelection::sourceNames
+({
+ { sourceType::FIELD, "field" },
+ { sourceType::STRIDE, "stride" },
+});
+
+
+const Foam::Enum
+<
+ Foam::Detail::parcelSelection::logicType
+> Foam::Detail::parcelSelection::logicNames
+({
+ { logicType::AND, "and" },
+ { logicType::OR, "or" },
+});
+
+
+// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+ template
+ static void apply
+ (
+ bitSet& selection,
+ const Detail::parcelSelection::actionType action,
+ const Predicate& accept,
+ const UList& list,
+ const AccessOp& aop
+ )
+ {
+ using actionType = Detail::parcelSelection::actionType;
+
+ const label len = selection.size();
+
+ switch (action)
+ {
+ case actionType::ADD:
+ {
+ for (label parceli = 0; parceli < len; ++parceli)
+ {
+ if (accept(aop(list[parceli])))
+ {
+ selection.set(parceli);
+ }
+ }
+ }
+ break;
+
+ case actionType::SUBTRACT:
+ {
+ for (label parceli = 0; parceli < len; ++parceli)
+ {
+ if (accept(aop(list[parceli])))
+ {
+ selection.unset(parceli);
+ }
+ }
+ }
+ break;
+
+ case actionType::SUBSET:
+ {
+ for (const label parceli : selection)
+ {
+ if (!accept(aop(list[parceli])))
+ {
+ selection.unset(parceli);
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+} // End namespace Foam
+
+
+// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
+
+Foam::Detail::parcelSelection::parcelSelection()
+:
+ parcelSelect_(),
+ parcelAddr_()
+{}
+
+
+// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
+
+bool Foam::Detail::parcelSelection::calculateFilter
+(
+ const objectRegistry& obrTmp,
+ const bool log
+)
+{
+ if (parcelSelect_.empty())
+ {
+ parcelAddr_.clear();
+ return false;
+ }
+
+ // Start with all parcels unselected
+
+ // Number of parcels (locally)
+ const auto* pointsPtr = obrTmp.findObject("position");
+ label nParcels = pointsPtr->size();
+
+ parcelAddr_.reset();
+ parcelAddr_.resize(nParcels);
+
+ reduce(nParcels, sumOp