LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
dirac_convergence_test.cc
1#include "dirac_convergence_test.h"
2
3#include "debugging.h"
4
5namespace projects::hldo_sphere {
6namespace debugging {
7
17void DiracConvergenceTest::Compute(unsigned refinement_levels) {
18 // Initialize solution wrapper
19 SolutionList solutions;
20 std::vector<std::shared_ptr<const lf::mesh::Mesh>> meshs =
21 std::vector<std::shared_ptr<const lf::mesh::Mesh>>(refinement_levels);
22
24
25 // functions are passed by reference hence changing the k still influences
26 // the functions
28 lse_builder.SetK(k_);
29
30 // Read the mesh from the gmsh file
31 std::unique_ptr<lf::mesh::MeshFactory> factory =
32 std::make_unique<lf::mesh::hybrid2d::MeshFactory>(3);
33
36
37 // we always take the same radius
38 sphere.setRadius(1.);
39
40 // start timer for total time
41 std::chrono::steady_clock::time_point start_time_total =
42 std::chrono::steady_clock::now();
43
44 // Initialize refinement level
45 solutions.mu_zero.resize(refinement_levels);
46 solutions.mu_one.resize(refinement_levels);
47 solutions.mu_two.resize(refinement_levels);
48
49 for (unsigned il = 0; il < refinement_levels; ++il) {
50 std::cout << "\nStart computation of refinement_level " << il << std::flush;
51
52 // start timer
53 std::chrono::steady_clock::time_point start_time =
54 std::chrono::steady_clock::now();
55
56 // get mesh
57 sphere.setRefinementLevel(il);
58 const std::shared_ptr<lf::mesh::Mesh> mesh = sphere.Build();
59 meshs[il] = mesh;
60
61 // end timer
62 std::chrono::steady_clock::time_point end_time =
63 std::chrono::steady_clock::now();
64 double elapsed_sec = std::chrono::duration_cast<std::chrono::milliseconds>(
65 end_time - start_time)
66 .count() /
67 1000.;
68
69 std::cout << " -> Built Mesh " << elapsed_sec << " [s] " << std::flush;
70
71 // setup the problem
72 lse_builder.SetMesh(mesh);
73
74 // start timer
75 start_time = std::chrono::steady_clock::now();
76
77 // compute the system
78 lse_builder.Compute();
79
80 // end timer
81 end_time = std::chrono::steady_clock::now();
82 elapsed_sec = std::chrono::duration_cast<std::chrono::milliseconds>(
83 end_time - start_time)
84 .count() /
85 1000.;
86
87 std::cout << " -> Computed LSE " << elapsed_sec << " [s] " << std::flush;
88
89 // start timer
90 start_time = std::chrono::steady_clock::now();
91
92 // solve the system
93 lse_builder.Solve();
94
95 // end timer
96 end_time = std::chrono::steady_clock::now();
97
98 elapsed_sec = std::chrono::duration_cast<std::chrono::milliseconds>(
99 end_time - start_time)
100 .count() /
101 1000.;
102
103 std::cout << " -> Solved System " << elapsed_sec << " [s] " << std::flush;
104
105 // store solutions
106 solutions.mu_zero[il] = lse_builder.GetMu(0);
107 solutions.mu_one[il] = lse_builder.GetMu(1);
108 solutions.mu_two[il] = lse_builder.GetMu(2);
109 } // end loop level
110
111 // end timer total
112 std::chrono::steady_clock::time_point end_time_total =
113 std::chrono::steady_clock::now();
114 double elapsed_sec_total =
115 std::chrono::duration_cast<std::chrono::milliseconds>(end_time_total -
116 start_time_total)
117 .count() /
118 1000.;
119
120 std::cout << "\nTotal computation time for all levels " << elapsed_sec_total
121 << " [s]\n";
122
123 /* Do convergence analyisis of the solutions that is
124 * | \|u_k\| - \|u_{k-1}\| |^2 -> 0
125 * with algebraic rate is expected
126 */
127
128 // create results direcotry
129 std::string main_dir = "results";
130 std::filesystem::create_directory(main_dir);
131
132 // prepare output
133 int table_width = 13;
134 int precision = 4;
135
136 // create csv file
137 std::ofstream csv_file;
138 std::string csv_name = concat("result_dirac_convergence_", refinement_levels);
139 std::replace(csv_name.begin(), csv_name.end(), '.', '_');
140 csv_file.open(concat(main_dir, "/", csv_name, ".csv"));
141 csv_file << "numCells,"
142 << "numEdges,"
143 << "numVerts,"
144 << "hMax";
145
146 // define square functions for norms
147 auto square_scalar = [](complex a) -> double {
148 return std::abs(a) * std::abs(a);
149 };
150 auto square_vector =
151 [](Eigen::Matrix<complex, Eigen::Dynamic, 1> a) -> double {
152 return a.squaredNorm();
153 };
154
155 // define quadrule for norms
157
158 Eigen::VectorXd L2ErrorZero = Eigen::VectorXd::Zero(refinement_levels);
159 Eigen::VectorXd L2ErrorOne = Eigen::VectorXd::Zero(refinement_levels);
160 Eigen::VectorXd L2ErrorTwo = Eigen::VectorXd::Zero(refinement_levels);
161 Eigen::VectorXd hMax = Eigen::VectorXd::Zero(refinement_levels);
162
163 // introduce columns for errors
164 csv_file << ",L2ErrorZero,DiffOfL2Zero,L2ErrorOne,DiffOfL2One,"
165 "L2ErrorTwo,DiffOfL2Two";
166 csv_file << std::endl;
167
168 // loop over all levels contained in the solution
169 for (lf::base::size_type lvl = 0; lvl <= refinement_levels; ++lvl) {
170 // create mesh Functions for solutions the level
171 auto &sol_mesh = meshs[lvl];
172
173 // compute meshwidth
174 for (const lf::mesh::Entity *e : sol_mesh->Entities(1)) {
175 double h = lf::geometry::Volume(*(e->Geometry()));
176 if (h > hMax(lvl)) hMax(lvl) = h;
177 }
178
179 // print level and mesh informations
180 csv_file << sol_mesh->NumEntities(0) << "," << sol_mesh->NumEntities(1)
181 << "," << sol_mesh->NumEntities(2) << "," << hMax(lvl);
182
184 solutions.mu_zero[lvl], sol_mesh);
186 solutions.mu_one[lvl], sol_mesh);
188 solutions.mu_two[lvl], sol_mesh);
189
190 // get error for zero form
191 const std::pair<double, lf::mesh::utils::CodimMeshDataSet<double>> L2_zero =
193 square_scalar, qr);
194 L2ErrorZero(lvl) = std::get<0>(L2_zero);
195
196 // get error for one form
197 const std::pair<double, lf::mesh::utils::CodimMeshDataSet<double>> L2_one =
199 square_vector, qr);
200 L2ErrorOne(lvl) = std::get<0>(L2_one);
201
202 // get error for two form
203 const std::pair<double, lf::mesh::utils::CodimMeshDataSet<double>> L2_two =
205 square_scalar, qr);
206 L2ErrorTwo(lvl) = std::get<0>(L2_two);
207
208 double l2RateZero = 0;
209 double l2RateOne = 0;
210 double l2RateTwo = 0;
211
212 // we can only compute order form the second level
213 if (lvl > 0) {
214 l2RateZero = abs(L2ErrorZero(lvl) - L2ErrorZero(lvl - 1));
215 l2RateOne = abs(L2ErrorOne(lvl) - L2ErrorOne(lvl - 1));
216 l2RateTwo = abs(L2ErrorTwo(lvl) - L2ErrorTwo(lvl - 1));
217 }
218
219 /******************************
220 * append solution of the current k in the outputs
221 ******************************/
222
223 csv_file << "," << L2ErrorZero(lvl) << "," << l2RateZero << ","
224 << L2ErrorOne(lvl) << "," << l2RateOne << "," << L2ErrorTwo(lvl)
225 << "," << l2RateTwo;
226 csv_file << "\n";
227 } // end loop over levels
228
229 // close csv file
230 csv_file.close();
231};
232
233} // namespace debugging
234} // namespace projects::hldo_sphere
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
Represents a Quadrature Rule over one of the Reference Elements.
Definition: quad_rule.h:58
std::function< complex(const Eigen::Matrix< double, 3, 1 > &)> f_zero_
std::function< Eigen::Matrix< complex, 3, 1 >(const Eigen::Matrix< double, 3, 1 > &)> f_one_
std::function< complex(const Eigen::Matrix< double, 3, 1 > &)> f_two_
void Compute(unsigned refinement_levels)
Solves the dirac opeartor source problems up to the given refinement_level.
void setRefinementLevel(lf::base::size_type n)
Set the refinement level.
std::shared_ptr< lf::mesh::Mesh > Build()
Build the mesh.
Computes the Galerkin LSE for the Dirac Operator source problem.
void SetLoadFunctions(std::function< complex(const Eigen::Matrix< double, 3, 1 > &)> f0, std::function< Eigen::Matrix< complex, 3, 1 >(const Eigen::Matrix< double, 3, 1 > &)> f1, std::function< complex(const Eigen::Matrix< double, 3, 1 > &)> f2)
Sets the load functions.
Provides Mesh Function for given basis expansion coefficients.
Provides Mesh Function for Whitney two basis expansion coefficients.
Provides Mesh Function for basis expansion coefficients of the zero form.
unsigned int size_type
general type for variables related to size of arrays
Definition: base.h:24
double Volume(const Geometry &geo)
Compute the (approximate) volume (area) of a shape.
QuadRule make_QuadRule(base::RefEl ref_el, unsigned degree)
Returns a QuadRule object for the given Reference Element and Degree.
static std::string concat(Args &&...args)
Concatenate objects defining an operator<<(std::ostream&)
Definition: debugging.h:26
std::pair< double, lf::mesh::utils::CodimMeshDataSet< double > > L2norm(const std::shared_ptr< const lf::mesh::Mesh > &mesh_p, const MF &f, const SQ_F &sq_f, const lf::quad::QuadRule &quadrule)
Computes the L2Norm of some MeshFunction (type MF) f.
Definition: norms.h:33
Implementation of the thesis Hogde Laplacians and Dirac Operators on the surface of the 3-Sphere.
Definition: assemble.h:15
stores solutions for a number of refinement levels
std::vector< Eigen::Matrix< complex, Eigen::Dynamic, 1 > > mu_one
std::vector< Eigen::Matrix< complex, Eigen::Dynamic, 1 > > mu_zero
std::vector< Eigen::Matrix< complex, Eigen::Dynamic, 1 > > mu_two