From 2ab81c3b6998836924806e0ddca1a51a417537c8 Mon Sep 17 00:00:00 2001
From: sergio <s.ferraris@opencfd.co.uk>
Date: Thu, 8 Jul 2021 12:15:41 -0700
Subject: [PATCH] BUG: Correcting surface tension calculation from pair order.
 Fixes #2051

---
 .../multiphaseMixture/multiphaseMixture.C     | 148 ++++++++++--------
 .../multiphaseMixture/multiphaseMixture.H     |  12 ++
 2 files changed, 97 insertions(+), 63 deletions(-)

diff --git a/applications/solvers/multiphase/multiphaseInterFoam/multiphaseMixture/multiphaseMixture.C b/applications/solvers/multiphase/multiphaseInterFoam/multiphaseMixture/multiphaseMixture.C
index d3f850db07b..da3547d18a6 100644
--- a/applications/solvers/multiphase/multiphaseInterFoam/multiphaseMixture/multiphaseMixture.C
+++ b/applications/solvers/multiphase/multiphaseInterFoam/multiphaseMixture/multiphaseMixture.C
@@ -6,6 +6,7 @@
      \\/     M anipulation  |
 -------------------------------------------------------------------------------
     Copyright (C) 2011-2017 OpenFOAM Foundation
+    Copyright (C) 2021 OpenCFD Ltd.
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -26,7 +27,6 @@ License
 \*---------------------------------------------------------------------------*/
 
 #include "multiphaseMixture.H"
-#include "alphaContactAngleFvPatchScalarField.H"
 #include "Time.H"
 #include "subCycle.H"
 #include "MULES.H"
@@ -36,6 +36,7 @@ License
 #include "fvcDiv.H"
 #include "fvcFlux.H"
 #include "unitConversion.H"
+#include "alphaContactAngleFvPatchScalarField.H"
 
 // * * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * //
 
@@ -416,99 +417,120 @@ void Foam::multiphaseMixture::correctContactAngle
     surfaceVectorField::Boundary& nHatb
 ) const
 {
-    const volScalarField::Boundary& gbf
-        = alpha1.boundaryField();
+    const volScalarField::Boundary& gb1f = alpha1.boundaryField();
+    const volScalarField::Boundary& gb2f = alpha2.boundaryField();
 
     const fvBoundaryMesh& boundary = mesh_.boundary();
 
     forAll(boundary, patchi)
     {
-        if (isA<alphaContactAngleFvPatchScalarField>(gbf[patchi]))
+        if (isA<alphaContactAngleFvPatchScalarField>(gb1f[patchi]))
         {
             const alphaContactAngleFvPatchScalarField& acap =
-                refCast<const alphaContactAngleFvPatchScalarField>(gbf[patchi]);
+                refCast<const alphaContactAngleFvPatchScalarField>(gb1f[patchi]);
 
-            vectorField& nHatPatch = nHatb[patchi];
+            correctBoundaryContactAngle(acap, patchi, alpha1, alpha2, nHatb);
+        }
+        else if (isA<alphaContactAngleFvPatchScalarField>(gb2f[patchi]))
+        {
+            const alphaContactAngleFvPatchScalarField& acap =
+                refCast<const alphaContactAngleFvPatchScalarField>(gb2f[patchi]);
 
-            vectorField AfHatPatch
-            (
-                mesh_.Sf().boundaryField()[patchi]
-               /mesh_.magSf().boundaryField()[patchi]
-            );
+            correctBoundaryContactAngle(acap, patchi, alpha2, alpha1, nHatb);
+        }
+    }
+}
 
-            const auto tp =
-                acap.thetaProps().cfind(interfacePair(alpha1, alpha2));
 
-            if (!tp.found())
-            {
-                FatalErrorInFunction
-                    << "Cannot find interface " << interfacePair(alpha1, alpha2)
-                    << "\n    in table of theta properties for patch "
-                    << acap.patch().name()
-                    << exit(FatalError);
-            }
+void Foam::multiphaseMixture::correctBoundaryContactAngle
+(
+    const alphaContactAngleFvPatchScalarField& acap,
+    label patchi,
+    const phase& alpha1,
+    const phase& alpha2,
+    surfaceVectorField::Boundary& nHatb
+) const
+{
+    const fvBoundaryMesh& boundary = mesh_.boundary();
 
-            const bool matched = (tp.key().first() == alpha1.name());
+    vectorField& nHatPatch = nHatb[patchi];
 
-            const scalar theta0 = degToRad(tp().theta0(matched));
-            scalarField theta(boundary[patchi].size(), theta0);
+    vectorField AfHatPatch
+    (
+        mesh_.Sf().boundaryField()[patchi]
+       /mesh_.magSf().boundaryField()[patchi]
+    );
 
-            const scalar uTheta = tp().uTheta();
+    const auto tp = acap.thetaProps().cfind(interfacePair(alpha1, alpha2));
 
-            // Calculate the dynamic contact angle if required
-            if (uTheta > SMALL)
-            {
-                const scalar thetaA = degToRad(tp().thetaA(matched));
-                const scalar thetaR = degToRad(tp().thetaR(matched));
+    if (!tp.found())
+    {
+        FatalErrorInFunction
+            << "Cannot find interface " << interfacePair(alpha1, alpha2)
+            << "\n    in table of theta properties for patch "
+            << acap.patch().name()
+            << exit(FatalError);
+    }
 
-                // Calculated the component of the velocity parallel to the wall
-                vectorField Uwall
-                (
-                    U_.boundaryField()[patchi].patchInternalField()
-                  - U_.boundaryField()[patchi]
-                );
-                Uwall -= (AfHatPatch & Uwall)*AfHatPatch;
+    const bool matched = (tp.key().first() == alpha1.name());
 
-                // Find the direction of the interface parallel to the wall
-                vectorField nWall
-                (
-                    nHatPatch - (AfHatPatch & nHatPatch)*AfHatPatch
-                );
+    const scalar theta0 = degToRad(tp().theta0(matched));
+    scalarField theta(boundary[patchi].size(), theta0);
 
-                // Normalise nWall
-                nWall /= (mag(nWall) + SMALL);
+    const scalar uTheta = tp().uTheta();
 
-                // Calculate Uwall resolved normal to the interface parallel to
-                // the interface
-                scalarField uwall(nWall & Uwall);
+    // Calculate the dynamic contact angle if required
+    if (uTheta > SMALL)
+    {
+        const scalar thetaA = degToRad(tp().thetaA(matched));
+        const scalar thetaR = degToRad(tp().thetaR(matched));
 
-                theta += (thetaA - thetaR)*tanh(uwall/uTheta);
-            }
+        // Calculated the component of the velocity parallel to the wall
+        vectorField Uwall
+        (
+            U_.boundaryField()[patchi].patchInternalField()
+          - U_.boundaryField()[patchi]
+        );
+        Uwall -= (AfHatPatch & Uwall)*AfHatPatch;
 
+        // Find the direction of the interface parallel to the wall
+        vectorField nWall
+        (
+            nHatPatch - (AfHatPatch & nHatPatch)*AfHatPatch
+        );
 
-            // Reset nHatPatch to correspond to the contact angle
+        // Normalise nWall
+        nWall /= (mag(nWall) + SMALL);
 
-            scalarField a12(nHatPatch & AfHatPatch);
+        // Calculate Uwall resolved normal to the interface parallel to
+        // the interface
+        scalarField uwall(nWall & Uwall);
 
-            scalarField b1(cos(theta));
+        theta += (thetaA - thetaR)*tanh(uwall/uTheta);
+    }
 
-            scalarField b2(nHatPatch.size());
 
-            forAll(b2, facei)
-            {
-                b2[facei] = cos(acos(a12[facei]) - theta[facei]);
-            }
+    // Reset nHatPatch to correspond to the contact angle
 
-            scalarField det(1.0 - a12*a12);
+    scalarField a12(nHatPatch & AfHatPatch);
 
-            scalarField a((b1 - a12*b2)/det);
-            scalarField b((b2 - a12*b1)/det);
+    scalarField b1(cos(theta));
 
-            nHatPatch = a*AfHatPatch + b*nHatPatch;
+    scalarField b2(nHatPatch.size());
 
-            nHatPatch /= (mag(nHatPatch) + deltaN_.value());
-        }
+    forAll(b2, facei)
+    {
+        b2[facei] = cos(acos(a12[facei]) - theta[facei]);
     }
+
+    scalarField det(1.0 - a12*a12);
+
+    scalarField a((b1 - a12*b2)/det);
+    scalarField b((b2 - a12*b1)/det);
+
+    nHatPatch = a*AfHatPatch + b*nHatPatch;
+
+    nHatPatch /= (mag(nHatPatch) + deltaN_.value());
 }
 
 
diff --git a/applications/solvers/multiphase/multiphaseInterFoam/multiphaseMixture/multiphaseMixture.H b/applications/solvers/multiphase/multiphaseInterFoam/multiphaseMixture/multiphaseMixture.H
index ddaa807a931..99bd1c38a96 100644
--- a/applications/solvers/multiphase/multiphaseInterFoam/multiphaseMixture/multiphaseMixture.H
+++ b/applications/solvers/multiphase/multiphaseInterFoam/multiphaseMixture/multiphaseMixture.H
@@ -57,6 +57,9 @@ SourceFiles
 namespace Foam
 {
 
+// Class forward declarations
+class alphaContactAngleFvPatchScalarField;
+
 /*---------------------------------------------------------------------------*\
                       Class multiphaseMixture Declaration
 \*---------------------------------------------------------------------------*/
@@ -170,6 +173,15 @@ private:
             surfaceVectorField::Boundary& nHatb
         ) const;
 
+        void correctBoundaryContactAngle
+        (
+            const alphaContactAngleFvPatchScalarField& acap,
+            label patchi,
+            const phase& alpha1,
+            const phase& alpha2,
+            surfaceVectorField::Boundary& nHatb
+        ) const;
+
         tmp<volScalarField> K(const phase& alpha1, const phase& alpha2) const;
 
 
-- 
GitLab