diff --git a/src/thermophysicalModels/reactionThermo/Make/files b/src/thermophysicalModels/reactionThermo/Make/files
index f72e0ff4a6..1778902590 100644
--- a/src/thermophysicalModels/reactionThermo/Make/files
+++ b/src/thermophysicalModels/reactionThermo/Make/files
@@ -19,6 +19,7 @@ derivedFvPatchFields/fixedUnburntEnthalpy/fixedUnburntEnthalpyFvPatchScalarField
derivedFvPatchFields/gradientUnburntEnthalpy/gradientUnburntEnthalpyFvPatchScalarField.C
derivedFvPatchFields/mixedUnburntEnthalpy/mixedUnburntEnthalpyFvPatchScalarField.C
derivedFvPatchFields/speciesSorption/speciesSorptionFvPatchScalarField.C
+derivedFvPatchFields/enthalpySorption/enthalpySorptionFvPatchScalarField.C
derivedFvPatchFields/boundarySourcePatch/boundarySourcePatch.C
functionObjects/moleFractions/moleFractionsFunctionObjects.C
diff --git a/src/thermophysicalModels/reactionThermo/derivedFvPatchFields/enthalpySorption/enthalpySorptionFvPatchScalarField.C b/src/thermophysicalModels/reactionThermo/derivedFvPatchFields/enthalpySorption/enthalpySorptionFvPatchScalarField.C
new file mode 100644
index 0000000000..694dc96d98
--- /dev/null
+++ b/src/thermophysicalModels/reactionThermo/derivedFvPatchFields/enthalpySorption/enthalpySorptionFvPatchScalarField.C
@@ -0,0 +1,350 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | www.openfoam.com
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+ Copyright (C) 2022 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 "enthalpySorptionFvPatchScalarField.H"
+#include "addToRunTimeSelectionTable.H"
+#include "fvPatchFieldMapper.H"
+#include "volFields.H"
+#include "rhoReactionThermo.H"
+#include "speciesSorptionFvPatchScalarField.H"
+
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+const Foam::Enum
+<
+ Foam::enthalpySorptionFvPatchScalarField::enthalpyModelType
+>
+Foam::enthalpySorptionFvPatchScalarField::enthalpyModelTypeNames
+({
+ { enthalpyModelType::estimated, "estimated" },
+ { enthalpyModelType::calculated, "calculated" }
+});
+
+
+// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
+
+Foam::enthalpySorptionFvPatchScalarField::enthalpySorptionFvPatchScalarField
+(
+ const fvPatch& p,
+ const DimensionedField& iF
+)
+:
+ zeroGradientFvPatchScalarField(p, iF),
+ enthalpyModel_(enthalpyModelType::estimated),
+ includeHs_(false),
+ enthalpyMassLoadPtr_(nullptr),
+ C_(0),
+ Hvap_(0),
+ speciesName_("none"),
+ pName_("p"),
+ TName_("T"),
+ dhdt_(p.size(), 0)
+{}
+
+
+Foam::enthalpySorptionFvPatchScalarField::enthalpySorptionFvPatchScalarField
+(
+ const fvPatch& p,
+ const DimensionedField& iF,
+ const dictionary& dict
+)
+:
+ zeroGradientFvPatchScalarField(p, iF, dict),
+ enthalpyModel_(enthalpyModelTypeNames.get("enthalpyModel", dict)),
+ includeHs_(dict.getOrDefault("includeHs", true)),
+ enthalpyMassLoadPtr_(nullptr),
+ C_(dict.getCheckOrDefault("C", 0, scalarMinMax::ge(0))),
+ Hvap_(dict.getCheckOrDefault("Hvap", 0, scalarMinMax::ge(0))),
+ speciesName_(dict.get("species")),
+ pName_(dict.getOrDefault("p", "p")),
+ TName_(dict.getOrDefault("T", "T")),
+ dhdt_
+ (
+ dict.found("dhdt")
+ ? scalarField("dhdt", dict, p.size())
+ : scalarField(p.size(), 0)
+ )
+{
+ switch (enthalpyModel_)
+ {
+ case enthalpyModelType::calculated:
+ {
+ enthalpyMassLoadPtr_ =
+ Function1::New("enthalpyTable", dict);
+ break;
+ }
+ case enthalpyModelType::estimated:
+ {
+ break;
+ }
+ }
+
+ if (dict.found("value"))
+ {
+ fvPatchScalarField::operator=
+ (
+ scalarField("value", dict, p.size())
+ );
+ }
+ else
+ {
+ fvPatchField::operator=(Zero);
+ }
+}
+
+
+Foam::enthalpySorptionFvPatchScalarField::enthalpySorptionFvPatchScalarField
+(
+ const enthalpySorptionFvPatchScalarField& ptf,
+ const fvPatch& p,
+ const DimensionedField& iF,
+ const fvPatchFieldMapper& mapper
+)
+:
+ zeroGradientFvPatchScalarField(ptf, p, iF, mapper),
+ enthalpyModel_(ptf.enthalpyModel_),
+ includeHs_(ptf.includeHs_),
+ enthalpyMassLoadPtr_(ptf.enthalpyMassLoadPtr_.clone()),
+ C_(ptf.C_),
+ Hvap_(ptf.Hvap_),
+ speciesName_(ptf.speciesName_),
+ pName_(ptf.pName_),
+ TName_(ptf.TName_),
+ dhdt_(ptf.dhdt_, mapper)
+{}
+
+
+Foam::enthalpySorptionFvPatchScalarField::enthalpySorptionFvPatchScalarField
+(
+ const enthalpySorptionFvPatchScalarField& ptf
+)
+:
+ zeroGradientFvPatchScalarField(ptf),
+ enthalpyModel_(ptf.enthalpyModel_),
+ includeHs_(ptf.includeHs_),
+ enthalpyMassLoadPtr_(ptf.enthalpyMassLoadPtr_.clone()),
+ C_(ptf.C_),
+ Hvap_(ptf.Hvap_),
+ speciesName_(ptf.speciesName_),
+ pName_(ptf.pName_),
+ TName_(ptf.TName_),
+ dhdt_(ptf.dhdt_)
+{}
+
+
+Foam::enthalpySorptionFvPatchScalarField::enthalpySorptionFvPatchScalarField
+(
+ const enthalpySorptionFvPatchScalarField& ptf,
+ const DimensionedField& iF
+)
+:
+ zeroGradientFvPatchScalarField(ptf, iF),
+ enthalpyModel_(ptf.enthalpyModel_),
+ includeHs_(ptf.includeHs_),
+ enthalpyMassLoadPtr_(ptf.enthalpyMassLoadPtr_.clone()),
+ C_(ptf.C_),
+ Hvap_(ptf.Hvap_),
+ speciesName_(ptf.speciesName_),
+ pName_(ptf.pName_),
+ TName_(ptf.TName_),
+ dhdt_(ptf.dhdt_)
+{}
+
+
+// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
+
+void Foam::enthalpySorptionFvPatchScalarField::autoMap
+(
+ const fvPatchFieldMapper& m
+)
+{
+ zeroGradientFvPatchScalarField::autoMap(m);
+
+ dhdt_.autoMap(m);
+}
+
+
+void Foam::enthalpySorptionFvPatchScalarField::rmap
+(
+ const fvPatchScalarField& ptf,
+ const labelList& addr
+)
+{
+ zeroGradientFvPatchScalarField::rmap(ptf, addr);
+
+ const auto& tiptf = refCast(ptf);
+
+ dhdt_.rmap(tiptf.dhdt_, addr);
+}
+
+
+Foam::tmp Foam::enthalpySorptionFvPatchScalarField::
+patchSource() const
+{
+ const auto& Yp =
+ refCast
+ (
+ patch().lookupPatchField
+ (
+ speciesName_
+ )
+ );
+
+ // mass rate [kg/sec/m3]
+ tmp tmassb = Yp.patchSource();
+ const scalarField& massb = tmassb();
+
+ // The moles absorbed by the solid
+ // dhdt[J/kg] * kg/sec/m3 = [J/m3/s]
+ scalarField dhdt(dhdt_*massb);
+
+ if (includeHs_)
+ {
+ const fvPatchField& pp =
+ patch().lookupPatchField(pName_);
+
+ const fvPatchField& Tp =
+ patch().lookupPatchField(TName_);
+
+ const auto& thermo = db().lookupObject
+ (
+ basicThermo::dictName
+ );
+
+ const basicSpecieMixture& composition = thermo.composition();
+
+ const label speicesId =
+ thermo.composition().species()[speciesName_];
+
+ scalarField hsp(this->patch().size(), 0);
+
+ forAll(pp, facei)
+ {
+ hsp[facei] = composition.Hs(speicesId, pp[facei], Tp[facei]);
+ }
+
+ dhdt += hsp*massb;
+ }
+
+ if (debug)
+ {
+ Info<< " Patch enthalpy rate min/max [J/m3/sec]: "
+ << gMin(dhdt) << " - " << gMax(dhdt) << endl;
+ }
+
+ return tmp::New(dhdt);
+}
+
+
+void Foam::enthalpySorptionFvPatchScalarField::updateCoeffs()
+{
+ if (updated())
+ {
+ return;
+ }
+
+ const auto& Yp =
+ refCast
+ (
+ patch().lookupPatchField
+ (
+ speciesName_
+ )
+ );
+
+ switch (enthalpyModel_)
+ {
+ case enthalpyModelType::estimated:
+ {
+ dhdt_ = -C_*Hvap_;
+ break;
+ }
+ case enthalpyModelType::calculated:
+ {
+ // mass [mol/kg]
+ tmp tmassb = Yp.mass();
+ const scalarField& massb = tmassb.ref();
+
+ forAll(massb, facei)
+ {
+ const scalar mfacei = massb[facei];
+
+ dhdt_[facei] = enthalpyMassLoadPtr_->value(mfacei);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (debug)
+ {
+ Info<< " Enthalpy change min/max [J/kg]: "
+ << gMin(dhdt_) << " - " << gMax(dhdt_) << endl;
+ }
+
+ zeroGradientFvPatchScalarField::updateCoeffs();
+}
+
+
+void Foam::enthalpySorptionFvPatchScalarField::write(Ostream& os) const
+{
+ fvPatchScalarField::write(os);
+
+ os.writeEntry("enthalpyModel", enthalpyModelTypeNames[enthalpyModel_]);
+
+ if (enthalpyMassLoadPtr_)
+ {
+ enthalpyMassLoadPtr_->writeData(os);
+ }
+
+ os.writeEntry("species", speciesName_);
+
+ os.writeEntryIfDifferent("includeHs", true, includeHs_);
+ os.writeEntryIfDifferent("C", scalar(0), C_);
+ os.writeEntryIfDifferent("Hvap", scalar(0), Hvap_);
+ os.writeEntryIfDifferent("p", "p", pName_);
+ os.writeEntryIfDifferent("T", "T", TName_);
+
+ dhdt_.writeEntry("dhdt", os);
+
+ writeEntry("value", os);
+}
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+ makePatchTypeField
+ (
+ fvPatchScalarField,
+ enthalpySorptionFvPatchScalarField
+ );
+}
+
+// ************************************************************************* //
diff --git a/src/thermophysicalModels/reactionThermo/derivedFvPatchFields/enthalpySorption/enthalpySorptionFvPatchScalarField.H b/src/thermophysicalModels/reactionThermo/derivedFvPatchFields/enthalpySorption/enthalpySorptionFvPatchScalarField.H
new file mode 100644
index 0000000000..f232c79c71
--- /dev/null
+++ b/src/thermophysicalModels/reactionThermo/derivedFvPatchFields/enthalpySorption/enthalpySorptionFvPatchScalarField.H
@@ -0,0 +1,284 @@
+/*---------------------------------------------------------------------------*\
+ ========= |
+ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
+ \\ / O peration |
+ \\ / A nd | www.openfoam.com
+ \\/ M anipulation |
+-------------------------------------------------------------------------------
+ Copyright (C) 2022 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::enthalpySorptionFvPatchScalarField
+
+Group
+ grpGenericBoundaryConditions
+
+Description
+ This is a temperature boundary condition which works
+ in conjunction with the \c speciesSorption condition for species.
+
+ This boundary condition substracts or adds enthalpy associated with the
+ adsorption provided by the \c speciesSorption condition.
+
+ It can handle two enthalpy models:
+
+ 1) Estimate
+ 2) Calculated
+
+ On top of this, the enthalpy associated with the sensible enthalpy
+ corresponding with the species transport can be added using \c includeHs.
+
+Usage
+ Example of the boundary condition specification:
+ \verbatim
+
+ {
+ // Mandatory entries
+ type enthalpySorption;
+ enthalpyModel ;
+ species ;
+
+ // Conditional mandatory entries
+
+ // when enthalpyModel == calculated
+ enthalpyTable >
+
+ // enthalpyTable
+ // {
+ // type table;
+ // values ((0 0)(1 50));
+ // }
+
+ // Optional entries
+ includeHs ;
+ C ;
+ Hvap ;
+ dhdt ;
+ p ;
+ T ;
+ }
+ \endverbatim
+
+ where the entries mean:
+ \table
+ Property | Description | Type | Reqd | Deflt
+ type | Type name: enthalpySorption | word | yes | -
+ enthalpyModel | Adsorption enthalpy model | word | yes | -
+ species | Name of associated species | word | yes | -
+ enthalpyTable | Calculated enthalpy model table | Function1\ | no | -
+ includeHs | Include sensible enthalpy | bool | no | true
+ C | Estimate enthalpy model constant | scalar | no | 0
+ Hvap | Evaporation heat for species | scalar | no | 0
+ p | Name of operand pressure field | word | no | p
+ T | Name of operand temperature field | word | no | T
+ dhdt | Enthalpy change on cells next to patch [J/kg] | scalarField | no | Zero
+ \endtable
+
+ Options for the \c enthalpyModel entry:
+ \verbatim
+ estimated | Enthalpy is estimated
+ calculated | Enthalpy is calculated based on enthalpyTable
+ \endverbatim
+
+ The inherited entries are elaborated in:
+ - \link zeroGradientFvPatchFields.H \endlink
+ - \link Function1.H \endlink
+
+SourceFiles
+ enthalpySorptionFvPatchScalarField.C
+
+\*---------------------------------------------------------------------------*/
+
+#ifndef Foam_enthalpySorptionFvPatchScalarField_H
+#define Foam_enthalpySorptionFvPatchScalarField_H
+
+#include "boundarySourcePatch.H"
+#include "zeroGradientFvPatchFields.H"
+#include "Function1.H"
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+namespace Foam
+{
+
+/*---------------------------------------------------------------------------*\
+ Class enthalpySorptionFvPatchScalarField Declaration
+\*---------------------------------------------------------------------------*/
+
+class enthalpySorptionFvPatchScalarField
+:
+ public zeroGradientFvPatchField,
+ public boundarySourcePatch
+{
+ // Private Enumeration
+
+ //- Options for the enthalpy model
+ enum enthalpyModelType : char
+ {
+ estimated,
+ calculated
+ };
+
+ //- Names for enthalpyModelType
+ static const Enum enthalpyModelTypeNames;
+
+
+ // Private Data
+
+ //- Enthalpy model
+ enum enthalpyModelType enthalpyModel_;
+
+ //- Include sensible enthalpy of the species
+ bool includeHs_;
+
+ //- Load enthalpy table for calculated model
+ autoPtr> enthalpyMassLoadPtr_;
+
+ //- Estimated enthalpy model constant
+ scalar C_;
+
+ //- Heat of evaporation of species
+ scalar Hvap_;
+
+ //- Name of operand species field
+ word speciesName_;
+
+ //- Name of operand pressure field
+ word pName_;
+
+ //- Name of operand temperature field
+ word TName_;
+
+ //- Enthalpy change on cells next to patch [J/kg]
+ scalarField dhdt_;
+
+
+public:
+
+ //- Runtime type information
+ TypeName("enthalpySorption");
+
+
+ // Constructors
+
+ //- Construct from patch and internal field
+ enthalpySorptionFvPatchScalarField
+ (
+ const fvPatch&,
+ const DimensionedField&
+ );
+
+ //- Construct from patch, internal field and dictionary
+ enthalpySorptionFvPatchScalarField
+ (
+ const fvPatch&,
+ const DimensionedField&,
+ const dictionary&
+ );
+
+ //- Construct by mapping given
+ //- enthalpySorptionFvPatchScalarField onto a new patch
+ enthalpySorptionFvPatchScalarField
+ (
+ const enthalpySorptionFvPatchScalarField&,
+ const fvPatch&,
+ const DimensionedField&,
+ const fvPatchFieldMapper&
+ );
+
+ //- Construct as copy
+ enthalpySorptionFvPatchScalarField
+ (
+ const enthalpySorptionFvPatchScalarField&
+ );
+
+ //- Construct and return a clone
+ virtual tmp clone() const
+ {
+ return tmp
+ (
+ new enthalpySorptionFvPatchScalarField(*this)
+ );
+ }
+
+ //- Construct as copy setting internal field reference
+ enthalpySorptionFvPatchScalarField
+ (
+ const enthalpySorptionFvPatchScalarField&,
+ const DimensionedField&
+ );
+
+ //- Construct and return a clone setting internal field reference
+ virtual tmp clone
+ (
+ const DimensionedField& iF
+ ) const
+ {
+ return tmp
+ (
+ new enthalpySorptionFvPatchScalarField(*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&
+ );
+
+
+ // Evaluation
+
+ //- Source of cells next to the patch
+ virtual tmp patchSource() const;
+
+ //- Update the coefficients associated with the patch field
+ virtual void updateCoeffs();
+
+
+ // I-O
+
+ //- Write
+ virtual void write(Ostream&) const;
+};
+
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+} // End namespace Foam
+
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
+
+#endif
+
+// ************************************************************************* //