G+Smo  24.08.0
Geometry + Simulation Modules
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
gsExpressions.h
Go to the documentation of this file.
1 
14 #pragma once
15 
16 #include <gsCore/gsFuncData.h>
19 
20 
21 namespace gismo
22 {
23 
24 // Adaptor to compute Hessian
25 template <typename Derived>
26 void secDerToHessian(const gsEigen::DenseBase<Derived> & secDers,
27  const index_t dim,
28  gsMatrix<typename Derived::Scalar> & hessian)
29 {
30  const index_t sz = dim*(dim+1)/2;
31  const gsAsConstMatrix<typename Derived::Scalar>
32  ders(secDers.derived().data(), sz, secDers.size() / sz );
33  hessian.resize(dim*dim, ders.cols() );
34 
35  switch ( dim )
36  {
37  case 1:
38  hessian = secDers.transpose(); //==ders
39  break;
40  case 2:
41  hessian.row(0)=ders.row(0);//0,0
42  hessian.row(1)=//1,0
43  hessian.row(2)=ders.row(2);//0,1
44  hessian.row(3)=ders.row(1);//1,1
45  break;
46  case 3:
47  hessian.row(0)=ders.row(0);//0,0
48  hessian.row(3)=//0,1
49  hessian.row(1)=ders.row(3);//1,0
50  hessian.row(6)=//0,2
51  hessian.row(2)=ders.row(4);//2,0
52  hessian.row(4)=ders.row(1);//1,1
53  hessian.row(7)=//1,2
54  hessian.row(5)=ders.row(5);//2,1
55  hessian.row(8)=ders.row(2);//2,2
56  break;
57  default:
58  break;
59  }
60 }
61 
63 template<class T> struct gsFeSpaceData
64 {
65  gsFeSpaceData(const gsFunctionSet<T> & _fs, index_t _dim, index_t _id):
66  fs(&_fs), dim(give(_dim)), id(give(_id)) { }
67 
68  const gsFunctionSet<T> * fs;
69  index_t dim, id;
70  gsDofMapper mapper;
71  gsMatrix<T> fixedDofs;
72  index_t cont; //int. coupling
73 
74  bool valid() const
75  {
76  GISMO_ASSERT(nullptr!=fs, "Invalid pointer.");
77  return static_cast<size_t>(fs->size()*dim)==mapper.mapSize();
78  }
79 
80  void init()
81  {
82  GISMO_ASSERT(nullptr!=fs, "Invalid pointer.");
83  if (const gsMultiBasis<T> * mb =
84  dynamic_cast<const gsMultiBasis<T>*>(fs) )
85  mapper = gsDofMapper(*mb, dim );
86  else if (const gsBasis<T> * b =
87  dynamic_cast<const gsBasis<T>*>(fs) )
88  mapper = gsDofMapper(*b, dim );
89  mapper.finalize();
90  fixedDofs.clear();
91  cont = -1;
92  }
93 };
94 
95 // Forward declaration in gismo namespace
96 template<class T> class gsExprHelper;
97 
105 namespace expr
106 {
107 
108 template <class E> struct is_arithmetic{enum{value=0};};
109 template <> struct is_arithmetic<real_t>{enum{value=1};};
110 template <typename E, bool = is_arithmetic<E>::value >
111 class _expr {using E::GISMO_ERROR_expr;};
112 
113 template<class T> class gsFeSpace;
114 template<class T> class gsFeVariable;
115 template<class T> class gsFeSolution;
116 template<class E> class symm_expr;
117 template<class E> class symmetrize_expr;
118 template<class E> class normalized_expr;
119 template<class E> class trace_expr;
120 template<class E> class integral_expr;
121 template<class E> class adjugate_expr;
122 template<class E> class norm_expr;
123 template<class E> class sqNorm_expr;
124 template<class E> class det_expr;
125 template<class E> class value_expr;
126 template<class E> class asdiag_expr;
127 template<class E> class max_expr;
128 template<class E> class rowsum_expr;
129 template<class E> class colsum_expr;
130 template<class E> class col_expr;
131 template<class T> class meas_expr;
132 template<class E> class inv_expr;
133 template<class E, bool cw = false> class tr_expr;
134 template<class E> class cb_expr;
135 template<class E> class abs_expr;
136 template<class E> class pow_expr;
137 template<class E> class sign_expr;
138 template<class E> class ppart_expr;
139 template<class E> class exp_expr;
140 template<class E> class ppartval_expr;
141 template<class T> class cdiam_expr;
142 template<class E> class temp_expr;
143 template<class E1, class E2, bool = E1::ColBlocks && !E1::ScalarValued && !E2::ScalarValued> class mult_expr
144 {using E1::GISMO_ERROR_mult_expr_has_invalid_template_arguments;};
145 
146 // Call as pow(a,b)
147 template<class E> pow_expr<E>
148 pow(_expr<E> const& u, real_t q) { return pow_expr<E>(u,q); }
149 
150 /*
151  Traits class for expressions
152 */
153 template <typename E> struct expr_traits
154 {
155 public:
156 // typedef typename E::Scalar Scalar;
157  typedef real_t Scalar;//todo
158  typedef const E Nested_t;
159 };
160 
161 # define Temporary_t typename util::conditional<ScalarValued,Scalar, \
162  typename gsMatrix<Scalar>::Base >::type
163 #if __cplusplus >= 201402L || _MSVC_LANG >= 201402L // c++14
164 # define MatExprType auto
165 # define AutoReturn_t auto
166 //note: in c++11 auto-return requires -> decltype(.)
167 #else // 199711L, 201103L
168 # define MatExprType typename gsMatrix<real_t>::constRef
169 # define AutoReturn_t typename util::conditional<ScalarValued,real_t,MatExprType>::type
170 #endif
171 
175 template <typename E>
176 class _expr<E, false>
177 {
178 protected://private:
179  _expr(){}
180  _expr(const _expr&) { }
181 public:
182  // Defined in derived classes: enum { Space, ScalarValued, ColBlocks }
183  // - ScalarValued: 0 is a scalar (must have Space=0),1 one denotes gsMatrix
184  // - ColBlocks: the expression stacks matrices per basis function
185  // - Space: 0: not a trial nor a test object (eg. normal vector, force function)
186  // 1: a test object (essentially a right-hand side vector expression)
187  // 2: a trial object
188  // 3: a trial+trial object (essentially a matrix expression)
189 
190  typedef typename expr_traits<E>::Nested_t Nested_t;
191  typedef typename expr_traits<E>::Scalar Scalar;
192 
194  void print(std::ostream &os) const
195  {
196  //gsInfo<<"\n Space="<<E::Space<<", ScV="<<E::ScalarValued<<", ColBlocks="<<E::ColBlocks<<"\n";
197  static_cast<E const&>(*this).print(os);
198  os<<"\n";
199  /*
200  std::string tmp(__PRETTY_FUNCTION__);
201  tmp.erase(0,74);
202  tmp.erase(tmp.size()-42,42);
203  size_t pos = 0;
204  while((pos=tmp.find(", false",0))!=std::string::npos) tmp.erase(pos,7);
205  while((pos=tmp.find(", true",0))!=std::string::npos) tmp.erase(pos,6);
206  while((pos=tmp.find("gismo::expr::",0))!=std::string::npos) tmp.erase(pos,13);
207  while((pos=tmp.find("_expr",0))!=std::string::npos) tmp.erase(pos,5);
208  while((pos=tmp.find("<double>",0))!=std::string::npos) tmp.erase(pos,8);
209  // while((pos=tmp.find("<long double>",0))!=std::string::npos) tmp.erase(pos,13);
210  // while((pos=tmp.find("<float>",0))!=std::string::npos) tmp.erase(pos,7);
211  tmp.erase(std::remove_if(tmp.begin(),tmp.end(),::isspace),tmp.end());
212  os<<tmp<<"\n";
213  */
214  }
215 
216  std::ostream & printDetail(std::ostream &os) const
217  {
218  os << (isVectorTr() ? "VectorTr " :
219  (isVector() ? "Vector " :
220  (isMatrix() ? "Matrix " :
221  "Scalar ") ) )
222  <<"expression of size "<< rows() // bug: this might be invalid if unparsed
223  << " x "<<cols()<<"\n";
224  print(os);
225  return os;
226  }
227 
229  MatExprType eval(const index_t k) const
230  { return static_cast<E const&>(*this).eval(k); }
231 
233  tr_expr<E> tr() const
234  { return tr_expr<E,false>(static_cast<E const&>(*this)); }
235 
237  tr_expr<E,true> cwisetr() const
238  { return tr_expr<E,true>(static_cast<E const&>(*this)); }
239 
241  cb_expr<E> cb() const
242  { return cb_expr<E>(static_cast<E const&>(*this)); }
243 
245  sign_expr<E> sgn(Scalar tolerance=0) const
246  { return sign_expr<E>(static_cast<E const&>(*this), tolerance); }
247 
249  exp_expr<E> exp() const
250  { return exp_expr<E>(static_cast<E const&>(*this)); }
251 
254  { return ppart_expr<E>(static_cast<E const&>(*this)); }
255  ppartval_expr<E> ppartval() const
256  { return ppartval_expr<E>(static_cast<E const&>(*this)); }
257 
259  mult_expr<real_t, ppart_expr<mult_expr<double,E,false>> , false>
260  npart() const { return -1* ( -(*this) ).ppart() ; }
261 
263  temp_expr<E> temp() const
264  { return temp_expr<E>(static_cast<E const&>(*this)); }
265 
267  inv_expr<E> const inv() const
268  { return inv_expr<E>(static_cast<E const&>(*this)); }
269 
271  trace_expr<E> trace() const
272  { return trace_expr<E>(static_cast<E const&>(*this)); }
273 
275  adjugate_expr<E> adj() const
276  { return adjugate_expr<E>(static_cast<E const&>(*this)); }
277 
279  norm_expr<E> norm() const
280  { return norm_expr<E>(static_cast<E const&>(*this)); }
281 
283  normalized_expr<E> normalized() const
284  { return normalized_expr<E>(static_cast<E const&>(*this)); }
285 
287  det_expr<E> det() const
288  { return det_expr<E>(static_cast<E const&>(*this)); }
289 
291  sqNorm_expr<E> sqNorm() const
292  { return sqNorm_expr<E>(static_cast<E const&>(*this)); }
293 
295  mult_expr<E,E,0> (sqr)() const { return (*this)*(*this); }
296 
297  symm_expr<E> symm() const
298  { return symm_expr<E>(static_cast<E const&>(*this)); }
299 
300  symmetrize_expr<E> symmetrize() const
301  { return symmetrize_expr<E>(static_cast<E const&>(*this)); }
302 
305  value_expr<E> val() const
306  { return value_expr<E>(static_cast<E const&>(*this)); }
307 
310  { return asdiag_expr<E>(static_cast<E const&>(*this)); }
311 
313  max_expr<E> max() const
314  { return max_expr<E>(static_cast<E const&>(*this)); }
315 
317  rowsum_expr<E> rowSum() const
318  { return rowsum_expr<E>(static_cast<E const&>(*this)); }
319 
321  colsum_expr<E> colSum() const
322  { return colsum_expr<E>(static_cast<E const&>(*this)); }
323 
324  col_expr<E> operator[](const index_t i) const
325  { return col_expr<E>(static_cast<E const&>(*this),i); }
326 
328  index_t rows() const
329  { return static_cast<E const&>(*this).rows(); }
330 
332  index_t cols() const
333  { return static_cast<E const&>(*this).cols(); }
334 
335  index_t cardinality() const
336  { return static_cast<E const&>(*this).cardinality_impl(); }
337 
338  static index_t cardinality_impl() { return 1; }
339 
342  bool isScalar() const { return rows()*cols()<=1; }
343 
344  static bool isVector () { return 1==E::Space; }
345  static bool isVectorTr() { return 2==E::Space; }
346  static bool isMatrix () { return 3==E::Space; }
347 
350  void parse(gsExprHelper<Scalar> & evList) const
351  { static_cast<E const&>(*this).parse(evList); }
352 
353  template<class op> void apply(op & _op) const
354  { static_cast<E const&>(*this).apply(_op); }
355 
358  const gsFeSpace<Scalar> & rowVar() const
359  {
360  // assert ValueType!=0
361  return static_cast<E const&>(*this).rowVar();
362  }
363 
366  const gsFeSpace<Scalar> & colVar() const
367  {
368  // assert ValueType==2
369  return static_cast<E const&>(*this).colVar();
370  }
371 
372  // Overload conversions, eg. converts _expr<mult_expr> to
373  // mult_expr.
374  operator E&() { return static_cast< E&>(*this); }
375  operator E const&() const { return static_cast<const E&>(*this); }
376 
377  E const & derived() const { return static_cast<const E&>(*this); }
378 };
379 
381 template <typename E>
382 std::ostream &operator<<(std::ostream &os, const _expr<E> & b)
383 {b.print(os); return os; }
384 
385 }
386 }
387 
389 
390 namespace gismo
391 {
392 namespace expr
393 {
394 
395 /*
396  Null expression is a compatibility expression invalid at runtime
397 */
398 template<class T>
399 class gsNullExpr : public _expr<gsNullExpr<T> >
400 {
401 public:
402 
403  operator const gsFeSpace<T> & () const
404  {
405  static gsFeSpace<T> vv(-1);
406  return vv;
407  }
408 
409  typedef T Scalar;
410  gsMatrix<T> eval(const index_t) const { GISMO_ERROR("gsNullExpr"); }
411  inline index_t rows() const { GISMO_ERROR("gsNullExpr"); }
412  inline index_t cols() const { GISMO_ERROR("gsNullExpr"); }
413  void parse(gsExprHelper<T> &) const { }
414 
415  const gsFeSpace<T> & rowVar() const { GISMO_ERROR("gsNullExpr"); }
416  const gsFeSpace<T> & colVar() const { GISMO_ERROR("gsNullExpr"); }
417 
418  void print(std::ostream &os) const { os << "NullExpr"; }
419 
420  static const gsNullExpr & get()
421  {
422  static gsNullExpr o;
423  return o;
424  }
425 //private:
426  gsNullExpr() {}
427 };
428 
429 
430 template<class E>
431 class symbol_expr : public _expr<E>
432 {
433 public:
434  typedef typename expr_traits<E>::Scalar Scalar;
435 
436  friend class gismo::gsExprHelper<Scalar>;
437 protected:
438  const gsFunctionSet<Scalar> * m_fs;
439  const gsFuncData<Scalar> * m_fd;
440  index_t m_d;
441  bool m_isAcross;
442 
443 public:
444 
446  bool isAcross() const { return m_isAcross; }
447 
448  E right() const
449  {
450  E ac(this->derived());
451  ac.m_fs = m_fs;//needed?
452  ac.m_isAcross = true;
453  return ac;
454  }
455 
456  E left() const
457  {
458  E ac(this->derived());
459  ac.m_fs = m_fs;
460  ac.m_isAcross = false;
461  return ac;
462  }
463 
465  const gsFunctionSet<Scalar> & source() const {return *m_fs;}
466 
468  const gsFuncData<Scalar> & data() const
469  {
470  GISMO_ASSERT(NULL!=m_fd, "FuncData member not registered "<<this<<"/"<< m_fs);
471  return *m_fd;
472  }
473 
474  // used by FeSpace, FeVariable, ..
475  void parse(gsExprHelper<Scalar> & evList) const
476  {
477  evList.add(*this);
478  this->m_fd->flags |= NEED_VALUE | NEED_ACTIVE;
479  }
480 
481  index_t cardinality_impl() const
482  {
483  GISMO_ASSERT(this->data().actives.rows()!=0,"Cardinality depends on the NEED_ACTIVE flag");
484  return m_d * this->data().actives.rows();
485  }
486 
487  //public for now due to Bc
488  void setSource(const gsFunctionSet<Scalar> & fs) { m_fs = &fs;}
489 
490 private:
491  void setData(const gsFuncData<Scalar> & val) { m_fd = &val;}
492  void setDim(index_t _d) { m_d = _d; }
493  void clear() { m_fs = NULL; }
494 
495 protected:
496  explicit symbol_expr(index_t _d)
497  : m_fs(NULL), m_fd(NULL), m_d(_d), m_isAcross(false) { }
498 
499 public:
500  bool isValid() const { return NULL!=m_fd && NULL!=m_fs; }
501 
502  // component
503  // expr comp(const index_t i) const { return comp_expr<Scalar>(*this,i); }
504  // eval(k).col(i)
505 
506  // The evaluation return rows for (basis) functions and columns
507  // for (coordinate) components
508  MatExprType eval(const index_t k) const
509  { return m_fd->values[0].col(k).blockDiag(m_d); }
510  //{ return m_fd->values[0].col(k); }
511 
512  const gsFeSpace<Scalar> & rowVar() const {return gsNullExpr<Scalar>::get();}
513  const gsFeSpace<Scalar> & colVar() const {return gsNullExpr<Scalar>::get();}
514 
515  index_t rows() const
516  {
517  GISMO_ASSERT(NULL!=m_fs, "FeVariable: Function source not registered");
518  return m_fs->targetDim();
519  }
520 
521  index_t cols() const { return m_d; }
522 
523  void print(std::ostream &os) const { os << "u"; }
524 
525 public:
526 
528  index_t dim() const { return m_d;}
529 
532  index_t targetDim() const { return m_fs->targetDim(); }
533 
535  index_t parDim() const { return m_fs->domainDim(); }
536 
537  index_t cSize() const
538  {
539  GISMO_ASSERT(0!=m_fd->values[0].size(),"Probable error.");
540  return m_fd->values[0].rows();
541  } // coordinate size
542 };
543 
544 /*
545  Column expression
546 */
547 template<class E>
548 class col_expr : public _expr<col_expr<E> >
549 {
550  typename E::Nested_t _c;
551  const index_t _i;
552 public:
553  typedef typename E::Scalar Scalar;
554  typedef const col_expr<E> Nested_t;
555 
556  enum { Space = E::Space, ScalarValued = 0, ColBlocks = 0 };
557 
558  col_expr(const E & c, const index_t i) : _c(c), _i(i) { }
559 
560 public:
561 
562  //ConstColXpr
563  inline MatExprType eval(const index_t k) const { return _c.eval(k).col(_i); }
564 
565  index_t rows() const { return _c.rows(); }
566  index_t cols() const { return 1; }
567  void parse(gsExprHelper<Scalar> & evList) const { _c.parse(evList); }
568 
569  const gsFeSpace<Scalar> & rowVar() const { return _c.rowVar(); }
570  const gsFeSpace<Scalar> & colVar() const { return _c.colVar(); }
571 
572  void print(std::ostream &os) const { os<<_c<<"["<<_i<<"]"; }
573 };
574 
575 /*
576  Expression for a constant value
577 */
578 template<class T>
579 class _expr<T, true> : public _expr<_expr<T> >
580 {
581  const T _c;
582 public:
583  typedef T Scalar;
584  typedef const _expr<T> Nested_t;
585 
586  explicit _expr(Scalar c) : _c(give(c)) { }
587 
588 public:
589  enum {Space = 0, ScalarValued = 1, ColBlocks= 0};
590 
591  inline Scalar eval(const index_t ) const { return _c; }
592 
593  inline _expr val() const { return *this; }
594  index_t rows() const { return 0; }
595  index_t cols() const { return 0; }
596  void parse(gsExprHelper<Scalar> &) const { }
597 
598  const gsFeSpace<T> & rowVar() const { return gsNullExpr<T>::get(); }
599  const gsFeSpace<T> & colVar() const { return gsNullExpr<T>::get(); }
600 
601  void print(std::ostream &os) const { os<<_c; }
602 };
603 
604 /*
605  Geometry map expression
606 */
607 template<class T>
608 class gsGeometryMap : public _expr<gsGeometryMap<T> >
609 {
610  const gsFunctionSet<T> * m_fs;
611  const gsMapData<T> * m_fd;
612  //index_t d, n;
613 
614  bool m_isAcross;
615 
616 public:
617  enum {Space = 0, ScalarValued= 0, ColBlocks= 0};
618 
619  bool isAcross() const { return m_isAcross; }
620 
621  gsGeometryMap right() const
622  {
623  gsGeometryMap ac;
624  ac.m_fs = m_fs;
625  ac.m_isAcross = true;
626  return ac;
627  }
628 
629  gsGeometryMap left() const
630  {
631  gsGeometryMap ac;
632  ac.m_fs = m_fs;
633  ac.m_isAcross = false;
634  return ac;
635  }
636 
638  const gsFunctionSet<T> & source() const {return *m_fs;}
639 
641  const gsMapData<T> & data() const
642  {
643  GISMO_ASSERT(NULL!=m_fd, "gsGeometryMap: invalid data "<< m_fs <<","<<m_fd);
644  return *m_fd;
645  }
646 
647  index_t targetDim() const { return m_fs->targetDim();}
648  index_t domainDim() const { return m_fs->domainDim();}
649 
651  void copyCoefs( const gsGeometryMap<T> & other) const
652  {
653  GISMO_ASSERT( dynamic_cast<const gsMultiPatch<T>*>( this->m_fs ), "error");
654  const gsMultiPatch<T> & thisMP = static_cast<const gsMultiPatch<T>&>(*this->m_fs );
655  GISMO_ASSERT( dynamic_cast<const gsMultiPatch<T>*>( other.m_fs ), "error");
656  const gsMultiPatch<T> & otherMP = static_cast<const gsMultiPatch<T>&>(*other.m_fs );
657  GISMO_ASSERT( (thisMP.domainDim()==otherMP.domainDim())&&
658  (thisMP.geoDim()==otherMP.geoDim())&&
659  (thisMP.coefsSize() == otherMP.coefsSize())&&
660  (thisMP.nPatches()==otherMP.nPatches()),
661  "The geometryMaps are not compatible!");
662 
663  // For every patch of the MultiPatch
664  for ( index_t p=0; p < thisMP.nPatches(); p++ )
665  {
666  // Copy coeffs of the other MultiPatch
667  thisMP.patch(p).coefs() = otherMP.patch(p).coefs();
668  }
669 
670  } //end copyCoffs
671 
672  void deformBy( const gsFeSolution<T> & displacement) const
673  {
674  const index_t dim = m_fs->domainDim();
675 
676  const gsMultiBasis<T> & mb = static_cast<const gsMultiBasis<T>&>(displacement.space().source());
677  const gsMultiPatch<T> & mp = static_cast<const gsMultiPatch<T>&>(*this->m_fs );
678  GISMO_ASSERT( dynamic_cast<const gsMultiBasis<T>*>(&displacement.space().source()), "error");
679  GISMO_ASSERT( dynamic_cast<const gsMultiPatch<T>*>( this->m_fs), "error");
680 
681  // For every patch of the MultiPatch
682  for ( size_t p=0; p < mp.nPatches(); p++ )
683  {
684  // Get the patch's coefficients
685  gsMatrix<T> &result = mp.patch(p).coefs();
686 
687  // Number of basis functions of patch with index p
688  const index_t sz = mb[p].size();
689 
690  // For all components
691  for (index_t c = 0; c!=dim; c++)
692  {
693  // loop over all basis functions (even the eliminated ones)
694  for (index_t i = 0; i < sz; ++i)
695  {
696  const int ii = displacement.mapper().index(i, p, c);
697  if ( displacement.mapper().is_free_index(ii) ) // DoF value is in the defVector
698  {
699  result(i,c) += displacement.coefs().at(ii);
700  }
701  else
702  {
703  result(i,c) += displacement.fixedPart().at( displacement.mapper().global_to_bindex(ii));
704  }
705  }
706  }
707  }
708  } // end deformBy
709 
710 public:
711  typedef T Scalar;
712 
713  friend class gismo::gsExprHelper<Scalar>;
714 
715  void print(std::ostream &os) const { os << "G"; }
716 
717  auto eval(const index_t k) const -> decltype(m_fd->values[0].col(k))
718  { return m_fd->values[0].col(k); }
719 
720 protected:
721 
722  gsGeometryMap() : m_fs(NULL), m_fd(NULL), m_isAcross(false) { }
723 
724  void setSource(const gsFunctionSet<Scalar> & fs) { m_fs = &fs;}
725  void setData(const gsMapData<Scalar> & val) { m_fd = &val;}
726 
727 public:
728 
729  index_t rows() const { return m_fs->targetDim(); }
730  index_t cols() const { return 1; }
731 
732  const gsFeSpace<T> & rowVar() const { return gsNullExpr<T>::get(); }
733  const gsFeSpace<T> & colVar() const { return gsNullExpr<T>::get(); }
734 
735  void parse(gsExprHelper<Scalar> & evList) const
736  {
737  evList.add(*this);
738  m_fd->flags |= NEED_VALUE;
739  }
740 };
741 
742 // Traits for gsGeometryMap
743 template <typename T> struct expr_traits<gsGeometryMap<T> >
744 {
745  typedef T Scalar;
746  typedef const gsGeometryMap<T> Nested_t; // nesting without ref!
747 };
748 
749 /*
750  Expression for the measure of a geometry map
751 */
752 template<class T>
753 class meas_expr : public _expr<meas_expr<T> >
754 {
755  typename gsGeometryMap<T>::Nested_t _G;
756 
757 public:
758  enum {Space = 0, ScalarValued = 1, ColBlocks = 0};
759 
760  typedef T Scalar;
761 
762  meas_expr(const gsGeometryMap<T> & G) : _G(G) { }
763 
764  T eval(const index_t k) const
765  {
766  return _G.data().measures.at(k);
767  }
768 
769  index_t rows() const { return 0; }
770  index_t cols() const { return 0; }
771  void parse(gsExprHelper<Scalar> & evList) const
772  {
773  evList.add(_G);
774  _G.data().flags |= NEED_MEASURE;
775  }
776 
777  const gsFeSpace<T> & rowVar() const { return gsNullExpr<T>::get(); }
778  const gsFeSpace<T> & colVar() const { return gsNullExpr<T>::get(); }
779 
780  void print(std::ostream &os) const { os << "meas("; _G.print(os); os <<")"; }
781 };
782 
783 
784 /*
785  An element object collecting relevant expressions
786 */
787 template<class T>
788 class gsFeElement
789 {
790  friend class cdiam_expr<T>;
791 
792  const gsDomainIterator<T> * m_di;
793 
794  const gsVector<T> * m_weights;
795  //const gsMatrix<T> * m_points;
796 
797  gsFeElement(const gsFeElement &);
798 public:
799  typedef T Scalar;
800 
801  gsFeElement() : m_di(NULL), m_weights(nullptr) { }
802 
803  void set(const gsDomainIterator<T> & di, const gsVector<T> & weights)
804  { m_di = &di, m_weights = &weights; }
805 
806  bool isValid() const { return nullptr!=m_weights; }
807 
808  const gsVector<T> & weights() const {return *m_weights;}
809 
810  template<class E>
811  integral_expr<E> integral(const _expr<E>& ff) const
812  { return integral_expr<E>(*this,ff); }
813 
814  typedef integral_expr<T> AreaRetType;
815  AreaRetType area() const
816  { return integral(_expr<T,true>(1)); }
817 
818  typedef integral_expr<meas_expr<T> > PHAreaRetType;
820  PHAreaRetType area(const gsGeometryMap<Scalar> & _G) const
821  { return integral(meas_expr<T>(_G)); }
822 
823  typedef pow_expr<integral_expr<T> > DiamRetType;
825  DiamRetType diam() const //-> int(1)^(1/d)
826  { return pow(integral(_expr<T,true>(1)),(T)(1)/(T)(2)); }
827 
828  typedef pow_expr<integral_expr<meas_expr<T> > > PHDiamRetType;
830  PHDiamRetType diam(const gsGeometryMap<Scalar> & _G) const
831  { return pow(integral(meas_expr<T>(_G)),(T)(1)/(T)(2)); }
832 
833  //const gsMatrix<T> points() const {return pts;}
834 
835  //index_t dim() { return di->
836 
837  void print(std::ostream &os) const { os << "e"; }
838 
839  void parse(gsExprHelper<T> & evList) const
840  {
841  GISMO_ERROR("EL");
842  evList.add(*this);
843  this->data().flags |= NEED_VALUE;
844  }
845 };
846 
850 template<class E>
851 class integral_expr : public _expr<integral_expr<E> >
852 {
853 public:
854  //typedef typename E::Scalar Scalar;
855  typedef real_t Scalar;
856  mutable Scalar m_val;
857 private:
858  const gsFeElement<Scalar> & _e;
859  typename _expr<E>::Nested_t _ff;
860 public:
861  enum {Space= 0, ScalarValued= 1, ColBlocks = 0};
862 
863  integral_expr(const gsFeElement<Scalar> & el, const _expr<E> & u)
864  : m_val(-1), _e(el), _ff(u) { }
865 
866  const Scalar & eval(const index_t k) const
867  {
868  GISMO_ENSURE(_e.isValid(), "Element is valid within integrals only.");
869  // if (0==k)
870  {
871  const Scalar * w = _e.weights().data();
872  m_val = (*w) * _ff.val().eval(0);
873  for (index_t j = 1; j != _e.weights().rows(); ++j)
874  m_val += (*(++w)) * _ff.val().eval(j);
875  }
876  return m_val;
877  }
878 
879  inline const integral_expr<E> & val() const { return *this; }
880  inline index_t rows() const { return 0; }
881  inline index_t cols() const { return 0; }
882  void parse(gsExprHelper<Scalar> & evList) const
883  {
884  _ff.parse(evList);
885  }
886 
887  const gsFeSpace<Scalar> & rowVar() const { return gsNullExpr<Scalar>::get(); }
888  const gsFeSpace<Scalar> & colVar() const { return gsNullExpr<Scalar>::get(); }
889 
890  void print(std::ostream &os) const
891  {
892  os << "integral(";
893  _ff.print(os);
894  os <<")";
895  }
896 };
897 
898 /*
899  template<class T>
900  class parNv_expr : public _expr<parNv_expr<T> >
901  {
902  const gsFeElement<T> & _e;
903  public:
904  typedef T Scalar;
905 
906  enum {ScalarValued = 1};
907 
908  explicit parNv_expr(const gsFeElement<T> & el) : _e(el) { }
909 
910  T eval(const index_t k) const { return _e.m_di->getCellSize(); }
911 
912  inline cdiam_expr<T> val() const { return *this; }
913  inline index_t rows() const { return 0; }
914  inline index_t cols() const { return 0; }
915  void parse(gsExprHelper<Scalar> &) const { }
916  const gsFeVariable<T> & rowVar() const { gsNullExpr<Scalar>::get(); }
917  const gsFeVariable<T> & colVar() const { gsNullExpr<Scalar>::get(); }
918 
919  void print(std::ostream &os) const
920  { os << "diam(e)"; }
921  };
922 */
923 
924 template <typename T>
925 struct expr_traits<gsFeVariable<T> >
926 {
927  typedef T Scalar;
928  typedef const gsFeVariable<T> Nested_t;
929 };
930 
935 template<class T>
936 class gsFeVariable : public symbol_expr< gsFeVariable<T> >
937 {
938  friend class gismo::gsExprHelper<T>;
939  typedef symbol_expr< gsFeVariable<T> > Base;
940 protected:
941  explicit gsFeVariable(index_t _d = 1) : Base(_d) { }
942 public:
943  enum {Space = 0, ScalarValued = 0, ColBlocks = 0};
944 };
945 
946 template<class T>
947 class gsComposition : public symbol_expr< gsComposition<T> >
948 { //comp(f,G)
949  friend class gismo::gsExprHelper<T>;
950  typedef symbol_expr< gsComposition<T> > Base;
951  typename gsGeometryMap<T>::Nested_t _G;
952 protected:
953  explicit gsComposition(const gsGeometryMap<T> & G, index_t _d = 1)
954  : Base(_d), _G(G) { }
955 public:
956  enum {Space = 0, ScalarValued= 0, ColBlocks= 0};
957 
958  typename gsMatrix<T>::constColumn
959  eval(const index_t k) const { return this->m_fd->values[0].col(k); }
960 
961  const gsGeometryMap<T> & inner() const { return _G;};
962 
963  void parse(gsExprHelper<T> & evList) const
964  {
965  //evList.add(_G); //done in gsExprHelper
966  evList.add(*this);
967  this->data().flags |= NEED_VALUE|NEED_ACTIVE;
968  //_G.data().flags |= NEED_VALUE; //done in gsExprHelper
969  }
970 };
971 
972 
980 template<class T>
981 class gsFeSpace :public symbol_expr< gsFeSpace<T> >
982 {
983  friend class gsNullExpr<T>;
984 
985 protected:
986  typedef symbol_expr< gsFeSpace<T> > Base;
987 
988  // contains id, mapper, fixedDofs, etc
989  gsFeSpaceData<T> * m_sd;
990 
991 public:
992  enum{Space = 1, ScalarValued=0, ColBlocks=0};// test space
993 
994  typedef const gsFeSpace Nested_t; //no ref
995 
996  typedef T Scalar;
997 
998  const gsFeSpace<T> & rowVar() const {return *this;}
999 
1000  gsDofMapper & mapper()
1001  {
1002  GISMO_ASSERT(NULL!=m_sd, "Space/mapper not properly initialized.");
1003  return m_sd->mapper;
1004  }
1005 
1006  const gsDofMapper & mapper() const
1007  {return const_cast<gsFeSpace*>(this)->mapper();}
1008 
1009  inline const gsMatrix<T> & fixedPart() const {return m_sd->fixedDofs;}
1010  gsMatrix<T> & fixedPart() {return m_sd->fixedDofs;}
1011 
1012  index_t id() const { return (m_sd ? m_sd->id : -101); }
1013  void setSpaceData(gsFeSpaceData<T>& sd) {m_sd = &sd;}
1014 
1015  index_t interfaceCont() const {return m_sd->cont;}
1016  index_t & setInterfaceCont(const index_t _r) const
1017  {
1018  GISMO_ASSERT(_r>-2 && _r<1, "Invalid or not implemented (r="<<_r<<").");
1019  return m_sd->cont = _r;
1020  }
1021 
1022  gsFeSolution<T> function(const gsMatrix<T>& solVector) const
1023  { return gsFeSolution<T>(*this); }
1024 
1025  void getCoeffs(const gsMatrix<T>& solVector, gsMatrix<T> & result,
1026  const index_t p = 0) const
1027  {
1028  const index_t dim = this->dim();
1029 
1030  const gsMultiBasis<T> & mb = static_cast<const gsMultiBasis<T>&>(this->source());
1031  GISMO_ASSERT( dynamic_cast<const gsMultiBasis<T>*>(&this->source()), "error");
1032 
1033  // Reconstruct solution coefficients on patch p
1034  const index_t sz = mb[p].size();
1035  result.resize(sz, dim!=1 ? dim : solVector.cols()); // (!)
1036 
1037  for (index_t c = 0; c!=dim; c++) // for all components
1038  {
1039  // loop over all basis functions (even the eliminated ones)
1040  for (index_t i = 0; i < sz; ++i)
1041  {
1042  const int ii = m_sd->mapper.index(i, p, c);
1043  if ( m_sd->mapper.is_free_index(ii) ) // DoF value is in the solVector
1044  for(index_t s = 0; s != solVector.cols(); ++s )
1045  result(i,c+s) = solVector(ii,s); //assume dim==1 xor solVector.cols()==1
1046  else // eliminated DoF: fill with Dirichlet data
1047  result(i,c) = m_sd->fixedDofs.at( m_sd->mapper.global_to_bindex(ii) );
1048  }
1049  }
1050  }
1051 
1052  // space restrictTo(boundaries);
1053  // space restrictTo(bcRefList domain);
1054 
1055  void setupMapper(gsDofMapper dofsMapper) const
1056  {
1057  GISMO_ASSERT( dofsMapper.isFinalized(), "The provided dof-mapper is not finalized.");
1058  GISMO_ASSERT( dofsMapper.mapSize()==static_cast<size_t>(this->source().size()*dofsMapper.numComponents()), "The dof-mapper is not consistent: mapSize()="<<dofsMapper.mapSize()<<"!="<<static_cast<size_t>(this->source().size())<<"=this->source().size()");
1059  m_sd->mapper = give(dofsMapper);
1060  }
1061 
1062  void setup(const index_t _icont = -1) const
1063  {
1064  this->setInterfaceCont(_icont);
1065  m_sd->mapper = gsDofMapper();
1066 
1067  if (const gsMultiBasis<T> * mb =
1068  dynamic_cast<const gsMultiBasis<T>*>(&this->source()) )
1069  {
1070  m_sd->mapper = gsDofMapper(*mb, this->dim() );
1071  //m_mapper.init(*mb, this->dim()); //bug
1072  if ( 0==this->interfaceCont() ) // Conforming boundaries ?
1073  {
1074  for ( gsBoxTopology::const_iiterator it = mb->topology().iBegin();
1075  it != mb->topology().iEnd(); ++it )
1076  {
1077  mb->matchInterface(*it, m_sd->mapper);
1078  }
1079  }
1080  }
1081 
1082  if (const gsMappedBasis<2,T> * mb =
1083  dynamic_cast<const gsMappedBasis<2,T>*>(&this->source()) )
1084  {
1085  m_sd->mapper.setIdentity(mb->nPatches(), mb->size() , this->dim());
1086  }
1087 
1088  m_sd->mapper.finalize();
1089  }
1090 
1091  void setup(const gsBoundaryConditions<T> & bc, const index_t dir_values,
1092  const index_t _icont = -1) const
1093  {
1094  this->setInterfaceCont(_icont);
1095  m_sd->mapper = gsDofMapper();
1096  const index_t dim = this->dim();
1097  const gsMultiBasis<T> *mb = dynamic_cast<const gsMultiBasis<T> *>(&this->source());
1098  if (mb != nullptr)
1099  {
1100  m_sd->mapper = gsDofMapper(*mb, this->dim());
1101  //m_mapper.init(*mb, this->dim()); //bug
1102  if (0 == this->interfaceCont()) // Conforming boundaries ?
1103  {
1104  for (gsBoxTopology::const_iiterator it = mb->topology().iBegin();
1105  it != mb->topology().iEnd(); ++it) {
1106  mb->matchInterface(*it, m_sd->mapper);
1107  }
1108  }
1109 
1110  // Strong Dirichlet conditions
1111  gsMatrix<index_t> bnd;
1112  for (typename gsBoundaryConditions<T>::const_iterator
1113  it = bc.begin("Dirichlet"); it != bc.end("Dirichlet"); ++it)
1114  {
1115  const index_t cc = it->unkComponent();
1116  GISMO_ASSERT(static_cast<size_t>(it->ps.patch) < this->mapper().numPatches(),
1117  "Problem: a boundary condition is set on a patch id which does not exist.");
1118 
1119  bnd = mb->basis(it->ps.patch).boundary(it->ps.side());
1120  m_sd->mapper.markBoundary(it->ps.patch, bnd, cc);
1121  }
1122  // Clamped boundary condition (per DoF)
1123  gsMatrix<index_t> bnd1;
1124  for (typename gsBoundaryConditions<T>::const_iterator
1125  it = bc.begin("Clamped"); it != bc.end("Clamped"); ++it)
1126  {
1127  const index_t cc = it->unkComponent();
1128 
1129  GISMO_ASSERT(static_cast<size_t>(it->ps.patch) < this->mapper().numPatches(),
1130  "Problem: a boundary condition is set on a patch id which does not exist.");
1131 
1132  bnd = mb->basis(it->ps.patch).boundaryOffset(it->ps.side(), 0);
1133  bnd1 = mb->basis(it->ps.patch).boundaryOffset(it->ps.side(), 1);
1134  // Cast to tensor b-spline basis
1135  if (!it->ps.parameter())
1136  bnd.swap(bnd1);
1137  for (index_t c = 0; c!=dim; c++) // for all components
1138  {
1139  if (c==cc || cc==-1 )
1140  for (index_t k = 0; k < bnd.size(); ++k)
1141  m_sd->mapper.matchDof(it->ps.patch, (bnd)(k, 0),
1142  it->ps.patch, (bnd1)(k, 0), c);
1143  }
1144 
1145  }
1146 
1147  // Collapsed
1148  for (typename gsBoundaryConditions<T>::const_iterator
1149  it = bc.begin("Collapsed"); it != bc.end("Collapsed"); ++it)
1150  {
1151  const index_t cc = it->unkComponent();
1152 
1153  GISMO_ASSERT(static_cast<size_t>(it->ps.patch) < this->mapper().numPatches(),
1154  "Problem: a boundary condition is set on a patch id which does not exist.");
1155 
1156  bnd = mb->basis(it->ps.patch).boundary(it->ps.side());
1157 
1158  // match all DoFs to the first one of the side
1159  for (index_t c = 0; c!=dim; c++) // for all components
1160  {
1161  if (c==cc || cc==-1)
1162  for (index_t k = 0; k < bnd.size() - 1; ++k)
1163  m_sd->mapper.matchDof(it->ps.patch, (bnd)(0, 0),
1164  it->ps.patch, (bnd)(k + 1, 0), c);
1165  }
1166  }
1167 
1168  // Coupled
1169  for (typename gsBoundaryConditions<T>::const_cpliterator
1170  it = bc.coupledBegin(); it != bc.coupledEnd(); ++it)
1171  {
1172  const index_t cc = it->component;
1173 
1174  GISMO_ASSERT(static_cast<size_t>(it->ifc.first().patch) < this->mapper().numPatches(),
1175  "Problem: a boundary condition is set on a patch id which does not exist.");
1176  GISMO_ASSERT(static_cast<size_t>(it->ifc.second().patch) < this->mapper().numPatches(),
1177  "Problem: a boundary condition is set on a patch id which does not exist.");
1178 
1179 
1180  bnd = mb->basis(it->ifc.first().patch).boundary(it->ifc.first().side());
1181  bnd1 = mb->basis(it->ifc.second().patch).boundary(it->ifc.second().side());
1182 
1183  // match all DoFs to the first one of the side
1184  for (index_t c = 0; c!=dim; c++) // for all components
1185  {
1186  if (c==cc || cc==-1)
1187  {
1188  for (index_t k = 0; k < bnd.size() - 1; ++k)
1189  m_sd->mapper.matchDof(it->ifc.first() .patch, (bnd)(0, 0),
1190  it->ifc.first() .patch, (bnd)(k + 1, 0), c);
1191  for (index_t k = 0; k < bnd1.size(); ++k)
1192  m_sd->mapper.matchDof(it->ifc.first() .patch, (bnd)(0, 0),
1193  it->ifc.second().patch, (bnd1)(k, 0), c);
1194  }
1195  }
1196  }
1197 
1198  // corners
1199  for (typename gsBoundaryConditions<T>::const_citerator
1200  it = bc.cornerBegin(); it != bc.cornerEnd(); ++it)
1201  {
1202  for (index_t r = 0; r!=this->dim(); ++r)
1203  {
1204  if (it->component!=-1 && r!=it->component) continue;
1205 
1206  //assumes (unk == -1 || it->unknown == unk)
1207  GISMO_ASSERT(static_cast<size_t>(it->patch) < mb->nBases(),
1208  "Problem: a corner boundary condition is set on a patch id which does not exist.");
1209  m_sd->mapper.eliminateDof(mb->basis(it->patch).functionAtCorner(it->corner),
1210  it->patch, it->component);
1211  }
1212  }
1213 
1214  } else if (const gsBasis<T> *b =
1215  dynamic_cast<const gsBasis<T> *>(&this->source()))
1216  {
1217  m_sd->mapper = gsDofMapper(*b, this->dim() );
1218  gsMatrix<index_t> bnd;
1219  for (typename gsBoundaryConditions<T>::const_iterator
1220  it = bc.begin("Dirichlet"); it != bc.end("Dirichlet"); ++it) {
1221  GISMO_ASSERT(it->ps.patch == 0,
1222  "Problem: a boundary condition is set on a patch id which does not exist.");
1223 
1224  bnd = b->boundary(it->ps.side());
1225  m_sd->mapper.markBoundary(0, bnd, it->unkComponent());
1226  }
1227 
1228  for (typename gsBoundaryConditions<T>::const_iterator
1229  it = bc.begin("Clamped"); it != bc.end("Clamped"); ++it) {
1230  GISMO_ASSERT(it->ps.patch == 0,
1231  "Problem: a boundary condition is set on a patch id which does not exist.");
1232 
1233  bnd = b->boundary(it->ps.side());
1234  //const index_t cc = it->unkComponent();
1235  // m_sd->mapper.markBoundary(0, bnd, 0);
1236  }
1237 
1238  m_sd->mapper = gsDofMapper(*b);
1239  for (typename gsBoundaryConditions<T>::const_iterator
1240  it = bc.begin("Collapsed"); it != bc.end("Collapsed"); ++it) {
1241  GISMO_ASSERT(it->ps.patch == 0,
1242  "Problem: a boundary condition is set on a patch id which does not exist.");
1243 
1244  bnd = b->boundary(it->ps.side());
1245  //const index_t cc = it->unkComponent();
1246  // m_sd->mapper.markBoundary(0, bnd, 0);
1247  }
1248  } else if (const gsMappedBasis<2, T> *mapb =
1249  dynamic_cast<const gsMappedBasis<2, T> *>(&this->source()))
1250  {
1251  m_sd->mapper.setIdentity(mapb->nPatches(), mapb->size(), this->dim());
1252 
1253  if (0 == this->interfaceCont()) // C^0 matching interface
1254  {
1255  gsMatrix<index_t> int1, int2;
1256  for (gsBoxTopology::const_iiterator it = mapb->getTopol().iBegin();
1257  it != mapb->getTopol().iEnd(); ++it) {
1258  int1 = mapb->basis(it->first().patch).boundaryOffset(it->first().side(), 0);
1259  int2 = mapb->basis(it->second().patch).boundaryOffset(it->second().side(), 0);
1260 
1261  m_sd->mapper.matchDofs(it->first().patch, int1, it->second().patch, int2);
1262  }
1263  }
1264  if (1 == this->interfaceCont()) // C^1 matching interface
1265  {
1266  GISMO_ERROR("Boundary offset function is not implemented for gsMappedBasis in general.");
1267  }
1268 
1269  gsMatrix<index_t> bnd;
1270  for (typename gsBoundaryConditions<T>::const_iterator
1271  it = bc.begin("Dirichlet"); it != bc.end("Dirichlet"); ++it) {
1272  const index_t cc = it->unkComponent();
1273  GISMO_ASSERT(static_cast<size_t>(it->ps.patch) < this->mapper().numPatches(),
1274  "Problem: a boundary condition is set on a patch id which does not exist.");
1275 
1276  bnd = mapb->basis(it->ps.patch).boundary(it->ps.side());
1277  m_sd->mapper.markBoundary(it->ps.patch, bnd, cc);
1278  }
1279 
1280  // Clamped boundary condition (per DoF)
1281  gsMatrix<index_t> bnd1;
1282  for (typename gsBoundaryConditions<T>::const_iterator
1283  it = bc.begin("Clamped"); it != bc.end("Clamped"); ++it) {
1284  const index_t cc = it->unkComponent();
1285 
1286  GISMO_ASSERT(static_cast<size_t>(it->ps.patch) < this->mapper().numPatches(),
1287  "Problem: a boundary condition is set on a patch id which does not exist.");
1288 
1289  bnd = mapb->basis(it->ps.patch).boundaryOffset(it->ps.side(), 0);
1290  bnd1 = mapb->basis(it->ps.patch).boundaryOffset(it->ps.side(), 1);
1291 
1292  // Cast to tensor b-spline basis
1293  if (mapb != NULL) // clamp adjacent dofs
1294  {
1295  if (!it->ps.parameter())
1296  bnd.swap(bnd1);
1297  for (index_t c = 0; c!=dim; c++) // for all components
1298  {
1299  if (c==cc || cc==-1 )
1300  for (index_t k = 0; k < bnd.size() - 1; ++k)
1301  m_sd->mapper.matchDof( it->ps.patch, (bnd)(k, 0),
1302  it->ps.patch, (bnd1)(k, 0), c);
1303  }
1304  } else
1305  gsWarn << "Unable to apply clamped condition.\n";
1306  }
1307 
1308  // COLLAPSED
1309  for (typename gsBoundaryConditions<T>::const_iterator
1310  it = bc.begin("Collapsed"); it != bc.end("Collapsed"); ++it) {
1311  const index_t cc = it->unkComponent();
1312 
1313  GISMO_ASSERT(static_cast<size_t>(it->ps.patch) < this->mapper().numPatches(),
1314  "Problem: a boundary condition is set on a patch id which does not exist.");
1315 
1316  bnd = mapb->basis(it->ps.patch).boundary(it->ps.side());
1317 
1318  // Cast to tensor b-spline basis
1319  if (mapb != NULL) // clamp adjacent dofs
1320  {
1321  // match all DoFs to the first one of the side
1322  for (index_t c = 0; c!=dim; c++) // for all components
1323  {
1324  if (c==cc || cc==-1)
1325  for (index_t k = 0; k < bnd.size() - 1; ++k)
1326  m_sd->mapper.matchDof(it->ps.patch, (bnd)(0, 0),
1327  it->ps.patch, (bnd)(k + 1, 0), c);
1328  }
1329  }
1330  }
1331 
1332  // corners
1333  for (typename gsBoundaryConditions<T>::const_citerator
1334  it = bc.cornerBegin(); it != bc.cornerEnd(); ++it)
1335  {
1336  //assumes (unk == -1 || it->unknown == unk)
1337  GISMO_ASSERT(it->patch < mapb->nPieces(),
1338  "Problem: a corner boundary condition is set on a patch id which does not exist.");
1339  m_sd->mapper.eliminateDof(mapb->basis(it->patch).functionAtCorner(it->corner), it->patch, it->component);
1340  }
1341  } else
1342  {
1343  GISMO_ASSERT(0 == bc.size(), "Problem: BCs are ignored.");
1344  m_sd->mapper.setIdentity(this->source().nPieces(), this->source().size());
1345  }
1346 
1347  m_sd->mapper.finalize();
1348 
1349  // Compute Dirichlet node values
1350  gsDirichletValues(bc, dir_values, *this);
1351  }
1352 
1353  void print(std::ostream &os) const { os << "u"; }
1354 
1355 protected:
1356  friend class gismo::gsExprHelper<Scalar>;
1357  friend class symbol_expr<gsFeSpace>;
1358  explicit gsFeSpace(index_t _d = 1) : Base(_d), m_sd(nullptr) { }
1359 };
1360 
1361 template<class T> inline bool
1362 operator== (const gsFeSpace<T> & a, const gsFeSpace<T> & b)
1363 { return a.id()== b.id() && a.isAcross()==b.isAcross(); }
1364 
1365 /*
1366  Expression representing a function given by a vector of
1367  coefficients in a gsFeSpace.
1368 
1369  Typically it used for accessing the solution of a boundary-value
1370  problem.
1371 */
1372 template<class T>
1373 class gsFeSolution : public _expr<gsFeSolution<T> >
1374 {
1375 protected:
1376  const gsFeSpace<T> _u;
1377  gsMatrix<T> * _Sv;
1378  bool m_isAcross;
1379 
1380 public:
1381  typedef T Scalar;
1382  enum {Space = 0, ScalarValued= 0, ColBlocks= 0};
1383 
1384  bool isAcross() const { return m_isAcross; }
1385 
1386  gsFeSolution right() const
1387  {
1388  gsFeSolution ac(*this);
1389  ac.m_isAcross = true;
1390  return ac;
1391  }
1392 
1393  gsFeSolution left() const { return gsFeSolution(*this); }
1394 
1395  explicit gsFeSolution(const gsFeSpace<T> & u) : _u(u), _Sv(NULL) { }
1396 
1397  gsFeSolution(const gsFeSpace<T> & u, gsMatrix<T> & Sv) : _u(u), _Sv(&Sv) { }
1398 
1399  const gsFeSpace<T> & space() const {return _u;};
1400 
1401  mutable gsMatrix<T> res;
1402  const gsMatrix<T> & eval(index_t k) const
1403  {
1404  bool singleActives = (1 == _u.data().actives.cols());
1405 
1406  res.setZero(_u.dim(), 1);
1407  const gsDofMapper & map = _u.mapper();
1408  GISMO_ASSERT(_Sv->size()==map.freeSize(), "The solution vector has wrong dimensions: "<<_Sv->size()<<" != "<<map.freeSize());
1409 
1410  for (index_t c = 0; c!=_u.dim(); c++) // for all components
1411  {
1412  for (index_t i = 0; i!=_u.data().actives.rows(); ++i)
1413  {
1414  const index_t ii = map.index(_u.data().actives(i, singleActives ? 0 : k), _u.data().patchId, c);
1415  if ( map.is_free_index(ii) ) // DoF value is in the solVector
1416  res.at(c) += _Sv->at(ii) * _u.data().values[0](i,k);
1417  else
1418  res.at(c) += _u.data().values[0](i,k) *
1419  _u.fixedPart().at( map.global_to_bindex(ii) );
1420  }
1421  }
1422  return res;
1423  }
1424 
1425  //template<class U>
1426  //linearComb(U & ie){ sum up ie[_u] times the _Sv }
1427  // ie.eval(k), _u.data().actives(), fixedPart() - see lapl_expr
1428 
1429  const gsFeSpace<Scalar> & rowVar() const {return gsNullExpr<Scalar>::get();}
1430  const gsFeSpace<Scalar> & colVar() const {return gsNullExpr<Scalar>::get();}
1431  index_t rows() const {return _u.dim(); }
1432 
1433  static index_t cols() {return 1; }
1434 
1435  void parse(gsExprHelper<Scalar> & evList) const
1436  {
1437  evList.add(_u);
1438  _u.data().flags |= NEED_VALUE | NEED_ACTIVE;
1439  }
1440 
1441  void print(std::ostream &os) const { os << "s"; }
1442 
1443 public:
1444  index_t dim() const { return _u.dim();}
1445 
1446  index_t parDim() const
1447  { return _u.source().domainDim(); }
1448 
1449  //gsDofMapper & mapper() {return _u.mapper();}
1450  const gsDofMapper & mapper() const {return _u.mapper();}
1451 
1452  inline const gsMatrix<T> & fixedPart() const {return _u.fixedPart();}
1453  gsMatrix<T> & fixedPart() {return _u.fixedPart();}
1454 
1455  //gsFuncData<T> & data() {return _u.data();}
1456  const gsFuncData<T> & data() const {return _u.data();}
1457 
1458  void setSolutionVector(gsMatrix<T>& solVector)
1459  { _Sv = & solVector; }
1460 
1466  void setComponent(index_t component, real_t value, index_t patch=-1)
1467  {
1468  gsMatrix<T> & solVector = *_Sv;
1469  const gsDofMapper & mapper = _u.mapper();
1470 
1471  index_t patchStart, patchEnd;
1472  if (patch==-1){
1473  patchStart = 0;
1474  patchEnd = _u.mapper().numPatches();
1475  }
1476  else{
1477  patchStart = patch;
1478  patchEnd = patch + 1;
1479  }
1480 
1481  for (index_t p=patchStart; p!=patchEnd; ++p)
1482  {
1483  for (size_t i = 0; i != mapper.patchSize(p, component); ++i)
1484  {
1485  const index_t ii = mapper.index(i, p, component);
1486  if ( mapper.is_free_index(ii) ) // DoF value is in the solVector
1487  solVector.at(ii) = value;
1488  }
1489  }
1490  }
1491 
1492  const gsMatrix<T> & coefs() const { return *_Sv; }
1493  //gsMatrix<T> & coefs() { return *_Sv; } // wd4702 ?
1494 
1495  //const gsMatrix<T> & coefs(component, patch) const { return *_Sv; }
1496 
1498  void perturbLocal(T val, index_t j, index_t p = 0)
1499  {
1500  // GISMO_ASSERT(1==_u.data().actives.cols(), "Single actives expected");
1501  //if (_u.mapper().is_free_index(j) )
1502  //{
1503  GISMO_ASSERT(j<_Sv->size(), "Solution vector is not initialized/allocated, sz="<<_Sv->size() );
1504  _Sv->at(j) += val;
1505  //}
1506  //else
1507  // _u.fixedPart().at( _u.mapper().global_to_bindex(j) ) += val;
1508  }
1509 
1511  void extract(gsMatrix<T> & result, const index_t p = 0) const
1512  { _u.getCoeffs(*_Sv, result, p); }
1513 
1516  void extractFull(gsMatrix<T> & result) const
1517  {
1518  index_t offset;
1519  const index_t dim = _u.dim();
1520  const size_t totalSz = _u.mapper().mapSize();
1521  result.resize(totalSz, 1);
1522  for (size_t p=0; p!=_u.mapper().numPatches(); ++p)
1523  {
1524  offset = _u.mapper().offset(p);
1525  // Reconstruct solution coefficients on patch p
1526 
1527  for (index_t c = 0; c!=dim; c++) // for all components
1528  {
1529  const index_t sz = _u.mapper().patchSize(p,c);
1530 
1531  // loop over all basis functions (even the eliminated ones)
1532  for (index_t i = 0; i < sz; ++i)
1533  {
1534  //gsDebugVar(i);
1535  const int ii = _u.mapper().index(i, p, c);
1536  //gsDebugVar(ii);
1537  if ( _u.mapper().is_free_index(ii) ) // DoF value is in the solVector
1538  {
1539  result(i+offset,0) = _Sv->at(ii);
1540  }
1541  else // eliminated DoF: fill with Dirichlet data
1542  result(i+offset,0) = _u.fixedPart().at( _u.mapper().global_to_bindex(ii) );
1543  }
1544  offset += sz;
1545  }
1546  }
1547  }
1548 
1550  void extract(gsMultiPatch<T> & result) const
1551  {
1552  result.clear();
1553 
1554  if( const gsMultiBasis<T>* basis = dynamic_cast<const gsMultiBasis<T>* >(&_u.source()) )
1555  for (size_t i = 0; i != basis->nBases(); ++i)
1556  {
1557  memory::unique_ptr<gsGeometry<T> > p(this->extractPiece(i));
1558  result.addPatch(*p);
1559  }
1560  }
1561 
1563  void extract(gsMappedSpline<2,T> & result) const
1564  {
1565  if( const gsMappedBasis<2,T>* basis = dynamic_cast<const gsMappedBasis<2,T>* >(&_u.source()) )
1566  {
1567  gsMatrix<T> coefs;
1568  this->extractFull(coefs);
1569  coefs.resize(coefs.rows()/_u.dim(),_u.dim());
1570  result.init(*basis,coefs);
1571  }
1572  }
1573 
1575  memory::unique_ptr<gsGeometry<T> > extractPiece(const index_t p) const
1576  {
1577  if ( const gsBasis<T> * b = dynamic_cast<const gsBasis<T>*>(&_u.source().piece(p)) )
1578  {
1579  gsMatrix<T> cf;
1580  extract(cf, p);
1581  return b->makeGeometry(give(cf));
1582  }
1583  GISMO_ERROR("gsFeSolution: Extraction error");
1584  }
1585 
1586  // insert g-coefficients to the solution vector
1587  void insert(const gsGeometry<T> & g, const index_t p = 0) const
1588  {
1589  const gsMatrix<T> & cf = g.coefs();
1590  gsMatrix<T> & sol = *_Sv;
1591  //gsMatrix<T> & fixedPart = _u.fixedPart();
1592  const gsDofMapper & mapper = _u.mapper();
1593  for (index_t c = 0; c!=_u.dim(); c++) // for all components
1594  {
1595  for (index_t i = 0; i != cf.rows(); ++i)
1596  {
1597  const index_t ii = mapper.index(i, p, c);
1598  if ( mapper.is_free_index(ii) ) // DoF value is in the solVector
1599  sol.at(ii) = cf(i, c);
1600  /*
1601  else
1602  {
1603  fixedPart.row(m_sd->mapper.global_to_bindex(ii)) = cf.row(i);
1604  }
1605  */
1606  }
1607  }
1608  }
1609 };
1610 
1611 /*
1612  Expression for the transpose of an expression
1613 */
1614 template<class E, bool cw>
1615 class tr_expr : public _expr<tr_expr<E,cw> >
1616 {
1617  typename E::Nested_t _u;
1618 
1619 public:
1620 
1621  typedef typename E::Scalar Scalar;
1622 
1623  tr_expr(_expr<E> const& u)
1624  : _u(u) { }
1625 
1626 public:
1627  enum {ColBlocks = E::ColBlocks, ScalarValued=E::ScalarValued};
1628  enum {Space = cw?E::Space:(E::Space==1?2:(E::Space==2?1:E::Space))};
1629 
1630  mutable Temporary_t res;
1631  const Temporary_t & eval(const index_t k) const
1632  {
1633  if (E::ColBlocks)
1634  res = _u.eval(k).blockTranspose( _u.cardinality() );
1635  else
1636  res = _u.eval(k).transpose();
1637  return res;
1638  }
1639 
1640  index_t rows() const { return _u.cols(); }
1641 
1642  index_t cols() const { return _u.rows(); }
1643 
1644  void parse(gsExprHelper<Scalar> & evList) const
1645  { _u.parse(evList); }
1646 
1647  const gsFeSpace<Scalar> & rowVar() const { return cw?_u.rowVar():_u.colVar(); }
1648  const gsFeSpace<Scalar> & colVar() const { return cw?_u.colVar():_u.rowVar(); }
1649 
1650  index_t cardinality_impl() const { return _u.cardinality_impl(); }
1651 
1652  void print(std::ostream &os) const { os<<"("; _u.print(os); os <<")\u1D40"; }
1653 private:
1654 /*
1655  template<class U> EIGEN_STRONG_INLINE MatExprType
1656  eval_impl(const U k, typename util::enable_if<1==ColBlocks,U>::type* = nullptr)
1657  { return _u.eval(k).blockTranspose(_u.cols()/_u.rows()); }
1658 
1659  template<class U> EIGEN_STRONG_INLINE MatExprType
1660  eval_impl(const U k, typename util::enable_if<0==ColBlocks,U>::type* = nullptr)
1661  { return _u.eval(k).transpose(); }
1662 */
1663 };
1664 
1665 /*
1666  Expression to make an expression colblocks
1667 */
1668 template<class E>
1669 class cb_expr : public _expr<cb_expr<E> >
1670 {
1671  typename E::Nested_t _u;
1672 
1673 public:
1674 
1675  typedef typename E::Scalar Scalar;
1676 
1677  cb_expr(_expr<E> const& u)
1678  : _u(u) { }
1679 
1680 public:
1681  enum {ColBlocks = 1, ScalarValued=E::ScalarValued};
1682  enum {Space = E::Space};
1683 
1684  mutable gsMatrix<Scalar> ev, res;
1685 
1686  const gsMatrix<Scalar> & eval(const index_t k) const
1687  {
1688  //return _u.eval(k).transpose();
1689  // /*
1690  ev = _u.eval(k);
1691  if (E::ColBlocks)
1692  {
1693  return ev;
1694  }
1695  else
1696  {
1697  res = _u.eval(k);
1698 
1699  GISMO_ASSERT(res.rows() % _u.rows() == 0 && res.cols() % _u.cols() == 0,"Result is not a multiple of the space dimensions?");
1700 
1701  index_t cardinality;
1702  if ( (cardinality = res.rows() / _u.rows()) >= 1 && res.cols() / _u.cols() == 1 ) // stored in rows
1703  {
1704  res.resize(_u.rows(), cardinality * _u.cols());
1705  for (index_t r = 0; r!=cardinality; r++)
1706  res.block(0 , r * _u.cols(), _u.rows(), _u.cols()) = ev.block( r * _u.rows(), 0, _u.rows(), _u.cols() );
1707  }
1708  else if ( (cardinality = res.rows() / _u.rows()) == 1 && res.cols() / _u.cols() >= 1 ) // stored in cols ----->>>> This is already colBlocks???
1709  {
1710  res.resize(_u.rows(), cardinality * _u.cols());
1711  for (index_t r = 0; r!=cardinality; r++)
1712  res.block(0 , r * _u.cols(), _u.rows(), _u.cols()) = ev.block( 0, r * _u.cols(), _u.rows(), _u.cols() );
1713  }
1714  }
1715  return res;
1716  }
1717 
1718  index_t rows() const { return _u.rows(); }
1719 
1720  index_t cols() const { return _u.cols(); }
1721 
1722  void parse(gsExprHelper<Scalar> & evList) const
1723  { _u.parse(evList); }
1724 
1725  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
1726  const gsFeSpace<Scalar> & colVar() const { return _u.colVar(); }
1727 
1728  index_t cardinality_impl() const
1729  {
1730  res = _u.eval(0);
1731  index_t cardinality;
1732  if ( res.rows() / _u.rows() >= 1 && res.cols() / _u.cols() == 1 ) // stored in rows
1733  cardinality = res.rows() / _u.rows();
1734  else if ( res.rows() / _u.rows() == 1 && res.cols() / _u.cols() >= 1 )
1735  cardinality = res.cols() / _u.cols();
1736  else
1737  GISMO_ERROR("Cardinality for cb_expr cannot be determined.");
1738 
1739  return cardinality;
1740  }
1741 
1742  void print(std::ostream &os) const { os<<"{"; _u.print(os); os <<"}"; }
1743 };
1744 
1745 
1746 /*
1747  Expression for an evaluation of the (sub-)expression in temporary memory
1748 */
1749 template<class E>
1750 class temp_expr : public _expr<temp_expr<E> >
1751 {
1752  typename E::Nested_t _u;
1753  typedef typename E::Scalar Scalar;
1754  mutable gsMatrix<Scalar> tmp;
1755 
1756 public:
1757  temp_expr(_expr<E> const& u)
1758  : _u(u) { }
1759 
1760 public:
1761  enum {Space = E::Space, ScalarValued = E::ScalarValued,
1762  ColBlocks = E::ColBlocks};
1763 
1764  // template<bool S = ColBlocks>
1765  // typename util::enable_if<S,MatExprType>::type
1766  const gsMatrix<Scalar> & eval(const index_t k) const
1767  {
1768  tmp = _u.eval(k);
1769  return tmp;
1770  }
1771 
1772  index_t rows() const { return _u.rows(); }
1773  index_t cols() const { return _u.cols(); }
1774  void parse(gsExprHelper<Scalar> & evList) const { _u.parse(evList); }
1775  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
1776  const gsFeSpace<Scalar> & colVar() const { return _u.colVar(); }
1777 
1778  void print(std::ostream &os) const { _u.print(os); }
1779 };
1780 
1781 /*
1782  Expression for the trace of a (matrix) expression
1783 */
1784 template<class E>
1785 class trace_expr : public _expr<trace_expr<E> >
1786 {
1787 public:
1788  typedef typename E::Scalar Scalar;
1789  enum {ScalarValued = 0, Space = E::Space, ColBlocks= 0};
1790 
1791 private:
1792  typename E::Nested_t _u;
1793  mutable gsMatrix<Scalar> res;
1794 
1795 public:
1796  trace_expr(_expr<E> const& u) : _u(u)
1797  {
1798  // gcc 4.8.4: invalid read due to _u.rows() using gsFuncData
1799  //GISMO_ASSERT(0== _u.cols()%_u.rows(), "Expecting square-block expression, got " << _u.rows() <<" x "<< _u.cols() );
1800  }
1801 
1802  // choose if ColBlocks
1803  const gsMatrix<Scalar> & eval(const index_t k) const
1804  {
1805  auto tmp = _u.eval(k);
1806  const index_t cb = _u.rows();
1807  const index_t r = _u.cardinality();
1808  if (Space==1)
1809  res.resize(r, 1);
1810  else
1811  res.resize(1, r);
1812 
1813  for (index_t i = 0; i!=r; ++i)
1814  res.at(i) = tmp.middleCols(i*cb,cb).trace();
1815  return res;
1816  }
1817 
1818  // choose if !ColBlocks
1819  //todo: Scalar eval(const index_t k) const
1820 
1821  index_t rows() const { return _u.cols() / _u.rows(); } //_u.cardinality()?
1822  index_t cols() const { return 1; }
1823 
1824  index_t cardinality_impl() const { return _u.cardinality(); }
1825 
1826  void parse(gsExprHelper<Scalar> & evList) const
1827  { _u.parse(evList); }
1828 
1829  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
1830  const gsFeSpace<Scalar> & colVar() const { return _u.colVar(); }
1831 
1832  void print(std::ostream &os) const { os << "trace("; _u.print(os); os<<")"; }
1833 };
1834 
1835 /*
1836  Expression for the adjugate of a (matrix) expression
1837 */
1838 template<class E>
1839 class adjugate_expr : public _expr<adjugate_expr<E> >
1840 {
1841 public:
1842  typedef typename E::Scalar Scalar;
1843  enum {ScalarValued = 0, ColBlocks = E::ColBlocks};
1844  enum {Space = E::Space};
1845 private:
1846  typename E::Nested_t _u;
1847  mutable gsMatrix<Scalar> res;
1848 
1849 public:
1850  adjugate_expr(_expr<E> const& u) : _u(u)
1851  {
1852  // gcc 4.8.4: invalid read due to _u.rows() using gsFuncData
1853  //GISMO_ASSERT(0== _u.cols()%_u.rows(), "Expecting square-block expression, got " << _u.rows() <<" x "<< _u.cols() );
1854  }
1855 
1856  // choose if ColBlocks
1857  const gsMatrix<Scalar> & eval(const index_t k) const
1858  {
1859  auto tmp = _u.eval(k);
1860  const index_t cb = _u.rows();
1861  const index_t r = _u.cols() / cb;
1862  res.resize(_u.rows(),_u.cols());
1863  for (index_t i = 0; i!=r; ++i){
1864  res.middleCols(i*cb,cb) = tmp.middleCols(i*cb,cb).adjugate();
1865  }
1866  return res;
1867  }
1868 
1869  // choose if !ColBlocks
1870  //todo: Scalar eval(const index_t k) const
1871 
1872  index_t rows() const { return _u.rows(); }
1873  index_t cols() const { return _u.cols(); }
1874 
1875  void parse(gsExprHelper<Scalar> & evList) const
1876  { _u.parse(evList); }
1877 
1878  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
1879  const gsFeSpace<Scalar> & colVar() const { return _u.colVar(); }
1880 
1881  void print(std::ostream &os) const { os << "adj("; _u.print(os); os<<")"; }
1882 };
1883 
1884 template<class E>
1885 class reshape_expr : public _expr<reshape_expr<E> >
1886 {
1887 public:
1888  typedef typename E::Scalar Scalar;
1889  enum {ScalarValued = 0, ColBlocks = E::ColBlocks};
1890  enum {Space = E::Space};
1891 private:
1892  typename E::Nested_t _u;
1893  index_t _n, _m;
1894  mutable gsMatrix<Scalar> tmp;
1895 
1896 public:
1897 
1898  //the reshaping is done column-wise
1899  reshape_expr(_expr<E> const& u, index_t n, index_t m) : _u(u), _n(n), _m(m)
1900  {
1901  //GISMO_ASSERT( _u.rows()*_u.cols() == _n*_m, "Wrong dimension"); //
1902  }
1903 
1904  const gsAsConstMatrix<Scalar> eval(const index_t k) const
1905  {
1906  // Note: this assertion would fail in the constructor!
1907  GISMO_ASSERT( _u.rows()*_u.cols() == _n*_m, "Wrong dimension "
1908  << _u.rows() << " x "<<_u.cols() << "!=" << _n << " * "<< _m );
1909  tmp = _u.eval(k);
1910  return gsAsConstMatrix<Scalar>(tmp.data(),_n,_m);
1911  }
1912 
1913  index_t rows() const { return _n; }
1914  index_t cols() const { return _m; }
1915 
1916  void parse(gsExprHelper<Scalar> & evList) const
1917  { _u.parse(evList); }
1918 
1919  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
1920  const gsFeSpace<Scalar> & colVar() const { return _u.colVar(); }
1921 
1922  void print(std::ostream &os) const { os << "reshape("; _u.print(os); os<<","<<_n<<","<<_m<<")"; }
1923 };
1924 
1926 template <typename E> EIGEN_STRONG_INLINE
1927 reshape_expr<E> const reshape(E const & u, index_t n, index_t m)
1928 { return reshape_expr<E>(u, n, m); }
1929 
1930 template<class E>
1931 class replicate_expr : public _expr<replicate_expr<E> >
1932 {
1933 public:
1934  typedef typename E::Scalar Scalar;
1935  enum {ScalarValued = 0, Space = E::Space, ColBlocks= E::ColBlocks};
1936 private:
1937  typename E::Nested_t _u;
1938  index_t _n, _m;
1939  mutable gsMatrix<Scalar> tmp;
1940 
1941 public:
1942 
1943  //the replicate is done nxm times
1944  replicate_expr(_expr<E> const& u, index_t n, index_t m) : _u(u), _n(n), _m(m)
1945  {
1946  }
1947 
1948  auto eval(const index_t k) const -> decltype(tmp.replicate(_n,_m))
1949  {
1950  tmp = _u.eval(k);
1951  return tmp.replicate(_n,_m);
1952  }
1953 
1954  index_t rows() const { return _n*_u.rows(); }
1955  index_t cols() const { return _m*_u.cols(); }
1956 
1957  void parse(gsExprHelper<Scalar> & evList) const
1958  { _u.parse(evList); }
1959 
1960  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
1961  const gsFeSpace<Scalar> & colVar() const { return _u.colVar(); }
1962  index_t cardinality_impl() const { return _u.cardinality_impl(); }
1963 
1964  void print(std::ostream &os) const { os << "replicate("; _u.print(os); os<<","<<_n<<","<<_m<<")"; }
1965 };
1966 
1968 template <typename E> EIGEN_STRONG_INLINE
1969 replicate_expr<E> const replicate(E const & u, index_t n, index_t m = 1)
1970 { return replicate_expr<E>(u, n, m); }
1971 
1979 template<class E>
1980 class flat_expr : public _expr<flat_expr<E> >
1981 {
1982 public:
1983  typedef typename E::Scalar Scalar;
1984  enum {ScalarValued = 0, Space = E::Space, ColBlocks= 0}; // to do: ColBlocks
1985 private:
1986  typename E::Nested_t _u;
1987  mutable gsMatrix<Scalar> tmp;
1988 
1989 public:
1990 
1991  flat_expr(_expr<E> const& u) : _u(u)
1992  {
1993  //GISMO_ASSERT( _u.rows()*_u.cols() == _n*_m, "Wrong dimension"); //
1994  }
1995 
1996  const gsMatrix<Scalar> & eval(const index_t k) const
1997  {
1998  tmp = _u.eval(k);
1999  const index_t numActives = _u.cardinality();
2000 
2001  for (index_t i = 0; i<numActives; ++i)
2002  {
2003  tmp(0,2*i+1) += tmp(1,2*i);
2004  std::swap(tmp(1,2*i), tmp(1,2*i+1));
2005  }
2006 
2007  tmp.resize(4,numActives);
2008  tmp.conservativeResize(3,numActives);
2009 
2010  if ( 1==Space )
2011  tmp.transposeInPlace();
2012  else if (2!=Space) // if not colSpan and not rowSpan
2013  tmp.transposeInPlace();
2014 
2015  return tmp;
2016  }
2017 
2018  index_t rows() const { return 1; }
2019  index_t cols() const { return 3; }
2020 
2021  void parse(gsExprHelper<Scalar> & evList) const
2022  { _u.parse(evList); }
2023 
2024  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
2025  const gsFeSpace<Scalar> & colVar() const { return _u.colVar(); }
2026  index_t cardinality_impl() const { return _u.cardinality_impl(); }
2027 
2028  void print(std::ostream &os) const { os << "flat("; _u.print(os); os<<")"; }
2029 };
2030 
2032 template <typename E> EIGEN_STRONG_INLINE
2033 flat_expr<E> const flat(E const & u)
2034 { return flat_expr<E>(u); }
2035 
2036 
2037 /*
2038  Expression for the diagonal(s) of a (matrix) expression
2039 */
2040  template<class E>
2041  class diag_expr : public _expr<diag_expr<E> >
2042  {
2043  public:
2044  typedef typename E::Scalar Scalar;
2045  enum {Space=0, ColBlocks=E::ColBlocks, ScalarValued = 0};
2046  private:
2047  typename E::Nested_t _u;
2048  mutable gsMatrix<Scalar> res;
2049 
2050  public:
2051  diag_expr(_expr<E> const& u) : _u(u)
2052  {
2053  GISMO_ASSERT(0== _u.cols()%_u.rows(), "Expecting square-block expression, got "
2054  << _u.rows() <<" x "<< _u.cols() );
2055  }
2056 
2057  const gsMatrix<Scalar> & eval(const index_t k) const
2058  {
2059  // Assume mat ??
2060  MatExprType tmp = _u.eval(k);
2061  const index_t cb = _u.rows();
2062  const index_t r = _u.cols() / cb;
2063  res.resize(r, cb);
2064  for (index_t i = 0; i!=r; ++i)
2065  res.row(i) = tmp.middleCols(i*cb,cb).diagonal();
2066  return res;
2067  }
2068 
2069  index_t rows() const { return _u.cols() / _u.rows(); }
2070  index_t cols() const { return _u.rows(); }
2071 
2072  void parse(gsExprHelper<Scalar> & evList) const
2073  { _u.parse(evList); }
2074 
2075  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
2076  const gsFeSpace<Scalar> & colVar() const { return _u.colVar(); }
2077 
2078 
2079  void print(std::ostream &os) const { os << "diag("; _u.print(os); os<<")"; }
2080  };
2081 
2083 template <typename E> EIGEN_STRONG_INLINE
2084 diag_expr<E> const diagonal(E const & u)
2085 { return diag_expr<E>(u); }
2086 
2087 #define GISMO_EXPR_VECTOR_EXPRESSION(name, mname, isSv) \
2088  template<class E> class name##_##expr : public _expr<name##_##expr<E> > { \
2089  typename E::Nested_t _u; \
2090  public: \
2091  typedef typename E::Scalar Scalar; \
2092  enum {Space= E::Space, ScalarValued= isSv, ColBlocks= E::ColBlocks}; \
2093  name##_##expr(_expr<E> const& u) : _u(u) { } \
2094  mutable Temporary_t tmp; \
2095  const Temporary_t & eval(const index_t k) const { \
2096  tmp = _u.eval(k).mname(); return tmp; } \
2097  index_t rows() const { return isSv ? 0 : _u.rows(); } \
2098  index_t cols() const { return isSv ? 0 : _u.cols(); } \
2099  void parse(gsExprHelper<Scalar> & evList) const { _u.parse(evList); } \
2100  const gsFeSpace<Scalar> & rowVar() const {return gsNullExpr<Scalar>::get();} \
2101  const gsFeSpace<Scalar> & colVar() const {return gsNullExpr<Scalar>::get();} \
2102  void print(std::ostream &os) const \
2103  { os << #name <<"("; _u.print(os); os <<")"; } \
2104  };
2105 
2107 GISMO_EXPR_VECTOR_EXPRESSION(norm,norm,1);
2109 GISMO_EXPR_VECTOR_EXPRESSION(sqNorm,squaredNorm,1);
2111 GISMO_EXPR_VECTOR_EXPRESSION(normalized,normalized,0);
2114 // GISMO_EXPR_VECTOR_EXPRESSION(cwSqr,array().square,0)
2115 // GISMO_EXPR_VECTOR_EXPRESSION(sum,array().sum,1)
2116 // GISMO_EXPR_VECTOR_EXPRESSION(sqrt,array().sqrt,0)
2117 //GISMO_EXPR_VECTOR_EXPRESSION(abs,array().abs,0)
2118 
2119 //Determinant
2120 GISMO_EXPR_VECTOR_EXPRESSION(det,determinant,1);
2121 
2122 //GISMO_EXPR_VECTOR_EXPRESSION(replicate,replicate,0);
2123 
2124 #undef GISMO_EXPR_VECTOR_EXPRESSION
2125 
2129 template<class E>
2130 class asdiag_expr : public _expr<asdiag_expr<E> >
2131 {
2132 public:
2133  typedef typename E::Scalar Scalar;
2134 private:
2135  typename E::Nested_t _u;
2136  mutable gsMatrix<Scalar> res;
2137 
2138 public:
2139  enum{Space = E::Space, ScalarValued= 0, ColBlocks= E::ColBlocks};
2140 
2141  asdiag_expr(_expr<E> const& u) : _u(u) { }
2142 
2143 public:
2144 
2145  const gsMatrix<Scalar> & eval(const index_t k) const
2146  {
2147  auto m = _u.eval(k);
2148  const index_t r = m.rows();
2149  const index_t c = m.cols();
2150  res.resize(r,r*c);
2151  for (index_t i = 0; i!=c; ++i)
2152  res.middleCols(i*r,r) = m.col(i).asDiagonal();
2153  return res;
2154  }
2155 
2156  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
2157  const gsFeSpace<Scalar> & colVar() const { return _u.colVar(); }
2158 
2159  index_t cardinality_impl() const { return _u.cardinality_impl(); }
2160 
2161  index_t rows() const { return _u.rows(); }
2162  index_t cols() const { return _u.rows() * _u.cols(); }
2163  void parse(gsExprHelper<Scalar> & evList) const
2164  { _u.parse(evList); }
2165 
2166  void print(std::ostream &os) const { os << "diag("; _u.print(os); os <<")";}
2167 };
2168 
2169 // Takes the max of a vector
2170 template<class E>
2171 class max_expr : public _expr<max_expr<E> >
2172 {
2173 public:
2174  typedef typename E::Scalar Scalar;
2175  enum {ScalarValued = 0, Space = E::Space, ColBlocks = 1};
2176 private:
2177  typename E::Nested_t _u;
2178  mutable gsMatrix<Scalar> tmp;
2179  mutable gsMatrix<Scalar> res;
2180 
2181 public:
2182 
2183  max_expr(_expr<E> const& u) : _u(u)
2184  {
2185  //GISMO_ASSERT( _u.rows()*_u.cols() == _n*_m, "Wrong dimension"); //
2186  }
2187 
2188  const gsMatrix<Scalar> & eval(const index_t k) const {return eval_impl(_u,k); }
2189 
2190  index_t rows() const { return 1; }
2191  index_t cols() const { return 1; }
2192  void setFlag() const { _u.setFlag(); }
2193 
2194  void parse(gsExprHelper<Scalar> & evList) const
2195  { _u.parse(evList); }
2196 
2197  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
2198  const gsFeSpace<Scalar> & colVar() const { return _u.colVar(); }
2199  index_t cardinality_impl() const { return _u.cardinality_impl(); }
2200 
2201  void print(std::ostream &os) const { os << "max("; _u.print(os); os<<")"; }
2202 private:
2203  template<class U> inline
2204  typename util::enable_if< util::is_same<U,gsFeSpace<Scalar> >::value, const gsMatrix<Scalar> & >::type
2205  eval_impl(const U & u, const index_t k) const
2206  {
2207  tmp = u.eval(k);
2208 
2209  res.resize(1,u.cardinality());
2210  if (E::ColBlocks)
2211  for (index_t c=0; c!=_u.cardinality(); c++)
2212  res(0,c) = tmp.block(0,c*u.cols(),u.rows(),u.cols()).maxCoeff();
2213  else
2214  for (index_t c=0; c!=_u.rows(); c++)
2215  res(0,c) = tmp.block(c*u.rows(),0,u.rows(),u.cols()).maxCoeff();
2216  return res;
2217  }
2218 
2219 
2220  template<class U> inline
2221  typename util::enable_if< !util::is_same<U,gsFeSpace<Scalar> >::value, const gsMatrix<Scalar> & >::type
2222  eval_impl(const U & u, const index_t k) const
2223  {
2224  res = u.eval(k).colwise().maxCoeff();
2225  return res;
2226  }
2227 };
2228 
2229 template<class E>
2230 class rowsum_expr : public _expr<rowsum_expr<E> >
2231 {
2232 public:
2233  typedef typename E::Scalar Scalar;
2234  enum {ScalarValued = 0, Space = E::Space, ColBlocks = E::ColBlocks};
2235 private:
2236  typename E::Nested_t _u;
2237  mutable gsMatrix<Scalar> tmp;
2238 
2239 public:
2240 
2241  rowsum_expr(_expr<E> const& u) : _u(u)
2242  {
2243  //GISMO_ASSERT( _u.rows()*_u.cols() == _n*_m, "Wrong dimension"); //
2244  }
2245 
2246  const gsMatrix<Scalar> & eval(const index_t k) const
2247  {
2248  tmp = _u.eval(k).rowwise().sum();
2249  return tmp;
2250  }
2251 
2252  index_t rows() const { return _u.rows(); }
2253  index_t cols() const { return 1; }
2254  void setFlag() const { _u.setFlag(); }
2255 
2256  void parse(gsExprHelper<Scalar> & evList) const
2257  { _u.parse(evList); }
2258 
2259  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
2260  const gsFeSpace<Scalar> & colVar() const { return _u.colVar(); }
2261  index_t cardinality_impl() const { return _u.cardinality_impl(); }
2262 
2263  void print(std::ostream &os) const { os << "rowsum("; _u.print(os); os<<")"; }
2264 };
2265 
2266 template<class E>
2267 class colsum_expr : public _expr<colsum_expr<E> >
2268 {
2269 public:
2270  typedef typename E::Scalar Scalar;
2271  enum {ScalarValued = 0, Space = E::Space, ColBlocks = E::ColBlocks};
2272 private:
2273  typename E::Nested_t _u;
2274  mutable gsMatrix<Scalar> tmp;
2275 
2276 public:
2277 
2278  colsum_expr(_expr<E> const& u) : _u(u)
2279  {
2280  //GISMO_ASSERT( _u.rows()*_u.cols() == _n*_m, "Wrong dimension"); //
2281  }
2282 
2283  const gsMatrix<Scalar> & eval(const index_t k) const
2284  {
2285  tmp = _u.eval(k).colwise().sum();
2286  return tmp;
2287  }
2288 
2289  index_t rows() const { return _u.rows(); }
2290  index_t cols() const { return 1; }
2291  void setFlag() const { _u.setFlag(); }
2292 
2293  void parse(gsExprHelper<Scalar> & evList) const
2294  { _u.parse(evList); }
2295 
2296  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
2297  const gsFeSpace<Scalar> & colVar() const { return _u.colVar(); }
2298  index_t cardinality_impl() const { return _u.cardinality_impl(); }
2299 
2300  void print(std::ostream &os) const { os << "colsum("; _u.print(os); os<<")"; }
2301 };
2302 
2306 class idMat_expr : public _expr<idMat_expr >
2307 {
2308 public:
2309  typedef real_t Scalar;
2310  enum {Space = 0, ScalarValued = 0, ColBlocks = 0};
2311 private:
2312  index_t _dim;
2313 
2314 public:
2315  idMat_expr(const index_t dim) : _dim(dim) { }
2316 
2317 public:
2318 
2320  {
2321  return gsMatrix<Scalar>::Identity(_dim,_dim);
2322  }
2323 
2324  index_t rows() const { return _dim; }
2325  index_t cols() const { return _dim; }
2326  void parse(gsExprHelper<Scalar> & ) const { }
2327 
2328  const gsFeSpace<Scalar> & rowVar() const {return gsNullExpr<Scalar>::get();}
2329  const gsFeSpace<Scalar> & colVar() const {return gsNullExpr<Scalar>::get();}
2330 
2331  void print(std::ostream &os) const { os << "id("<<_dim <<")";}
2332 };
2333 
2337 class constMat_expr : public _expr<constMat_expr >
2338 {
2339 public:
2340  typedef real_t Scalar;
2341  enum {Space = 0, ScalarValued = 0, ColBlocks = 0};
2342 private:
2343  gsMatrix<Scalar> _mat;
2344 
2345 public:
2346  constMat_expr(const gsMatrix<Scalar> mat) : _mat(mat) { }
2347 
2348 public:
2349 
2350  gsMatrix<Scalar> eval(const index_t) const
2351  {
2352  return _mat;
2353  }
2354 
2355  index_t rows() const { return _mat.rows(); }
2356  index_t cols() const { return _mat.cols(); }
2357  void parse(gsExprHelper<Scalar> & ) const { }
2358 
2359  const gsFeSpace<Scalar> & rowVar() const {return gsNullExpr<Scalar>::get();}
2360  const gsFeSpace<Scalar> & colVar() const {return gsNullExpr<Scalar>::get();}
2361 
2362  void print(std::ostream &os) const { os << "constMat";}
2363 };
2364 
2368 template<class E>
2369 class sign_expr : public _expr<sign_expr<E> >
2370 {
2371  typename E::Nested_t _u;
2372  typename E::Scalar _tol;
2373 public:
2374  typedef typename E::Scalar Scalar;
2375  enum {ScalarValued = 1, Space = E::Space, ColBlocks= 0};
2376 
2377  sign_expr(_expr<E> const& u, Scalar tolerance = 0.0) : _u(u),_tol(tolerance){
2378  GISMO_ASSERT( _tol >= 0, "Tolerance for sign_expr should be a positive number.");
2379  }
2380 
2381  Scalar eval(const index_t k) const
2382  {
2383  const Scalar v = _u.val().eval(k);
2384  return ( v>_tol ? 1 : ( v<-_tol ? -1 : 0 ) );
2385  }
2386 
2387  static index_t rows() { return 0; }
2388  static index_t cols() { return 0; }
2389 
2390  void parse(gsExprHelper<Scalar> & el) const
2391  { _u.parse(el); }
2392 
2393  static bool isScalar() { return true; }
2394 
2395  const gsFeSpace<Scalar> & rowVar() const {return gsNullExpr<Scalar>::get();}
2396  const gsFeSpace<Scalar> & colVar() const {return gsNullExpr<Scalar>::get();}
2397 
2398  void print(std::ostream &os) const { os<<"sgn("; _u.print(os); os <<")"; }
2399 };
2400 
2404 template<class E>
2405 class exp_expr : public _expr<exp_expr<E> >
2406 {
2407  typename E::Nested_t _u;
2408  public:
2409  typedef typename E::Scalar Scalar;
2410  enum {ScalarValued = 1, Space = E::Space, ColBlocks= 0};
2411 
2412  exp_expr(_expr<E> const& u) : _u(u) { }
2413 
2414  Scalar eval(const index_t k) const
2415  {
2416  const Scalar v = _u.val().eval(k);
2417  return math::exp(v);
2418  }
2419 
2420  static index_t rows() { return 0; }
2421  static index_t cols() { return 0; }
2422 
2423  void parse(gsExprHelper<Scalar> & el) const
2424  { _u.parse(el); }
2425 
2426  static bool isScalar() { return true; }
2427 
2428  const gsFeSpace<Scalar> & rowVar() const {return gsNullExpr<Scalar>::get();}
2429  const gsFeSpace<Scalar> & colVar() const {return gsNullExpr<Scalar>::get();}
2430 
2431  void print(std::ostream &os) const { os<<"exp("; _u.print(os); os <<")"; }
2432 };
2433 
2437 template<class E>
2438 class ppart_expr : public _expr<ppart_expr<E> >
2439 {
2440 public:
2441  typedef typename E::Scalar Scalar;
2442  enum {ScalarValued = E::ScalarValued, Space = E::Space, ColBlocks= E::ColBlocks};
2443 private:
2444  typename E::Nested_t _u;
2445  mutable gsMatrix<Scalar> res;
2446 public:
2447 
2448  ppart_expr(_expr<E> const& u) : _u(u) { }
2449 
2450  const gsMatrix<Scalar> & eval(index_t k) const
2451  {
2452  res = _u.eval(k).cwiseMax(0.0); // component-wise maximum with zero
2453  return res;
2454  }
2455 
2456 
2457  index_t rows() const { return _u.rows(); }
2458  index_t cols() const { return _u.cols(); }
2459 
2460  void parse(gsExprHelper<Scalar> & el) const
2461  { _u.parse(el); }
2462 
2463  const gsFeSpace<Scalar> & rowVar() const {return _u.rowVar();}
2464  const gsFeSpace<Scalar> & colVar() const {return _u.colVar();}
2465 
2466  void print(std::ostream &os) const { os<<"posPart("; _u.print(os); os <<")"; }
2467 };
2468 
2472 template<class E>
2473 class ppartval_expr : public _expr<ppartval_expr<E> >
2474 {
2475  typename E::Nested_t _u;
2476  public:
2477  typedef typename E::Scalar Scalar;
2478  enum {ScalarValued = 1, Space = 0, ColBlocks= 0};
2479  mutable Scalar res;
2480  public:
2481 
2482  ppartval_expr(_expr<E> const& u) : _u(u) { }
2483 
2484  Scalar & eval(index_t k) const
2485  {
2486  res = std::max(0.0,_u.eval(k));
2487  return res; // component-wise maximum with zero
2488  }
2489 
2490  index_t rows() const { return 0; }
2491  index_t cols() const { return 0; }
2492 
2493  void parse(gsExprHelper<Scalar> & evList) const
2494  { _u.parse(evList); }
2495 
2496  const gsFeSpace<Scalar> & rowVar() const {return gsNullExpr<Scalar>::get();}
2497  const gsFeSpace<Scalar> & colVar() const {return gsNullExpr<Scalar>::get();}
2498 
2499  void print(std::ostream &os) const { os<<"posPart("; _u.print(os); os <<")"; }
2500 };
2501 
2505 template<class E>
2506 class pow_expr : public _expr<pow_expr<E> >
2507 {
2508  typename E::Nested_t _u;
2509 
2510 public:
2511  typedef typename E::Scalar Scalar;
2512  enum {ScalarValued = 1, Space = E::Space, ColBlocks= E::ColBlocks};
2513 
2514  Scalar _q;// power
2515 
2516  pow_expr(_expr<E> const& u, Scalar q) : _u(u), _q(q) { }
2517 
2518  Scalar eval(const index_t k) const
2519  {
2520  const Scalar v = _u.val().eval(k);
2521  return math::pow(v,_q);
2522  }
2523 
2524  static index_t rows() { return 0; }
2525  static index_t cols() { return 0; }
2526 
2527  void parse(gsExprHelper<Scalar> & el) const
2528  { _u.parse(el); }
2529 
2530  static bool isScalar() { return true; }
2531 
2532  const gsFeSpace<Scalar> & rowVar() const {return gsNullExpr<Scalar>::get();}
2533  const gsFeSpace<Scalar> & colVar() const {return gsNullExpr<Scalar>::get();}
2534 
2535  void print(std::ostream &os) const { os<<"pow("; _u.print(os); os <<")"; }
2536 };
2537 
2543 template <typename E1, typename E2>
2544 class matrix_by_space_expr : public _expr<matrix_by_space_expr<E1,E2> >
2545 {
2546 public:
2547  typedef typename E1::Scalar Scalar;
2548  enum {ScalarValued = 0, ColBlocks = 1};
2549  enum {Space = E2::Space};
2550 
2551 private:
2552  typename E1::Nested_t _u;
2553  typename E2::Nested_t _v;
2554  mutable gsMatrix<Scalar> res;
2555 
2556 public:
2557  matrix_by_space_expr(E1 const& u, E2 const& v) : _u(u), _v(v) { }
2558 
2559 
2560  // choose if ColBlocks
2561  const gsMatrix<Scalar> & eval(const index_t k) const
2562  {
2563  const index_t r = _u.rows();
2564  const index_t N = _v.cols() / (r*r);
2565 
2566  const auto uEv = _u.eval(k);
2567  const auto vEv = _v.eval(k);
2568 
2569  res.resize(r, N*r*r);
2570  // gsDebugVar(res.cols());
2571  for (index_t s = 0; s!=r; ++s)
2572  for (index_t i = 0; i!=N; ++i)
2573  {
2574  res.middleCols((s*N + i)*r,r).noalias() =
2575  uEv.col(s) * vEv.middleCols((s*N + i)*r,r).row(s);
2576  //uEv*vEv.middleCols((s*N + i)*r,r);
2577  }
2578  //meaning: [Jg Jg Jg] * Jb ..
2579  return res;
2580  }
2581 
2582  index_t rows() const { return _u.cols(); }
2583  index_t cols() const { return _v.cols(); }
2584 
2585  void parse(gsExprHelper<Scalar> & evList) const
2586  { _u.parse(evList); _v.parse(evList); }
2587 
2588  const gsFeSpace<Scalar> & rowVar() const { return _v.rowVar(); }
2589  const gsFeSpace<Scalar> & colVar() const { return _v.colVar(); }
2590 
2591  void print(std::ostream &os) const { os << "matrix_by_space("; _u.print(os); os<<")"; }
2592 };
2593 
2599 template <typename E1, typename E2>
2600 class matrix_by_space_expr_tr : public _expr<matrix_by_space_expr_tr<E1,E2> >
2601 {
2602 public:
2603  typedef typename E1::Scalar Scalar;
2604  enum {ScalarValued = 0, ColBlocks = 1};
2605  enum {Space = E2::Space};
2606 
2607 private:
2608  typename E1::Nested_t _u;
2609  typename E2::Nested_t _v;
2610  mutable gsMatrix<Scalar> res;
2611 
2612 public:
2613  matrix_by_space_expr_tr(E1 const& u, E2 const& v) : _u(u), _v(v) { }
2614 
2615 
2616  // choose if ColBlocks
2617  const gsMatrix<Scalar> & eval(const index_t k) const
2618  {
2619  const index_t r = _u.rows();
2620  const index_t N = _v.cols() / (r*r);
2621 
2622  const auto uEv = _u.eval(k);
2623  const auto vEv = _v.eval(k);
2624 
2625  res.resize(r, N*r*r);
2626  for (index_t s = 0; s!=r; ++s)
2627  for (index_t i = 0; i!=N; ++i)
2628  {
2629  res.middleCols((s*N + i)*r,r).noalias() =
2630  uEv.transpose()*vEv.middleCols((s*N + i)*r,r).transpose();
2631  }
2632  //meaning: [Jg Jg Jg] * Jb ..
2633  return res;
2634  }
2635 
2636  index_t rows() const { return _u.cols(); }
2637  index_t cols() const { return _v.cols(); }
2638 
2639  void parse(gsExprHelper<Scalar> & evList) const
2640  { _u.parse(evList); _v.parse(evList); }
2641 
2642  const gsFeSpace<Scalar> & rowVar() const { return _v.rowVar(); }
2643  const gsFeSpace<Scalar> & colVar() const { return _v.colVar(); }
2644 
2645  void print(std::ostream &os) const { os << "matrix_by_space_tr("; _u.print(os); os<<")"; }
2646 };
2647 
2648 /*
2649  Adaptor for scalar-valued expression
2650 */
2651 template<class E>
2652 class value_expr : public _expr<value_expr<E> >
2653 {
2654  typename E::Nested_t _u;
2655 
2656 public:
2657  typedef typename E::Scalar Scalar;
2658  value_expr(_expr<E> const& u) : _u(u)
2659  {
2660  // rows/cols not known at construction time
2661  //GISMO_ASSERT(u.rows()*u.cols()<=1, "Expression\n"<<u<<"is not a scalar.");
2662  }
2663 
2664 public:
2665  enum {Space= 0, ScalarValued= 1, ColBlocks= 0};
2666 
2667  Scalar eval(const index_t k) const { return eval_impl(_u,k); }
2668 
2669  // enables expr.val().val()
2670  inline value_expr<E> val() const { return *this; }
2671  index_t rows() const { return 0; }
2672  index_t cols() const { return 0; }
2673  void parse(gsExprHelper<Scalar> & evList) const
2674  { _u.parse(evList); }
2675 
2676  static bool isScalar() { return true; }
2677 
2678  const gsFeSpace<Scalar> & rowVar() const {return gsNullExpr<Scalar>::get();}
2679  const gsFeSpace<Scalar> & colVar() const {return gsNullExpr<Scalar>::get();}
2680 
2681  void print(std::ostream &os) const { _u.print(os); }
2682 
2683  // Math functions. eg
2684  // sqrt_mexpr<T> sqrt() { return sqrt_mexpr<T>(*this); }
2685 private:
2686  template<class U> static inline
2687  typename util::enable_if<U::ScalarValued,Scalar>::type
2688  eval_impl(const U & u, const index_t k) { return u.eval(k); }
2689 
2690  template<class U> static inline
2691  typename util::enable_if<!U::ScalarValued,Scalar>::type
2692  eval_impl(const U & u, const index_t k) { return u.eval(k).value(); }
2693 };
2694 
2695 template<class E>
2696 class abs_expr : public _expr<abs_expr<E> >
2697 {
2698  typename E::Nested_t _u;
2699 
2700 public:
2701  typedef typename E::Scalar Scalar;
2702  explicit abs_expr(_expr<E> const& u) : _u(u) { }
2703 
2704 public:
2705  enum {Space= 0, ScalarValued= 1, ColBlocks= 0};
2706 
2707  Scalar eval(const index_t k) const { return abs_expr::eval_impl(_u,k); }
2708 
2709  index_t rows() const { return _u.rows(); }
2710  index_t cols() const { return _u.cols(); }
2711  void parse(gsExprHelper<Scalar> & evList) const
2712  { _u.parse(evList); }
2713 
2714  static bool isScalar() { return true; }
2715 
2716  const gsFeSpace<Scalar> & rowVar() const {return gsNullExpr<Scalar>::get();}
2717  const gsFeSpace<Scalar> & colVar() const {return gsNullExpr<Scalar>::get();}
2718 
2719  void print(std::ostream &os) const { _u.print(os); }
2720 
2721  // Math functions. eg
2722  // sqrt_mexpr<T> sqrt() { return sqrt_mexpr<T>(*this); }
2723 private:
2724  template<class U> static inline
2725  typename util::enable_if<U::ScalarValued,Scalar>::type
2726  eval_impl(const U & u, const index_t k) {return math::abs(u.eval(k)); }
2727  template<class U> static inline
2728  typename util::enable_if<!U::ScalarValued,gsMatrix<Scalar> >::type
2729  eval_impl(const U & u, const index_t k) { return u.eval(k).cwiseAbs(); }
2730 };
2731 
2732 /*
2733  Expression for the gradient of a finite element variable
2734 
2735  Transposed gradient vectors are returned as a matrix
2736 */
2737 template<class E>
2738 class grad_expr : public _expr<grad_expr<E> >
2739 {
2740  typename E::Nested_t _u;
2741 public:
2742  enum {Space = E::Space, ScalarValued= 0, ColBlocks= 0};
2743 
2744  typedef typename E::Scalar Scalar;
2745  mutable gsMatrix<Scalar> tmp;
2746 
2747  grad_expr(const E & u) : _u(u)
2748  { GISMO_ASSERT(1==u.dim(),"grad(.) requires 1D variable, use jac(.) instead.");}
2749 
2750  const gsMatrix<Scalar> & eval(const index_t k) const
2751  {
2752  // Assumes: derivatives are in _u.data().values[1]
2753  // gsExprHelper acounts for compositions/physical expressions
2754  // so that derivs are directly computed
2755  tmp = _u.data().values[1].reshapeCol(k, cols(), cardinality_impl()).transpose();
2756  return tmp;
2757  }
2758 
2759  index_t rows() const { return 1 /*==u.dim()*/; }
2760 
2761  index_t cols() const { return _u.source().domainDim(); }
2762 
2763  index_t cardinality_impl() const
2764  { return _u.data().values[1].rows() / cols(); }
2765 
2766  void parse(gsExprHelper<Scalar> & evList) const
2767  {
2768  evList.add(_u);
2769  _u.data().flags |= NEED_GRAD;
2770  }
2771 
2772  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
2773  const gsFeSpace<Scalar> & colVar() const
2774  {return gsNullExpr<Scalar>::get();}
2775 
2776  void print(std::ostream &os) const { os << "\u2207("; _u.print(os); os <<")"; }
2777 private:
2778 
2779  template<class U> static inline
2780  typename util::enable_if<util::is_same<U,gsComposition<Scalar> >::value,
2781  const gsMatrix<Scalar> &>::type
2782  eval_impl(const U & u, const index_t k)
2783  {
2784  return u.eval(k);
2785  }
2786 };
2787 
2788 /*
2789  \brief Expression for the gradient of a finite element variable
2790 
2791  Transposed gradient vectors are returned as a matrix.
2792  This specialization is for a gsFeSolution object
2793 */
2794 
2795 template<class T>
2796 class grad_expr<gsFeSolution<T> > : public _expr<grad_expr<gsFeSolution<T> > >
2797 {
2798 protected:
2799  const gsFeSolution<T> _u;
2800 
2801 public:
2802  typedef T Scalar;
2803  enum {Space = 0, ScalarValued= 0, ColBlocks= 0};
2804 
2805  explicit grad_expr(const gsFeSolution<T> & u) : _u(u) { }
2806 
2807  mutable gsMatrix<T> res;
2808  const gsMatrix<T> & eval(index_t k) const
2809  {
2810  GISMO_ASSERT(1==_u.data().actives.cols(), "Single actives expected");
2811 
2812  res.setZero(_u.dim(), _u.parDim());
2813  const gsDofMapper & map = _u.mapper();
2814  for (index_t c = 0; c!= _u.dim(); c++)
2815  {
2816  for (index_t i = 0; i!=_u.data().actives.size(); ++i)
2817  {
2818  const index_t ii = map.index(_u.data().actives.at(i), _u.data().patchId,c);
2819  if ( map.is_free_index(ii) ) // DoF value is in the solVector
2820  {
2821  res.row(c) += _u.coefs().at(ii) *
2822  _u.data().values[1].col(k).segment(i*_u.parDim(), _u.parDim()).transpose();
2823  }
2824  else
2825  {
2826  res.row(c) +=
2827  _u.fixedPart().at( map.global_to_bindex(ii) ) *
2828  _u.data().values[1].col(k).segment(i*_u.parDim(), _u.parDim()).transpose();
2829  }
2830  }
2831  }
2832  return res;
2833  }
2834 
2835  index_t rows() const {return _u.dim();}
2836  index_t cols() const {return _u.parDim(); }
2837 
2838  const gsFeSpace<Scalar> & rowVar() const
2839  {return gsNullExpr<Scalar>::get();}
2840  const gsFeSpace<Scalar> & colVar() const
2841  {return gsNullExpr<Scalar>::get();}
2842 
2843  void parse(gsExprHelper<Scalar> & evList) const
2844  {
2845  _u.parse(evList); // add symbol
2846  evList.add(_u.space());
2847  _u.data().flags |= NEED_GRAD|NEED_ACTIVE; // define flags
2848  }
2849 
2850  void print(std::ostream &os) const { os << "\u2207(s)"; }
2851 };
2852 
2853 /*
2854  Expression for the derivative of the jacobian of a spline geometry map,
2855  with respect to the coordinate c.
2856 
2857  It returns a matrix with the gradient of u in row d.
2858 */
2859 template<class E>
2860 class dJacdc_expr : public _expr<dJacdc_expr<E> >
2861 {
2862  typename E::Nested_t _u;
2863 public:
2864  enum{ Space = E::Space, ScalarValued = 0, ColBlocks = (1==E::Space?1:0)};
2865 
2866  typedef typename E::Scalar Scalar;
2867 
2868  mutable gsMatrix<Scalar> res;
2869  index_t _c;
2870 
2871  dJacdc_expr(const E & u, index_t c) : _u(u), _c(c)
2872  { GISMO_ASSERT(1==u.dim(),"grad(.) requires 1D variable, use jac(.) instead.");}
2873 
2874  const gsMatrix<Scalar> & eval(const index_t k) const
2875  {
2876  index_t dd = _u.source().domainDim();
2877  index_t n = _u.rows();
2878  res.setZero(dd, dd*n);
2879 
2880  gsMatrix<Scalar> grad = _u.data().values[1].reshapeCol(k, dd, n);
2881  for(index_t i = 0; i < n; i++){
2882  res.row(_c).segment(i*dd,dd) = grad.col(i);
2883  }
2884  return res;
2885  }
2886 
2887  index_t rows() const { return _u.source().domainDim(); }
2888 
2889  index_t cols() const { return _u.source().domainDim()*_u.rows(); }
2890 
2891  void parse(gsExprHelper<Scalar> & evList) const
2892  {
2893  evList.add(_u);
2894  _u.data().flags |= NEED_GRAD;
2895  }
2896 
2897  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
2898  const gsFeSpace<Scalar> & colVar() const
2899  {return gsNullExpr<Scalar>::get();}
2900 
2901  void print(std::ostream &os) const { os << "dJacdc("; _u.print(os); os <<")"; }
2902 };
2903 
2904 
2905 /*
2906  Expression for the nabla (\f$\nabla\f$) of a finite element variable,
2907 */
2908 template<class T>
2909 class nabla_expr : public _expr<nabla_expr<T> >
2910 {
2911  typename gsFeVariable<T>::Nested_t u;
2912 
2913 public:
2914  typedef T Scalar;
2915  enum{Space = 1};
2916 
2917  /* // todo
2918  nabla_expr(const gsGeometryMap<T> & G)
2919  : m_data(G.data()) { }
2920  */
2921 
2922  nabla_expr(const gsFeVariable<T> & _u) : u(_u)
2923  {
2924  //GISMO_ASSERT(u.parDim()==u.dim(),"nabla(.) requires tarDim==parDim:"
2925  // << u.parDim() <<"!="<< u.dim() <<"\n" );
2926  }
2927 
2928  mutable gsMatrix<Scalar> res;
2929 
2930  const gsMatrix<Scalar> & eval(const index_t k) const
2931  {
2932  const index_t d = u.cols();
2933  const index_t n = rows() / d;
2934  res.setZero(rows(), d);
2935 
2936  for (index_t i = 0; i!=d; ++i)
2937  res.col(i).segment(i*n,n) = u.data().values[1].reshapeCol(k, d, n).row(i);
2938  return res;
2939  }
2940 
2941  index_t rows() const { return u.rows(); }
2942  index_t cols() const { return u.cols(); }
2943 
2944  void parse(gsExprHelper<Scalar> & evList) const
2945  {
2946  evList.add(u);
2947  u.data().flags |= NEED_GRAD;
2948  }
2949 
2950  const gsFeSpace<T> & rowVar() const { return u.rowVar(); }
2951  const gsFeSpace<T> & colVar() const
2952  {return gsNullExpr<Scalar>::get();}
2953 
2954  void print(std::ostream &os) const { os << "nabla("; u.print(os); os <<")"; }
2955 };
2956 
2957 /*
2958  Expression for the nabla2 (\f$\nabla^2\f$ or Del2) of a finite element variable,
2959  see also https://en.wikipedia.org/wiki/Del
2960 
2961  Transposed pure second derivatives are returned as a matrix
2962 */
2963 template<class T>
2964 class nabla2_expr : public _expr<nabla2_expr<T> >
2965 {
2966  typename gsFeVariable<T>::Nested_t u;
2967 
2968 public:
2969  typedef T Scalar;
2970  enum{Space = 1};
2971 
2972  /* // todo
2973  nabla2_expr(const gsGeometryMap<T> & G)
2974  : m_data(G.data()) { }
2975  */
2976 
2977  nabla2_expr(const gsFeVariable<T> & _u)
2978  : u(_u)
2979  { }
2980 
2981  MatExprType eval(const index_t k) const
2982  {
2983  // numActive x parDim
2984  return u.data().values[2]
2985  .reShapeCol(k, u.data().values[2].rows()/u.cSize(), u.cSize() )
2986  .topRows(u.parDim()).transpose();
2987  }
2988 
2989  index_t rows() const { return u.rows(); }
2990  index_t cols() const { return u.parDim(); }
2991 
2992  void parse(gsExprHelper<Scalar> & evList) const
2993  {
2994  evList.add(u);
2995  u.data().flags |= NEED_DERIV2;
2996  }
2997 
2998  const gsFeSpace<T> & rowVar() const { return u.rowVar(); }
2999  const gsFeSpace<T> & colVar() const
3000  {return gsNullExpr<T>::get();}
3001 };
3002 
3004 template<class T>
3005 nabla2_expr<T> nabla2(const gsFeVariable<T> & u) { return nabla2_expr<T>(u); }
3006 // #define lapl(x) nabla2(x).sum() // assume tarDim==1
3007 
3012 template<class T>
3013 class onormal_expr : public _expr<onormal_expr<T> >
3014 {
3015  typename gsGeometryMap<T>::Nested_t _G;
3016 
3017 public:
3018  typedef T Scalar;
3019  enum {Space = 0, ScalarValued= 0, ColBlocks= 0};
3020 
3021  explicit onormal_expr(const gsGeometryMap<T> & G) : _G(G) { }
3022 
3023  auto eval(const index_t k) const -> decltype(_G.data().outNormals.col(k))
3024  { return _G.data().outNormals.col(k); }
3025 
3026  index_t rows() const { return _G.source().targetDim(); }
3027  index_t cols() const { return 1; }
3028 
3029  const gsFeSpace<T> & rowVar() const {return gsNullExpr<T>::get();}
3030  const gsFeSpace<T> & colVar() const {return gsNullExpr<T>::get();}
3031 
3032  void parse(gsExprHelper<Scalar> & evList) const
3033  {
3034  evList.add(_G);
3035  _G.data().flags |= NEED_OUTER_NORMAL;
3036  }
3037 
3038  void print(std::ostream &os) const { os << "nv("; _G.print(os); os <<")"; }
3039 };
3040 
3045 template<class T>
3046 class normal_expr : public _expr<normal_expr<T> >
3047 {
3048  typename gsGeometryMap<T>::Nested_t _G;
3049 
3050 public:
3051  typedef T Scalar;
3052  enum {Space = 0, ScalarValued= 0, ColBlocks= 0};
3053 
3054  normal_expr(const gsGeometryMap<T> & G) : _G(G)
3055  {
3056  GISMO_ENSURE( _G.source().domainDim()+1 == _G.source().targetDim(), "Surface normal requires codimension 1");
3057  }
3058 
3059  auto eval(const index_t k) const -> decltype(_G.data().normals.col(k))
3060  { return _G.data().normals.col(k); }
3061 
3062  index_t rows() const { return _G.source().targetDim(); }
3063  index_t cols() const { return 1; }
3064 
3065  const gsFeSpace<T> & rowVar() const {return gsNullExpr<T>::get();}
3066  const gsFeSpace<T> & colVar() const {return gsNullExpr<T>::get();}
3067 
3068  void parse(gsExprHelper<Scalar> & evList) const
3069  {
3070  evList.add(_G);
3071  _G.data().flags |= NEED_NORMAL;
3072  }
3073 
3074  void print(std::ostream &os) const { os << "sn("; _G.print(os); os <<")"; }
3075 };
3076 
3081 template<class T>
3082 class tangent_expr : public _expr<tangent_expr<T> >
3083 {
3084  typename gsGeometryMap<T>::Nested_t _G;
3085 
3086 public:
3087  typedef T Scalar;
3088  enum {Space = 0, ScalarValued= 0, ColBlocks= 0};
3089 
3090  tangent_expr(const gsGeometryMap<T> & G) : _G(G) { }
3091 
3092  mutable gsVector<Scalar> res;
3093  const gsVector<Scalar> & eval(const index_t k) const
3094  {
3095  if (_G.targetDim()==2)
3096  {
3097  res = _G.data().outNormals.col(k);//2x1
3098  std::swap( res(0,0), res(1,0) );
3099  res(0,0) *= -1;
3100  return res;
3101  }
3102  else if (_G.targetDim()==3)
3103  {
3104  res.resize(3);
3105  res.col3d(0) = _G.data().normals.col3d(k)
3106  .cross( _G.data().outNormals.col3d(k) );
3107  return res;
3108  }
3109  else
3110  GISMO_ERROR("Function not implemented for dimension"<<_G.targetDim());
3111 
3112  }
3113 
3114  index_t rows() const { return _G.source().targetDim(); }
3115  index_t cols() const { return 1; }
3116 
3117  static const gsFeSpace<Scalar> & rowVar() {return gsNullExpr<Scalar>::get();}
3118  static const gsFeSpace<Scalar> & colVar() {return gsNullExpr<Scalar>::get();}
3119 
3120  void parse(gsExprHelper<Scalar> & evList) const
3121  {
3122  evList.add(_G);
3123  _G.data().flags |= NEED_NORMAL;
3124  _G.data().flags |= NEED_OUTER_NORMAL;
3125  }
3126 
3127  void print(std::ostream &os) const { os << "tv("; _G.print(os); os <<")"; }
3128 };
3129 
3133 template<class E>
3134 class lapl_expr : public _expr<lapl_expr<E> >
3135 {
3136  typename E::Nested_t _u;
3137 
3138 public:
3139  typedef typename E::Scalar Scalar;
3140  enum {Space = E::Space, ScalarValued= 0, ColBlocks= 0};
3141 
3142  lapl_expr(const E & u) : _u(u) { }
3143 
3144  auto eval(const index_t k) const -> decltype(_u.data().laplacians.col(k))
3145  {
3146  // numActive x 1
3147  return _u.data().laplacians.col(k);
3148  //todo: replace by
3149  // NEED_DERIV2
3150  // ..nabla2.sum()
3151  }
3152 
3153  index_t rows() const { return _u.data().laplacians.rows(); }
3154  index_t cols() const { return 1; }
3155 
3156  index_t cardinality_impl() const { return _u.cardinality_impl(); }
3157 
3158  void parse(gsExprHelper<Scalar> & evList) const
3159  {
3160  evList.add(_u);
3161  _u.data().flags |= NEED_LAPLACIAN;
3162  }
3163 
3164  static const gsFeSpace<Scalar> & rowVar() {return E::rowVar();}
3165  static const gsFeSpace<Scalar> & colVar() {return gsNullExpr<Scalar>::get();}
3166 
3167  void print(std::ostream &os) const { os << "\u2206("; _u.print(os); os <<")"; } //or \u0394
3168 };
3169 
3170 /*
3171  Expression for the Laplacian of a finite element solution
3172 */
3173 template<class T>
3174 class lapl_expr<gsFeSolution<T> > : public _expr<lapl_expr<gsFeSolution<T> > >
3175 {
3176 protected:
3177  const gsFeSolution<T> _u;
3178 
3179 public:
3180  typedef T Scalar;
3181  enum {Space = 0, ScalarValued= 0, ColBlocks= 0};
3182 
3183  lapl_expr(const gsFeSolution<T> & u) : _u(u) { }
3184 
3185  mutable gsMatrix<T> res;
3186  const gsMatrix<T> & eval(const index_t k) const
3187  {
3188  GISMO_ASSERT(1==_u.data().actives.cols(), "Single actives expected");
3189 
3190  res.setZero(_u.dim(), 1); // scalar, but per component
3191  const gsDofMapper & map = _u.mapper();
3192 
3193  index_t numActs = _u.data().values[0].rows();
3194  index_t numDers = _u.parDim() * (_u.parDim() + 1) / 2;
3195  gsMatrix<T> deriv2;
3196 
3197  for (index_t c = 0; c!= _u.dim(); c++)
3198  for (index_t i = 0; i!=numActs; ++i)
3199  {
3200  const index_t ii = map.index(_u.data().actives.at(i), _u.data().patchId,c);
3201  deriv2 = _u.data().values[2].block(i*numDers,k,_u.parDim(),1); // this only takes d11, d22, d33 part. For all the derivatives [d11, d22, d33, d12, d13, d23]: col.block(i*numDers,k,numDers,1)
3202  if ( map.is_free_index(ii) ) // DoF value is in the solVector
3203  res.at(c) += _u.coefs().at(ii) * deriv2.sum();
3204  else
3205  res.at(c) +=_u.fixedPart().at( map.global_to_bindex(ii) ) * deriv2.sum();
3206  }
3207  return res;
3208  }
3209 
3210  index_t rows() const { return _u.dim(); }
3211  index_t cols() const { return 1; }
3212 
3213  void parse(gsExprHelper<Scalar> & evList) const
3214  {
3215  evList.add(_u.space());
3216  _u.data().flags |= NEED_ACTIVE | NEED_DERIV2;
3217  }
3218 
3219  const gsFeSpace<Scalar> & rowVar() const {return gsNullExpr<T>::get();}
3220  const gsFeSpace<Scalar> & colVar() const {return gsNullExpr<T>::get();}
3221 
3222  void print(std::ostream &os) const { os << "\u2206(s)"; }
3223 };
3224 
3225 /*
3226  Expression for the (precomputed) second fundamental form of a surface
3227 */
3228 template<class T>
3229 class fform2nd_expr : public _expr<fform2nd_expr<T> >
3230 {
3231  typename gsGeometryMap<T>::Nested_t _G;
3232 public:
3233  typedef T Scalar;
3234  enum {Space = 0, ScalarValued = 0, ColBlocks = 0};
3235 
3236  fform2nd_expr(const gsGeometryMap<T> & G) : _G(G) { }
3237 
3238  const gsAsConstMatrix<Scalar> eval(const index_t k) const
3239  {
3240  return gsAsConstMatrix<Scalar>(_G.data().fundForms.col(k).data(),rows(),cols());
3241  }
3242 
3243  index_t rows() const { return _G.source().domainDim() ; }
3244  index_t cols() const { return _G.source().domainDim() ; }
3245 
3246  void parse(gsExprHelper<Scalar> & evList) const
3247  {
3248  evList.add(_G);
3249  _G.data().flags |= NEED_2ND_FFORM;
3250  }
3251 
3252  const gsFeSpace<Scalar> & rowVar() const {return gsNullExpr<T>::get();}
3253  const gsFeSpace<Scalar> & colVar() const {return gsNullExpr<T>::get();}
3254 
3255  void print(std::ostream &os) const { os << "fform2nd("; _G.print(os); os <<")"; }
3256 };
3257 
3258 /*
3259  Expression for the (precomputed) inverse of the Jacobian matrix of
3260  a geometry map
3261 */
3262 template<class T>
3263 class jacInv_expr : public _expr<jacInv_expr<T> >
3264 {
3265  typename gsGeometryMap<T>::Nested_t _G;
3266 public:
3267  typedef T Scalar;
3268  enum {Space = 0, ScalarValued = 0, ColBlocks = 0};
3269 
3270  jacInv_expr(const gsGeometryMap<T> & G) : _G(G)
3271  {
3272  // Note: for non-square Jacobian matrices, generalized inverse, i.e.: (J^t J)^{-t} J^t
3273  //GISMO_ASSERT(rows() == cols(), "The Jacobian matrix is not square");
3274  }
3275 
3276  MatExprType eval(const index_t k) const { return _G.data().jacInvTr.reshapeCol(k,cols(),rows()).transpose(); }
3277 
3278  index_t rows() const { return _G.source().domainDim(); }
3279  index_t cols() const { return _G.source().targetDim(); }
3280 
3281  void parse(gsExprHelper<Scalar> & evList) const
3282  {
3283  evList.add(_G);
3284  _G.data().flags |= NEED_GRAD_TRANSFORM;
3285  }
3286 
3287  const gsFeSpace<Scalar> & rowVar() const {return gsNullExpr<T>::get();}
3288  const gsFeSpace<Scalar> & colVar() const {return gsNullExpr<T>::get();}
3289 
3290  // todo mat_expr ?
3291  // tr() const --> _G.data().fundForm(k)
3292 
3293  void print(std::ostream &os) const { os << "jacInv("; _G.print(os); os <<")"; }
3294 };
3295 
3296 /*
3297  Expression for the Jacobian matrix of a FE variable
3298 */
3299 template<class E>
3300 class jac_expr : public _expr<jac_expr<E> >
3301 {
3302  typename E::Nested_t _u;
3303 public:
3304  enum {ColBlocks = (1==E::Space?1:0) };
3305  enum {Space = E::Space, ScalarValued= 0 };
3306 
3307  typedef typename E::Scalar Scalar;
3308 
3309  mutable gsMatrix<Scalar> res;
3310 
3311  jac_expr(const E & _u_)
3312  : _u(_u_) { }
3313 
3314  MatExprType eval(const index_t k) const
3315  {
3316  if (0!=Space)
3317  {
3318  // Dim x (numActive*Dim)
3319  res = _u.data().values[1].col(k).transpose().blockDiag(_u.dim());
3320  }
3321  else
3322  {
3323  res = _u.data().values[1]
3324  .reshapeCol(k, _u.parDim(), _u.targetDim()).transpose()
3325  .blockDiag(_u.dim());
3326  }
3327  return res;
3328  }
3329 
3330  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
3331  //const gsFeSpace<Scalar> & rowVar() const { return rowVar_impl<E>(); }
3332  const gsFeSpace<Scalar> & colVar() const { return gsNullExpr<Scalar>::get(); }
3333 
3334  index_t rows() const { return rows_impl(_u); }
3335  index_t cols() const { return cols_impl(_u); }
3336 
3337  // index_t rows() const { return _u.dim(); }
3338  // index_t cols() const { return _u.source().domainDim(); }
3339 
3340  index_t cardinality_impl() const
3341  {
3342  return _u.dim() * _u.data().actives.rows();
3343  }
3344 
3345  void parse(gsExprHelper<Scalar> & evList) const
3346  {
3347  evList.add(_u);
3348  _u.data().flags |= NEED_DERIV|NEED_ACTIVE;
3349  //note: cardinality() depends on actives
3350  }
3351 
3352  void print(std::ostream &os) const { os << "\u2207("; _u.print(os);os <<")"; }
3353 
3354 private:
3355 
3356  // The jacobian is different for gsFeVariable, gsFeSolution and gsFeSpace
3357  // gsFeSolution: Does not work
3358  // gsFeVariable: dim()=1 and source().targetDim()=d
3359  // gsFeSpace: dim()=d and source().targetDim()=1
3360  template<class U> inline
3361  typename util::enable_if<!(util::is_same<U,gsFeSpace<Scalar> >::value), index_t >::type // What about solution??
3362  rows_impl(const U & u) const
3363  {
3364  return u.source().targetDim();
3365  }
3366 
3367  template<class U> inline
3368  typename util::enable_if< (util::is_same<U,gsFeSpace<Scalar> >::value), index_t >::type
3369  rows_impl(const U & u) const
3370  {
3371  return u.dim();
3372  }
3373 
3374  template<class U> inline
3375  typename util::enable_if<!(util::is_same<U,gsFeSpace<Scalar> >::value), index_t >::type
3376  cols_impl(const U & u) const
3377  {
3378  return u.source().domainDim();
3379  }
3380 
3381  template<class U> inline
3382  typename util::enable_if< (util::is_same<U,gsFeSpace<Scalar> >::value), index_t >::type
3383  cols_impl(const U & u) const
3384  {
3385  return u.source().domainDim();
3386  }
3387 
3388  // The jacobian is different for gsFeVariable, gsFeSolution and gsFeSpace
3389  // gsFeSolution: Does not work
3390  // gsFeVariable: rowVar = NULL
3391  // gsFeSpace: rowVar = u
3392  template<class U> inline
3393  typename util::enable_if<!(util::is_same<U,gsFeSpace<Scalar> >::value), const gsFeSpace<Scalar> & >::type
3394  rowVar_impl() const
3395  {
3396  return gsNullExpr<Scalar>::get();
3397  }
3398 
3399  template<class U> inline
3400  typename util::enable_if<(util::is_same<U,gsFeSpace<Scalar> >::value), const gsFeSpace<Scalar> & >::type
3401  rowVar_impl() const
3402  {
3403  return _u;
3404  }
3405 };
3406 
3407 /*
3408  Expression for the Jacobian matrix of a geometry map
3409 */
3410 template<class T>
3411 class jac_expr<gsGeometryMap<T> > : public _expr<jac_expr<gsGeometryMap<T> > >
3412 {
3413  typename gsGeometryMap<T>::Nested_t _G;
3414 
3415 public:
3416  typedef T Scalar;
3417  enum {Space = 0, ScalarValued= 0, ColBlocks= 0};
3418 
3419  jac_expr(const gsGeometryMap<T> & G) : _G(G) { }
3420  MatExprType eval(const index_t k) const
3421  {
3422  // TarDim x ParDim
3423  return _G.data().values[1]
3424  .reshapeCol(k, _G.data().dim.first, _G.data().dim.second).transpose();
3425  }
3426 
3427  index_t rows() const { return _G.source().targetDim(); }
3428 
3429  index_t cols() const { return _G.source().domainDim(); }
3430 
3431  static const gsFeSpace<Scalar> & rowVar() { return gsNullExpr<Scalar>::get(); }
3432  static const gsFeSpace<Scalar> & colVar() { return gsNullExpr<Scalar>::get(); }
3433 
3434  void parse(gsExprHelper<Scalar> & evList) const
3435  {
3436  evList.add(_G);
3437  _G.data().flags |= NEED_DERIV;
3438  }
3439 
3440  meas_expr<T> absDet() const
3441  {
3442  GISMO_ASSERT(rows() == cols(), "The Jacobian matrix is not square");
3443  return meas_expr<T>(_G);
3444  }
3445 
3446  jacInv_expr<T> inv() const
3447  {
3448  GISMO_ASSERT(rows() == cols(), "The Jacobian matrix is not square");
3449  return jacInv_expr<T>(_G);
3450  }
3451 
3453  jacInv_expr<T> ginv() const { return jacInv_expr<T>(_G); }
3454 
3455  void print(std::ostream &os) const { os << "\u2207("; _G.print(os); os <<")"; }
3456 };
3457 
3458 template<class E>
3459 class hess_expr : public _expr<hess_expr<E> >
3460 {
3461 public:
3462  typedef typename E::Scalar Scalar;
3463 private:
3464  typename E::Nested_t _u;
3465  mutable gsMatrix<Scalar> res;
3466 public:
3467  enum {ScalarValued = 0, ColBlocks = (1==E::Space?1:0) };
3468  enum {Space = E::Space };
3469 
3470 public:
3471  hess_expr(const E & u) : _u(u)
3472  {
3473  //gsInfo << "\n-expression is space ? "<<E::Space <<"\n"; _u.print(gsInfo);
3474  //GISMO_ASSERT(1==_u.dim(),"hess(.) requires 1D variable");
3475  }
3476 
3477  const gsMatrix<Scalar> & eval(const index_t k) const
3478  {
3479  const gsFuncData<Scalar> & dd = _u.data();
3480  const index_t sz = cardinality_impl();
3481  res.resize(dd.dim.first, sz*dd.dim.first);
3482  secDerToHessian(dd.values[2].col(k), dd.dim.first, res);
3483  res.resize(dd.dim.first, res.cols()*dd.dim.first);
3484  // Note: auto returns by value here,
3485  // in C++11 we may add in -> decltype(res) &
3486  return res;
3487  }
3488 
3489  index_t rows() const { return _u.data().dim.first; }
3490  index_t cols() const
3491  { return rows();
3492  //return 2*_u.data().values[2].rows() / (1+_u.data().dim.first);
3493  }
3494 
3495  index_t cardinality_impl() const
3496  {
3497  return 2*_u.data().values[2].rows()/
3498  (_u.data().dim.first*(1+_u.data().dim.first));
3499  //gsDebugVar(_u.data().values.front().rows());//empty!
3500  }
3501 
3502  void parse(gsExprHelper<Scalar> & evList) const
3503  {
3504  evList.add(_u);
3505  _u.data().flags |= NEED_2ND_DER;
3506  }
3507 
3508  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
3509  const gsFeSpace<Scalar> & colVar() const { return gsNullExpr<Scalar>::get(); }
3510 
3511  void print(std::ostream &os) const
3512  // { os << "hess("; _u.print(os);os <<")"; }
3513  { os << "\u210D(U)"; }
3514 };
3515 
3516 template<class T>
3517 class hess_expr<gsFeSolution<T> > : public _expr<hess_expr<gsFeSolution<T> > >
3518 {
3519 protected:
3520  const gsFeSolution<T> _u;
3521 
3522 public:
3523  typedef T Scalar;
3524  enum{Space = 0, ScalarValued = 0, ColBlocks = 0 };
3525 
3526  hess_expr(const gsFeSolution<T> & u) : _u(u) { }
3527 
3528  mutable gsMatrix<T> res;
3529  const gsMatrix<T> & eval(const index_t k) const
3530  {
3531  GISMO_ASSERT(1==_u.data().actives.cols(), "Single actives expected. Actives: \n"<<_u.data().actives);
3532 
3533  const gsDofMapper & map = _u.mapper();
3534 
3535  const index_t numActs = _u.data().values[0].rows();
3536  const index_t pdim = _u.parDim();
3537  index_t numDers = pdim*(pdim+1)/2;
3538  gsMatrix<T> deriv2;
3539 
3540  // In the scalar case, the hessian is returned as a pdim x pdim matrix
3541  if (1==_u.dim())
3542  {
3543  res.setZero(numDers,1);
3544  for (index_t i = 0; i!=numActs; ++i)
3545  {
3546  const index_t ii = map.index(_u.data().actives.at(i), _u.data().patchId,0);
3547  deriv2 = _u.data().values[2].block(i*numDers,k,numDers,1);
3548  if ( map.is_free_index(ii) ) // DoF value is in the solVector
3549  res += _u.coefs().at(ii) * deriv2;
3550  else
3551  res +=_u.fixedPart().at( map.global_to_bindex(ii) ) * deriv2;
3552  }
3553  secDerToHessian(res, pdim, deriv2);
3554  res.swap(deriv2);
3555  res.resize(pdim,pdim);
3556  }
3557  // In the vector case, the hessian is returned as a matrix where each row corresponds to the component of the solution and contains the derivatives in the columns
3558  else
3559  {
3560  res.setZero(rows(), numDers);
3561  for (index_t c = 0; c != _u.dim(); c++)
3562  for (index_t i = 0; i != numActs; ++i) {
3563  const index_t ii = map.index(_u.data().actives.at(i), _u.data().patchId, c);
3564  deriv2 = _u.space().data().values[2].block(i * numDers, k, numDers,
3565  1).transpose(); // start row, start col, rows, cols
3566  if (map.is_free_index(ii)) // DoF value is in the solVector
3567  res.row(c) += _u.coefs().at(ii) * deriv2;
3568  else
3569  res.row(c) += _u.fixedPart().at(map.global_to_bindex(ii)) * deriv2;
3570  }
3571  }
3572  return res;
3573  }
3574 
3575  index_t rows() const
3576  {
3577  if (1==_u.dim())
3578  return _u.parDim();
3579  else
3580  return _u.dim(); // number of components
3581  }
3582  index_t cols() const
3583  {
3584  if (1==_u.dim())
3585  return _u.parDim();
3586  // second derivatives in the columns; i.e. [d11, d22, d33, d12, d13, d23]
3587  else
3588  return _u.parDim() * (_u.parDim() + 1) / 2;
3589  }
3590 
3591  const gsFeSpace<Scalar> & rowVar() const { return gsNullExpr<Scalar>::get(); }
3592  const gsFeSpace<Scalar> & colVar() const { return gsNullExpr<Scalar>::get(); }
3593 
3594  void parse(gsExprHelper<Scalar> & evList) const
3595  {
3596  _u.parse(evList); // add symbol
3597  evList.add(_u.space());
3598  _u.data().flags |= NEED_ACTIVE | NEED_VALUE | NEED_DERIV2;
3599  }
3600 
3601  void print(std::ostream &os) const { os << "\u210D(s)"; }
3602 };
3603 
3604 
3605 /*
3606  Expression for the partial derivative (matrices) of the Jacobian
3607  matrix of the geometry map
3608 */
3609 template<class T>
3610 class dJacG_expr : public _expr<dJacG_expr<T> >
3611 {
3612  typename gsGeometryMap<T>::Nested_t _G;
3613 
3614  mutable gsMatrix<T> res;
3615 public:
3616  typedef T Scalar;
3617 
3618  dJacG_expr(const gsGeometryMap<T> & G) : _G(G) { }
3619 
3620  MatExprType eval(const index_t k) const
3621  {
3622  const index_t sz = _G.data().values[0].rows();
3623  const index_t s = _G.data().derivSize(); //dim.first*(_G.data().dim.first+1)/2;
3624  (void)s;
3625  res.resize(_G.data().dim.second, sz*_G.data().dim.first);
3626  res.setOnes();//_G.data().values[2].segment(i*k,k); // todo
3627  return res;
3628  }
3629 
3630  index_t rows() const { return _G.source().targetDim(); }
3631  index_t cols() const { return _G.source().domainDim(); }
3632 
3633  void parse(gsExprHelper<Scalar> & evList) const
3634  {
3635  evList.add(_G);
3636  _G.data().flags |= NEED_2ND_DER;
3637  }
3638 };
3639 
3640 
3641 /*
3642  Expression for the curl
3643 */
3644 template<class T>
3645 class curl_expr : public _expr<curl_expr<T> >
3646 {
3647 public:
3648  typedef T Scalar;
3649 private:
3650  typename gsFeVariable<T>::Nested_t _u;
3651  mutable gsMatrix<Scalar> res;
3652 public:
3653  enum{ Space = 1, ScalarValued= 0, ColBlocks= 0};
3654 
3655  curl_expr(const gsFeVariable<T> & u) : _u(u)
3656  { GISMO_ASSERT(3==u.dim(),"curl(.) requires 3D variable."); }
3657 
3658  const gsMatrix<T> & eval(const index_t k) const
3659  {
3660  res.setZero( rows(), _u.dim());
3661  const index_t na = _u.data().values[0].rows();
3662  gsAsConstMatrix<T, Dynamic, Dynamic> pd =
3663  _u.data().values[1].reshapeCol(k, cols(), na);
3664 
3665  res.col(0).segment(na ,na) = -pd.row(2);
3666  res.col(0).segment(2*na,na) = pd.row(1);
3667  res.col(1).segment(0 ,na) = pd.row(2);
3668  res.col(1).segment(2*na,na) = -pd.row(0);
3669  res.col(2).segment(0 ,na) = -pd.row(1);
3670  res.col(2).segment(na ,na) = pd.row(0);
3671  return res;
3672  }
3673 
3674  index_t rows() const { return _u.dim() * _u.data().values[0].rows(); }
3675  index_t cols() const { return _u.data().dim.first; }
3676 
3677  void parse(gsExprHelper<Scalar> & evList) const
3678  {
3679  evList.add(_u);
3680  _u.data().flags |= NEED_GRAD;
3681  }
3682 
3683  const gsFeSpace<T> & rowVar() const { return _u.rowVar(); }
3684  const gsFeSpace<T> & colVar() const {return gsNullExpr<T>::get();}
3685 
3686  void print(std::ostream &os) const { os << "curl("; _u.print(os); os <<")"; }
3687 };
3688 
3689 /*
3690  Expression for multiplication operation (first version)
3691 
3692  First argument E1 has ColBlocks = false
3693 
3694  Partial specialization for (right) blockwise multiplication
3695 
3696  B * [A1 A2 A3] = [B*A1 B*A2 B*A3]
3697 
3698 */
3699 template <typename E1, typename E2>
3700 class mult_expr<E1,E2,false> : public _expr<mult_expr<E1, E2, false> >
3701 {
3702  typename E1::Nested_t _u;
3703  typename E2::Nested_t _v;
3704 
3705 public:
3706  enum {ScalarValued = E1::ScalarValued && E2::ScalarValued,
3707  ColBlocks = E2::ColBlocks};
3708  enum {Space = (int)E1::Space + (int)E2::Space };
3709 
3710  typedef typename E1::Scalar Scalar;
3711 
3712  mult_expr(_expr<E1> const& u,
3713  _expr<E2> const& v)
3714  : _u(u), _v(v) { }
3715 
3716  mutable Temporary_t tmp;
3717  const Temporary_t & eval(const index_t k) const
3718  {
3719  GISMO_ASSERT(0==_u.cols()*_v.rows() || _u.cols() == _v.rows(),
3720  "Wrong dimensions "<<_u.cols()<<"!="<<_v.rows()<<" in * operation:\n"
3721  << _u <<" times \n" << _v );
3722 
3723  // Note: a * b * c --> (a*b).eval()*c
3724  tmp = _u.eval(k) * _v.eval(k);
3725  return tmp; // assumes result is not scalarvalued
3726  }
3727 
3728  index_t rows() const { return E1::ScalarValued ? _v.rows() : _u.rows(); }
3729  index_t cols() const { return E2::ScalarValued ? _u.cols() : _v.cols(); }
3730  void parse(gsExprHelper<Scalar> & evList) const
3731  { _u.parse(evList); _v.parse(evList); }
3732 
3733 
3734  index_t cardinality_impl() const
3735  { return 0==E1::Space ? _v.cardinality(): _u.cardinality(); }
3736 
3737  const gsFeSpace<Scalar> & rowVar() const
3738  { return 0==E1::Space ? _v.rowVar() : _u.rowVar(); }
3739  const gsFeSpace<Scalar> & colVar() const
3740  { return 0==E2::Space ? _u.colVar() : _v.colVar(); }
3741 
3742  void print(std::ostream &os) const { _u.print(os); os<<"*"; _v.print(os); }
3743 };
3744 
3745 /*
3746  Expression for multiplication operation (second version)
3747 
3748  First argument E1 has ColBlocks = true
3749 
3750  Partial specialization for (right) blockwise multiplication
3751  [A1 A2 A3] * B = [A1*B A2*B A3*B]
3752 
3753  as well as
3754 
3755  both are ColBlocks: [A1 A2 A3] * [B1 B2 B3] = [A1*B1 A2*B2 A3*B3]
3756  [A2*B1 .. ]
3757  [ ]
3758 */
3759 template <typename E1, typename E2>
3760 class mult_expr<E1, E2, true> : public _expr<mult_expr<E1, E2, true> >
3761 {
3762 public:
3763  typedef typename E2::Scalar Scalar;
3764 private:
3765  typename E1::Nested_t _u;
3766  typename E2::Nested_t _v;
3767 
3768  mutable gsMatrix<Scalar> res;
3769 public:
3770  enum {ScalarValued = 0, ColBlocks = E1::ColBlocks}; //(!)
3771  enum {Space = (int)E1::Space + (int)E2::Space };
3772 
3773  mult_expr(_expr<E1> const& u,
3774  _expr<E2> const& v)
3775  : _u(u), _v(v)
3776  {
3777 
3778  }
3779 
3780  const gsMatrix<Scalar> & eval(const index_t k) const
3781  {
3782  const index_t uc = _u.cols();
3783  const index_t ur = _u.rows();
3784  const index_t nb = _u.cardinality();
3785  const auto tmpA = _u.eval(k);
3786  const auto tmpB = _v.eval(k);
3787 
3788  const index_t vc = _v.cols();
3789 
3790  // either _v.cardinality()==1 or _v.cardinality()==_u.cardinality()
3791  if ( 1 == _v.cardinality() ) //second is not ColBlocks
3792  {
3793  res.resize(ur, vc*nb);
3794  GISMO_ASSERT(tmpA.cols()==uc*nb, "Dimension error.. "<< tmpA.cols()<<"!="<<uc*nb );
3795  GISMO_ASSERT(1==_v.cardinality(), "Dimension error");
3796  //gsInfo<<"cols = "<<res.cols()<<"; rows = "<<res.rows()<<"\n";
3797  for (index_t i = 0; i!=nb; ++i)
3798  res.middleCols(i*vc,vc).noalias()
3799  = tmpA.middleCols(i*uc,uc) * tmpB;
3800  }
3801  // both are ColBlocks: [A1 A2 A3] * [B1 B2 B3] = [A1*B1 A2*B2 A3*B3]
3802  // [A2*B1 .. ]
3803  // [ ]
3804  else
3805  {
3806  const index_t nbv = _v.cardinality();
3807  res.resize(ur*nb, vc*nbv);
3808  for (index_t i = 0; i!=nb; ++i)
3809  for (index_t j = 0; j!=nbv; ++j)
3810  {
3811  res.block(i*ur,j*vc,ur,vc).noalias() =
3812  tmpA.middleCols(i*uc,uc) * tmpB.middleCols(j*vc,vc);
3813  // res.middleCols(i*vc,vc).noalias()
3814  // = tmpA.middleCols(i*uc,uc) * tmpB.middleCols(i*vc,vc);
3815  }
3816  }
3817  return res;
3818  }
3819 
3820  index_t rows() const {
3821  return _u.rows();
3822  }
3823  index_t cols() const {
3824  return _v.cols();
3825  }
3826 
3827  void parse(gsExprHelper<Scalar> & evList) const
3828  { _u.parse(evList); _v.parse(evList); }
3829 
3830 
3831  index_t cardinality_impl() const { return _u.cardinality(); }
3832 
3833  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
3834  const gsFeSpace<Scalar> & colVar() const
3835  {
3836  if ( 1 == _v.cardinality() )
3837  return _u.colVar();
3838  else
3839  return _v.colVar();
3840  }
3841 
3842  void print(std::ostream &os) const
3843  { os << "("; _u.print(os);os <<"*";_v.print(os);os << ")"; }
3844 };
3845 
3846 /*
3847  Expression for multiplication operation (third version)
3848 
3849  Scalar multiplication
3850 */
3851 template <typename E2>
3852 class mult_expr<typename E2::Scalar, E2, false>
3853  : public _expr<mult_expr<typename E2::Scalar, E2, false> >
3854 // template <typename E> class scmult_expr : public _expr<scmult_expr<E> >
3855 {
3856 public:
3857  typedef typename E2::Scalar Scalar;
3858 private:
3859  Scalar const _c;
3860  typename E2::Nested_t _v;
3861 
3862  //mult_expr(const mult_expr&);
3863 public:
3864  enum {ScalarValued = E2::ScalarValued, ColBlocks = E2::ColBlocks};
3865  enum {Space = E2::Space};
3866 
3867  mult_expr(Scalar const & c, _expr<E2> const& v)
3868  : _c(c), _v(v) { }
3869 
3870  EIGEN_STRONG_INLINE AutoReturn_t eval(const index_t k) const
3871  {
3872  return ( _c * _v.eval(k) );
3873 
3874  }
3875 
3876  index_t rows() const { return _v.rows(); }
3877  index_t cols() const { return _v.cols(); }
3878 
3879  void parse(gsExprHelper<Scalar> & evList) const
3880  { _v.parse(evList); }
3881 
3882  index_t cardinality_impl() const
3883  { return _v.cardinality(); }
3884 
3885  const gsFeSpace<Scalar> & rowVar() const { return _v.rowVar(); }
3886  const gsFeSpace<Scalar> & colVar() const { return _v.colVar(); }
3887 
3888  void print(std::ostream &os) const { os << _c <<"*";_v.print(os); }
3889 };
3890 
3891 
3892 template <typename E1, typename E2>
3893 class collapse_expr : public _expr<collapse_expr<E1, E2> >
3894 {
3895  typename E1::Nested_t _u;
3896  typename E2::Nested_t _v;
3897 
3898 public:
3899  enum {ScalarValued = 0, ColBlocks = 0};
3900  enum { Space = (int)E1::Space + (int)E2::Space };
3901 
3902  typedef typename E1::Scalar Scalar;
3903 
3904  mutable gsMatrix<Scalar> res;
3905 
3906  collapse_expr(_expr<E1> const& u,
3907  _expr<E2> const& v)
3908  : _u(u), _v(v) { }
3909 
3910  //EIGEN_STRONG_INLINE MatExprType
3911  const gsMatrix<Scalar> &
3912  eval(const index_t k) const
3913  {
3914  const index_t nb = rows();
3915  const auto tmpA = _u.eval(k);
3916  const auto tmpB = _v.eval(k);
3917 
3918  if (E1::ColBlocks)
3919  {
3920  const index_t ur = _v.rows();
3921  res.resize(nb, ur);
3922  for (index_t i = 0; i!=nb; ++i)
3923  {
3924  res.row(i).transpose().noalias() = tmpA.middleCols(i*ur,ur) * tmpB;
3925  }
3926  }
3927  else if (E2::ColBlocks)
3928  {
3929  const index_t ur = _u.cols();
3930  res.resize(nb, ur);
3931  for (index_t i = 0; i!=nb; ++i)
3932  {
3933  res.row(i).noalias() = tmpA * tmpB.middleCols(i*ur,ur);
3934  }
3935  }
3936 
3937  return res;
3938  }
3939 
3940  index_t rows() const { return E1::ColBlocks ? _u.cols() / _v.rows() : _v.cols() / _u.cols() ; }
3941  index_t cols() const { return E1::ColBlocks ? _v.rows() : _u.cols(); }
3942 
3943  void parse(gsExprHelper<Scalar> & evList) const
3944  { _u.parse(evList); _v.parse(evList); }
3945 
3946  const gsFeSpace<Scalar> & rowVar() const
3947  { return E1::ColBlocks ? _u.rowVar() : _v.rowVar(); }
3948  const gsFeSpace<Scalar> & colVar() const
3949  {
3950  GISMO_ERROR("none");
3951  }
3952 
3953  void print(std::ostream &os) const { _u.print(os); os<<"~"; _v.print(os); }
3954 };
3955 
3956 // Multi-matrix collapsed by a vector
3957 template <typename E1, typename E2> //EIGEN_STRONG_INLINE
3958 //collapse_expr<E1,E2> const operator&(<E1> const& u, _expr<E2> const& v)
3959 collapse_expr<E1,E2> collapse( _expr<E1> const& u, _expr<E2> const& v)
3960 { return collapse_expr<E1, E2>(u, v); }
3961 
3962 
3963 /*
3964  Expression for the Frobenius matrix (or double dot) product (first
3965  version) Also block-wise
3966 
3967  [A1 A2 A3] . [B1 B2 B3]
3968  =
3969  [ A1.B1 A1.B2 A1.B3 ]
3970  [ A2.B1 A2.B2 A2.B3 ]
3971  [ A3.B1 A3.B2 A3.B3 ]
3972 */
3973 template <typename E1, typename E2, bool = E2::ColBlocks>
3974 class frprod_expr : public _expr<frprod_expr<E1, E2> >
3975 {
3976 public:
3977  typedef typename E1::Scalar Scalar;
3978  enum {ScalarValued = 0, ColBlocks=E2::ColBlocks};
3979  enum { Space = (int)E1::Space + (int)E2::Space };
3980  // E1 E2 this (16 cases..)
3981  // 0 0 0
3982  // 1 1
3983  // 2 2
3984  // 3 3
3985 
3986 private:
3987  typename E1::Nested_t _u;
3988  typename E2::Nested_t _v;
3989 
3990  mutable gsMatrix<Scalar> res;
3991 
3992 public:
3993 
3994  frprod_expr(_expr<E1> const& u, _expr<E2> const& v)
3995  : _u(u), _v(v)
3996  {
3997  //todo: add check() functions, which will evaluate expressions on an empty matrix (no points) to setup initial dimensions ???
3998  //GISMO_ASSERT(_u.rows() == _v.rows(),
3999  // "Wrong dimensions "<<_u.rows()<<"!="<<_v.rows()<<" in % operation");
4000  //GISMO_ASSERT(_u.cols() == _v.cols(),
4001  // "Wrong dimensions "<<_u.cols()<<"!="<<_v.cols()<<" in % operation");
4002  }
4003 
4004  const gsMatrix<Scalar> & eval(const index_t k) const //todo: specialize for nb==1
4005  {
4006  // assert _u.size()==_v.size()
4007  const index_t rb = _u.rows();
4008  const index_t nb = _u.cardinality();
4009  auto A = _u.eval(k);
4010  auto B = _v.eval(k);
4011  res.resize(nb, nb);
4012  for (index_t i = 0; i!=nb; ++i) // all with all
4013  for (index_t j = 0; j!=nb; ++j)
4014  res(i,j) =
4015  (A.middleCols(i*rb,rb).array() * B.middleCols(j*rb,rb).array()).sum();
4016  return res;
4017  }
4018 
4019  index_t rows() const { return _u.cols() / _u.rows(); }
4020  index_t cols() const { return _u.cols() / _u.rows(); }
4021 
4022  void parse(gsExprHelper<Scalar> & evList) const
4023  { _u.parse(evList); _v.parse(evList); }
4024 
4025  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
4026  const gsFeSpace<Scalar> & colVar() const { return _v.colVar(); }
4027 
4028  void print(std::ostream &os) const
4029  { os << "("; _u.print(os); os<<" % "; _v.print(os); os<<")";}
4030 };
4031 
4032 /*
4033 
4034  Expression for the Frobenius matrix (or double dot) product (second
4035  version), When left hand only side is block-wise
4036 
4037  [A1 A2 A3] : B = [A1:B A2:B A3:B]
4038 */
4039 template <typename E1, typename E2>
4040 class frprod_expr<E1,E2,false> : public _expr<frprod_expr<E1, E2,false> >
4041 {
4042 public:
4043  typedef typename E1::Scalar Scalar;
4044  enum {ScalarValued = 0, Space = E1::Space, ColBlocks= E1::ColBlocks};
4045 
4046 private:
4047  typename E1::Nested_t _u;
4048  typename E2::Nested_t _v;
4049 
4050  mutable gsMatrix<Scalar> res;
4051 
4052 public:
4053 
4054  frprod_expr(_expr<E1> const& u, _expr<E2> const& v)
4055  : _u(u), _v(v)
4056  {
4057  // gsInfo << "expression is space ? "<<E1::Space <<"\n"; _u.print(gsInfo);
4058  // GISMO_ASSERT(_u.rows() == _v.rows(),
4059  // "Wrong dimensions "<<_u.rows()<<"!="<<_v.rows()<<" in % operation");
4060  // GISMO_ASSERT(_u.cols() == _v.cols(),
4061  // "Wrong dimensions "<<_u.cols()<<"!="<<_v.cols()<<" in % operation");
4062  }
4063 
4064  const gsMatrix<Scalar> & eval(const index_t k) const //todo: specialize for nb==1
4065  {
4066  // assert _u.size()==_v.size()
4067  auto A = _u.eval(k);
4068  auto B = _v.eval(k);
4069  const index_t rb = A.rows(); //==cb
4070  const index_t nb = _u.cardinality();
4071  res.resize(nb, 1);
4072  for (index_t i = 0; i!=nb; ++i) // all with all
4073  res(i,0) =
4074  (A.middleCols(i*rb,rb).array() * B.array()).sum();
4075  return res;
4076  }
4077 
4078  index_t rows() const { return _u.cols() / _u.rows(); }
4079  index_t cols() const { return 1; }
4080 
4081  void parse(gsExprHelper<Scalar> & evList) const
4082  { _u.parse(evList); _v.parse(evList); }
4083 
4084 
4085  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
4086  const gsFeSpace<Scalar> & colVar() const { return _v.rowVar(); }
4087 
4088  void print(std::ostream &os) const
4089  { os << "("; _u.print(os); os<<" % "; _v.print(os); os<<")";}
4090 };
4091 
4092 /*
4093  Expression for scalar division operation (first version)
4094 */
4095 template <typename E1, typename E2>
4096 class divide_expr : public _expr<divide_expr<E1,E2> >
4097 {
4098  typename E1::Nested_t _u;
4099  typename E2::Nested_t _v;
4100 
4101 public:
4102  typedef typename E1::Scalar Scalar;
4103 
4104 public:
4105  enum {ScalarValued = E1::ScalarValued, ColBlocks= E2::ColBlocks};
4106  enum {Space = E1::Space}; // The denominator E2 has to be scalar.
4107 
4108  divide_expr(_expr<E1> const& u, _expr<E2> const& v)
4109  : _u(u), _v(v)
4110  {
4111  GISMO_STATIC_ASSERT(E2::ScalarValued, "The denominator needs to be scalar valued.");
4112  }
4113 
4114  AutoReturn_t eval(const index_t k) const
4115  { return ( _u.eval(k) / _v.eval(k) ); }
4116 
4117  index_t rows() const { return _u.rows(); }
4118  index_t cols() const { return _u.cols(); }
4119 
4120  void parse(gsExprHelper<Scalar> & evList) const
4121  { _u.parse(evList); _v.parse(evList); }
4122 
4123 
4124  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
4125  const gsFeSpace<Scalar> & colVar() const { return _u.colVar(); }
4126 
4127  void print(std::ostream &os) const
4128  { os << "("; _u.print(os);os <<" / ";_v.print(os);os << ")"; }
4129 };
4130 
4131 /*
4132  Division specialization (second version) for constant value denominator
4133 */
4134 template <typename E1>
4135 class divide_expr<E1,typename E1::Scalar>
4136  : public _expr<divide_expr<E1,typename E1::Scalar> >
4137 {
4138 public:
4139  typedef typename E1::Scalar Scalar;
4140 
4141 private:
4142  typename E1::Nested_t _u;
4143  Scalar const _c;
4144 
4145 public:
4146  enum {Space= E1::Space, ScalarValued = E1::ScalarValued, ColBlocks= E1::ColBlocks};
4147 
4148  divide_expr(_expr<E1> const& u, Scalar const c)
4149  : _u(u), _c(c) { }
4150 
4151  AutoReturn_t eval(const index_t k) const
4152  { return ( _u.eval(k) / _c ); }
4153 
4154  index_t rows() const { return _u.rows(); }
4155  index_t cols() const { return _u.cols(); }
4156 
4157  void parse(gsExprHelper<Scalar> & evList) const
4158  { _u.parse(evList); }
4159 
4160 
4161  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
4162  const gsFeSpace<Scalar> & colVar() const { return _u.colVar(); }
4163 
4164  void print(std::ostream &os) const
4165  { os << "("; _u.print(os);os <<"/"<< _c << ")"; }
4166 };
4167 
4168 /*
4169  Division specialization (third version) for constant value
4170  numerator
4171 */
4172 template <typename E2>
4173 class divide_expr<typename E2::Scalar,E2>
4174  : public _expr<divide_expr<typename E2::Scalar,E2> >
4175 {
4176 public:
4177  typedef typename E2::Scalar Scalar;
4178 
4179 private:
4180  Scalar const _c;
4181  typename E2::Nested_t _u;
4182 public:
4183  enum {Space= 0, ScalarValued = 1, ColBlocks= 0};
4184 
4185  divide_expr(Scalar const c, _expr<E2> const& u)
4186  : _c(c), _u(u)
4187  { GISMO_STATIC_ASSERT(E2::ScalarValued, "The denominator needs to be scalar valued."); }
4188 
4189  Scalar eval(const index_t k) const
4190  { return ( _c / _u.val().eval(k) ); }
4191 
4192  index_t rows() const { return 0; }
4193  index_t cols() const { return 0; }
4194 
4195  void parse(gsExprHelper<Scalar> & evList) const
4196  { _u.parse(evList); }
4197 
4198 
4199  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
4200  const gsFeSpace<Scalar> & colVar() const { return _u.colVar(); }
4201 
4202  void print(std::ostream &os) const
4203  { os << "("<< _c <<"/";_u.print(os);os << ")";}
4204 };
4205 
4206 /*
4207  Expression for addition operation
4208 */
4209 template <typename E1, typename E2>
4210 class add_expr : public _expr<add_expr<E1, E2> >
4211 {
4212  typename E1::Nested_t _u;
4213  typename E2::Nested_t _v;
4214 
4215 public:
4216  enum {ScalarValued = E1::ScalarValued && E2::ScalarValued,
4217  ColBlocks = E1::ColBlocks || E2::ColBlocks };
4218  enum {Space = E1::Space}; // == E2::Space
4219 
4220  typedef typename E1::Scalar Scalar;
4221 
4222  add_expr(_expr<E1> const& u, _expr<E2> const& v)
4223  : _u(u), _v(v)
4224  {
4225  GISMO_ENSURE((int)E1::Space == (int)E2::Space &&
4226  _u.rowVar()==_v.rowVar() && _u.colVar()==_v.colVar(),
4227  "Error: adding apples and oranges (use comma instead),"
4228  " namely:\n" << _u <<"\n"<<_v<<
4229  " \nvars:\n" << _u.rowVar().id()<<"!="<<_v.rowVar().id() <<", "<< _u.colVar().id()<<"!="<<_v.colVar().id()<<
4230  " \nspaces:\n" << (int)E1::Space<< "!="<< (int)E2::Space
4231  );
4232  }
4233 
4234  mutable Temporary_t res;
4235  const Temporary_t & eval(const index_t k) const
4236  {
4237  GISMO_ASSERT(_u.rows() == _v.rows(),
4238  "Wrong dimensions "<<_u.rows()<<"!="<<_v.rows()<<" in + operation:\n"
4239  << _u <<" plus \n" << _v );
4240  GISMO_ASSERT(_u.cols() == _v.cols(),
4241  "Wrong dimensions "<<_u.cols()<<"!="<<_v.cols()<<" in + operation:\n"
4242  << _u <<" plus \n" << _v );
4243  res = _u.eval(k) + _v.eval(k);
4244  return res;
4245  }
4246 
4247  index_t rows() const { return _u.rows(); }
4248  index_t cols() const { return _u.cols(); }
4249 
4250  void parse(gsExprHelper<Scalar> & evList) const
4251  { _u.parse(evList); _v.parse(evList); }
4252 
4253 
4254  index_t cardinality_impl() const { return _u.cardinality_impl(); }
4255 
4256  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
4257  const gsFeSpace<Scalar> & colVar() const { return _v.colVar(); }
4258 
4259  void print(std::ostream &os) const
4260  { os << "("; _u.print(os);os <<" + ";_v.print(os);os << ")"; }
4261 };
4262 
4263 /*
4264  lincom_expr (lc) ?
4265  Expression for (square) matrix summation operation
4266 
4267  M [r x r*k] is a list of matrices
4268  Summation is done over k,
4269  [M1 M2 .. Mk]
4270 
4271  u [s x k] is a list of vectors
4272 
4273  Computed quantity is of size [r x r*s] and contains
4274  [ ... sum_k(Mk * u(s,k) ) ... ]_s
4275 */
4276 template <typename E1, typename E2>
4277 class summ_expr : public _expr<summ_expr<E1,E2> >
4278 {
4279 public:
4280  typedef typename E1::Scalar Scalar;
4281 
4282  enum {Space = E1::Space, ScalarValued= 0, ColBlocks= E2::ColBlocks};
4283 
4284  summ_expr(E1 const& u, E2 const& M) : _u(u), _M(M) { }
4285 
4286  const gsMatrix<Scalar> & eval(const index_t k) const
4287  {
4288  auto sl = _u.eval(k);
4289  const index_t sr = sl.rows();
4290  auto ml = _M.eval(k);
4291  const index_t mr = ml.rows();
4292  const index_t mb = _M.cardinality();
4293 
4294  GISMO_ASSERT(_M.cols()==_M.rows(),"Matrix must be square: "<< _M.rows()<<" x "<< _M.cols() << " expr: "<< _M );
4295  GISMO_ASSERT(mb==_u.cols(),"cardinality must match vector, but card(M)="<<_M.cardinality()<<" and cols(u)="<<_u.cols());
4296 
4297  res.setZero(mr, sr * mr);
4298  for (index_t i = 0; i!=sr; ++i)
4299  for (index_t t = 0; t!=mb; ++t) // lc
4300  res.middleCols(i*mr,mr) += sl(i,t) * ml.middleCols(t*mr,mr);
4301  return res;
4302  }
4303 
4304  index_t rows() const { return _M.rows(); }
4305  index_t cols() const { return _M.rows(); } //_u.rows()
4306 
4307  void parse(gsExprHelper<Scalar> & evList) const
4308  { _u.parse(evList); _M.parse(evList); }
4309 
4310  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
4311  const gsFeSpace<Scalar> & colVar() const { return gsNullExpr<Scalar>::get(); }
4312 
4313  index_t cardinality_impl() const
4314  { GISMO_ERROR("Something went terribly wrong"); }
4315 
4316  void print(std::ostream &os) const
4317  { os << "sum("; _M.print(os); os<<","; _u.print(os); os<<")"; }
4318 
4319 private:
4320  typename E1::Nested_t _u;
4321  typename E2::Nested_t _M;
4322 
4323  mutable gsMatrix<Scalar> res;
4324 };
4325 
4326 
4327 /*
4328  Expression for subtraction operation
4329 */
4330 template <typename E1, typename E2>
4331 class sub_expr : public _expr<sub_expr<E1, E2> >
4332 {
4333  typename E1::Nested_t _u;
4334  typename E2::Nested_t _v;
4335 
4336 public:
4337  enum {ScalarValued = E1::ScalarValued && E2::ScalarValued,
4338  ColBlocks = E1::ColBlocks || E2::ColBlocks };
4339  enum {Space = E1::Space}; // == E2::Space
4340 
4341  typedef typename E1::Scalar Scalar;
4342 
4343  sub_expr(_expr<E1> const& u, _expr<E2> const& v)
4344  : _u(u), _v(v)
4345  {
4346  GISMO_ENSURE((int)E1::Space == (int)E2::Space &&
4347  _u.rowVar()==_v.rowVar() && _u.colVar()==_v.colVar(),
4348  "Error: substracting apples from oranges (use comma instead),"
4349  " namely:\n" << _u <<"\n"<<_v);
4350  }
4351 
4352  mutable Temporary_t res;
4353  const Temporary_t & eval(const index_t k) const
4354  {
4355  // GISMO_ASSERT(_u.rowVar().id()==_v.rowVar().id() && _u.rowVar().isAcross()==_v.rowVar().isAcross(),
4356  // "The row spaces are not split compatibly.");
4357  // GISMO_ASSERT(_u.colVar().id()==_v.colVar().id() && _u.colVar().isAcross()==_v.colVar().isAcross(),
4358  // "The col spaces are not split compatibly.");
4359  GISMO_ASSERT(_u.rows() == _v.rows(),
4360  "Wrong dimensions "<<_u.rows()<<"!="<<_v.rows()<<" in - operation:\n" << _u <<" minus \n" << _v );
4361  GISMO_ASSERT(_u.cols() == _v.cols(),
4362  "Wrong dimensions "<<_u.cols()<<"!="<<_v.cols()<<" in - operation:\n" << _u <<" minus \n" << _v );
4363  GISMO_ASSERT(_u.cardinality() == _u.cardinality(),
4364  "Cardinality "<< _u.cardinality()<<" != "<< _v.cardinality());
4365  //return (_u.eval(k) - _v.eval(k) ).eval();
4366  //return (_u.eval(k) - _v.eval(k) ); // any temporary matrices eval(.) will leak mem.
4367  res = _u.eval(k) - _v.eval(k);
4368  return res;
4369  }
4370 
4371  index_t rows() const { return _u.rows(); }
4372  index_t cols() const { return _u.cols(); }
4373 
4374  void parse(gsExprHelper<Scalar> & evList) const
4375  { _u.parse(evList); _v.parse(evList); }
4376 
4377  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
4378  const gsFeSpace<Scalar> & colVar() const { return _v.colVar(); }
4379 
4380  index_t cardinality_impl() const
4381  {
4382  GISMO_ASSERT(_u.cardinality() == _u.cardinality(),
4383  "Cardinality "<< _u.cardinality()<<" != "<< _v.cardinality());
4384  return _u.cardinality();
4385  }
4386 
4387  void print(std::ostream &os) const
4388  { os << "("; _u.print(os); os<<" - ";_v.print(os); os << ")";}
4389 };
4390 
4391 /*
4392  Expression for symmetrization operation
4393 */
4394 template <typename E>
4395 class symm_expr : public _expr<symm_expr<E> >
4396 {
4397  typename E::Nested_t _u;
4398 
4399  mutable gsMatrix<typename E::Scalar> tmp;
4400 public:
4401  typedef typename E::Scalar Scalar;
4402 
4403  enum { Space = (0==E::Space ? 0 : E::Space), ScalarValued= E::ScalarValued, ColBlocks= E::ColBlocks };
4404 
4405  symm_expr(_expr<E> const& u)
4406  : _u(u) { }
4407 
4408  MatExprType eval(const index_t k) const
4409  {
4410  //const MatExprType tmp = _u.eval(k);
4411  tmp = _u.eval(k);
4412  // todo: avoid temporary or not ?
4413  return tmp * tmp.transpose();
4414  }
4415 
4416  index_t rows() const { return _u.rows(); }
4417  index_t cols() const { return _u.rows(); }
4418 
4419  void parse(gsExprHelper<Scalar> & evList) const
4420  { _u.parse(evList); }
4421 
4422  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
4423  const gsFeSpace<Scalar> & colVar() const { return _u.rowVar(); }
4424 
4425  void print(std::ostream &os) const { os << "symm("; _u.print(os); os <<")"; }
4426 };
4427 
4428 template <typename E>
4429 class symmetrize_expr : public _expr<symmetrize_expr<E> >
4430 {
4431  typename E::Nested_t _u;
4432 
4433  mutable gsMatrix<typename E::Scalar> tmp;
4434 public:
4435  enum { Space = (0==E::Space ? 0 : 3), ScalarValued=E::ScalarValued, ColBlocks= E::ColBlocks };
4436  typedef typename E::Scalar Scalar;
4437 
4438  symmetrize_expr(_expr<E> const& u)
4439  : _u(u) { }
4440 
4441  MatExprType eval(const index_t k) const
4442  {
4443  //const MatExprType tmp = _u.eval(k);
4444  tmp = _u.eval(k);
4445  // todo: avoid temporary or not ?
4446  return tmp + tmp.transpose();
4447  }
4448 
4449  index_t rows() const { return _u.rows(); }
4450  index_t cols() const { return _u.rows(); }
4451 
4452  void parse(gsExprHelper<Scalar> & evList) const
4453  { _u.parse(evList); }
4454 
4455  const gsFeSpace<Scalar> & rowVar() const { return _u.rowVar(); }
4456  const gsFeSpace<Scalar> & colVar() const { return _u.rowVar(); }
4457  index_t cardinality_impl() const { return _u.cardinality_impl(); }
4458 
4459  void print(std::ostream &os) const { os << "symmetrize("; _u.print(os); os <<")"; }
4460 };
4461 
4462 /* Symmetrization operation
4463  template <typename E> symm_expr<E> const
4464  symm(_expr<E> const& u) { return symm_expr<E>(u);}
4465 */
4466 
4467 #undef MatExprType
4468 #undef AutoReturn_t
4469 //----------------------------------------------------------------------------------
4470 
4472 EIGEN_STRONG_INLINE idMat_expr id(const index_t dim) { return idMat_expr(dim); }
4473 
4474 EIGEN_STRONG_INLINE constMat_expr ones(const index_t dim) {
4475  gsMatrix<real_t> ones(dim, dim);
4476  ones.fill(1);
4477  return constMat_expr(ones);
4478  }
4479 
4480 EIGEN_STRONG_INLINE constMat_expr mat(const gsMatrix<real_t> mat) { return constMat_expr(mat); }
4481 
4482 // Returns the unit as an expression
4483 //EIGEN_STRONG_INLINE _expr<real_t> one() { return _expr<real_t,true>(1); }
4484 
4485 
4487 template<class E> EIGEN_STRONG_INLINE
4488 abs_expr<E> abs(const E & u) { return abs_expr<E>(u); }
4489 
4491 template<class E> EIGEN_STRONG_INLINE
4492 grad_expr<E> grad(const E & u) { return grad_expr<E>(u); }
4493 
4495 template<class E> EIGEN_STRONG_INLINE
4496 dJacdc_expr<E> dJacdc(const E & u, index_t c) { return dJacdc_expr<E>(u,c); }
4497 
4499 template<class T> EIGEN_STRONG_INLINE
4500 curl_expr<T> curl(const gsFeVariable<T> & u) { return curl_expr<T>(u); }
4501 
4503 template<class T> EIGEN_STRONG_INLINE
4504 nabla_expr<T> nabla(const gsFeVariable<T> & u) { return nabla_expr<T>(u); }
4505 
4507 template<class T> EIGEN_STRONG_INLINE
4508 onormal_expr<T> nv(const gsGeometryMap<T> & u) { return onormal_expr<T>(u); }
4509 
4510 template<class T> EIGEN_STRONG_INLINE
4511 normal_expr<T> sn(const gsGeometryMap<T> & u) { return normal_expr<T>(u); }
4512 
4514 template<class T> EIGEN_STRONG_INLINE
4515 tangent_expr<T> tv(const gsGeometryMap<T> & u) { return tangent_expr<T>(u); }
4516 
4517 template<class E> EIGEN_STRONG_INLINE
4518 lapl_expr<E> lapl(const symbol_expr<E> & u) { return lapl_expr<E>(u); }
4519 
4520 template<class T> EIGEN_STRONG_INLINE
4521 lapl_expr<gsFeSolution<T> > lapl(const gsFeSolution<T> & u)
4522 { return lapl_expr<gsFeSolution<T> >(u); }
4523 
4525 template<class T> EIGEN_STRONG_INLINE fform2nd_expr<T> fform2nd(const gsGeometryMap<T> & G)
4526 { return fform2nd_expr<T>(G); }
4527 
4529 template<class E> EIGEN_STRONG_INLINE
4530 jac_expr<E> jac(const symbol_expr<E> & u) { return jac_expr<E>(u); }
4531 
4533 template<class T> EIGEN_STRONG_INLINE
4534 jac_expr<gsGeometryMap<T> > jac(const gsGeometryMap<T> & G) {return jac_expr<gsGeometryMap<T> >(G);}
4535 
4537 template<class T> EIGEN_STRONG_INLINE
4538 grad_expr<gsFeSolution<T> > jac(const gsFeSolution<T> & s) {return grad_expr<gsFeSolution<T> >(s);}
4539 
4540 template<class E> EIGEN_STRONG_INLINE
4541 hess_expr<E> hess(const symbol_expr<E> & u) { return hess_expr<E>(u); }
4542 
4544 template<class T> EIGEN_STRONG_INLINE
4545 hess_expr<gsGeometryMap<T> > hess(const gsGeometryMap<T> & u) { return hess_expr<gsGeometryMap<T> >(u); }
4546 
4548 template<class T> EIGEN_STRONG_INLINE
4549 hess_expr<gsFeSolution<T> > hess(const gsFeSolution<T> & u) { return hess_expr<gsFeSolution<T> >(u); }
4550 
4552 template<class T> EIGEN_STRONG_INLINE
4553 dJacG_expr<T> dJac(const gsGeometryMap<T> & G) { return dJacG_expr<T>(G); }
4554 
4556 template<class T> EIGEN_STRONG_INLINE
4557 meas_expr<T> meas(const gsGeometryMap<T> & G) { return meas_expr<T>(G); }
4558 
4560 template <typename E1, typename E2> EIGEN_STRONG_INLINE
4561 mult_expr<E1,E2> const operator*(_expr<E1> const& u, _expr<E2> const& v)
4562 { return mult_expr<E1, E2>(u, v); }
4563 
4564 template <typename E2> EIGEN_STRONG_INLINE
4565 mult_expr<typename E2::Scalar,E2,false> const
4566 operator*(typename E2::Scalar const& u, _expr<E2> const& v)
4567 { return mult_expr<typename E2::Scalar, E2, false>(u, v); }
4568 
4569 template <typename E1> EIGEN_STRONG_INLINE
4570 mult_expr<typename E1::Scalar,E1,false> const
4571 operator*(_expr<E1> const& v, typename E1::Scalar const& u)
4572 { return mult_expr<typename E1::Scalar,E1, false>(u, v); }
4573 
4574 template <typename E1> EIGEN_STRONG_INLINE
4575 mult_expr<typename E1::Scalar,E1,false> const
4576 operator-(_expr<E1> const& u)
4577 { return mult_expr<typename E1::Scalar,E1, false>(-1, u); }
4578 
4579 template <typename E> mult_expr<constMat_expr, E> const
4580 operator*( gsMatrix<typename E::Scalar> const& u, _expr<E> const& v)
4581 { return mult_expr<constMat_expr, E>(mat(u), v); }
4582 
4583 template <typename E> mult_expr<E, constMat_expr> const
4584 operator*(_expr<E> const& u, gsMatrix<typename E::Scalar> const& v)
4585 { return mult_expr<E, constMat_expr>(u, mat(v) ); }
4586 
4588 template <typename E1, typename E2> EIGEN_STRONG_INLINE
4589 frprod_expr<E1,E2> const operator%(_expr<E1> const& u, _expr<E2> const& v)
4590 { return frprod_expr<E1, E2>(u, v); }
4591 
4593 template <typename E1, typename E2> EIGEN_STRONG_INLINE
4594 divide_expr<E1,E2> const operator/(_expr<E1> const& u, _expr<E2> const& v)
4595 { return divide_expr<E1,E2>(u, v); }
4596 
4597 template <typename E> EIGEN_STRONG_INLINE
4598 divide_expr<E,typename E::Scalar> const
4599 operator/(_expr<E> const& u, const typename E::Scalar v)
4600 { return divide_expr<E,typename E::Scalar>(u, v); }
4601 
4602 template <typename E> EIGEN_STRONG_INLINE
4603 divide_expr<typename E::Scalar,E> const
4604 operator/(const typename E::Scalar u, _expr<E> const& v)
4605 { return divide_expr<typename E::Scalar,E>(u, v); }
4606 
4608 template <typename E1, typename E2> EIGEN_STRONG_INLINE
4609 add_expr<E1,E2> const operator+(_expr<E1> const& u, _expr<E2> const& v)
4610 { return add_expr<E1, E2>(u, v); }
4611 
4613 template <typename E> EIGEN_STRONG_INLINE
4614 add_expr< E, _expr<typename E::Scalar, true> >
4615 operator+(_expr<E> const& u, const typename E::Scalar v)
4616 { return add_expr<E,_expr<typename E::Scalar>>(u, _expr<typename E::Scalar,true>(v)); }
4617 
4619 template <typename E> EIGEN_STRONG_INLINE
4620 add_expr< E, _expr<typename E::Scalar, true> >
4621 operator+(const typename E::Scalar v, _expr<E> const& u)
4622 { return add_expr<E,_expr<typename E::Scalar>>(u, _expr<typename E::Scalar,true>(v)); }
4623 
4625 template <typename E1, typename E2> EIGEN_STRONG_INLINE
4626 summ_expr<E1,E2> const summ(E1 const & u, E2 const& M)
4627 { return summ_expr<E1,E2>(u, M); }
4628 
4631 template <typename E1, typename E2> EIGEN_STRONG_INLINE
4632 matrix_by_space_expr<E1,E2> const matrix_by_space(E1 const & u, E2 const& v)
4633 { return matrix_by_space_expr<E1,E2>(u, v); }
4634 
4637 template <typename E1, typename E2> EIGEN_STRONG_INLINE
4638 matrix_by_space_expr_tr<E1,E2> const matrix_by_space_tr(E1 const & u, E2 const& v)
4639 { return matrix_by_space_expr_tr<E1,E2>(u, v); }
4640 
4642 template <typename E1, typename E2> EIGEN_STRONG_INLINE
4643 sub_expr<E1,E2> const operator-(_expr<E1> const& u, _expr<E2> const& v)
4644 { return sub_expr<E1, E2>(u, v); }
4645 
4646 template <typename E2> EIGEN_STRONG_INLINE
4647 sub_expr<_expr<typename E2::Scalar>,E2> const
4648 operator-(typename E2::Scalar const& s, _expr<E2> const& v)
4649 {
4650  // assert E2::ScalarValued
4651  return sub_expr<_expr<typename E2::Scalar>, E2>(_expr<typename E2::Scalar>(s), v);
4652 }
4653 
4654 
4655 // Shortcuts for common quantities, for instance function
4656 // transformations by the geometry map \a G
4657 #define GISMO_SHORTCUT_VAR_EXPRESSION(name,impl) template<class E> EIGEN_STRONG_INLINE \
4658  auto name(const E & u) -> decltype(impl) { return impl; }
4659 #define GISMO_SHORTCUT_MAP_EXPRESSION(name,impl) template<class T> EIGEN_STRONG_INLINE \
4660  auto name(const gsGeometryMap<T> & G) -> decltype(impl) { return impl; }
4661 #define GISMO_SHORTCUT_PHY_EXPRESSION(name,impl) template<class E> EIGEN_STRONG_INLINE \
4662  auto name(const E & u, const gsGeometryMap<typename E::Scalar> & G) -> decltype(impl) { return impl; }
4663 
4664 // Divergence
4665 GISMO_SHORTCUT_VAR_EXPRESSION( div, jac(u).trace() )
4666 GISMO_SHORTCUT_PHY_EXPRESSION( idiv, ijac(u,G).trace() )
4667 
4668 // The unit (normalized) boundary (outer pointing) normal
4669 GISMO_SHORTCUT_MAP_EXPRESSION(unv, nv(G).normalized() )
4670 // The unit (normalized) boundary (surface) normal
4671 GISMO_SHORTCUT_MAP_EXPRESSION(usn, sn(G).normalized() )
4672 
4673 GISMO_SHORTCUT_PHY_EXPRESSION(igrad, grad(u)*jac(G).ginv() ) // transpose() problem ??
4674 GISMO_SHORTCUT_VAR_EXPRESSION(igrad, grad(u) ) // u is presumed to be defined over G
4675 
4676 GISMO_SHORTCUT_PHY_EXPRESSION( ijac, jac(u) * jac(G).ginv())
4677 
4678 // note and todo: does this work for non-scalar solutions?
4679 GISMO_SHORTCUT_PHY_EXPRESSION(ihess,
4680  jac(G).ginv().tr()*( hess(u) - summ(igrad(u,G),hess(G)) ) * jac(G).ginv() )
4681 GISMO_SHORTCUT_VAR_EXPRESSION(ihess, hess(u) )
4682 
4683 GISMO_SHORTCUT_PHY_EXPRESSION(ilapl, ihess(u,G).trace() )
4684 GISMO_SHORTCUT_VAR_EXPRESSION(ilapl, hess(u).trace() )
4685 
4686 GISMO_SHORTCUT_VAR_EXPRESSION(fform, jac(u).tr()*jac(u) )
4687 GISMO_SHORTCUT_VAR_EXPRESSION(shapeop, fform(u).inv() * fform2nd(u) )
4688 
4689 #undef GISMO_SHORTCUT_PHY_EXPRESSION
4690 #undef GISMO_SHORTCUT_VAR_EXPRESSION
4691 #undef GISMO_SHORTCUT_MAP_EXPRESSION
4692 
4693 } // namespace expr
4694 
4695 } //namespace gismo
EIGEN_STRONG_INLINE matrix_by_space_expr< E1, E2 > const matrix_by_space(E1 const &u, E2 const &v)
Definition: gsExpressions.h:4632
asdiag_expr< E > asDiag() const
Returns a diagonal matrix expression of the vector expression.
Definition: gsExpressions.h:309
#define MatExprType
[Include namespace]
Definition: gsThinShellUtils.h:32
mult_expr< real_t, ppart_expr< mult_expr< double, E, false > >, false > npart() const
Returns the expression&#39;s negative part.
Definition: gsExpressions.h:260
Definition: gsExpressions.h:120
Definition: gsExpressions.h:96
Definition: gsExpressions.h:137
size_t mapSize() const
Returns the total number of patch-local degrees of freedom that are being mapped. ...
Definition: gsDofMapper.h:473
Gradient of the object.
Definition: gsForwardDeclarations.h:73
EIGEN_STRONG_INLINE diag_expr< E > const diagonal(E const &u)
Get diagonal elements of matrix as a vector.
Definition: gsExpressions.h:2084
Matrix< Scalar, Dynamic, Dynamic > cramerInverse() const
Inversion for small matrices using Cramer&#39;s Rule.
Definition: gsMatrixAddons.h:55
Definition: gsExpressions.h:3046
normalized_expr< E > normalized() const
Returns the vector normalized to unit length.
Definition: gsExpressions.h:283
The functions compute Dirichlet degrees of freedom using various methods.
EIGEN_STRONG_INLINE matrix_by_space_expr_tr< E1, E2 > const matrix_by_space_tr(E1 const &u, E2 const &v)
Definition: gsExpressions.h:4638
sqNorm_expr< E > sqNorm() const
Returns the squared Euclidean norm of the expression.
Definition: gsExpressions.h:291
index_t rows() const
Returns the row-size of the expression.
Definition: gsExpressions.h:328
Definition: gsExpressions.h:2306
ppart_expr< E > ppart() const
Returns the expression&#39;s positive part.
Definition: gsExpressions.h:253
const gsFeSpace< Scalar > & rowVar() const
Definition: gsExpressions.h:358
Outward normal on the boundary.
Definition: gsForwardDeclarations.h:86
EIGEN_STRONG_INLINE tangent_expr< T > tv(const gsGeometryMap< T > &u)
The tangent boundary vector of a geometry map in 2D.
Definition: gsExpressions.h:4515
norm_expr< E > norm() const
Returns the Euclidean norm of the expression.
Definition: gsExpressions.h:279
adjugate_expr< E > adj() const
Returns the adjugate of the expression (for matrix-valued expressions)
Definition: gsExpressions.h:275
Definition: gsExpressions.h:3013
S give(S &x)
Definition: gsMemory.h:266
EIGEN_STRONG_INLINE dJacG_expr< T > dJac(const gsGeometryMap< T > &G)
The partial derivatives of the Jacobian matrix of a geometry map.
Definition: gsExpressions.h:4553
Second derivatives.
Definition: gsForwardDeclarations.h:80
#define index_t
Definition: gsConfig.h:32
#define GISMO_ENSURE(cond, message)
Definition: gsDebug.h:102
const gsFeElement< Scalar > & _e
Reference to the element.
Definition: gsExpressions.h:858
EIGEN_STRONG_INLINE fform2nd_expr< T > fform2nd(const gsGeometryMap< T > &G)
The second fundamental form of G.
Definition: gsExpressions.h:4525
EIGEN_STRONG_INLINE frprod_expr< E1, E2 > const operator%(_expr< E1 > const &u, _expr< E2 > const &v)
Frobenious product (also known as double dot product) operator for expressions.
Definition: gsExpressions.h:4589
det_expr< E > det() const
Returns the determinant of the expression.
Definition: gsExpressions.h:287
#define GISMO_ASSERT(cond, message)
Definition: gsDebug.h:89
EIGEN_STRONG_INLINE summ_expr< E1, E2 > const summ(E1 const &u, E2 const &M)
Matrix-summation operator for expressions.
Definition: gsExpressions.h:4626
Maintains a mapping from patch-local dofs to global dof indices and allows the elimination of individ...
Definition: gsDofMapper.h:68
Definition: gsExpressions.h:3134
Struct containing information for matrix assembly.
Definition: gsExpressions.h:63
colsum_expr< E > colSum() const
Returns the colSum of a matrix.
Definition: gsExpressions.h:321
Laplacian.
Definition: gsForwardDeclarations.h:83
const gsFeSpace< Scalar > & colVar() const
Definition: gsExpressions.h:366
void finalize()
Must be called after all boundaries and interfaces have been marked to set up the dof numbering...
Definition: gsDofMapper.cpp:240
value_expr< E > val() const
Definition: gsExpressions.h:305
temp_expr< E > temp() const
Returns an evaluation of the (sub-)expression in temporary memory.
Definition: gsExpressions.h:263
exp_expr< E > exp() const
Returns exp(expression)
Definition: gsExpressions.h:249
#define gsWarn
Definition: gsDebug.h:50
Definition: gsExpressions.h:2337
Holds a set of patch-wise bases and their topology information.
Definition: gsMultiBasis.h:36
Normal vector of the object.
Definition: gsForwardDeclarations.h:85
inv_expr< E > const inv() const
Returns the inverse of the expression (for matrix-valued expressions)
Definition: gsExpressions.h:267
Provides declaration of Basis abstract interface.
EIGEN_STRONG_INLINE mult_expr< E1, E2 > const operator*(_expr< E1 > const &u, _expr< E2 > const &v)
Multiplication operator for expressions.
Definition: gsExpressions.h:4561
EIGEN_STRONG_INLINE onormal_expr< T > nv(const gsGeometryMap< T > &u)
The (outer pointing) boundary normal of a geometry map.
Definition: gsExpressions.h:4508
Definition: gsExpressions.h:139
Definition: gsExpressions.h:140
cb_expr< E > cb() const
Returns the puts the expression to colBlocks.
Definition: gsExpressions.h:241
tr_expr< E > tr() const
Returns the transpose of the expression.
Definition: gsExpressions.h:233
void print(std::ostream &os) const
Prints the expression as a string to os.
Definition: gsExpressions.h:194
MatExprType eval(const index_t k) const
Evaluates the expression at evaluation point indexed by k.
Definition: gsExpressions.h:229
Active function ids.
Definition: gsForwardDeclarations.h:84
Interface for the set of functions defined on a domain (the total number of functions in the set equa...
Definition: gsFuncData.h:23
EIGEN_STRONG_INLINE nabla_expr< T > nabla(const gsFeVariable< T > &u)
The nabla ( ) of a finite element variable.
Definition: gsExpressions.h:4504
Definition: gsExpressions.h:138
Second fundamental form.
Definition: gsForwardDeclarations.h:87
Definition: gsExpressions.h:126
The density of the measure pull back.
Definition: gsForwardDeclarations.h:76
trace_expr< E > trace() const
Returns the trace of the expression (for matrix-valued expressions)
Definition: gsExpressions.h:271
tr_expr< E, true > cwisetr() const
Returns the coordinate-wise transpose of the expression.
Definition: gsExpressions.h:237
EIGEN_STRONG_INLINE curl_expr< T > curl(const gsFeVariable< T > &u)
The curl of a finite element variable.
Definition: gsExpressions.h:4500
Definition: gsExpressions.h:2600
size_t numPatches() const
Returns the number of patches present underneath the mapper.
Definition: gsDofMapper.h:469
EIGEN_STRONG_INLINE reshape_expr< E > const reshape(E const &u, index_t n, index_t m)
Reshape an expression.
Definition: gsExpressions.h:1927
EIGEN_STRONG_INLINE dJacdc_expr< E > dJacdc(const E &u, index_t c)
The derivative of the jacobian of a geometry map with respect to a coordinate.
Definition: gsExpressions.h:4496
nabla2_expr< T > nabla2(const gsFeVariable< T > &u)
The nabla2 ( ) of a finite element variable.
Definition: gsExpressions.h:3005
Definition: gsExpressions.h:136
EIGEN_STRONG_INLINE flat_expr< E > const flat(E const &u)
Make a matrix 2x2 expression &quot;flat&quot;.
Definition: gsExpressions.h:2033
Value of the object.
Definition: gsForwardDeclarations.h:72
EIGEN_STRONG_INLINE grad_expr< E > grad(const E &u)
The gradient of a variable.
Definition: gsExpressions.h:4492
index_t cols() const
Returns the column-size of the expression.
Definition: gsExpressions.h:332
EIGEN_STRONG_INLINE idMat_expr id(const index_t dim)
The identity matrix of dimension dim.
Definition: gsExpressions.h:4472
#define GISMO_ERROR(message)
Definition: gsDebug.h:118
EIGEN_STRONG_INLINE meas_expr< T > meas(const gsGeometryMap< T > &G)
The measure of a geometry map.
Definition: gsExpressions.h:4557
EIGEN_STRONG_INLINE abs_expr< E > abs(const E &u)
Absolute value.
Definition: gsExpressions.h:4488
EIGEN_STRONG_INLINE divide_expr< E1, E2 > const operator/(_expr< E1 > const &u, _expr< E2 > const &v)
Scalar division operator for expressions.
Definition: gsExpressions.h:4594
Gradient transformation matrix.
Definition: gsForwardDeclarations.h:77
static bool isVector()
rowSpan &amp;&amp; !colSpan
Definition: gsExpressions.h:344
max_expr< E > max() const
Returns the rowSum of a matrix.
Definition: gsExpressions.h:313
GISMO_EXPR_VECTOR_EXPRESSION(norm, norm, 1)
Eucledian Norm.
void parse(gsExprHelper< Scalar > &evList) const
Parse the expression and discover the list of evaluation sources, also sets the required evaluation f...
Definition: gsExpressions.h:350
This object is a cache for computed values from an evaluator.
EIGEN_STRONG_INLINE add_expr< E1, E2 > const operator+(_expr< E1 > const &u, _expr< E2 > const &v)
Addition operator for expressions.
Definition: gsExpressions.h:4609
rowsum_expr< E > rowSum() const
Returns the rowSum of a matrix.
Definition: gsExpressions.h:317
Definition: gsExpressions.h:1980
EIGEN_STRONG_INLINE replicate_expr< E > const replicate(E const &u, index_t n, index_t m=1)
Replicate an expression.
Definition: gsExpressions.h:1969
Definition: gsExpressions.h:114
Defines expression precomputed_expr.
A basis represents a family of scalar basis functions defined over a common parameter domain...
Definition: gsBasis.h:78
sign_expr< E > sgn(Scalar tolerance=0) const
Returns the sign of the expression.
Definition: gsExpressions.h:245
Definition: gsExpressions.h:3082
bool isScalar() const
Returns true iff the expression is scalar-valued.
Definition: gsExpressions.h:342
Definition: gsExpressions.h:2544
EIGEN_STRONG_INLINE jac_expr< E > jac(const symbol_expr< E > &u)
The Jacobian matrix of a FE variable.
Definition: gsExpressions.h:4530