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