DUNE-FEM (unstable)

localmassmatrix.hh
1#ifndef DUNE_FEM_LOCALMASSMATRIX_HH
2#define DUNE_FEM_LOCALMASSMATRIX_HH
3
4#include <memory>
5#include <vector>
6
7//- dune-common includes
10
11//- dune-geometry includes
13
14//- dune-fem includes
15#include <dune/fem/common/memory.hh>
16#include <dune/fem/common/utility.hh>
17#include <dune/fem/misc/checkgeomaffinity.hh>
18#include <dune/fem/quadrature/cachingquadrature.hh>
19#include <dune/fem/space/common/allgeomtypes.hh>
20#include <dune/fem/space/common/capabilities.hh>
21#include <dune/fem/version.hh>
22
23namespace Dune
24{
25
26 namespace Fem
27 {
28
35 template< class DiscreteFunctionSpace, class VolumeQuadrature, bool refElemScaling = true >
37 {
39
40 public:
42 typedef typename DiscreteFunctionSpaceType :: RangeFieldType ctype;
43 typedef typename DiscreteFunctionSpaceType :: RangeFieldType RangeFieldType;
44 typedef typename DiscreteFunctionSpaceType :: RangeType RangeType;
45
46 enum { dimRange = DiscreteFunctionSpaceType :: dimRange };
47 enum { localBlockSize = DiscreteFunctionSpaceType :: localBlockSize };
48 enum { dgNumDofs = localBlockSize };
49
52
53 typedef typename DiscreteFunctionSpaceType :: GridPartType GridPartType;
54
55 typedef typename DiscreteFunctionSpaceType :: IndexSetType IndexSetType;
56 typedef typename IndexSetType :: IndexType IndexType;
57
58 typedef typename DiscreteFunctionSpaceType :: BasisFunctionSetType BasisFunctionSetType;
59
60 typedef typename GridPartType :: GridType GridType;
61 typedef typename DiscreteFunctionSpaceType :: EntityType EntityType;
62 typedef typename EntityType :: Geometry Geometry;
63
64 static const bool hasSingleGeometryType = Dune :: Capabilities :: hasSingleGeometryType< GridType > :: v;
65
66 typedef VolumeQuadrature VolumeQuadratureType;
67
69
71 enum { StructuredGrid = Dune::Capabilities::isCartesian< GridType >::v };
72
75
76 // use dynamic matrix from dune-common
79
80 protected:
81 std::shared_ptr< const DiscreteFunctionSpaceType > spc_;
82 const IndexSetType& indexSet_;
83
85 const std::function<int(const int)> volumeQuadratureOrder_;
86 const bool affine_;
87
88 mutable DGMatrixType dgMatrix_;
89 mutable DGVectorType dgX_, dgRhs_;
90
91 // use dynamic vector from dune-common
92
93 mutable VectorType rhs_, row_;
94 mutable MatrixType matrix_;
95
96 mutable std::vector< RangeType > phi_;
97 mutable std::vector< RangeType > phiMass_;
98
99 mutable std::vector< std::shared_ptr< VolumeQuadratureType > > volumeQuadratures_;
100 mutable std::mutex mutex_;
101
102 typedef std::pair< std::unique_ptr< MatrixType >, std::unique_ptr< VectorType > > MatrixPairType;
103 typedef std::map< const int, MatrixPairType > MassMatrixStorageType;
104 typedef std::vector< MassMatrixStorageType > LocalInverseMassMatrixStorageType;
105
106 mutable LocalInverseMassMatrixStorageType localInverseMassMatrix_;
107
108 // index of entity from index set, don't setup mass matrix for the same entity twice
109 mutable IndexType lastEntityIndex_;
110 mutable unsigned int lastTopologyId_ ;
111 // sequence number (obtained from DofManager via the space)
112 mutable int sequence_;
113
114 struct NoMassDummyCaller
115 {
117
118 // return false since we don;t have a mass term
119 bool hasMass () const { return false; }
120
121 void mass ( const EntityType &, const VolumeQuadratureType &, int, MassFactorType & ) const
122 {}
123 };
124
125
126 bool checkDiagonalMatrix( const MatrixType& matrix ) const
127 {
128 const int rows = matrix.rows();
129 for( int r=0; r<rows; ++r )
130 {
131 for( int c=0; c<r; ++c ) // the mass matrix is symmetric
132 {
133 // if we find one off diagonal non-zero return false
134 if( std::abs(matrix[r][c]) > 1e-12 )
135 return false;
136 }
137 }
138 return true;
139 }
140
141 template< class BasisFunctionSet >
142 MatrixPairType&
143 getLocalInverseMassMatrix ( const EntityType &entity, const Geometry &geo,
144 const BasisFunctionSet &basisSet, int numBasisFct ) const
145 {
146 const GeometryType geomType = geo.type();
147 typedef typename MassMatrixStorageType::iterator iterator;
148 MassMatrixStorageType &massMap = localInverseMassMatrix_[ GlobalGeometryTypeIndex::index( geomType ) ];
149
150 auto it = massMap.find( numBasisFct );
151 if( it == massMap.end() )
152 {
153 std::pair< iterator, bool > insertPair = massMap.insert( std::make_pair( numBasisFct, MatrixPairType(nullptr,nullptr) ) );
154 it = insertPair.first;
155 insertPair.first->second.first.reset( new MatrixType( numBasisFct, numBasisFct, 0.0 ));
156 MatrixType& matrix = insertPair.first->second.first.operator *();
157
158 auto volQuadPtr = getVolumeQuadrature( entity, volumeQuadratureOrder( entity ) );
159 const VolumeQuadratureType& volQuad = *volQuadPtr;
160
161 buildMatrixNoMassFactor( entity, geo, basisSet, volQuad, numBasisFct, matrix, false );
162 try {
163 matrix.invert();
164 }
165 catch ( Dune::FMatrixError &e )
166 {
167 std::cerr << "Matrix is singular:" << std::endl << matrix << std::endl;
168 std::terminate();
169 }
170 const bool diagonal = checkDiagonalMatrix( matrix );
171 // store diagonal if matrix is diagonal
172 if( diagonal )
173 {
174 insertPair.first->second.second.reset( new VectorType( matrix.rows() ) );
175 VectorType& diag = insertPair.first->second.second.operator *();
176 const int rows = matrix.rows();
177 for( int row=0; row<rows; ++row )
178 {
179 diag[ row ] = matrix[ row ][ row ];
180 }
181 }
182 }
183
184 return it->second;
185 }
186
187 template< class MassCaller, class BasisFunctionSet >
188 MatrixType &getLocalInverseMassMatrixDefault ( MassCaller &caller, const EntityType &entity,
189 const Geometry &geo, const BasisFunctionSet &basisSet ) const
190 {
191 const int numDofs = basisSet.size();
192 // if sequence changed or entity index changed: recompute mass matrix
193 if( entityHasChanged( entity ) || (numDofs != int( matrix_.rows())) )
194 {
195 // resize temporary memory if necessary
196 if( numDofs != int( matrix_.rows() ) )
197 matrix_.resize( numDofs, numDofs );
198
199 buildMatrix( caller, entity, geo, basisSet, numDofs, matrix_ );
200 matrix_.invert();
201 }
202
203 // make sure that rhs_ has the correct size
204 assert( numDofs == int( matrix_.rows() ) );
205 return matrix_;
206 }
207
208 // return number of max non blocked dofs
209 int maxNumDofs () const
210 {
211 return space().blockMapper().maxNumDofs() * localBlockSize;
212 }
213
216 {
217 return volumeQuadratureOrder_( space().order() );
218 }
219
220 public:
222 int volumeQuadratureOrder ( const EntityType &entity ) const
223 {
224 return volumeQuadratureOrder_( space().order( entity ) );
225 }
226
228 explicit LocalMassMatrixImplementation ( const DiscreteFunctionSpaceType &spc, int volQuadOrd )
229 : LocalMassMatrixImplementation( spc, [volQuadOrd](const int order) { return volQuadOrd; } )
230 {}
231
234 std::function<int(const int)> volQuadOrderFct = [](const int order) { return Capabilities::DefaultQuadrature< DiscreteFunctionSpaceType >::volumeOrder(order); } )
235 : spc_( referenceToSharedPtr( spc ) )
236 , indexSet_( space().indexSet() )
237 , geoInfo_( indexSet_ )
238 , volumeQuadratureOrder_ ( volQuadOrderFct )
239 , affine_ ( setup() )
240 , rhs_(), row_(), matrix_()
241 , phi_( maxNumDofs() )
242 , phiMass_( maxNumDofs() )
243 , volumeQuadratures_( std::max(20, 4*spc.order()+4) ) // 19 is the highest order for gauss quadratures currently implemented
244 , localInverseMassMatrix_( GlobalGeometryTypeIndex :: size( GridType::dimension ) )
245 , lastEntityIndex_( -1 )
246 , lastTopologyId_( ~0u )
247 , sequence_( -1 )
248 {
249 }
250
253 : spc_(other.spc_),
254 indexSet_( space().indexSet() ),
255 geoInfo_( indexSet_ ),
256 volumeQuadratureOrder_( other.volumeQuadratureOrder_ ),
257 affine_( other.affine_ ),
258 rhs_( other.rhs_ ), row_( other.row_ ), matrix_( other.matrix_ ),
259 phi_( other.phi_ ),
260 phiMass_( other.phiMass_ ),
261 volumeQuadratures_( other.volumeQuadratures_ ),
262 localInverseMassMatrix_( GlobalGeometryTypeIndex :: size( GridType::dimension ) ),
263 lastEntityIndex_( other.lastEntityIndex_ ),
264 lastTopologyId_( other.lastTopologyId_ ),
265 sequence_( other.sequence_ )
266 {}
267
268 std::shared_ptr< VolumeQuadratureType >
269 getVolumeQuadrature( const EntityType& entity, const int order ) const
270 {
271 std::shared_ptr< VolumeQuadratureType > volQuadPtr;
272 // for single geometry types cache quadratures
273 // since these are expensive to create
274 if constexpr ( hasSingleGeometryType )
275 {
276 assert( order < int(volumeQuadratures_.size()) );
277 // caching does only work for normal geometry types
278 assert( ! entity.type().isNone() );
279 if( ! volumeQuadratures_[ order ] )
280 {
281 std::lock_guard< std::mutex > guard( mutex_ );
282 // check again since the state may have changed
283 if( ! volumeQuadratures_[ order ] )
284 {
285 volumeQuadratures_[ order ].reset( new VolumeQuadrature( entity, order ) );
286 }
287 }
288 volQuadPtr = volumeQuadratures_[ order ];
289 }
290 else
291 {
292 // this call needs the entity (not just the type) since it might be an
293 // agglomeration quadrature
294 volQuadPtr.reset( new VolumeQuadrature( entity, order ) );
295 }
296 return volQuadPtr;
297 }
298
299 public:
301 bool affine () const { return affine_; }
302
304 double getAffineMassFactor(const Geometry& geo) const
305 {
306 // for all normalized spaces scaling with reference element volume
307 // is needed (DG spaces)
308 if constexpr( refElemScaling )
309 {
310 return geoInfo_.referenceVolume( geo.type() ) / geo.volume();
311 }
312 else
313 {
314 // no scaling is needed for finite volume spaces
315 return 1.0 / geo.volume();
316 }
317 }
318
319 template< class BasisFunctionSet >
320 bool checkInterpolationBFS(const BasisFunctionSet &bfs) const
321 {
322 static const int quadPointSetId = SelectQuadraturePointSetId< VolumeQuadratureType >::value;
323 // if BasisFunctionSet does not have an static int member called pointSetId then this will be -1
324 static const int basePointSetId = detail::SelectPointSetId< BasisFunctionSet >::value;
325 // for Lagrange-type basis evaluated on interpolation points
326 // this is the Kronecker delta, so the mass matrix is diagonal even
327 // on non affine grids
328 if constexpr ( quadPointSetId == basePointSetId )
329 {
330 const unsigned int numShapeFunctions = bfs.size() / dimRange;
331 auto volQuadPtr = getVolumeQuadrature( bfs.entity(), volumeQuadratureOrder( bfs.entity() ) );
332 return volQuadPtr->isInterpolationQuadrature(numShapeFunctions);
333 }
334 return false;
335 }
336
339 template< class MassCaller, class BasisFunctionSet, class LocalFunction >
340 void applyInverse ( MassCaller &caller, const EntityType &entity, const BasisFunctionSet &basisFunctionSet, LocalFunction &lf ) const
341 {
342 Geometry geo = entity.geometry();
343 if( ( affine() || geo.affine() || checkInterpolationBFS(basisFunctionSet) )
344 && !caller.hasMass() )
345 applyInverseLocally( entity, geo, basisFunctionSet, lf );
346 else
347 applyInverseDefault( caller, entity, geo, basisFunctionSet, lf );
348 }
349
352 template< class MassCaller, class LocalFunction >
353 void applyInverse ( MassCaller &caller, const EntityType &entity, LocalFunction &lf ) const
354 {
355 applyInverse( caller, entity, lf.basisFunctionSet(), lf );
356 }
357
359 template< class LocalFunction >
360 void applyInverse ( const EntityType &entity, LocalFunction &lf ) const
361 {
362 NoMassDummyCaller caller;
363 applyInverse( caller, entity, lf.basisFunctionSet(), lf );
364 }
365 template< class BasisFunctionSet, class LocalFunction >
366 void applyInverse ( const EntityType &entity, const BasisFunctionSet &basisFunctionSet, LocalFunction &lf ) const
367 {
368 NoMassDummyCaller caller;
369 applyInverse( caller, entity, basisFunctionSet, lf );
370 }
371
372
374 template< class LocalFunction >
375 void applyInverse ( LocalFunction &lf ) const
376 {
377 applyInverse( lf.entity(), lf );
378 }
379
381 template< class LocalMatrix >
382 void rightMultiplyInverse ( LocalMatrix &localMatrix ) const
383 {
384 const EntityType &entity = localMatrix.rangeEntity();
385 Geometry geo = entity.geometry();
386 if( ( affine() || geo.affine() || checkInterpolationBFS(localMatrix.rangeBasisFunctionSet())) )
387 rightMultiplyInverseLocally( entity, geo, localMatrix );
388 else
389 rightMultiplyInverseDefault( entity, geo, localMatrix );
390 }
391
393 template< class LocalMatrix >
394 void leftMultiplyInverse ( LocalMatrix &localMatrix ) const
395 {
396 const EntityType &entity = localMatrix.domainEntity();
397 Geometry geo = entity.geometry();
398 if( ( affine() || geo.affine() || checkInterpolationBFS(localMatrix.rangeBasisFunctionSet())) )
399 leftMultiplyInverseLocally( entity, geo, localMatrix );
400 else
401 leftMultiplyInverseDefault( entity, geo, localMatrix );
402 }
403
404 const DiscreteFunctionSpaceType &space () const { return *spc_; }
405
407 // end of public methods
409
410 protected:
412 // applyInverse for DG spaces
414 template< class MassCaller, class BasisFunctionSet, class LocalFunction >
415 void applyInverseDgOrthoNormalBasis ( MassCaller &caller, const EntityType &entity,
416 const BasisFunctionSet &basisFunctionSet, LocalFunction &lf ) const
417 {
418 Geometry geo = entity.geometry();
419 assert( dgNumDofs == lf.size() );
420
421 // affine_ can be a static information
422 const bool isAffine = affine() || geo.affine();
423 // make sure that for affine grids the geometry info is also correct
424 assert( affine() ? geo.affine() : true );
425
426 // in case of affine mappings we only have to multiply with a factor
427 if( isAffine && !caller.hasMass() )
428 {
429 const double massVolInv = getAffineMassFactor( geo );
430
431 // apply inverse mass matrix
432 for( int l = 0; l < dgNumDofs; ++l )
433 lf[ l ] *= massVolInv;
434 }
435 else
436 {
437 // copy local function to right hand side
438 for( int l = 0; l < dgNumDofs; ++l )
439 dgRhs_[ l ] = lf[ l ];
440
441 buildMatrix( caller, entity, geo, basisFunctionSet, dgNumDofs, dgMatrix_ );
442 dgMatrix_.solve( dgX_, dgRhs_ );
443
444 // copy back to local function
445 for( int l = 0; l < dgNumDofs; ++l )
446 lf[ l ] = dgX_[ l ];
447 }
448 }
449
451 template< class LocalMatrix >
452 void rightMultiplyInverseDgOrthoNormalBasis ( LocalMatrix &localMatrix ) const
453 {
454 const EntityType &entity = localMatrix.rangeEntity();
455 Geometry geo = entity.geometry();
456 assert( dgNumDofs == localMatrix.columns() );
457
458 // in case of affine mappings we only have to multiply with a factor
459 if( affine() || geo.affine() )
460 {
461 localMatrix.scale( getAffineMassFactor( geo ) );
462 }
463 else
464 {
465 NoMassDummyCaller caller;
466 buildMatrix( caller, entity, geo, localMatrix.rangeBasisFunctionSet(), dgNumDofs, dgMatrix_ );
467 dgMatrix_.invert();
468
469 const int rows = localMatrix.rows();
470 for( int i = 0; i < rows; ++i )
471 {
472 for( int j = 0; j < dgNumDofs; ++j )
473 dgRhs_[ j ] = localMatrix.get( i, j );
474 dgMatrix_.mtv( dgRhs_, dgX_ );
475 for( int j = 0; j < dgNumDofs; ++j )
476 localMatrix.set( i, j, dgX_[ j ] );
477 }
478 }
479 }
480
482 template< class LocalMatrix >
483 void leftMultiplyInverseDgOrthoNormalBasis ( LocalMatrix &localMatrix ) const
484 {
485 const EntityType &entity = localMatrix.domainEntity();
486 Geometry geo = entity.geometry();
487 assert( dgNumDofs == localMatrix.columns() );
488
489 // in case of affine mappings we only have to multiply with a factor
490 if( affine() || geo.affine() )
491 {
492 localMatrix.scale( getAffineMassFactor( geo ) );
493 }
494 else
495 {
496 NoMassDummyCaller caller;
497 buildMatrix( caller, entity, geo, localMatrix.domainBasisFunctionSet(), dgNumDofs, dgMatrix_ );
498 dgMatrix_.invert();
499
500 const int rows = localMatrix.rows();
501 for( int i = 0; i < rows; ++i )
502 {
503 for( int j = 0; j < dgNumDofs; ++j )
504 dgRhs_[ j ] = localMatrix.get( i, j );
505 dgMatrix_.mv( dgRhs_, dgX_ );
506 for( int j = 0; j < dgNumDofs; ++j )
507 localMatrix.set( i, j, dgX_[ j ] );
508 }
509 }
510 }
511
513 bool entityHasChanged( const EntityType& entity ) const
514 {
515 // don't compute matrix new for the same entity
516 const int currentSequence = space().sequence();
517 const unsigned int topologyId = entity.type().id();
518 const IndexType entityIndex = indexSet_.index( entity ) ;
519
520 // check whether sequence has been updated
521 if( sequence_ != currentSequence ||
522 lastEntityIndex_ != entityIndex ||
523 lastTopologyId_ != topologyId )
524 {
525 // update identifiers
526 lastEntityIndex_ = entityIndex ;
527 sequence_ = currentSequence;
528 lastTopologyId_ = topologyId ;
529
530 return true ;
531 }
532 else
533 // the entity did not change
534 return false ;
535 }
536
538 // standard applyInverse method
542 template< class MassCaller, class BasisFunctionSet, class LocalFunction >
543 void applyInverseDefault ( MassCaller &caller, const EntityType &entity,
544 const Geometry &geo, const BasisFunctionSet &basisFunctionSet, LocalFunction &lf ) const
545 {
546 // get local inverted mass matrix
547 MatrixType &invMassMatrix
548 = getLocalInverseMassMatrixDefault ( caller, entity, geo, basisFunctionSet );
549
550 // copy local function to right hand side
551 const int numDofs = lf.size();
552 rhs_.resize( numDofs );
553 for( int l = 0; l < numDofs; ++l )
554 rhs_[ l ] = lf[ l ];
555
556 // apply inverse to right hand side and store in lf
557 multiply( numDofs, invMassMatrix, rhs_, lf );
558 }
559
561 template< class LocalMatrix >
562 void rightMultiplyInverseDefault ( const EntityType &entity, const Geometry &geo, LocalMatrix &localMatrix ) const
563 {
564 NoMassDummyCaller caller;
565 MatrixType &invMassMatrix
566 = getLocalInverseMassMatrixDefault ( caller, entity, geo, localMatrix.rangeBasisFunctionSet() );
567
568 const int cols = localMatrix.columns();
569 rhs_.resize( cols );
570 row_.resize( cols );
571
572 const int rows = localMatrix.rows();
573 for( int i = 0; i < rows; ++i )
574 {
575 // get i-th row from localMatrix
576 for( int j = 0; j < cols; ++j )
577 rhs_[ j ] = localMatrix.get( i, j );
578
579 // multiply with all columns of inverse mass matrix
580 invMassMatrix.mtv( rhs_, row_ );
581
582 // store as i-th row in localMatrix
583 for( int j = 0; j < cols; ++j )
584 localMatrix.set( i, j, row_[ j ] );
585 }
586 }
587
589 template< class LocalMatrix >
590 void leftMultiplyInverseDefault ( const EntityType &entity, const Geometry &geo, LocalMatrix &localMatrix ) const
591 {
592 NoMassDummyCaller caller;
593 MatrixType &invMassMatrix
594 = getLocalInverseMassMatrixDefault ( caller, entity, geo, localMatrix.rangeBasisFunctionSet() );
595
596 const int cols = localMatrix.columns();
597 rhs_.resize( cols );
598 row_.resize( cols );
599
600 const int rows = localMatrix.rows();
601 for( int i = 0; i < rows; ++i )
602 {
603 // get i-th column from localMatrix
604 for( int j = 0; j < cols; ++j )
605 rhs_[ j ] = localMatrix.get( j, i );
606
607 // multiply with all rows in inverse mass matrix
608 invMassMatrix.mv( rhs_, row_ );
609
610 // store as i-th column in localMatrix
611 for( int j = 0; j < cols; ++j )
612 localMatrix.set( j, i, row_[ j ] );
613 }
614 }
615
616
618 // local applyInverse method for affine geometries
621 template< class BasisFunctionSet, class LocalFunction >
622 void applyInverseLocally ( const EntityType &entity,
623 const Geometry &geo, const BasisFunctionSet &basisFunctionSet, LocalFunction &lf ) const
624 {
625 const int numDofs = lf.size();
626
627 // get local inverted mass matrix
628 MatrixPairType& matrixPair =
629 getLocalInverseMassMatrix( entity, geo, basisFunctionSet, numDofs );
630
631 // if diagonal exists then matrix is in diagonal form
632 if( matrixPair.second )
633 {
634 const VectorType& diagonal = *matrixPair.second;
635 assert( int(diagonal.size()) == numDofs );
636
637 auto volQuadPtr = getVolumeQuadrature( entity, volumeQuadratureOrder( entity ) );
638 const VolumeQuadratureType& volQuad = *volQuadPtr;
639
640 const int nop = volQuad.nop();
641 assert(nop*dimRange == numDofs);
642 for( int l=0, qt = 0; qt < nop; ++qt )
643 {
644 const auto intel = geo.integrationElement( volQuad.point(qt) );
645 for (int r = 0; r < dimRange; ++r, ++l )
646 {
647 lf[ l ] *= diagonal[ l ] / intel;
648 }
649 }
650 }
651 else
652 {
653 const double massVolInv = getAffineMassFactor( geo );
654 // copy local function to right hand side
655 // and apply inverse mass volume fraction
656 rhs_.resize( numDofs );
657 for( int l = 0; l < numDofs; ++l )
658 rhs_[ l ] = lf[ l ] * massVolInv;
659
660 const MatrixType& invMassMatrix = *matrixPair.first;
661 // apply inverse local mass matrix and store in lf
662 multiply( numDofs, invMassMatrix, rhs_, lf );
663 }
664 }
665
666 template <class LocalMatrix>
667 const VectorType&
668 setupInverseDiagonal( const EntityType &entity, const Geometry &geo,
669 const VectorType& refElemDiagonal,
670 LocalMatrix &localMatrix ) const
671 {
672 const int cols = localMatrix.columns();
673
674 assert( int(refElemDiagonal.size()) == cols );
675
676 auto volQuadPtr = getVolumeQuadrature( entity, volumeQuadratureOrder( entity ) );
677 const VolumeQuadratureType& volQuad = *volQuadPtr;
678
679 VectorType& elementDiagonal = rhs_;
680 elementDiagonal.resize( cols );
681
682 const int nop = volQuad.nop();
683 assert(nop*dimRange == cols);
684 for( int l = 0, qt = 0; qt < nop; ++qt )
685 {
686 const auto intel = geo.integrationElement( volQuad.point(qt) );
687 for (int r = 0; r < dimRange; ++r,++l )
688 {
689 elementDiagonal[ l ] = refElemDiagonal[ l ] / intel;
690 }
691 }
692 return elementDiagonal;
693 }
694
695 template< class LocalMatrix >
696 void rightMultiplyInverseLocally ( const EntityType &entity, const Geometry &geo, LocalMatrix &localMatrix ) const
697 {
698 const int cols = localMatrix.columns();
699 MatrixPairType& matrixPair =
700 getLocalInverseMassMatrix( entity, geo, localMatrix.rangeBasisFunctionSet(), cols );
701
702 // if diagonal exists then matrix is in diagonal form
703 // stored as inverse on the reference element
704 if( matrixPair.second )
705 {
706 const VectorType& elementDiagonal =
707 setupInverseDiagonal( entity, geo, *matrixPair.second, localMatrix );
708
709 row_.resize( cols );
710 const int rows = localMatrix.rows();
711 for( int i = 0; i < rows; ++i )
712 {
713 // get i-th row from localMatrix
714 // and multiply with diagonal of inverse mass matrix
715 for( int j = 0; j < cols; ++j )
716 row_[ j ] = elementDiagonal[ j ] * localMatrix.get( i, j );
717
718 // store as i-th row in localMatrix
719 for( int j = 0; j < cols; ++j )
720 localMatrix.set( i, j, row_[ j ] );
721 }
722 }
723 else
724 {
725 const MatrixType &invMassMatrix = *matrixPair.first;
726
727 const double massVolInv = getAffineMassFactor( geo );
728
729 rhs_.resize( cols );
730 row_.resize( cols );
731
732 const int rows = localMatrix.rows();
733 for( int i = 0; i < rows; ++i )
734 {
735 // get i-th row from localMatrix
736 // and multiply with diagonal of inverse mass matrix
737 for( int j = 0; j < cols; ++j )
738 rhs_[ j ] = localMatrix.get( i, j ) * massVolInv;
739
740 // multiply with all columns of inverse mass matrix
741 invMassMatrix.mtv( rhs_, row_ );
742
743 // store as i-th row of localMatrix
744 for( int j = 0; j < cols; ++j )
745 localMatrix.set( i, j, row_[ j ] );
746 }
747 }
748 }
749
751 template< class LocalMatrix >
752 void leftMultiplyInverseLocally ( const EntityType &entity, const Geometry &geo, LocalMatrix &localMatrix ) const
753 {
754 const int cols = localMatrix.columns();
755 MatrixPairType& matrixPair =
756 getLocalInverseMassMatrix( entity, geo, localMatrix.rangeBasisFunctionSet(), cols );
757
758 // if diagonal exists then matrix is in diagonal form
759 // stored as inverse on the reference element
760 if( matrixPair.second )
761 {
762 const VectorType& elementDiagonal =
763 setupInverseDiagonal( entity, geo, *matrixPair.second, localMatrix );
764
765 row_.resize( cols );
766 const int rows = localMatrix.rows();
767 for( int i = 0; i < rows; ++i )
768 {
769 // get i-th column from localMatrix
770 // and multiply with diagonal of inverse mass matrix
771 for( int j = 0; j < cols; ++j )
772 row_[ j ] = elementDiagonal[ j ] * localMatrix.get( j, i );
773
774 // store as i-th column of localMatrix
775 for( int j = 0; j < cols; ++j )
776 localMatrix.set( j, i, row_[ j ] );
777 }
778 }
779 else
780 {
781 const MatrixType &invMassMatrix = *matrixPair.first;
782
783 const double massVolInv = getAffineMassFactor( geo );
784
785 rhs_.resize( cols );
786 row_.resize( cols );
787
788 const int rows = localMatrix.rows();
789 for( int i = 0; i < rows; ++i )
790 {
791 // get i-th column from localMatrix
792 for( int j = 0; j < cols; ++j )
793 rhs_[ j ] = localMatrix.get( j, i ) * massVolInv;
794
795 // apply to all rows of inverse mass matrix
796 invMassMatrix.mv( rhs_, row_ );
797
798 // store as i-th column of localMatrix
799 for( int j = 0; j < cols; ++j )
800 localMatrix.set( j, i, row_[ j ] );
801 }
802 }
803 }
804
805
807 bool setup () const
808 {
809 // for structured grids this is always true
810 if( StructuredGrid )
811 return true;
812
813 // get types for codim 0
814 const std::vector<Dune::GeometryType>& geomTypes = geoInfo_.geomTypes(0);
815
816 // for simplices we also have affine mappings
817 if( (geomTypes.size() == 1) && geomTypes[0].isSimplex() )
818 {
819 return true;
820 }
821
822 // otherwise use geometry affinity
823 return false ;
824 }
825
827 template< class MassCaller, class Matrix >
828 void buildMatrix ( MassCaller &caller, const EntityType &entity,
829 const Geometry &geo, const BasisFunctionSetType &set,
830 std::size_t numDofs, Matrix &matrix ) const
831 {
832 assert( numDofs == set.size() );
833
834 // clear matrix
835 matrix = 0;
836
837 // create quadrature
838 auto volQuadPtr = getVolumeQuadrature( entity, volumeQuadratureOrder( entity ) );
839 const VolumeQuadratureType& volQuad = *volQuadPtr;
840
841 if( caller.hasMass() )
842 buildMatrixWithMassFactor( caller, entity, geo, set, volQuad, numDofs, matrix );
843 else
844 buildMatrixNoMassFactor( entity, geo, set, volQuad, numDofs, matrix );
845 }
846
848 template <class Matrix>
850 const EntityType& en,
851 const Geometry& geo,
852 const BasisFunctionSetType& set,
853 const VolumeQuadratureType& volQuad,
854 const int numDofs,
855 Matrix& matrix,
856 const bool applyIntegrationElement = true ) const
857 {
858 const int volNop = volQuad.nop();
859 for(int qp=0; qp<volNop; ++qp)
860 {
861 // calculate integration weight
862 const double intel = ( applyIntegrationElement ) ?
863 ( volQuad.weight(qp) * geo.integrationElement(volQuad.point(qp)) ) : volQuad.weight(qp) ;
864
865 // eval basis functions
866 set.evaluateAll(volQuad[qp], phi_);
867
868 for(int m=0; m<numDofs; ++m)
869 {
870 const RangeType& phi_m = phi_[m];
871 const ctype val = intel * (phi_m * phi_m);
872 matrix[m][m] += val;
873
874 for(int k=m+1; k<numDofs; ++k)
875 {
876 const ctype val = intel * (phi_m * phi_[k]);
877 matrix[m][k] += val;
878 matrix[k][m] += val;
879 }
880 }
881 }
882 }
883
885 template <class MassCallerType, class Matrix>
887 MassCallerType& caller,
888 const EntityType& en,
889 const Geometry& geo,
890 const BasisFunctionSetType& set,
891 const VolumeQuadratureType& volQuad,
892 const int numDofs,
893 Matrix& matrix) const
894 {
895 typedef typename MassCallerType :: MassFactorType MassFactorType;
896 MassFactorType mass;
897
898 const int volNop = volQuad.nop();
899 for(int qp=0; qp<volNop; ++qp)
900 {
901 // calculate integration weight
902 const double intel = volQuad.weight(qp)
903 * geo.integrationElement(volQuad.point(qp));
904
905 // eval basis functions
906 set.evaluateAll( volQuad[qp], phi_);
907
908 // call mass factor
909 caller.mass( en, volQuad, qp, mass);
910
911 // apply mass matrix to all basis functions
912 for(int m=0; m<numDofs; ++m)
913 {
914 mass.mv( phi_[m], phiMass_[m] );
915 }
916
917 // add values to matrix
918 for(int m=0; m<numDofs; ++m)
919 {
920 for(int k=0; k<numDofs; ++k)
921 {
922 matrix[m][k] += intel * (phiMass_[m] * phi_[k]);
923 }
924 }
925 }
926 }
927
928 // implement matvec with matrix (mv of densematrix is too stupid)
929 template <class Matrix, class Rhs, class X>
930 void multiply( const int size,
931 const Matrix& matrix,
932 const Rhs& rhs,
933 X& x ) const
934 {
935 assert( (int) matrix.rows() == size );
936 assert( (int) matrix.cols() == size );
937 assert( (int) rhs.size() == size );
938
939 for( int row = 0; row < size; ++ row )
940 {
941 RangeFieldType sum = 0;
942 // get matrix row
943 typedef typename Matrix :: const_row_reference MatRow;
944 MatRow matRow = matrix[ row ];
945
946 // multiply row with right hand side
947 for( int col = 0; col < size; ++ col )
948 {
949 sum += matRow[ col ] * rhs[ col ];
950 }
951
952 // set to result to result vector
953 x[ row ] = sum;
954 }
955 }
956 };
957
958
959
960 // LocalMassMatrix
961 // ---------------
962
964 template< class DiscreteFunctionSpace, class VolumeQuadrature >
966 : public LocalMassMatrixImplementation< DiscreteFunctionSpace, VolumeQuadrature >
967 {
969
970 public:
971 // copy base class constructors
972 using BaseType :: BaseType;
973 };
974
975
976
978 //
979 // DG LocalMassMatrix Implementation
980 //
982
984 template< class DiscreteFunctionSpace, class VolumeQuadrature, bool refElemScaling = true >
986 : public LocalMassMatrixImplementation< DiscreteFunctionSpace, VolumeQuadrature, refElemScaling >
987 {
989
990 public:
991 typedef typename BaseType :: EntityType EntityType;
992
993 // copy base class constructors
995
998 template <class MassCallerType, class BasisFunction, class LocalFunctionType>
999 void applyInverse(MassCallerType& caller,
1000 const EntityType& en,
1001 const BasisFunction &basisFunction,
1002 LocalFunctionType& lf) const
1003 {
1004 BaseType :: applyInverseDgOrthoNormalBasis( caller, en, basisFunction, lf );
1005 }
1006 template <class MassCallerType, class LocalFunctionType>
1007 void applyInverse(MassCallerType& caller,
1008 const EntityType& en,
1009 LocalFunctionType& lf) const
1010 {
1011 BaseType :: applyInverseDgOrthoNormalBasis( caller, en, lf.basisFunctionSet(), lf );
1012 }
1013
1015 template <class LocalFunctionType>
1016 void applyInverse(const EntityType& en,
1017 LocalFunctionType& lf) const
1018 {
1019 typename BaseType :: NoMassDummyCaller caller;
1020 applyInverse(caller, en, lf );
1021 }
1022
1023 template <class BasisFunction, class LocalFunctionType>
1024 void applyInverse(const EntityType& en,
1025 const BasisFunction &basisFunction,
1026 LocalFunctionType& lf) const
1027 {
1028 typename BaseType :: NoMassDummyCaller caller;
1029 applyInverse(caller, en, basisFunction, lf );
1030 }
1031
1033 template< class LocalFunction >
1034 void applyInverse ( LocalFunction &lf ) const
1035 {
1036 applyInverse( lf.entity(), lf.basisFunctionSet(), lf );
1037 }
1038
1040 template< class LocalMatrix >
1041 void rightMultiplyInverse ( LocalMatrix &localMatrix ) const
1042 {
1044 }
1045
1047 template< class LocalMatrix >
1048 void leftMultiplyInverse ( LocalMatrix &localMatrix ) const
1049 {
1051 }
1052 };
1053
1055
1056 } // namespace Fem
1057
1058} // namespace Dune
1059
1060#endif // #ifndef DUNE_FEM_LOCALMASSMATRIX_HH
discrete function space
void solve(V1 &x, const V2 &b, bool doPivoting=true) const
Solve system A x = b.
void mv(const X &x, Y &y) const
y = A x
Definition: densematrix.hh:368
void invert(bool doPivoting=true)
Compute inverse.
void mtv(const X &x, Y &y) const
y = A^T x
Definition: densematrix.hh:387
constexpr size_type rows() const
number of rows
Definition: densematrix.hh:709
void resize(size_type r, size_type c, value_type v=value_type())
resize matrix to r × c
Definition: dynmatrix.hh:106
Error thrown if operations of a FieldMatrix fail.
Definition: densematrix.hh:126
BaseType::IndexType IndexType
index type *‍/
Definition: adaptiveleafindexset.hh:125
const std ::vector< GeometryType > & geomTypes(unsigned int codim) const
returns vector with geometry tpyes this index set has indices for
Definition: allgeomtypes.hh:171
Interface class for basis function sets.
Definition: basisfunctionset.hh:32
const EntityType & entity() const
return entity
std::size_t size() const
return size of basis function set
ctype referenceVolume(const GeometryType &type) const
return volume of reference element for geometry of type type
Definition: allgeomtypes.hh:72
FieldVector< ctype, dim > DomainType
type of domain vector
Definition: allgeomtypes.hh:51
interface for local functions
Definition: localfunction.hh:77
const EntityType & entity() const
obtain the entity, this local function lives on
Definition: localfunction.hh:305
const BasisFunctionSetType & basisFunctionSet() const
obtain the basis function set for this local function
Definition: localfunction.hh:299
SizeType size() const
obtain the number of local DoFs
Definition: localfunction.hh:369
DG Local Mass Matrix for arbitrary spaces.
Definition: localmassmatrix.hh:987
void applyInverse(const EntityType &en, LocalFunctionType &lf) const
apply local dg mass matrix to local function lf without mass factor
Definition: localmassmatrix.hh:1016
void rightMultiplyInverse(LocalMatrix &localMatrix) const
compute localMatrix * M^-1
Definition: localmassmatrix.hh:1041
void applyInverse(MassCallerType &caller, const EntityType &en, const BasisFunction &basisFunction, LocalFunctionType &lf) const
Definition: localmassmatrix.hh:999
void applyInverse(LocalFunction &lf) const
apply local dg mass matrix to local function lf without mass factor
Definition: localmassmatrix.hh:1034
void leftMultiplyInverse(LocalMatrix &localMatrix) const
compute M^-1 * localMatrix
Definition: localmassmatrix.hh:1048
Local Mass Matrix inversion implementation, select the correct method in your implementation.
Definition: localmassmatrix.hh:37
void buildMatrixNoMassFactor(const EntityType &en, const Geometry &geo, const BasisFunctionSetType &set, const VolumeQuadratureType &volQuad, const int numDofs, Matrix &matrix, const bool applyIntegrationElement=true) const
build local mass matrix with mass factor
Definition: localmassmatrix.hh:849
void applyInverseDefault(MassCaller &caller, const EntityType &entity, const Geometry &geo, const BasisFunctionSet &basisFunctionSet, LocalFunction &lf) const
Definition: localmassmatrix.hh:543
void leftMultiplyInverse(LocalMatrix &localMatrix) const
compute M^-1 * localMatrix
Definition: localmassmatrix.hh:394
void leftMultiplyInverseLocally(const EntityType &entity, const Geometry &geo, LocalMatrix &localMatrix) const
compute M^-1 * localMatrix
Definition: localmassmatrix.hh:752
bool entityHasChanged(const EntityType &entity) const
returns true if the entity has been changed
Definition: localmassmatrix.hh:513
LocalMassMatrixImplementation(const DiscreteFunctionSpaceType &spc, int volQuadOrd)
constructor taking space and volume quadrature order
Definition: localmassmatrix.hh:228
void applyInverse(MassCaller &caller, const EntityType &entity, const BasisFunctionSet &basisFunctionSet, LocalFunction &lf) const
Definition: localmassmatrix.hh:340
bool affine() const
returns true if geometry mapping is affine
Definition: localmassmatrix.hh:301
double getAffineMassFactor(const Geometry &geo) const
return mass factor for diagonal mass matrix
Definition: localmassmatrix.hh:304
void applyInverseLocally(const EntityType &entity, const Geometry &geo, const BasisFunctionSet &basisFunctionSet, LocalFunction &lf) const
apply local mass matrix to local function lf
Definition: localmassmatrix.hh:622
void applyInverse(const EntityType &entity, LocalFunction &lf) const
apply local dg mass matrix to local function lf without mass factor
Definition: localmassmatrix.hh:360
void applyInverse(LocalFunction &lf) const
apply local dg mass matrix to local function lf without mass factor
Definition: localmassmatrix.hh:375
void buildMatrix(MassCaller &caller, const EntityType &entity, const Geometry &geo, const BasisFunctionSetType &set, std::size_t numDofs, Matrix &matrix) const
build local mass matrix
Definition: localmassmatrix.hh:828
void rightMultiplyInverseDgOrthoNormalBasis(LocalMatrix &localMatrix) const
compute localMatrix * M^-1
Definition: localmassmatrix.hh:452
int maxVolumeQuadratureOrder() const
return appropriate quadrature order, default is 2 * order()
Definition: localmassmatrix.hh:215
LocalMassMatrixImplementation(const ThisType &other)
copy constructor
Definition: localmassmatrix.hh:252
int volumeQuadratureOrder(const EntityType &entity) const
return appropriate quadrature order, default is 2 * order(entity)
Definition: localmassmatrix.hh:222
void rightMultiplyInverseDefault(const EntityType &entity, const Geometry &geo, LocalMatrix &localMatrix) const
compute localMatrix * M^-1
Definition: localmassmatrix.hh:562
void applyInverse(MassCaller &caller, const EntityType &entity, LocalFunction &lf) const
Definition: localmassmatrix.hh:353
void buildMatrixWithMassFactor(MassCallerType &caller, const EntityType &en, const Geometry &geo, const BasisFunctionSetType &set, const VolumeQuadratureType &volQuad, const int numDofs, Matrix &matrix) const
build local mass matrix with mass factor
Definition: localmassmatrix.hh:886
void rightMultiplyInverse(LocalMatrix &localMatrix) const
compute localMatrix * M^-1
Definition: localmassmatrix.hh:382
void leftMultiplyInverseDefault(const EntityType &entity, const Geometry &geo, LocalMatrix &localMatrix) const
compute M^-1 * localMatrix
Definition: localmassmatrix.hh:590
LocalMassMatrixImplementation(const DiscreteFunctionSpaceType &spc, std::function< int(const int)> volQuadOrderFct=[](const int order) { return Capabilities::DefaultQuadrature< DiscreteFunctionSpaceType >::volumeOrder(order);})
constructor taking space and volume quadrature order
Definition: localmassmatrix.hh:233
bool setup() const
setup and return affinity
Definition: localmassmatrix.hh:807
void leftMultiplyInverseDgOrthoNormalBasis(LocalMatrix &localMatrix) const
compute M^-1 * localMatrix
Definition: localmassmatrix.hh:483
Local Mass Matrix for arbitrary spaces.
Definition: localmassmatrix.hh:967
Unique label for each type of entities that can occur in DUNE grids.
Definition: type.hh:114
Wrapper class for geometries.
Definition: geometry.hh:71
Volume integrationElement(const LocalCoordinate &local) const
Return the factor appearing in the integral transformation formula.
Definition: geometry.hh:265
bool affine() const
Return true if the geometry mapping is affine and false otherwise.
Definition: geometry.hh:197
Compute indices for geometry types, taking the dimension into account.
Definition: typeindex.hh:90
static constexpr std::size_t index(const GeometryType &gt)
Compute the index for the given geometry type over all dimensions.
Definition: typeindex.hh:138
static constexpr std::size_t size(std::size_t maxdim)
Compute total number of geometry types up to and including the given dimension.
Definition: typeindex.hh:125
A generic dynamic dense matrix.
Definition: matrix.hh:561
This file implements a dense matrix with dynamic numbers of rows and columns.
Implements a matrix constructed from a given type representing a field and compile-time given number ...
Dune namespace.
Definition: alignedallocator.hh:13
constexpr std::integral_constant< std::size_t, sizeof...(II)> size(std::integer_sequence< T, II... >)
Return the size of the sequence.
Definition: integersequence.hh:75
Specialize with 'true' if the grid is a Cartesian grid. Cartesian grids satisfy the following propert...
Definition: capabilities.hh:48
static int volumeOrder(const int k)
return quadrature order for volume quadratures for given polynomial order k
Definition: capabilities.hh:138
Helper class to check affinity of the grid's geometries.
Definition: checkgeomaffinity.hh:22
selects Obj::pointSetId if available, otherwise defaultValue (default is -1)
Definition: utility.hh:174
Helper classes to provide indices for geometrytypes for use in a vector.
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Nov 21, 23:30, 2024)