/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2013-2016 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 . \*---------------------------------------------------------------------------*/ #include "multiphaseMixtureThermo.H" #include "alphaContactAngleFvPatchScalarField.H" #include "Time.H" #include "subCycle.H" #include "MULES.H" #include "fvcDiv.H" #include "fvcGrad.H" #include "fvcSnGrad.H" #include "fvcFlux.H" #include "fvcMeshPhi.H" #include "surfaceInterpolate.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // namespace Foam { defineTypeNameAndDebug(multiphaseMixtureThermo, 0); } const Foam::scalar Foam::multiphaseMixtureThermo::convertToRad = Foam::constant::mathematical::pi/180.0; // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // void Foam::multiphaseMixtureThermo::calcAlphas() { scalar level = 0.0; alphas_ == 0.0; forAllIter(PtrDictionary, phases_, phase) { alphas_ += level*phase(); level += 1.0; } } // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::multiphaseMixtureThermo::multiphaseMixtureThermo ( const volVectorField& U, const surfaceScalarField& phi ) : psiThermo(U.mesh(), word::null), phases_(lookup("phases"), phaseModel::iNew(p_, T_)), mesh_(U.mesh()), U_(U), phi_(phi), rhoPhi_ ( IOobject ( "rhoPhi", mesh_.time().timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, dimensionedScalar("rhoPhi", dimMass/dimTime, 0.0) ), alphas_ ( IOobject ( "alphas", mesh_.time().timeName(), mesh_, IOobject::NO_READ, IOobject::AUTO_WRITE ), mesh_, dimensionedScalar("alphas", dimless, 0.0) ), sigmas_(lookup("sigmas")), dimSigma_(1, 0, -2, 0, 0), deltaN_ ( "deltaN", 1e-8/pow(average(mesh_.V()), 1.0/3.0) ) { calcAlphas(); alphas_.write(); correct(); } // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // void Foam::multiphaseMixtureThermo::correct() { forAllIter(PtrDictionary, phases_, phasei) { phasei().correct(); } PtrDictionary::iterator phasei = phases_.begin(); psi_ = phasei()*phasei().thermo().psi(); mu_ = phasei()*phasei().thermo().mu(); alpha_ = phasei()*phasei().thermo().alpha(); for (++phasei; phasei != phases_.end(); ++phasei) { psi_ += phasei()*phasei().thermo().psi(); mu_ += phasei()*phasei().thermo().mu(); alpha_ += phasei()*phasei().thermo().alpha(); } } void Foam::multiphaseMixtureThermo::correctRho(const volScalarField& dp) { forAllIter(PtrDictionary, phases_, phasei) { phasei().thermo().rho() += phasei().thermo().psi()*dp; } } bool Foam::multiphaseMixtureThermo::incompressible() const { bool ico = true; forAllConstIter(PtrDictionary, phases_, phase) { ico &= phase().thermo().incompressible(); } return ico; } bool Foam::multiphaseMixtureThermo::isochoric() const { bool iso = true; forAllConstIter(PtrDictionary, phases_, phase) { iso &= phase().thermo().incompressible(); } return iso; } Foam::tmp Foam::multiphaseMixtureThermo::he ( const volScalarField& p, const volScalarField& T ) const { PtrDictionary::const_iterator phasei = phases_.begin(); tmp the(phasei()*phasei().thermo().he(p, T)); for (++phasei; phasei != phases_.end(); ++phasei) { the.ref() += phasei()*phasei().thermo().he(p, T); } return the; } Foam::tmp Foam::multiphaseMixtureThermo::he ( const scalarField& p, const scalarField& T, const labelList& cells ) const { PtrDictionary::const_iterator phasei = phases_.begin(); tmp the ( scalarField(phasei(), cells)*phasei().thermo().he(p, T, cells) ); for (++phasei; phasei != phases_.end(); ++phasei) { the.ref() += scalarField(phasei(), cells)*phasei().thermo().he(p, T, cells); } return the; } Foam::tmp Foam::multiphaseMixtureThermo::he ( const scalarField& p, const scalarField& T, const label patchi ) const { PtrDictionary::const_iterator phasei = phases_.begin(); tmp the ( phasei().boundaryField()[patchi]*phasei().thermo().he(p, T, patchi) ); for (++phasei; phasei != phases_.end(); ++phasei) { the.ref() += phasei().boundaryField()[patchi]*phasei().thermo().he(p, T, patchi); } return the; } Foam::tmp Foam::multiphaseMixtureThermo::hc() const { PtrDictionary::const_iterator phasei = phases_.begin(); tmp thc(phasei()*phasei().thermo().hc()); for (++phasei; phasei != phases_.end(); ++phasei) { thc.ref() += phasei()*phasei().thermo().hc(); } return thc; } Foam::tmp Foam::multiphaseMixtureThermo::THE ( const scalarField& h, const scalarField& p, const scalarField& T0, const labelList& cells ) const { NotImplemented; return T0; } Foam::tmp Foam::multiphaseMixtureThermo::THE ( const scalarField& h, const scalarField& p, const scalarField& T0, const label patchi ) const { NotImplemented; return T0; } Foam::tmp Foam::multiphaseMixtureThermo::rho() const { PtrDictionary::const_iterator phasei = phases_.begin(); tmp trho(phasei()*phasei().thermo().rho()); for (++phasei; phasei != phases_.end(); ++phasei) { trho.ref() += phasei()*phasei().thermo().rho(); } return trho; } Foam::tmp Foam::multiphaseMixtureThermo::rho ( const label patchi ) const { PtrDictionary::const_iterator phasei = phases_.begin(); tmp trho ( phasei().boundaryField()[patchi]*phasei().thermo().rho(patchi) ); for (++phasei; phasei != phases_.end(); ++phasei) { trho.ref() += phasei().boundaryField()[patchi]*phasei().thermo().rho(patchi); } return trho; } Foam::tmp Foam::multiphaseMixtureThermo::Cp() const { PtrDictionary::const_iterator phasei = phases_.begin(); tmp tCp(phasei()*phasei().thermo().Cp()); for (++phasei; phasei != phases_.end(); ++phasei) { tCp.ref() += phasei()*phasei().thermo().Cp(); } return tCp; } Foam::tmp Foam::multiphaseMixtureThermo::Cp ( const scalarField& p, const scalarField& T, const label patchi ) const { PtrDictionary::const_iterator phasei = phases_.begin(); tmp tCp ( phasei().boundaryField()[patchi]*phasei().thermo().Cp(p, T, patchi) ); for (++phasei; phasei != phases_.end(); ++phasei) { tCp.ref() += phasei().boundaryField()[patchi]*phasei().thermo().Cp(p, T, patchi); } return tCp; } Foam::tmp Foam::multiphaseMixtureThermo::Cv() const { PtrDictionary::const_iterator phasei = phases_.begin(); tmp tCv(phasei()*phasei().thermo().Cv()); for (++phasei; phasei != phases_.end(); ++phasei) { tCv.ref() += phasei()*phasei().thermo().Cv(); } return tCv; } Foam::tmp Foam::multiphaseMixtureThermo::Cv ( const scalarField& p, const scalarField& T, const label patchi ) const { PtrDictionary::const_iterator phasei = phases_.begin(); tmp tCv ( phasei().boundaryField()[patchi]*phasei().thermo().Cv(p, T, patchi) ); for (++phasei; phasei != phases_.end(); ++phasei) { tCv.ref() += phasei().boundaryField()[patchi]*phasei().thermo().Cv(p, T, patchi); } return tCv; } Foam::tmp Foam::multiphaseMixtureThermo::gamma() const { PtrDictionary::const_iterator phasei = phases_.begin(); tmp tgamma(phasei()*phasei().thermo().gamma()); for (++phasei; phasei != phases_.end(); ++phasei) { tgamma.ref() += phasei()*phasei().thermo().gamma(); } return tgamma; } Foam::tmp Foam::multiphaseMixtureThermo::gamma ( const scalarField& p, const scalarField& T, const label patchi ) const { PtrDictionary::const_iterator phasei = phases_.begin(); tmp tgamma ( phasei().boundaryField()[patchi]*phasei().thermo().gamma(p, T, patchi) ); for (++phasei; phasei != phases_.end(); ++phasei) { tgamma.ref() += phasei().boundaryField()[patchi] *phasei().thermo().gamma(p, T, patchi); } return tgamma; } Foam::tmp Foam::multiphaseMixtureThermo::Cpv() const { PtrDictionary::const_iterator phasei = phases_.begin(); tmp tCpv(phasei()*phasei().thermo().Cpv()); for (++phasei; phasei != phases_.end(); ++phasei) { tCpv.ref() += phasei()*phasei().thermo().Cpv(); } return tCpv; } Foam::tmp Foam::multiphaseMixtureThermo::Cpv ( const scalarField& p, const scalarField& T, const label patchi ) const { PtrDictionary::const_iterator phasei = phases_.begin(); tmp tCpv ( phasei().boundaryField()[patchi]*phasei().thermo().Cpv(p, T, patchi) ); for (++phasei; phasei != phases_.end(); ++phasei) { tCpv.ref() += phasei().boundaryField()[patchi] *phasei().thermo().Cpv(p, T, patchi); } return tCpv; } Foam::tmp Foam::multiphaseMixtureThermo::CpByCpv() const { PtrDictionary::const_iterator phasei = phases_.begin(); tmp tCpByCpv(phasei()*phasei().thermo().CpByCpv()); for (++phasei; phasei != phases_.end(); ++phasei) { tCpByCpv.ref() += phasei()*phasei().thermo().CpByCpv(); } return tCpByCpv; } Foam::tmp Foam::multiphaseMixtureThermo::CpByCpv ( const scalarField& p, const scalarField& T, const label patchi ) const { PtrDictionary::const_iterator phasei = phases_.begin(); tmp tCpByCpv ( phasei().boundaryField()[patchi]*phasei().thermo().CpByCpv(p, T, patchi) ); for (++phasei; phasei != phases_.end(); ++phasei) { tCpByCpv.ref() += phasei().boundaryField()[patchi] *phasei().thermo().CpByCpv(p, T, patchi); } return tCpByCpv; } Foam::tmp Foam::multiphaseMixtureThermo::nu() const { return mu()/rho(); } Foam::tmp Foam::multiphaseMixtureThermo::nu ( const label patchi ) const { return mu(patchi)/rho(patchi); } Foam::tmp Foam::multiphaseMixtureThermo::kappa() const { PtrDictionary::const_iterator phasei = phases_.begin(); tmp tkappa(phasei()*phasei().thermo().kappa()); for (++phasei; phasei != phases_.end(); ++phasei) { tkappa.ref() += phasei()*phasei().thermo().kappa(); } return tkappa; } Foam::tmp Foam::multiphaseMixtureThermo::kappa ( const label patchi ) const { PtrDictionary::const_iterator phasei = phases_.begin(); tmp tkappa ( phasei().boundaryField()[patchi]*phasei().thermo().kappa(patchi) ); for (++phasei; phasei != phases_.end(); ++phasei) { tkappa.ref() += phasei().boundaryField()[patchi]*phasei().thermo().kappa(patchi); } return tkappa; } Foam::tmp Foam::multiphaseMixtureThermo::kappaEff ( const volScalarField& alphat ) const { PtrDictionary::const_iterator phasei = phases_.begin(); tmp tkappaEff(phasei()*phasei().thermo().kappaEff(alphat)); for (++phasei; phasei != phases_.end(); ++phasei) { tkappaEff.ref() += phasei()*phasei().thermo().kappaEff(alphat); } return tkappaEff; } Foam::tmp Foam::multiphaseMixtureThermo::kappaEff ( const scalarField& alphat, const label patchi ) const { PtrDictionary::const_iterator phasei = phases_.begin(); tmp tkappaEff ( phasei().boundaryField()[patchi] *phasei().thermo().kappaEff(alphat, patchi) ); for (++phasei; phasei != phases_.end(); ++phasei) { tkappaEff.ref() += phasei().boundaryField()[patchi] *phasei().thermo().kappaEff(alphat, patchi); } return tkappaEff; } Foam::tmp Foam::multiphaseMixtureThermo::alphaEff ( const volScalarField& alphat ) const { PtrDictionary::const_iterator phasei = phases_.begin(); tmp talphaEff(phasei()*phasei().thermo().alphaEff(alphat)); for (++phasei; phasei != phases_.end(); ++phasei) { talphaEff.ref() += phasei()*phasei().thermo().alphaEff(alphat); } return talphaEff; } Foam::tmp Foam::multiphaseMixtureThermo::alphaEff ( const scalarField& alphat, const label patchi ) const { PtrDictionary::const_iterator phasei = phases_.begin(); tmp talphaEff ( phasei().boundaryField()[patchi] *phasei().thermo().alphaEff(alphat, patchi) ); for (++phasei; phasei != phases_.end(); ++phasei) { talphaEff.ref() += phasei().boundaryField()[patchi] *phasei().thermo().alphaEff(alphat, patchi); } return talphaEff; } Foam::tmp Foam::multiphaseMixtureThermo::rCv() const { PtrDictionary::const_iterator phasei = phases_.begin(); tmp trCv(phasei()/phasei().thermo().Cv()); for (++phasei; phasei != phases_.end(); ++phasei) { trCv.ref() += phasei()/phasei().thermo().Cv(); } return trCv; } Foam::tmp Foam::multiphaseMixtureThermo::surfaceTensionForce() const { tmp tstf ( new surfaceScalarField ( IOobject ( "surfaceTensionForce", mesh_.time().timeName(), mesh_ ), mesh_, dimensionedScalar ( "surfaceTensionForce", dimensionSet(1, -2, -2, 0, 0), 0.0 ) ) ); surfaceScalarField& stf = tstf.ref(); forAllConstIter(PtrDictionary, phases_, phase1) { const phaseModel& alpha1 = phase1(); PtrDictionary::const_iterator phase2 = phase1; ++phase2; for (; phase2 != phases_.end(); ++phase2) { const phaseModel& alpha2 = phase2(); sigmaTable::const_iterator sigma = sigmas_.find(interfacePair(alpha1, alpha2)); if (sigma == sigmas_.end()) { 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::multiphaseMixtureThermo::solve() { const Time& runTime = mesh_.time(); const dictionary& alphaControls = mesh_.solverDict("alpha"); label nAlphaSubCycles(readLabel(alphaControls.lookup("nAlphaSubCycles"))); scalar cAlpha(readScalar(alphaControls.lookup("cAlpha"))); volScalarField& alpha = phases_.first(); if (nAlphaSubCycles > 1) { surfaceScalarField rhoPhiSum(0.0*rhoPhi_); dimensionedScalar totalDeltaT = runTime.deltaT(); for ( subCycle alphaSubCycle(alpha, nAlphaSubCycles); !(++alphaSubCycle).end(); ) { solveAlphas(cAlpha); rhoPhiSum += (runTime.deltaT()/totalDeltaT)*rhoPhi_; } rhoPhi_ = rhoPhiSum; } else { solveAlphas(cAlpha); } } Foam::tmp Foam::multiphaseMixtureThermo::nHatfv ( const volScalarField& alpha1, const volScalarField& alpha2 ) const { /* // Cell gradient of alpha volVectorField gradAlpha = alpha2*fvc::grad(alpha1) - alpha1*fvc::grad(alpha2); // Interpolated face-gradient of alpha surfaceVectorField gradAlphaf = fvc::interpolate(gradAlpha); */ surfaceVectorField gradAlphaf ( fvc::interpolate(alpha2)*fvc::interpolate(fvc::grad(alpha1)) - fvc::interpolate(alpha1)*fvc::interpolate(fvc::grad(alpha2)) ); // Face unit interface normal return gradAlphaf/(mag(gradAlphaf) + deltaN_); } Foam::tmp Foam::multiphaseMixtureThermo::nHatf ( const volScalarField& alpha1, const volScalarField& alpha2 ) const { // Face unit interface normal flux return nHatfv(alpha1, alpha2) & mesh_.Sf(); } // 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::multiphaseMixtureThermo::correctContactAngle ( const phaseModel& alpha1, const phaseModel& alpha2, surfaceVectorField::Boundary& nHatb ) const { const volScalarField::Boundary& gbf = alpha1.boundaryField(); const fvBoundaryMesh& boundary = mesh_.boundary(); forAll(boundary, patchi) { if (isA(gbf[patchi])) { const alphaContactAngleFvPatchScalarField& acap = refCast(gbf[patchi]); vectorField& nHatPatch = nHatb[patchi]; vectorField AfHatPatch ( mesh_.Sf().boundaryField()[patchi] /mesh_.magSf().boundaryField()[patchi] ); alphaContactAngleFvPatchScalarField::thetaPropsTable:: const_iterator tp = acap.thetaProps().find(interfacePair(alpha1, alpha2)); if (tp == acap.thetaProps().end()) { FatalErrorInFunction << "Cannot find interface " << interfacePair(alpha1, alpha2) << "\n in table of theta properties for patch " << acap.patch().name() << exit(FatalError); } bool matched = (tp.key().first() == alpha1.name()); scalar theta0 = convertToRad*tp().theta0(matched); scalarField theta(boundary[patchi].size(), theta0); scalar uTheta = tp().uTheta(); // Calculate the dynamic contact angle if required if (uTheta > SMALL) { scalar thetaA = convertToRad*tp().thetaA(matched); scalar thetaR = convertToRad*tp().thetaR(matched); // 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 ); // Normalise nWall nWall /= (mag(nWall) + SMALL); // Calculate Uwall resolved normal to the interface parallel to // the interface scalarField uwall(nWall & Uwall); theta += (thetaA - thetaR)*tanh(uwall/uTheta); } // Reset nHatPatch to correspond to the contact angle scalarField a12(nHatPatch & AfHatPatch); scalarField b1(cos(theta)); scalarField b2(nHatPatch.size()); 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()); } } } Foam::tmp Foam::multiphaseMixtureThermo::K ( const phaseModel& alpha1, const phaseModel& alpha2 ) const { tmp tnHatfv = nHatfv(alpha1, alpha2); correctContactAngle(alpha1, alpha2, tnHatfv.ref().boundaryFieldRef()); // Simple expression for curvature return -fvc::div(tnHatfv & mesh_.Sf()); } Foam::tmp Foam::multiphaseMixtureThermo::nearInterface() const { tmp tnearInt ( new volScalarField ( IOobject ( "nearInterface", mesh_.time().timeName(), mesh_ ), mesh_, dimensionedScalar("nearInterface", dimless, 0.0) ) ); forAllConstIter(PtrDictionary, phases_, phase) { tnearInt.ref() = max(tnearInt(), pos(phase() - 0.01)*pos(0.99 - phase())); } return tnearInt; } void Foam::multiphaseMixtureThermo::solveAlphas ( const scalar cAlpha ) { static label nSolves=-1; nSolves++; word alphaScheme("div(phi,alpha)"); word alpharScheme("div(phirb,alpha)"); surfaceScalarField phic(mag(phi_/mesh_.magSf())); phic = min(cAlpha*phic, max(phic)); PtrList alphaPhiCorrs(phases_.size()); int phasei = 0; forAllIter(PtrDictionary, phases_, phase) { phaseModel& alpha = phase(); alphaPhiCorrs.set ( phasei, new surfaceScalarField ( phi_.name() + alpha.name(), fvc::flux ( phi_, alpha, alphaScheme ) ) ); surfaceScalarField& alphaPhiCorr = alphaPhiCorrs[phasei]; forAllIter(PtrDictionary, phases_, phase2) { phaseModel& alpha2 = phase2(); if (&alpha2 == &alpha) continue; surfaceScalarField phir(phic*nHatf(alpha, alpha2)); alphaPhiCorr += fvc::flux ( -fvc::flux(-phir, alpha2, alpharScheme), alpha, alpharScheme ); } MULES::limit ( 1.0/mesh_.time().deltaT().value(), geometricOneField(), alpha, phi_, alphaPhiCorr, zeroField(), zeroField(), 1, 0, true ); phasei++; } MULES::limitSum(alphaPhiCorrs); rhoPhi_ = dimensionedScalar("0", dimensionSet(1, 0, -1, 0, 0), 0); volScalarField sumAlpha ( IOobject ( "sumAlpha", mesh_.time().timeName(), mesh_ ), mesh_, dimensionedScalar("sumAlpha", dimless, 0) ); volScalarField divU(fvc::div(fvc::absolute(phi_, U_))); phasei = 0; forAllIter(PtrDictionary, phases_, phase) { phaseModel& alpha = phase(); surfaceScalarField& alphaPhi = alphaPhiCorrs[phasei]; alphaPhi += upwind(mesh_, phi_).flux(alpha); volScalarField::Internal Sp ( IOobject ( "Sp", mesh_.time().timeName(), mesh_ ), mesh_, dimensionedScalar("Sp", alpha.dgdt().dimensions(), 0.0) ); volScalarField::Internal Su ( IOobject ( "Su", mesh_.time().timeName(), mesh_ ), // Divergence term is handled explicitly to be // consistent with the explicit transport solution divU*min(alpha, scalar(1)) ); { const scalarField& dgdt = alpha.dgdt(); forAll(dgdt, celli) { if (dgdt[celli] < 0.0 && alpha[celli] > 0.0) { Sp[celli] += dgdt[celli]*alpha[celli]; Su[celli] -= dgdt[celli]*alpha[celli]; } else if (dgdt[celli] > 0.0 && alpha[celli] < 1.0) { Sp[celli] -= dgdt[celli]*(1.0 - alpha[celli]); } } } forAllConstIter(PtrDictionary, phases_, phase2) { const phaseModel& alpha2 = phase2(); if (&alpha2 == &alpha) continue; const scalarField& dgdt2 = alpha2.dgdt(); forAll(dgdt2, celli) { if (dgdt2[celli] > 0.0 && alpha2[celli] < 1.0) { Sp[celli] -= dgdt2[celli]*(1.0 - alpha2[celli]); Su[celli] += dgdt2[celli]*alpha[celli]; } else if (dgdt2[celli] < 0.0 && alpha2[celli] > 0.0) { Sp[celli] += dgdt2[celli]*alpha2[celli]; } } } MULES::explicitSolve ( geometricOneField(), alpha, alphaPhi, Sp, Su ); rhoPhi_ += fvc::interpolate(alpha.thermo().rho())*alphaPhi; Info<< alpha.name() << " volume fraction, min, max = " << alpha.weightedAverage(mesh_.V()).value() << ' ' << min(alpha).value() << ' ' << max(alpha).value() << endl; sumAlpha += alpha; phasei++; } Info<< "Phase-sum volume fraction, min, max = " << sumAlpha.weightedAverage(mesh_.V()).value() << ' ' << min(sumAlpha).value() << ' ' << max(sumAlpha).value() << endl; calcAlphas(); } // ************************************************************************* //