G+Smo  25.01.0
Geometry + Simulation Modules
 
Loading...
Searching...
No Matches
gsTensorBasis.hpp
Go to the documentation of this file.
1
14#pragma once
15
19
20#include <gsCore/gsBoundary.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
30namespace gismo
31{
32
33template<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
47template<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");
64
65template<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
85/*
86template<short_t d, class T>
87gsTensorBasis<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
98template<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
107template<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
123template<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
147template<short_t d, class T>
149{
150 gsVector<index_t, d> ti = tensorIndex(i);
151
152 gsMatrix<T> gr;
153 result.resize(d, 1);
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
162template<short_t d, class T>
164 gsMesh<T> & mesh) const
166 const index_t sz = size();
167 GISMO_ASSERT( nodes.rows() == sz, "Invalid input.");
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
203template<short_t d, class T>
205{
206 //gsWarn<<"genericActive "<< *this;
208 gsMatrix<index_t> act[d];
209 gsVector<index_t, d> v, size;
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)
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;
234 ++r ;
235 } while (nextLexicographic(v, size));
236}
238template<short_t d, class T>
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
249template<short_t d, class T>
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" );
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;
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
282template<short_t d, class T>
284{
286 std::set<index_t> bdofs;
287
288 for (short_t k = 0; k != d; ++k)
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) );
298
299 return makeMatrix<index_t>(bdofs.begin(), static_cast<index_t>(bdofs.size()), 1 );
301
302
303template<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
313template<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/*
334template<short_t d, class T>
335void 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/*
356template <short_t d, class BB, class B>
357struct MakeBoundaryBasis
358{
359 static BB* make (const std::vector< B * >& bases)
360 {
361 return new BB( bases );
362 }
363};
364
365template <class BB, class B>
366struct MakeBoundaryBasis<2, BB, B>
367{
368 static BB* make (const std::vector< B * >& bases)
369 {
370 return bases[0];
371 }
372};
373*/
374
375template<short_t d, class T>
376void
377gsTensorBasis<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
389template<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
398template<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
409template<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
428template<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
453template<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() );
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
501template<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
538template<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);
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 ;
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
593template<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
633template<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
730template<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
749template<short_t d, class T>
750void 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
794template<short_t d, class T>
795void 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
823template<short_t d, class T>
824void 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
860template<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
875template<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
889template<short_t d, class T>
890typename gsTensorBasis<d,T>::domainIter
892{
893 return domainIter(new gsTensorDomainIterator<T, d>(*this));
894}
895
896template<short_t d, class T>
897typename 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
906template<short_t d, class T>
907typename 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
919template<short_t d, class T>
920typename 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;
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
972template<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
1032template<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
1041template<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
1053template<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
1065template<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
Struct which represents a certain side of a box.
Definition gsBoundary.h:85
bool parameter() const
Returns the parameter value (false=0=start, true=1=end) that corresponds to this side.
Definition gsBoundary.h:128
short_t direction() const
Returns the parametric direction orthogonal to this side.
Definition gsBoundary.h:113
Creates a mapped object or data pointer to a matrix without copying data.
Definition gsAsMatrix.h:32
A basis represents a family of scalar basis functions defined over a common parameter domain.
Definition gsBasis.h:79
uPtr clone()
Clone methode. Produceds a deep copy inside a uPtr.
memory::unique_ptr< gsGeometry > uPtr
Unique pointer for gsGeometry.
Definition gsGeometry.h:100
A matrix with arbitrary coefficient type and fixed or dynamic size.
Definition gsMatrix.h:41
Class Representing a triangle mesh with 3D vertices.
Definition gsMesh.h:32
This class is derived from std::vector, and adds sort tracking.
Definition gsSortedVector.h:110
Sparse matrix class, based on gsEigen::SparseMatrix.
Definition gsSparseMatrix.h:139
virtual std::string detail() const
Prints the object as a string with extended details.
Definition gsSparseSolver.h:114
Abstract base class for tensor product bases.
Definition gsTensorBasis.h:34
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
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 refineElements(std::vector< index_t > const &elements)
Refine elements defined by their tensor-index.
Definition gsTensorBasis.hpp:795
void anchors_into(gsMatrix< T > &result) const
Returns the anchors (graville absissae) that represent the members of the basis.
Definition gsTensorBasis.hpp:124
virtual T getMaxCellLength() const
Get the maximum mesh size, as expected for approximation error estimates.
Definition gsTensorBasis.hpp:1054
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
gsMatrix< index_t > coefSlice(short_t dir, index_t k) const
Returns all the basis functions with tensor-numbering.
Definition gsTensorBasis.hpp:250
gsGeometry< T >::uPtr interpolateGrid(gsMatrix< T > const &vals, std::vector< gsMatrix< T > >const &grid) const
Definition gsTensorBasis.hpp:921
void uniformRefine_withTransfer(gsSparseMatrix< T, RowMajor > &transfer, int numKnots=1, int mul=1)
Definition gsTensorBasis.hpp:861
gsMatrix< index_t > allBoundary() const
Definition gsTensorBasis.hpp:283
virtual 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
virtual void connectivity(const gsMatrix< T > &nodes, gsMesh< T > &mesh) const
Definition gsTensorBasis.hpp:163
void uniformRefine_withCoefs(gsMatrix< T > &coefs, int numKnots=1, int mul=1, short_t const dir=-1)
Definition gsTensorBasis.hpp:824
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
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
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
gsMatrix< index_t > boundaryOffset(boxSide const &s, index_t offset) const
Definition gsTensorBasis.hpp:304
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
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
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 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
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
virtual T getMinCellLength() const
Get the minimum mesh size, as expected for inverse inequalities.
Definition gsTensorBasis.hpp:1042
gsMatrix< T > support() const
Returns (a bounding box for) the domain of the whole basis.
Definition gsTensorBasis.hpp:390
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 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
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
Re-implements gsDomainIterator for iteration over all elements of the boundary of a tensor product pa...
Definition gsTensorDomainBoundaryIterator.h:38
Re-implements gsDomainIterator for iteration over all elements of a tensor product parameter domain....
Definition gsTensorDomainIterator.h:36
A vector with arbitrary coefficient type and fixed or dynamic size.
Definition gsVector.h:37
T at(index_t i) const
Returns the i-th element of the vector.
Definition gsVector.h:177
void swapTensorDirection(int k1, int k2, gsVector< index_t, d > &sz, gsMatrix< T > &coefs)
Definition gsTensorTools.h:129
void flipTensorVector(const int dir, const gsVector< index_t, d > &sz, gsMatrix< T > &coefs)
Flips tensor directions in place.
Definition gsTensorTools.h:201
void permuteTensorVector(const gsVector< index_t, d > &perm, gsVector< index_t, d > &sz, gsMatrix< T > &coefs)
Definition gsTensorTools.h:169
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
bool nextComposition(Vec &v)
Returns (inplace) the next composition in lexicographic order.
Definition gsCombinatorics.h:667
void firstComposition(typename Vec::Scalar sum, index_t dim, Vec &res)
Construct first composition of sum into dim integers.
Definition gsCombinatorics.h:657
unsigned numCompositions(int sum, short_t dim)
Number of compositions of sum into dim integers.
Definition gsCombinatorics.h:691
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
Provides structs and classes related to interfaces and boundaries.
#define short_t
Definition gsConfig.h:35
#define index_t
Definition gsConfig.h:32
#define GISMO_ERROR(message)
Definition gsDebug.h:118
#define gsWarn
Definition gsDebug.h:50
#define GISMO_ASSERT(cond, message)
Definition gsDebug.h:89
Provides declaration of Geometry abstract interface.
Provides declaration of the Mesh class.
Iterator over the boundary elements of a tensor-structured grid.
Iterator over the elements of a tensor-structured grid.
Utility functions related to tensor-structured objects.
The G+Smo namespace, containing all definitions for the library.
S give(S &x)
Definition gsMemory.h:266
Struct which represents an interface between two patches.
Definition gsBoundary.h:650
patchSide & first()
first, returns the first patchSide of this interface
Definition gsBoundary.h:776
patchSide & second()
second, returns the second patchSide of this interface
Definition gsBoundary.h:782
Struct which represents a certain corner of a hyper-cube.
Definition gsBoundary.h:292
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