3#ifndef DUNE_PYTHON_MMESH_JACOBIAN_HH
4#define DUNE_PYTHON_MMESH_JACOBIAN_HH
14#include <dune/fem/operator/linear/spoperator.hh>
16#include <dune/python/pybind11/functional.h>
17#include <dune/python/pybind11/numpy.h>
18#include <dune/python/pybind11/pybind11.h>
19#include <dune/python/pybind11/stl.h>
29 using Dune::Indices::_0;
30 using Dune::Indices::_1;
33 template<
class Gr
idPart,
class Intersection,
class Entity >
34 const typename GridPart::IntersectionType convert(
const GridPart& gridPart,
const Intersection& intersection,
const Entity& inside, Dune::PriorityTag<0> )
36 const Entity outside = gridPart.convert(intersection.outside());
38 for (
auto is : intersections(gridPart, inside))
39 if (is.outside() == outside)
41 DUNE_THROW(InvalidStateException,
"Intersection not found!");
45 template<
class Gr
idPart,
class Intersection,
class Entity >
46 std::enable_if_t<std::is_convertible_v<Intersection, typename GridPart::IntersectionType>,
const typename GridPart::IntersectionType>
47 convert(
const GridPart& gridPart,
const Intersection& intersection,
const Entity& inside, Dune::PriorityTag<1> )
53 template<
class Gr
idPart,
class Intersection,
class Entity >
54 const typename GridPart::IntersectionType convert(
const GridPart& gridPart,
const Intersection& intersection,
const Entity& inside )
56 return convert(gridPart, intersection, inside, Dune::PriorityTag<1>{});
64 template <
class DomainSpace,
class RangeSpace,
class Partition = Dune::Partitions::All>
65 struct NeighborInterfaceStencil :
public Fem::Stencil<DomainSpace, RangeSpace>
67 typedef Fem::Stencil<DomainSpace, RangeSpace> BaseType;
69 typedef typename DomainSpace::GridPartType DomainGridPart;
70 typedef typename RangeSpace::GridPartType RangeGridPart;
73 NeighborInterfaceStencil(
const DomainSpace &dSpace,
const RangeSpace &rSpace)
74 : BaseType( dSpace, rSpace ),
75 domainGridPart_( dSpace.gridPart() ),
76 rangeGridPart_( rSpace.gridPart() )
79 void setupStencil()
const
81 const auto& mmesh = domainGridPart_.grid().getMMesh();
82 for(
const auto& entity : elements(domainGridPart_, Partition{}) )
84 const auto mmeshIntersection = mmesh.asIntersection( entity );
85 const auto inside = rangeGridPart_.convert( mmeshIntersection.inside() );
86 const auto intersection = convert( rangeGridPart_, mmeshIntersection, inside );
88 BaseType::fill(entity, intersection.inside());
89 BaseType::fill(entity, intersection.outside());
94 const DomainGridPart& domainGridPart_;
95 const RangeGridPart& rangeGridPart_;
102 template <
class DomainSpace,
class RangeSpace,
class Partition = Dune::Partitions::All>
103 struct InterfaceNeighborStencil :
public Fem::Stencil<DomainSpace, RangeSpace>
105 typedef Fem::Stencil<DomainSpace, RangeSpace> BaseType;
107 typedef typename DomainSpace::GridPartType DomainGridPart;
108 typedef typename RangeSpace::GridPartType RangeGridPart;
111 InterfaceNeighborStencil(
const DomainSpace &dSpace,
const RangeSpace &rSpace)
112 : BaseType( dSpace, rSpace ),
113 domainGridPart_( dSpace.gridPart() ),
114 rangeGridPart_( rSpace.gridPart() )
117 void setupStencil()
const
119 for(
const auto& entity : elements(domainGridPart_, Partition{}) )
121 for(
const auto& intersection : intersections(domainGridPart_, entity) )
123 if( intersection.neighbor() && domainGridPart_.grid().isInterface(intersection) )
125 auto ientity = domainGridPart_.grid().asInterfaceEntity(intersection);
126 BaseType::fill(entity, ientity);
133 const DomainGridPart& domainGridPart_;
134 const RangeGridPart& rangeGridPart_;
138 template<
class X,
class BulkDF,
class InterfaceDF>
139 class ParallelizedScalarProduct :
public ScalarProduct<X> {
141 typedef X domain_type;
142 typedef typename X::field_type field_type;
143 typedef typename FieldTraits<field_type>::real_type real_type;
145 ParallelizedScalarProduct(
const BulkDF& uh,
const InterfaceDF& th)
146 : u(uh), v(uh), t(th), s(th)
149 virtual field_type dot (
const X& x,
const X& y)
const
151 u.blockVector() = x[_0];
152 t.blockVector() = x[_1];
153 v.blockVector() = y[_0];
154 s.blockVector() = y[_1];
155 return u.scalarProductDofs(v) + t.scalarProductDofs(s);
158 virtual real_type norm (
const X& x)
const
160 u.blockVector() = x[_0];
161 t.blockVector() = x[_1];
162 return std::sqrt( u.scalarProductDofs(u) + t.scalarProductDofs(t) );
167 mutable InterfaceDF t, s;
170 template<
class M,
class X,
class Y,
class BulkDF,
class InterfaceDF>
171 class ParallelizedMatrixAdapter :
public AssembledLinearOperator<M,X,Y>
175 typedef M matrix_type;
176 typedef X domain_type;
177 typedef Y range_type;
178 typedef typename X::field_type field_type;
181 explicit ParallelizedMatrixAdapter (
const M& A,
const BulkDF& uh,
const InterfaceDF& th)
182 : _A_(stackobject_to_shared_ptr(A)), u(uh), t(th)
186 void apply (
const X& x, Y& y)
const override
193 void applyscaleadd (field_type alpha,
const X& x, Y& y)
const override
195 _A_->usmv(alpha, x, y);
200 const M& getmat ()
const override
206 SolverCategory::Category category()
const override
208 return SolverCategory::sequential;
212 void communicate(Y& y)
const
214 u.blockVector() = y[_0];
215 t.blockVector() = y[_1];
218 y[_0] = u.blockVector();
219 y[_1] = t.blockVector();
222 const std::shared_ptr<const M> _A_;
224 mutable InterfaceDF t;
228 template<
class Sch,
class ISch,
class Sol,
class ISol >
231 using ThisType = Jacobian<Sch, ISch, Sol, ISol>;
234 using IScheme = ISch;
235 using Solution = Sol;
236 using ISolution = ISol;
238 using AType =
typename Scheme::JacobianOperatorType;
239 using BType = Dune::Fem::ISTLLinearOperator<ISolution, Solution>;
240 using CType = Dune::Fem::ISTLLinearOperator<Solution, ISolution>;
241 using DType =
typename IScheme::JacobianOperatorType;
244 using AMatrixBlock = Dune::BCRSMatrix<typename AType::MatrixBlockType>;
245 using BMatrixBlock = Dune::BCRSMatrix<typename BType::MatrixBlockType>;
246 using CMatrixBlock = Dune::BCRSMatrix<typename CType::MatrixBlockType>;
247 using DMatrixBlock = Dune::BCRSMatrix<typename DType::MatrixBlockType>;
249 using ABRowType = Dune::MultiTypeBlockVector<AMatrixBlock, BMatrixBlock>;
250 using CDRowType = Dune::MultiTypeBlockVector<CMatrixBlock, DMatrixBlock>;
251 using BlockMatrix = Dune::MultiTypeBlockMatrix<ABRowType, CDRowType>;
254 using AVectorBlock =
typename AType::ColumnBlockVectorType;
255 using DVectorBlock =
typename DType::ColumnBlockVectorType;
256 using BlockVector = Dune::MultiTypeBlockVector<AVectorBlock, DVectorBlock>;
258 typedef typename AType::DomainSpaceType BulkSpaceType;
259 typedef typename DType::DomainSpaceType InterfaceSpaceType;
260 using ParameterType = Fem::NewtonParameter<typename IScheme::LinearInverseOperatorType::SolverParameterType>;
262 Jacobian(
const Scheme &scheme,
const IScheme &ischeme,
const Solution &uh,
const ISolution &th,
263 const double eps,
const std::function<
void()> &callback )
264 : scheme_(scheme), ischeme_(ischeme),
265 A_(
"A", uh.space(), uh.space() ),
266 B_(
"B", th.space(), uh.space() ),
267 C_(
"C", uh.space(), th.space() ),
268 D_(
"D", th.space(), th.space() ),
274 x_[_0] = uh.blockVector();
275 x_[_1] = th.blockVector();
278 const Scheme& scheme()
const {
return scheme_; };
279 const BlockMatrix& M()
const {
return M_; };
283 if (n_ == 0 || m_ == 0)
286 NeighborInterfaceStencil< InterfaceSpaceType, BulkSpaceType > stencilB( B_.domainSpace(), B_.rangeSpace() );
287 stencilB.setupStencil();
288 B_.reserve( stencilB );
290 InterfaceNeighborStencil< BulkSpaceType, InterfaceSpaceType > stencilC( C_.domainSpace(), C_.rangeSpace() );
291 stencilC.setupStencil();
292 C_.reserve( stencilC );
295 void update(
const Solution &uh,
const ISolution &th )
297 scheme_.jacobian(uh, A_);
298 ischeme_.jacobian(th, D_);
300 if (n_ > 0 && m_ > 0)
304 assembleB(scheme_, th, uh);
305 assembleC(ischeme_, uh, th);
309 void solve(
const Solution &f,
const ISolution &g, Solution& u, ISolution& t )
311 auto setBlock = [
this](
const auto& block,
const auto blockrow,
const auto blockcol)
313 this->M_[blockrow][blockcol] = block.exportMatrix();
317 setBlock(A_, _0, _0);
318 if (n_ > 0 && m_ > 0)
320 setBlock(B_, _0, _1);
321 setBlock(C_, _1, _0);
324 setBlock(D_, _1, _1);
326 b_[_0] = f.blockVector();
327 b_[_1] = g.blockVector();
329 auto params = std::make_shared<Fem::ISTLSolverParameter>( ParameterType( scheme_.parameter() ).linear() );
330 const size_t numIterations = params->preconditionerIteration();
331 const double relaxFactor = params->relaxation();
333 using SolverAdapterType = Fem::ISTLSolverAdapter<-1, BlockVector>;
334 using ReductionType =
typename SolverAdapterType::ReductionType;
335 SolverAdapterType solver( ReductionType( params ), params );
336 solver.setMaxIterations( params->maxIterations() );
338 ParallelizedMatrixAdapter<BlockMatrix, BlockVector, BlockVector, Solution, ISolution> linop(M_, u, t);
339 ParallelizedScalarProduct<BlockVector, Solution, ISolution> scp (u, t);
340 Dune::Richardson<BlockVector, BlockVector> prec(1.0);
341 InverseOperatorResult res;
343 solver( linop, scp, prec, b_, x_, res );
345 u.blockVector() = x_[_0];
346 t.blockVector() = x_[_1];
352 template<
class Scheme,
class DomainGr
idFunction,
class RangeGr
idFunction >
353 void assembleB (
const Scheme &scheme,
const DomainGridFunction &t,
const RangeGridFunction &u)
355 typedef InterfaceSpaceType DomainSpaceType;
356 typedef BulkSpaceType RangeSpaceType;
358 typedef Fem::TemporaryLocalMatrix< DomainSpaceType, RangeSpaceType > TemporaryLocalMatrixType;
359 typedef typename RangeGridFunction::DiscreteFunctionSpaceType DiscreteFunctionSpaceType;
361 const auto& gridPart = t.gridPart();
362 const auto& grid = gridPart.grid();
363 const auto& mmesh = grid.getMMesh();
368 Dune::Fem::TemporaryLocalFunction< DiscreteFunctionSpaceType > FmTmpIn( u.space() );
369 Dune::Fem::TemporaryLocalFunction< DiscreteFunctionSpaceType > FmTmpOut( u.space() );
370 Dune::Fem::TemporaryLocalFunction< DiscreteFunctionSpaceType > FpTmpIn( u.space() );
371 Dune::Fem::TemporaryLocalFunction< DiscreteFunctionSpaceType > FpTmpOut( u.space() );
373 Dune::Fem::MutableLocalFunction< DomainGridFunction > tLocal( t );
375 Dune::Fem::ConstLocalFunction< RangeGridFunction > uInside( u );
376 Dune::Fem::ConstLocalFunction< RangeGridFunction > uOutside( u );
378 Dune::Fem::MutableLocalFunction< RangeGridFunction > dFLocalIn( dFIn );
379 Dune::Fem::MutableLocalFunction< RangeGridFunction > dFLocalOut( dFOut );
381 TemporaryLocalMatrixType localMatrixIn( B_.domainSpace(), B_.rangeSpace() );
382 TemporaryLocalMatrixType localMatrixOut( B_.domainSpace(), B_.rangeSpace() );
384 for(
const auto &interface : elements( gridPart, Partitions::all ) )
386 tLocal.bind( interface );
387 auto& tDof = tLocal.localDofVector();
389 const auto mmeshIntersection = mmesh.asIntersection( interface );
390 const auto inside = u.gridPart().convert( mmeshIntersection.inside() );
391 const auto intersection = convert( u.gridPart(), mmeshIntersection, inside );
393 const auto& outside = intersection.outside();
395 FmTmpIn.bind( inside );
396 FmTmpOut.bind( outside );
397 FpTmpIn.bind( inside );
398 FpTmpOut.bind( outside );
400 uInside.bind( inside );
401 uOutside.bind( outside );
403 dFLocalIn.bind( inside );
404 dFLocalOut.bind( outside );
406 localMatrixIn.init( interface, inside );
407 localMatrixOut.init( interface, outside );
409 localMatrixIn.clear();
410 localMatrixOut.clear();
412 for (std::size_t i = 0; i < tDof.size(); ++i)
422 double h = std::max(tDof[ i ] * eps_, eps_);
425 scheme.fullOperator().impl().addSkeletonIntegral( intersection, uInside, uOutside, FmTmpIn, FmTmpOut );
428 dFIn.addLocalDofs( inside, FmTmpIn.localDofVector() );
429 dFOut.addLocalDofs( outside, FmTmpOut.localDofVector() );
436 scheme.fullOperator().impl().addSkeletonIntegral( intersection, uInside, uOutside, FpTmpIn, FpTmpOut );
439 dFIn.addLocalDofs( inside, FpTmpIn.localDofVector() );
440 dFOut.addLocalDofs( outside, FpTmpOut.localDofVector() );
445 for (std::size_t j = 0; j < dFLocalIn.localDofVector().size(); ++j)
446 localMatrixIn.set(j, i, dFLocalIn[j]);
448 for (std::size_t j = 0; j < dFLocalOut.localDofVector().size(); ++j)
449 localMatrixOut.set(j, i, dFLocalOut[j]);
452 B_.addLocalMatrix( interface, inside, localMatrixIn );
453 B_.addLocalMatrix( interface, outside, localMatrixOut );
458 template<
class Scheme,
class DomainGr
idFunction,
class RangeGr
idFunction >
459 void assembleC (
const Scheme &ischeme,
const DomainGridFunction &u,
const RangeGridFunction &t)
461 typedef BulkSpaceType DomainSpaceType;
462 typedef InterfaceSpaceType RangeSpaceType;
464 typedef Fem::TemporaryLocalMatrix< DomainSpaceType, RangeSpaceType > TemporaryLocalMatrixType;
465 typedef typename RangeGridFunction::DiscreteFunctionSpaceType DiscreteFunctionSpaceType;
467 const auto& gridPart = u.gridPart();
468 const auto& grid = gridPart.grid();
472 Dune::Fem::TemporaryLocalFunction< DiscreteFunctionSpaceType > GmTmp( t.space() );
473 Dune::Fem::TemporaryLocalFunction< DiscreteFunctionSpaceType > GpTmp( t.space() );
475 Dune::Fem::MutableLocalFunction< DomainGridFunction > uLocal( u );
477 Dune::Fem::ConstLocalFunction< RangeGridFunction > tInterface( t );
478 Dune::Fem::MutableLocalFunction< RangeGridFunction > dGLocal( dG );
480 TemporaryLocalMatrixType localMatrix( C_.domainSpace(), C_.rangeSpace() );
482 for(
const auto &element : elements( gridPart, Partitions::all ) )
484 for(
const auto& intersection : intersections( gridPart, element ) )
486 if( grid.isInterface( intersection ) )
488 const auto&
interface = grid.asInterfaceEntity( intersection );
490 uLocal.bind( element );
491 auto& uDof = uLocal.localDofVector();
493 GmTmp.bind( interface );
494 GpTmp.bind( interface );
495 tInterface.bind( interface );
497 dGLocal.bind( interface );
498 localMatrix.init( element, interface );
501 for (std::size_t i = 0; i < uDof.size(); ++i)
508 double h = std::max(uDof[ i ] * eps_, eps_);
511 ischeme.fullOperator().impl().addInteriorIntegral( tInterface, GmTmp );
514 dG.addLocalDofs( interface, GmTmp.localDofVector() );
519 ischeme.fullOperator().impl().addInteriorIntegral( tInterface, GpTmp );
522 dG.addLocalDofs( interface, GpTmp.localDofVector() );
525 for (std::size_t j = 0; j < dGLocal.localDofVector().size(); ++j)
526 localMatrix.set(j, i, dGLocal[j]);
529 C_.addLocalMatrix( element, interface, localMatrix );
536 const Scheme& scheme_;
537 const IScheme& ischeme_;
546 const std::function<void()> callback_;
549 template<
class Jacobian,
class... options >
550 inline static auto registerJacobian ( pybind11::handle scope, pybind11::class_< Jacobian, options... > cls )
552 using Solution =
typename Jacobian::Solution;
553 using ISolution =
typename Jacobian::ISolution;
555 cls.def(
"init", [] ( Jacobian &self ) {
559 Initialize the mixed-dimensional jacobian.
563 cls.def( "update", [] ( Jacobian &self,
const Solution& uh,
const ISolution& th ) {
567 Update the mixed-dimensional jacobian.
571 cls.def( "solve", [] ( Jacobian &self,
const Solution& f,
const ISolution& g, Solution& ux, ISolution& tx ) {
572 self.solve(f, g, ux, tx);
575 Solve the mixed-dimensional jacobian.