From b5206472b5b5f738352cd035a23d73642e888d1b Mon Sep 17 00:00:00 2001
From: Henry Weller <http://cfd.direct>
Date: Fri, 4 Nov 2016 12:07:09 +0000
Subject: [PATCH] reactingEulerFoam: Corrected and rationalized pressure-work

In many publications and Euler-Euler codes the pressure-work term in the
total enthalpy is stated and implemented as -alpha*dp/dt rather than the
conservative form derived from the total internal energy equation
-d(alpha*p)/dt.  In order for the enthalpy and internal energy equations
to be consistent this error/simplification propagates to the total
internal energy equation as a spurious additional term p*d(alpha)/dt
which is included in the OpenFOAM Euler-Euler solvers and causes
stability and conservation issues.

I have now re-derived the energy equations for multiphase flow from
first-principles and implemented in the reactingEulerFoam solvers the
correct conservative form of pressure-work in both the internal energy
and enthalpy equations.

Additionally an optional limiter may be applied to the pressure-work
term in either of the energy forms to avoid spurious fluctuations in the
phase temperature in regions where the phase-fraction -> 0.  This may
specified in the "thermophysicalProperties.<phase>" file, e.g.

pressureWorkAlphaLimit 1e-3;

which sets the pressure work term to 0 for phase-fractions below 1e-3.
---
 .../AnisothermalPhaseModel.C                  | 44 ++++++++++++++++---
 .../AnisothermalPhaseModel.H                  |  9 ++++
 2 files changed, 48 insertions(+), 5 deletions(-)

diff --git a/applications/solvers/multiphase/reactingEulerFoam/phaseSystems/phaseModel/AnisothermalPhaseModel/AnisothermalPhaseModel.C b/applications/solvers/multiphase/reactingEulerFoam/phaseSystems/phaseModel/AnisothermalPhaseModel/AnisothermalPhaseModel.C
index 6ca75c6ed49..4285a40c0ca 100644
--- a/applications/solvers/multiphase/reactingEulerFoam/phaseSystems/phaseModel/AnisothermalPhaseModel/AnisothermalPhaseModel.C
+++ b/applications/solvers/multiphase/reactingEulerFoam/phaseSystems/phaseModel/AnisothermalPhaseModel/AnisothermalPhaseModel.C
@@ -77,11 +77,39 @@ void Foam::AnisothermalPhaseModel<BasePhaseModel>::correctThermo()
 }
 
 
+template<class BasePhaseModel>
+Foam::tmp<Foam::volScalarField>
+Foam::AnisothermalPhaseModel<BasePhaseModel>::filterPressureWork
+(
+    const tmp<volScalarField>& pressureWork
+) const
+{
+    const volScalarField& alpha = *this;
+
+    scalar pressureWorkAlphaLimit =
+        this->thermo_->lookupOrDefault("pressureWorkAlphaLimit", 0.0);
+
+    if (pressureWorkAlphaLimit > 0)
+    {
+        return
+        (
+            max(alpha - pressureWorkAlphaLimit, scalar(0))
+           /max(alpha - pressureWorkAlphaLimit, pressureWorkAlphaLimit)
+        )*pressureWork;
+    }
+    else
+    {
+        return pressureWork;
+    }
+}
+
+
 template<class BasePhaseModel>
 Foam::tmp<Foam::fvScalarMatrix>
 Foam::AnisothermalPhaseModel<BasePhaseModel>::heEqn()
 {
     const volScalarField& alpha = *this;
+    const volVectorField& U = this->U();
     const surfaceScalarField& alphaPhi = this->alphaPhi();
     const surfaceScalarField& alphaRhoPhi = this->alphaRhoPhi();
 
@@ -93,7 +121,8 @@ Foam::AnisothermalPhaseModel<BasePhaseModel>::heEqn()
 
     tmp<fvScalarMatrix> tEEqn
     (
-        fvm::ddt(alpha, this->rho(), he) + fvm::div(alphaRhoPhi, he)
+        fvm::ddt(alpha, this->rho(), he)
+      + fvm::div(alphaRhoPhi, he)
       - fvm::Sp(contErr, he)
 
       + fvc::ddt(alpha, this->rho(), K_) + fvc::div(alphaRhoPhi, K_)
@@ -112,13 +141,18 @@ Foam::AnisothermalPhaseModel<BasePhaseModel>::heEqn()
     // Add the appropriate pressure-work term
     if (he.name() == this->thermo_->phasePropertyName("e"))
     {
-        tEEqn.ref() +=
-            fvc::ddt(alpha)*this->thermo().p()
-          + fvc::div(alphaPhi, this->thermo().p());
+        tEEqn.ref() += filterPressureWork
+        (
+            fvc::div(fvc::absolute(alphaPhi, alpha, U), this->thermo().p())
+        );
     }
     else if (this->thermo_->dpdt())
     {
-        tEEqn.ref() -= alpha*this->fluid().dpdt();
+        tEEqn.ref() -= filterPressureWork
+        (
+           fvc::ddt(alpha, this->thermo().p())
+         + alpha*(this->fluid().dpdt() - fvc::ddt(this->thermo().p()))
+        );
     }
 
     return tEEqn;
diff --git a/applications/solvers/multiphase/reactingEulerFoam/phaseSystems/phaseModel/AnisothermalPhaseModel/AnisothermalPhaseModel.H b/applications/solvers/multiphase/reactingEulerFoam/phaseSystems/phaseModel/AnisothermalPhaseModel/AnisothermalPhaseModel.H
index 7a9cbd51bfb..86edbcd1f8b 100644
--- a/applications/solvers/multiphase/reactingEulerFoam/phaseSystems/phaseModel/AnisothermalPhaseModel/AnisothermalPhaseModel.H
+++ b/applications/solvers/multiphase/reactingEulerFoam/phaseSystems/phaseModel/AnisothermalPhaseModel/AnisothermalPhaseModel.H
@@ -58,6 +58,15 @@ class AnisothermalPhaseModel
         volScalarField K_;
 
 
+    // Private member functions
+
+        //- Optionally filter the pressure work term as the phase-fraction -> 0
+        tmp<volScalarField> filterPressureWork
+        (
+            const tmp<volScalarField>& pressureWork
+        ) const;
+
+
 public:
 
     // Constructors
-- 
GitLab