/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
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 "advectiveFvPatchField.H"
#include "addToRunTimeSelectionTable.H"
#include "fvPatchFieldMapper.H"
#include "volFields.H"
#include "EulerDdtScheme.H"
#include "CrankNicolsonDdtScheme.H"
#include "backwardDdtScheme.H"
#include "localEulerDdtScheme.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template
Foam::advectiveFvPatchField::advectiveFvPatchField
(
const fvPatch& p,
const DimensionedField& iF
)
:
mixedFvPatchField(p, iF),
phiName_("phi"),
rhoName_("rho"),
fieldInf_(Zero),
lInf_(-GREAT)
{
this->refValue() = Zero;
this->refGrad() = Zero;
this->valueFraction() = 0.0;
}
template
Foam::advectiveFvPatchField::advectiveFvPatchField
(
const advectiveFvPatchField& ptf,
const fvPatch& p,
const DimensionedField& iF,
const fvPatchFieldMapper& mapper
)
:
mixedFvPatchField(ptf, p, iF, mapper),
phiName_(ptf.phiName_),
rhoName_(ptf.rhoName_),
fieldInf_(ptf.fieldInf_),
lInf_(ptf.lInf_)
{}
template
Foam::advectiveFvPatchField::advectiveFvPatchField
(
const fvPatch& p,
const DimensionedField& iF,
const dictionary& dict
)
:
mixedFvPatchField(p, iF),
phiName_(dict.getOrDefault("phi", "phi")),
rhoName_(dict.getOrDefault("rho", "rho")),
fieldInf_(Zero),
lInf_(-GREAT)
{
// Use 'value' supplied, or set to internal field
if (!this->readValueEntry(dict))
{
this->extrapolateInternal(); // Zero-gradient patch values
}
this->refValue() = *this;
this->refGrad() = Zero;
this->valueFraction() = 0;
if (dict.readIfPresent("lInf", lInf_))
{
dict.readEntry("fieldInf", fieldInf_);
if (lInf_ < 0.0)
{
FatalIOErrorInFunction(dict)
<< "unphysical lInf specified (lInf < 0)" << nl
<< " on patch " << this->patch().name()
<< " of field " << this->internalField().name()
<< " in file " << this->internalField().objectPath()
<< exit(FatalIOError);
}
}
}
template
Foam::advectiveFvPatchField::advectiveFvPatchField
(
const advectiveFvPatchField& ptpsf
)
:
mixedFvPatchField(ptpsf),
phiName_(ptpsf.phiName_),
rhoName_(ptpsf.rhoName_),
fieldInf_(ptpsf.fieldInf_),
lInf_(ptpsf.lInf_)
{}
template
Foam::advectiveFvPatchField::advectiveFvPatchField
(
const advectiveFvPatchField& ptpsf,
const DimensionedField& iF
)
:
mixedFvPatchField(ptpsf, iF),
phiName_(ptpsf.phiName_),
rhoName_(ptpsf.rhoName_),
fieldInf_(ptpsf.fieldInf_),
lInf_(ptpsf.lInf_)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template
Foam::tmp
Foam::advectiveFvPatchField::advectionSpeed() const
{
const auto& phip =
this->patch().template lookupPatchField(phiName_);
if (phip.internalField().dimensions() == dimMass/dimTime)
{
const auto& rhop =
this->patch().template lookupPatchField(rhoName_);
return phip/(rhop*this->patch().magSf());
}
else
{
return phip/this->patch().magSf();
}
}
template
void Foam::advectiveFvPatchField::updateCoeffs()
{
if (this->updated())
{
return;
}
const fvMesh& mesh = this->internalField().mesh();
word ddtScheme
(
mesh.ddtScheme(this->internalField().name())
);
scalar deltaT = this->db().time().deltaTValue();
const GeometricField& field =
this->db().objectRegistry::template
lookupObject>
(
this->internalField().name()
);
// Calculate the advection speed of the field wave
// If the wave is incoming set the speed to 0.
const scalarField w(Foam::max(advectionSpeed(), scalar(0)));
// Calculate the field wave coefficient alpha (See notes)
const scalarField alpha(w*deltaT*this->patch().deltaCoeffs());
label patchi = this->patch().index();
// Non-reflecting outflow boundary
// If lInf_ defined setup relaxation to the value fieldInf_.
if (lInf_ > 0)
{
// Calculate the field relaxation coefficient k (See notes)
const scalarField k(w*deltaT/lInf_);
if
(
ddtScheme == fv::EulerDdtScheme::typeName
|| ddtScheme == fv::CrankNicolsonDdtScheme::typeName
)
{
this->refValue() =
(
field.oldTime().boundaryField()[patchi] + k*fieldInf_
)/(1.0 + k);
this->valueFraction() = (1.0 + k)/(1.0 + alpha + k);
}
else if (ddtScheme == fv::backwardDdtScheme::typeName)
{
this->refValue() =
(
2.0*field.oldTime().boundaryField()[patchi]
- 0.5*field.oldTime().oldTime().boundaryField()[patchi]
+ k*fieldInf_
)/(1.5 + k);
this->valueFraction() = (1.5 + k)/(1.5 + alpha + k);
}
else if
(
ddtScheme == fv::localEulerDdtScheme::typeName
)
{
const volScalarField& rDeltaT =
fv::localEulerDdt::localRDeltaT(mesh);
// Calculate the field wave coefficient alpha (See notes)
const scalarField alpha
(
w*this->patch().deltaCoeffs()/rDeltaT.boundaryField()[patchi]
);
// Calculate the field relaxation coefficient k (See notes)
const scalarField k(w/(rDeltaT.boundaryField()[patchi]*lInf_));
this->refValue() =
(
field.oldTime().boundaryField()[patchi] + k*fieldInf_
)/(1.0 + k);
this->valueFraction() = (1.0 + k)/(1.0 + alpha + k);
}
else
{
FatalErrorInFunction
<< ddtScheme << nl
<< " on patch " << this->patch().name()
<< " of field " << this->internalField().name()
<< " in file " << this->internalField().objectPath()
<< exit(FatalError);
}
}
else
{
if
(
ddtScheme == fv::EulerDdtScheme::typeName
|| ddtScheme == fv::CrankNicolsonDdtScheme::typeName
)
{
this->refValue() = field.oldTime().boundaryField()[patchi];
this->valueFraction() = 1.0/(1.0 + alpha);
}
else if (ddtScheme == fv::backwardDdtScheme::typeName)
{
this->refValue() =
(
2.0*field.oldTime().boundaryField()[patchi]
- 0.5*field.oldTime().oldTime().boundaryField()[patchi]
)/1.5;
this->valueFraction() = 1.5/(1.5 + alpha);
}
else if
(
ddtScheme == fv::localEulerDdtScheme::typeName
)
{
const volScalarField& rDeltaT =
fv::localEulerDdt::localRDeltaT(mesh);
// Calculate the field wave coefficient alpha (See notes)
const scalarField alpha
(
w*this->patch().deltaCoeffs()/rDeltaT.boundaryField()[patchi]
);
this->refValue() = field.oldTime().boundaryField()[patchi];
this->valueFraction() = 1.0/(1.0 + alpha);
}
else
{
FatalErrorInFunction
<< ddtScheme
<< "\n on patch " << this->patch().name()
<< " of field " << this->internalField().name()
<< " in file " << this->internalField().objectPath()
<< exit(FatalError);
}
}
mixedFvPatchField::updateCoeffs();
}
template
void Foam::advectiveFvPatchField::write(Ostream& os) const
{
fvPatchField::write(os);
os.writeEntryIfDifferent("phi", "phi", phiName_);
os.writeEntryIfDifferent("rho", "rho", rhoName_);
if (lInf_ > 0)
{
os.writeEntry("fieldInf", fieldInf_);
os.writeEntry("lInf", lInf_);
}
fvPatchField::writeValueEntry(os);
}
// ************************************************************************* //