ENH: support exprField specification for SemiImplicitSource

- this allows more flexibility when defining the location or intensity
  of sources.

  For example,

  {
      type            scalarSemiImplicitSource;
      volumeMode      specific;
      selectionMode   all;

      sources
      {
          tracer0
          {
              explicit
              {
                  type       exprField;

                  functions<scalar>
                  {
                      square
                      {
                          type square;
                          scale 0.0025;
                          level 0.0025;
                          frequency 10;
                      }
                  }

                  expression
                  #{
                      (hypot(pos().x() + 0.025, pos().y()) < 0.01)
                    ? fn:square(time())
                    : 0
                  #};
              }
          }
      }
  }

ENH: SemiImplicitSource: handle "sources" with explicit/implicit entries

- essentially the same as injectionRateSuSp with Su/Sp,
  but potentially clearer in purpose.

ENH: add Function1 good() method to define if function can be evaluated

- for example, provides a programmatic means of avoiding the 'none'
  function
This commit is contained in:
Mark Olesen
2022-05-30 13:27:22 +02:00
parent ef743147ea
commit d2e10bca40
14 changed files with 575 additions and 107 deletions

View File

@ -243,6 +243,9 @@ public:
//- Is value constant (i.e. independent of x) //- Is value constant (i.e. independent of x)
virtual bool constant() const { return false; } virtual bool constant() const { return false; }
//- Can function be evaluated?
virtual bool good() const { return true; }
// Evaluation // Evaluation

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2021 OpenCFD Ltd. Copyright (C) 2021-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -34,8 +34,8 @@ Description
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#ifndef Function1Types_None_H #ifndef Foam_Function1Types_None_H
#define Function1Types_None_H #define Foam_Function1Types_None_H
#include "Function1.H" #include "Function1.H"
@ -102,6 +102,9 @@ public:
//- Value is independent of x //- Value is independent of x
virtual inline bool constant() const { return true; } virtual inline bool constant() const { return true; }
//- Function cannot be evaluated
virtual inline bool good() const { return false; }
//- Placeholder: generates an error if called //- Placeholder: generates an error if called
virtual Type value(const scalar x) const; virtual Type value(const scalar x) const;

View File

@ -44,7 +44,7 @@ namespace Foam
void Foam::fa::option::resetApplied() void Foam::fa::option::resetApplied()
{ {
applied_.resize(fieldNames_.size()); applied_.resize_nocopy(fieldNames_.size());
applied_ = false; applied_ = false;
} }
@ -91,7 +91,7 @@ Foam::autoPtr<Foam::fa::option> Foam::fa::option::New
Info<< indent Info<< indent
<< "Selecting finite area options type " << modelType << endl; << "Selecting finite area options type " << modelType << endl;
const_cast<Time&>(patch.boundaryMesh().mesh().time()).libs().open patch.boundaryMesh().mesh().time().libs().open
( (
coeffs, coeffs,
"libs", "libs",
@ -102,15 +102,16 @@ Foam::autoPtr<Foam::fa::option> Foam::fa::option::New
if (!ctorPtr) if (!ctorPtr)
{ {
FatalErrorInFunction FatalIOErrorInLookup
<< "Unknown faOption model type " (
<< modelType << nl << nl coeffs,
<< "Valid faOption types are:" << nl "faOption",
<< dictionaryConstructorTablePtr_->sortedToc() modelType,
<< exit(FatalError); *dictionaryConstructorTablePtr_
) << exit(FatalIOError);
} }
return autoPtr<option>(ctorPtr(name, modelType, coeffs, patch)); return autoPtr<fa::option>(ctorPtr(name, modelType, coeffs, patch));
} }

View File

@ -72,8 +72,8 @@ SourceFiles
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#ifndef faOption_H #ifndef Foam_faOption_H
#define faOption_H #define Foam_faOption_H
#include "faMatricesFwd.H" #include "faMatricesFwd.H"
#include "areaFieldsFwd.H" #include "areaFieldsFwd.H"
@ -263,7 +263,7 @@ public:
//- Return dictionary //- Return dictionary
inline const dictionary& coeffs() const noexcept; inline const dictionary& coeffs() const noexcept;
//- Return const access to the source active flag //- True if source is active
inline bool active() const noexcept; inline bool active() const noexcept;
//- Set the applied flag to true for field index fieldi //- Set the applied flag to true for field index fieldi

View File

@ -47,7 +47,7 @@ namespace Foam
void Foam::fv::option::resetApplied() void Foam::fv::option::resetApplied()
{ {
applied_.resize(fieldNames_.size()); applied_.resize_nocopy(fieldNames_.size());
applied_ = false; applied_ = false;
} }

View File

@ -68,14 +68,13 @@ SourceFiles
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#ifndef fvOption_H #ifndef Foam_fvOption_H
#define fvOption_H #define Foam_fvOption_H
#include "fvMatricesFwd.H" #include "fvMatricesFwd.H"
#include "primitiveFieldsFwd.H" #include "primitiveFieldsFwd.H"
#include "volFieldsFwd.H" #include "volFieldsFwd.H"
#include "dictionary.H" #include "dictionary.H"
#include "Switch.H"
#include "runTimeSelectionTables.H" #include "runTimeSelectionTables.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -83,6 +82,7 @@ SourceFiles
namespace Foam namespace Foam
{ {
// Forward Declarations
class fvMesh; class fvMesh;
namespace fv namespace fv

View File

@ -100,14 +100,12 @@ Usage
type scalarSemiImplicitSource; type scalarSemiImplicitSource;
enabled true; enabled true;
scalarSemiImplicitSourceCoeffs selectionMode all;
volumeMode specific;
sources
{ {
selectionMode all; s (1 0);
volumeMode specific;
injectionRateSuSp
{
s (1 0);
}
} }
} }
} }

View File

@ -50,56 +50,159 @@ Foam::fv::SemiImplicitSource<Type>::volumeModeTypeNames_
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class Type> template<class Type>
void Foam::fv::SemiImplicitSource<Type>::setFieldInjectionRates void Foam::fv::SemiImplicitSource<Type>::setFieldCoeffs
( (
const dictionary& dict const dictionary& dict,
const word& keyExplicit,
const word& keyImplicit
) )
{ {
label count = dict.size(); label count = dict.size();
fieldNames_.resize_nocopy(count); fieldNames_.resize_nocopy(count);
Su_.resize(count); Su_.clear();
Sp_.resize(count); Sp_.clear();
Su_.resize(2*count);
Sp_.resize(2*count);
driverSu_.clear();
driverSp_.clear();
driverSu_.resize(2*count);
driverSp_.resize(2*count);
valueExprSu_.clear();
valueExprSp_.clear();
valueExprSu_.resize(2*count);
valueExprSp_.resize(2*count);
fv::option::resetApplied(); fv::option::resetApplied();
word modelType;
Tuple2<Type, scalar> sourceRates;
count = 0; count = 0;
for (const entry& dEntry : dict) for (const entry& dEntry : dict)
{ {
const word& fieldName = dEntry.keyword(); const word& fieldName = dEntry.keyword();
bool ok = false;
if (dEntry.isDict()) if (dEntry.isDict())
{ {
const dictionary& subdict = dEntry.dict(); const dictionary& subDict = dEntry.dict();
Su_.set(count, Function1<Type>::New("Su", subdict, &mesh_));
Sp_.set(count, Function1<scalar>::New("Sp", subdict, &mesh_)); const entry* eptr;
if
(
(eptr = subDict.findEntry(keyExplicit, keyType::LITERAL))
!= nullptr
)
{
ok = true;
if
(
eptr->isDict()
&& eptr->dict().readEntry("type", modelType, keyType::LITERAL)
&& (modelType == "exprField")
)
{
const dictionary& exprDict = eptr->dict();
valueExprSu_.emplace_set(fieldName);
valueExprSu_[fieldName].readEntry("expression", exprDict);
driverSu_.set
(
fieldName,
new expressions::volumeExprDriver(mesh_, exprDict)
);
}
else
{
Su_.set
(
fieldName,
Function1<Type>::New(keyExplicit, subDict, &mesh_)
);
}
}
if
(
(eptr = subDict.findEntry(keyImplicit, keyType::LITERAL))
!= nullptr
)
{
ok = true;
if
(
eptr->isDict()
&& eptr->dict().readEntry("type", modelType, keyType::LITERAL)
&& (modelType == "exprField")
)
{
const dictionary& exprDict = eptr->dict();
valueExprSp_.emplace_set(fieldName);
valueExprSp_[fieldName].readEntry("expression", exprDict);
driverSp_.set
(
fieldName,
new expressions::volumeExprDriver(mesh_, exprDict)
);
}
else
{
Sp_.set
(
fieldName,
Function1<scalar>::New(keyImplicit, subDict, &mesh_)
);
}
}
} }
else else
{ {
Tuple2<Type, scalar> injectionRate; // Non-dictionary form
dEntry.readEntry(injectionRate);
dEntry.readEntry(sourceRates);
ok = true;
Su_.set Su_.set
( (
count, fieldName,
new Function1Types::Constant<Type> new Function1Types::Constant<Type>
( (
"Su", keyExplicit,
injectionRate.first() sourceRates.first()
) )
); );
Sp_.set Sp_.set
( (
count, fieldName,
new Function1Types::Constant<scalar> new Function1Types::Constant<scalar>
( (
"Sp", keyImplicit,
injectionRate.second() sourceRates.second()
) )
); );
} }
if (!ok)
{
FatalIOErrorInFunction(dict)
<< "Require at least one of "
<< keyExplicit << '/' << keyImplicit << " entries for "
<< "field: " << fieldName << endl
<< exit(FatalIOError);
}
fieldNames_[count] = fieldName; fieldNames_[count] = fieldName;
++count; ++count;
} }
@ -154,6 +257,7 @@ void Foam::fv::SemiImplicitSource<Type>::addSup
const GeometricField<Type, fvPatchField, volMesh>& psi = eqn.psi(); const GeometricField<Type, fvPatchField, volMesh>& psi = eqn.psi();
// Note: field name may deviate from psi name
const word& fieldName = fieldNames_[fieldi]; const word& fieldName = fieldNames_[fieldi];
const scalar tmVal = mesh_.time().timeOutputValue(); const scalar tmVal = mesh_.time().timeOutputValue();
@ -161,67 +265,254 @@ void Foam::fv::SemiImplicitSource<Type>::addSup
const dimensionSet SuDims(eqn.dimensions()/dimVolume); const dimensionSet SuDims(eqn.dimensions()/dimVolume);
const dimensionSet SpDims(SuDims/psi.dimensions()); const dimensionSet SpDims(SuDims/psi.dimensions());
// Explicit source // Explicit source
{ {
const dimensioned<Type> SuValue const auto iter1 = valueExprSu_.cfind(fieldName);
( const auto iter2 = Su_.cfind(fieldName);
"Su",
SuDims,
Su_[fieldi].value(tmVal)/VDash_
);
if (mag(SuValue.value()) <= ROOTVSMALL) tmp<DimensionedField<Type, volMesh>> tsu;
if (iter1.found())
{ {
// No-op const auto& valueExpr = iter1.val();
}
else if (this->useSubMesh()) typedef
{ GeometricField<Type, fvPatchField, volMesh>
auto tsu = DimensionedField<Type, volMesh>::New ExprResultType;
if (debug)
{
Info<< "Explicit expression source:" << nl
<< ">>>>" << nl
<< valueExpr.c_str() << nl
<< "<<<<" << nl;
}
auto& driver = *(driverSu_[fieldName]);
driver.clearVariables();
if (notNull(rho))
{
driver.addContextObject("rho", &rho);
}
// Switch dimension checking off
const bool oldDimChecking = dimensionSet::checking(false);
driver.parse(valueExpr);
// Restore dimension checking
dimensionSet::checking(oldDimChecking);
const ExprResultType* ptr = driver.isResultType<ExprResultType>();
if (!ptr)
{
FatalErrorInFunction
<< "Expression for Su " << fieldName
<< " evaluated to <" << driver.resultType()
<< "> but expected <" << ExprResultType::typeName
<< ">" << endl
<< exit(FatalError);
}
else if (ptr->size() != mesh_.nCells())
{
FatalErrorInFunction
<< "Expression for Su " << fieldName
<< " evaluated to " << ptr->size()
<< " instead of " << mesh_.nCells() << " values" << endl
<< exit(FatalError);
}
if (notNull(rho))
{
driver.removeContextObject(&rho);
}
const Field<Type>& exprFld = ptr->primitiveField();
tsu = DimensionedField<Type, volMesh>::New
( (
name_ + fieldName + "Su", name_ + fieldName + "Su",
mesh_, mesh_,
dimensioned<Type>(SuDims, Zero) dimensioned<Type>(SuDims, Zero)
); );
UIndirectList<Type>(tsu.ref(), cells_) = SuValue.value();
eqn += tsu; if (this->useSubMesh())
{
for (const label celli : cells_)
{
tsu.ref()[celli] = exprFld[celli]/VDash_;
}
}
else
{
tsu.ref().field() = exprFld;
if (!equal(VDash_, 1))
{
tsu.ref().field() /= VDash_;
}
}
} }
else else if (iter2.found() && iter2.val()->good())
{ {
eqn += SuValue; const dimensioned<Type> SuValue
(
"Su",
SuDims,
iter2.val()->value(tmVal)/VDash_
);
if (mag(SuValue.value()) <= ROOTVSMALL)
{
// No-op
}
else if (this->useSubMesh())
{
tsu = DimensionedField<Type, volMesh>::New
(
name_ + fieldName + "Su",
mesh_,
dimensioned<Type>(SuDims, Zero)
);
UIndirectList<Type>(tsu.ref(), cells_) = SuValue.value();
}
else
{
eqn += SuValue;
}
}
if (tsu.valid())
{
eqn += tsu;
} }
} }
// Implicit source // Implicit source
{ {
const dimensioned<scalar> SpValue const auto iter1 = valueExprSp_.cfind(fieldName);
( const auto iter2 = Sp_.cfind(fieldName);
"Sp",
SpDims,
Sp_[fieldi].value(tmVal)/VDash_
);
if (mag(SpValue.value()) <= ROOTVSMALL) tmp<DimensionedField<scalar, volMesh>> tsp;
if (iter1.found())
{ {
// No-op const auto& valueExpr = iter1.val();
}
else if (this->useSubMesh()) typedef volScalarField ExprResultType;
{
auto tsp = DimensionedField<scalar, volMesh>::New if (debug)
{
Info<< "Implicit expression source:" << nl
<< ">>>>" << nl
<< valueExpr.c_str() << nl
<< "<<<<" << nl;
}
auto& driver = *(driverSp_[fieldName]);
driver.clearVariables();
if (notNull(rho))
{
driver.addContextObject("rho", &rho);
}
// Switch dimension checking off
const bool oldDimChecking = dimensionSet::checking(false);
driver.parse(valueExpr);
// Restore dimension checking
dimensionSet::checking(oldDimChecking);
const ExprResultType* ptr = driver.isResultType<ExprResultType>();
if (!ptr)
{
FatalErrorInFunction
<< "Expression for Sp " << fieldName
<< " evaluated to <" << driver.resultType()
<< "> but expected <" << ExprResultType::typeName
<< ">" << endl
<< exit(FatalError);
}
else if (ptr->size() != mesh_.nCells())
{
FatalErrorInFunction
<< "Expression for Sp " << fieldName
<< " evaluated to " << ptr->size()
<< " instead of " << mesh_.nCells() << " values" << endl
<< exit(FatalError);
}
if (notNull(rho))
{
driver.removeContextObject(&rho);
}
const Field<scalar>& exprFld = ptr->primitiveField();
tsp = DimensionedField<scalar, volMesh>::New
( (
name_ + fieldName + "Sp", name_ + fieldName + "Sp",
mesh_, mesh_,
dimensioned<scalar>(SpDims, Zero) dimensioned<scalar>(SpDims, Zero)
); );
UIndirectList<scalar>(tsp.ref(), cells_) = SpValue.value();
eqn += fvm::SuSp(tsp, psi); if (this->useSubMesh())
{
for (const label celli : cells_)
{
tsp.ref()[celli] = exprFld[celli]/VDash_;
}
}
else
{
tsp.ref().field() = exprFld;
if (!equal(VDash_, 1))
{
tsp.ref().field() /= VDash_;
}
}
} }
else else if (iter2.found() && iter2.val()->good())
{ {
eqn += fvm::SuSp(SpValue, psi); const dimensioned<scalar> SpValue
(
"Sp",
SpDims,
iter2.val()->value(tmVal)/VDash_
);
if (mag(SpValue.value()) <= ROOTVSMALL)
{
// No-op
}
else if (this->useSubMesh())
{
tsp = DimensionedField<scalar, volMesh>::New
(
name_ + fieldName + "Sp",
mesh_,
dimensioned<scalar>(SpDims, Zero)
);
UIndirectList<scalar>(tsp.ref(), cells_) = SpValue.value();
}
else
{
eqn += fvm::SuSp(SpValue, psi);
}
}
if (tsp.valid())
{
eqn += fvm::SuSp(tsp, psi);
} }
} }
} }
@ -242,10 +533,26 @@ bool Foam::fv::SemiImplicitSource<Type>::read(const dictionary& dict)
VDash_ = V_; VDash_ = V_;
} }
// Compatibility (2112 and earlier)
const dictionary* injectDict =
coeffs_.findDict("injectionRateSuSp", keyType::LITERAL);
if (injectDict)
{ {
setFieldInjectionRates setFieldCoeffs
( (
coeffs_.subDict("injectionRateSuSp", keyType::LITERAL) *injectDict,
"Su", // Su = explicit
"Sp" // Sp = implicit
);
}
else
{
setFieldCoeffs
(
coeffs_.subDict("sources", keyType::LITERAL),
"explicit",
"implicit"
); );
} }

View File

@ -33,7 +33,7 @@ Group
Description Description
Applies semi-implicit source within a specified region for \c Type, Applies semi-implicit source within a specified region for \c Type,
where \c \<Type\>=Scalar/Vector/SphericalTensor/SymmTensor/Tensor. where \c \<Type\>=Scalar/Vector/SphericalTensor/SymmTensor/Tensor.
The injection rate coefficients are specified The source rate coefficients are specified
as pairs of Su-Sp coefficients, i.e.: as pairs of Su-Sp coefficients, i.e.:
\f[ \f[
@ -57,27 +57,49 @@ Usage
// Mandatory entries (runtime modifiable) // Mandatory entries (runtime modifiable)
volumeMode <volumeModeType>; volumeMode <volumeModeType>;
injectionRateSuSp
// Specification of sources (OpenFOAM-2206 and newer)
sources
{ {
// Specified as explicit(Su)/implicit(Sp) tuple:
k (30.7 0); k (30.7 0);
epsilon (1.5 0); epsilon (1.5 0);
// The injectionRate can also be specified as a Function1 // Specified as Function1 or exprField
// by having dictionaries for the field entries instead
k k
{ {
// Time-ramp from 0 to 30.7 at time 5 // Time-ramp from 0 to 30.7 at time 5
Su table explicit table ((0 0) (5 30.7));
( implicit none;
(0 0.0)
(5 30.7)
);
Sp 0.0;
} }
epsilon epsilon
{ {
Su 1.5; explicit
Sp 0.0; {
type exprField:
expression "(mag(pos()) < 0.1) ? 1.5 : 0";
}
}
}
// Traditional specification of sources (OpenFOAM-2112 and older)
injectionRateSuSp
{
// Specified as explicit(Su)/implicit(Sp) tuple:
k (30.7 0);
epsilon (1.5 0);
// Specified as Function1
k
{
// Time-ramp from 0 to 30.7 at time 5
Su table ((0 0) (5 30.7));
Sp 0;
}
epsilon
{
Su 1.5;
Sp 0;
} }
} }
@ -92,7 +114,8 @@ Usage
type | Type name: \<Type\>SemiImplicitSource <!-- type | Type name: \<Type\>SemiImplicitSource <!--
--> | word | yes | - --> | word | yes | -
volumeMode | Volume mode type | word | yes | - volumeMode | Volume mode type | word | yes | -
injectionRateSuSp | Injection rate settings | dictionary | yes | - sources | Explicit/implicit sources | dict | cndtnl | -
injectionRateSuSp | Explicit/implicit sources | dict | cndtnl | -
\endtable \endtable
The inherited entries are elaborated in: The inherited entries are elaborated in:
@ -105,6 +128,14 @@ Usage
specific | Values are given as \<quantity\>/m3 specific | Values are given as \<quantity\>/m3
\endverbatim \endverbatim
Note
Missing explicit/implicit, Su/Sp entries are equivalent to constant values
of zero. However, at one entry must be supplied for the source terms.
Note
To use the \c exprField (expression fields) handling, the \em sources
dictionary form must be used.
See also See also
- Foam::fvOption - Foam::fvOption
@ -119,6 +150,8 @@ SourceFiles
#include "cellSetOption.H" #include "cellSetOption.H"
#include "Enum.H" #include "Enum.H"
#include "Function1.H" #include "Function1.H"
#include "HashPtrTable.H"
#include "volumeExprDriver.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -127,12 +160,6 @@ namespace Foam
namespace fv namespace fv
{ {
// Forward Declarations
template<class Type> class SemiImplicitSource;
template<class Type>
Ostream& operator<<(Ostream&, const SemiImplicitSource<Type>&);
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Class SemiImplicitSource Declaration Class SemiImplicitSource Declaration
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
@ -168,16 +195,34 @@ private:
scalar VDash_; scalar VDash_;
//- Explicit source contributions //- Explicit source contributions
PtrList<Function1<Type>> Su_; HashPtrTable<Function1<Type>> Su_;
//- Linearised implicit contributions //- Linearised implicit contributions
PtrList<Function1<scalar>> Sp_; HashPtrTable<Function1<scalar>> Sp_;
//- Expression to evaluate for explicit source contribution
HashTable<expressions::exprString> valueExprSu_;
//- Expression to evaluate for linearised implicit contribution
HashTable<expressions::exprString> valueExprSp_;
//- Expression driver for explicit sources
HashPtrTable<expressions::volumeExprDriver> driverSu_;
//- Expression driver for implicit sources
HashPtrTable<expressions::volumeExprDriver> driverSp_;
// Private Member Functions // Private Member Functions
//- Set the source coefficients from "injectionRateSuSp" //- Set the source coefficients from "sources" (explicit/implicit)
void setFieldInjectionRates(const dictionary& dict); //- or from "injectionRateSuSp" (Su/Sp)
void setFieldCoeffs
(
const dictionary& dict,
const word& keyExplicit,
const word& keyImplicit
);
public: public:

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2018-2021 OpenCFD Ltd. Copyright (C) 2018-2022 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -218,6 +218,9 @@ public:
//- Is value constant (i.e. independent of x) //- Is value constant (i.e. independent of x)
virtual bool constant() const { return false; } virtual bool constant() const { return false; }
//- Can function be evaluated?
virtual bool good() const { return true; }
//- Is value uniform (i.e. independent of coordinate) //- Is value uniform (i.e. independent of coordinate)
virtual bool uniform() const = 0; virtual bool uniform() const = 0;

View File

@ -130,7 +130,13 @@ public:
//- Is value constant (i.e. independent of x) //- Is value constant (i.e. independent of x)
virtual inline bool constant() const virtual inline bool constant() const
{ {
return uniformValuePtr_ && uniformValuePtr_->constant(); return (uniformValuePtr_ && uniformValuePtr_->constant());
}
//- Can function be evaluated?
virtual inline bool good() const
{
return (uniformValuePtr_ && uniformValuePtr_->good());
} }
//- Is value uniform (i.e. independent of coordinate) //- Is value uniform (i.e. independent of coordinate)

View File

@ -0,0 +1,47 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2206 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class volScalarField;
object tracer0;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
dimensions [0 0 0 0 0 0 0];
internalField uniform 0;
boundaryField
{
#includeEtc "caseDicts/setConstraintTypes"
rotor
{
type zeroGradient;
}
stator
{
type zeroGradient;
}
front
{
type empty;
}
back
{
type empty;
}
}
// ************************************************************************* //

View File

@ -33,9 +33,50 @@ tracer0
} }
} }
injectionRateSuSp sources
{ {
tracer0 (0.01 0); tracer0
{
explicit constant 0.01;
}
}
}
source2
{
type scalarSemiImplicitSource;
volumeMode specific;
selectionMode all;
sources
{
tracer0
{
explicit
{
type exprField;
functions<scalar>
{
square
{
type square;
scale 0.0025;
level 0.0025;
frequency 10;
}
}
expression
#{
(hypot(pos().x() + 0.025, pos().y()) < 0.01)
? fn:square(time())
: 0
#};
}
}
} }
} }
} }

View File

@ -49,10 +49,24 @@ IOdictionary fvOptions
IOobject::NO_WRITE IOobject::NO_WRITE
) )
); );
const dictionary& gradPDict =
fvOptions.subDict("momentumSource").subDict("injectionRateSuSp"); scalar K(0);
const scalar K =
gradPDict.get<Tuple2<vector, scalar>>("U").first().x(); // Get x() component from U source
{
const dictionary& momSource = fvOptions.subDict("momentumSource");
if (momSource.findDict("sources"))
{
K = momSource.subDict("sources")
.get<Tuple2<vector, scalar>>("U").first().x();
}
else
{
K = momSource.subDict("injectionRateSuSp")
.get<Tuple2<vector, scalar>>("U").first().x();
}
}
dictionary probes(IFstream(runTime.system()/"probes")()); dictionary probes(IFstream(runTime.system()/"probes")());
const point location = pointField(probes.lookup("probeLocations"))[0]; const point location = pointField(probes.lookup("probeLocations"))[0];