1#ifndef DUNE_FEM_SCHEMES_GALERKIN_HH
2#define DUNE_FEM_SCHEMES_GALERKIN_HH
13#include <dune/common/hybridutilities.hh>
16#include <dune/grid/common/rangegenerators.hh>
18#include <dune/fem/function/localfunction/temporary.hh>
19#include <dune/fem/io/parameter/reader.hh>
20#include <dune/fem/operator/common/automaticdifferenceoperator.hh>
21#include <dune/fem/operator/common/differentiableoperator.hh>
22#include <dune/fem/operator/common/operator.hh>
23#include <dune/fem/operator/common/stencil.hh>
24#include <dune/fem/operator/common/temporarylocalmatrix.hh>
25#include <dune/fem/quadrature/cachingquadrature.hh>
26#include <dune/fem/quadrature/intersectionquadrature.hh>
27#include <dune/fem/common/bindguard.hh>
29#include <dune/fem/misc/threads/threaditerator.hh>
30#include <dune/fem/misc/threads/threadsafevalue.hh>
32#include <dune/fem/operator/common/localmatrixcolumn.hh>
33#include <dune/fem/operator/common/localcontribution.hh>
34#include <dune/fem/operator/1order/localmassmatrix.hh>
35#include <dune/fem/schemes/integrands.hh>
36#include <dune/fem/schemes/dirichletwrapper.hh>
37#include <dune/fem/schemes/femscheme.hh>
39#include <dune/fem/space/common/capabilities.hh>
42#include <dune/fempy/quadrature/fempyquadratures.hh>
57 static int callOrder(
const F& f,
char)
60 std::cerr <<
"WARNING: no order method available on " <<
typeid(F).name() <<
", defaulting to 1!" << std::endl;
66 static auto callOrder(
const F& f,
int) ->
decltype( f.order() )
73 static int order (
const F& f ) {
return callOrder(f, 0); }
79 template <
class Space>
80 struct DefaultGalerkinOperatorQuadratureSelector
82 typedef typename Space :: GridPartType GridPartType;
83 typedef CachingQuadrature< GridPartType, 0, Capabilities::DefaultQuadrature< Space > :: template DefaultQuadratureTraits > InteriorQuadratureType;
84 typedef CachingQuadrature< GridPartType, 1, Capabilities::DefaultQuadrature< Space > :: template DefaultQuadratureTraits > SurfaceQuadratureType;
92 template<
class Integrands,
template <
class>
class QuadSelector = DefaultGalerkinOperatorQuadratureSelector >
93 struct LocalGalerkinOperator
95 typedef LocalGalerkinOperator<Integrands> ThisType;
96 typedef std::conditional_t< Fem::IntegrandsTraits< Integrands >::isFull, Integrands, FullIntegrands< Integrands > > IntegrandsType;
98 typedef typename IntegrandsType::GridPartType GridPartType;
100 typedef typename GridPartType::ctype ctype;
101 typedef typename GridPartType::template Codim< 0 >::EntityType EntityType;
104 template <
class Space>
105 using QuadratureSelector = QuadSelector< Space >;
108 template<
class... Args >
109 explicit LocalGalerkinOperator (
const GridPartType &gridPart, Args &&... args )
110 : gridPart_( gridPart ),
111 integrands_(
std::forward< Args >( args )... ),
112 defaultInteriorOrder_( [] (const int order) {
return 2 * order; } ),
113 defaultSurfaceOrder_ ( [] (
const int order) {
return 2 * order + 1; } ),
114 interiorQuadOrder_(0), surfaceQuadOrder_(0)
119 typedef typename IntegrandsType::DomainValueType DomainValueType;
120 typedef typename IntegrandsType::RangeValueType RangeValueType;
121 typedef std::make_index_sequence< std::tuple_size< DomainValueType >::value > DomainValueIndices;
122 typedef std::make_index_sequence< std::tuple_size< RangeValueType >::value > RangeValueIndices;
125 template< std::size_t... i >
126 static auto makeDomainValueVector ( std::size_t maxNumLocalDofs, std::index_sequence< i... > )
128 return std::make_tuple( std::vector< std::tuple_element_t< i, DomainValueType > >( maxNumLocalDofs )... );
131 static auto makeDomainValueVector ( std::size_t maxNumLocalDofs )
133 return makeDomainValueVector( maxNumLocalDofs, DomainValueIndices() );
136 template< std::size_t... i >
137 static auto makeRangeValueVector ( std::size_t maxNumLocalDofs, std::index_sequence< i... > )
139 return std::make_tuple( std::vector< std::tuple_element_t< i, RangeValueType > >( maxNumLocalDofs )... );
142 static auto makeRangeValueVector ( std::size_t maxNumLocalDofs )
144 return makeRangeValueVector( maxNumLocalDofs, RangeValueIndices() );
147 typedef decltype( makeDomainValueVector( 0u ) ) DomainValueVectorType;
148 typedef decltype( makeRangeValueVector( 0u ) ) RangeValueVectorType;
150 static void resizeDomainValueVector ( DomainValueVectorType& vec,
const std::size_t
size )
153 std::get< i >( vec ).resize(
size );
157 static void resizeRangeValueVector ( RangeValueVectorType& vec,
const std::size_t
size )
160 std::get< i >( vec ).resize(
size );
165 void prepare(
const std::size_t
size )
const
167 resizeDomainValueVector( phiIn_,
size );
168 resizeDomainValueVector( phiOut_,
size );
169 resizeDomainValueVector( basisValues_,
size );
170 resizeDomainValueVector( domainValues_,
size );
173 template<
class LocalFunction,
class Quadrature >
174 static void evaluateQuadrature (
const LocalFunction &u,
const Quadrature &quad, std::vector< typename LocalFunction::RangeType > &phi )
176 u.evaluateQuadrature( quad, phi );
179 template<
class LocalFunction,
class Quadrature>
180 static void evaluateQuadrature (
const LocalFunction &u,
const Quadrature &quad, std::vector< typename LocalFunction::JacobianRangeType > &phi )
182 u.jacobianQuadrature( quad, phi );
185 template<
class LocalFunction,
class Quadrature >
186 static void evaluateQuadrature (
const LocalFunction &u,
const Quadrature &quad, std::vector< typename LocalFunction::HessianRangeType > &phi )
188 u.hessianQuadrature( quad, phi );
192 template<
class LocalFunction,
class Po
int >
195 u.evaluate( x, phi );
198 template<
class LocalFunction,
class Po
int >
201 u.jacobian( x, phi );
204 template<
class LocalFunction,
class Po
int >
210 template<
class LocalFunction,
class Point,
class... T >
211 static void value (
const LocalFunction &u,
const Point &x, std::tuple< T... > &phi )
213 Hybrid::forEach( std::index_sequence_for< T... >(), [ &u, &x, &phi ] (
auto i ) { LocalGalerkinOperator::value( u, x, std::get< i >( phi ) ); } );
216 template<
class Basis,
class Po
int >
217 static void values (
const Basis &basis,
const Point &x, std::vector< typename Basis::RangeType > &phi )
219 basis.evaluateAll( x, phi );
222 template<
class Basis,
class Po
int >
223 static void values (
const Basis &basis,
const Point &x, std::vector< typename Basis::JacobianRangeType > &phi )
225 basis.jacobianAll( x, phi );
228 template<
class Basis,
class Po
int >
229 static void values (
const Basis &basis,
const Point &x, std::vector< typename Basis::HessianRangeType > &phi )
231 basis.hessianAll( x, phi );
234 template<
class Basis,
class Point,
class... T >
235 static void values (
const Basis &basis,
const Point &x, std::tuple< std::vector< T >... > &phi )
237 Hybrid::forEach( std::index_sequence_for< T... >(), [ &basis, &x, &phi ] (
auto i ) { LocalGalerkinOperator::values( basis, x, std::get< i >( phi ) ); } );
240 template<
class LocalFunction,
class Po
int >
241 static DomainValueType domainValue (
const LocalFunction &u,
const Point &x )
248 static DomainValueType domainValue (
const unsigned int qpIdx, DomainValueVectorType& vec)
251 Hybrid::forEach( DomainValueIndices(), [ &qpIdx, &vec, &phi ] (
auto i ) {
252 std::get< i > ( phi ) = std::get< i >( vec )[ qpIdx ];
257 template<
class LocalFunction,
class Quadrature >
258 static void domainValue (
const LocalFunction &u,
const Quadrature& quadrature, DomainValueVectorType &result )
260 Hybrid::forEach( DomainValueIndices(), [ &u, &quadrature, &result ] (
auto i ) {
261 auto& vec = std::get< i >( result );
262 vec.resize( quadrature.nop() );
263 ThisType::evaluateQuadrature( u, quadrature, vec );
267 template<
class Phi, std::size_t... i >
268 static auto value (
const Phi &phi, std::size_t col, std::index_sequence< i... > )
270 return std::make_tuple( std::get< i >( phi )[ col ]... );
273 template<
class... T >
274 static auto value (
const std::tuple< std::vector< T >... > &phi, std::size_t col )
276 return value( phi, col, std::index_sequence_for< T... >() );
279 static void assignRange( RangeValueVectorType& ranges,
const std::size_t idx,
const RangeValueType& range )
281 Hybrid::forEach( RangeValueIndices(), [ &ranges, &idx, &range ] (
auto i ) {
282 std::get< i >( ranges )[ idx ] = std::get< i >( range );
286 static void assignRange( RangeValueVectorType& ranges,
const std::size_t idx,
const RangeValueType& range,
const W &weight )
288 Hybrid::forEach( RangeValueIndices(), [ &ranges, &idx, &range, &weight ] (
auto i ) {
289 std::get< i >( ranges )[ idx ] = std::get< i >( range );
290 std::get< i >( ranges )[ idx ] *= weight;
294 static void assignDomain( DomainValueVectorType& domains,
const std::size_t idx,
const DomainValueType& domain )
296 Hybrid::forEach( DomainValueIndices(), [ &domains, &idx, &domain ] (
auto i ) {
297 std::get< i >( domains )[ idx ] = std::get< i >( domain );
301 template <
class W,
class Quadrature>
302 static void axpyQuadrature( W& w,
const Quadrature& quadrature, RangeValueVectorType& ranges )
304 Hybrid::forEach( RangeValueIndices(), [ &w, &quadrature, &ranges ] (
auto i ) {
305 w.axpyQuadrature( quadrature, std::get< i >( ranges ) );
312 template<
class U,
class W >
313 void addInteriorIntegral (
const U &u, W &w )
const
315 if( !integrands().init( u.entity() ) )
318 const auto geometry = u.entity().geometry();
320 typedef typename QuadratureSelector< typename W::DiscreteFunctionSpaceType > :: InteriorQuadratureType InteriorQuadratureType;
321 const InteriorQuadratureType quadrature( u.entity(), interiorQuadratureOrder(maxOrder(u, w)) );
324 DomainValueVectorType& domains = domainValues_;
325 domainValue( u, quadrature, domains );
327 auto& ranges = values_;
328 resizeRangeValueVector( ranges, quadrature.nop() );
331 for(
const auto qp : quadrature )
333 const ctype weight = qp.weight() * geometry.integrationElement( qp.position() );
334 assignRange( ranges, qp.index(), integrands().
interior( qp, domainValue( qp.index(), domains ) ), weight );
338 axpyQuadrature( w, quadrature, ranges );
339 integrands().unbind();
342 template<
class U,
class J >
343 void addLinearizedInteriorIntegral (
const U &u, J &j )
const
345 if( !integrands().init( u.entity() ) )
348 const auto geometry = u.entity().geometry();
349 const auto &domainBasis = j.domainBasisFunctionSet();
350 const auto &rangeBasis = j.rangeBasisFunctionSet();
352 typedef typename QuadratureSelector< typename J::RangeSpaceType > :: InteriorQuadratureType InteriorQuadratureType;
353 const InteriorQuadratureType quadrature( u.entity(), interiorQuadratureOrder( maxOrder( u, domainBasis, rangeBasis )) );
354 const size_t domainSize = domainBasis.size();
355 const size_t quadNop = quadrature.nop();
357 auto& basisValues = basisValues_;
358 resizeDomainValueVector( basisValues, domainSize );
361 auto& rangeValues = rangeValues_;
362 DomainValueVectorType& domains = domainValues_;
363 domainValue( u, quadrature, domains );
365 rangeValues.resize( domainSize );
366 for( std::size_t col = 0; col < domainSize; ++col )
368 resizeRangeValueVector( rangeValues[ col ], quadNop );
372 for(
const auto qp : quadrature )
374 values( domainBasis, qp, basisValues );
375 const auto weight = qp.weight() * geometry.integrationElement( qp.position() );
376 auto integrand = integrands().linearizedInterior( qp, domainValue( qp.index(), domains ) );
377 for( std::size_t col = 0; col < domainSize; ++col )
379 assignRange( rangeValues[ col ], qp.index(), integrand( value( basisValues, col ) ), weight );
384 for( std::size_t col = 0; col < domainSize; ++col )
386 LocalMatrixColumn< J > jCol( j, col );
387 axpyQuadrature( jCol, quadrature, rangeValues[ col ] );
389 integrands().unbind();
394 template<
class Intersection,
class U,
class W >
395 void addBoundaryIntegral (
const Intersection &intersection,
const U &u, W &w )
const
397 if( !integrands().init( intersection ) )
400 const auto geometry = intersection.geometry();
401 typedef typename QuadratureSelector< typename W::DiscreteFunctionSpaceType > :: SurfaceQuadratureType SurfaceQuadratureType;
402 const SurfaceQuadratureType quadrature( gridPart(), intersection, surfaceQuadratureOrder(maxOrder( u, w )), SurfaceQuadratureType::INSIDE );
403 for(
const auto qp : quadrature )
405 const ctype weight = qp.weight() * geometry.integrationElement( qp.localPosition() );
407 RangeValueType integrand = integrands().boundary( qp, domainValue( u, qp ) );
409 Hybrid::forEach( RangeValueIndices(), [ &qp, &w, &integrand, weight ] (
auto i ) {
410 std::get< i >( integrand ) *= weight;
411 w.axpy( qp, std::get< i >( integrand ) );
414 integrands().unbind();
417 template<
class Intersection,
class U,
class J >
418 void addLinearizedBoundaryIntegral (
const Intersection &intersection,
const U &u, J &j )
const
420 if( !integrands().init( intersection ) )
423 DomainValueVectorType &phi = phiIn_;
425 const auto geometry = intersection.geometry();
426 const auto &domainBasis = j.domainBasisFunctionSet();
427 const auto &rangeBasis = j.rangeBasisFunctionSet();
429 typedef typename QuadratureSelector< typename J::RangeSpaceType > :: SurfaceQuadratureType SurfaceQuadratureType;
430 const SurfaceQuadratureType quadrature( gridPart(), intersection, surfaceQuadratureOrder(maxOrder(u, domainBasis, rangeBasis )), SurfaceQuadratureType::INSIDE );
431 for(
const auto qp : quadrature )
433 const ctype weight = qp.weight() * geometry.integrationElement( qp.localPosition() );
435 values( domainBasis, qp, phi );
436 auto integrand = integrands().linearizedBoundary( qp, domainValue( u, qp ) );
438 for( std::size_t col = 0, cols = domainBasis.size(); col < cols; ++col )
440 LocalMatrixColumn< J > jCol( j, col );
441 RangeValueType intPhi = integrand( value( phi, col ) );
443 Hybrid::forEach( RangeValueIndices(), [ &qp, &jCol, &intPhi, weight ] (
auto i ) {
444 std::get< i >( intPhi ) *= weight;
445 jCol.axpy( qp, std::get< i >( intPhi ) );
449 integrands().unbind();
455 template<
bool conforming,
class Intersection,
class U,
class W >
456 void addSkeletonIntegral (
const Intersection &intersection,
const U &uIn,
const U &uOut, W &wIn )
const
458 const auto geometry = intersection.geometry();
460 typedef typename QuadratureSelector< typename W::DiscreteFunctionSpaceType > :: SurfaceQuadratureType SurfaceQuadratureType;
461 typedef IntersectionQuadrature< SurfaceQuadratureType, conforming > IntersectionQuadratureType;
462 const IntersectionQuadratureType quadrature( gridPart(), intersection, surfaceQuadratureOrder(maxOrder( uIn, uOut, wIn)),
false );
463 for( std::size_t qp = 0, nop = quadrature.nop(); qp != nop; ++qp )
465 const ctype weight = quadrature.weight( qp ) * geometry.integrationElement( quadrature.localPoint( qp ) );
467 const auto qpIn = quadrature.inside()[ qp ];
468 const auto qpOut = quadrature.outside()[ qp ];
469 std::pair< RangeValueType, RangeValueType > integrand = integrands().skeleton( qpIn, domainValue( uIn, qpIn ), qpOut, domainValue( uOut, qpOut ) );
471 Hybrid::forEach( RangeValueIndices(), [ &qpIn, &wIn, &integrand, weight ] (
auto i ) {
472 std::get< i >( integrand.first ) *= weight;
473 wIn.axpy( qpIn, std::get< i >( integrand.first ) );
478 template<
bool conforming,
class Intersection,
class U,
class W >
479 void addSkeletonIntegral (
const Intersection &intersection,
const U &uIn,
const U &uOut, W &wIn, W &wOut )
const
481 const auto geometry = intersection.geometry();
482 typedef typename QuadratureSelector< typename W::DiscreteFunctionSpaceType > :: SurfaceQuadratureType SurfaceQuadratureType;
483 typedef IntersectionQuadrature< SurfaceQuadratureType, conforming > IntersectionQuadratureType;
484 const IntersectionQuadratureType quadrature( gridPart(), intersection, surfaceQuadratureOrder(maxOrder( uIn, uOut, wIn, wOut)),
false );
485 for( std::size_t qp = 0, nop = quadrature.nop(); qp != nop; ++qp )
487 const ctype weight = quadrature.weight( qp ) * geometry.integrationElement( quadrature.localPoint( qp ) );
489 const auto qpIn = quadrature.inside()[ qp ];
490 const auto qpOut = quadrature.outside()[ qp ];
491 std::pair< RangeValueType, RangeValueType > integrand = integrands().skeleton( qpIn, domainValue( uIn, qpIn ), qpOut, domainValue( uOut, qpOut ) );
493 Hybrid::forEach( RangeValueIndices(), [ &qpIn, &wIn, &qpOut, &wOut, &integrand, weight ] (
auto i ) {
494 std::get< i >( integrand.first ) *= weight;
495 wIn.axpy( qpIn, std::get< i >( integrand.first ) );
497 std::get< i >( integrand.second ) *= weight;
498 wOut.axpy( qpOut, std::get< i >( integrand.second ) );
503 template<
bool conforming,
class Intersection,
class U,
class J >
504 void addLinearizedSkeletonIntegral (
const Intersection &intersection,
505 const U &uIn,
const U &uOut, J &jInIn, J &jOutIn )
const
507 DomainValueVectorType &phiIn = phiIn_;
508 DomainValueVectorType &phiOut = phiOut_;
510 const auto &domainBasisIn = jInIn.domainBasisFunctionSet();
511 const auto &domainBasisOut = jOutIn.domainBasisFunctionSet();
513 const auto &rangeBasisIn = jInIn.rangeBasisFunctionSet();
515 const int order = std::max( maxOrder(uIn, uOut), maxOrder( domainBasisIn, domainBasisOut, rangeBasisIn ));
517 const auto geometry = intersection.geometry();
518 typedef typename QuadratureSelector< typename J::RangeSpaceType > :: SurfaceQuadratureType SurfaceQuadratureType;
519 typedef IntersectionQuadrature< SurfaceQuadratureType, conforming > IntersectionQuadratureType;
520 const IntersectionQuadratureType quadrature( gridPart(), intersection, surfaceQuadratureOrder(order),
false );
521 for( std::size_t qp = 0, nop = quadrature.nop(); qp != nop; ++qp )
523 const ctype weight = quadrature.weight( qp ) * geometry.integrationElement( quadrature.localPoint( qp ) );
525 const auto qpIn = quadrature.inside()[ qp ];
526 const auto qpOut = quadrature.outside()[ qp ];
528 values( domainBasisIn, qpIn, phiIn );
529 values( domainBasisOut, qpOut, phiOut );
531 auto integrand = integrands().linearizedSkeleton( qpIn, domainValue( uIn, qpIn ), qpOut, domainValue( uOut, qpOut ) );
532 for( std::size_t col = 0, cols = domainBasisIn.size(); col < cols; ++col )
534 LocalMatrixColumn< J > jInInCol( jInIn, col );
535 std::pair< RangeValueType, RangeValueType > intPhi = integrand.first( value( phiIn, col ) );
537 Hybrid::forEach( RangeValueIndices(), [ &qpIn, &jInInCol, &intPhi, weight ] (
auto i ) {
538 std::get< i >( intPhi.first ) *= weight;
539 jInInCol.axpy( qpIn, std::get< i >( intPhi.first ) );
542 for( std::size_t col = 0, cols = domainBasisOut.size(); col < cols; ++col )
544 LocalMatrixColumn< J > jOutInCol( jOutIn, col );
545 std::pair< RangeValueType, RangeValueType > intPhi = integrand.second( value( phiOut, col ) );
547 Hybrid::forEach( RangeValueIndices(), [ &qpIn, &jOutInCol, &intPhi, weight ] (
auto i ) {
548 std::get< i >( intPhi.first ) *= weight;
549 jOutInCol.axpy( qpIn, std::get< i >( intPhi.first ) );
555 template<
bool conforming,
class Intersection,
class U,
class J >
556 void addLinearizedSkeletonIntegral (
const Intersection &intersection,
const U &uIn,
const U &uOut,
557 J &jInIn, J &jOutIn, J &jInOut, J &jOutOut )
const
559 DomainValueVectorType &phiIn = phiIn_;
560 DomainValueVectorType &phiOut = phiOut_;
562 const auto &domainBasisIn = jInIn.domainBasisFunctionSet();
563 const auto &domainBasisOut = jOutIn.domainBasisFunctionSet();
565 const auto &rangeBasisIn = jInIn.rangeBasisFunctionSet();
566 const auto &rangeBasisOut = jInOut.rangeBasisFunctionSet();
568 const int order = std::max( maxOrder(uIn, uOut), maxOrder( domainBasisIn, domainBasisOut, rangeBasisIn, rangeBasisOut ));
570 const auto geometry = intersection.geometry();
571 typedef typename QuadratureSelector< typename J::RangeSpaceType > :: SurfaceQuadratureType SurfaceQuadratureType;
572 typedef IntersectionQuadrature< SurfaceQuadratureType, conforming > IntersectionQuadratureType;
573 const IntersectionQuadratureType quadrature( gridPart(), intersection, surfaceQuadratureOrder(order),
false );
574 for( std::size_t qp = 0, nop = quadrature.nop(); qp != nop; ++qp )
576 const ctype weight = quadrature.weight( qp ) * geometry.integrationElement( quadrature.localPoint( qp ) );
578 const auto qpIn = quadrature.inside()[ qp ];
579 const auto qpOut = quadrature.outside()[ qp ];
581 values( domainBasisIn, qpIn, phiIn );
582 values( domainBasisOut, qpOut, phiOut );
584 auto integrand = integrands().linearizedSkeleton( qpIn, domainValue( uIn, qpIn ), qpOut, domainValue( uOut, qpOut ) );
585 for( std::size_t col = 0, cols = domainBasisIn.size(); col < cols; ++col )
587 LocalMatrixColumn< J > jInInCol( jInIn, col );
588 LocalMatrixColumn< J > jInOutCol( jInOut, col );
589 std::pair< RangeValueType, RangeValueType > intPhi = integrand.first( value( phiIn, col ) );
591 Hybrid::forEach( RangeValueIndices(), [ &qpIn, &jInInCol, &qpOut, &jInOutCol, &intPhi, weight ] (
auto i ) {
592 std::get< i >( intPhi.first ) *= weight;
593 jInInCol.axpy( qpIn, std::get< i >( intPhi.first ) );
595 std::get< i >( intPhi.second ) *= weight;
596 jInOutCol.axpy( qpOut, std::get< i >( intPhi.second ) );
599 for( std::size_t col = 0, cols = domainBasisOut.size(); col < cols; ++col )
601 LocalMatrixColumn< J > jOutInCol( jOutIn, col );
602 LocalMatrixColumn< J > jOutOutCol( jOutOut, col );
603 std::pair< RangeValueType, RangeValueType > intPhi = integrand.second( value( phiOut, col ) );
605 Hybrid::forEach( RangeValueIndices(), [ &qpIn, &jOutInCol, &qpOut, &jOutOutCol, &intPhi, weight ] (
auto i ) {
606 std::get< i >( intPhi.first ) *= weight;
607 jOutInCol.axpy( qpIn, std::get< i >( intPhi.first ) );
609 std::get< i >( intPhi.second ) *= weight;
610 jOutOutCol.axpy( qpOut, std::get< i >( intPhi.second ) );
617 template<
class Intersection,
class U,
class... W >
618 void addSkeletonIntegral (
const Intersection &intersection,
const U &uIn,
const U &uOut, W &... w )
const
620 if( !integrands().init( intersection ) )
623 if( intersection.conforming() )
624 addSkeletonIntegral< true >( intersection, uIn, uOut, w... );
626 addSkeletonIntegral< false >( intersection, uIn, uOut, w... );
627 integrands().unbind();
630 template<
class Intersection,
class U,
class... J >
631 void addLinearizedSkeletonIntegral (
const Intersection &intersection,
const U &uIn,
const U &uOut, J &... j )
const
633 if( !integrands().init( intersection ) )
636 if( intersection.conforming() )
637 addLinearizedSkeletonIntegral< true >( intersection, uIn, uOut, j... );
639 addLinearizedSkeletonIntegral< false >( intersection, uIn, uOut, j... );
640 integrands().unbind();
643 void setQuadratureOrders(
unsigned int interior,
unsigned int surface)
646 surfaceQuadOrder_ = surface;
649 IntegrandsType& model()
const
653 bool nonlinear()
const {
return model().nonlinear(); }
654 bool hasInterior()
const {
return model().hasInterior(); }
655 bool hasSkeleton()
const {
return model().hasSkeleton(); }
656 bool hasBoundary()
const {
return model().hasBoundary(); }
659 IntegrandsType& integrands()
const
666 const GridPartType &gridPart ()
const {
return gridPart_; }
668 unsigned int interiorQuadratureOrder(
unsigned int order)
const {
return interiorQuadOrder_ == 0 ? defaultInteriorOrder_(order) : interiorQuadOrder_; }
669 unsigned int surfaceQuadratureOrder(
unsigned int order)
const {
return surfaceQuadOrder_ == 0 ? defaultSurfaceOrder_ (order) : surfaceQuadOrder_; }
673 int maxOrder(
const U& u )
const
675 return CallOrder< U > :: order( u );
678 template<
class U,
class W >
679 int maxOrder(
const U& u,
const W& w )
const
681 return std::max( maxOrder( u ), maxOrder( w ) );
684 template<
class U,
class V,
class W >
685 int maxOrder(
const U& u,
const V& v,
const W& w )
const
687 return std::max( maxOrder( u, v ), maxOrder( w ) );
690 template<
class U,
class V,
class W,
class X >
691 int maxOrder(
const U& u,
const V& v,
const W& w,
const X& x )
const
693 return std::max( maxOrder( u, v ), maxOrder( w, x) );
697 const GridPartType &gridPart_;
699 mutable IntegrandsType integrands_;
701 mutable std::function<int(
const int)> defaultInteriorOrder_;
702 mutable std::function<int(
const int)> defaultSurfaceOrder_;
704 unsigned int interiorQuadOrder_;
705 unsigned int surfaceQuadOrder_;
707 mutable std::vector< RangeValueVectorType > rangeValues_;
708 mutable RangeValueVectorType values_;
709 mutable DomainValueVectorType phiIn_;
710 mutable DomainValueVectorType phiOut_;
711 mutable DomainValueVectorType basisValues_;
712 mutable DomainValueVectorType domainValues_;
720 template<
class Gr
idPart >
722 struct GalerkinOperator
724 typedef GridPart GridPartType;
725 typedef GalerkinOperator< GridPartType > ThisType;
727 typedef typename GridPartType::ctype ctype;
728 typedef typename GridPartType::template Codim< 0 >::EntityType EntityType;
731 explicit GalerkinOperator (
const GridPartType &gridPart )
732 : gridPart_( gridPart ),
733 gridSizeInterior_( 0 )
738 template <
class IntegrandsTuple>
739 bool hasBoundary(
const IntegrandsTuple& integrandsTuple )
const
741 typedef std::make_index_sequence< std::tuple_size< IntegrandsTuple >::value > Indices;
742 bool hasBoundary = false ;
743 Hybrid::forEach( Indices(), [&integrandsTuple, &hasBoundary](
auto i ) {
744 if( std::get< i > (integrandsTuple).hasBoundary() )
753 template<
class Gr
idFunction,
class DiscreteFunction,
class Iterators,
class IntegrandsTuple,
class Functor,
bool hasSkeleton >
754 void evaluateImpl (
const GridFunction &u, DiscreteFunction &w,
const Iterators& iterators,
755 const IntegrandsTuple& integrandsTuple, Functor& addLocalDofs, std::integral_constant<bool, hasSkeleton> )
const
757 Dune::Fem::ConstLocalFunction< GridFunction > uInside( u );
758 Dune::Fem::ConstLocalFunction< GridFunction > uOutside( u );
760 typedef typename DiscreteFunction::DiscreteFunctionSpaceType DiscreteFunctionSpaceType;
764 gridSizeInterior_ = 0;
766 typedef std::make_index_sequence< std::tuple_size< IntegrandsTuple >::value > Indices;
769 const bool hasBnd = hasBoundary( integrandsTuple );
771 const auto &indexSet = gridPart().indexSet();
772 const auto end = iterators.end();
773 for(
auto it = iterators.begin(); it != end; ++it )
776 const EntityType inside = *it ;
781 auto uGuard = bindGuard( uInside, inside );
782 auto wGuard = bindGuard( wInside, inside );
785 auto addInteriorIntegral = [&integrandsTuple, &uInside, &wInside](
auto i )
787 const auto& integrands = std::get< i >( integrandsTuple );
788 if( integrands.hasInterior() )
789 integrands.addInteriorIntegral( uInside, wInside );
794 if( hasSkeleton || (hasBnd && inside.hasBoundaryIntersections() ) )
796 for(
const auto &intersection : intersections( gridPart(), inside ) )
798 bool neighbor =
false;
799 if constexpr ( hasSkeleton )
803 if( intersection.neighbor() )
806 const EntityType outside = intersection.outside();
810 auto uOutGuard = bindGuard( uOutside, outside );
812 auto addSkeletonIntegral = [&integrandsTuple, &intersection, &uInside, &uOutside, &wInside] (
auto i )
814 const auto& integrands = std::get< i >( integrandsTuple );
815 if( integrands.hasSkeleton() )
816 integrands.addSkeletonIntegral( intersection, uInside, uOutside, wInside );
821 else if( indexSet.index( inside ) < indexSet.index( outside ) )
823 auto uOutGuard = bindGuard( uOutside, outside );
824 auto wOutGuard = bindGuard( wOutside, outside );
827 auto addSkeletonIntegral = [&integrandsTuple, &intersection, &uInside, &uOutside, &wInside, &wOutside] (
auto i )
829 const auto& integrands = std::get< i >( integrandsTuple );
830 if( integrands.hasSkeleton() )
831 integrands.addSkeletonIntegral( intersection, uInside, uOutside, wInside, wOutside );
838 addLocalDofs( outside, wOutside );
843 if( ! neighbor && intersection.boundary() )
845 auto addBoundaryIntegral = [&integrandsTuple, &intersection, &uInside, &wInside](
auto i )
847 const auto& integrands = std::get< i >( integrandsTuple );
848 if( integrands.hasBoundary() )
849 integrands.addBoundaryIntegral( intersection, uInside, wInside );
857 addLocalDofs( inside, wInside );
861 template <
class Space>
864 typedef typename Space::EntityType EntityType;
865 template <
class Iterators>
866 InsideEntity(
const Space &space,
const Iterators& iterators)
867 : space_(space), dofThread_(space.
size(),-1)
868 , thread_(MPIManager::thread())
870 const auto& mapper = space_.blockMapper();
871 for (
const auto &entity : space_)
873 int t=iterators.threadParallel(entity);
874 mapper.mapEach(entity, [
this, t ] (
int local,
auto global )
875 { dofThread_[global] = (dofThread_[global]==t || dofThread_[global]==-1)?
879 bool operator()(
const EntityType &entity)
const
881 bool needsLocking =
false;
882 space_.blockMapper().mapEach(entity,
883 [
this, &needsLocking ] (
int local,
auto global )
884 { needsLocking = (needsLocking || dofThread_[global]!=thread_); });
885 return !needsLocking;
888 std::vector<int> dofThread_;
892 template <
class DiscreteFunction>
893 struct AddLocalEvaluate
895 AddLocalEvaluate(DiscreteFunction &w)
897 template <
class LocalDofs>
898 void operator () (
const EntityType& entity,
const LocalDofs& wLocal )
const
900 w_.addLocalDofs( entity, wLocal.localDofVector() );
902 DiscreteFunction &w_;
905 template <
class DiscreteFunction>
906 struct AddLocalEvaluateLocked :
public AddLocalEvaluate<DiscreteFunction>
908 typedef AddLocalEvaluate<DiscreteFunction> BaseType;
910 std::shared_mutex& mutex_;
911 InsideEntity<typename DiscreteFunction::DiscreteFunctionSpaceType> inside_;
913 template <
class Iterators>
914 AddLocalEvaluateLocked(DiscreteFunction &w, std::shared_mutex& mtx,
const Iterators &iterators)
915 : BaseType(w), mutex_(mtx), inside_(w.space(),iterators) {}
917 template <
class LocalDofs>
918 void operator () (
const EntityType& entity,
const LocalDofs& wLocal )
const
923 std::shared_lock<std::shared_mutex> guard ( mutex_ );
924 BaseType::operator()( entity, wLocal );
929 std::lock_guard<std::shared_mutex> guard ( mutex_ );
930 BaseType::operator()( entity, wLocal );
935 template<
class Gr
idFunction,
class DiscreteFunction,
class Iterators,
class IntegrandsTuple,
class Functor >
936 void evaluate (
const GridFunction &u, DiscreteFunction &w,
const Iterators& iterators,
937 const IntegrandsTuple& integrandsTuple, Functor& addLocalDofs )
const
939 static_assert( std::is_same< typename GridFunction::GridPartType, GridPartType >::value,
"Argument 'u' and Integrands must be defined on the same grid part." );
940 static_assert( std::is_same< typename DiscreteFunction::GridPartType, GridPartType >::value,
"Argument 'w' and Integrands must be defined on the same grid part." );
942 if( hasSkeleton( integrandsTuple ) )
943 evaluateImpl( u, w, iterators, integrandsTuple, addLocalDofs, std::true_type() );
945 evaluateImpl( u, w, iterators, integrandsTuple, addLocalDofs, std::false_type() );
949 template <
class IntegrandsTuple>
950 bool hasSkeleton(
const IntegrandsTuple& integrandsTuple )
const
952 typedef std::make_index_sequence< std::tuple_size< IntegrandsTuple >::value > Indices;
953 bool hasSkeleton = false ;
954 Hybrid::forEach( Indices(), [&integrandsTuple, &hasSkeleton] (
auto i ) {
955 if( std::get< i >( integrandsTuple ).hasSkeleton() )
964 template<
class Gr
idFunction,
class DiscreteFunction,
class Iterators,
class IntegrandsTuple >
965 void evaluate (
const GridFunction &u, DiscreteFunction &w,
const Iterators& iterators,
966 const IntegrandsTuple& integrandsTuple, std::shared_mutex& mtx )
const
968 AddLocalEvaluateLocked<DiscreteFunction> addLocalEvaluate(w,mtx,iterators);
969 evaluate( u, w, iterators, integrandsTuple, addLocalEvaluate );
972 template<
class Gr
idFunction,
class DiscreteFunction,
class Iterators,
class IntegrandsTuple >
973 void evaluate (
const GridFunction &u, DiscreteFunction &w,
const Iterators& iterators,
const IntegrandsTuple& integrandsTuple )
const
975 AddLocalEvaluate<DiscreteFunction> addLocalEvaluate(w);
976 evaluate( u, w, iterators, integrandsTuple, addLocalEvaluate );
980 template<
class T,
int length>
985 FiniteStack () : _f(0) {}
988 bool empty ()
const {
return _f <= 0; }
991 bool full ()
const {
return (_f >= length); }
994 void clear() { _f = 0; }
997 void push (
const T& t)
999 assert ( _f < length );
1016 int size ()
const {
return _f; }
1024 template <
class JacobianOperator>
1025 struct AddLocalAssemble
1027 typedef typename JacobianOperator::DomainSpaceType DomainSpaceType;
1028 typedef typename JacobianOperator::RangeSpaceType RangeSpaceType;
1029 typedef TemporaryLocalMatrix< DomainSpaceType, RangeSpaceType > TemporaryLocalMatrixType;
1030 JacobianOperator &jOp_;
1031 std::vector< TemporaryLocalMatrixType > jOpLocal_;
1033 FiniteStack< TemporaryLocalMatrixType*, 12 > jOpLocalFinalized_;
1034 FiniteStack< TemporaryLocalMatrixType*, 12 > jOpLocalFree_;
1036 std::size_t locked, notLocked, timesLocked;
1037 AddLocalAssemble(JacobianOperator& jOp)
1039 , jOpLocal_(12, TemporaryLocalMatrixType(jOp_.domainSpace(), jOp_.rangeSpace()))
1040 , jOpLocalFinalized_()
1042 , locked(0), notLocked(0), timesLocked(0)
1044 for(
auto& jOpLocal : jOpLocal_ )
1045 jOpLocalFree_.push( &jOpLocal );
1048 TemporaryLocalMatrixType& bind(
const EntityType& dE,
const EntityType& rE)
1050 assert( ! jOpLocalFree_.empty() );
1051 TemporaryLocalMatrixType& lop = *(jOpLocalFree_.pop());
1057 void unbind(TemporaryLocalMatrixType &lop)
1060 jOp_.addLocalMatrix( lop.domainEntity(), lop.rangeEntity(), lop );
1062 jOpLocalFree_.push( &lop );
1067 locked += jOpLocalFinalized_.size();
1068 while ( ! jOpLocalFinalized_.empty() )
1070 TemporaryLocalMatrixType &lop = *(jOpLocalFinalized_.pop());
1071 jOp_.addLocalMatrix( lop.domainEntity(), lop.rangeEntity(), lop );
1073 jOpLocalFree_.push( &lop );
1078 template <
class JacobianOperator>
1079 struct AddLocalAssembleLocked :
public AddLocalAssemble<JacobianOperator>
1081 typedef AddLocalAssemble<JacobianOperator> BaseType;
1082 typedef typename BaseType::TemporaryLocalMatrixType TemporaryLocalMatrixType;
1083 using BaseType::jOpLocalFinalized_;
1084 using BaseType::jOpLocalFree_;
1086 std::shared_mutex& mutex_;
1087 InsideEntity<typename JacobianOperator::DomainSpaceType> insideDomain_;
1088 InsideEntity<typename JacobianOperator::RangeSpaceType> insideRange_;
1090 template <
class Iterators>
1091 AddLocalAssembleLocked(JacobianOperator &jOp, std::shared_mutex &mtx,
const Iterators &iterators)
1094 , insideDomain_(jOp.domainSpace(),iterators)
1095 , insideRange_(jOp.rangeSpace(),iterators)
1101 ++BaseType::timesLocked;
1102 std::lock_guard<std::shared_mutex> guard ( mutex_ );
1103 BaseType::finalize();
1106 TemporaryLocalMatrixType& bind(
const EntityType& dE,
const EntityType& rE)
1108 if ( jOpLocalFree_.empty() )
1112 return BaseType::bind(dE,rE);
1115 void unbind(TemporaryLocalMatrixType &lop)
1124 if ( insideDomain_(lop.domainEntity()) &&
1125 insideRange_(lop.rangeEntity()) )
1127 std::shared_lock<std::shared_mutex> guard ( mutex_ );
1128 BaseType::unbind(lop);
1132 jOpLocalFinalized_.push( &lop );
1137 template<
class Gr
idFunction,
class JacobianOperator,
class Iterators,
class IntegrandsTuple,
class Functor,
bool hasSkeleton >
1138 void assembleImpl (
const GridFunction &u, JacobianOperator &jOp,
const Iterators& iterators,
const IntegrandsTuple& integrandsTuple,
1139 Functor& addLocalMatrix, std::integral_constant<bool, hasSkeleton> )
const
1141 typedef typename JacobianOperator::DomainSpaceType DomainSpaceType;
1142 typedef typename JacobianOperator::RangeSpaceType RangeSpaceType;
1144 typedef TemporaryLocalMatrix< DomainSpaceType, RangeSpaceType > TemporaryLocalMatrixType;
1146 Dune::Fem::ConstLocalFunction< GridFunction > uIn( u );
1147 Dune::Fem::ConstLocalFunction< GridFunction > uOut( u );
1149 typedef std::make_index_sequence< std::tuple_size< IntegrandsTuple >::value > Indices;
1150 const std::size_t maxNumLocalDofs = jOp.domainSpace().blockMapper().maxNumDofs() * jOp.domainSpace().localBlockSize;
1153 Hybrid::forEach( Indices(), [&integrandsTuple, &maxNumLocalDofs] (
auto i ) {
1154 const auto& integrands = std::get< i >( integrandsTuple );
1155 integrands.prepare( maxNumLocalDofs );
1159 gridSizeInterior_ = 0;
1162 const bool hasBnd = hasBoundary( integrandsTuple );
1164 const auto &indexSet = gridPart().indexSet();
1166 const auto end = iterators.end();
1167 for(
auto it = iterators.begin(); it != end; ++it )
1170 ++gridSizeInterior_;
1172 const EntityType inside = *it;
1174 auto uiGuard = bindGuard( uIn, inside );
1176 TemporaryLocalMatrixType& jOpInIn = addLocalMatrix.bind( inside, inside );
1177 auto addLinearizedInteriorIntegral = [&integrandsTuple, &uIn, &jOpInIn](
auto i )
1179 const auto& integrands = std::get< i >( integrandsTuple );
1180 if( integrands.hasInterior() )
1181 integrands.addLinearizedInteriorIntegral( uIn, jOpInIn );
1186 if( hasSkeleton || (hasBnd && inside.hasBoundaryIntersections() ) )
1188 for(
const auto &intersection : intersections( gridPart(), inside ) )
1190 bool neighbor = false ;
1193 if constexpr ( hasSkeleton )
1195 if( intersection.neighbor() )
1198 const EntityType &outside = intersection.outside();
1200 TemporaryLocalMatrixType &jOpOutIn = addLocalMatrix.bind( outside, inside );
1202 auto uoGuard = bindGuard( uOut, outside );
1206 auto addLinearizedSkeletonIntegral = [&integrandsTuple, &intersection, &uIn, &uOut, &jOpInIn, &jOpOutIn](
auto i )
1208 const auto& integrands = std::get< i >( integrandsTuple );
1209 if( integrands.hasSkeleton() )
1210 integrands.addLinearizedSkeletonIntegral( intersection, uIn, uOut, jOpInIn, jOpOutIn );
1215 else if( indexSet.index( inside ) < indexSet.index( outside ) )
1217 TemporaryLocalMatrixType &jOpInOut = addLocalMatrix.bind( inside, outside );
1218 TemporaryLocalMatrixType &jOpOutOut = addLocalMatrix.bind( outside, outside );
1220 auto addLinearizedSkeletonIntegral = [&integrandsTuple, &intersection, &uIn, &uOut, &jOpInIn, &jOpOutIn, &jOpInOut, &jOpOutOut](
auto i )
1222 const auto& integrands = std::get< i >( integrandsTuple );
1223 if( integrands.hasSkeleton() )
1224 integrands.addLinearizedSkeletonIntegral( intersection, uIn, uOut, jOpInIn, jOpOutIn, jOpInOut, jOpOutOut );
1229 addLocalMatrix.unbind(jOpInOut);
1230 addLocalMatrix.unbind(jOpOutOut);
1233 addLocalMatrix.unbind(jOpOutIn);
1237 if( !neighbor && intersection.boundary() )
1239 auto addLinearizedBoundaryIntegral = [&integrandsTuple, &intersection, &uIn, &jOpInIn](
auto i )
1241 const auto& integrands = std::get< i >( integrandsTuple );
1242 if( integrands.hasBoundary() )
1243 integrands.addLinearizedBoundaryIntegral( intersection, uIn, jOpInIn );
1251 addLocalMatrix.unbind(jOpInIn);
1255 addLocalMatrix.finalize();
1259 template<
class Gr
idFunction,
class JacobianOperator,
class Iterators,
class IntegrandsTuple,
class Functor >
1260 void assemble (
const GridFunction &u, JacobianOperator &jOp,
const Iterators& iterators,
1261 const IntegrandsTuple& integrandsTuple, Functor& addLocalMatrix,
int )
const
1263 static_assert( std::is_same< typename GridFunction::GridPartType, GridPartType >::value,
"Argument 'u' and Integrands must be defined on the same grid part." );
1264 static_assert( std::is_same< typename JacobianOperator::DomainSpaceType::GridPartType, GridPartType >::value,
"Argument 'jOp' and Integrands must be defined on the same grid part." );
1265 static_assert( std::is_same< typename JacobianOperator::RangeSpaceType::GridPartType, GridPartType >::value,
"Argument 'jOp' and Integrands must be defined on the same grid part." );
1267 if( hasSkeleton( integrandsTuple ) )
1268 assembleImpl( u, jOp, iterators, integrandsTuple ,addLocalMatrix, std::true_type() );
1270 assembleImpl( u, jOp, iterators, integrandsTuple, addLocalMatrix, std::false_type() );
1274 template<
class Gr
idFunction,
class JacobianOperator,
class Iterators,
class IntegrandsTuple>
1275 void assemble (
const GridFunction &u, JacobianOperator &jOp,
const Iterators& iterators,
1276 const IntegrandsTuple& integrandsTuple, std::shared_mutex& mtx)
const
1278 AddLocalAssembleLocked<JacobianOperator> addLocalAssemble( jOp, mtx, iterators);
1279 assemble( u, jOp, iterators, integrandsTuple, addLocalAssemble, 10 );
1281 std::lock_guard guard ( mtx );
1282 std::cout << MPIManager::thread() <<
" : "
1283 << addLocalAssemble.locked <<
" " << addLocalAssemble.notLocked <<
" "
1284 << addLocalAssemble.timesLocked << std::endl;
1288 template<
class Gr
idFunction,
class JacobianOperator,
class Iterators,
class IntegrandsTuple>
1289 void assemble (
const GridFunction &u, JacobianOperator &jOp,
const Iterators& iterators,
const IntegrandsTuple& integrandsTuple )
const
1291 AddLocalAssemble<JacobianOperator> addLocalAssemble(jOp);
1292 assemble( u, jOp, iterators, integrandsTuple, addLocalAssemble, 10 );
1296 const GridPartType &gridPart ()
const {
return gridPart_; }
1298 std::size_t gridSizeInterior ()
const {
return gridSizeInterior_; }
1301 const GridPartType &gridPart_;
1302 mutable std::size_t gridSizeInterior_;
1306 template <
class GalerkinOperator >
1307 static std::size_t accumulateGridSize(
const ThreadSafeValue< GalerkinOperator >& ops )
1309 std::size_t s = ops.size();
1310 std::size_t sum = 0;
1311 for( std::size_t i=0; i<s; ++i )
1312 sum += ops[ i ].gridSizeInterior();
1325 template<
class Integrands,
class DomainFunction,
class RangeFunction = DomainFunction >
1326 struct GalerkinOperator
1327 :
public virtual Operator< DomainFunction, RangeFunction >
1329 typedef DomainFunction DomainFunctionType;
1330 typedef RangeFunction RangeFunctionType;
1332 typedef typename RangeFunctionType::GridPartType GridPartType;
1334 typedef Impl::LocalGalerkinOperator< Integrands > LocalGalerkinOperatorImplType;
1335 typedef Impl::GalerkinOperator< GridPartType > GalerkinOperatorImplType;
1337 static_assert( std::is_same< typename DomainFunctionType::GridPartType, typename RangeFunctionType::GridPartType >::value,
"DomainFunction and RangeFunction must be defined on the same grid part." );
1341 template<
class... Args >
1342 explicit GalerkinOperator (
const GridPartType &gridPart, Args &&... args )
1343 : iterators_( gridPart ),
1344 opImpl_( gridPart ),
1345 localOp_( gridPart,
std::forward< Args >( args )... ),
1346 gridSizeInterior_( 0 ),
1347 communicate_( true )
1351 void setCommunicate(
const bool communicate )
1353 communicate_ = communicate;
1356 std::cout <<
"GalerkinOperator::setCommunicate: communicate was disabled!" << std::endl;
1360 void setQuadratureOrders(
unsigned int interior,
unsigned int surface)
1362 size_t size = localOp_.size();
1363 for(
size_t i=0; i<
size; ++i )
1364 localOp_[ i ].setQuadratureOrders(interior,surface);
1367 virtual bool nonlinear() const final
override
1369 return localOperator().nonlinear();
1372 virtual void operator() (
const DomainFunctionType &u, RangeFunctionType &w )
const final override
1377 template<
class Gr
idFunction >
1378 void operator() (
const GridFunction &u, RangeFunctionType &w )
const
1383 const GridPartType &gridPart ()
const {
return op().gridPart(); }
1385 typedef Integrands ModelType;
1386 typedef Integrands DirichletModelType;
1387 ModelType &model()
const {
return localOperator().model(); }
1389 [[deprecated(
"Use localOperator instead!")]]
1390 const LocalGalerkinOperatorImplType& impl()
const {
return localOperator(); }
1393 const LocalGalerkinOperatorImplType& localOperator()
const {
return *localOp_; }
1395 std::size_t gridSizeInterior ()
const {
return gridSizeInterior_; }
1399 const GalerkinOperatorImplType& op()
const {
return *opImpl_; }
1401 template <
class Gr
idFunction >
1402 void evaluate(
const GridFunction &u, RangeFunctionType &w )
const
1404 iterators_.update();
1407 std::shared_mutex mutex;
1409 auto doEval = [
this, &u, &w, &mutex] ()
1412 std::tuple< const LocalGalerkinOperatorImplType& > integrands( localOperator() );
1413 this->op().evaluate( u, w, this->iterators_, integrands, mutex );
1418 MPIManager :: run ( doEval );
1421 gridSizeInterior_ = Impl::accumulateGridSize( opImpl_ );
1423 catch (
const SingleThreadModeError& e )
1428 std::tuple< const LocalGalerkinOperatorImplType& > integrands( localOperator() );
1429 op().evaluate( u, w, iterators_, integrands );
1432 gridSizeInterior_ = op().gridSizeInterior();
1440 mutable ThreadIteratorType iterators_;
1444 mutable std::size_t gridSizeInterior_;
1453 template<
class Integrands,
class JacobianOperator >
1454 class DifferentiableGalerkinOperator
1455 :
public GalerkinOperator< Integrands, typename JacobianOperator::DomainFunctionType, typename JacobianOperator::RangeFunctionType >,
1456 public DifferentiableOperator< JacobianOperator >
1458 typedef GalerkinOperator< Integrands, typename JacobianOperator::DomainFunctionType, typename JacobianOperator::RangeFunctionType > BaseType;
1460 typedef typename BaseType :: LocalGalerkinOperatorImplType LocalGalerkinOperatorImplType;
1462 typedef JacobianOperator JacobianOperatorType;
1464 typedef typename BaseType::DomainFunctionType DomainFunctionType;
1465 typedef typename BaseType::RangeFunctionType RangeFunctionType;
1466 typedef typename DomainFunctionType::DiscreteFunctionSpaceType DomainDiscreteFunctionSpaceType;
1467 typedef typename RangeFunctionType::DiscreteFunctionSpaceType RangeDiscreteFunctionSpaceType;
1469 typedef DiagonalAndNeighborStencil< DomainDiscreteFunctionSpaceType, RangeDiscreteFunctionSpaceType > DiagonalAndNeighborStencilType;
1470 typedef DiagonalStencil< DomainDiscreteFunctionSpaceType, RangeDiscreteFunctionSpaceType > DiagonalStencilType;
1472 typedef typename BaseType::GridPartType GridPartType;
1474 template<
class... Args >
1475 explicit DifferentiableGalerkinOperator (
const DomainDiscreteFunctionSpaceType &dSpace,
1476 const RangeDiscreteFunctionSpaceType &rSpace,
1478 : BaseType( rSpace.gridPart(),
std::forward< Args >( args )... ),
1479 dSpace_(dSpace), rSpace_(rSpace),
1480 domainSpaceSequence_(dSpace.sequence()),
1481 rangeSpaceSequence_(rSpace.sequence()),
1482 stencilDAN_(), stencilD_()
1485 stencilDAN_.reset(
new DiagonalAndNeighborStencilType( dSpace_, rSpace_ ) );
1487 stencilD_.reset(
new DiagonalStencilType( dSpace_, rSpace_ ) );
1490 virtual void jacobian (
const DomainFunctionType &u, JacobianOperatorType &jOp )
const final override
1495 template<
class Gr
idFunction >
1496 void jacobian (
const GridFunction &u, JacobianOperatorType &jOp )
const
1501 const DomainDiscreteFunctionSpaceType& domainSpace()
const
1505 const RangeDiscreteFunctionSpaceType& rangeSpace()
const
1510 using BaseType::localOperator;
1511 using BaseType::nonlinear;
1516 bool hasSkeleton()
const
1518 std::tuple< const LocalGalerkinOperatorImplType& > integrands( localOperator() );
1519 return op().hasSkeleton( integrands );
1522 void prepare( JacobianOperatorType& jOp )
const
1524 if ( domainSpaceSequence_ != domainSpace().sequence()
1525 || rangeSpaceSequence_ != rangeSpace().sequence() )
1527 domainSpaceSequence_ = domainSpace().sequence();
1528 rangeSpaceSequence_ = rangeSpace().sequence();
1531 assert( stencilDAN_ );
1532 stencilDAN_->update();
1536 assert( stencilD_ );
1537 stencilD_->update();
1541 jOp.reserve( *stencilDAN_ );
1543 jOp.reserve( *stencilD_ );
1548 template <
class Gr
idFunction >
1549 void assemble(
const GridFunction &u, JacobianOperatorType &jOp )
const
1554 iterators_.update();
1557 std::shared_mutex mutex;
1559 auto doAssemble = [
this, &u, &jOp, &mutex] ()
1561 std::tuple< const LocalGalerkinOperatorImplType& > integrands( localOperator() );
1562 this->op().assemble( u, jOp, this->iterators_, integrands, mutex );
1567 MPIManager :: run ( doAssemble );
1570 gridSizeInterior_ = Impl::accumulateGridSize( this->opImpl_ );
1572 catch (
const SingleThreadModeError& e )
1576 std::tuple< const LocalGalerkinOperatorImplType& > integrands( localOperator() );
1577 op().assemble( u, jOp, iterators_, integrands );
1579 gridSizeInterior_ = op().gridSizeInterior();
1584 jOp.flushAssembly();
1587 using BaseType::iterators_;
1588 using BaseType::gridSizeInterior_;
1590 const DomainDiscreteFunctionSpaceType &dSpace_;
1591 const RangeDiscreteFunctionSpaceType &rSpace_;
1593 mutable int domainSpaceSequence_, rangeSpaceSequence_;
1595 mutable std::unique_ptr< DiagonalAndNeighborStencilType > stencilDAN_;
1596 mutable std::unique_ptr< DiagonalStencilType > stencilD_;
1604 template<
class Integrands,
class DomainFunction,
class RangeFunction >
1605 class AutomaticDifferenceGalerkinOperator
1606 :
public GalerkinOperator< Integrands, DomainFunction, RangeFunction >,
1607 public AutomaticDifferenceOperator< DomainFunction, RangeFunction >
1609 typedef GalerkinOperator< Integrands, DomainFunction, RangeFunction > BaseType;
1613 typedef typename BaseType::GridPartType GridPartType;
1615 template<
class... Args >
1616 explicit AutomaticDifferenceGalerkinOperator (
const GridPartType &gridPart, Args &&... args )
1617 : BaseType( gridPart,
std::forward< Args >( args )... ), AutomaticDifferenceOperatorType()
1626 template <
class LinearOperator,
class ModelIntegrands >
1627 struct ModelDifferentiableGalerkinOperator
1628 :
public DifferentiableGalerkinOperator< ModelIntegrands, LinearOperator >
1630 typedef DifferentiableGalerkinOperator< ModelIntegrands, LinearOperator > BaseType;
1632 typedef typename ModelIntegrands::ModelType ModelType;
1635 typedef typename LinearOperator::RangeSpaceType DiscreteFunctionSpaceType;
1637 ModelDifferentiableGalerkinOperator ( ModelType &model,
const DiscreteFunctionSpaceType &dfSpace )
1638 : BaseType( dfSpace.gridPart(), model )
1641 template<
class Gr
idFunction >
1642 void apply (
const GridFunction &u, RangeFunctionType &w )
const
1647 template<
class Gr
idFunction >
1648 void apply (
const GridFunction &u, LinearOperator &jOp )
const
1650 (*this).jacobian( u, jOp );
1659 template<
class Integrands,
class LinearOperator,
bool addDirichletBC,
1660 template <
class,
class>
class DifferentiableGalerkinOperatorImpl >
1661 struct GalerkinSchemeTraits
1663 template <
class O,
bool addDBC>
1664 struct DirichletBlockSelector {
using type = void; };
1666 struct DirichletBlockSelector<O,true> {
using type =
typename O::DirichletBlockVector; };
1668 using DifferentiableOperatorType = std::conditional_t< addDirichletBC,
1669 DirichletWrapperOperator< DifferentiableGalerkinOperatorImpl< Integrands, LinearOperator >>,
1670 DifferentiableGalerkinOperatorImpl< Integrands, LinearOperator > >;
1671 using DirichletBlockVector =
typename DirichletBlockSelector<
1672 DirichletWrapperOperator<
1673 DifferentiableGalerkinOperatorImpl< Integrands, LinearOperator >>,
1674 addDirichletBC>::type;
1676 typedef DifferentiableOperatorType type;
1679 template<
class Integrands,
class LinearOperator,
class LinearInverseOperator,
bool addDirichletBC,
1680 template <
class,
class>
class DifferentiableGalerkinOperatorImpl = DifferentiableGalerkinOperator >
1681 struct GalerkinSchemeImpl :
public FemScheme< typename
1682 GalerkinSchemeTraits< Integrands, LinearOperator,
1683 addDirichletBC, DifferentiableGalerkinOperatorImpl>::type,
1684 LinearInverseOperator >
1686 typedef FemScheme<
typename GalerkinSchemeTraits< Integrands, LinearOperator,
1687 addDirichletBC, DifferentiableGalerkinOperatorImpl>::type,
1688 LinearInverseOperator >
1691 typedef typename BaseType :: DiscreteFunctionSpaceType DiscreteFunctionSpaceType;
1693 GalerkinSchemeImpl (
const DiscreteFunctionSpaceType &dfSpace,
1694 const Integrands &integrands,
1695 const ParameterReader& parameter = Parameter::container() )
1698 std::move(integrands))
1707 template<
class Integrands,
class LinearOperator,
class InverseOperator,
bool addDirichletBC >
1708 using GalerkinScheme = Impl::GalerkinSchemeImpl< Integrands, LinearOperator, InverseOperator, addDirichletBC,
1709 DifferentiableGalerkinOperator >;
FunctionSpaceType::RangeType RangeType
type of range vectors, i.e., type of function values
Definition: localfunction.hh:107
FunctionSpaceType::HessianRangeType HessianRangeType
type of the Hessian
Definition: localfunction.hh:111
FunctionSpaceType::JacobianRangeType JacobianRangeType
type of the Jacobian, i.e., type of evaluated Jacobian matrix
Definition: localfunction.hh:109
static bool verbose()
obtain the cached value for fem.verbose with default verbosity level 2
Definition: parameter.hh:466
constexpr void forEach(Range &&range, F &&f)
Range based for loop.
Definition: hybridutilities.hh:256
constexpr Interior interior
PartitionSet for the interior partition.
Definition: partitionset.hh:271
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
constexpr std::bool_constant<(sizeof...(II)==0)> empty(std::integer_sequence< T, II... >)
Checks whether the sequence is empty.
Definition: integersequence.hh:80
DomainFunction DomainFunctionType
type of discrete function in the operator's domain
Definition: operator.hh:36