LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
primal_dpg_adapted_norm.h
1
9#ifndef PROJECTS_DPG_CS_PRIMAL_DPG_AN_H
10#define PROJECTS_DPG_CS_PRIMAL_DPG_AN_H
11
12#include <lf/base/base.h>
13#include <lf/fe/fe.h>
14#include <lf/io/io.h>
15#include <lf/mesh/test_utils/test_meshes.h>
16#include <lf/mesh/utils/utils.h>
17#include <lf/refinement/refinement.h>
18#include <lf/uscalfe/uscalfe.h>
19
20#include "../dpg_element_matrix_provider.h"
21#include "../dpg_element_vector_provider.h"
22#include "../product_element_matrix_provider_builder.h"
23#include "../product_element_vector_provider_builder.h"
24#include "../product_fe_space.h"
25#include "../product_fe_space_factory.h"
26#include "../test/convection_diffusion_ell_bvp.h"
27
28// utility type to return the reported energy norms.
29// we return: number of dofs, H1-error, error estimator.
30using energy_vector = std::vector<std::tuple<int, double, double>>;
31
32namespace projects::dpg::test {
54template <typename SOLFUNC, typename SOLGRAD, typename ALPHAFUNC,
55 typename BETAFUNC, typename FFUNC, typename GFUNC>
56energy_vector
58 size_type reflevels, SOLFUNC solution, SOLGRAD sol_grad, ALPHAFUNC alpha,
59 BETAFUNC beta, FFUNC f, GFUNC g, int degree_p, int enrichement,
60 lf::base::RefEl ref_el) {
61 std::vector<std::tuple<int, double, double>> errnorms{};
62 std::cout << "Approximation order: " << degree_p
63 << ", Enrichement: " << enrichement << std::endl;
64
65 // calculate degree for enriched spaces
66 int degree_r = degree_p + enrichement;
67
68 // generate a tensor product mesh based on the provided reference element.
69 std::shared_ptr<lf::mesh::Mesh> top_mesh;
70 std::unique_ptr<lf::mesh::MeshFactory> mesh_factory_ptr =
71 std::make_unique<lf::mesh::hybrid2d::MeshFactory>(2);
72 switch (ref_el) {
74 // construct a triangular tensor product mesh
75 lf::mesh::utils::TPTriagMeshBuilder builder(std::move(mesh_factory_ptr));
76 builder.setBottomLeftCorner(Eigen::Vector2d{0.0, 0.0})
77 .setTopRightCorner(Eigen::Vector2d{1.0, 1.0})
78 .setNumXCells(2)
79 .setNumYCells(2);
80 top_mesh = builder.Build();
81 break;
82 }
83
85 lf::mesh::utils::TPQuadMeshBuilder builder(std::move(mesh_factory_ptr));
86 builder.setBottomLeftCorner(Eigen::Vector2d{0.0, 0.0})
87 .setTopRightCorner(Eigen::Vector2d{1.0, 1.0})
88 .setNumXCells(2)
89 .setNumYCells(2);
90 top_mesh = builder.Build();
91 break;
92 }
93 default: {
94 LF_ASSERT_MSG(false, "unsupported reference element:" << ref_el);
95 break;
96 }
97 }
98
99 // Generate a hierarchy of test meshes by uniform refinement
100 std::shared_ptr<lf::refinement::MeshHierarchy> multi_mesh_p =
102 reflevels);
103 lf::refinement::MeshHierarchy& multi_mesh{*multi_mesh_p};
104 multi_mesh.PrintInfo(std::cout);
105
106 // get number of levels:
107 size_type L = multi_mesh.NumLevels();
108
109 // perform computations on all levels:
110 for (size_type l = 0; l < L; ++l) {
111 // retrive mesh for current level
112 std::shared_ptr<const lf::mesh::Mesh> mesh_p{multi_mesh.getMesh(l)};
113
114 // construct trial space:
115 ProductUniformFESpaceFactory<double> factory_trial(mesh_p);
116 auto u = factory_trial.AddH1Component(degree_p);
117 auto q_n = factory_trial.AddFluxComponent(degree_p - 1);
118 auto fe_space_trial = factory_trial.Build();
119
120 // construct test space:
121 ProductUniformFESpaceFactory<double> factory_test(mesh_p);
122 auto v = factory_test.AddL2Component(degree_r);
123 auto fe_space_test = factory_test.Build();
124
125 // wrap functions into a mesh function:
126 auto alpha_mf = lf::mesh::utils::MeshFunctionGlobal(alpha);
127 auto beta_mf = lf::mesh::utils::MeshFunctionGlobal(beta);
129 auto one_mf = lf::mesh::utils::MeshFunctionConstant(1.0);
130 auto zero_mf =
131 lf::mesh::utils::MeshFunctionConstant(Eigen::Vector2d(0.0, 0.0));
132
133 // construct extended stiffness provider
134 ProductElementMatrixProviderBuilder stiffness_builder(fe_space_trial,
135 fe_space_test);
136 stiffness_builder.AddDiffusionElementMatrixProvider(u, v, alpha_mf);
137 stiffness_builder.AddFluxElementMatrixProvider(q_n, v, -one_mf);
138 stiffness_builder.AddConvectionElementMatrixProvider(u, v, zero_mf,
139 beta_mf);
140 auto stiffness_provider = stiffness_builder.Build();
141
142 // construct gram matrix provider
143 auto alpha_squared_mf = lf::mesh::utils::MeshFunctionGlobal(
144 [alpha](const Eigen::Vector2d& x) { return alpha(x) * alpha(x); });
145 ProductElementMatrixProviderBuilder gramian_builder(fe_space_test,
146 fe_space_test);
147 gramian_builder.AddDiffusionElementMatrixProvider(v, v, alpha_squared_mf);
148 gramian_builder.AddReactionElementMatrixProvider(v, v, one_mf);
149 auto gramian_provider = gramian_builder.Build();
150
151 // construct the rhs provider:
152 ProductElementVectorProviderBuilder rhs_builder(fe_space_test);
153 rhs_builder.AddLoadElementVectorProvider(v, f_mf);
154 auto rhs_provider = rhs_builder.Build();
155
156 // initialize the dpg providers:
157 auto element_matrix_provider =
158 std::make_shared<DpgElementMatrixProvider<double>>(stiffness_provider,
159 gramian_provider);
160 auto element_vector_provider =
161 std::make_shared<DpgElementVectorProvider<double>>(
162 rhs_provider, stiffness_provider, gramian_provider);
163
164 // initialize the boundary value problem
165 auto h = [](const Eigen::Vector2d & /*x*/) -> double { return 0.0; };
166 auto dirichlet_selector = lf::mesh::utils::flagEntitiesOnBoundary(mesh_p);
167 auto bvp = std::make_shared<FullConvectionDiffusionBVP<
168 decltype(alpha), decltype(beta), decltype(f), decltype(g), decltype(h),
169 decltype(dirichlet_selector)>>(
170 FullConvectionDiffusionBVP(alpha, beta, f, g, h,
171 std::move(dirichlet_selector)));
172
173 // Assemble full system:
174 auto [A, phi] = ConvectionDiffusionDPGLinSys<double>(
175 fe_space_trial, element_matrix_provider, element_vector_provider, bvp,
176 u, q_n);
177
178 // calculate full solution
179 Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>> solver;
180 solver.compute(A);
181 Eigen::VectorXd sol_vec = solver.solve(phi);
182
183 // extract u component:
184 auto& dofh = fe_space_trial->LocGlobMap();
185 auto fe_space_u = fe_space_trial->ComponentFESpace(u);
186 Eigen::VectorXd sol_vec_u = sol_vec.head(dofh.NumDofs(u));
187
188 // wrap finite element solution and exact solution into a mesh function:
189 auto mf_fe_u = lf::fe::MeshFunctionFE(fe_space_u, sol_vec_u);
190 auto mf_fe_grad_u = lf::fe::MeshFunctionGradFE(fe_space_u, sol_vec_u);
191 auto mf_solution = lf::mesh::utils::MeshFunctionGlobal(solution);
192 auto mf_solution_grad = lf::mesh::utils::MeshFunctionGlobal(sol_grad);
193
194 // calculate the error in the H1 norm
195 double H1_err = std::sqrt(lf::fe::IntegrateMeshFunction(
196 *mesh_p,
197 lf::mesh::utils::squaredNorm(mf_fe_u - mf_solution) +
198 lf::mesh::utils::squaredNorm(mf_fe_grad_u - mf_solution_grad),
199 10));
200
201 // evaluate error estimators:
202 auto local_errors =
203 ElementErrorEstimators(fe_space_trial->LocGlobMap(), stiffness_provider,
204 gramian_provider, rhs_provider, sol_vec);
205 double posteriorError = EvalPosteriorError(mesh_p, local_errors);
206 std::cout << "Level " << l << " ( " << dofh.NumDofs() << ")"
207 << ", H1 error: " << H1_err << ", post:" << posteriorError
208 << std::endl;
209 errnorms.emplace_back(dofh.NumDofs(), H1_err, posteriorError);
210 }
211 return errnorms;
212}
213} // namespace projects::dpg::test
214
215#endif // PROJECTS_DPG_CS_PRIMAL_DPG_AN_H
Represents a reference element with all its properties.
Definition: ref_el.h:106
static constexpr RefEl kTria()
Returns the reference triangle.
Definition: ref_el.h:158
static constexpr RefEl kQuad()
Returns the reference quadrilateral.
Definition: ref_el.h:166
A MeshFunction which takes the same constant value on the whole mesh.
MeshFunction wrapper for a simple function of physical coordinates.
StructuredMeshBuilder & setBottomLeftCorner(const VECTOR &blc)
StructuredMeshBuilder & setNumYCells(size_type nyc)
Implements a Builder for a tensor product grid (with rectangular cells)
std::shared_ptr< mesh::Mesh > Build() override
actual construction of the mesh
Implements a MeshBuilder that generates a triangular structured mesh.
std::shared_ptr< mesh::Mesh > Build() override
actual construction of the mesh
A hierarchy of nested 2D hybrid meshes created by refinement.
std::ostream & PrintInfo(std::ostream &o, unsigned ctrl=0) const
Output of information about the mesh hierarchy.
Builder class to build a ProductElementMatrixProvider.
std::shared_ptr< ProductElementMatrixProvider< SCALAR > > Build()
Build the ProdcutElementMatrixProvider for the bilinear form based on the provided bilinear forms .
ProductElementMatrixProviderBuilder & AddFluxElementMatrixProvider(size_type trial_component, size_type test_component, DIFF_COEFF alpha)
ProductElementMatrixProviderBuilder & AddConvectionElementMatrixProvider(size_type trial_component, size_type test_component, CONVECTION_COEFF_1 beta_1, CONVECTION_COEFF_2 beta_2)
ProductElementMatrixProviderBuilder & AddDiffusionElementMatrixProvider(size_type trial_component, size_type test_component, DIFF_COEFF alpha)
Builder class to build a ProductElementVectorProvider.
ProductElementVectorProviderBuilder & AddLoadElementVectorProvider(size_type test_component, FUNCTOR f)
Adds a linear form to representing a simple load linear form.
std::shared_ptr< ProductElementVectorProvider< SCALAR > > Build()
Build the ProductElementVectorProvider based on the provided linear forms.
Factory class to build a ProductUniformFESpace.
size_type AddFluxComponent(size_type degree)
Adds a -conforming finite element to the space, that represents a flux on the mesh skeleton.
size_type AddH1Component(size_type degree)
Adds a -conforming finite element to the space.
size_type AddL2Component(size_type degree)
Adds a -conforming finite element to the space.
std::shared_ptr< ProductUniformFESpace< SCALAR > > Build()
Build the ProductUniformFespace based on the provided specifications.
MeshFunctionGradFE(std::shared_ptr< T >, const Eigen::Matrix< SCALAR_COEFF, Eigen::Dynamic, 1 > &) -> MeshFunctionGradFE< typename T::Scalar, SCALAR_COEFF >
MeshFunctionFE(std::shared_ptr< T >, const Eigen::Matrix< SCALAR_COEFF, Eigen::Dynamic, 1 > &) -> MeshFunctionFE< typename T::Scalar, SCALAR_COEFF >
auto IntegrateMeshFunction(const lf::mesh::Mesh &mesh, const MF &mf, const QR_SELECTOR &qr_selector, const ENTITY_PREDICATE &ep=base::PredicateTrue{}, int codim=0) -> mesh::utils::MeshFunctionReturnType< MF >
Integrate a MeshFunction over a mesh (with quadrature rules)
Definition: fe_tools.h:111
CodimMeshDataSet< bool > flagEntitiesOnBoundary(const std::shared_ptr< const Mesh > &mesh_p, lf::base::dim_t codim)
flag entities of a specific co-dimension located on the boundary
std::shared_ptr< MeshHierarchy > GenerateMeshHierarchyByUniformRefinemnt(const std::shared_ptr< lf::mesh::Mesh > &mesh_p, lf::base::size_type ref_lev, RefPat ref_pat)
Generated a sequence of nested 2D hybrid mehes by regular or barycentric refinement.
energy_vector TestConververgencePrimalDPGAdaptedNormConvectionDiffusionDirichletBVP(size_type reflevels, SOLFUNC solution, SOLGRAD sol_grad, ALPHAFUNC alpha, BETAFUNC beta, FFUNC f, GFUNC g, int degree_p, int enrichement, lf::base::RefEl ref_el)
Examines the convergence behaviour of the primal DPG method for a pure Dirichlet convection-diffusion...
lf::mesh::utils::CodimMeshDataSet< SCALAR > ElementErrorEstimators(const ProductUniformFEDofHandler &trial_dofh, std::shared_ptr< ProductElementMatrixProvider< SCALAR > > stiffness_provider, std::shared_ptr< ProductElementMatrixProvider< SCALAR > > gramian_provider, std::shared_ptr< ProductElementVectorProvider< SCALAR > > load_provider, const Eigen::Matrix< SCALAR, Eigen::Dynamic, 1 > &sol_vec)
Evaluation of the local DPG error estimators on a mesh.
Definition: dpg_tools.h:327
SCALAR EvalPosteriorError(const std::shared_ptr< const lf::mesh::Mesh > &mesh_p, const lf::mesh::utils::CodimMeshDataSet< SCALAR > &local_errors)
Evaluation of the DPG error estimator.
Definition: dpg_tools.h:374
lf::uscalfe::size_type size_type
Type for vector length/matrix sizes.
Definition: dpg.h:17