LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
hodge_laplacians_source_problems.h
1#ifndef HLDO_SPHERE_OPERATORS_HODGE_LAPLACIANS_SOURCE_PROBLEMS_H
2#define HLDO_SPHERE_OPERATORS_HODGE_LAPLACIANS_SOURCE_PROBLEMS_H
3
9#include <mass_matrix_provider.h>
10#include <whitney_one_hodge_laplacian.h>
11#include <whitney_one_mass_matrix_provider.h>
12#include <whitney_two_hodge_laplacian.h>
13#include <whitney_two_mass_matrix_provider.h>
14#include <whitney_zero_hodge_laplacian.h>
15
16#include <Eigen/Dense>
17#include <cmath>
18
19namespace projects::hldo_sphere {
20
21namespace operators {
22
33template <typename SCALAR>
35 public:
47 // create mesh factory for basic mesh
48 std::unique_ptr<lf::mesh::MeshFactory> factory =
49 std::make_unique<lf::mesh::hybrid2d::MeshFactory>(3);
50
51 std::shared_ptr<projects::hldo_sphere::mesh::SphereTriagMeshBuilder>
52 sphere = std::make_shared<
54 std::move(factory));
55 sphere->setRefinementLevel(0);
56 sphere->setRadius(1);
57
58 mesh_p_ = sphere->Build();
59
60 k_ = 1.;
61
62 // initialize matrix vector
63 coo_matrix_ = std::vector<lf::assemble::COOMatrix<SCALAR>>{
67
68 phi_ = std::vector<Eigen::Matrix<SCALAR, Eigen::Dynamic, 1>>(3);
69
70 mu_ = std::vector<Eigen::Matrix<SCALAR, Eigen::Dynamic, 1>>(3);
71
72 // create zero functions as default
73 auto f_0 = [](Eigen::Matrix<double, 3, 1> x) -> SCALAR { return 0; };
74 auto f_1 =
75 [](Eigen::Matrix<double, 3, 1> x) -> Eigen::Matrix<SCALAR, 3, 1> {
76 return Eigen::Matrix<double, 3, 1>::Zero();
77 };
78 auto f_2 = [](Eigen::Matrix<double, 3, 1> x) -> SCALAR { return 0; };
79 f0_ = f_0;
80 f1_ = f_1;
81 f2_ = f_2;
82 }
83
95 void Compute() {
96 //*****************
97 // Whitney 0 form
98 //*****************
99
100 // get the Hodge laplacian for the zero form and take the negative
102 zero_builder;
103 zero_builder.SetMesh(mesh_p_);
104 zero_builder.SetLoadFunction(f0_);
105 zero_builder.Compute();
106 lf::assemble::COOMatrix<SCALAR> coo_mat_zero_pos =
107 zero_builder.GetGalerkinMatrix();
108 lf::assemble::COOMatrix<SCALAR> coo_mat_zero(coo_mat_zero_pos.rows(),
109 coo_mat_zero_pos.cols());
110 coo_mat_zero.setZero();
111
112 for (Eigen::Triplet<SCALAR> triplet : coo_mat_zero_pos.triplets()) {
113 int col = triplet.col();
114 int row = triplet.row();
115 // we need the negative laplacian
116 SCALAR val = triplet.value();
117 coo_mat_zero.AddToEntry(row, col, val);
118 }
119
120 // create mass Matrix
121
123 mass_matrix_provider_zero;
124
125 const lf::assemble::DofHandler &dof_handler_zero =
127 {{lf::base::RefEl::kPoint(), 1}});
128 const lf::assemble::size_type n_dofs_zero(dof_handler_zero.NumDofs());
129
130 // prepare matrix
131 lf::assemble::COOMatrix<double> coo_mass_mat_zero(n_dofs_zero, n_dofs_zero);
132 coo_mass_mat_zero.setZero();
133
134 lf::assemble::AssembleMatrixLocally<lf::assemble::COOMatrix<double>>(
135 0, dof_handler_zero, dof_handler_zero, mass_matrix_provider_zero,
136 coo_mass_mat_zero);
137
138 // merge whitney zero for with k^2 * mass Matrix
139 for (Eigen::Triplet<double> triplet : coo_mass_mat_zero.triplets()) {
140 int row = triplet.row();
141 int col = triplet.col();
142 SCALAR val = k_ * k_ * triplet.value();
143 coo_mat_zero.AddToEntry(row, col, val);
144 };
145
146 coo_matrix_[0] = coo_mat_zero;
147
148 // get righthandside
149 Eigen::Matrix<SCALAR, Eigen::Dynamic, 1> phi_zero =
150 zero_builder.GetLoadVector();
151 phi_[0] = phi_zero;
152
153 //*****************
154 // Whitney 1 form
155 //*****************
156
157 // get the Hodge laplacian for the one form and take the negative
159 one_builder;
160 one_builder.SetMesh(mesh_p_);
161 one_builder.SetLoadFunction(f1_);
162 one_builder.Compute();
163 lf::assemble::COOMatrix<SCALAR> coo_mat_one_pos =
164 one_builder.GetGalerkinMatrix();
165 lf::assemble::COOMatrix<SCALAR> coo_mat_one(coo_mat_one_pos.rows(),
166 coo_mat_one_pos.cols());
167 coo_mat_one.setZero();
168
169 for (Eigen::Triplet<SCALAR> triplet : coo_mat_one_pos.triplets()) {
170 int col = triplet.col();
171 int row = triplet.row();
172 SCALAR val = triplet.value();
173 coo_mat_one.AddToEntry(row, col, val);
174 }
175
176 // create mass Matrix
178 mass_matrix_provider_one;
179 const lf::assemble::DofHandler &dof_handler_one =
182 const lf::assemble::size_type n_dofs_one(dof_handler_one.NumDofs());
183 lf::assemble::COOMatrix<double> coo_mass_mat_one(n_dofs_one, n_dofs_one);
184 coo_mass_mat_one.setZero();
185
186 lf::assemble::AssembleMatrixLocally<lf::assemble::COOMatrix<double>>(
187 0, dof_handler_one, dof_handler_one, mass_matrix_provider_one,
188 coo_mass_mat_one);
189
190 // merge whitney one for with k^2 * mass Matrix
191 for (Eigen::Triplet<double> triplet : coo_mass_mat_one.triplets()) {
192 int col = triplet.col();
193 int row = triplet.row();
194 SCALAR val = k_ * k_ * triplet.value();
195 coo_mat_one.AddToEntry(row, col, val);
196 }
197 coo_matrix_[1] = coo_mat_one;
198
199 // get righthandside
200 Eigen::Matrix<SCALAR, Eigen::Dynamic, 1> phi_one =
201 one_builder.GetLoadVector();
202 phi_[1] = phi_one;
203
204 //*****************
205 // Whitney 2 form
206 //*****************
207
208 // get the Hodge laplacian for the one form and take the negative
210 two_builder;
211 two_builder.SetMesh(mesh_p_);
212 two_builder.SetLoadFunction(f2_);
213 two_builder.Compute();
214
215 lf::assemble::COOMatrix<SCALAR> coo_mat_two_pos =
216 two_builder.GetGalerkinMatrix();
217 lf::assemble::COOMatrix<SCALAR> coo_mat_two(coo_mat_two_pos.rows(),
218 coo_mat_two_pos.cols());
219
220 coo_mat_two.setZero();
221 for (Eigen::Triplet<SCALAR> triplet : coo_mat_two_pos.triplets()) {
222 int col = triplet.col();
223 int row = triplet.row();
224 SCALAR val = triplet.value();
225 coo_mat_two.AddToEntry(row, col, val);
226 }
227
228 // create mass Matrix
230 mass_matrix_provider_two;
231 const lf::assemble::DofHandler &dof_handler_two =
233 {{lf::base::RefEl::kTria(), 1}});
234 const lf::assemble::size_type n_dofs_two(dof_handler_two.NumDofs());
235 lf::assemble::COOMatrix<double> coo_mass_mat_two(n_dofs_two, n_dofs_two);
236 coo_mass_mat_two.setZero();
237 lf::assemble::AssembleMatrixLocally<lf::assemble::COOMatrix<double>>(
238 0, dof_handler_two, dof_handler_two, mass_matrix_provider_two,
239 coo_mass_mat_two);
240
241 // merge whitney two for with k^2 * mass Matrix
242 for (Eigen::Triplet<double> triplet : coo_mass_mat_two.triplets()) {
243 // n_dofs_one contains the number of edges and hence the
244 // dimension of A_{11}
245 int col = triplet.col() + n_dofs_one;
246 int row = triplet.row() + n_dofs_one;
247 SCALAR val = k_ * k_ * triplet.value();
248 coo_mat_two.AddToEntry(row, col, val);
249 }
250
251 coo_matrix_[2] = coo_mat_two;
252
253 // get righthandside
254 Eigen::Matrix<SCALAR, Eigen::Dynamic, 1> phi_two =
255 two_builder.GetLoadVector();
256 phi_[2] = phi_two;
257 }
258
276 void Solve() {
277 Eigen::SparseLU<Eigen::SparseMatrix<SCALAR>> solver;
278 for (int l = 0; l < 3; l++) {
279 Eigen::SparseMatrix<SCALAR> sparse_mat = coo_matrix_[l].makeSparse();
280 solver.compute(sparse_mat);
281 if (solver.info() != Eigen::Success) {
282 throw std::runtime_error("Could not decompose the matrix");
283 }
284
285 mu_[l] = solver.solve(phi_[l]);
286 }
287 }
288
296 void SetMesh(std::shared_ptr<const lf::mesh::Mesh> mesh_p) {
297 // check if cells are triagles
298 for (const lf::mesh::Entity *tria : mesh_p->Entities(0)) {
299 LF_ASSERT_MSG(
300 tria->RefEl() == lf::base::RefEl::kTria(),
301 "Mesh must be Triangular, unsupported cell " << tria->RefEl());
302 }
303
304 // check if dimension of the mesh is 3
305 LF_ASSERT_MSG(mesh_p->DimWorld() == 3,
306 "World Dimension must be 3 but is" << mesh_p->DimWorld());
307
308 // set mesh
309 mesh_p_ = mesh_p;
310 }
311
319 std::function<SCALAR(const Eigen::Matrix<double, 3, 1> &)> &f0,
320 std::function<
321 Eigen::Matrix<SCALAR, 3, 1>(const Eigen::Matrix<double, 3, 1> &)> &f1,
322 std::function<SCALAR(const Eigen::Matrix<double, 3, 1> &)> &f2) {
323 f0_ = f0;
324 f1_ = f1;
325 f2_ = f2;
326 }
327
333 void SetK(double k) { k_ = k; }
334
344 Eigen::Matrix<SCALAR, Eigen::Dynamic, 1> GetLoadVector(int index) {
345 return phi_[index];
346 }
347
358 return coo_matrix_[index];
359 }
360
374 Eigen::Matrix<SCALAR, Eigen::Dynamic, 1> GetMuZero() { return mu_[0]; }
375
398 std::tuple<Eigen::Matrix<SCALAR, Eigen::Dynamic, 1>,
399 Eigen::Matrix<SCALAR, Eigen::Dynamic, 1>>
401 lf::base::size_type numPoints = mesh_p_->NumEntities(2);
402 lf::base::size_type numEdges = mesh_p_->NumEntities(1);
403 Eigen::Matrix<SCALAR, Eigen::Dynamic, 1> u = mu_[1].head(numEdges);
404 Eigen::Matrix<SCALAR, Eigen::Dynamic, 1> p = mu_[1].tail(numPoints);
405 return std::make_tuple(u, p);
406 }
407
431 std::tuple<Eigen::Matrix<SCALAR, Eigen::Dynamic, 1>,
432 Eigen::Matrix<SCALAR, Eigen::Dynamic, 1>>
434 lf::base::size_type numCells = mesh_p_->NumEntities(0);
435 lf::base::size_type numEdges = mesh_p_->NumEntities(1);
436 Eigen::Matrix<SCALAR, Eigen::Dynamic, 1> j = mu_[2].head(numEdges);
437 Eigen::Matrix<SCALAR, Eigen::Dynamic, 1> u = mu_[2].tail(numCells);
438 return std::make_tuple(j, u);
439 }
440
441 private:
442 std::shared_ptr<const lf::mesh::Mesh> mesh_p_;
443 std::function<SCALAR(const Eigen::Matrix<double, 3, 1> &)> f0_;
444 std::function<Eigen::Matrix<SCALAR, 3, 1>(
445 const Eigen::Matrix<double, 3, 1> &)>
447 std::function<SCALAR(const Eigen::Matrix<double, 3, 1> &)> f2_;
448 std::vector<lf::assemble::COOMatrix<SCALAR>> coo_matrix_;
449 std::vector<Eigen::Matrix<SCALAR, Eigen::Dynamic, 1>> phi_;
450 std::vector<Eigen::Matrix<SCALAR, Eigen::Dynamic, 1>> mu_;
451 double k_;
452};
453
454} // namespace operators
455
456} // namespace projects::hldo_sphere
457
458#endif // HLDO_SPHERE_OPERATORS_HODGE_LAPLACIANS_SOURCE_PROBLEMS_H
A temporary data structure for matrix in COO format.
Definition: coomatrix.h:52
void setZero()
Erase all entries of the matrix.
Definition: coomatrix.h:98
Index cols() const
return number of column
Definition: coomatrix.h:72
TripletVec & triplets()
Gives access to the vector of triplets.
Definition: coomatrix.h:124
Index rows() const
return number of rows
Definition: coomatrix.h:70
void AddToEntry(gdof_idx_t i, gdof_idx_t j, SCALAR increment)
Add a value to the specified entry.
Definition: coomatrix.h:87
A general (interface) class for DOF handling, see Lecture Document Paragraph 2.7.4....
Definition: dofhandler.h:109
virtual size_type NumDofs() const =0
total number of dof's handled by the object
Dofhandler for uniform finite element spaces.
Definition: dofhandler.h:257
static constexpr RefEl kSegment()
Returns the (1-dimensional) reference segment.
Definition: ref_el.h:150
constexpr RefEl(RefElType type) noexcept
Create a RefEl from a lf::base::RefElType enum.
Definition: ref_el.h:172
static constexpr RefEl kPoint()
Returns the (0-dimensional) reference point.
Definition: ref_el.h:141
static constexpr RefEl kTria()
Returns the reference triangle.
Definition: ref_el.h:158
Interface class representing a topological entity in a cellular complex
Definition: entity.h:39
Element Matrix Provider for the mass matrix using picewise linear barycentric basis functions.
Element matrix provider for the Whitney one mass matrix that is the dot product of two Whitney one ba...
Element matrix provider for the bilinear form with cellwise constant basis functions.
void setRefinementLevel(lf::base::size_type n)
Set the refinement level.
Creates and solves the discretised Hodge Laplacian source problems.
std::vector< Eigen::Matrix< SCALAR, Eigen::Dynamic, 1 > > mu_
void SetMesh(std::shared_ptr< const lf::mesh::Mesh > mesh_p)
Sets the mesh and creates dof_handler.
Eigen::Matrix< SCALAR, Eigen::Dynamic, 1 > GetMuZero()
retunrs the basis expansion coefficiants for the solution of the zero form
std::tuple< Eigen::Matrix< SCALAR, Eigen::Dynamic, 1 >, Eigen::Matrix< SCALAR, Eigen::Dynamic, 1 > > GetMuOne()
retunrs the basis expansion coefficiants for the solution of the one form
Eigen::Matrix< SCALAR, Eigen::Dynamic, 1 > GetLoadVector(int index)
returns the Loadvector
lf::assemble::COOMatrix< SCALAR > GetGalerkinMatrix(int index)
returns the Galerkin Matrix
void SetLoadFunctions(std::function< SCALAR(const Eigen::Matrix< double, 3, 1 > &)> &f0, std::function< Eigen::Matrix< SCALAR, 3, 1 >(const Eigen::Matrix< double, 3, 1 > &)> &f1, std::function< SCALAR(const Eigen::Matrix< double, 3, 1 > &)> &f2)
Sets the load functions.
std::function< Eigen::Matrix< SCALAR, 3, 1 >(const Eigen::Matrix< double, 3, 1 > &)> f1_
std::function< SCALAR(const Eigen::Matrix< double, 3, 1 > &)> f2_
HodgeLaplaciansSourceProblems()
Constructor initializes basic mesh (Octaeder with radius 1.0)
std::function< SCALAR(const Eigen::Matrix< double, 3, 1 > &)> f0_
std::tuple< Eigen::Matrix< SCALAR, Eigen::Dynamic, 1 >, Eigen::Matrix< SCALAR, Eigen::Dynamic, 1 > > GetMuTwo()
retunrs the basis expansion coefficiants for the solution of the two form
std::vector< Eigen::Matrix< SCALAR, Eigen::Dynamic, 1 > > phi_
void Compute()
Computes the Galerkin LSE for all three source problems.
Computes the Galerkin LSE for the Hodge Laplacian of the whitney one form.
lf::assemble::COOMatrix< SCALAR > GetGalerkinMatrix()
returns the Galerkin Matrix
Eigen::Matrix< SCALAR, Eigen::Dynamic, 1 > GetLoadVector()
returns the Loadvector
void SetLoadFunction(std::function< Eigen::Matrix< SCALAR, 3, 1 >(const Eigen::Matrix< double, 3, 1 > &)> &f)
Sets the load function.
void SetMesh(std::shared_ptr< const lf::mesh::Mesh > mesh_p)
Sets the mesh and creates dof_handler.
Computes the Galerkin LSE for the Hodge Laplacian of the whitney two form.
void SetMesh(std::shared_ptr< const lf::mesh::Mesh > mesh_p)
Sets the mesh and creates dof_handler.
lf::assemble::COOMatrix< SCALAR > GetGalerkinMatrix()
returns the Galerkin Matrix
void SetLoadFunction(std::function< SCALAR(const Eigen::Matrix< double, 3, 1 > &)> &f)
Sets the load function.
Eigen::Matrix< SCALAR, Eigen::Dynamic, 1 > GetLoadVector()
returns the Loadvector
Computes the Galerkin LSE for the Hodge Laplacian of the whitney zero form.
void SetMesh(std::shared_ptr< const lf::mesh::Mesh > mesh_p)
Sets the mesh for later computations.
lf::assemble::COOMatrix< SCALAR > GetGalerkinMatrix()
returns the Galerkin Matrix
Eigen::Matrix< SCALAR, Eigen::Dynamic, 1 > GetLoadVector()
returns the Loadvector
void SetLoadFunction(std::function< SCALAR(const Eigen::Matrix< double, 3, 1 > &)> &f)
Sets the load function for later computations.
unsigned int size_type
general type for variables related to size of arrays
Definition: base.h:24
lf::base::size_type size_type
Implementation of the thesis Hogde Laplacians and Dirac Operators on the surface of the 3-Sphere.
Definition: assemble.h:15