G+Smo  25.01.0
Geometry + Simulation Modules
 
Loading...
Searching...
No Matches
gsExprAssembler.h
Go to the documentation of this file.
1
14#pragma once
15
16#include <gsUtils/gsPointGrid.h>
19
21
23
24namespace gismo
25{
26
31template<class T>
33{
34private:
35 typename gsExprHelper<T>::Ptr m_exprdata;
36 const gsMultiPatch<T>* m_gmap;
37
38 gsOptionList m_options;
39
40 mutable gsSparseMatrix<T> m_matrix;
42 FiberMatrix m_fmatrix;
43 gsMatrix<T> m_rhs;
44
45 std::list<gsFeSpaceData<T> > m_sdata;
46 std::vector<gsFeSpaceData<T>*> m_vrow;
47 std::vector<gsFeSpaceData<T>*> m_vcol;
48
49 int m_sparsity;//0:unknown, 1:volume, 2:boundary, 4:interface pre-allocated
50 mutable bool m_modified;
51
52 typedef typename gsExprHelper<T>::nullExpr nullExpr;
53
54public:
55
56 typedef typename gsSparseMatrix<T>::BlockView matBlockView;
57
58 typedef typename gsSparseMatrix<T>::constBlockView matConstBlockView;
59
60 typedef typename gsBoundaryConditions<T>::bcRefList bcRefList;
61 typedef gsBoxTopology::bContainer bContainer;
62 typedef gsBoxTopology::ifContainer ifContainer;
63
64 typedef typename gsExprHelper<T>::element element;
65 typedef typename gsExprHelper<T>::geometryMap geometryMap;
67 typedef typename gsExprHelper<T>::space space;
68 typedef typename expr::gsFeSolution<T> solution;
69
70public:
71
72 void cleanUp()
73 {
74 m_exprdata->cleanUp();
75 }
76
80 gsExprAssembler(index_t _rBlocks = 1, index_t _cBlocks = 1)
81 : m_exprdata(gsExprHelper<T>::make()), m_gmap(nullptr), m_options(defaultOptions()),
82 m_vrow(_rBlocks,nullptr), m_vcol(_cBlocks,nullptr), m_sparsity(0), m_modified(false)
83 { }
84
85 // The copy constructor replicates the same environent but does
86 // not copy the expression helper
87
90
93 {
94 GISMO_ASSERT( m_vcol.back()->mapper.isFinalized(),
95 "gsExprAssembler::numDofs() says: initSystem() has not been called.");
96 return m_vcol.back()->mapper.firstIndex() +
97 m_vcol.back()->mapper.freeSize();
98 }
99
102 {
103 GISMO_ASSERT( m_vrow.back()->mapper.isFinalized(),
104 "initSystem() has not been called.");
105 return m_vrow.back()->mapper.firstIndex() +
106 m_vrow.back()->mapper.freeSize();
107 }
108
112 {
113 index_t nb = 0;
114 for (size_t i = 0; i!=m_vrow.size(); ++i)
115 nb += m_vrow[i]->dim;
116 return nb;
117 }
118
120 gsOptionList & options() {return m_options;}
121
123 const FiberMatrix & fiberMatrix() const
124 { return m_fmatrix; }
125
127 const gsSparseMatrix<T> & matrix() const
128 { return m_modified ? makeMatrix() : m_matrix; }
129
133 {
134 m_fmatrix.toSparseMatrix(m_matrix);
135 m_modified = false;
136 return m_matrix;
137 }
138
141 {
142 matrix();
143 out = give(m_matrix);
144 }
145
146 EIGEN_STRONG_INLINE gsSparseMatrix<T> giveMatrix()
147 {
148 matrix();
149 m_modified = true;
150 return give(m_matrix);
151 }
152
154 const gsMatrix<T> & rhs() const { return m_rhs; }
155
157 void rhs_into(gsMatrix<T> & out) { out = give(m_rhs); }
158
162 { m_exprdata->setMultiBasis(mesh); }
163
167 { m_gmap = &gMap;}
168
169 const gsMultiPatch<T>& getGeometryMap() const
170 {
171 return (nullptr == m_gmap ? m_exprdata->multiPatch() : *m_gmap);
172 }
173
174#if EIGEN_HAS_RVALUE_REFERENCES
175 void setIntegrationElements(const gsMultiBasis<T> &&) = delete;
176 //const gsMultiBasis<T> * c++98
177#endif
178
181 { return m_exprdata->multiBasis(); }
182
183 const typename gsExprHelper<T>::Ptr exprData() const { return m_exprdata; }
184
187 { return m_exprdata->getMap(g); }
188
191 space getSpace(const gsFunctionSet<T> & mp, index_t dim = 1, index_t id = 0)
192 {
193 //if multiBasisSet() then check domainDom
194 GISMO_ASSERT(1==mp.targetDim(), "Expecting scalar source space");
195 GISMO_ASSERT(static_cast<size_t>(id)<m_vcol.size(),
196 "Given ID "<<id<<" exceeds "<<m_vcol.size()-1 );
197
198 if (m_vcol[id]==nullptr)
199 {
200 m_sdata.emplace_back(mp,dim,id);
201 m_vcol[id] = &m_sdata.back();
202 if ((size_t)id<m_vrow.size() && nullptr==m_vrow[id]) m_vrow[id]=m_vcol[id];
203 }
204 else
205 {
206 m_vcol[id]->fs = &mp;
207 m_vcol[id]->dim = dim;
208 }
209
210 expr::gsFeSpace<T> u = m_exprdata->getSpace(mp,dim);
211 u.setSpaceData(*m_vcol[id]);
212 return u;
213 }
214
217 space getTestSpace(const gsFunctionSet<T> & mp, index_t dim = 1, index_t id = 0)
218 {
219 GISMO_ASSERT(1==mp.targetDim(), "Expecting scalar source space");
220 GISMO_ASSERT(static_cast<size_t>(id)<m_vrow.size(),
221 "Given ID "<<id<<" exceeds "<<m_vrow.size()-1 );
222
223 if ( (m_vrow[id]==nullptr) ||
224 ((size_t)id<m_vcol.size() && m_vrow[id]==m_vcol[id]) )
225 {
226 m_sdata.emplace_back(mp,dim,id);
227 m_vrow[id] = &m_sdata.back();
228 }
229 else
230 {
231 m_vrow[id]->fs = &mp;
232 m_vrow[id]->dim = dim;
233 }
234
235 expr::gsFeSpace<T> s = m_exprdata->getSpace(mp,dim);
236 s.setSpaceData(m_sdata.back());
237 return s;
238 }
239
253 { return getTestSpace( mp,(-1 == dim ? u.dim() : dim), u.id() ); }
254
257 space trialSpace(const index_t id) const
258 {
259 GISMO_ASSERT(NULL!=m_vcol[id], "Not set.");
260 expr::gsFeSpace<T> s = m_exprdata->
261 getSpace(*m_vcol[id]->fs,m_vcol[id]->dim);
262 s.setSpaceData(*m_vcol[id]);
263 return s;
264 }
265
267 space trialSpace(space & v) const { return trialSpace(v.id()); }
268
272 {
273 GISMO_ASSERT(NULL!=m_vrow[id], "Not set.");
274 expr::gsFeSpace<T> s = m_exprdata->
275 getSpace(*m_vrow[id]->fs,m_vrow[id]->dim);
276 s.setSpaceData(*m_vrow[id]);
277 return s;
278 }
279
281 space testSpace(space u) const { return testSpace(u.id()); }
282
286 { return m_exprdata->getVar(func, 1); }
287
290 expr::gsComposition<T> getCoeff(const gsFunctionSet<T> & func, geometryMap & G)
291 { return m_exprdata->getVar(func,G); }
292
300 { return solution(s, cf); }
301
302 variable getBdrFunction() const { return m_exprdata->getMutVar(); }
303
304 expr::gsComposition<T> getBdrFunction(geometryMap & G) const
305 { return m_exprdata->getMutVar(G); }
306
307 element getElement() const { return m_exprdata->getElement(); }
308
309 // note: not used
310 void setFixedDofVector(gsMatrix<T> & dof, short_t unk = 0);
311 // note: not used
312 void setFixedDofs(const gsMatrix<T> & coefMatrix, short_t unk = 0, size_t patch = 0);
313
315 void initSystem(const index_t numRhs = 1)
316 {
317 // Check spaces.nPatches==mesh.patches
318 initMatrix();
319 m_rhs.setZero(numTestDofs(), numRhs);
320 }
321
324 {
326 clearMatrix(false);
327 }
328
329 void clearRhs() { m_rhs.setZero(); }
330
337 void clearMatrix(const bool& save_sparsety_pattern = true)
338 {
339 if (m_fmatrix.nonZeros() && save_sparsety_pattern)
340 {
341 m_fmatrix.assignZero();
342 }
343 else
344 {
345 m_fmatrix.resize(numTestDofs(), numDofs());
346 m_sparsity = 0;
347
348 if (0 == m_fmatrix.rows() || 0 == m_fmatrix.cols())
349 gsWarn << " No internal DOFs, zero sized system.\n";
350 else {
351 // Pick up values from options
352 const T bdA = m_options.getReal("bdA");
353 const index_t bdB = m_options.getInt("bdB");
354 const T bdO = m_options.getReal("bdO");
355 T nz = 1;
356 const short_t dim = m_exprdata->multiBasis().domainDim();
357 for (short_t i = 0; i != dim; ++i)
358 nz *= bdA * static_cast<T>(
359 m_exprdata->multiBasis().maxDegree(i)) +
360 static_cast<T>(bdB);
361
362 m_fmatrix.reservePerColumn(numBlocks() *
363 cast<T, index_t>(nz * (1.0 + bdO)));
364 }
365 }
366 }
367
369 template<class... expr> void computePattern(const expr &... args)
370 {
371 _computePattern(args...);
372 m_sparsity |= 1;
373 }
374
376 template<class... expr> void computePatternBdr(const bcRefList & BCs, const expr &... args)
377 {
378 _computePatternBdr(BCs, args...);
379 m_sparsity |= 2;
380 }
381
383 template<class... expr> void computePatternIfc(const ifContainer & iFaces, expr... args)
384 {
385 _computePatternIfc(iFaces, args...);
386 m_sparsity |= 4;
387 }
388
390 void initVector(const index_t numRhs = 1)
391 {
393 m_rhs.setZero(numTestDofs(), numRhs);
394 }
395
399 matBlockView matrixBlockView()
400 {
401 GISMO_ASSERT( m_vcol.back()->mapper.isFinalized(),
402 "initSystem() has not been called.");
403 gsVector<index_t> rowSizes, colSizes;
404 _blockDims(rowSizes, colSizes);
405 matrix();
406 return m_matrix.blockView(rowSizes,colSizes);
407 }
408
412 matConstBlockView matrixBlockView() const
413 {
414 GISMO_ASSERT( m_vcol.back()->mapper.isFinalized(),
415 "initSystem() has not been called.");
416 gsVector<index_t> rowSizes, colSizes;
417 _blockDims(rowSizes, colSizes);
418 matrix();
419 return m_matrix.blockView(rowSizes,colSizes);
420 }
421
423 void setOptions(gsOptionList opt) { m_options = opt; } // gsOptionList opt
424 // .swap(opt) todo
425
429 template<class... expr> void assemble(const expr &... args);
430
434 template<class... expr> void assembleBdr(const bcRefList & BCs, expr&... args);
435
436 template<class... expr> void assembleBdr(const bContainer & bnd, expr&... args);
437
438 template<class... expr> void assembleIfc(const ifContainer & iFaces, expr... args);
439 /*
440 template<class... expr> void collocate(expr... args);// eg. collocate(-ilapl(u), f)
441 */
442
443 void quPointsWeights(std::vector<gsMatrix<T> >& cPoints, std::vector<gsVector<T> > & cWeights);
444
446 // respect to the solution \a u
447 template<class expr> void assembleJacobian(const expr residual, solution & u);
448
449 template<class expr> void assembleJacobianIfc(const ifContainer & iFaces,
450 const expr residual, solution u);
451
452private:
453
454 template<class... expr> void _computePattern(const expr &... args);
455 template<class... expr> void _computePatternBdr(const bcRefList & BCs, const expr &... args);
456 template<class... expr> void _computePatternIfc(const ifContainer & iFaces, expr... args);
457
458 void _blockDims(gsVector<index_t> & rowSizes,
459 gsVector<index_t> & colSizes)
460 {
461 if (1==m_vcol.size() && 1==m_vrow.size())
462 {
463 const gsDofMapper & dm = m_vcol.back()->mapper;
464 rowSizes.resize(3);
465 colSizes.resize(3);
466 rowSizes[0]=colSizes[0] = dm.freeSize()-dm.coupledSize();
467 rowSizes[1]=colSizes[1] = dm.coupledSize();
468 rowSizes[2]=colSizes[2] = dm.boundarySize();
469 }
470 else
471 {
472 rowSizes.resize(m_vrow.size());
473 for (index_t r = 0; r != rowSizes.size(); ++r) // for all row-blocks
474 rowSizes[r] = m_vrow[r]->dim() * m_vrow[r]->mapper.freeSize();
475 colSizes.resize(m_vcol.size());
476 for (index_t c = 0; c != colSizes.size(); ++c) // for all col-blocks
477 colSizes[c] = m_vcol[c]->dim() * m_vcol[c]->mapper.freeSize();
478 }
479 }
480
484
485 // Prints the expression to a text stream
486 struct __printExpr
487 {
488 template <typename E> void operator() (const gismo::expr::_expr<E> & v)
489 { v.print(gsInfo);gsInfo<<"\n"; }
490 } _printExpr;
491
492 // Checks validity of an expression
493 struct __checkExpr
494 {
495 template <typename E> void operator() (const gsExprAssembler & ea,
496 const gismo::expr::_expr<E> & ee)
497 {
498 auto u = ee.rowVar();
499 auto v = ee.colVar();
500#ifndef NDEBUG
501 const bool m = E::isMatrix();
502#endif
503 GISMO_ASSERT(v.isValid(), "The row space is not valid");
504 GISMO_ASSERT(!m || u.isValid(), "The column space is not valid");
505 GISMO_ASSERT(m || (ea.numDofs()==ee.rhs().size()), "The right-hand side vector is not initialized");
506 }
507 };
508
509 // Checks if an expression is a matrix
510 struct _checkMatrix
511 {
512 bool & m_result;
513 _checkMatrix( bool & _result) : m_result(_result) { }
514 template <typename E> void operator() (const gismo::expr::_expr<E> &)
515 { m_result |= E::isMatrix(); }
516 };
517
518
519 // Evaluates expression and and assembles global matrix/rhs
520 struct _eval
521 {
522 FiberMatrix & m_fmatrix;
523 gsMatrix<T> & m_rhs;
524 const gsVector<T> & m_quWeights;
525 bool m_elim;
526 gsMatrix<T> localMat;
527 gsMatrix<T> aux;
528
529 _eval(FiberMatrix & _fmatrix,
530 gsMatrix<T> & _rhs,
531 const gsVector<> & _quWeights)
532 : m_fmatrix(_fmatrix), m_rhs(_rhs),
533 m_quWeights(_quWeights), m_elim(true)
534 { }
535
536 void setElim(bool elim) {m_elim = elim;}
537
538 template <typename E> void operator() (const gismo::expr::_expr<E> & ee)
539 {
540 GISMO_ASSERT(E::isMatrix() || E::isVector(), "Expecting a matrix or vector expression.");
541 if ((ee.rowVar().data().flags & SAME_ELEMENT) &&
542 ( E::isVector() || (ee.colVar().data().flags & SAME_ELEMENT) ) )
543 {
544 // ------- Compute -------
545 quadrature(ee, localMat);
546 // ------- Accumulate -------
547 if (m_elim) push<E::isMatrix(),true>(ee.rowVar(), ee.colVar(), 0, 0);
548 else push<E::isMatrix(),false>(ee.rowVar(), ee.colVar(), 0, 0);
549 }
550 else
551 {
552 index_t k;
553 static index_t _zero(0);
554 index_t & ra = ( (ee.rowVar().data().flags & SAME_ELEMENT) ? _zero : k);
555 index_t & ca = ( (E::isVector() || ee.colVar().data().flags & SAME_ELEMENT) ? _zero : k);
556 const T * w = m_quWeights.data();
557 for (k = 0; k != m_quWeights.rows(); ++k)
558 {
559 // ------- Compute -------
560 localMat.noalias() = (*(w++)) * ee.eval(k);
561 // ------- Accumulate -------
562 if (m_elim) push<E::isMatrix(),true>(ee.rowVar(), ee.colVar(), ra, ca);
563 else push<E::isMatrix(),false>(ee.rowVar(), ee.colVar(), ra, ca);
564 }
565 }
566 }// operator()
567
568 template <typename E>
569 inline void quadrature(const gismo::expr::_expr<E> & ee,
570 gsMatrix<T> & lm)
571 {
572 // ------- Compute -------
573 const T * w = m_quWeights.data();
574 lm.noalias() = (*w) * ee.eval(0);
575 for (index_t k = 1; k != m_quWeights.rows(); ++k)
576 lm.noalias() += (*(++w)) * ee.eval(k);
577 }
578
579 template <typename E> void diff(const gismo::expr::_expr<E> & ee,
580 solution & u)
581 {
582 GISMO_ASSERT(E::isVector(), "Expecting a vector expression.");
583 static const T delta = 0.00001;
584
585 const index_t sz = u.space().cardinality();
586 localMat.setZero(sz, sz);
587
588 for ( index_t c=0; c!= u.dim(); c++)
589 {
590 const index_t rls = c * u.data().actives.rows(); //local stride
591 for ( index_t j = 0; j != sz/u.dim(); j++ ) // for all basis functions (col(j))
592 {
593 const index_t jj = u.mapper().index(u.data().actives.at(j),
594 u.space().data().patchId, c);
595 if (u.mapper().is_free_index(jj) )
596 {
597 //todo: take local copy of local solution u
598
599 //Perturb \a u
600 u.perturbLocal( delta , jj, u.space().data().patchId);
601 quadrature(ee, aux);
602 localMat.col(rls+j) += 8 * aux;
603 u.perturbLocal( delta , jj, u.space().data().patchId);
604 quadrature(ee, aux);
605 localMat.col(rls+j) -= aux;
606 u.perturbLocal(-3*delta, jj, u.space().data().patchId);
607 quadrature(ee, aux);
608 localMat.col(rls+j) -= 8 * aux;
609 u.perturbLocal( -delta , jj, u.space().data().patchId);
610 quadrature(ee, aux);
611 localMat.col(rls+j) += aux;
612 localMat.col(rls+j) /= 12*delta;
613 //Unperturb \a u
614 u.perturbLocal(2*delta, jj, u.space().data().patchId);
615 }
616 }
617 }
618
619 // ------- Accumulate -------
620 push<true,false>(ee.rowVar(), ee.rowVar());
621 }
622
623 void operator() (const expr::_expr<expr::gsNullExpr<T> > &) {}
624
625 template<bool isMatrix, bool elim = true>
626 void push(const expr::gsFeSpace<T> & v,
627 const expr::gsFeSpace<T> & u, index_t ra = 0, index_t ca = 0)
628 {
629 GISMO_ASSERT(v.isValid(), "The row space is not valid");
630 GISMO_ASSERT(!isMatrix || u.isValid(), "The column space is not valid");
631 //GISMO_ASSERT(isMatrix || (numDofs()==m_rhs.size()), "The right-hand side vector is not initialized");
632
633 const index_t rd = v.dim();//row
634 const index_t cd = u.dim();//col
635 //const index_t rp = v.data().patchId;
636 //const index_t cp = (isMatrix ? u.data().patchId : 0);
637 const gsDofMapper & rowMap = v.mapper();
638 const gsDofMapper & colMap = (isMatrix ? u.mapper() : rowMap);
639 gsMatrix<index_t> & rowInd0 = const_cast<gsMatrix<index_t>&>(v.data().actives);
640 gsMatrix<index_t> & colInd0 = (isMatrix ? const_cast<gsMatrix<index_t>&>(u.data().actives) : rowInd0);
641 const gsMatrix<T> & fixedDofs = (isMatrix ? u.fixedPart() : gsMatrix<T>());
642
643 if (isMatrix)
644 {
645 GISMO_ASSERT( rowInd0.rows()*rd==localMat.rows() && colInd0.rows()*cd==localMat.cols(),
646 "Invalid local matrix (expected "<<rowInd0.rows()*rd <<"x"<< colInd0.rows()*cd <<"), got\n" << localMat );
647
648 GISMO_ASSERT( colMap.boundarySize()==fixedDofs.size(),
649 "Invalid values for fixed part");
650
651 //GISMO_ASSERT( colMap.boundarySize()==0 || m_rhs.cols()==1,
652 // "Invalid values for fixed part");
653 }
654
655 for (index_t r = 0; r != rd; ++r)
656 {
657 const index_t rls = r * rowInd0.rows(); //local stride
658 for (index_t i = 0; i != rowInd0.rows(); ++i)
659 {
660 const index_t ii = rowMap.index(rowInd0(i,ra),v.data().patchId,r); //N_i
661 if ( rowMap.is_free_index(ii) )
662 {
663 if (isMatrix)
664 {
665 for (index_t c = 0; c != cd; ++c)
666 {
667 const index_t cls = c * colInd0.rows(); //local stride
668
669 for (index_t j = 0; j != colInd0.rows(); ++j)
670 {
671 if ( 0 == localMat(rls+i,cls+j) ) continue;
672
673 const index_t jj = colMap.index(colInd0(j,ca),u.data().patchId,c); // N_j
674 if ( colMap.is_free_index(jj) )
675 {
676 // If matrix is symmetric, we could
677 // store only lower triangular part
678 //if ( (!symm) || jj <= ii )
679# pragma omp atomic
680 m_fmatrix.coeffRef(ii, jj) += localMat(rls+i,cls+j);
681 }
682 else if (elim) // colMap.is_boundary_index(jj) )
683 {
684 // Symmetric treatment of eliminated BCs
685 // GISMO_ASSERT(1==m_rhs.cols(), "-");
686# pragma omp atomic
687 m_rhs.at(ii) -= localMat(rls+i,cls+j) *
688 fixedDofs.at(colMap.global_to_bindex(jj));
689 }
690 }
691 }
692 }
693 else
694 {
695 //The right-hand side can have more than one columns
696#ifdef _OPENMP
697 for(index_t a = 0; a!= m_rhs.cols();++a)
698 {
699# pragma omp atomic
700 m_rhs(ii,a) += localMat(rls+i,a);
701 }
702#else
703 m_rhs.row(ii) += localMat.row(rls+i);
704#endif
705 }
706 }
707 }
708 }
709 }//push
710 };
711
712 // Constructs the sparsity pattern of the global matrix
713 struct _pattern
714 {
715 FiberMatrix & m_fmatrix;
716 const gsMatrix<T> & m_point;
717 unsigned & patchid;
718 gsMatrix<index_t> rowInd0, colInd0;
719#ifdef _OPENMP
720 std::vector<omp_lock_t> & m_lock;
721#endif
722 _pattern(FiberMatrix & _fmatrix,
723 const gsMatrix<T> & _point, unsigned & _patchid
724#ifdef _OPENMP
725 , std::vector<omp_lock_t> & _lock
726#endif
727 )
728 : m_fmatrix(_fmatrix), m_point(_point), patchid(_patchid)
729#ifdef _OPENMP
730 , m_lock(_lock)
731#endif
732 { }
733
734 template <typename E> void operator() (const gismo::expr::_expr<E> & ee)
735 {
736 // ------- Accumulate -------
737 if (E::isMatrix())
738 push(ee.rowVar(), ee.colVar());
739 }
740
741 void operator() (const expr::_expr<expr::gsNullExpr<T> > &) {}
742
743 void push(const expr::gsFeSpace<T> & v,
744 const expr::gsFeSpace<T> & u)
745 {
746 GISMO_ASSERT(v.isValid(), "The row space is not valid");
747 GISMO_ASSERT(u.isValid(), "The column space is not valid");
748 const index_t rd = v.dim();//row
749 const index_t cd = u.dim();//col
750 const gsDofMapper & rowMap = v.mapper();
751 const gsDofMapper & colMap = u.mapper();
752 rowInd0 = v.source().piece(patchid).active(m_point); //.. pattern ifc ?
753 colInd0 = u.source().piece(patchid).active(m_point);
754 for (index_t c = 0; c != cd; ++c)
755 for (index_t j = 0; j != colInd0.rows(); ++j)
756 {
757 const index_t jj = colMap.index(colInd0.at(j),patchid,c); // N_j
758 if ( colMap.is_free_index(jj) )
759 {
760#ifdef _OPENMP
761 omp_set_lock(&m_lock[jj]);
762#endif
763 for (index_t r = 0; r != rd; ++r)
764 for (index_t i = 0; i != rowInd0.rows(); ++i)
765 {
766 const index_t ii = rowMap.index(rowInd0.at(i),patchid,r); //N_i
767 if ( rowMap.is_free_index(ii) )
768 m_fmatrix.insertExplicitZero(ii, jj);
769 }
770#ifdef _OPENMP
771 omp_unset_lock(&m_lock[jj]);
772#endif
773 }
774 }
775 }//push
776 };
777
778}; // gsExprAssembler
779
780template<class T>
782{
783 gsOptionList opt;
784 opt.addInt("DirichletValues" , "Method for computation of Dirichlet DoF values [100..103]", 101);
785 opt.addInt("DirichletStrategy", "Method for enforcement of Dirichlet BCs [11..14]", 11);
786 opt.addReal("quA", "Number of quadrature points: quA*deg + quB; For patchRule: Regularity of the target space", 1.0 );
787 opt.addInt ("quB", "Number of quadrature points: quA*deg + quB; For patchRule: Degree of the target space", 1 );
788 opt.addReal("bdA", "Estimated nonzeros per column of the matrix: bdA*deg + bdB", 2.0 );
789 opt.addInt ("bdB", "Estimated nonzeros per column of the matrix: bdA*deg + bdB", 1 );
790 opt.addReal("bdO", "Overhead of sparse mem. allocation: (1+bdO)(bdA*deg + bdB) [0..1]", 0.333);
791 opt.addInt ("quRule", "Quadrature rule used (1) Gauss-Legendre; (2) Gauss-Lobatto; (3) Patch-Rule",1);
792 opt.addSwitch("overInt", "Apply over-integration on boundary elements or not?", false);
793 opt.addSwitch("flipSide", "Flip side of interface where integration is performed.", false);
794 opt.addSwitch("movingInterface", "Used in interface assembly when interface is not stationary.", false);
795 return opt;
796
798
799 //storage of quadrature points, TP, ... non-linear assembly.
800
801 //gsExpressions.h -> split ?
802
803 //parallel interface assembly..
804
805 // mpi assemly. ???
806}
807
808template<class T>
810{
811 gsMatrix<T> & fixedDofs = m_vcol[unk]->fixedDofs;
812 fixedDofs.swap(vals);
813 vals.resize(0, 0);
814 // Assuming that the DoFs are already set by the user
815 GISMO_ENSURE( fixedDofs.size() == m_vcol[unk]->mapper.boundarySize(),
816 "The Dirichlet DoFs were not provided correctly.");
817}
818
819template<class T>
820void gsExprAssembler<T>::setFixedDofs(const gsMatrix<T> & coefMatrix, short_t unk, size_t patch)
821{
822 GISMO_ASSERT( m_options.getInt("DirichletValues") == dirichlet::user, "Incorrect options");
823
824 expr::gsFeSpace<T> & u = *m_vcol[unk];
825 //const index_t dirStr = m_options.getInt("DirichletStrategy");
826 const gsMultiBasis<T> & mbasis = *dynamic_cast<const gsMultiBasis<T>* >(m_vcol[unk]->fs);
827
828 const gsDofMapper & mapper = m_vcol[unk]->mapper;
829// const gsDofMapper & mapper =
830// dirichlet::elimination == dirStr ? u.mapper
831// : mbasis.getMapper(dirichlet::elimination,
832// static_cast<iFace::strategy>(m_options.getInt("InterfaceStrategy")),
833// bbc, u.id()) ;
834
835 gsMatrix<T> & fixedDofs = m_vcol[unk]->fixedDofs;
836 GISMO_ASSERT(fixedDofs.size() == m_vcol[unk]->mapper.boundarySize(),
837 "Fixed DoFs were not initialized.");
838
839 // for every side with a Dirichlet BC
840 typedef typename gsBoundaryConditions<T>::bcRefList bcRefList;
841 for ( typename bcRefList::const_iterator it = u.bc().dirichletBegin();
842 it != u.bc().dirichletEnd() ; ++it )
843 {
844 const index_t com = it->unkComponent();
845 const index_t k = it->patch();
846 if ( k == patch )
847 {
848 // Get indices in the patch on this boundary
849 const gsMatrix<index_t> boundary =
850 mbasis[k].boundary(it->side());
851
852 //gsInfo <<"Setting the value for: "<< boundary.transpose() <<"\n";
853
854 for (index_t i=0; i!= boundary.size(); ++i)
855 {
856 // Note: boundary.at(i) is the patch-local index of a
857 // control point on the patch
858 const index_t ii = mapper.bindex( boundary.at(i) , k, com );
859
860 fixedDofs.at(ii) = coefMatrix(boundary.at(i), com);
861 }
862 }
863 }
864} // setFixedDofs
865
866
868{
869 if (!m_vcol.front()->valid()) m_vcol.front()->init();
870 if (!m_vrow.front()->valid()) m_vrow.front()->init();
871 for (size_t i = 1; i!=m_vcol.size(); ++i)
872 {
873 if (!m_vcol.front()->valid()) m_vcol.front()->init();
874 m_vcol[i]->mapper.setShift(m_vcol[i-1]->mapper.firstIndex() +
875 m_vcol[i-1]->dim*m_vcol[i-1]->mapper.freeSize() );
876
877 if ( m_vcol[i] != m_vrow[i] )
878 {
879 if (!m_vrow.front()->valid()) m_vrow.front()->init();
880 m_vrow[i]->mapper.setShift(m_vrow[i-1]->mapper.firstIndex() +
881 m_vrow[i-1]->dim*m_vrow[i-1]->mapper.freeSize() );
882 }
883 }
884}
885
886template<size_t I, class op, typename... Ts>
887void op_tuple_impl (op & _op, const std::tuple<Ts...> &tuple)
888{
889 _op(std::get<I>(tuple));
890 if (I + 1 < sizeof... (Ts))
891 op_tuple_impl<(I+1 < sizeof... (Ts) ? I+1 : I)> (_op, tuple);
892}
893
894template<class op, typename... Ts>
895void op_tuple (op & _op, const std::tuple<Ts...> &tuple)
896{ op_tuple_impl<0>(_op,tuple); }
897
898template<class T>
899template<class... expr>
900void gsExprAssembler<T>::_computePattern(const expr &... args)
901{
902 GISMO_ASSERT(m_fmatrix.cols()==numDofs(), "System not initialized, matrix.cols() = "<<m_fmatrix.cols()<<"!="<<numDofs()<<" = numDofs()");
903
904#ifdef _OPENMP
905 std::vector<omp_lock_t> lock(numDofs());
906 for (auto & l : lock)
907 omp_init_lock(&l);
908#endif
909
910#pragma omp parallel
911 {
912#ifdef _OPENMP
913 const int tid = omp_get_thread_num();
914 const int nt = omp_get_num_threads();
915#endif
916 auto arg_tpl = std::make_tuple(args...);
917 m_exprdata->parsePattern(arg_tpl);
918
919 typename gsBasis<T>::domainIter domIt;
920 unsigned patchInd;
921 _pattern pp(m_fmatrix, m_exprdata->points(), patchInd
922#ifdef _OPENMP
923 , lock
924#endif
925 );
926 const unsigned nP = m_exprdata->multiBasis().nBases();
927#ifdef _OPENMP
928 const unsigned offset = (nP<(unsigned)(nt) ? 1 : nP/nt);
929 for (unsigned Ind = 0; Ind != nP; ++Ind)
930 {
931 patchInd = (Ind + offset * tid) % nP;
932 domIt = m_exprdata->multiBasis().basis(patchInd).makeDomainIterator();
933 for ( domIt->next(tid); domIt->good(); domIt->next(nt) ) //tid>numElements??? barrier.
934#else
935 for (patchInd = 0; patchInd != nP; ++patchInd)
936 {
937 domIt = m_exprdata->multiBasis().basis(patchInd).makeDomainIterator();
938 for (; domIt->good(); domIt->next() )
939#endif
940 {
941 m_exprdata->points() = domIt->centerPoint();
942 op_tuple(pp, arg_tpl);
943 }
944 }
945 }//parallel
946#ifdef _OPENMP
947 for (auto & l : lock)
948 omp_destroy_lock(&l);
949#endif
950}
951
952template<class T>
953template<class... expr>
954void gsExprAssembler<T>::_computePatternBdr(const bcRefList & BCs, const expr &... args)
955{
956 GISMO_ASSERT(m_fmatrix.cols()==numDofs(), "System not initialized, matrix.cols() = "<<m_fmatrix.cols()<<"!="<<numDofs()<<" = numDofs()");
957
958 if ( BCs.empty() || 0==numDofs() ) return;
959
960#ifdef _OPENMP
961 std::vector<omp_lock_t> lock(numDofs());
962 for (auto & l : lock)
963 omp_init_lock(&l);
964#endif
965
966#pragma omp parallel
967{
968/*
969#ifdef _OPENMP
970 const int tid = omp_get_thread_num();
971 const int nt = omp_get_num_threads();
972#endif
973*/
974 auto arg_tpl = std::make_tuple(args...);
975 m_exprdata->parsePattern(arg_tpl);
976 typename gsBasis<T>::domainIter domIt;
977 unsigned patchInd;
978 _pattern pp(m_fmatrix, m_exprdata->points(), patchInd
979#ifdef _OPENMP
980 , lock
981#endif
982 );
983
984 for (typename bcRefList::const_iterator iit = BCs.begin(); iit!= BCs.end(); ++iit)
985 {
986 const boundary_condition<T> * it = &iit->get();
987
988 patchInd = it->patch();
989 domIt = m_exprdata->multiBasis().basis(it->patch()).
990 makeDomainIterator(it->side());
991
992 // Start iteration over elements
993 //for ( domIt->next(tid); domIt->good(); domIt->next(nt) )
994 for (; domIt->good(); domIt->next() )
995 {
996# pragma omp single nowait
997 {
998 m_exprdata->points() = domIt->centerPoint();
999 op_tuple(pp, arg_tpl);
1000 }
1001 }
1002
1003 }
1004}//omp parallel
1005
1006#ifdef _OPENMP
1007 for (auto & l : lock)
1008 omp_destroy_lock(&l);
1009#endif
1010}
1011
1012
1013template<class T>
1014template<class... expr>
1015void gsExprAssembler<T>::_computePatternIfc(const ifContainer & iFaces, expr... args)
1016{
1017 GISMO_ASSERT(m_fmatrix.cols()==numDofs(), "System not initialized");
1018 if ( iFaces.empty() || 0==numDofs() ) return;
1019
1020#ifdef _OPENMP
1021 std::vector<omp_lock_t> lock(numDofs());
1022 for (auto & l : lock)
1023 omp_init_lock(&l);
1024#endif
1025 typedef typename gsFunction<T>::uPtr ifacemap;
1026 typename gsBasis<T>::domainIter domIt;
1027 const bool flipSide = m_options.askSwitch("flipSide", false);
1028#pragma omp parallel
1029{
1030 auto arg_tpl = std::make_tuple(args...);
1031 m_exprdata->parsePattern(arg_tpl);
1032 unsigned patchInd(0);
1033 _pattern pp(m_fmatrix, m_exprdata->points(), patchInd
1034#ifdef _OPENMP
1035 , lock
1036#endif
1037 );
1038
1039 ifacemap interfaceMap;
1040 for (gsBoxTopology::const_iiterator it = iFaces.begin();
1041 it != iFaces.end(); ++it )
1042 {
1043 // If flipSide switch is enabled, then the integration will be
1044 // performed on the opposite side of the interface
1045 const boundaryInterface & iFace = flipSide ? it->getInverse() : *it;
1046 const index_t patch1 = iFace.first() .patch;
1047 const index_t patch2 = iFace.second().patch;
1048
1049 if (iFace.type() == interaction::conforming)
1050 interfaceMap = gsAffineFunction<T>::make( iFace.dirMap(), iFace.dirOrientation(),
1051 m_exprdata->multiBasis().basis(patch1).support(),
1052 m_exprdata->multiBasis().basis(patch2).support() );
1053 else
1054 interfaceMap = gsCPPInterface<T>::make(getGeometryMap(), m_exprdata->multiBasis(), iFace);
1055
1056 domIt = m_exprdata->multiBasis().basis(patch1)
1057 .makeDomainIterator(iFace.first().side());
1058
1059 // Start iteration over elements
1060 //for ( domIt->next(tid); domIt->good(); domIt->next(nt) )
1061 for (; domIt->good(); domIt->next() )
1062 {
1063# pragma omp single nowait
1064 {
1065 m_exprdata->points() = domIt->centerPoint();
1066 interfaceMap->eval_into(m_exprdata->points(), m_exprdata->pointsIfc());
1067 op_tuple(pp, arg_tpl);
1068 }
1069 }
1070 }
1071}//omp parallel
1072}
1073
1074
1075template<class T>
1076template<class... expr>
1077void gsExprAssembler<T>::assemble(const expr &... args)
1078{
1079 GISMO_ASSERT(m_fmatrix.cols()==numDofs(), "System not initialized, matrix.cols() = "<<m_fmatrix.cols()<<"!="<<numDofs()<<" = numDofs()");
1080
1081 if ((m_sparsity & 1) == 0)
1082 this->_computePattern(args...);
1083
1084 bool failed = false;
1085 const index_t elim = m_options.getInt("DirichletStrategy");
1086#pragma omp parallel shared(failed)
1087{
1088# ifdef _OPENMP
1089 const int tid = omp_get_thread_num();
1090 const int nt = omp_get_num_threads();
1091# endif
1092 auto arg_tpl = std::make_tuple(args...);
1093 m_exprdata->parse(arg_tpl);
1094 m_exprdata->activateFlags(SAME_ELEMENT);
1095 //op_tuple(__printExpr(), arg_tpl);
1096
1097 // check if matrix is modified
1098 _checkMatrix CM(m_modified);
1099 op_tuple(CM, arg_tpl);
1100
1101 _eval ee(m_fmatrix, m_rhs, m_exprdata->weights());
1102 ee.setElim(dirichlet::elimination==elim);
1103 typename gsQuadRule<T>::uPtr QuRule; // Quadrature rule
1104 typename gsBasis<T>::domainIter domIt;
1105
1106 // Note: omp thread will loop over all patches and will work on Ep/nt
1107 // elements, where Ep is the elements on the patch.
1108 const unsigned nP = m_exprdata->multiBasis().nBases();
1109#ifdef _OPENMP
1110 const unsigned offset = (nP<(unsigned)(nt) ? 1 : nP/nt);
1111 for (unsigned Ind = 0; Ind < nP && (!failed); ++Ind)
1112 {
1113 // Spread the threads on different patches
1114 const unsigned patchInd = (Ind + offset * tid) % nP;
1115#else
1116 for (unsigned patchInd = 0; patchInd < nP && (!failed); ++patchInd)
1117 {
1118#endif
1119 QuRule = gsQuadrature::getPtr(m_exprdata->multiBasis().basis(patchInd), m_options);
1120
1121 // Initialize domain element iterator for current patch
1122 domIt = // add patchInd to domainiter ?
1123 m_exprdata->multiBasis().basis(patchInd).makeDomainIterator();
1124
1125 // Start iteration over elements of patchInd
1126# ifdef _OPENMP
1127 for ( domIt->next(tid); domIt->good() && (!failed); domIt->next(nt) )
1128# else
1129 for (; domIt->good(); domIt->next() )
1130# endif
1131 {
1132 // Map the Quadrature rule to the element
1133 QuRule->mapTo( domIt->lowerCorner(), domIt->upperCorner(),
1134 m_exprdata->points(), m_exprdata->weights());
1135
1136 if (m_exprdata->points().cols()==0)
1137 continue;
1138
1139// Activate the try-catch only if G+Smo is in DEBUG
1140#ifndef NDEBUG
1141 // Perform required pre-computations on the quadrature nodes
1142 try
1143 {
1144 m_exprdata->precompute(patchInd);
1145 //m_exprdata->precompute(patchInd, QuRule, *domIt); // todo
1146 }
1147 catch (...)
1148 {
1149 #pragma omp atomic write
1150 failed = true;
1151 break;
1152 }
1153#else
1154 m_exprdata->precompute(patchInd);
1155#endif
1156 // Assemble contributions of the element
1157 op_tuple(ee, arg_tpl);
1158 }
1159 }
1160}//omp parallel
1161 // Throw something else?? (floating point exception?)
1162 GISMO_ENSURE(!failed,"Assembly failed due to an error");
1163}
1164
1165template<class T>
1166template<class... expr>
1167void gsExprAssembler<T>::assembleBdr(const bcRefList & BCs, expr&... args)
1168{
1169 GISMO_ASSERT(m_fmatrix.cols()==numDofs(), "System not initialized");
1170
1171 if ( BCs.empty() || 0==numDofs() ) return;
1172
1173 if ((m_sparsity & 2) == 0)
1174 this->_computePatternBdr(BCs, args...);
1175
1176 m_exprdata->setMutSource(*BCs.front().get().function()); //initialize once
1177
1178// #pragma omp parallel
1179// {
1180// # ifdef _OPENMP
1181// const int tid = omp_get_thread_num();
1182// const int nt = omp_get_num_threads();
1183// # endif
1184 auto arg_tpl = std::make_tuple(args...);
1185 m_exprdata->parse(arg_tpl);
1186 m_exprdata->activateFlags(SAME_ELEMENT);
1187
1188 typename gsQuadRule<T>::uPtr QuRule; // Quadrature rule
1189
1190 // check if matrix is modified
1191 _checkMatrix CM(m_modified);
1192 op_tuple(CM, arg_tpl);
1193 _eval ee(m_fmatrix, m_rhs, m_exprdata->weights());
1194
1195//# pragma omp parallel for
1196 for (typename bcRefList::const_iterator iit = BCs.begin(); iit!= BCs.end(); ++iit)
1197 {
1198 const boundary_condition<T> * it = &iit->get();
1199
1200 QuRule = gsQuadrature::getPtr(m_exprdata->multiBasis().basis(it->patch()), m_options, it->side().direction());
1201
1202 // Update boundary function source
1203 m_exprdata->setMutSource(*it->function());
1204
1205 typename gsBasis<T>::domainIter domIt =
1206 m_exprdata->multiBasis().basis(it->patch()).
1207 makeDomainIterator(it->side());
1208
1209 // Start iteration over elements
1210 for (; domIt->good(); domIt->next() )
1211 {
1212 // Map the Quadrature rule to the element
1213 QuRule->mapTo( domIt->lowerCorner(), domIt->upperCorner(),
1214 m_exprdata->points(), m_exprdata->weights());
1215
1216 if (m_exprdata->points().cols()==0)
1217 continue;
1218
1219 // Perform required pre-computations on the quadrature nodes
1220 m_exprdata->precompute(it->patch(), it->side());
1221
1222 // Assemble contributions of the element
1223 op_tuple(ee, arg_tpl);
1224 }
1225 }
1226
1227//}//omp parallel
1228}
1229
1230
1231template<class T>
1232template<class... expr>
1233void gsExprAssembler<T>::assembleBdr(const bContainer & bnd, expr&... args)
1234{
1235 GISMO_ASSERT(m_fmatrix.cols()==numDofs(), "System not initialized");
1236
1237 if ( bnd.size()==0 || 0==numDofs() ) return;
1238
1239 auto arg_tpl = std::make_tuple(args...);
1240 m_exprdata->parse(arg_tpl);
1241
1242 typename gsQuadRule<T>::uPtr QuRule;
1243
1244 // check if matrix is modified
1245 _checkMatrix CM(m_modified);
1246 op_tuple(CM, arg_tpl);
1247 _eval ee(m_fmatrix, m_rhs, m_exprdata->weights());
1248
1249//# pragma omp parallel for
1250
1251 for (gsBoxTopology::const_biterator it = bnd.begin();
1252 it != bnd.end(); ++it )
1253 {
1254 QuRule = gsQuadrature::getPtr(m_exprdata->multiBasis().basis(it->patch),
1255 m_options, it->side().direction());
1256
1257 typename gsBasis<T>::domainIter domIt =
1258 m_exprdata->multiBasis().basis(it->patch).
1259 makeDomainIterator(it->side());
1260
1261 // Start iteration over elements
1262 for (; domIt->good(); domIt->next() )
1263 {
1264 // Map the Quadrature rule to the element
1265 QuRule->mapTo( domIt->lowerCorner(), domIt->upperCorner(),
1266 m_exprdata->points(), m_exprdata->weights());
1267
1268 if (m_exprdata->points().cols()==0)
1269 continue;
1270
1271 // Perform required pre-computations on the quadrature nodes
1272 m_exprdata->precompute(it->patch, it->side());
1273
1274 // Assemble contributions of the element
1275 op_tuple(ee, arg_tpl);
1276 }
1277 }
1278
1279//}//omp parallel
1280
1281}
1282
1283template<class T> template<class... expr>
1284void gsExprAssembler<T>::assembleIfc(const ifContainer & iFaces, expr... args)
1285{
1286 GISMO_ASSERT(m_fmatrix.cols()==numDofs(), "System not initialized");
1287
1288 if ((m_sparsity & 4) == 0)
1289 this->_computePatternIfc(iFaces, args...);
1290
1291// #pragma omp parallel //TODO
1292// {
1293 typedef typename gsFunction<T>::uPtr ifacemap;
1294
1295 auto arg_tpl = std::make_tuple(args...);
1296
1297 m_exprdata->parse(arg_tpl);
1298 m_exprdata->activateFlags(SAME_ELEMENT); //note: SAME_ELEMENT is 0 at the opposite/mirrored patch
1299
1300 typename gsQuadRule<T>::uPtr QuRule;
1301
1302 // check if matrix is modified
1303 _checkMatrix CM(m_modified);
1304 op_tuple(CM, arg_tpl);
1305 _eval ee(m_fmatrix, m_rhs, m_exprdata->weights());
1306
1307 const bool flipSide = m_options.askSwitch("flipSide", false);
1308
1309 ifacemap interfaceMap;
1310// # pragma omp for
1311 for (gsBoxTopology::const_iiterator it = iFaces.begin();
1312 it != iFaces.end(); ++it )
1313 {
1314 // If flipSide switch is enabled, then the integration will be
1315 // performed on the opposite side of the interface
1316 const boundaryInterface & iFace = flipSide ? it->getInverse() : *it;
1317 const index_t patch1 = iFace.first() .patch;
1318 const index_t patch2 = iFace.second().patch;
1319
1320 if (iFace.type() == interaction::conforming)
1321 interfaceMap = gsAffineFunction<T>::make( iFace.dirMap(), iFace.dirOrientation(),
1322 m_exprdata->multiBasis().basis(patch1).support(),
1323 m_exprdata->multiBasis().basis(patch2).support() );
1324 else
1325 interfaceMap = gsCPPInterface<T>::make(getGeometryMap(), m_exprdata->multiBasis(), iFace);
1326
1327 QuRule = gsQuadrature::getPtr(m_exprdata->multiBasis().basis(patch1),
1328 m_options, iFace.first().side().direction());
1329
1330 typename gsBasis<T>::domainIter domIt =
1331 m_exprdata->multiBasis().basis(patch1)
1332 .makeDomainIterator(iFace.first().side());
1333
1334 // Start iteration over elements
1335 for (; domIt->good(); domIt->next() )
1336 {
1337 // Map the Quadrature rule to the element
1338 QuRule->mapTo( domIt->lowerCorner(), domIt->upperCorner(),
1339 m_exprdata->points(), m_exprdata->weights());
1340 interfaceMap->eval_into(m_exprdata->points(), m_exprdata->pointsIfc());
1341
1342 if (m_exprdata->points().cols()==0)
1343 continue;
1344
1345 // Perform required pre-computations on the quadrature nodes
1346 m_exprdata->precompute(iFace);
1347
1348 //eg.
1349 // uL*vL/2 + uR*vL/2 - uL*vR/2 - uR*vR/2
1350 //[ B11 B21 ]
1351 //[ B12 B22 ]
1352
1353 op_tuple(ee, arg_tpl);
1354 }
1355 }
1356
1357// }//omp parallel
1358}
1359
1360template<class T> template<class expr>
1362{
1363 GISMO_ASSERT(m_fmatrix.cols()==numDofs(), "System not initialized");
1364 GISMO_ASSERT(expr::isVector(), "Expecting a vector expression.");
1365
1366 clearMatrix();
1367 clearRhs();
1368
1369#pragma omp parallel
1370{
1371# ifdef _OPENMP
1372 const int tid = omp_get_thread_num();
1373 const int nt = omp_get_num_threads();
1374# endif
1375
1376 m_exprdata->parse(residual, u);
1377 m_exprdata->activateFlags(SAME_ELEMENT);
1378 //op_tuple(__printExpr(), arg_tpl);
1379
1380 typename gsQuadRule<T>::uPtr QuRule; // Quadrature rule ---->OUT
1381
1382 m_modified = true;
1383 _eval ee(m_fmatrix, m_rhs, m_exprdata->weights());
1384
1385 // Note: omp thread will loop over all patches and will work on Ep/nt
1386 // elements, where Ep is the elements on the patch.
1387 for (unsigned patchInd = 0; patchInd < m_exprdata->multiBasis().nBases(); ++patchInd)
1388 {
1389 QuRule = gsQuadrature::getPtr(m_exprdata->multiBasis().basis(patchInd), m_options);
1390
1391 // Initialize domain element iterator for current patch
1392 typename gsBasis<T>::domainIter domIt = // add patchInd to domainiter ?
1393 m_exprdata->multiBasis().basis(patchInd).makeDomainIterator();
1394
1395 // Start iteration over elements of patchInd
1396# ifdef _OPENMP
1397 for ( domIt->next(tid); domIt->good(); domIt->next(nt) )
1398# else
1399 for (; domIt->good(); domIt->next() )
1400# endif
1401 {
1402 // Map the Quadrature rule to the element
1403 QuRule->mapTo( domIt->lowerCorner(), domIt->upperCorner(),
1404 m_exprdata->points(), m_exprdata->weights());
1405
1406 if (m_exprdata->points().cols()==0)
1407 continue;
1408
1409 // Evaluate at quadrature points
1410 m_exprdata->precompute(patchInd);
1411
1412# pragma omp critical (assemble_fdiffs)
1413 {
1414 // ee(residual); //Computes residual to m_rhs
1415 ee.diff(residual, u); //Computes Jacobian
1416 }
1417 }
1418 }
1419
1420}//omp parallel
1421}
1422
1423
1424template<class T> template<class expr>
1425void gsExprAssembler<T>::assembleJacobianIfc(const ifContainer & iFaces,
1426 const expr residual, solution u)
1427{
1428 GISMO_ASSERT(m_fmatrix.cols()==numDofs(), "System not initialized");
1429 GISMO_ASSERT(expr::isVector(), "Expecting a vector expression.");
1430
1431 // clearMatrix();
1432
1433 m_exprdata->parse(residual, u);
1434 m_exprdata->activateFlags(SAME_ELEMENT);
1435 //op_tuple(__printExpr(), arg_tpl);
1436
1437 typename gsQuadRule<T>::uPtr QuRule; // Quadrature rule
1438
1439 // check if matrix is modified
1440 m_modified = true;
1441 _eval ee(m_fmatrix, m_rhs, m_exprdata->weights());
1442 const bool flipSide = m_options.askSwitch("flipSide", false);
1443 const bool movingInterface = m_options.askSwitch("movingInterface", false);
1444
1445 for (gsBoxTopology::const_iiterator it = iFaces.begin();
1446 it != iFaces.end(); ++it )
1447 {
1448 // If flipSide switch is enabled, then the integration will be
1449 // performed on the opposite side of the interface
1450 const boundaryInterface & iFace = flipSide ? it->getInverse() : *it;
1451 const index_t patch1 = iFace.first() .patch;
1452 //const index_t patch2 = iFace.second().patch;
1453
1454 gsCPPInterface<T> interfaceMap(getGeometryMap(), // ! make current geometry
1455 m_exprdata->multiBasis(), iFace);
1456
1457 QuRule = gsQuadrature::getPtr(m_exprdata->multiBasis().basis(patch1),
1458 m_options, iFace.first().side().direction());
1459
1460 typename gsBasis<T>::domainIter domIt =
1461 m_exprdata->multiBasis().basis(patch1)
1462 .makeDomainIterator(iFace.first().side());
1463
1464 // Start iteration over elements
1465 for (; domIt->good(); domIt->next() )
1466 {
1467 // Map the Quadrature rule to the element
1468 QuRule->mapTo( domIt->lowerCorner(), domIt->upperCorner(),
1469 m_exprdata->points(), m_exprdata->weights());
1470 interfaceMap.eval_into(m_exprdata->points(), m_exprdata->pointsIfc());
1471
1472 if (m_exprdata->points().cols()==0)
1473 continue;
1474
1475 // Perform required pre-computations on the quadrature nodes
1476 m_exprdata->precompute(iFace);
1477
1478 // ee(residual);
1479 if (!movingInterface)
1480 {
1481 ee.diff(residual, u);
1482 }
1483 else // For Moving Geometry Maps
1484 {
1485 GISMO_ASSERT(expr::isVector(), "Expecting a vector expression.");
1486 static const T delta = 0.00001;
1487
1488 const index_t sz = residual.eval(0).rows(); // Caution this must be the correct size , depending if .right() or .left() are used
1489 ee.localMat.setZero(sz, sz);
1490
1491 auto & rowVar = residual.rowVar();
1492
1493 for ( index_t c=0; c!= u.dim(); c++)
1494 {
1495 const index_t rls = c * rowVar.data().actives.rows(); //local stride
1496 for ( index_t j = 0; j != sz/u.dim(); j++ ) // for all basis functions (col(j))
1497 {
1498 const index_t jj = u.mapper().index(rowVar.data().actives(j),
1499 rowVar.data().patchId, c);
1500 if (rowVar.mapper().is_free_index(jj) )
1501 {
1502 //Perturb \a u
1503 u.perturbLocal( delta , jj, rowVar.data().patchId);
1504 interfaceMap.updateBdr();
1505 interfaceMap.eval_into(m_exprdata->points(), m_exprdata->pointsIfc());
1506 m_exprdata->precompute(iFace);
1507 ee.quadrature(residual, ee.aux);
1508 ee.localMat.col(rls+j) += 8 * ee.aux;
1509
1510
1511 u.perturbLocal( delta , jj, rowVar.data().patchId);
1512 interfaceMap.updateBdr();
1513 interfaceMap.eval_into(m_exprdata->points(), m_exprdata->pointsIfc());
1514 m_exprdata->precompute(iFace);
1515 ee.quadrature(residual, ee.aux);
1516 ee.localMat.col(rls+j) -= ee.aux;
1517
1518 u.perturbLocal(-3*delta, jj, rowVar.data().patchId);
1519 interfaceMap.updateBdr();
1520 interfaceMap.eval_into(m_exprdata->points(), m_exprdata->pointsIfc());
1521 m_exprdata->precompute(iFace);
1522 ee.quadrature(residual, ee.aux);
1523 ee.localMat.col(rls+j) -= 8 * ee.aux;
1524
1525 u.perturbLocal( -delta , jj, rowVar.data().patchId);
1526 interfaceMap.updateBdr();
1527 interfaceMap.eval_into(m_exprdata->points(), m_exprdata->pointsIfc());
1528 m_exprdata->precompute(iFace);
1529 ee.quadrature(residual, ee.aux);
1530 ee.localMat.col(rls+j) += ee.aux;
1531
1532 ee.localMat.col(rls+j) /= 12*delta;
1533 //Unperturb \a u
1534 u.perturbLocal(2*delta, jj, rowVar.data().patchId);
1535 interfaceMap.updateBdr();
1536 }
1537 }
1538 }
1539
1540 // ------- Accumulate -------
1541 ee.template push<true,false>(residual.rowVar(), residual.rowVar());
1542 }
1543 }
1544 }
1545}
1546
1547template<class T>
1548void gsExprAssembler<T>::quPointsWeights(std::vector<gsMatrix<T> >& cPoints, std::vector<gsVector<T> > & cWeights)
1549{
1550 GISMO_ASSERT(m_fmatrix.cols()==numDofs(), "System not initialized, matrix.cols() = "<<m_fmatrix.cols()<<"!="<<numDofs()<<" = numDofs()");
1551
1552#pragma omp parallel
1553{
1554# ifdef _OPENMP
1555 const int tid = omp_get_thread_num();
1556 const int nt = omp_get_num_threads();
1557# endif
1558
1559 typename gsQuadRule<T>::uPtr QuRule; // Quadrature rule
1560 cPoints.resize( m_exprdata->multiBasis().nBases() );
1561 cWeights.resize( m_exprdata->multiBasis().nBases() );
1562
1563 // Note: omp thread will loop over all patches and will work on Ep/nt
1564 // elements, where Ep is the elements on the patch.
1565 index_t count = 0;
1566 for (unsigned patchInd = 0; patchInd < m_exprdata->multiBasis().nBases(); ++patchInd)
1567 {
1568 auto & bb = m_exprdata->multiBasis().basis(patchInd);
1569
1570 QuRule = gsQuadrature::getPtr(bb, m_options);
1571 const index_t numNodes = QuRule->numNodes();
1572
1573 const index_t sz = bb.numElements() * numNodes;
1574 cPoints[patchInd].resize(bb.domainDim(), sz );
1575 cWeights[patchInd].resize( sz );
1576
1577 // Initialize domain element iterator for current patch
1578 typename gsBasis<T>::domainIter domIt = bb.makeDomainIterator();
1579
1580 // Start iteration over elements of patchInd
1581# ifdef _OPENMP
1582 for ( domIt->next(tid); domIt->good(); domIt->next(nt) )
1583# else
1584 for (; domIt->good(); domIt->next() )
1585# endif
1586 {
1587 // Map the Quadrature rule to the element
1588 QuRule->mapTo( domIt->lowerCorner(), domIt->upperCorner(),
1589 m_exprdata->points(), m_exprdata->weights());
1590
1591 cWeights[patchInd].segment(count, numNodes) = m_exprdata->weights();
1592 cPoints[patchInd].middleCols(count, numNodes) = m_exprdata->points();
1593 count += numNodes;
1594 }
1595 }
1596}//omp parallel
1597
1598}
1599
1600
1601
1602} //namespace gismo
short_t direction() const
Returns the parametric direction orthogonal to this side.
Definition gsBoundary.h:113
Definition gsExpressions.h:973
Definition gsExpressions.h:928
static uPtr make(const gsMatrix< T > mat, const gsVector< T > trans)
Affine maps are the composition of a linear map with a translation this constructor takes the two com...
Definition gsAffineFunction.h:75
virtual domainIter makeDomainIterator() const
Create a domain iterator for the computational mesh of this basis, that points to the first element o...
Definition gsBasis.hpp:542
Provides a mapping between the corresponding sides of two patches sharing an interface,...
Definition gsCPPInterface.h:33
Maintains a mapping from patch-local dofs to global dof indices and allows the elimination of individ...
Definition gsDofMapper.h:69
index_t boundarySize() const
Returns the number of eliminated dofs.
Definition gsDofMapper.h:457
index_t coupledSize() const
Returns the number of coupled (not eliminated) dofs.
Definition gsDofMapper.cpp:601
index_t freeSize() const
Returns the number of free (not eliminated) dofs.
Definition gsDofMapper.h:436
Definition gsExprAssembler.h:33
void computePatternBdr(const bcRefList &BCs, const expr &... args)
Initializes the pattern of the sparse matrix at boundary integrals.
Definition gsExprAssembler.h:376
void computePattern(const expr &... args)
Initializes the pattern of the sparse matrix.
Definition gsExprAssembler.h:369
void setIntegrationElements(const gsMultiBasis< T > &mesh)
Sets the domain of integration.
Definition gsExprAssembler.h:161
void assembleBdr(const bcRefList &BCs, expr &... args)
Adds the expressions args to the system matrix/rhs The arguments are considered as integrals over the...
Definition gsExprAssembler.h:1167
void rhs_into(gsMatrix< T > &out)
Writes the resulting vector in out. The internal data is moved.
Definition gsExprAssembler.h:157
space trialSpace(const index_t id) const
Definition gsExprAssembler.h:257
gsExprHelper< T >::geometryMap geometryMap
Geometry map type.
Definition gsExprAssembler.h:65
space getTestSpace(const gsFunctionSet< T > &mp, index_t dim=1, index_t id=0)
Definition gsExprAssembler.h:217
space getSpace(const gsFunctionSet< T > &mp, index_t dim=1, index_t id=0)
Definition gsExprAssembler.h:191
index_t numDofs() const
Returns the number of degrees of freedom (after initialization)
Definition gsExprAssembler.h:92
void initMatrix()
Initializes the sparse matrix only.
Definition gsExprAssembler.h:323
const gsSparseMatrix< T > & makeMatrix() const
Definition gsExprAssembler.h:132
const gsMatrix< T > & rhs() const
Returns the right-hand side vector(s)
Definition gsExprAssembler.h:154
gsExprHelper< T >::element element
Current element.
Definition gsExprAssembler.h:64
void resetDimensions()
Reset the dimensions of all involved spaces. Called internally by the init* functions.
Definition gsExprAssembler.h:867
void computePatternIfc(const ifContainer &iFaces, expr... args)
Initializes the pattern of the sparse matrix at boundary integrals.
Definition gsExprAssembler.h:383
solution getSolution(const expr::gsFeSpace< T > &s, gsMatrix< T > &cf) const
Registers a representation of a solution variable from space s, based on the vector cf.
Definition gsExprAssembler.h:299
geometryMap getMap(const gsFunctionSet< T > &g)
Registers g as an isogeometric geometry map and return a handle to it.
Definition gsExprAssembler.h:186
space testSpace(space u) const
Return the test space of a pre-existing trial space u.
Definition gsExprAssembler.h:281
space trialSpace(space &v) const
Return the trial space of a pre-existing test space v.
Definition gsExprAssembler.h:267
gsExprAssembler(index_t _rBlocks=1, index_t _cBlocks=1)
Definition gsExprAssembler.h:80
gsExprHelper< T >::variable variable
Variable type.
Definition gsExprAssembler.h:66
void initSystem(const index_t numRhs=1)
Initializes the sparse system (sparse matrix and rhs)
Definition gsExprAssembler.h:315
void matrix_into(gsSparseMatrix< T > &out)
Writes the resulting matrix in out. The internal matrix is moved.
Definition gsExprAssembler.h:140
void setOptions(gsOptionList opt)
Set the assembler options.
Definition gsExprAssembler.h:423
variable getCoeff(const gsFunctionSet< T > &func)
Definition gsExprAssembler.h:285
void setGeometryMap(const gsMultiPatch< T > &gMap)
Set the geometrymap ( used for interface assembly)
Definition gsExprAssembler.h:166
void assembleJacobian(const expr residual, solution &u)
Assembles the Jacobian matrix of the expression args with.
Definition gsExprAssembler.h:1361
void assemble(const expr &... args)
Adds the expressions args to the system matrix/rhs The arguments are considered as integrals over the...
Definition gsExprAssembler.h:1077
expr::gsFeSolution< T > solution
Solution type.
Definition gsExprAssembler.h:68
matBlockView matrixBlockView()
Definition gsExprAssembler.h:399
space testSpace(const index_t id)
Definition gsExprAssembler.h:271
const gsMultiBasis< T > & integrationElements() const
Returns the domain of integration.
Definition gsExprAssembler.h:180
gsOptionList & options()
Returns a reference to the options structure.
Definition gsExprAssembler.h:120
matConstBlockView matrixBlockView() const
Definition gsExprAssembler.h:412
void clearMatrix(const bool &save_sparsety_pattern=true)
Re-Init Matrix (set zero by default)
Definition gsExprAssembler.h:337
space getTestSpace(space u, const gsFunctionSet< T > &mp, index_t dim=-1)
Registers mp as an isogeometric test space corresponding to trial space u and return a handle to it.
Definition gsExprAssembler.h:252
index_t numBlocks() const
Definition gsExprAssembler.h:111
expr::gsComposition< T > getCoeff(const gsFunctionSet< T > &func, geometryMap &G)
Definition gsExprAssembler.h:290
void initVector(const index_t numRhs=1)
Initializes the right-hand side vector only.
Definition gsExprAssembler.h:390
static gsOptionList defaultOptions()
Returns the list of default options for assembly.
Definition gsExprAssembler.h:781
gsExprHelper< T >::space space
Space type.
Definition gsExprAssembler.h:67
const FiberMatrix & fiberMatrix() const
Returns the internally stored sparse fiber matrix.
Definition gsExprAssembler.h:123
const gsSparseMatrix< T > & matrix() const
Returns the left-hand global matrix.
Definition gsExprAssembler.h:127
index_t numTestDofs() const
Returns the number of test functions (after initialization)
Definition gsExprAssembler.h:101
Definition gsExprHelper.h:27
A specialized sparse matrix class which stores each row as a separate sparse vector.
Definition gsFiberMatrix.h:31
index_t rows() const
Definition gsFiberMatrix.h:93
index_t cols() const
Definition gsFiberMatrix.h:96
Interface for the set of functions defined on a domain (the total number of functions in the set equa...
Definition gsFunctionSet.h:219
memory::unique_ptr< gsFunction > uPtr
Unique pointer for gsFunction.
Definition gsFunction.h:68
Represents a block-view of the given matrix.
Definition gsMatrixBlockView.h:32
A matrix with arbitrary coefficient type and fixed or dynamic size.
Definition gsMatrix.h:41
Holds a set of patch-wise bases and their topology information.
Definition gsMultiBasis.h:37
Container class for a set of geometry patches and their topology, that is, the interface connections ...
Definition gsMultiPatch.h:100
Class which holds a list of parameters/options, and provides easy access to them.
Definition gsOptionList.h:33
void addInt(const std::string &label, const std::string &desc, const index_t &value)
Adds a option named label, with description desc and value value.
Definition gsOptionList.cpp:201
bool askSwitch(const std::string &label, const bool &value=false) const
Reads value for option label from options.
Definition gsOptionList.cpp:128
const index_t & getInt(const std::string &label) const
Reads value for option label from options.
Definition gsOptionList.cpp:37
Real getReal(const std::string &label) const
Reads value for option label from options.
Definition gsOptionList.cpp:44
void addReal(const std::string &label, const std::string &desc, const Real &value)
Adds a option named label, with description desc and value value.
Definition gsOptionList.cpp:211
void addSwitch(const std::string &label, const std::string &desc, const bool &value)
Adds a option named label, with description desc and value value.
Definition gsOptionList.cpp:235
virtual void mapTo(const gsVector< T > &lower, const gsVector< T > &upper, gsMatrix< T > &nodes, gsVector< T > &weights) const
Maps quadrature rule (i.e., points and weights) from the reference domain to an element.
Definition gsQuadRule.h:177
Sparse matrix class, based on gsEigen::SparseMatrix.
Definition gsSparseMatrix.h:139
BlockView blockView(const gsVector< index_t > &rowSizes, const gsVector< index_t > &colSizes)
Return a block view of the matrix with rowSizes and colSizes.
Definition gsSparseMatrix.h:336
A vector with arbitrary coefficient type and fixed or dynamic size.
Definition gsVector.h:37
Provides a mapping between the corresponding sides of two patches sharing an interface,...
#define short_t
Definition gsConfig.h:35
#define index_t
Definition gsConfig.h:32
#define gsWarn
Definition gsDebug.h:50
#define GISMO_ENSURE(cond, message)
Definition gsDebug.h:102
#define gsInfo
Definition gsDebug.h:43
#define GISMO_ASSERT(cond, message)
Definition gsDebug.h:89
Generic expressions helper.
A specialized sparse matrix class which stores separately each fiber.
Provides functions to generate structured point data.
Creates a variety of quadrature rules.
The G+Smo namespace, containing all definitions for the library.
@ SAME_ELEMENT
Enable optimizations based on the assumption that all evaluation points are in the same bezier domain...
Definition gsForwardDeclarations.h:89
S give(S &x)
Definition gsMemory.h:266
Struct which represents an interface between two patches.
Definition gsBoundary.h:650
patchSide & first()
first, returns the first patchSide of this interface
Definition gsBoundary.h:776
Class that defines a boundary condition for a side of a patch for some unknown variable of a PDE.
Definition gsBoundaryConditions.h:107
static gsQuadRule< T >::uPtr getPtr(const gsBasis< T > &basis, const gsOptionList &options, short_t fixDir=-1)
Constructs a quadrature rule based on input options.
Definition gsQuadrature.h:64
index_t patch
The index of the patch.
Definition gsBoundary.h:234