Files
mfem/fem/tcoefficient.hpp
T

349 lines
11 KiB
C++

// Copyright (c) 2010-2020, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.
#ifndef MFEM_TEMPLATE_COEFFICIENT
#define MFEM_TEMPLATE_COEFFICIENT
#include "../config/tconfig.hpp"
#include "../linalg/ttensor.hpp"
#include "../linalg/tlayout.hpp"
#include "../linalg/vector.hpp"
#include "gridfunc.hpp"
namespace mfem
{
/// Templated coefficient classes, cf. coefficient.?pp
class TCoefficient
{
public:
static const int rank = 0; // 0 - scalar, 1 - vector, 2 - matrix
static const bool is_const = false;
static const bool uses_coordinates = false;
static const bool uses_Jacobians = false;
static const bool uses_attributes = false;
static const bool uses_element_idxs = false;
};
template <typename complex_t = double>
class TConstantCoefficient : public TCoefficient
{
public:
static const bool is_const = true;
typedef complex_t complex_type;
complex_t value;
TConstantCoefficient(complex_t val) : value(val) { }
// default copy constructor
// T_result_t is the transformation result type (not used here).
template <typename T_result_t, typename c_layout_t, typename c_data_t>
inline MFEM_ALWAYS_INLINE
void Eval(const T_result_t &T, const c_layout_t &l, c_data_t &c) const
{
TAssign<AssignOp::Set>(l, c, value);
}
};
/** @brief Function coefficient.
@tparam Func has to implement at least one of the following methods,
depending on the dimension that will be used:
complex_t Eval1D(real_t);
complex_t Eval2D(real_t,real_t);
complex_t Eval3D(real_t,real_t,real_t);
Use MFEM_FLOPS_ADD() to count flops inside Eval*D. */
template <typename Func, typename complex_t = double>
class TFunctionCoefficient : public TCoefficient
{
public:
static const bool uses_coordinates = true;
typedef complex_t complex_type;
protected:
Func F;
template <int dim, bool dummy> struct Dim;
template <bool dummy> struct Dim<1,dummy>
{
template <typename T_result_t, typename c_layout_t, typename c_data_t>
static inline MFEM_ALWAYS_INLINE
void Eval(Func &F, const T_result_t &T, const c_layout_t &l, c_data_t &c)
{
const int qpts = T_result_t::x_type::layout_type::dim_1;
const int ne = T_result_t::x_type::layout_type::dim_3;
const int vs = sizeof(T.x[0])/sizeof(T.x[0][0]);
for (int k = 0; k < ne; k++)
{
for (int i = 0; i < qpts; i++)
{
for (int s = 0; s < vs; s++)
{
c[l.ind(i,k)][s] = F.Eval1D(T.x(i,0,k)[s]);
}
}
}
}
};
template <bool dummy> struct Dim<2,dummy>
{
template <typename T_result_t, typename c_layout_t, typename c_data_t>
static inline MFEM_ALWAYS_INLINE
void Eval(Func &F, const T_result_t &T, const c_layout_t &l, c_data_t &c)
{
const int qpts = T_result_t::x_type::layout_type::dim_1;
const int ne = T_result_t::x_type::layout_type::dim_3;
const int vs = sizeof(T.x[0])/sizeof(T.x[0][0]);
for (int k = 0; k < ne; k++)
{
for (int i = 0; i < qpts; i++)
{
for (int s = 0; s < vs; s++)
{
c[l.ind(i,k)][s] = F.Eval2D(T.x(i,0,k)[s], T.x(i,1,k)[s]);
}
}
}
}
};
template <bool dummy> struct Dim<3,dummy>
{
template <typename T_result_t, typename c_layout_t, typename c_data_t>
static inline MFEM_ALWAYS_INLINE
void Eval(Func &F, const T_result_t &T, const c_layout_t &l, c_data_t &c)
{
const int qpts = T_result_t::x_type::layout_type::dim_1;
const int ne = T_result_t::x_type::layout_type::dim_3;
const int vs = sizeof(T.x[0])/sizeof(T.x[0][0]);
for (int k = 0; k < ne; k++)
{
for (int i = 0; i < qpts; i++)
{
for (int s = 0; s < vs; s++)
{
c[l.ind(i,k)][s] =
F.Eval3D(T.x(i,0,k)[s], T.x(i,1,k)[s], T.x(i,2,k)[s]);
}
}
}
}
};
public:
/// Constructor for the case when Func has no data members.
TFunctionCoefficient() : F() { }
/// Constructor for the case when Func has data members.
TFunctionCoefficient(Func &F_) : F(F_) { }
// Default copy constructor, Func has to have copy constructor.
template <typename T_result_t, typename c_layout_t, typename c_data_t>
inline MFEM_ALWAYS_INLINE
void Eval(const T_result_t &T, const c_layout_t &l, c_data_t &c)
{
const int qpts = T_result_t::x_type::layout_type::dim_1;
const int sdim = T_result_t::x_type::layout_type::dim_2;
const int ne = T_result_t::x_type::layout_type::dim_3;
MFEM_STATIC_ASSERT(c_layout_t::rank == 2 && c_layout_t::dim_1 == qpts &&
c_layout_t::dim_2 == ne, "invalid c_layout_t");
Dim<sdim,true>::Eval(F, T, l, c);
}
};
/// Piecewise constant coefficient class. The subdomains where the coefficient
/// is constant are given by the mesh attributes.
template <typename complex_t = double>
class TPiecewiseConstCoefficient : public TCoefficient
{
public:
static const bool uses_attributes = true;
typedef complex_t complex_type;
protected:
Vector constants; // complex_t = double
public:
/// Note: in the input array index i corresponds to mesh attribute i+1.
TPiecewiseConstCoefficient(const Vector &constants)
: constants(constants) { }
// default copy constructor
template <typename T_result_t, typename c_layout_t, typename c_data_t>
inline MFEM_ALWAYS_INLINE
void Eval(const T_result_t &T, const c_layout_t &l, c_data_t &c)
{
const int ne = T_result_t::ne;
const int vs = sizeof(T.attrib[0])/sizeof(T.attrib[0][0]);
MFEM_STATIC_ASSERT(vs == sizeof(c[0])/sizeof(c[0][0]), "");
for (int i = 0; i < ne; i++)
{
typename c_data_t::data_type ci;
for (int s = 0; s < vs; s++)
{
ci[s] = constants(T.attrib[i][s]-1);
}
TAssign<AssignOp::Set>(l.ind2(i), c, ci);
}
}
};
/// GridFunction coefficient class.
template <typename FieldEval>
class TGridFunctionCoefficient : public TCoefficient
{
public:
static const bool uses_element_idxs = true;
typedef typename FieldEval::FESpace_type FESpace_type;
typedef typename FieldEval::ShapeEval_type ShapeEval_type;
typedef typename FieldEval::VecLayout_type VecLayout_type;
typedef typename FieldEval::complex_type complex_type;
protected:
FieldEval fieldEval;
public:
// This constructor uses a shallow copy of fE.fespace as part of fieldEval.
inline MFEM_ALWAYS_INLINE
TGridFunctionCoefficient(const FieldEval &fE,
const complex_type *data)
: fieldEval(fE, data, NULL)
{ }
// This constructor uses a shallow copy of tfes as part of fieldEval.
inline MFEM_ALWAYS_INLINE
TGridFunctionCoefficient(const FESpace_type &tfes,
const ShapeEval_type &shapeEval,
const VecLayout_type &vec_layout,
const complex_type *data)
: fieldEval(tfes, shapeEval, vec_layout, data, NULL)
{ }
// This constructor creates new FESpace_type as part of fieldEval.
inline MFEM_ALWAYS_INLINE
TGridFunctionCoefficient(const FiniteElementSpace &fes,
const complex_type *data)
: fieldEval(fes, data, NULL)
{ }
// This constructor creates new FESpace_type as part of fieldEval.
inline MFEM_ALWAYS_INLINE
TGridFunctionCoefficient(const GridFunction &func)
: fieldEval(*func.FESpace(), func.GetData(), NULL)
{ }
// default copy constructor
template <typename T_result_t, typename c_layout_t, typename c_data_t>
inline MFEM_ALWAYS_INLINE
void Eval(const T_result_t &T, const c_layout_t &l, c_data_t &c)
{
const int ne = T_result_t::ne;
const int vdim = FieldEval::vdim;
const int qpts = FieldEval::qpts;
MFEM_STATIC_ASSERT(c_layout_t::rank == 2, "tensor rank must be 2");
MFEM_STATIC_ASSERT(c_layout_t::dim_1 == qpts, "incompatible quadrature");
MFEM_STATIC_ASSERT(c_layout_t::dim_2 == ne, "");
MFEM_STATIC_ASSERT(vdim == 1, "vdim != 1 is not supported");
fieldEval.GetValues(T.first_elem_idx, l.template split_2<1,ne>(), c);
}
};
/// Auxiliary class that is used to simplify the evaluation of a coefficient and
/// scaling it by the weights of a quadrature rule.
template <typename IR, typename coeff_t, typename impl_traits_t>
struct IntRuleCoefficient
{
static const int qpts = IR::qpts;
static const int ne = impl_traits_t::batch_size;
typedef typename coeff_t::complex_type complex_type;
typedef typename impl_traits_t::vcomplex_t vcomplex_t;
template <bool is_const, bool dummy> struct Aux;
// constant coefficient
template <bool dummy> struct Aux<true,dummy>
{
typedef struct { } result_t;
TMatrix<qpts,1,complex_type> cw;
inline MFEM_ALWAYS_INLINE Aux(const IR &int_rule, const coeff_t &c)
{
c.Eval(true, cw.layout, cw);
int_rule.ApplyWeights(cw);
}
template <typename T_result_t>
inline MFEM_ALWAYS_INLINE
void Eval(const T_result_t &F, result_t &res) { }
inline MFEM_ALWAYS_INLINE
const complex_type &get(const result_t &res, int i, int k) const
{
return cw(i,0);
}
};
// non-constant coefficient
template <bool dummy> struct Aux<false,dummy>
{
typedef TMatrix<qpts,ne,vcomplex_t> result_t;
#ifdef MFEM_TEMPLATE_INTRULE_COEFF_PRECOMP
TMatrix<qpts,1,typename IR::real_type> w;
#else
IR int_rule;
#endif
coeff_t c;
#ifdef MFEM_TEMPLATE_INTRULE_COEFF_PRECOMP
inline MFEM_ALWAYS_INLINE Aux(const IR &int_rule, const coeff_t &c)
: c(c)
{
int_rule.template AssignWeights<AssignOp::Set>(w.layout, w);
}
#else
inline MFEM_ALWAYS_INLINE Aux(const IR &int_rule, const coeff_t &c)
: int_rule(int_rule), c(c) { }
#endif
template <typename T_result_t>
inline MFEM_ALWAYS_INLINE
void Eval(const T_result_t &F, result_t &res)
{
c.Eval(F, res.layout, res);
#ifdef MFEM_TEMPLATE_INTRULE_COEFF_PRECOMP
for (int i = 0; i < ne; i++)
{
TAssign<AssignOp::Mult>(res.layout.ind2(i), res,
w.layout.merge_12(), w);
}
#else
int_rule.template AssignWeights<AssignOp::Mult>(res.layout, res);
#endif
}
inline MFEM_ALWAYS_INLINE
const vcomplex_t &get(const result_t &res, int i, int k) const
{
return res(i,k);
}
};
typedef Aux<coeff_t::is_const,true> Type;
};
} // namespace mfem
#endif // MFEM_TEMPLATE_COEFFICIENT