/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | foam-extend: Open Source CFD \\ / O peration | Version: 4.1 \\ / A nd | Web: http://www.foam-extend.org \\/ M anipulation | For copyright notice see file Copyright ------------------------------------------------------------------------------- License This file is part of foam-extend. foam-extend 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. foam-extend 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 foam-extend. If not, see . Author Hrvoje Jasak, Wikki Ltd. All rights reserved \*----------------------------------------------------------------------------*/ #include "bubbleHistory.H" #include "addToRunTimeSelectionTable.H" #include "volFields.H" #include "boundBox.H" #include "freeSurface.H" // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // namespace Foam { defineTypeNameAndDebug(bubbleHistory, 0); addToRunTimeSelectionTable ( functionObject, bubbleHistory, dictionary ); } // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // Foam::bubbleHistory::bubbleHistory ( const word& name, const Time& t, const dictionary& dict ) : functionObject(name), name_(name), time_(t), regionName_(polyMesh::defaultRegion), V0_(SMALL), historyFilePtr_(nullptr) { if (dict.found("region")) { dict.lookup("region") >> regionName_; } if (Pstream::master()) { if (!time_.processorCase()) { mkDir ( time_.path() /"history" /time_.timeName() ); historyFilePtr_ = new OFstream ( time_.path() /"history" /time_.timeName() /"history.dat" ); } else { mkDir ( time_.path()/".."/"history" /time_.timeName() ); historyFilePtr_ = new OFstream ( time_.path()/".." /"history" /time_.timeName() /"history.dat" ); } (*historyFilePtr_) << "Time" << tab << "Cx" << tab << "Cy" << tab << "Cz" << tab << "Ux" << tab << "Uy" << tab << "Uz" << tab << "ax" << tab << "ay" << tab << "az" << tab << "Fx" << tab << "Fy" << tab << "Fz" << tab << "D" << tab << "Lx" << tab << "Ly" << tab << "Lz" << tab << "CD" << tab << "CVM" << tab << "RE" << tab << "WE" << tab << "V/V0" << tab << "A" << tab << "B" << tab << "C" << endl; } const fvMesh& mesh = time_.lookupObject(regionName_); const volScalarField& fluidIndicator = mesh.lookupObject("fluidIndicator"); V0_ = gSum((1 - fluidIndicator.internalField())*mesh.V().field()); const freeSurface& fs = mesh.lookupObject("freeSurfaceProperties"); if (!fs.twoFluids()) { V0_ = - gSum ( mesh.Cf().boundaryField()[fs.aPatchID()] & mesh.Sf().boundaryField()[fs.aPatchID()] )/3; if (mesh.nGeometricD() != 3) { FatalErrorIn("bubbleHistory::") << "One-fluid bubble centroid calc " << "is not implemented for 2d mesh" << abort(FatalError); } } } // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // bool Foam::bubbleHistory::start() { const fvMesh& mesh = time_.lookupObject(regionName_); const volScalarField& fluidIndicator = mesh.lookupObject("fluidIndicator"); const freeSurface& fs = mesh.lookupObject("freeSurfaceProperties"); scalar V = gSum((1 - fluidIndicator.internalField())*mesh.V().field()); if (!fs.twoFluids()) { V = - gSum ( mesh.Cf().boundaryField()[fs.aPatchID()] & mesh.Sf().boundaryField()[fs.aPatchID()] )/3; if (mesh.nGeometricD() != 3) { FatalErrorIn("bubbleHistory::") << "One-fluid bubble centroid calc " << "is not implemented for 2d mesh" << abort(FatalError); } } const IOdictionary& mrf = mesh.lookupObject("movingReferenceFrame"); dimensionedVector C(mrf.lookup("XF")); dimensionedVector U(mrf.lookup("UF")); dimensionedVector a(mrf.lookup("aF")); vector F = fs.totalViscousForce() + fs.totalPressureForce(); vector dragDir; if(mag(U.value()) > SMALL) { dragDir = -U.value()/mag(U.value()); } else { dragDir = fs.g().value()/(mag(fs.g().value()) + SMALL); } scalar dragForce = (dragDir&F); vector liftForce = transform(I - dragDir*dragDir, F); scalar Deq = 2*pow(3*V/(4*M_PI), 1.0/3.0); scalar Ug = -(U.value()&(fs.g().value()/(mag(fs.g().value()) + SMALL))); scalar CD = (4.0/3.0)*(fs.rhoFluidA().value() - fs.rhoFluidB().value()) *mag(fs.g().value())*Deq /(fs.rhoFluidA().value()*mag(U.value())*Ug + SMALL); scalar ag = -(a.value()&(fs.g().value()/(mag(fs.g().value()) + SMALL))); scalar CVM = (fs.rhoFluidA().value() - fs.rhoFluidB().value())*mag(fs.g().value()) /(fs.rhoFluidA().value()*ag + SMALL) - (fs.rhoFluidB().value()/(fs.rhoFluidA().value() + SMALL)); scalar RE = Ug*Deq*fs.rhoFluidA().value()/(fs.muFluidA().value() + SMALL); scalar WE = fs.rhoFluidA().value()*sqr(Ug)*Deq /(fs.cleanInterfaceSurfTension().value() + SMALL); boundBox box(mesh.C().boundaryField()[fs.aPatchID()]); if (Pstream::master()) { historyFilePtr_->precision(12); (*historyFilePtr_) << time_.value() << tab << C.value().x() << tab << C.value().y() << tab << C.value().z() << tab << U.value().x() << tab << U.value().y() << tab << U.value().z() << tab << a.value().x() << tab << a.value().y() << tab << a.value().z() << tab << F.x() << tab << F.y() << tab << F.z() << tab << dragForce << tab << liftForce.x() << tab << liftForce.y() << tab << liftForce.z() << tab << CD << tab << CVM << tab << RE << tab << WE << tab << mag(1.0 - V/V0_) << tab << (box.max().x()-box.min().x())/2 << tab << (box.max().y()-box.min().y())/2 << tab << (box.max().z()-box.min().z())/2 << endl; return true; } return false; } bool Foam::bubbleHistory::execute(const bool forceWrite) { const fvMesh& mesh = time_.lookupObject(regionName_); const volScalarField& fluidIndicator = mesh.lookupObject("fluidIndicator"); const freeSurface& fs = mesh.lookupObject("freeSurfaceProperties"); scalar V = gSum((1 - fluidIndicator.internalField())*mesh.V().field()); if (!fs.twoFluids()) { V = - gSum ( mesh.Cf().boundaryField()[fs.aPatchID()] & mesh.Sf().boundaryField()[fs.aPatchID()] )/3; if (mesh.nGeometricD() != 3) { FatalErrorIn("bubbleHistory") << "One-fluid bubble centroid calc " << "is not implemented for 2d mesh" << abort(FatalError); } } const IOdictionary& mrf = mesh.lookupObject("movingReferenceFrame"); dimensionedVector C(mrf.lookup("XF")); dimensionedVector U(mrf.lookup("UF")); dimensionedVector a(mrf.lookup("aF")); vector F = fs.totalViscousForce() + fs.totalPressureForce(); vector dragDir; if(mag(U.value()) > SMALL) { dragDir = -U.value()/mag(U.value()); } else { dragDir = fs.g().value()/(mag(fs.g().value()) + SMALL); } scalar dragForce = (dragDir&F); vector liftForce = transform(I - dragDir*dragDir, F); scalar Deq = pow(3*V/(4*M_PI), 1.0/3.0); scalar Ug = -(U.value()&(fs.g().value()/(mag(fs.g().value()) + SMALL))); scalar CD = (4.0/3.0)*(fs.rhoFluidA().value() - fs.rhoFluidB().value()) *mag(fs.g().value())*Deq /(fs.rhoFluidA().value()*mag(U.value())*Ug + SMALL); scalar ag = -(a.value()&(fs.g().value()/(mag(fs.g().value()) + SMALL))); scalar CVM = (fs.rhoFluidA().value() - fs.rhoFluidB().value())*mag(fs.g().value()) /(fs.rhoFluidA().value()*ag + SMALL) - (fs.rhoFluidB().value()/(fs.rhoFluidA().value() + SMALL)); scalar RE = Ug*Deq*fs.rhoFluidA().value()/(fs.muFluidA().value() + SMALL); scalar WE = fs.rhoFluidA().value()*sqr(Ug)*Deq /(fs.cleanInterfaceSurfTension().value() + SMALL); boundBox box(mesh.C().boundaryField()[fs.aPatchID()]); if (Pstream::master()) { historyFilePtr_->precision(12); (*historyFilePtr_) << time_.value() << tab << C.value().x() << tab << C.value().y() << tab << C.value().z() << tab << U.value().x() << tab << U.value().y() << tab << U.value().z() << tab << a.value().x() << tab << a.value().y() << tab << a.value().z() << tab << F.x() << tab << F.y() << tab << F.z() << tab << dragForce << tab << liftForce.x() << tab << liftForce.y() << tab << liftForce.z() << tab << CD << tab << CVM << tab << RE << tab << WE << tab << mag(1.0 - V/V0_) << tab << (box.max().x()-box.min().x())/2 << tab << (box.max().y()-box.min().y())/2 << tab << (box.max().z()-box.min().z())/2 << endl; return true; } return false; } bool Foam::bubbleHistory::setTime() { return true; } bool Foam::bubbleHistory::read(const dictionary& dict) { if (dict.found("region")) { dict.lookup("region") >> regionName_; } return true; } // ************************************************************************* //