diff --git a/src/phaseSystemModels/multiphaseInter/phasesSystem/Make/files b/src/phaseSystemModels/multiphaseInter/phasesSystem/Make/files
index ce9bf08878..37df8ee1b4 100644
--- a/src/phaseSystemModels/multiphaseInter/phasesSystem/Make/files
+++ b/src/phaseSystemModels/multiphaseInter/phasesSystem/Make/files
@@ -25,4 +25,6 @@ $(surfaceTension)/surfaceTensionModel/surfaceTensionModel.C
$(surfaceTension)/constantSurfaceTensionCoefficient/constantSurfaceTensionCoefficient.C
*/
+derivedFvPatchFields/timeVaryingMassSorption/timeVaryingMassSorptionFvPatchScalarField.C
+
LIB = $(FOAM_LIBBIN)/libincompressibleMultiphaseSystems
diff --git a/src/phaseSystemModels/multiphaseInter/phasesSystem/derivedFvPatchFields/timeVaryingMassSorption/timeVaryingMassSorptionFvPatchScalarField.C b/src/phaseSystemModels/multiphaseInter/phasesSystem/derivedFvPatchFields/timeVaryingMassSorption/timeVaryingMassSorptionFvPatchScalarField.C
new file mode 100644
index 0000000000..a57d9ebf09
--- /dev/null
+++ b/src/phaseSystemModels/multiphaseInter/phasesSystem/derivedFvPatchFields/timeVaryingMassSorption/timeVaryingMassSorptionFvPatchScalarField.C
@@ -0,0 +1,282 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | www.openfoam.com
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+ Copyright (C) 2021 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 .
+
+\*---------------------------------------------------------------------------*/
+
+#include "timeVaryingMassSorptionFvPatchScalarField.H"
+#include "addToRunTimeSelectionTable.H"
+#include "fvPatchFieldMapper.H"
+#include "volFields.H"
+#include "EulerDdtScheme.H"
+#include "CrankNicolsonDdtScheme.H"
+#include "backwardDdtScheme.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+const Foam::Enum
+<
+ Foam::timeVaryingMassSorptionFvPatchScalarField::ddtSchemeType
+>
+Foam::timeVaryingMassSorptionFvPatchScalarField::ddtSchemeTypeNames_
+({
+ {
+ ddtSchemeType::tsEuler,
+ fv::EulerDdtScheme::typeName_()
+ },
+ {
+ ddtSchemeType::tsCrankNicolson,
+ fv::CrankNicolsonDdtScheme::typeName_()
+ },
+ {
+ ddtSchemeType::tsBackward,
+ fv::backwardDdtScheme::typeName_()
+ },
+});
+
+
+// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
+
+Foam::timeVaryingMassSorptionFvPatchScalarField::
+timeVaryingMassSorptionFvPatchScalarField
+(
+ const fvPatch& p,
+ const DimensionedField& iF
+)
+:
+ fixedValueFvPatchScalarField(p, iF),
+ kabs_(scalar(1)),
+ max_(scalar(1)),
+ kdes_(scalar(1))
+{}
+
+
+Foam::timeVaryingMassSorptionFvPatchScalarField::
+timeVaryingMassSorptionFvPatchScalarField
+(
+ const fvPatch& p,
+ const DimensionedField& iF,
+ const dictionary& dict
+)
+:
+ fixedValueFvPatchScalarField(p, iF, dict, false),
+ kabs_(dict.getCheck("kabs", scalarMinMax::ge(0))),
+ max_(dict.getCheck("max", scalarMinMax::ge(0))),
+ kdes_(dict.getCheckOrDefault("kdes", 0, scalarMinMax::ge(0)))
+{
+ if (dict.found("value"))
+ {
+ fvPatchScalarField::operator=
+ (
+ scalarField("value", dict, p.size())
+ );
+ }
+ else
+ {
+ fvPatchField::operator=(Zero);
+ }
+}
+
+
+Foam::timeVaryingMassSorptionFvPatchScalarField::
+timeVaryingMassSorptionFvPatchScalarField
+(
+ const timeVaryingMassSorptionFvPatchScalarField& ptf,
+ const fvPatch& p,
+ const DimensionedField& iF,
+ const fvPatchFieldMapper& mapper
+)
+:
+ fixedValueFvPatchScalarField(ptf, p, iF, mapper),
+ kabs_(ptf.kabs_),
+ max_(ptf.max_),
+ kdes_(ptf.kdes_)
+{}
+
+
+Foam::timeVaryingMassSorptionFvPatchScalarField::
+timeVaryingMassSorptionFvPatchScalarField
+(
+ const timeVaryingMassSorptionFvPatchScalarField& ptf
+)
+:
+ fixedValueFvPatchScalarField(ptf),
+ kabs_(ptf.kabs_),
+ max_(ptf.max_),
+ kdes_(ptf.kdes_)
+{}
+
+
+Foam::timeVaryingMassSorptionFvPatchScalarField::
+timeVaryingMassSorptionFvPatchScalarField
+(
+ const timeVaryingMassSorptionFvPatchScalarField& ptf,
+ const DimensionedField& iF
+)
+:
+ fixedValueFvPatchScalarField(ptf, iF),
+ kabs_(ptf.kabs_),
+ max_(ptf.max_),
+ kdes_(ptf.kdes_)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
+
+void Foam::timeVaryingMassSorptionFvPatchScalarField::autoMap
+(
+ const fvPatchFieldMapper& m
+)
+{
+ fixedValueFvPatchScalarField::autoMap(m);
+}
+
+
+void Foam::timeVaryingMassSorptionFvPatchScalarField::rmap
+(
+ const fvPatchScalarField& ptf,
+ const labelList& addr
+)
+{
+ fixedValueFvPatchScalarField::rmap(ptf, addr);
+}
+
+
+Foam::tmp
+Foam::timeVaryingMassSorptionFvPatchScalarField::source() const
+{
+ auto tsource = tmp::New(patch().size(), Zero);
+ auto& source = tsource.ref();
+
+ const scalarField cp(*this);
+ const scalarField w(max(1 - cp/max_, scalar(0)));
+
+ source = -kabs_*w*max(patchInternalField() - cp, scalar(0));
+
+ source += kdes_*max(cp - patchInternalField(), scalar(0));
+
+ return tsource;
+}
+
+
+void Foam::timeVaryingMassSorptionFvPatchScalarField::updateCoeffs()
+{
+ if (updated())
+ {
+ return;
+ }
+
+ const label patchi = patch().index();
+
+ const scalar dt = db().time().deltaTValue();
+
+ const auto& fld =
+ db().lookupObject(this->internalField().name());
+ const volScalarField& fld0 = fld.oldTime();
+
+ // Lookup d/dt scheme from database
+ const word ddtSchemeName(fld.mesh().ddtScheme(fld.name()));
+ const ddtSchemeType& ddtScheme = ddtSchemeTypeNames_[ddtSchemeName];
+
+ const scalarField cp(*this);
+ const scalarField w(max(1 - cp/max_, scalar(0)));
+
+ tmp dfldp =
+ kabs_
+ *w
+ *max(patchInternalField() - cp, scalar(0))
+ *dt;
+
+ dfldp.ref() -=
+ kdes_
+ *max(cp - patchInternalField(), scalar(0))
+ *dt;
+
+ switch (ddtScheme)
+ {
+ case tsEuler:
+ case tsCrankNicolson:
+ {
+ operator==(fld0.boundaryField()[patchi] + dfldp);
+
+ break;
+ }
+ case tsBackward:
+ {
+ const scalar dt0 = db().time().deltaT0Value();
+
+ const scalar c = scalar(1) + dt/(dt + dt0);
+ const scalar c00 = dt*dt/(dt0*(dt + dt0));
+ const scalar c0 = c + c00;
+
+ operator==
+ (
+ (
+ c0*fld0.boundaryField()[patchi]
+ - c00*fld0.oldTime().boundaryField()[patchi]
+ + dfldp
+ )/c
+ );
+
+ break;
+ }
+ default:
+ {
+ FatalErrorInFunction
+ << ddtSchemeName << nl
+ << " on patch " << this->patch().name()
+ << " of field " << this->internalField().name()
+ << " in file " << this->internalField().objectPath()
+ << exit(FatalError);
+ }
+ }
+
+ fixedValueFvPatchScalarField::updateCoeffs();
+}
+
+
+void Foam::timeVaryingMassSorptionFvPatchScalarField::write(Ostream& os) const
+{
+ fvPatchScalarField::write(os);
+
+ os.writeEntry("kabs", kabs_);
+ os.writeEntry("max", max_);
+ os.writeEntryIfDifferent("kdes", scalar(0), kdes_);
+
+ writeEntry("value", os);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+ makePatchTypeField
+ (
+ fvPatchScalarField,
+ timeVaryingMassSorptionFvPatchScalarField
+ );
+}
+
+// ************************************************************************* //
diff --git a/src/phaseSystemModels/multiphaseInter/phasesSystem/derivedFvPatchFields/timeVaryingMassSorption/timeVaryingMassSorptionFvPatchScalarField.H b/src/phaseSystemModels/multiphaseInter/phasesSystem/derivedFvPatchFields/timeVaryingMassSorption/timeVaryingMassSorptionFvPatchScalarField.H
new file mode 100644
index 0000000000..0a8a3d753e
--- /dev/null
+++ b/src/phaseSystemModels/multiphaseInter/phasesSystem/derivedFvPatchFields/timeVaryingMassSorption/timeVaryingMassSorptionFvPatchScalarField.H
@@ -0,0 +1,249 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | www.openfoam.com
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+ Copyright (C) 2021 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 .
+
+Class
+ Foam::timeVaryingMassSorptionFvPatchScalarField
+
+Group
+ grpGenericBoundaryConditions
+
+Description
+ This boundary condition provides a first order fixed-value condition
+ for a given scalar field to model time-dependent adsorption-desoprtion
+ processes to be used with the \c interfaceOxideRate mass model
+
+ \f[
+ \frac{d c}{d t} =
+ k_{abs} w (c_{int} - c_{p_{w}}) + k_{des} (c_{p_{w} - c_{int}})
+ \f]
+
+ \f[
+ w = max(1 - c_{p_{w}/max, 0);
+ \f]
+
+ where
+ \vartable
+ c_{int} | Concentration at cell
+ c_{p_{w}} | Concentration at wall
+ k_{abs} | Adsorption rate constant [1/s]
+ k_{des} | Desorption rate constant [1/s]
+ w | Weight function
+ max | Max concentration at wall
+ \endvartable
+
+Usage
+ Example of the boundary condition specification:
+ \verbatim
+
+ {
+ // Mandatory entries
+ type timeVaryingMassSorption;
+ kbas ;
+ max ;
+
+ // Optional entries
+ kdes ;
+
+ // Inherited entries
+ ...
+ }
+ \endverbatim
+
+ where the entries mean:
+ \table
+ Property | Description | Type | Reqd | Deflt
+ type | Type name: timeVaryingAdsorption | word | yes | -
+ kbas | Adsorption rate constant | scalar | yes | -
+ max | Maximum concentation at wall | scalar | yes | -
+ kdes | Desorption rate constant | scalar | no | 0
+ \endtable
+
+ The inherited entries are elaborated in:
+ - \link fixedValueFvPatchFields.H \endlink
+
+SourceFiles
+ timeVaryingMassSorptionFvPatchScalarField.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef timeVaryingMassSorptionFvPatchScalarField_H
+#define timeVaryingMassSorptionFvPatchScalarField_H
+
+#include "fixedValueFvPatchFields.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+ Class timeVaryingMassSorptionFvPatchScalarField Declaration
+\*---------------------------------------------------------------------------*/
+
+class timeVaryingMassSorptionFvPatchScalarField
+:
+ public fixedValueFvPatchScalarField
+{
+public:
+
+ // Public Enumeration
+
+ //- Enumeration defining the available ddt schemes
+ enum ddtSchemeType
+ {
+ tsEuler,
+ tsCrankNicolson,
+ tsBackward
+ };
+
+
+private:
+
+ // Private Data
+
+ //- Time scheme type names
+ static const Enum ddtSchemeTypeNames_;
+
+ //- Adsorption rate constant
+ scalar kabs_;
+
+ //- Maximum level of adsorption of a given substance on patch
+ scalar max_;
+
+ //- Desorption rate constant
+ scalar kdes_;
+
+
+public:
+
+ //- Runtime type information
+ TypeName("timeVaryingMassSorption");
+
+
+ // Constructors
+
+ //- Construct from patch and internal field
+ timeVaryingMassSorptionFvPatchScalarField
+ (
+ const fvPatch&,
+ const DimensionedField&
+ );
+
+ //- Construct from patch, internal field and dictionary
+ timeVaryingMassSorptionFvPatchScalarField
+ (
+ const fvPatch&,
+ const DimensionedField&,
+ const dictionary&
+ );
+
+ //- Construct by mapping given
+ //- timeVaryingMassSorptionFvPatchScalarField onto a new patch
+ timeVaryingMassSorptionFvPatchScalarField
+ (
+ const timeVaryingMassSorptionFvPatchScalarField&,
+ const fvPatch&,
+ const DimensionedField&,
+ const fvPatchFieldMapper&
+ );
+
+ //- Construct as copy
+ timeVaryingMassSorptionFvPatchScalarField
+ (
+ const timeVaryingMassSorptionFvPatchScalarField&
+ );
+
+ //- Construct and return a clone
+ virtual tmp clone() const
+ {
+ return tmp
+ (
+ new timeVaryingMassSorptionFvPatchScalarField(*this)
+ );
+ }
+
+ //- Construct as copy setting internal field reference
+ timeVaryingMassSorptionFvPatchScalarField
+ (
+ const timeVaryingMassSorptionFvPatchScalarField&,
+ const DimensionedField&
+ );
+
+ //- Construct and return a clone setting internal field reference
+ virtual tmp clone
+ (
+ const DimensionedField& iF
+ ) const
+ {
+ return tmp
+ (
+ new timeVaryingMassSorptionFvPatchScalarField(*this, iF)
+ );
+ }
+
+
+ // Member Functions
+
+ // Mapping
+
+ //- Map (and resize as needed) from self given a mapping object
+ virtual void autoMap
+ (
+ const fvPatchFieldMapper&
+ );
+
+ //- Reverse map the given fvPatchField onto this fvPatchField
+ virtual void rmap
+ (
+ const fvPatchScalarField&,
+ const labelList&
+ );
+
+ // Help
+
+ //- Return source rate
+ tmp source() const;
+
+
+ // Evaluation
+
+ //- Update the coefficients associated with the patch field
+ virtual void updateCoeffs();
+
+
+ //- Write
+ virtual void write(Ostream&) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //