1#ifndef HLDO_SPHERE_DEBUGGING_WHITNEY_ONE_BASIS_EXPANSION_COEFFS_H
2#define HLDO_SPHERE_DEBUGGING_WHITNEY_ONE_BASIS_EXPANSION_COEFFS_H
8#include <lf/assemble/coomatrix.h>
9#include <lf/mesh/hybrid2d/mesh_factory.h>
10#include <lf/mesh/mesh.h>
11#include <lf/mesh/utils/tp_triag_mesh_builder.h>
12#include <lf/mesh/utils/utils.h>
13#include <lf/quad/quad.h>
14#include <lf/refinement/refinement.h>
15#include <lf/uscalfe/uscalfe.h>
17#include <results_processing.h>
18#include <sphere_triag_mesh_builder.h>
31using lf::uscalfe::operator-;
54 auto u = [](Eigen::Matrix<double, 3, 1> x) -> Eigen::Matrix<double, 3, 1> {
55 return Eigen::Matrix<double, 3, 1>::Zero();
58 mu_ = Eigen::VectorXd::Zero(1);
59 res_ = Eigen::VectorXd::Zero(1);
63 std::unique_ptr<lf::mesh::MeshFactory> factory =
64 std::make_unique<lf::mesh::hybrid2d::MeshFactory>(3);
65 std::shared_ptr<projects::hldo_sphere::mesh::SphereTriagMeshBuilder>
66 sphere = std::make_shared<
71 mesh_ = sphere->Build();
94 "Unsupported cell type " << cell_p->
RefEl());
97 const auto *geom = cell_p->Geometry();
100 Eigen::MatrixXd vertices = geom->Global(cell_p->RefEl().NodeCoords());
105 const Eigen::MatrixXd ref_grads =
109 const Eigen::MatrixXd J_inv_trans =
110 geom->JacobianInverseGramian(Eigen::VectorXd::Zero(2));
113 const Eigen::MatrixXd grad = J_inv_trans * ref_grads;
116 auto edgeOrientations = cell_p->RelativeOrientations();
122 auto edges = cell_p->SubEntities(1);
124 Eigen::Matrix<lf::base::size_type, 3, 1> global_idx;
125 global_idx <<
mesh_->Index(*edges[0]),
mesh_->Index(*edges[1]),
126 mesh_->Index(*edges[2]);
129 for (
int i = 0; i < 3; i++) {
130 int i_p1 = (i + 1) % 3;
131 int i_p2 = (i + 2) % 3;
134 Eigen::Vector3d ent_i_p1 = s(i_p1) / 4. * grad.col(i_p2);
135 Eigen::Vector3d ent_i_p2 = -s(i_p2) / 4. * grad.col(i_p2);
136 Eigen::Vector3d ent_i = s(i) / 4. * (grad.col(i_p1) - grad.col(i));
139 coo_mat.
AddToEntry(3 * global_idx[i], global_idx[i_p1], ent_i_p1(0));
140 coo_mat.
AddToEntry(3 * global_idx[i] + 1, global_idx[i_p1],
142 coo_mat.
AddToEntry(3 * global_idx[i] + 2, global_idx[i_p1],
145 coo_mat.
AddToEntry(3 * global_idx[i], global_idx[i_p2], ent_i_p2(0));
146 coo_mat.
AddToEntry(3 * global_idx[i] + 1, global_idx[i_p2],
148 coo_mat.
AddToEntry(3 * global_idx[i] + 2, global_idx[i_p2],
151 coo_mat.
AddToEntry(3 * global_idx[i], global_idx[i], ent_i(0));
152 coo_mat.
AddToEntry(3 * global_idx[i] + 1, global_idx[i], ent_i(1));
153 coo_mat.
AddToEntry(3 * global_idx[i] + 2, global_idx[i], ent_i(2));
158 Eigen::VectorXd phi(3 * n_edge);
160 const auto *geom = edge_p->Geometry();
161 Eigen::MatrixXd vertices = geom->Global(edge_p->RefEl().NodeCoords());
162 Eigen::Vector3d midpoint = 1. / 2. * vertices.col(0) + vertices.col(1);
166 phi.segment(3 * glob_idx, 3) =
u_(midpoint);
170 Eigen::SparseQR<Eigen::SparseMatrix<double>, Eigen::COLAMDOrdering<int>>
172 Eigen::SparseMatrix<double> sparse_mat = coo_mat.
makeSparse();
173 sparse_mat.makeCompressed();
174 solver.analyzePattern(sparse_mat);
175 solver.factorize(sparse_mat);
176 if (solver.info() != Eigen::Success) {
177 throw std::runtime_error(
"Could not decompose the matrix");
180 mu_ = solver.solve(phi);
182 Eigen::VectorXd phi_hat = sparse_mat *
mu_;
184 res_ = phi_hat - phi;
193 const Eigen::Matrix<double, 3, 1> &)>
204 void SetMesh(std::shared_ptr<const lf::mesh::Mesh> mesh) {
mesh_ = mesh; }
217 [](Eigen::Matrix<double, Eigen::Dynamic, 1> a) ->
double {
218 return a.squaredNorm();
226 auto mf_diff = mf_uh - mf_u;
227 const std::pair<double, lf::mesh::utils::CodimMeshDataSet<double>> l2 =
230 double error = std::get<0>(l2);
250 unsigned refinement_level,
251 std::function<Eigen::Vector3d(
const Eigen::Vector3d &)> u) {
252 std::vector<std::shared_ptr<const lf::mesh::Mesh>> meshs =
253 std::vector<std::shared_ptr<const lf::mesh::Mesh>>(refinement_level +
258 std::vector<std::pair<double, double>> solutions(refinement_level + 1);
261 std::unique_ptr<lf::mesh::MeshFactory> factory =
262 std::make_unique<lf::mesh::hybrid2d::MeshFactory>(3);
275 std::chrono::steady_clock::time_point start_time_total =
276 std::chrono::steady_clock::now();
278 for (
unsigned il = 0; il <= refinement_level; ++il) {
279 std::cout <<
"\nStart computation of refinement_level " << il
283 std::chrono::steady_clock::time_point start_time =
284 std::chrono::steady_clock::now();
288 const std::shared_ptr<lf::mesh::Mesh> mesh = sphere.
Build();
294 std::chrono::steady_clock::time_point end_time =
295 std::chrono::steady_clock::now();
297 std::chrono::duration_cast<std::chrono::milliseconds>(end_time -
302 std::cout <<
" -> Built Mesh " << elapsed_sec <<
" [s] " << std::flush;
305 start_time = std::chrono::steady_clock::now();
310 end_time = std::chrono::steady_clock::now();
311 elapsed_sec = std::chrono::duration_cast<std::chrono::milliseconds>(
312 end_time - start_time)
316 std::cout <<
" -> Computed basis expansion coefficients " << elapsed_sec
317 <<
" [s] " << std::flush;
320 start_time = std::chrono::steady_clock::now();
322 solutions[il].first = coeff_creator.
GetL2Error();
326 end_time = std::chrono::steady_clock::now();
328 elapsed_sec = std::chrono::duration_cast<std::chrono::milliseconds>(
329 end_time - start_time)
333 std::cout <<
" -> Computed Errors " << elapsed_sec <<
" [s] "
339 std::chrono::steady_clock::time_point end_time_total =
340 std::chrono::steady_clock::now();
341 double elapsed_sec_total =
342 std::chrono::duration_cast<std::chrono::milliseconds>(end_time_total -
347 std::cout <<
"\nTotal computation time for all levels " << elapsed_sec_total
351 std::string main_dir =
"results";
352 std::filesystem::create_directory(main_dir);
355 int table_width = 13;
359 std::ofstream csv_file;
360 std::string csv_name =
concat(
"basis_expansion_coeffs_", refinement_level);
361 std::replace(csv_name.begin(), csv_name.end(),
'.',
'_');
362 csv_file.open(
concat(main_dir,
"/", csv_name,
".csv"));
363 csv_file <<
"numCells,"
369 csv_file <<
",L2Error,SquaredRes";
370 csv_file << std::endl;
372 Eigen::VectorXd hMax(refinement_level + 1);
378 auto &sol_mesh = meshs[lvl];
383 if (h > hMax(lvl)) hMax(lvl) = h;
387 csv_file << sol_mesh->NumEntities(0) <<
"," << sol_mesh->NumEntities(1)
388 <<
"," << sol_mesh->NumEntities(2) <<
"," << hMax(lvl);
390 csv_file <<
"," << solutions[lvl].first <<
"," << solutions[lvl].second
399 std::function<Eigen::Matrix<double, 3, 1>(
400 const Eigen::Matrix<double, 3, 1> &)>
404 std::shared_ptr<const lf::mesh::Mesh>
mesh_;
A temporary data structure for matrix in COO format.
Eigen::SparseMatrix< Scalar > makeSparse() const
Create an Eigen::SparseMatrix out of the COO format.
void AddToEntry(gdof_idx_t i, gdof_idx_t j, SCALAR increment)
Add a value to the specified entry.
constexpr RefEl(RefElType type) noexcept
Create a RefEl from a lf::base::RefElType enum.
static constexpr RefEl kTria()
Returns the reference triangle.
Interface class representing a topological entity in a cellular complex
MeshFunction wrapper for a simple function of physical coordinates.
Represents a Quadrature Rule over one of the Reference Elements.
Linear Lagrange finite element on triangular reference element.
Eigen::Matrix< SCALAR, Eigen::Dynamic, Eigen::Dynamic > GradientsReferenceShapeFunctions(const Eigen::MatrixXd &refcoords) const override
Computation of the gradients of all reference shape functions in a number of points.
Class to find the "best" basisexpansion coefficients with the analytical solution.
void Compute()
Computes the "best" basisexpansion coefficients.
void SetMesh(std::shared_ptr< const lf::mesh::Mesh > mesh)
double GetL2Error()
returns L2 Error between the approximation and the analytical solution
void SetFunction(std::function< Eigen::Matrix< double, 3, 1 >(const Eigen::Matrix< double, 3, 1 > &)> u)
Sets the analytical solution.
WhitneyOneBasisExpansionCoeffs()
Constructor.
std::shared_ptr< const lf::mesh::Mesh > mesh_
double GetSquaredResidualError()
returns the squared sum of all residuals at the edge midpoints, this is the quanity minimized in the ...
std::function< Eigen::Matrix< double, 3, 1 >(const Eigen::Matrix< double, 3, 1 > &)> u_
static void Experiemnt(unsigned refinement_level, std::function< Eigen::Vector3d(const Eigen::Vector3d &)> u)
Eigen::VectorXd GetMu()
returns basis expansion coefficients computed in Compute
A mesh builder for regular 3-Sphere.
void setRefinementLevel(lf::base::size_type n)
Set the refinement level.
void setRadius(double r)
Sets the radius.
std::shared_ptr< lf::mesh::Mesh > Build()
Build the mesh.
Provides Mesh Function for given basis expansion coefficients.
unsigned int size_type
general type for variables related to size of arrays
lf::base::size_type size_type
double Volume(const Geometry &geo)
Compute the (approximate) volume (area) of a shape.
int to_sign(Orientation o)
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&)
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.
Implementation of the thesis Hogde Laplacians and Dirac Operators on the surface of the 3-Sphere.