Files
mfem/fem/ceed/interface/integrator.hpp
T

778 lines
32 KiB
C++

// Copyright (c) 2010-2025, 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_LIBCEED_INTEG
#define MFEM_LIBCEED_INTEG
#include "../../../config/config.hpp"
#include "../../fespace.hpp"
#include "../../gridfunc.hpp"
#include "operator.hpp"
#include "coefficient.hpp"
#include "restriction.hpp"
#include "util.hpp"
#include "ceed.hpp"
namespace mfem
{
namespace ceed
{
/** The different evaluation modes available for PA and MF CeedIntegrator. */
enum class EvalMode { None, Interp, Grad, InterpAndGrad };
#ifdef MFEM_USE_CEED
/** This structure is a template interface for the Assemble methods of
PAIntegrator and MFIntegrator. See ceed/mass.cpp for an example. */
struct OperatorInfo
{
/** The path to the qFunction header. */
const char *header;
/** The name of the qFunction to build a partially assembled CeedOperator
with a constant Coefficient. */
const char *build_func_const;
/** The qFunction to build a partially assembled CeedOperator with a constant
Coefficient. */
CeedQFunctionUser build_qf_const;
/** The name of the qFunction to build a partially assembled CeedOperator
with a variable Coefficient. */
const char *build_func_quad;
/** The qFunction to build a partially assembled CeedOperator with a variable
Coefficient. */
CeedQFunctionUser build_qf_quad;
/** The name of the qFunction to apply a partially assembled CeedOperator. */
const char *apply_func;
/** The qFunction to apply a partially assembled CeedOperator. */
CeedQFunctionUser apply_qf;
/** The name of the qFunction to apply a matrix-free CeedOperator with a
constant Coefficient. */
const char *apply_func_mf_const;
/** The qFunction to apply a matrix-free CeedOperator with a constant
Coefficient. */
CeedQFunctionUser apply_qf_mf_const;
/** The name of the qFunction to apply a matrix-free CeedOperator with a
variable Coefficient. */
const char *apply_func_mf_quad;
/** The qFunction to apply a matrix-free CeedOperator with a variable
Coefficient. */
CeedQFunctionUser apply_qf_mf_quad;
/** The EvalMode on the trial basis functions. */
EvalMode trial_op;
/** The EvalMode on the test basis functions. */
EvalMode test_op;
/** The size of the data at each quadrature point. */
int qdatasize;
};
#endif
/** This class represent a partially assembled operator using libCEED. */
class PAIntegrator : public ceed::Operator
{
#ifdef MFEM_USE_CEED
protected:
CeedBasis trial_basis, test_basis, mesh_basis;
CeedElemRestriction trial_restr, test_restr, mesh_restr, restr_i;
CeedQFunction build_qfunc, apply_qfunc;
CeedVector node_coords, qdata;
Coefficient *coeff;
CeedQFunctionContext build_ctx;
CeedOperator build_oper;
public:
PAIntegrator()
: Operator(),
trial_basis(nullptr), test_basis(nullptr), mesh_basis(nullptr),
trial_restr(nullptr), test_restr(nullptr), mesh_restr(nullptr),
restr_i(nullptr),
build_qfunc(nullptr), apply_qfunc(nullptr), node_coords(nullptr),
qdata(nullptr), coeff(nullptr), build_ctx(nullptr), build_oper(nullptr)
{ }
/** @brief This method assembles the `PAIntegrator` with the given
`CeedOperatorInfo` @a info, an `mfem::FiniteElementSpace` @a fes, an
`mfem::IntegrationRule` @a ir, and `mfem::Coefficient` or
`mfem::VectorCoefficient` @a Q.
The `CeedOperatorInfo` type is expected to inherit from `OperatorInfo`,
and contain a `Context` type relevant to the qFunctions.
@param[in] info is the structure describing the CeedOperator to assemble.
@param[in] fes is the finite element space.
@param[in] ir is the integration rule for the operator.
@param[in] Q is the coefficient from the `Integrator`. */
template <typename CeedOperatorInfo, typename CoeffType>
void Assemble(CeedOperatorInfo &info,
const mfem::FiniteElementSpace &fes,
const mfem::IntegrationRule &ir,
CoeffType *Q)
{
Assemble(info, fes, ir, fes.GetNE(), nullptr, Q);
}
/** @brief This method assembles the `PAIntegrator` with the given
`CeedOperatorInfo` @a info, an `mfem::FiniteElementSpace` @a fes, an
`mfem::IntegrationRule` @a ir, and `mfem::Coefficient` or
`mfem::VectorCoefficient` @a Q for the elements given by the indices
@a indices.
The `CeedOperatorInfo` type is expected to inherit from `OperatorInfo`,
and contain a `Context` type relevant to the qFunctions.
@param[in] info is the structure describing the CeedOperator to assemble.
@param[in] fes is the finite element space.
@param[in] ir is the integration rule for the operator.
@param[in] nelem The number of elements.
@param[in] indices The indices of the elements of same type in the
`FiniteElementSpace`. If `indices == nullptr`, assumes
that the `FiniteElementSpace` is not mixed.
@param[in] Q is the coefficient from the `Integrator`. */
template <typename CeedOperatorInfo, typename CoeffType>
void Assemble(CeedOperatorInfo &info,
const mfem::FiniteElementSpace &fes,
const mfem::IntegrationRule &ir,
int nelem,
const int* indices,
CoeffType *Q)
{
Assemble(info, fes, fes, ir, nelem, indices, Q);
}
/** This method assembles the PAIntegrator for mixed forms.
@param[in] info the `CeedOperatorInfo` describing the `CeedOperator`,
the `CeedOperatorInfo` type is expected to inherit from
`OperatorInfo` and contain a `Context` type relevant to
the qFunctions.
@param[in] trial_fes the trial `FiniteElementSpace` for the form,
@param[in] test_fes the test `FiniteElementSpace` for the form,
@param[in] ir the `IntegrationRule` for the numerical integration,
@param[in] Q `Coefficient` or `VectorCoefficient`. */
template <typename CeedOperatorInfo, typename CoeffType>
void Assemble(CeedOperatorInfo &info,
const mfem::FiniteElementSpace &trial_fes,
const mfem::FiniteElementSpace &test_fes,
const mfem::IntegrationRule &ir,
CoeffType *Q)
{
Assemble(info, trial_fes, test_fes, ir, trial_fes.GetNE(), nullptr, Q);
}
/** This method assembles the PAIntegrator for mixed forms on mixed meshes.
@param[in] info the `CeedOperatorInfo` describing the `CeedOperator`,
the `CeedOperatorInfo` type is expected to inherit from
`OperatorInfo` and contain a `Context` type relevant to
the qFunctions.
@param[in] trial_fes the trial `FiniteElementSpace` for the form,
@param[in] test_fes the test `FiniteElementSpace` for the form,
@param[in] ir the `IntegrationRule` for the numerical integration,
@param[in] nelem The number of elements,
@param[in] indices The indices of the elements of same type in the
`FiniteElementSpace`. If `indices == nullptr`, assumes
that the `FiniteElementSpace` is not mixed,
@param[in] Q `Coefficient` or `VectorCoefficient`. */
template <typename CeedOperatorInfo, typename CoeffType>
void Assemble(CeedOperatorInfo &info,
const mfem::FiniteElementSpace &trial_fes,
const mfem::FiniteElementSpace &test_fes,
const mfem::IntegrationRule &ir,
int nelem,
const int* indices,
CoeffType *Q)
{
Ceed ceed(internal::ceed);
mfem::Mesh &mesh = *trial_fes.GetMesh();
MFEM_VERIFY(!(!indices && mesh.GetNumGeometries(mesh.Dimension()) > 1),
"Use ceed::MixedIntegrator on mixed meshes.");
InitCoefficient(Q, mesh, ir, nelem, indices, coeff, info.ctx);
bool const_coeff = coeff->IsConstant();
std::string build_func = const_coeff ? info.build_func_const
: info.build_func_quad;
CeedQFunctionUser build_qf = const_coeff ? info.build_qf_const
: info.build_qf_quad;
PAOperator op {info.qdatasize, info.header,
build_func, build_qf,
info.apply_func, info.apply_qf,
info.trial_op,
info.test_op
};
CeedInt dim = mesh.SpaceDimension();
CeedInt trial_vdim = trial_fes.GetVDim();
CeedInt test_vdim = test_fes.GetVDim();
mesh.EnsureNodes();
if ( &trial_fes == &test_fes )
{
InitBasisAndRestriction(trial_fes, ir, nelem, indices,
ceed, &trial_basis, &trial_restr);
test_basis = trial_basis;
test_restr = trial_restr;
}
else
{
InitBasisAndRestriction(trial_fes, ir, nelem, indices,
ceed, &trial_basis, &trial_restr);
InitBasisAndRestriction(test_fes, ir, nelem, indices,
ceed, &test_basis, &test_restr);
}
const mfem::FiniteElementSpace *mesh_fes = mesh.GetNodalFESpace();
MFEM_VERIFY(mesh_fes, "the Mesh has no nodal FE space");
InitBasisAndRestriction(*mesh_fes, ir, nelem, indices,
ceed, &mesh_basis, &mesh_restr);
CeedInt trial_nqpts, test_nqpts;
CeedBasisGetNumQuadraturePoints(trial_basis, &trial_nqpts);
CeedBasisGetNumQuadraturePoints(test_basis, &test_nqpts);
MFEM_VERIFY(trial_nqpts == test_nqpts,
"Trial and test basis must have the same number of quadrature"
" points.");
CeedInt nqpts = trial_nqpts;
const int qdatasize = op.qdatasize;
InitStridedRestriction(*mesh_fes, nelem, nqpts, qdatasize,
CEED_STRIDES_BACKEND,
&restr_i);
InitVector(*mesh.GetNodes(), node_coords);
CeedVectorCreate(ceed, nelem * nqpts * qdatasize, &qdata);
// Context data to be passed to the Q-function.
info.ctx.dim = mesh.Dimension();
info.ctx.space_dim = mesh.SpaceDimension();
info.ctx.vdim = trial_fes.GetVDim();
std::string qf_file = GetCeedPath() + op.header;
std::string qf = qf_file + op.build_func;
CeedQFunctionCreateInterior(ceed, 1, op.build_qf, qf.c_str(),
&build_qfunc);
// Create the Q-function that builds the operator (i.e. computes its
// quadrature data) and set its context data.
if (VariableCoefficient *var_coeff =
dynamic_cast<VariableCoefficient*>(coeff))
{
CeedQFunctionAddInput(build_qfunc, "coeff", coeff->ncomp,
var_coeff->emode);
}
CeedQFunctionAddInput(build_qfunc, "dx", dim * dim, CEED_EVAL_GRAD);
CeedQFunctionAddInput(build_qfunc, "weights", 1, CEED_EVAL_WEIGHT);
CeedQFunctionAddOutput(build_qfunc, "qdata", qdatasize, CEED_EVAL_NONE);
CeedQFunctionContextCreate(ceed, &build_ctx);
CeedQFunctionContextSetData(build_ctx, CEED_MEM_HOST,
CEED_COPY_VALUES,
sizeof(info.ctx),
&info.ctx);
CeedQFunctionSetContext(build_qfunc, build_ctx);
// Create the operator that builds the quadrature data for the operator.
CeedOperatorCreate(ceed, build_qfunc, NULL, NULL, &build_oper);
if (GridCoefficient *gridCoeff = dynamic_cast<GridCoefficient*>(coeff))
{
InitBasisAndRestriction(*gridCoeff->gf.FESpace(), ir,
nelem, indices, ceed,
&gridCoeff->basis,
&gridCoeff->restr);
CeedOperatorSetField(build_oper, "coeff", gridCoeff->restr,
gridCoeff->basis, gridCoeff->coeffVector);
}
else if (QuadCoefficient *quadCoeff =
dynamic_cast<QuadCoefficient*>(coeff))
{
const int ncomp = quadCoeff->ncomp;
CeedInt strides[3] = {ncomp, 1, ncomp*nqpts};
InitStridedRestriction(*mesh.GetNodalFESpace(),
nelem, nqpts, ncomp, strides,
&quadCoeff->restr);
CeedOperatorSetField(build_oper, "coeff", quadCoeff->restr,
CEED_BASIS_NONE, quadCoeff->coeffVector);
}
CeedOperatorSetField(build_oper, "dx", mesh_restr,
mesh_basis, CEED_VECTOR_ACTIVE);
CeedOperatorSetField(build_oper, "weights", CEED_ELEMRESTRICTION_NONE,
mesh_basis, CEED_VECTOR_NONE);
CeedOperatorSetField(build_oper, "qdata", restr_i,
CEED_BASIS_NONE, CEED_VECTOR_ACTIVE);
// Compute the quadrature data for the operator.
CeedOperatorApply(build_oper, node_coords, qdata, CEED_REQUEST_IMMEDIATE);
// Create the Q-function that defines the action of the operator.
qf = qf_file + op.apply_func;
CeedQFunctionCreateInterior(ceed, 1, op.apply_qf, qf.c_str(),
&apply_qfunc);
// input
switch (op.trial_op)
{
case EvalMode::None:
CeedQFunctionAddInput(apply_qfunc, "u", trial_vdim, CEED_EVAL_NONE);
break;
case EvalMode::Interp:
CeedQFunctionAddInput(apply_qfunc, "u", trial_vdim, CEED_EVAL_INTERP);
break;
case EvalMode::Grad:
CeedQFunctionAddInput(apply_qfunc, "gu", trial_vdim*dim, CEED_EVAL_GRAD);
break;
case EvalMode::InterpAndGrad:
CeedQFunctionAddInput(apply_qfunc, "u", trial_vdim, CEED_EVAL_INTERP);
CeedQFunctionAddInput(apply_qfunc, "gu", trial_vdim*dim, CEED_EVAL_GRAD);
break;
}
// qdata
CeedQFunctionAddInput(apply_qfunc, "qdata", qdatasize, CEED_EVAL_NONE);
// output
switch (op.test_op)
{
case EvalMode::None:
CeedQFunctionAddOutput(apply_qfunc, "v", test_vdim, CEED_EVAL_NONE);
break;
case EvalMode::Interp:
CeedQFunctionAddOutput(apply_qfunc, "v", test_vdim, CEED_EVAL_INTERP);
break;
case EvalMode::Grad:
CeedQFunctionAddOutput(apply_qfunc, "gv", test_vdim*dim, CEED_EVAL_GRAD);
break;
case EvalMode::InterpAndGrad:
CeedQFunctionAddOutput(apply_qfunc, "v", test_vdim, CEED_EVAL_INTERP);
CeedQFunctionAddOutput(apply_qfunc, "gv", test_vdim*dim, CEED_EVAL_GRAD);
break;
}
CeedQFunctionSetContext(apply_qfunc, build_ctx);
// Create the operator.
CeedOperatorCreate(ceed, apply_qfunc, NULL, NULL, &oper);
// input
switch (op.trial_op)
{
case EvalMode::None:
CeedOperatorSetField(oper, "u", trial_restr,
CEED_BASIS_NONE, CEED_VECTOR_ACTIVE);
break;
case EvalMode::Interp:
CeedOperatorSetField(oper, "u", trial_restr, trial_basis, CEED_VECTOR_ACTIVE);
break;
case EvalMode::Grad:
CeedOperatorSetField(oper, "gu", trial_restr, trial_basis, CEED_VECTOR_ACTIVE);
break;
case EvalMode::InterpAndGrad:
CeedOperatorSetField(oper, "u", trial_restr, trial_basis, CEED_VECTOR_ACTIVE);
CeedOperatorSetField(oper, "gu", trial_restr, trial_basis, CEED_VECTOR_ACTIVE);
break;
}
// qdata
CeedOperatorSetField(oper, "qdata", restr_i, CEED_BASIS_NONE,
qdata);
// output
switch (op.test_op)
{
case EvalMode::None:
CeedOperatorSetField(oper, "v", test_restr,
CEED_BASIS_NONE, CEED_VECTOR_ACTIVE);
break;
case EvalMode::Interp:
CeedOperatorSetField(oper, "v", test_restr, test_basis, CEED_VECTOR_ACTIVE);
break;
case EvalMode::Grad:
CeedOperatorSetField(oper, "gv", test_restr, test_basis, CEED_VECTOR_ACTIVE);
break;
case EvalMode::InterpAndGrad:
CeedOperatorSetField(oper, "v", test_restr, test_basis, CEED_VECTOR_ACTIVE);
CeedOperatorSetField(oper, "gv", test_restr, test_basis, CEED_VECTOR_ACTIVE);
break;
}
CeedVectorCreate(ceed, trial_vdim*trial_fes.GetNDofs(), &u);
CeedVectorCreate(ceed, test_vdim*test_fes.GetNDofs(), &v);
}
virtual ~PAIntegrator()
{
CeedQFunctionDestroy(&build_qfunc);
CeedQFunctionDestroy(&apply_qfunc);
CeedQFunctionContextDestroy(&build_ctx);
CeedVectorDestroy(&node_coords);
CeedVectorDestroy(&qdata);
delete coeff;
CeedOperatorDestroy(&build_oper);
}
private:
/** This structure contains the data to assemble a partially assembled
operator with libCEED. */
struct PAOperator
{
/** The number of quadrature data at each quadrature point. */
int qdatasize;
/** The path to the header containing the functions for libCEED. */
std::string header;
/** The name of the Qfunction to build the quadrature data. */
std::string build_func;
/** The Qfunction to build the quadrature data. */
CeedQFunctionUser build_qf;
/** The name of the Qfunction to apply the operator. */
std::string apply_func;
/** The Qfunction to apply the operator. */
CeedQFunctionUser apply_qf;
/** The evaluation mode to apply to the trial function (CEED_EVAL_INTERP,
CEED_EVAL_GRAD, etc.) */
EvalMode trial_op;
/** The evaluation mode to apply to the test function ( CEED_EVAL_INTERP,
CEED_EVAL_GRAD, etc.)*/
EvalMode test_op;
};
#endif
};
/** This class represent a matrix-free operator using libCEED. */
class MFIntegrator : public ceed::Operator
{
#ifdef MFEM_USE_CEED
protected:
CeedBasis trial_basis, test_basis, mesh_basis;
CeedElemRestriction trial_restr, test_restr, mesh_restr, restr_i;
CeedQFunction apply_qfunc;
CeedVector node_coords, qdata;
Coefficient *coeff;
CeedQFunctionContext build_ctx;
public:
MFIntegrator()
: Operator(),
trial_basis(nullptr), test_basis(nullptr), mesh_basis(nullptr),
trial_restr(nullptr), test_restr(nullptr), mesh_restr(nullptr),
restr_i(nullptr),
apply_qfunc(nullptr), node_coords(nullptr),
qdata(nullptr), coeff(nullptr), build_ctx(nullptr) { }
/** @brief This method assembles the `MFIntegrator` with the given
`CeedOperatorInfo` @a info, an `mfem::FiniteElementSpace` @a fes, an
`mfem::IntegrationRule` @a ir, and `mfem::Coefficient` or
`mfem::VectorCoefficient` @a Q.
The `CeedOperatorInfo` type is expected to inherit from `OperatorInfo`,
and contain a `Context` type relevant to the qFunctions.
@param[in] info is the structure describing the CeedOperator to assemble.
@param[in] fes is the finite element space.
@param[in] ir is the integration rule for the operator.
@param[in] Q is the coefficient from the `Integrator`. */
template <typename CeedOperatorInfo, typename CoeffType>
void Assemble(CeedOperatorInfo &info,
const mfem::FiniteElementSpace &fes,
const mfem::IntegrationRule &ir,
CoeffType *Q)
{
Assemble(info, fes, ir, fes.GetNE(), nullptr, Q);
}
/** @brief This method assembles the `MFIntegrator` with the given
`CeedOperatorInfo` @a info, an `mfem::FiniteElementSpace` @a fes, an
`mfem::IntegrationRule` @a ir, and `mfem::Coefficient` or
`mfem::VectorCoefficient` @a Q for the elements given by the indices
@a indices.
The `CeedOperatorInfo` type is expected to inherit from `OperatorInfo`,
and contain a `Context` type relevant to the qFunctions.
@param[in] info is the structure describing the CeedOperator to assemble.
@param[in] fes is the finite element space.
@param[in] ir is the integration rule for the operator.
@param[in] nelem The number of elements.
@param[in] indices The indices of the elements of same type in the
`FiniteElementSpace`. If `indices == nullptr`, assumes
that the `FiniteElementSpace` is not mixed.
@param[in] Q is the coefficient from the `Integrator`. */
template <typename CeedOperatorInfo, typename CoeffType>
void Assemble(CeedOperatorInfo &info,
const mfem::FiniteElementSpace &fes,
const mfem::IntegrationRule &ir,
int nelem,
const int* indices,
CoeffType *Q)
{
Assemble(info, fes, fes, ir, nelem, indices, Q);
}
/** This method assembles the MFIntegrator for mixed forms.
@param[in] info the `CeedOperatorInfo` describing the `CeedOperator`,
the `CeedOperatorInfo` type is expected to inherit from
`OperatorInfo` and contain a `Context` type relevant to
the qFunctions.
@param[in] trial_fes the trial `FiniteElementSpace` for the form,
@param[in] test_fes the test `FiniteElementSpace` for the form,
@param[in] ir the `IntegrationRule` for the numerical integration,
@param[in] Q `Coefficient` or `VectorCoefficient`. */
template <typename CeedOperatorInfo, typename CoeffType>
void Assemble(CeedOperatorInfo &info,
const mfem::FiniteElementSpace &trial_fes,
const mfem::FiniteElementSpace &test_fes,
const mfem::IntegrationRule &ir,
CoeffType *Q)
{
Assemble(info, trial_fes, test_fes, ir, trial_fes.GetNE(), nullptr, Q);
}
/** This method assembles the MFIntegrator for mixed forms.
@param[in] info the `CeedOperatorInfo` describing the `CeedOperator`,
the `CeedOperatorInfo` type is expected to inherit from
`OperatorInfo` and contain a `Context` type relevant to
the qFunctions.
@param[in] trial_fes the trial `FiniteElementSpace` for the form,
@param[in] test_fes the test `FiniteElementSpace` for the form,
@param[in] ir the `IntegrationRule` for the numerical integration,
@param[in] nelem The number of elements,
@param[in] indices The indices of the elements of same type in the
`FiniteElementSpace`. If `indices == nullptr`, assumes
that the `FiniteElementSpace` is not mixed,
@param[in] Q `Coefficient` or `VectorCoefficient`. */
template <typename CeedOperatorInfo, typename CoeffType>
void Assemble(CeedOperatorInfo &info,
const mfem::FiniteElementSpace &trial_fes,
const mfem::FiniteElementSpace &test_fes,
const mfem::IntegrationRule &ir,
int nelem,
const int* indices,
CoeffType *Q)
{
Ceed ceed(internal::ceed);
Mesh &mesh = *trial_fes.GetMesh();
MFEM_VERIFY(!(!indices && mesh.GetNumGeometries(mesh.Dimension()) > 1),
"Use ceed::MixedIntegrator on mixed meshes.");
InitCoefficient(Q, mesh, ir, nelem, indices, coeff, info.ctx);
bool const_coeff = coeff->IsConstant();
std::string apply_func = const_coeff ? info.apply_func_mf_const
: info.apply_func_mf_quad;
CeedQFunctionUser apply_qf = const_coeff ? info.apply_qf_mf_const
: info.apply_qf_mf_quad;
MFOperator op {info.header,
apply_func, apply_qf,
info.trial_op,
info.test_op
};
CeedInt dim = mesh.SpaceDimension();
CeedInt trial_vdim = trial_fes.GetVDim();
CeedInt test_vdim = test_fes.GetVDim();
mesh.EnsureNodes();
if ( &trial_fes == &test_fes )
{
InitBasisAndRestriction(trial_fes, ir, nelem, indices, ceed,
&trial_basis, &trial_restr);
test_basis = trial_basis;
test_restr = trial_restr;
}
else
{
InitBasisAndRestriction(trial_fes, ir, nelem, indices, ceed,
&trial_basis, &trial_restr);
InitBasisAndRestriction(test_fes, ir, nelem, indices, ceed,
&test_basis, &test_restr);
}
const mfem::FiniteElementSpace *mesh_fes = mesh.GetNodalFESpace();
MFEM_VERIFY(mesh_fes, "the Mesh has no nodal FE space");
InitBasisAndRestriction(*mesh_fes, ir, nelem, indices, ceed, &mesh_basis,
&mesh_restr);
CeedInt trial_nqpts, test_nqpts;
CeedBasisGetNumQuadraturePoints(trial_basis, &trial_nqpts);
CeedBasisGetNumQuadraturePoints(trial_basis, &test_nqpts);
MFEM_VERIFY(trial_nqpts == test_nqpts,
"Trial and test basis must have the same number of quadrature"
" points.");
CeedInt nqpts = trial_nqpts;
InitVector(*mesh.GetNodes(), node_coords);
// Context data to be passed to the Q-function.
info.ctx.dim = mesh.Dimension();
info.ctx.space_dim = mesh.SpaceDimension();
info.ctx.vdim = trial_fes.GetVDim();
std::string qf_file = GetCeedPath() + op.header;
std::string qf = qf_file + op.apply_func;
CeedQFunctionCreateInterior(ceed, 1, op.apply_qf, qf.c_str(),
&apply_qfunc);
// Create the Q-function that builds the operator (i.e. computes its
// quadrature data) and set its context data.
if (VariableCoefficient *var_coeff =
dynamic_cast<VariableCoefficient*>(coeff))
{
CeedQFunctionAddInput(apply_qfunc, "coeff", coeff->ncomp,
var_coeff->emode);
}
// input
switch (op.trial_op)
{
case EvalMode::None:
CeedQFunctionAddInput(apply_qfunc, "u", trial_vdim,
CEED_EVAL_NONE);
break;
case EvalMode::Interp:
CeedQFunctionAddInput(apply_qfunc, "u", trial_vdim,
CEED_EVAL_INTERP);
break;
case EvalMode::Grad:
CeedQFunctionAddInput(apply_qfunc, "gu", trial_vdim*dim,
CEED_EVAL_GRAD);
break;
case EvalMode::InterpAndGrad:
CeedQFunctionAddInput(apply_qfunc, "u", trial_vdim,
CEED_EVAL_INTERP);
CeedQFunctionAddInput(apply_qfunc, "gu", trial_vdim*dim,
CEED_EVAL_GRAD);
break;
}
CeedQFunctionAddInput(apply_qfunc, "dx", dim * dim, CEED_EVAL_GRAD);
CeedQFunctionAddInput(apply_qfunc, "weights", 1, CEED_EVAL_WEIGHT);
// output
switch (op.test_op)
{
case EvalMode::None:
CeedQFunctionAddOutput(apply_qfunc, "v", test_vdim,
CEED_EVAL_NONE);
break;
case EvalMode::Interp:
CeedQFunctionAddOutput(apply_qfunc, "v", test_vdim,
CEED_EVAL_INTERP);
break;
case EvalMode::Grad:
CeedQFunctionAddOutput(apply_qfunc, "gv", test_vdim*dim,
CEED_EVAL_GRAD);
break;
case EvalMode::InterpAndGrad:
CeedQFunctionAddOutput(apply_qfunc, "v", test_vdim,
CEED_EVAL_INTERP);
CeedQFunctionAddOutput(apply_qfunc, "gv", test_vdim*dim,
CEED_EVAL_GRAD);
break;
}
CeedQFunctionContextCreate(ceed, &build_ctx);
CeedQFunctionContextSetData(build_ctx, CEED_MEM_HOST,
CEED_COPY_VALUES,
sizeof(info.ctx),
&info.ctx);
CeedQFunctionSetContext(apply_qfunc, build_ctx);
// Create the operator.
CeedOperatorCreate(ceed, apply_qfunc, NULL, NULL, &oper);
// coefficient
if (GridCoefficient *gridCoeff = dynamic_cast<GridCoefficient*>(coeff))
{
InitBasisAndRestriction(*gridCoeff->gf.FESpace(), ir, nelem, indices,
ceed, &gridCoeff->basis, &gridCoeff->restr);
CeedOperatorSetField(oper, "coeff", gridCoeff->restr,
gridCoeff->basis, gridCoeff->coeffVector);
}
else if (QuadCoefficient *quadCoeff =
dynamic_cast<QuadCoefficient*>(coeff))
{
const int ncomp = quadCoeff->ncomp;
CeedInt strides[3] = {ncomp, 1, ncomp*nqpts};
InitStridedRestriction(*mesh.GetNodalFESpace(),
nelem, nqpts, ncomp, strides,
&quadCoeff->restr);
CeedOperatorSetField(oper, "coeff", quadCoeff->restr,
CEED_BASIS_NONE, quadCoeff->coeffVector);
}
// input
switch (op.trial_op)
{
case EvalMode::None:
CeedOperatorSetField(oper, "u", trial_restr,
CEED_BASIS_NONE, CEED_VECTOR_ACTIVE);
break;
case EvalMode::Interp:
CeedOperatorSetField(oper, "u", trial_restr, trial_basis,
CEED_VECTOR_ACTIVE);
break;
case EvalMode::Grad:
CeedOperatorSetField(oper, "gu", trial_restr, trial_basis,
CEED_VECTOR_ACTIVE);
break;
case EvalMode::InterpAndGrad:
CeedOperatorSetField(oper, "u", trial_restr, trial_basis,
CEED_VECTOR_ACTIVE);
CeedOperatorSetField(oper, "gu", trial_restr, trial_basis,
CEED_VECTOR_ACTIVE);
break;
}
CeedOperatorSetField(oper, "dx", mesh_restr,
mesh_basis, node_coords);
CeedOperatorSetField(oper, "weights", CEED_ELEMRESTRICTION_NONE,
mesh_basis, CEED_VECTOR_NONE);
// output
switch (op.test_op)
{
case EvalMode::None:
CeedOperatorSetField(oper, "v", test_restr,
CEED_BASIS_NONE, CEED_VECTOR_ACTIVE);
break;
case EvalMode::Interp:
CeedOperatorSetField(oper, "v", test_restr, test_basis,
CEED_VECTOR_ACTIVE);
break;
case EvalMode::Grad:
CeedOperatorSetField(oper, "gv", test_restr, test_basis,
CEED_VECTOR_ACTIVE);
break;
case EvalMode::InterpAndGrad:
CeedOperatorSetField(oper, "v", test_restr, test_basis,
CEED_VECTOR_ACTIVE);
CeedOperatorSetField(oper, "gv", test_restr, test_basis,
CEED_VECTOR_ACTIVE);
break;
}
CeedVectorCreate(ceed, trial_vdim*trial_fes.GetNDofs(), &u);
CeedVectorCreate(ceed, test_vdim*test_fes.GetNDofs(), &v);
}
virtual ~MFIntegrator()
{
CeedQFunctionDestroy(&apply_qfunc);
CeedQFunctionContextDestroy(&build_ctx);
CeedVectorDestroy(&node_coords);
CeedVectorDestroy(&qdata);
delete coeff;
}
private:
/** This structure contains the data to assemble a matrix-free operator with
libCEED. */
struct MFOperator
{
/** The path to the header containing the functions for libCEED. */
std::string header;
/** The name of the Qfunction to apply the operator. */
std::string apply_func;
/** The Qfunction to apply the operator. */
CeedQFunctionUser apply_qf;
/** The evaluation mode to apply to the trial function (CEED_EVAL_INTERP,
CEED_EVAL_GRAD, etc.) */
EvalMode trial_op;
/** The evaluation mode to apply to the test function ( CEED_EVAL_INTERP,
CEED_EVAL_GRAD, etc.) */
EvalMode test_op;
};
#endif
};
} // namespace ceed
} // namespace mfem
#endif // MFEM_LIBCEED_INTEG