Commit 2f2dcdcf authored by Mark OLESEN's avatar Mark OLESEN
Browse files

ENH: Function1 and PatchFunction1 improvements (#1917)

- easier support for non-mandatory functions.

  In some boundary conditions it can be desirable to support
  additional functions, but not necessarily require them. Make this
  easier to support with a Function1, PatchFunction1 NewIfPresent()
  selector.

- support for compatibility lookups

- harmonize branching logic and error handling between Function1 and
  PatchFunction1.

ENH: refactor a base class for Function1, PatchFunction1

- includes base characteristics, patch or scalar information

ENH: additional creation macros

- makeConcreteFunction1, makeConcretePatchFunction1Type for adding a
  non-templated function into the correct templated selection table.
  makeScalarPatchFunction1 for similarity with makeScalarFunction1
parent 4b964f67
......@@ -90,7 +90,7 @@ ${typeName}PatchFunction1${FieldType}::
${typeName}PatchFunction1${FieldType}
(
const polyPatch& pp,
const word& type,
const word& redirectType,
const word& entryName,
const dictionary& dict,
const bool faceValues
......
......@@ -75,7 +75,7 @@ public:
${typeName}PatchFunction1${FieldType}
(
const polyPatch& pp,
const word& type,
const word& redirectType,
const word& entryName,
const dictionary& dict,
const bool faceValues = true
......@@ -84,13 +84,13 @@ public:
//- Copy construct
${typeName}PatchFunction1${FieldType}
(
const ${typeName}PatchFunction1${FieldType}&
const ${typeName}PatchFunction1${FieldType}& rhs
);
//- Copy construct, resetting patch
${typeName}PatchFunction1${FieldType}
(
const ${typeName}PatchFunction1${FieldType}&,
const ${typeName}PatchFunction1${FieldType}& rhs,
const polyPatch& pp
);
......
......@@ -106,6 +106,7 @@ primitives/septernion/septernion.C
primitives/triad/triad.C
/* Run-time selectable functions */
primitives/functions/Function1/Function1/function1Base.C
primitives/functions/Function1/makeFunction1s.C
primitives/functions/Function1/ramp/ramp.C
primitives/functions/Function1/step/stepFunction.C
......
......@@ -36,7 +36,7 @@ Foam::Function1Types::Function1Expression<Type>::Function1Expression
const dictionary& dict
)
:
Function1<Type>(entryName),
Function1<Type>(entryName, dict),
dict_(dict),
valueExpr_(),
driver_(1, dict_)
......
......@@ -99,27 +99,22 @@ class Function1Expression
mutable expressions::fieldExprDriver driver_;
// Private Member Functions
//- No copy assignment
void operator=(const Function1Expression<Type>&) = delete;
public:
//- Runtime type information
TypeName("expression");
// Generated Methods
//- No copy assignment
void operator=(const Function1Expression<Type>&) = delete;
// Constructors
//- Construct from patch, entry name and dictionary
// The patch must correspond to an fvPatch!
Function1Expression
(
const word& entryName,
const dictionary& dict
);
//- Construct from entry name and dictionary
Function1Expression(const word& entryName, const dictionary& dict);
//- Copy construct
explicit Function1Expression(const Function1Expression<Type>& rhs);
......
......@@ -250,13 +250,8 @@ const Foam::fileName& Foam::Function1Types::CSV<Type>::fName() const
template<class Type>
void Foam::Function1Types::CSV<Type>::writeData(Ostream& os) const
void Foam::Function1Types::CSV<Type>::writeEntries(Ostream& os) const
{
Function1<Type>::writeData(os);
os.endEntry();
os.beginBlock(word(this->name() + "Coeffs"));
// Note: for TableBase write the dictionary entries it needs but not
// the values themselves
TableBase<Type>::writeEntries(os);
......@@ -273,7 +268,17 @@ void Foam::Function1Types::CSV<Type>::writeData(Ostream& os) const
os.writeEntry("separator", string(separator_));
os.writeEntry("mergeSeparators", mergeSeparators_);
os.writeEntry("file", fName_);
}
template<class Type>
void Foam::Function1Types::CSV<Type>::writeData(Ostream& os) const
{
Function1<Type>::writeData(os);
os.endEntry();
os.beginBlock(word(this->name() + "Coeffs"));
writeEntries(os);
os.endBlock();
}
......
......@@ -154,6 +154,9 @@ public:
//- Write in dictionary format
virtual void writeData(Ostream& os) const;
//- Write coefficient entries in dictionary format
void writeEntries(Ostream& os) const;
};
......
......@@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2015 OpenCFD Ltd.
Copyright (C) 2015-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -49,7 +49,7 @@ Foam::Function1Types::Constant<Type>::Constant
const dictionary& dict
)
:
Function1<Type>(entryName),
Function1<Type>(entryName, dict),
value_(Zero)
{
Istream& is = dict.lookup(entryName);
......
......@@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2015 OpenCFD Ltd.
Copyright (C) 2015-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -61,24 +61,25 @@ class Constant
:
public Function1<Type>
{
// Private data
// Private Data
//- Constant value
Type value_;
// Private Member Functions
//- No copy assignment
void operator=(const Constant<Type>&) = delete;
public:
// Runtime type information
TypeName("constant");
// Generated Methods
//- No copy assignment
void operator=(const Constant<Type>&) = delete;
// Constructors
//- Construct from components
......
......@@ -36,32 +36,26 @@ License
template<class Type>
Foam::Function1<Type>::Function1(const word& entryName)
:
name_(entryName)
function1Base(entryName)
{}
template<class Type>
Foam::Function1<Type>::Function1(const Function1<Type>& rhs)
Foam::Function1<Type>::Function1(const word& entryName, const dictionary& dict)
:
refCount(),
name_(rhs.name_)
function1Base(entryName, dict)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type>
const Foam::word& Foam::Function1<Type>::name() const
{
return name_;
}
template<class Type>
void Foam::Function1<Type>::convertTimeBase(const Time&)
Foam::Function1<Type>::Function1(const Function1<Type>& rhs)
:
function1Base(rhs)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type>
Type Foam::Function1<Type>::value(const scalar x) const
{
......@@ -71,7 +65,8 @@ Type Foam::Function1<Type>::value(const scalar x) const
template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::Function1<Type>::value
Foam::tmp<Foam::Field<Type>>
Foam::Function1<Type>::value
(
const scalarField& x
) const
......@@ -90,7 +85,8 @@ Type Foam::Function1<Type>::integrate(const scalar x1, const scalar x2) const
template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::Function1<Type>::integrate
Foam::tmp<Foam::Field<Type>>
Foam::Function1<Type>::integrate
(
const scalarField& x1,
const scalarField& x2
......@@ -161,6 +157,11 @@ Foam::FieldFunction1<Function1Type>::integrate
}
template<class Type>
void Foam::Function1<Type>::writeEntries(Ostream& os) const
{}
template<class Type>
void Foam::Function1<Type>::writeData(Ostream& os) const
{
......@@ -179,7 +180,7 @@ Foam::Ostream& Foam::operator<<
{
os.check(FUNCTION_NAME);
os << rhs.name_;
os << rhs.name();
rhs.writeData(os);
return os;
......
......@@ -74,7 +74,7 @@ SourceFiles
#ifndef Function1_H
#define Function1_H
#include "dictionary.H"
#include "function1Base.H"
#include "Field.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
......@@ -94,15 +94,22 @@ template<class Type> Ostream& operator<<(Ostream&, const Function1<Type>&);
template<class Type>
class Function1
:
public refCount
public function1Base
{
protected:
// Private Member Functions
// Protected Data
//- Selector, with alternative entry, fallback redirection, etc
static autoPtr<Function1<Type>> New
(
const word& entryName, // Entry name for function
const entry* eptr, // Eg, dict.findEntry(entryName)
const dictionary& dict,
const word& redirectType,
const bool mandatory
);
//- Name of entry
const word name_;
protected:
// Protected Member Functions
......@@ -136,39 +143,59 @@ public:
//- Construct from entry name
explicit Function1(const word& entryName);
//- Copy constructor
//- Construct from entry name and dictionary
Function1(const word& entryName, const dictionary& dict);
//- Copy construct
explicit Function1(const Function1<Type>& rhs);
//- Construct and return a clone
virtual tmp<Function1<Type>> clone() const = 0;
//- Selector
static autoPtr<Function1<Type>> New
(
const word& entryName,
const dictionary& dict,
const word& redirectType = word::null
);
//- Destructor
virtual ~Function1() = default;
// Selectors
// Member Functions
//- Selector, with fallback redirection
static autoPtr<Function1<Type>> New
(
const word& entryName,
const dictionary& dict,
const word& redirectType,
const bool mandatory = true
);
// Access
//- Compatibility selector, with fallback redirection
static autoPtr<Function1<Type>> NewCompat
(
const word& entryName,
std::initializer_list<std::pair<const char*,int>> compat,
const dictionary& dict,
const word& redirectType = word::null,
const bool mandatory = true
);
//- Selector, without fallback redirection
static autoPtr<Function1<Type>> New
(
const word& entryName,
const dictionary& dict,
const bool mandatory = true
);
//- Return the name of the entry
const word& name() const;
//- An optional selector
static autoPtr<Function1<Type>> NewIfPresent
(
const word& entryName,
const dictionary& dict,
const word& redirectType = word::null
);
// Manipulation
//- Destructor
virtual ~Function1() = default;
//- Convert time
virtual void convertTimeBase(const Time& t);
// Member Functions
// Evaluation
......@@ -189,17 +216,22 @@ public:
) const;
// I/O
// I/O
//- Ostream Operator
friend Ostream& operator<< <Type>
(
Ostream& os,
const Function1<Type>& func
);
//- Ostream Operator
friend Ostream& operator<< <Type>
(
Ostream& os,
const Function1<Type>& func
);
//- Write in dictionary format
virtual void writeData(Ostream& os) const;
//- Write in dictionary format.
// \note The base output is \em without an END_STATEMENT
virtual void writeData(Ostream& os) const;
//- Write coefficient entries in dictionary format
void writeEntries(Ostream& os) const;
};
......@@ -212,7 +244,6 @@ class FieldFunction1
:
public Function1Type
{
public:
typedef typename Function1Type::returnType Type;
......@@ -256,6 +287,7 @@ public:
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Define Function1 run-time selection
#define makeFunction1(Type) \
\
defineNamedTemplateTypeNameAndDebug(Function1<Type>, 0); \
......@@ -267,6 +299,7 @@ public:
);
// Define (templated) Function1, add to (templated) run-time selection
#define makeFunction1Type(SS, Type) \
\
defineNamedTemplateTypeNameAndDebug(Function1Types::SS<Type>, 0); \
......@@ -276,12 +309,20 @@ public:
add##SS##Type##ConstructorToTable_;
#define makeScalarFunction1(SS) \
// Define a non-templated Function1 and add to (templated) run-time selection
#define makeConcreteFunction1(SS, Type) \
\
defineTypeNameAndDebug(SS, 0); \
\
Function1<scalar>::adddictionaryConstructorToTable<FieldFunction1<SS>> \
add##SS##ConstructorToTable_;
Function1<Type>::adddictionaryConstructorToTable \
<FieldFunction1<SS>> \
add##SS##Type##ConstructorToTable_;
// Define scalar Function1 and add to (templated) run-time selection
#define makeScalarFunction1(SS) \
\
makeConcreteFunction1(SS, scalar);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
......
......@@ -35,59 +35,43 @@ Foam::autoPtr<Foam::Function1<Type>>
Foam::Function1<Type>::New
(
const word& entryName,
const entry* eptr,
const dictionary& dict,
const word& redirectType
const word& redirectType,
const bool mandatory
)
{
word modelType(redirectType);
const entry* eptr = dict.findEntry(entryName, keyType::LITERAL);
const dictionary* coeffs = (eptr ? eptr->dictPtr() : nullptr);
if (!eptr)
{
if (modelType.empty())
{
FatalIOErrorInFunction(dict)
<< "No Function1 dictionary entry: "
<< entryName << nl << nl
<< exit(FatalIOError);
}
}
else if (eptr->isDict())
if (coeffs)
{
const dictionary& coeffsDict = eptr->dict();
// Dictionary entry
coeffsDict.readEntry
coeffs->readEntry
(
"type",
modelType,
keyType::LITERAL,
redirectType.empty() // mandatory when redirectType is empty
modelType.empty() // "type" entry is mandatory if no 'redirect'
);
auto cstrIter = dictionaryConstructorTablePtr_->cfind(modelType);
if (!cstrIter.found())
{
FatalIOErrorInFunction(dict)
<< "Unknown Function1 type "
<< modelType << " for " << entryName
<< "\n\nValid Function1 types :\n"
<< dictionaryConstructorTablePtr_->sortedToc() << nl
<< exit(FatalIOError);
}
return cstrIter()(entryName, coeffsDict);
// Fallthrough
}
else
else if (eptr)
{
// Primitive entry
// - non-word : value for constant function
// - word : the modelType
Istream& is = eptr->stream();
token firstToken(is);
if (!firstToken.isWord())
{
// Backwards-compatibility for reading straight fields
// A value
is.putBack(firstToken);
const Type constValue = pTraits<Type>(is);
......@@ -97,8 +81,40 @@ Foam::Function1<Type>::New
new Function1Types::Constant<Type>(entryName, constValue)
);
}
else
{
modelType = firstToken.wordToken();
}
modelType = firstToken.wordToken();
// Fallthrough
}
if (modelType.empty())
{
// Entry missing
if (mandatory)
{
FatalIOErrorInFunction(dict)
<< "Missing or invalid Function1 entry: "
<< entryName << nl
<< exit(FatalIOError);
}
return nullptr;
}
else if (!coeffs)
{
// Primitive entry. Coeffs dictionary is optional.
// Use keyword() - not entryName - for compatibility lookup!
coeffs =
&dict.optionalSubDict
(
eptr->keyword() + "Coeffs",
keyType::LITERAL
);
}
......@@ -114,12 +130,78 @@ Foam::Function1<Type>::New
<< exit(FatalIOError);
}
return cstrIter()
return cstrIter()(entryName, *coeffs);
}
template<class Type>
Foam::autoPtr<Foam::Function1<Type>>
Foam::Function1<Type>::New
(
const word& entryName,