11 #ifndef BEMBEL_SRC_ANSATZSPACE_GLUE_HPP_
12 #define BEMBEL_SRC_ANSATZSPACE_GLUE_HPP_
38 namespace GlueRoutines {
43 std::vector<int> dofs;
49 template <
typename Derived,
unsigned int DF>
51 static std::vector<dofIdentification> makeIdentification(
52 const std::vector<std::array<int, 4>> &edges_,
54 assert(
false &&
"Needs to be specialized");
75 template <
typename Derived>
77 std::vector<std::array<int, 4>> edges_;
79 Eigen::SparseMatrix<double> glue_mat_;
158 std::vector<Eigen::Triplet<double>> trips;
159 std::vector<GlueRoutines::dofIdentification> dof_id =
163 std::vector<bool> dof_is_slave(pre_dofs,
false);
164 std::vector<bool> dof_is_master(pre_dofs,
false);
167 int number_of_slaves = 0;
168 int number_of_boundary_dofs = 0;
169 for (
auto dofset : dof_id) {
174 std::sort(dofset.dofs.begin(), dofset.dofs.end());
175 dof_is_master[dofset.dofs[0]] =
true;
176 if (dofset.dofs.size() == 1) ++number_of_boundary_dofs;
177 for (
int i = 1; i < dofset.dofs.size(); ++i) {
178 dof_is_slave[dofset.dofs[i]] =
true;
184 std::sort(dof_id.begin(), dof_id.end(),
187 return a.dofs[0] < b.dofs[0];
190 const int post_dofs = pre_dofs - number_of_slaves - number_of_boundary_dofs;
191 const int glued_dofs = pre_dofs - number_of_slaves;
192 assert(post_dofs != 0 &&
"All degrees of freedom are on the boundary!");
198 int master_index = 0;
200 for (
int i = 0; i < glued_dofs; ++i) {
201 while (dof_is_slave[i + skip] && ((i + skip) < pre_dofs)) ++skip;
202 const int pre_index = i + skip;
204 if (dof_is_master[pre_index] && dof_id[master_index].dofs.size() == 1) {
208 trips.push_back(Eigen::Triplet<double>(pre_index, post_index, 1));
210 assert(!(dof_is_master[pre_index] && dof_is_slave[pre_index]));
211 if (dof_is_master[pre_index]) {
215 assert(pre_index == dof_id[master_index].dofs[0]);
216 const int number_of_partners = dof_id[master_index].dofs.size();
217 for (
int j = 1; j < number_of_partners; ++j) {
218 trips.push_back(Eigen::Triplet<double>(dof_id[master_index].dofs[j],
220 dof_id[master_index].coef));
227 Eigen::SparseMatrix<double> glue_matrix(pre_dofs, post_dofs);
228 glue_matrix.setFromTriplets(trips.begin(), trips.end());
230 assert(trips.size() == (pre_dofs - number_of_boundary_dofs));
235 namespace GlueRoutines {
259 std::vector<int> getEdgeDofIndices(
int edgeCase,
int dimXdir,
int dimYdir,
261 std::vector<int> out;
264 out.reserve(dimXdir);
266 "This should be a given. If not something went wrong in Glue.hpp" &&
268 for (
int i = 0; i < dimXdir; ++i) {
269 out.push_back(i + shift);
274 out.reserve(dimYdir);
276 "This should be a given. If not something went wrong in Glue.hpp" &&
278 for (
int i = 0; i < dimYdir; ++i) {
279 out.push_back(dimXdir * (i + 1) - 1 + shift);
284 out.reserve(dimXdir);
286 "This should be a given. If not something went wrong in Glue.hpp" &&
288 for (
int i = 0; i < dimXdir; ++i) {
289 out.push_back(dimXdir * (dimYdir - 1) + i + shift);
294 out.reserve(dimYdir);
296 "This should be a given. If not something went wrong in Glue.hpp" &&
298 for (
int i = 0; i < dimYdir; ++i) {
299 out.push_back(dimXdir * i + shift);
313 inline bool edgeIsForwardParametrized(
int edgeCase) {
314 return edgeCase == 0 || edgeCase == 1;
316 inline bool edgeIsBackwardsParametrized(
int edgeCase) {
317 return !(edgeIsForwardParametrized(edgeCase));
319 inline bool normalComponentIsInwardDirected(
int edgeCase) {
320 return edgeCase == 0 || edgeCase == 3;
322 inline bool normalComponentIsOutwardDirected(
int edgeCase) {
323 return !(normalComponentIsInwardDirected(edgeCase));
326 inline bool reverseParametrized(
const std::array<int, 4> &edge) {
327 return ((edgeIsForwardParametrized(edge[2]) &&
328 edgeIsForwardParametrized(edge[3])) ||
329 (edgeIsBackwardsParametrized(edge[2]) &&
330 edgeIsBackwardsParametrized(edge[3])))
335 inline int glueCoefficientDivergenceConforming(
const std::array<int, 4> &edge) {
336 return ((normalComponentIsInwardDirected(edge[2]) &&
337 normalComponentIsInwardDirected(edge[3])) ||
338 (normalComponentIsOutwardDirected(edge[2]) &&
339 normalComponentIsOutwardDirected(edge[3])))
343 inline bool edgeToBeGluedInFirstComp(
int edgeCase) {
344 return (edgeCase == 0 || edgeCase == 2) ? false :
true;
352 template <
typename Derived>
354 static std::vector<dofIdentification> makeIdentification(
355 const std::vector<std::array<int, 4>> &edges_,
370 template <
typename Derived>
372 static std::vector<dofIdentification> makeIdentification(
373 const std::vector<std::array<int, 4>> &edges_,
376 assert(superspace.get_polynomial_degree() >= 1);
377 const int one_d_dim = superspace.get_polynomial_degree() + 1 +
379 ((1 << superspace.get_refinement_level()) - 1);
380 const int dofs_per_patch = one_d_dim * one_d_dim;
382 std::vector<GlueRoutines::dofIdentification> out;
383 out.reserve(edges_.size() * one_d_dim);
387 for (
auto edge : edges_) {
390 const int shift_e1 = edge[0] * dofs_per_patch;
391 const int shift_e2 = edge[1] * dofs_per_patch;
392 const bool needReversion = reverseParametrized(edge);
394 std::vector<int> dofs_e1 =
395 getEdgeDofIndices(edge[2], one_d_dim, one_d_dim, shift_e1);
396 std::vector<int> dofs_e2 =
397 getEdgeDofIndices(edge[3], one_d_dim, one_d_dim, shift_e2);
400 if (edge[1] > -1 && edge[0] > -1) {
401 for (
int i = 0; i < one_d_dim; ++i) {
403 const int j = needReversion ? one_d_dim - 1 - i : i;
405 assert(dofs_e1[i] != dofs_e2[j] &&
406 "If this happens something went horribly wrong.");
408 const int small_dof = std::min(dofs_e1[i], dofs_e2[j]);
409 const int large_dof = std::max(dofs_e1[i], dofs_e2[j]);
415 if (already_stored_in[small_dof] > -1) {
419 if (already_stored_in[large_dof] == -1) {
420 out[already_stored_in[small_dof]].dofs.push_back(large_dof);
421 already_stored_in[large_dof] = already_stored_in[small_dof];
423 if (!(already_stored_in[small_dof] ==
424 already_stored_in[large_dof])) {
429 const int small_store = std::min(already_stored_in[large_dof],
430 already_stored_in[small_dof]);
431 const int large_store = std::max(already_stored_in[large_dof],
432 already_stored_in[small_dof]);
433 for (
auto dfs : out[large_store].dofs) {
436 already_stored_in[dfs] = small_store;
437 for (
auto other_dfs : out[small_store].dofs) {
438 assert(dfs != other_dfs);
440 out[small_store].dofs.push_back(dfs);
443 out[large_store].dofs = {};
444 out[large_store].coef = 0;
447 }
else if (already_stored_in[large_dof] > -1) {
451 if (already_stored_in[small_dof] == -1) {
452 out[already_stored_in[large_dof]].dofs.push_back(small_dof);
453 already_stored_in[small_dof] = already_stored_in[large_dof];
455 if (!(already_stored_in[small_dof] ==
456 already_stored_in[large_dof])) {
461 const int small_store = std::min(already_stored_in[large_dof],
462 already_stored_in[small_dof]);
463 const int large_store = std::max(already_stored_in[large_dof],
464 already_stored_in[small_dof]);
465 for (
auto dfs : out[large_store].dofs) {
468 already_stored_in[dfs] = small_store;
469 for (
auto other_dfs : out[small_store].dofs) {
470 assert(dfs != other_dfs);
472 out[small_store].dofs.push_back(dfs);
475 out[large_store].dofs = {};
476 out[large_store].coef = 0;
482 d.dofs.push_back(small_dof);
483 d.dofs.push_back(large_dof);
484 already_stored_in[small_dof] = d_count;
485 already_stored_in[large_dof] = d_count;
495 for (
auto x = out.begin(); x != out.end(); ++x) {
496 if ((*x).dofs.size() == 0) {
511 template <
typename Derived>
513 static std::vector<dofIdentification> makeIdentification(
514 const std::vector<std::array<int, 4>> &edges_,
518 const int small_dim = superspace.get_polynomial_degree() +
520 ((1 << superspace.get_refinement_level()) - 1);
521 const int large_dim = superspace.get_polynomial_degree() + 1 +
523 ((1 << superspace.get_refinement_level()) - 1);
524 const int dofs_per_patch_per_component = small_dim * large_dim;
526 assert(dofs_per_patch_per_component ==
528 (superspace.get_number_of_patches() * 2)) &&
529 "The assembly of the glue matrix is highly specific to the space. "
530 "Something went wrong; is the discrete space correct?");
532 std::vector<GlueRoutines::dofIdentification> out;
533 out.reserve(edges_.size() * small_dim);
535 for (
auto edge : edges_) {
536 assert(edge[0] <= edge[1] || edge[1] == -1);
540 const int shift_e1 = edge[0] * dofs_per_patch_per_component +
541 (edgeToBeGluedInFirstComp(edge[2])
543 : (dofs_per_patch_per_component *
544 superspace.get_number_of_patches()));
545 const int shift_e2 = edge[1] * dofs_per_patch_per_component +
546 (edgeToBeGluedInFirstComp(edge[3])
548 : (dofs_per_patch_per_component *
549 superspace.get_number_of_patches()));
551 const int xdir_dim_1 =
552 edgeToBeGluedInFirstComp(edge[2]) ? large_dim : small_dim;
553 const int ydir_dim_1 =
554 edgeToBeGluedInFirstComp(edge[2]) ? small_dim : large_dim;
555 const int xdir_dim_2 =
556 edgeToBeGluedInFirstComp(edge[3]) ? large_dim : small_dim;
557 const int ydir_dim_2 =
558 edgeToBeGluedInFirstComp(edge[3]) ? small_dim : large_dim;
559 std::vector<int> dofs_e1 =
560 getEdgeDofIndices(edge[2], xdir_dim_1, ydir_dim_1, shift_e1);
561 std::vector<int> dofs_e2 =
562 getEdgeDofIndices(edge[3], xdir_dim_2, ydir_dim_2, shift_e2);
564 const int size_of_edge_dofs = dofs_e1.size();
565 assert(size_of_edge_dofs == dofs_e2.size() || edge[1] == -1);
567 const bool needReversion = reverseParametrized(edge);
568 const int coef = glueCoefficientDivergenceConforming(edge);
571 if (edge[1] > -1 && edge[0] > -1) {
572 for (
int i = 0; i < size_of_edge_dofs; ++i) {
574 const int j = needReversion ? size_of_edge_dofs - 1 - i : i;
575 assert(dofs_e1[i] != dofs_e2[j] &&
576 "If this happens something went horribly wrong.");
577 d.dofs.push_back(std::min(dofs_e1[i], dofs_e2[j]));
578 d.dofs.push_back(std::max(dofs_e1[i], dofs_e2[j]));
583 for (
int i = 0; i < size_of_edge_dofs; ++i) {
586 d.dofs.push_back(dofs_e1[i]);
ElementTree & get_element_tree()
getter
std::vector< std::array< int, 4 > > patchTopologyInfo() const
Resolves neighborhood relations of the patches.
This class takes care of identifying DOFs on different edges, which must be identified with one anoth...
void init_Glue(const SuperSpace< Derived > &superspace, const Projector< Derived > &proj)
Initializes the AnsatzSpace object.
Eigen::SparseMatrix< double > get_glue_matrix() const
Returns Glue matrix to assemble continuous B-splines.
std::vector< GlueRoutines::dofIdentification > makeDofIdentificationList(const SuperSpace< Derived > &superspace, const Projector< Derived > &proj)
Generates a list of degrees of freedom (DOFs) identifications.
Glue(const SuperSpace< Derived > &superspace, const Projector< Derived > &proj)
Constructor for the Glue class.
Eigen::SparseMatrix< double > assembleGlueMatrix(const SuperSpace< Derived > &superspace, const Projector< Derived > &proj)
Assembles the Glue matrix according to the DOF identification list.
The Projector provides routines to assemble smooth B-Splines on each patch.
int get_knot_repetition() const
getter
int get_dofs_after_projector() const
Return number of smooth B-splines.
Routines for the evalutation of pointwise errors.
Helper struct for assembling the Glue for the different cases.
struct containing specifications on the linear operator has to be specialized or derived for any part...
The superspace manages local polynomial bases on each element of the mesh and provides an interface t...