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>
31#include <dune/fem/misc/hasboundaryintersection.hh>
32#include <dune/fem/misc/griddeclaration.hh>
34#include <dune/fem/operator/common/localmatrixcolumn.hh>
35#include <dune/fem/operator/common/localcontribution.hh>
36#include <dune/fem/operator/1order/localmassmatrix.hh>
37#include <dune/fem/schemes/integrands.hh>
38#include <dune/fem/schemes/dirichletwrapper.hh>
39#include <dune/fem/schemes/femscheme.hh>
41#include <dune/fem/space/common/capabilities.hh>
44#include <dune/fempy/quadrature/fempyquadratures.hh>
59 static int callOrder(
const F& f,
char)
62 std::cerr <<
"WARNING: no order method available on " <<
typeid(F).name() <<
", defaulting to 1!" << std::endl;
68 static auto callOrder(
const F& f,
int) ->
decltype( f.order() )
75 static int order (
const F& f ) {
return callOrder(f, 0); }
81 template <
class Space>
82 struct DefaultGalerkinOperatorQuadratureSelector
84 typedef typename Space :: GridPartType GridPartType;
85 typedef typename GridPartType :: GridType GridType;
88 struct AnotherQuadSelector
90 typedef CachingQuadrature< GridPartType, 0, Capabilities::DefaultQuadrature< Space > :: template DefaultQuadratureTraits > InteriorQuadratureType;
91 typedef CachingQuadrature< GridPartType, 1, Capabilities::DefaultQuadrature< Space > :: template DefaultQuadratureTraits > SurfaceQuadratureType;
95#if HAVE_DUNE_POLYGONGRID
97 struct AnotherQuadSelector<
Dune::PolygonGrid< ct > >
104 typedef typename AnotherQuadSelector< GridType >::InteriorQuadratureType InteriorQuadratureType;
105 typedef typename AnotherQuadSelector< GridType >::SurfaceQuadratureType SurfaceQuadratureType;
111 template<
class Integrands,
template <
class>
class QuadSelector = DefaultGalerkinOperatorQuadratureSelector >
112 struct LocalGalerkinOperator
114 typedef LocalGalerkinOperator<Integrands> ThisType;
115 typedef std::conditional_t< Fem::IntegrandsTraits< Integrands >::isFull, Integrands, FullIntegrands< Integrands > > IntegrandsType;
117 typedef typename IntegrandsType::GridPartType GridPartType;
119 typedef typename GridPartType::ctype ctype;
120 typedef typename GridPartType::template Codim< 0 >::EntityType EntityType;
123 template <
class Space>
124 using QuadratureSelector = QuadSelector< Space >;
127 template<
class... Args >
128 explicit LocalGalerkinOperator (
const GridPartType &gridPart, Args &&... args )
129 : gridPart_( gridPart ),
130 integrands_(
std::forward< Args >( args )... ),
131 defaultInteriorOrder_( [] (const int order) {
return 2 * order; } ),
132 defaultSurfaceOrder_ ( [] (
const int order) {
return 2 * order + 1; } ),
133 interiorQuadOrder_(0), surfaceQuadOrder_(0)
138 typedef typename IntegrandsType::DomainValueType DomainValueType;
139 typedef typename IntegrandsType::RangeValueType RangeValueType;
140 typedef std::make_index_sequence< std::tuple_size< DomainValueType >::value > DomainValueIndices;
141 typedef std::make_index_sequence< std::tuple_size< RangeValueType >::value > RangeValueIndices;
144 template< std::size_t... i >
145 static auto makeDomainValueVector ( std::size_t maxNumLocalDofs, std::index_sequence< i... > )
147 return std::make_tuple( std::vector< std::tuple_element_t< i, DomainValueType > >( maxNumLocalDofs )... );
150 static auto makeDomainValueVector ( std::size_t maxNumLocalDofs )
152 return makeDomainValueVector( maxNumLocalDofs, DomainValueIndices() );
155 template< std::size_t... i >
156 static auto makeRangeValueVector ( std::size_t maxNumLocalDofs, std::index_sequence< i... > )
158 return std::make_tuple( std::vector< std::tuple_element_t< i, RangeValueType > >( maxNumLocalDofs )... );
161 static auto makeRangeValueVector ( std::size_t maxNumLocalDofs )
163 return makeRangeValueVector( maxNumLocalDofs, RangeValueIndices() );
166 typedef decltype( makeDomainValueVector( 0u ) ) DomainValueVectorType;
167 typedef decltype( makeRangeValueVector( 0u ) ) RangeValueVectorType;
169 static void resizeDomainValueVector ( DomainValueVectorType& vec,
const std::size_t
size )
172 std::get< i >( vec ).resize(
size );
176 static void resizeRangeValueVector ( RangeValueVectorType& vec,
const std::size_t
size )
179 std::get< i >( vec ).resize(
size );
184 void prepare(
const std::size_t
size )
const
186 resizeDomainValueVector( phiIn_,
size );
187 resizeDomainValueVector( phiOut_,
size );
188 resizeDomainValueVector( basisValues_,
size );
189 resizeDomainValueVector( domainValues_,
size );
190 resizeDomainValueVector( domainValuesOut_,
size );
193 template<
class LocalFunction,
class Quadrature >
194 static void evaluateQuadrature (
const LocalFunction &u,
const Quadrature &quad, std::vector< typename LocalFunction::RangeType > &phi )
196 u.evaluateQuadrature( quad, phi );
199 template<
class LocalFunction,
class Quadrature>
200 static void evaluateQuadrature (
const LocalFunction &u,
const Quadrature &quad, std::vector< typename LocalFunction::JacobianRangeType > &phi )
202 u.jacobianQuadrature( quad, phi );
205 template<
class LocalFunction,
class Quadrature >
206 static void evaluateQuadrature (
const LocalFunction &u,
const Quadrature &quad, std::vector< typename LocalFunction::HessianRangeType > &phi )
208 u.hessianQuadrature( quad, phi );
212 template<
class LocalFunction,
class Po
int >
215 u.evaluate( x, phi );
218 template<
class LocalFunction,
class Po
int >
221 u.jacobian( x, phi );
224 template<
class LocalFunction,
class Po
int >
230 template<
class LocalFunction,
class Point,
class... T >
231 static void value (
const LocalFunction &u,
const Point &x, std::tuple< T... > &phi )
233 Hybrid::forEach( std::index_sequence_for< T... >(), [ &u, &x, &phi ] (
auto i ) { LocalGalerkinOperator::value( u, x, std::get< i >( phi ) ); } );
236 template<
class Basis,
class Po
int >
237 static void values (
const Basis &basis,
const Point &x, std::vector< typename Basis::RangeType > &phi )
239 basis.evaluateAll( x, phi );
242 template<
class Basis,
class Po
int >
243 static void values (
const Basis &basis,
const Point &x, std::vector< typename Basis::JacobianRangeType > &phi )
245 basis.jacobianAll( x, phi );
248 template<
class Basis,
class Po
int >
249 static void values (
const Basis &basis,
const Point &x, std::vector< typename Basis::HessianRangeType > &phi )
251 basis.hessianAll( x, phi );
254 template<
class Basis,
class Point,
class... T >
255 static void values (
const Basis &basis,
const Point &x, std::tuple< std::vector< T >... > &phi )
257 Hybrid::forEach( std::index_sequence_for< T... >(), [ &basis, &x, &phi ] (
auto i ) { LocalGalerkinOperator::values( basis, x, std::get< i >( phi ) ); } );
260 template<
class LocalFunction,
class Po
int >
261 static DomainValueType domainValue (
const LocalFunction &u,
const Point &x )
268 static DomainValueType domainValue (
const unsigned int qpIdx, DomainValueVectorType& vec)
271 Hybrid::forEach( DomainValueIndices(), [ &qpIdx, &vec, &phi ] (
auto i ) {
272 std::get< i > ( phi ) = std::get< i >( vec )[ qpIdx ];
277 template<
class LocalFunction,
class Quadrature >
278 static void domainValue (
const LocalFunction &u,
const Quadrature& quadrature, DomainValueVectorType &result )
280 Hybrid::forEach( DomainValueIndices(), [ &u, &quadrature, &result ] (
auto i ) {
281 auto& vec = std::get< i >( result );
282 vec.resize( quadrature.nop() );
283 ThisType::evaluateQuadrature( u, quadrature, vec );
287 template<
class Phi, std::size_t... i >
288 static auto value (
const Phi &phi, std::size_t col, std::index_sequence< i... > )
290 return std::make_tuple( std::get< i >( phi )[ col ]... );
293 template<
class... T >
294 static auto value (
const std::tuple< std::vector< T >... > &phi, std::size_t col )
296 return value( phi, col, std::index_sequence_for< T... >() );
299 static void assignRange( RangeValueVectorType& ranges,
const std::size_t idx,
const RangeValueType&
range )
302 std::get< i >( ranges )[ idx ] = std::get< i >(
range );
306 static void assignRange( RangeValueVectorType& ranges,
const std::size_t idx,
const RangeValueType&
range,
const W &weight )
309 std::get< i >( ranges )[ idx ] = std::get< i >(
range );
310 std::get< i >( ranges )[ idx ] *= weight;
314 static void assignDomain( DomainValueVectorType& domains,
const std::size_t idx,
const DomainValueType& domain )
316 Hybrid::forEach( DomainValueIndices(), [ &domains, &idx, &domain ] (
auto i ) {
317 std::get< i >( domains )[ idx ] = std::get< i >( domain );
321 template <
class W,
class Quadrature>
322 static void axpyQuadrature( W& w,
const Quadrature& quadrature, RangeValueVectorType& ranges )
324 Hybrid::forEach( RangeValueIndices(), [ &w, &quadrature, &ranges ] (
auto i ) {
325 w.axpyQuadrature( quadrature, std::get< i >( ranges ) );
332 template<
class U,
class W >
333 void addInteriorIntegral (
const U &u, W &w )
const
335 if( !integrands().init( u.entity() ) )
338 const auto& geometry = u.geometry();
340 typedef typename QuadratureSelector< typename W::DiscreteFunctionSpaceType > :: InteriorQuadratureType InteriorQuadratureType;
341 const InteriorQuadratureType quadrature( u.entity(), interiorQuadratureOrder(maxOrder(u, w)) );
344 DomainValueVectorType& domains = domainValues_;
345 domainValue( u, quadrature, domains );
347 auto& ranges = values_;
348 resizeRangeValueVector( ranges, quadrature.nop() );
351 for(
const auto qp : quadrature )
353 const ctype weight = qp.weight() * geometry.integrationElement( qp.position() );
354 assignRange( ranges, qp.index(), integrands().
interior( qp, domainValue( qp.index(), domains ) ), weight );
358 axpyQuadrature( w, quadrature, ranges );
359 integrands().unbind();
362 template<
class U,
class J >
363 void addLinearizedInteriorIntegral (
const U &u, J &j )
const
365 if( !integrands().init( u.entity() ) )
368 const auto &geometry = u.geometry();
369 const auto &domainBasis = j.domainBasisFunctionSet();
370 const auto &rangeBasis = j.rangeBasisFunctionSet();
372 typedef typename QuadratureSelector< typename J::RangeSpaceType > :: InteriorQuadratureType InteriorQuadratureType;
373 const InteriorQuadratureType quadrature( u.entity(), interiorQuadratureOrder( maxOrder( u, domainBasis, rangeBasis )) );
374 const size_t domainSize = domainBasis.size();
375 const size_t quadNop = quadrature.nop();
377 auto& basisValues = basisValues_;
378 resizeDomainValueVector( basisValues, domainSize );
381 auto& rangeValues = rangeValues_;
382 DomainValueVectorType& domains = domainValues_;
383 domainValue( u, quadrature, domains );
385 rangeValues.resize( domainSize );
386 for( std::size_t col = 0; col < domainSize; ++col )
388 resizeRangeValueVector( rangeValues[ col ], quadNop );
392 for(
const auto qp : quadrature )
394 values( domainBasis, qp, basisValues );
395 const auto weight = qp.weight() * geometry.integrationElement( qp.position() );
396 auto integrand = integrands().linearizedInterior( qp, domainValue( qp.index(), domains ) );
397 for( std::size_t col = 0; col < domainSize; ++col )
399 assignRange( rangeValues[ col ], qp.index(), integrand( value( basisValues, col ) ), weight );
404 for( std::size_t col = 0; col < domainSize; ++col )
406 LocalMatrixColumn< J > jCol( j, col );
407 axpyQuadrature( jCol, quadrature, rangeValues[ col ] );
409 integrands().unbind();
414 template<
class Intersection,
class U,
class W >
415 void addBoundaryIntegral (
const Intersection &intersection,
const U &u, W &w )
const
417 if( !integrands().init( intersection ) )
420 const auto geometry = intersection.geometry();
421 typedef typename QuadratureSelector< typename W::DiscreteFunctionSpaceType > :: SurfaceQuadratureType SurfaceQuadratureType;
422 const SurfaceQuadratureType quadrature( gridPart(), intersection, surfaceQuadratureOrder(maxOrder( u, w )), SurfaceQuadratureType::INSIDE );
423 for(
const auto qp : quadrature )
425 const ctype weight = qp.weight() * geometry.integrationElement( qp.localPosition() );
427 RangeValueType integrand = integrands().boundary( qp, domainValue( u, qp ) );
429 Hybrid::forEach( RangeValueIndices(), [ &qp, &w, &integrand, weight ] (
auto i ) {
430 std::get< i >( integrand ) *= weight;
431 w.axpy( qp, std::get< i >( integrand ) );
434 integrands().unbind();
437 template<
class Intersection,
class U,
class J >
438 void addLinearizedBoundaryIntegral (
const Intersection &intersection,
const U &u, J &j )
const
440 if( !integrands().init( intersection ) )
443 DomainValueVectorType &phi = phiIn_;
445 const auto geometry = intersection.geometry();
446 const auto &domainBasis = j.domainBasisFunctionSet();
447 const auto &rangeBasis = j.rangeBasisFunctionSet();
449 typedef typename QuadratureSelector< typename J::RangeSpaceType > :: SurfaceQuadratureType SurfaceQuadratureType;
450 const SurfaceQuadratureType quadrature( gridPart(), intersection, surfaceQuadratureOrder(maxOrder(u, domainBasis, rangeBasis )), SurfaceQuadratureType::INSIDE );
451 for(
const auto qp : quadrature )
453 const ctype weight = qp.weight() * geometry.integrationElement( qp.localPosition() );
455 values( domainBasis, qp, phi );
456 auto integrand = integrands().linearizedBoundary( qp, domainValue( u, qp ) );
458 for( std::size_t col = 0, cols = domainBasis.size(); col < cols; ++col )
460 LocalMatrixColumn< J > jCol( j, col );
461 RangeValueType intPhi = integrand( value( phi, col ) );
463 Hybrid::forEach( RangeValueIndices(), [ &qp, &jCol, &intPhi, weight ] (
auto i ) {
464 std::get< i >( intPhi ) *= weight;
465 jCol.axpy( qp, std::get< i >( intPhi ) );
469 integrands().unbind();
475 template<
bool conforming,
class Intersection,
class U,
class W >
476 void addSkeletonIntegral (
const Intersection &intersection,
const U &uIn,
const U &uOut, W &wIn )
const
478 const auto geometry = intersection.geometry();
480 typedef typename QuadratureSelector< typename W::DiscreteFunctionSpaceType > :: SurfaceQuadratureType SurfaceQuadratureType;
481 typedef IntersectionQuadrature< SurfaceQuadratureType, conforming > IntersectionQuadratureType;
482 const IntersectionQuadratureType quadrature( gridPart(), intersection, surfaceQuadratureOrder(maxOrder( uIn, uOut, wIn)),
false );
484 DomainValueVectorType& domainsIn = domainValues_;
485 domainValue( uIn, quadrature.inside(), domainsIn );
487 DomainValueVectorType& domainsOut = domainValuesOut_;
488 domainValue( uOut, quadrature.outside(), domainsOut );
490 for(
unsigned int qp = 0, nop = quadrature.nop(); qp != nop; ++qp )
492 const ctype weight = quadrature.weight( qp ) * geometry.integrationElement( quadrature.localPoint( qp ) );
494 const auto qpIn = quadrature.inside()[ qp ];
495 const auto qpOut = quadrature.outside()[ qp ];
496 std::pair< RangeValueType, RangeValueType > integrand
497 = integrands().skeleton( qpIn, domainValue( qp, domainsIn ), qpOut, domainValue( qp, domainsOut ) );
499 Hybrid::forEach( RangeValueIndices(), [ &qpIn, &wIn, &integrand, weight ] (
auto i ) {
500 std::get< i >( integrand.first ) *= weight;
501 wIn.axpy( qpIn, std::get< i >( integrand.first ) );
506 template<
bool conforming,
class Intersection,
class U,
class W >
507 void addSkeletonIntegral (
const Intersection &intersection,
const U &uIn,
const U &uOut, W &wIn, W &wOut )
const
509 const auto geometry = intersection.geometry();
510 typedef typename QuadratureSelector< typename W::DiscreteFunctionSpaceType > :: SurfaceQuadratureType SurfaceQuadratureType;
511 typedef IntersectionQuadrature< SurfaceQuadratureType, conforming > IntersectionQuadratureType;
512 const IntersectionQuadratureType quadrature( gridPart(), intersection, surfaceQuadratureOrder(maxOrder( uIn, uOut, wIn, wOut)),
false );
514 DomainValueVectorType& domainsIn = domainValues_;
515 domainValue( uIn, quadrature.inside(), domainsIn );
517 DomainValueVectorType& domainsOut = domainValuesOut_;
518 domainValue( uOut, quadrature.outside(), domainsOut );
520 for(
unsigned int qp = 0, nop = quadrature.nop(); qp != nop; ++qp )
522 const ctype weight = quadrature.weight( qp ) * geometry.integrationElement( quadrature.localPoint( qp ) );
524 const auto qpIn = quadrature.inside()[ qp ];
525 const auto qpOut = quadrature.outside()[ qp ];
526 std::pair< RangeValueType, RangeValueType > integrand
527 = integrands().skeleton( qpIn, domainValue( qp, domainsIn ), qpOut, domainValue( qp, domainsOut ) );
529 Hybrid::forEach( RangeValueIndices(), [ &qpIn, &wIn, &qpOut, &wOut, &integrand, weight ] (
auto i ) {
530 std::get< i >( integrand.first ) *= weight;
531 wIn.axpy( qpIn, std::get< i >( integrand.first ) );
533 std::get< i >( integrand.second ) *= weight;
534 wOut.axpy( qpOut, std::get< i >( integrand.second ) );
539 template<
bool conforming,
class Intersection,
class U,
class J >
540 void addLinearizedSkeletonIntegral (
const Intersection &intersection,
541 const U &uIn,
const U &uOut, J &jInIn, J &jOutIn )
const
543 DomainValueVectorType &phiIn = phiIn_;
544 DomainValueVectorType &phiOut = phiOut_;
546 const auto &domainBasisIn = jInIn.domainBasisFunctionSet();
547 const auto &domainBasisOut = jOutIn.domainBasisFunctionSet();
549 const auto &rangeBasisIn = jInIn.rangeBasisFunctionSet();
551 const int order = std::max( maxOrder(uIn, uOut), maxOrder( domainBasisIn, domainBasisOut, rangeBasisIn ));
553 const auto geometry = intersection.geometry();
554 typedef typename QuadratureSelector< typename J::RangeSpaceType > :: SurfaceQuadratureType SurfaceQuadratureType;
555 typedef IntersectionQuadrature< SurfaceQuadratureType, conforming > IntersectionQuadratureType;
556 const IntersectionQuadratureType quadrature( gridPart(), intersection, surfaceQuadratureOrder(order),
false );
558 DomainValueVectorType& domainsIn = domainValues_;
559 domainValue( uIn, quadrature.inside(), domainsIn );
561 DomainValueVectorType& domainsOut = domainValuesOut_;
562 domainValue( uOut, quadrature.outside(), domainsOut );
564 for(
unsigned int qp = 0, nop = quadrature.nop(); qp != nop; ++qp )
566 const ctype weight = quadrature.weight( qp ) * geometry.integrationElement( quadrature.localPoint( qp ) );
568 const auto qpIn = quadrature.inside()[ qp ];
569 const auto qpOut = quadrature.outside()[ qp ];
571 values( domainBasisIn, qpIn, phiIn );
572 values( domainBasisOut, qpOut, phiOut );
574 auto integrand = integrands().linearizedSkeleton( qpIn, domainValue( qp, domainsIn ), qpOut, domainValue( qp, domainsOut ) );
575 for( std::size_t col = 0, cols = domainBasisIn.size(); col < cols; ++col )
577 LocalMatrixColumn< J > jInInCol( jInIn, col );
578 std::pair< RangeValueType, RangeValueType > intPhi = integrand.first( value( phiIn, col ) );
580 Hybrid::forEach( RangeValueIndices(), [ &qpIn, &jInInCol, &intPhi, weight ] (
auto i ) {
581 std::get< i >( intPhi.first ) *= weight;
582 jInInCol.axpy( qpIn, std::get< i >( intPhi.first ) );
585 for( std::size_t col = 0, cols = domainBasisOut.size(); col < cols; ++col )
587 LocalMatrixColumn< J > jOutInCol( jOutIn, col );
588 std::pair< RangeValueType, RangeValueType > intPhi = integrand.second( value( phiOut, col ) );
590 Hybrid::forEach( RangeValueIndices(), [ &qpIn, &jOutInCol, &intPhi, weight ] (
auto i ) {
591 std::get< i >( intPhi.first ) *= weight;
592 jOutInCol.axpy( qpIn, std::get< i >( intPhi.first ) );
598 template<
bool conforming,
class Intersection,
class U,
class J >
599 void addLinearizedSkeletonIntegral (
const Intersection &intersection,
const U &uIn,
const U &uOut,
600 J &jInIn, J &jOutIn, J &jInOut, J &jOutOut )
const
602 DomainValueVectorType &phiIn = phiIn_;
603 DomainValueVectorType &phiOut = phiOut_;
605 const auto &domainBasisIn = jInIn.domainBasisFunctionSet();
606 const auto &domainBasisOut = jOutIn.domainBasisFunctionSet();
608 const auto &rangeBasisIn = jInIn.rangeBasisFunctionSet();
609 const auto &rangeBasisOut = jInOut.rangeBasisFunctionSet();
611 const int order = std::max( maxOrder(uIn, uOut), maxOrder( domainBasisIn, domainBasisOut, rangeBasisIn, rangeBasisOut ));
613 const auto geometry = intersection.geometry();
614 typedef typename QuadratureSelector< typename J::RangeSpaceType > :: SurfaceQuadratureType SurfaceQuadratureType;
615 typedef IntersectionQuadrature< SurfaceQuadratureType, conforming > IntersectionQuadratureType;
616 const IntersectionQuadratureType quadrature( gridPart(), intersection, surfaceQuadratureOrder(order),
false );
618 DomainValueVectorType& domainsIn = domainValues_;
619 domainValue( uIn, quadrature.inside(), domainsIn );
621 DomainValueVectorType& domainsOut = domainValuesOut_;
622 domainValue( uOut, quadrature.outside(), domainsOut );
624 for(
unsigned int qp = 0, nop = quadrature.nop(); qp != nop; ++qp )
626 const ctype weight = quadrature.weight( qp ) * geometry.integrationElement( quadrature.localPoint( qp ) );
628 const auto qpIn = quadrature.inside()[ qp ];
629 const auto qpOut = quadrature.outside()[ qp ];
631 values( domainBasisIn, qpIn, phiIn );
632 values( domainBasisOut, qpOut, phiOut );
634 auto integrand = integrands().linearizedSkeleton( qpIn, domainValue( qp, domainsIn ), qpOut, domainValue( qp, domainsOut ) );
635 for( std::size_t col = 0, cols = domainBasisIn.size(); col < cols; ++col )
637 LocalMatrixColumn< J > jInInCol( jInIn, col );
638 LocalMatrixColumn< J > jInOutCol( jInOut, col );
639 std::pair< RangeValueType, RangeValueType > intPhi = integrand.first( value( phiIn, col ) );
641 Hybrid::forEach( RangeValueIndices(), [ &qpIn, &jInInCol, &qpOut, &jInOutCol, &intPhi, weight ] (
auto i ) {
642 std::get< i >( intPhi.first ) *= weight;
643 jInInCol.axpy( qpIn, std::get< i >( intPhi.first ) );
645 std::get< i >( intPhi.second ) *= weight;
646 jInOutCol.axpy( qpOut, std::get< i >( intPhi.second ) );
649 for( std::size_t col = 0, cols = domainBasisOut.size(); col < cols; ++col )
651 LocalMatrixColumn< J > jOutInCol( jOutIn, col );
652 LocalMatrixColumn< J > jOutOutCol( jOutOut, col );
653 std::pair< RangeValueType, RangeValueType > intPhi = integrand.second( value( phiOut, col ) );
655 Hybrid::forEach( RangeValueIndices(), [ &qpIn, &jOutInCol, &qpOut, &jOutOutCol, &intPhi, weight ] (
auto i ) {
656 std::get< i >( intPhi.first ) *= weight;
657 jOutInCol.axpy( qpIn, std::get< i >( intPhi.first ) );
659 std::get< i >( intPhi.second ) *= weight;
660 jOutOutCol.axpy( qpOut, std::get< i >( intPhi.second ) );
667 template<
class Intersection,
class U,
class... W >
668 void addSkeletonIntegral (
const Intersection &intersection,
const U &uIn,
const U &uOut, W &... w )
const
670 if( !integrands().init( intersection ) )
673 if( intersection.conforming() )
674 addSkeletonIntegral< true >( intersection, uIn, uOut, w... );
676 addSkeletonIntegral< false >( intersection, uIn, uOut, w... );
677 integrands().unbind();
680 template<
class Intersection,
class U,
class... J >
681 void addLinearizedSkeletonIntegral (
const Intersection &intersection,
const U &uIn,
const U &uOut, J &... j )
const
683 if( !integrands().init( intersection ) )
686 if( intersection.conforming() )
687 addLinearizedSkeletonIntegral< true >( intersection, uIn, uOut, j... );
689 addLinearizedSkeletonIntegral< false >( intersection, uIn, uOut, j... );
690 integrands().unbind();
693 void setQuadratureOrders(
unsigned int interior,
unsigned int surface)
696 surfaceQuadOrder_ = surface;
699 void setQuadratureOrderFunctions( std::function<
int(
const int)> interiorOrder,
700 std::function<
int(
const int)> surfaceOrder )
702 defaultInteriorOrder_ = interiorOrder;
703 defaultSurfaceOrder_ = surfaceOrder;
706 IntegrandsType& model()
const
710 bool nonlinear()
const {
return model().nonlinear(); }
711 bool hasInterior()
const {
return model().hasInterior(); }
712 bool hasSkeleton()
const {
return model().hasSkeleton(); }
713 bool hasBoundary()
const {
return model().hasBoundary(); }
716 IntegrandsType& integrands()
const
723 const GridPartType &gridPart ()
const {
return gridPart_; }
725 unsigned int interiorQuadratureOrder(
unsigned int order)
const {
return interiorQuadOrder_ == 0 ? defaultInteriorOrder_(order) : interiorQuadOrder_; }
726 unsigned int surfaceQuadratureOrder(
unsigned int order)
const {
return surfaceQuadOrder_ == 0 ? defaultSurfaceOrder_ (order) : surfaceQuadOrder_; }
730 int maxOrder(
const U& u )
const
732 return CallOrder< U > :: order( u );
735 template<
class U,
class W >
736 int maxOrder(
const U& u,
const W& w )
const
738 return std::max( maxOrder( u ), maxOrder( w ) );
741 template<
class U,
class V,
class W >
742 int maxOrder(
const U& u,
const V& v,
const W& w )
const
744 return std::max( maxOrder( u, v ), maxOrder( w ) );
747 template<
class U,
class V,
class W,
class X >
748 int maxOrder(
const U& u,
const V& v,
const W& w,
const X& x )
const
750 return std::max( maxOrder( u, v ), maxOrder( w, x) );
754 const GridPartType &gridPart_;
756 mutable IntegrandsType integrands_;
758 mutable std::function<int(
const int)> defaultInteriorOrder_;
759 mutable std::function<int(
const int)> defaultSurfaceOrder_;
761 unsigned int interiorQuadOrder_;
762 unsigned int surfaceQuadOrder_;
764 mutable std::vector< RangeValueVectorType > rangeValues_;
765 mutable RangeValueVectorType values_;
766 mutable DomainValueVectorType phiIn_;
767 mutable DomainValueVectorType phiOut_;
768 mutable DomainValueVectorType basisValues_;
769 mutable DomainValueVectorType domainValues_;
770 mutable DomainValueVectorType domainValuesOut_;
778 template<
class Gr
idPart >
780 struct GalerkinOperator
782 typedef GridPart GridPartType;
783 typedef GalerkinOperator< GridPartType > ThisType;
785 typedef typename GridPartType::ctype ctype;
786 typedef typename GridPartType::template Codim< 0 >::EntityType EntityType;
789 explicit GalerkinOperator (
const GridPartType &gridPart )
790 : gridPart_( gridPart ),
791 gridSizeInterior_( 0 )
796 template <
class IntegrandsTuple>
797 bool hasBoundary(
const IntegrandsTuple& integrandsTuple )
const
799 typedef std::make_index_sequence< std::tuple_size< IntegrandsTuple >::value > Indices;
800 bool hasBoundary = false ;
801 Hybrid::forEach( Indices(), [&integrandsTuple, &hasBoundary](
auto i ) {
802 if( std::get< i > (integrandsTuple).hasBoundary() )
811 template<
class Gr
idFunction,
class DiscreteFunction,
class Iterators,
class IntegrandsTuple,
class Functor,
bool hasSkeleton >
812 void evaluateImpl (
const GridFunction &u, DiscreteFunction &w,
const Iterators& iterators,
813 const IntegrandsTuple& integrandsTuple, Functor& addLocalDofs, std::integral_constant<bool, hasSkeleton> )
const
815 Dune::Fem::ConstLocalFunction< GridFunction > uInside( u );
816 Dune::Fem::ConstLocalFunction< GridFunction > uOutside( u );
818 typedef typename DiscreteFunction::DiscreteFunctionSpaceType DiscreteFunctionSpaceType;
822 gridSizeInterior_ = 0;
824 typedef std::make_index_sequence< std::tuple_size< IntegrandsTuple >::value > Indices;
827 const bool hasBnd = hasBoundary( integrandsTuple );
829 const auto &indexSet = gridPart().indexSet();
830 const auto end = iterators.end();
831 for(
auto it = iterators.begin(); it != end; ++it )
834 const EntityType inside = *it ;
839 auto uGuard = bindGuard( uInside, inside );
840 auto wGuard = bindGuard( wInside, inside );
843 auto addInteriorIntegral = [&integrandsTuple, &uInside, &wInside](
auto i )
845 const auto& integrands = std::get< i >( integrandsTuple );
846 if( integrands.hasInterior() )
847 integrands.addInteriorIntegral( uInside, wInside );
852 if( hasSkeleton || (hasBnd && HasBoundaryIntersection<GridPartType>::apply(inside) ) )
854 for(
const auto &intersection : intersections( gridPart(), inside ) )
856 bool neighbor =
false;
857 if constexpr ( hasSkeleton )
861 if( intersection.neighbor() )
864 const EntityType outside = intersection.outside();
868 auto uOutGuard = bindGuard( uOutside, outside );
870 auto addSkeletonIntegral = [&integrandsTuple, &intersection, &uInside, &uOutside, &wInside] (
auto i )
872 const auto& integrands = std::get< i >( integrandsTuple );
873 if( integrands.hasSkeleton() )
874 integrands.addSkeletonIntegral( intersection, uInside, uOutside, wInside );
879 else if( indexSet.index( inside ) < indexSet.index( outside ) )
881 auto uOutGuard = bindGuard( uOutside, outside );
882 auto wOutGuard = bindGuard( wOutside, outside );
885 auto addSkeletonIntegral = [&integrandsTuple, &intersection, &uInside, &uOutside, &wInside, &wOutside] (
auto i )
887 const auto& integrands = std::get< i >( integrandsTuple );
888 if( integrands.hasSkeleton() )
889 integrands.addSkeletonIntegral( intersection, uInside, uOutside, wInside, wOutside );
896 addLocalDofs( outside, wOutside );
901 if( ! neighbor && intersection.boundary() )
903 auto addBoundaryIntegral = [&integrandsTuple, &intersection, &uInside, &wInside](
auto i )
905 const auto& integrands = std::get< i >( integrandsTuple );
906 if( integrands.hasBoundary() )
907 integrands.addBoundaryIntegral( intersection, uInside, wInside );
915 addLocalDofs( inside, wInside );
919 template <
class Space>
922 typedef typename Space::EntityType EntityType;
923 template <
class Iterators>
924 InsideEntity(
const Space &space,
const Iterators& iterators)
925 : space_(space), dofThread_(space.
size(),-1)
926 , thread_( iterators.thread() )
928 const auto& mapper = space_.blockMapper();
929 for (
const auto &entity : space_)
931 int t=iterators.threadParallel(entity);
932 mapper.mapEach(entity, [
this, t ] (
int local,
auto global )
933 { dofThread_[global] = (dofThread_[global]==t || dofThread_[global]==-1)?
937 bool operator()(
const EntityType &entity)
const
939 bool needsLocking =
false;
940 space_.blockMapper().mapEach(entity,
941 [
this, &needsLocking ] (
int local,
auto global )
942 { needsLocking = (needsLocking || dofThread_[global]!=thread_); });
943 return !needsLocking;
946 std::vector<int> dofThread_;
950 template <
class DiscreteFunction>
951 struct AddLocalEvaluate
953 AddLocalEvaluate(DiscreteFunction &w)
955 template <
class LocalDofs>
956 void operator () (
const EntityType& entity,
const LocalDofs& wLocal )
const
958 w_.addLocalDofs( entity, wLocal.localDofVector() );
960 DiscreteFunction &w_;
963 template <
class DiscreteFunction>
964 struct AddLocalEvaluateLocked :
public AddLocalEvaluate<DiscreteFunction>
966 typedef AddLocalEvaluate<DiscreteFunction> BaseType;
968 std::shared_mutex& mutex_;
969 InsideEntity<typename DiscreteFunction::DiscreteFunctionSpaceType> inside_;
971 template <
class Iterators>
972 AddLocalEvaluateLocked(DiscreteFunction &w, std::shared_mutex& mtx,
const Iterators &iterators)
973 : BaseType(w), mutex_(mtx), inside_(w.space(),iterators) {}
975 template <
class LocalDofs>
976 void operator () (
const EntityType& entity,
const LocalDofs& wLocal )
const
981 std::shared_lock<std::shared_mutex> guard ( mutex_ );
982 BaseType::operator()( entity, wLocal );
987 std::lock_guard<std::shared_mutex> guard ( mutex_ );
988 BaseType::operator()( entity, wLocal );
993 template<
class Gr
idFunction,
class DiscreteFunction,
class Iterators,
class IntegrandsTuple,
class Functor >
994 void evaluate (
const GridFunction &u, DiscreteFunction &w,
const Iterators& iterators,
995 const IntegrandsTuple& integrandsTuple, Functor& addLocalDofs )
const
997 static_assert( std::is_same< typename GridFunction::GridPartType, GridPartType >::value,
"Argument 'u' and Integrands must be defined on the same grid part." );
998 static_assert( std::is_same< typename DiscreteFunction::GridPartType, GridPartType >::value,
"Argument 'w' and Integrands must be defined on the same grid part." );
1000 if( hasSkeleton( integrandsTuple ) )
1001 evaluateImpl( u, w, iterators, integrandsTuple, addLocalDofs, std::true_type() );
1003 evaluateImpl( u, w, iterators, integrandsTuple, addLocalDofs, std::false_type() );
1007 template <
class IntegrandsTuple>
1008 bool hasSkeleton(
const IntegrandsTuple& integrandsTuple )
const
1010 typedef std::make_index_sequence< std::tuple_size< IntegrandsTuple >::value > Indices;
1011 bool hasSkeleton = false ;
1012 Hybrid::forEach( Indices(), [&integrandsTuple, &hasSkeleton] (
auto i ) {
1013 if( std::get< i >( integrandsTuple ).hasSkeleton() )
1019 return hasSkeleton ;
1022 template<
class Gr
idFunction,
class DiscreteFunction,
class Iterators,
class IntegrandsTuple >
1023 void evaluate (
const GridFunction &u, DiscreteFunction &w,
const Iterators& iterators,
1024 const IntegrandsTuple& integrandsTuple, std::shared_mutex& mtx )
const
1026 AddLocalEvaluateLocked<DiscreteFunction> addLocalEvaluate(w,mtx,iterators);
1027 evaluate( u, w, iterators, integrandsTuple, addLocalEvaluate );
1030 template<
class Gr
idFunction,
class DiscreteFunction,
class Iterators,
class IntegrandsTuple >
1031 void evaluate (
const GridFunction &u, DiscreteFunction &w,
const Iterators& iterators,
const IntegrandsTuple& integrandsTuple )
const
1033 AddLocalEvaluate<DiscreteFunction> addLocalEvaluate(w);
1034 evaluate( u, w, iterators, integrandsTuple, addLocalEvaluate );
1038 template<
class T,
int length>
1043 FiniteStack () : _f(0) {}
1046 bool empty ()
const {
return _f <= 0; }
1049 bool full ()
const {
return (_f >= length); }
1052 void clear() { _f = 0; }
1055 void push (
const T& t)
1057 assert ( _f < length );
1074 int size ()
const {
return _f; }
1082 template <
class JacobianOperator>
1083 struct AddLocalAssemble
1085 typedef typename JacobianOperator::DomainSpaceType DomainSpaceType;
1086 typedef typename JacobianOperator::RangeSpaceType RangeSpaceType;
1087 typedef TemporaryLocalMatrix< DomainSpaceType, RangeSpaceType > TemporaryLocalMatrixType;
1088 JacobianOperator &jOp_;
1089 std::vector< TemporaryLocalMatrixType > jOpLocal_;
1091 FiniteStack< TemporaryLocalMatrixType*, 12 > jOpLocalFinalized_;
1092 FiniteStack< TemporaryLocalMatrixType*, 12 > jOpLocalFree_;
1094 std::size_t locked, notLocked, timesLocked;
1095 AddLocalAssemble(JacobianOperator& jOp)
1097 , jOpLocal_(12, TemporaryLocalMatrixType(jOp_.domainSpace(), jOp_.rangeSpace()))
1098 , jOpLocalFinalized_()
1100 , locked(0), notLocked(0), timesLocked(0)
1102 for(
auto& jOpLocal : jOpLocal_ )
1103 jOpLocalFree_.push( &jOpLocal );
1106 TemporaryLocalMatrixType& bind(
const EntityType& dE,
const EntityType& rE)
1108 assert( ! jOpLocalFree_.empty() );
1109 TemporaryLocalMatrixType& lop = *(jOpLocalFree_.pop());
1115 void unbind(TemporaryLocalMatrixType &lop)
1118 jOp_.addLocalMatrix( lop.domainEntity(), lop.rangeEntity(), lop );
1120 jOpLocalFree_.push( &lop );
1125 locked += jOpLocalFinalized_.size();
1126 while ( ! jOpLocalFinalized_.empty() )
1128 TemporaryLocalMatrixType &lop = *(jOpLocalFinalized_.pop());
1129 jOp_.addLocalMatrix( lop.domainEntity(), lop.rangeEntity(), lop );
1131 jOpLocalFree_.push( &lop );
1136 template <
class JacobianOperator>
1137 struct AddLocalAssembleLocked :
public AddLocalAssemble<JacobianOperator>
1139 typedef AddLocalAssemble<JacobianOperator> BaseType;
1140 typedef typename BaseType::TemporaryLocalMatrixType TemporaryLocalMatrixType;
1141 using BaseType::jOpLocalFinalized_;
1142 using BaseType::jOpLocalFree_;
1144 std::shared_mutex& mutex_;
1145 InsideEntity<typename JacobianOperator::DomainSpaceType> insideDomain_;
1146 InsideEntity<typename JacobianOperator::RangeSpaceType> insideRange_;
1148 template <
class Iterators>
1149 AddLocalAssembleLocked(JacobianOperator &jOp, std::shared_mutex &mtx,
const Iterators &iterators)
1152 , insideDomain_(jOp.domainSpace(),iterators)
1153 , insideRange_(jOp.rangeSpace(),iterators)
1159 ++BaseType::timesLocked;
1160 std::lock_guard<std::shared_mutex> guard ( mutex_ );
1161 BaseType::finalize();
1164 TemporaryLocalMatrixType& bind(
const EntityType& dE,
const EntityType& rE)
1166 if ( jOpLocalFree_.empty() )
1170 return BaseType::bind(dE,rE);
1173 void unbind(TemporaryLocalMatrixType &lop)
1182 if ( insideDomain_(lop.domainEntity()) &&
1183 insideRange_(lop.rangeEntity()) )
1185 std::shared_lock<std::shared_mutex> guard ( mutex_ );
1186 BaseType::unbind(lop);
1190 jOpLocalFinalized_.push( &lop );
1195 template<
class Gr
idFunction,
class JacobianOperator,
class Iterators,
class IntegrandsTuple,
class Functor,
bool hasSkeleton >
1196 void assembleImpl (
const GridFunction &u, JacobianOperator &jOp,
const Iterators& iterators,
const IntegrandsTuple& integrandsTuple,
1197 Functor& addLocalMatrix, std::integral_constant<bool, hasSkeleton> )
const
1199 typedef typename JacobianOperator::DomainSpaceType DomainSpaceType;
1200 typedef typename JacobianOperator::RangeSpaceType RangeSpaceType;
1202 typedef TemporaryLocalMatrix< DomainSpaceType, RangeSpaceType > TemporaryLocalMatrixType;
1204 Dune::Fem::ConstLocalFunction< GridFunction > uIn( u );
1205 Dune::Fem::ConstLocalFunction< GridFunction > uOut( u );
1207 typedef std::make_index_sequence< std::tuple_size< IntegrandsTuple >::value > Indices;
1208 const std::size_t maxNumLocalDofs = jOp.domainSpace().blockMapper().maxNumDofs() * jOp.domainSpace().localBlockSize;
1211 Hybrid::forEach( Indices(), [&integrandsTuple, &maxNumLocalDofs] (
auto i ) {
1212 const auto& integrands = std::get< i >( integrandsTuple );
1213 integrands.prepare( maxNumLocalDofs );
1217 gridSizeInterior_ = 0;
1220 const bool hasBnd = hasBoundary( integrandsTuple );
1222 const auto &indexSet = gridPart().indexSet();
1224 const auto end = iterators.end();
1225 for(
auto it = iterators.begin(); it != end; ++it )
1228 ++gridSizeInterior_;
1230 const EntityType inside = *it;
1232 auto uiGuard = bindGuard( uIn, inside );
1234 TemporaryLocalMatrixType& jOpInIn = addLocalMatrix.bind( inside, inside );
1235 auto addLinearizedInteriorIntegral = [&integrandsTuple, &uIn, &jOpInIn](
auto i )
1237 const auto& integrands = std::get< i >( integrandsTuple );
1238 if( integrands.hasInterior() )
1239 integrands.addLinearizedInteriorIntegral( uIn, jOpInIn );
1244 if( hasSkeleton || (hasBnd && HasBoundaryIntersection<GridPartType>::apply(inside) ) )
1246 for(
const auto &intersection : intersections( gridPart(), inside ) )
1248 bool neighbor = false ;
1251 if constexpr ( hasSkeleton )
1253 if( intersection.neighbor() )
1256 const EntityType &outside = intersection.outside();
1258 TemporaryLocalMatrixType &jOpOutIn = addLocalMatrix.bind( outside, inside );
1260 auto uoGuard = bindGuard( uOut, outside );
1264 auto addLinearizedSkeletonIntegral = [&integrandsTuple, &intersection, &uIn, &uOut, &jOpInIn, &jOpOutIn](
auto i )
1266 const auto& integrands = std::get< i >( integrandsTuple );
1267 if( integrands.hasSkeleton() )
1268 integrands.addLinearizedSkeletonIntegral( intersection, uIn, uOut, jOpInIn, jOpOutIn );
1273 else if( indexSet.index( inside ) < indexSet.index( outside ) )
1275 TemporaryLocalMatrixType &jOpInOut = addLocalMatrix.bind( inside, outside );
1276 TemporaryLocalMatrixType &jOpOutOut = addLocalMatrix.bind( outside, outside );
1278 auto addLinearizedSkeletonIntegral = [&integrandsTuple, &intersection, &uIn, &uOut, &jOpInIn, &jOpOutIn, &jOpInOut, &jOpOutOut](
auto i )
1280 const auto& integrands = std::get< i >( integrandsTuple );
1281 if( integrands.hasSkeleton() )
1282 integrands.addLinearizedSkeletonIntegral( intersection, uIn, uOut, jOpInIn, jOpOutIn, jOpInOut, jOpOutOut );
1287 addLocalMatrix.unbind(jOpInOut);
1288 addLocalMatrix.unbind(jOpOutOut);
1291 addLocalMatrix.unbind(jOpOutIn);
1295 if( !neighbor && intersection.boundary() )
1297 auto addLinearizedBoundaryIntegral = [&integrandsTuple, &intersection, &uIn, &jOpInIn](
auto i )
1299 const auto& integrands = std::get< i >( integrandsTuple );
1300 if( integrands.hasBoundary() )
1301 integrands.addLinearizedBoundaryIntegral( intersection, uIn, jOpInIn );
1309 addLocalMatrix.unbind(jOpInIn);
1313 addLocalMatrix.finalize();
1317 template<
class Gr
idFunction,
class JacobianOperator,
class Iterators,
class IntegrandsTuple,
class Functor >
1318 void assemble (
const GridFunction &u, JacobianOperator &jOp,
const Iterators& iterators,
1319 const IntegrandsTuple& integrandsTuple, Functor& addLocalMatrix,
int )
const
1321 static_assert( std::is_same< typename GridFunction::GridPartType, GridPartType >::value,
"Argument 'u' and Integrands must be defined on the same grid part." );
1322 static_assert( std::is_same< typename JacobianOperator::DomainSpaceType::GridPartType, GridPartType >::value,
"Argument 'jOp' and Integrands must be defined on the same grid part." );
1323 static_assert( std::is_same< typename JacobianOperator::RangeSpaceType::GridPartType, GridPartType >::value,
"Argument 'jOp' and Integrands must be defined on the same grid part." );
1325 if( hasSkeleton( integrandsTuple ) )
1326 assembleImpl( u, jOp, iterators, integrandsTuple ,addLocalMatrix, std::true_type() );
1328 assembleImpl( u, jOp, iterators, integrandsTuple, addLocalMatrix, std::false_type() );
1332 template<
class Gr
idFunction,
class JacobianOperator,
class Iterators,
class IntegrandsTuple>
1333 void assemble (
const GridFunction &u, JacobianOperator &jOp,
const Iterators& iterators,
1334 const IntegrandsTuple& integrandsTuple, std::shared_mutex& mtx)
const
1336 AddLocalAssembleLocked<JacobianOperator> addLocalAssemble( jOp, mtx, iterators);
1337 assemble( u, jOp, iterators, integrandsTuple, addLocalAssemble, 10 );
1339 std::lock_guard guard ( mtx );
1340 std::cout << MPIManager::thread() <<
" : "
1341 << addLocalAssemble.locked <<
" " << addLocalAssemble.notLocked <<
" "
1342 << addLocalAssemble.timesLocked << std::endl;
1346 template<
class Gr
idFunction,
class JacobianOperator,
class Iterators,
class IntegrandsTuple>
1347 void assemble (
const GridFunction &u, JacobianOperator &jOp,
const Iterators& iterators,
const IntegrandsTuple& integrandsTuple )
const
1349 AddLocalAssemble<JacobianOperator> addLocalAssemble(jOp);
1350 assemble( u, jOp, iterators, integrandsTuple, addLocalAssemble, 10 );
1354 const GridPartType &gridPart ()
const {
return gridPart_; }
1356 std::size_t gridSizeInterior ()
const {
return gridSizeInterior_; }
1359 const GridPartType &gridPart_;
1360 mutable std::size_t gridSizeInterior_;
1364 template <
class GalerkinOperator >
1365 static std::size_t accumulateGridSize(
const ThreadSafeValue< GalerkinOperator >& ops )
1367 std::size_t s = ops.size();
1368 std::size_t sum = 0;
1369 for( std::size_t i=0; i<s; ++i )
1370 sum += ops[ i ].gridSizeInterior();
1383 template<
class Integrands,
class DomainFunction,
class RangeFunction = DomainFunction >
1384 struct GalerkinOperator
1385 :
public virtual Operator< DomainFunction, RangeFunction >
1387 typedef DomainFunction DomainFunctionType;
1388 typedef RangeFunction RangeFunctionType;
1390 typedef typename RangeFunctionType::GridPartType GridPartType;
1392 typedef Impl::LocalGalerkinOperator< Integrands > LocalGalerkinOperatorImplType;
1393 typedef Impl::GalerkinOperator< GridPartType > GalerkinOperatorImplType;
1395 static_assert( std::is_same< typename DomainFunctionType::GridPartType, typename RangeFunctionType::GridPartType >::value,
"DomainFunction and RangeFunction must be defined on the same grid part." );
1399 template<
class... Args >
1400 explicit GalerkinOperator (
const GridPartType &gridPart, Args &&... args )
1401 : iterators_( gridPart ),
1402 opImpl_( gridPart ),
1403 localOp_( gridPart,
std::forward< Args >( args )... ),
1404 gridSizeInterior_( 0 ),
1405 communicate_( true )
1409 void setCommunicate(
const bool communicate )
1411 communicate_ = communicate;
1414 std::cout <<
"GalerkinOperator::setCommunicate: communicate was disabled!" << std::endl;
1418 void setQuadratureOrders(
unsigned int interior,
unsigned int surface)
1420 size_t size = localOp_.size();
1421 for(
size_t i=0; i<
size; ++i )
1422 localOp_[ i ].setQuadratureOrders(interior,surface);
1425 virtual bool nonlinear() const final
override
1427 return localOperator().nonlinear();
1430 virtual void operator() (
const DomainFunctionType &u, RangeFunctionType &w )
const final override
1435 template<
class Gr
idFunction >
1436 void operator() (
const GridFunction &u, RangeFunctionType &w )
const
1441 const GridPartType &gridPart ()
const {
return op().gridPart(); }
1443 typedef Integrands ModelType;
1444 typedef Integrands DirichletModelType;
1445 ModelType &model()
const {
return localOperator().model(); }
1447 [[deprecated(
"Use localOperator instead!")]]
1448 const LocalGalerkinOperatorImplType& impl()
const {
return localOperator(); }
1451 const LocalGalerkinOperatorImplType& localOperator()
const {
return *localOp_; }
1453 std::size_t gridSizeInterior ()
const {
return gridSizeInterior_; }
1457 const GalerkinOperatorImplType& op()
const {
return *opImpl_; }
1459 template <
class Gr
idFunction >
1460 void evaluate(
const GridFunction &u, RangeFunctionType &w )
const
1462 iterators_.update();
1465 std::shared_mutex mutex;
1467 auto doEval = [
this, &u, &w, &mutex] ()
1470 std::tuple< const LocalGalerkinOperatorImplType& > integrands( localOperator() );
1471 this->op().evaluate( u, w, this->iterators_, integrands, mutex );
1476 MPIManager :: run ( doEval );
1479 gridSizeInterior_ = Impl::accumulateGridSize( opImpl_ );
1481 catch (
const SingleThreadModeError& e )
1486 std::tuple< const LocalGalerkinOperatorImplType& > integrands( localOperator() );
1487 op().evaluate( u, w, iterators_, integrands );
1490 gridSizeInterior_ = op().gridSizeInterior();
1498 mutable ThreadIteratorType iterators_;
1502 mutable std::size_t gridSizeInterior_;
1511 template<
class Integrands,
class JacobianOperator >
1512 class DifferentiableGalerkinOperator
1513 :
public GalerkinOperator< Integrands, typename JacobianOperator::DomainFunctionType, typename JacobianOperator::RangeFunctionType >,
1514 public DifferentiableOperator< JacobianOperator >
1516 typedef GalerkinOperator< Integrands, typename JacobianOperator::DomainFunctionType, typename JacobianOperator::RangeFunctionType > BaseType;
1518 typedef typename BaseType :: LocalGalerkinOperatorImplType LocalGalerkinOperatorImplType;
1520 typedef JacobianOperator JacobianOperatorType;
1522 typedef typename BaseType::DomainFunctionType DomainFunctionType;
1523 typedef typename BaseType::RangeFunctionType RangeFunctionType;
1524 typedef typename DomainFunctionType::DiscreteFunctionSpaceType DomainDiscreteFunctionSpaceType;
1525 typedef typename RangeFunctionType::DiscreteFunctionSpaceType RangeDiscreteFunctionSpaceType;
1527 typedef DiagonalAndNeighborStencil< DomainDiscreteFunctionSpaceType, RangeDiscreteFunctionSpaceType > DiagonalAndNeighborStencilType;
1528 typedef DiagonalStencil< DomainDiscreteFunctionSpaceType, RangeDiscreteFunctionSpaceType > DiagonalStencilType;
1530 typedef typename BaseType::GridPartType GridPartType;
1532 template<
class... Args >
1533 explicit DifferentiableGalerkinOperator (
const DomainDiscreteFunctionSpaceType &dSpace,
1534 const RangeDiscreteFunctionSpaceType &rSpace,
1536 : BaseType( rSpace.gridPart(),
std::forward< Args >( args )... ),
1537 dSpace_(dSpace), rSpace_(rSpace),
1538 domainSpaceSequence_(dSpace.sequence()),
1539 rangeSpaceSequence_(rSpace.sequence()),
1540 stencilDAN_(), stencilD_()
1543 stencilDAN_.reset(
new DiagonalAndNeighborStencilType( dSpace_, rSpace_ ) );
1545 stencilD_.reset(
new DiagonalStencilType( dSpace_, rSpace_ ) );
1548 virtual void jacobian (
const DomainFunctionType &u, JacobianOperatorType &jOp )
const final override
1553 template<
class Gr
idFunction >
1554 void jacobian (
const GridFunction &u, JacobianOperatorType &jOp )
const
1559 const DomainDiscreteFunctionSpaceType& domainSpace()
const
1563 const RangeDiscreteFunctionSpaceType& rangeSpace()
const
1568 using BaseType::localOperator;
1569 using BaseType::nonlinear;
1574 bool hasSkeleton()
const
1576 std::tuple< const LocalGalerkinOperatorImplType& > integrands( localOperator() );
1577 return op().hasSkeleton( integrands );
1580 void prepare( JacobianOperatorType& jOp )
const
1582 if ( domainSpaceSequence_ != domainSpace().sequence()
1583 || rangeSpaceSequence_ != rangeSpace().sequence() )
1585 domainSpaceSequence_ = domainSpace().sequence();
1586 rangeSpaceSequence_ = rangeSpace().sequence();
1589 assert( stencilDAN_ );
1590 stencilDAN_->update();
1594 assert( stencilD_ );
1595 stencilD_->update();
1599 jOp.reserve( *stencilDAN_ );
1601 jOp.reserve( *stencilD_ );
1606 template <
class Gr
idFunction >
1607 void assemble(
const GridFunction &u, JacobianOperatorType &jOp )
const
1612 iterators_.update();
1615 std::shared_mutex mutex;
1617 auto doAssemble = [
this, &u, &jOp, &mutex] ()
1619 std::tuple< const LocalGalerkinOperatorImplType& > integrands( localOperator() );
1620 this->op().assemble( u, jOp, this->iterators_, integrands, mutex );
1625 MPIManager :: run ( doAssemble );
1628 gridSizeInterior_ = Impl::accumulateGridSize( this->opImpl_ );
1630 catch (
const SingleThreadModeError& e )
1634 std::tuple< const LocalGalerkinOperatorImplType& > integrands( localOperator() );
1635 op().assemble( u, jOp, iterators_, integrands );
1637 gridSizeInterior_ = op().gridSizeInterior();
1642 jOp.flushAssembly();
1645 using BaseType::iterators_;
1646 using BaseType::gridSizeInterior_;
1648 const DomainDiscreteFunctionSpaceType &dSpace_;
1649 const RangeDiscreteFunctionSpaceType &rSpace_;
1651 mutable int domainSpaceSequence_, rangeSpaceSequence_;
1653 mutable std::unique_ptr< DiagonalAndNeighborStencilType > stencilDAN_;
1654 mutable std::unique_ptr< DiagonalStencilType > stencilD_;
1662 template<
class Integrands,
class DomainFunction,
class RangeFunction >
1663 class AutomaticDifferenceGalerkinOperator
1664 :
public GalerkinOperator< Integrands, DomainFunction, RangeFunction >,
1665 public AutomaticDifferenceOperator< DomainFunction, RangeFunction >
1667 typedef GalerkinOperator< Integrands, DomainFunction, RangeFunction > BaseType;
1671 typedef typename BaseType::GridPartType GridPartType;
1673 template<
class... Args >
1674 explicit AutomaticDifferenceGalerkinOperator (
const GridPartType &gridPart, Args &&... args )
1675 : BaseType( gridPart,
std::forward< Args >( args )... ), AutomaticDifferenceOperatorType()
1684 template <
class LinearOperator,
class ModelIntegrands >
1685 struct ModelDifferentiableGalerkinOperator
1686 :
public DifferentiableGalerkinOperator< ModelIntegrands, LinearOperator >
1688 typedef DifferentiableGalerkinOperator< ModelIntegrands, LinearOperator > BaseType;
1690 typedef typename ModelIntegrands::ModelType ModelType;
1693 typedef typename LinearOperator::RangeSpaceType DiscreteFunctionSpaceType;
1695 ModelDifferentiableGalerkinOperator ( ModelType &model,
const DiscreteFunctionSpaceType &dfSpace )
1696 : BaseType( dfSpace.gridPart(), model )
1699 template<
class Gr
idFunction >
1700 void apply (
const GridFunction &u, RangeFunctionType &w )
const
1705 template<
class Gr
idFunction >
1706 void apply (
const GridFunction &u, LinearOperator &jOp )
const
1708 (*this).jacobian( u, jOp );
1717 template<
class Integrands,
class LinearOperator,
bool addDirichletBC,
1718 template <
class,
class>
class DifferentiableGalerkinOperatorImpl >
1719 struct GalerkinSchemeTraits
1721 template <
class O,
bool addDBC>
1722 struct DirichletBlockSelector {
using type = void; };
1724 struct DirichletBlockSelector<O,true> {
using type =
typename O::DirichletBlockVector; };
1726 using DifferentiableOperatorType = std::conditional_t< addDirichletBC,
1727 DirichletWrapperOperator< DifferentiableGalerkinOperatorImpl< Integrands, LinearOperator >>,
1728 DifferentiableGalerkinOperatorImpl< Integrands, LinearOperator > >;
1729 using DirichletBlockVector =
typename DirichletBlockSelector<
1730 DirichletWrapperOperator<
1731 DifferentiableGalerkinOperatorImpl< Integrands, LinearOperator >>,
1732 addDirichletBC>::type;
1734 typedef DifferentiableOperatorType type;
1737 template<
class Integrands,
class LinearOperator,
class LinearInverseOperator,
bool addDirichletBC,
1738 template <
class,
class>
class DifferentiableGalerkinOperatorImpl = DifferentiableGalerkinOperator >
1739 struct GalerkinSchemeImpl :
public FemScheme< typename
1740 GalerkinSchemeTraits< Integrands, LinearOperator,
1741 addDirichletBC, DifferentiableGalerkinOperatorImpl>::type,
1742 LinearInverseOperator >
1744 typedef FemScheme<
typename GalerkinSchemeTraits< Integrands, LinearOperator,
1745 addDirichletBC, DifferentiableGalerkinOperatorImpl>::type,
1746 LinearInverseOperator >
1749 typedef typename BaseType :: DiscreteFunctionSpaceType DiscreteFunctionSpaceType;
1751 GalerkinSchemeImpl (
const DiscreteFunctionSpaceType &dfSpace,
1752 const Integrands &integrands,
1753 const ParameterReader& parameter = Parameter::container() )
1756 std::move(integrands))
1765 template<
class Integrands,
class LinearOperator,
class InverseOperator,
bool addDirichletBC >
1766 using GalerkinScheme = Impl::GalerkinSchemeImpl< Integrands, LinearOperator, InverseOperator, addDirichletBC,
1767 DifferentiableGalerkinOperator >;
FunctionSpaceType::RangeType RangeType
type of range vectors, i.e., type of function values
Definition: localfunction.hh:110
FunctionSpaceType::HessianRangeType HessianRangeType
type of the Hessian
Definition: localfunction.hh:114
FunctionSpaceType::JacobianRangeType JacobianRangeType
type of the Jacobian, i.e., type of evaluated Jacobian matrix
Definition: localfunction.hh:112
static bool verbose()
obtain the cached value for fem.verbose with default verbosity level 2
Definition: parameter.hh:466
quadrature on the codim-0 reference element
actual interface class for quadratures
constexpr void forEach(Range &&range, F &&f)
Range based for loop.
Definition: hybridutilities.hh:261
static constexpr IntegralRange< std::decay_t< T > > range(T &&from, U &&to) noexcept
free standing function for setting up a range based for loop over an integer range for (auto i: range...
Definition: rangeutilities.hh:288
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