G+Smo  24.08.0
Geometry + Simulation Modules
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
gsDPatch.hpp
Go to the documentation of this file.
1 
16 #include <gsHSplines/gsTHBSpline.h>
17 #include <gsSolver/gsBlockOp.h>
18 #include <gsSolver/gsMatrixOp.h>
19 
20 #include <gsIO/gsWriteParaview.h>
21 
22 // #define PI 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647
23 
24 namespace gismo
25 {
26  // Constructors
27  template<short_t d,class T>
29  :
30  Base(patches)
31  {
32  this->defaultOptions();
33  }
34 
35  // Constructors
36  template<short_t d,class T>
38  :
39  Base(bases)
40  {
41  this->defaultOptions();
42  }
43 
44  template<short_t d,class T>
46  {
47  // freeAll(m_bases);
48  }
49 
50  template<short_t d,class T>
52  {
53  Base::defaultOptions();
54  m_options.addInt("Pi","Pi matrix to be applied, 0: Non-negative, 1: Idempotent",0);
55  m_options.addInt("RefLevel","Refinement level",0);
56  m_options.addReal("Beta","Beta parameter",0.4);
57  }
58 
59  /*=====================================================================================
60  Coefficients
61  =====================================================================================*/
62  template<short_t d,class T>
64  {
65  GISMO_ASSERT(m_mapModified.isFinalized(),"Mapper is not finalized");
66 
67  gsMatrix<T> coefs(m_mapModified.freeSize(),patches.geoDim());
68 
69  index_t size;
70  for (size_t p=0; p!=m_bases0.nBases(); p++) // patches
71  {
72  gsMatrix<T> tmpCoefs;
73  if (m_tMatrices[p].rows()!=0 && m_tMatrices[p].cols()!=0)
74  tmpCoefs = m_tMatrices[p]*patches.patch(p).coefs();
75  else
76  tmpCoefs = patches.patch(p).coefs();
77 
78  size = m_mapModified.patchSize(p);
79  for (index_t k=0; k!=size; k++)
80  {
81  if (m_mapModified.is_free(k,p,0))
82  coefs.row(m_mapModified.index(k,p,0)) = tmpCoefs.row(k);
83  }
84  }
85 
86  // Correct the v=3 boundary vertices:
87  std::fill(m_vertCheck.begin(), m_vertCheck.end(), false);
88  for (size_t p=0; p!=m_bases0.nBases(); p++)
89  {
90  for (index_t c=1; c<5; c++)
91  {
92  index_t idx = this->_vertIndex(p,c);
93  if(m_vertCheck[ idx] )
94  continue;
95 
96  patchCorner pcorner(p,c);
97  std::pair<index_t,bool> vdata = this->_vertexData(pcorner); // corner c
98 
99  if (std::count(m_C0s.begin(), m_C0s.end(), pcorner))
100  continue;
101  if (vdata.first==3 && !vdata.second)
102  {
103  std::vector<patchCorner> otherCorners;
104  std::vector<patchSide> csides;
105 
106  m_topology.getCornerList(pcorner,otherCorners);
107  index_t b00 = -1, b11i = -1;
108  std::vector<index_t> b11b;
109  for (std::vector<patchCorner>::iterator corner = otherCorners.begin(); corner != otherCorners.end(); corner++)
110  {
111  corner->getContainingSides(d,csides);
112  if ( m_topology.isBoundary(csides[0]) || m_topology.isBoundary(csides[1]) ) //
113  b11b.push_back(m_mapModified.index( this->_indexFromVert(m_bases0,1,*corner,csides[0],1) , corner->patch) );
114  else if (b11i==-1)
115  b11i = m_mapModified.index( this->_indexFromVert(m_bases0,1,*corner,csides[0],1) , corner->patch);
116  else
117  GISMO_ERROR("b11i is already assigned?");
118 
119  if (corner==otherCorners.begin())
120  {
121  const gsBasis <T> * basis = &m_bases0.basis(corner->patch);
122  b00 = m_mapModified.index( basis->functionAtCorner(corner->corner()), corner->patch );
123  }
124 
125  idx = this->_vertIndex(corner->patch,corner->corner());
126  m_vertCheck[ idx ] = true;
127  }
128  coefs.row(b00) = coefs.row(b11b[0]) + coefs.row(b11b[1]) - coefs.row(b11i);
129  }
130  else
131  m_vertCheck[ idx ] = true;
132 
133  }
134  }
135 
136  return coefs;
137  }
138 
139  /*=====================================================================================
140  Construction functions
141  =====================================================================================*/
142 
143  template<short_t d,class T>
145  {
146  // Cast all patches of the mp object to THB splines
147  for (size_t k=0; k!=m_Bbases.nBases(); ++k)
148  {
149  // Check the basis and make the new level(s)
150  std::vector<gsKnotVector<T>> KVs(d);
151  index_t degree;
152  if ( const gsTensorBSplineBasis<d,T> * tbasis0 = dynamic_cast<const gsTensorBSplineBasis<d,T> * > (&m_Bbases.basis(k)) )
153  {
154  gsTHBSplineBasis<d,T> thbBasis(*tbasis0,true);
155  for (short_t dim=0; dim!=d; dim++)
156  {
157  GISMO_ENSURE(tbasis0->degree(dim)>=2,"Degree of the basis must be larger than or equal to 2, but is "<<tbasis0->degree(dim)<<" (component "<<d<<")");
158  const gsKnotVector<T> & KV = tbasis0->knots(dim);
159  KVs[dim] = tbasis0->knots(dim);
160  degree = KVs[dim].degree();
161 
162  // Every knot needs multiplicity p-1. For degree 2, this gives the same basis!
163  for (typename gsKnotVector<T>::uiterator knot = std::next(KV.ubegin()); knot!=std::prev(KV.uend()); knot++)
164  KVs[dim].insert(*knot,degree-KV.multiplicity(*knot)-1);
165 
166  }
167  // Create level 1
168  gsTensorBSplineBasis<d,T> tbasis1(KVs);
169  thbBasis.addLevel(tbasis1);
170 
171  // Create level 2
172  gsTensorBSplineBasis<d,T> tbasis2 = tbasis1;
173  for (short_t dim = 0; dim!=d; dim++)
174  tbasis2.uniformRefine(1,tbasis2.degree(dim)-1,dim);
175  thbBasis.addLevel(tbasis2);
176 
177  m_bases0.addBasis(thbBasis.clone());
178  }
179  else
180  GISMO_ERROR("Basis can only be constructed on gsTensorBSplineBasis");
181  }
182  m_bases0.setTopology(m_topology);
183  m_bases = m_bases0;
184  }
185 
186  template <short_t d, class T>
187  void gsDPatch<d,T>::_refBoxes(std::vector<std::vector<index_t>> & patchBoxes)
188  {
189  patchBoxes.clear();
190  patchBoxes.resize(m_bases0.size());
191 
192  // prepare the geometry
193  gsMatrix<index_t> box(d,2);
194  std::vector<index_t> boxes;
195  gsVector<bool> pars;
196  index_t nelements;
197  index_t degree;
198  patchCorner corner;
199  std::vector<patchCorner> cornerList;
200  std::vector<std::vector<patchCorner> > cornerLists;
201 
202  m_topology.getEVs(cornerLists);
203 
204  index_t N = cornerLists.size();
205 
206  // Make a mask of corners per patch to track which ones have been handled
207  gsMatrix<bool> mask(m_bases0.nBases(),math::pow(2,d));
208  mask.setConstant(false);
209 
210  for (index_t v =0; v<N; v++)
211  {// Loop over EVs
212  for (size_t c = 0; c<cornerLists[v].size(); c++)
213  {// Loop over corners per EV
214  corner = cornerLists[v].at(c);
215  gsHTensorBasis<d,T> * basis = dynamic_cast<gsHTensorBasis<d,T>*>(&m_bases0.basis(corner.patch));
216 
217  if (mask(corner.patch,corner.corner()-1))
218  continue;
219 
220  corner.parameters_into(d,pars);
221  box.setZero();
222  for (short_t dim = 0; dim!=d; dim++)
223  {
224  const gsKnotVector<T> & KV = basis->tensorLevel(0).knots(dim);
225  degree = KV.degree();
226  nelements = (degree < 4) ? 2 : 1;
227  nelements *= std::pow(2,m_options.getInt("RefLevel"));
228 
229  GISMO_ASSERT(nelements<=(index_t)KV.numElements(),"Need more elements than available for refinement around corner "<<corner.corner()<<" of patch "<<corner.patch<<".\n"<<"nelements = "<<nelements<<"; KV.numElements() = "<<KV.numElements()<<"\n");
230 
231  box.row(dim).setConstant(pars(dim)*(KV.uSize()-1));
232  box(dim,!pars(dim)) += ( 1 - 2*pars(dim) ) * nelements; // subtracts from box(d,0) if pars(d)==1, adds to box(d,1) if pars(d)==0
233 
234  // If all elements in this direction are refined, we need to add the other corner of this side to the list of corners to be refined
235  if ((index_t)KV.numElements()==nelements)
236  {
237  // Get the patch side in the direction of the knot vector KV
238  GISMO_ASSERT(d==2,"This does not work for d!=2!");
239  boxCorner otherCorner;
240  if ((corner.m_index==1 && dim==0) || (corner.m_index==4 && dim==1)) // the other corner is south east
241  otherCorner = 2;
242  else if ((corner.m_index==1 && dim==1) || (corner.m_index==4 && dim==0)) // the other corner is north west
243  otherCorner = 3;
244  else if ((corner.m_index==2 && dim==0) || (corner.m_index==3 && dim==1)) // the other corner is south west
245  otherCorner = 1;
246  else if ((corner.m_index==2 && dim==1) || (corner.m_index==3 && dim==0)) // the other corner is north east
247  otherCorner = 4;
248  else
249  GISMO_ERROR("Combination unknown...");
250 
251  patchCorner otherPCorner(corner.patch,otherCorner.m_index);
252 
253  cornerList.clear();
254  m_topology.getCornerList(otherPCorner,cornerList);
255  cornerLists.push_back(cornerList);
256  N++;
257  }
258  }
259  boxes.clear();
260  // Assign boxes. This is the box on the current level, level 0.
261  boxes.push_back(0);
262  boxes.insert(boxes.end(), box.data(), box.data()+box.size());
263  patchBoxes.at(corner.patch).insert(patchBoxes.at(corner.patch).end(), boxes.begin(), boxes.end());
264 
265  mask(corner.patch,corner.corner()-1) = true;
266  }// Loop over corners per EV
267  }// Loop over EVs
268  }
269 
270  template<short_t d,class T>
272  {
273  std::vector< std::vector<index_t> > elVec;
274  this->_refBoxes(elVec);
275  m_tMatrices.resize(m_bases0.nBases());
276  for (size_t p=0; p!=m_bases0.nBases(); p++)
277  {
278  // Transform using gsAsMatrix
279  gsAsMatrix<index_t> boxMat(elVec[p],2*d+1,elVec[p].size()/(2*d+1));
280  boxMat.row(0).array() += 1;
281  boxMat.block(1,0,boxMat.rows()-1,boxMat.cols()).array() *= 2;
282 
283  // Refine elements
284  gsHTensorBasis<d,T> *basis = dynamic_cast<gsHTensorBasis<d,T>*>(&m_bases0.basis(p));
285  std::vector< gsSortedVector< index_t > > xmat = basis->getXmatrix();
286  basis->refineElements_withTransfer(elVec[p],m_tMatrices[p]);
287  }
288  m_bases = m_bases0;
289  }
290 
291  template<short_t d,class T>
292  void gsDPatch<d,T>::_makeTHB() //IMPLEMENT THIS
293  {
294  gsMultiBasis<> refBases = m_bases;
295  std::vector< std::vector<index_t> > elVec;
296  this->_refBoxes(elVec);
297 
298  gsSparseMatrix<T> tmp;
299  index_t rows = 0, cols = 0;
300  std::vector<gsEigen::Triplet<T,index_t>> tripletList;
301  for (size_t p=0; p!=m_bases0.nBases(); p++)
302  {
303  // Transform using gsAsMatrix
304  gsAsMatrix<index_t> boxMat(elVec[p],2*d+1,elVec[p].size()/(2*d+1));
305  boxMat.row(0).array() += 2;
306  boxMat.block(1,0,boxMat.rows()-1,boxMat.cols()).array() *= 4;
307 
308  gsHTensorBasis<d,T> *basis = dynamic_cast<gsHTensorBasis<d,T>*>(&refBases.basis(p));
309  std::vector< gsSortedVector< index_t > > xmat = basis->getXmatrix();
310  basis->refineElements_withTransfer(elVec[p],tmp);
311  for (index_t i = 0; i<tmp.outerSize(); ++i)
312  for (typename gsSparseMatrix<T>::iterator it(tmp,i); it; ++it)
313  tripletList.push_back(gsEigen::Triplet<T,index_t>(it.row()+rows,it.col()+cols,it.value()));
314 
315  rows += tmp.rows();
316  cols += tmp.cols();
317  }
318 
319  m_tMatrix.resize(rows,cols);
320  m_tMatrix.setFromTriplets(tripletList.begin(), tripletList.end());
321 
322  m_tMatrix.makeCompressed();
323  m_bases = refBases;
324 
325  // redefine the mappers
326  // m_mapModified = gsDofMapper(m_bases);
327  m_mapOriginal = gsDofMapper(m_bases);
328  m_mapOriginal.finalize();
329  }
330 
331  template<short_t d,class T>
333  {
334  /*
335  Our goal is to create three vectors cij[0], cij[1], cij[2] which all contain the
336  cij[0], cij[1] and cij[2] coefficients of the patches around the EV in the right order
337  (counter)-clockwise.
338  */
339 
340  std::vector<std::vector<patchCorner> > cornerLists;
341  m_topology.getEVs(cornerLists);
342 
343  if (cornerLists.size()!=0)
344  {
345  // gsWriteCSV(m_matrix.toDense(),"matrix0.csv");
346  m_matrix = m_matrix * m_tMatrix.transpose();
347  // gsWriteCSV(m_tMatrix.toDense(),"matrixTHB.csv");
348  // gsWriteCSV(m_matrix.toDense(),"matrix1.csv");
349 
351  std::vector<patchSide> sides(2);
352  std::vector<patchSide> allSides;
353  std::vector<std::vector<patchCorner> > cornerLists;
354  std::vector<patchCorner> corners;
355  std::vector<index_t> allPatches;
356  std::map<index_t,index_t> patches;
357  std::vector<boundaryInterface> interfaces;
358  m_topology.getEVs(cornerLists);
359 
360  sparseEntry_t entries;
361 
362  if (cornerLists.size()!=0)
363  {
364  for (size_t v =0; v!=cornerLists.size(); v++) // over EVs
365  {
366  patches.clear();
367  index_t N = cornerLists[v].size();
368 
369  allPatches.resize(m_bases.nBases());
370  corners.resize(N);
371  interfaces.resize(N);
372 
373  std::vector<gsMatrix<index_t>> cij(3);
374  for (index_t k=0; k!=3; k++)
375  cij.at(k) = gsMatrix<index_t>::Zero(N,1);
376 
377  std::vector<gsMatrix<index_t>> cijo = cij;
378 
379  /*
380  First, we loop over all the interfaces to construct a (counter)clock-wise map for our coefficients
381  Looping clock-wise or counter clock-wise does not matter, as long as the coefficients are neighboring
382  */
383  // Loop over all sides such that we can fill cij[1] and cij[2]. We just start from side 0 of corner 0
384  patchCorner corner = cornerLists[v][0];
385  patchCorner otherCorner = patchCorner(0,0);
386  corner.getContainingSides(d,sides);
387  patchSide side = sides[0];
388  patchSide otherSide;
389  std::vector<patchCorner> pcorners(2);
390 
391  // Initialize patch map
392  for (index_t i = 0; i!=N; i++) // over interfaces
393  {
394  patches.insert(std::make_pair(side.patch,i));
395  corners[i] = corner;
396  bool isInterface = m_topology.getInterface(side,interfaces[i]);
397  GISMO_ENSURE(isInterface,"Side must be an interface!");
398 
399  std::vector<boxCorner> adjcorners;
400  m_topology.getNeighbour(side,otherSide);
401  otherSide.getContainedCorners(d,adjcorners);
402  for (index_t k=0; k!=N; k++)
403  {
404  if (cornerLists[v][k] == patchCorner(otherSide.patch,adjcorners[0]))
405  otherCorner = patchCorner(otherSide.patch,adjcorners[0]);
406  else if (cornerLists[v][k] == patchCorner(otherSide.patch,adjcorners[1]))
407  otherCorner = patchCorner(otherSide.patch,adjcorners[1]);
408  else continue;
409  }
410  GISMO_ENSURE(otherCorner!=patchCorner(0,0),"Error");
411 
412  // interfaces[i] = boundaryInterface(side,otherSide,d);
413  // GISMO_ASSERT(corners[i].patch==interfaces[i].first().patch,"Must be true");
414 
415  // get the NEXT side
416  otherCorner.getContainingSides(d,sides);
417  if (otherSide == sides[0])
418  otherSide = sides[1];
419  else if (otherSide == sides[1])
420  otherSide = sides[0];
421  else
422  GISMO_ERROR("An error occurred.");
423 
424  corner = otherCorner;
425  side = otherSide;
426  }
427 
428  for (index_t i = 0; i!=N; i++) // over corners in EVs
429  {
430 
431  otherCorner = interfaces[i].mapCorner(corners[i]);
432 
433  if (interfaces[i].first().patch==corners[i].patch)
434  {
435  otherSide = interfaces[i].second();
436  side = interfaces[i].first();
437  }
438  else
439  {
440  otherSide = interfaces[i].first();
441  side = interfaces[i].second();
442  }
443 
444  // C11 coefficients
445  cij[0](patches[side.patch],0) = this->_indexFromVert(m_bases,1,corners[i],side,1);
446  // C21 coefficients
447  cij[1](patches[otherSide.patch],0) = this->_indexFromVert(m_bases,2,otherCorner,otherSide,1);
448  // C12 coefficients
449  cij[2](patches[side.patch],0) = this->_indexFromVert(m_bases,2,corners[i],side,1);
450 
451  // C11 coefficients
452  cijo[0](patches[side.patch],0) = this->_indexFromVert(m_bases0,1,corners[i],side,1);
453  // C21 coefficients
454  cijo[1](patches[otherSide.patch],0) = this->_indexFromVert(m_bases0,2,otherCorner,otherSide,1);
455  // C12 coefficients
456  cijo[2](patches[side.patch],0) = this->_indexFromVert(m_bases0,2,corners[i],side,1);
457  }
458 
459  std::vector<gsMatrix<index_t>> rowIndices(3);
460  for (index_t k=0; k!=3; k++)
461  rowIndices.at(k) = gsMatrix<index_t>::Zero(N,1);
462 
463  for (index_t i = 0; i!=N; i++)
464  {
465  corner = corners[i];
466  corner.getContainingSides(d,sides);
467  // we look for the 1,1 index so it does not matter which side we use
468  for (index_t k=0; k!=3; k++)
469  {
470  GISMO_ASSERT(m_mapModified.is_free(cijo[k](i,0),corner.patch),"Something went wrong in the indexing of the sparse matrix for EVs.\n corner = "<<corner.corner()<<"\n patch = "<<corner.patch<<"\n k = "<<k<<"\n i = "<<i<<"\n cijo[k](i,0) = "<<cijo[k](i,0)<<"\n cijo[k] = "<<cijo[k]<<"\n");
471  rowIndices[k](i,0) = m_mapModified.index(cijo[k](i,0),corner.patch);
472  GISMO_ASSERT(m_mapOriginal.is_free(cij[k](i,0),corner.patch),"Something went wrong in the indexing of the sparse matrix for EVs");
473  cij[k](i,0) = m_mapOriginal.index(cij[k](i,0),corner.patch);
474  }
475  }
476 
477  gsMatrix<T> Pi = _makePi(N);
478  gsVector<T> c(3*N);
479  index_t colIdx = 0, idx = 0;
480  for (index_t i = 0; i!=N; i++) // for all involved corners
481  {
482  for (index_t k = 0; k!=3; k++) // loop over ij=11,12,21
483  {
484  for (index_t j=0; j!=N; j++) // loop over the connected corners
485  for (index_t l = 0; l!=3; l++) // loop over ij=11,12,21
486  c.at(j+l*N) = m_matrix.coeff(rowIndices[k](i,0),cij[l](j,0));
487  c = Pi * c;
488  for (index_t j=0; j!=N; j++) // loop over the connected corners
489  for (index_t l = 0; l!=3; l++) // loop over ij=11,12,21
490  entries.push_back(std::make_tuple(rowIndices[k](i,0),cij[l](j,0),c.at(j+l*N)));
491  }
492  }
493 
494  #pragma omp critical (_computeEV1)
495  _push(entries);
496 
497  entries.clear();
498 
499  // smoothing center, i.e all 0,0, 1,0 and 0,1 basis functions get the same value as the 1,1
500  for (index_t i = 0; i!=N; i++) // for all involved corners
501  {
502  for (index_t j=0; j!=N; j++) // loop over the connected corners
503  {
504  for (index_t k = 0; k!=3; k++) // loop over ij=11,12,21
505  {
506  corners[j].getContainingSides(d,sides);
508  colIdx = this->_indexFromVert(m_bases,0,corners[j],sides[0],0); // 0,0
509  GISMO_ASSERT(m_mapOriginal.is_free(colIdx,corners[j].patch),"Something went wrong in the indexing of the sparse matrix for EVs");
510  colIdx = m_mapOriginal.index(colIdx,corners[j].patch);
511  entries.push_back(std::make_tuple(rowIndices[k](i,0),colIdx,m_matrix.coeff(rowIndices[k](i,0),cij[0](j,0))));
512 
513  colIdx = this->_indexFromVert(m_bases,1,corners[j],sides[0],0); // 1,0
514  GISMO_ASSERT(m_mapOriginal.is_free(colIdx,corners[j].patch),"Something went wrong in the indexing of the sparse matrix for EVs");
515  colIdx = m_mapOriginal.index(colIdx,corners[j].patch);
516  entries.push_back(std::make_tuple(rowIndices[k](i,0),colIdx,m_matrix.coeff(rowIndices[k](i,0),cij[0](j,0))));
517 
518  colIdx = this->_indexFromVert(m_bases,1,corners[j],sides[1],0); // 0,1
519  GISMO_ASSERT(m_mapOriginal.is_free(colIdx,corners[j].patch),"Something went wrong in the indexing of the sparse matrix for EVs");
520  colIdx = m_mapOriginal.index(colIdx,corners[j].patch);
521  entries.push_back(std::make_tuple(rowIndices[k](i,0),colIdx,m_matrix.coeff(rowIndices[k](i,0),cij[0](j,0))));
522 
523  }
524  }
525  }
526 
527  #pragma omp critical (_computeEV2)
528  _push(entries);
529 
530  entries.clear();
531 
532  // interface smoothing
533  for (index_t i = 0; i!=N; i++) // for all involved interfaces
534  {
535  patchCorner corner = corners[patches[interfaces[i][0].patch]];
536  patchCorner otherCorner = corners[patches[interfaces[i][1].patch]];
537  patchSide side = interfaces[i][0];
538  patchSide otherSide = interfaces[i][1];
539  for (index_t k = 2; k!=4 ; k++)// std::max(basis1->maxDegree(),basis2->maxDegree())+
540  {
541  idx = this->_indexFromVert(m_bases,k,corner,side,0);
542  GISMO_ASSERT(m_mapOriginal.is_free(idx,side.patch),"Something went wrong in the indexing of the sparse matrix for EVs");
543  index_t j0k = m_mapOriginal.index(idx,side.patch);
544 
545  idx = this->_indexFromVert(m_bases,k,otherCorner,otherSide,0);
546  GISMO_ASSERT(m_mapOriginal.is_free(idx,otherSide.patch),"Something went wrong in the indexing of the sparse matrix for EVs");
547  index_t jk0 = m_mapOriginal.index(idx,otherSide.patch);
548 
549  idx = this->_indexFromVert(m_bases,k,corner,side,1); // point (k,0)
550  GISMO_ASSERT(m_mapOriginal.is_free(idx,side.patch),"Something went wrong in the indexing of the sparse matrix for EVs");
551  index_t jk1 = m_mapOriginal.index(idx,side.patch); // point (k,0)
552 
553  idx = this->_indexFromVert(m_bases,k,otherCorner,otherSide,1); // point (k,0)
554  GISMO_ASSERT(m_mapOriginal.is_free(idx,otherSide.patch),"Something went wrong in the indexing of the sparse matrix for EVs");
555  index_t j1k = m_mapOriginal.index(idx,otherSide.patch); // point (k,0)
556 
557  index_t row;
558  for (index_t l = 0; l!=3; l++) // loop over ij=11,12,21
559  {
560  for (index_t r=0; r!=N; r++)
561  {
562  row = rowIndices[l](r,0);
563  entries.push_back(std::make_tuple(rowIndices[l](r,0),j0k,0.5 * ( m_matrix.coeff(row,jk1) + m_matrix.coeff(row,j1k) )));
564  entries.push_back(std::make_tuple(rowIndices[l](r,0),jk0,0.5 * ( m_matrix.coeff(row,jk1) + m_matrix.coeff(row,j1k) )));
565  }
566  }
567  }
568  }
569 
570  #pragma omp critical (_computeEV3)
571  _push(entries);
572  }
573  }
574  }
575 
576  m_matrix.makeCompressed();
577  // gsDebugVar(m_matrix.toDense());
578  }
579 
580  template<short_t d,class T>
582  {
583  gsMatrix<T> Pi(3*valence,3*valence);
584  gsMatrix<T> P(valence,9);
585  P.setZero();
586 
587  T pi = 4*std::atan(1);
588  T phi = 2*pi / valence;
589  std::complex<T> I(0,1);
590  T beta = m_options.getReal("Beta") * std::pow(0.5,m_options.getInt("RefLevel"));
591  T psi = std::arg( std::complex<T>((T(1.0)+I*beta*T(math::sin(phi)))*math::exp( -I*phi / T(2.0) ) ));
592  if (m_options.getInt("Pi")==0)//idempotent
593  {
594  for (index_t j=0; j!=valence; j++)
595  {
596  P(j,0) = P(j,1) = P(j,2) = P(j,3) = P(j,6) = 1.0 / (3.0 * valence);;
597  P(j,4) = P(j,8) = 1.0 / (3.0 * valence) * ( 1.0 + 3.0*math::cos( j * phi ) );
598  P(j,5) = 1.0 / (3.0 * valence) * ( 1.0 + 3.0*math::cos( 2.0 * psi + j * phi ) );
599  P(j,7) = 1.0 / (3.0 * valence) * ( 1.0 + 3.0*math::cos( 2.0 * psi - j * phi ) );
600  }
601  }
602  else if (m_options.getInt("Pi")==1) //non-negative entries
603  {
604  for (index_t j=0; j!=valence; j++)
605  {
606  P(j,0) = P(j,3) = P(j,6) = 0;
607  P(j,1) = P(j,2) = 1.0 / (2.0 * valence);
608  P(j,4) = P(j,8) = 1.0 / (2.0 * valence) * ( 1.0 + math::cos( j * phi ) );
609  P(j,5) = 1.0 / (2.0 * valence) * ( 1.0 + math::cos( 2.0 * psi + j * phi ) );
610  P(j,7) = 1.0 / (2.0 * valence) * ( 1.0 + math::cos( 2.0 * psi - j * phi ) );
611  }
612  }
613  else
614  GISMO_ERROR("Pi option unknown");
615 
616  index_t offsetI, offsetJ = 0;
617  gsMatrix<T> tmp(valence,valence);
618  for (index_t i=0; i!=9; i++)
619  {
620  offsetI = (i / 3)*valence;// std::floor(i/3)
621  offsetJ = (i % 3)*valence;
622  for (index_t j=0; j!=valence; j++ )
623  for (index_t k=0; k!=valence; k++ )
624  {
625  index_t c = (j-k) % valence;
626  if (c < 0)
627  c += valence;
628  tmp(j,k) = P( c, i);
629  }
630 
631  // gsDebugVar(offsetI);
632  // gsDebugVar(offsetJ);
633  // tmp.setOnes();
634  // tmp *= i;
635  Pi.block(offsetI,offsetJ,valence, valence) = tmp;
636  }
637 
638  return Pi;
639  }
640 
641  template<short_t d,class T>
642  void gsDPatch<d,T>::_countDoFs() // also initialize the mappers!
643  {
644  size_t tmp;
645  m_size = tmp = 0;
646  // number of interior basis functions
647  for (size_t p=0; p!=m_bases.nBases(); p++)
648  {
649  tmp += m_bases.basis(p).size();
650  for (index_t k=0; k!=2; k++)
651  {
652  tmp -= m_bases.basis(p).boundaryOffset(boxSide(1),k).size();
653  tmp -= m_bases.basis(p).boundaryOffset(boxSide(2),k).size();
654  tmp -= m_bases.basis(p).boundaryOffset(boxSide(3),k).size()-4;
655  tmp -= m_bases.basis(p).boundaryOffset(boxSide(4),k).size()-4;
656  }
657  }
658 
659  // gsDebug<<"Number of interior DoFs: "<<tmp<<"\n";
660  m_size += tmp;
661 
662  // interfaces
663  gsBasis<T> * basis1;
664  gsBasis<T> * basis2;
665  gsVector<index_t> indices1,indices2;
666  tmp = 0;
667  for(gsBoxTopology::const_iiterator iit = m_topology.iBegin(); iit!= m_topology.iEnd(); iit++)
668  {
669  basis1 = &m_bases.basis(iit->first().patch);
670  basis2 = &m_bases.basis(iit->second().patch);
671  tmp += basis1->boundary(iit->first().side()).size() - 4;
672  tmp += basis2->boundary(iit->second().side()).size() - 4;
673  }
674  // gsDebug<<"Number of interface DoFs: "<<tmp<<"\n";
675  m_size += tmp;
676 
677  // boundaries
678  tmp = 0;
679  for(gsBoxTopology::const_biterator bit = m_topology.bBegin(); bit!= m_topology.bEnd(); bit++)
680  {
681  basis1 = &m_bases.basis(bit->patch);
682  tmp += (basis1->boundaryOffset(bit->side(),0).size() - 4);
683  tmp += (basis1->boundaryOffset(bit->side(),1).size() - 4);
684  }
685  // gsDebug<<"Number of boundary DoFs: "<<tmp<<"\n";
686  m_size += tmp;
687 
688  // vertices
689  tmp = 0;
690  std::vector<bool> passed(m_bases.nBases()*4);
691  std::fill(passed.begin(), passed.end(), false);
692 
693  std::vector<patchCorner> corners;
694  // index_t corn = 0;
695  for (size_t p=0; p!=m_bases.nBases(); p++)
696  for (index_t c=1; c<5; c++)
697  {
698  index_t idx = this->_vertIndex(p,c);
699  if (!passed.at(idx))
700  {
701  m_topology.getCornerList(patchCorner(p,c),corners);
702 
703  for (size_t k=0; k!=corners.size(); k++)
704  passed.at(this->_vertIndex(corners[k].patch,corners[k])) = true;
705 
706  std::pair<index_t,bool> vdata = this->_vertexData(patchCorner(p,c)); // corner c
707  bool C0 = m_C0s[idx];
708  if ((!vdata.second) && vdata.first==1) // valence = 1, must be a boundary vertex
709  tmp += 4;
710  else if ((!vdata.second) && vdata.first==2 && !C0)
711  tmp += 4;
712  else if ((!vdata.second) && vdata.first>2 && !C0)
713  tmp += 4;
714  else if ((!vdata.second) && vdata.first==2 && C0)
715  tmp += 6;
716  else if ((!vdata.second) && vdata.first>2 && C0)
717  tmp += 4;
718  else
719  tmp += vdata.first; // valence;
720 
721  // corn +=1;
722  }
723  }
724  // gsDebug<<"Number of unique corners: "<<corn<<"\n";
725 
726  // gsDebug<<"Number of vertex DoFs: "<<tmp<<"\n";
727 
728  m_size += tmp;
729  }
730 
731  template<short_t d,class T>
733  {
734  // // 2. make container for the interfaces
735  // std::vector<boundaryInterface> ifaces;
736  // boundaryInterface iface;
737  // std::vector<patchSide> boundaries;
738  // index_t extraRow;
739  // std::vector<patchCorner> temp_corners, corners;
740  // std::vector<patchSide> psides;
741  // std::vector<index_t> colIndices,rowIndices, patches;
742 
743  // sparseEntry_t entries;
744 
745  // m_topology.getCornerList(pcorner,corners);
746 
747  // /*
748  // Warning:
749  // This case handles all patchCorners related to this vertex at once!
750  // */
751 
752  // // 1. get all adjacent vertices
753 
754  // // find corner with the lowest patch index
755  // patchCorner lowest = corners[0];
756  // for (size_t k=0; k!=corners.size(); k++)
757  // lowest = (corners[k].patch < lowest.patch ) ? corners[k] : lowest;
758 
759  // lowest.getContainingSides(d,psides);
760  // // get (0,0) index from the corner with lowest patch number and store the row index.
761  // extraRow = this->_indexFromVert(0,lowest,psides[0],0);
762  // extraRow = m_mapModified.index(extraRow,lowest.patch);
763 
764  // // 2. loop over the adjacent vertices
765  // colIndices.clear();
766  // rowIndices.clear();
767  // patches.clear();
768  // for (std::vector<patchCorner>::iterator it = corners.begin(); it!=corners.end(); ++it)
769  // {
770  // // *it is a patchCorner
771  // // 3. determine if one of the contained sides is a boundary
772  // it->getContainingSides(d,psides);
773 
774  // // store the 0,0 indices
775  // colIndices.push_back( this->_indexFromVert(0,*it,psides[0],0) );
776  // rowIndices.push_back( this->_indexFromVert(1,*it,psides[0],1) );
777  // patches.push_back(it->patch);
778 
779  // for (index_t k = 0; k!=2; k++) // index of point over the interface
780  // {
781  // if ( m_topology.getInterface(psides[k],iface) ) // if it is an interface, store it
782  // {
783  // ifaces.push_back(iface);
784  // }
785  // else // if not, then store the side
786  // {
787  // //
788  // index_t colIdx = m_mapOriginal.index(this->_indexFromVert(1,*it,psides[k],0),it->patch);
789  // index_t rowIdx = m_mapModified.index(this->_indexFromVert(1,*it,psides[k],1),it->patch);
790  // entries.push_back(std::make_tuple(rowIdx,colIdx,0.5));
791  // entries.push_back(std::make_tuple(extraRow,colIdx,0.5));
792  // // m_matrix(rowIdx,colIdx) = 0.5;
793  // // m_matrix(extraRow,colIdx) = 0.5;
794  // // m_basisCheck[rowIdx] = true;
795  // }
796  // }
797  // }
798 
799  // // GISMO_ASSERT(boundaries.size()==2,"There must be two boundaries that are not an interface!");
800  // // ifaces.push_back(boundaryInterface(boundaries[0],boundaries[1],d));
801 
802  // // the extra (0,0) node gets 0.25 for all (0,0) entries
803  // for (size_t k = 0; k!=colIndices.size(); k++)
804  // {
805  // index_t colIdx = m_mapOriginal.index(colIndices[k],patches[k]);
806  // entries.push_back(std::make_tuple(extraRow,colIdx,0.25));
807  // // m_matrix(extraRow,colIdx) = 0.25;
808  // }
809 
810  // // Fill the matrix entries related to the 1,1 coefs (stored in indices) with 1 for itself and with 0.25 for the others
811  // for (size_t k = 0; k!=rowIndices.size(); k++)
812  // {
813  // index_t rowIdx = m_mapModified.index(rowIndices[k],patches[k]);
814  // index_t colIdx = m_mapOriginal.index(rowIndices[k],patches[k]);
815  // // Fill the matrix entries related to itself (1,1) with a 1.0
816  // entries.push_back(std::make_tuple(rowIdx,colIdx,1.0));
817  // // m_matrix(rowIdx,colIdx) = 1.0;
818 
819  // for (size_t l = 0; l!=colIndices.size(); l++)
820  // {
821  // // Fill the matrix entries related to the 0,0 coefs (stored in indices) 0.25 for all corners
822  // colIdx = m_mapOriginal.index(colIndices[l],patches[l]);
823  // entries.push_back(std::make_tuple(extraRow,colIdx,0.25));
824  // // m_matrix(rowIdx,colIdx) = 0.25;
825  // }
826 
827  // // m_basisCheck[rowIdx] = true;
828  // }
829 
830  // rowIndices.resize(2);
831  // colIndices.resize(2);
832  // patches.resize(2);
833 
834  // // extra point handling
835  // colIndices.resize(2);
836  // for (std::vector<patchSide>::iterator it = boundaries.begin(); it!=boundaries.end(); ++it)
837  // {
838  // // find which corner of the interface
839  // it->getContainedCorners(d,temp_corners);
840  // for (std::vector<patchCorner>::iterator corn = temp_corners.begin(); corn!=temp_corners.end(); ++corn)
841  // {
842  // if ( std::find(corners.begin(), corners.end(), *corn) == corners.end() ) // the contained corner is not in corners
843  // continue;
844 
845  // index_t colIdx = this->_indexFromVert(1,*corn,*it,0);
846  // colIdx = m_mapOriginal.index(colIdx,corn->patch);
847  // entries.push_back(std::make_tuple(extraRow,colIdx,0.5));
848  // // m_matrix(extraRow,colIdx) = 0.5;
849 
850  // }
851  // }
852 
853  // // m_basisCheck[extraRow] = true;
854  // // }
855  // // Interface handling
856  // for (std::vector<boundaryInterface>::iterator it = ifaces.begin(); it!=ifaces.end(); ++it)
857  // {
858  // // if (!m_topology.isInterface(it->first()))
859  // // continue;
860 
861  // // find which corner of the interface
862  // it->first().getContainedCorners(d,temp_corners);
863 
864  // std::vector<patchSide> isides(2);
865  // std::vector<patchCorner> icorners(2);
866 
867  // for (std::vector<patchCorner>::iterator corn = temp_corners.begin(); corn!=temp_corners.end(); ++corn)
868  // {
869  // if ( std::find(corners.begin(), corners.end(), *corn) == corners.end() ) // the contained corner is not in corners
870  // {
871  // continue;
872  // }
873 
874  // // Now we need to fill the matrix for the rows corresponding to the (1,1) coefficients of the corners
875  // icorners[0] = *corn;
876  // icorners[1] = it->mapCorner(*corn);
877  // isides[0] = it->first();
878  // isides[1] = it->second();
879 
880  // // get rowIndices
881  // for (size_t k=0; k!=icorners.size(); k++)
882  // {
883  // rowIndices[k] = this->_indexFromVert(1,icorners[k],isides[k],1);
884  // colIndices[k] = this->_indexFromVert(1,icorners[k],isides[k],0);
885  // patches[k] = icorners[k].patch;
886  // }
887 
888  // for (size_t k = 0; k!=rowIndices.size(); k++)
889  // {
890  // index_t rowIdx = m_mapModified.index(rowIndices[k],patches[k]);
891  // // Fill the matrix entries related to the 0,0 coefs (stored in indices) 0.25 for all corners
892  // for (size_t l = 0; l!=colIndices.size(); l++)
893  // {
894  // index_t colIdx = m_mapOriginal.index(colIndices[l],patches[l]);
895  // entries.push_back(std::make_tuple(rowIdx,colIdx,0.5));
896  // // m_matrix(rowIdx,colIdx) = 0.5;
897  // }
898  // // m_basisCheck[rowIdx] = true;
899  // }
900  // }
901  // }
902 
903  // #pragma omp critical (handle_boundary_vertex_ff)
904  // {
905  // _pushAndCheck(entries);
906 
907  // // Furthermore, all adjacent vertices are checked
908  // for (std::vector<patchCorner>::iterator it = corners.begin(); it!=corners.end(); ++it)
909  // m_vertCheck[ this->_vertIndex(it->patch, it->corner()) ] = true;
910  // }
911 
912  // 2. make container for the interfaces
913  std::vector<boundaryInterface> ifaces;
914  boundaryInterface iface;
915  std::vector<patchSide> boundaries;
916  index_t extraRow;
917  std::vector<patchCorner> temp_corners, corners;
918  std::vector<patchSide> psides;
919  std::vector<index_t> colIndices,rowIndices, patches;
920 
921  sparseEntry_t entries;
922 
923  m_topology.getCornerList(pcorner,corners);
924 
925  // if (!(std::count(m_C0s.begin(), m_C0s.end(), pcorner)))
926  // {
927  if ((std::count(m_C0s.begin(), m_C0s.end(), pcorner)))
928  gsWarn<<"C0 handling for boundary corners with valence 3 has not yet been implemented\n";
929 
930 
931  /*
932  Warning:
933  This case handles all patchCorners related to this vertex at once!
934  */
935 
936  // 1. get all adjacent vertices
937 
938  // find corner with the lowest patch index
939  patchCorner lowest = corners[0];
940  for (size_t k=0; k!=corners.size(); k++)
941  lowest = (corners[k].patch < lowest.patch ) ? corners[k] : lowest;
942 
943  lowest.getContainingSides(d,psides);
944  // get (0,0) index from the corner with lowest patch number and store the row index.
945  extraRow = this->_indexFromVert(0,lowest,psides[0],0);
946  extraRow = m_mapModified.index(extraRow,lowest.patch);
947 
948  // 2. loop over the adjacent vertices
949  colIndices.clear();
950  rowIndices.clear();
951  patches.clear();
952  for (std::vector<patchCorner>::iterator it = corners.begin(); it!=corners.end(); ++it)
953  {
954  // *it is a patchCorner
955  // 3. determine if one of the contained sides is a boundary
956  it->getContainingSides(d,psides);
957 
958  // store the 0,0 indices
959  colIndices.push_back( this->_indexFromVert(0,*it,psides[0],0) );
960  rowIndices.push_back( this->_indexFromVert(1,*it,psides[0],1) );
961  patches.push_back(it->patch);
962 
963  for (index_t k = 0; k!=2; k++) // index of point over the interface
964  {
965  if ( m_topology.getInterface(psides[k],iface) ) // if it is an interface, store it
966  {
967  ifaces.push_back(iface);
968  }
969  else // if not, then store the side
970  {
971  //
972  index_t colIdx = m_mapOriginal.index(this->_indexFromVert(1,*it,psides[k],0),it->patch);
973  index_t rowIdx = m_mapModified.index(this->_indexFromVert(1,*it,psides[k],1),it->patch);
974  // m_matrix(rowIdx,colIdx) = 0.5;
975  // m_matrix(extraRow,colIdx) = 0.5;
976  // m_basisCheck[rowIdx] = true;
977  entries.push_back(std::make_tuple(rowIdx,colIdx,0.5));
978  entries.push_back(std::make_tuple(extraRow,colIdx,0.5));
979  // boundaries.push_back(psides[k]);
980  }
981  }
982  }
983 
984  // GISMO_ASSERT(boundaries.size()==2,"There must be two boundaries that are not an interface!");
985  // ifaces.push_back(boundaryInterface(boundaries[0],boundaries[1],d));
986 
987 
988 
989 
990  // the extra (0,0) node gets 0.25 for all (0,0) entries
991  for (size_t k = 0; k!=colIndices.size(); k++)
992  {
993  index_t colIdx = m_mapOriginal.index(colIndices[k],patches[k]);
994  // m_matrix(extraRow,colIdx) = 0.25;
995  entries.push_back(std::make_tuple(extraRow,colIdx,0.25));
996 
997  }
998  // Fill the matrix entries related to the 1,1 coefs (stored in indices) with 1 for itself and with 0.25 for the others
999  for (size_t k = 0; k!=rowIndices.size(); k++)
1000  {
1001  index_t rowIdx = m_mapModified.index(rowIndices[k],patches[k]);
1002  index_t colIdx = m_mapOriginal.index(rowIndices[k],patches[k]);
1003  // Fill the matrix entries related to itself (1,1) with a 1.0
1004  entries.push_back(std::make_tuple(rowIdx,colIdx,1.0));
1005  // m_matrix(rowIdx,colIdx) = 1.0;
1006 
1007  for (size_t l = 0; l!=colIndices.size(); l++)
1008  {
1009  // Fill the matrix entries related to the 0,0 coefs (stored in indices) 0.25 for all corners
1010  colIdx = m_mapOriginal.index(colIndices[l],patches[l]);
1011  // m_matrix(rowIdx,colIdx) = 0.25;
1012  entries.push_back(std::make_tuple(rowIdx,colIdx,0.25));
1013  }
1014 
1015  // m_basisCheck[rowIdx] = true;
1016  }
1017 
1018  rowIndices.resize(2);
1019  colIndices.resize(2);
1020  patches.resize(2);
1021 
1022  // extra point handling
1023  colIndices.resize(2);
1024  for (std::vector<patchSide>::iterator it = boundaries.begin(); it!=boundaries.end(); ++it)
1025  {
1026  // find which corner of the interface
1027  it->getContainedCorners(d,temp_corners);
1028  for (std::vector<patchCorner>::iterator corn = temp_corners.begin(); corn!=temp_corners.end(); ++corn)
1029  {
1030  if ( std::find(corners.begin(), corners.end(), *corn) == corners.end() ) // the contained corner is not in corners
1031  continue;
1032 
1033  index_t colIdx = this->_indexFromVert(1,*corn,*it,0);
1034  colIdx = m_mapOriginal.index(colIdx,corn->patch);
1035  entries.push_back(std::make_tuple(extraRow,colIdx,0.5));
1036  // m_matrix(extraRow,colIdx) = 0.5;
1037 
1038  }
1039  }
1040 
1041  // m_basisCheck[extraRow] = true;
1042  // }
1043  // Interface handling
1044  for (std::vector<boundaryInterface>::iterator it = ifaces.begin(); it!=ifaces.end(); ++it)
1045  {
1046  // if (!m_topology.isInterface(it->first()))
1047  // continue;
1048 
1049  // find which corner of the interface
1050  it->first().getContainedCorners(d,temp_corners);
1051 
1052  std::vector<patchSide> isides(2);
1053  std::vector<patchCorner> icorners(2);
1054 
1055  for (std::vector<patchCorner>::iterator corn = temp_corners.begin(); corn!=temp_corners.end(); ++corn)
1056  {
1057  if ( std::find(corners.begin(), corners.end(), *corn) == corners.end() ) // the contained corner is not in corners
1058  {
1059  continue;
1060  }
1061 
1062  // Now we need to fill the matrix for the rows corresponding to the (1,1) coefficients of the corners
1063  icorners[0] = *corn;
1064  icorners[1] = it->mapCorner(*corn);
1065  isides[0] = it->first();
1066  isides[1] = it->second();
1067 
1068  // get rowIndices
1069  for (size_t k=0; k!=icorners.size(); k++)
1070  {
1071  rowIndices[k] = this->_indexFromVert(1,icorners[k],isides[k],1);
1072  colIndices[k] = this->_indexFromVert(1,icorners[k],isides[k],0);
1073  patches[k] = icorners[k].patch;
1074  }
1075 
1076  for (size_t k = 0; k!=rowIndices.size(); k++)
1077  {
1078  index_t rowIdx = m_mapModified.index(rowIndices[k],patches[k]);
1079  // Fill the matrix entries related to the 0,0 coefs (stored in indices) 0.25 for all corners
1080  for (size_t l = 0; l!=colIndices.size(); l++)
1081  {
1082  index_t colIdx = m_mapOriginal.index(colIndices[l],patches[l]);
1083  entries.push_back(std::make_tuple(rowIdx,colIdx,0.5));
1084  // m_matrix(rowIdx,colIdx) = 0.5;
1085  }
1086  // m_basisCheck[rowIdx] = true;
1087  }
1088  }
1089 
1090  }
1091 
1092  #pragma omp critical (handle_boundary_vertex_ff)
1093  {
1094  _pushAndCheck(entries);
1095 
1096  // Furthermore, all adjacent vertices are checked
1097  for (std::vector<patchCorner>::iterator it = corners.begin(); it!=corners.end(); ++it)
1098  m_vertCheck[ this->_vertIndex(it->patch, it->corner()) ] = true;
1099  }
1100  }
1101 
1102  template<short_t d,class T>
1104  {
1105  gsWarn<<"C0 handling for boundary corners with valence 3 has not yet been implemented. Using the default approach\n";
1106  this->_handleIrregularBoundaryVertexSmooth(pcorner,valence);
1107  }
1108 
1109  template<short_t d,class T>
1110  void gsDPatch<d,T>::_computeVertexMapper(patchCorner pcorner)
1111  {
1112  index_t cidx = _vertIndex(pcorner.patch,pcorner.corner());
1113  if (m_vertCheck.at(cidx))
1114  return;
1115 
1116  bool C0 = m_C0s[cidx];
1117  bool interior;
1118  index_t valence;
1119 
1120  std::tie(valence,interior) = _vertexData(pcorner); // corner c
1121  if (!interior && valence==1) //valence = 1
1122  _computeMapperRegularCorner_v1(pcorner,valence);
1123  else if (!interior && valence==2 && C0)
1124  _computeMapperRegularBoundaryVertexNonSmooth_v2(pcorner,valence);
1125  else if (!interior && valence==2 && !C0)
1126  _computeMapperRegularBoundaryVertexSmooth_v2(pcorner,valence);
1127  else if (!interior && valence==3 && C0)
1128  _computeMapperIrregularBoundaryVertexNonSmooth_v3(pcorner,valence);
1129  else if (!interior && valence==3 && !C0)
1130  _computeMapperIrregularBoundaryVertexSmooth_v3(pcorner,valence);
1131  else if (!interior && valence >3 && C0)
1132  _computeMapperIrregularBoundaryVertexNonSmooth_v(pcorner,valence);
1133  else if (!interior && valence >3 && !C0)
1134  _computeMapperIrregularBoundaryVertexSmooth_v(pcorner,valence);
1135  else if (interior)
1136  _computeMapperInteriorVertex_v(pcorner,valence);
1137  else
1138  GISMO_ERROR("Something went terribly wrong, interior="<<interior<<"; valence="<<valence);
1139 
1140  // label vertex as processed
1141  m_vertCheck[ cidx ] = true;
1142  }
1143 
1144  // Different for DPatch and AlmostC1
1145  template<short_t d,class T>
1146  void gsDPatch<d,T>::_computeMapperIrregularBoundaryVertexSmooth_v3(patchCorner pcorner, index_t valence)
1147  {
1148  std::vector<patchSide> psides(2);
1149  std::vector<patchCorner> pcorners;
1150  /*
1151  o o o @ X |i| X @ o o o x: eliminated DoFs by vertex rule
1152  o o o @ X |n| X @ o o o X: eliminated DoFs by interface/boundary rule
1153  o o o @ X |t| X @ o o o o: preserved DoFs (interior)
1154  @ @ @ * x |e| x * @ @ @ @: modified DoFs by interface rule
1155  X X X x % |r| % x X X X *: modified DoFs by vertex rule (unique DoFs)
1156  ----------------------- %: modified DoFs by vertex rule (matched DoFs)
1157  -boundary-| |-interface
1158  -----------------------
1159  b| | % x X X X
1160  o| | x * @ @ @
1161  u| | X @ o o o
1162  n| | X @ o o o
1163  d| | X @ o o o
1164 
1165  */
1166  // if (!(std::count(m_C0s.begin(), m_C0s.end(), pcorner)))
1167  // {
1168 
1169  // We handle all corners associated to pcorner
1170  m_topology.getCornerList(pcorner,pcorners);
1171 
1172  for (size_t c=0; c!=pcorners.size(); c++)
1173  {
1174  // Eliminate their 0,1 and 1,0 vertices
1175  pcorners[c].getContainingSides(d,psides);
1176  m_mapModified.eliminateDof(this->_indexFromVert(1,pcorners[c],psides[0]),pcorners[c].patch);
1177  m_mapModified.eliminateDof(this->_indexFromVert(1,pcorners[c],psides[1]),pcorners[c].patch);
1178 
1179  // And match the 0,0 vertex (i.e. the corner) to the corner that is first in the list pcorners.
1180  patchSide pseudo; // this side does not contribute since we use index = 0 in this->_indexFromVert
1181  if (c!=0)
1182  m_mapModified.matchDof(pcorners[0].patch,this->_indexFromVert(0,pcorners[0],pseudo,0),pcorners[c].patch,this->_indexFromVert(0,pcorners[c],pseudo,0));
1183  // mark the vertex as passed
1184  m_vertCheck[ this->_vertIndex(pcorners[c].patch, pcorners[c].corner()) ] = true;
1185  }
1186  // }
1187  // else
1188  // {
1189  // pcorner.getContainingSides(d,psides);
1190  // for (size_t p=0; p!=psides.size(); p++)
1191  // {
1192  // if (m_topology.isInterface(psides[p]))
1193  // {
1194  // m_mapModified.eliminateDof(this->_indexFromVert(1,pcorner,psides[p],0),pcorner.patch);
1195  // }
1196  // }
1197  // }
1198  }
1199 
1200  // Different for DPatch and AlmostC1
1201  template<short_t d,class T>
1202  void gsDPatch<d,T>::_computeMapperIrregularBoundaryVertexNonSmooth_v3(patchCorner pcorner, index_t valence)
1203  {
1204  gsWarn<<"C0 handling for boundary corners with valence 3 has not yet been implemented. Using the default approach\n";
1205  this->_computeMapperIrregularBoundaryVertexSmooth_v3(pcorner,valence);
1206  }
1207 
1208  template<short_t d,class T>
1209  void gsDPatch<d,T>::_computeMapperIrregularBoundaryVertexSmooth_v(patchCorner pcorner, index_t valence)
1210  {
1211  GISMO_ERROR("Boundary vertex on patch"<<pcorner.patch<<" with index "<<pcorner.corner()<<" with valence = "<<valence<<" has no implementation");
1212  }
1213 
1214  template<short_t d,class T>
1215  void gsDPatch<d,T>::_computeMapperIrregularBoundaryVertexNonSmooth_v(patchCorner pcorner, index_t valence)
1216  {
1217  GISMO_ERROR("Boundary vertex on patch"<<pcorner.patch<<" with index "<<pcorner.corner()<<" with valence = "<<valence<<" has no implementation");
1218  }
1219 
1220 } // namespace gismo
void _handleIrregularBoundaryVertexSmooth(patchCorner pcorner, index_t valence) override
Handles a vertex in the global matrix.
Definition: gsDPatch.hpp:732
Provides definition of HTensorBasis abstract interface.
internal::gsUKnotIterator< T > uiterator
Definition: gsKnotVector.h:102
short_t degree(short_t i) const
Returns the degree of the basis wrt variable i.
Definition: gsTensorBasis.h:465
void parameters_into(index_t dim, gsVector< bool > &param) const
returns a vector of parameters describing the position of the corner
Definition: gsBoundary.h:322
Struct which represents a certain side of a patch.
Definition: gsBoundary.h:231
Creates a mapped object or data pointer to a matrix without copying data.
Definition: gsLinearAlgebra.h:126
short_t geoDim() const
Dimension of the geometry (must match for all patches).
Definition: gsMultiPatch.hpp:149
#define short_t
Definition: gsConfig.h:35
Simple class create a block preconditioner structure.
size_t numElements() const
Number of knot intervals inside domain.
Definition: gsKnotVector.h:268
void getContainedCorners(short_t dim, std::vector< patchCorner > &corners) const
returns the vector of the corners contained in the side
Definition: gsBoundary.cpp:35
Provides declaration of THBSplineBasis class.
#define index_t
Definition: gsConfig.h:32
#define GISMO_ENSURE(cond, message)
Definition: gsDebug.h:102
void getContainingSides(short_t dim, std::vector< patchSide > &sides) const
returns a vector of patchSides that contain this corner
Definition: gsBoundary.h:416
virtual void uniformRefine(int numKnots=1, int mul=1, int dir=-1)
Refine the basis uniformly by inserting numKnots new knots with multiplicity mul on each knot span...
Definition: gsTensorBasis.h:315
Provides declaration of functions writing Paraview files.
A tensor product B-spline basis.
Definition: gsTensorBSplineBasis.h:36
Struct which represents a certain corner of a patch.
Definition: gsBoundary.h:392
#define GISMO_ASSERT(cond, message)
Definition: gsDebug.h:89
Maintains a mapping from patch-local dofs to global dof indices and allows the elimination of individ...
Definition: gsDofMapper.h:68
gsDPatch()
Empty constructor.
Definition: gsDPatch.h:48
Provides declaration of THBSplineBasis class.
Class representing a (scalar) hierarchical tensor basis of functions .
Definition: gsHTensorBasis.h:74
#define gsWarn
Definition: gsDebug.h:50
Holds a set of patch-wise bases and their topology information.
Definition: gsMultiBasis.h:36
void _countDoFs() override
Initializes the matrix, the basis and the mappers.
Definition: gsDPatch.hpp:642
gsGeometry< T > & patch(size_t i) const
Return the i-th patch.
Definition: gsMultiPatch.h:226
const gsBasis< T > & basis(const index_t k) const
Helper which casts and returns the k-th piece of this function set as a gsBasis.
Definition: gsFunctionSet.hpp:33
void addLevel(const gsTensorBSplineBasis< d, T > &next_basis)
Adds a level, only if manual levels are activated.
Definition: gsHTensorBasis.hpp:35
void defaultOptions() override
Sets the default options.
Definition: gsDPatch.hpp:51
Constructs the D-Patch, from which the transformation matrix can be called.
Definition: gsDPatchBase.h:36
T at(index_t i) const
Returns the i-th element of the vector.
Definition: gsVector.h:177
Container class for a set of geometry patches and their topology, that is, the interface connections ...
Definition: gsMultiPatch.h:33
Struct which represents a certain side of a box.
Definition: gsBoundary.h:84
uPtr clone()
Clone methode. Produceds a deep copy inside a uPtr.
Constructs the D-Patch, from which the transformation matrix can be called.
Definition: gsDPatch.h:33
void _computeEVs() override
Corrects the EVs.
Definition: gsDPatch.hpp:332
virtual gsMatrix< index_t > boundaryOffset(boxSide const &s, index_t offset) const
Definition: gsBasis.hpp:316
const gsBasis< T > & basis(const size_t i) const
Return the i-th basis block.
Definition: gsMultiBasis.h:267
tensorBasis & tensorLevel(index_t i) const
Returns the tensor basis member of level i.
Definition: gsHTensorBasis.h:668
#define GISMO_ERROR(message)
Definition: gsDebug.h:118
Class for representing a knot vector.
Definition: gsKnotVector.h:79
void _initTHB() override
Initializes the matrix, the basis and the mappers.
Definition: gsDPatch.hpp:144
void _initBasis() override
Initializes the basis.
Definition: gsDPatch.hpp:271
Struct which represents an interface between two patches.
Definition: gsBoundary.h:649
size_t uSize() const
Number of unique knots (i.e., without repetitions).
Definition: gsKnotVector.h:245
Truncated hierarchical B-spline basis.
Definition: gsTHBSplineBasis.h:35
void _makeTHB() override
Prints which DoFs have been handled and which have been eliminated.
Definition: gsDPatch.hpp:292
int degree() const
Returns the degree of the knot vector.
Definition: gsKnotVector.hpp:700
index_t patch
The index of the patch.
Definition: gsBoundary.h:234
index_t m_index
Index of the corner.
Definition: gsBoundary.h:298
Struct which represents a certain corner of a hyper-cube.
Definition: gsBoundary.h:291
Simple adapter classes to use matrices or linear solvers as gsLinearOperators.
gsMatrix< T > _makePi(index_t valence)
Makes the Pi matrix.
Definition: gsDPatch.hpp:581
gsMatrix< index_t > boundary(boxSide const &s) const
Returns the indices of the basis functions that are nonzero at the domain boundary as single-column-m...
Definition: gsBasis.h:520
A basis represents a family of scalar basis functions defined over a common parameter domain...
Definition: gsBasis.h:78