/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation Copyright (C) 2021-2024 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 "OwenRyleyModel.H" #include "processorFaPatch.H" #include "addToRunTimeSelectionTable.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // namespace Foam { namespace filmSeparationModels { defineTypeNameAndDebug(OwenRyleyModel, 0); addToRunTimeSelectionTable(filmSeparationModel, OwenRyleyModel, dictionary); // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // tmp OwenRyleyModel::calcInvR1 ( const areaVectorField& U ) const { const dimensionedScalar smallU(dimVelocity, ROOTVSMALL); const areaVectorField UHat(U/(mag(U) + smallU)); auto tinvR1 = areaScalarField::New ( "invR1", IOobjectOption::NO_REGISTER, (UHat & (UHat & -gradNHat_)) ); scalarField& invR1 = tinvR1.ref().primitiveFieldRef(); // Apply defined patch radii if (definedPatchRadii_ > 0) { invR1 = 1.0/max(1e-6, definedPatchRadii_); } // Filter out large radii for (auto& x : invR1) { if (mag(x) < 1e-6) { x = -1; } } return tinvR1; } tmp OwenRyleyModel::calcCosAngle ( const edgeScalarField& phi, const scalarField& invR1 ) const { const areaVectorField& U = film().Uf(); const dimensionedScalar smallU(dimVelocity, ROOTVSMALL); const areaVectorField UHat(U/(mag(U) + smallU)); const vector gHat(normalised(film().g().value())); const faMesh& mesh = film().regionMesh(); const labelUList& own = mesh.edgeOwner(); const labelUList& nbr = mesh.edgeNeighbour(); scalarField phiMax(mesh.nFaces(), -GREAT); scalarField cosAngle(UHat.size(), Zero); // Internal edges forAll(nbr, edgei) { const label cellO = own[edgei]; const label cellN = nbr[edgei]; const scalar phiEdge = phi[edgei]; if (phiEdge > phiMax[cellO]) { phiMax[cellO] = phiEdge; cosAngle[cellO] = -gHat & UHat[cellN]; } if (-phiEdge > phiMax[cellN]) { phiMax[cellN] = -phiEdge; cosAngle[cellN] = -gHat & UHat[cellO]; } } // Processor edges for (const auto& phip : phi.boundaryField()) { if (isA(phip.patch())) { const auto& edgeFaces = phip.patch().edgeFaces(); const auto& UHatp = UHat.boundaryField()[phip.patch().index()]; forAll(phip, edgei) { const label cellO = edgeFaces[edgei]; if (phip[edgei] > phiMax[cellO]) { phiMax[cellO] = phip[edgei]; cosAngle[cellO] = -gHat & UHatp[edgei]; } } } } cosAngle *= pos(invR1); if (debug && mesh.time().writeTime()) { { areaScalarField areaCosAngle ( mesh.newIOobject("cosAngle"), mesh, dimensionedScalar(dimless, Zero) ); areaCosAngle.primitiveFieldRef() = cosAngle; areaCosAngle.correctBoundaryConditions(); areaCosAngle.write(); } { areaScalarField areaInvR1 ( mesh.newIOobject("InvR1"), mesh, dimensionedScalar(inv(dimLength), Zero) ); areaInvR1.primitiveFieldRef() = invR1; areaInvR1.write(); } } return clamp(cosAngle, scalarMinMax(-1, 1)); } tmp OwenRyleyModel::netForce() const { const faMesh& mesh = film().regionMesh(); const areaScalarField& h = film().h(); const areaVectorField& U = film().Uf(); const edgeScalarField& phi = film().phi2s(); const areaScalarField& rho = film().rho(); const areaScalarField& sigma = film().sigma(); const scalarField magSqrU(magSqr(U)); const scalarField invR1(calcInvR1(U)); const scalarField cosAngle(calcCosAngle(phi, invR1)); const scalar magG = mag(film().g().value()); // Initialize the net-force magnitude auto tFnet = tmp::New(mesh.nFaces(), Zero); auto& Fnet = tFnet.ref(); forAll(Fnet, i) { if ((invR1[i] > minInvR1()) && (h[i]*invR1[i] > minHbyR1())) { const scalar R1 = 1.0/(invR1[i] + ROOTVSMALL); const scalar R2 = R1 + h[i]; // Inertial force (OR:Eq. 11; '2' is an exponent in the Eq.) const scalar Fi = -4.0/3.0*h[i]*rho[i]*magSqrU[i]*invR1[i]; // Body force (OR:Eq. 11) const scalar Fb = -0.5*rho[i]*magG*invR1[i]*(sqr(R1) - sqr(R2))*cosAngle[i]; // Surface force (OR:Eq. 11) const scalar Fs = sigma[i]/R2; Fnet[i] = Fi + Fb + Fs; } } if (debug && mesh.time().writeTime()) { { areaScalarField areaFnet ( mesh.newIOobject("Fnet"), mesh, dimensionedScalar(dimForce, Zero) ); areaFnet.primitiveFieldRef() = Fnet; areaFnet.write(); } } return tFnet; } // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // OwenRyleyModel::OwenRyleyModel ( const regionModels::areaSurfaceFilmModels::liquidFilmBase& film, const dictionary& dict ) : filmSeparationModel(film, dict), fThreshold_(dict.getOrDefault("fThreshold", 1e-8)), definedPatchRadii_(dict.getOrDefault("definedPatchRadii", 0)), minHbyR1_(dict.getOrDefault("deltaByR1Min", 0)), minInvR1_(dict.getOrDefault("minInvR1", 5)), gradNHat_(fac::grad(film.regionMesh().faceAreaNormals())) { if (mag(film.g().value()) < ROOTVSMALL) { FatalErrorInFunction << "Gravitational acceleration must be non-zero." << exit(FatalError); } } // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // tmp OwenRyleyModel::separatedMassRatio() const { const faMesh& mesh = film().regionMesh(); tmp tFnet = netForce(); const auto& Fnet = tFnet.cref(); // Initialize the mass ratio of film separation auto tseparated = tmp::New(mesh.nFaces(), Zero); auto& separated = tseparated.ref(); forAll(Fnet, i) { if ((Fnet[i] + fThreshold_) < 0) { separated[i] = 1; } } return tseparated; } // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // } // End namespace filmSeparationModels } // End namespace Foam // ************************************************************************* //