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...