diff --git a/src/functionObjects/field/Make/files b/src/functionObjects/field/Make/files index 6746b0b4a1..86eb165e04 100644 --- a/src/functionObjects/field/Make/files +++ b/src/functionObjects/field/Make/files @@ -96,4 +96,6 @@ flux/flux.C ddt2/ddt2.C zeroGradient/zeroGradient.C +stabilityBlendingFactor/stabilityBlendingFactor.C + LIB = $(FOAM_LIBBIN)/libfieldFunctionObjects diff --git a/src/functionObjects/field/stabilityBlendingFactor/stabilityBlendingFactor.C b/src/functionObjects/field/stabilityBlendingFactor/stabilityBlendingFactor.C new file mode 100644 index 0000000000..a67339b00f --- /dev/null +++ b/src/functionObjects/field/stabilityBlendingFactor/stabilityBlendingFactor.C @@ -0,0 +1,647 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2018 OpenCFD Ltd. + \\/ 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 "stabilityBlendingFactor.H" +#include "addToRunTimeSelectionTable.H" +#include "zeroGradientFvPatchFields.H" +#include "fvcGrad.H" +#include "surfaceInterpolate.H" + +// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // + +namespace Foam +{ +namespace functionObjects +{ + defineTypeNameAndDebug(stabilityBlendingFactor, 0); + addToRunTimeSelectionTable + ( + functionObject, + stabilityBlendingFactor, + dictionary + ); +} +} + + +// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // + +void Foam::functionObjects::stabilityBlendingFactor::writeFileHeader +( + Ostream& os +) const +{ + writeHeader(os, "Stabilization blending factor"); + writeCommented(os, "Time"); + writeTabbed(os, "Scheme1"); + writeTabbed(os, "Scheme2"); + writeTabbed(os, "Blended"); + os << endl; +} + +bool Foam::functionObjects::stabilityBlendingFactor::calc() +{ + init(true); + return true; +} + + +bool Foam::functionObjects::stabilityBlendingFactor::init(bool first) +{ + + const IOField* residualPtr = + mesh_.lookupObjectPtr>(residualName_); + + if (residuals_) + { + if (!residualPtr) + { + WarningInFunction + << residualName_ << " is not available in the database." + << "It won't be considered for the blended field. " << nl + << "Add the corresponding FO (residuals). If the FO is already " + << "set, you need to wait for the first iteration." + << endl; + + } + else + { + scalar meanRes = gAverage(mag(*residualPtr)) + VSMALL; + + if (log) + { + Log << " Average(mag(residuals)) : " << meanRes << endl; + } + + oldError_ = error_; + oldErrorIntegral_ = errorIntegral_; + error_ = mag(meanRes - mag(*residualPtr)); + errorIntegral_ = oldErrorIntegral_ + 0.5*(error_ + oldError_); + const scalarField errorDifferential = error_ - oldError_; + + const scalarField factorList + ( + + P_*error_ + + I_*errorIntegral_ + + D_*errorDifferential + ); + + const scalarField indicatorResidual + ( + max + ( + min + ( + mag(factorList - meanRes)/(maxResidual_*meanRes), + 1.0 + ), + 0.0 + ) + ); + + forAll (indicator_, i) + { + indicator_[i] = indicatorResidual[i]; + } + } + } + + const volScalarField* nonOrthPtr = + mesh_.lookupObjectPtr(nonOrthogonalityName_); + + if (nonOrthogonality_) + { + indicator_ = + max + ( + indicator_, + min + ( + max + ( + 0.0, + (*nonOrthPtr - maxNonOrthogonality_) + /(minNonOrthogonality_ - maxNonOrthogonality_) + ), + 1.0 + ) + ); + + if (log) + { + Log << " Max non-orthogonality : " << max(*nonOrthPtr).value() + << endl; + } + } + + const volScalarField* skewnessPtr = + mesh_.lookupObjectPtr(skewnessName_); + + if (skewness_) + { + indicator_ = + max + ( + indicator_, + min + ( + max + ( + 0.0, + (*skewnessPtr - maxSkewness_) + / (minSkewness_ - maxSkewness_) + ), + 1.0 + ) + ); + + if (log) + { + Log << " Max skewness : " << max(*skewnessPtr).value() + << endl; + } + } + + const volScalarField* faceWeightsPtr = + mesh_.lookupObjectPtr(faceWeightName_); + + if (faceWeight_) + { + indicator_ = + max + ( + indicator_, + min + ( + max + ( + 0.0, + (minFaceWeight_ - *faceWeightsPtr) + / (minFaceWeight_ - maxFaceWeight_) + ), + 1.0 + ) + ); + + if (log) + { + Log << " Min face weight: " << min(*faceWeightsPtr).value() + << endl; + } + } + + + if (gradCc_) + { + tmp magGradCCPtr + ( + new volScalarField + ( + IOobject + ( + "magGradCC", + time_.timeName(), + mesh_, + IOobject::NO_READ, + IOobject::NO_WRITE + ), + mesh_, + dimensionedScalar("0", dimless, Zero), + zeroGradientFvPatchScalarField::typeName + ) + ); + + for (direction i=0; i(UName_); + + if (Co_) + { + tmp CoPtr + ( + new volScalarField + ( + IOobject + ( + "Co", + time_.timeName(), + mesh_, + IOobject::NO_READ, + IOobject::NO_WRITE + ), + mesh_, + dimensionedScalar("0", dimless, Zero), + zeroGradientFvPatchScalarField::typeName + ) + ); + + volScalarField& Co = CoPtr.ref(); + + Co.primitiveFieldRef() = + mesh_.time().deltaT()*mag(*UNamePtr)/pow(mesh_.V(), 1.0/3.0); + + indicator_ = + max + ( + indicator_, + min(max(0.0, (Co - Co1_)/(Co2_ - Co1_)), 1.0) + ); + + if (log) + { + Log << " Max Co : " << max(Co).value() + << endl; + } + } + + indicator_.correctBoundaryConditions(); + indicator_.min(1.0); + indicator_.max(0.0); + + // Update the blended surface field + surfaceScalarField* surBlendedPtr = + ( + mesh_.lookupObjectRefPtr(resultName_) + ); + + *surBlendedPtr = fvc::interpolate(indicator_); + + return true; +} + + +// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // + +Foam::functionObjects::stabilityBlendingFactor::stabilityBlendingFactor +( + const word& name, + const Time& runTime, + const dictionary& dict +) +: + fieldExpression(name, runTime, dict), + writeFile(obr_, name, typeName, dict), + indicator_ + ( + IOobject + ( + "blendedIndicator", + time_.timeName(), + mesh_, + IOobject::NO_READ, + IOobject::NO_WRITE + ), + mesh_, + dimensionedScalar("0", dimless, 0.0), + zeroGradientFvPatchScalarField::typeName + ), + nonOrthogonality_(dict.lookupOrDefault("switchNonOrtho", false)), + gradCc_(dict.lookupOrDefault("switchGradCc", false)), + residuals_(dict.lookupOrDefault("switchResiduals", false)), + faceWeight_(dict.lookupOrDefault("switchFaceWeight", false)), + skewness_(dict.lookupOrDefault("switchSkewness", false)), + Co_(dict.lookupOrDefault("switchCo", false)), + + maxNonOrthogonality_ + ( + dict.lookupOrDefault("maxNonOrthogonality", 20.0) + ), + minNonOrthogonality_ + ( + dict.lookupOrDefault("minNonOrthogonality", 60.0) + ), + maxGradCc_(dict.lookupOrDefault("maxGradCc", 3.0)), + minGradCc_(dict.lookupOrDefault("minGradCc", 4.0)), + maxResidual_(dict.lookupOrDefault("maxResidual", 10.0)), + minFaceWeight_(dict.lookupOrDefault("minFaceWeight", 0.3)), + maxFaceWeight_(dict.lookupOrDefault("maxFaceWeight", 0.2)), + maxSkewness_(dict.lookupOrDefault("maxSkewness", 2.0)), + minSkewness_(dict.lookupOrDefault("minSkewness", 3.0)), + Co1_(dict.lookupOrDefault("Co1", 1.0)), + Co2_(dict.lookupOrDefault("Co2", 10.0)), + + nonOrthogonalityName_ + ( + dict.lookupOrDefault("nonOrthogonality", "nonOrthoAngle") + ), + faceWeightName_ + ( + dict.lookupOrDefault("faceWeight", "faceWeight") + ), + skewnessName_ + ( + dict.lookupOrDefault("skewness", "skewness") + ), + residualName_ + ( + dict.lookupOrDefault("residual", "initialResidual:p") + ), + UName_ + ( + dict.lookupOrDefault("U", "U") + ), + + tolerance_(0.001), + error_(mesh_.nCells(), 0.0), + errorIntegral_(mesh_.nCells(), 0.0), + oldError_(mesh_.nCells(), 0.0), + oldErrorIntegral_(mesh_.nCells(), 0.0), + P_(dict.lookupOrDefault("P", 3)), + I_(dict.lookupOrDefault("I", 0.0)), + D_(dict.lookupOrDefault("D", 0.25)) +{ + read(dict); + setResultName(typeName, ""); + + tmp faceBlendedPtr + ( + new surfaceScalarField + ( + IOobject + ( + resultName_, + time_.timeName(), + mesh_, + IOobject::NO_READ, + IOobject::NO_WRITE + ), + mesh_, + dimensionedScalar("0", dimless, 0.0) + ) + ); + store(resultName_, faceBlendedPtr); + + const volScalarField* nonOrthPtr = + mesh_.lookupObjectPtr(nonOrthogonalityName_); + + if (nonOrthogonality_) + { + if (!nonOrthPtr) + { + IOobject fieldHeader + ( + nonOrthogonalityName_, + mesh_.time().constant(), + mesh_, + IOobject::MUST_READ, + IOobject::NO_WRITE + ); + + if (fieldHeader.typeHeaderOk(true, true, false)) + { + volScalarField* vfPtr(new volScalarField(fieldHeader, mesh_)); + mesh_.objectRegistry::store(vfPtr); + } + else + { + FatalErrorInFunction + << "Field : " << nonOrthogonalityName_ << " not found." + << exit(FatalError); + } + } + } + + + const volScalarField* faceWeightsPtr = + mesh_.lookupObjectPtr(faceWeightName_); + + if (faceWeight_) + { + if (!faceWeightsPtr) + { + IOobject fieldHeader + ( + faceWeightName_, + mesh_.time().constant(), + mesh_, + IOobject::MUST_READ, + IOobject::NO_WRITE + ); + + if (fieldHeader.typeHeaderOk(true, true, false)) + { + volScalarField* vfPtr(new volScalarField(fieldHeader, mesh_)); + mesh_.objectRegistry::store(vfPtr); + } + else + { + FatalErrorInFunction + << "Field : " << faceWeightName_ << " not found." + << exit(FatalError); + } + } + } + + const volScalarField* skewnessPtr = + mesh_.lookupObjectPtr(skewnessName_); + + if (skewness_) + { + if (!skewnessPtr) + { + IOobject fieldHeader + ( + skewnessName_, + mesh_.time().constant(), + mesh_, + IOobject::MUST_READ, + IOobject::NO_WRITE + ); + + if (fieldHeader.typeHeaderOk(true, true, false)) + { + volScalarField* vfPtr(new volScalarField(fieldHeader, mesh_)); + mesh_.objectRegistry::store(vfPtr); + } + else + { + FatalErrorInFunction + << "Field : " << skewnessName_ << " not found." + << exit(FatalError); + } + } + } + + if (log) + { + indicator_.writeOpt() = IOobject::AUTO_WRITE; + } + + init(true); +} + + +// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // + +Foam::functionObjects::stabilityBlendingFactor::~stabilityBlendingFactor() +{} + + +// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // + +bool Foam::functionObjects::stabilityBlendingFactor::read +( + const dictionary& dict +) +{ + if (fieldExpression::read(dict) && writeFile::read(dict)) + { + dict.lookup("switchNonOrtho") >> nonOrthogonality_; + dict.lookup("switchGradCc") >> gradCc_; + dict.lookup("switchResiduals") >> residuals_; + dict.lookup("switchFaceWeight") >> faceWeight_; + dict.lookup("switchSkewness") >> skewness_; + dict.lookup("switchCo") >> Co_; + + dict.readIfPresent("maxNonOrthogonality", maxNonOrthogonality_); + dict.readIfPresent("maxGradCc", maxGradCc_); + dict.readIfPresent("maxResidual", maxResidual_); + dict.readIfPresent("maxSkewness", maxSkewness_); + dict.readIfPresent("maxFaceWeight", maxFaceWeight_); + dict.readIfPresent("Co2", Co2_); + + dict.readIfPresent("minFaceWeight", minFaceWeight_); + dict.readIfPresent("minNonOrthogonality", minNonOrthogonality_); + dict.readIfPresent("minGradCc", minGradCc_); + dict.readIfPresent("minSkewness", minSkewness_); + dict.readIfPresent("Co1", Co1_); + + + dict.readIfPresent("P", P_); + dict.readIfPresent("I", I_); + dict.readIfPresent("D", D_); + + tolerance_ = 0.001; + if + ( + dict.readIfPresent("tolerance", tolerance_) + && (tolerance_ < 0 || tolerance_ > 1) + ) + { + FatalErrorInFunction + << "tolerance must be in the range 0 to 1. Supplied value: " + << tolerance_ << exit(FatalError); + } + + return true; + } + else + { + return false; + } +} + + +bool Foam::functionObjects::stabilityBlendingFactor::write() +{ + // Generate scheme statistics + label nCellsScheme1 = 0; + label nCellsScheme2 = 0; + label nCellsBlended = 0; + forAll(indicator_, celli) + { + scalar i = indicator_[celli]; + + if (i < tolerance_) + { + nCellsScheme2++; + } + else if (i > (1 - tolerance_)) + { + nCellsScheme1++; + } + else + { + nCellsBlended++; + } + } + + reduce(nCellsScheme1, sumOp