Files
openfoam/src/OpenFOAM/expressionTemplates/GeometricFieldExpression.H
mattijs b0066fc550 ENH: ListExpression: support par_unseq, multi-storage container
(ListsRefWrap etc. supplied by AMD)
2025-10-22 15:44:22 +00:00

1880 lines
70 KiB
C++

/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2024,2025 M. Janssens
Copyright (C) 2025 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/>.
Namespace
Foam::Expression
Description
Expression templates for GeometricFields
SourceFiles
GeometricFieldExpression.C
\*---------------------------------------------------------------------------*/
#ifndef Foam_GeometricFieldExpression_H
#define Foam_GeometricFieldExpression_H
#include "ListExpression.H"
#include "pointMesh.H"
//#include "fixedValuePointPatchField.H" // no assignable yet. tbd.
//#include <boost/core/demangle.hpp>
//#include <typeinfo>
//#include <iostream>
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
namespace Expression
{
/*---------------------------------------------------------------------------*\
Namespace Expression Declarations
\*---------------------------------------------------------------------------*/
// Expression of GeometricField
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template
<
typename E,
typename IntExpr,
typename UncoupledPatchExpr,
typename CoupledPatchExpr,
typename Type
>
class GeometricFieldExpression
{
protected:
const dimensionSet dimensions_;
const orientedType oriented_;
public:
static constexpr bool is_leaf = false;
GeometricFieldExpression
(
const dimensionSet& dimensions,
const orientedType oriented
)
:
dimensions_(dimensions),
oriented_(oriented)
{
//Pout<< "GeometricFieldExpression :" << nl
// << " E : "
// << boost::core::demangle(typeid(E).name())
// << nl
// << " IntExpr : "
// << boost::core::demangle(typeid(IntExpr).name()) << nl
// << " dimensions : " << dimensions_ << nl
// << " oriented : " << oriented_ << nl
// << endl;
}
// TBD. Do we still need this? Is faster than always going through
// internalField() though.
Type operator[](const label i) const
{
// Delegation to the actual expression type. This avoids dynamic
// polymorphism (a.k.a. virtual functions in C++)
return static_cast<E const&>(*this)[i];
}
auto size() const noexcept { return static_cast<const E&>(*this).size(); }
const dimensionSet& dimensions() const noexcept
{
return dimensions_;
}
const orientedType& oriented() const noexcept
{
return oriented_;
}
IntExpr internalField() const
{
return static_cast<const E&>(*this).internalField();
}
IntExpr internalField()
{
return static_cast<E&>(*this).internalField();
}
UncoupledPatchExpr patchField(const label i)
{
return static_cast<E&>(*this).patchField(i);
}
UncoupledPatchExpr patchField(const label i) const
{
return static_cast<const E&>(*this).patchField(i);
}
CoupledPatchExpr coupledPatchField(const label i)
{
return static_cast<E&>(*this).coupledPatchField(i);
}
CoupledPatchExpr coupledPatchField(const label i) const
{
return static_cast<const E&>(*this).coupledPatchField(i);
}
template<class Op>
auto access(const Op& cop, const label i) const
{
return static_cast<const E&>(*this).access(cop, i);
}
//- Helper to evaluate a GeometricField
template<class GeoField>
GeoField& evaluate(GeoField& fld, const bool force = false) const
{
fld.dimensions() = this->dimensions();
fld.oriented() = this->oriented();
assert(fld.size() == this->size());
using ActualType = typename IntExpr::value_type;
ListRefWrap<ActualType> wfld(fld.internalFieldRef(), internalField());
// Do boundary field
auto& bfld = fld.boundaryFieldRef();
const label n = bfld.size();
for (label i = 0; i < n; ++i)
{
auto& pfld = bfld[i];
if (force || pfld.assignable())
{
if (pfld.coupled())
{
// Get patch expression
const auto patchExpr = this->coupledPatchField(i);
// Note: check can be removed once assignable also on
// pointPatchFields. TBD.
if constexpr
(
std::is_same_v<pointMesh, typename GeoField::Mesh>
)
{
const auto* vp = isA<Field<Type>>(pfld);
if (vp)
{
patchExpr.evaluate(const_cast<Field<Type>&>(*vp));
}
}
else
{
patchExpr.evaluate(pfld);
}
}
else
{
// Get patch expression
const auto patchExpr = this->patchField(i);
// Note: check can be removed once assignable also on
// pointPatchFields. TBD.
if constexpr
(
std::is_same_v<pointMesh, typename GeoField::Mesh>
)
{
const auto* vp = isA<Field<Type>>(pfld);
if (vp)
{
patchExpr.evaluate(const_cast<Field<Type>&>(*vp));
}
}
else
{
patchExpr.evaluate(pfld);
}
}
}
}
fld.correctLocalBoundaryConditions();
return fld;
}
};
template<class GeoField>
class GeometricFieldRefWrap
:
public GeometricFieldExpression
<
GeometricFieldRefWrap<GeoField>,
ListRefWrap<typename GeoField::value_type>,
ListRefWrap<typename GeoField::value_type>,
ListTmpWrap<Field<typename GeoField::value_type>>,
typename GeoField::value_type
>
{
public:
static constexpr bool is_leaf = false; //true;
//- The GeometricField type
typedef GeoField this_type;
//- Type to return for internal field
typedef typename GeoField::value_type value_type;
//- Type to return for patchField
typedef ListRefWrap<value_type> IntExpr;
typedef ListRefWrap<value_type> UncoupledPatchExpr;
typedef ListTmpWrap<Field<value_type>> CoupledPatchExpr;
private:
this_type& elems_;
public:
//- Copy construct
GeometricFieldRefWrap(this_type& elems)
:
GeometricFieldExpression
<
GeometricFieldRefWrap<GeoField>,
IntExpr,
UncoupledPatchExpr,
CoupledPatchExpr,
value_type
>
(
elems.dimensions(),
elems.oriented()
),
elems_(elems)
{}
//- Move construct
GeometricFieldRefWrap(this_type&& elems)
:
GeometricFieldExpression
<
GeometricFieldRefWrap<GeoField>,
IntExpr,
UncoupledPatchExpr,
CoupledPatchExpr,
value_type
>
(
elems.dimensions(),
elems.oriented()
),
elems_(elems)
{}
// Construct from ListExpression, forcing its evaluation.
template<typename E>
GeometricFieldRefWrap
(
this_type& elems,
const GeometricFieldExpression
<
E,
typename E::IntExpr,
typename E::UncoupledPatchExpr,
typename E::CoupledPatchExpr,
typename E::value_type
>& expr
)
:
GeometricFieldExpression
<
GeometricFieldRefWrap<GeoField>,
IntExpr,
UncoupledPatchExpr,
CoupledPatchExpr,
value_type
>
(
elems.dimensions(),
elems.oriented()
),
elems_(elems)
{
expr.evaluate(elems_);
}
//- Assignment
template<typename E>
void operator=
(
const GeometricFieldExpression
<
E,
typename E::IntExpr,
typename E::UncoupledPatchExpr,
typename E::CoupledPatchExpr,
typename E::value_type
>& expr
)
{
expr.evaluate(elems_);
}
//- Evaluate and return as GeoField. Rename to evaluate to make it clear
//- it takes time? Or leave as indexing for convenience?
template<typename E>
this_type& evaluate
(
const GeometricFieldExpression
<
E,
typename E::IntExpr,
typename E::UncoupledPatchExpr,
typename E::CoupledPatchExpr,
typename E::value_type
>& expr
)
{
return expr.evaluate(elems_);
}
value_type operator[](const label i) const
{
return elems_[i];
}
value_type& operator[](const label i)
{
return elems_[i];
}
auto size() const noexcept
{
return elems_.size();
}
IntExpr internalField()
{
auto& fld = elems_.internalFieldRef();
return IntExpr(fld.size(), fld);
}
IntExpr internalField() const
{
auto& fld = elems_.internalField();
return IntExpr(fld.size(), fld);
}
UncoupledPatchExpr patchField(const label i)
{
auto& fld = elems_.boundaryFieldRef()[i];
if constexpr
(
std::is_same_v<pointMesh, typename GeoField::Mesh>
)
{
const auto* vp = isA<Field<value_type>>(fld);
if (vp)
{
auto& v = *vp;
return UncoupledPatchExpr
(
v.size(),
const_cast<Field<value_type>&>(v)
);
}
else
{
return UncoupledPatchExpr(0, List<value_type>::null());
}
}
else
{
return UncoupledPatchExpr(fld.size(), fld);
}
}
UncoupledPatchExpr patchField(const label i) const
{
const auto& fld = elems_.boundaryField()[i];
if constexpr
(
std::is_same_v<pointMesh, typename GeoField::Mesh>
)
{
const auto* vp = isA<Field<value_type>>(fld);
if (vp)
{
return UncoupledPatchExpr(vp->size(), *vp);
}
else
{
return UncoupledPatchExpr(0, List<value_type>::null());
}
}
else
{
return UncoupledPatchExpr(fld.size(), fld);
}
}
CoupledPatchExpr coupledPatchField(const label i)
{
auto& fld = elems_.boundaryFieldRef()[i];
if constexpr
(
std::is_same_v<pointMesh, typename GeoField::Mesh>
)
{
const auto* vp = isA<Field<value_type>>(fld);
if (vp)
{
auto& v = *vp;
return CoupledPatchExpr
(
//v.size(),
const_cast<Field<value_type>&>(v)
);
}
else
{
return CoupledPatchExpr(List<value_type>::null());
}
}
else
{
return CoupledPatchExpr(fld);
}
}
CoupledPatchExpr coupledPatchField(const label i) const
{
const auto& fld = elems_.boundaryField()[i];
if constexpr
(
std::is_same_v<pointMesh, typename GeoField::Mesh>
)
{
const auto* vp = isA<Field<value_type>>(fld);
if (vp)
{
//return CoupledPatchExpr(vp->size(), *vp);
return CoupledPatchExpr(*vp);
}
else
{
//return CoupledPatchExpr(0, List<value_type>::null());
return CoupledPatchExpr(List<value_type>::null());
}
}
else
{
//return UncoupledPatchExpr(fld.size(), fld);
return CoupledPatchExpr(fld);
}
}
template<class AccessOp>
auto access(const AccessOp& cop, const label i) const
{
return cop(elems_, i);
}
};
template<class GeoField>
class GeometricFieldConstRefWrap
:
public GeometricFieldExpression
<
GeometricFieldConstRefWrap<GeoField>,
ListConstRefWrap<typename GeoField::value_type>,
ListConstRefWrap<typename GeoField::value_type>,
ListConstTmpWrap<Field<typename GeoField::value_type>>,
typename GeoField::value_type
>
{
public:
static constexpr bool is_leaf = false; //true;
//- The GeometricField type
typedef GeoField this_type;
//- Type to return for internal field
typedef typename GeoField::value_type value_type;
//- Type to return for patchField
typedef ListConstRefWrap<value_type> IntExpr;
typedef ListConstRefWrap<value_type> UncoupledPatchExpr;
typedef ListConstTmpWrap<Field<value_type>> CoupledPatchExpr;
private:
const this_type& elems_;
public:
// Construct from components
GeometricFieldConstRefWrap(const this_type& elems)
:
GeometricFieldExpression
<
GeometricFieldConstRefWrap<GeoField>,
IntExpr,
UncoupledPatchExpr,
CoupledPatchExpr,
value_type
>
(
elems.dimensions(),
elems.oriented()
),
elems_(elems)
{}
// return the underlying data
const auto& data() const
{
return elems_;
}
value_type operator[](const label i) const
{
return elems_[i];
}
auto size() const noexcept
{
return elems_.size();
}
IntExpr internalField() const
{
return elems_.internalField();
}
UncoupledPatchExpr patchField(const label i) const
{
//return elems_.boundaryField()[i];
const auto& fld = elems_.boundaryField()[i];
if constexpr
(
std::is_same_v<pointMesh, typename GeoField::Mesh>
)
{
const auto* vp = isA<Field<value_type>>(fld);
if (vp)
{
return UncoupledPatchExpr(*vp);
}
else
{
return UncoupledPatchExpr(List<value_type>::null());
}
}
else
{
return UncoupledPatchExpr(fld);
}
}
CoupledPatchExpr coupledPatchField(const label i) const
{
const auto& fld = elems_.boundaryField()[i];
if constexpr
(
std::is_same_v<pointMesh, typename GeoField::Mesh>
)
{
const auto* vp = isA<Field<value_type>>(fld);
if (vp)
{
return CoupledPatchExpr(*vp);
}
else
{
return CoupledPatchExpr(tmp<Field<value_type>>(nullptr));
}
}
else
{
return CoupledPatchExpr(fld);
}
}
template<class AccessOp>
auto access(const AccessOp& cop, const label i) const
{
return cop(elems_, i);
}
};
template<class GeoField>
class GeometricFieldConstTmpWrap
:
public GeometricFieldExpression
<
GeometricFieldConstTmpWrap<GeoField>,
ListConstRefWrap<typename GeoField::value_type>,
ListConstRefWrap<typename GeoField::value_type>,
ListConstTmpWrap<Field<typename GeoField::value_type>>,
typename GeoField::value_type
>
{
public:
//- Have expressions use copy to maintain tmp refCount
static constexpr bool is_leaf = false;
//- The GeometricField type
typedef GeoField this_type;
//- Type to return for internal field
typedef typename GeoField::value_type value_type;
//- Type to return for patchField
typedef ListConstRefWrap<value_type> IntExpr;
typedef ListConstRefWrap<value_type> UncoupledPatchExpr;
typedef ListConstTmpWrap<Field<value_type>> CoupledPatchExpr;
private:
const tmp<this_type> elems_;
public:
// Construct from components
GeometricFieldConstTmpWrap(const tmp<this_type>& elems)
:
GeometricFieldExpression
<
GeometricFieldConstTmpWrap<GeoField>,
IntExpr,
UncoupledPatchExpr,
CoupledPatchExpr,
value_type
>
(
elems().dimensions(),
elems().oriented()
),
elems_(elems, true)
{
//Pout<< "GeometricFieldConstTmpWrap :" << nl
// << " this_type : "
// << boost::core::demangle(typeid(this_type).name())
// << nl
// << " PatchExpr : "
// << boost::core::demangle(typeid(IntExpr).name()) << nl
// << endl;
}
GeometricFieldConstTmpWrap
(
const GeometricFieldConstTmpWrap<GeoField>& w
)
:
GeometricFieldExpression
<
GeometricFieldConstTmpWrap<GeoField>,
IntExpr,
UncoupledPatchExpr,
CoupledPatchExpr,
value_type
>
(
w.dimensions(),
w.oriented()
),
//elems_(std::move(w.elems_))
elems_(w.elems_)
{
//Pout<< "GeometricFieldConstTmpWrap copy :" << nl
// << " this_type : "
// << boost::core::demangle(typeid(this_type).name())
// << nl
// << " PatchExpr : "
// << boost::core::demangle(typeid(IntExpr).name()) << nl
// << endl;
}
~GeometricFieldConstTmpWrap()
{
//Pout<< "~GeometricFieldConstTmpWrap destructor :" << nl
// << " this_type : "
// << boost::core::demangle(typeid(this_type).name())
// << nl
// << endl;
}
// return the underlying data
const auto& data() const
{
return elems_();
}
value_type operator[](const label i) const
{
// Redirection for every access. Slow?
return elems_()[i];
}
auto size() const noexcept
{
return elems_().size();
}
IntExpr internalField() const
{
return elems_().internalField();
}
UncoupledPatchExpr patchField(const label i) const
{
const auto& fld = elems_().boundaryField()[i];
if constexpr
(
std::is_same_v<pointMesh, typename GeoField::Mesh>
)
{
const auto* vp = isA<Field<value_type>>(fld);
if (vp)
{
return UncoupledPatchExpr(*vp);
}
else
{
return UncoupledPatchExpr(List<value_type>::null());
}
}
else
{
return UncoupledPatchExpr(fld);
}
}
CoupledPatchExpr coupledPatchField(const label i) const
{
const auto& fld = elems_().boundaryField()[i];
if constexpr
(
std::is_same_v<pointMesh, typename GeoField::Mesh>
)
{
const auto* vp = isA<Field<value_type>>(fld);
if (vp)
{
return CoupledPatchExpr(*vp);
}
else
{
return CoupledPatchExpr(List<value_type>::null());
}
}
else
{
return CoupledPatchExpr(fld);
}
}
template<class AccessOp>
auto access(const AccessOp& cop, const label i) const
{
return cop(elems_(), i);
}
};
// Expressions on GeometricFields
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Do '+' ourselves - just to show. Others done with macros below.
template<typename E1, typename E2>
class GF_add
:
public GeometricFieldExpression
<
GF_add<E1, E2>,
List_add
<
typename E1::IntExpr,
typename E2::IntExpr
>,
List_add
<
typename E1::UncoupledPatchExpr,
typename E2::UncoupledPatchExpr
>,
List_add
<
typename E1::CoupledPatchExpr,
typename E2::CoupledPatchExpr
>,
typename E1::value_type
>
{
// cref if leaf, copy otherwise
typename std::conditional<E1::is_leaf, const E1&, const E1>::type u_;
typename std::conditional<E2::is_leaf, const E2&, const E2>::type v_;
public:
static constexpr bool is_leaf = false;
//- Type to return for internal field
typedef typename E1::value_type value_type;
//- Type to return for patchField
typedef List_add
<
typename E1::IntExpr,
typename E2::IntExpr
> IntExpr;
typedef List_add
<
typename E1::UncoupledPatchExpr,
typename E2::UncoupledPatchExpr
> UncoupledPatchExpr;
typedef List_add
<
typename E1::CoupledPatchExpr,
typename E2::CoupledPatchExpr
> CoupledPatchExpr;
GF_add(const E1& u, const E2& v)
:
GeometricFieldExpression
<
GF_add<E1, E2>,
IntExpr,
UncoupledPatchExpr,
CoupledPatchExpr,
value_type
>
(
u.dimensions() + v.dimensions(),
u.oriented() // + v.oriented()
),
u_(u),
v_(v)
{
assert(u.size() == v.size());
static_assert
(
std::is_same_v
<
typename E1::value_type,
typename E2::value_type
> == true
);
}
auto operator[](const label i) const
{
return u_[i] + v_[i];
}
auto size() const noexcept { return u_.size(); }
IntExpr internalField() const
{
return IntExpr(u_.internalField(), v_.internalField());
}
UncoupledPatchExpr patchField(const label i) const
{
return UncoupledPatchExpr(u_.patchField(i), v_.patchField(i));
}
CoupledPatchExpr coupledPatchField(const label i) const
{
return CoupledPatchExpr
(
u_.coupledPatchField(i),
v_.coupledPatchField(i)
);
}
template<class AccessOp>
auto access(const AccessOp& cop, const label i) const
{
return UncoupledPatchExpr(u_.access(cop, i), v_.access(cop, i));
}
};
template<typename E1, typename E2>
GF_add<E1, E2>
operator+
(
GeometricFieldExpression
<
E1,
typename E1::IntExpr,
typename E1::UncoupledPatchExpr,
typename E1::CoupledPatchExpr,
typename E1::value_type
> const& u,
GeometricFieldExpression
<
E2,
typename E2::IntExpr,
typename E2::UncoupledPatchExpr,
typename E2::CoupledPatchExpr,
typename E2::value_type
> const& v
)
{
return GF_add<E1, E2>
(
static_cast<const E1&>(u),
static_cast<const E2&>(v)
);
}
#define EXPRESSION_GF_FUNCTION1_DIMLESS(Func, BaseFunc, WrapType, OpFunc) \
template<typename E1> \
class OpFunc \
: \
public GeometricFieldExpression \
< \
OpFunc<E1>, \
WrapType<typename E1::IntExpr>, \
WrapType<typename E1::UncoupledPatchExpr>, \
WrapType<typename E1::CoupledPatchExpr>, \
typename E1::value_type \
> \
{ \
/* cref if leaf, copy otherwise */ \
typename std::conditional<E1::is_leaf, const E1&, const E1>::type u_; \
\
public: \
static constexpr bool is_leaf = false; \
\
/* Type to return for internal field */ \
typedef typename E1::value_type value_type; \
\
/* Type to return for patchField */ \
typedef WrapType<typename E1::IntExpr> IntExpr; \
typedef WrapType<typename E1::UncoupledPatchExpr> UncoupledPatchExpr; \
typedef WrapType<typename E1::CoupledPatchExpr> CoupledPatchExpr; \
\
OpFunc(const E1& u) \
: \
GeometricFieldExpression \
< \
OpFunc<E1>, \
IntExpr, \
UncoupledPatchExpr, \
CoupledPatchExpr, \
value_type \
> \
( \
u.dimensions(), \
u.oriented() \
), \
u_(u) \
{} \
auto operator[](const label i) const \
{ \
return BaseFunc(u_[i]); \
} \
auto size() const noexcept { return u_.size(); } \
\
IntExpr internalField() const \
{ \
return IntExpr(u_.internalField()); \
} \
\
UncoupledPatchExpr patchField(const label i) const \
{ \
return UncoupledPatchExpr(u_.patchField(i)); \
} \
\
CoupledPatchExpr coupledPatchField(const label i) const \
{ \
return CoupledPatchExpr(u_.coupledPatchField(i)); \
} \
\
template<class AccessOpOp> \
auto access(const AccessOpOp& cop, const label i) const \
{ \
return UncoupledPatchExpr(u_.access(cop, i)); \
} \
}; \
template<typename E1> \
OpFunc<E1> Func \
( \
GeometricFieldExpression \
< \
E1, \
typename E1::IntExpr, \
typename E1::UncoupledPatchExpr, \
typename E1::CoupledPatchExpr, \
typename E1::value_type \
> const& u \
) \
{ \
return OpFunc<E1>(static_cast<const E1&>(u)); \
}
#define EXPRESSION_GF_FUNCTION1(Func, BaseFunc, WrapType, OpFunc) \
template<typename E1> \
class OpFunc \
: \
public GeometricFieldExpression \
< \
OpFunc<E1>, \
WrapType<typename E1::IntExpr>, \
WrapType<typename E1::UncoupledPatchExpr>, \
WrapType<typename E1::CoupledPatchExpr>, \
typename E1::value_type \
> \
{ \
/* cref if leaf, copy otherwise */ \
typename std::conditional<E1::is_leaf, const E1&, const E1>::type u_; \
\
public: \
static constexpr bool is_leaf = false; \
\
/* Type to return for internal field */ \
typedef typename E1::value_type value_type; \
\
/* Type to return for patchField */ \
typedef WrapType<typename E1::IntExpr> IntExpr; \
typedef WrapType<typename E1::UncoupledPatchExpr> UncoupledPatchExpr; \
typedef WrapType<typename E1::CoupledPatchExpr> CoupledPatchExpr; \
\
OpFunc(const E1& u) \
: \
GeometricFieldExpression \
< \
OpFunc<E1>, \
IntExpr, \
UncoupledPatchExpr, \
CoupledPatchExpr, \
value_type \
> \
( \
BaseFunc(u.dimensions()), \
BaseFunc(u.oriented()) \
), \
u_(u) \
{} \
auto operator[](const label i) const \
{ \
return BaseFunc(u_[i]); \
} \
auto size() const noexcept { return u_.size(); } \
\
IntExpr internalField() const \
{ \
return IntExpr(u_.internalField()); \
} \
\
UncoupledPatchExpr patchField(const label i) const \
{ \
return UncoupledPatchExpr(u_.patchField(i)); \
} \
\
CoupledPatchExpr coupledPatchField(const label i) const \
{ \
return CoupledPatchExpr(u_.coupledPatchField(i)); \
} \
\
template<class AccessOpOp> \
auto access(const AccessOpOp& cop, const label i) const \
{ \
return UncoupledPatchExpr(u_.access(cop, i)); \
} \
}; \
template<typename E1> \
OpFunc<E1> Func \
( \
GeometricFieldExpression \
< \
E1, \
typename E1::IntExpr, \
typename E1::UncoupledPatchExpr, \
typename E1::CoupledPatchExpr, \
typename E1::value_type \
> const& u \
) \
{ \
return OpFunc<E1>(static_cast<const E1&>(u)); \
}
//// Do negation separately - problem with macro expansion. Tbd.
//template<typename E1>
//class GeometricFieldNegate
//:
// public GeometricFieldExpression
// <
// GeometricFieldNegate<E1>,
// List_negate<typename E1::IntExpr>,
// List_negate<typename E1::UncoupledPatchExpr>,
// List_negate<typename E1::CoupledPatchExpr>,
// typename E1::value_type
// >
//{
// /* cref if leaf, copy otherwise */
// typename std::conditional<E1::is_leaf, const E1&, const E1>::type u_;
//
//public:
// static constexpr bool is_leaf = false;
//
// /* Type to return for internal field */
// typedef typename E1::value_type value_type;
//
// /* Type to return for patchField */
// typedef List_negate<typename E1::IntExpr> IntExpr;
// typedef List_negate<typename E1::UncoupledPatchExpr> UncoupledPatchExpr;
// typedef List_negate<typename E1::CoupledPatchExpr> CoupledPatchExpr;
//
// GeometricFieldNegate(const E1& u)
// :
// GeometricFieldExpression
// <
// GeometricFieldNegate<E1>,
// IntExpr,
// UncoupledPatchExpr,
// CoupledPatchExpr,
// value_type
// >
// (
// -u.dimensions(),
// -u.oriented()
// ),
// u_(u)
// {}
// auto operator[](const label i) const
// {
// return -u_[i];
// }
// label size() const { return u_.size(); }
//
// IntExpr internalField() const
// {
// return PatchExpr(u_.internalField());
// }
//
// UncoupledPatchExpr patchField(const label i) const
// {
// return UncoupledPatchExpr(u_.patchField(i));
// }
//};
//template<typename E1>
//GeometricFieldNegate<E1> operator-
//(
// GeometricFieldExpression
// <
// E1,
// typename E1::IntExpr,
// typename E1::UncoupledPatchExpr,
// typename E1::CoupledPatchExpr,
// typename E1::value_type
// > const& u
//)
//{
// return GeometricFieldNegate<E1>(static_cast<const E1&>(u));
//}
#define EXPRESSION_GF_OPERATOR(Op, WrapType, OpFunc) \
template<typename E1, typename E2> \
class OpFunc \
: \
public GeometricFieldExpression \
< \
OpFunc<E1, E2>, \
WrapType \
< \
typename E1::IntExpr, \
typename E2::IntExpr \
>, \
WrapType \
< \
typename E1::UncoupledPatchExpr, \
typename E2::UncoupledPatchExpr \
>, \
WrapType \
< \
typename E1::CoupledPatchExpr, \
typename E2::CoupledPatchExpr \
>, \
typename E1::value_type \
> \
{ \
/* cref if leaf, copy otherwise */ \
typename std::conditional<E1::is_leaf, const E1&, const E1>::type u_; \
typename std::conditional<E2::is_leaf, const E2&, const E2>::type v_; \
\
public: \
static constexpr bool is_leaf = false; \
\
/* Type to return for internal field */ \
typedef typename E1::value_type value_type; \
\
/* Type to return for patchField */ \
typedef WrapType \
< \
typename E1::IntExpr, \
typename E2::IntExpr \
> IntExpr; \
typedef WrapType \
< \
typename E1::UncoupledPatchExpr, \
typename E2::UncoupledPatchExpr \
> UncoupledPatchExpr; \
typedef WrapType \
< \
typename E1::CoupledPatchExpr, \
typename E2::CoupledPatchExpr \
> CoupledPatchExpr; \
\
OpFunc(const E1& u, const E2& v) \
: \
GeometricFieldExpression \
< \
OpFunc<E1, E2>, \
IntExpr, \
UncoupledPatchExpr, \
CoupledPatchExpr, \
typename E1::value_type \
> \
( \
u.dimensions() Op v.dimensions(), \
u.oriented() Op v.oriented() \
), \
u_(u), \
v_(v) \
{ \
/*static_assert \
( \
std::is_same_v \
< \
typename E1::value_type, \
typename E2::value_type \
> == true \
);*/ \
assert(u.size() == v.size()); \
} \
auto operator[](const label i) const \
{ \
return u_[i] Op v_[i]; \
} \
auto size() const noexcept { return u_.size(); } \
\
IntExpr internalField() const \
{ \
return IntExpr(u_.internalField(), v_.internalField()); \
} \
\
UncoupledPatchExpr patchField(const label i) const \
{ \
return UncoupledPatchExpr(u_.patchField(i), v_.patchField(i)); \
} \
\
CoupledPatchExpr coupledPatchField(const label i) const \
{ \
return CoupledPatchExpr \
( \
u_.coupledPatchField(i), \
v_.coupledPatchField(i) \
); \
} \
\
template<class AccessOp> \
auto access(const AccessOp& cop, const label i) const \
{ \
return UncoupledPatchExpr \
( \
u_.access(cop, i), \
v_.access(cop, i) \
); \
} \
}; \
template<typename E1, typename E2> \
OpFunc<E1, E2> \
operator Op \
( \
GeometricFieldExpression \
< \
E1, \
typename E1::IntExpr, \
typename E1::UncoupledPatchExpr, \
typename E1::CoupledPatchExpr, \
typename E1::value_type \
> const& u, \
GeometricFieldExpression \
< \
E2, \
typename E2::IntExpr, \
typename E2::UncoupledPatchExpr, \
typename E2::CoupledPatchExpr, \
typename E2::value_type \
> const& v \
) \
{ \
return OpFunc<E1, E2> \
( \
static_cast<const E1&>(u), \
static_cast<const E2&>(v) \
); \
}
#define EXPRESSION_GF_FUNCTION2(Func, BaseFunc, WrapType, OpFunc) \
template<typename E1, typename E2> \
class OpFunc \
: \
public GeometricFieldExpression \
< \
OpFunc<E1, E2>, \
WrapType \
< \
typename E1::IntExpr, \
typename E2::IntExpr \
>, \
WrapType \
< \
typename E1::UncoupledPatchExpr, \
typename E2::UncoupledPatchExpr \
>, \
WrapType \
< \
typename E1::CoupledPatchExpr, \
typename E2::CoupledPatchExpr \
>, \
typename E1::value_type \
> \
{ \
/* cref if leaf, copy otherwise */ \
typename std::conditional<E1::is_leaf, const E1&, const E1>::type u_; \
typename std::conditional<E2::is_leaf, const E2&, const E2>::type v_; \
\
public: \
static constexpr bool is_leaf = false; \
\
/* Type to return for internal field */ \
typedef typename E1::value_type value_type; \
\
/* Type to return for patchField */ \
typedef WrapType \
< \
typename E1::IntExpr, \
typename E2::IntExpr \
> IntExpr; \
typedef WrapType \
< \
typename E1::UncoupledPatchExpr, \
typename E2::UncoupledPatchExpr \
> UncoupledPatchExpr; \
typedef WrapType \
< \
typename E1::CoupledPatchExpr, \
typename E2::CoupledPatchExpr \
> CoupledPatchExpr; \
\
OpFunc(const E1& u, const E2& v) \
: \
GeometricFieldExpression \
< \
OpFunc<E1, E2>, \
IntExpr, \
UncoupledPatchExpr, \
CoupledPatchExpr, \
value_type \
> \
( \
BaseFunc(u.dimensions(), v.dimensions()), \
BaseFunc(u.oriented(), v.oriented()) \
), \
u_(u), \
v_(v) \
{ \
/*static_assert \
( \
std::is_same_v \
< \
typename E1::value_type, \
typename E2::value_type \
> == true \
);*/ \
} \
auto operator[](const label i) const \
{ \
return BaseFunc(u_[i], v_[i]); \
} \
auto size() const noexcept {return u_.size(); } \
\
IntExpr internalField() const \
{ \
return IntExpr(u_.internalField(), v_.internalField()); \
} \
\
UncoupledPatchExpr patchField(const label i) const \
{ \
return UncoupledPatchExpr(u_.patchField(i), v_.patchField(i)); \
} \
\
CoupledPatchExpr coupledPatchField(const label i) const \
{ \
return CoupledPatchExpr \
( \
u_.coupledPatchField(i), \
v_.coupledPatchField(i) \
); \
} \
\
template<class AccessOp> \
auto access(const AccessOp& cop, const label i) const \
{ \
return UncoupledPatchExpr \
( \
u_.access(cop, i), \
v_.access(cop, i) \
); \
} \
}; \
template<typename E1, typename E2> \
OpFunc<E1, E2> Func \
( \
GeometricFieldExpression \
< \
E1, \
typename E1::IntExpr, \
typename E1::UncoupledPatchExpr, \
typename E1::CoupledPatchExpr, \
typename E1::value_type \
> const& u, \
GeometricFieldExpression \
< \
E2, \
typename E2::IntExpr, \
typename E2::UncoupledPatchExpr, \
typename E2::CoupledPatchExpr, \
typename E2::value_type \
> const& v \
) \
{ \
return OpFunc<E1, E2> \
( \
static_cast<const E1&>(u), \
static_cast<const E2&>(v) \
); \
}
//- GeometricField expressions.
// macro arguments:
// - 'sin' : name of new function (in Expression namespace)
// - '::sin' : per-element function to call
// - 'List_sin' : helper class to handle patchFields
// - 'GF_sin' : generated expression helper class
EXPRESSION_GF_FUNCTION1_DIMLESS(sin, ::sin, List_sin, GF_sin)
EXPRESSION_GF_FUNCTION1_DIMLESS(cos, ::cos, List_cos, GF_cos)
EXPRESSION_GF_FUNCTION1_DIMLESS(tan, ::tan, List_tan, GF_tan)
EXPRESSION_GF_FUNCTION1_DIMLESS(sinh, ::sinh, List_sinh, GF_sinh)
EXPRESSION_GF_FUNCTION1_DIMLESS(cosh, ::cosh, List_cosh, GF_cosh)
EXPRESSION_GF_FUNCTION1_DIMLESS(tanh, ::tanh, List_tanh, GF_tanh)
#undef EXPRESSION_GF_FUNCTION1_DIMLESS
EXPRESSION_GF_FUNCTION1(sqr, Foam::sqr, List_sqr, GF_sqr)
EXPRESSION_GF_FUNCTION1(sqrt, Foam::sqrt, List_sqrt, GF_sqrt)
EXPRESSION_GF_FUNCTION1(magSqr, Foam::magSqr, List_magSqr, GF_magSqr)
EXPRESSION_GF_FUNCTION1(mag, Foam::mag, List_mag, GF_mag)
EXPRESSION_GF_FUNCTION1(symm, Foam::symm, List_symm, GF_symm)
EXPRESSION_GF_FUNCTION1(pow2, Foam::pow2, List_pow2, GF_pow2)
EXPRESSION_GF_FUNCTION1(pow3, Foam::pow3, List_pow3, GF_pow3)
EXPRESSION_GF_FUNCTION1(pow4, Foam::pow4, List_pow4, GF_pow4)
#undef EXPRESSION_GF_FUNCTION1
EXPRESSION_GF_FUNCTION2(min, Foam::min, List_min, GF_min)
EXPRESSION_GF_FUNCTION2(max, Foam::max, List_max, GF_max)
#undef EXPRESSION_GF_FUNCTION2
EXPRESSION_GF_OPERATOR(-, List_subtract, GF_subtract)
EXPRESSION_GF_OPERATOR(*, List_multiply, GF_multiply)
EXPRESSION_GF_OPERATOR(/, List_divide, GF_divide)
EXPRESSION_GF_OPERATOR(&, List_dot, GF_dot)
#undef EXPRESSION_GF_OPERATOR
// Expressions on constants
// ~~~~~~~~~~~~~~~~~~~~~~~~
template<class GeoField>
class UniformGeometricFieldWrap
:
public GeometricFieldExpression
<
UniformGeometricFieldWrap<GeoField>,
UniformListWrap<typename GeoField::value_type>,
UniformListWrap<typename GeoField::value_type>,
UniformListWrap<typename GeoField::value_type>,
typename GeoField::value_type
>
{
public:
static constexpr bool is_leaf = false; //true;
//- Type to return for internal field
typedef typename GeoField::value_type value_type;
//- Type to return for patchField
typedef UniformListWrap<value_type> IntExpr;
typedef UniformListWrap<value_type> UncoupledPatchExpr;
typedef UniformListWrap<value_type> CoupledPatchExpr;
private:
const GeoField& elems_;
const value_type val_;
public:
// Construct from field (sizes only) and value
UniformGeometricFieldWrap(const GeoField& elems, const value_type val)
:
GeometricFieldExpression
<
UniformGeometricFieldWrap<GeoField>,
IntExpr,
UncoupledPatchExpr,
CoupledPatchExpr,
value_type
>
(
dimless,
orientedType()
),
elems_(elems),
val_(val)
{}
// Construct from field (sizes only) and value, dimension
UniformGeometricFieldWrap
(
const GeoField& elems,
const dimensioned<value_type> val
)
:
GeometricFieldExpression
<
UniformGeometricFieldWrap<GeoField>,
IntExpr,
UncoupledPatchExpr,
CoupledPatchExpr,
value_type
>
(
val.dimensions(),
orientedType()
),
elems_(elems),
val_(val.value())
{}
value_type operator[](const label i) const
{
return val_;
}
auto size() const noexcept
{
return elems_.size();
}
IntExpr internalField() const
{
return IntExpr(elems_.internalField().size(), val_);
}
UncoupledPatchExpr patchField(const label i) const
{
return UncoupledPatchExpr(elems_.boundaryField()[i].size(), val_);
}
CoupledPatchExpr coupledPatchField(const label i) const
{
return CoupledPatchExpr(elems_.boundaryField()[i].size(), val_);
}
template<class AccessOp>
auto access(const AccessOp& cop, const label i) const
{
// Size+value only
return patchField(i);
}
};
//- Fully self-contained constant field wrapper. Not needed?
//template<class GeoField>
//class UniformGeometricFieldWrap2
//:
// public GeometricFieldExpression
// <
// UniformGeometricFieldWrap2<GeoField>,
// UniformListWrap<typename GeoField::value_type>,
// typename GeoField::value_type
// >
//{
//public:
//
// static constexpr bool is_leaf = true;
//
// //- Type to return for internal field
// typedef typename GeoField::value_type value_type;
//
// //- Type to return for patchField
// typedef UniformListWrap<value_type> PatchExpr;
//
//
//private:
//
// const value_type val_;
//
// const label nInternal_;
//
// labelList patchSizes_;
//
// //const dimensionSet& dimensions_;
//
//public:
//
// // Construct from field (sizes only) and value
// UniformGeometricFieldWrap2(const GeoField& elems, const value_type val)
// :
// val_(val),
// nInternal_(elems.size()),
// patchSizes_(elems.boundaryField().size())
// //dimensions_(elems.dimensions()),
// {
// for (const auto& pfld : elems.boundaryField())
// {
// patchSizes_[pfld.patch().index()] = pfld.size();
// }
// }
//
// // Construct from field (sizes only) and value, dimension
// UniformGeometricFieldWrap2
// (
// const GeoField& elems,
// const dimensioned<value_type> val
// )
// :
// val_(val.value()),
// nInternal_(elems.size()),
// patchSizes_(elems.boundaryField().size())
// //dimensions_(val.dimensions()),
// {
// for (const auto& pfld : elems.boundaryField())
// {
// patchSizes_[pfld.patch().index()] = pfld.size();
// }
// }
//
// value_type operator[](const label i) const
// {
// return val_;
// }
//
// auto size() const noexcept
// {
// return nInternal_;
// }
//
// PatchExpr internalField() const
// {
// return PatchExpr(nInternal_, val_);
// }
//
// PatchExpr patchField(const label i) const
// {
// return PatchExpr(patchSizes_[i], val_);
// }
//};
/*
// Some fvm functions using expressions
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Supply a multiplier, either 1 or -1
template<class Expr, class Expr2>
void Su
(
fvMatrix<typename Expr::value_type>& m,
const Expr2& mult,
const Expr& expression
)
{
//- Wrap of List as an expression
typedef ListConstRefWrap<typename Expr::value_type> expr;
//- Evaluator of an expression
typedef ListRefWrap<typename Expr::value_type> evaluator;
// Wrap mesh volume
const expr V(m.psi().mesh().V());
// Add expression to source
auto& s = m.source();
evaluator(s, expr(s) + mult*V*expression);
}
// Always add
template<class Expr>
void Su
(
fvMatrix<typename Expr::value_type>& m,
const Expr& expression
)
{
//- Wrap of List as an expression
typedef ListConstRefWrap<typename Expr::value_type> expr;
//- Evaluator of an expression
typedef ListRefWrap<typename Expr::value_type> evaluator;
// Wrap mesh volume
const expr V(m.psi().mesh().V());
// Add expression to source
auto& s = m.source();
evaluator(s, expr(s) + V*expression);
}
template<class Expr>
void rhs
(
fvMatrix<typename Expr::value_type>& m,
const Expr& expression
)
{
Su(m, expression);
}
template<class Expr, class Expr2>
void Sp
(
fvMatrix<typename Expr::value_type>& m,
const Expr2& mult,
const Expr& expression
)
{
//- Wrap of List as an expression
typedef ListConstRefWrap<typename Expr::value_type> expr;
//- Evaluator of an expression
typedef ListRefWrap<typename Expr::value_type> evaluator;
// Wrap mesh volume
const expr V(m.psi().mesh().V());
// Add expression onto diag
auto& d = m.diag();
evaluator(d, expr(d) - mult*V*expression);
}
template<class Expr, class Expr2>
void SuSp
(
fvMatrix<typename Expr::value_type>& m,
const Expr2& mult,
const Expr& expression
)
{
//- Wrap of constant as a list expression
typedef UniformListWrap<scalar> constant;
//- Wrap of List as an expression
typedef ListConstRefWrap<typename Expr::value_type> expr;
//- Evaluator of an expression
typedef ListRefWrap<typename Expr::value_type> evaluator;
const constant constantZero(expression.size(), 0.0);
// Wrap mesh volume
const expr V(m.psi().mesh().V());
// Linearise expression
auto& diag = m.diag();
auto& source = m.source();
// diag() += domain*max(susp.field(), scalar(0));
evaluator
(
diag,
expr(diag) - mult*V*max(expression, constantZero)
);
// source() -= domain*min(susp.field(), scalar(0))*fld.primitiveField();
evaluator
(
source,
expr(source)
+ (
mult
*V
*min(expression, constantZero)
*expr(m.psi().internalField())
)
);
}
*/
} // End namespace Expression
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //