diff --git a/src/lagrangian/intermediate/parcels/include/makeParcelCloudFunctionObjects.H b/src/lagrangian/intermediate/parcels/include/makeParcelCloudFunctionObjects.H
index ed6c4f6bf95e21c263d23f90aeb2caba1ce0a842..7101579845a23ec60e3a4bf4507746f4814755e9 100644
--- a/src/lagrangian/intermediate/parcels/include/makeParcelCloudFunctionObjects.H
+++ b/src/lagrangian/intermediate/parcels/include/makeParcelCloudFunctionObjects.H
@@ -37,6 +37,7 @@ License
 #include "ParticleTracks.H"
 #include "ParticleTrap.H"
 #include "PatchCollisionDensity.H"
+#include "PatchInteractionFields.H"
 #include "PatchPostProcessing.H"
 #include "PatchParticleHistogram.H"
 #include "RemoveParcels.H"
@@ -54,6 +55,7 @@ License
     makeCloudFunctionObjectType(ParticleTracks, CloudType);                    \
     makeCloudFunctionObjectType(ParticleTrap, CloudType);                      \
     makeCloudFunctionObjectType(PatchCollisionDensity, CloudType);             \
+    makeCloudFunctionObjectType(PatchInteractionFields, CloudType);            \
     makeCloudFunctionObjectType(PatchPostProcessing, CloudType);               \
     makeCloudFunctionObjectType(PatchParticleHistogram, CloudType);            \
     makeCloudFunctionObjectType(RemoveParcels, CloudType);                     \
diff --git a/src/lagrangian/intermediate/parcels/include/makeReactingParcelCloudFunctionObjects.H b/src/lagrangian/intermediate/parcels/include/makeReactingParcelCloudFunctionObjects.H
index dd45507c68b131bcdcff2e4920fab76895c65d04..cd1eb439c9667ca0e4aacbd9426795ceb0eb5f20 100644
--- a/src/lagrangian/intermediate/parcels/include/makeReactingParcelCloudFunctionObjects.H
+++ b/src/lagrangian/intermediate/parcels/include/makeReactingParcelCloudFunctionObjects.H
@@ -37,6 +37,7 @@ License
 #include "ParticleTracks.H"
 #include "ParticleTrap.H"
 #include "PatchCollisionDensity.H"
+#include "PatchInteractionFields.H"
 #include "PatchPostProcessing.H"
 #include "PatchParticleHistogram.H"
 #include "RemoveParcels.H"
@@ -55,6 +56,7 @@ License
     makeCloudFunctionObjectType(ParticleTracks, CloudType);                    \
     makeCloudFunctionObjectType(ParticleTrap, CloudType);                      \
     makeCloudFunctionObjectType(PatchCollisionDensity, CloudType);             \
+    makeCloudFunctionObjectType(PatchInteractionFields, CloudType);            \
     makeCloudFunctionObjectType(PatchPostProcessing, CloudType);               \
     makeCloudFunctionObjectType(PatchParticleHistogram, CloudType);            \
     makeCloudFunctionObjectType(RemoveParcels, CloudType);                     \
diff --git a/src/lagrangian/intermediate/submodels/CloudFunctionObjects/PatchInteractionFields/PatchInteractionFields.C b/src/lagrangian/intermediate/submodels/CloudFunctionObjects/PatchInteractionFields/PatchInteractionFields.C
new file mode 100644
index 0000000000000000000000000000000000000000..47ef0e92ac2adb7c84b2844468bbb8ac916b49ae
--- /dev/null
+++ b/src/lagrangian/intermediate/submodels/CloudFunctionObjects/PatchInteractionFields/PatchInteractionFields.C
@@ -0,0 +1,188 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2020 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 "PatchInteractionFields.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+template<class CloudType>
+const Foam::Enum<typename Foam::PatchInteractionFields<CloudType>::resetMode>
+Foam::PatchInteractionFields<CloudType>::resetModeNames_
+({
+    { resetMode::none, "none" },
+    { resetMode::timeStep, "timeStep" },
+    { resetMode::writeTime, "writeTime" },
+});
+
+// * * * * * * * * * * * * * Protected Member Functions  * * * * * * * * * * //
+
+template<class CloudType>
+void Foam::PatchInteractionFields<CloudType>::clearOrReset
+(
+    autoPtr<volScalarField>& fieldPtr,
+    const word& fieldName,
+    const dimensionSet& dims
+) const
+{
+    if (fieldPtr)
+    {
+        fieldPtr->primitiveFieldRef() = 0.0;
+    }
+    else
+    {
+        const fvMesh& mesh = this->owner().mesh();
+
+        fieldPtr.reset
+        (
+            new volScalarField
+            (
+                IOobject
+                (
+                    this->owner().name() + ":" + this->modelName() + ":" + fieldName,
+                    mesh.time().timeName(),
+                    mesh,
+                    IOobject::READ_IF_PRESENT,
+                    IOobject::NO_WRITE
+                ),
+                mesh,
+                dimensionedScalar(dims, Zero)
+            )
+        );
+    }
+}
+
+
+template<class CloudType>
+void Foam::PatchInteractionFields<CloudType>::reset()
+{
+    clearOrReset(massPtr_, "mass", dimMass);
+    clearOrReset(countPtr_, "count", dimless);
+}
+
+
+template<class CloudType>
+void Foam::PatchInteractionFields<CloudType>::write()
+{
+    if (massPtr_)
+    {
+        massPtr_->write();
+    }
+    else
+    {
+        FatalErrorInFunction
+            << "massPtr not valid" << abort(FatalError);
+    }
+
+    if (countPtr_)
+    {
+        countPtr_->write();
+    }
+    else
+    {
+        FatalErrorInFunction
+            << "countPtr not valid" << abort(FatalError);
+    }
+
+    if (resetMode_ == resetMode::writeTime)
+    {
+        reset();
+    }
+}
+
+
+// * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
+
+template<class CloudType>
+Foam::PatchInteractionFields<CloudType>::PatchInteractionFields
+(
+    const dictionary& dict,
+    CloudType& owner,
+    const word& modelName
+)
+:
+    CloudFunctionObject<CloudType>(dict, owner, modelName, typeName),
+    massPtr_(nullptr),
+    countPtr_(nullptr),
+    resetMode_
+    (
+        resetModeNames_.getOrDefault
+        (
+            "resetMode",
+            this->coeffDict(),
+            resetMode::none
+        )
+    )
+{
+    reset();
+}
+
+
+template<class CloudType>
+Foam::PatchInteractionFields<CloudType>::PatchInteractionFields
+(
+    const PatchInteractionFields<CloudType>& pii
+)
+:
+    CloudFunctionObject<CloudType>(pii),
+    massPtr_(nullptr),
+    countPtr_(nullptr),
+    resetMode_(pii.resetMode_)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
+
+template<class CloudType>
+void Foam::PatchInteractionFields<CloudType>::preEvolve
+(
+    const typename parcelType::trackingData&
+)
+{
+    if (resetMode_ == resetMode::timeStep)
+    {
+        reset();
+    }
+}
+
+
+template<class CloudType>
+void Foam::PatchInteractionFields<CloudType>::postPatch
+(
+    const parcelType& p,
+    const polyPatch& pp,
+    bool&
+)
+{
+    const label patchi = pp.index();
+    const label facei = pp.whichFace(p.face());
+
+    massPtr_->boundaryFieldRef()[patchi][facei] += p.nParticle()*p.mass();
+    countPtr_->boundaryFieldRef()[patchi][facei] += 1;
+}
+
+
+// ************************************************************************* //
diff --git a/src/lagrangian/intermediate/submodels/CloudFunctionObjects/PatchInteractionFields/PatchInteractionFields.H b/src/lagrangian/intermediate/submodels/CloudFunctionObjects/PatchInteractionFields/PatchInteractionFields.H
new file mode 100644
index 0000000000000000000000000000000000000000..9b84a0437129d6080215f10b2728df56b48d7af0
--- /dev/null
+++ b/src/lagrangian/intermediate/submodels/CloudFunctionObjects/PatchInteractionFields/PatchInteractionFields.H
@@ -0,0 +1,199 @@
+/*---------------------------------------------------------------------------*\
+  =========                 |
+  \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
+   \\    /   O peration     |
+    \\  /    A nd           | www.openfoam.com
+     \\/     M anipulation  |
+-------------------------------------------------------------------------------
+    Copyright (C) 2020 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::PatchInteractionFields
+
+Group
+    grpLagrangianIntermediateFunctionObjects
+
+Description
+    Creates volume fields whose boundaries are used to store patch interaction
+    statistics.
+
+    Current field output per patch face:
+    - \<cloud\>\<model\>:count - cumulative particle hits
+    - \<cloud\>\<model\>:mass - cumulative mass of hitting particles
+
+    Fields can be reset according to:
+    - none: fields are not reset
+    - timeStep: reset at each time step
+    - writeTime: reset at each write time
+
+Usage
+
+    \verbatim
+    patchInteractionFields1
+    {
+        type            patchInteractionFields;
+        resetMode       writeTime;
+    }
+    \endverbatim
+
+SourceFiles
+    PatchInteractionFields.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef PatchInteractionFields_H
+#define PatchInteractionFields_H
+
+#include "CloudFunctionObject.H"
+#include "volFields.H"
+#include "Enum.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+                   Class PatchInteractionFields Declaration
+\*---------------------------------------------------------------------------*/
+
+template<class CloudType>
+class PatchInteractionFields
+:
+    public CloudFunctionObject<CloudType>
+{
+public:
+
+    // Public enumerations
+
+        //- Reset mode
+        enum class resetMode
+        {
+            none,
+            timeStep,
+            writeTime
+        };
+
+        static const Enum<resetMode> resetModeNames_;
+
+
+private:
+
+    // Private Data
+
+        //- Convenience typedef for parcel type
+        typedef typename CloudType::parcelType parcelType;
+
+        //- Parcel mass field
+        autoPtr<volScalarField> massPtr_;
+
+        //- Parcel count field
+        autoPtr<volScalarField> countPtr_;
+
+        //- Reset mode
+        resetMode resetMode_;
+
+
+protected:
+
+    // Protected Member Functions
+
+        //- Create|read|reset the fields
+        void reset();
+
+        //- Write post-processing info
+        virtual void write();
+
+        //- Helper function to clear or reset fields
+        void clearOrReset
+        (
+            autoPtr<volScalarField>& fieldPtr,
+            const word& fieldName,
+            const dimensionSet& dims
+        ) const;
+
+
+public:
+
+    //- Runtime type information
+    TypeName("patchInteractionFields");
+
+
+    // Constructors
+
+        //- Construct from dictionary
+        PatchInteractionFields
+        (
+            const dictionary& dict,
+            CloudType& owner,
+            const word& modelName
+        );
+
+        //- Construct copy
+        PatchInteractionFields(const PatchInteractionFields<CloudType>& pii);
+
+        //- Construct and return a clone
+        virtual autoPtr<CloudFunctionObject<CloudType>> clone() const
+        {
+            return autoPtr<CloudFunctionObject<CloudType>>
+            (
+                new PatchInteractionFields<CloudType>(*this)
+            );
+        }
+
+
+    //- Destructor
+    virtual ~PatchInteractionFields() = default;
+
+
+    // Member Functions
+
+        // Evaluation
+
+            //- Pre-evolve hook
+            virtual void preEvolve
+            (
+                const typename parcelType::trackingData& td
+            );
+
+            //- Post-patch hook
+            virtual void postPatch
+            (
+                const parcelType& p,
+                const polyPatch& pp,
+                bool& keepParticle
+            );
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#ifdef NoRepository
+    #include "PatchInteractionFields.C"
+#endif
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //
diff --git a/tutorials/lagrangian/reactingParcelFoam/filter/constant/reactingCloud1Properties b/tutorials/lagrangian/reactingParcelFoam/filter/constant/reactingCloud1Properties
index bbda9f138c2f6c68d5620e8870be403fad0b58b3..6141c2c3107fb219934565db6b6fc307798c71fc 100644
--- a/tutorials/lagrangian/reactingParcelFoam/filter/constant/reactingCloud1Properties
+++ b/tutorials/lagrangian/reactingParcelFoam/filter/constant/reactingCloud1Properties
@@ -199,6 +199,12 @@ cloudFunctions
             cycLeft
         );
     }
+
+    patchInteractionFields1
+    {
+        type            patchInteractionFields;
+        resetMode       writeTime;
+    }
 }