v0.16.0
Loading...
Searching...
No Matches
dg_projection.cpp
Go to the documentation of this file.
1/**
2 * @file dg_projection.cpp
3 * @example mofem/atom_tests/dg_projection.cpp
4 *
5 * @brief Testing Discontinuous Galerkin (DG) projection operators
6 *
7 * This test validates the accuracy of DG projection algorithms used to
8 * represent functions on finite element meshes. The projection process
9 * involves solving local least-squares problems to find the best
10 * approximation of a given function in the finite element space.
11 *
12 * Mathematical background:
13 * - DG projection finds coefficients c_i such that ∑c_i φ_i minimizes
14 * ||u - ∑c_i φ_i||_{L2} where u is the target function and φ_i are basis functions
15 * - This leads to the normal equation: M c = f, where M is the mass matrix
16 * and f is the load vector from projecting the target function
17 * - The test verifies that the projection accurately represents a polynomial
18 * function that should be exactly representable in the chosen finite element space
19 *
20 * Test workflow:
21 * 1. Setup finite element space with polynomial basis functions
22 * 2. Assemble mass matrix and load vector for the projection problem
23 * 3. Solve the projection system to get approximation coefficients
24 * 4. Evaluate the projected function and compare with analytical values
25 */
26
27#include <MoFEM.hpp>
28
29using namespace MoFEM;
30
31static char help[] = "DG Projection Test - validates discontinuous Galerkin "
32 "projection accuracy\n\n";
33
34constexpr char FIELD_NAME[] = "U";
35constexpr int BASE_DIM = 1;
36constexpr int FIELD_DIM = 1;
37constexpr int SPACE_DIM = 2;
38constexpr int order = 2;
39
40template <int DIM> struct ElementsAndOps {};
41
42template <> struct ElementsAndOps<2> {
45};
46
48using DomainEleOp = DomainEle::UserDataOperator;
50
51auto fun = [](const double x, const double y, const double z) {
52 return x + y + x * x + y * y;
53};
54
57
60
61struct AtomTest {
62
63 AtomTest(MoFEM::Interface &m_field) : mField(m_field) {}
64
66
67private:
70
76
77 struct CommonData {
78 boost::shared_ptr<MatrixDouble> invJacPtr;
79 boost::shared_ptr<VectorDouble> approxVals;
80 boost::shared_ptr<MatrixDouble> approxGradVals;
81 boost::shared_ptr<MatrixDouble> approxHessianVals;
83 };
84
85 struct OpError;
86};
87
88struct AtomTest::OpError : public DomainEleOp {
89 boost::shared_ptr<CommonData> commonDataPtr;
90
91 OpError(boost::shared_ptr<MatrixDouble> data_ptr)
92 : DomainEleOp(NOSPACE, OPSPACE), dataPtr(data_ptr) {}
93
94 MoFEMErrorCode doWork(int side, EntityType type, EntData &data) {
96
97 const int nb_integration_pts = getGaussPts().size2();
98
99 auto t_val = getFTensor1FromMat<1>(*(dataPtr));
100 auto t_coords = getFTensor1CoordsAtGaussPts();
101
102 for (int gg = 0; gg != nb_integration_pts; ++gg) {
103
104 double projected_value = t_val(0);
105 double analytical_value = fun(t_coords(0), t_coords(1), t_coords(2));
106 double error = projected_value - analytical_value;
107
108 constexpr double eps = 1e-8;
109 if (std::abs(error) > eps) {
110 MOFEM_LOG("SELF", Sev::error)
111 << "Projection error too large: " << error << " at point ("
112 << t_coords(0) << ", " << t_coords(1) << ")"
113 << " projected=" << projected_value
114 << " analytical=" << analytical_value;
115 SETERRQ(PETSC_COMM_SELF, MOFEM_ATOM_TEST_INVALID,
116 "DG projection failed accuracy test");
117 }
118
119 ++t_val;
120 ++t_coords;
121 }
122
123 MOFEM_LOG("SELF", Sev::noisy) << "DG projection accuracy validation passed";
124
126 }
127
128private:
129 boost::shared_ptr<MatrixDouble> dataPtr;
130};
131
132//! [Run programme]
141}
142//! [Run programme]
143
144//! [Read mesh]
147
149
151
153
155}
156//! [Read mesh]
157
158//! [Set up problem]
161
164
166
168
170}
171//! [Set up problem]
172
173//! [Push operators to pipeline]
176
177 auto rule = [](int, int, int p) -> int { return 2 * p; };
178
180
181 CHKERR pipeline_mng->setDomainLhsIntegrationRule(rule);
182 CHKERR pipeline_mng->setDomainRhsIntegrationRule(rule);
183
184 auto beta = [](const double, const double, const double) { return 1; };
185
186 pipeline_mng->getOpDomainLhsPipeline().push_back(
188
189 pipeline_mng->getOpDomainRhsPipeline().push_back(
191
193}
194//! [Push operators to pipeline]
195
196//! [Solve]
200
201 MOFEM_LOG("WORLD", Sev::inform) << "Solving DG projection system";
202
203 auto solver = pipeline_mng->createKSP();
204 CHKERR KSPSetFromOptions(solver);
205 CHKERR KSPSetUp(solver);
206
207 auto dm = simpleInterface->getDM();
208 auto D = createDMVector(dm);
209 auto F = vectorDuplicate(D);
210
211 CHKERR KSPSolve(solver, F, D);
212
213 CHKERR VecGhostUpdateBegin(D, INSERT_VALUES, SCATTER_FORWARD);
214 CHKERR VecGhostUpdateEnd(D, INSERT_VALUES, SCATTER_FORWARD);
215
216 CHKERR DMoFEMMeshToLocalVector(dm, D, INSERT_VALUES, SCATTER_REVERSE);
217
219}
220//! [Solve]
221
222//! [Check results]
226 auto pipeline_mng = mField.getInterface<PipelineManager>();
227
228 pipeline_mng->getDomainLhsFE().reset();
229 pipeline_mng->getDomainRhsFE().reset();
230 pipeline_mng->getOpDomainRhsPipeline().clear();
231
232 auto rule = [](int, int, int p) -> int { return 2 * p + 1; };
233 CHKERR pipeline_mng->setDomainRhsIntegrationRule(rule);
234
235 auto entity_data_l2 = boost::make_shared<EntitiesFieldData>(MBENTITYSET);
236
237 auto mass_ptr = boost::make_shared<MatrixDouble>();
238 auto coeffs_ptr = boost::make_shared<MatrixDouble>();
239 auto data_ptr = boost::make_shared<MatrixDouble>();
240
241 auto op_this =
242 new OpLoopThis<DomainEle>(mField, simple->getDomainFEName(), Sev::noisy);
243 pipeline_mng->getOpDomainRhsPipeline().push_back(op_this);
244
245 pipeline_mng->getOpDomainRhsPipeline().push_back(new OpDGProjectionEvaluation(
246 data_ptr, coeffs_ptr, entity_data_l2, AINSWORTH_LEGENDRE_BASE, L2));
247
248 pipeline_mng->getOpDomainRhsPipeline().push_back(new OpError(data_ptr));
249
250 auto fe_physics_ptr = op_this->getThisFEPtr();
251 fe_physics_ptr->getRuleHook = [](int, int, int p) { return 2 * p; };
252
253 fe_physics_ptr->getOpPtrVector().push_back(new OpDGProjectionMassMatrix(
254 order, mass_ptr, entity_data_l2, AINSWORTH_LEGENDRE_BASE, L2));
255
256 fe_physics_ptr->getOpPtrVector().push_back(
258
259 fe_physics_ptr->getOpPtrVector().push_back(new OpDGProjectionCoefficients(
260 data_ptr, coeffs_ptr, mass_ptr, entity_data_l2, AINSWORTH_LEGENDRE_BASE,
261 L2, Sev::noisy));
262
263 CHKERR pipeline_mng->loopFiniteElements();
264
266}
267//! [Check results]
268
269int main(int argc, char *argv[]) {
270
271 MoFEM::Core::Initialize(&argc, &argv, NULL, help);
272
273 try {
274
275 //! [Register MoFEM discrete manager in PETSc]
276 DMType dm_name = "DMMOFEM";
277 CHKERR DMRegister_MoFEM(dm_name);
278 //! [Register MoFEM discrete manager in PETSc]
279
280 //! [Create MoAB]
281 moab::Core mb_instance;
282 moab::Interface &moab = mb_instance;
283 //! [Create MoAB]
284
285 //! [Create MoFEM]
286 MoFEM::Core core(moab);
287 MoFEM::Interface &m_field = core;
288 //! [Create MoFEM]
289
290 //! [Execute DG Projection Test]
291 AtomTest ex(m_field);
292 CHKERR ex.runProblem();
293 //! [Execute DG Projection Test]
294 }
296
298}
std::string type
void simple(double P1[], double P2[], double P3[], double c[], const int N)
Definition acoustic.cpp:69
int main()
static const double eps
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::LinearForm< GAUSS >::OpSource< 1, FIELD_DIM > OpDomainSource
ElementsAndOps< SPACE_DIM >::DomainEle DomainEle
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::BiLinearForm< GAUSS >::OpMass< 1, FIELD_DIM > OpDomainMass
#define CATCH_ERRORS
Catch errors.
@ AINSWORTH_LEGENDRE_BASE
Ainsworth Cole (Legendre) approx. base .
Definition definitions.h:60
@ L2
field with C-1 continuity
Definition definitions.h:88
@ H1
continuous field
Definition definitions.h:85
@ NOSPACE
Definition definitions.h:83
#define MoFEMFunctionBegin
First executable line of each MoFEM function, used for error handling. Final line of MoFEM functions ...
@ MOFEM_ATOM_TEST_INVALID
Definition definitions.h:40
#define MoFEMFunctionReturn(a)
Last executable line of each PETSc function used for error handling. Replaces return()
#define CHKERR
Inline error check.
static char help[]
constexpr char FIELD_NAME[]
auto fun
constexpr int SPACE_DIM
constexpr int FIELD_DIM
constexpr int BASE_DIM
constexpr int order
@ F
PetscErrorCode DMoFEMMeshToLocalVector(DM dm, Vec l, InsertMode mode, ScatterMode scatter_mode, RowColData rc=RowColData::COL)
set local (or ghosted) vector values on mesh for partition only
Definition DMMoFEM.cpp:514
PetscErrorCode DMRegister_MoFEM(const char sname[])
Register MoFEM problem.
Definition DMMoFEM.cpp:43
auto createDMVector(DM dm, RowColData rc=RowColData::COL)
Get smart vector from DM.
Definition DMMoFEM.hpp:1237
boost::ptr_deque< UserDataOperator > & getOpDomainLhsPipeline()
Get the Op Domain Lhs Pipeline object.
SmartPetscObj< KSP > createKSP(SmartPetscObj< DM > dm=nullptr)
Create KSP (linear) solver.
boost::ptr_deque< UserDataOperator > & getOpDomainRhsPipeline()
Get the Op Domain Rhs Pipeline object.
@ PETSC
Standard PETSc assembly.
#define MOFEM_LOG(channel, severity)
Log.
constexpr char FIELD_NAME[]
auto fun
Function to approximate.
constexpr int FIELD_DIM
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::BiLinearForm< GAUSS >::OpMass< BASE_DIM, FIELD_DIM > OpDomainMass
OPerator to integrate mass matrix for least square approximation.
FormsIntegrators< DomainEleOp >::Assembly< PETSC >::LinearForm< GAUSS >::OpSource< BASE_DIM, FIELD_DIM > OpDomainSource
Operator to integrate the right hand side matrix for the problem.
double D
PetscErrorCode MoFEMErrorCode
MoFEM/PETSc error code.
implementation of Data Operators for Forces and Sources
Definition Common.hpp:10
SmartPetscObj< Vec > vectorDuplicate(Vec vec)
Create duplicate vector of smart vector.
Collected data use d by operator to evaluate errors for the test.
boost::shared_ptr< VectorDouble > approxVals
SmartPetscObj< Vec > L2Vec
boost::shared_ptr< MatrixDouble > invJacPtr
boost::shared_ptr< MatrixDouble > approxHessianVals
boost::shared_ptr< MatrixDouble > approxGradVals
Operator to evaluate errors.
boost::shared_ptr< CommonData > commonDataPtr
OpError(boost::shared_ptr< MatrixDouble > data_ptr)
boost::shared_ptr< MatrixDouble > dataPtr
MoFEMErrorCode doWork(int side, EntityType type, EntData &data)
Simple * simpleInterface
MoFEMErrorCode checkResults()
[Solve]
MoFEMErrorCode solveSystem()
AtomTest(MoFEM::Interface &m_field)
MoFEMErrorCode setupProblem()
MoFEMErrorCode readMesh()
MoFEMErrorCode assembleSystem()
MoFEM::Interface & mField
MoFEMErrorCode runProblem()
Core (interface) class.
Definition Core.hpp:83
static MoFEMErrorCode Initialize(int *argc, char ***args, const char file[], const char help[])
Initializes the MoFEM database PETSc, MOAB and MPI.
Definition Core.cpp:68
static MoFEMErrorCode Finalize()
Checks for options to be called at the conclusion of the program.
Definition Core.cpp:123
Deprecated interface functions.
Data on single entity (This is passed as argument to DataOperator::doWork)
Specialization for MatrixDouble vector field values calculation.
Evaluate field for given DG projection coefficients.
Evaluate right hand side for given data coefficients.
Execute "this" element in the operator.
PipelineManager interface.
MoFEM::FaceElementForcesAndSourcesCore FaceEle
MoFEMErrorCode setDomainRhsIntegrationRule(RuleHookFun rule)
Set integration rule for domain right-hand side finite element.
MoFEMErrorCode setDomainLhsIntegrationRule(RuleHookFun rule)
Set integration rule for domain left-hand side finite element.
Simple interface for fast problem set-up.
Definition Simple.hpp:27
MoFEMErrorCode addDomainField(const std::string name, const FieldSpace space, const FieldApproximationBase base, const FieldCoefficientsNumber nb_of_coefficients, const TagType tag_type=MB_TAG_SPARSE, const enum MoFEMTypes bh=MF_ZERO, int verb=-1)
Add field on domain.
Definition Simple.cpp:261
MoFEMErrorCode loadFile(const std::string options, const std::string mesh_file_name, LoadFileFunc loadFunc=defaultLoadFileFunc)
Load mesh file.
Definition Simple.cpp:191
MoFEMErrorCode getOptions()
get options
Definition Simple.cpp:180
MoFEMErrorCode getDM(DM *dm)
Get DM.
Definition Simple.cpp:799
MoFEMErrorCode setFieldOrder(const std::string field_name, const int order, const Range *ents=NULL)
Set field order.
Definition Simple.cpp:575
MoFEMErrorCode setUp(const PetscBool is_partitioned=PETSC_TRUE)
Setup problem.
Definition Simple.cpp:735
intrusive_ptr for managing petsc objects
MoFEMErrorCode getInterface(IFACE *&iface) const
Get interface reference to pointer of interface.