These models have been particularly designed for use in the VoF solvers, both incompressible and compressible. Currently constant and temperature dependent surface tension models are provided but it easy to write models in which the surface tension is evaluated from any fields held by the mesh database.
248 lines
6.7 KiB
C
248 lines
6.7 KiB
C
/*---------------------------------------------------------------------------*\
|
|
========= |
|
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
|
\\ / O peration |
|
|
\\ / A nd | Copyright (C) 2011-2017 OpenFOAM Foundation
|
|
\\/ M anipulation |
|
|
-------------------------------------------------------------------------------
|
|
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 "interfaceProperties.H"
|
|
#include "alphaContactAngleFvPatchScalarField.H"
|
|
#include "mathematicalConstants.H"
|
|
#include "surfaceInterpolate.H"
|
|
#include "fvcDiv.H"
|
|
#include "fvcGrad.H"
|
|
#include "fvcSnGrad.H"
|
|
|
|
// * * * * * * * * * * * * * * * Static Member Data * * * * * * * * * * * * //
|
|
|
|
const Foam::scalar Foam::interfaceProperties::convertToRad =
|
|
Foam::constant::mathematical::pi/180.0;
|
|
|
|
|
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
|
|
|
// Correction for the boundary condition on the unit normal nHat on
|
|
// walls to produce the correct contact angle.
|
|
|
|
// The dynamic contact angle is calculated from the component of the
|
|
// velocity on the direction of the interface, parallel to the wall.
|
|
|
|
void Foam::interfaceProperties::correctContactAngle
|
|
(
|
|
surfaceVectorField::Boundary& nHatb,
|
|
const surfaceVectorField::Boundary& gradAlphaf
|
|
) const
|
|
{
|
|
const fvMesh& mesh = alpha1_.mesh();
|
|
const volScalarField::Boundary& abf = alpha1_.boundaryField();
|
|
|
|
const fvBoundaryMesh& boundary = mesh.boundary();
|
|
|
|
forAll(boundary, patchi)
|
|
{
|
|
if (isA<alphaContactAngleFvPatchScalarField>(abf[patchi]))
|
|
{
|
|
alphaContactAngleFvPatchScalarField& acap =
|
|
const_cast<alphaContactAngleFvPatchScalarField&>
|
|
(
|
|
refCast<const alphaContactAngleFvPatchScalarField>
|
|
(
|
|
abf[patchi]
|
|
)
|
|
);
|
|
|
|
fvsPatchVectorField& nHatp = nHatb[patchi];
|
|
const scalarField theta
|
|
(
|
|
convertToRad*acap.theta(U_.boundaryField()[patchi], nHatp)
|
|
);
|
|
|
|
const vectorField nf
|
|
(
|
|
boundary[patchi].nf()
|
|
);
|
|
|
|
// Reset nHatp to correspond to the contact angle
|
|
|
|
const scalarField a12(nHatp & nf);
|
|
const scalarField b1(cos(theta));
|
|
|
|
scalarField b2(nHatp.size());
|
|
forAll(b2, facei)
|
|
{
|
|
b2[facei] = cos(acos(a12[facei]) - theta[facei]);
|
|
}
|
|
|
|
const scalarField det(1.0 - a12*a12);
|
|
|
|
scalarField a((b1 - a12*b2)/det);
|
|
scalarField b((b2 - a12*b1)/det);
|
|
|
|
nHatp = a*nf + b*nHatp;
|
|
nHatp /= (mag(nHatp) + deltaN_.value());
|
|
|
|
acap.gradient() = (nf & nHatp)*mag(gradAlphaf[patchi]);
|
|
acap.evaluate();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void Foam::interfaceProperties::calculateK()
|
|
{
|
|
const fvMesh& mesh = alpha1_.mesh();
|
|
const surfaceVectorField& Sf = mesh.Sf();
|
|
|
|
// Cell gradient of alpha
|
|
const volVectorField gradAlpha(fvc::grad(alpha1_, "nHat"));
|
|
|
|
// Interpolated face-gradient of alpha
|
|
surfaceVectorField gradAlphaf(fvc::interpolate(gradAlpha));
|
|
|
|
//gradAlphaf -=
|
|
// (mesh.Sf()/mesh.magSf())
|
|
// *(fvc::snGrad(alpha1_) - (mesh.Sf() & gradAlphaf)/mesh.magSf());
|
|
|
|
// Face unit interface normal
|
|
surfaceVectorField nHatfv(gradAlphaf/(mag(gradAlphaf) + deltaN_));
|
|
// surfaceVectorField nHatfv
|
|
// (
|
|
// (gradAlphaf + deltaN_*vector(0, 0, 1)
|
|
// *sign(gradAlphaf.component(vector::Z)))/(mag(gradAlphaf) + deltaN_)
|
|
// );
|
|
correctContactAngle(nHatfv.boundaryFieldRef(), gradAlphaf.boundaryField());
|
|
|
|
// Face unit interface normal flux
|
|
nHatf_ = nHatfv & Sf;
|
|
|
|
// Simple expression for curvature
|
|
K_ = -fvc::div(nHatf_);
|
|
|
|
// Complex expression for curvature.
|
|
// Correction is formally zero but numerically non-zero.
|
|
/*
|
|
volVectorField nHat(gradAlpha/(mag(gradAlpha) + deltaN_));
|
|
forAll(nHat.boundaryField(), patchi)
|
|
{
|
|
nHat.boundaryField()[patchi] = nHatfv.boundaryField()[patchi];
|
|
}
|
|
|
|
K_ = -fvc::div(nHatf_) + (nHat & fvc::grad(nHatfv) & nHat);
|
|
*/
|
|
}
|
|
|
|
|
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
|
|
|
Foam::interfaceProperties::interfaceProperties
|
|
(
|
|
const volScalarField& alpha1,
|
|
const volVectorField& U,
|
|
const IOdictionary& dict
|
|
)
|
|
:
|
|
transportPropertiesDict_(dict),
|
|
cAlpha_
|
|
(
|
|
readScalar
|
|
(
|
|
alpha1.mesh().solverDict(alpha1.name()).lookup("cAlpha")
|
|
)
|
|
),
|
|
|
|
sigmaPtr_(surfaceTensionModel::New(dict, alpha1.mesh())),
|
|
|
|
deltaN_
|
|
(
|
|
"deltaN",
|
|
1e-8/pow(average(alpha1.mesh().V()), 1.0/3.0)
|
|
),
|
|
|
|
alpha1_(alpha1),
|
|
U_(U),
|
|
|
|
nHatf_
|
|
(
|
|
IOobject
|
|
(
|
|
"nHatf",
|
|
alpha1_.time().timeName(),
|
|
alpha1_.mesh()
|
|
),
|
|
alpha1_.mesh(),
|
|
dimensionedScalar("nHatf", dimArea, 0.0)
|
|
),
|
|
|
|
K_
|
|
(
|
|
IOobject
|
|
(
|
|
"interfaceProperties:K",
|
|
alpha1_.time().timeName(),
|
|
alpha1_.mesh()
|
|
),
|
|
alpha1_.mesh(),
|
|
dimensionedScalar("K", dimless/dimLength, 0.0)
|
|
)
|
|
{
|
|
calculateK();
|
|
}
|
|
|
|
|
|
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
|
|
|
|
Foam::tmp<Foam::volScalarField>
|
|
Foam::interfaceProperties::sigmaK() const
|
|
{
|
|
return sigmaPtr_->sigma()*K_;
|
|
}
|
|
|
|
|
|
Foam::tmp<Foam::surfaceScalarField>
|
|
Foam::interfaceProperties::surfaceTensionForce() const
|
|
{
|
|
return fvc::interpolate(sigmaK())*fvc::snGrad(alpha1_);
|
|
}
|
|
|
|
|
|
Foam::tmp<Foam::volScalarField>
|
|
Foam::interfaceProperties::nearInterface() const
|
|
{
|
|
return pos(alpha1_ - 0.01)*pos(0.99 - alpha1_);
|
|
}
|
|
|
|
|
|
void Foam::interfaceProperties::correct()
|
|
{
|
|
calculateK();
|
|
}
|
|
|
|
|
|
bool Foam::interfaceProperties::read()
|
|
{
|
|
alpha1_.mesh().solverDict(alpha1_.name()).lookup("cAlpha") >> cAlpha_;
|
|
sigmaPtr_->read(transportPropertiesDict_);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
// ************************************************************************* //
|