/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | foam-extend: Open Source CFD \\ / O peration | Version: 4.0 \\ / 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 . \*---------------------------------------------------------------------------*/ #include "freeSurface.H" #include "primitivePatchInterpolation.H" #include "wedgeFaPatch.H" #include "wallFvPatch.H" #include "wedgeFaPatchFields.H" #include "slipFaPatchFields.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // namespace Foam { // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // void freeSurface::makeInterpolators() { if (debug) { Info<< "freeSurface::makeInterpolators() : " << "making pathc to patch interpolator" << endl; } // It is an error to attempt to recalculate // if the pointer is already set if ( interpolatorBAPtr_ || interpolatorABPtr_ ) { FatalErrorIn("freeSurface::makeInterpolators()") << "patch to patch interpolators already exists" << abort(FatalError); } if(aPatchID() == -1) { FatalErrorIn("freeSurface::makeInterpolators()") << "Free surface patch A not defined." << abort(FatalError); } if(bPatchID() == -1) { FatalErrorIn("freeSurface::makeInterpolators()") << "Free surface patch B not defined." << abort(FatalError); } // patchToPatchInterpolation::setDirectHitTol(1e-2); interpolatorBAPtr_ = new IOpatchToPatchInterpolation ( IOobject ( "baInterpolator", DB().timeName(), mesh(), IOobject::READ_IF_PRESENT, IOobject::AUTO_WRITE ), mesh().boundaryMesh()[bPatchID()], mesh().boundaryMesh()[aPatchID()], intersection::VISIBLE // intersection::HALF_RAY ); const scalarField& faceDistBA = interpolatorBAPtr_->faceDistanceToIntersection(); forAll(faceDistBA, faceI) { if(mag(faceDistBA[faceI] - GREAT) < SMALL) { FatalErrorIn("freeSurface::makeInterpolators()") << "Error in B-to-A face patchToPatchInterpolation." << abort(FatalError); } } const scalarField& pointDistBA = interpolatorBAPtr_->pointDistanceToIntersection(); forAll(pointDistBA, pointI) { if(mag(pointDistBA[pointI] - GREAT) < SMALL) { FatalErrorIn("freeSurface::makeInterpolators()") << "Error in B-to-A point patchToPatchInterpolation." << abort(FatalError); } } interpolatorABPtr_ = new IOpatchToPatchInterpolation ( IOobject ( "abInterpolator", DB().timeName(), mesh(), IOobject::READ_IF_PRESENT, IOobject::AUTO_WRITE ), mesh().boundaryMesh()[aPatchID()], mesh().boundaryMesh()[bPatchID()], intersection::VISIBLE // intersection::HALF_RAY ); const scalarField& faceDistAB = interpolatorABPtr_->faceDistanceToIntersection(); forAll(faceDistAB, faceI) { if(mag(faceDistAB[faceI] - GREAT) < SMALL) { FatalErrorIn("freeSurface::makeInterpolators()") << "Error in A-to-B face patchToPatchInterpolation." << abort(FatalError); } } const scalarField& pointDistAB = interpolatorABPtr_->pointDistanceToIntersection(); forAll(pointDistAB, pointI) { if(mag(pointDistAB[pointI] - GREAT)faceInterpolate ( vectorField(mesh().boundaryMesh()[aPatchID()] .faceCentres()) ) - mesh().boundaryMesh()[bPatchID()].faceCentres() ) ); scalar maxDistPt = max ( mag ( interpolatorABPtr_->pointInterpolate ( vectorField(mesh().boundaryMesh()[aPatchID()] .localPoints()) ) - mesh().boundaryMesh()[bPatchID()].localPoints() ) ); Info << "A-to-B interpolation error, face: " << maxDist << ", point: " << maxDistPt << endl; maxDist = max ( mag ( interpolatorBAPtr_->faceInterpolate ( vectorField ( mesh().boundaryMesh()[bPatchID()].faceCentres() ) ) - mesh().boundaryMesh()[aPatchID()].faceCentres() ) ); maxDistPt = max ( mag ( interpolatorBAPtr_->pointInterpolate ( vectorField ( mesh().boundaryMesh()[bPatchID()].localPoints() ) ) - mesh().boundaryMesh()[aPatchID()].localPoints() ) ); Info << "B-to-A interpolation error, face: " << maxDist << ", point: " << maxDistPt << endl; } void freeSurface::makeControlPoints() { if (debug) { Info<< "freeSurface::makeControlPoints() : " << "making control points" << endl; } // It is an error to attempt to recalculate // if the pointer is already set if (controlPointsPtr_) { FatalErrorIn("freeSurface::makeInterpolators()") << "patch to patch interpolators already exists" << abort(FatalError); } IOobject controlPointsHeader ( "controlPoints", DB().timeName(), mesh(), IOobject::MUST_READ ); if (controlPointsHeader.headerOk()) { controlPointsPtr_ = new vectorIOField ( IOobject ( "controlPoints", DB().timeName(), mesh(), IOobject::MUST_READ, IOobject::AUTO_WRITE ) ); } else { controlPointsPtr_ = new vectorIOField ( IOobject ( "controlPoints", DB().timeName(), mesh(), IOobject::NO_READ, IOobject::AUTO_WRITE ), aMesh().areaCentres().internalField() ); initializeControlPointsPosition(); } } void freeSurface::makeMotionPointsMask() { if (debug) { Info<< "freeSurface::makeMotionPointsMask() : " << "making motion points mask" << endl; } // It is an error to attempt to recalculate // if the pointer is already set if (motionPointsMaskPtr_) { FatalErrorIn("freeSurface::motionPointsMask()") << "motion points mask already exists" << abort(FatalError); } if(aPatchID() == -1) { FatalErrorIn("freeSurface::makeMotionPointsMask()") << "Free surface patch A not defined." << abort(FatalError); } motionPointsMaskPtr_ = new labelList ( mesh().boundaryMesh()[aPatchID()].nPoints(), 1 ); } void freeSurface::makeDirections() { if (debug) { Info<< "freeSurface::makeDirections() : " << "making displacement directions for points and " << "control points" << endl; } // It is an error to attempt to recalculate // if the pointer is already set if ( pointsDisplacementDirPtr_ || facesDisplacementDirPtr_ ) { FatalErrorIn("freeSurface::makeDirections()") << "points and control points displacement directions " << "already exists" << abort(FatalError); } if(aPatchID() == -1) { FatalErrorIn("freeSurface::makeDirections()") << "Free surface patch A not defined." << abort(FatalError); } pointsDisplacementDirPtr_ = new vectorField ( mesh().boundaryMesh()[aPatchID()].nPoints(), vector::zero ); facesDisplacementDirPtr_ = new vectorField ( mesh().boundaryMesh()[aPatchID()].size(), vector::zero ); if(!normalMotionDir()) { if(mag(motionDir_) < SMALL) { FatalErrorIn("freeSurface::makeDirections()") << "Zero motion direction" << abort(FatalError); } facesDisplacementDir() = motionDir_; pointsDisplacementDir() = motionDir_; } updateDisplacementDirections(); } void freeSurface::makeTotalDisplacement() { if (debug) { Info<< "freeSurface::makeTotalDisplacement() : " << "making zero total points displacement" << endl; } // It is an error to attempt to recalculate // if the pointer is already set if (totalDisplacementPtr_) { FatalErrorIn("freeSurface::makeTotalDisplacement()") << "total points displacement already exists" << abort(FatalError); } totalDisplacementPtr_ = new vectorIOField ( IOobject ( "totalDisplacement", DB().timeName(), mesh(), IOobject::NO_READ, IOobject::AUTO_WRITE ), vectorField ( mesh().boundaryMesh()[aPatchID()].nPoints(), vector::zero ) ); } void freeSurface::readTotalDisplacement() { if (debug) { Info<< "freeSurface::readTotalDisplacement() : " << "reading total points displacement if present" << endl; } // It is an error to attempt to recalculate // if the pointer is already set if (totalDisplacementPtr_) { FatalErrorIn("freeSurface::makeTotalDisplacement()") << "total points displacement already exists" << abort(FatalError); } if ( IOobject ( "totalDisplacement", DB().timeName(), mesh(), IOobject::MUST_READ, IOobject::AUTO_WRITE ).headerOk() ) { totalDisplacementPtr_ = new vectorIOField ( IOobject ( "totalDisplacement", DB().timeName(), mesh(), IOobject::MUST_READ, IOobject::AUTO_WRITE ) ); } } void freeSurface::makeFaMesh() const { if (debug) { Info<< "freeSurface::makeFaMesh() : " << "making finite area mesh" << endl; } // It is an error to attempt to recalculate // if the pointer is already set if (aMeshPtr_) { FatalErrorIn("freeSurface::makeFaMesh()") << "finite area mesh already exists" << abort(FatalError); } aMeshPtr_ = new faMesh(mesh()); } void freeSurface::makeUs() const { if (debug) { Info<< "freeSurface::makeUs() : " << "making free-surface velocity field" << endl; } // It is an error to attempt to recalculate // if the pointer is already set if (UsPtr_) { FatalErrorIn("freeSurface::makeUs()") << "free-surface velocity field already exists" << abort(FatalError); } wordList patchFieldTypes ( aMesh().boundary().size(), zeroGradientFaPatchVectorField::typeName ); forAll(aMesh().boundary(), patchI) { if ( aMesh().boundary()[patchI].type() == wedgeFaPatch::typeName ) { patchFieldTypes[patchI] = wedgeFaPatchVectorField::typeName; } else { label ngbPolyPatchID = aMesh().boundary()[patchI].ngbPolyPatchIndex(); if (ngbPolyPatchID != -1) { if ( mesh().boundary()[ngbPolyPatchID].type() == wallFvPatch::typeName ) { patchFieldTypes[patchI] = slipFaPatchVectorField::typeName; } } } } UsPtr_ = new areaVectorField ( IOobject ( "Us", DB().timeName(), mesh(), IOobject::NO_READ, IOobject::NO_WRITE ), aMesh(), dimensioned("Us", dimVelocity, vector::zero), patchFieldTypes ); } void freeSurface::makePhis() { if (debug) { Info<< "freeSurface::makePhis() : " << "making free-surface fluid flux" << endl; } // It is an error to attempt to recalculate // if the pointer is already set if (phisPtr_) { FatalErrorIn("freeSurface::makePhis()") << "free-surface fluid flux already exists" << abort(FatalError); } phisPtr_ = new edgeScalarField ( IOobject ( "phis", DB().timeName(), mesh(), IOobject::NO_READ, IOobject::NO_WRITE ), linearEdgeInterpolate(Us()) & aMesh().Le() ); } void freeSurface::makeSurfactConc() const { if (debug) { Info<< "freeSurface::makeSurfactConc() : " << "making free-surface surfactant concentration field" << endl; } // It is an error to attempt to recalculate // if the pointer is already set if (surfactConcPtr_) { FatalErrorIn("freeSurface::makeSurfaceConc()") << "free-surface surfactant concentratio field already exists" << abort(FatalError); } surfactConcPtr_ = new areaScalarField ( IOobject ( "Cs", DB().timeName(), mesh(), IOobject::MUST_READ, IOobject::AUTO_WRITE ), aMesh() ); } void freeSurface::makeSurfaceTension() const { if (debug) { Info<< "freeSurface::makeSurfaceTension() : " << "making surface tension field" << endl; } // It is an error to attempt to recalculate // if the pointer is already set if (surfaceTensionPtr_) { FatalErrorIn("freeSurface::makeSurfaceTension()") << "surface tension field already exists" << abort(FatalError); } surfaceTensionPtr_ = new areaScalarField ( IOobject ( "surfaceTension", DB().timeName(), mesh(), IOobject::NO_READ, IOobject::NO_WRITE ), cleanInterfaceSurfTension() + surfactant().surfactR()* surfactant().surfactT()* surfactant().surfactSaturatedConc()* log(1.0 - surfactantConcentration()/ surfactant().surfactSaturatedConc()) ); } void freeSurface::makeSurfactant() const { if (debug) { Info<< "freeSurface::makeSurfactant() : " << "making surfactant properties" << endl; } // It is an error to attempt to recalculate // if the pointer is already set if (surfactantPtr_) { FatalErrorIn("freeSurface::makeSurfactant()") << "surfactant properties already exists" << abort(FatalError); } const dictionary& surfactProp = this->subDict("surfactantProperties"); surfactantPtr_ = new surfactantProperties(surfactProp); } void freeSurface::makeFluidIndicator() { if (debug) { Info<< "freeSurface::makeFluidIndicator() : " << "making fluid indicator" << endl; } // It is an error to attempt to recalculate // if the pointer is already set if (fluidIndicatorPtr_) { FatalErrorIn("freeSurface::makeFluidIndicator()") << "fluid indicator already exists" << abort(FatalError); } fluidIndicatorPtr_ = new volScalarField ( IOobject ( "fluidIndicator", DB().timeName(), mesh(), IOobject::NO_READ, IOobject::NO_WRITE ), mesh(), dimensionedScalar("1", dimless, 1.0), zeroGradientFvPatchScalarField::typeName ); volScalarField& fluidIndicator = *fluidIndicatorPtr_; if (twoFluids()) { // find start cell label pointOnShadowPatch = mesh().boundaryMesh()[bPatchID()][0][0]; label startCell = mesh().pointCells()[pointOnShadowPatch][0]; // get cell-cells addressing const labelListList& cellCells = mesh().cellCells(); SLList