dune-mmesh 1.4.1-git
Loading...
Searching...
No Matches
jacobian.hh
Go to the documentation of this file.
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 <dune/python/pybind11/functional.h>
7#include <dune/python/pybind11/numpy.h>
8#include <dune/python/pybind11/pybind11.h>
9#include <dune/python/pybind11/stl.h>
10
11#include <array>
13#include <dune/istl/umfpack.hh>
14#include <functional>
15#include <list>
16#include <map>
17#include <memory>
18#include <sstream>
19#include <type_traits>
20
21namespace Dune {
22
23namespace Python {
24
25namespace MMesh {
26
28template <class GridPart, class Intersection, class Entity>
29const typename GridPart::IntersectionType convert(
30 const GridPart& gridPart, const Intersection& intersection,
31 const Entity& inside, Dune::PriorityTag<0>) {
32 const Entity outside = gridPart.convert(intersection.outside());
33
34 for (auto is : intersections(gridPart, inside))
35 if (is.neighbor())
36 if (is.outside() == outside) return is;
37 DUNE_THROW(InvalidStateException, "Intersection not found!");
38}
39
41template <class GridPart, class Intersection, class Entity>
43 std::is_convertible_v<Intersection, typename GridPart::IntersectionType>,
44 const typename GridPart::IntersectionType>
45convert(const GridPart& gridPart, const Intersection& intersection,
46 const Entity& inside, Dune::PriorityTag<1>) {
47 return intersection;
48}
49
51template <class GridPart, class Intersection, class Entity>
52const typename GridPart::IntersectionType convert(
53 const GridPart& gridPart, const Intersection& intersection,
54 const Entity& inside) {
55 return convert(gridPart, intersection, inside, Dune::PriorityTag<1>{});
56}
57
62template <class DomainSpace, class RangeSpace,
63 class Partition = Dune::Partitions::InteriorBorder>
64struct NeighborInterfaceStencil : public Fem::Stencil<DomainSpace, RangeSpace> {
66
67 typedef typename DomainSpace::GridPartType DomainGridPart;
68 typedef typename RangeSpace::GridPartType RangeGridPart;
69
70 public:
71 NeighborInterfaceStencil(const DomainSpace& dSpace, const RangeSpace& rSpace)
72 : BaseType(dSpace, rSpace),
73 domainGridPart_(dSpace.gridPart()),
74 rangeGridPart_(rSpace.gridPart()) {}
75
76 void setupStencil() const {
77 const auto& mmesh = domainGridPart_.grid().getMMesh();
78 for (const auto& entity : elements(domainGridPart_, Partition{})) {
79 const auto mmeshIntersection = mmesh.asIntersection(entity);
80 const auto inside = rangeGridPart_.convert(mmeshIntersection.inside());
81 const auto intersection =
82 convert(rangeGridPart_, mmeshIntersection, inside);
83
84 BaseType::fill(entity, intersection.inside());
85 BaseType::fill(entity, intersection.outside());
86 }
87 }
88
89 private:
90 const DomainGridPart& domainGridPart_;
91 const RangeGridPart& rangeGridPart_;
92};
93
98template <class DomainSpace, class RangeSpace,
99 class Partition = Dune::Partitions::InteriorBorder>
100struct InterfaceNeighborStencil : public Fem::Stencil<DomainSpace, RangeSpace> {
102
103 typedef typename DomainSpace::GridPartType DomainGridPart;
104 typedef typename RangeSpace::GridPartType RangeGridPart;
105
106 public:
107 InterfaceNeighborStencil(const DomainSpace& dSpace, const RangeSpace& rSpace)
108 : BaseType(dSpace, rSpace),
109 domainGridPart_(dSpace.gridPart()),
110 rangeGridPart_(rSpace.gridPart()) {}
111
112 void setupStencil() const {
113 for (const auto& entity : elements(domainGridPart_, Partition{})) {
114 for (const auto& intersection : intersections(domainGridPart_, entity)) {
115 if (intersection.neighbor() &&
116 domainGridPart_.grid().isInterface(intersection)) {
117 auto ientity = domainGridPart_.grid().asInterfaceEntity(intersection);
118 BaseType::fill(entity, ientity);
119 }
120 }
121 }
122 }
123
124 private:
125 const DomainGridPart& domainGridPart_;
126 const RangeGridPart& rangeGridPart_;
127};
128
129template <class Sch, class ISch, class Sol, class ISol>
130class Jacobian {
131 public:
132 using Scheme = Sch;
133 using IScheme = ISch;
134 using Solution = Sol;
135 using ISolution = ISol;
136
138
139 using AType = typename Scheme::JacobianOperatorType;
140 using BType =
142 using CType =
144 using DType = typename IScheme::JacobianOperatorType;
145
148
149 typedef typename AType::DomainSpaceType BulkSpaceType;
150 typedef typename DType::DomainSpaceType InterfaceSpaceType;
151
152 Jacobian(const Scheme& scheme, const IScheme& ischeme, const Solution& uh,
153 const ISolution& th, const double eps,
154 const std::function<void()>& callback)
155 : scheme_(scheme),
156 ischeme_(ischeme),
157 A_("A", uh.space(), uh.space()),
158 B_("B", th.space(), uh.space()),
159 C_("C", uh.space(), th.space()),
160 D_("D", th.space(), th.space()),
161 eps_(eps),
162 callback_(callback) {}
163
164 void init() {
166 B_.domainSpace(), B_.rangeSpace());
167 stencilB.setupStencil();
168 B_.reserve(stencilB);
169
171 C_.domainSpace(), C_.rangeSpace());
172 stencilC.setupStencil();
173 C_.reserve(stencilC);
174 }
175
176 void update(const Solution& uh, const ISolution& th) {
177 scheme_.jacobian(uh, A_);
178 ischeme_.jacobian(th, D_);
179
180 B_.clear();
181 assembleB(scheme_, th, uh);
182
183 C_.clear();
184 assembleC(ischeme_, uh, th);
185 }
186
187 void solve(const Solution& f, const ISolution& g, Solution& u, ISolution& t) {
188 if (M_.buildStage() != UMFPackMatrix::built) setup();
189
190 std::size_t n = B_.exportMatrix().rows();
191 std::size_t m = B_.exportMatrix().cols();
192
193 auto setBlock = [this](const auto& block, std::size_t row0,
194 std::size_t col0) {
195 auto crs = block.exportMatrix().exportCRS();
196 const auto& val = std::get<0>(crs);
197 const auto& col = std::get<1>(crs);
198 const auto& row = std::get<2>(crs);
199
200 for (std::size_t i = 0; i < row.size() - 1; ++i)
201 for (std::size_t j = row[i]; j < row[i + 1]; ++j)
202 this->M_[row0 + i][col0 + col[j]] = val[j];
203 };
204
205 setBlock(A_, 0, 0);
206 setBlock(B_, 0, n);
207 setBlock(C_, n, 0);
208 setBlock(D_, n, n);
209
210 for (std::size_t i = 0; i < n; ++i) b_[i] = f.leakPointer()[i];
211 for (std::size_t i = 0; i < m; ++i) b_[i + n] = g.leakPointer()[i];
212
215 solver.apply(x_, b_, res);
216 solver.free();
217
218 for (std::size_t i = 0; i < u.size(); ++i) u.leakPointer()[i] = x_[i];
219 for (std::size_t i = 0; i < t.size(); ++i) t.leakPointer()[i] = x_[i + n];
220 }
221
222 private:
223 // Setup UMFPackMatrix
224 void setup() {
225 std::size_t n = B_.exportMatrix().rows();
226 std::size_t m = B_.exportMatrix().cols();
227 x_.resize(n + m);
228 b_.resize(n + m);
229
231 A_.exportMatrix().maxNzPerRow() + B_.exportMatrix().maxNzPerRow(),
232 C_.exportMatrix().maxNzPerRow() + D_.exportMatrix().maxNzPerRow());
235 M_.setSize(n + m, n + m);
236
237 auto addBlock = [this](const auto& block, std::size_t row0,
238 std::size_t col0) {
239 auto crs = block.exportMatrix().exportCRS();
240 const auto& val = std::get<0>(crs);
241 const auto& col = std::get<1>(crs);
242 const auto& row = std::get<2>(crs);
243
244 for (std::size_t i = 0; i < row.size() - 1; ++i)
245 for (std::size_t j = row[i]; j < row[i + 1]; ++j)
246 this->M_.entry(row0 + i, col0 + col[j]) = val[j];
247 };
248
249 addBlock(A_, 0, 0);
250 addBlock(B_, 0, n);
251 addBlock(C_, n, 0);
252 addBlock(D_, n, n);
253
254 M_.compress();
255 }
256
257 template <class Scheme, class DomainGridFunction, class RangeGridFunction>
258 void assembleB(const Scheme& scheme, const DomainGridFunction& t,
259 const RangeGridFunction& u) {
260 typedef InterfaceSpaceType DomainSpaceType;
261 typedef BulkSpaceType RangeSpaceType;
262
264 TemporaryLocalMatrixType;
265 typedef typename RangeGridFunction::DiscreteFunctionSpaceType
266 DiscreteFunctionSpaceType;
267
268 const auto& gridPart = t.gridPart();
269 const auto& grid = gridPart.grid();
270 const auto& mmesh = grid.getMMesh();
271
272 auto dFIn = u;
273 auto dFOut = u;
274
276 u.space());
278 u.space());
280 u.space());
282 u.space());
283
285
288
291
292 TemporaryLocalMatrixType localMatrixIn(B_.domainSpace(), B_.rangeSpace());
293 TemporaryLocalMatrixType localMatrixOut(B_.domainSpace(), B_.rangeSpace());
294
295 for (const auto& interface :
296 elements(gridPart, Partitions::interiorBorder)) {
297 tLocal.bind(interface);
298 auto& tDof = tLocal.localDofVector();
299
300 const auto mmeshIntersection = mmesh.asIntersection(interface);
301 const auto inside = u.gridPart().convert(mmeshIntersection.inside());
302 const auto intersection =
303 convert(u.gridPart(), mmeshIntersection, inside);
304
305 const auto& outside = intersection.outside();
306
307 FmTmpIn.bind(inside);
308 FmTmpOut.bind(outside);
309 FpTmpIn.bind(inside);
310 FpTmpOut.bind(outside);
311
312 uInside.bind(inside);
313 uOutside.bind(outside);
314
315 dFLocalIn.bind(inside);
316 dFLocalOut.bind(outside);
317
318 localMatrixIn.init(interface, inside);
319 localMatrixOut.init(interface, outside);
320
321 localMatrixIn.clear();
322 localMatrixOut.clear();
323
324 for (std::size_t i = 0; i < tDof.size(); ++i) {
325 dFIn.clear();
326 dFOut.clear();
327
328 FmTmpIn.clear();
329 FmTmpOut.clear();
330 FpTmpIn.clear();
331 FpTmpOut.clear();
332
333 double h = std::max(tDof[i] * eps_, eps_);
334 tDof[i] -= h;
335 callback_();
336 scheme.fullOperator().impl().addSkeletonIntegral(
337 intersection, uInside, uOutside, FmTmpIn, FmTmpOut);
338 tDof[i] += h;
339
340 dFIn.addLocalDofs(inside, FmTmpIn.localDofVector());
341 dFOut.addLocalDofs(outside, FmTmpOut.localDofVector());
342
343 dFIn *= -1.;
344 dFOut *= -1.;
345
346 tDof[i] += h;
347 callback_();
348 scheme.fullOperator().impl().addSkeletonIntegral(
349 intersection, uInside, uOutside, FpTmpIn, FpTmpOut);
350 tDof[i] -= h;
351
352 dFIn.addLocalDofs(inside, FpTmpIn.localDofVector());
353 dFOut.addLocalDofs(outside, FpTmpOut.localDofVector());
354
355 dFIn /= 2 * h;
356 dFOut /= 2 * h;
357
358 for (std::size_t j = 0; j < dFLocalIn.localDofVector().size(); ++j)
359 localMatrixIn.set(j, i, dFLocalIn[j]);
360
361 for (std::size_t j = 0; j < dFLocalOut.localDofVector().size(); ++j)
362 localMatrixOut.set(j, i, dFLocalOut[j]);
363 }
364
365 B_.addLocalMatrix(interface, inside, localMatrixIn);
366 B_.addLocalMatrix(interface, outside, localMatrixOut);
367 }
368 B_.compress();
369 }
370
371 template <class Scheme, class DomainGridFunction, class RangeGridFunction>
372 void assembleC(const Scheme& ischeme, const DomainGridFunction& u,
373 const RangeGridFunction& t) {
374 typedef BulkSpaceType DomainSpaceType;
375 typedef InterfaceSpaceType RangeSpaceType;
376
377 typedef Fem::TemporaryLocalMatrix<DomainSpaceType, RangeSpaceType>
378 TemporaryLocalMatrixType;
379 typedef typename RangeGridFunction::DiscreteFunctionSpaceType
380 DiscreteFunctionSpaceType;
381
382 const auto& gridPart = u.gridPart();
383 const auto& grid = gridPart.grid();
384
385 auto dG = t;
386
388 t.space());
390 t.space());
391
393
396
397 TemporaryLocalMatrixType localMatrix(C_.domainSpace(), C_.rangeSpace());
398
399 for (const auto& element : elements(gridPart, Partitions::interiorBorder)) {
400 for (const auto& intersection : intersections(gridPart, element)) {
401 if (grid.isInterface(intersection)) {
402 const auto& interface = grid.asInterfaceEntity(intersection);
403
404 uLocal.bind(element);
405 auto& uDof = uLocal.localDofVector();
406
407 GmTmp.bind(interface);
408 GpTmp.bind(interface);
409 tInterface.bind(interface);
410
411 dGLocal.bind(interface);
412 localMatrix.init(element, interface);
413 localMatrix.clear();
414
415 for (std::size_t i = 0; i < uDof.size(); ++i) {
416 dG.clear();
417
418 GmTmp.clear();
419 GpTmp.clear();
420
421 double h = std::max(uDof[i] * eps_, eps_);
422 uDof[i] -= h;
423 callback_();
424 ischeme.fullOperator().impl().addInteriorIntegral(tInterface,
425 GmTmp);
426 uDof[i] += h;
427
428 dG.addLocalDofs(interface, GmTmp.localDofVector());
429 dG *= -1.;
430
431 uDof[i] += h;
432 callback_();
433 ischeme.fullOperator().impl().addInteriorIntegral(tInterface,
434 GpTmp);
435 uDof[i] -= h;
436
437 dG.addLocalDofs(interface, GpTmp.localDofVector());
438 dG /= 2 * h;
439
440 for (std::size_t j = 0; j < dGLocal.localDofVector().size(); ++j)
441 localMatrix.set(j, i, dGLocal[j]);
442 }
443
444 C_.addLocalMatrix(element, interface, localMatrix);
445 }
446 }
447 }
448 C_.compress();
449 }
450
451 const Scheme& scheme_;
452 const IScheme& ischeme_;
453 AType A_;
454 BType B_;
455 CType C_;
456 DType D_;
457 UMFPackMatrix M_;
458 UMFPackVector x_, b_;
459 const double eps_;
460 const std::function<void()> callback_;
461};
462
463template <class Jacobian, class... options>
464inline static auto registerJacobian(
465 pybind11::handle scope, pybind11::class_<Jacobian, options...> cls) {
466 using Solution = typename Jacobian::Solution;
467 using ISolution = typename Jacobian::ISolution;
468
469 cls.def(
470 "init", [](Jacobian& self) { self.init(); },
471 R"doc(
472 Initialize the mixed-dimensional jacobian.
473 )doc");
474
475 cls.def(
476 "update",
477 [](Jacobian& self, const Solution& uh, const ISolution& th) {
478 self.update(uh, th);
479 },
480 R"doc(
481 Update the mixed-dimensional jacobian.
482 )doc");
483
484 cls.def(
485 "solve",
486 [](Jacobian& self, const Solution& f, const ISolution& g, Solution& ux,
487 ISolution& tx) { self.solve(f, g, ux, tx); },
488 R"doc(
489 Solve the mixed-dimensional jacobian.
490 )doc");
491}
492
493} // namespace MMesh
494
495} // namespace Python
496
497} // namespace Dune
498
499#endif
Dune::ParameterTree options
static auto registerJacobian(pybind11::handle scope, pybind11::class_< Jacobian, options... > cls)
Definition jacobian.hh:464
const GridPart::IntersectionType convert(const GridPart &gridPart, const Intersection &intersection, const Entity &inside, Dune::PriorityTag< 0 >)
Convert intersection if gridPart is wrapped, e.g. geometryGridPart.
Definition jacobian.hh:29
void apply(domain_type &x, range_type &b, InverseOperatorResult &res) override
Col col
int size() const
#define DUNE_THROW(E,...)
const Grid & grid() const
IteratorRange<... > intersections(const GV &gv, const Entity &e)
IteratorRange<... > elements(const GV &gv)
constexpr InteriorBorder interiorBorder
const GridPartType & gridPart() const
const DiscreteFunctionSpaceType & space() const
const EntityType & entity() const
typename Impl::ConstLocalFunction< GridFunction >::Type ConstLocalFunction
BuildStage buildStage() const
B & entry(size_type row, size_type col)
void setImplicitBuildModeParameters(size_type _avg, double compressionBufferSize)
CompressionStatistics compress()
void setBuildMode(BuildMode bm)
void setSize(size_type rows, size_type columns, size_type nnz=0)
void resize(size_type size)
Entity outside() const
void fill(const DomainEntityType &dEntity, const RangeEntityType &rEntity, bool fillGhost=true) const
MatrixType & exportMatrix() const
const DomainSpaceType & domainSpace() const
void reserve(const std::vector< Set > &sparsityPattern)
void addLocalMatrix(const DomainEntityType &domainEntity, const RangeEntityType &rangeEntity, const LocalMatrix &localMat)
const RangeSpaceType & rangeSpace() const
The MMesh class templatized by the CGAL host grid type and the dimension. .
Definition grid/mmesh.hh:158
Stencil contaning the entries (ien,en) for all interface entities ien and adjacent bulk entities en.
Definition jacobian.hh:64
NeighborInterfaceStencil(const DomainSpace &dSpace, const RangeSpace &rSpace)
Definition jacobian.hh:71
Fem::Stencil< DomainSpace, RangeSpace > BaseType
Definition jacobian.hh:65
DomainSpace::GridPartType DomainGridPart
Definition jacobian.hh:67
void setupStencil() const
Definition jacobian.hh:76
RangeSpace::GridPartType RangeGridPart
Definition jacobian.hh:68
Stencil contaning the entries (en,ien) for all entities en in the bulk and interface edges ien.
Definition jacobian.hh:100
RangeSpace::GridPartType RangeGridPart
Definition jacobian.hh:104
DomainSpace::GridPartType DomainGridPart
Definition jacobian.hh:103
Fem::Stencil< DomainSpace, RangeSpace > BaseType
Definition jacobian.hh:101
InterfaceNeighborStencil(const DomainSpace &dSpace, const RangeSpace &rSpace)
Definition jacobian.hh:107
void setupStencil() const
Definition jacobian.hh:112
Definition jacobian.hh:130
void solve(const Solution &f, const ISolution &g, Solution &u, ISolution &t)
Definition jacobian.hh:187
void update(const Solution &uh, const ISolution &th)
Definition jacobian.hh:176
ISch IScheme
Definition jacobian.hh:133
DType::DomainSpaceType InterfaceSpaceType
Definition jacobian.hh:150
typename Scheme::JacobianOperatorType AType
Definition jacobian.hh:139
Sol Solution
Definition jacobian.hh:134
Dune::Fem::SparseRowLinearOperator< ISolution, Solution, SparseMatrix > BType
Definition jacobian.hh:141
Dune::BlockVector< double > UMFPackVector
Definition jacobian.hh:147
Jacobian(const Scheme &scheme, const IScheme &ischeme, const Solution &uh, const ISolution &th, const double eps, const std::function< void()> &callback)
Definition jacobian.hh:152
typename IScheme::JacobianOperatorType DType
Definition jacobian.hh:144
Dune::BCRSMatrix< double > UMFPackMatrix
Definition jacobian.hh:146
ISol ISolution
Definition jacobian.hh:135
void init()
Definition jacobian.hh:164
const Scheme & scheme() const
Definition jacobian_iterative.hh:260
AType::DomainSpaceType BulkSpaceType
Definition jacobian.hh:149
Sch Scheme
Definition jacobian.hh:132
Dune::Fem::SparseRowLinearOperator< Solution, ISolution, SparseMatrix > CType
Definition jacobian.hh:143
T max(T... args)