Compare commits
2 Commits
develop.me
...
feature-ev
| Author | SHA1 | Date | |
|---|---|---|---|
| 413c91d873 | |||
| f6539e4d52 |
@ -33,7 +33,15 @@ fvOptions/atmPlantCanopyTurbSource/atmPlantCanopyTurbSource.C
|
|||||||
fvOptions/atmPlantCanopyUSource/atmPlantCanopyUSource.C
|
fvOptions/atmPlantCanopyUSource/atmPlantCanopyUSource.C
|
||||||
fvOptions/atmPlantCanopyTSource/atmPlantCanopyTSource.C
|
fvOptions/atmPlantCanopyTSource/atmPlantCanopyTSource.C
|
||||||
fvOptions/atmNutSource/atmNutSource.C
|
fvOptions/atmNutSource/atmNutSource.C
|
||||||
|
fvOptions/treeTurbulence/treeTurbulence.C
|
||||||
|
|
||||||
|
etht = fvOptions/evapotranspirationHeatTransfer
|
||||||
|
ethtModels = $(etht)/evapotranspirationHeatTransferModels
|
||||||
|
$(etht)/evapotranspirationHeatTransfer.C
|
||||||
|
$(ethtModels)/evapotranspirationHeatTransferModel/evapotranspirationHeatTransferModel.C
|
||||||
|
$(ethtModels)/evapotranspirationHeatTransferModel/evapotranspirationHeatTransferModelNew.C
|
||||||
|
$(ethtModels)/tree/tree.C
|
||||||
|
$(ethtModels)/grass/grass.C
|
||||||
|
|
||||||
/* functionObjects */
|
/* functionObjects */
|
||||||
functionObjects/ObukhovLength/ObukhovLength.C
|
functionObjects/ObukhovLength/ObukhovLength.C
|
||||||
|
|||||||
@ -8,6 +8,7 @@ EXE_INC = \
|
|||||||
-I$(LIB_SRC)/thermophysicalModels/basic/lnInclude \
|
-I$(LIB_SRC)/thermophysicalModels/basic/lnInclude \
|
||||||
-I$(LIB_SRC)/thermophysicalModels/specie/lnInclude \
|
-I$(LIB_SRC)/thermophysicalModels/specie/lnInclude \
|
||||||
-I$(LIB_SRC)/thermophysicalModels/solidThermo/lnInclude \
|
-I$(LIB_SRC)/thermophysicalModels/solidThermo/lnInclude \
|
||||||
|
-I$(LIB_SRC)/thermophysicalModels/radiation/lnInclude \
|
||||||
-I$(LIB_SRC)/TurbulenceModels/turbulenceModels/lnInclude \
|
-I$(LIB_SRC)/TurbulenceModels/turbulenceModels/lnInclude \
|
||||||
-I$(LIB_SRC)/TurbulenceModels/compressible/lnInclude \
|
-I$(LIB_SRC)/TurbulenceModels/compressible/lnInclude \
|
||||||
-I$(LIB_SRC)/TurbulenceModels/incompressible/lnInclude \
|
-I$(LIB_SRC)/TurbulenceModels/incompressible/lnInclude \
|
||||||
@ -18,6 +19,7 @@ LIB_LIBS = \
|
|||||||
-lfvOptions \
|
-lfvOptions \
|
||||||
-lmeshTools \
|
-lmeshTools \
|
||||||
-lsurfMesh \
|
-lsurfMesh \
|
||||||
|
-lradiationModels \
|
||||||
-lfluidThermophysicalModels \
|
-lfluidThermophysicalModels \
|
||||||
-lsolidThermo \
|
-lsolidThermo \
|
||||||
-lturbulenceModels \
|
-lturbulenceModels \
|
||||||
|
|||||||
@ -0,0 +1,172 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | www.openfoam.com
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2022 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "evapotranspirationHeatTransfer.H"
|
||||||
|
#include "evapotranspirationHeatTransferModel.H"
|
||||||
|
#include "fvMesh.H"
|
||||||
|
#include "fvMatrix.H"
|
||||||
|
#include "basicThermo.H"
|
||||||
|
#include "addToRunTimeSelectionTable.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
namespace fv
|
||||||
|
{
|
||||||
|
defineTypeNameAndDebug(evapotranspirationHeatTransfer, 0);
|
||||||
|
addToRunTimeSelectionTable
|
||||||
|
(
|
||||||
|
option,
|
||||||
|
evapotranspirationHeatTransfer,
|
||||||
|
dictionary
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::fv::evapotranspirationHeatTransfer::evapotranspirationHeatTransfer
|
||||||
|
(
|
||||||
|
const word& sourceName,
|
||||||
|
const word& modelType,
|
||||||
|
const dictionary& dict,
|
||||||
|
const fvMesh& mesh
|
||||||
|
)
|
||||||
|
:
|
||||||
|
fv::cellSetOption(sourceName, modelType, dict, mesh),
|
||||||
|
ethtModelPtr_()
|
||||||
|
{
|
||||||
|
// Set the field name to that of the energy
|
||||||
|
// field from which the temperature is obtained
|
||||||
|
|
||||||
|
const auto& thermo = mesh_.lookupObject<basicThermo>(basicThermo::dictName);
|
||||||
|
|
||||||
|
fieldNames_.resize(1, thermo.he().name());
|
||||||
|
|
||||||
|
fv::option::resetApplied();
|
||||||
|
|
||||||
|
Info<< " Applying evapotranspirationHeatTransfer to: " << fieldNames_[0]
|
||||||
|
<< endl;
|
||||||
|
|
||||||
|
read(dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::fv::evapotranspirationHeatTransfer::~evapotranspirationHeatTransfer()
|
||||||
|
{} // evapotranspirationHeatTransferModel was forward declared
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
void Foam::fv::evapotranspirationHeatTransfer::addSup
|
||||||
|
(
|
||||||
|
fvScalarMatrix& eqn,
|
||||||
|
const label fieldi
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (this->V() < VSMALL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const scalar V = this->V();
|
||||||
|
const scalarField& Vcells = mesh_.V();
|
||||||
|
|
||||||
|
const volScalarField& he = eqn.psi();
|
||||||
|
scalarField& heSource = eqn.source();
|
||||||
|
|
||||||
|
// Calculate evapotranspiration heat transfer rate per volume [J/s/m^3]
|
||||||
|
const scalarField Q(ethtModelPtr_->Q(cells_)/V);
|
||||||
|
|
||||||
|
if (he.dimensions() == dimEnergy/dimMass)
|
||||||
|
{
|
||||||
|
forAll(cells_, i)
|
||||||
|
{
|
||||||
|
const label celli = cells_[i];
|
||||||
|
|
||||||
|
heSource[celli] += Q[i]*Vcells[celli];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (he.dimensions() == dimTemperature)
|
||||||
|
{
|
||||||
|
const auto& thermo =
|
||||||
|
mesh_.lookupObject<basicThermo>(basicThermo::dictName);
|
||||||
|
|
||||||
|
// Calculate density*heat capacity at constant pressure/volume
|
||||||
|
const volScalarField rhoCpv(thermo.rho()*thermo.Cpv());
|
||||||
|
|
||||||
|
// heSource [K m^3/s] = [J/s/m^3] * m^3 / [kg/m^3] / [J/kg/K]
|
||||||
|
forAll(cells_, i)
|
||||||
|
{
|
||||||
|
const label celli = cells_[i];
|
||||||
|
|
||||||
|
heSource[celli] += Q[i]*Vcells[celli]*rhoCpv[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::fv::evapotranspirationHeatTransfer::addSup
|
||||||
|
(
|
||||||
|
const volScalarField& rho,
|
||||||
|
fvScalarMatrix& eqn,
|
||||||
|
const label fieldi
|
||||||
|
)
|
||||||
|
{
|
||||||
|
addSup(eqn, fieldi);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::fv::evapotranspirationHeatTransfer::read(const dictionary& dict)
|
||||||
|
{
|
||||||
|
if (!fv::cellSetOption::read(dict))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectionMode_ != selectionModeType::smCellZone)
|
||||||
|
{
|
||||||
|
FatalIOErrorInFunction(dict)
|
||||||
|
<< "evapotranspirationHeatTransfer requires "
|
||||||
|
<< selectionModeTypeNames_[selectionModeType::smCellZone]
|
||||||
|
<< exit(FatalIOError);
|
||||||
|
}
|
||||||
|
|
||||||
|
ethtModelPtr_.reset
|
||||||
|
(
|
||||||
|
evapotranspirationHeatTransferModel::New(dict, mesh_)
|
||||||
|
);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -0,0 +1,183 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | www.openfoam.com
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2022 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Class
|
||||||
|
Foam::fv::evapotranspirationHeatTransfer
|
||||||
|
|
||||||
|
Description
|
||||||
|
Applies sources on temperature (\c T - incompressible)
|
||||||
|
or energy (\c h/e - compressible) equation to incorporate
|
||||||
|
evapotranspiration heat-transfer effects from the specified
|
||||||
|
plant canopy. Heat transfer is usually calculated based on
|
||||||
|
empirical relations between plants and solar radiation.
|
||||||
|
|
||||||
|
Usage
|
||||||
|
Example by using \c constant/fvOptions:
|
||||||
|
\verbatim
|
||||||
|
evapotranspirationHeatTransfer1
|
||||||
|
{
|
||||||
|
// Mandatory entries
|
||||||
|
type evapotranspirationHeatTransfer;
|
||||||
|
model <word>;
|
||||||
|
|
||||||
|
// Model-specific entries
|
||||||
|
...
|
||||||
|
|
||||||
|
// Inherited entries
|
||||||
|
...
|
||||||
|
}
|
||||||
|
\endverbatim
|
||||||
|
|
||||||
|
where the entries mean:
|
||||||
|
\table
|
||||||
|
Property | Description | Type | Reqd | Deflt
|
||||||
|
type | Type name: evapotranspirationHeatTransfer | word | yes | -
|
||||||
|
model | Name of heat-transfer model | word | yes | -
|
||||||
|
\endtable
|
||||||
|
|
||||||
|
Options for the \c model entry:
|
||||||
|
\verbatim
|
||||||
|
tree | Regression-based heat-transfer model for trees
|
||||||
|
grass | Heat-transfer model for grass
|
||||||
|
\endverbatim
|
||||||
|
|
||||||
|
The inherited entries are elaborated in:
|
||||||
|
- \link fvOption.H \endlink
|
||||||
|
- \link cellSetOption.H \endlink
|
||||||
|
|
||||||
|
Note
|
||||||
|
- Evapotranspiration mass transfer is not modelled.
|
||||||
|
|
||||||
|
SourceFiles
|
||||||
|
evapotranspirationHeatTransfer.C
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef Foam_fv_evapotranspirationHeatTransfer_H
|
||||||
|
#define Foam_fv_evapotranspirationHeatTransfer_H
|
||||||
|
|
||||||
|
#include "cellSetOption.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
|
||||||
|
// Forward Declarations
|
||||||
|
class evapotranspirationHeatTransferModel;
|
||||||
|
|
||||||
|
namespace fv
|
||||||
|
{
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
Class evapotranspirationHeatTransfer Declaration
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
class evapotranspirationHeatTransfer
|
||||||
|
:
|
||||||
|
public fv::cellSetOption
|
||||||
|
{
|
||||||
|
// Private Data
|
||||||
|
|
||||||
|
//- Runtime-selectable evapotranspiration heat transfer model
|
||||||
|
autoPtr<evapotranspirationHeatTransferModel> ethtModelPtr_;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//- Runtime type information
|
||||||
|
TypeName("evapotranspirationHeatTransfer");
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
|
||||||
|
//- Construct from explicit source name and mesh
|
||||||
|
evapotranspirationHeatTransfer
|
||||||
|
(
|
||||||
|
const word& sourceName,
|
||||||
|
const word& modelType,
|
||||||
|
const dictionary& dict,
|
||||||
|
const fvMesh& mesh
|
||||||
|
);
|
||||||
|
|
||||||
|
//- No copy construct
|
||||||
|
evapotranspirationHeatTransfer(const evapotranspirationHeatTransfer&) =
|
||||||
|
delete;
|
||||||
|
|
||||||
|
//- No copy assignment
|
||||||
|
void operator=(const evapotranspirationHeatTransfer&) = delete;
|
||||||
|
|
||||||
|
|
||||||
|
//- Destructor
|
||||||
|
virtual ~evapotranspirationHeatTransfer();
|
||||||
|
|
||||||
|
|
||||||
|
// Member Functions
|
||||||
|
|
||||||
|
//- Add explicit contribution to energy equation
|
||||||
|
//- for incompressible flow computations
|
||||||
|
virtual void addSup
|
||||||
|
(
|
||||||
|
fvScalarMatrix& eqn,
|
||||||
|
const label fieldi
|
||||||
|
);
|
||||||
|
|
||||||
|
//- Add explicit contribution to energy equation
|
||||||
|
//- for compressible flow computations
|
||||||
|
virtual void addSup
|
||||||
|
(
|
||||||
|
const volScalarField& rho,
|
||||||
|
fvScalarMatrix& eqn,
|
||||||
|
const label fieldi
|
||||||
|
);
|
||||||
|
|
||||||
|
//- Add explicit contribution to energy equation
|
||||||
|
//- for multiphase flow computations
|
||||||
|
virtual void addSup
|
||||||
|
(
|
||||||
|
const volScalarField& alpha,
|
||||||
|
const volScalarField& rho,
|
||||||
|
fvScalarMatrix& eqn,
|
||||||
|
const label fieldi
|
||||||
|
)
|
||||||
|
{
|
||||||
|
NotImplemented;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- Read dictionary
|
||||||
|
virtual bool read(const dictionary& dict);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
} // End namespace fv
|
||||||
|
} // End namespace Foam
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -0,0 +1,196 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | www.openfoam.com
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2022 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "evapotranspirationHeatTransferModel.H"
|
||||||
|
#include "radiationModel.H"
|
||||||
|
#include "solarLoadBase.H"
|
||||||
|
#include "fvMesh.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
defineTypeNameAndDebug(evapotranspirationHeatTransferModel, 0);
|
||||||
|
defineRunTimeSelectionTable
|
||||||
|
(
|
||||||
|
evapotranspirationHeatTransferModel,
|
||||||
|
dictionary
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::volScalarField& Foam::evapotranspirationHeatTransferModel::getOrReadField
|
||||||
|
(
|
||||||
|
const word& fieldName
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
auto* ptr = mesh_.getObjectPtr<volScalarField>(fieldName);
|
||||||
|
|
||||||
|
if (!ptr)
|
||||||
|
{
|
||||||
|
ptr = new volScalarField
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
fieldName,
|
||||||
|
mesh_.time().timeName(),
|
||||||
|
mesh_,
|
||||||
|
IOobject::MUST_READ,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh_
|
||||||
|
);
|
||||||
|
mesh_.objectRegistry::store(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::scalar Foam::evapotranspirationHeatTransferModel::q() const
|
||||||
|
{
|
||||||
|
// Retrieve solar-load information
|
||||||
|
const auto& base =
|
||||||
|
mesh().lookupObject<radiation::solarLoadBase>("solarLoadBase");
|
||||||
|
const solarCalculator& solar = base.solarCalculatorRef();
|
||||||
|
|
||||||
|
// Retrieve internal & boundary faces directly hit by solar rays
|
||||||
|
const faceShading& shade = base.faceShadingRef();
|
||||||
|
const labelList& hitFacesId = shade.rayStartFaces();
|
||||||
|
|
||||||
|
// Retrieve face zone information
|
||||||
|
const faceZone& zone = mesh_.faceZones()[faceZoneId_];
|
||||||
|
const vectorField& faceNormals = zone().faceNormals();
|
||||||
|
const scalarField& faceAreas = zone().magFaceAreas();
|
||||||
|
|
||||||
|
// Retrieve direct solar load [W/m^2]
|
||||||
|
const vector directSolarRad(solar.directSolarRad()*solar.direction());
|
||||||
|
|
||||||
|
// Identify zone faces within mesh
|
||||||
|
bitSet isZoneFace(mesh_.nFaces());
|
||||||
|
isZoneFace.set(zone);
|
||||||
|
|
||||||
|
// Calculate area-averaged incident solar load
|
||||||
|
// Assuming hit faces are updated by solarLoad
|
||||||
|
scalar q = 0;
|
||||||
|
scalar totalFaceArea = 0;
|
||||||
|
|
||||||
|
for (const label facei : hitFacesId)
|
||||||
|
{
|
||||||
|
if (isZoneFace[facei])
|
||||||
|
{
|
||||||
|
const label localFacei = zone.whichFace(facei);
|
||||||
|
|
||||||
|
const vector& faceNormal = faceNormals[localFacei];
|
||||||
|
const scalar faceArea = faceAreas[localFacei];
|
||||||
|
|
||||||
|
const scalar qIncident = directSolarRad & faceNormal;
|
||||||
|
|
||||||
|
q += qIncident*faceArea;
|
||||||
|
totalFaceArea += faceArea;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reduce(q, sumOp<scalar>());
|
||||||
|
reduce(totalFaceArea, sumOp<scalar>());
|
||||||
|
q /= totalFaceArea;
|
||||||
|
|
||||||
|
|
||||||
|
// Sum diffusive solar loads
|
||||||
|
switch(solar.sunLoadModel())
|
||||||
|
{
|
||||||
|
case solarCalculator::mSunLoadFairWeatherConditions:
|
||||||
|
case solarCalculator::mSunLoadTheoreticalMaximum:
|
||||||
|
{
|
||||||
|
// Calculate diffusive radiance
|
||||||
|
// contribution from sky and ground
|
||||||
|
tmp<scalarField> tdiffuseSolarRad =
|
||||||
|
solar.diffuseSolarRad(faceNormals);
|
||||||
|
const scalarField& diffuseSolarRad = tdiffuseSolarRad.cref();
|
||||||
|
|
||||||
|
// Calculate area-averaged diffusive solar load
|
||||||
|
scalar meanDiffuseSolarRad = 0;
|
||||||
|
forAll(faceAreas, i)
|
||||||
|
{
|
||||||
|
meanDiffuseSolarRad += diffuseSolarRad[i]*faceAreas[i];
|
||||||
|
}
|
||||||
|
meanDiffuseSolarRad /= totalFaceArea;
|
||||||
|
|
||||||
|
q += meanDiffuseSolarRad;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case solarCalculator::mSunLoadConstant:
|
||||||
|
case solarCalculator::mSunLoadTimeDependent:
|
||||||
|
{
|
||||||
|
q += solar.diffuseSolarRad();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::evapotranspirationHeatTransferModel::evapotranspirationHeatTransferModel
|
||||||
|
(
|
||||||
|
const dictionary& dict,
|
||||||
|
const fvMesh& mesh
|
||||||
|
)
|
||||||
|
:
|
||||||
|
mesh_(mesh)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
bool Foam::evapotranspirationHeatTransferModel::read(const dictionary& dict)
|
||||||
|
{
|
||||||
|
faceZoneId_ = mesh_.faceZones().findZoneID(dict.get<word>("faceZone"));
|
||||||
|
|
||||||
|
if (faceZoneId_ < 0)
|
||||||
|
{
|
||||||
|
const word faceZoneName(mesh_.faceZones()[faceZoneId_].name());
|
||||||
|
|
||||||
|
FatalIOErrorInFunction(dict)
|
||||||
|
<< type() << ' ' << typeName << ": "
|
||||||
|
<< " No matching face zone: " << faceZoneName << nl
|
||||||
|
<< " Known face zones: "
|
||||||
|
<< flatOutput(mesh_.faceZones().names()) << nl
|
||||||
|
<< exit(FatalIOError);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -0,0 +1,180 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | www.openfoam.com
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2022 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Class
|
||||||
|
Foam::evapotranspirationHeatTransferModel
|
||||||
|
|
||||||
|
Description
|
||||||
|
Base class for evapotranspiration models
|
||||||
|
to handle general evapotranspiration characteristics.
|
||||||
|
|
||||||
|
SourceFiles
|
||||||
|
evapotranspirationHeatTransferModel.C
|
||||||
|
evapotranspirationHeatTransferModelNew.C
|
||||||
|
evapotranspirationHeatTransferModelTemplates.C
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef Foam_evapotranspirationHeatTransferModel_H
|
||||||
|
#define Foam_evapotranspirationHeatTransferModel_H
|
||||||
|
|
||||||
|
#include "dictionary.H"
|
||||||
|
#include "HashSet.H"
|
||||||
|
#include "volFields.H"
|
||||||
|
#include "runTimeSelectionTables.H"
|
||||||
|
#include "OFstream.H"
|
||||||
|
#include "coordinateSystem.H"
|
||||||
|
#include "writeFile.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
|
||||||
|
// Forward Declarations
|
||||||
|
class fvMesh;
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
Class evapotranspirationHeatTransferModel Declaration
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
class evapotranspirationHeatTransferModel
|
||||||
|
{
|
||||||
|
// Private Data
|
||||||
|
|
||||||
|
//- Reference to the mesh
|
||||||
|
const fvMesh& mesh_;
|
||||||
|
|
||||||
|
//- Identifier of specified face zone
|
||||||
|
label faceZoneId_;
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// Protected Member Functions
|
||||||
|
|
||||||
|
//- Return requested field from the object registry
|
||||||
|
//- or read+register the field to the object registry
|
||||||
|
volScalarField& getOrReadField(const word& fieldName) const;
|
||||||
|
|
||||||
|
//- Area-averaged heat flux due to short-wave
|
||||||
|
//- solar rays on face zone [W/m^2]
|
||||||
|
// Short-wave: direct and diffusive solar rays
|
||||||
|
scalar q() const;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//- Runtime type information
|
||||||
|
TypeName("evapotranspirationHeatTransferModel");
|
||||||
|
|
||||||
|
|
||||||
|
// Declare runtime constructor selection table
|
||||||
|
|
||||||
|
declareRunTimeSelectionTable
|
||||||
|
(
|
||||||
|
autoPtr,
|
||||||
|
evapotranspirationHeatTransferModel,
|
||||||
|
dictionary,
|
||||||
|
(
|
||||||
|
const dictionary& dict,
|
||||||
|
const fvMesh& mesh
|
||||||
|
),
|
||||||
|
(dict, mesh)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// Selectors
|
||||||
|
|
||||||
|
//- Return a reference to the selected evapotranspiration model
|
||||||
|
static autoPtr<evapotranspirationHeatTransferModel> New
|
||||||
|
(
|
||||||
|
const dictionary& dict,
|
||||||
|
const fvMesh& mesh
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
|
||||||
|
//- Construct from components
|
||||||
|
evapotranspirationHeatTransferModel
|
||||||
|
(
|
||||||
|
const dictionary& dict,
|
||||||
|
const fvMesh& mesh
|
||||||
|
);
|
||||||
|
|
||||||
|
//- No copy construct
|
||||||
|
evapotranspirationHeatTransferModel
|
||||||
|
(
|
||||||
|
const evapotranspirationHeatTransferModel&
|
||||||
|
) = delete;
|
||||||
|
|
||||||
|
//- No copy assignment
|
||||||
|
void operator=(const evapotranspirationHeatTransferModel&) = delete;
|
||||||
|
|
||||||
|
|
||||||
|
//- Destructor
|
||||||
|
virtual ~evapotranspirationHeatTransferModel() = default;
|
||||||
|
|
||||||
|
|
||||||
|
// Member Functions
|
||||||
|
|
||||||
|
// Access
|
||||||
|
|
||||||
|
//- Return const reference to the mesh
|
||||||
|
const fvMesh& mesh() const noexcept
|
||||||
|
{
|
||||||
|
return mesh_;
|
||||||
|
}
|
||||||
|
|
||||||
|
//- Return the face-zone identifier
|
||||||
|
label faceZoneId() const noexcept
|
||||||
|
{
|
||||||
|
return faceZoneId_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Evaluation
|
||||||
|
|
||||||
|
//- Return heat-transfer rate for speficied cells [J/s]
|
||||||
|
virtual tmp<scalarField> Q(const labelList& cells) const = 0;
|
||||||
|
|
||||||
|
|
||||||
|
// I-O
|
||||||
|
|
||||||
|
//- Read the dictionary
|
||||||
|
virtual bool read(const dictionary& dict);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
} // End namespace Foam
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | www.openfoam.com
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2022 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "evapotranspirationHeatTransferModel.H"
|
||||||
|
#include "fvMesh.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::autoPtr<Foam::evapotranspirationHeatTransferModel>
|
||||||
|
Foam::evapotranspirationHeatTransferModel::New
|
||||||
|
(
|
||||||
|
const dictionary& dict,
|
||||||
|
const fvMesh& mesh
|
||||||
|
)
|
||||||
|
{
|
||||||
|
word modelType(dict.get<word>("model"));
|
||||||
|
|
||||||
|
auto cstrIter = dictionaryConstructorTablePtr_->cfind(modelType);
|
||||||
|
|
||||||
|
if (!cstrIter.found())
|
||||||
|
{
|
||||||
|
FatalIOErrorInLookup
|
||||||
|
(
|
||||||
|
dict,
|
||||||
|
"model",
|
||||||
|
modelType,
|
||||||
|
*dictionaryConstructorTablePtr_
|
||||||
|
) << exit(FatalIOError);
|
||||||
|
}
|
||||||
|
|
||||||
|
return autoPtr<evapotranspirationHeatTransferModel>
|
||||||
|
(
|
||||||
|
cstrIter()(dict, mesh)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -0,0 +1,418 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | www.openfoam.com
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2022 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "grass.H"
|
||||||
|
#include "basicThermo.H"
|
||||||
|
#include "fluidThermo.H"
|
||||||
|
#include "turbulentTransportModel.H"
|
||||||
|
#include "turbulentFluidThermoModel.H"
|
||||||
|
#include "addToRunTimeSelectionTable.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
namespace evapotranspirationHeatTransferModels
|
||||||
|
{
|
||||||
|
defineTypeNameAndDebug(grass, 0);
|
||||||
|
addToRunTimeSelectionTable
|
||||||
|
(
|
||||||
|
evapotranspirationHeatTransferModel,
|
||||||
|
grass,
|
||||||
|
dictionary
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const Foam::Enum
|
||||||
|
<
|
||||||
|
Foam::evapotranspirationHeatTransferModels::grass::soilHeatFluxType
|
||||||
|
>
|
||||||
|
Foam::evapotranspirationHeatTransferModels::grass::soilHeatFluxTypeNames
|
||||||
|
({
|
||||||
|
{
|
||||||
|
soilHeatFluxType::PROPORTIONAL_TO_SOLAR_RADIATION,
|
||||||
|
"proportionalToSolarRadiation"
|
||||||
|
},
|
||||||
|
{ soilHeatFluxType::BOUNDARY, "boundary" }
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::tmp<Foam::scalarField>
|
||||||
|
Foam::evapotranspirationHeatTransferModels::grass::E(const labelList& cells)
|
||||||
|
const
|
||||||
|
{
|
||||||
|
const scalar q = this->q();
|
||||||
|
const scalar G = this->G(cells);
|
||||||
|
const scalar Delta = this->Delta();
|
||||||
|
const scalar D = this->D();
|
||||||
|
const scalar ra = this->ra();
|
||||||
|
const scalar rs = this->rs();
|
||||||
|
const scalar gamma = this->gamma();
|
||||||
|
|
||||||
|
// (BSG:Eq. 11)
|
||||||
|
const scalar E =
|
||||||
|
(Delta*(q - G) + rho_*Cp_*D/ra)/(Delta + gamma*(1 + rs/ra));
|
||||||
|
|
||||||
|
return tmp<scalarField>::New(cells.size(), E);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::scalar Foam::evapotranspirationHeatTransferModels::grass::Delta() const
|
||||||
|
{
|
||||||
|
// (BSG:Eq. 15), (APR:Eq. 13) - note 0.6108 -> 610.8 due to kPa -> Pa
|
||||||
|
const scalar Ta = Tref_ + 237.3;
|
||||||
|
|
||||||
|
return 4098*(610.8*exp(17.27*Tref_/Ta))/sqr(Ta);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::scalar Foam::evapotranspirationHeatTransferModels::grass::D() const
|
||||||
|
{
|
||||||
|
// (BSG:Eq. 16)
|
||||||
|
const scalar RHref = RHptr_->value(mesh().time().timeOutputValue());
|
||||||
|
|
||||||
|
return (1 - RHref)*pSat();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::scalar Foam::evapotranspirationHeatTransferModels::grass::pSat() const
|
||||||
|
{
|
||||||
|
// (BSG:Eq. 17; Arden Buck equation)
|
||||||
|
const scalar p1 = (1.0007 + 3.46e-8*pAtm_)*611.21;
|
||||||
|
|
||||||
|
return p1*exp((18.678 - Tref_/234.5)*Tref_/(Tref_ + 257.14));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::scalar Foam::evapotranspirationHeatTransferModels::grass::gamma() const
|
||||||
|
{
|
||||||
|
// (APR:Eq. 8)
|
||||||
|
return Cp_*pAtm_/(epsilon_*lambda());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::scalar Foam::evapotranspirationHeatTransferModels::grass::lambda() const
|
||||||
|
{
|
||||||
|
// (BSG:Eq. 12)
|
||||||
|
const scalar T1 = Tref_ + 273.15;
|
||||||
|
const scalar T2 = Tref_ + 239.24;
|
||||||
|
|
||||||
|
return 1.91846e6*sqr(T1/T2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::scalar Foam::evapotranspirationHeatTransferModels::grass::ra() const
|
||||||
|
{
|
||||||
|
// (APR:Eq. 4), (BSG:Eq. 14)
|
||||||
|
const scalar log1 = log((zRefU_ - d_*h_)/(zom_*h_));
|
||||||
|
const scalar log2 = log((zRefH_ - d_*h_)/(zoh_*h_));
|
||||||
|
|
||||||
|
return log1*log2/(sqr(kappa_)*uRef_);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::scalar Foam::evapotranspirationHeatTransferModels::grass::rs() const
|
||||||
|
{
|
||||||
|
// (BSG:Eq. 13), (APR:Eq. 5; reduced form in p. 4-5)
|
||||||
|
return ri_/(scalar(12)*h_);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::scalar Foam::evapotranspirationHeatTransferModels::grass::S
|
||||||
|
(
|
||||||
|
const labelList& cells
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
// Mark fvOption cells within mesh
|
||||||
|
bitSet isZoneCell(mesh().nCells());
|
||||||
|
isZoneCell.set(cells);
|
||||||
|
|
||||||
|
scalar S = 0;
|
||||||
|
|
||||||
|
// Select cells next to specified patches
|
||||||
|
// Sum patch area that is covered by fvOption cells
|
||||||
|
for (const label patchi : patchSet_)
|
||||||
|
{
|
||||||
|
const scalarField& s = mesh().magSf().boundaryField()[patchi];
|
||||||
|
|
||||||
|
const polyPatch& pp = mesh().boundaryMesh()[patchi];
|
||||||
|
const labelList& faceCells = pp.faceCells();
|
||||||
|
|
||||||
|
forAll(faceCells, i)
|
||||||
|
{
|
||||||
|
const bool isCovered = isZoneCell[faceCells[i]];
|
||||||
|
|
||||||
|
if (isCovered)
|
||||||
|
{
|
||||||
|
S += s[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reduce(S, sumOp<scalar>());
|
||||||
|
|
||||||
|
if (mag(S) < SMALL)
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "Area coverage of grass cannot be zero. "
|
||||||
|
<< "Check whether cellZone has any boundary faces."
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
return S;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::scalar Foam::evapotranspirationHeatTransferModels::grass::G
|
||||||
|
(
|
||||||
|
const labelList& cells
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
switch (soilHeatFluxMethod_)
|
||||||
|
{
|
||||||
|
case soilHeatFluxType::PROPORTIONAL_TO_SOLAR_RADIATION:
|
||||||
|
{
|
||||||
|
return Csoil_*q();
|
||||||
|
}
|
||||||
|
|
||||||
|
case soilHeatFluxType::BOUNDARY:
|
||||||
|
{
|
||||||
|
// Retrieve heat flux through patches
|
||||||
|
tmp<FieldField<Field, scalar>> tqBf = this->qBf();
|
||||||
|
const FieldField<Field, scalar>& qBf = tqBf.cref();
|
||||||
|
|
||||||
|
// Mark fvOption cells within mesh
|
||||||
|
bitSet isZoneCell(mesh().nCells());
|
||||||
|
isZoneCell.set(cells);
|
||||||
|
|
||||||
|
scalar G = 0;
|
||||||
|
|
||||||
|
for (const label patchi : patchSet_)
|
||||||
|
{
|
||||||
|
const scalarField& s = mesh().magSf().boundaryField()[patchi];
|
||||||
|
|
||||||
|
const scalarField& qfld = qBf[patchi];
|
||||||
|
|
||||||
|
const polyPatch& pp = mesh().boundaryMesh()[patchi];
|
||||||
|
const labelList& faceCells = pp.faceCells();
|
||||||
|
|
||||||
|
forAll(faceCells, i)
|
||||||
|
{
|
||||||
|
const bool isCovered = isZoneCell[faceCells[i]];
|
||||||
|
|
||||||
|
if (isCovered)
|
||||||
|
{
|
||||||
|
G += qfld[i]*s[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
reduce(G, sumOp<scalar>());
|
||||||
|
|
||||||
|
return G/area_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::tmp<Foam::FieldField<Foam::Field, Foam::scalar>>
|
||||||
|
Foam::evapotranspirationHeatTransferModels::grass::qBf() const
|
||||||
|
{
|
||||||
|
const auto& T = mesh().lookupObject<volScalarField>(TName_);
|
||||||
|
const volScalarField::Boundary& Tbf = T.boundaryField();
|
||||||
|
|
||||||
|
auto tq = tmp<FieldField<Field, scalar>>::New(Tbf.size());
|
||||||
|
auto& q = tq.ref();
|
||||||
|
|
||||||
|
forAll(q, patchi)
|
||||||
|
{
|
||||||
|
q.set(patchi, new Field<scalar>(Tbf[patchi].size(), Zero));
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef compressible::turbulenceModel cmpTurbModel;
|
||||||
|
|
||||||
|
if (mesh().foundObject<cmpTurbModel>(cmpTurbModel::propertiesName))
|
||||||
|
{
|
||||||
|
const auto& turb =
|
||||||
|
mesh().lookupObject<cmpTurbModel>(cmpTurbModel::propertiesName);
|
||||||
|
|
||||||
|
// Note: calling he(p,T) instead of he()
|
||||||
|
const volScalarField he(turb.transport().he(turb.transport().p(), T));
|
||||||
|
const volScalarField::Boundary& hebf = he.boundaryField();
|
||||||
|
|
||||||
|
const volScalarField alphaEff(turb.alphaEff());
|
||||||
|
const volScalarField::Boundary& alphaEffbf = alphaEff.boundaryField();
|
||||||
|
|
||||||
|
for (const label patchi : patchSet_)
|
||||||
|
{
|
||||||
|
q[patchi] = alphaEffbf[patchi]*hebf[patchi].snGrad();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (mesh().foundObject<fluidThermo>(fluidThermo::dictName))
|
||||||
|
{
|
||||||
|
const auto& thermo =
|
||||||
|
mesh().lookupObject<fluidThermo>(fluidThermo::dictName);
|
||||||
|
|
||||||
|
// Note: calling he(p,T) instead of he()
|
||||||
|
const volScalarField he(thermo.he(thermo.p(), T));
|
||||||
|
const volScalarField::Boundary& hebf = he.boundaryField();
|
||||||
|
|
||||||
|
const volScalarField& alpha(thermo.alpha());
|
||||||
|
const volScalarField::Boundary& alphabf = alpha.boundaryField();
|
||||||
|
|
||||||
|
for (const label patchi : patchSet_)
|
||||||
|
{
|
||||||
|
q[patchi] = alphabf[patchi]*hebf[patchi].snGrad();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "Unable to find a valid thermo model to evaluate q. " << nl
|
||||||
|
<< "Database contents are: " << mesh().objectRegistry::sortedToc()
|
||||||
|
<< exit(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
// No radiative heat flux contribution is present
|
||||||
|
|
||||||
|
return tq;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::evapotranspirationHeatTransferModels::grass::grass
|
||||||
|
(
|
||||||
|
const dictionary& dict,
|
||||||
|
const fvMesh& mesh
|
||||||
|
)
|
||||||
|
:
|
||||||
|
evapotranspirationHeatTransferModel(dict, mesh),
|
||||||
|
soilHeatFluxMethod_
|
||||||
|
(
|
||||||
|
soilHeatFluxTypeNames.getOrDefault
|
||||||
|
(
|
||||||
|
"soilHeatFluxMethod",
|
||||||
|
dict,
|
||||||
|
soilHeatFluxType::PROPORTIONAL_TO_SOLAR_RADIATION
|
||||||
|
)
|
||||||
|
),
|
||||||
|
Tptr_(nullptr),
|
||||||
|
RHptr_(nullptr),
|
||||||
|
area_(-1),
|
||||||
|
Csoil_(),
|
||||||
|
rho_(),
|
||||||
|
Cp_(),
|
||||||
|
epsilon_(),
|
||||||
|
h_(),
|
||||||
|
kappa_(),
|
||||||
|
uRef_(),
|
||||||
|
zRefU_(),
|
||||||
|
zRefH_(),
|
||||||
|
zom_(),
|
||||||
|
zoh_(),
|
||||||
|
d_(),
|
||||||
|
ri_(),
|
||||||
|
pAtm_(),
|
||||||
|
Tref_(0),
|
||||||
|
TName_(),
|
||||||
|
patchSet_()
|
||||||
|
{
|
||||||
|
Info<< " Activating evapotranspiration heat transfer model: "
|
||||||
|
<< typeName << endl;
|
||||||
|
|
||||||
|
read(dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::tmp<Foam::scalarField>
|
||||||
|
Foam::evapotranspirationHeatTransferModels::grass::Q
|
||||||
|
(
|
||||||
|
const labelList& cells
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
if (area_ == -1)
|
||||||
|
{
|
||||||
|
area_ = S(cells);
|
||||||
|
}
|
||||||
|
|
||||||
|
Tref_ = Tptr_->value(mesh().time().timeOutputValue());
|
||||||
|
|
||||||
|
return E(cells)*area_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::evapotranspirationHeatTransferModels::grass::read
|
||||||
|
(
|
||||||
|
const dictionary& dict
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (!evapotranspirationHeatTransferModel::read(dict))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tptr_.reset(Function1<scalar>::New("Tref", dict, &mesh()));
|
||||||
|
RHptr_.reset(Function1<scalar>::New("RHref", dict, &mesh()));
|
||||||
|
|
||||||
|
area_ = -1;
|
||||||
|
|
||||||
|
const auto range = scalarMinMax::ge(SMALL);
|
||||||
|
|
||||||
|
Csoil_ = dict.getCheckOrDefault<scalar>("Csoil", 0.1, range);
|
||||||
|
rho_ = dict.getCheckOrDefault<scalar>("rho", 1.225, range);
|
||||||
|
Cp_ = dict.getCheckOrDefault<scalar>("Cp", 1013.0, range);
|
||||||
|
epsilon_ = dict.getCheckOrDefault<scalar>("epsilon", 0.622, range);
|
||||||
|
h_ = dict.getCheckOrDefault<scalar>("h", 0.1, range);
|
||||||
|
kappa_ = dict.getCheckOrDefault<scalar>("kappa", 0.41, range);
|
||||||
|
uRef_ = dict.getCheckOrDefault<scalar>("uRef", 2, range);
|
||||||
|
zRefU_ = dict.getCheckOrDefault<scalar>("zRefU", 10, range);
|
||||||
|
zRefH_ = dict.getCheckOrDefault<scalar>("zRefH", 10, range);
|
||||||
|
zom_ = dict.getCheckOrDefault<scalar>("zom", 0.123, range);
|
||||||
|
zoh_ = dict.getCheckOrDefault<scalar>("zoh", 0.0123, range);
|
||||||
|
d_ = dict.getCheckOrDefault<scalar>("d", 2.0/3.0, range);
|
||||||
|
ri_ = dict.getCheckOrDefault<scalar>("ri", 100, range);
|
||||||
|
pAtm_ = dict.getCheckOrDefault<scalar>("pAtm", 101.325, range);
|
||||||
|
TName_ = dict.getOrDefault<word>("T", "T");
|
||||||
|
|
||||||
|
if (soilHeatFluxMethod_ == soilHeatFluxType::BOUNDARY)
|
||||||
|
{
|
||||||
|
patchSet_ =
|
||||||
|
mesh().boundaryMesh().patchSet(dict.get<wordRes>("patches"));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -0,0 +1,342 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | www.openfoam.com
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2022 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Class
|
||||||
|
Foam::evapotranspirationHeatTransferModels::grass
|
||||||
|
|
||||||
|
Description
|
||||||
|
Applies sources on temperature (\c T - incompressible) or energy
|
||||||
|
(\c h/e - compressible) equation to incorporate evapotranspiration
|
||||||
|
heat-transfer effects from the specified grass canopy.
|
||||||
|
The model is based on Pemnan-Monteith Equation model.
|
||||||
|
|
||||||
|
Sources applied to either of the below, if exist:
|
||||||
|
\verbatim
|
||||||
|
T | Temperature [K]
|
||||||
|
e | Internal energy [m^2/s^2]
|
||||||
|
h | Enthalphy [m^2/s^2]
|
||||||
|
\endverbatim
|
||||||
|
|
||||||
|
Required fields:
|
||||||
|
\verbatim
|
||||||
|
T | Temperature [K]
|
||||||
|
e | Internal energy [m^2/s^2]
|
||||||
|
h | Enthalphy [m^2/s^2]
|
||||||
|
LAD | Leaf area density [m^2/m^3]
|
||||||
|
\endverbatim
|
||||||
|
|
||||||
|
References:
|
||||||
|
\verbatim
|
||||||
|
Governing equations (tag:BSG):
|
||||||
|
Brozovsky, J., Simonsen, A., & Gaitani, N. (2021).
|
||||||
|
Validation of a CFD model for the evaluation of urban
|
||||||
|
microclimate at high latitudes: A case study in Trondheim, Norway.
|
||||||
|
Building and Environment, 205, 108175.
|
||||||
|
DOI:10.1016/j.buildenv.2021.108175
|
||||||
|
|
||||||
|
Governing equations (tag:APR):
|
||||||
|
Allen, R. G., Pereira, L. S., Raes, D., & Smith, M. (1998).
|
||||||
|
Crop evapotranspiration-Guidelines for computing crop
|
||||||
|
water requirements-FAO Irrigation and drainage paper 56.
|
||||||
|
Fao, Rome, 300(9), D05109.
|
||||||
|
\endverbatim
|
||||||
|
|
||||||
|
Usage
|
||||||
|
Example by using \c constant/fvOptions:
|
||||||
|
\verbatim
|
||||||
|
evapotranspirationHeatTransfer1
|
||||||
|
{
|
||||||
|
// Inherited entries
|
||||||
|
...
|
||||||
|
|
||||||
|
// Mandatory entries
|
||||||
|
model grass;
|
||||||
|
Tref <Function1<scalar>>;
|
||||||
|
RHref <Function1<scalar>>;
|
||||||
|
|
||||||
|
// Conditional entries
|
||||||
|
|
||||||
|
// when soilHeatFluxMethod == boundary
|
||||||
|
patches <wordRes>;
|
||||||
|
|
||||||
|
// Optional entries
|
||||||
|
soilHeatFluxMethod <word>;
|
||||||
|
Csoil <scalar>;
|
||||||
|
rho <scalar>;
|
||||||
|
Cp <scalar>;
|
||||||
|
epsilon <scalar>;
|
||||||
|
h <scalar>;
|
||||||
|
kappa <scalar>;
|
||||||
|
uRef <scalar>;
|
||||||
|
zRefU <scalar>;
|
||||||
|
zRefH <scalar>;
|
||||||
|
zom <scalar>;
|
||||||
|
zoh <scalar>;
|
||||||
|
d <scalar>;
|
||||||
|
ri <scalar>;
|
||||||
|
pAtm <scalar>;
|
||||||
|
T <word>;
|
||||||
|
}
|
||||||
|
\endverbatim
|
||||||
|
|
||||||
|
where the entries mean:
|
||||||
|
\table
|
||||||
|
Property | Description | Type | Reqd | Deflt
|
||||||
|
model | Model name: grass | word | yes | -
|
||||||
|
Tref | Reference weather station air temperature [Celsius] <!--
|
||||||
|
--> | Function1\<scalar\> | yes | -
|
||||||
|
RHref | Reference weather station relative humidity [%] <!--
|
||||||
|
--> | Function1\<scalar\> | yes | -
|
||||||
|
patches | Names of ground patches | wordRes | yes | -
|
||||||
|
soilHeatFluxMethod | Method to calculate soil heat flux - see below <!--
|
||||||
|
--> | word | no | -
|
||||||
|
Csoil | Proportionality constant of soil heat-flux wrt <!--
|
||||||
|
--> solar radiation | scalar | no | 0.1
|
||||||
|
rho | Mean air density at constant pressure [kg/m^3] <!--
|
||||||
|
--> | scalar | no | 1.225
|
||||||
|
Cp | Specific heat at constant pressure [J/kg/C] <!--
|
||||||
|
--> | scalar | no | 1013.0
|
||||||
|
epsilon | Molecular-weight ratio of water vapour/dry air [-] <!--
|
||||||
|
--> | scalar | no | 0.622
|
||||||
|
h | Height of grass layer [m] | scalar | no | 0.1
|
||||||
|
kappa | Von Karman constant [-] | scalar | no | 0.41
|
||||||
|
uRef | Reference velocity magnitude [m/s] | scalar | no | 2.0
|
||||||
|
zRefU | Height of wind speed measurements [m] | scalar | no | 10.0
|
||||||
|
zRefH | Height of humidity measurements [m] | scalar | no | 10.0
|
||||||
|
zom | Roughness length governing momentum transfer coefficient <!--
|
||||||
|
--> [-] | scalar | no | 0.123
|
||||||
|
zoh | Roughness length governing transfer of heat and vapour <!--
|
||||||
|
--> coefficient [-] | scalar | no | 0.0123
|
||||||
|
d | Zero plane displacement height coefficient [-] <!--
|
||||||
|
--> | scalar | no | 0.666
|
||||||
|
ri | Bulk stomata resistance of leaf [s/m] | scalar | no | 100.0
|
||||||
|
pAtm | Atmospheric pressure [kPa] | scalar | no | 101.325
|
||||||
|
T | Name of temperature field | word | no | T
|
||||||
|
\endtable
|
||||||
|
|
||||||
|
Options for the \c soilHeatFluxMethod entry:
|
||||||
|
\verbatim
|
||||||
|
proportionalToSolarRadiation | Estimate from solar load
|
||||||
|
boundary | Obtain soil heat flux from boundary
|
||||||
|
\endverbatim
|
||||||
|
|
||||||
|
The inherited entries are elaborated in:
|
||||||
|
- \link evapotranspirationHeatTransfer.H \endlink
|
||||||
|
- \link evapotranspirationHeatTransferModel.H \endlink
|
||||||
|
|
||||||
|
SourceFiles
|
||||||
|
grass.C
|
||||||
|
grassTemplates.C
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef Foam_evapotranspirationHeatTransferModels_grass_H
|
||||||
|
#define Foam_evapotranspirationHeatTransferModels_grass_H
|
||||||
|
|
||||||
|
#include "evapotranspirationHeatTransferModel.H"
|
||||||
|
#include "Function1.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
namespace evapotranspirationHeatTransferModels
|
||||||
|
{
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
Class grass Declaration
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
class grass
|
||||||
|
:
|
||||||
|
public evapotranspirationHeatTransferModel
|
||||||
|
{
|
||||||
|
// Private Enumerations
|
||||||
|
|
||||||
|
//- Options for the soil heat flux
|
||||||
|
enum soilHeatFluxType : char
|
||||||
|
{
|
||||||
|
PROPORTIONAL_TO_SOLAR_RADIATION = 0, //!< "Estimate from solar load"
|
||||||
|
BOUNDARY, //!< "Obtain soil heat flux from boundary"
|
||||||
|
};
|
||||||
|
|
||||||
|
//- Names for soilHeatFluxType
|
||||||
|
static const Enum<soilHeatFluxType> soilHeatFluxTypeNames;
|
||||||
|
|
||||||
|
|
||||||
|
// Private Data
|
||||||
|
|
||||||
|
//- Soil heat-flux calculation method
|
||||||
|
enum soilHeatFluxType soilHeatFluxMethod_;
|
||||||
|
|
||||||
|
//- Reference weather station air temperature [Celsius]
|
||||||
|
autoPtr<Function1<scalar>> Tptr_;
|
||||||
|
|
||||||
|
//- Reference weather station relative humidity [%]
|
||||||
|
autoPtr<Function1<scalar>> RHptr_;
|
||||||
|
|
||||||
|
//- Area coverage of grass [m^2]
|
||||||
|
mutable scalar area_;
|
||||||
|
|
||||||
|
//- Proportionality constant of soil heat-flux wrt solar radiation [-]
|
||||||
|
scalar Csoil_;
|
||||||
|
|
||||||
|
//- Mean air density at constant pressure [kg/m^3]
|
||||||
|
scalar rho_;
|
||||||
|
|
||||||
|
//- Specific heat at constant pressure [J/kg/C]
|
||||||
|
scalar Cp_;
|
||||||
|
|
||||||
|
//- Molecular-weight ratio of water vapour/dry air [-]
|
||||||
|
scalar epsilon_;
|
||||||
|
|
||||||
|
//- Height of grass layer [m]
|
||||||
|
scalar h_;
|
||||||
|
|
||||||
|
//- Von Karman constant [-]
|
||||||
|
scalar kappa_;
|
||||||
|
|
||||||
|
//- Reference velocity magnitude [m/s]
|
||||||
|
scalar uRef_;
|
||||||
|
|
||||||
|
//- Height of wind speed measurements [m]
|
||||||
|
scalar zRefU_;
|
||||||
|
|
||||||
|
//- Height of humidity measurements [m]
|
||||||
|
scalar zRefH_;
|
||||||
|
|
||||||
|
//- Roughness length governing momentum transfer coefficient [-]
|
||||||
|
scalar zom_;
|
||||||
|
|
||||||
|
//- Roughness length governing transfer of heat and vapour coeff [-]
|
||||||
|
scalar zoh_;
|
||||||
|
|
||||||
|
//- Zero plane displacement height coefficient [-]
|
||||||
|
scalar d_;
|
||||||
|
|
||||||
|
//- Bulk stomata resistance of leaf [s/m]
|
||||||
|
scalar ri_;
|
||||||
|
|
||||||
|
//- Atmospheric pressure [kPa]
|
||||||
|
scalar pAtm_;
|
||||||
|
|
||||||
|
//- Cached reference weather station air temperature [Celsius]
|
||||||
|
mutable scalar Tref_;
|
||||||
|
|
||||||
|
//- Name of temperature field
|
||||||
|
word TName_;
|
||||||
|
|
||||||
|
//- List of patches to calculate boundary heat flux
|
||||||
|
labelHashSet patchSet_;
|
||||||
|
|
||||||
|
|
||||||
|
// Private Member Functions
|
||||||
|
|
||||||
|
//- Return evapotranspiration heat flux through grass layer [W/m^2]
|
||||||
|
tmp<scalarField> E(const labelList& cells) const;
|
||||||
|
|
||||||
|
//- Return slope of the relation between
|
||||||
|
//- vapour pressure-temperature [Pa/K]
|
||||||
|
scalar Delta() const;
|
||||||
|
|
||||||
|
//- Return atmospheric vapour pressure deficit [Pa]
|
||||||
|
scalar D() const;
|
||||||
|
|
||||||
|
//- Return saturated vapour pressure over water [Pa]
|
||||||
|
scalar pSat() const;
|
||||||
|
|
||||||
|
//- Return psychrometric constant [kPa/K]
|
||||||
|
scalar gamma() const;
|
||||||
|
|
||||||
|
//- Return specific latent heat of vaporisation [MJ/kg]
|
||||||
|
scalar lambda() const;
|
||||||
|
|
||||||
|
//- Return bulk aerodynamic resistance [Pa]
|
||||||
|
scalar ra() const;
|
||||||
|
|
||||||
|
//- Return bulk surface resistance [Pa]
|
||||||
|
scalar rs() const;
|
||||||
|
|
||||||
|
//- Return area coverage of grass [m^2]
|
||||||
|
scalar S(const labelList& cells) const;
|
||||||
|
|
||||||
|
//- Return area-averaged heat flux through ground [W/m^2]
|
||||||
|
scalar G(const labelList& cells) const;
|
||||||
|
|
||||||
|
//- Return heat-flux boundary fields
|
||||||
|
tmp<FieldField<Field, scalar>> qBf() const;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//- Runtime type information
|
||||||
|
TypeName("grass");
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
|
||||||
|
//- Construct from components
|
||||||
|
grass
|
||||||
|
(
|
||||||
|
const dictionary& dict,
|
||||||
|
const fvMesh& mesh
|
||||||
|
);
|
||||||
|
|
||||||
|
//- No copy construct
|
||||||
|
grass(const grass&) = delete;
|
||||||
|
|
||||||
|
//- No copy assignment
|
||||||
|
void operator=(const grass&) = delete;
|
||||||
|
|
||||||
|
|
||||||
|
//- Destructor
|
||||||
|
virtual ~grass() = default;
|
||||||
|
|
||||||
|
|
||||||
|
// Member Functions
|
||||||
|
|
||||||
|
// Evaluation
|
||||||
|
|
||||||
|
//- Return heat-transfer rate for speficied cells [J/s]
|
||||||
|
virtual tmp<scalarField> Q(const labelList& cells) const;
|
||||||
|
|
||||||
|
|
||||||
|
// I-O
|
||||||
|
|
||||||
|
//- Read the dictionary
|
||||||
|
virtual bool read(const dictionary& dict);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
} // End namespace evapotranspirationHeatTransferModels
|
||||||
|
} // End namespace Foam
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -0,0 +1,139 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | www.openfoam.com
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2022 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "tree.H"
|
||||||
|
#include "addToRunTimeSelectionTable.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
namespace evapotranspirationHeatTransferModels
|
||||||
|
{
|
||||||
|
defineTypeNameAndDebug(tree, 0);
|
||||||
|
addToRunTimeSelectionTable
|
||||||
|
(
|
||||||
|
evapotranspirationHeatTransferModel,
|
||||||
|
tree,
|
||||||
|
dictionary
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::scalar Foam::evapotranspirationHeatTransferModels::tree::Et() const
|
||||||
|
{
|
||||||
|
return a_*q() + b_;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Foam::tmp<Foam::scalarField>
|
||||||
|
Foam::evapotranspirationHeatTransferModels::tree::leafArea
|
||||||
|
(
|
||||||
|
const labelList& cells
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
const volScalarField& LAD = getOrReadField(LADname_);
|
||||||
|
|
||||||
|
const scalarField& V = mesh().V();
|
||||||
|
|
||||||
|
auto tleafArea = tmp<scalarField>::New(cells.size(), Zero);
|
||||||
|
auto& leafArea = tleafArea.ref();
|
||||||
|
|
||||||
|
forAll(cells, i)
|
||||||
|
{
|
||||||
|
const label celli = cells[i];
|
||||||
|
|
||||||
|
leafArea[i] = LAD[celli]*V[celli];
|
||||||
|
}
|
||||||
|
|
||||||
|
return tleafArea;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::evapotranspirationHeatTransferModels::tree::tree
|
||||||
|
(
|
||||||
|
const dictionary& dict,
|
||||||
|
const fvMesh& mesh
|
||||||
|
)
|
||||||
|
:
|
||||||
|
evapotranspirationHeatTransferModel(dict, mesh),
|
||||||
|
a_(),
|
||||||
|
b_(),
|
||||||
|
lambda_(),
|
||||||
|
LADname_()
|
||||||
|
{
|
||||||
|
Info<< " Activating evapotranspiration heat transfer model: "
|
||||||
|
<< typeName << endl;
|
||||||
|
|
||||||
|
read(dict);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::tmp<Foam::scalarField>
|
||||||
|
Foam::evapotranspirationHeatTransferModels::tree::Q
|
||||||
|
(
|
||||||
|
const labelList& cells
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
// Convert units from [MJ g/hr] to [J kg/s]
|
||||||
|
static const scalar unitConverter = scalar(1000)/scalar(3600);
|
||||||
|
|
||||||
|
return unitConverter*lambda_*Et()*leafArea(cells);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::evapotranspirationHeatTransferModels::tree::read
|
||||||
|
(
|
||||||
|
const dictionary& dict
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (!evapotranspirationHeatTransferModel::read(dict))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto range = scalarMinMax::ge(SMALL);
|
||||||
|
|
||||||
|
a_ = dict.getOrDefault<scalar>("a", 0.3622);
|
||||||
|
b_ = dict.getOrDefault<scalar>("b", 60.758);
|
||||||
|
lambda_ = dict.getCheckOrDefault<scalar>("lambda", 2.44, range);
|
||||||
|
LADname_ = dict.getOrDefault<word>("LAD", "LAD");
|
||||||
|
|
||||||
|
(void) getOrReadField(LADname_);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -0,0 +1,219 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | www.openfoam.com
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2022 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Class
|
||||||
|
Foam::evapotranspirationHeatTransferModels::tree
|
||||||
|
|
||||||
|
Description
|
||||||
|
Applies sources on temperature (\c T - incompressible) or energy
|
||||||
|
(\c h/e - compressible) equation to incorporate evapotranspiration
|
||||||
|
heat-transfer effects from the specified tree canopy.
|
||||||
|
|
||||||
|
The heat-transfer is calculated based on the following relations.
|
||||||
|
The heat transfer is given by the first equation and the
|
||||||
|
evapotranspiration is calculated linearly proportional to absorbed
|
||||||
|
solar radiation (direct and diffusive) with the empirical relation
|
||||||
|
shown in the second equation below.
|
||||||
|
|
||||||
|
\f[
|
||||||
|
Q = \lambda E_t \frac{1000}{3600} \int_{cellZone} LAD \, dV
|
||||||
|
\f]
|
||||||
|
|
||||||
|
where
|
||||||
|
\vartable
|
||||||
|
Q | Heat transfer from tree crown [W]
|
||||||
|
\lambda | Specific latent heat of vaporisation [MJ/kg]
|
||||||
|
E_t | Area-averaged evapotranspiration [g/m^2/hr]
|
||||||
|
LAD | Leaf area density [m^2/m^3]
|
||||||
|
V | Volume [m^3]
|
||||||
|
\endvartable
|
||||||
|
|
||||||
|
with
|
||||||
|
|
||||||
|
\f[
|
||||||
|
E_t = a R_n + b
|
||||||
|
\f]
|
||||||
|
|
||||||
|
where
|
||||||
|
\vartable
|
||||||
|
R_n | Heat flux through tree crown [W/m^2]
|
||||||
|
a | Linear-regression coefficient - slope parameter [g/W/hr]
|
||||||
|
b | Linear-regression coefficient - intercept parameter [g/m^2/hr]
|
||||||
|
\endvartable
|
||||||
|
|
||||||
|
Sources applied to either of the below, if exist:
|
||||||
|
\verbatim
|
||||||
|
T | Temperature [K]
|
||||||
|
e | Internal energy [m^2/s^2]
|
||||||
|
h | Enthalphy [m^2/s^2]
|
||||||
|
\endverbatim
|
||||||
|
|
||||||
|
Required fields:
|
||||||
|
\verbatim
|
||||||
|
T | Temperature [K]
|
||||||
|
e | Internal energy [m^2/s^2]
|
||||||
|
h | Enthalphy [m^2/s^2]
|
||||||
|
LAD | Leaf area density [m^2/m^3]
|
||||||
|
\endverbatim
|
||||||
|
|
||||||
|
Usage
|
||||||
|
Example by using \c constant/fvOptions:
|
||||||
|
\verbatim
|
||||||
|
evapotranspirationHeatTransfer1
|
||||||
|
{
|
||||||
|
// Inherited entries
|
||||||
|
...
|
||||||
|
|
||||||
|
// Mandatory entries
|
||||||
|
model tree;
|
||||||
|
|
||||||
|
// Optional entries
|
||||||
|
a <scalar>;
|
||||||
|
b <scalar>;
|
||||||
|
lambda <scalar>;
|
||||||
|
LAD <word>;
|
||||||
|
}
|
||||||
|
\endverbatim
|
||||||
|
|
||||||
|
where the entries mean:
|
||||||
|
\table
|
||||||
|
Property | Description | Type | Reqd | Deflt
|
||||||
|
model | Model name: tree | word | yes | -
|
||||||
|
a | Linear-regression coefficient - slope parameter [g/W/hr] | scalar <!--
|
||||||
|
--> | no | 0.3622
|
||||||
|
b | Linear-regression coefficient - intercept parameter [g/m^2/hr] <!--
|
||||||
|
--> | scalar | no | 60.758
|
||||||
|
lambda | Specific latent heat of vaporisation [MJ/kg] | scalar <!--
|
||||||
|
--> | no | 2.44
|
||||||
|
LAD | Name of leaf-area density field | word | no | LAD
|
||||||
|
\endtable
|
||||||
|
|
||||||
|
The inherited entries are elaborated in:
|
||||||
|
- \link evapotranspirationHeatTransfer.H \endlink
|
||||||
|
- \link evapotranspirationHeatTransferModel.H \endlink
|
||||||
|
|
||||||
|
SourceFiles
|
||||||
|
tree.C
|
||||||
|
treeTemplates.C
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef Foam_evapotranspirationHeatTransferModels_tree_H
|
||||||
|
#define Foam_evapotranspirationHeatTransferModels_tree_H
|
||||||
|
|
||||||
|
#include "evapotranspirationHeatTransferModel.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
namespace evapotranspirationHeatTransferModels
|
||||||
|
{
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
Class tree Declaration
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
class tree
|
||||||
|
:
|
||||||
|
public evapotranspirationHeatTransferModel
|
||||||
|
{
|
||||||
|
// Private Data
|
||||||
|
|
||||||
|
//- Linear-regression coefficient - slope parameter [g/W/hr]
|
||||||
|
scalar a_;
|
||||||
|
|
||||||
|
//- Linear-regression coefficient - intercept parameter [g/m^2/hr]
|
||||||
|
scalar b_;
|
||||||
|
|
||||||
|
//- Specific latent heat of vaporisation [MJ/kg]
|
||||||
|
scalar lambda_;
|
||||||
|
|
||||||
|
//- Name of leaf-area density field
|
||||||
|
word LADname_;
|
||||||
|
|
||||||
|
|
||||||
|
// Private Member Functions
|
||||||
|
|
||||||
|
//- Return area-averaged transpiration [g/m^2/hr]
|
||||||
|
// Calculated from empirical regressions with heat flux
|
||||||
|
scalar Et() const;
|
||||||
|
|
||||||
|
//- Return volume weighted leaf area density (LAD) [m^2]
|
||||||
|
// LAD [m^2/m^3]: one-sided area of leaves per unit volume
|
||||||
|
tmp<scalarField> leafArea(const labelList& cells) const;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//- Runtime type information
|
||||||
|
TypeName("tree");
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
|
||||||
|
//- Construct from components
|
||||||
|
tree
|
||||||
|
(
|
||||||
|
const dictionary& dict,
|
||||||
|
const fvMesh& mesh
|
||||||
|
);
|
||||||
|
|
||||||
|
//- No copy construct
|
||||||
|
tree(const tree&) = delete;
|
||||||
|
|
||||||
|
//- No copy assignment
|
||||||
|
void operator=(const tree&) = delete;
|
||||||
|
|
||||||
|
|
||||||
|
//- Destructor
|
||||||
|
virtual ~tree() = default;
|
||||||
|
|
||||||
|
|
||||||
|
// Member Functions
|
||||||
|
|
||||||
|
// Evaluation
|
||||||
|
|
||||||
|
//- Return heat-transfer rate for speficied cells [J/s]
|
||||||
|
virtual tmp<scalarField> Q(const labelList& cells) const;
|
||||||
|
|
||||||
|
|
||||||
|
// I-O
|
||||||
|
|
||||||
|
//- Read the dictionary
|
||||||
|
virtual bool read(const dictionary& dict);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
} // End namespace evapotranspirationHeatTransferModels
|
||||||
|
} // End namespace Foam
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
234
src/atmosphericModels/fvOptions/treeTurbulence/treeTurbulence.C
Normal file
234
src/atmosphericModels/fvOptions/treeTurbulence/treeTurbulence.C
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | www.openfoam.com
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2022 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "treeTurbulence.H"
|
||||||
|
#include "addToRunTimeSelectionTable.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
namespace fv
|
||||||
|
{
|
||||||
|
defineTypeNameAndDebug(treeTurbulence, 0);
|
||||||
|
addToRunTimeSelectionTable(option, treeTurbulence, dictionary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::volScalarField& Foam::fv::treeTurbulence::getOrReadField
|
||||||
|
(
|
||||||
|
const word& fieldName
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
auto* ptr = mesh_.getObjectPtr<volScalarField>(fieldName);
|
||||||
|
|
||||||
|
if (!ptr)
|
||||||
|
{
|
||||||
|
ptr = new volScalarField
|
||||||
|
(
|
||||||
|
IOobject
|
||||||
|
(
|
||||||
|
fieldName,
|
||||||
|
mesh_.time().timeName(),
|
||||||
|
mesh_,
|
||||||
|
IOobject::MUST_READ,
|
||||||
|
IOobject::AUTO_WRITE
|
||||||
|
),
|
||||||
|
mesh_
|
||||||
|
);
|
||||||
|
mesh_.objectRegistry::store(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
Foam::fv::treeTurbulence::treeTurbulence
|
||||||
|
(
|
||||||
|
const word& sourceName,
|
||||||
|
const word& modelType,
|
||||||
|
const dictionary& dict,
|
||||||
|
const fvMesh& mesh
|
||||||
|
)
|
||||||
|
:
|
||||||
|
fv::cellSetOption(sourceName, modelType, dict, mesh),
|
||||||
|
isEpsilon_(true),
|
||||||
|
betaP_(),
|
||||||
|
betaD_(),
|
||||||
|
Ceps1_(),
|
||||||
|
Ceps2_(),
|
||||||
|
betaStar_(),
|
||||||
|
CdName_(),
|
||||||
|
LADname_()
|
||||||
|
{
|
||||||
|
read(dict);
|
||||||
|
|
||||||
|
const auto* turbPtr = mesh_.findObject<turbulenceModel>
|
||||||
|
(
|
||||||
|
turbulenceModel::propertiesName
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!turbPtr)
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "Unable to find a turbulence model."
|
||||||
|
<< abort(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldNames_.resize(2);
|
||||||
|
|
||||||
|
tmp<volScalarField> tepsilon = turbPtr->epsilon();
|
||||||
|
tmp<volScalarField> tomega = turbPtr->omega();
|
||||||
|
|
||||||
|
if (!tepsilon.isTmp())
|
||||||
|
{
|
||||||
|
fieldNames_[0] = tepsilon().name();
|
||||||
|
}
|
||||||
|
else if (!tomega.isTmp())
|
||||||
|
{
|
||||||
|
isEpsilon_ = false;
|
||||||
|
fieldNames_[0] = tomega().name();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FatalErrorInFunction
|
||||||
|
<< "Unable to find epsilon or omega field." << nl
|
||||||
|
<< abort(FatalError);
|
||||||
|
}
|
||||||
|
|
||||||
|
fieldNames_[1] = turbPtr->k()().name();
|
||||||
|
|
||||||
|
fv::option::resetApplied();
|
||||||
|
|
||||||
|
Log << " Applying treeTurbulence to: "
|
||||||
|
<< fieldNames_[0] << " and " << fieldNames_[1]
|
||||||
|
<< endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
void Foam::fv::treeTurbulence::addSup
|
||||||
|
(
|
||||||
|
fvScalarMatrix& eqn,
|
||||||
|
const label fieldi
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (fieldi == 1)
|
||||||
|
{
|
||||||
|
kSource(geometricOneField(), geometricOneField(), eqn, fieldi);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isEpsilon_)
|
||||||
|
{
|
||||||
|
epsilonSource(geometricOneField(), geometricOneField(), eqn, fieldi);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
omegaSource(geometricOneField(), geometricOneField(), eqn, fieldi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::fv::treeTurbulence::addSup
|
||||||
|
(
|
||||||
|
const volScalarField& rho,
|
||||||
|
fvScalarMatrix& eqn,
|
||||||
|
const label fieldi
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (fieldi == 1)
|
||||||
|
{
|
||||||
|
kSource(geometricOneField(), rho, eqn, fieldi);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isEpsilon_)
|
||||||
|
{
|
||||||
|
epsilonSource(geometricOneField(), rho, eqn, fieldi);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
omegaSource(geometricOneField(), rho, eqn, fieldi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Foam::fv::treeTurbulence::addSup
|
||||||
|
(
|
||||||
|
const volScalarField& alpha,
|
||||||
|
const volScalarField& rho,
|
||||||
|
fvScalarMatrix& eqn,
|
||||||
|
const label fieldi
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (fieldi == 1)
|
||||||
|
{
|
||||||
|
kSource(alpha, rho, eqn, fieldi);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isEpsilon_)
|
||||||
|
{
|
||||||
|
epsilonSource(alpha, rho, eqn, fieldi);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
omegaSource(alpha, rho, eqn, fieldi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Foam::fv::treeTurbulence::read(const dictionary& dict)
|
||||||
|
{
|
||||||
|
if (!fv::cellSetOption::read(dict))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
betaP_ = dict.getOrDefault<scalar>("betaP", 1.0);
|
||||||
|
betaD_ = dict.getOrDefault<scalar>("betaD", 4.0);
|
||||||
|
Ceps1_ = dict.getOrDefault<scalar>("Ceps1", 0.9);
|
||||||
|
Ceps2_ = dict.getOrDefault<scalar>("Ceps2", 0.9);
|
||||||
|
betaStar_ = dict.getOrDefault<scalar>("betaStar", 0.09);
|
||||||
|
CdName_ = dict.getOrDefault<word>("Cd", "Cd");
|
||||||
|
LADname_ = dict.getOrDefault<word>("LAD", "LAD");
|
||||||
|
|
||||||
|
(void) getOrReadField(CdName_);
|
||||||
|
(void) getOrReadField(LADname_);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
262
src/atmosphericModels/fvOptions/treeTurbulence/treeTurbulence.H
Normal file
262
src/atmosphericModels/fvOptions/treeTurbulence/treeTurbulence.H
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | www.openfoam.com
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2022 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
Class
|
||||||
|
Foam::fv::treeTurbulence
|
||||||
|
|
||||||
|
Group
|
||||||
|
grpFvOptionsSources
|
||||||
|
|
||||||
|
Description
|
||||||
|
Applies sources on \c k and either \c epsilon or \c omega
|
||||||
|
to incorporate effects of trees on atmospheric boundary layer.
|
||||||
|
|
||||||
|
Corrections applied to:
|
||||||
|
\verbatim
|
||||||
|
k | Turbulent kinetic energy [m^2/s^2]
|
||||||
|
\endverbatim
|
||||||
|
|
||||||
|
Corrections applied to either of the below, if exist:
|
||||||
|
\verbatim
|
||||||
|
epsilon | Turbulent kinetic energy dissipation rate [m^2/s^3]
|
||||||
|
omega | Specific dissipation rate [1/s]
|
||||||
|
\endverbatim
|
||||||
|
|
||||||
|
Required fields:
|
||||||
|
\verbatim
|
||||||
|
k | Turbulent kinetic energy [m^2/s^2]
|
||||||
|
Cd | Canopy drag coefficient [-]
|
||||||
|
LAD | Leaf area density [m^2/m^3]
|
||||||
|
epsilon | Turbulent kinetic energy dissipation rate [m^2/s^3]
|
||||||
|
omega | Specific dissipation rate [1/s]
|
||||||
|
\endverbatim
|
||||||
|
|
||||||
|
References:
|
||||||
|
\verbatim
|
||||||
|
Governing equations (tag:BSG):
|
||||||
|
Brozovsky, J., Simonsen, A., & Gaitani, N. (2021).
|
||||||
|
Validation of a CFD model for the evaluation of urban microclimate
|
||||||
|
at high latitudes: A case study in Trondheim, Norway.
|
||||||
|
Building and Environment, 205, 108175.
|
||||||
|
DOI:10.1016/j.buildenv.2021.108175
|
||||||
|
\endverbatim
|
||||||
|
|
||||||
|
Usage
|
||||||
|
Example by using \c constant/fvOptions:
|
||||||
|
\verbatim
|
||||||
|
treeTurbulence1
|
||||||
|
{
|
||||||
|
// Mandatory entries
|
||||||
|
type treeTurbulence;
|
||||||
|
|
||||||
|
// Optional entries
|
||||||
|
Cd <word>;
|
||||||
|
LAD <word>;
|
||||||
|
betaP <scalar>;
|
||||||
|
betaD <scalar>;
|
||||||
|
Ceps1 <scalar>;
|
||||||
|
Ceps2 <scalar>;
|
||||||
|
betaStar <scalar>;
|
||||||
|
|
||||||
|
// Inherited entries
|
||||||
|
...
|
||||||
|
}
|
||||||
|
\endverbatim
|
||||||
|
|
||||||
|
where the entries mean:
|
||||||
|
\table
|
||||||
|
Property | Description | Type | Reqd | Deflt
|
||||||
|
type | Type name: treeTurbulence | word | yes | -
|
||||||
|
Cd | Name of operand canopy drag coefficient field | word | no | Cd
|
||||||
|
LAD | Name of operand leaf area density field | word | no | LAD
|
||||||
|
betaP | Model coefficient | scalar | no | 1.0
|
||||||
|
betaD | Model coefficient | scalar | no | 4.0
|
||||||
|
Ceps1 | Model coefficient | scalar | no | 0.9
|
||||||
|
Ceps2 | Model coefficient | scalar | no | 0.9
|
||||||
|
betaStar | Model coefficient | scalar | no | 0.09
|
||||||
|
\endtable
|
||||||
|
|
||||||
|
The inherited entries are elaborated in:
|
||||||
|
- \link fvOption.H \endlink
|
||||||
|
- \link cellSetOption.H \endlink
|
||||||
|
|
||||||
|
SourceFiles
|
||||||
|
treeTurbulence.C
|
||||||
|
treeTurbulenceTemplates.C
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef fv_treeTurbulence_H
|
||||||
|
#define fv_treeTurbulence_H
|
||||||
|
|
||||||
|
#include "cellSetOption.H"
|
||||||
|
#include "turbulentTransportModel.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
namespace Foam
|
||||||
|
{
|
||||||
|
namespace fv
|
||||||
|
{
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
Class treeTurbulence Declaration
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
class treeTurbulence
|
||||||
|
:
|
||||||
|
public fv::cellSetOption
|
||||||
|
{
|
||||||
|
// Private Data
|
||||||
|
|
||||||
|
//- Internal flag to determine the working field is epsilon or omega
|
||||||
|
bool isEpsilon_;
|
||||||
|
|
||||||
|
// Model coefficients
|
||||||
|
|
||||||
|
scalar betaP_;
|
||||||
|
scalar betaD_;
|
||||||
|
scalar Ceps1_;
|
||||||
|
scalar Ceps2_;
|
||||||
|
scalar betaStar_;
|
||||||
|
|
||||||
|
//- Name of operand canopy drag coefficient field
|
||||||
|
word CdName_;
|
||||||
|
|
||||||
|
//- Name of operand leaf area density field
|
||||||
|
word LADname_;
|
||||||
|
|
||||||
|
|
||||||
|
// Private Member Functions
|
||||||
|
|
||||||
|
//- Return requested field from the object registry
|
||||||
|
//- or read+register the field to the object registry
|
||||||
|
volScalarField& getOrReadField(const word& fieldName) const;
|
||||||
|
|
||||||
|
//- Apply sources to turbulent kinetic energy
|
||||||
|
template<class AlphaFieldType, class RhoFieldType>
|
||||||
|
void kSource
|
||||||
|
(
|
||||||
|
const AlphaFieldType& alpha,
|
||||||
|
const RhoFieldType& rho,
|
||||||
|
fvScalarMatrix& eqn,
|
||||||
|
const label fieldi
|
||||||
|
) const;
|
||||||
|
|
||||||
|
//- Apply sources to turbulent kinetic energy dissipation rate
|
||||||
|
template<class AlphaFieldType, class RhoFieldType>
|
||||||
|
void epsilonSource
|
||||||
|
(
|
||||||
|
const AlphaFieldType& alpha,
|
||||||
|
const RhoFieldType& rho,
|
||||||
|
fvScalarMatrix& eqn,
|
||||||
|
const label fieldi
|
||||||
|
) const;
|
||||||
|
|
||||||
|
//- Apply sources to specific dissipation rate
|
||||||
|
template<class AlphaFieldType, class RhoFieldType>
|
||||||
|
void omegaSource
|
||||||
|
(
|
||||||
|
const AlphaFieldType& alpha,
|
||||||
|
const RhoFieldType& rho,
|
||||||
|
fvScalarMatrix& eqn,
|
||||||
|
const label fieldi
|
||||||
|
) const;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//- Runtime type information
|
||||||
|
TypeName("treeTurbulence");
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors
|
||||||
|
|
||||||
|
//- Construct from explicit source name and mesh
|
||||||
|
treeTurbulence
|
||||||
|
(
|
||||||
|
const word& sourceName,
|
||||||
|
const word& modelType,
|
||||||
|
const dictionary& dict,
|
||||||
|
const fvMesh& mesh
|
||||||
|
);
|
||||||
|
|
||||||
|
//- No copy construct
|
||||||
|
treeTurbulence(const treeTurbulence&) = delete;
|
||||||
|
|
||||||
|
//- No copy assignment
|
||||||
|
void operator=(const treeTurbulence&) = delete;
|
||||||
|
|
||||||
|
|
||||||
|
// Member Functions
|
||||||
|
|
||||||
|
//- Add explicit contribution to epsilon or omega equation
|
||||||
|
//- for incompressible flow computations
|
||||||
|
virtual void addSup
|
||||||
|
(
|
||||||
|
fvScalarMatrix& eqn,
|
||||||
|
const label fieldi
|
||||||
|
);
|
||||||
|
|
||||||
|
//- Add explicit contribution to epsilon or omega equation
|
||||||
|
//- for compressible flow computations
|
||||||
|
virtual void addSup
|
||||||
|
(
|
||||||
|
const volScalarField& rho,
|
||||||
|
fvScalarMatrix& eqn,
|
||||||
|
const label fieldi
|
||||||
|
);
|
||||||
|
|
||||||
|
//- Add explicit contribution to epsilon or omega equation
|
||||||
|
//- for multiphase flow computations
|
||||||
|
virtual void addSup
|
||||||
|
(
|
||||||
|
const volScalarField& alpha,
|
||||||
|
const volScalarField& rho,
|
||||||
|
fvScalarMatrix& eqn,
|
||||||
|
const label fieldi
|
||||||
|
);
|
||||||
|
|
||||||
|
//- Read source dictionary
|
||||||
|
virtual bool read(const dictionary& dict);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
} // End namespace fv
|
||||||
|
} // End namespace Foam
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
#ifdef NoRepository
|
||||||
|
#include "treeTurbulenceTemplates.C"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
@ -0,0 +1,124 @@
|
|||||||
|
/*---------------------------------------------------------------------------*\
|
||||||
|
========= |
|
||||||
|
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
|
||||||
|
\\ / O peration |
|
||||||
|
\\ / A nd | www.openfoam.com
|
||||||
|
\\/ M anipulation |
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Copyright (C) 2022 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 <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
\*---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "treeTurbulence.H"
|
||||||
|
#include "volFields.H"
|
||||||
|
#include "fvmSup.H"
|
||||||
|
|
||||||
|
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
|
||||||
|
|
||||||
|
template<class AlphaFieldType, class RhoFieldType>
|
||||||
|
void Foam::fv::treeTurbulence::kSource
|
||||||
|
(
|
||||||
|
const AlphaFieldType& alpha,
|
||||||
|
const RhoFieldType& rho,
|
||||||
|
fvScalarMatrix& eqn,
|
||||||
|
const label fieldi
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
const auto* turbPtr = mesh_.findObject<turbulenceModel>
|
||||||
|
(
|
||||||
|
turbulenceModel::propertiesName
|
||||||
|
);
|
||||||
|
|
||||||
|
const volScalarField& k = turbPtr->k();
|
||||||
|
const volVectorField& U = turbPtr->U();
|
||||||
|
const volScalarField magU(mag(U));
|
||||||
|
const volScalarField& Cd = getOrReadField(CdName_);
|
||||||
|
const volScalarField& LAD = getOrReadField(LADname_);
|
||||||
|
|
||||||
|
// (BSG:Eq. 8)
|
||||||
|
eqn +=
|
||||||
|
alpha*rho*LAD*Cd*betaP_*pow3(magU)
|
||||||
|
- fvm::Sp(alpha*rho*LAD*Cd*betaD_*magU, k);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class AlphaFieldType, class RhoFieldType>
|
||||||
|
void Foam::fv::treeTurbulence::epsilonSource
|
||||||
|
(
|
||||||
|
const AlphaFieldType& alpha,
|
||||||
|
const RhoFieldType& rho,
|
||||||
|
fvScalarMatrix& eqn,
|
||||||
|
const label fieldi
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
const auto* turbPtr = mesh_.findObject<turbulenceModel>
|
||||||
|
(
|
||||||
|
turbulenceModel::propertiesName
|
||||||
|
);
|
||||||
|
|
||||||
|
const volScalarField& epsilon = turbPtr->epsilon();
|
||||||
|
const volScalarField& k = turbPtr->k();
|
||||||
|
const volVectorField& U = turbPtr->U();
|
||||||
|
const volScalarField magU(mag(U));
|
||||||
|
const volScalarField& Cd = getOrReadField(CdName_);
|
||||||
|
const volScalarField& LAD = getOrReadField(LADname_);
|
||||||
|
|
||||||
|
// (BSG:Eq. 9)
|
||||||
|
eqn +=
|
||||||
|
fvm::Sp
|
||||||
|
(
|
||||||
|
alpha*rho*LAD*Cd*(Ceps1_*betaP_/k*pow3(magU) - Ceps2_*betaD_*magU),
|
||||||
|
epsilon
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class AlphaFieldType, class RhoFieldType>
|
||||||
|
void Foam::fv::treeTurbulence::omegaSource
|
||||||
|
(
|
||||||
|
const AlphaFieldType& alpha,
|
||||||
|
const RhoFieldType& rho,
|
||||||
|
fvScalarMatrix& eqn,
|
||||||
|
const label fieldi
|
||||||
|
) const
|
||||||
|
{
|
||||||
|
const auto* turbPtr = mesh_.findObject<turbulenceModel>
|
||||||
|
(
|
||||||
|
turbulenceModel::propertiesName
|
||||||
|
);
|
||||||
|
|
||||||
|
const volScalarField& omega = turbPtr->omega();
|
||||||
|
const volScalarField& k = turbPtr->k();
|
||||||
|
const volVectorField& U = turbPtr->U();
|
||||||
|
const volScalarField magU(mag(U));
|
||||||
|
const volScalarField& Cd = getOrReadField(CdName_);
|
||||||
|
const volScalarField& LAD = getOrReadField(LADname_);
|
||||||
|
|
||||||
|
// (derived from BSG:Eq. 9 by assuming epsilon = betaStar*omega*k)
|
||||||
|
eqn +=
|
||||||
|
fvm::Sp
|
||||||
|
(
|
||||||
|
alpha*rho*LAD*Cd*betaStar_
|
||||||
|
*(Ceps1_*betaP_*pow3(magU) - Ceps2_*betaD_*k*magU),
|
||||||
|
omega
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ************************************************************************* //
|
||||||
Reference in New Issue
Block a user