DUNE-FEM (unstable)

molgalerkin.hh
1#ifndef DUNE_FEM_SCHEMES_MOLGALERKIN_HH
2#define DUNE_FEM_SCHEMES_MOLGALERKIN_HH
3
4// fem includes
5#include <dune/fem/schemes/galerkin.hh>
6#include <dune/fem/function/localfunction/temporary.hh>
7#include <dune/fem/common/bindguard.hh>
8
9namespace Dune
10{
11
12 namespace Fem
13 {
14
15#if HAVE_PETSC
16 //forward declaration of PetscLinearOperator
17 template <typename DomainFunction, typename RangeFunction >
18 class PetscLinearOperator ;
19#endif
20
21 // GalerkinOperator
22 // ----------------
23
24 template< class Integrands, class DomainFunction, class RangeFunction = DomainFunction >
25 struct MOLGalerkinOperator
26 : public virtual Operator< DomainFunction, RangeFunction >
27 {
28 typedef DomainFunction DomainFunctionType;
29 typedef RangeFunction RangeFunctionType;
30
31
32 static_assert( std::is_same< typename DomainFunctionType::GridPartType, typename RangeFunctionType::GridPartType >::value, "DomainFunction and RangeFunction must be defined on the same grid part." );
33
34 typedef typename RangeFunctionType::GridPartType GridPartType;
35 typedef ThreadIterator< GridPartType > ThreadIteratorType;
36
37 typedef Impl::GalerkinOperator< GridPartType > GalerkinOperatorImplType;
38 typedef Impl::LocalGalerkinOperator< Integrands > LocalGalerkinOperatorImplType;
39
40 typedef typename RangeFunctionType :: DiscreteFunctionSpaceType DiscreteFunctionSpaceType;
41
42 typedef typename LocalGalerkinOperatorImplType::template QuadratureSelector<
43 DiscreteFunctionSpaceType > :: InteriorQuadratureType InteriorQuadratureType;
44
45 typedef LocalMassMatrix< DiscreteFunctionSpaceType, InteriorQuadratureType > LocalMassMatrixType ;
46
47 template< class... Args >
48 explicit MOLGalerkinOperator ( const GridPartType &gridPart, Args &&... args )
49 : iterators_( gridPart ),
50 opImpl_( gridPart ),
51 localOp_( gridPart, std::forward< Args >( args )... ),
52 gridSizeInterior_( 0 ),
53 communicate_( true )
54 {
55 }
56
57 void setCommunicate( const bool communicate )
58 {
59 communicate_ = communicate;
60 if( ! communicate_ && Dune::Fem::Parameter::verbose() )
61 {
62 std::cout << "MOLGalerkinOperator::setCommunicate: communicate was disabled!" << std::endl;
63 }
64 }
65
66 void setQuadratureOrders(unsigned int interior, unsigned int surface)
67 {
68 size_t size = localOp_.size();
69 for( size_t i=0; i<size; ++i )
70 localOp_[ i ].setQuadratureOrders(interior,surface);
71 }
72
73 virtual void operator() ( const DomainFunctionType &u, RangeFunctionType &w ) const final override
74 {
75 evaluate( u, w );
76 }
77
78 template< class GridFunction >
79 void operator() ( const GridFunction &u, RangeFunctionType &w ) const
80 {
81 evaluate( u, w );
82 }
83
84 const GridPartType &gridPart () const { return op().gridPart(); }
85
86 typedef Integrands ModelType;
87 typedef Integrands DirichletModelType;
88 ModelType &model() const { return localOperator().model(); }
89
90 [[deprecated("Use localOperator instead!")]]
91 const GalerkinOperatorImplType& impl() const { return localOperator(); }
92
93 const LocalGalerkinOperatorImplType& localOperator() const { return (*localOp_); }
94
95 std::size_t gridSizeInterior () const { return gridSizeInterior_; }
96
97 protected:
98 const GalerkinOperatorImplType& op() const { return (*opImpl_); }
99
100 template <class Iterators>
101 void applyInverseMass( const Iterators& iterators, RangeFunctionType& w ) const
102 {
103 // temporary local function
104 typedef TemporaryLocalFunction< typename RangeFunctionType::DiscreteFunctionSpaceType > TemporaryLocalFunctionType;
105 TemporaryLocalFunctionType wLocal( w.space() );
106 LocalMassMatrixType localMassMatrix( w.space(), localOperator().interiorQuadratureOrder( w.space().order() ) );
107
108 // iterate over all elements (in the grid or per thread)
109 // thread safety is guaranteed through discontinuous data (spaces)
110 for( const auto& entity : iterators )
111 {
112 // obtain local function
113 auto guard = bindGuard( wLocal, entity );
114 // obtain local dofs
115 w.getLocalDofs( entity, wLocal.localDofVector() );
116
117 // apply inverse mass matrix
118 // TODO: add mass term if needed (from ufl expression)
119 localMassMatrix.applyInverse( entity, wLocal );
120
121 // overwrite dofs in discrete function
122 w.setLocalDofs( entity, wLocal.localDofVector() );
123 }
124 }
125
126 template< class GridFunction >
127 void evaluate( const GridFunction &u, RangeFunctionType &w ) const
128 {
129 iterators_.update();
130 w.clear();
131
132 std::shared_mutex mutex;
133
134 auto doEval = [this, &u, &w, &mutex] ()
135 {
136 // version with locking
137 std::tuple< const LocalGalerkinOperatorImplType& > integrands( localOperator() );
138 this->op().evaluate( u, w, this->iterators_, integrands, mutex );
139
140 // version without locking
141 //RangeFunctionType wTmp( w );
142 //this->op().evaluate( u, wTmp, this->iterators_ );
143 //std::lock_guard guard ( mutex );
144 //w += wTmp;
145 };
146
147 bool singleThreadModeError = false ;
148
149 try {
150 // execute in parallel
151 MPIManager :: run ( doEval );
152
153 // update grid size interior
154 gridSizeInterior_ = Impl::accumulateGridSize( opImpl_ );
155 }
156 catch ( const SingleThreadModeError& e )
157 {
158 singleThreadModeError = true;
159 }
160
161 // method of lines
162 auto doInvMass = [this, &w] ()
163 {
164 this->applyInverseMass( this->iterators_, w );
165 };
166
167 if( ! singleThreadModeError )
168 {
169 try {
170 // execute in parallel
171 MPIManager :: run ( doInvMass );
172 }
173 catch ( const SingleThreadModeError& e )
174 {
175 singleThreadModeError = true;
176 }
177 }
178
179 // if error occurred, redo the whole evaluation
180 if( singleThreadModeError )
181 {
182 // reset w from previous entries
183 w.clear();
184 // re-run in single thread mode if previous attempt failed
185 std::tuple< const LocalGalerkinOperatorImplType& > integrands( localOperator() );
186 op().evaluate( u, w, iterators_, integrands );
187
188 // update number of interior elements as sum over threads
189 gridSizeInterior_ = Impl::accumulateGridSize( opImpl_ );
190
191 applyInverseMass( iterators_, w );
192 }
193
194 // synchronize data
195 if( communicate_ )
196 w.communicate();
197 }
198
199 // GalerkinOperator implementation (see galerkin.hh)
200 mutable ThreadIteratorType iterators_;
203
204 mutable std::size_t gridSizeInterior_;
205 bool communicate_;
206 };
207
208
209
210 // DifferentiableGalerkinOperator
211 // ------------------------------
212
213 template< class Integrands, class JacobianOperator >
214 class MOLDifferentiableGalerkinOperator
215 : public MOLGalerkinOperator< Integrands, typename JacobianOperator::DomainFunctionType, typename JacobianOperator::RangeFunctionType >,
216 public DifferentiableOperator< JacobianOperator >
217 {
218 typedef MOLGalerkinOperator< Integrands, typename JacobianOperator::DomainFunctionType, typename JacobianOperator::RangeFunctionType > BaseType;
219
220 public:
221 typedef JacobianOperator JacobianOperatorType;
222
223 typedef typename BaseType::DomainFunctionType DomainFunctionType;
224 typedef typename BaseType::RangeFunctionType RangeFunctionType;
225 typedef typename DomainFunctionType::DiscreteFunctionSpaceType DomainDiscreteFunctionSpaceType;
226 typedef typename RangeFunctionType::DiscreteFunctionSpaceType RangeDiscreteFunctionSpaceType;
227
228 typedef typename BaseType::LocalGalerkinOperatorImplType LocalGalerkinOperatorImplType;
229
230 typedef DiagonalAndNeighborStencil< DomainDiscreteFunctionSpaceType, RangeDiscreteFunctionSpaceType > DiagonalAndNeighborStencilType;
231 typedef DiagonalStencil< DomainDiscreteFunctionSpaceType, RangeDiscreteFunctionSpaceType > DiagonalStencilType;
232
233 typedef typename BaseType::GridPartType GridPartType;
234
235 template< class... Args >
236 explicit MOLDifferentiableGalerkinOperator ( const DomainDiscreteFunctionSpaceType &dSpace,
237 const RangeDiscreteFunctionSpaceType &rSpace,
238 Args &&... args )
239 : BaseType( rSpace.gridPart(), std::forward< Args >( args )... ),
240 dSpace_(dSpace),
241 rSpace_(rSpace),
242 domainSpaceSequence_(dSpace.sequence()),
243 rangeSpaceSequence_(rSpace.sequence()),
244 stencilDAN_(), stencilD_()
245 {
246 if( hasSkeleton() )
247 stencilDAN_.reset( new DiagonalAndNeighborStencilType( dSpace_, rSpace_ ) );
248 else
249 stencilD_.reset( new DiagonalStencilType( dSpace_, rSpace_ ) );
250 }
251
252 virtual void jacobian ( const DomainFunctionType &u, JacobianOperatorType &jOp ) const final override
253 {
254 // assemble Jacobian, same as GalerkinOperator
255 assemble( u, jOp );
256 }
257
258 template< class GridFunction >
259 void jacobian ( const GridFunction &u, JacobianOperatorType &jOp ) const
260 {
261 assemble( u, jOp );
262 }
263
264 const DomainDiscreteFunctionSpaceType& domainSpace() const
265 {
266 return dSpace_;
267 }
268 const RangeDiscreteFunctionSpaceType& rangeSpace() const
269 {
270 return rSpace_;
271 }
272 // needed for DGHelmholtz operator
273 const RangeDiscreteFunctionSpaceType& space() const
274 {
275 return rangeSpace();
276 }
277
278 using BaseType::gridPart;
279 using BaseType::localOperator;
280
281 protected:
282 using BaseType::op;
283 using BaseType::iterators_;
284 using BaseType::gridSizeInterior_;
285
287 bool hasSkeleton() const
288 {
289 std::tuple< const LocalGalerkinOperatorImplType& > integrands( localOperator() );
290 return op().hasSkeleton( integrands );
291 }
292
293 void prepare( JacobianOperatorType& jOp ) const
294 {
295 if ( domainSpaceSequence_ != domainSpace().sequence()
296 || rangeSpaceSequence_ != rangeSpace().sequence() )
297 {
298 domainSpaceSequence_ = domainSpace().sequence();
299 rangeSpaceSequence_ = rangeSpace().sequence();
300 if( hasSkeleton() )
301 {
302 assert( stencilDAN_ );
303 stencilDAN_->update();
304 }
305 else
306 {
307 assert( stencilD_ );
308 stencilD_->update();
309 }
310 }
311
312 if( hasSkeleton() )
313 jOp.reserve( *stencilDAN_ );
314 else
315 jOp.reserve( *stencilD_ );
316 // set all entries to zero
317 jOp.clear();
318 }
319
320 template < class GridFunction >
321 void assemble( const GridFunction &u, JacobianOperatorType &jOp ) const
322 {
323 prepare( jOp );
324 iterators_.update();
325
326 bool singleThreadModeError = false;
327 std::shared_mutex mutex;
328
329 auto doAssemble = [this, &u, &jOp, &mutex] ()
330 {
331 std::tuple< const LocalGalerkinOperatorImplType& > integrands( localOperator() );
332 // assemble Jacobian, same as GalerkinOperator
333 this->op().assemble( u, jOp, this->iterators_, integrands, mutex );
334 };
335
336 try {
337 // execute in parallel
338 MPIManager :: run ( doAssemble );
339
340 // update number of interior elements as sum over threads
341 gridSizeInterior_ = Impl::accumulateGridSize( this->opImpl_ );
342 }
343 catch ( const SingleThreadModeError& e )
344 {
345 singleThreadModeError = true;
346 }
347
348 if (!singleThreadModeError)
349 {
350 GetSetLocalMatrix< JacobianOperatorType > getSet( jOp );
351
352 // method of lines
353 auto doInvMass = [this, &getSet] ()
354 {
355 applyInverseMass( this->iterators_, getSet, this->hasSkeleton() );
356 };
357
358 try {
359 // execute in parallel
360 MPIManager :: run ( doInvMass );
361 }
362 catch ( const SingleThreadModeError& e )
363 {
364 singleThreadModeError = true;
365 }
366 }
367
368 if (singleThreadModeError)
369 {
370 // redo matrix assembly since it failed
371 jOp.clear();
372 std::tuple< const LocalGalerkinOperatorImplType& > integrands( localOperator() );
373 op().assemble( u, jOp, iterators_, integrands );
374
375 // update number of interior elements as sum over threads
376 gridSizeInterior_ = Impl::accumulateGridSize( this->opImpl_ );
377
378 GetSetLocalMatrixImpl getSet( jOp );
379
380 // apply inverse mass
381 applyInverseMass( iterators_, getSet, hasSkeleton() );
382 }
383
384 // note: assembly done without local contributions so need
385 // to call flush assembly
386 jOp.flushAssembly();
387 }
388
389
390 struct GetSetLocalMatrixImpl
391 {
392 JacobianOperatorType& jOp_;
393 GetSetLocalMatrixImpl( JacobianOperatorType& jOp ) : jOp_( jOp ) {}
394
395 template <class Entity, class LocalMatrix>
396 void getLocalMatrix( const Entity& domainEntity, const Entity& rangeEntity,
397 LocalMatrix& lop ) const
398 {
399 jOp_.getLocalMatrix( domainEntity, rangeEntity, lop );
400 }
401
402 template <class Entity, class LocalMatrix>
403 void setLocalMatrix( const Entity& domainEntity, const Entity& rangeEntity,
404 const LocalMatrix& lop )
405 {
406 jOp_.setLocalMatrix( domainEntity, rangeEntity, lop );
407 }
408 };
409
410 struct GetSetLocalMatrixImplLocked : public GetSetLocalMatrixImpl
411 {
412 typedef GetSetLocalMatrixImpl BaseType;
413 typedef std::shared_mutex mutex_t;
414 mutable mutex_t mutex_;
415
416 GetSetLocalMatrixImplLocked( JacobianOperatorType &jOp ) : BaseType( jOp ) {}
417
418 template <class Entity, class LocalMatrix>
419 void getLocalMatrix( const Entity& domainEntity, const Entity& rangeEntity,
420 LocalMatrix& lop ) const
421 {
422 std::lock_guard< mutex_t > lock( mutex_ );
423 BaseType::getLocalMatrix( domainEntity, rangeEntity, lop );
424 }
425
426 template <class Entity, class LocalMatrix>
427 void setLocalMatrix( const Entity& domainEntity, const Entity& rangeEntity,
428 const LocalMatrix& lop )
429 {
430 std::lock_guard< mutex_t > lock( mutex_ );
431 BaseType::setLocalMatrix( domainEntity, rangeEntity, lop );
432 }
433 };
434
435 template <class JacOp>
436 struct GetSetLocalMatrix : public GetSetLocalMatrixImpl
437 {
438 typedef GetSetLocalMatrixImpl BaseType;
439 GetSetLocalMatrix( JacobianOperatorType &jOp ) : BaseType( jOp ) {}
440 };
441
442#if HAVE_PETSC
443 //- PetscLinearOperator does not work with threaded applyInverseMass
444 //- because the mix of getLocalMatrix and setLocalMatrix seems to be
445 //- problematic. Therefore we used the locked version.
446 template <class DomainFunction, class RangeFunction>
447 struct GetSetLocalMatrix< PetscLinearOperator< DomainFunction, RangeFunction > > : public GetSetLocalMatrixImplLocked
448 {
449 typedef GetSetLocalMatrixImplLocked BaseType;
450 GetSetLocalMatrix( JacobianOperatorType &jOp ) : BaseType( jOp ) {}
451 };
452#endif
453
454 template <class Iterators, class GetSetLocalMatrixOp >
455 void applyInverseMass ( const Iterators& iterators, GetSetLocalMatrixOp& getSet,
456 const bool hasSkeleton ) const
457 {
458 typedef typename BaseType::LocalMassMatrixType LocalMassMatrixType;
459 JacobianOperatorType& jOp = getSet.jOp_;
460
461 LocalMassMatrixType localMassMatrix( jOp.rangeSpace(), localOperator().interiorQuadratureOrder( jOp.rangeSpace().order() ) );
462
463 TemporaryLocalMatrix< DomainDiscreteFunctionSpaceType, RangeDiscreteFunctionSpaceType >
464 lop(jOp.domainSpace(), jOp.rangeSpace());
465
466 // multiply with inverse mass matrix
467 for( const auto& inside : iterators )
468 {
469 // scale diagonal
470 {
471 auto guard = bindGuard( lop, inside,inside );
472 lop.bind(inside,inside);
473 getSet.getLocalMatrix( inside, inside, lop );
474 localMassMatrix.leftMultiplyInverse( lop );
475 getSet.setLocalMatrix( inside, inside, lop );
476 }
477
478 if( hasSkeleton )
479 {
480 for( const auto &intersection : intersections( gridPart(), inside ) )
481 {
482 // scale off-diagonal
483 if( intersection.neighbor() )
484 {
485 const auto& outside = intersection.outside();
486 auto guard = bindGuard( lop, outside,inside );
487 getSet.getLocalMatrix( outside, inside, lop );
488 localMassMatrix.leftMultiplyInverse( lop );
489 getSet.setLocalMatrix( outside, inside, lop );
490 }
491 }
492 }
493 }
494 }
495
496 const DomainDiscreteFunctionSpaceType &dSpace_;
497 const RangeDiscreteFunctionSpaceType &rSpace_;
498 mutable int domainSpaceSequence_, rangeSpaceSequence_;
499
500 mutable std::unique_ptr< DiagonalAndNeighborStencilType > stencilDAN_;
501 mutable std::unique_ptr< DiagonalStencilType > stencilD_;
502 };
503
504
505
506 // AutomaticDifferenceGalerkinOperator
507 // -----------------------------------
508
509 template< class Integrands, class DomainFunction, class RangeFunction >
510 class MOLAutomaticDifferenceGalerkinOperator
511 : public MOLGalerkinOperator< Integrands, DomainFunction, RangeFunction >,
512 public AutomaticDifferenceOperator< DomainFunction, RangeFunction >
513 {
514 typedef MOLGalerkinOperator< Integrands, DomainFunction, RangeFunction > BaseType;
515 typedef AutomaticDifferenceOperator< DomainFunction, RangeFunction > AutomaticDifferenceOperatorType;
516
517 public:
518 typedef typename BaseType::GridPartType GridPartType;
519
520 template< class... Args >
521 explicit MOLAutomaticDifferenceGalerkinOperator ( const GridPartType &gridPart, Args &&... args )
522 : BaseType( gridPart, std::forward< Args >( args )... ), AutomaticDifferenceOperatorType()
523 {}
524 };
525
526
527
528 // ModelDifferentiableGalerkinOperator
529 // -----------------------------------
530
531 template < class LinearOperator, class ModelIntegrands >
532 struct MOLModelDifferentiableGalerkinOperator
533 : public MOLDifferentiableGalerkinOperator< ModelIntegrands, LinearOperator >
534 {
535 typedef MOLDifferentiableGalerkinOperator< ModelIntegrands, LinearOperator > BaseType;
536
537 typedef typename ModelIntegrands::ModelType ModelType;
538
539 typedef typename LinearOperator::DomainFunctionType RangeFunctionType;
540 typedef typename LinearOperator::RangeSpaceType DiscreteFunctionSpaceType;
541
542 MOLModelDifferentiableGalerkinOperator ( ModelType &model, const DiscreteFunctionSpaceType &dfSpace )
543 : BaseType( dfSpace.gridPart(), model )
544 {}
545
546 template< class GridFunction >
547 void apply ( const GridFunction &u, RangeFunctionType &w ) const
548 {
549 (*this)( u, w );
550 }
551
552 template< class GridFunction >
553 void apply ( const GridFunction &u, LinearOperator &jOp ) const
554 {
555 (*this).jacobian( u, jOp );
556 }
557 };
558
559
560 // MethodOfLinesScheme
561 // -------------------
562
563 template< class Integrands, class LinearOperator, class InverseOperator, bool addDirichletBC>
564 using MethodOfLinesScheme = Impl::GalerkinSchemeImpl< Integrands, LinearOperator, InverseOperator, addDirichletBC,
565 MOLDifferentiableGalerkinOperator >;
566
567 } // namespace Fem
568
569} // namespace Dune
570
571#endif // #ifndef DUNE_FEM_SCHEMES_MOLGALERKIN_HH
static bool verbose()
obtain the cached value for fem.verbose with default verbosity level 2
Definition: parameter.hh:466
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
STL namespace.
DomainFunction DomainFunctionType
type of discrete function in the operator's domain
Definition: operator.hh:36
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden  |  generated with Hugo v0.111.3 (Jul 27, 22:29, 2024)