ENH: fanFvPatchField - refactored; added flowRate option

The basis of the table is specified according to the mode:

- velocity: deltap = F(velocity per face) \[DEFAULT\]
- uniformVelocity: deltap = F(patch area-averaged velocity)
- volumeFlowRate:  deltap = F(patch volume flow rate)
- nonDimensional:  non-dim deltap = F(non-dim volume flow rate)

Example of the boundary condition specification:

    <patchName>
    {
        type            fan;
        patchType       cyclic;
        jumpTable       csvFile;
        mode            velocity; // New entry

        jumpTableCoeffs
        {
            nHeaderLine     1;
            refColumn       0;
            componentColumns 1(1);
            separator       ",";
            mergeSeparators no;
            file            "<constant>/UvsPressure";
        }
        value           uniform 0;
    }
This commit is contained in:
Andrew Heather 2024-12-18 15:24:30 +00:00
parent b0b1d0f8b2
commit 4423efd313
4 changed files with 186 additions and 86 deletions

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2015 OpenFOAM Foundation Copyright (C) 2011-2015 OpenFOAM Foundation
Copyright (C) 2017-2021 OpenCFD Ltd. Copyright (C) 2017-2024 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -28,6 +28,19 @@ License
#include "fanFvPatchField.H" #include "fanFvPatchField.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
template<class Type>
const Foam::Enum<typename Foam::fanFvPatchField<Type>::operatingMode>
Foam::fanFvPatchField<Type>::operatingModeNames_
({
{ operatingMode::VELOCITY, "velocity" },
{ operatingMode::UNIFORM_VELOCITY, "uniformVelocity" },
{ operatingMode::VOL_FLOW_RATE, "volumeFlowRate" },
{ operatingMode::NON_DIMENSIONAL, "nonDimensional" },
});
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class Type> template<class Type>
@ -50,10 +63,9 @@ Foam::fanFvPatchField<Type>::fanFvPatchField
) )
: :
uniformJumpFvPatchField<Type>(p, iF), uniformJumpFvPatchField<Type>(p, iF),
operatingMode_(operatingMode::VELOCITY),
phiName_("phi"), phiName_("phi"),
rhoName_("rho"), rhoName_("rho"),
uniformJump_(false),
nonDimensional_(false),
rpm_(nullptr), rpm_(nullptr),
dm_(nullptr) dm_(nullptr)
{} {}
@ -68,15 +80,36 @@ Foam::fanFvPatchField<Type>::fanFvPatchField
) )
: :
uniformJumpFvPatchField<Type>(p, iF, dict, false), // needValue = false uniformJumpFvPatchField<Type>(p, iF, dict, false), // needValue = false
operatingMode_
(
operatingModeNames_.getOrDefault("mode", dict, operatingMode::VELOCITY)
),
phiName_(dict.getOrDefault<word>("phi", "phi")), phiName_(dict.getOrDefault<word>("phi", "phi")),
rhoName_(dict.getOrDefault<word>("rho", "rho")), rhoName_(dict.getOrDefault<word>("rho", "rho")),
uniformJump_(dict.getOrDefault("uniformJump", false)),
nonDimensional_(dict.getOrDefault("nonDimensional", false)),
rpm_(nullptr), rpm_(nullptr),
dm_(nullptr) dm_(nullptr)
{ {
// Backwards compatibility
if (operatingMode_ == operatingMode::VELOCITY)
{
bool nonDimCompat = dict.getOrDefault("nonDimensional", false);
if (nonDimCompat)
{
// Warn?
operatingMode_ = operatingMode::NON_DIMENSIONAL;
}
bool uniformCompat = dict.getOrDefault("uniformJump", false);
if (uniformCompat)
{
// Warn?
operatingMode_ = operatingMode::UNIFORM_VELOCITY;
}
}
// Note that we've not read jumpTable_ etc // Note that we've not read jumpTable_ etc
if (nonDimensional_) if (operatingMode_ == operatingMode::NON_DIMENSIONAL)
{ {
rpm_.reset(Function1<scalar>::New("rpm", dict, &this->db())); rpm_.reset(Function1<scalar>::New("rpm", dict, &this->db()));
dm_.reset(Function1<scalar>::New("dm", dict, &this->db())); dm_.reset(Function1<scalar>::New("dm", dict, &this->db()));
@ -104,10 +137,9 @@ Foam::fanFvPatchField<Type>::fanFvPatchField
) )
: :
uniformJumpFvPatchField<Type>(rhs, p, iF, mapper), uniformJumpFvPatchField<Type>(rhs, p, iF, mapper),
operatingMode_(rhs.operatingMode_),
phiName_(rhs.phiName_), phiName_(rhs.phiName_),
rhoName_(rhs.rhoName_), rhoName_(rhs.rhoName_),
uniformJump_(rhs.uniformJump_),
nonDimensional_(rhs.nonDimensional_),
rpm_(rhs.rpm_.clone()), rpm_(rhs.rpm_.clone()),
dm_(rhs.dm_.clone()) dm_(rhs.dm_.clone())
{} {}
@ -120,10 +152,9 @@ Foam::fanFvPatchField<Type>::fanFvPatchField
) )
: :
uniformJumpFvPatchField<Type>(rhs), uniformJumpFvPatchField<Type>(rhs),
operatingMode_(rhs.operatingMode_),
phiName_(rhs.phiName_), phiName_(rhs.phiName_),
rhoName_(rhs.rhoName_), rhoName_(rhs.rhoName_),
uniformJump_(rhs.uniformJump_),
nonDimensional_(rhs.nonDimensional_),
rpm_(rhs.rpm_.clone()), rpm_(rhs.rpm_.clone()),
dm_(rhs.dm_.clone()) dm_(rhs.dm_.clone())
{} {}
@ -137,10 +168,9 @@ Foam::fanFvPatchField<Type>::fanFvPatchField
) )
: :
uniformJumpFvPatchField<Type>(rhs, iF), uniformJumpFvPatchField<Type>(rhs, iF),
operatingMode_(rhs.operatingMode_),
phiName_(rhs.phiName_), phiName_(rhs.phiName_),
rhoName_(rhs.rhoName_), rhoName_(rhs.rhoName_),
uniformJump_(rhs.uniformJump_),
nonDimensional_(rhs.nonDimensional_),
rpm_(rhs.rpm_.clone()), rpm_(rhs.rpm_.clone()),
dm_(rhs.dm_.clone()) dm_(rhs.dm_.clone())
{} {}
@ -170,14 +200,10 @@ void Foam::fanFvPatchField<Type>::write(Ostream& os) const
os.writeEntryIfDifferent<word>("phi", "phi", phiName_); os.writeEntryIfDifferent<word>("phi", "phi", phiName_);
os.writeEntryIfDifferent<word>("rho", "rho", rhoName_); os.writeEntryIfDifferent<word>("rho", "rho", rhoName_);
if (uniformJump_) os.writeEntry("mode", operatingModeNames_[operatingMode_]);
{
os.writeEntry("uniformJump", "true");
}
if (nonDimensional_) if (operatingMode_ == operatingMode::NON_DIMENSIONAL)
{ {
os.writeEntry("nonDimensional", "true");
rpm_->writeData(os); rpm_->writeData(os);
dm_->writeData(os); dm_->writeData(os);
} }

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2019 OpenCFD Ltd. Copyright (C) 2017-2024 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -37,14 +37,21 @@ Description
The jump is specified as a \c Function1 type, to enable the use of, e.g. The jump is specified as a \c Function1 type, to enable the use of, e.g.
constant, polynomial, table values. constant, polynomial, table values.
The switch nonDimensional can be used for a non-dimensional table, The basis of the table is specified according to the \c mode:
in combination with uniformJump = true.
- velocity: deltap = F(velocity per face) \[DEFAULT\]
- uniformVelocity: deltap = F(patch area-averaged velocity)
- volumeFlowRate: deltap = F(patch volume flow rate)
- nonDimensional: non-dim deltap = F(non-dim volume flow rate)
Non-dimensional operation:
As inputs it needs the fan RPM (rpm) and the mean diameter (dm). As inputs it needs the fan RPM (rpm) and the mean diameter (dm).
The non-dimensional U for the table is calculated as follows: The non-dimensional U for the table is calculated as follows:
\verbatim \verbatim
phi = 120*Un/(PI^3*dm*rpm) phi = 120*Un/(PI^3*dm^3*rpm)
where: where:
dm is the mean diameter. dm is the mean diameter.
rpm is the RPM of the fan. rpm is the RPM of the fan.
@ -64,11 +71,10 @@ Usage
\table \table
Property | Description | Required | Default Property | Description | Required | Default
patchType | underlying patch type should be \c cyclic | yes | patchType | underlying patch type should be \c cyclic | yes |
mode | jump table operating mode (see above) | no | velocity
jumpTable | jump data, e.g. \c csvFile | yes | jumpTable | jump data, e.g. \c csvFile | yes |
phi | flux field name | no | phi phi | flux field name | no | phi
rho | density field name | no | rho rho | density field name | no | rho
uniformJump | apply uniform pressure based on avg velocity | no | false
nonDimensional | use non-dimensional table | no | false
rpm | fan rpm (non-dimensional table) | no | rpm | fan rpm (non-dimensional table) | no |
dm | mean diameter (non-dimensional table) | no | dm | mean diameter (non-dimensional table) | no |
\endtable \endtable
@ -80,6 +86,7 @@ Usage
type fan; type fan;
patchType cyclic; patchType cyclic;
jumpTable csvFile; jumpTable csvFile;
mode velocity;
jumpTableCoeffs jumpTableCoeffs
{ {
@ -107,15 +114,15 @@ SourceFiles
fanFvPatchField.C fanFvPatchField.C
fanFvPatchFields.H fanFvPatchFields.H
fanFvPatchFields.C fanFvPatchFields.C
fanFvPatchFieldsFwd.H
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#ifndef fanFvPatchField_H #ifndef foam_fanFvPatchField_H
#define fanFvPatchField_H #define foam_fanFvPatchField_H
#include "uniformJumpFvPatchField.H" #include "uniformJumpFvPatchField.H"
#include "Function1.H" #include "Function1.H"
#include "Enum.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -131,20 +138,36 @@ class fanFvPatchField
: :
public uniformJumpFvPatchField<Type> public uniformJumpFvPatchField<Type>
{ {
public:
// Public Data Types
//- Enumeration defining the operating modes
enum class operatingMode
{
VELOCITY, //!< velocity-based lookup
UNIFORM_VELOCITY, //!< uniform velocity-based lookup
VOL_FLOW_RATE, //!< volume-flow-rate-based lookup
NON_DIMENSIONAL //!< non-dimensional-based lookup
};
//- Names for the operating modes
static const Enum<operatingMode> operatingModeNames_;
private:
// Private Data // Private Data
//- Operating mode
operatingMode operatingMode_;
//- Name of the flux transporting the field //- Name of the flux transporting the field
word phiName_; word phiName_;
//- Name of the density field for normalising the mass flux if necessary //- Name of the density field for normalising the mass flux if necessary
word rhoName_; word rhoName_;
//- Apply uniform pressure drop
bool uniformJump_;
//- Use non-dimensional curve
bool nonDimensional_;
//- Fan rpm (for non-dimensional curve) //- Fan rpm (for non-dimensional curve)
autoPtr<Function1<scalar>> rpm_; autoPtr<Function1<scalar>> rpm_;

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2017-2021 OpenCFD Ltd. Copyright (C) 2017-2024 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -44,69 +44,120 @@ namespace Foam
template<> template<>
void Foam::fanFvPatchField<Foam::scalar>::calcFanJump() void Foam::fanFvPatchField<Foam::scalar>::calcFanJump()
{ {
if (this->cyclicPatch().owner()) if (!this->cyclicPatch().owner())
{ {
const auto& phip = return;
patch().lookupPatchField<surfaceScalarField>(phiName_); }
scalarField Un(max(phip/patch().magSf(), scalar(0))); const auto& phip = patch().lookupPatchField<surfaceScalarField>(phiName_);
// The non-dimensional parameters scalarField volFlowRate(max(phip, scalar(0)));
scalar rpm(0); if (phip.internalField().dimensions() == dimVolume/dimTime)
scalar meanDiam(0); {
// No conversion of volFlowRate required
}
else if (phip.internalField().dimensions() == dimMass/dimTime)
{
const auto& rhop = patch().lookupPatchField<volScalarField>(rhoName_);
volFlowRate /= rhop;
}
else
{
FatalErrorInFunction
<< "dimensions of phi are not correct\n"
<< " on patch " << patch().name()
<< " of field " << internalField().name()
<< " in file " << internalField().objectPath() << nl
<< exit(FatalError);
}
if (nonDimensional_)
// The non-dimensional parameters
scalar rpm(0);
scalar meanDiam(0);
scalarField pdFan(patch().size(), Zero);
switch (operatingMode_)
{
case operatingMode::VELOCITY:
{ {
// Note: volFlowRate now becomes face normal velocity
volFlowRate /= patch().magSf();
// Per-face values
pdFan = this->jumpTable_->value(volFlowRate);
break;
}
case operatingMode::UNIFORM_VELOCITY:
{
// Note: volFlowRate now becomes face normal velocity
volFlowRate /= patch().magSf();
// Set face values to patch area-averaged value
const scalar area = gSum(patch().magSf());
const scalar UnAve = gSum(volFlowRate*patch().magSf())/area;
// Assign uniform value
pdFan = this->jumpTable_->value(UnAve);
break;
}
case operatingMode::VOL_FLOW_RATE:
{
// Face-based volFlowRate converted to patch-based volFlowRate
// for pd curve lookup
const scalar sumVolFlowRate = gSum(volFlowRate);
// Assign uniform value
pdFan = this->jumpTable_->value(sumVolFlowRate);
break;
}
case operatingMode::NON_DIMENSIONAL:
{
// Face-based volFlowRate converted to patch-based volFlowRate
// for pd curve lookup
scalar sumVolFlowRate = gSum(volFlowRate);
rpm = rpm_->value(this->db().time().timeOutputValue()); rpm = rpm_->value(this->db().time().timeOutputValue());
meanDiam = dm_->value(this->db().time().timeOutputValue()); meanDiam = dm_->value(this->db().time().timeOutputValue());
}
if (uniformJump_) // Create a non-dimensional flow rate
{ sumVolFlowRate *=
const scalar area = gSum(patch().magSf());
Un = gSum(Un*patch().magSf())/area;
if (nonDimensional_)
{
// Create an non-dimensional velocity
Un =
(
120.0*Un
/ stabilise
(
pow3(constant::mathematical::pi) * meanDiam * rpm,
VSMALL
)
);
}
}
if (phip.internalField().dimensions() == dimMass/dimTime)
{
Un /= patch().lookupPatchField<volScalarField>(rhoName_);
}
if (nonDimensional_)
{
scalarField deltap(this->jumpTable_->value(Un));
// Convert non-dimensional deltap from curve into deltaP
scalarField pdFan
( (
deltap*pow4(constant::mathematical::pi) 120.0
* sqr(meanDiam*rpm)/1800.0 /stabilise
(
pow3(constant::mathematical::pi*meanDiam)*rpm,
VSMALL
)
); );
this->setJump(pdFan); const scalar pdNonDim = this->jumpTable_->value(sumVolFlowRate);
}
else
{
this->setJump(jumpTable_->value(Un));
}
this->relax(); // Convert uniform non-dimensional pdFan from curve into deltaP
pdFan =
pdNonDim
*pow4(constant::mathematical::pi)*sqr(meanDiam*rpm)/1800.0;
break;
}
default:
{
FatalErrorInFunction
<< "Unhandled enumeration "
<< operatingModeNames_[operatingMode_]
<< abort(FatalError);
}
} }
this->setJump(pdFan);
this->relax();
} }

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011 OpenFOAM Foundation Copyright (C) 2024 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -25,8 +25,8 @@ License
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#ifndef fanFvPatchFields_H #ifndef foam_fanFvPatchFields_H
#define fanFvPatchFields_H #define foam_fanFvPatchFields_H
#include "fanFvPatchField.H" #include "fanFvPatchField.H"
#include "fieldTypes.H" #include "fieldTypes.H"