G+Smo  24.08.0
Geometry + Simulation Modules
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
gsTensorBasis.hpp
Go to the documentation of this file.
1 
14 #pragma once
15 
16 #include <gsTensor/gsTensorTools.h>
19 
20 #include <gsCore/gsBoundary.h>
21 #include <gsUtils/gsMesh/gsMesh.h>
22 #include <gsCore/gsGeometry.h>
23 //#include <gsUtils/gsSortedVector.h>
24 
25 
26 #if defined __INTEL_COMPILER
27 #pragma warning (disable : 175 ) /* disable subscript out of range warning */
28 #endif
29 
30 namespace gismo
31 {
32 
33 template<short_t d, class T>
35 {
36  GISMO_ASSERT( d==2, "gsTensorBasis error: wrong dimension." );
37 
38  if ( x->dim() == 1 && y->dim() == 1 )
39  {
40  m_bases[0] = x;
41  m_bases[1] = y;
42  } else
43  GISMO_ERROR("gsTensorBasis error: Spaces must be of topological dimension 1.");
44 }
45 
46 
47 template<short_t d, class T>
49 {
50  GISMO_ASSERT( d==3, "gsTensorBasis error: wrong dimension." );
51 
52  GISMO_ASSERT( x->dim() == 1 && y->dim() == 1 && z->dim() == 1,
53  "Spaces must be of topological dimension 1." );
54 
55  if ( d==3 )
56  {
57  m_bases[0] = x;
58  m_bases[1] = y;
59  m_bases[2] = z;
60  }
61  else
62  GISMO_ERROR("gsTensorBasis incorrect constructor for "<<d<<"D basis");
63 }
64 
65 template<short_t d, class T>
67 {
68  GISMO_ASSERT( d==4, "gsTensorBasis error: wrong dimension." );
69 
70  GISMO_ASSERT( x->dim() == 1 && y->dim() == 1 && z->dim() == 1 && w->dim() == 1,
71  "Spaces must be of topological dimension 1." );
72 
73  if ( d==4 )
74  {
75  m_bases[0] = x;
76  m_bases[1] = y;
77  m_bases[2] = z;
78  m_bases[3] = w;
79  }
80  else
81  GISMO_ERROR("gsTensorBasis incorrect constructor for "<<d<<"D basis");
82 }
83 
84 
85 /*
86 template<short_t d, class T>
87 gsTensorBasis<d,T>::gsTensorBasis( std::vector<Basis_t*> const & bb )
88 {
89  GISMO_ASSERT( d==bb.size(), "gsTensorBasis error: wrong number of bases given ("
90  << bb.size()<< ", expected "<< d );
91 
92  for (unsigned i = 0; i < d; ++i)
93  m_bases[i] = bb[i];
94 }
95 */
96 
98 template<short_t d, class T>
100 : gsBasis<T>(o)
101 {
102  for (short_t i = 0; i < d; ++i)
103  m_bases[i] = o.m_bases[i]->clone().release();
104 }
105 
106 
107 template<short_t d, class T>
109 {
110  if ( this == &o )
111  return *this;
113 
114  for (short_t i = 0; i < d; ++i)
115  {
116  delete m_bases[i];
117  m_bases[i] = o.m_bases[i]->clone().release();
118  }
119  return *this;
120 }
121 
122 
123 template<short_t d, class T>
125 {
126  gsMatrix<T> gr[d];
127  gsVector<unsigned, d> v, size;
128  result.resize( d, this->size() );
129 
130  for (short_t i = 0; i < d; ++i)
131  {
132  gr[i] = m_bases[i]->anchors();
133  size[i] = this->size(i);
134  }
135 
136  // iterate over all tensor product basis functions
137  v.setZero();
138  unsigned r = 0;
139  do {
140  // Make tensor product of greville points
141  for (unsigned i=0; i<d; ++i )
142  result(i,r)= (gr[i])( 0, v(i) );
143  ++r ;
144  } while (nextLexicographic(v, size));
145 }
146 
147 template<short_t d, class T>
149 {
150  gsVector<index_t, d> ti = tensorIndex(i);
151 
152  gsMatrix<T> gr;
153  result.resize(d, 1);
154 
155  for (short_t l = 0; l < d; ++l)
156  {
157  m_bases[l]->anchor_into(ti[l], gr);
158  result(l,0) = gr.value();
159  }
160 }
161 
162 template<short_t d, class T>
164  gsMesh<T> & mesh) const
165 {
166  const index_t sz = size();
167  GISMO_ASSERT( nodes.rows() == sz, "Invalid input.");
168 
169  // Add vertices
170  for(index_t i = 0; i< sz; ++i )
171  mesh.addVertex( nodes.row(i).transpose() );
172 
173  // Starting from lower corner
175 
176  // Last tensor-index
178  for (short_t i = 0; i < d; ++i)
179  end(i) = this->size(i) - 1;
180 
181  unsigned k, s;
182  gsVector<index_t,d> v, upp;
183  for (short_t i = 0; i < d; ++i) // For all axes
184  {
185  s = stride(i);
186  v = low;
187  upp = end;
188  upp[i] = 0; // suppress to face v[i]==0
189 
190  do // Insert all edges normal to axis i
191  {
192  k = index(v);
193  for (index_t j = 0; j != end[i]; ++j)
194  {
195  mesh.addEdge(k, k + s );
196  k += s;
197  }
198  }
199  while ( nextCubePoint(v, low, upp) );
200  }
201 }
202 
203 template<short_t d, class T>
205 {
206  //gsWarn<<"genericActive "<< *this;
207 
208  gsMatrix<index_t> act[d];
209  gsVector<index_t, d> v, size;
210 
211  // Get component active basis functions
212  index_t nb = 1;
213  for (short_t i = 0; i < d; ++i)
214  {
215  m_bases[i]->active_into(u.row(i), act[i]);
216  size[i] = act[i].rows();
217  nb *= size[i];
218  }
219 
220  result.resize( nb, u.cols() );
221 
222  // iterate over all tensor product active functions
223  unsigned r = 0;
224  v.setZero();
225  do {
226  // Fill with active bases indices
227  for ( index_t j=0; j<u.cols(); ++j)
228  {
229  nb = act[d-1]( v(d-1) ,j) ;//compute global index in the tensor product
230  for ( short_t i=d-2; i>=0; --i ) // to do: strides
231  nb = nb * m_bases[i]->size() + act[i](v(i), j) ;
232  result(r, j) = nb;
233  }
234  ++r ;
235  } while (nextLexicographic(v, size));
236 }
237 
238 template<short_t d, class T>
239 bool gsTensorBasis<d,T>::isActive(const index_t i, const gsVector<T>& u) const
240 {
241  GISMO_ASSERT( u.rows() == static_cast<index_t>(d), "Invalid input.");
242  const gsVector<index_t, d> ti = tensorIndex(i);
243  for (short_t k = 0; k < d; ++k)
244  if ( ! m_bases[k]->isActive(ti[k], u.row(k)) )
245  return false;
246  return true;
247 }
248 
249 template<short_t d, class T>
251 {
252  GISMO_ASSERT( dir>=0 && dir < this->dim(), "Invalid slice direction requested" );
253  GISMO_ASSERT( k >=0 && k < this->size(dir), "Invalid slice position requested" );
254 
255  index_t sliceSize = 1, r = 0;
256  gsVector<index_t, d> low, upp;
257 
258  // Set low and upp to point to the range of indices
259  for (short_t i = 0; i < d; ++i)
260  {
261  sliceSize *= this->size(i); // or trueSize(i) ?
262  low(r) = 0;
263  upp(r++) = this->size(i); // or trueSize(i) ?
264  }
265  sliceSize /= upp(dir);
266  upp(dir) = k + 1;
267  low(dir) = k;
268 
269  gsMatrix<index_t> res(sliceSize,1);
270 
271  // iterate over all tensor product basis indices
272  gsVector<index_t,d> v = low;
273  r = 0;
274  do {
275  res(r++,0) = this->index(v);
276  } while ( nextLexicographic(v, low, upp) );
277 
278  return res;
279 }
280 
281 
282 template<short_t d, class T>
284 {
286  std::set<index_t> bdofs;
287 
288  for (short_t k = 0; k != d; ++k)
289  {
290  bd = this->coefSlice(k, 0);
291  for (index_t i = 0; i < bd.size(); ++i)
292  bdofs.insert( bd(i) );
293 
294  bd = this->coefSlice(k, size(k) - 1);
295  for (index_t i = 0; i < bd.size(); ++i)
296  bdofs.insert( bd(i) );
297  }
298 
299  return makeMatrix<index_t>(bdofs.begin(), static_cast<index_t>(bdofs.size()), 1 );
300 }
301 
302 
303 template<short_t d, class T>
305 {
306  //get m_bases index and start or end case
307  short_t k = s.direction();
308  bool r = s.parameter();
309  GISMO_ASSERT(offset < size(k),"Offset cannot be bigger than the amount of basis functions orthogonal to Boxside s!");
310  return (this->coefSlice(k, (r ? size(k) - 1 -offset : offset) ));
311 }
312 
313 template<short_t d, class T>
315 {
316  gsVector<bool> position(d);
317  c.parameters_into(d, position);
318 
319  index_t index = 0;
320  index_t str = 1;
321 
322  for(short_t i = 0; i!=d; ++i)
323  {
324  const index_t sz_i = size(i);
325  if ( position[i] )
326  index+= str * ( sz_i - 1 );
327  str *= sz_i;
328  }
329 
330  return index;
331 }
332 
333 /*
334 template<short_t d, class T>
335 void gsTensorBasis<d,T>::boundary_into(boxSide const & s, gsMatrix<int> & bstruct, gsMatrix<unsigned>& result) const
336 {
337  //get m_bases index and start or end case
338  index_t k = s.direction();
339  index_t r = s.parameter();
340 
341  // Compute the structure of the boundary dofs
342  bstruct.resize(d-1);
343  index_t c = 0;
344  for (index_t k = 0; k<d; ++k )
345  {
346  if ( k == s ) continue;
347  bSize[c] = m_bases[k]->size();
348  c++;
349  }
350 
351  return this->slice(k, (r ? size(k) - 1 : 0) ).release();
352 }
353 */
354 
355 /*
356 template <short_t d, class BB, class B>
357 struct MakeBoundaryBasis
358 {
359  static BB* make (const std::vector< B * >& bases)
360  {
361  return new BB( bases );
362  }
363 };
364 
365 template <class BB, class B>
366 struct MakeBoundaryBasis<2, BB, B>
367 {
368  static BB* make (const std::vector< B * >& bases)
369  {
370  return bases[0];
371  }
372 };
373 */
374 
375 template<short_t d, class T>
376 void
377 gsTensorBasis<d,T>::getComponentsForSide(boxSide const& s, std::vector<Basis_t*> & rr) const
378 {
379  index_t dir = s.direction( );
380 
381  rr.clear();
382  rr.reserve( d - 1 );
383  for ( short_t i=0; i < d; ++i )
384  if (i != dir)
385  rr.push_back(m_bases[i]->clone().release());
386 }
387 
388 
389 template<short_t d, class T>
391 {
392  gsMatrix<T> res(d,2);
393  for (short_t i = 0; i < d; ++i)
394  res.row(i) = m_bases[i]->support();
395  return res;
396 }
397 
398 template<short_t d, class T>
401 {
402  gsMatrix<T> res(d,2);
403  gsVector<index_t, d> ti = tensorIndex(i);
404  for (short_t j = 0; j < d; ++j)
405  res.row(j) = m_bases[j]->support( ti[j] );
406  return res;
407 }
408 
409 template<short_t d, class T>
411  const gsMatrix<T> & u,
412  gsMatrix<T>& result) const
413 {
414  result.resize(1,u.cols() );
415  gsMatrix<T> ev;
417  ti = tensorIndex(i);
418 
419  // Evaluate univariate basis functions and compute the product
420  this->m_bases[0]->evalSingle_into(ti[0], u.row(0), result);
421  for (short_t k = 1; k < d; ++k)
422  {
423  this->m_bases[k]->evalSingle_into( ti[k], u.row(k), ev);
424  result = result.cwiseProduct(ev);
425  }
426 }
427 
428 template<short_t d, class T>
430  const gsMatrix<T> & u,
431  gsMatrix<T>& result) const
432 {
434  ti.noalias() = tensorIndex(i);
435  gsMatrix<T> ev, dev;
436  result.setOnes(d, u.cols() );
437 
438  for (short_t k = 0; k != d; ++k)
439  {
440  m_bases[k]->evalSingle_into ( ti[k], u.row(k), ev );
441  m_bases[k]->derivSingle_into( ti[k], u.row(k), dev );
442 
443  result.row(k) = result.row(k).cwiseProduct(dev);
444  result.topRows(k) = result.topRows(k) * ev.asDiagonal();
445  // for (unsigned j = 0; j != k; ++j)
446  // result.row(j) = result.row(j).cwiseProduct(ev);
447  result.bottomRows(d-k-1) = result.bottomRows(d-k-1) * ev.asDiagonal();
448  // for (unsigned j = k+1; j != d; ++j)
449  // result.row(j) = result.row(j).cwiseProduct(ev);
450  }
451 }
452 
453 template<short_t d, class T>
455  const gsMatrix<T> & u,
456  gsMatrix<T>& result) const
457 {
459  ti.noalias() = tensorIndex(i);
460  gsMatrix<T> ev[d], dev[d], ddev;
461  result.setOnes( d*(d + 1)/2, u.cols() );
462 
463  // Precompute values and first derivatives
464  for (short_t k = 0; k != d; ++k)
465  {
466  m_bases[k]->evalSingle_into ( ti[k], u.row(k), ev[k] );
467  m_bases[k]->derivSingle_into( ti[k], u.row(k), dev[k] );
468  }
469 
470  index_t c = d;
471  for (short_t k = 0; k != d; ++k)
472  {
473  // Pure second derivatives
474  m_bases[k]->deriv2Single_into( ti[k], u.row(k), ddev );
475  result.row(k) = result.row(k).cwiseProduct(ddev);
476 
477  // Multiply values to all other second derivatives
478  result.topRows(k) = result.topRows(k) * ev[k].asDiagonal();
479  result.middleRows(k+1,d-k-1) = result.middleRows(k+1, d-k-1) * ev[k].asDiagonal();
480 
481  // Second mixed derivatives
482  for (short_t l = k+1; l != d; ++l)
483  {
484  // Multiply with k-th first derivative
485  result.row(c) = result.row(c).cwiseProduct(dev[k]);
486  // Multiply with l-th first derivative
487  result.row(c) = result.row(c).cwiseProduct(dev[l]);
488 
489  // Multiply with values
490  for (short_t r = 0; r != k; ++r)
491  result.row(c) = result.row(c).cwiseProduct(ev[r]);
492  for (short_t r = k+1; r != l; ++r)
493  result.row(c) = result.row(c).cwiseProduct(ev[r]);
494  for (short_t r = l+1; r < d; ++r)
495  result.row(c) = result.row(c).cwiseProduct(ev[r]);
496  c++;
497  }
498  }
499 }
500 
501 template<short_t d, class T>
503  gsMatrix<T>& result) const
504 {
505  GISMO_ASSERT( u.rows() == d,
506  "Attempted to evaluate the tensor-basis on points with the wrong dimension" );
507 
509 
510  gsMatrix<T> ev[d];
511  gsVector<unsigned, d> v, size;
512 
513  // Evaluate univariate basis functions
514  unsigned nb = 1;
515  for (short_t i = 0; i < d; ++i)
516  {
517  m_bases[i]->eval_into( u.row(i), ev[i] );
518  nb *= ev[i].rows();
519  size[i] = ev[i].rows();
520  }
521 
522  // initialize result
523  result.resize( nb, u.cols() );
524 
525  // iterate over all tensor product basis functions
526  v.setZero();
527  unsigned r = 0;
528  do {
529  // Multiply BSplines to get the value of basis function v
530  result.row( r )= ev[0].row( v(0) );
531  for ( short_t i=1; i<d; ++i)
532  result.row( r )= result.row( r ).cwiseProduct( ev[i].row( v(i) ) ) ;
533 
534  ++r ;
535  } while (nextLexicographic(v, size));
536 };
537 
538 template<short_t d, class T>
540  const gsMatrix<T> & coefs,
541  gsMatrix<T> & result ) const
542 {
543 
544 #if (0)
545  //~ version using the tensor structure; uses more memory, check
546  result.resize( coefs.cols(), u.cols() ) ;
547 
548  unsigned sz = this->size()/m_bases[0]->size();
549  unsigned n = coefs.cols();
550  gsAsMatrix<T> cc(coefs.data(), m_bases[0]->size(), n * sz);
551  gsMatrix<T> e0,e1;
552 
553  for ( index_t j=0; j< u.cols() ; j++ ) // for all points (columns of u)
554  { // to try:: all points at once instead
555  gsMatrix<T> uu = u.col(j);
556  //gsDebug<< "uu : \n"<< uu <<std::endl;
557  //gsDebug<< "coefs: \n"<< cc <<std::endl;
558 
559  m_bases[0]->eval_into(uu.row(0), cc, e0);
560 
561  for ( short_t i=1; i< d ; ++i )
562  {
563  sz /= m_bases[i]->size();
564  e0.resize( m_bases[i]->size(), n * sz );
565  //gsDebug<< "e0 : \n"<< e0 <<"\n";
566  m_bases[i]->eval(uu.row(i), e0, e1);
567  //gsDebug<< "e1 : \n"<< e1 <<"\n";
568  std::swap(e0, e1);
569  }
570  result->col(j) = e0;
571  }
572  //gsDebug<< "final: \n"<< *result <<std::endl;
573 #endif
574 
575  // Default version - linear combination of basis functions
576  // Basis_t:: eval_into(u,coefs,result);
577  result.resize( coefs.cols(), u.cols() ) ;
578  gsMatrix<T> B ;
579  gsMatrix<index_t> ind;
580 
581  this->eval_into(u, B); // col j = nonzero basis functions at column point u(..,j)
582  this->active_into(u,ind);// col j = indices of active functions at column point u(..,j)
583 
584  for ( index_t j=0; j< u.cols() ; j++ ) // for all points (columns of u)
585  {
586  result.col(j) = coefs.row( ind(0,j) ) * B(0,j);
587  for ( index_t i = 1; i < ind.rows(); ++i ) // for all non-zero basis functions
588  result.col(j) += coefs.row( ind(i,j) ) * B(i,j);
589  }
590 }
591 
592 
593 template<short_t d, class T>
595  gsMatrix<T>& result) const
596 {
597  std::vector<gsMatrix<T> > values[d];
598 
599  gsVector<unsigned, d> v, size;
600 
601  index_t nb = 1;
602  for (short_t i = 0; i < d; ++i)
603  {
604  // evaluate basis functions and their first derivatives
605  m_bases[i]->evalAllDers_into( u.row(i), 1, values[i]);
606 
607  // number of basis functions
608  const index_t num_i = values[i].front().rows();
609  nb *= num_i;
610  size[i] = num_i;
611  }
612 
613  result.resize( d*nb, u.cols() );
614 
615  v.setZero();
616  unsigned r = 0;
617  do {
618  for ( short_t k=0; k<d; ++k)
619  {
620  // derivative w.r.t. k-th variable
621  const index_t rownum = r*d + k;
622  result.row(rownum) = values[k][1].row( v(k) );
623  for ( short_t i=0; i<k; ++i)
624  result.row(rownum).array() *= values[i][0].row( v(i) ).array();
625  for ( short_t i=k+1; i<d; ++i)
626  result.row(rownum).array() *= values[i][0].row( v(i) ).array();
627  }
628  ++r ;
629  } while (nextLexicographic(v, size));
630 }
631 
632 
633 template<short_t d, class T>
635  std::vector<gsMatrix<T> >& result,
636  bool sameElement) const
637 {
638  GISMO_ASSERT(n>-2, "gsTensorBasis::evalAllDers() is implemented only for -2<n<=2: -1 means no value, 0 values only, ... " );
639  if (n==-1)
640  {
641  result.resize(0);
642  return;
643  }
644 
645  std::vector< gsMatrix<T> >values[d];
646  gsVector<unsigned, d> v, nb_cwise;
647  result.resize(n+1);
648 
649  unsigned nb = 1;
650  for (short_t i = 0; i < d; ++i)
651  {
652  // evaluate basis functions/derivatives
653  m_bases[i]->evalAllDers_into( u.row(i), n, values[i], sameElement);
654 
655  // number of basis functions
656  const index_t num_i = values[i].front().rows();
657  nb_cwise[i] = num_i;
658  nb *= num_i;
659  }
660 
661  // iterate over all tensor product basis functions
662  v.setZero();
663  gsMatrix<T> & vals = result[0];
664  vals.resize(nb, u.cols());
665  unsigned r = 0;
666  do // for all basis functions
667  {
668  // Multiply basis functions to get the value of basis function v
669  vals.row( r )= values[0].front().row( v[0] );
670  for ( short_t i=1; i!=d; ++i) // for all variables
671  vals.row(r).array() *= values[i].front().row( v[i] ).array();
672 
673  ++r;
674  } while (nextLexicographic(v, nb_cwise));
675 
676  // iterate again and write derivatives
677  if ( n>=1)
678  {
679  gsMatrix<T> & der = result[1];
680  der.resize(d*nb, u.cols());;
681  v.setZero();
682  r = 0;
683  do // for all basis functions
684  {
685  for ( short_t k=0; k<d; ++k) // for partial derivatives
686  {
687  // derivative w.r.t. k-th variable // TODO Check this!
688  der.row(r) = values[k][1].row( v(k) );
689  for ( short_t i=0; i<k; ++i)
690  der.row(r).array() *= values[i][0].row( v(i) ).array();
691  for ( short_t i=k+1; i<d; ++i)
692  der.row(r).array() *= values[i][0].row( v(i) ).array();
693  ++r;
694  }
695 
696  } while (nextLexicographic(v, nb_cwise));
697  }
698 
699  if (n>1)
700  {
701  deriv2_tp( values, nb_cwise, result[2] );
702 
704  for (int i = 3; i <=n; ++i) // for all orders of derivation
705  {
706  gsMatrix<T> & der = result[i];
707  der.resize( nb*numCompositions(i,d), u.cols());
708  v.setZero();
709 
710  r = 0;
711  do // for all basis functions
712  {
713  firstComposition(i, d, cc);
714  do // for all partial derivatives of order \a i
715  {
716  // cc[k]: order of derivation w.r.t. variable \a k
717  der.row(r) = values[0][cc[0]].row(v[0]);
718  for (short_t k = 1; k!=d; ++k) // for all variables
719  der.row(r).array() *= values[k][cc[k]].row(v[k]).array();
720  ++r;
721  } while (nextComposition(cc));
722  } while (nextLexicographic(v, nb_cwise));
723  }
724 
725  // n==2: bubble up // <- not needed due to call of deriv2_tp
726  }
727 
728 }
729 
730 template<short_t d, class T>
732  gsMatrix<T> & result ) const
733 {
734  std::vector< gsMatrix<T> >values[d];
735  gsVector<unsigned, d> v, nb_cwise;
736 
737  for (short_t i = 0; i < d; ++i)
738  {
739  m_bases[i]->evalAllDers_into( u.row(i), 2, values[i]);
740  const int num_i = values[i].front().rows();
741  nb_cwise[i] = num_i;
742  }
743 
744  deriv2_tp(values, nb_cwise, result);
745 }
746 
747 
748 
749 template<short_t d, class T>
750 void gsTensorBasis<d,T>::deriv2_tp(const std::vector< gsMatrix<T> > values[],
751  const gsVector<unsigned, d> & nb_cwise,
752  gsMatrix<T>& result)
753 {
754  const unsigned nb = nb_cwise.prod();
755  const unsigned stride = d + d*(d-1)/2;
756 
757  result.resize( stride*nb, values[0][0].cols() );
758 
760  v.setZero();
761  unsigned r = 0; // r is a local index of a basis function times the stride
762  do
763  {
764  unsigned m = d;
765  for ( short_t k=0; k<d; ++k)// First compute the pure second derivatives
766  {
767  index_t cur = r + k;
768  result.row(cur) = values[k][2].row( v.at(k) ) ;// pure 2nd derivate w.r.t. k-th var
769  for ( short_t i=0; i<k; ++i)
770  result.row(cur).array() *= values[i][0].row( v.at(i) ).array();
771  for ( short_t i=k+1; i<d; ++i)
772  result.row(cur).array() *= values[i][0].row( v.at(i) ).array();
773 
774  for ( short_t l=k+1; l<d; ++l) // Then all mixed derivatives follow in lex order
775  {
776  cur = r + m;
777  result.row(cur).noalias() =
778  values[k][1].row( v.at(k) ).cwiseProduct( values[l][1].row( v.at(l) ) );
779  for ( short_t i=0; i<k; ++i)
780  result.row(cur).array() *= values[i][0].row( v.at(i) ).array() ;
781  for ( short_t i=k+1; i<l; ++i)
782  result.row(cur).array() *= values[i][0].row( v.at(i) ).array();
783  for ( short_t i=l+1; i<d; ++i)
784  result.row(cur).array() *= values[i][0].row( v.at(i) ).array() ;
785  ++m;
786  }
787  }
788 
789  r+= stride;
790  } while (nextLexicographic(v, nb_cwise));
791 }
792 
793 
794 template<short_t d, class T>
795 void gsTensorBasis<d,T>::refineElements(std::vector<index_t> const & elements)
796 {
797  gsSortedVector<index_t> elIndices[d];
798  index_t tmp, mm;
799 
800  // Get coordinate wise element indices
801  for ( typename std::vector<index_t>::const_iterator
802  it = elements.begin(); it != elements.end(); ++it )
803  {
804  mm = *it;
805  for (short_t i = 0; i<d; ++i )
806  {
807  const index_t nEl_i = m_bases[i]->numElements();
808  tmp = mm % nEl_i;
809  mm = (mm - tmp) / nEl_i;
810  elIndices[i].push_sorted_unique(tmp);
811  }
812  }
813 
814  // Refine in each coordinate
815  // Element refinement propagates along knot-lines
816  for (short_t i = 0; i<d; ++i )
817  {
818  m_bases[i]->refineElements(elIndices[i]);
819  }
820 }
821 
822 
823 template<short_t d, class T>
824 void gsTensorBasis<d,T>::uniformRefine_withCoefs(gsMatrix<T>& coefs, int numKnots, int mul, int dir)
825 {
826  // Simple implementation: get the transfer matrix and apply it.
827  // Could be done more efficiently if needed.
829  if (dir==-1)
830  {
831  this->uniformRefine_withTransfer( transfer, numKnots, mul );
832  coefs = transfer * coefs;
833  }
834  else
835  {
836  GISMO_ASSERT( dir >= 0 && static_cast<unsigned>(dir) < d,
837  "Invalid basis component "<< dir <<" requested for uniform refinement." );
838 
840  this->size_cwise(sz);
841 
842 
843  this->m_bases[dir]->uniformRefine_withTransfer( transfer, numKnots, mul );
844 
845  const index_t n = coefs.cols();
846 
847  swapTensorDirection(0, dir, sz, coefs);
848  coefs.resize( sz[0], n * sz.template tail<static_cast<short_t>(d-1)>().prod() );
849 
850  coefs = transfer * coefs;
851 
852  sz[0] = coefs.rows();
853 
854  coefs.resize( sz.prod(), n );
855  swapTensorDirection(0, dir, sz, coefs);
856  }
857 }
858 
859 
860 template<short_t d, class T>
862 {
864 
865  // refine component bases and obtain their transfer matrices
866  for (short_t i = 0; i < d; ++i)
867  {
868  m_bases[i]->uniformRefine_withTransfer( B[i], numKnots, mul );
869  }
870 
871  tensorCombineTransferMatrices<d, T>( B, transfer );
872 }
873 
874 
875 template<short_t d, class T>
877 {
879 
880  // refine component bases and obtain their transfer matrices
881  for (short_t i = 0; i < d; ++i)
882  {
883  m_bases[i]->uniformCoarsen_withTransfer( B[i], numKnots );
884  }
885 
886  tensorCombineTransferMatrices<d, T>( B, transfer );
887 }
888 
889 template<short_t d, class T>
890 typename gsTensorBasis<d,T>::domainIter
892 {
893  return domainIter(new gsTensorDomainIterator<T, d>(*this));
894 }
895 
896 template<short_t d, class T>
897 typename gsTensorBasis<d,T>::domainIter
899 {
900  return ( s == boundary::none ?
901  domainIter(new gsTensorDomainIterator<T,d>(*this)) :
902  domainIter(new gsTensorDomainBoundaryIterator<T,d>(*this, s))
903  );
904 }
905 
906 template<short_t d, class T>
907 typename gsGeometry<T>::uPtr
909 {
910  std::vector<gsMatrix<T> > grid(d);
911 
912  for (short_t i = 0; i < d; ++i) // for all coordinate bases
913  m_bases[i]->anchors_into(grid[i]);
914 
915  return interpolateGrid(vals,grid);
916 }
917 
918 
919 template<short_t d, class T>
920 typename gsGeometry<T>::uPtr
922  std::vector<gsMatrix<T> >const& grid) const
923 {
924  GISMO_ASSERT (this->size() == vals.cols(),
925  "Expecting as many values as the number of basis functions." );
926 
927  const index_t n = vals.rows();
928  const int sz = this->size();
929 
930  // Note: algorithm relies on col-major matrices
932 
933  //Note: Sparse LU might fail for rank deficient Cmat
934  typename gsSparseSolver<T>::LU solver;
935  gsSparseMatrix<T> Cmat;
936 
937  // size: sz x n
938  q0 = vals.transpose();
939 
940  for (short_t i = 0; i < d; ++i) // for all coordinate bases
941  {
942  // Re-order right-hand sides
943  const index_t sz_i = m_bases[i]->size();
944  const index_t r_i = sz / sz_i;
945  q0.resize(sz_i, n * r_i);
946 
947  // Solve for i-th coordinate basis
948  Cmat = m_bases[i]->collocationMatrix(grid[i]);
949  solver.compute(Cmat);
950  #ifndef NDEBUG
951  if ( solver.info() != gsEigen::Success )
952  {
953  gsWarn<< "Failed LU decomposition for:\n";//<< Cmat.toDense() <<"\n";
954  gsWarn<< "Points:\n"<< grid[i] <<"\n";
955  gsWarn<< "Knots:\n"<< m_bases[i]->detail() <<"\n";
956  return typename gsGeometry<T>::uPtr();
957  }
958  #endif
959  // Transpose solution component-wise
960  q1.resize(r_i, n * sz_i);
961  for ( index_t k = 0; k!=n; ++k)
962  q1.middleCols(k*sz_i, sz_i) = solver.solve(q0.middleCols(k*r_i,r_i)).transpose();
963 
964  q1.swap( q0 ); // move solution as next right-hand side
965  }
966 
967  q0.resize(sz, n);
968  return this->makeGeometry( give(q0) );
969 }
970 
971 
972 template<short_t d, class T>
974  const gsBasis<T> & other,
975  gsMatrix<index_t> & bndThis,
976  gsMatrix<index_t> & bndOther,
977  index_t offset) const
978 {
979  if ( const Self_t * _other = dynamic_cast<const Self_t*>(&other) )
980  {
981  // Grab the indices to be matched
982  bndThis = this->boundaryOffset( bi.first() .side(), offset );
983  bndOther= _other->boundaryOffset( bi.second().side(), offset );
984  GISMO_ASSERT( bndThis.rows() == bndOther.rows(),
985  "Input error, sizes do not match: "
986  <<bndThis.rows()<<"!="<<bndOther.rows() );
987  if (bndThis.size() == 1) return;
988 
989  // Get interface data
990  const index_t s1 = bi.first() .direction();
991  const index_t s2 = bi.second().direction();
992  const gsVector<bool> & dirOr = bi.dirOrientation();
993  const gsVector<index_t> & bMap = bi.dirMap();
994 
995  // Compute the tensor structure of bndThis
996  gsVector<index_t> bSize(d-1);
997  index_t c = 0;
998  for (short_t k = 0; k<d; ++k )
999  {
1000  if ( k == s1 )
1001  continue;
1002  bSize[c] = this->component(k).size();
1003  c++;
1004  }
1005 
1006  // Apply flips to bndThis and bndOther so that they have the
1007  // same orientation
1008  gsVector<index_t> bPerm(d-1);
1009  c = 0;
1010  for (short_t k = 0; k<d; ++k )
1011  {
1012  if ( k == s1 ) // skip ?
1013  continue;
1014 
1015  if ( ! dirOr[k] ) // flip ?
1016  flipTensorVector(c, bSize, bndThis);
1017 
1018  bPerm[c] = ( bMap[k] < s2 ? bMap[k] : bMap[k]-1 );
1019  c++;
1020  }
1021 
1022  // Apply permutation to bndThis and bndOther so that they
1023  // finally match on both sides
1024  permuteTensorVector<index_t,-1>(bPerm, bSize, bndThis);
1025 
1026  return;
1027  }
1028 
1029  gsWarn<<"Cannot match with "<< other <<"\n";
1030 }
1031 
1032 template<short_t d, class T>
1034  const gsBasis<T> & other,
1035  gsMatrix<index_t> & bndThis,
1036  gsMatrix<index_t> & bndOther) const
1037 {
1038  this->matchWith(bi,other,bndThis,bndOther,0);
1039 }
1040 
1041 template<short_t d, class T>
1043 {
1044  T h = 0;
1045  for (short_t i = 0; i < d; ++i)
1046  {
1047  const T sz = m_bases[i]->getMinCellLength();
1048  if ( sz < h || h == 0 ) h = sz;
1049  }
1050  return h;
1051 }
1052 
1053 template<short_t d, class T>
1055 {
1056  T h = 0;
1057  for (short_t i = 0; i < d; ++i)
1058  {
1059  const T sz = m_bases[i]->getMaxCellLength();
1060  if ( sz > h ) h = sz;
1061  }
1062  return h;
1063 }
1064 
1065 template<short_t d, class T>
1067 {
1068  const gsVector<index_t, d> ti = tensorIndex(j);
1069  gsMatrix<T> el, res(d,2);
1070  for (short_t i = 0; i < d; ++i)
1071  {
1072  el = m_bases[i]->elementInSupportOf(ti[i]);
1073  res.row(i) = el;
1074  }
1075  return res;
1076 }
1077 
1078 //template<short_t d, class T>
1079 //gsDomain<T> * gsTensorBasis<d,T>::makeDomain() const
1080 //{
1081 // return new gsTensorDomain<T>();
1082 //}
1083 
1084 
1085 } // namespace gismo
Re-implements gsDomainIterator for iteration over all elements of a tensor product parameter domain...
Definition: gsTensorDomainIterator.h:35
Iterator over the elements of a tensor-structured grid.
void evalSingle_into(index_t i, const gsMatrix< T > &u, gsMatrix< T > &result) const
Evaluate the i-th basis function at points u into result.
Definition: gsTensorBasis.hpp:410
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
std::vector< T * > release(std::vector< unique_ptr< T > > &cont)
Takes a vector of smart pointers, releases them and returns the corresponding raw pointers...
Definition: gsMemory.h:228
Creates a mapped object or data pointer to a matrix without copying data.
Definition: gsLinearAlgebra.h:126
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
virtual void deriv2Single_into(index_t i, const gsMatrix< T > &u, gsMatrix< T > &result) const
Evaluate the (partial) derivatives of the i-th basis function at points u into result.
Definition: gsTensorBasis.hpp:454
void uniformCoarsen_withTransfer(gsSparseMatrix< T, RowMajor > &transfer, int numKnots=1)
Coarsen the basis uniformly and produce a sparse matrix which maps coarse coefficient vectors to refi...
Definition: gsTensorBasis.hpp:876
void firstComposition(typename Vec::Scalar sum, index_t dim, Vec &res)
Construct first composition of sum into dim integers.
Definition: gsCombinatorics.h:657
#define short_t
Definition: gsConfig.h:35
Provides structs and classes related to interfaces and boundaries.
void anchor_into(index_t i, gsMatrix< T > &result) const
Returns the anchors (graville absissae) that represent the members of the basis.
Definition: gsTensorBasis.hpp:148
bool parameter() const
Returns the parameter value (false=0=start, true=1=end) that corresponds to this side.
Definition: gsBoundary.h:128
virtual void connectivity(const gsMatrix< T > &nodes, gsMesh< T > &mesh) const
Definition: gsTensorBasis.hpp:163
void swapTensorDirection(int k1, int k2, gsVector< index_t, d > &sz, gsMatrix< T > &coefs)
Definition: gsTensorTools.h:129
Utility functions related to tensor-structured objects.
S give(S &x)
Definition: gsMemory.h:266
Provides declaration of Geometry abstract interface.
void flipTensorVector(const int dir, const gsVector< index_t, d > &sz, gsMatrix< T > &coefs)
Flips tensor directions in place.
Definition: gsTensorTools.h:201
#define index_t
Definition: gsConfig.h:32
This class is derived from std::vector, and adds sort tracking.
Definition: gsSortedVector.h:109
void refineElements(std::vector< index_t > const &elements)
Refine elements defined by their tensor-index.
Definition: gsTensorBasis.hpp:795
#define GISMO_ASSERT(cond, message)
Definition: gsDebug.h:89
bool nextComposition(Vec &v)
Returns (inplace) the next composition in lexicographic order.
Definition: gsCombinatorics.h:667
gsMatrix< T > elementInSupportOf(index_t j) const
Returns (the coordinates of) an element in the support of basis function j.
Definition: gsTensorBasis.hpp:1066
virtual void eval_into(const gsMatrix< T > &u, gsMatrix< T > &result) const
Evaluates nonzero basis functions at point u into result.
Definition: gsTensorBasis.hpp:502
Class Representing a triangle mesh with 3D vertices.
Definition: gsMesh.h:31
virtual void evalAllDers_into(const gsMatrix< T > &u, int n, std::vector< gsMatrix< T > > &result, bool sameElement=false) const
Evaluate the nonzero functions and their derivatives up to order n at points u into result...
Definition: gsTensorBasis.hpp:634
A vector with arbitrary coefficient type and fixed or dynamic size.
Definition: gsVector.h:35
#define gsWarn
Definition: gsDebug.h:50
virtual T getMinCellLength() const
Get the minimum mesh size, as expected for inverse inequalities.
Definition: gsTensorBasis.hpp:1042
Re-implements gsDomainIterator for iteration over all elements of the boundary of a tensor product pa...
Definition: gsTensorDomainBoundaryIterator.h:37
virtual void derivSingle_into(index_t i, const gsMatrix< T > &u, gsMatrix< T > &result) const
Evaluates the (partial) derivatives of the i-th basis function at points u into result.
Definition: gsTensorBasis.hpp:429
T at(index_t i) const
Returns the i-th element of the vector.
Definition: gsVector.h:177
bool isActive(const index_t i, const gsVector< T > &u) const
Returns true if there the point u with non-zero value or derivatives when evaluated at the basis func...
Definition: gsTensorBasis.hpp:239
Abstract base class for tensor product bases.
Definition: gsTensorBasis.h:33
Struct which represents a certain side of a box.
Definition: gsBoundary.h:84
gsMatrix< T > support() const
Returns (a bounding box for) the domain of the whole basis.
Definition: gsTensorBasis.hpp:390
void getComponentsForSide(boxSide const &s, std::vector< Basis_t * > &rr) const
Returns the components for a basis on the face s.
Definition: gsTensorBasis.hpp:377
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: gsTensorBasis.hpp:204
void anchors_into(gsMatrix< T > &result) const
Returns the anchors (graville absissae) that represent the members of the basis.
Definition: gsTensorBasis.hpp:124
Provides declaration of the Mesh class.
uPtr clone()
Clone methode. Produceds a deep copy inside a uPtr.
memory::unique_ptr< gsGeometry > uPtr
Unique pointer for gsGeometry.
Definition: gsGeometry.h:100
gsGeometry< T >::uPtr interpolateGrid(gsMatrix< T > const &vals, std::vector< gsMatrix< T > >const &grid) const
Definition: gsTensorBasis.hpp:921
virtual void deriv_into(const gsMatrix< T > &u, gsMatrix< T > &result) const
Evaluates the first partial derivatives of the nonzero basis function.
Definition: gsTensorBasis.hpp:594
gsMatrix< index_t > coefSlice(short_t dir, index_t k) const
Returns all the basis functions with tensor-numbering.
Definition: gsTensorBasis.hpp:250
gsMatrix< index_t > boundaryOffset(boxSide const &s, index_t offset) const
Definition: gsTensorBasis.hpp:304
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
virtual void deriv2_into(const gsMatrix< T > &u, gsMatrix< T > &result) const
Evaluate the second derivatives of all active basis function at points u.
Definition: gsTensorBasis.hpp:731
gsMatrix< index_t > allBoundary() const
Definition: gsTensorBasis.hpp:283
#define GISMO_ERROR(message)
Definition: gsDebug.h:118
void permuteTensorVector(const gsVector< index_t, d > &perm, gsVector< index_t, d > &sz, gsMatrix< T > &coefs)
Definition: gsTensorTools.h:169
Iterator over the boundary elements of a tensor-structured grid.
patchSide & second()
second, returns the second patchSide of this interface
Definition: gsBoundary.h:782
gsBasis< T >::domainIter makeDomainIterator() const
Create a domain iterator for the computational mesh of this basis, that points to the first element o...
Definition: gsTensorBasis.hpp:891
void uniformRefine_withCoefs(gsMatrix< T > &coefs, int numKnots=1, int mul=1, int dir=-1)
Definition: gsTensorBasis.hpp:824
Struct which represents an interface between two patches.
Definition: gsBoundary.h:649
void uniformRefine_withTransfer(gsSparseMatrix< T, RowMajor > &transfer, int numKnots=1, int mul=1)
Definition: gsTensorBasis.hpp:861
unsigned numCompositions(int sum, short_t dim)
Number of compositions of sum into dim integers.
Definition: gsCombinatorics.h:691
virtual T getMaxCellLength() const
Get the maximum mesh size, as expected for approximation error estimates.
Definition: gsTensorBasis.hpp:1054
Struct which represents a certain corner of a hyper-cube.
Definition: gsBoundary.h:291
virtual gsGeometry< T >::uPtr interpolateAtAnchors(gsMatrix< T > const &vals) const
Applies interpolation of values pts using the anchors as parameter points. May be reimplemented in de...
Definition: gsTensorBasis.hpp:908
short_t direction() const
Returns the parametric direction orthogonal to this side.
Definition: gsBoundary.h:113
A basis represents a family of scalar basis functions defined over a common parameter domain...
Definition: gsBasis.h:78
patchSide & first()
first, returns the first patchSide of this interface
Definition: gsBoundary.h:776