21 using namespace assembler;
33 std::vector<int> compute_nonzero_bases_ids(
const Mesh2D &mesh,
const int element_index,
const std::vector<ElementBases> &bases,
const std::map<int, InterfaceData> &poly_edge_to_data)
35 std::vector<int> local_to_global;
37 const int n_edges = mesh.n_face_vertices(element_index);
38 Navigation::Index index = mesh.get_index_from_face(element_index);
39 for (
int i = 0; i < n_edges; ++i)
41 const int f2 = mesh.switch_face(index).face;
43 const InterfaceData &bdata = poly_edge_to_data.at(index.edge);
44 const ElementBases &b = bases[f2];
45 for (
int other_local_basis_id : bdata.local_indices)
47 for (
const auto &
x : b.bases[other_local_basis_id].global())
49 const int global_node_id =
x.index;
50 local_to_global.push_back(global_node_id);
54 index = mesh.next_around_face(index);
57 std::sort(local_to_global.begin(), local_to_global.end());
58 auto it = std::unique(local_to_global.begin(), local_to_global.end());
59 local_to_global.resize(std::distance(local_to_global.begin(), it));
62 return local_to_global;
67 void sample_parametric_edge(
const Mesh2D &mesh, Navigation::Index index,
int n_samples, Eigen::MatrixXd &samples)
71 assert(mesh.is_cube(index.face));
75 Eigen::Matrix2d endpoints;
78 const Eigen::VectorXd t = Eigen::VectorXd::LinSpaced(n_samples, 0, 1);
79 samples.resize(n_samples, endpoints.cols());
80 for (
int c = 0; c < 2; ++c)
82 samples.col(c) = (1.0 - t.array()).matrix() * endpoints(0, c) + t * endpoints(1, c);
88 void compute_offset_kernels(
const Eigen::MatrixXd &polygon,
int n_kernels,
double eps, Eigen::MatrixXd &kernel_centers)
90 Eigen::MatrixXd offset, samples;
91 std::vector<bool> inside;
94 int n_inside =
is_inside(polygon, samples, inside);
95 assert(n_inside == 0);
96 kernel_centers = samples;
111 void sample_polygon(
const int element_index,
const int n_samples_per_edge,
const Mesh2D &mesh,
const std::map<int, InterfaceData> &poly_edge_to_data,
112 const std::vector<ElementBases> &bases,
const std::vector<ElementBases> &gbases,
const double eps, std::vector<int> &local_to_global,
113 Eigen::MatrixXd &collocation_points, Eigen::MatrixXd &kernel_centers, Eigen::MatrixXd &rhs)
115 const int n_edges = mesh.n_face_vertices(element_index);
117 const int n_kernel_per_edges = (n_samples_per_edge - 1) / 3;
118 const int n_collocation_points = (n_samples_per_edge - 1) * n_edges;
119 const int n_kernels = n_kernel_per_edges * n_edges;
122 local_to_global = compute_nonzero_bases_ids(mesh, element_index, bases, poly_edge_to_data);
124 collocation_points.resize(n_collocation_points, 2);
125 collocation_points.setZero();
127 rhs.resize(n_collocation_points, local_to_global.size());
130 Eigen::MatrixXd samples, mapped;
131 std::vector<AssemblyValues> basis_val;
132 auto index = mesh.get_index_from_face(element_index);
133 for (
int i = 0; i < n_edges; ++i)
135 const int f2 = mesh.switch_face(index).face;
138 const InterfaceData &bdata = poly_edge_to_data.at(index.edge);
139 const ElementBases &b = bases[f2];
140 const ElementBases &gb = gbases[f2];
143 sample_parametric_edge(mesh, mesh.switch_face(index), n_samples_per_edge, samples);
144 samples.conservativeResize(samples.rows() - 1, samples.cols());
145 gb.eval_geom_mapping(samples, mapped);
146 assert(mapped.rows() == (n_samples_per_edge - 1));
147 collocation_points.block(i * (n_samples_per_edge - 1), 0, mapped.rows(), mapped.cols()) = mapped;
149 b.evaluate_bases(samples, basis_val);
151 for (
int other_local_basis_id : bdata.local_indices)
155 for (
const auto &
x : b.bases[other_local_basis_id].global())
157 const int global_node_id =
x.index;
158 const double weight =
x.val;
160 const int poly_local_basis_id = std::distance(local_to_global.begin(), std::find(local_to_global.begin(), local_to_global.end(), global_node_id));
161 rhs.block(i * (n_samples_per_edge - 1), poly_local_basis_id, basis_val[other_local_basis_id].
val.size(), 1) += basis_val[other_local_basis_id].val * weight;
165 index = mesh.next_around_face(index);
168 compute_offset_kernels(collocation_points, n_kernels, eps, kernel_centers);
177 const std::vector<ElementBases> &bases,
const std::vector<ElementBases> &gbases, Eigen::MatrixXd &basis_integrals)
183 const int dim = assembler.
is_tensor() ? 2 : 1;
186 basis_integrals.setZero();
188 std::array<Eigen::MatrixXd, 5> strong;
191 for (
int e = 0; e < n_elements; ++e)
202 const auto &quadr =
vals.quadrature;
206 const int n_local_bases = int(
vals.basis_values.size());
209 vals.basis_values.resize(n_local_bases + 5);
213 for (
int j = 0; j < n_local_bases; ++j)
217 for (
int d = 0; d < 5; ++d)
221 for (
size_t ii = 0; ii < v.
global.size(); ++ii)
223 for (
int alpha = 0; alpha < dim; ++alpha)
225 for (
int beta = 0; beta < dim; ++beta)
227 const int loc_index = alpha * dim + beta;
230 basis_integrals(v.
global[ii].index, r) += tmp(loc_index) + (strong[d].row(loc_index).transpose().array() * v.
val.array()).sum();
248 for (
int i = 0; i < n_edges; ++i)
250 Eigen::Matrix2d det_mat;
254 area += det_mat.determinant();
258 area = std::fabs(area);
260 const double eps = 0.08 * area;
349 const int quadrature_order,
const int mass_quadrature_order,
const int integral_constraints, std::vector<ElementBases> &bases,
const std::vector<ElementBases> &gbases,
350 const std::map<int, InterfaceData> &poly_edge_to_data, std::map<int, Eigen::MatrixXd> &mapped_boundary)
353 if (poly_edge_to_data.empty())
358 const int dim = assembler.
is_tensor() ? 2 : 1;
361 Eigen::MatrixXd basis_integrals;
378 std::vector<int> local_to_global;
379 Eigen::MatrixXd collocation_points, kernel_centers;
382 sample_polygon(e, n_samples_per_edge, mesh, poly_edge_to_data, bases, gbases, eps, local_to_global, collocation_points, kernel_centers, rhs);
419 Eigen::MatrixXd local_basis_integrals(rhs.cols(), basis_integrals.cols());
420 for (
long k = 0; k < rhs.cols(); ++k)
422 local_basis_integrals.row(k) = -basis_integrals.row(local_to_global[k]);
424 auto set_rbf = [&b](
auto rbf) {
425 b.
set_bases_func([rbf](
const Eigen::MatrixXd &uv, std::vector<AssemblyValues> &
val) {
427 rbf->bases_values(uv, tmp);
428 val.resize(tmp.cols());
429 assert(tmp.rows() == uv.rows());
431 for (
size_t i = 0; i < tmp.cols(); ++i)
433 val[i].val = tmp.col(i);
436 b.
set_grads_func([rbf](
const Eigen::MatrixXd &uv, std::vector<AssemblyValues> &
val) {
437 Eigen::MatrixXd tmpx, tmpy;
439 rbf->bases_grads(0, uv, tmpx);
440 rbf->bases_grads(1, uv, tmpy);
442 val.resize(tmpx.cols());
443 assert(tmpx.cols() == tmpy.cols());
444 assert(tmpx.rows() == uv.rows());
445 for (
size_t i = 0; i < tmpx.cols(); ++i)
447 val[i].grad.resize(uv.rows(), uv.cols());
448 val[i].grad.col(0) = tmpx.col(i);
449 val[i].grad.col(1) = tmpy.col(i);
453 if (integral_constraints == 0)
455 set_rbf(std::make_shared<RBFWithLinear>(kernel_centers, collocation_points, local_basis_integrals, tmp_quadrature, rhs,
false));
457 else if (integral_constraints == 1)
459 set_rbf(std::make_shared<RBFWithLinear>(kernel_centers, collocation_points, local_basis_integrals, tmp_quadrature, rhs));
461 else if (integral_constraints == 2)
463 set_rbf(std::make_shared<RBFWithQuadraticLagrange>(assembler, kernel_centers, collocation_points, local_basis_integrals, tmp_quadrature, rhs));
467 throw std::runtime_error(fmt::format(
"Unsupported constraint order: {:d}", integral_constraints));
471 const int n_poly_bases = int(local_to_global.size());
472 b.
bases.resize(n_poly_bases);
473 for (
int i = 0; i < n_poly_bases; ++i)
475 b.
bases[i].init(-2, local_to_global[i], i, Eigen::MatrixXd::Constant(1, 2, std::nan(
"")));
479 mapped_boundary[e] = collocation_points;
ElementAssemblyValues vals
virtual bool is_tensor() const
virtual std::string name() const =0
static int quadrature_order(const std::string &assembler, const int basis_degree, const BasisType &b_type, const int dim)
utility for retrieving the needed quadrature order to precisely integrate the given form on the given...
stores per local bases evaluations
std::vector< basis::Local2Global > global
stores per element basis values at given quadrature points and geometric mapping
void compute(const int el_index, const bool is_volume, const Eigen::MatrixXd &pts, const basis::ElementBases &basis, const basis::ElementBases &gbasis)
computes the per element values at the local (ref el) points (pts) sets basis_values,...
assemble matrix based on the local assembler local assembler is eg Laplace, LinearElasticity etc
void assemble(const bool is_volume, const int n_basis, const std::vector< basis::ElementBases > &bases, const std::vector< basis::ElementBases > &gbases, const AssemblyValsCache &cache, const double t, StiffnessMatrix &stiffness, const bool is_mass=false) const override
assembles the stiffness matrix for the given basis the bilinear form (local assembler) is encoded by ...
Stores the basis functions for a given element in a mesh (facet in 2d, cell in 3d).
void set_bases_func(EvalBasesFunc fun)
void set_quadrature(const QuadratureFunction &fun)
void set_grads_func(EvalBasesFunc fun)
std::vector< Basis > bases
one basis function per node in the element
bool has_parameterization
void set_mass_quadrature(const QuadratureFunction &fun)
static Eigen::VectorXi quad_edge_local_nodes(const int q, const mesh::Mesh2D &mesh, mesh::Navigation::Index index)
static void compute_integral_constraints(const assembler::LinearAssembler &assembler, const mesh::Mesh2D &mesh, const int n_bases, const std::vector< ElementBases > &bases, const std::vector< ElementBases > &gbases, Eigen::MatrixXd &basis_integrals)
static int build_bases(const assembler::LinearAssembler &assembler, const int n_samples_per_edge, const mesh::Mesh2D &mesh, const int n_bases, const int quadrature_order, const int mass_quadrature_order, const int integral_constraints, std::vector< ElementBases > &bases, const std::vector< ElementBases > &gbases, const std::map< int, InterfaceData > &poly_edge_to_data, std::map< int, Eigen::MatrixXd > &mapped_boundary)
Build bases over the remaining polygons of a mesh.
static void setup_monomials_strong_2d(const int dim, const assembler::LinearAssembler &assembler, const Eigen::MatrixXd &pts, const QuadratureVector &da, std::array< Eigen::MatrixXd, 5 > &strong)
static void setup_monomials_vals_2d(const int star_index, const Eigen::MatrixXd &pts, assembler::ElementAssemblyValues &vals)
static int index_mapping(const int alpha, const int beta, const int d, const int ass_dim)
Navigation::Index next_around_face(Navigation::Index idx) const
bool is_volume() const override
checks if mesh is volume
virtual Navigation::Index switch_vertex(Navigation::Index idx) const =0
virtual Navigation::Index get_index_from_face(int f, int lv=0) const =0
int n_elements() const
utitlity to return the number of elements, cells or faces in 3d and 2d
bool is_polytope(const int el_id) const
checks if element is polygon compatible
virtual RowVectorNd point(const int global_index) const =0
point coordinates
virtual int n_face_vertices(const int f_id) const =0
number of vertices of a face
void get_quadrature(const Eigen::MatrixXd &poly, const int order, Quadrature &quadr)
Gets the quadrature points & weights for a polygon.
void q_nodes_2d(const int q, Eigen::MatrixXd &val)
double compute_epsilon(const Mesh2D &mesh, int e)
void sample_polygon(const Eigen::MatrixXd &IV, int num_samples, Eigen::MatrixXd &S)
Sample points on a polygon, evenly spaced from each other.
void offset_polygon(const Eigen::MatrixXd &IV, Eigen::MatrixXd &OV, double eps)
Compute offset polygon.
int is_inside(const Eigen::MatrixXd &IV, const Eigen::MatrixXd &Q, std::vector< bool > &inside)
Compute whether points are inside a polygon.
Eigen::Matrix< double, Eigen::Dynamic, 1, 0, MAX_QUAD_POINTS, 1 > QuadratureVector