G+Smo  24.08.0
Geometry + Simulation Modules
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
gsHTensorBasis.hpp
Go to the documentation of this file.
1 
14 #pragma once
15 
16 #include <gsUtils/gsMesh/gsMesh.h>
17 
18 #include <gsUtils/gsPointGrid.h>
19 
20 #include <gsIO/gsXml.h>
22 
23 namespace gismo
24 {
25  // Central element implementation
26 // template<short_t d, class T>
27 // gsMatrix<T> gsHTensorBasis<d,T>::elementInSupportOf(index_t i) const
28 // {
29 // index_t lvl = levelOf(i);
30 // index_t j = flatTensorIndexOf(i);
31 // return m_bases[lvl]->elementInSupportOf(j);
32 // }
33 
34 template<short_t d, class T>
36 {
37  GISMO_ENSURE(m_manualLevels,"Add level only works when m_manualLevels==true");
38  // Fill the unique indices
39  std::vector<std::vector<index_t>> lvlIndices(d);
40  const tensorBasis * tb2 = dynamic_cast<const tensorBasis*>(m_bases.back());
41  std::vector<T> difference, intersection;
42  std::vector<T> knots1, knots2;
43  std::vector<index_t> dirIndices;
44  gsKnotVector<T> tmpknots;
45  for (short_t dim=0; dim!=d; dim++)
46  {
47  dirIndices = m_uIndices.back()[dim];
48  // Take the difference of the knot vectors
49  tmpknots= tb2->knots(dim);
50 
51  GISMO_ASSERT(tmpknots.maxInteriorMultiplicity()<tmpknots.degree()+1,"Knot vector cannot have knot multiplicities higher than p="<<tmpknots.degree());
52 
53  knots1 = tb2->knots(dim).unique();
54  knots2 = next_basis.knots(dim).unique();
55 
56  // Check nestedness.
57  intersection.clear();
58  difference.clear();
59  // The unique knots of the new basis must contain the ones of the previous level
60  std::set_intersection( knots2.begin(), knots2.end(),
61  knots1.begin(), knots1.end(),
62  std::back_inserter(intersection) );
63  // The difference of the two must not contain any knot in knots1!
64  std::set_difference( knots1.begin(), knots1.end(),
65  intersection.begin(), intersection.end(),
66  std::back_inserter(difference) );
67  GISMO_ASSERT(difference.size()==0,"Knot vector is not nested!");
68 
69  difference.clear();
70  // The difference of the two must not contain any knot in knots1!
71  std::set_difference(knots2.begin(), knots2.end(),
72  knots1.begin(), knots1.end(),
73  std::back_inserter(difference) );
74 
75  // We reverse since later on we loop and pop the elements on the back
76  std::reverse(difference.begin(),difference.end());
77  // Double all indices in dirIndices. These correspond to the indices that come from the nested bases
78  std::transform(dirIndices.begin(), dirIndices.end(), dirIndices.begin(), [=](index_t& i){return 2*i;});
79 
80  // Find the extra indices for the nodes in difference
81  while (difference.size()!=0)
82  {
83  index_t i, n;
84  typename std::vector<T>::iterator diff_ptr = difference.begin();
85  // Find the index of the highest knot below the different knot
86  i = tmpknots.uFind(*diff_ptr).uIndex(); // index of the knot span in which *it is located
87 
88  // Count how many difference knots lay in the same span
89  for (n = 0, diff_ptr = difference.begin(); diff_ptr!=difference.end() && tmpknots.uFind(*diff_ptr).uIndex()==i; n++, diff_ptr++);
90  // Count the distance between two element indices. It should be larger than n
91  GISMO_ENSURE(n < dirIndices[i+1] - dirIndices[i],"Trying to insert more knots than available in the tensor structure");
92 
93  index_t newIdx;
94  if (n % 2 != 0)
95  {
96  // We add the middle knot
97  diff_ptr = std::next(difference.begin(),(n-1)/2);
98  newIdx = (dirIndices[i] + dirIndices[i+1]) / 2;
99  }
100  else
101  {
102  // We add the first knot
103  diff_ptr = difference.begin();
104  newIdx = dirIndices[i] + 1;
105  }
106 
107  // Add the correct index
108  dirIndices.insert(std::upper_bound( dirIndices.begin(), dirIndices.end(), newIdx ),newIdx);
109  // Insert the removed difference knot in the temporary knot vector
110  tmpknots.insert(*diff_ptr);
111  // Remove the difference knot, since it is treated
112  difference.erase(diff_ptr);
113  }
114 
115  lvlIndices[dim] = dirIndices;
116  }
117  m_uIndices.push_back(lvlIndices);
118 
119  // m_bases.push_back( new gsTensorBSplineBasis<d, T>( give( next_basis ) ));
120  m_bases.push_back( next_basis.clone().release() );
121 }
122 
123 template<short_t d, class T>
125 {
126  return m_bases[0]->support();
127 }
128 
129 //i in continuous numbering
130 template<short_t d, class T>
132 {
133  // Get the level
134  int lvl = levelOf(i);
135  // Return the the support
136  return m_bases[lvl]->support( this->flatTensorIndexOf(i) );
137 }
138 
139 // S.K.
140 template<short_t d, class T> inline
142 {
143  GISMO_ASSERT(Pt.cols() == 1, "Waiting for single point");
144  point loIdx;
145 
146  const int maxLevel = m_tree.getMaxInsLevel();
147 
148  needLevel(maxLevel);
149 
150  for( int i =0; i < Dim; i++)
151  loIdx[i] = m_bases[maxLevel]->knots(i).uFind( Pt(i,0) ).uIndex();
152 
153  if (m_manualLevels)
154  this->_knotIndexToDiadicIndex(maxLevel,loIdx);
155 
156  return m_tree.levelOf( loIdx, maxLevel);
157 }
158 
159 template<short_t d, class T> inline
161 {
162  const int maxLevel = m_tree.getMaxInsLevel();
163 
164  needLevel(maxLevel);
165 
166  return m_tree.levelOf( Pt, maxLevel);
167 }
168 
169 template<short_t d, class T> inline
171  gsVector<index_t> & lvl,
172  gsMatrix<index_t> & loIdx ) const
173 {
174  lvl.resize( Pt.cols() );
175  loIdx.resize( Pt.rows(), Pt.cols() );
176  lvl.setZero();
177  loIdx.setZero();
178  for( index_t i = 0; i < Pt.cols(); i++)
179  {
180  lvl[i] = getLevelAtPoint( Pt.col(i) );
181  for( index_t j = 0; j < Pt.rows(); j++)
182  loIdx(j,i) = m_bases[ lvl[i] ]->knots(j).uFind( Pt(j,i) ).uIndex() ;
183  }
184 }
185 
186 template<short_t d, class T> inline
188 {
189  result.resize( u.cols() );
190  result.setZero();
191 
192  point low, upp, cur;
193  const int maxLevel = m_tree.getMaxInsLevel();
194 
195  for(index_t p = 0; p < u.cols(); p++ ) //for all input points
196  {
197  for(short_t i = 0; i != d; ++i)
198  low[i] = m_bases[maxLevel]->knots(i).uFind(u(i,p)).uIndex();
199 
200  // Identify the level of the point
201  const int lvl = m_tree.levelOf(low, maxLevel);
202 
203  for(int i = 0; i <= lvl; i++)
204  {
205  m_bases[i]->active_cwise(u.col(p), low, upp);
206  cur = low;
207  do //iterate over all points in [low,upp]
208  {
209  CMatrix::const_iterator it =
210  m_xmatrix[i].find_it_or_fail( m_bases[i]->index(cur) );
211 
212  if( it != m_xmatrix[i].end() )// if index is found
213  result[p]++;
214  }
215  while( nextCubePoint(cur,low,upp) );
216  }
217  }
218 }
219 
220 template<short_t d, class T>
221 void gsHTensorBasis<d, T>::addConnectivity(int lvl, gsMesh<T> & mesh) const
222 {
224 
225  const gsTensorBSplineBasis<d, T> & bb = *m_bases[lvl];
226  const CMatrix & cmat = m_xmatrix[lvl];
227 
228  // Last tensor-index in level lvl
229  gsVector<index_t, d> end(d);
230  for (index_t i = 0; i < d; ++i)
231  end(i) = bb.component(i).size() - 1;
232 
233  index_t k, s;
234  gsVector<index_t, d> v, upp;
235  for (index_t i = 0; i < d; ++i) // For all axes
236  {
237  s = bb.stride(i);
238  v = low;
239  upp = end;
240  upp[i] = 0; // suppress to face v[i]==0
241 
242  do // Insert all edges normal to axis i
243  {
244  k = bb.index(v);
245  for (index_t j = 0; j != end[i]; ++j)
246  {
247  if (cmat.bContains(k) && cmat.bContains(k + s))
248  {
249  // inefficient for now
250  const index_t kInd = m_xmatrix_offset[lvl] +
251  (std::lower_bound(cmat.begin(), cmat.end(), k)
252  - cmat.begin());
253 
254  // inefficient for now
255  const index_t kNextInd = m_xmatrix_offset[lvl] +
256  (std::lower_bound(cmat.begin(), cmat.end(), k + s)
257  - cmat.begin());
258 
259  mesh.addEdge(kInd, kNextInd);
260  }
261  k += s;
262  }
263  } while (nextCubePoint(v, low, upp));
264  }
265 }
266 
267 template<short_t d, class T>
268 void gsHTensorBasis<d, T>::connectivity(const gsMatrix<T> & nodes, int level, gsMesh<T> & mesh) const
269 {
270  const index_t sz = size();
271  GISMO_ASSERT(nodes.rows() == sz, "Invalid input.");
272 
273  // Add all vertices
274  for (index_t i = 0; i< sz; ++i)
275  mesh.addVertex(nodes.row(i).transpose());
276 
277  addConnectivity(level, mesh);
278 }
279 
280 template<short_t d, class T>
281 void gsHTensorBasis<d,T>::connectivity(const gsMatrix<T> & nodes, gsMesh<T> & mesh) const
282 {
283  const index_t sz = size();
284  GISMO_ASSERT( nodes.rows() == sz, "Invalid input.");
285 
286  // Add vertices
287  for(index_t i = 0; i< sz; ++i )
288  mesh.addVertex( nodes.row(i).transpose() );
289 
290  // For all levels
291  for(size_t lvl = 0; lvl <= maxLevel(); lvl++)
292  {
293  addConnectivity(lvl, mesh);
294  }
295 }
296 
297 template<short_t d, class T>
299 {
300  return m_xmatrix_offset.back();
301 }
302 template<short_t d, class T>
304 {
305  std::vector<gsSortedVector<index_t> > OX = m_xmatrix;
306  refine(boxes);
307  gsSparseMatrix<> transf;
308  this->transfer(OX, transf);
309  gsDebug<<"tranf orig:\n"<<transf<<std::endl;
310  coefs = transf*coefs;
311 }
312 
313 template<short_t d, class T>
314 void gsHTensorBasis<d,T>::refineElements_withCoefs(gsMatrix<T> & coefs,std::vector<index_t> const & boxes)
315 {
316  gsSparseMatrix<> transf;
317  this->refineElements_withTransfer(boxes,transf);
318  //gsDebug<<"tranf orig:\n"<<transf<<std::endl;
319  coefs = transf*coefs;
320 }
321 
322 template<short_t d, class T>
323 void gsHTensorBasis<d,T>::refineElements_withTransfer(std::vector<index_t> const & boxes, gsSparseMatrix<T> & tran)
324 {
325  std::vector<gsSortedVector<index_t> > OX = m_xmatrix;
326  this->refineElements(boxes);
327  this->transfer(OX, tran);
328 }
329 
330 template<short_t d, class T>
331 void gsHTensorBasis<d,T>::refineElements_withTransfer2(std::vector<index_t> const & boxes, gsSparseMatrix<T> & tran)
332 {
333  std::vector<gsSortedVector<index_t> > OX = m_xmatrix;
334  this->refineElements(boxes);
335  this->transfer2(OX, tran);
336 }
337 
338 template<short_t d, class T>
339 void gsHTensorBasis<d,T>::refineElements_withCoefs2(gsMatrix<T> & coefs,std::vector<index_t> const & boxes)
340 {
341  std::vector<gsSortedVector<index_t> > OX = m_xmatrix;
342  refineElements(boxes);
343  gsSparseMatrix<> transf;
344  this->transfer2(OX, transf);
345  //gsDebug<<"tranf 2:\n"<<transf<<std::endl;
346  coefs = transf*coefs;
347 }
348 
349 // template<short_t d, class T>
350 // void gsHTensorBasis<d,T>::unrefine_withCoefs(gsMatrix<T> & coefs, gsMatrix<T> const & boxes)
351 // {
352 // std::vector<gsSortedVector<index_t> > OX = m_xmatrix;
353 // unrefine(boxes);
354 // gsSparseMatrix<> transf;
355 // this->transfer(OX, transf);
356 // gsDebug<<"tranf orig:\n"<<transf<<std::endl;
357 // coefs = transf*coefs;
358 // }
359 
360 template<short_t d, class T>
361 void gsHTensorBasis<d,T>::unrefineElements_withCoefs(gsMatrix<T> & coefs,std::vector<index_t> const & boxes)
362 {
363  gsSparseMatrix<> transf;
364  this->unrefineElements_withTransfer(boxes,transf);
365  //gsDebug<<"tranf orig:\n"<<transf<<std::endl;
366 
367  typename gsSparseSolver<T>::QR solver(transf);
368  coefs=solver.solve(coefs);
369 }
370 
371 template<short_t d, class T>
372 void gsHTensorBasis<d,T>::unrefineElements_withTransfer(std::vector<index_t> const & boxes, gsSparseMatrix<T> & tran)
373 {
374  typename gsHTensorBasis<d,T>::uPtr cp = this->clone();
375  this->unrefineElements(boxes);
376  cp->transfer(this->m_xmatrix,tran);
377 }
378 
379 template<short_t d, class T>
380 void gsHTensorBasis<d,T>::uniformRefine_withCoefs(gsMatrix<T>& coefs, int numKnots, int mul, int dir)
381 {
382  GISMO_ASSERT(dir==-1,"Direction is not implemented");
383 
384  std::vector<gsSortedVector<index_t> > OX = m_xmatrix;
385  //uniformRefine(numKnots);
386  //gsMatrix<> transf;
387  //CMatrix temp;
388  //this->m_xmatrix.insert(this->m_xmatrix.begin(), temp);
389  //gsVector<index_t> level;
390  //gsMatrix<index_t> p1, p2;
391  //this->m_tree.getBoxes(p1,p2,level);
392  std::vector<index_t> boxes;
393  index_t lvl;
394  for ( typename hdomain_type::literator it = m_tree.beginLeafIterator(); it.good(); it.next() )
395  {
396  // gsDebug <<" level : "<< it.level() <<"\n";
397  // gsDebug <<" lower : "<< it.lowerCorner() <<"\n";
398  // gsDebug <<" upper : "<< it.upperCorner() <<"\n";
399 
400  lvl = it.level() + 1;
401  const point & l = it.lowerCorner();
402  const point & u = it.upperCorner();
403 
404  boxes.push_back(lvl);
405  for( short_t i = 0; i < d; i++)
406  boxes.push_back( l(i) * 2);
407  for( short_t i = 0; i < d; i++)
408  boxes.push_back( u(i) * 2);
409  }
410 
411  this->clone()->refineElements_withCoefs(coefs, boxes);
412  this->uniformRefine(numKnots, mul);
413  //this->m_xmatrix.erase(this->m_xmatrix.begin(),this->m_xmatrix.begin()+1);
414  //coefs = transf*coefs;
415 }
416 
417 template<short_t d, class T>
419 {
420  std::vector<gsSortedVector<index_t> > OX = m_xmatrix;
421  std::vector<index_t> boxes;
422  index_t lvl;
423  for ( typename hdomain_type::literator it = m_tree.beginLeafIterator(); it.good(); it.next() )
424  {
425  if (it.level() == 0)
426  continue;
427  lvl = it.level() - 1;
428  const point & l = it.lowerCorner();
429  const point & u = it.upperCorner();
430 
431  boxes.push_back(lvl);
432  for( short_t i = 0; i < d; i++)
433  boxes.push_back( l(i) / 2);
434  for( short_t i = 0; i < d; i++)
435  boxes.push_back( u(i)/2 + (index_t)(u(i)%2!=0));
436  }
437 
438  this->clone()->unrefineElements_withCoefs(coefs, boxes);
439  this->uniformCoarsen(numKnots);
440 }
441 
442 
443 template<short_t d, class T>
444 void gsHTensorBasis<d,T>::refine(gsMatrix<T> const & boxes, int refExt)
445 {
446  GISMO_ASSERT(boxes.rows() == d, "refine() needs d rows of boxes.");
447  GISMO_ASSERT(boxes.cols()%2 == 0, "Each box needs two corners but you don't provide refine() with them.");
448 
449 #ifndef NDEBUG
450  gsMatrix<T> para = support();
451  for(int i = 0; i < boxes.cols()/2; i++)
452  {
453  for( short_t j = 0; j < d; j++ )
454  {
455  GISMO_ASSERT( para(j,0) <= boxes(j, 2*i) ,
456  "In refine() the first corner is outside the computational domain.");
457  GISMO_ASSERT( para(j,1) >= boxes(j, 2*i+1),
458  "In refine() the second corner is outside the computational domain." );
459  }
460  }
461 #endif
462 
463  if( refExt == 0 )
464  {
465  // If there is no refinement-extension, just use the
466  // "regular" refinement function refine( gsMatrix )
467  this->refine( boxes );
468 
469  // Make sure there are enough levels
470  needLevel( m_tree.getMaxInsLevel() );
471  }
472  else
473  {
474  // Make an element vector
475  std::vector<index_t> refVector = this->asElements(boxes, refExt);//std::vector<unsigned> refVector = this->asElements(boxes, refExt);
476 
477  // ...and refine
478  this->refineElements( refVector );
479  }
480 
481  // Update the basis (already done by now)
482  //update_structure();
483 }
484 
485 template<short_t d, class T>
486 void gsHTensorBasis<d,T>::unrefine(gsMatrix<T> const & boxes, int refExt)
487 {
488  GISMO_ASSERT(boxes.rows() == d, "refine() needs d rows of boxes.");
489  GISMO_ASSERT(boxes.cols()%2 == 0, "Each box needs two corners but you don't provide refine() with them.");
490 
491 #ifndef NDEBUG
492  gsMatrix<T> para = support();
493  for(int i = 0; i < boxes.cols()/2; i++)
494  {
495  for( short_t j = 0; j < d; j++ )
496  {
497  GISMO_ASSERT( para(j,0) <= boxes(j, 2*i) ,
498  "In refine() the first corner is outside the computational domain.");
499  GISMO_ASSERT( para(j,1) >= boxes(j, 2*i+1),
500  "In refine() the second corner is outside the computational domain." );
501  }
502  }
503 #endif
504 
505  // Make an element vector
506  std::vector<index_t> refVector = this->asElementsUnrefine(boxes, refExt);//std::vector<unsigned> refVector = this->asElements(boxes, refExt);
507 
508  // ...and refine
509  this->unrefineElements( refVector );
510 
511  // if( refExt == 0 )
512  // {
513  // // If there is no refinement-extension, just use the
514  // // "regular" unrefinement function unrefine( gsMatrix )
515  // // this->unrefine( boxes );
516 
517  // // Make an element vector
518  // std::vector<index_t> refVector = this->asElements(boxes, 0);//std::vector<unsigned> refVector = this->asElements(boxes, refExt);
519 
520  // // ...and refine
521  // this->unrefineElements( refVector );
522 
523  // // Make an element vector
524  // // this->unrefine( boxes );
525  // }
526  // else
527  // {
528  // // Make an element vector
529  // std::vector<index_t> refVector = this->asElements(boxes, refExt);//std::vector<unsigned> refVector = this->asElements(boxes, refExt);
530 
531  // // ...and refine
532  // this->unrefineElements( refVector );
533  // }
534 
535  // Update the basis (already done by now)
536  //update_structure();
537 }
538 
539 template<short_t d, class T>
540 std::vector<index_t> gsHTensorBasis<d,T>::asElements(gsMatrix<T> const & boxes, int refExt) const
541 {
542  // If there is a refinement-extension, we will have to use
543  // refineElements( std::vector )
544  //
545  // Each box will be represented by 2*d+1 entries specifying
546  // <level to be refined to>,<lower corner>,<upper corner>
547  const int offset = 2*d+1;
548 
549  // Initialize vector of size
550  // "entries per box" times "number of boxes":
551  std::vector<index_t> refVector( offset * boxes.cols()/2 );
552  gsMatrix<T> ctr(d,1);
553 
554  // Loop over all boxes:
555  for(index_t i = 0; i < boxes.cols()/2; i++)
556  {
557  ctr = ( boxes.col( 2*i ) + boxes.col( 2*i+1) )/2;
558 
559  // Compute the level we want to refine to.
560  // Note that, if the box extends over several elements,
561  // the level at the centerpoint will be taken for reference
562  const int refLevel = getLevelAtPoint( ctr ) + 1;
563 
564  // Make sure there are enough levels
565  needLevel( refLevel );
566 
567  for(index_t j = 0; j < boxes.rows();j++)
568  {
569  // Convert the parameter coordinates to (unique) knot indices
570  const gsKnotVector<T> & kv = m_bases[refLevel]->knots(j);
571  index_t k1 = (std::upper_bound(kv.domainUBegin(), kv.domainUEnd(),
572  boxes(j,2*i ) ) - 1).uIndex();
573  index_t k2 = (std::upper_bound(kv.domainUBegin(), kv.domainUEnd()+1,
574  boxes(j,2*i+1) ) - 1).uIndex();
575 
576  // Trivial boxes trigger some refinement
577  if ( k1 == k2)
578  {
579  if (0!=k1) {--k1;}
580  ++k2;
581  }
582 
583  index_t maxKtIndex = kv.size();
584  if (m_manualLevels)
585  {
586  _knotIndexToDiadicIndex(refLevel,j,k1);
587  _knotIndexToDiadicIndex(refLevel,j,k2);
588 
589  _knotIndexToDiadicIndex(refLevel,j,maxKtIndex);
590  }
591  // If applicable, add the refinement extension.
592  // Note that extending by one cell on level L means
593  // extending by two cells in level L+1
594  ( k1 < 2*refExt ? k1=0 : k1-=2*refExt );
595  ( k2 + 2*refExt >= maxKtIndex ? k2=maxKtIndex-1 : k2+=2*refExt);
596 
597  // Store the data...
598  refVector[i*offset] = refLevel;
599  refVector[i*offset+1+j] = k1;
600  refVector[i*offset+1+j+d] = k2;
601  }
602  }
603  // gsDebug<<"begin\n";
604  // for (std::vector<unsigned>::const_iterator i = refVector.begin(); i != refVector.end(); ++i)
605  // std::cout << *i << ' ';
606  // gsDebug<<"end\n";
607 
608  return refVector;
609 }
610 
611 template<short_t d, class T>
612 std::vector<index_t> gsHTensorBasis<d,T>::asElementsUnrefine(gsMatrix<T> const & boxes, int refExt) const
613 {
614  // If there is a refinement-extension, we will have to use
615  // refineElements( std::vector )
616  //
617  // Each box will be represented by 2*d+1 entries specifying
618  // <level to be refined to>,<lower corner>,<upper corner>
619  const int offset = 2*d+1;
620 
621  // Initialize vector of size
622  // "entries per box" times "number of boxes":
623  std::vector<index_t> refVector;
624  refVector.reserve( offset * boxes.cols()/2 );
625  gsMatrix<T> ctr(d,1);
626 
627  // Index for the actual boxes that can be unrefined
628  // (so not the ones with level < 0 )
629  index_t I = 0;
630  // Loop over all boxes:
631  for(index_t i = 0; i < boxes.cols()/2; i++)
632  {
633  ctr = ( boxes.col( 2*i ) + boxes.col( 2*i+1) )/2;
634 
635  // Compute the level we want to refine to.
636  // Note that, if the box extends over several elements,
637  // the level at the centerpoint will be taken for reference
638  const int refLevel = getLevelAtPoint( ctr ) - 1;
639 
640  // If the level is 0, we cannot coarsen
641  if (refLevel < 0) continue;
642 
643  refVector.resize(refVector.size() + offset);
644 
645  for(index_t j = 0; j < boxes.rows();j++)
646  {
647  // Convert the parameter coordinates to (unique) knot indices
648  const gsKnotVector<T> & kv = m_bases[refLevel+1]->knots(j);
649  index_t k1 = (std::upper_bound(kv.domainUBegin(), kv.domainUEnd(),
650  boxes(j,2*i ) ) - 1).uIndex();
651  index_t k2 = (std::upper_bound(kv.domainUBegin(), kv.domainUEnd()+1,
652  boxes(j,2*i+1) ) - 1).uIndex();
653 
654  // Trivial boxes trigger some refinement
655  if ( k1 == k2)
656  {
657  if (0!=k1) {--k1;}
658  ++k2;
659  }
660 
661  index_t maxKtIndexd = kv.size();
662  if (m_manualLevels)
663  {
664  _knotIndexToDiadicIndex(refLevel,j,k1);
665  _knotIndexToDiadicIndex(refLevel,j,k2);
666 
667  _knotIndexToDiadicIndex(refLevel,j,maxKtIndexd);
668  }
669 
670  // If applicable, add the refinement extension.
671  ( k1 < refExt ? k1=0 : k1-=refExt );
672  ( k2 + refExt >= maxKtIndexd ? k2=maxKtIndexd-1 : k2+=refExt);
673 
674  // go one level up;
675  k1 /= 2;
676  k2 = k2/2 + (index_t)(k2%2 != 0);
677 
678  // Store the data...
679  refVector[I*offset] = refLevel;
680  refVector[I*offset+1+j] = k1;
681  refVector[I*offset+1+j+d] = k2;
682  }
683 
684  I++;
685  }
686 
687  return refVector;
688 }
689 
690 template<short_t d, class T>
692 {
693  GISMO_ASSERT(boxes.rows() == d, "refine() needs d rows of boxes.");
694  GISMO_ASSERT(boxes.cols()%2 == 0, "Each box needs two corners but you don't provide refine() with them.");
695 
696 #ifndef NDEBUG
697  gsMatrix<T> para = support();
698  for(int i = 0; i < boxes.cols()/2; i++)
699  {
700  for( short_t j = 0; j < d; j++ )
701  {
702  GISMO_ASSERT( para(j,0) <= boxes(j, 2*i) ,
703  "In refine() the first corner is outside the computational domain.");
704  GISMO_ASSERT( para(j,1) >= boxes(j, 2*i+1),
705  "In refine() the second corner is outside the computational domain." );
706  }
707  }
708 #endif
709 
710  gsVector<index_t,d> k1, k2;
711  for(index_t i = 0; i < boxes.cols()/2; i++)
712  {
713  // 1. Get a small cell containing the box
714  const int fLevel = m_bases.size()-1;
715 
716  for(index_t j = 0; j < k1.size();j++)
717  {
718  const gsKnotVector<T> & kv = m_bases.back()->knots(j);
719  k1[j] = (std::upper_bound(kv.domainUBegin(), kv.domainUEnd(),
720  boxes(j,2*i ) ) - 1).uIndex();
721  k2[j] = (std::upper_bound(kv.domainUBegin(), kv.domainUEnd()+1,
722  boxes(j,2*i+1) ) - 1).uIndex();
723 
724  // Trivial boxes trigger some refinement
725  if ( k1[j] == k2[j])
726  {
727  if (0!=k1[j]) {--k1[j];}
728  ++k2[j];
729  }
730  }
731 
732  if (m_manualLevels)
733  {
734  _knotIndexToDiadicIndex(fLevel,k1);
735  _knotIndexToDiadicIndex(fLevel,k2);
736  }
737 
738  // 2. Find the smallest level in which the box is completely contained
739  //const int level = m_tree.query3(k1,k2,fLevel) + 1;
740  // make sure that the grid is computed ( needLevel(level) )
741  //const tensorBasis & tb = tensorLevel(level);
742  //GISMO_UNUSED(tb);
743 
744  // Sink box
745  m_tree.sinkBox(k1, k2, fLevel);
746  // Make sure we have enough levels
747  needLevel( m_tree.getMaxInsLevel() );
748  }
749 
750  // Update the basis
751  update_structure();
752 }
753 
754 // template<short_t d, class T>
755 // void gsHTensorBasis<d,T>::unrefine(gsMatrix<T> const & boxes)
756 // {
757 // GISMO_ASSERT(boxes.rows() == d, "unrefine() needs d rows of boxes.");
758 // GISMO_ASSERT(boxes.cols()%2 == 0, "Each box needs two corners but you don't provide unrefine() with them.");
759 
760 // #ifndef NDEBUG
761 // gsMatrix<T> para = support();
762 // for(int i = 0; i < boxes.cols()/2; i++)
763 // {
764 // for( short_t j = 0; j < d; j++ )
765 // {
766 // GISMO_ASSERT( para(j,0) <= boxes(j, 2*i) ,
767 // "In unrefine() the first corner is outside the computational domain.");
768 // GISMO_ASSERT( para(j,1) >= boxes(j, 2*i+1),
769 // "In unrefine() the second corner is outside the computational domain." );
770 // }
771 // }
772 // #endif
773 
774 // gsVector<index_t,d> k1, k2;
775 // for(index_t i = 0; i < boxes.cols()/2; i++)
776 // {
777 // // 1. Get a small cell containing the box
778 // const int fLevel = m_bases.size()-1;
779 
780 // for(index_t j = 0; j < k1.size();j++)
781 // {
782 // const gsKnotVector<T> & kv = m_bases.back()->knots(j);
783 // k1[j] = (std::upper_bound(kv.domainUBegin(), kv.domainUEnd(),
784 // boxes(j,2*i ) ) - 1).uIndex();
785 // k2[j] = (std::upper_bound(kv.domainUBegin(), kv.domainUEnd()+1,
786 // boxes(j,2*i+1) ) - 1).uIndex();
787 
788 // // Trivial boxes trigger some refinement
789 // if ( k1[j] == k2[j])
790 // {
791 // if (0!=k1[j]) {--k1[j];}
792 // ++k2[j];
793 // }
794 // }
795 
796 // // 2. Find the smallest level in which the box is completely contained
797 // //const int level = m_tree.query3(k1,k2,fLevel) + 1;
798 // // make sure that the grid is computed ( needLevel(level) )
799 // //const tensorBasis & tb = tensorLevel(level);
800 // //GISMO_UNUSED(tb);
801 
802 // // Sink box
803 // m_tree.raiseBox(k1, k2, fLevel);
804 // }
805 
806 // // Update the basis
807 // // update_structure();
808 // }
809 
810 template<short_t d, class T>
812 {
813  // Get current level
814  const index_t lvl = this->levelOf(i);
815  // Get the support endpoints
816  gsMatrix<index_t, d, 2> elements;
817  m_bases[lvl]->elementSupport_into(m_xmatrix[lvl][ i - m_xmatrix_offset[lvl] ],
818  elements);
819  point low = elements.col(0);
820  point upp = elements.col(1);
821  // Advance the indices to one level deeper
822  for ( short_t k = 0; k!=d; ++k )
823  {
824  low[k] = low[k] << 1;
825  upp[k] = upp[k] << 1;
826  }
827  // Insert the domain to the lvl+1 nested domain
828  m_tree.insertBox(low,upp,lvl+1);
829  // Update the basis
830  update_structure();
831 }
832 
833 
834 /*
835  template<short_t d, class T>
836  void gsHTensorBasis<d,T>::refine(gsDomainIterator<T> const & boxes)
837  {
838 
839  }
840 */
841 
842 template<short_t d, class T>
843 void gsHTensorBasis<d,T>::refineElements(std::vector<index_t> const & boxes)
844 {
845  point i1;
846  point i2;
847 
848  GISMO_ASSERT( (boxes.size()%(2*d + 1))==0,
849  "The points did not define boxes properly. The boxes were not added to the basis.");
850  for(size_t i = 0; i < (boxes.size())/(2*d+1); i++)
851  {
852  for( short_t j = 0; j < d; j++ )
853  {
854  i1[j] = boxes[(i*(2*d+1))+j+1];
855  i2[j] = boxes[(i*(2*d+1))+d+j+1];
856  }
857  insert_box(i1,i2,boxes[i*(2*d+1)]);
858  }
859 
860  update_structure();
861 }
862 
863 template<short_t d, class T>
864 void gsHTensorBasis<d,T>::unrefineElements(std::vector<index_t> const & boxes)
865 {
866  point i1;
867  point i2;
868 
869  GISMO_ASSERT( (boxes.size()%(2*d + 1))==0,
870  "The points did not define boxes properly. The boxes were not added to the basis.");
871 
872  for(size_t i = 0; i < (boxes.size())/(2*d+1); i++)
873  {
874  for( short_t j = 0; j < d; j++ )
875  {
876  i1[j] = boxes[(i*(2*d+1))+j+1];
877  i2[j] = boxes[(i*(2*d+1))+d+j+1];
878  }
879 
880  m_tree.clearBox(i1,i2, boxes[i*(2*d+1)]);
881  // needLevel( m_tree.getMaxInsLevel() );
882  }
883 
884  // reconstruct the whole tree to fix alignment
885  gsHDomain<d> newtree( m_tree.upperCornerIndex() );
886  auto leafIt = m_tree.beginLeafIterator();
887  for (; leafIt.good(); leafIt.next())
888  {
889  if ( leafIt.level()>0 )
890  newtree.insertBox(leafIt.lowerCorner(),
891  leafIt.upperCorner(), leafIt.level() );
892  }
893  m_tree = newtree;
894 
895  //recompute max-ins-level
896  m_tree.computeMaxInsLevel();
897  update_structure();
898 }
899 
900 template<short_t d, class T>
902 {
903  const index_t dir = side.direction();
904  const index_t par = side.parameter();
905  gsMatrix<T> rf = this->support();
906  rf(dir,!par) = rf(dir,par);
907  for (index_t i = 0; i!=lvl; ++i) // lazy impl., this can be more efficient
908  this->refine(rf);
909 }
910 
911 template<short_t d, class T>
913  const gsBasis<T> & other,
914  gsMatrix<index_t> & bndThis,
915  gsMatrix<index_t> & bndOther,
916  index_t offset) const
917 {
918  if( const Self_t * _other = dynamic_cast<const Self_t*>( &other) )
919  {
920  // tens1 will store the tensor-index on side second(),...
921  gsVector<index_t,d> N, tens0, tens1;
922 
923  // see if the orientation is preserved on side second()
924  const gsVector<bool> dirOrient = bi.dirOrientation();
925  const gsVector<index_t> dirMap = bi.dirMap();
926 
927  // get the global indices of the basis functions which are
928  // active on the interface
929  bndThis = this->boundaryOffset( bi.first().side(), offset );
930 
931  // this is only for checking whether, at least, both involved
932  // bases have the same number of DOF on the interface.
933  bndOther= _other->boundaryOffset( bi.second().side(), offset );
934  GISMO_ASSERT( bndThis.rows() == bndOther.rows(),
935  "Input error, sizes do not match: "
936  <<bndThis.rows()<<"!="<<bndOther.rows() );
937  // bndOther gets overwritten completely, so here is the setZero():
938  bndOther.setZero();
939 
940  for( index_t i=0; i < bndThis.rows(); i++)
941  {
942  // get the level of the basis function on side first()
943  index_t L = this->levelOf( bndThis(i,0) );
944  // get the flat tensor index
945  // (i.e., the single-number-index on level L)...
946  index_t flat0 = this->flatTensorIndexOf( bndThis(i,0) );
947  // ... and change it to the tensor-index.
948  tens0 = this->tensorLevel(L).tensorIndex( flat0 );
949 
950  // ...flat1 the corresponding flat index
951  // (single-number on level)...
952  index_t flat1 = 0;
953  // ...and cont1 the corresponding continued (global) index.
954  index_t cont1 = 0;
955 
956  // get the sizes of the components of the tensor-basis on this level,
957  // i.e., the sizes of the univariate bases corresponding
958  // to the respective coordinate directions
959  for( short_t j=0; j < d; j++)
960  N[j] = _other->tensorLevel(L).component(j).size();
961 
962  // get the tensor-index of the basis function on level L on
963  // second() that should be matched with flatp/tens0
964  for( short_t j=0; j<d; j++)
965  {
966  // coordinate direction j on first() gets
967  // mapped to direction jj on second()
968  index_t jj = dirMap[j];
969  // store the respective component of the tensor-index
970  tens1[jj] = tens0[j];
971 
972  if( jj == bi.second().direction() )
973  {
974  // if jj is the direction() of the interface,
975  // however, we need either the first
976  // or last basis function
977  if( bi.second().parameter() ) // true = 1 = end
978  tens1[jj] = N[jj]-(1+offset);
979  else
980  tens1[jj] = offset;
981  }
982  else
983  {
984  // otherwise, check if the orientation is
985  // preserved. If necessary, flip it.
986  if( !dirOrient[j] )
987  tens1[jj] = N[jj]-1 - tens1[jj];
988  }
989 
990  }
991 
992  flat1 = _other->tensorLevel(L).index( tens1 );
993 
994  // compute the "continuous" index on second(), i.e., the index
995  // in the numbering which is global over all levels.
996  cont1 = _other->flatTensorIndexToHierachicalIndex( flat1, L );
997  // this is the index that has to be matched with bndThis(i,0)
998  bndOther( i, 0 ) = cont1;
999  }
1000  return;
1001  }
1002  gsWarn<<"Cannot match with "<< other <<"\n";
1003 }
1004 
1005 template<short_t d, class T>
1007  const gsBasis<T> & other,
1008  gsMatrix<index_t> & bndThis,
1009  gsMatrix<index_t> & bndOther) const
1010 {
1011  matchWith(bi,other,bndThis,bndOther,0);
1012 }
1013 
1014 
1015 //protected functions
1016 
1017 // Construct the characteristic matrix of level \a level ; i.e., set
1018 // all the matrix entries corresponding to active functions to one and
1019 // the rest to zero.
1020 template<short_t d, class T>
1021 void gsHTensorBasis<d,T>::set_activ1(int level)
1022 {
1023  typedef typename gsKnotVector<T>::smart_iterator knotIter;
1024 
1025  //gsDebug<<" Setting level "<< level <<"\n";
1026  point low, upp;
1027 
1028  CMatrix & cmat = m_xmatrix[level];
1029 
1030  // Clear previous entries
1031  cmat.clear();
1032 
1033  // If a level is to be checked which is larger than
1034  // the maximum inserted level, nothing need so to be done
1035  if ( level > static_cast<int>(m_tree.getMaxInsLevel() ) )
1036  return;
1037 
1038 
1039  gsVector<knotIter,d> starts, ends, curr;
1040  point ind;
1041  ind[0] = 0; // for d==1: warning: may be used uninitialized in this function (snap-ci)
1042 
1043  for(short_t i = 0; i != d; ++i)
1044  {
1045  // beginning of the iteration in i-th direction
1046  starts[i] = m_bases[level]->knots(i).sbegin() ;
1047  // end of the iteration in i-th direction
1048  ends [i] = m_bases[level]->knots(i).send()-m_deg[i]-1;
1049  }
1050 
1051  curr = starts;// start iteration
1052  do
1053  {
1054  for(short_t i = 0; i != d; ++i)
1055  {
1056  low[i] = curr[i].uIndex(); // lower left corner of the support of the function
1057  upp[i] = (curr[i]+m_deg[i]+1).uIndex(); // upper right corner of the support
1058  ind[i] = curr[i].index(); // index of the function in the matrix
1059  }
1060 
1061  //Here: get knot indices in some standard indexing (eg. dyadic)
1062  if (m_manualLevels)
1063  {
1064  _knotIndexToDiadicIndex(level,low);
1065  _knotIndexToDiadicIndex(level,upp);
1066  }
1067 
1068  if ( m_tree.query3(low, upp,level) == level) //if active ????
1069  cmat.push_unsorted( m_bases[level]->index( ind ) );
1070 
1071  }
1072  while ( nextLexicographic(curr,starts,ends) ); // while there are some functions (i.e., some combinations of iterators) left
1073 
1074  cmat.sort();
1075 
1076 }
1077 
1078 template<short_t d, class T>
1079 void gsHTensorBasis<d,T>::functionOverlap(const point & boxLow, const point & boxUpp,
1080  const int level, point & actLow, point & actUpp)
1081 {
1082  const tensorBasis & tb = *m_bases[level];
1083  for(short_t i = 0; i != d; ++i)
1084  {
1085  actLow[i] = tb.knots(i).lastKnotIndex (boxLow[i]) - m_deg[i];
1086  actUpp[i] = tb.knots(i).firstKnotIndex(boxUpp[i]) - 1 ;
1087 
1088  // Note aao:
1089  //actLow[i] = firstKnotIndex(boxLow[i]);
1090  //actUpp[i] = tb.knots(i).lastKnotIndex(boxUpp[i])-m_deg[i]-1;
1091  }
1092 }
1093 
1094 template<short_t d, class T>
1096 {
1097  // for(size_t lvl = 0; lvl != m_xmatrix.size(); lvl++)
1098  // set_activ1(lvl);
1099  // return;
1100 
1101  // iterate over leaf-boxes
1102  // for all overlapping supports with the box
1103  // set obvious to active
1104  // for the rest candidates (supp. not fully contained in box ~ !query2)
1105  // (equiv: actives on the boundary cells of the box)
1106  // query3(supp,box.level) == level (min. is level: no coarser)
1107  // take care: duplicates from different leaves or adj. cells
1108  point curr, actUpp;
1109  gsMatrix<index_t,d,2> elSupp;
1110 
1111  // try: iteration per level
1112  for ( typename hdomain_type::literator it = m_tree.beginLeafIterator();
1113  it.good(); it.next() )
1114  {
1115  const int lvl = it.level();
1116  CMatrix & cmat = m_xmatrix[lvl];
1117 
1118  // Get candidate functions
1119  functionOverlap(it.lowerCorner(), it.upperCorner(), lvl, curr, actUpp);
1120 
1121  do
1122  {
1123  const index_t gi = m_bases[lvl]->index( curr );
1124 
1125  // Get element support
1126  m_bases[lvl]->elementSupport_into(gi, elSupp);
1127 
1128  if ( (elSupp.col(0).array() >= it.lowerCorner().array()).all() &&
1129  (elSupp.col(1).array() <= it.upperCorner().array()).all() )
1130  {
1131  // to do: all-at-once
1132  cmat.push_unsorted( gi );
1133  }
1134  else
1135  {
1136  // Check if active (iff no overlap with level less than lvl)
1137  if ( m_tree.query3(elSupp.col(0), elSupp.col(1), lvl) == lvl)
1138  cmat.push_unsorted( gi );
1139  }
1140  }
1141  while( nextCubePoint(curr, actUpp) );
1142  }
1143 
1144  for(size_t lvl = 0; lvl != m_xmatrix.size(); ++lvl)
1145  {
1146  m_xmatrix[lvl].sort();
1147  m_xmatrix[lvl].erase( std::unique( m_xmatrix[lvl].begin(), m_xmatrix[lvl].end() ),
1148  m_xmatrix[lvl].end() );
1149  }
1150 }
1151 
1152 template<short_t d, class T>
1154  std::vector<CMatrix> & x_matrix_lvl) const
1155 {
1156  x_matrix_lvl.resize(level+1);
1157 
1158  // vectors of iterators. one iterator for each dimension
1160  gsVector<index_t,d> ind;
1161  ind[0] = 0; // for d==1: warning: may be used uninitialized in this function (snap-ci)
1162  gsVector<index_t,d> low, upp;
1163  for(int j =0; j < level+1; j++)
1164  {
1165  // Clear previous entries
1166  x_matrix_lvl[j].clear();
1167 
1168  for(index_t i = 0; i != d; ++i)
1169  {
1170  // beginning of the iteration in i-th direction
1171  starts[i] = m_bases[j]->knots(i).sbegin() ;
1172  // end of the iteration in i-th direction
1173  ends [i] = m_bases[j]->knots(i).send()-m_deg[i]-1;
1174  }
1175 
1176  curr = starts; // set start of iteration
1177  do
1178  {
1179  for(index_t i = 0; i != d; ++i)
1180  {
1181  low[i] = curr[i].uIndex(); // lower left corner of the support of the function
1182  upp[i] = (curr[i]+m_deg[i]+1).uIndex(); // upper right corner of the support
1183  ind[i] = curr[i].index(); // index of the function in the matrix
1184  }
1185  if(j < level)
1186  {
1187  if ( m_tree.query3(low, upp,j) == j)
1188  { //if active
1189  x_matrix_lvl[j].push_unsorted( m_bases[j]->index( ind ) );
1190  }
1191  }else{
1192  if ( m_tree.query3(low, upp,j) >= j)
1193  { //if active
1194  x_matrix_lvl[j].push_unsorted( m_bases[j]->index( ind ) );
1195  }
1196  }
1197  }
1198  while ( nextLexicographic(curr,starts,ends) ); // while there are some functions (i.e., some combinations of iterators) left
1199 
1200  x_matrix_lvl[j].sort();
1201  }
1202 
1203 }
1204 
1206 template<short_t d, class T> inline
1208  typename gsHTensorBasis<d,T>::point const & k2,
1209  int lvl )
1210 {
1211  // Remember box in History (for debugging)
1212  // m_boxHistory.push_back( box(k1,k2,lvl) );
1213 
1214  m_tree.insertBox(k1,k2, lvl);
1215  needLevel( m_tree.getMaxInsLevel() );
1216 }
1217 
1218 template<short_t d, class T>
1220 {
1221  // Compress the tree
1222  // m_tree.makeCompressed();
1223 
1224  while ( ! m_xmatrix_offset[1] )
1225  {
1226  delete m_bases.front();
1227  m_bases.erase( m_bases.begin() );
1228  m_tree.decrementLevel();
1229  m_xmatrix.erase( m_xmatrix.begin() );
1230  m_xmatrix_offset.erase( m_xmatrix_offset.begin() );
1231  }
1232  // Note/to do: cleaning up empty levels at the end as well.
1233 }
1234 
1235 template<short_t d, class T>
1237 {
1238  GISMO_ASSERT( static_cast<size_t>(level) < m_xmatrix.size(), "Requested level does not exist.\n");
1239 
1240  CMatrix::const_iterator xmat_pointer = m_xmatrix[level].begin();
1241  CMatrix::const_iterator xmat_end = m_xmatrix[level].end();
1242  gsSortedVector< int >::iterator ind_pointer = indexes.begin();
1243  gsSortedVector< int >::iterator ind_end = indexes.end();
1244  index_t index = 0;
1245  while(ind_pointer!=ind_end&&xmat_pointer!=xmat_end)
1246  {
1247  if(*ind_pointer<static_cast<int>(*xmat_pointer))
1248  {
1249  (*ind_pointer)=-1;
1250  ++ind_pointer;
1251  }
1252  else if(*ind_pointer==static_cast<int>(*xmat_pointer))
1253  {
1254  (*ind_pointer)=m_xmatrix_offset[level]+index;
1255  ++xmat_pointer;
1256  ++index;
1257  ++ind_pointer;
1258  }
1259  else
1260  {
1261  ++xmat_pointer;
1262  ++index;
1263  }
1264  }
1265  while(ind_pointer!=ind_end)
1266  {
1267  (*ind_pointer)=-1;
1268  ++ind_pointer;
1269  }
1270 }
1271 
1272 template<short_t d, class T>
1274 {
1275  if( m_xmatrix.size()<=static_cast<size_t>(level) )
1276  return -1;
1277  CMatrix::const_iterator it = std::lower_bound(m_xmatrix[level].begin(), m_xmatrix[level].end(), index );
1278  if(it == m_xmatrix[level].end() || *it != index)
1279  return -1;
1280  else
1281  return m_xmatrix_offset[level] + ( it - m_xmatrix[level].begin() );
1282 }
1283 
1284 template<short_t d, class T>
1285 void gsHTensorBasis<d,T>::activeBoundaryFunctionsOfLevel(const unsigned level,const boxSide & s,std::vector<bool>& actives) const
1286 {
1287  needLevel( level );
1288 
1289  const gsMatrix<index_t> bound = m_bases[level]->boundary(s);
1290  const index_t sz = bound.rows();
1291  //gsSortedVector< int > indexes(bound->data(),bound->data()+sz);
1292  gsSortedVector< int > indexes;
1293  indexes.resize(sz,-1);
1294  if(level<=maxLevel())
1295  {
1296  for(index_t i = 0;i<sz;++i)
1297  indexes[i]=(bound)(i,0);
1298  flatTensorIndexesToHierachicalIndexes(indexes,level);
1299  }
1300  actives.resize(indexes.size(),false);
1301  std::fill (actives.begin(),actives.end(),false);
1302  for(size_t i = 0;i<indexes.size();i++)
1303  if(indexes[i]!=-1)
1304  actives[i]=true;
1305 }
1306 
1307 template<short_t d, class T>
1308 void gsHTensorBasis<d,T>::update_structure() // to do: rename as updateHook
1309 {
1310  // Make sure we have computed enough levels
1311  needLevel( m_tree.getMaxInsLevel() );
1312 
1313  // Setup the characteristic matrices
1314  m_xmatrix.clear();
1315  m_xmatrix.resize( m_tree.getMaxInsLevel()+1 );
1316  // Compress the tree
1317  m_tree.makeCompressed();
1318 
1319  for(size_t i = 0; i != m_xmatrix.size(); i ++)
1320  set_activ1(i);
1321 
1322  // Store all indices of active basis functions to m_matrix
1323  //setActive();
1324 
1325  // Compute offsets
1326  m_xmatrix_offset.clear();
1327  m_xmatrix_offset.reserve(m_xmatrix.size()+1);
1328  m_xmatrix_offset.push_back(0);
1329  for (size_t i = 0; i != m_xmatrix.size(); i++)
1330  {
1331  m_xmatrix_offset.push_back(
1332  m_xmatrix_offset.back() + m_xmatrix[i].size() );
1333  }
1334 }
1335 
1336 template<short_t d, class T>
1337 void gsHTensorBasis<d,T>::needLevel(int maxLevel) const
1338 {
1339  GISMO_ENSURE(!m_manualLevels || (size_t)(maxLevel)<m_uIndices.size(),"Maximum manual level reached, maxLevel = "<<maxLevel<<", m_uIndices.size() = "<<m_uIndices.size());
1340  // +1 for the initial basis in m_bases
1341  const int extraLevels = maxLevel + 1 - m_bases.size();
1342  for ( int i = 0; i < extraLevels; ++i )
1343  {
1344  tensorBasis * next_basis = m_bases.back()->clone().release();
1345  next_basis->uniformRefine(1);
1346  m_bases.push_back (next_basis); //note: m_bases is mutable
1347  }
1348 }
1349 
1350 template<short_t d, class T>
1352 {
1353  // Degrees
1354  //m_deg = tbasis.cwiseDegree();
1355  m_deg.resize(d);
1356  for( index_t i = 0; i < d; i++)
1357  m_deg[i] = tbasis.degree(i);
1358 
1359  // Construct the initial basis
1360  if ( const tensorBasis * tb2 =
1361  dynamic_cast<const tensorBasis*>(&tbasis) )
1362  {
1363  m_bases.push_back(tb2->clone().release());
1364  }
1365  else
1366  {
1367  GISMO_ERROR("Cannot construct a Hierarchical basis from "<< tbasis );
1368  }
1369 
1370  // Initialize the binary tree
1371  point upp;
1372  for ( index_t i = 0; i!=d; ++i )
1373  upp[i] = m_bases[0]->knots(i).numElements();
1374 
1375  m_tree.init(upp);
1376 
1377  // Need one level at least, in case refine(gsMatrix<T> boxes) is called
1378  this->needLevel(1);
1379 }
1380 
1381 
1382 template<short_t d, class T>
1384 {
1385  gsMatrix<T> currPoint;
1386  point low, upp, cur;
1387  const int maxLevel = m_tree.getMaxInsLevel();
1388 
1389  std::vector<std::vector<index_t> > temp_output;//collects the outputs
1390  temp_output.resize( u.cols() );
1391  size_t sz = 0;
1392 
1393  //gsMatrix<index_t> activesLvl;
1394 
1395  for(index_t p = 0; p < u.cols(); p++) //for all input points
1396  {
1397  currPoint = u.col(p);
1398  for(short_t i = 0; i != d; ++i)
1399  low[i] = m_bases[maxLevel]->knots(i).uFind( currPoint(i,0) ).uIndex();
1400 
1401  if (m_manualLevels)
1402  this->_knotIndexToDiadicIndex(maxLevel,low);
1403 
1404  // Identify the level of the point
1405  const int lvl = m_tree.levelOf(low, maxLevel);
1406  for(int i = 0; i <= lvl; i++)
1407  {
1408  /*
1409  m_bases[i]->active_into(currPoint, activesLvl);
1410 
1411  std::set_intersection(m_xmatrix[i].begin(), m_xmatrix[i].end(),
1412  activesLvl.data(), activesLvl.data() + activesLvl.size(),
1413  std::back_inserter( temp_output[p] ) );
1414  +++ Renumbering to H-basis indexing
1415  */
1416 
1417  m_bases[i]->active_cwise(currPoint, low, upp);
1418  cur = low;
1419  do
1420  {
1421  CMatrix::const_iterator it =
1422  m_xmatrix[i].find_it_or_fail( m_bases[i]->index(cur) );
1423 
1424  if( it != m_xmatrix[i].end() )// if index is found
1425  {
1426  temp_output[p].push_back(
1427  this->m_xmatrix_offset[i] + (it - m_xmatrix[i].begin() )
1428  );
1429  }
1430  }
1431  while( nextCubePoint(cur,low,upp) );
1432  }
1433 
1434  // update result size
1435  if ( temp_output[p].size() > sz )
1436  sz = temp_output[p].size();
1437  }
1438 
1439  result.resize(sz, u.cols() );
1440  for(index_t i = 0; i < result.cols(); i++)
1441  {
1442  result.col(i).topRows(temp_output[i].size())
1443  = gsAsConstVector<index_t>(temp_output[i]);
1444  result.col(i).bottomRows(sz-temp_output[i].size()).setZero();
1445  }
1446 }
1447 
1448 template<short_t d, class T>
1450 {
1451  std::vector<index_t> temp;
1453  for(size_t i = 0; i != m_xmatrix[i].size(); i++)
1454  for (CMatrix::const_iterator it = m_xmatrix[i].begin();
1455  it != m_xmatrix[i].end(); it++)
1456  {
1457  ind = this->m_bases[i]->tensorIndex(*it);
1458  for (unsigned j=0; j!=d; ++j )
1459  if ( (ind[j]==0) || (ind[j]==(this->m_bases[i]->size(j)-1)) )
1460  {
1461  temp.push_back(m_xmatrix_offset[i] + (it-m_xmatrix[i].begin()) );
1462  break;
1463  }
1464  }
1465  return makeMatrix<index_t>(temp.begin(),temp.size(),1 );
1466 }
1467 
1468 template<short_t d, class T>
1470 boundaryOffset(boxSide const & s,index_t offset) const
1471 {
1472  //get information on the side
1473  const index_t k = s.direction();
1474  const bool par = s.parameter();
1475 
1476  std::vector<index_t> temp;
1477  gsVector<index_t,d> ind;
1478  // i goes through all levels of the hierarchical basis
1479  GISMO_ASSERT(this->maxLevel() < this->m_bases.size(),"Something went wrong: maxLevel() < m_bases.size(), "<<this->maxLevel()<<" < "<<m_bases.size());
1480  needLevel(m_xmatrix.size()-1);
1481 
1482  for(size_t i = 0; i != m_xmatrix.size(); i++)
1483  {
1484  GISMO_ASSERT(static_cast<int>(offset)<this->m_bases[i]->size(k),
1485  "Offset ("<<offset<<") cannot be bigger than the amount of basis"
1486  "functions orthogonal to Boxside s! ("<<this->m_bases[i]->size(k)<<")");
1487 
1488  index_t r = ( par ? this->m_bases[i]->size(k) - 1 -offset : offset);
1489  for (CMatrix::const_iterator it = m_xmatrix[i].begin();
1490  it != m_xmatrix[i].end(); it++)
1491  {
1492  ind = this->m_bases[i]->tensorIndex(*it);
1493  if ( ind[k]==r )
1494  temp.push_back(
1495  m_xmatrix_offset[i] + (it - m_xmatrix[i].begin() )
1496  );
1497  }
1498  }
1499  return makeMatrix<index_t>(temp.begin(),temp.size(),1 );
1500 }
1501 
1502 template<short_t d, class T>
1504 boundaryOffsetLevel(boxSide const & s,index_t offset, index_t level) const
1505 {
1506  //get information on the side
1507  //index_t k = s.direction();
1508  //bool par = s.parameter();
1509  return this->m_bases[level]->boundaryOffset(s, offset);
1510 }
1511 
1512 template<short_t d, class T>
1513 index_t gsHTensorBasis<d,T>::
1514 levelAtCorner(boxCorner const & c) const
1515 {
1516  // Get parametric points of corner
1517  gsVector<bool> pars;
1518  c.parameters_into(d,pars);
1519  // Get the support of the underlying tensor basis
1520  gsMatrix<T> supp = m_bases.front()->support();
1521  // Assign the extreme of the support depending on the parametric coordinate
1522  gsVector<T> vec(supp.rows());
1523  for (index_t r = 0; r!=supp.rows(); r++)
1524  vec(r) = supp(r,pars(r));
1525 
1526  return getLevelAtPoint(vec);
1527 }
1528 
1529 template<short_t d, class T>
1530 index_t gsHTensorBasis<d,T>::
1531 functionAtCorner(boxCorner const & c) const
1532 {
1533  index_t lvl = this->levelAtCorner(c);
1534 
1535  // Get the index of the corner on the level
1536  index_t index = m_bases[lvl]->functionAtCorner(c);
1537 
1538  // Transform to (continuous) HBspline index.
1539  return this->flatTensorIndexToHierachicalIndex(index,lvl);
1540 }
1541 
1542 template<short_t d, class T>
1543 index_t gsHTensorBasis<d,T>::
1544 functionAtCorner(boxCorner const & c, index_t level) const
1545 {
1546  // Get the index of the corner on the level
1547  index_t index = m_bases[level]->functionAtCorner(c);
1548 
1549  // Transform to (continuous) HBspline index.
1550  return this->flatTensorIndexToHierachicalIndex(index,level);
1551 }
1552 
1553 /*
1554 template<short_t d, class T>
1555 void gsHTensorBasis<d,T>::evalAllDers_into(const gsMatrix<T> & u, int n,
1556  std::vector<gsMatrix<T> >& result, bool sameElement) const;
1557 {
1558  result.resize(n+1);
1559 
1560 }
1561 */
1562 
1563 template<short_t d, class T>
1564 void gsHTensorBasis<d,T>::uniformRefine(int numKnots, int mul, int dir)
1565 {
1566  GISMO_UNUSED(numKnots);
1567  GISMO_ASSERT(numKnots == 1, "Only implemented for numKnots = 1");
1568 
1569  GISMO_ASSERT( m_tree.getMaxInsLevel() < static_cast<unsigned>(m_bases.size()),
1570  "Problem with max inserted levels: "<< m_tree.getMaxInsLevel()
1571  <<"<" << m_bases.size() <<"\n");
1572 
1573  // Keep consistency of finest level
1574  tensorBasis * last_basis = m_bases.back()->clone().release();
1575  last_basis->uniformRefine(1,mul,dir);
1576  m_bases.push_back( last_basis );
1577 
1578  // Delete the first level
1579  delete m_bases.front();
1580  m_bases.erase( m_bases.begin() );
1581 
1582  // Lift all indices in the tree by one level
1583  m_tree.multiplyByTwo();
1584 
1585  update_structure();
1586 }
1587 
1588 template<short_t d, class T>
1590 {
1591  GISMO_UNUSED(numKnots);
1592  GISMO_ASSERT(numKnots == 1, "Only implemented for numKnots = 1");
1593 
1594  tensorBasis * first_basis = m_bases.front()->clone().release();
1595  first_basis->uniformCoarsen(1);
1596  m_bases.insert( m_bases.begin(), first_basis );
1597 
1598  // Delete the last level
1599  delete m_bases.back();
1600  m_bases.pop_back();
1601 
1602  // Lift all indices in the tree by one level
1603  m_tree.divideByTwo();
1604  // What happens when zero interior knots???????
1605 
1606  update_structure();
1607 }
1608 
1609 
1610 template<short_t d, class T>
1611 std::vector< std::vector< std::vector<index_t > > > gsHTensorBasis<d,T>::domainBoundariesParams( std::vector< std::vector< std::vector< std::vector< T > > > >& result) const
1612 {
1613  std::vector< std::vector< std::vector< std::vector<index_t > > > > dummy;
1614  return domainBoundariesGeneric( dummy, result, false );
1615 }
1616 
1617 template<short_t d, class T>
1618 std::vector< std::vector< std::vector<index_t > > > gsHTensorBasis<d,T>::domainBoundariesIndices( std::vector< std::vector< std::vector< std::vector<index_t > > > >& result ) const
1619 {
1620  std::vector< std::vector< std::vector< std::vector< T > > > > dummy;
1621  return domainBoundariesGeneric( result, dummy, true );
1622 }
1623 
1624 
1625 template<short_t d, class T>
1626 std::vector< std::vector< std::vector<index_t > > > gsHTensorBasis<d,T>::domainBoundariesGeneric(std::vector< std::vector< std::vector< std::vector<index_t > > > >& indices,
1627  std::vector< std::vector< std::vector< std::vector< T > > > >& params,
1628  bool indicesFlag ) const
1629 {
1630  indices.clear();
1631  params.clear();
1632  std::vector< std::vector< std::vector< int > > > res_aabb;
1633  std::vector< std::vector< std::vector<index_t > > > res_aabb_unsigned;
1634  std::vector< std::vector< std::vector< std::vector< index_t > > > > polylines;
1635 
1636  polylines = this->m_tree.getPolylines();
1637  res_aabb.resize( polylines.size() );
1638  // We cannot simply say
1639  // result = this->m_tree.getPolylines();
1640  // because the return value of getPolylines() are vectors of ints and we have no implicit conversion of int to T.
1641 
1642  // We want indices/params to be of the same size as polylines. We achieve this here and in the for cycles.
1643  if( indicesFlag )
1644  indices.resize( polylines.size() );
1645 
1646  else
1647  params.resize(polylines.size());
1648 
1649  int maxLevel = static_cast<int>( this->maxLevel() );
1650  // We precompute the parameter values corresponding to indices of m_maxInsLevel
1651  // although we don't need them if indicesFlag == true.
1652  std::vector<T> x_dir(m_bases[maxLevel]->knots(0).unique());
1653  std::vector<T> y_dir(m_bases[maxLevel]->knots(1).unique());
1654 
1655  for(unsigned int i0 = 0; i0 < polylines.size(); i0++)
1656  {
1657  if( indicesFlag )
1658  indices[i0].resize( polylines[i0].size() );
1659  else
1660  params[i0].resize( polylines[i0].size() );
1661 
1662  res_aabb[i0].resize( polylines[i0].size() );
1663  for(unsigned int i1 = 0; i1 < polylines[i0].size(); i1++)
1664  {
1665  if( indicesFlag )
1666  indices[i0][i1].resize( polylines[i0][i1].size() );
1667  else
1668  params[i0][i1].resize( polylines[i0][i1].size() );
1669 
1670  res_aabb[i0][i1].resize( 4 );
1671  res_aabb[i0][i1][0] = 1000000;
1672  res_aabb[i0][i1][1] = 1000000;
1673  res_aabb[i0][i1][2] = -10000000;
1674  res_aabb[i0][i1][3] = -10000000;
1675  for(unsigned int i2 = 0; i2 < polylines[i0][i1].size(); i2++)
1676  {
1677  if( indicesFlag )
1678  {
1679  indices[i0][i1][i2].resize(4);
1680  indices[i0][i1][i2][0] = polylines[i0][i1][i2][0];
1681  indices[i0][i1][i2][1] = polylines[i0][i1][i2][1];
1682  indices[i0][i1][i2][2] = polylines[i0][i1][i2][2];
1683  indices[i0][i1][i2][3] = polylines[i0][i1][i2][3];
1684 
1685  }
1686  else
1687  {
1688  params[i0][i1][i2].resize(4);
1689  // We could as well successively push_back() them but this should be slightly more efficient.
1690  params[i0][i1][i2][0] = (x_dir[polylines[i0][i1][i2][0]]);
1691  params[i0][i1][i2][1] = (y_dir[polylines[i0][i1][i2][1]]);
1692  params[i0][i1][i2][2] = (x_dir[polylines[i0][i1][i2][2]]);
1693  params[i0][i1][i2][3] = (y_dir[polylines[i0][i1][i2][3]]);
1694  }
1695  if(res_aabb[i0][i1][0]>signed(polylines[i0][i1][i2][0]))
1696  {
1697  res_aabb[i0][i1][0] = polylines[i0][i1][i2][0];
1698  }
1699  if(res_aabb[i0][i1][1]>signed(polylines[i0][i1][i2][1]))
1700  {
1701  res_aabb[i0][i1][1] = polylines[i0][i1][i2][1];
1702  }
1703  if(res_aabb[i0][i1][2]<signed(polylines[i0][i1][i2][2]))
1704  {
1705  res_aabb[i0][i1][2] = polylines[i0][i1][i2][2];
1706  }
1707  if(res_aabb[i0][i1][3]<signed(polylines[i0][i1][i2][3]))
1708  {
1709  res_aabb[i0][i1][3] = polylines[i0][i1][i2][3];
1710  }
1711  }
1712  }
1713  }
1714 
1715  res_aabb_unsigned.resize(res_aabb.size());
1716  for (unsigned int i = 0; i < res_aabb.size(); i++)
1717  {
1718  res_aabb_unsigned[i].resize(res_aabb[i].size());
1719  for (unsigned int j = 0; j < res_aabb[i].size(); j++)
1720  {
1721  res_aabb_unsigned[i][j].resize(res_aabb[i][j].size());
1722  for (unsigned int k = 0; k < res_aabb[i][j].size(); k++)
1723  {
1724  if(res_aabb[i][j][k]<0)
1725  gsWarn << "conversion form signed to unsigned\n";
1726  res_aabb_unsigned[i][j][k] = res_aabb[i][j][k];
1727  }
1728  }
1729  }
1730  return res_aabb_unsigned;
1731 }
1732 
1733 
1734 template<short_t d, class T>
1736 {
1737  // Note: implementation assumes number of old + 1 m_bases exists in this basis
1738  needLevel( old.size() );
1739 
1740  tensorBasis T_0_copy = this->tensorLevel(0);
1741 
1742  std::vector< gsSparseMatrix<T,RowMajor> > transfer(m_bases.size()-1);
1743  std::vector<std::vector<T> > knots(d);
1744 
1745  for(size_t i = 1; i < m_bases.size(); ++i)
1746  {
1747  //T_0_copy.uniformRefine_withTransfer(transfer[i-1], 1);
1748  for(unsigned dim = 0; dim != d; ++dim)
1749  {
1750  const gsKnotVector<T> & ckv = m_bases[i-1]->knots(dim);
1751  const gsKnotVector<T> & fkv = m_bases[i ]->knots(dim);
1752  ckv.symDifference(fkv, knots[dim]);
1753  // equivalent (dyadic ref.):
1754  // ckv.getUniformRefinementKnots(1, knots[dim]);
1755 
1756  //gsDebug << "level: " << i << "\n"
1757  // << "direction: " << dim << "\n";
1758  //gsDebugVar(gsAsMatrix<T>(dirKnots));
1759  }
1760 
1761  T_0_copy.refine_withTransfer(transfer[i-1], knots);
1762  }
1763 
1764  // Add missing empty char. matrices
1765  while ( old.size() >= m_xmatrix.size() )
1766  m_xmatrix.push_back( gsSortedVector<index_t>() );
1767 
1768  result = this->coarsening_direct(old, m_xmatrix, transfer);
1769 
1770  // This function automatically adds additional characteristic matrices,
1771  // even if they are not needed.
1772  // Check whether the characteristic matrices corresponding to the finest
1773  // levels are actually used. If they are empty, i.e., if there are no
1774  // active functions on that level, drop them...
1775  while( m_xmatrix.back().size() == 0 )
1776  m_xmatrix.pop_back();
1777 
1778  // ...similarly, erase all those fine bases which are actually not used.
1779  const int sizeDiff = static_cast<int>( m_bases.size() - m_xmatrix.size() );
1780  if( sizeDiff > 0 )
1781  {
1782  freeAll(m_bases.end() - sizeDiff, m_bases.end());
1783  m_bases.resize(m_xmatrix.size());
1784  }
1785 
1786  result.makeCompressed();
1787 }
1788 
1789 template<short_t d, class T>
1790 void gsHTensorBasis<d,T>::transfer2(const std::vector<gsSortedVector<index_t> >& old, gsSparseMatrix<T>& result)
1791 {
1792  // Note: implementation assumes number of old + 1 m_bases exists in this basis
1793  needLevel( old.size() );
1794 
1795  tensorBasis T_0_copy = this->tensorLevel(0);
1796  std::vector< gsSparseMatrix<T,RowMajor> > transfer( m_bases.size()-1 );
1797  std::vector<std::vector<T> > knots(d);
1798 
1799  for(size_t i = 1; i < m_bases.size(); ++i)
1800  {
1801  //T_0_copy.uniformRefine_withTransfer(transfer[i], 1);
1802  for(short_t dim = 0; dim != d; ++dim)
1803  {
1804  const gsKnotVector<T> & ckv = m_bases[i-1]->knots(dim);
1805  const gsKnotVector<T> & fkv = m_bases[i ]->knots(dim);
1806  ckv.symDifference(fkv, knots[dim]);
1807  // equivalent (dyadic ref.):
1808  // ckv.getUniformRefinementKnots(1, knots[dim]);
1809 
1810  //gsDebug << "level: " << i << "\n"
1811  // << "direction: " << dim << "\n";
1812  //gsDebugVar(gsAsMatrix<T>(dirKnots));
1813  }
1814  T_0_copy.refine_withTransfer(transfer[i-1], knots);
1815  }
1816 
1817  // Add missing empty char. matrices
1818  while ( old.size() >= m_xmatrix.size())
1819  m_xmatrix.push_back( gsSortedVector<index_t>() );
1820 
1821  result = this->coarsening_direct2(old, m_xmatrix, transfer);
1822 
1823  result.makeCompressed();
1824 }
1825 
1826 
1827 template<short_t d, class T>
1828 void gsHTensorBasis<d,T>::increaseMultiplicity(index_t lvl, int dir, T knotValue, int mult)
1829 {
1830  GISMO_ASSERT( static_cast<size_t>(lvl) < m_xmatrix.size(),
1831  "Requested level does not exist.\n");
1832 
1833  if (m_bases[lvl]->knots(dir).has(knotValue))
1834  {
1835  for(unsigned int i =lvl;i < m_bases.size();i++)
1836  m_bases[i]->component(dir).insertKnot(knotValue,mult);
1837  }
1838  else
1839  {
1840  gsWarn<<"Knot value not in the given knot vector."<<std::endl;
1841  }
1842 
1843  update_structure();
1844 }
1845 
1846 
1847 template<short_t d, class T>
1848 void gsHTensorBasis<d,T>::increaseMultiplicity(index_t lvl, int dir, const std::vector<T> & knotValue, int mult)
1849 {
1850  for(unsigned int k =0; k < knotValue.size(); ++k)
1851  {
1852  if (m_bases[lvl]->knots(dir).has(knotValue[k]))
1853  {
1854  for(unsigned int i =lvl;i < m_bases.size(); ++i)
1855  m_bases[i]->component(dir).insertKnot(knotValue[k],mult);
1856  }
1857  else
1858  {
1859  gsWarn<<"Knot value not in the given knot vector."<<std::endl;
1860  }
1861  }
1862  update_structure();
1863 }
1864 
1865 template<short_t d, class T>
1866 void gsHTensorBasis<d,T>::getBoxesAlongSlice( int dir, T par,std::vector<index_t>& boxes ) const
1867 {
1868  gsMatrix<index_t> b1,b2;
1869  gsVector<index_t> level;
1870  m_tree.getBoxesInLevelIndex(b1,b2,level);
1871  gsVector<index_t> min,max;
1872  for(index_t i = 0;i<level.rows();i++)
1873  {
1874  min = b1.row(i);
1875  max = b2.row(i);
1876  const index_t l = level(i);
1877  const index_t par_index = m_bases[l]->knots(dir).uFind(par).uIndex();
1878  if(l>0 && (par_index>=min(dir)) && (par_index<=max(dir)))
1879  {
1880  boxes.push_back(l);
1881  for(index_t j=0;j<min.rows();++j)
1882  if(j!=dir)
1883  boxes.push_back(min(j));
1884  for(index_t j=0;j<max.rows();++j)
1885  if(j!=dir)
1886  boxes.push_back(max(j));
1887  }
1888  }
1889 }
1890 
1891 template<short_t d, class T>
1892 void gsHTensorBasis<d,T>::_knotIndexToDiadicIndex(const index_t level, const index_t dir, index_t & knotIndex) const
1893 {
1894  GISMO_ASSERT(m_manualLevels,"Only works for manual levels");
1895  knotIndex = m_uIndices[level][dir][knotIndex];
1896 }
1897 
1898 template<short_t d, class T>
1900 {
1901  for (index_t r = 0; r != d; r++)
1902  this->_knotIndexToDiadicIndex(level,r,knotIndex[r]);
1903 }
1904 
1905 template<short_t d, class T>
1906 void gsHTensorBasis<d,T>::_diadicIndexToKnotIndex(const index_t level, const index_t dir, index_t & diadicIndex) const
1907 {
1908  GISMO_ASSERT(m_manualLevels,"Only works for manual levels");
1909  typename std::vector<index_t>::const_iterator it = std::find_if(m_uIndices[level][dir].begin(),m_uIndices[level][dir].end(),[&diadicIndex](const index_t i) { return i >= diadicIndex; });
1910  GISMO_ASSERT(it!=m_uIndices[level][dir].end(),"Index not found");
1911  diadicIndex = std::distance(m_uIndices[level][dir].begin(),it);
1912 }
1913 
1914 template<short_t d, class T>
1916 {
1917  for (index_t r = 0; r != d; r++)
1918  this->_diadicIndexToKnotIndex(level,r,diadicIndex[r]);
1919 }
1920 
1921 
1922 template<short_t d, class T>
1923 void gsHTensorBasis<d,T>::degreeElevate(int const & i, int const dir)
1924 {
1925  for (size_t level=0;level<m_bases.size();++level)
1926  m_bases[level]->degreeElevate(i,dir);
1927 
1928  for(unsigned c=0; c<d; ++c)
1929  m_deg[c]=m_bases[0]->degree(c);
1930 
1931  this->update_structure();
1932 }
1933 
1934 template<short_t d, class T>
1935 void gsHTensorBasis<d,T>::degreeReduce(int const & i, int const dir)
1936 {
1937  for (size_t level=0;level<m_bases.size();++level)
1938  m_bases[level]->degreeReduce(i,dir);
1939 
1940  for(unsigned c=0; c<d; ++c)
1941  m_deg[c]=m_bases[0]->degree(c);
1942 
1943  this->update_structure();
1944 }
1945 
1946 template<short_t d, class T>
1947 void gsHTensorBasis<d,T>::degreeIncrease(int const & i, int const dir)
1948 {
1949  for (size_t level=0;level<m_bases.size();++level)
1950  m_bases[level]->degreeIncrease(i,dir);
1951 
1952  for(unsigned c=0; c<d; ++c)
1953  m_deg[c]=m_bases[0]->degree(c);
1954 
1955  this->update_structure();
1956 }
1957 
1958 template<short_t d, class T>
1959 void gsHTensorBasis<d,T>::degreeDecrease(int const & i, int const dir)
1960 {
1961  for (size_t level=0;level<m_bases.size();++level)
1962  m_bases[level]->degreeDecrease(i,dir);
1963 
1964  for(unsigned c=0; c<d; ++c)
1965  m_deg[c]=m_bases[0]->degree(c);
1966 
1967  this->update_structure();
1968 }
1969 
1970 template<short_t d, class T>
1971 bool gsHTensorBasis<d,T>::testPartitionOfUnity(const index_t npts, const T tol) const
1972 {
1973  gsVector<unsigned> np(d);
1974  np.setConstant(npts);
1975  gsMatrix<T> supp = this->support();
1976  gsMatrix<T> grid = gsPointGrid<T>(supp.col(0),supp.col(1),np);
1977  gsMatrix<T> res;
1978  this->eval_into(grid,res);
1979  gsVector<T> sums = res.colwise().sum();
1980  return ((sums.array()>1-tol && sums.array()<1+tol).all());
1981 }
1982 
1983 
1984 namespace internal
1985 {
1986 
1988 template<short_t d, class T>
1989 class gsXml< gsHTensorBasis<d,T> >
1990 {
1991 private:
1992  gsXml() { }
1993 public:
1994  GSXML_COMMON_FUNCTIONS(gsHTensorBasis<TMPLA2(d,T)>);
1995  static std::string tag () { return "Basis"; }
1996  static std::string type () { return ""; } // tag ?
1997 
1998  static gsHTensorBasis<d,T> * get (gsXmlNode * node)
1999  {
2000  gsXmlAttribute * btype = node->first_attribute("type");
2001  if ( ! btype )
2002  {
2003  gsWarn<< "Basis without a type in the xml file.\n";
2004  return NULL;
2005  }
2006  std::string s = btype->value() ;
2007  if ( s.compare(0, 9, "HBSplineB" , 9 ) == 0 ) // needs correct d as well
2008  return gsXml< gsHBSplineBasis<d,T> >::get(node);
2009  if ( s.compare(0, 10,"THBSplineB", 10) == 0 )
2010  return gsXml< gsTHBSplineBasis<d,T> >::get(node);
2011 
2012  gsWarn<<"gsXmlUtils: gsHTensorBasis: No known basis \""<<s<<"\". Error.\n";
2013  return NULL;
2014  }
2015 
2016  static gsXmlNode * put (const gsHTensorBasis<d,T> & obj,
2017  gsXmlTree & data )
2018  {
2019  const gsBasis<T> * ptr = & obj;
2020 
2021  // Hier. B-splines
2022  if ( const gsHBSplineBasis<d,T> * g =
2023  dynamic_cast<const gsHBSplineBasis<d,T> *>( ptr ) )
2024  return gsXml< gsHBSplineBasis<d,T> >::put(*g,data);
2025 
2026  // Truncated hier. B-splines
2027  if ( const gsTHBSplineBasis<d,T> * g =
2028  dynamic_cast<const gsTHBSplineBasis<d,T> *>( ptr ) )
2029  return gsXml< gsTHBSplineBasis<d,T> >::put(*g,data);
2030 
2031  gsWarn<<"gsXmlUtils put: getBasis: No known basis \""<<obj<<"\". Error.\n";
2032  return NULL;
2033  }
2034 };
2035 
2036 } // namespace internal
2037 
2038 
2039 } // namespace gismo
void insert_box(point const &k1, point const &k2, int lvl)
Inserts a domain into the basis.
Definition: gsHTensorBasis.hpp:1207
index_t getLevelAtIndex(const point &Pt) const
Returns the level(s) at indexes in the parameter domain.
Definition: gsHTensorBasis.hpp:160
virtual void connectivity(const gsMatrix< T > &nodes, gsMesh< T > &mesh) const
Definition: gsHTensorBasis.hpp:281
void refineElements_withCoefs(gsMatrix< T > &coefs, std::vector< index_t > const &boxes)
Definition: gsHTensorBasis.hpp:314
T distance(gsMatrix< T > const &A, gsMatrix< T > const &B, index_t i=0, index_t j=0, bool cols=false)
compute a distance between the point number in the set and the point number &lt;j&gt; in the set ; by def...
Iterates over the leaves of an gsHDomain (tree).
Definition: gsHDomainLeafIter.h:29
mult_t maxInteriorMultiplicity() const
Returns the maximum multiplicity in the interior.
Definition: gsKnotVector.hpp:724
bool nextCubePoint(Vec &cur, const Vec &end)
Iterate in lexigographic order through the points of the integer lattice contained in the cube [0...
Definition: gsCombinatorics.h:327
#define gsDebug
Definition: gsDebug.h:61
void getBoxesAlongSlice(int dir, T par, std::vector< index_t > &boxes) const
Definition: gsHTensorBasis.hpp:1866
#define short_t
Definition: gsConfig.h:35
void uniformRefine_withCoefs(gsMatrix< T > &coefs, int numKnots=1, int mul=1, int dir=-1)
Refine the basis uniformly.
Definition: gsHTensorBasis.hpp:380
void _diadicIndexToKnotIndex(const index_t level, gsVector< index_t, d > &diadicIndex) const
Transfers the diadicIndex in the knot span in direction on level level to knot indices.
Definition: gsHTensorBasis.hpp:1915
void setActiveToLvl(int level, std::vector< CMatrix > &x_matrix_lvl) const
Creates characteristic matrices for basis where &quot;level&quot; is the maximum level i.e. ignoring higher lev...
Definition: gsHTensorBasis.hpp:1153
virtual short_t degree(short_t i) const
Degree with respect to the i-th variable. If the basis is a tensor product of (piecewise) polynomial ...
Definition: gsBasis.hpp:650
bool parameter() const
Returns the parameter value (false=0=start, true=1=end) that corresponds to this side.
Definition: gsBoundary.h:128
std::vector< std::vector< std::vector< index_t > > > domainBoundariesGeneric(std::vector< std::vector< std::vector< std::vector< index_t > > > > &indices, std::vector< std::vector< std::vector< std::vector< T > > > > &params, bool indicesFlag) const
Implementation of the features common to domainBoundariesParams and domainBoundariesIndices. It takes both.
Definition: gsHTensorBasis.hpp:1626
virtual void increaseMultiplicity(index_t lvl, int dir, T knotValue, int mult=1)
Increases the multiplicity of a knot with the value knotValue in level lvl in direction dir by mult...
Definition: gsHTensorBasis.hpp:1828
uiterator domainUEnd() const
Returns a unique iterator pointing to the ending knot of the domain.
Definition: gsKnotVector.h:367
#define index_t
Definition: gsConfig.h:32
virtual void uniformCoarsen(int numKnots=1)
Coarsen the basis uniformly by removing groups of numKnots consecutive knots, each knot removed mul t...
Definition: gsTensorBasis.h:349
#define GISMO_ENSURE(cond, message)
Definition: gsDebug.h:102
This class is derived from std::vector, and adds sort tracking.
Definition: gsSortedVector.h:109
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
void insert(T knot, mult_t mult=1)
Inserts knot knot into the knot vector with multiplicity mult.
Definition: gsKnotVector.hpp:325
A tensor product B-spline basis.
Definition: gsTensorBSplineBasis.h:36
#define GISMO_ASSERT(cond, message)
Definition: gsDebug.h:89
Provides implementation of generic XML functions.
bool testPartitionOfUnity(const index_t npts=100, const T tol=1e-12) const
Test the partition of unity.
Definition: gsHTensorBasis.hpp:1971
virtual void unrefineElements(std::vector< index_t > const &boxes)
Clear the given boxes into the quadtree.
Definition: gsHTensorBasis.hpp:864
Sparse matrix class, based on gsEigen::SparseMatrix.
Definition: gsSparseMatrix.h:140
uiterator uFind(const T u) const
Returns the uiterator pointing to the knot at the beginning of the knot interval containing u...
Definition: gsKnotVector.hpp:747
void makeCompressed()
Cleans the basis, removing any inactive levels.
Definition: gsHTensorBasis.hpp:1219
void _knotIndexToDiadicIndex(const index_t level, const index_t dir, index_t &knotIndex) const
Transfers the knotIndex in the knot span in direction dir on level level to diadic indices...
Definition: gsHTensorBasis.hpp:1892
Class Representing a triangle mesh with 3D vertices.
Definition: gsMesh.h:31
index_t getLevelAtPoint(const gsMatrix< T > &Pt) const
Returns the level(s) at point(s) in the parameter domain.
Definition: gsHTensorBasis.hpp:141
index_t size() const
The number of basis functions in this basis.
Definition: gsHTensorBasis.hpp:298
void activeBoundaryFunctionsOfLevel(const unsigned level, const boxSide &s, std::vector< bool > &actives) const
Definition: gsHTensorBasis.hpp:1285
gsMatrix< T > support() const
Returns the boundary basis for side s.
Definition: gsHTensorBasis.hpp:124
Class representing a (scalar) hierarchical tensor basis of functions .
Definition: gsHTensorBasis.h:74
#define gsWarn
Definition: gsDebug.h:50
uiterator domainUBegin() const
Returns a unique iterator pointing to the starting knot of the domain.
Definition: gsKnotVector.h:359
void functionOverlap(const point &boxLow, const point &boxUpp, const int level, point &actLow, point &actUpp)
Returns the basis functions of level which have support on box, represented as an index box...
Definition: gsHTensorBasis.hpp:1079
void numActive_into(const gsMatrix< T > &u, gsVector< index_t > &result) const
The number of active basis functions at points u.
Definition: gsHTensorBasis.hpp:187
virtual void refineElements(std::vector< index_t > const &boxes)
Insert the given boxes into the quadtree.
Definition: gsHTensorBasis.hpp:843
void addLevel(const gsTensorBSplineBasis< d, T > &next_basis)
Adds a level, only if manual levels are activated.
Definition: gsHTensorBasis.hpp:35
virtual void active_into(const gsMatrix< T > &u, gsMatrix< index_t > &result) const
Returns the indices of active basis functions at points u, as a list of indices, in result...
Definition: gsHTensorBasis.hpp:1383
int flatTensorIndexToHierachicalIndex(index_t index, const int level) const
takes a flat tensor index of the bspline basis of level and gives back the hierachical index...
Definition: gsHTensorBasis.hpp:1273
void symDifference(const gsKnotVector< T > &other, std::vector< T > &result) const
Computes the symmetric difference between this knot-vector and other.
Definition: gsKnotVector.hpp:172
void refineSide(const boxSide side, index_t lvl)
Refines all the cells on the side side up to level lvl.
Definition: gsHTensorBasis.hpp:901
void freeAll(It begin, It end)
Frees all pointers in the range [begin end)
Definition: gsMemory.h:312
gsMatrix< index_t > allBoundary() const
Returns the indices of the basis functions that are nonzero at the domain boundary.
Definition: gsHTensorBasis.hpp:1449
virtual void refine(gsMatrix< T > const &boxes, int refExt)
Refine the basis to levels and in the areas defined by boxes with an extension.
Definition: gsHTensorBasis.hpp:444
Struct which represents a certain side of a box.
Definition: gsBoundary.h:84
void getLevelUniqueSpanAtPoints(const gsMatrix< T > &Pt, gsVector< index_t > &lvl, gsMatrix< index_t > &loIdx) const
Returns the level(s) and knot span(s) at point(s) in the parameter domain.
Definition: gsHTensorBasis.hpp:170
virtual void update_structure()
Updates the basis structure (eg. charact. matrices, etc), to be called after any modifications.
Definition: gsHTensorBasis.hpp:1308
virtual gsMatrix< index_t > boundaryOffset(boxSide const &s, index_t offset) const
Definition: gsHTensorBasis.hpp:1470
virtual void uniformCoarsen(int numKnots=1)
Coarsen the basis uniformly by removing groups of numKnots consecutive knots, each knot removed mul t...
Definition: gsHTensorBasis.hpp:1589
unsigned index(unsigned i, unsigned j, unsigned k=0) const
Definition: gsTensorBasis.h:882
Provides declaration of the Mesh class.
uPtr clone()
Clone methode. Produceds a deep copy inside a uPtr.
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: gsHTensorBasis.hpp:1564
void uniformCoarsen_withCoefs(gsMatrix< T > &coefs, int numKnots=1)
Coarsen the basis uniformly.
Definition: gsHTensorBasis.hpp:418
const point & upperCorner() const
Accessor for gsHDomain::m_upperIndex.
Definition: gsHDomain.h:249
unsigned stride(short_t dir) const
Returns the stride for dimension dir.
Definition: gsTensorBasis.h:889
bool nextLexicographic(Vec &cur, const Vec &size)
Iterates through a tensor lattice with the given size. Updates cur and returns true if another entry ...
Definition: gsCombinatorics.h:196
#define GISMO_UNUSED(x)
Definition: gsDebug.h:112
Provides functions to generate structured point data.
void needLevel(int maxLevel) const
Makes sure that there are numLevels grids computed in the hierarachy.
Definition: gsHTensorBasis.hpp:1337
void flatTensorIndexesToHierachicalIndexes(gsSortedVector< int > &indexes, const int level) const
transformes a sortedVector indexes of flat tensor index of the bspline basis of level to hierachical ...
Definition: gsHTensorBasis.hpp:1236
#define GISMO_ERROR(message)
Definition: gsDebug.h:118
Class for representing a knot vector.
Definition: gsKnotVector.h:79
void refineBasisFunction(const index_t i)
Refines the basis function with (hierarchical) index i.
Definition: gsHTensorBasis.hpp:811
Creates a mapped object or data pointer to a const vector without copying data.
Definition: gsLinearAlgebra.h:130
patchSide & second()
second, returns the second patchSide of this interface
Definition: gsBoundary.h:782
Struct which represents an interface between two patches.
Definition: gsBoundary.h:649
std::vector< std::vector< std::vector< index_t > > > domainBoundariesIndices(std::vector< std::vector< std::vector< std::vector< index_t > > > > &result) const
Gives polylines on the boundaries between different levels of the mesh.
Definition: gsHTensorBasis.hpp:1618
void transfer(const std::vector< gsSortedVector< index_t > > &old, gsSparseMatrix< T > &result)
Returns transfer matrix between the hirarchical spline given by the characteristic matrix &quot;old&quot; and t...
Definition: gsHTensorBasis.hpp:1735
const Basis_t & component(short_t dir) const
For a tensor product basis, return the (const) 1-d basis for the i-th parameter component.
Definition: gsTensorBSplineBasis.h:202
int degree() const
Returns the degree of the knot vector.
Definition: gsKnotVector.hpp:700
std::vector< std::vector< std::vector< index_t > > > domainBoundariesParams(std::vector< std::vector< std::vector< std::vector< T > > > > &result) const
Gives polylines on the boundaries between different levels of the mesh.
Definition: gsHTensorBasis.hpp:1611
short_t direction() const
Returns the parametric direction orthogonal to this side.
Definition: gsBoundary.h:113
Provides declaration of input/output XML utilities struct.
A basis represents a family of scalar basis functions defined over a common parameter domain...
Definition: gsBasis.h:78
bool good() const
Returns true iff we are still pointing at a valid leaf.
Definition: gsHDomainLeafIter.h:81
patchSide & first()
first, returns the first patchSide of this interface
Definition: gsBoundary.h:776