/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2011-2017 OpenFOAM Foundation ------------------------------------------------------------------------------- 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 "multiphaseMixture.H" #include "alphaContactAngleFvPatchScalarField.H" #include "Time.H" #include "subCycle.H" #include "MULES.H" #include "surfaceInterpolate.H" #include "fvcGrad.H" #include "fvcSnGrad.H" #include "fvcDiv.H" #include "fvcFlux.H" #include "unitConversion.H" // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // void Foam::multiphaseMixture::calcAlphas() { scalar level = 0.0; alphas_ == 0.0; for (const phase& ph : phases_) { alphas_ += level * ph; level += 1.0; } } // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::multiphaseMixture::multiphaseMixture ( const volVectorField& U, const surfaceScalarField& phi ) : IOdictionary ( IOobject ( "transportProperties", U.time().constant(), U.db(), IOobject::MUST_READ_IF_MODIFIED, IOobject::NO_WRITE ) ), phases_(lookup("phases"), phase::iNew(U, phi)), mesh_(U.mesh()), U_(U), phi_(phi), rhoPhi_ ( IOobject ( "rhoPhi", mesh_.time().timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar(dimMass/dimTime, Zero) ), alphas_ ( IOobject ( "alphas", mesh_.time().timeName(), mesh_, IOobject::NO_READ, IOobject::AUTO_WRITE ), mesh_, dimensionedScalar(dimless, Zero) ), nu_ ( IOobject ( "nu", mesh_.time().timeName(), mesh_ ), mu()/rho() ), sigmas_(lookup("sigmas")), dimSigma_(1, 0, -2, 0, 0), deltaN_ ( "deltaN", 1e-8/cbrt(average(mesh_.V())) ) { rhoPhi_.setOriented(); calcAlphas(); alphas_.write(); } // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // Foam::tmp Foam::multiphaseMixture::rho() const { auto iter = phases_.cbegin(); tmp trho = iter()*iter().rho(); volScalarField& rho = trho.ref(); for (++iter; iter != phases_.cend(); ++iter) { rho += iter()*iter().rho(); } return trho; } Foam::tmp Foam::multiphaseMixture::rho(const label patchi) const { auto iter = phases_.cbegin(); tmp trho = iter().boundaryField()[patchi]*iter().rho().value(); scalarField& rho = trho.ref(); for (++iter; iter != phases_.cend(); ++iter) { rho += iter().boundaryField()[patchi]*iter().rho().value(); } return trho; } Foam::tmp Foam::multiphaseMixture::mu() const { auto iter = phases_.cbegin(); tmp tmu = iter()*iter().rho()*iter().nu(); volScalarField& mu = tmu.ref(); for (++iter; iter != phases_.cend(); ++iter) { mu += iter()*iter().rho()*iter().nu(); } return tmu; } Foam::tmp Foam::multiphaseMixture::mu(const label patchi) const { auto iter = phases_.cbegin(); tmp tmu = ( iter().boundaryField()[patchi] *iter().rho().value() *iter().nu(patchi) ); scalarField& mu = tmu.ref(); for (++iter; iter != phases_.cend(); ++iter) { mu += ( iter().boundaryField()[patchi] *iter().rho().value() *iter().nu(patchi) ); } return tmu; } Foam::tmp Foam::multiphaseMixture::muf() const { auto iter = phases_.cbegin(); tmp tmuf = fvc::interpolate(iter())*iter().rho()*fvc::interpolate(iter().nu()); surfaceScalarField& muf = tmuf.ref(); for (++iter; iter != phases_.cend(); ++iter) { muf += fvc::interpolate(iter())*iter().rho()*fvc::interpolate(iter().nu()); } return tmuf; } Foam::tmp Foam::multiphaseMixture::nu() const { return nu_; } Foam::tmp Foam::multiphaseMixture::nu(const label patchi) const { return nu_.boundaryField()[patchi]; } Foam::tmp Foam::multiphaseMixture::nuf() const { return muf()/fvc::interpolate(rho()); } Foam::tmp Foam::multiphaseMixture::surfaceTensionForce() const { tmp tstf ( new surfaceScalarField ( IOobject ( "surfaceTensionForce", mesh_.time().timeName(), mesh_ ), mesh_, dimensionedScalar(dimensionSet(1, -2, -2, 0, 0), Zero) ) ); surfaceScalarField& stf = tstf.ref(); stf.setOriented(); forAllConstIters(phases_, iter1) { const phase& alpha1 = iter1(); auto iter2 = iter1; for (++iter2; iter2 != phases_.cend(); ++iter2) { const phase& alpha2 = iter2(); auto sigma = sigmas_.cfind(interfacePair(alpha1, alpha2)); if (!sigma.found()) { FatalErrorInFunction << "Cannot find interface " << interfacePair(alpha1, alpha2) << " in list of sigma values" << exit(FatalError); } stf += dimensionedScalar("sigma", dimSigma_, *sigma) *fvc::interpolate(K(alpha1, alpha2))* ( fvc::interpolate(alpha2)*fvc::snGrad(alpha1) - fvc::interpolate(alpha1)*fvc::snGrad(alpha2) ); } } return tstf; } void Foam::multiphaseMixture::solve() { correct(); const Time& runTime = mesh_.time(); volScalarField& alpha = phases_.first(); const dictionary& alphaControls = mesh_.solverDict("alpha"); label nAlphaSubCycles(alphaControls.get