1 /** @file gsExprAssembler.h
2 
3     @brief Generic expressions matrix assembly
4 
5     This file is part of the G+Smo library.
6 
7     This Source Code Form is subject to the terms of the Mozilla Public
8     License, v. 2.0. If a copy of the MPL was not distributed with this
9     file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 
11     Author(s): A. Mantzaflaris
12 */
13 
14 #pragma once
15 
16 #include <gsUtils/gsPointGrid.h>
17 #include <gsAssembler/gsQuadrature.h>
18 #include <gsAssembler/gsExprHelper.h>
19 
20 namespace gismo
21 {
22 
23 /**
24    Assembler class for generating matrices and right-hand sides based
25    on isogeometric expressions
26 */
27 template<class T>
28 class gsExprAssembler
29 {
30 private:
31     typename gsExprHelper<T>::Ptr m_exprdata;
32 
33     gsOptionList m_options;
34 
35     expr::gsFeElement<T> m_element;
36 
37     gsSparseMatrix<T> m_matrix;
38     gsMatrix<T>       m_rhs;
39 
40     std::vector<expr::gsFeSpace<T>*> m_vrow;
41     std::vector<expr::gsFeSpace<T>*> m_vcol;
42 
43     typedef typename gsExprHelper<T>::nullExpr    nullExpr;
44 
45 public:
46 
47     typedef typename gsSparseMatrix<T>::BlockView matBlockView;
48 
49     typedef typename gsSparseMatrix<T>::constBlockView matConstBlockView;
50 
51     typedef typename gsBoundaryConditions<T>::bcRefList   bcRefList;
52     typedef typename gsBoundaryConditions<T>::bcContainer bcContainer;
53     //typedef typename gsBoundaryConditions<T>::ppContainer ifContainer;
54     typedef gsBoxTopology::ifContainer ifContainer;
55 
56     typedef typename gsExprHelper<T>::element     element;     ///< Current element
57     typedef typename gsExprHelper<T>::geometryMap geometryMap; ///< Geometry map type
58 
59     typedef typename gsExprHelper<T>::variable    variable;    ///< Variable type
60     typedef typename gsExprHelper<T>::space       space;       ///< Space type
61     typedef typename expr::gsFeSolution<T>        solution;    ///< Solution type
62 
63     /*
64     typedef typename gsExprHelper<T>::function    function;    ///< Variable type
65     typedef typename gsExprHelper<T>::variable    variable;    ///< Space type
66     typedef typename expr::gsFeSolution<T>        solution;    ///< Solution type
67     */
68 public:
69 
cleanUp()70     void cleanUp()
71     {
72         m_exprdata->clean();
73     }
74 
75     /// Constructor
76     /// \param _rBlocks Number of spaces for test functions
77     /// \param _cBlocks Number of spaces for solution variables
78     gsExprAssembler(index_t _rBlocks = 1, index_t _cBlocks = 1)
m_exprdata(gsExprHelper<T>::make ())79     : m_exprdata(gsExprHelper<T>::make()), m_options(defaultOptions()),
80       m_vrow(_rBlocks,nullptr), m_vcol(_cBlocks,nullptr)
81     { }
82 
83     // The copy constructor replicates the same environemnt but does
84     // not copy any matrix data
85 
86     /// @brief Returns the list of default options for assembly
87     static gsOptionList defaultOptions();
88 
89     /// Returns the number of degrees of freedom (after initialization)
numDofs()90     index_t numDofs() const
91     {
92         GISMO_ASSERT( m_vcol.back()->mapper().isFinalized(),
93                       "gsExprAssembler::numDofs() says: initSystem() has not been called.");
94         return m_vcol.back()->mapper().firstIndex() +
95 	  m_vcol.back()->mapper().freeSize();
96     }
97 
98     /// Returns the number of test functions (after initialization)
numTestDofs()99     index_t numTestDofs() const
100     {
101         GISMO_ASSERT( m_vrow.back()->mapper().isFinalized(),
102                       "initSystem() has not been called.");
103         return m_vrow.back()->mapper().firstIndex() +
104 	  m_vrow.back()->mapper().freeSize();
105     }
106 
107     /// Returns the number of blocks in the matrix, corresponding to
108     /// variables/components
numBlocks()109     index_t numBlocks() const
110     {
111         index_t nb = 0;
112         for (size_t i = 0; i!=m_vrow.size(); ++i)
113             nb += m_vrow[i]->dim();
114         return nb;
115     }
116 
117     /// Returns a reference to the options structure
options()118     gsOptionList & options() {return m_options;}
119 
120     /// @brief Returns the left-hand global matrix
matrix()121     const gsSparseMatrix<T> & matrix() const { return m_matrix; }
122 
123     /// @brief Writes the resulting matrix in \a out. The internal matrix is moved.
matrix_into(gsSparseMatrix<T> & out)124     void matrix_into(gsSparseMatrix<T> & out) { out = give(m_matrix); }
125 
giveMatrix()126     EIGEN_STRONG_INLINE gsSparseMatrix<T> giveMatrix()
127     {
128          gsSparseMatrix<T> rvo;
129          rvo.swap(m_matrix);
130           return rvo;
131     }
132 
133     /// @brief Returns the right-hand side vector(s)
rhs()134     const gsMatrix<T> & rhs() const { return m_rhs; }
135 
136     /// @brief Writes the resulting vector in \a out. The internal data is moved.
rhs_into(gsMatrix<T> & out)137     void rhs_into(gsMatrix<T> & out) { out = give(m_rhs); }
138 
139     /// \brief Sets the domain of integration.
140     /// \warning Must be called before any computation is requested
setIntegrationElements(const gsMultiBasis<T> & mesh)141     void setIntegrationElements(const gsMultiBasis<T> & mesh)
142     { m_exprdata->setMultiBasis(mesh); }
143 
144 #if EIGEN_HAS_RVALUE_REFERENCES
145     void setIntegrationElements(const gsMultiBasis<T> &&) = delete;
146     //const gsMultiBasis<T> * c++98
147 #endif
148 
149     /// \brief Returns the domain of integration
integrationElements()150     const gsMultiBasis<T> & integrationElements() const
151     { return m_exprdata->multiBasis(); }
152 
exprData()153     const typename gsExprHelper<T>::Ptr exprData() const { return m_exprdata; }
154 
155     /// Registers \a mp as an isogeometric geometry map and return a handle to it
getMap(const gsMultiPatch<T> & mp)156     geometryMap getMap(const gsMultiPatch<T> & mp) //conv->tmp->error
157     { return m_exprdata->getMap(mp); }
158 
159     /// Registers \a g as an isogeometric geometry map and return a handle to it
getMap(const gsFunction<T> & g)160     geometryMap getMap(const gsFunction<T> & g)
161     { return m_exprdata->getMap(g); }
162 
163     /// Registers \a mp as an isogeometric (both trial and test) space
164     /// and return a handle to it
165     space getSpace(const gsFunctionSet<T> & mp, index_t dim = 1, index_t id = 0)
166     {
167         //if multiBasisSet() then check domainDom
168         GISMO_ASSERT(1==mp.targetDim(), "Expecting scalar source space");
169         GISMO_ASSERT(static_cast<size_t>(id)<m_vrow.size(),
170                      "Given ID "<<id<<" exceeds "<<m_vrow.size()-1 );
171         expr::gsFeSpace<T> & u = m_exprdata->getSpace(mp,dim);
172         u.setId(id);
173         m_vrow[id] = m_vcol[id] = &u;
174         return u;
175     }
176 
177     /// \brief Registers \a mp as an isogeometric test space
178     /// corresponding to trial space \a u and return a handle to it
179     ///
180     /// \note Both test and trial spaces are registered at once by
181     /// gsExprAssembler::getSpace.
182     ///
183     ///Use this function after calling gsExprAssembler::getSpace when
184     /// a distinct test space is requred (eg. Petrov-Galerkin
185     /// methods).
186     ///
187     /// \note The dimension is set to the same as \a u, unless the caller
188     /// sets as a third argument a new value.
189     space getTestSpace(space u, const gsFunctionSet<T> & mp, index_t dim = -1)
190     {
191         //GISMO_ASSERT(0!=u.mapper(), "Not a space"); // done on initSystem
192         expr::gsFeSpace<T> & s = m_exprdata->getSpace(mp,(-1 == dim ? u.dim() : dim));
193         space uu = static_cast<space>(u);
194         s.setId(uu.id());
195         m_vrow[s.id()] = &s;
196         return s;
197     }
198 
199     /// Return the variable (previously created by getSpace) with the given \a id
trialSpace(const index_t id)200     space trialSpace(const index_t id) const
201     {
202         GISMO_ASSERT(NULL!=m_vcol[id], "Not set.");
203         return *m_vcol[id];
204     }
205 
206     /// Return the trial space of a pre-existing test space \a v
trialSpace(space v)207     space trialSpace(space v) const { return trialSpace(v.id()); }
208 
209     /// Return the variable (previously created by getTrialSpace) with the given \a id
testSpace(const index_t id)210     space testSpace(const index_t id)
211     {
212         GISMO_ASSERT(NULL!=m_vrow[id], "Not set.");
213         return *m_vrow[id];
214     }
215 
216     /// Return the test space of a pre-existing trial space \a u
testSpace(space u)217     space testSpace(space u) const { return testSpace(u.id()); }
218 
219     /// Registers \a func as a variable and returns a handle to it
220     ///
getCoeff(const gsFunctionSet<T> & func)221     variable getCoeff(const gsFunctionSet<T> & func)
222     { return m_exprdata->getVar(func, 1); }
223 
224     /// Registers \a func as a variable defined on \a G and returns a handle to it
225     ///
getCoeff(const gsFunctionSet<T> & func,geometryMap G)226     variable getCoeff(const gsFunctionSet<T> & func, geometryMap G)
227     { return m_exprdata->getVar(func,G); }
228 
229     /// \brief Registers a representation of a solution variable from
230     /// space \a s, based on the vector \a cf.
231     ///
232     /// The vector \a cf should have the structure of the columns of
233     /// the system matrix this->matrix(). The returned handle
234     /// corresponds to a function in the space \a s
getSolution(space s,gsMatrix<T> & cf)235     solution getSolution(space s, gsMatrix<T> & cf) const
236     {
237         // todo: if (m_exprdata->isSpace(u));
238         //space s = static_cast<space>(u);
239         return solution(s, cf);
240     }
241 
getBdrFunction()242     variable getBdrFunction() const { return m_exprdata->getMutVar(); }
243 
getElement()244     element getElement() const { return m_element; }
245 
246     void computeDirichletDofs2(short_t unk);
247     void computeDirichletDofsIntpl2(const expr::gsFeSpace<T> & u);
248     void computeDirichletDofsL2Proj(const expr::gsFeSpace<T> & u);
249     void setFixedDofVector(gsMatrix<T> & dof, short_t unk = 0);
250     void setFixedDofs(const gsMatrix<T> & coefMatrix, short_t unk = 0, size_t patch = 0);
251 
252     /// \brief Initializes the sparse system (sparse matrix and rhs)
253     void initSystem(bool resetFirst = true)
254     {
255         // Check spaces.nPatches==mesh.patches
256         initMatrix(resetFirst);
257         m_rhs.setZero(numDofs(), 1);
258 
259         // USE setup and gsDirichletValues instead
260         //for (size_t i = 0; i!= m_vcol.size(); ++i)
261         // computeDirichletDofs2(i);
262     }
263 
264     /// \brief Initializes the sparse matrix only
265     void initMatrix(bool resetFirst = true)
266     {
267         if (resetFirst)
268             resetSpaces();
269         resetDimensions();
270         m_matrix = gsSparseMatrix<T>(numTestDofs(), numDofs());
271 
272         if ( 0 == m_matrix.rows() || 0 == m_matrix.cols() )
273             gsWarn << " No internal DOFs, zero sized system.\n";
274         else
275         {
276             // Pick up values from options
277             const T bdA       = m_options.getReal("bdA");
278             const index_t bdB = m_options.getInt("bdB");
279             const T bdO       = m_options.getReal("bdO");
280             T nz = 1;
281             const short_t dim = m_exprdata->multiBasis().domainDim();
282             for (short_t i = 0; i != dim; ++i)
283                 nz *= bdA * m_exprdata->multiBasis().maxDegree(i) + bdB;
284 
285             m_matrix.reservePerColumn(numBlocks()*cast<T,index_t>(nz*(1.0+bdO)) );
286         }
287     }
288 
289     /// \brief Initializes the right-hand side vector only
290     void initVector(const index_t numRhs = 1, bool resetFirst = true)
291     {
292         if (resetFirst)
293             resetSpaces();
294         resetDimensions();
295         m_rhs.setZero(numDofs(), numRhs);
296     }
297 
298     /// Returns a block view of the system matrix, each block
299     /// corresponding to a different space, or to different groups of
300     /// dofs, in case of calar problems
matrixBlockView()301     matBlockView matrixBlockView()
302     {
303         GISMO_ASSERT( m_vcol.back()->mapper().isFinalized(),
304                       "initSystem() has not been called.");
305         gsVector<index_t> rowSizes, colSizes;
306         _blockDims(rowSizes, colSizes);
307         return m_matrix.blockView(rowSizes,colSizes);
308     }
309 
310     /// Returns a const block view of the system matrix, each block
311     /// corresponding to a different space, or to different groups of
312     /// dofs, in case of calar problems
matrixBlockView()313     matConstBlockView matrixBlockView() const
314     {
315         GISMO_ASSERT( m_vcol.back()->mapper().isFinalized(),
316                       "initSystem() has not been called.");
317         gsVector<index_t> rowSizes, colSizes;
318         _blockDims(rowSizes, colSizes);
319         return m_matrix.blockView(rowSizes,colSizes);
320     }
321 
322     /// Set the assembler options
setOptions(gsOptionList opt)323     void setOptions(gsOptionList opt) { m_options = opt; } // gsOptionList opt
324     // .swap(opt) todo
325 
326 #   if(__cplusplus >= 201103L || _MSC_VER >= 1600 || defined(__DOXYGEN__))
327     /// Adds the expressions \a args to the system matrix/rhs
328     ///
329     /// The arguments are considered as integrals over the whole domain
330     /// \sa gsExprAssembler::setIntegrationElements
331     template<class... expr> void assemble(expr... args);
332 
333     /// Adds the expressions \a args to the system matrix/rhs
334     ///
335     /// The arguments are considered as integrals over the boundary parts in \a BCs
336     template<class... expr> void assemble(const bcRefList & BCs, expr... args);
337 
338     /*
339       template<class... expr> void assemble(const ifContainer & iFaces, expr... args);
340       template<class... expr> void collocate(expr... args);// eg. collocate(-ilapl(u), f)
341     */
342 #else
assemble(const expr::_expr<E1> & a1)343     template<class E1> void assemble(const expr::_expr<E1> & a1)
344     {assemble(a1,nullExpr(),nullExpr(),nullExpr(),nullExpr());}
345     template <class E1, class E2>
assemble(const expr::_expr<E1> & a1,const expr::_expr<E2> & a2)346     void assemble(const expr::_expr<E1> & a1, const expr::_expr<E2> & a2)
347     {assemble(a1,a2,nullExpr(),nullExpr(),nullExpr());}
348     template <class E1, class E2, class E3>
assemble(const expr::_expr<E1> & a1,const expr::_expr<E2> & a2,const expr::_expr<E3> & a3)349     void assemble(const expr::_expr<E1> & a1, const expr::_expr<E2> & a2,
350                   const expr::_expr<E3> & a3)
351     {assemble(a1,a2,a3,nullExpr(),nullExpr());}
352     template <class E1, class E2, class E3, class E4, class E5>
assemble(const expr::_expr<E1> & a1,const expr::_expr<E2> & a2,const expr::_expr<E3> & a3,const expr::_expr<E4> & a4)353     void assemble(const expr::_expr<E1> & a1, const expr::_expr<E2> & a2,
354                   const expr::_expr<E3> & a3, const expr::_expr<E4> & a4)
355     {assemble(a1,a2,a3,a4,nullExpr());}
356     template <class E1, class E2, class E3, class E4, class E5>
357     void assemble(const expr::_expr<E1> & a1, const expr::_expr<E2> & a2,
358                   const expr::_expr<E3> & a3, const expr::_expr<E4> & a4,
359                   const expr::_expr<E5> & a5 );
360 
361     template<class E1> void assemble(const bcRefList & BCs, const expr::_expr<E1> & a1);
362 #   endif
363 
364     template<class E1, class E2>
assembleLhsRhsBc(const expr::_expr<E1> & exprLhs,const expr::_expr<E2> & exprRhs,const bcContainer & BCs)365     void assembleLhsRhsBc(const expr::_expr<E1> & exprLhs,
366                           const expr::_expr<E2> & exprRhs,
367                           const bcContainer & BCs)
368     {
369         space rvar = static_cast<space>(exprLhs.rowVar());
370         GISMO_ASSERT(m_exprdata->exists(rvar), "Error - inexistent variable.");
371         space cvar = static_cast<space>(exprLhs.colVar());
372         GISMO_ASSERT(m_exprdata->exists(cvar), "Error - inexistent variable.");
373         GISMO_ASSERT(&rvar==&exprRhs.rowVar(), "Inconsistent left and right hand side");
374         assembleLhsRhsBc_impl<true,true>(exprLhs, exprRhs, rvar, cvar, BCs);
375     }
376 
377     template<class E1>
assembleRhsBc(const expr::_expr<E1> & exprRhs,const bcContainer & BCs)378     void assembleRhsBc(const expr::_expr<E1> & exprRhs, const bcContainer & BCs)
379     {
380         space var = static_cast<space>(exprRhs.rowVar());
381         GISMO_ASSERT(m_exprdata->exists(var), "Error - inexistent variable.");
382         assembleLhsRhsBc_impl<false,true>(nullExpr(), exprRhs, var, var, BCs);
383     }
384 
385     template<class E1>
assembleInterface(const expr::_expr<E1> & exprInt)386     void assembleInterface(const expr::_expr<E1> & exprInt)
387     {
388         space rvar = static_cast<space>(exprInt.rowVar());
389         space cvar = static_cast<space>(exprInt.colVar());
390         assembleInterface_impl<true,false>(exprInt, nullExpr(), rvar, rvar, m_exprdata->multiBasis().topology().interfaces() );
391     }
392 
393     template<class E1>
assembleRhsInterface(const expr::_expr<E1> & exprInt,const ifContainer & iFaces)394     void assembleRhsInterface(const expr::_expr<E1> & exprInt, const ifContainer & iFaces)
395     {
396         space rvar = static_cast<space>(exprInt.rowVar());
397         GISMO_ASSERT(m_exprdata->exists(rvar), "Error - inexistent variable.");
398         assembleInterface_impl<false,true>(nullExpr(), exprInt, rvar, rvar, iFaces);
399     }
400 
401 private:
402 
_blockDims(gsVector<index_t> & rowSizes,gsVector<index_t> & colSizes)403     void _blockDims(gsVector<index_t> & rowSizes,
404                     gsVector<index_t> & colSizes)
405     {
406         if (1==m_vcol.size() && 1==m_vrow.size())
407         {
408             const gsDofMapper & dm = m_vcol.back()->mapper();
409             rowSizes.resize(3);
410             colSizes.resize(3);
411             rowSizes[0]=colSizes[0] = dm.freeSize()-dm.coupledSize();
412             rowSizes[1]=colSizes[1] = dm.coupledSize();
413             rowSizes[2]=colSizes[2] = dm.boundarySize();
414         }
415         else
416         {
417             rowSizes.resize(m_vrow.size());
418             for (index_t r = 0; r != rowSizes.size(); ++r) // for all row-blocks
419                 rowSizes[r] = m_vrow[r]->dim() * m_vrow[r]->mapper().freeSize();
420             colSizes.resize(m_vcol.size());
421             for (index_t c = 0; c != colSizes.size(); ++c) // for all col-blocks
422                 colSizes[c] = m_vcol[c]->dim() * m_vcol[c]->mapper().freeSize();
423         }
424     }
425 
426     /// \brief Reset the dimensions of all involved spaces.
427     /// Called internally by the init* functions
428     void resetDimensions();
429 
430     void resetSpaces();
431 
432     // template<bool left, bool right, class E1, class E2>
433     // void assembleLhsRhs_impl(const expr::_expr<E1> & exprLhs,
434     //                          const expr::_expr<E2> & exprRhs,
435     //                          space rvar, space cvar);
436 
437     template<bool left, bool right, class E1, class E2>
438     void assembleLhsRhsBc_impl(const expr::_expr<E1> & exprLhs,
439                                const expr::_expr<E2> & exprRhs,
440                                space rvar, space cvar,
441                                const bcContainer & BCs);
442 
443     template<bool left, bool right, class E1, class E2>
444     void assembleInterface_impl(const expr::_expr<E1> & exprLhs,
445                                 const expr::_expr<E2> & exprRhs,
446                                 space rvar, space cvar,
447                                 const ifContainer & iFaces);
448 
449 #if __cplusplus >= 201103L || _MSC_VER >= 1600 // c++11
450     template <class op, class E1>
_apply(op _op,const expr::_expr<E1> & firstArg)451     void _apply(op _op, const expr::_expr<E1> & firstArg) {_op(firstArg);}
452     template <class op, class E1, class... Rest>
_apply(op _op,const expr::_expr<E1> & firstArg,Rest...restArgs)453     void _apply(op _op, const expr::_expr<E1> & firstArg, Rest... restArgs)
454     { _op(firstArg); _apply<op>(_op, restArgs...); }
455 #endif
456 
457     struct __setFlag
458     {
operator__setFlag459         template <typename E> void operator() (const gismo::expr::_expr<E> & v)
460         { v.setFlag(); }
461 
operator__setFlag462         void operator() (const expr::_expr<expr::gsNullExpr<T> > &) {}
463     } _setFlag;
464 
465     struct __printExpr
466     {
operator__printExpr467         template <typename E> void operator() (const gismo::expr::_expr<E> & v)
468         { v.print(gsInfo);gsInfo<<"\n"; }
469     } _printExpr;
470 
471     struct _eval
472     {
473         gsSparseMatrix<T> & m_matrix;
474         gsMatrix<T>       & m_rhs;
475         const gsVector<T> & m_quWeights;
476         index_t       m_patchInd;
477         gsMatrix<T>         localMat;
478 
_eval_eval479         _eval(gsSparseMatrix<T> & _matrix,
480               gsMatrix<T>       & _rhs,
481               const gsVector<>  & _quWeights)
482         : m_matrix(_matrix), m_rhs(_rhs),
483           m_quWeights(_quWeights), m_patchInd(0)
484         { }
485 
setPatch_eval486         void setPatch(const index_t p) { m_patchInd=p; }
487 
operator_eval488         template <typename E> void operator() (const gismo::expr::_expr<E> & ee)
489         {
490             // ------- Compute  -------
491             const T * w = m_quWeights.data();
492             localMat.noalias() = (*w) * ee.eval(0);
493             for (index_t k = 1; k != m_quWeights.rows(); ++k)
494                 localMat.noalias() += (*(++w)) * ee.eval(k);
495 
496             //  ------- Accumulate  -------
497             if (E::isMatrix())
498                 push<true>(ee.rowVar(), ee.colVar(), m_patchInd);
499             else if (E::isVector())
500                 push<false>(ee.rowVar(), ee.colVar(), m_patchInd);
501             else
502             {
503                 GISMO_ERROR("Something went wrong at this point (rowspan: "<< E::rowSpan<< ", colSpan: "<< E::colSpan <<")");
504                 //GISMO_ASSERTrowSpan() && (!colSpan())
505             }
506 
507         }// operator()
508 
operator_eval509         void operator() (const expr::_expr<expr::gsNullExpr<T> > &) {}
510 
push_eval511         template<bool isMatrix> void push(const expr::gsFeSpace<T> & v,
512                                           const expr::gsFeSpace<T> & u,
513                                           const index_t patchInd)
514         {
515             GISMO_ASSERT(v.isValid(), "The row space is not valid");
516             GISMO_ASSERT(!isMatrix || u.isValid(), "The column space is not valid");
517             GISMO_ASSERT(isMatrix || (0!=m_rhs.size()), "The right-hand side vector is not initialized");
518 
519             const index_t cd            = u.dim();
520             const index_t rd            = v.dim();
521             const gsDofMapper  & colMap = u.mapper();
522             const gsDofMapper  & rowMap = v.mapper();
523             gsMatrix<index_t> & colInd0 = const_cast<gsMatrix<index_t>&>(u.data().actives);
524             gsMatrix<index_t> & rowInd0 = const_cast<gsMatrix<index_t>&>(v.data().actives);
525             const gsMatrix<T>  & fixedDofs = u.fixedPart();
526 
527             gsMatrix<index_t> rowInd, colInd;
528             rowMap.localToGlobal(rowInd0, patchInd, rowInd);
529 
530             if (isMatrix)
531             {
532                 //if (&rowInd0!=&colInd0)
533                 colMap.localToGlobal(colInd0, patchInd, colInd);
534                 GISMO_ASSERT( colMap.boundarySize()==fixedDofs.size(),
535                               "Invalid values for fixed part");
536             }
537             for (index_t r = 0; r != rd; ++r)
538             {
539                 const index_t rls = r * rowInd0.rows();     //local stride
540                 for (index_t i = 0; i != rowInd0.rows(); ++i)
541                 {
542                     const index_t ii = rowMap.index(rowInd0.at(i),patchInd,r); // N_i
543                     if ( rowMap.is_free_index(ii) )
544                     {
545                         for (index_t c = 0; c != cd; ++c)
546                         {
547                             if (isMatrix)
548                             {
549                                 const index_t cls = c * colInd0.rows();     //local stride
550 
551                                 for (index_t j = 0; j != colInd0.rows(); ++j)
552                                 {
553                                     if ( 0 == localMat(rls+i,cls+j) ) continue;
554 
555                                     const index_t jj = colMap.index(colInd0.at(j),patchInd,c); // N_j
556                                     if ( colMap.is_free_index(jj) )
557                                     {
558                                         // If matrix is symmetric, we could
559                                         // store only lower triangular part
560                                         //if ( (!symm) || jj <= ii )
561                                         m_matrix.coeffRef(ii, jj) += localMat(rls+i,cls+j);
562                                     }
563                                     else // colMap.is_boundary_index(jj) )
564                                     {
565                                         // Symmetric treatment of eliminated BCs
566                                         // GISMO_ASSERT(1==m_rhs.cols(), "-");
567                                         m_rhs.at(ii) -= localMat(rls+i,cls+j) *
568                                             fixedDofs.at(colMap.global_to_bindex(jj));
569                                     }
570                                 }
571                             }
572                             else
573                             {
574                                 m_rhs.row(ii) += localMat.row(rls+i);
575                             }
576                         }
577                     }
578                 }
579             }
580         }//push
581 
582     };
583 
584 }; // gsExprAssembler
585 
586 template<class T>
defaultOptions()587 gsOptionList gsExprAssembler<T>::defaultOptions()
588 {
589     gsOptionList opt;
590     opt.addInt("DirichletValues"  , "Method for computation of Dirichlet DoF values [100..103]", 101);
591     opt.addReal("quA", "Number of quadrature points: quA*deg + quB", 1.0  );
592     opt.addInt ("quB", "Number of quadrature points: quA*deg + quB", 1    );
593     opt.addReal("bdA", "Estimated nonzeros per column of the matrix: bdA*deg + bdB", 2.0  );
594     opt.addInt ("bdB", "Estimated nonzeros per column of the matrix: bdA*deg + bdB", 1    );
595     opt.addReal("bdO", "Overhead of sparse mem. allocation: (1+bdO)(bdA*deg + bdB) [0..1]", 0.333);
596     return opt;
597 }
598 
599 template<class T>
computeDirichletDofs2(short_t unk)600 void gsExprAssembler<T>::computeDirichletDofs2(short_t unk)
601 {
602     expr::gsFeSpace<T> & u = *m_vcol[unk];
603 
604     //if ( m_options.getInt("DirichletStrategy") == dirichlet::nitsche)
605     //    return; // Nothing to compute
606 
607     //const gsMultiBasis<T> & mbasis = dynamic_cast<const gsMultiBasis<T>&>(u.source());
608 
609     // eg. not penalize
610     const gsDofMapper & mapper = u.mapper();
611 
612     switch ( m_options.getInt("DirichletValues") )
613     {
614     case dirichlet::homogeneous:
615         // If we have a homogeneous Dirichlet problem fill boundary
616         // DoFs with zeros
617         u.fixedPart().setZero(mapper.boundarySize(), 1 );
618         break;
619     case dirichlet::interpolation:
620         computeDirichletDofsIntpl2(u);
621         break;
622     case dirichlet::l2Projection:
623         computeDirichletDofsL2Proj(u); //this->computeDirichletDofsL2Proj(mapper, mbasis,unk);
624         break;
625     case dirichlet::user :
626         // Assuming that the DoFs are already set by the user
627         GISMO_ENSURE( u.fixedPart().size() == mapper.boundarySize(),
628                       "The Dirichlet DoFs are not set.");
629         break;
630     default:
631         GISMO_ERROR("Something went wrong with Dirichlet values.");
632     }
633 
634     /* Corner values -- todo
635     for ( typename gsBoundaryConditions<T>::const_citerator
636               it = bbc.cornerBegin();
637           it != bbc.cornerEnd(); ++it )
638     {
639         if(it->unknown == unk)
640         {
641             const index_t i  = mbasis[it->patch].functionAtCorner(it->corner);
642             const index_t ii = mapper.bindex( i , it->patch );
643             u.fixedPart().row(ii).setConstant(it->value);
644         }
645         else
646             continue;
647     }
648     */
649 }
650 
651 template<class T>
setFixedDofVector(gsMatrix<T> & vals,short_t unk)652 void gsExprAssembler<T>::setFixedDofVector(gsMatrix<T> & vals, short_t unk)
653 {
654     expr::gsFeSpace<T> & u = *m_vcol[unk];
655     gsMatrix<T>        & fixedDofs = const_cast<expr::gsFeSpace<T>&>(u).fixedPart();
656     fixedDofs.swap(vals);
657     vals.resize(0, 0);
658     // Assuming that the DoFs are already set by the user
659     GISMO_ENSURE( fixedDofs.size() == u.mapper().boundarySize(),
660                      "The Dirichlet DoFs were not provided correctly.");
661 }
662 
663 template<class T>
setFixedDofs(const gsMatrix<T> & coefMatrix,short_t unk,size_t patch)664 void gsExprAssembler<T>::setFixedDofs(const gsMatrix<T> & coefMatrix, short_t unk, size_t patch)
665 {
666     GISMO_ASSERT( m_options.getInt("DirichletValues") == dirichlet::user, "Incorrect options");
667 
668     expr::gsFeSpace<T> & u = *m_vcol[unk];
669     //const index_t dirStr = m_options.getInt("DirichletStrategy");
670     const gsMultiBasis<T> & mbasis = *dynamic_cast<const gsMultiBasis<T>* >(&(u).source());
671 
672     //const gsBoundaryConditions<> & bbc = u.hasBc() ? u.bc() : gsBoundaryConditions<>();
673 
674     const gsDofMapper & mapper = u.mapper();
675 //    const gsDofMapper & mapper =
676 //        dirichlet::elimination == dirStr ? u.mapper()
677 //        : mbasis.getMapper(dirichlet::elimination,
678 //                           static_cast<iFace::strategy>(m_options.getInt("InterfaceStrategy")),
679 //                           bbc, u.id()) ;
680 
681     gsMatrix<T> & fixedDofs = const_cast<expr::gsFeSpace<T>& >(u).fixedPart();
682     GISMO_ASSERT(fixedDofs.size() == mapper.boundarySize(),
683                  "Fixed DoFs were not initialized.");
684 
685     // for every side with a Dirichlet BC
686     // for ( typename gsBoundaryConditions<T>::const_iterator
687     //       it =  bbc.dirichletBegin();
688     //       it != bbc.dirichletEnd()  ; ++it )
689     typedef typename gsBoundaryConditions<T>::bcRefList bcRefList;
690     for ( typename bcRefList::const_iterator it =  u.bc().dirichletBegin();
691           it != u.bc().dirichletEnd()  ; ++it )
692     {
693         const index_t com = it->unkComponent();
694         const index_t k = it->patch();
695         if ( k == patch )
696         {
697             // Get indices in the patch on this boundary
698             const gsMatrix<index_t> boundary =
699                     mbasis[k].boundary(it->side());
700 
701             //gsInfo <<"Setting the value for: "<< boundary.transpose() <<"\n";
702 
703             for (index_t i=0; i!= boundary.size(); ++i)
704             {
705                 // Note: boundary.at(i) is the patch-local index of a
706                 // control point on the patch
707                 const index_t ii  = mapper.bindex( boundary.at(i) , k, com );
708 
709                 fixedDofs.at(ii) = coefMatrix(boundary.at(i), com);
710             }
711         }
712     }
713 } // setFixedDofs
714 
resetSpaces()715 template<class T> void gsExprAssembler<T>::resetSpaces()
716 {
717     for (size_t i = 0; i!=m_vcol.size(); ++i)
718     {
719         GISMO_ASSERT(NULL!=m_vcol[i], "The assembler spaces where not set.");
720         m_vcol[i]->reset();
721 
722         if ( m_vcol[i] != m_vrow[i] )
723         {
724             GISMO_ASSERT(NULL!=m_vrow[i], "The assembler spaces where not set.");
725             m_vrow[i]->reset();
726         }
727     }
728 }
729 
resetDimensions()730 template<class T> void gsExprAssembler<T>::resetDimensions()
731 {
732     for (size_t i = 1; i!=m_vcol.size(); ++i)
733     {
734         m_vcol[i]->mapper().setShift(m_vcol[i-1]->mapper().firstIndex() +
735                                      m_vcol[i-1]->dim()*m_vcol[i-1]->mapper().freeSize() );
736 
737         if ( m_vcol[i] != m_vrow[i] )
738             m_vrow[i]->mapper().setShift(m_vrow[i-1]->mapper().firstIndex() +
739                                          m_vrow[i-1]->dim()*m_vrow[i-1]->mapper().freeSize() );
740     }
741 }
742 
743 template<class T>
744 #if(__cplusplus >= 201103L || _MSC_VER >= 1600 || defined(__DOXYGEN__)) // c++11
745 template<class... expr>
assemble(expr...args)746 void gsExprAssembler<T>::assemble(expr... args)
747 #else
748     template <class E1, class E2, class E3, class E4, class E5>
749     void gsExprAssembler<T>::assemble( const expr::_expr<E1> & a1, const expr::_expr<E2> & a2,
750     const expr::_expr<E3> & a3, const expr::_expr<E4> & a4, const expr::_expr<E5> & a5)
751 #endif
752 {
753     GISMO_ASSERT(matrix().cols()==numDofs(), "System not initialized");
754 
755     // initialize flags
756     m_exprdata->initFlags(SAME_ELEMENT|NEED_ACTIVE, SAME_ELEMENT);
757 #   if __cplusplus >= 201103L || _MSC_VER >= 1600
758     _apply(_setFlag, args...);
759     //_apply(_printExpr, args...);
760 #   else
761     _setFlag(a1);_setFlag(a1);_setFlag(a2);_setFlag(a4);_setFlag(a5);
762 #   endif
763     typename gsQuadRule<T>::uPtr QuRule;
764     gsVector<T> quWeights; // quadrature weights
765 
766     _eval ee(m_matrix, m_rhs, quWeights);
767 
768     for (unsigned patchInd = 0; patchInd < m_exprdata->multiBasis().nBases(); ++patchInd)
769     {
770         ee.setPatch(patchInd);
771         QuRule = gsQuadrature::getPtr(m_exprdata->multiBasis().basis(patchInd), m_options);
772 
773         // Initialize domain element iterator for current patch
774         typename gsBasis<T>::domainIter domIt =  // add patchInd to domainiter ?
775             m_exprdata->multiBasis().basis(patchInd).makeDomainIterator();
776         m_element.set(*domIt);
777 
778         // Start iteration over elements of patchInd
779         for (; domIt->good(); domIt->next() )
780         {
781             // Map the Quadrature rule to the element
782             QuRule->mapTo( domIt->lowerCorner(), domIt->upperCorner(),
783                            m_exprdata->points(), quWeights);
784 
785             if (m_exprdata->points().cols()==0)
786                 continue;
787 
788             // Perform required pre-computations on the quadrature nodes
789             m_exprdata->precompute(patchInd);
790             //m_exprdata->precompute(QuRule, *domIt); // todo
791 
792             // Assemble contributions of the element
793 #           if __cplusplus >= 201103L || _MSC_VER >= 1600
794             _apply(ee, args...);
795 #           else
796             ee(a1);ee(a2);ee(a3);ee(a4);ee(a5);
797 #           endif
798         }
799     }
800 
801     m_matrix.makeCompressed();
802 }
803 
804 template<class T>
805 #if __cplusplus >= 201103L || _MSC_VER >= 1600 // c++11
806 template<class... expr>
assemble(const bcRefList & BCs,expr...args)807 void gsExprAssembler<T>::assemble(const bcRefList & BCs, expr... args)
808 #else
809 template <class E1>
810 void gsExprAssembler<T>::assemble(const bcRefList & BCs, const expr::_expr<E1> & a1)
811 #endif
812 {
813     // initialize flags
814     m_exprdata->initFlags(SAME_ELEMENT|NEED_ACTIVE, SAME_ELEMENT);
815 #   if __cplusplus >= 201103L || _MSC_VER >= 1600
816     _apply(_setFlag, args...);
817 #   else
818     _setFlag(a1);
819 #   endif
820 
821     gsVector<T> quWeights;// quadrature weights
822     typename gsQuadRule<T>::uPtr QuRule;
823 
824     _eval ee(m_matrix, m_rhs, quWeights);
825 
826     for (typename bcRefList::const_iterator iit = BCs.begin(); iit!= BCs.end(); ++iit)
827     {
828         const boundary_condition<T> * it = &iit->get();
829 
830         QuRule = gsQuadrature::getPtr(m_exprdata->multiBasis().basis(it->patch()), m_options, it->side().direction());
831         m_exprdata->mapData.side = it->side();
832 
833         // Update boundary function source
834         m_exprdata->setMutSource(*it->function(), it->parametric());
835         //mutVar.registerVariable(func, mutData);
836 
837         typename gsBasis<T>::domainIter domIt =
838             m_exprdata->multiBasis().basis(it->patch()).makeDomainIterator(it->side());
839         m_element.set(*domIt);
840 
841         // Start iteration over elements
842         for (; domIt->good(); domIt->next() )
843         {
844             // Map the Quadrature rule to the element
845             QuRule->mapTo( domIt->lowerCorner(), domIt->upperCorner(),
846                            m_exprdata->points(), quWeights);
847 
848             if (m_exprdata->points().cols()==0)
849                 continue;
850 
851             // Perform required pre-computations on the quadrature nodes
852             m_exprdata->precompute(it->patch());
853 
854             // Assemble contributions of the element
855 #           if __cplusplus >= 201103L || _MSC_VER >= 1600
856             _apply(ee, args...);
857 #           else
858             ee(a1);
859 #           endif
860         }
861     }
862 
863     //this->finalize();
864     m_matrix.makeCompressed();
865     //g_bd.clear();
866     //mutVar.clear();
867 }
868 
869 
870 template<class T>
871 template<bool left, bool right, class E1, class E2>
assembleLhsRhsBc_impl(const expr::_expr<E1> & exprLhs,const expr::_expr<E2> & exprRhs,space rvar,space cvar,const bcContainer & BCs)872 void gsExprAssembler<T>::assembleLhsRhsBc_impl(const expr::_expr<E1> & exprLhs,
873                                                const expr::_expr<E2> & exprRhs,
874                                                space rvar, space cvar,
875                                                const bcContainer & BCs)
876 {
877     //GISMO_ASSERT( exprRhs.isVector(), "Expecting vector expression");
878 
879     // initialize flags
880     m_exprdata->initFlags(SAME_ELEMENT|NEED_ACTIVE, SAME_ELEMENT);
881     if (left ) exprLhs.setFlag();
882     if (right) exprRhs.setFlag();
883 
884     gsVector<T> quWeights;// quadrature weights
885     typename gsQuadRule<T>::uPtr QuRule;
886     _eval ee(m_matrix, m_rhs, quWeights);
887 
888     for (typename bcContainer::const_iterator it = BCs.begin(); it!= BCs.end(); ++it)
889     {
890         QuRule = gsQuadrature::getPtr(m_exprdata->multiBasis().basis(it->patch()), m_options, it->side().direction());
891 
892         m_exprdata->mapData.side = it->side();
893 
894         // Update boundary function source
895         m_exprdata->setMutSource(*it->function(), it->parametric());
896         //mutVar.registerVariable(func, mutData);
897 
898         typename gsBasis<T>::domainIter domIt =
899             m_exprdata->multiBasis().basis(it->patch()).makeDomainIterator(it->side());
900         m_element.set(*domIt);
901 
902         // Start iteration over elements
903         for (; domIt->good(); domIt->next() )
904         {
905             // Map the Quadrature rule to the element
906             QuRule->mapTo( domIt->lowerCorner(), domIt->upperCorner(),
907                            m_exprdata->points(), quWeights);
908 
909             if (m_exprdata->points().cols()==0)
910                 continue;
911 
912             // Perform required pre-computations on the quadrature nodes
913             m_exprdata->precompute(it->patch());
914 
915             ee.setPatch(it->patch());
916     	    ee(exprLhs);
917 	        ee(exprRhs);
918         }
919     }
920 
921     //this->finalize();
922     m_matrix.makeCompressed();
923     //g_bd.clear();
924     //mutVar.clear();
925 }
926 
927 template<class T>
928 template<bool left, bool right, class E1, class E2>
assembleInterface_impl(const expr::_expr<E1> & exprLhs,const expr::_expr<E2> & exprRhs,space rvar,space cvar,const ifContainer & iFaces)929 void gsExprAssembler<T>::assembleInterface_impl(const expr::_expr<E1> & exprLhs,
930                                                 const expr::_expr<E2> & exprRhs,
931                                                 space rvar, space cvar,
932                                                 const ifContainer & iFaces)
933 {
934     //GISMO_ASSERT( exprRhs.isVector(), "Expecting vector expression");
935 
936     // initialize flags
937 
938     m_exprdata->initFlags(SAME_ELEMENT|NEED_ACTIVE, SAME_ELEMENT);
939     if (left ) exprLhs.setFlag();
940     if (right) exprRhs.setFlag();
941     //m_exprdata->parse(exprLhs,exprRhs);
942     //m_exprdata->parse(exprRhs);
943 
944     gsVector<T> quWeights;// quadrature weights
945     typename gsQuadRule<T>::uPtr QuRule;
946     _eval ee(m_matrix, m_rhs, quWeights);
947 
948     //gsMatrix<T> tmp;
949 
950     for (gsBoxTopology::const_iiterator it = iFaces.begin();
951          it != iFaces.end(); ++it )
952     {
953         const boundaryInterface & iFace = *it;
954         const index_t patch1 = iFace.first() .patch;
955         //const index_t patch2 = iFace.second().patch;
956         //const gsAffineFunction<T> interfaceMap(m_pde_ptr->patches().getMapForInterface(bi));
957 
958         QuRule = gsQuadrature::getPtr(m_exprdata->multiBasis().basis(patch1),
959                                    m_options, iFace.first().side().direction());
960 
961         m_exprdata->mapData.side = iFace.first().side(); // (!)
962 
963         typename gsBasis<T>::domainIter domIt =
964             m_exprdata->multiBasis().basis(patch1).makeDomainIterator(iFace.first().side());
965         m_element.set(*domIt);
966 
967         // Start iteration over elements
968         for (; domIt->good(); domIt->next() )
969         {
970             // Map the Quadrature rule to the element
971             QuRule->mapTo( domIt->lowerCorner(), domIt->upperCorner(),
972                            m_exprdata->points(), quWeights);
973 
974             if (m_exprdata->points().cols()==0)
975                 continue;
976 
977             // Perform required pre-computations on the quadrature nodes
978             m_exprdata->precompute(patch1);
979 
980             // DG: need data1, data2
981             // coupling: need to know patch1/patch2
982 
983 //            interfaceMap.eval_into(m_exprdata->points(), tmp);
984 //            m_exprdata->points().swap(tmp);
985 //            m_exprdata->precompute(patch2);
986 
987         ee.setPatch(patch1);
988 	    ee(exprLhs);
989 	    ee(exprRhs);
990         }
991     }
992 
993     m_matrix.makeCompressed();
994 }
995 
996 
997 template<class T> //
computeDirichletDofsIntpl2(const expr::gsFeSpace<T> & u)998 void gsExprAssembler<T>::computeDirichletDofsIntpl2(const expr::gsFeSpace<T> & u)
999 {
1000     const gsDofMapper  & mapper    = u.mapper();
1001     gsMatrix<T>        & fixedDofs = const_cast<expr::gsFeSpace<T>&>(u).fixedPart();
1002     fixedDofs.resize(mapper.boundarySize(), u.dim() );
1003     const index_t parDim = u.source().domainDim();
1004 
1005     const gsMultiBasis<T> & mbasis =
1006         *dynamic_cast<const gsMultiBasis<T>*>(&u.source());
1007 
1008     // Iterate over all patch-sides with Boundary conditions
1009     typedef typename gsBoundaryConditions<T>::bcRefList bcRefList;
1010     for ( typename bcRefList::const_iterator iit =  u.bc().begin();
1011           iit != u.bc().end()  ; ++iit )
1012     {
1013         const boundary_condition<T> * it = &iit->get();
1014         const index_t com = it->unkComponent();
1015 
1016         const index_t k = it->patch();
1017         if( it->unknown()!=u.id() )
1018             continue;
1019         const gsBasis<T> & basis = mbasis[k];
1020 
1021         // Get dofs on this boundary
1022         const gsMatrix<index_t> boundary = basis.boundary(it->side());
1023 
1024         // If the condition is homogeneous then fill with zeros
1025         if ( it->isHomogeneous() )
1026         {
1027             for (index_t i=0; i!= boundary.size(); ++i)
1028             {
1029                 const index_t ii= mapper.bindex( boundary.at(i) , k, com );
1030                 fixedDofs.at(ii) = 0;
1031             }
1032             continue;
1033         }
1034 
1035         // Get the side information
1036         short_t dir = it->side().direction( );
1037         index_t param = (it->side().parameter() ? 1 : 0);
1038 
1039         // Compute grid of points on the face ("face anchors")
1040         std::vector< gsVector<T> > rr;
1041         rr.reserve( parDim );
1042 
1043         for ( short_t i=0; i < parDim; ++i)
1044         {
1045             if ( i==dir )
1046             {
1047                 gsVector<T> b(1);
1048                 b[0] = ( basis.component(i).support() ) (0, param);
1049                 rr.push_back(b);
1050             }
1051             else
1052             {
1053                 rr.push_back( basis.component(i).anchors().transpose() );
1054             }
1055         }
1056 
1057         // GISMO_ASSERT(it->function()->targetDim() == u.dim(),
1058         //              "Given Dirichlet boundary function does not match problem dimension."
1059         //              <<it->function()->targetDim()<<" != "<<u.dim()<<"\n");
1060 
1061         // Compute dirichlet values
1062         gsMatrix<T> fpts;
1063         if ( it->parametric() )
1064             fpts = it->function()->eval( gsPointGrid<T>( rr ) );
1065         else
1066             fpts = it->function()->eval(
1067                 m_exprdata->getMap().source().piece(it->patch()).eval(  gsPointGrid<T>( rr ) ) );
1068 
1069         /*
1070         if ( fpts.rows() != u.dim() )
1071         {
1072             // assume scalar
1073             gsMatrix<T> tmp(u.dim(), fpts.cols());
1074             tmp.setZero();
1075             gsDebugVar(!dir);
1076             tmp.row(!dir) = (param ? 1 : -1) * fpts; // normal !
1077             fpts.swap(tmp);
1078         }
1079         */
1080 
1081         // Interpolate dirichlet boundary
1082         typename gsBasis<T>::uPtr h = basis.boundaryBasis(it->side());
1083         typename gsGeometry<T>::uPtr geo = h->interpolateAtAnchors(fpts);
1084         const gsMatrix<T> & dVals =  geo->coefs();
1085 
1086         // Save corresponding boundary dofs
1087         for (index_t l=0; l!= boundary.size(); ++l)
1088         {
1089             const index_t ii = mapper.bindex( boundary.at(l) , it->patch(), com);
1090             fixedDofs.at(ii) = dVals.at(l);
1091         }
1092     }
1093 }
1094 
1095 
1096 /*
1097 template<class T> //
1098 void gsExprAssembler<T>::computeDirichletDofsIntpl3(const expr::gsFeSpace<T> & u)
1099 {
1100     const gsDofMapper  & mapper    = u.mapper();
1101     gsMatrix<T>        & fixedDofs = const_cast<expr::gsFeSpace<T>&>(u).fixedPart();
1102     const index_t bsz = mapper.boundarySize();
1103     fixedDofs.resize(bsz, u.dim() );
1104     gsMatrix<T> pt, val, rhs;
1105     rhs.resize(bsz, u.dim() );
1106     gsMatrix<index_t> act;
1107     gsSparseMatrix<T> cmat(bsz, bsz);
1108     // todo: reserve
1109 
1110     const gsMultiBasis<T> & mbasis =
1111         *dynamic_cast<const gsMultiBasis<T>*>(&u.source());
1112 
1113     // Iterate over all patch-sides with Boundary conditions
1114     // Iterate over all patch-sides with Dirichlet-boundary conditions
1115     typedef typename gsBoundaryConditions<T>::bcRefList bcRefList;
1116     for ( typename bcRefList::const_iterator iit =  u.bc().begin();
1117           iit != u.bc().end()  ; ++iit )
1118     {
1119         const boundary_condition<T> * it = &iit->get();
1120 
1121         GISMO_ASSERT(it->function()->targetDim() == u.dim(),
1122                      "Given Dirichlet boundary function does not match problem dimension."
1123                      <<it->function()->targetDim()<<" != "<<u.dim()<<"\n");
1124 
1125         const index_t k   = it->patch();
1126         if( it->unknown()!=u.id() )
1127             continue;
1128         const gsBasis<T> & basis = mbasis[k];
1129 
1130         // Get dofs on this boundary
1131         gsMatrix<index_t> boundary = basis.boundary(it->side());
1132 
1133         // If the condition is homogeneous then fill with zeros
1134         if ( it->isHomogeneous() )
1135         {
1136             for (index_t i=0; i!= boundary.size(); ++i)
1137             {
1138                 const index_t ii= mapper.bindex( boundary.at(i) , k );
1139                 fixedDofs.row(ii).setZero();
1140             }
1141             continue;
1142         }
1143 
1144         // Get anchor points for the respective dofs
1145         for ( index_t i=0; i != boundary.size(); ++i)
1146             // or: preimage ?
1147         {
1148             const index_t cc = mapper.bindex( boundary.at(l) , k );
1149             basis.anchor_into(boundary.at(i), pt);
1150             basis.active_into(pt, act);
1151             basis.eval_into  (pt, val);
1152 
1153             for ( index_t l = 0; l != act.size(); ++l)
1154             {
1155                 const index_t ii = mapper.index( act.at(l) , k );
1156                 if ( mapper.is_boundary_index(ii) ) // && cmat.isExpZero
1157                     cmat.insert(cc, mapper.global_to_bindex(ii)) = val.at(l);
1158             }
1159 
1160             // rhs
1161             if ( it->parametric() )
1162                 it->function()->eval_into(pt, val);
1163             else
1164             {
1165                 it->function()->eval_into(
1166                     m_exprdata->getMap().source().piece(it->patch()).eval(pt), val );
1167             }
1168             rhs.row(cc) = val.transpose();
1169         }
1170 
1171         // Interpolate dirichlet boundary
1172         // Solve overconstraint using QR ?
1173         //fixedDofs = ..
1174     }
1175 }
1176 //*/
1177 
1178 template<class T>
computeDirichletDofsL2Proj(const expr::gsFeSpace<T> & u)1179 void gsExprAssembler<T>::computeDirichletDofsL2Proj(const expr::gsFeSpace<T>& u)
1180 {
1181     GISMO_ASSERT(&m_exprdata->getMap().source() != NULL, "Geometry not set, call setMap(...) first!");
1182 
1183     const gsDofMapper & mapper = u.mapper();
1184     gsMatrix<T> & fixedDofs = const_cast<expr::gsFeSpace<T>& >(u).fixedPart();
1185     fixedDofs.resize(mapper.boundarySize(), u.dim());
1186 
1187     const gsMultiBasis<T> & mbasis = *dynamic_cast<const gsMultiBasis<T>* >(&u.source());
1188 
1189     //const gsBoundaryConditions<> & bbc = u.hasBc() ? u.bc() : gsBoundaryConditions<>();
1190 
1191     // Set up matrix, right-hand-side and solution vector/matrix for
1192     // the L2-projection
1193     gsSparseEntries<T> projMatEntries;
1194     gsMatrix<T>        globProjRhs;
1195     globProjRhs.setZero(mapper.boundarySize(), u.dim());
1196 
1197     // Temporaries
1198     gsVector<T> quWeights;
1199 
1200     gsMatrix<T> rhsVals;
1201     gsMatrix<index_t> globIdxAct;
1202     gsMatrix<T> basisVals;
1203 
1204     gsMapData<T> md(NEED_MEASURE | SAME_ELEMENT);
1205 
1206     const gsMultiPatch<T> & mp = static_cast<const gsMultiPatch<T> &>(m_exprdata->getMap().source());
1207 
1208     // Iterate over all patch-sides with Dirichlet-boundary conditions
1209     typedef typename gsBoundaryConditions<T>::bcRefList bcRefList;
1210     for (typename bcRefList::const_iterator iit = u.bc().begin();
1211          iit != u.bc().end(); ++iit)
1212     {
1213         const boundary_condition<T> * iter = &iit->get();
1214 
1215         const short_t unk = iter->unknown();
1216         if(unk != u.id())
1217             continue;
1218         const index_t patchIdx   = iter->patch();
1219         const gsBasis<T> & basis = mbasis[patchIdx];
1220 
1221         const gsGeometry<T> & patch = mp.patch(patchIdx);
1222 
1223         // Set up quadrature to degree+1 Gauss points per direction,
1224         // all lying on iter->side() except from the direction which
1225         // is NOT along the element
1226         gsGaussRule<T> bdQuRule(basis, 1.0, 1, iter->side().direction());
1227 
1228         // Create the iterator along the given part boundary.
1229         typename gsBasis<T>::domainIter bdryIter = basis.makeDomainIterator(iter->side());
1230 
1231         for (; bdryIter->good(); bdryIter->next())
1232         {
1233             bdQuRule.mapTo(bdryIter->lowerCorner(), bdryIter->upperCorner(),
1234                            md.points, quWeights);
1235 
1236             patch.computeMap(md);
1237 
1238             // the values of the boundary condition are stored
1239             // to rhsVals. Here, "rhs" refers to the right-hand-side
1240             // of the L2-projection, not of the PDE.
1241             rhsVals = iter->function()->eval(m_exprdata->getMap().source().piece(patchIdx).eval(md.points));
1242 
1243             basis.eval_into(md.points, basisVals);
1244 
1245             // Indices involved here:
1246             // --- Local index:
1247             // Index of the basis function/DOF on the patch.
1248             // Does not take into account any boundary or interface conditions.
1249             // --- Global Index:
1250             // Each DOF has a unique global index that runs over all patches.
1251             // This global index includes a re-ordering such that all eliminated
1252             // DOFs come at the end.
1253             // The global index also takes care of glued interface, i.e., corresponding
1254             // DOFs on different patches will have the same global index, if they are
1255             // glued together.
1256             // --- Boundary Index (actually, it's a "Dirichlet Boundary Index"):
1257             // The eliminated DOFs, which come last in the global indexing,
1258             // have their own numbering starting from zero.
1259 
1260             // Get the global indices (second line) of the local
1261             // active basis (first line) functions/DOFs:
1262             basis.active_into(md.points.col(0), globIdxAct);
1263             mapper.localToGlobal(globIdxAct, patchIdx, globIdxAct);
1264 
1265             // Out of the active functions/DOFs on this element, collect all those
1266             // which correspond to a boundary DOF.
1267             // This is checked by calling mapper.is_boundary_index( global Index )
1268 
1269             // eltBdryFcts stores the row in basisVals/globIdxAct, i.e.,
1270             // something like a "element-wise index"
1271             std::vector<index_t> eltBdryFcts;
1272             eltBdryFcts.reserve(mapper.boundarySize());
1273             for (index_t i = 0; i < globIdxAct.rows(); i++)
1274             {
1275                 if (mapper.is_boundary_index(globIdxAct(i, 0)))
1276                 {
1277                     eltBdryFcts.push_back(i);
1278                 }
1279             }
1280 
1281             // Do the actual assembly:
1282             for (index_t k = 0; k < md.points.cols(); k++)
1283             {
1284                 const T weight_k = quWeights[k] * md.measure(k);
1285 
1286                 // Only run through the active boundary functions on the element:
1287                 for (size_t i0 = 0; i0 < eltBdryFcts.size(); i0++)
1288                 {
1289                     // Each active boundary function/DOF in eltBdryFcts has...
1290                     // ...the above-mentioned "element-wise index"
1291                     const index_t i = eltBdryFcts[i0];
1292                     // ...the boundary index.
1293                     const index_t ii = mapper.global_to_bindex(globIdxAct(i));
1294 
1295                     for (size_t j0 = 0; j0 < eltBdryFcts.size(); j0++)
1296                     {
1297                         const index_t j = eltBdryFcts[j0];
1298                         const index_t jj = mapper.global_to_bindex(globIdxAct(j));
1299 
1300                         // Use the "element-wise index" to get the needed
1301                         // function value.
1302                         // Use the boundary index to put the value in the proper
1303                         // place in the global projection matrix.
1304                         projMatEntries.add(ii, jj, weight_k * basisVals(i, k) * basisVals(j, k));
1305                     } // for j
1306 
1307                     globProjRhs.row(ii) += weight_k * basisVals(i, k) * rhsVals.col(k).transpose();
1308 
1309                 } // for i
1310             } // for k
1311         } // bdryIter
1312     } // boundaryConditions-Iterator
1313 
1314     gsSparseMatrix<T> globProjMat(mapper.boundarySize(), mapper.boundarySize());
1315     globProjMat.setFrom(projMatEntries);
1316     globProjMat.makeCompressed();
1317 
1318     // Solve the linear system:
1319     // The position in the solution vector already corresponds to the
1320     // numbering by the boundary index. Hence, we can simply take them
1321     // for the values of the eliminated Dirichlet DOFs.
1322     typename gsSparseSolver<T>::CGDiagonal solver;
1323     fixedDofs = solver.compute(globProjMat).solve(globProjRhs);
1324 
1325 } // computeDirichletDofsL2Proj
1326 
1327 
1328 } //namespace gismo
1329