Loading [MathJax]/extensions/tex2jax.js

dune-mmesh (1.4)

jacobian.hh
1// -*- tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2// vi: set et ts=4 sw=2 sts=2:
3#ifndef DUNE_PYTHON_MMESH_JACOBIAN_HH
4#define DUNE_PYTHON_MMESH_JACOBIAN_HH
5
6#include <array>
7#include <functional>
8#include <list>
9#include <map>
10#include <memory>
11#include <sstream>
12#include <type_traits>
13
14#include <dune/istl/umfpack.hh>
15#include <dune/fem/operator/linear/spoperator.hh>
16
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>
21
22namespace Dune
23{
24
25 namespace Python
26 {
27
28 namespace MMesh
29 {
30
32 template< class GridPart, class Intersection, class Entity >
33 const typename GridPart::IntersectionType convert( const GridPart& gridPart, const Intersection& intersection, const Entity& inside, Dune::PriorityTag<0> )
34 {
35 const Entity outside = gridPart.convert(intersection.outside());
36
37 for (auto is : intersections(gridPart, inside))
38 if (is.neighbor())
39 if (is.outside() == outside)
40 return is;
41 DUNE_THROW(InvalidStateException, "Intersection not found!");
42 }
43
45 template< class GridPart, 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> )
48 {
49 return intersection;
50 }
51
53 template< class GridPart, class Intersection, class Entity >
54 const typename GridPart::IntersectionType convert( const GridPart& gridPart, const Intersection& intersection, const Entity& inside )
55 {
56 return convert(gridPart, intersection, inside, Dune::PriorityTag<1>{});
57 }
58
59
64 template <class DomainSpace, class RangeSpace, class Partition = Dune::Partitions::InteriorBorder>
65 struct NeighborInterfaceStencil : public Fem::Stencil<DomainSpace, RangeSpace>
66 {
67 typedef Fem::Stencil<DomainSpace, RangeSpace> BaseType;
68
69 typedef typename DomainSpace::GridPartType DomainGridPart;
70 typedef typename RangeSpace::GridPartType RangeGridPart;
71
72 public:
73 NeighborInterfaceStencil(const DomainSpace &dSpace, const RangeSpace &rSpace)
74 : BaseType( dSpace, rSpace ),
75 domainGridPart_( dSpace.gridPart() ),
76 rangeGridPart_( rSpace.gridPart() )
77 {}
78
79 void setupStencil() const
80 {
81 const auto& mmesh = domainGridPart_.grid().getMMesh();
82 for( const auto& entity : elements(domainGridPart_, Partition{}) )
83 {
84 const auto mmeshIntersection = mmesh.asIntersection( entity );
85 const auto inside = rangeGridPart_.convert( mmeshIntersection.inside() );
86 const auto intersection = convert( rangeGridPart_, mmeshIntersection, inside );
87
88 BaseType::fill(entity, intersection.inside());
89 BaseType::fill(entity, intersection.outside());
90 }
91 }
92
93 private:
94 const DomainGridPart& domainGridPart_;
95 const RangeGridPart& rangeGridPart_;
96 };
97
102 template <class DomainSpace, class RangeSpace, class Partition = Dune::Partitions::InteriorBorder>
103 struct InterfaceNeighborStencil : public Fem::Stencil<DomainSpace, RangeSpace>
104 {
105 typedef Fem::Stencil<DomainSpace, RangeSpace> BaseType;
106
107 typedef typename DomainSpace::GridPartType DomainGridPart;
108 typedef typename RangeSpace::GridPartType RangeGridPart;
109
110 public:
111 InterfaceNeighborStencil(const DomainSpace &dSpace, const RangeSpace &rSpace)
112 : BaseType( dSpace, rSpace ),
113 domainGridPart_( dSpace.gridPart() ),
114 rangeGridPart_( rSpace.gridPart() )
115 {}
116
117 void setupStencil() const
118 {
119 for( const auto& entity : elements(domainGridPart_, Partition{}) )
120 {
121 for( const auto& intersection : intersections(domainGridPart_, entity) )
122 {
123 if( intersection.neighbor() && domainGridPart_.grid().isInterface(intersection) )
124 {
125 auto ientity = domainGridPart_.grid().asInterfaceEntity(intersection);
126 BaseType::fill(entity, ientity);
127 }
128 }
129 }
130 }
131
132 private:
133 const DomainGridPart& domainGridPart_;
134 const RangeGridPart& rangeGridPart_;
135 };
136
137 template< class Sch, class ISch, class Sol, class ISol >
138 class Jacobian
139 {
140 public:
141 using Scheme = Sch;
142 using IScheme = ISch;
143 using Solution = Sol;
144 using ISolution = ISol;
145
146 using SparseMatrix = Dune::Fem::SparseRowMatrix<double, int>;
147
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;
152
153 using UMFPackMatrix = Dune::BCRSMatrix<double>;
154 using UMFPackVector = Dune::BlockVector<double>;
155
156 typedef typename AType::DomainSpaceType BulkSpaceType;
157 typedef typename DType::DomainSpaceType InterfaceSpaceType;
158
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() ),
166 eps_(eps),
167 callback_(callback)
168 {}
169
170 void init()
171 {
172 NeighborInterfaceStencil< InterfaceSpaceType, BulkSpaceType > stencilB( B_.domainSpace(), B_.rangeSpace() );
173 stencilB.setupStencil();
174 B_.reserve( stencilB );
175
176 InterfaceNeighborStencil< BulkSpaceType, InterfaceSpaceType > stencilC( C_.domainSpace(), C_.rangeSpace() );
177 stencilC.setupStencil();
178 C_.reserve( stencilC );
179 }
180
181 void update( const Solution &uh, const ISolution &th )
182 {
183 scheme_.jacobian(uh, A_);
184 ischeme_.jacobian(th, D_);
185
186 B_.clear();
187 assembleB(scheme_, th, uh);
188
189 C_.clear();
190 assembleC(ischeme_, uh, th);
191 }
192
193 void solve( const Solution &f, const ISolution &g, Solution& u, ISolution& t )
194 {
195 if (M_.buildStage() != UMFPackMatrix::built)
196 setup();
197
198 std::size_t n = B_.exportMatrix().rows();
199 std::size_t m = B_.exportMatrix().cols();
200
201 auto setBlock = [this](const auto& block, std::size_t row0, std::size_t col0)
202 {
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);
207
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];
211 };
212
213 setBlock(A_, 0, 0);
214 setBlock(B_, 0, n);
215 setBlock(C_, n, 0);
216 setBlock(D_, n, n);
217
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];
222
223 Dune::UMFPack<UMFPackMatrix> solver(M_);
224 Dune::InverseOperatorResult res;
225 solver.apply(x_, b_, res);
226 solver.free();
227
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];
232 }
233
234 private:
235
236 // Setup UMFPackMatrix
237 void setup()
238 {
239 std::size_t n = B_.exportMatrix().rows();
240 std::size_t m = B_.exportMatrix().cols();
241 x_.resize(n+m);
242 b_.resize(n+m);
243
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);
249
250 auto addBlock = [this](const auto& block, std::size_t row0, std::size_t col0)
251 {
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);
256
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];
260 };
261
262 addBlock(A_, 0, 0);
263 addBlock(B_, 0, n);
264 addBlock(C_, n, 0);
265 addBlock(D_, n, n);
266
267 M_.compress();
268 }
269
270
271 template< class Scheme, class DomainGridFunction, class RangeGridFunction >
272 void assembleB (const Scheme &scheme, const DomainGridFunction &t, const RangeGridFunction &u)
273 {
274 typedef InterfaceSpaceType DomainSpaceType;
275 typedef BulkSpaceType RangeSpaceType;
276
277 typedef Fem::TemporaryLocalMatrix< DomainSpaceType, RangeSpaceType > TemporaryLocalMatrixType;
278 typedef typename RangeGridFunction::DiscreteFunctionSpaceType DiscreteFunctionSpaceType;
279
280 const auto& gridPart = t.gridPart();
281 const auto& grid = gridPart.grid();
282 const auto& mmesh = grid.getMMesh();
283
284 auto dFIn = u;
285 auto dFOut = u;
286
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() );
291
292 Dune::Fem::MutableLocalFunction< DomainGridFunction > tLocal( t );
293
294 Dune::Fem::ConstLocalFunction< RangeGridFunction > uInside( u );
295 Dune::Fem::ConstLocalFunction< RangeGridFunction > uOutside( u );
296
297 Dune::Fem::MutableLocalFunction< RangeGridFunction > dFLocalIn( dFIn );
298 Dune::Fem::MutableLocalFunction< RangeGridFunction > dFLocalOut( dFOut );
299
300 TemporaryLocalMatrixType localMatrixIn( B_.domainSpace(), B_.rangeSpace() );
301 TemporaryLocalMatrixType localMatrixOut( B_.domainSpace(), B_.rangeSpace() );
302
303 for( const auto &interface : elements( gridPart, Partitions::interiorBorder ) )
304 {
305 tLocal.bind( interface );
306 auto& tDof = tLocal.localDofVector();
307
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 );
311
312 const auto& outside = intersection.outside();
313
314 FmTmpIn.bind( inside );
315 FmTmpOut.bind( outside );
316 FpTmpIn.bind( inside );
317 FpTmpOut.bind( outside );
318
319 uInside.bind( inside );
320 uOutside.bind( outside );
321
322 dFLocalIn.bind( inside );
323 dFLocalOut.bind( outside );
324
325 localMatrixIn.init( interface, inside );
326 localMatrixOut.init( interface, outside );
327
328 localMatrixIn.clear();
329 localMatrixOut.clear();
330
331 for (std::size_t i = 0; i < tDof.size(); ++i)
332 {
333 dFIn.clear();
334 dFOut.clear();
335
336 FmTmpIn.clear();
337 FmTmpOut.clear();
338 FpTmpIn.clear();
339 FpTmpOut.clear();
340
341 double h = std::max(tDof[ i ] * eps_, eps_);
342 tDof[ i ] -= h;
343 callback_();
344 scheme.fullOperator().impl().addSkeletonIntegral( intersection, uInside, uOutside, FmTmpIn, FmTmpOut );
345 tDof[ i ] += h;
346
347 dFIn.addLocalDofs( inside, FmTmpIn.localDofVector() );
348 dFOut.addLocalDofs( outside, FmTmpOut.localDofVector() );
349
350 dFIn *= -1.;
351 dFOut *= -1.;
352
353 tDof[ i ] += h;
354 callback_();
355 scheme.fullOperator().impl().addSkeletonIntegral( intersection, uInside, uOutside, FpTmpIn, FpTmpOut );
356 tDof[ i ] -= h;
357
358 dFIn.addLocalDofs( inside, FpTmpIn.localDofVector() );
359 dFOut.addLocalDofs( outside, FpTmpOut.localDofVector() );
360
361 dFIn /= 2 * h;
362 dFOut /= 2 * h;
363
364 for (std::size_t j = 0; j < dFLocalIn.localDofVector().size(); ++j)
365 localMatrixIn.set(j, i, dFLocalIn[j]);
366
367 for (std::size_t j = 0; j < dFLocalOut.localDofVector().size(); ++j)
368 localMatrixOut.set(j, i, dFLocalOut[j]);
369 }
370
371 B_.addLocalMatrix( interface, inside, localMatrixIn );
372 B_.addLocalMatrix( interface, outside, localMatrixOut );
373 }
374 B_.compress();
375 }
376
377 template< class Scheme, class DomainGridFunction, class RangeGridFunction >
378 void assembleC (const Scheme &ischeme, const DomainGridFunction &u, const RangeGridFunction &t)
379 {
380 typedef BulkSpaceType DomainSpaceType;
381 typedef InterfaceSpaceType RangeSpaceType;
382
383 typedef Fem::TemporaryLocalMatrix< DomainSpaceType, RangeSpaceType > TemporaryLocalMatrixType;
384 typedef typename RangeGridFunction::DiscreteFunctionSpaceType DiscreteFunctionSpaceType;
385
386 const auto& gridPart = u.gridPart();
387 const auto& grid = gridPart.grid();
388
389 auto dG = t;
390
391 Dune::Fem::TemporaryLocalFunction< DiscreteFunctionSpaceType > GmTmp( t.space() );
392 Dune::Fem::TemporaryLocalFunction< DiscreteFunctionSpaceType > GpTmp( t.space() );
393
394 Dune::Fem::MutableLocalFunction< DomainGridFunction > uLocal( u );
395
396 Dune::Fem::ConstLocalFunction< RangeGridFunction > tInterface( t );
397 Dune::Fem::MutableLocalFunction< RangeGridFunction > dGLocal( dG );
398
399 TemporaryLocalMatrixType localMatrix( C_.domainSpace(), C_.rangeSpace() );
400
401 for( const auto &element : elements( gridPart, Partitions::interiorBorder ) )
402 {
403 for( const auto& intersection : intersections( gridPart, element ) )
404 {
405 if( grid.isInterface( intersection ) )
406 {
407 const auto& interface = grid.asInterfaceEntity( intersection );
408
409 uLocal.bind( element );
410 auto& uDof = uLocal.localDofVector();
411
412 GmTmp.bind( interface );
413 GpTmp.bind( interface );
414 tInterface.bind( interface );
415
416 dGLocal.bind( interface );
417 localMatrix.init( element, interface );
418 localMatrix.clear();
419
420 for (std::size_t i = 0; i < uDof.size(); ++i)
421 {
422 dG.clear();
423
424 GmTmp.clear();
425 GpTmp.clear();
426
427 double h = std::max(uDof[ i ] * eps_, eps_);
428 uDof[ i ] -= h;
429 callback_();
430 ischeme.fullOperator().impl().addInteriorIntegral( tInterface, GmTmp );
431 uDof[ i ] += h;
432
433 dG.addLocalDofs( interface, GmTmp.localDofVector() );
434 dG *= -1.;
435
436 uDof[ i ] += h;
437 callback_();
438 ischeme.fullOperator().impl().addInteriorIntegral( tInterface, GpTmp );
439 uDof[ i ] -= h;
440
441 dG.addLocalDofs( interface, GpTmp.localDofVector() );
442 dG /= 2 * h;
443
444 for (std::size_t j = 0; j < dGLocal.localDofVector().size(); ++j)
445 localMatrix.set(j, i, dGLocal[j]);
446 }
447
448 C_.addLocalMatrix( element, interface, localMatrix );
449 }
450 }
451 }
452 C_.compress();
453 }
454
455 const Scheme& scheme_;
456 const IScheme& ischeme_;
457 AType A_;
458 BType B_;
459 CType C_;
460 DType D_;
461 UMFPackMatrix M_;
462 UMFPackVector x_, b_;
463 const double eps_;
464 const std::function<void()> callback_;
465 };
466
467 template< class Jacobian, class... options >
468 inline static auto registerJacobian ( pybind11::handle scope, pybind11::class_< Jacobian, options... > cls )
469 {
470 using Solution = typename Jacobian::Solution;
471 using ISolution = typename Jacobian::ISolution;
472
473 cls.def( "init", [] ( Jacobian &self ) {
474 self.init();
475 },
476 R"doc(
477 Initialize the mixed-dimensional jacobian.
478 )doc"
479 );
480
481 cls.def( "update", [] ( Jacobian &self, const Solution& uh, const ISolution& th ) {
482 self.update(uh, th);
483 },
484 R"doc(
485 Update the mixed-dimensional jacobian.
486 )doc"
487 );
488
489 cls.def( "solve", [] ( Jacobian &self, const Solution& f, const ISolution& g, Solution& ux, ISolution& tx ) {
490 self.solve(f, g, ux, tx);
491 },
492 R"doc(
493 Solve the mixed-dimensional jacobian.
494 )doc"
495 );
496 }
497
498 } // namespace MMesh
499
500 } // namespace Python
501
502} // namespace Dune
503
504#endif
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
Creative Commons License   |  Legal Statements / Impressum  |  Hosted by TU Dresden & Uni Heidelberg  |  generated with Hugo v0.111.3 (Apr 5, 23:02, 2025)