G+Smo  25.01.0
Geometry + Simulation Modules
 
Loading...
Searching...
No Matches
gsPatchPreconditionersCreator.hpp
Go to the documentation of this file.
1
13#pragma once
14
15#include <gsSolver/gsSumOp.h>
18#include <gsSolver/gsMatrixOp.h>
21
22namespace gismo
23{
24
25namespace {
26
27template<typename T>
28gsBoundaryConditions<T> boundaryConditionsForDirection( const gsBoundaryConditions<T>& bc, index_t direction )
29{
30 gsBoundaryConditions<T> result;
31
32 for ( index_t i = 1; i <= 2; ++i)
33 {
34 patchSide global(0,i+2*direction), local(0,i);
35 const boundary_condition<T>* cond = bc.getConditionFromSide(global);
36 if (cond)
37 result.addCondition(local,cond->type(),cond->function());
38 }
39 return result;
40}
41
42template<typename T>
43void eliminateDirichlet1D(const gsBoundaryConditions<T>& bc,
44 const gsOptionList& opt, gsSparseMatrix<T> & result)
45{
46 dirichlet::strategy ds = (dirichlet::strategy)opt.askInt("DirichletStrategy",dirichlet::elimination);
47 if (ds == dirichlet::elimination)
48 {
49 patchSide west(0,boundary::west), east(0,boundary::east);
50 index_t i = 0;
51 if (bc.getConditionFromSide( west ) && bc.getConditionFromSide( west )->type() == condition_type::dirichlet ) i += 1;
52 if (bc.getConditionFromSide( east ) && bc.getConditionFromSide( east )->type() == condition_type::dirichlet ) i += 2;
53 if (i%2 + i/2 >= result.rows() || i%2 + i/2 >= result.cols())
54 result.resize(0,0);
55 else switch ( i )
56 {
57 case 0: break;
58 case 1: result = result.block( 1, 1, result.rows()-1, result.cols()-1 ); break;
59 case 2: result = result.block( 0, 0, result.rows()-1, result.cols()-1 ); break;
60 case 3: result = result.block( 1, 1, result.rows()-2, result.cols()-2 ); break;
61 }
62 }
63 else
64 GISMO_ERROR("Unknown Dirichlet strategy.");
65}
66
67template<typename T>
68gsSparseMatrix<T> assembleMass(const gsBasis<T>& basis)
69{
70 gsExprAssembler<T> mass(1,1);
71 gsMultiBasis<T> mb(basis);
72 mass.setIntegrationElements(mb);
73 typename gsExprAssembler<T>::space u = mass.getSpace(mb);
74 mass.initMatrix();
75 mass.assemble( u * u.tr() );
76 gsSparseMatrix<T> result;
77 mass.matrix_into(result);
78 return result;
79}
80
81template<typename T>
82gsSparseMatrix<T> assembleStiffness(const gsBasis<T>& basis)
83{
84 gsExprAssembler<T> stiff(1,1);
85 gsMultiBasis<T> mb(basis);
86 stiff.setIntegrationElements(mb);
87 typename gsExprAssembler<T>::space u = stiff.getSpace(mb);
88 stiff.initMatrix();
89 stiff.assemble( grad(u) * grad(u).tr() );
90 gsSparseMatrix<T> result;
91 stiff.matrix_into(result);
92 return result;
93}
94
95
96template<typename T>
97std::vector< gsSparseMatrix<T> > assembleTensorMass(
98 const gsBasis<T>& basis,
99 const gsBoundaryConditions<T>& bc,
100 const gsOptionList& opt
101 )
102{
103 const index_t d = basis.dim();
104 std::vector< gsSparseMatrix<T> > result(d);
105 for ( index_t i=0; i!=d; ++i )
106 {
107 result[i] = assembleMass(basis.component(d-1-i));
108 eliminateDirichlet1D(boundaryConditionsForDirection(bc,d-1-i), opt, result[i]);
109 }
110 return result;
111}
112
113template<typename T>
114std::vector< gsSparseMatrix<T> > assembleTensorStiffness(
115 const gsBasis<T>& basis,
116 const gsBoundaryConditions<T>& bc,
117 const gsOptionList& opt
118 )
119{
120 const index_t d = basis.dim();
121 std::vector< gsSparseMatrix<T> > result(d);
122 for ( index_t i=0; i!=d; ++i )
123 {
124 result[i] = assembleStiffness(basis.component(d-1-i));
125 eliminateDirichlet1D(boundaryConditionsForDirection(bc,d-1-i), opt, result[i]);
126 }
127 return result;
128}
129
130} // anonymous namespace
131
132template<typename T>
134 const gsBasis<T>& basis,
135 const gsBoundaryConditions<T>& bc,
136 const gsOptionList& opt
137 )
138{
139 std::vector< gsSparseMatrix<T> > local_mass = assembleTensorMass(basis, bc, opt);
140 const index_t d = local_mass.size();
141 gsSparseMatrix<T> result = local_mass[d-1];
142 for (index_t i=d-2; i>-1; --i)
143 result = local_mass[i].kron(result);
144 return result;
145}
146
147template<typename T>
148typename gsPatchPreconditionersCreator<T>::OpUPtr gsPatchPreconditionersCreator<T>::massMatrixOp(
149 const gsBasis<T>& basis,
150 const gsBoundaryConditions<T>& bc,
151 const gsOptionList& opt
152 )
153{
154 const index_t d = basis.dim();
155
156 std::vector< gsSparseMatrix<T> > local_mass = assembleTensorMass(basis, bc, opt);
157
158 std::vector<OpPtr> local_mass_op(d);
159 for (index_t i=0; i<d; ++i)
160 local_mass_op[i] = makeMatrixOp(local_mass[i].moveToPtr());
161
162 return gsKroneckerOp<T>::make(local_mass_op);
163}
164
165template<typename T>
166typename gsPatchPreconditionersCreator<T>::OpUPtr gsPatchPreconditionersCreator<T>::massMatrixInvOp(
167 const gsBasis<T>& basis,
168 const gsBoundaryConditions<T>& bc,
169 const gsOptionList& opt
170 )
171{
172 const index_t d = basis.dim();
173
174 std::vector< gsSparseMatrix<T> > local_mass = assembleTensorMass(basis, bc, opt);
175
176 std::vector<OpPtr> local_mass_op(d);
177 for (index_t i=0; i<d; ++i)
178 local_mass_op[i] = makeSparseCholeskySolver(local_mass[i]);
179
180 return gsKroneckerOp<T>::make(local_mass_op);
181}
182
183template<typename T>
185 const gsBasis<T>& basis,
186 const gsBoundaryConditions<T>& bc,
187 const gsOptionList& opt,
188 T alpha,
189 T beta
190 )
191{
192 const index_t d = basis.dim();
193
194 std::vector< gsSparseMatrix<T> > local_stiff = assembleTensorStiffness(basis, bc, opt);
195 std::vector< gsSparseMatrix<T> > local_mass = assembleTensorMass(basis, bc, opt);
196
197 if ( beta!=1 )
198 {
199 for (index_t i=0; i!=d; ++i)
200 local_stiff[i] *= beta;
201 }
202
203 gsSparseMatrix<T> K = give(local_stiff[d-1]);
204 gsSparseMatrix<T> M = give(local_mass [d-1]);
205
206 for (index_t i=d-2; i>-1; --i)
207 {
208 K = local_mass[i].kron(K);
209 K += local_stiff[i].kron(M);
210 if ( i != 0 || alpha != 0 )
211 M = local_mass[i].kron(M);
212 }
213 if (alpha==1)
214 K += M;
215 else if (alpha!=0)
216 K += alpha * M;
217 return K;
218}
219
220template<typename T>
221typename gsPatchPreconditionersCreator<T>::OpUPtr gsPatchPreconditionersCreator<T>::stiffnessMatrixOp(
222 const gsBasis<T>& basis,
223 const gsBoundaryConditions<T>& bc,
224 const gsOptionList& opt,
225 T alpha,
226 T beta
227 )
228{
229 const index_t d = basis.dim();
230
231 std::vector< gsSparseMatrix<T> > local_stiff = assembleTensorStiffness(basis, bc, opt);
232 std::vector< gsSparseMatrix<T> > local_mass = assembleTensorMass(basis, bc, opt);
233
234 std::vector<OpUPtr> local_stiff_op(d);
235 std::vector<OpPtr > local_mass_op (d);
236 for (index_t i=0; i<d; ++i)
237 {
238 if (beta!=1)
239 local_stiff[i] *= beta;
240 local_stiff_op[i] = makeMatrixOp(local_stiff[i].moveToPtr());
241 local_mass_op [i] = makeMatrixOp(local_mass [i].moveToPtr());
242 }
243 OpUPtr K = give(local_stiff_op[0]);
244 OpPtr M = give(local_mass_op [0]);
245
246 for (index_t i=1; i<d; ++i)
247 {
249 gsKroneckerOp<T>::make( give(K), local_mass_op [i] ),
250 gsKroneckerOp<T>::make( M, give(local_stiff_op[i]) )
251 );
252 if ( i < d-1 || alpha != 0 )
253 M = gsKroneckerOp<T>::make(M, local_mass_op[i]);
254 }
255 if (alpha==1)
256 K = gsSumOp<T>::make( give(K), M );
257 else if (alpha!=0)
258 K = gsSumOp<T>::make( give(K), gsScaledOp<T>::make( M, alpha ) );
259
260 return K;
261}
262
263template<typename T>
264typename gsPatchPreconditionersCreator<T>::OpUPtr gsPatchPreconditionersCreator<T>::fastDiagonalizationOp(
265 const gsBasis<T>& basis,
266 const gsBoundaryConditions<T>& bc,
267 const gsOptionList& opt,
268 T alpha,
269 T beta,
270 T gamma
271 )
272{
273 GISMO_ASSERT ( beta != 0, "gsPatchPreconditionersCreator<T>::fastDiagonalizationOp() does not work for beta==0." );
274
275 const index_t d = basis.dim();
276
277 // Assemble univariate
278 std::vector< gsSparseMatrix<T> > local_stiff = assembleTensorStiffness(basis, bc, opt);
279 std::vector< gsSparseMatrix<T> > local_mass = assembleTensorMass(basis, bc, opt);
280
281 if (beta!=0)
282 {
283 for (index_t i=0; i!=d; ++i)
284 local_stiff[i] *= beta;
285 }
286
287 // Determine overall size
288 index_t sz = 1;
289 for ( index_t i=0; i<d; ++i )
290 sz *= local_stiff[i].rows();
291
292 // Initialize the diagonal with 1
293 gsMatrix<T> diag;
294 diag.setConstant(sz,1,alpha); // This is the pure-mass part!
295
296 index_t glob = sz; // Indexing value for setting up the Kronecker product
297
298 typedef typename gsMatrix<T>::GenSelfAdjEigenSolver EVSolver;
299 typedef typename EVSolver::EigenvectorsType evMatrix;
300 typedef typename EVSolver::RealVectorType evVector;
301 EVSolver ges;
302
303 std::vector<OpPtr> Qop(d);
304 std::vector<OpPtr> QTop(d);
305 gsMatrix<T> ev;
306
307 T avg_term = gamma;
308
309 // Now, setup the Q's and update the D's
310 for ( index_t i=0; i<d; ++i )
311 {
312 // Solve generalized eigenvalue problem
313 ges.compute(local_stiff[i], local_mass[i], gsEigen::ComputeEigenvectors);
314 // Q^T M Q = I, or M = Q^{-T} Q^{-1}
315 // Q^T K Q = D, or K = Q^{-T} D Q^{-1}
316
317 if (gamma != (T)(0))
318 {
319 gsMatrix<T> etrans = ges.eigenvectors().transpose()*local_mass[i]*gsMatrix<T>::Ones(local_mass[i].rows(),1);
320 GISMO_ASSERT((etrans.block(1, 0, etrans.rows()-1, 1).array() < (T)(1)/100000000).all(),
321 "gsPatchPreconditionerCreator::fastDiagonalizationOp: gamma!=0 only allowed for pure Neumann.");
322 avg_term *= etrans(0,0) * etrans(0,0);
323 }
324
325 // From the eigenvalues, we setup the matrix D already in an Kroneckerized way.
326 const evVector & D = ges.eigenvalues();
327
328 const index_t loc = D.rows();
329 glob /= loc;
330 const index_t glob2 = sz / loc / glob;
331
332 for ( index_t l=0; l<loc; ++l )
333 for ( index_t m=0; m<glob; ++m )
334 for ( index_t n=0; n<glob2; ++n )
335 diag( m + l*glob + n*loc*glob, 0 ) += D(l,0);
336
337 // Finally, we store the eigenvectors
338 ev.swap(const_cast<evMatrix&>(ges.eigenvectors()));
339
340 // These are the operators representing the eigenvectors
341 typename gsMatrixOp< gsMatrix<T> >::Ptr matrOp = makeMatrixOp( ev.moveToPtr() );
342 Qop [i] = matrOp;
343 // Here we are safe as long as we do not want to apply QTop after Qop got destroyed.
344 QTop[i] = makeMatrixOp( matrOp->matrix().transpose() );
345 }
346
347 GISMO_ASSERT( glob == 1,
348 "gsPatchPreconditionerCreator::fastDiagonalizationOp: Internal error." );
349
350 diag(0,0) += avg_term;
351
352 for ( index_t l=0; l<sz; ++l )
353 diag( l, 0 ) = (T)(1)/diag( l, 0 );
354
355 memory::unique_ptr< gsEigen::DiagonalMatrix<T,Dynamic> > diag_mat( new gsEigen::DiagonalMatrix<T,Dynamic>( give(diag) ) );
356
359 makeMatrixOp(give(diag_mat)),
361 );
362}
363
364namespace {
365
366// Get the tilde basis
367template<typename T>
368void tildeSpaceBasis_oneside(const gsTensorBSplineBasis<1,T>& basis, bool isLeftHandSide, gsMatrix<T>& tildeBasis, gsMatrix<T>& complBasis, bool bc = 0, const bool odd = true)
369{
370 // bc == false: Neumann (or any other not-eliminating bc), bc == true: Dirichlet
371
372 const index_t b = (index_t)bc;
373 const index_t p = basis.degree();
374 const T h = basis.knots().maxIntervalLength();
375
376 if (p-b<=0)
377 {
378 tildeBasis.resize(0,0); complBasis.resize(0,0);
379 return;
380 }
381
382 const T u = (isLeftHandSide ? basis.knots().first() : basis.knots().last());
383 gsMatrix<T> U(1,1);
384 U(0,0) = u;
385
386 std::vector< gsMatrix<T> > allDerivs;
387 basis.evalAllDers_into(U, p-1, allDerivs);
388
389 // Collect all derivatives in matrix (rows: derivatives, columns: basis functions)
390 // normalize with h^(deriv)
391 // use only odd derivatives if odd = true and only even derivatives if odd = false
392 // skip last (on left) or first (on right) basis function since it's always in S-tilde
393 gsMatrix<T> derivs;
394 // If we have Dirichlet bc, we reduce the number of rows and columns by 1. We basically
395 // eliminate the first row and the first column (first basis function, 0th derivative)
396 // for the right-side, we have to remove the last basis function.
397 derivs.setZero(p-b, p-b);
398
399 const index_t offset = (isLeftHandSide ? b : 1);
400
401 index_t i_start;
402 if (odd) i_start = 1;
403 else i_start = 2*b;
404
405 for (index_t i = i_start; i < p; i += 2)
406 for (index_t j = 0; j < p-b; ++j)
407 derivs(i-b, j) = math::pow(h, i) * allDerivs[i](j+offset);
408
409 typename gsMatrix<T>::JacobiSVD svd = derivs.jacobiSvd(gsEigen::ComputeFullV);
410
411 index_t n_tilde;
412 if (odd) n_tilde = (p + 1) / 2 - b;
413 else n_tilde = p / 2 - b;
414
415 tildeBasis = svd.matrixV().rightCols(n_tilde);
416 complBasis = svd.matrixV().leftCols(p - b - n_tilde);
417}
418
419// Compute a basis for S-tilde and one for its orthogonal complement
420template<typename T>
421void tildeSpaceBasis(const gsBasis<T>& basis, gsSparseMatrix<T>& B_tilde, gsSparseMatrix<T>& B_compl, const gsBoundaryConditions<T>& bc, const bool odd = true)
422{
423 GISMO_ASSERT( nullptr != (dynamic_cast<const gsTensorBSplineBasis<1,T>*>(&basis)),
424 "gsPatchPreconditionersCreator<T>::getTildeSpaceBasisTransformation and "
425 "gsPatchPreconditionersCreator<T>::subspaceCorrectedMassSmootherOp only work with tensor-B-spline bases." );
426 const gsTensorBSplineBasis<1,T>& bbasis = static_cast<const gsTensorBSplineBasis<1,T>&>(basis);
427
428 patchSide west(0,boundary::west), east(0,boundary::east);
429 bool bwest = ( bc.getConditionFromSide( west ) && bc.getConditionFromSide( west )->type() == condition_type::dirichlet );
430 bool beast = ( bc.getConditionFromSide( east ) && bc.getConditionFromSide( east )->type() == condition_type::dirichlet );
431
432 gsMatrix<T> b_L, b_compl_L;
433 gsMatrix<T> b_R, b_compl_R;
434
435 // Contruct space with vanishing odd derivatives
436 tildeSpaceBasis_oneside(bbasis, true, b_L, b_compl_L, bwest, odd);
437 tildeSpaceBasis_oneside(bbasis, false, b_R, b_compl_R, beast, odd);
438
439 const index_t n = bbasis.size() - (index_t)bwest - (index_t)beast;
440 const index_t n_L = b_L.cols();
441 const index_t m_L = b_L.rows();
442 const index_t n_R = b_R.cols();
443 const index_t m_R = b_R.rows();
444 const index_t n_c_L = b_compl_L.cols();
445 const index_t m_c_L = b_compl_L.rows();
446 const index_t n_c_R = b_compl_R.cols();
447 const index_t m_c_R = b_compl_R.rows();
448 const index_t n_I = n - n_L - n_R - n_c_L - n_c_R;
449
450 //GISMO_ENSURE ( n_I >= 0, "tildeSpaceBasis: Too few knots for that spline degree." );
451 if ( n_I <= 0 )
452 {
453 static bool warned = false;
454 if (!warned)
455 {
456 gsWarn << "tildeSpaceBasis was called with too few knots for that spline degree.\n"
457 << "So, we assume that S_tilde is empty.\n";
458 warned = true;
459 }
460
461 B_tilde.resize(n,0);
462
463 gsSparseEntries<T> E_compl;
464 E_compl.reserve(n);
465 for (index_t i = 0; i < n; ++i)
466 E_compl.add(i,i,1.0);
467 B_compl.resize(n,n);
468 B_compl.setFrom(E_compl);
469 return;
470 }
471
472 gsSparseEntries<T> E_tilde, E_compl;
473
474 // put b_L into upper left block of S-tilde basis
475 for (index_t j = 0; j < n_L; ++j)
476 {
477 for (index_t i = 0; i < m_L; ++i)
478 E_tilde.add(i, j, b_L(i, j));
479 }
480 // fill identity matrix into interior part of S-tilde basis
481 for (index_t j = 0; j < n_I; ++j)
482 {
483 E_tilde.add(m_L + j, n_L + j, 1.0);
484 }
485 // put b_R into lower right block of S-tilde basis
486 for (index_t j = 0; j < n_R; ++j)
487 {
488 for (index_t i = 0; i < m_R; ++i)
489 E_tilde.add(m_L + n_I + i, n_L + n_I + j, b_R(i, j));
490 }
491 B_tilde.resize(n, n_L + n_I + n_R);
492 B_tilde.setFrom(E_tilde);
493
494 // put b_compl_L into upper left block of complement basis
495 for (index_t j = 0; j < n_c_L; ++j)
496 {
497 for (index_t i = 0; i < m_c_L; ++i)
498 E_compl.add(i, j, b_compl_L(i, j));
499 }
500 // put b_compl_R into lower right block of complement basis
501 for (index_t j = 0; j < n_c_R; ++j)
502 {
503 for (index_t i = 0; i < m_c_R; ++i)
504 E_compl.add(m_c_L + n_I + i, n_c_L + j, b_compl_R(i, j));
505 }
506 B_compl.resize(n, n_c_L + n_c_R);
507 B_compl.setFrom(E_compl);
508
509}
510
511template<typename T>
512void constructTildeSpaceBasis(
513 const gsBasis<T>& basis,
514 const gsBoundaryConditions<T>& bc,
515 const gsOptionList& opt,
516 std::vector< gsSparseMatrix<T> >& B_tilde,
517 std::vector< gsSparseMatrix<T> >& B_l2compl,
518 const bool odd = true
519 )
520{
521 const index_t d = basis.dim();
522 B_tilde.resize(d);
523 B_l2compl.resize(d);
524 dirichlet::strategy ds = (dirichlet::strategy)opt.askInt("DirichletStrategy",dirichlet::elimination);
525 if (ds == dirichlet::elimination)
526 {
527 for ( index_t i=0; i<d; ++i )
528 tildeSpaceBasis(basis.component(d-1-i), B_tilde[i], B_l2compl[i], boundaryConditionsForDirection(bc,d-1-i), odd);
529 }
530 else
531 GISMO_ERROR("Unknown Dirichlet strategy.");
532
533}
534
535// Constructs a matrix for swapping a tensor product
536// from A (x) B (x) C (x) D (x) E to A (x) D (x) C (x) B (x) E,
537// where only the dimensions of those matrices have to be given.
538// Note that also those A, B, etc. could be tensor products (here as dimension just provide the products)
539// Note that also those A, B, etc. could vanish. Then just provide a 1 as dimension, i.e., a scalar.
540// So, literally every thinkable swap is possible.
541template<typename T>
542gsSparseMatrix<T> kroneckerSwap( index_t e, index_t d, index_t c, index_t b, index_t a )
543{
544 const index_t sz = a*b*c*d*e;
545 gsSparseMatrix<T> result(sz,sz);
546 gsSparseEntries<T> entries;
547 entries.reserve(sz);
548 for ( index_t i=0; i<a; ++i )
549 for ( index_t j=0; j<b; ++j )
550 for ( index_t k=0; k<c; ++k )
551 for ( index_t l=0; l<d; ++l )
552 for ( index_t m=0; m<e; ++m )
553 entries.add( i+a*(j+b*(k+c*(l+d*m))), i+a*(l+d*(k+c*(j+b*m))), 1. );
554
555 result.setFrom(entries);
556 result.makeCompressed();
557
558 return result;
559}
560
561} // anonymous namespace
562
563template<typename T>
564std::pair< std::vector< gsSparseMatrix<T> >, std::vector< gsSparseMatrix<T> > > gsPatchPreconditionersCreator<T>::getTildeSpaceBasisTransformation(
565 const gsBasis<T>& basis,
566 const gsBoundaryConditions<T>& bc,
567 const gsOptionList& opt
568 )
569{
570 std::vector< gsSparseMatrix<T> > B_tilde, B_l2compl;
571 constructTildeSpaceBasis( basis, bc, opt, B_tilde, B_l2compl, !opt.askSwitch( "UseVanishingEvenDerivatives", false ) );
572 return std::pair< std::vector< gsSparseMatrix<T> >, std::vector< gsSparseMatrix<T> > >( B_tilde, B_l2compl );
573}
574
575template<typename T>
576typename gsPatchPreconditionersCreator<T>::OpUPtr gsPatchPreconditionersCreator<T>::subspaceCorrectedMassSmootherOp(
577 const gsBasis<T>& basis,
578 const gsBoundaryConditions<T>& bc,
579 const gsOptionList& opt,
580 T sigma,
581 T alpha,
582 T beta
583 )
584{
585 GISMO_ASSERT ( beta != 0, "gsPatchPreconditionersCreator<T>::subspaceCorrectedMassSmootherOp() does not work for beta==0." );
586
587 // Get some properties
588 const index_t d = basis.dim();
589 const T h = basis.getMinCellLength();
590
591 // Assemble univariate
592 std::vector< gsSparseMatrix<T> > local_stiff = assembleTensorStiffness(basis, bc, opt);
593 std::vector< gsSparseMatrix<T> > local_mass = assembleTensorMass(basis, bc, opt);
594
595 if (beta != 1)
596 {
597 for (index_t i=0; i!=d; ++i)
598 local_stiff[i] *= beta;
599 }
600
601 // Setup of basis
602 std::vector< gsSparseMatrix<T> > B_tilde(d), B_l2compl(d);
603 constructTildeSpaceBasis(basis, bc, opt, B_tilde, B_l2compl);
604
605 std::vector< gsSparseMatrix<T> > M_compl(d), K_compl(d), B_compl(d);
606 std::vector< typename gsLinearOperator<T>::Ptr > M_tilde_inv(d);
607 for ( index_t i=0; i<d; ++i )
608 {
609 // Transform the complement
610 typename gsLinearOperator<T>::Ptr M_inv = makeSparseCholeskySolver(local_mass[i]);
611 gsMatrix<T> B_compl_dense;
612 M_inv->apply( B_l2compl[i], B_compl_dense );
613 B_compl[i] = B_compl_dense.sparseView();
614
615 // Setup of matrices and corresponding solvers
616 gsSparseMatrix<T> M_tilde = B_tilde[i].transpose() * local_mass[i] * B_tilde[i];
617 M_tilde_inv[i] = makeSparseCholeskySolver( M_tilde );
618 M_compl[i] = B_compl[i].transpose() * local_mass[i] * B_compl[i];
619 K_compl[i] = B_compl[i].transpose() * local_stiff[i] * B_compl[i];
620 }
621
622 // Setup of final operator
623 typename gsSumOp<T>::uPtr result = gsSumOp<T>::make();
624
625 for ( index_t type = 0; type < (1<<d); ++ type )
626 {
627 std::vector< typename gsLinearOperator<T>::Ptr > correction(0);
628 gsSparseMatrix<T> transfer;
629
630 std::vector< gsSparseMatrix<T>* > transfers(d);
631
632 index_t numberInteriors = 0;
633
634 // Setup of transfer
635 for ( index_t j = 0; j<d; ++ j )
636 {
637 if ( type & ( 1 << j ) )
638 transfers[j] = &(B_compl[d-1-j]);
639 else
640 {
641 transfers[j] = &(B_tilde[d-1-j]);
642 ++numberInteriors;
643 }
644
645 if ( j == 0 )
646 transfer = *(transfers[j]);
647 else
648 transfer = transfers[j]->kron(transfer);
649
650 }
651
652 // If the subspace is not present, ignore it.
653 if ( transfer.cols() == 0 )
654 continue;
655
656 // Setup of swap, where the boundary part is shifted to the begin
657
658 index_t left = 1, current = transfers[d-1]->cols(), right = 1;
659 for ( index_t j = 0; j < d-1; ++j )
660 left *= transfers[j]->cols();
661
662 for ( index_t j = d-1; j >= 0; --j )
663 {
664 if ( type & ( 1 << j ) )
665 {
666 transfer = transfer * kroneckerSwap<T>( right, current, left, 1, 1 );
667 if ( j > 0 )
668 {
669 left *= current;
670 current = transfers[j-1]->cols();
671 left /= current;
672 }
673 }
674 else
675 {
676 if ( j > 0 )
677 {
678 right *= current;
679 current = transfers[j-1]->cols();
680 left /= current;
681 }
682 }
683
684 }
685
686 // Setup of interior correction
687 for ( index_t j = d-1; j>=0; --j )
688 {
689 if ( ! ( type & ( 1 << j ) ) )
690 correction.push_back( M_tilde_inv[d-1-j] );
691 }
692
693 // If we are in the interior, we have to do the scaling here as there is no boundary correction.
694 if ( numberInteriors == d )
695 correction[0] = gsScaledOp<T>::make( correction[0], (T)(1)/( alpha + beta*(T)(numberInteriors)/(sigma*h*h) ) );
696
697 // Setup of bondary correction
698 if ( numberInteriors < d )
699 {
700 gsSparseMatrix<T> bc_matrix;
701
702 {
703 gsSparseMatrix<T> s(0,0);
704 for ( index_t k = d-1; k>=0; --k )
705 {
706 if ( type & ( 1 << k ) )
707 {
708 if ( s.rows() == 0 )
709 s = M_compl[d-1-k];
710 else
711 s = M_compl[d-1-k].kron(s);
712 }
713 }
714 bc_matrix = ( alpha + beta*(T)(numberInteriors)/(sigma*h*h) ) * s;
715 }
716
717 for ( index_t j = d-1; j>=0; --j )
718 {
719 if ( type & ( 1 << j ) )
720 {
721 gsSparseMatrix<T> s(0,0);
722 for ( index_t k = d-1; k>=0; --k )
723 {
724 if ( type & ( 1 << k ) )
725 {
726 gsSparseMatrix<T>* chosenMatrix;
727 if ( j == k )
728 chosenMatrix = &(K_compl[d-1-k]);
729 else
730 chosenMatrix = &(M_compl[d-1-k]);
731
732 if ( s.rows() == 0 )
733 s = *chosenMatrix;
734 else
735 s = s.kron(*chosenMatrix);
736 }
737 }
738 bc_matrix += s;
739 }
740 }
741
742 correction.push_back(makeSparseCholeskySolver(bc_matrix));
743 }
744
745 typename gsMatrixOp< gsSparseMatrix<T> >::Ptr transOp = makeMatrixOp(transfer.moveToPtr());
746 // Setup of whole operator
747 // The correction is the Kronecker-product of the operators in the vector correction.
748 result->addOperator(
750 makeMatrixOp( transOp->matrix().transpose() ),
751 gsKroneckerOp<T>::make( correction ),
752 transOp
753 )
754 );
755 }
756
757 return give(result);
758
759}
760
761} // namespace gismo
A basis represents a family of scalar basis functions defined over a common parameter domain.
Definition gsBasis.h:79
Class containing a set of boundary conditions.
Definition gsBoundaryConditions.h:342
gsExprHelper< T >::space space
Space type.
Definition gsExprAssembler.h:67
Class for representing a Kronecker product of operators of type gsLinearOperator.
Definition gsKroneckerOp.h:29
static uPtr make(std::vector< BasePtr > ops)
Make command returning a smart pointer.
Definition gsKroneckerOp.h:55
virtual void apply(const gsMatrix< T > &input, gsMatrix< T > &x) const =0
apply the operator on the input vector and store the result in x
memory::shared_ptr< gsLinearOperator > Ptr
Shared pointer for gsLinearOperator.
Definition gsLinearOperator.h:33
Simple adapter class to use a matrix (or matrix-like object) as a linear operator....
Definition gsMatrixOp.h:34
NestedMatrix matrix() const
Returns the matrix.
Definition gsMatrixOp.h:84
A matrix with arbitrary coefficient type and fixed or dynamic size.
Definition gsMatrix.h:41
uPtr moveToPtr()
This function returns a smart pointer to the matrix. After calling it, the matrix object becomes empt...
Definition gsMatrix.h:170
gsMatrix kron(const gsEigen::MatrixBase< OtherDerived > &other) const
Returns the Kronecker product of this with other.
Definition gsMatrix.h:524
Class which holds a list of parameters/options, and provides easy access to them.
Definition gsOptionList.h:33
bool askSwitch(const std::string &label, const bool &value=false) const
Reads value for option label from options.
Definition gsOptionList.cpp:128
static OpUPtr massMatrixInvOp(const gsBasis< T > &basis, const gsBoundaryConditions< T > &bc=gsBoundaryConditions< T >(), const gsOptionList &opt=gsAssembler< T >::defaultOptions())
Definition gsPatchPreconditionersCreator.hpp:166
static OpUPtr massMatrixOp(const gsBasis< T > &basis, const gsBoundaryConditions< T > &bc=gsBoundaryConditions< T >(), const gsOptionList &opt=gsAssembler< T >::defaultOptions())
Definition gsPatchPreconditionersCreator.hpp:148
static gsSparseMatrix< T > stiffnessMatrix(const gsBasis< T > &basis, const gsBoundaryConditions< T > &bc=gsBoundaryConditions< T >(), const gsOptionList &opt=gsAssembler< T >::defaultOptions(), T alpha=0, T beta=1)
Definition gsPatchPreconditionersCreator.hpp:184
static OpUPtr subspaceCorrectedMassSmootherOp(const gsBasis< T > &basis, const gsBoundaryConditions< T > &bc=gsBoundaryConditions< T >(), const gsOptionList &opt=gsAssembler< T >::defaultOptions(), T sigma=(T)(12)/(T)(100), T alpha=0, T beta=1)
Definition gsPatchPreconditionersCreator.hpp:576
static OpUPtr fastDiagonalizationOp(const gsBasis< T > &basis, const gsBoundaryConditions< T > &bc=gsBoundaryConditions< T >(), const gsOptionList &opt=gsAssembler< T >::defaultOptions(), T alpha=0, T beta=1, T gamma=0)
Definition gsPatchPreconditionersCreator.hpp:264
static gsSparseMatrix< T > massMatrix(const gsBasis< T > &basis, const gsBoundaryConditions< T > &bc=gsBoundaryConditions< T >(), const gsOptionList &opt=gsAssembler< T >::defaultOptions())
Definition gsPatchPreconditionersCreator.hpp:133
static OpUPtr stiffnessMatrixOp(const gsBasis< T > &basis, const gsBoundaryConditions< T > &bc=gsBoundaryConditions< T >(), const gsOptionList &opt=gsAssembler< T >::defaultOptions(), T alpha=0, T beta=1)
Definition gsPatchPreconditionersCreator.hpp:221
static std::pair< std::vector< gsSparseMatrix< T > >, std::vector< gsSparseMatrix< T > > > getTildeSpaceBasisTransformation(const gsBasis< T > &basis, const gsBoundaryConditions< T > &bc=gsBoundaryConditions< T >(), const gsOptionList &opt=gsAssembler< T >::defaultOptions())
Definition gsPatchPreconditionersCreator.hpp:564
Class for representing the product of objects of type gsLinearOperator as gsLinearOperator.
Definition gsProductOp.h:34
static uPtr make()
Make command returning a smart pointer.
Definition gsProductOp.h:77
Allows an operator to be multiplied with a scalar.
Definition gsLinearOperator.h:78
static uPtr make(BasePtr op, T scalar=1)
Make function returning a smart pointer.
Definition gsLinearOperator.h:93
Sparse matrix class, based on gsEigen::SparseMatrix.
Definition gsSparseMatrix.h:139
gsSparseMatrix kron(const gsSparseMatrix &other) const
Returns the Kronecker product of this with other.
Definition gsSparseMatrix.h:457
uPtr moveToPtr()
This function returns a smart pointer to the matrix. After calling it, the matrix object becomes empt...
Definition gsSparseMatrix.h:247
memory::unique_ptr< gsSumOp > uPtr
Unique pointer for gsSumOp.
Definition gsSumOp.h:33
void addOperator(BasePtr op)
Add another operator.
Definition gsSumOp.h:86
static uPtr make()
Make command returning a smart pointer.
Definition gsSumOp.h:70
A tensor product B-spline basis.
Definition gsTensorBSplineBasis.h:37
#define index_t
Definition gsConfig.h:32
#define GISMO_ERROR(message)
Definition gsDebug.h:118
#define gsWarn
Definition gsDebug.h:50
#define GISMO_ASSERT(cond, message)
Definition gsDebug.h:89
Generic expressions matrix assembly.
Provides a linear operator representing the Kronecker product of linear operators.
Simple adapter classes to use matrices or linear solvers as gsLinearOperators.
A class representing the product of gsLinearOperator s.
Provides the sum of gsLinearOperator s as a gsLinearOperator.
Provides declaration of TensorBSplineBasis abstract interface.
EIGEN_STRONG_INLINE grad_expr< E > grad(const E &u)
The gradient of a variable.
Definition gsExpressions.h:4490
The G+Smo namespace, containing all definitions for the library.
GISMO_DEPRECATED index_t direction(index_t s)
Returns the parametric direction that corresponds to side s.
Definition gsBoundary.h:1048
S give(S &x)
Definition gsMemory.h:266
@ dirichlet
Dirichlet type.
Definition gsBoundaryConditions.h:31