3#ifndef DUNE_PYTHON_MMESH_JACOBIAN_HH
4#define DUNE_PYTHON_MMESH_JACOBIAN_HH
14#include <dune/istl/umfpack.hh>
15#include <dune/fem/operator/linear/spoperator.hh>
17#include <dune/python/pybind11/functional.h>
18#include <dune/python/pybind11/numpy.h>
19#include <dune/python/pybind11/pybind11.h>
20#include <dune/python/pybind11/stl.h>
32 template<
class Gr
idPart,
class Intersection,
class Entity >
33 const typename GridPart::IntersectionType convert(
const GridPart& gridPart,
const Intersection& intersection,
const Entity& inside, Dune::PriorityTag<0> )
35 const Entity outside = gridPart.convert(intersection.outside());
37 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::InteriorBorder>
67 typedef Fem::Stencil<DomainSpace, RangeSpace> BaseType;
69 typedef typename DomainSpace::GridPartType DomainGridPart;
70 typedef typename RangeSpace::GridPartType RangeGridPart;
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::InteriorBorder>
105 typedef Fem::Stencil<DomainSpace, RangeSpace> BaseType;
107 typedef typename DomainSpace::GridPartType DomainGridPart;
108 typedef typename RangeSpace::GridPartType RangeGridPart;
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_;
137 template<
class Sch,
class ISch,
class Sol,
class ISol >
142 using IScheme = ISch;
143 using Solution = Sol;
144 using ISolution = ISol;
146 using SparseMatrix = Dune::Fem::SparseRowMatrix<double, int>;
148 using AType =
typename Scheme::JacobianOperatorType;
149 using BType = Dune::Fem::SparseRowLinearOperator<ISolution, Solution, SparseMatrix>;
150 using CType = Dune::Fem::SparseRowLinearOperator<Solution, ISolution, SparseMatrix>;
151 using DType =
typename IScheme::JacobianOperatorType;
153 using UMFPackMatrix = Dune::BCRSMatrix<double>;
154 using UMFPackVector = Dune::BlockVector<double>;
156 typedef typename AType::DomainSpaceType BulkSpaceType;
157 typedef typename DType::DomainSpaceType InterfaceSpaceType;
159 Jacobian(
const Scheme &scheme,
const IScheme &ischeme,
const Solution &uh,
const ISolution &th,
160 const double eps,
const std::function<
void()> &callback )
161 : scheme_(scheme), ischeme_(ischeme),
162 A_(
"A", uh.space(), uh.space() ),
163 B_(
"B", th.space(), uh.space() ),
164 C_(
"C", uh.space(), th.space() ),
165 D_(
"D", th.space(), th.space() ),
172 NeighborInterfaceStencil< InterfaceSpaceType, BulkSpaceType > stencilB( B_.domainSpace(), B_.rangeSpace() );
173 stencilB.setupStencil();
174 B_.reserve( stencilB );
176 InterfaceNeighborStencil< BulkSpaceType, InterfaceSpaceType > stencilC( C_.domainSpace(), C_.rangeSpace() );
177 stencilC.setupStencil();
178 C_.reserve( stencilC );
181 void update(
const Solution &uh,
const ISolution &th )
183 scheme_.jacobian(uh, A_);
184 ischeme_.jacobian(th, D_);
187 assembleB(scheme_, th, uh);
190 assembleC(ischeme_, uh, th);
193 void solve(
const Solution &f,
const ISolution &g, Solution& u, ISolution& t )
195 if (M_.buildStage() != UMFPackMatrix::built)
198 std::size_t n = B_.exportMatrix().rows();
199 std::size_t m = B_.exportMatrix().cols();
201 auto setBlock = [
this](
const auto& block, std::size_t row0, std::size_t col0)
203 auto crs = block.exportMatrix().exportCRS();
204 const auto& val = std::get<0>(crs);
205 const auto& col = std::get<1>(crs);
206 const auto& row = std::get<2>(crs);
208 for (std::size_t i = 0; i < row.size()-1; ++i)
209 for (std::size_t j = row[i]; j < row[i+1]; ++j)
210 this->M_[row0 + i][col0 + col[j]] = val[j];
218 for (std::size_t i = 0; i < n; ++i)
219 b_[i] = f.leakPointer()[i];
220 for (std::size_t i = 0; i < m; ++i)
221 b_[i+n] = g.leakPointer()[i];
223 Dune::UMFPack<UMFPackMatrix> solver(M_);
224 Dune::InverseOperatorResult res;
225 solver.apply(x_, b_, res);
228 for (std::size_t i = 0; i < u.size(); ++i)
229 u.leakPointer()[i] = x_[i];
230 for (std::size_t i = 0; i < t.size(); ++i)
231 t.leakPointer()[i] = x_[i+n];
239 std::size_t n = B_.exportMatrix().rows();
240 std::size_t m = B_.exportMatrix().cols();
244 std::size_t nz = std::max( A_.exportMatrix().maxNzPerRow() + B_.exportMatrix().maxNzPerRow(),
245 C_.exportMatrix().maxNzPerRow() + D_.exportMatrix().maxNzPerRow() );
246 M_.setBuildMode(UMFPackMatrix::implicit);
247 M_.setImplicitBuildModeParameters(nz, 0.1);
248 M_.setSize(n+m, n+m);
250 auto addBlock = [
this](
const auto& block, std::size_t row0, std::size_t col0)
252 auto crs = block.exportMatrix().exportCRS();
253 const auto& val = std::get<0>(crs);
254 const auto& col = std::get<1>(crs);
255 const auto& row = std::get<2>(crs);
257 for (std::size_t i = 0; i < row.size()-1; ++i)
258 for (std::size_t j = row[i]; j < row[i+1]; ++j)
259 this->M_.entry(row0 + i, col0 + col[j]) = val[j];
271 template<
class Scheme,
class DomainGr
idFunction,
class RangeGr
idFunction >
272 void assembleB (
const Scheme &scheme,
const DomainGridFunction &t,
const RangeGridFunction &u)
274 typedef InterfaceSpaceType DomainSpaceType;
275 typedef BulkSpaceType RangeSpaceType;
277 typedef Fem::TemporaryLocalMatrix< DomainSpaceType, RangeSpaceType > TemporaryLocalMatrixType;
278 typedef typename RangeGridFunction::DiscreteFunctionSpaceType DiscreteFunctionSpaceType;
280 const auto& gridPart = t.gridPart();
281 const auto& grid = gridPart.grid();
282 const auto& mmesh = grid.getMMesh();
287 Dune::Fem::TemporaryLocalFunction< DiscreteFunctionSpaceType > FmTmpIn( u.space() );
288 Dune::Fem::TemporaryLocalFunction< DiscreteFunctionSpaceType > FmTmpOut( u.space() );
289 Dune::Fem::TemporaryLocalFunction< DiscreteFunctionSpaceType > FpTmpIn( u.space() );
290 Dune::Fem::TemporaryLocalFunction< DiscreteFunctionSpaceType > FpTmpOut( u.space() );
292 Dune::Fem::MutableLocalFunction< DomainGridFunction > tLocal( t );
294 Dune::Fem::ConstLocalFunction< RangeGridFunction > uInside( u );
295 Dune::Fem::ConstLocalFunction< RangeGridFunction > uOutside( u );
297 Dune::Fem::MutableLocalFunction< RangeGridFunction > dFLocalIn( dFIn );
298 Dune::Fem::MutableLocalFunction< RangeGridFunction > dFLocalOut( dFOut );
300 TemporaryLocalMatrixType localMatrixIn( B_.domainSpace(), B_.rangeSpace() );
301 TemporaryLocalMatrixType localMatrixOut( B_.domainSpace(), B_.rangeSpace() );
303 for(
const auto &interface : elements( gridPart, Partitions::interiorBorder ) )
305 tLocal.bind( interface );
306 auto& tDof = tLocal.localDofVector();
308 const auto mmeshIntersection = mmesh.asIntersection( interface );
309 const auto inside = u.gridPart().convert( mmeshIntersection.inside() );
310 const auto intersection = convert( u.gridPart(), mmeshIntersection, inside );
312 const auto& outside = intersection.outside();
314 FmTmpIn.bind( inside );
315 FmTmpOut.bind( outside );
316 FpTmpIn.bind( inside );
317 FpTmpOut.bind( outside );
319 uInside.bind( inside );
320 uOutside.bind( outside );
322 dFLocalIn.bind( inside );
323 dFLocalOut.bind( outside );
325 localMatrixIn.init( interface, inside );
326 localMatrixOut.init( interface, outside );
328 localMatrixIn.clear();
329 localMatrixOut.clear();
331 for (std::size_t i = 0; i < tDof.size(); ++i)
341 double h = std::max(tDof[ i ] * eps_, eps_);
344 scheme.fullOperator().impl().addSkeletonIntegral( intersection, uInside, uOutside, FmTmpIn, FmTmpOut );
347 dFIn.addLocalDofs( inside, FmTmpIn.localDofVector() );
348 dFOut.addLocalDofs( outside, FmTmpOut.localDofVector() );
355 scheme.fullOperator().impl().addSkeletonIntegral( intersection, uInside, uOutside, FpTmpIn, FpTmpOut );
358 dFIn.addLocalDofs( inside, FpTmpIn.localDofVector() );
359 dFOut.addLocalDofs( outside, FpTmpOut.localDofVector() );
364 for (std::size_t j = 0; j < dFLocalIn.localDofVector().size(); ++j)
365 localMatrixIn.set(j, i, dFLocalIn[j]);
367 for (std::size_t j = 0; j < dFLocalOut.localDofVector().size(); ++j)
368 localMatrixOut.set(j, i, dFLocalOut[j]);
371 B_.addLocalMatrix( interface, inside, localMatrixIn );
372 B_.addLocalMatrix( interface, outside, localMatrixOut );
377 template<
class Scheme,
class DomainGr
idFunction,
class RangeGr
idFunction >
378 void assembleC (
const Scheme &ischeme,
const DomainGridFunction &u,
const RangeGridFunction &t)
380 typedef BulkSpaceType DomainSpaceType;
381 typedef InterfaceSpaceType RangeSpaceType;
383 typedef Fem::TemporaryLocalMatrix< DomainSpaceType, RangeSpaceType > TemporaryLocalMatrixType;
384 typedef typename RangeGridFunction::DiscreteFunctionSpaceType DiscreteFunctionSpaceType;
386 const auto& gridPart = u.gridPart();
387 const auto& grid = gridPart.grid();
391 Dune::Fem::TemporaryLocalFunction< DiscreteFunctionSpaceType > GmTmp( t.space() );
392 Dune::Fem::TemporaryLocalFunction< DiscreteFunctionSpaceType > GpTmp( t.space() );
394 Dune::Fem::MutableLocalFunction< DomainGridFunction > uLocal( u );
396 Dune::Fem::ConstLocalFunction< RangeGridFunction > tInterface( t );
397 Dune::Fem::MutableLocalFunction< RangeGridFunction > dGLocal( dG );
399 TemporaryLocalMatrixType localMatrix( C_.domainSpace(), C_.rangeSpace() );
401 for(
const auto &element : elements( gridPart, Partitions::interiorBorder ) )
403 for(
const auto& intersection : intersections( gridPart, element ) )
405 if( grid.isInterface( intersection ) )
407 const auto&
interface = grid.asInterfaceEntity( intersection );
409 uLocal.bind( element );
410 auto& uDof = uLocal.localDofVector();
412 GmTmp.bind( interface );
413 GpTmp.bind( interface );
414 tInterface.bind( interface );
416 dGLocal.bind( interface );
417 localMatrix.init( element, interface );
420 for (std::size_t i = 0; i < uDof.size(); ++i)
427 double h = std::max(uDof[ i ] * eps_, eps_);
430 ischeme.fullOperator().impl().addInteriorIntegral( tInterface, GmTmp );
433 dG.addLocalDofs( interface, GmTmp.localDofVector() );
438 ischeme.fullOperator().impl().addInteriorIntegral( tInterface, GpTmp );
441 dG.addLocalDofs( interface, GpTmp.localDofVector() );
444 for (std::size_t j = 0; j < dGLocal.localDofVector().size(); ++j)
445 localMatrix.set(j, i, dGLocal[j]);
448 C_.addLocalMatrix( element, interface, localMatrix );
455 const Scheme& scheme_;
456 const IScheme& ischeme_;
462 UMFPackVector x_, b_;
464 const std::function<void()> callback_;
467 template<
class Jacobian,
class... options >
468 inline static auto registerJacobian ( pybind11::handle scope, pybind11::class_< Jacobian, options... > cls )
470 using Solution =
typename Jacobian::Solution;
471 using ISolution =
typename Jacobian::ISolution;
473 cls.def(
"init", [] ( Jacobian &self ) {
477 Initialize the mixed-dimensional jacobian.
481 cls.def( "update", [] ( Jacobian &self,
const Solution& uh,
const ISolution& th ) {
485 Update the mixed-dimensional jacobian.
489 cls.def( "solve", [] ( Jacobian &self,
const Solution& f,
const ISolution& g, Solution& ux, ISolution& tx ) {
490 self.solve(f, g, ux, tx);
493 Solve the mixed-dimensional jacobian.
Stencil contaning the entries (en,ien) for all entities en in the bulk and interface edges ien.
Definition: jacobian.hh:104
Stencil contaning the entries (ien,en) for all interface entities ien and adjacent bulk entities en.
Definition: jacobian.hh:66